| # |
| # This file is part of pyasn1 software. |
| # |
| # Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com> |
| # License: http://snmplabs.com/pyasn1/license.html |
| # |
| import math |
| import sys |
| |
| from pyasn1 import error |
| from pyasn1.codec.ber import eoo |
| from pyasn1.compat import binary |
| from pyasn1.compat import integer |
| from pyasn1.compat import octets |
| from pyasn1.type import base |
| from pyasn1.type import constraint |
| from pyasn1.type import namedtype |
| from pyasn1.type import namedval |
| from pyasn1.type import tag |
| from pyasn1.type import tagmap |
| |
| NoValue = base.NoValue |
| noValue = NoValue() |
| |
| __all__ = ['Integer', 'Boolean', 'BitString', 'OctetString', 'Null', |
| 'ObjectIdentifier', 'Real', 'Enumerated', |
| 'SequenceOfAndSetOfBase', 'SequenceOf', 'SetOf', |
| 'SequenceAndSetBase', 'Sequence', 'Set', 'Choice', 'Any', |
| 'NoValue', 'noValue'] |
| |
| # "Simple" ASN.1 types (yet incomplete) |
| |
| |
| class Integer(base.SimpleAsn1Type): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its |
| objects are immutable and duck-type Python :class:`int` objects. |
| |
| Keyword Args |
| ------------ |
| value: :class:`int`, :class:`str` or |ASN.1| object |
| Python :class:`int` or :class:`str` literal or |ASN.1| class |
| instance. If `value` is not given, schema object will be created. |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s). Constraints |
| verification for |ASN.1| type occurs automatically on object |
| instantiation. |
| |
| namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` |
| Object representing non-default symbolic aliases for numbers |
| |
| Raises |
| ------ |
| ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error |
| On constraint violation or bad initializer. |
| |
| Examples |
| -------- |
| |
| .. code-block:: python |
| |
| class ErrorCode(Integer): |
| ''' |
| ASN.1 specification: |
| |
| ErrorCode ::= |
| INTEGER { disk-full(1), no-disk(-1), |
| disk-not-formatted(2) } |
| |
| error ErrorCode ::= disk-full |
| ''' |
| namedValues = NamedValues( |
| ('disk-full', 1), ('no-disk', -1), |
| ('disk-not-formatted', 2) |
| ) |
| |
| error = ErrorCode('disk-full') |
| """ |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x02) |
| ) |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object |
| #: representing symbolic aliases for numbers |
| namedValues = namedval.NamedValues() |
| |
| # Optimization for faster codec lookup |
| typeId = base.SimpleAsn1Type.getTypeId() |
| |
| def __init__(self, value=noValue, **kwargs): |
| if 'namedValues' not in kwargs: |
| kwargs['namedValues'] = self.namedValues |
| |
| base.SimpleAsn1Type.__init__(self, value, **kwargs) |
| |
| def __and__(self, value): |
| return self.clone(self._value & value) |
| |
| def __rand__(self, value): |
| return self.clone(value & self._value) |
| |
| def __or__(self, value): |
| return self.clone(self._value | value) |
| |
| def __ror__(self, value): |
| return self.clone(value | self._value) |
| |
| def __xor__(self, value): |
| return self.clone(self._value ^ value) |
| |
| def __rxor__(self, value): |
| return self.clone(value ^ self._value) |
| |
| def __lshift__(self, value): |
| return self.clone(self._value << value) |
| |
| def __rshift__(self, value): |
| return self.clone(self._value >> value) |
| |
| def __add__(self, value): |
| return self.clone(self._value + value) |
| |
| def __radd__(self, value): |
| return self.clone(value + self._value) |
| |
| def __sub__(self, value): |
| return self.clone(self._value - value) |
| |
| def __rsub__(self, value): |
| return self.clone(value - self._value) |
| |
| def __mul__(self, value): |
| return self.clone(self._value * value) |
| |
| def __rmul__(self, value): |
| return self.clone(value * self._value) |
| |
| def __mod__(self, value): |
| return self.clone(self._value % value) |
| |
| def __rmod__(self, value): |
| return self.clone(value % self._value) |
| |
| def __pow__(self, value, modulo=None): |
| return self.clone(pow(self._value, value, modulo)) |
| |
| def __rpow__(self, value): |
| return self.clone(pow(value, self._value)) |
| |
| def __floordiv__(self, value): |
| return self.clone(self._value // value) |
| |
| def __rfloordiv__(self, value): |
| return self.clone(value // self._value) |
| |
| if sys.version_info[0] <= 2: |
| def __div__(self, value): |
| if isinstance(value, float): |
| return Real(self._value / value) |
| else: |
| return self.clone(self._value / value) |
| |
| def __rdiv__(self, value): |
| if isinstance(value, float): |
| return Real(value / self._value) |
| else: |
| return self.clone(value / self._value) |
| else: |
| def __truediv__(self, value): |
| return Real(self._value / value) |
| |
| def __rtruediv__(self, value): |
| return Real(value / self._value) |
| |
| def __divmod__(self, value): |
| return self.clone(divmod(self._value, value)) |
| |
| def __rdivmod__(self, value): |
| return self.clone(divmod(value, self._value)) |
| |
| __hash__ = base.SimpleAsn1Type.__hash__ |
| |
| def __int__(self): |
| return int(self._value) |
| |
| if sys.version_info[0] <= 2: |
| def __long__(self): |
| return long(self._value) |
| |
| def __float__(self): |
| return float(self._value) |
| |
| def __abs__(self): |
| return self.clone(abs(self._value)) |
| |
| def __index__(self): |
| return int(self._value) |
| |
| def __pos__(self): |
| return self.clone(+self._value) |
| |
| def __neg__(self): |
| return self.clone(-self._value) |
| |
| def __invert__(self): |
| return self.clone(~self._value) |
| |
| def __round__(self, n=0): |
| r = round(self._value, n) |
| if n: |
| return self.clone(r) |
| else: |
| return r |
| |
| def __floor__(self): |
| return math.floor(self._value) |
| |
| def __ceil__(self): |
| return math.ceil(self._value) |
| |
| if sys.version_info[0:2] > (2, 5): |
| def __trunc__(self): |
| return self.clone(math.trunc(self._value)) |
| |
| def __lt__(self, value): |
| return self._value < value |
| |
| def __le__(self, value): |
| return self._value <= value |
| |
| def __eq__(self, value): |
| return self._value == value |
| |
| def __ne__(self, value): |
| return self._value != value |
| |
| def __gt__(self, value): |
| return self._value > value |
| |
| def __ge__(self, value): |
| return self._value >= value |
| |
| def prettyIn(self, value): |
| try: |
| return int(value) |
| |
| except ValueError: |
| try: |
| return self.namedValues[value] |
| |
| except KeyError: |
| raise error.PyAsn1Error( |
| 'Can\'t coerce %r into integer: %s' % (value, sys.exc_info()[1]) |
| ) |
| |
| def prettyOut(self, value): |
| try: |
| return str(self.namedValues[value]) |
| |
| except KeyError: |
| return str(value) |
| |
| # backward compatibility |
| |
| def getNamedValues(self): |
| return self.namedValues |
| |
| |
| class Boolean(Integer): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its |
| objects are immutable and duck-type Python :class:`int` objects. |
| |
| Keyword Args |
| ------------ |
| value: :class:`int`, :class:`str` or |ASN.1| object |
| Python :class:`int` or :class:`str` literal or |ASN.1| class |
| instance. If `value` is not given, schema object will be created. |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s).Constraints |
| verification for |ASN.1| type occurs automatically on object |
| instantiation. |
| |
| namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` |
| Object representing non-default symbolic aliases for numbers |
| |
| Raises |
| ------ |
| ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error |
| On constraint violation or bad initializer. |
| |
| Examples |
| -------- |
| .. code-block:: python |
| |
| class RoundResult(Boolean): |
| ''' |
| ASN.1 specification: |
| |
| RoundResult ::= BOOLEAN |
| |
| ok RoundResult ::= TRUE |
| ko RoundResult ::= FALSE |
| ''' |
| ok = RoundResult(True) |
| ko = RoundResult(False) |
| """ |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x01), |
| ) |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = Integer.subtypeSpec + constraint.SingleValueConstraint(0, 1) |
| |
| #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object |
| #: representing symbolic aliases for numbers |
| namedValues = namedval.NamedValues(('False', 0), ('True', 1)) |
| |
| # Optimization for faster codec lookup |
| typeId = Integer.getTypeId() |
| |
| if sys.version_info[0] < 3: |
| SizedIntegerBase = long |
| else: |
| SizedIntegerBase = int |
| |
| |
| class SizedInteger(SizedIntegerBase): |
| bitLength = leadingZeroBits = None |
| |
| def setBitLength(self, bitLength): |
| self.bitLength = bitLength |
| self.leadingZeroBits = max(bitLength - integer.bitLength(self), 0) |
| return self |
| |
| def __len__(self): |
| if self.bitLength is None: |
| self.setBitLength(integer.bitLength(self)) |
| |
| return self.bitLength |
| |
| |
| class BitString(base.SimpleAsn1Type): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its |
| objects are immutable and duck-type both Python :class:`tuple` (as a tuple |
| of bits) and :class:`int` objects. |
| |
| Keyword Args |
| ------------ |
| value: :class:`int`, :class:`str` or |ASN.1| object |
| Python :class:`int` or :class:`str` literal representing binary |
| or hexadecimal number or sequence of integer bits or |ASN.1| object. |
| If `value` is not given, schema object will be created. |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s). Constraints |
| verification for |ASN.1| type occurs automatically on object |
| instantiation. |
| |
| namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` |
| Object representing non-default symbolic aliases for numbers |
| |
| binValue: :py:class:`str` |
| Binary string initializer to use instead of the *value*. |
| Example: '10110011'. |
| |
| hexValue: :py:class:`str` |
| Hexadecimal string initializer to use instead of the *value*. |
| Example: 'DEADBEEF'. |
| |
| Raises |
| ------ |
| ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error |
| On constraint violation or bad initializer. |
| |
| Examples |
| -------- |
| .. code-block:: python |
| |
| class Rights(BitString): |
| ''' |
| ASN.1 specification: |
| |
| Rights ::= BIT STRING { user-read(0), user-write(1), |
| group-read(2), group-write(3), |
| other-read(4), other-write(5) } |
| |
| group1 Rights ::= { group-read, group-write } |
| group2 Rights ::= '0011'B |
| group3 Rights ::= '3'H |
| ''' |
| namedValues = NamedValues( |
| ('user-read', 0), ('user-write', 1), |
| ('group-read', 2), ('group-write', 3), |
| ('other-read', 4), ('other-write', 5) |
| ) |
| |
| group1 = Rights(('group-read', 'group-write')) |
| group2 = Rights('0011') |
| group3 = Rights(0x3) |
| """ |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x03) |
| ) |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object |
| #: representing symbolic aliases for numbers |
| namedValues = namedval.NamedValues() |
| |
| # Optimization for faster codec lookup |
| typeId = base.SimpleAsn1Type.getTypeId() |
| |
| defaultBinValue = defaultHexValue = noValue |
| |
| def __init__(self, value=noValue, **kwargs): |
| if value is noValue: |
| if kwargs: |
| try: |
| value = self.fromBinaryString(kwargs.pop('binValue'), internalFormat=True) |
| |
| except KeyError: |
| pass |
| |
| try: |
| value = self.fromHexString(kwargs.pop('hexValue'), internalFormat=True) |
| |
| except KeyError: |
| pass |
| |
| if value is noValue: |
| if self.defaultBinValue is not noValue: |
| value = self.fromBinaryString(self.defaultBinValue, internalFormat=True) |
| |
| elif self.defaultHexValue is not noValue: |
| value = self.fromHexString(self.defaultHexValue, internalFormat=True) |
| |
| if 'namedValues' not in kwargs: |
| kwargs['namedValues'] = self.namedValues |
| |
| base.SimpleAsn1Type.__init__(self, value, **kwargs) |
| |
| def __str__(self): |
| return self.asBinary() |
| |
| def __eq__(self, other): |
| other = self.prettyIn(other) |
| return self is other or self._value == other and len(self._value) == len(other) |
| |
| def __ne__(self, other): |
| other = self.prettyIn(other) |
| return self._value != other or len(self._value) != len(other) |
| |
| def __lt__(self, other): |
| other = self.prettyIn(other) |
| return len(self._value) < len(other) or len(self._value) == len(other) and self._value < other |
| |
| def __le__(self, other): |
| other = self.prettyIn(other) |
| return len(self._value) <= len(other) or len(self._value) == len(other) and self._value <= other |
| |
| def __gt__(self, other): |
| other = self.prettyIn(other) |
| return len(self._value) > len(other) or len(self._value) == len(other) and self._value > other |
| |
| def __ge__(self, other): |
| other = self.prettyIn(other) |
| return len(self._value) >= len(other) or len(self._value) == len(other) and self._value >= other |
| |
| # Immutable sequence object protocol |
| |
| def __len__(self): |
| return len(self._value) |
| |
| def __getitem__(self, i): |
| if i.__class__ is slice: |
| return self.clone([self[x] for x in range(*i.indices(len(self)))]) |
| else: |
| length = len(self._value) - 1 |
| if i > length or i < 0: |
| raise IndexError('bit index out of range') |
| return (self._value >> (length - i)) & 1 |
| |
| def __iter__(self): |
| length = len(self._value) |
| while length: |
| length -= 1 |
| yield (self._value >> length) & 1 |
| |
| def __reversed__(self): |
| return reversed(tuple(self)) |
| |
| # arithmetic operators |
| |
| def __add__(self, value): |
| value = self.prettyIn(value) |
| return self.clone(SizedInteger(self._value << len(value) | value).setBitLength(len(self._value) + len(value))) |
| |
| def __radd__(self, value): |
| value = self.prettyIn(value) |
| return self.clone(SizedInteger(value << len(self._value) | self._value).setBitLength(len(self._value) + len(value))) |
| |
| def __mul__(self, value): |
| bitString = self._value |
| while value > 1: |
| bitString <<= len(self._value) |
| bitString |= self._value |
| value -= 1 |
| return self.clone(bitString) |
| |
| def __rmul__(self, value): |
| return self * value |
| |
| def __lshift__(self, count): |
| return self.clone(SizedInteger(self._value << count).setBitLength(len(self._value) + count)) |
| |
| def __rshift__(self, count): |
| return self.clone(SizedInteger(self._value >> count).setBitLength(max(0, len(self._value) - count))) |
| |
| def __int__(self): |
| return self._value |
| |
| def __float__(self): |
| return float(self._value) |
| |
| if sys.version_info[0] < 3: |
| def __long__(self): |
| return self._value |
| |
| def asNumbers(self): |
| """Get |ASN.1| value as a sequence of 8-bit integers. |
| |
| If |ASN.1| object length is not a multiple of 8, result |
| will be left-padded with zeros. |
| """ |
| return tuple(octets.octs2ints(self.asOctets())) |
| |
| def asOctets(self): |
| """Get |ASN.1| value as a sequence of octets. |
| |
| If |ASN.1| object length is not a multiple of 8, result |
| will be left-padded with zeros. |
| """ |
| return integer.to_bytes(self._value, length=len(self)) |
| |
| def asInteger(self): |
| """Get |ASN.1| value as a single integer value. |
| """ |
| return self._value |
| |
| def asBinary(self): |
| """Get |ASN.1| value as a text string of bits. |
| """ |
| binString = binary.bin(self._value)[2:] |
| return '0' * (len(self._value) - len(binString)) + binString |
| |
| @classmethod |
| def fromHexString(cls, value, internalFormat=False, prepend=None): |
| """Create a |ASN.1| object initialized from the hex string. |
| |
| Parameters |
| ---------- |
| value: :class:`str` |
| Text string like 'DEADBEEF' |
| """ |
| try: |
| value = SizedInteger(value, 16).setBitLength(len(value) * 4) |
| |
| except ValueError: |
| raise error.PyAsn1Error('%s.fromHexString() error: %s' % (cls.__name__, sys.exc_info()[1])) |
| |
| if prepend is not None: |
| value = SizedInteger( |
| (SizedInteger(prepend) << len(value)) | value |
| ).setBitLength(len(prepend) + len(value)) |
| |
| if not internalFormat: |
| value = cls(value) |
| |
| return value |
| |
| @classmethod |
| def fromBinaryString(cls, value, internalFormat=False, prepend=None): |
| """Create a |ASN.1| object initialized from a string of '0' and '1'. |
| |
| Parameters |
| ---------- |
| value: :class:`str` |
| Text string like '1010111' |
| """ |
| try: |
| value = SizedInteger(value or '0', 2).setBitLength(len(value)) |
| |
| except ValueError: |
| raise error.PyAsn1Error('%s.fromBinaryString() error: %s' % (cls.__name__, sys.exc_info()[1])) |
| |
| if prepend is not None: |
| value = SizedInteger( |
| (SizedInteger(prepend) << len(value)) | value |
| ).setBitLength(len(prepend) + len(value)) |
| |
| if not internalFormat: |
| value = cls(value) |
| |
| return value |
| |
| @classmethod |
| def fromOctetString(cls, value, internalFormat=False, prepend=None, padding=0): |
| """Create a |ASN.1| object initialized from a string. |
| |
| Parameters |
| ---------- |
| value: :class:`str` (Py2) or :class:`bytes` (Py3) |
| Text string like '\\\\x01\\\\xff' (Py2) or b'\\\\x01\\\\xff' (Py3) |
| """ |
| value = SizedInteger(integer.from_bytes(value) >> padding).setBitLength(len(value) * 8 - padding) |
| |
| if prepend is not None: |
| value = SizedInteger( |
| (SizedInteger(prepend) << len(value)) | value |
| ).setBitLength(len(prepend) + len(value)) |
| |
| if not internalFormat: |
| value = cls(value) |
| |
| return value |
| |
| def prettyIn(self, value): |
| if isinstance(value, SizedInteger): |
| return value |
| elif octets.isStringType(value): |
| if not value: |
| return SizedInteger(0).setBitLength(0) |
| |
| elif value[0] == '\'': # "'1011'B" -- ASN.1 schema representation (deprecated) |
| if value[-2:] == '\'B': |
| return self.fromBinaryString(value[1:-2], internalFormat=True) |
| elif value[-2:] == '\'H': |
| return self.fromHexString(value[1:-2], internalFormat=True) |
| else: |
| raise error.PyAsn1Error( |
| 'Bad BIT STRING value notation %s' % (value,) |
| ) |
| |
| elif self.namedValues and not value.isdigit(): # named bits like 'Urgent, Active' |
| names = [x.strip() for x in value.split(',')] |
| |
| try: |
| |
| bitPositions = [self.namedValues[name] for name in names] |
| |
| except KeyError: |
| raise error.PyAsn1Error('unknown bit name(s) in %r' % (names,)) |
| |
| rightmostPosition = max(bitPositions) |
| |
| number = 0 |
| for bitPosition in bitPositions: |
| number |= 1 << (rightmostPosition - bitPosition) |
| |
| return SizedInteger(number).setBitLength(rightmostPosition + 1) |
| |
| elif value.startswith('0x'): |
| return self.fromHexString(value[2:], internalFormat=True) |
| |
| elif value.startswith('0b'): |
| return self.fromBinaryString(value[2:], internalFormat=True) |
| |
| else: # assume plain binary string like '1011' |
| return self.fromBinaryString(value, internalFormat=True) |
| |
| elif isinstance(value, (tuple, list)): |
| return self.fromBinaryString(''.join([b and '1' or '0' for b in value]), internalFormat=True) |
| |
| elif isinstance(value, BitString): |
| return SizedInteger(value).setBitLength(len(value)) |
| |
| elif isinstance(value, intTypes): |
| return SizedInteger(value) |
| |
| else: |
| raise error.PyAsn1Error( |
| 'Bad BitString initializer type \'%s\'' % (value,) |
| ) |
| |
| |
| try: |
| # noinspection PyStatementEffect |
| all |
| |
| except NameError: # Python 2.4 |
| # noinspection PyShadowingBuiltins |
| def all(iterable): |
| for element in iterable: |
| if not element: |
| return False |
| return True |
| |
| |
| class OctetString(base.SimpleAsn1Type): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its |
| objects are immutable and duck-type Python 2 :class:`str` or |
| Python 3 :class:`bytes`. When used in Unicode context, |ASN.1| type |
| assumes "|encoding|" serialisation. |
| |
| Keyword Args |
| ------------ |
| value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object |
| class:`str` (Python 2) or :class:`bytes` (Python 3), alternatively |
| class:`unicode` object (Python 2) or :class:`str` (Python 3) |
| representing character string to be serialised into octets |
| (note `encoding` parameter) or |ASN.1| object. |
| If `value` is not given, schema object will be created. |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s). Constraints |
| verification for |ASN.1| type occurs automatically on object |
| instantiation. |
| |
| encoding: :py:class:`str` |
| Unicode codec ID to encode/decode :class:`unicode` (Python 2) or |
| :class:`str` (Python 3) the payload when |ASN.1| object is used |
| in text string context. |
| |
| binValue: :py:class:`str` |
| Binary string initializer to use instead of the *value*. |
| Example: '10110011'. |
| |
| hexValue: :py:class:`str` |
| Hexadecimal string initializer to use instead of the *value*. |
| Example: 'DEADBEEF'. |
| |
| Raises |
| ------ |
| ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error |
| On constraint violation or bad initializer. |
| |
| Examples |
| -------- |
| .. code-block:: python |
| |
| class Icon(OctetString): |
| ''' |
| ASN.1 specification: |
| |
| Icon ::= OCTET STRING |
| |
| icon1 Icon ::= '001100010011001000110011'B |
| icon2 Icon ::= '313233'H |
| ''' |
| icon1 = Icon.fromBinaryString('001100010011001000110011') |
| icon2 = Icon.fromHexString('313233') |
| """ |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x04) |
| ) |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| # Optimization for faster codec lookup |
| typeId = base.SimpleAsn1Type.getTypeId() |
| |
| defaultBinValue = defaultHexValue = noValue |
| encoding = 'iso-8859-1' |
| |
| def __init__(self, value=noValue, **kwargs): |
| if kwargs: |
| if value is noValue: |
| try: |
| value = self.fromBinaryString(kwargs.pop('binValue')) |
| |
| except KeyError: |
| pass |
| |
| try: |
| value = self.fromHexString(kwargs.pop('hexValue')) |
| |
| except KeyError: |
| pass |
| |
| if value is noValue: |
| if self.defaultBinValue is not noValue: |
| value = self.fromBinaryString(self.defaultBinValue) |
| |
| elif self.defaultHexValue is not noValue: |
| value = self.fromHexString(self.defaultHexValue) |
| |
| if 'encoding' not in kwargs: |
| kwargs['encoding'] = self.encoding |
| |
| base.SimpleAsn1Type.__init__(self, value, **kwargs) |
| |
| if sys.version_info[0] <= 2: |
| def prettyIn(self, value): |
| if isinstance(value, str): |
| return value |
| |
| elif isinstance(value, unicode): |
| try: |
| return value.encode(self.encoding) |
| |
| except (LookupError, UnicodeEncodeError): |
| exc = sys.exc_info()[1] |
| raise error.PyAsn1UnicodeEncodeError( |
| "Can't encode string '%s' with codec " |
| "%s" % (value, self.encoding), exc |
| ) |
| |
| elif isinstance(value, (tuple, list)): |
| try: |
| return ''.join([chr(x) for x in value]) |
| |
| except ValueError: |
| raise error.PyAsn1Error( |
| "Bad %s initializer '%s'" % (self.__class__.__name__, value) |
| ) |
| |
| else: |
| return str(value) |
| |
| def __str__(self): |
| return str(self._value) |
| |
| def __unicode__(self): |
| try: |
| return self._value.decode(self.encoding) |
| |
| except UnicodeDecodeError: |
| exc = sys.exc_info()[1] |
| raise error.PyAsn1UnicodeDecodeError( |
| "Can't decode string '%s' with codec " |
| "%s" % (self._value, self.encoding), exc |
| ) |
| |
| def asOctets(self): |
| return str(self._value) |
| |
| def asNumbers(self): |
| return tuple([ord(x) for x in self._value]) |
| |
| else: |
| def prettyIn(self, value): |
| if isinstance(value, bytes): |
| return value |
| |
| elif isinstance(value, str): |
| try: |
| return value.encode(self.encoding) |
| |
| except UnicodeEncodeError: |
| exc = sys.exc_info()[1] |
| raise error.PyAsn1UnicodeEncodeError( |
| "Can't encode string '%s' with '%s' " |
| "codec" % (value, self.encoding), exc |
| ) |
| elif isinstance(value, OctetString): # a shortcut, bytes() would work the same way |
| return value.asOctets() |
| |
| elif isinstance(value, base.SimpleAsn1Type): # this mostly targets Integer objects |
| return self.prettyIn(str(value)) |
| |
| elif isinstance(value, (tuple, list)): |
| return self.prettyIn(bytes(value)) |
| |
| else: |
| return bytes(value) |
| |
| def __str__(self): |
| try: |
| return self._value.decode(self.encoding) |
| |
| except UnicodeDecodeError: |
| exc = sys.exc_info()[1] |
| raise error.PyAsn1UnicodeDecodeError( |
| "Can't decode string '%s' with '%s' codec at " |
| "'%s'" % (self._value, self.encoding, |
| self.__class__.__name__), exc |
| ) |
| |
| def __bytes__(self): |
| return bytes(self._value) |
| |
| def asOctets(self): |
| return bytes(self._value) |
| |
| def asNumbers(self): |
| return tuple(self._value) |
| |
| # |
| # Normally, `.prettyPrint()` is called from `__str__()`. Historically, |
| # OctetString.prettyPrint() used to return hexified payload |
| # representation in cases when non-printable content is present. At the |
| # same time `str()` used to produce either octet-stream (Py2) or |
| # text (Py3) representations. |
| # |
| # Therefore `OctetString.__str__()` -> `.prettyPrint()` call chain is |
| # reversed to preserve the original behaviour. |
| # |
| # Eventually we should deprecate `.prettyPrint()` / `.prettyOut()` harness |
| # and end up with just `__str__()` producing hexified representation while |
| # both text and octet-stream representation should only be requested via |
| # the `.asOctets()` method. |
| # |
| # Note: ASN.1 OCTET STRING is never mean to contain text! |
| # |
| |
| def prettyOut(self, value): |
| return value |
| |
| def prettyPrint(self, scope=0): |
| # first see if subclass has its own .prettyOut() |
| value = self.prettyOut(self._value) |
| |
| if value is not self._value: |
| return value |
| |
| numbers = self.asNumbers() |
| |
| for x in numbers: |
| # hexify if needed |
| if x < 32 or x > 126: |
| return '0x' + ''.join(('%.2x' % x for x in numbers)) |
| else: |
| # this prevents infinite recursion |
| return OctetString.__str__(self) |
| |
| @staticmethod |
| def fromBinaryString(value): |
| """Create a |ASN.1| object initialized from a string of '0' and '1'. |
| |
| Parameters |
| ---------- |
| value: :class:`str` |
| Text string like '1010111' |
| """ |
| bitNo = 8 |
| byte = 0 |
| r = [] |
| for v in value: |
| if bitNo: |
| bitNo -= 1 |
| else: |
| bitNo = 7 |
| r.append(byte) |
| byte = 0 |
| if v in ('0', '1'): |
| v = int(v) |
| else: |
| raise error.PyAsn1Error( |
| 'Non-binary OCTET STRING initializer %s' % (v,) |
| ) |
| byte |= v << bitNo |
| |
| r.append(byte) |
| |
| return octets.ints2octs(r) |
| |
| @staticmethod |
| def fromHexString(value): |
| """Create a |ASN.1| object initialized from the hex string. |
| |
| Parameters |
| ---------- |
| value: :class:`str` |
| Text string like 'DEADBEEF' |
| """ |
| r = [] |
| p = [] |
| for v in value: |
| if p: |
| r.append(int(p + v, 16)) |
| p = None |
| else: |
| p = v |
| if p: |
| r.append(int(p + '0', 16)) |
| |
| return octets.ints2octs(r) |
| |
| # Immutable sequence object protocol |
| |
| def __len__(self): |
| return len(self._value) |
| |
| def __getitem__(self, i): |
| if i.__class__ is slice: |
| return self.clone(self._value[i]) |
| else: |
| return self._value[i] |
| |
| def __iter__(self): |
| return iter(self._value) |
| |
| def __contains__(self, value): |
| return value in self._value |
| |
| def __add__(self, value): |
| return self.clone(self._value + self.prettyIn(value)) |
| |
| def __radd__(self, value): |
| return self.clone(self.prettyIn(value) + self._value) |
| |
| def __mul__(self, value): |
| return self.clone(self._value * value) |
| |
| def __rmul__(self, value): |
| return self * value |
| |
| def __int__(self): |
| return int(self._value) |
| |
| def __float__(self): |
| return float(self._value) |
| |
| def __reversed__(self): |
| return reversed(self._value) |
| |
| |
| class Null(OctetString): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its |
| objects are immutable and duck-type Python :class:`str` objects |
| (always empty). |
| |
| Keyword Args |
| ------------ |
| value: :class:`str` or |ASN.1| object |
| Python empty :class:`str` literal or any object that evaluates to :obj:`False` |
| If `value` is not given, schema object will be created. |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| Raises |
| ------ |
| ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error |
| On constraint violation or bad initializer. |
| |
| Examples |
| -------- |
| .. code-block:: python |
| |
| class Ack(Null): |
| ''' |
| ASN.1 specification: |
| |
| Ack ::= NULL |
| ''' |
| ack = Ack('') |
| """ |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05) |
| ) |
| subtypeSpec = OctetString.subtypeSpec + constraint.SingleValueConstraint(octets.str2octs('')) |
| |
| # Optimization for faster codec lookup |
| typeId = OctetString.getTypeId() |
| |
| def prettyIn(self, value): |
| if value: |
| return value |
| |
| return octets.str2octs('') |
| |
| if sys.version_info[0] <= 2: |
| intTypes = (int, long) |
| else: |
| intTypes = (int,) |
| |
| numericTypes = intTypes + (float,) |
| |
| |
| class ObjectIdentifier(base.SimpleAsn1Type): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its |
| objects are immutable and duck-type Python :class:`tuple` objects |
| (tuple of non-negative integers). |
| |
| Keyword Args |
| ------------ |
| value: :class:`tuple`, :class:`str` or |ASN.1| object |
| Python sequence of :class:`int` or :class:`str` literal or |ASN.1| object. |
| If `value` is not given, schema object will be created. |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s). Constraints |
| verification for |ASN.1| type occurs automatically on object |
| instantiation. |
| |
| Raises |
| ------ |
| ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error |
| On constraint violation or bad initializer. |
| |
| Examples |
| -------- |
| .. code-block:: python |
| |
| class ID(ObjectIdentifier): |
| ''' |
| ASN.1 specification: |
| |
| ID ::= OBJECT IDENTIFIER |
| |
| id-edims ID ::= { joint-iso-itu-t mhs-motif(6) edims(7) } |
| id-bp ID ::= { id-edims 11 } |
| ''' |
| id_edims = ID('2.6.7') |
| id_bp = id_edims + (11,) |
| """ |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x06) |
| ) |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| # Optimization for faster codec lookup |
| typeId = base.SimpleAsn1Type.getTypeId() |
| |
| def __add__(self, other): |
| return self.clone(self._value + other) |
| |
| def __radd__(self, other): |
| return self.clone(other + self._value) |
| |
| def asTuple(self): |
| return self._value |
| |
| # Sequence object protocol |
| |
| def __len__(self): |
| return len(self._value) |
| |
| def __getitem__(self, i): |
| if i.__class__ is slice: |
| return self.clone(self._value[i]) |
| else: |
| return self._value[i] |
| |
| def __iter__(self): |
| return iter(self._value) |
| |
| def __contains__(self, value): |
| return value in self._value |
| |
| def index(self, suboid): |
| return self._value.index(suboid) |
| |
| def isPrefixOf(self, other): |
| """Indicate if this |ASN.1| object is a prefix of other |ASN.1| object. |
| |
| Parameters |
| ---------- |
| other: |ASN.1| object |
| |ASN.1| object |
| |
| Returns |
| ------- |
| : :class:`bool` |
| :obj:`True` if this |ASN.1| object is a parent (e.g. prefix) of the other |ASN.1| object |
| or :obj:`False` otherwise. |
| """ |
| l = len(self) |
| if l <= len(other): |
| if self._value[:l] == other[:l]: |
| return True |
| return False |
| |
| def prettyIn(self, value): |
| if isinstance(value, ObjectIdentifier): |
| return tuple(value) |
| elif octets.isStringType(value): |
| if '-' in value: |
| raise error.PyAsn1Error( |
| 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) |
| ) |
| try: |
| return tuple([int(subOid) for subOid in value.split('.') if subOid]) |
| except ValueError: |
| raise error.PyAsn1Error( |
| 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) |
| ) |
| |
| try: |
| tupleOfInts = tuple([int(subOid) for subOid in value if subOid >= 0]) |
| |
| except (ValueError, TypeError): |
| raise error.PyAsn1Error( |
| 'Malformed Object ID %s at %s: %s' % (value, self.__class__.__name__, sys.exc_info()[1]) |
| ) |
| |
| if len(tupleOfInts) == len(value): |
| return tupleOfInts |
| |
| raise error.PyAsn1Error('Malformed Object ID %s at %s' % (value, self.__class__.__name__)) |
| |
| def prettyOut(self, value): |
| return '.'.join([str(x) for x in value]) |
| |
| |
| class Real(base.SimpleAsn1Type): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its |
| objects are immutable and duck-type Python :class:`float` objects. |
| Additionally, |ASN.1| objects behave like a :class:`tuple` in which case its |
| elements are mantissa, base and exponent. |
| |
| Keyword Args |
| ------------ |
| value: :class:`tuple`, :class:`float` or |ASN.1| object |
| Python sequence of :class:`int` (representing mantissa, base and |
| exponent) or :class:`float` instance or |ASN.1| object. |
| If `value` is not given, schema object will be created. |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s). Constraints |
| verification for |ASN.1| type occurs automatically on object |
| instantiation. |
| |
| Raises |
| ------ |
| ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error |
| On constraint violation or bad initializer. |
| |
| Examples |
| -------- |
| .. code-block:: python |
| |
| class Pi(Real): |
| ''' |
| ASN.1 specification: |
| |
| Pi ::= REAL |
| |
| pi Pi ::= { mantissa 314159, base 10, exponent -5 } |
| |
| ''' |
| pi = Pi((314159, 10, -5)) |
| """ |
| binEncBase = None # binEncBase = 16 is recommended for large numbers |
| |
| try: |
| _plusInf = float('inf') |
| _minusInf = float('-inf') |
| _inf = _plusInf, _minusInf |
| |
| except ValueError: |
| # Infinity support is platform and Python dependent |
| _plusInf = _minusInf = None |
| _inf = () |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x09) |
| ) |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| # Optimization for faster codec lookup |
| typeId = base.SimpleAsn1Type.getTypeId() |
| |
| @staticmethod |
| def __normalizeBase10(value): |
| m, b, e = value |
| while m and m % 10 == 0: |
| m /= 10 |
| e += 1 |
| return m, b, e |
| |
| def prettyIn(self, value): |
| if isinstance(value, tuple) and len(value) == 3: |
| if (not isinstance(value[0], numericTypes) or |
| not isinstance(value[1], intTypes) or |
| not isinstance(value[2], intTypes)): |
| raise error.PyAsn1Error('Lame Real value syntax: %s' % (value,)) |
| if (isinstance(value[0], float) and |
| self._inf and value[0] in self._inf): |
| return value[0] |
| if value[1] not in (2, 10): |
| raise error.PyAsn1Error( |
| 'Prohibited base for Real value: %s' % (value[1],) |
| ) |
| if value[1] == 10: |
| value = self.__normalizeBase10(value) |
| return value |
| elif isinstance(value, intTypes): |
| return self.__normalizeBase10((value, 10, 0)) |
| elif isinstance(value, float) or octets.isStringType(value): |
| if octets.isStringType(value): |
| try: |
| value = float(value) |
| except ValueError: |
| raise error.PyAsn1Error( |
| 'Bad real value syntax: %s' % (value,) |
| ) |
| if self._inf and value in self._inf: |
| return value |
| else: |
| e = 0 |
| while int(value) != value: |
| value *= 10 |
| e -= 1 |
| return self.__normalizeBase10((int(value), 10, e)) |
| elif isinstance(value, Real): |
| return tuple(value) |
| raise error.PyAsn1Error( |
| 'Bad real value syntax: %s' % (value,) |
| ) |
| |
| def prettyPrint(self, scope=0): |
| try: |
| return self.prettyOut(float(self)) |
| |
| except OverflowError: |
| return '<overflow>' |
| |
| @property |
| def isPlusInf(self): |
| """Indicate PLUS-INFINITY object value |
| |
| Returns |
| ------- |
| : :class:`bool` |
| :obj:`True` if calling object represents plus infinity |
| or :obj:`False` otherwise. |
| |
| """ |
| return self._value == self._plusInf |
| |
| @property |
| def isMinusInf(self): |
| """Indicate MINUS-INFINITY object value |
| |
| Returns |
| ------- |
| : :class:`bool` |
| :obj:`True` if calling object represents minus infinity |
| or :obj:`False` otherwise. |
| """ |
| return self._value == self._minusInf |
| |
| @property |
| def isInf(self): |
| return self._value in self._inf |
| |
| def __add__(self, value): |
| return self.clone(float(self) + value) |
| |
| def __radd__(self, value): |
| return self + value |
| |
| def __mul__(self, value): |
| return self.clone(float(self) * value) |
| |
| def __rmul__(self, value): |
| return self * value |
| |
| def __sub__(self, value): |
| return self.clone(float(self) - value) |
| |
| def __rsub__(self, value): |
| return self.clone(value - float(self)) |
| |
| def __mod__(self, value): |
| return self.clone(float(self) % value) |
| |
| def __rmod__(self, value): |
| return self.clone(value % float(self)) |
| |
| def __pow__(self, value, modulo=None): |
| return self.clone(pow(float(self), value, modulo)) |
| |
| def __rpow__(self, value): |
| return self.clone(pow(value, float(self))) |
| |
| if sys.version_info[0] <= 2: |
| def __div__(self, value): |
| return self.clone(float(self) / value) |
| |
| def __rdiv__(self, value): |
| return self.clone(value / float(self)) |
| else: |
| def __truediv__(self, value): |
| return self.clone(float(self) / value) |
| |
| def __rtruediv__(self, value): |
| return self.clone(value / float(self)) |
| |
| def __divmod__(self, value): |
| return self.clone(float(self) // value) |
| |
| def __rdivmod__(self, value): |
| return self.clone(value // float(self)) |
| |
| def __int__(self): |
| return int(float(self)) |
| |
| if sys.version_info[0] <= 2: |
| def __long__(self): |
| return long(float(self)) |
| |
| def __float__(self): |
| if self._value in self._inf: |
| return self._value |
| else: |
| return float( |
| self._value[0] * pow(self._value[1], self._value[2]) |
| ) |
| |
| def __abs__(self): |
| return self.clone(abs(float(self))) |
| |
| def __pos__(self): |
| return self.clone(+float(self)) |
| |
| def __neg__(self): |
| return self.clone(-float(self)) |
| |
| def __round__(self, n=0): |
| r = round(float(self), n) |
| if n: |
| return self.clone(r) |
| else: |
| return r |
| |
| def __floor__(self): |
| return self.clone(math.floor(float(self))) |
| |
| def __ceil__(self): |
| return self.clone(math.ceil(float(self))) |
| |
| if sys.version_info[0:2] > (2, 5): |
| def __trunc__(self): |
| return self.clone(math.trunc(float(self))) |
| |
| def __lt__(self, value): |
| return float(self) < value |
| |
| def __le__(self, value): |
| return float(self) <= value |
| |
| def __eq__(self, value): |
| return float(self) == value |
| |
| def __ne__(self, value): |
| return float(self) != value |
| |
| def __gt__(self, value): |
| return float(self) > value |
| |
| def __ge__(self, value): |
| return float(self) >= value |
| |
| if sys.version_info[0] <= 2: |
| def __nonzero__(self): |
| return bool(float(self)) |
| else: |
| def __bool__(self): |
| return bool(float(self)) |
| |
| __hash__ = base.SimpleAsn1Type.__hash__ |
| |
| def __getitem__(self, idx): |
| if self._value in self._inf: |
| raise error.PyAsn1Error('Invalid infinite value operation') |
| else: |
| return self._value[idx] |
| |
| # compatibility stubs |
| |
| def isPlusInfinity(self): |
| return self.isPlusInf |
| |
| def isMinusInfinity(self): |
| return self.isMinusInf |
| |
| def isInfinity(self): |
| return self.isInf |
| |
| |
| class Enumerated(Integer): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, its |
| objects are immutable and duck-type Python :class:`int` objects. |
| |
| Keyword Args |
| ------------ |
| value: :class:`int`, :class:`str` or |ASN.1| object |
| Python :class:`int` or :class:`str` literal or |ASN.1| object. |
| If `value` is not given, schema object will be created. |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s). Constraints |
| verification for |ASN.1| type occurs automatically on object |
| instantiation. |
| |
| namedValues: :py:class:`~pyasn1.type.namedval.NamedValues` |
| Object representing non-default symbolic aliases for numbers |
| |
| Raises |
| ------ |
| ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error |
| On constraint violation or bad initializer. |
| |
| Examples |
| -------- |
| |
| .. code-block:: python |
| |
| class RadioButton(Enumerated): |
| ''' |
| ASN.1 specification: |
| |
| RadioButton ::= ENUMERATED { button1(0), button2(1), |
| button3(2) } |
| |
| selected-by-default RadioButton ::= button1 |
| ''' |
| namedValues = NamedValues( |
| ('button1', 0), ('button2', 1), |
| ('button3', 2) |
| ) |
| |
| selected_by_default = RadioButton('button1') |
| """ |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x0A) |
| ) |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| # Optimization for faster codec lookup |
| typeId = Integer.getTypeId() |
| |
| #: Default :py:class:`~pyasn1.type.namedval.NamedValues` object |
| #: representing symbolic aliases for numbers |
| namedValues = namedval.NamedValues() |
| |
| |
| # "Structured" ASN.1 types |
| |
| class SequenceOfAndSetOfBase(base.ConstructedAsn1Type): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`, |
| its objects are mutable and duck-type Python :class:`list` objects. |
| |
| Keyword Args |
| ------------ |
| componentType : :py:class:`~pyasn1.type.base.PyAsn1Item` derivative |
| A pyasn1 object representing ASN.1 type allowed within |ASN.1| type |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s). Constraints |
| verification for |ASN.1| type can only occur on explicit |
| `.isInconsistent` call. |
| |
| Examples |
| -------- |
| |
| .. code-block:: python |
| |
| class LotteryDraw(SequenceOf): # SetOf is similar |
| ''' |
| ASN.1 specification: |
| |
| LotteryDraw ::= SEQUENCE OF INTEGER |
| ''' |
| componentType = Integer() |
| |
| lotteryDraw = LotteryDraw() |
| lotteryDraw.extend([123, 456, 789]) |
| """ |
| def __init__(self, *args, **kwargs): |
| # support positional params for backward compatibility |
| if args: |
| for key, value in zip(('componentType', 'tagSet', |
| 'subtypeSpec'), args): |
| if key in kwargs: |
| raise error.PyAsn1Error('Conflicting positional and keyword params!') |
| kwargs['componentType'] = value |
| |
| self._componentValues = noValue |
| |
| base.ConstructedAsn1Type.__init__(self, **kwargs) |
| |
| # Python list protocol |
| |
| def __getitem__(self, idx): |
| try: |
| return self.getComponentByPosition(idx) |
| |
| except error.PyAsn1Error: |
| raise IndexError(sys.exc_info()[1]) |
| |
| def __setitem__(self, idx, value): |
| try: |
| self.setComponentByPosition(idx, value) |
| |
| except error.PyAsn1Error: |
| raise IndexError(sys.exc_info()[1]) |
| |
| def append(self, value): |
| if self._componentValues is noValue: |
| pos = 0 |
| |
| else: |
| pos = len(self._componentValues) |
| |
| self[pos] = value |
| |
| def count(self, value): |
| return list(self._componentValues.values()).count(value) |
| |
| def extend(self, values): |
| for value in values: |
| self.append(value) |
| |
| if self._componentValues is noValue: |
| self._componentValues = {} |
| |
| def index(self, value, start=0, stop=None): |
| if stop is None: |
| stop = len(self) |
| |
| indices, values = zip(*self._componentValues.items()) |
| |
| # TODO: remove when Py2.5 support is gone |
| values = list(values) |
| |
| try: |
| return indices[values.index(value, start, stop)] |
| |
| except error.PyAsn1Error: |
| raise ValueError(sys.exc_info()[1]) |
| |
| def reverse(self): |
| self._componentValues.reverse() |
| |
| def sort(self, key=None, reverse=False): |
| self._componentValues = dict( |
| enumerate(sorted(self._componentValues.values(), |
| key=key, reverse=reverse))) |
| |
| def __len__(self): |
| if self._componentValues is noValue or not self._componentValues: |
| return 0 |
| |
| return max(self._componentValues) + 1 |
| |
| def __iter__(self): |
| for idx in range(0, len(self)): |
| yield self.getComponentByPosition(idx) |
| |
| def _cloneComponentValues(self, myClone, cloneValueFlag): |
| for idx, componentValue in self._componentValues.items(): |
| if componentValue is not noValue: |
| if isinstance(componentValue, base.ConstructedAsn1Type): |
| myClone.setComponentByPosition( |
| idx, componentValue.clone(cloneValueFlag=cloneValueFlag) |
| ) |
| else: |
| myClone.setComponentByPosition(idx, componentValue.clone()) |
| |
| def getComponentByPosition(self, idx, default=noValue, instantiate=True): |
| """Return |ASN.1| type component value by position. |
| |
| Equivalent to Python sequence subscription operation (e.g. `[]`). |
| |
| Parameters |
| ---------- |
| idx : :class:`int` |
| Component index (zero-based). Must either refer to an existing |
| component or to N+1 component (if *componentType* is set). In the latter |
| case a new component type gets instantiated and appended to the |ASN.1| |
| sequence. |
| |
| Keyword Args |
| ------------ |
| default: :class:`object` |
| If set and requested component is a schema object, return the `default` |
| object instead of the requested component. |
| |
| instantiate: :class:`bool` |
| If :obj:`True` (default), inner component will be automatically instantiated. |
| If :obj:`False` either existing component or the :class:`NoValue` object will be |
| returned. |
| |
| Returns |
| ------- |
| : :py:class:`~pyasn1.type.base.PyAsn1Item` |
| Instantiate |ASN.1| component type or return existing component value |
| |
| Examples |
| -------- |
| |
| .. code-block:: python |
| |
| # can also be SetOf |
| class MySequenceOf(SequenceOf): |
| componentType = OctetString() |
| |
| s = MySequenceOf() |
| |
| # returns component #0 with `.isValue` property False |
| s.getComponentByPosition(0) |
| |
| # returns None |
| s.getComponentByPosition(0, default=None) |
| |
| s.clear() |
| |
| # returns noValue |
| s.getComponentByPosition(0, instantiate=False) |
| |
| # sets component #0 to OctetString() ASN.1 schema |
| # object and returns it |
| s.getComponentByPosition(0, instantiate=True) |
| |
| # sets component #0 to ASN.1 value object |
| s.setComponentByPosition(0, 'ABCD') |
| |
| # returns OctetString('ABCD') value object |
| s.getComponentByPosition(0, instantiate=False) |
| |
| s.clear() |
| |
| # returns noValue |
| s.getComponentByPosition(0, instantiate=False) |
| """ |
| if isinstance(idx, slice): |
| indices = tuple(range(len(self))) |
| return [self.getComponentByPosition(subidx, default, instantiate) |
| for subidx in indices[idx]] |
| |
| if idx < 0: |
| idx = len(self) + idx |
| if idx < 0: |
| raise error.PyAsn1Error( |
| 'SequenceOf/SetOf index is out of range') |
| |
| try: |
| componentValue = self._componentValues[idx] |
| |
| except (KeyError, error.PyAsn1Error): |
| if not instantiate: |
| return default |
| |
| self.setComponentByPosition(idx) |
| |
| componentValue = self._componentValues[idx] |
| |
| if default is noValue or componentValue.isValue: |
| return componentValue |
| else: |
| return default |
| |
| def setComponentByPosition(self, idx, value=noValue, |
| verifyConstraints=True, |
| matchTags=True, |
| matchConstraints=True): |
| """Assign |ASN.1| type component by position. |
| |
| Equivalent to Python sequence item assignment operation (e.g. `[]`) |
| or list.append() (when idx == len(self)). |
| |
| Parameters |
| ---------- |
| idx: :class:`int` |
| Component index (zero-based). Must either refer to existing |
| component or to N+1 component. In the latter case a new component |
| type gets instantiated (if *componentType* is set, or given ASN.1 |
| object is taken otherwise) and appended to the |ASN.1| sequence. |
| |
| Keyword Args |
| ------------ |
| value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative |
| A Python value to initialize |ASN.1| component with (if *componentType* is set) |
| or ASN.1 value object to assign to |ASN.1| component. |
| If `value` is not given, schema object will be set as a component. |
| |
| verifyConstraints: :class:`bool` |
| If :obj:`False`, skip constraints validation |
| |
| matchTags: :class:`bool` |
| If :obj:`False`, skip component tags matching |
| |
| matchConstraints: :class:`bool` |
| If :obj:`False`, skip component constraints matching |
| |
| Returns |
| ------- |
| self |
| |
| Raises |
| ------ |
| ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error |
| On constraint violation or bad initializer |
| IndexError |
| When idx > len(self) |
| """ |
| if isinstance(idx, slice): |
| indices = tuple(range(len(self))) |
| startIdx = indices and indices[idx][0] or 0 |
| for subIdx, subValue in enumerate(value): |
| self.setComponentByPosition( |
| startIdx + subIdx, subValue, verifyConstraints, |
| matchTags, matchConstraints) |
| return self |
| |
| if idx < 0: |
| idx = len(self) + idx |
| if idx < 0: |
| raise error.PyAsn1Error( |
| 'SequenceOf/SetOf index is out of range') |
| |
| componentType = self.componentType |
| |
| if self._componentValues is noValue: |
| componentValues = {} |
| |
| else: |
| componentValues = self._componentValues |
| |
| currentValue = componentValues.get(idx, noValue) |
| |
| if value is noValue: |
| if componentType is not None: |
| value = componentType.clone() |
| |
| elif currentValue is noValue: |
| raise error.PyAsn1Error('Component type not defined') |
| |
| elif not isinstance(value, base.Asn1Item): |
| if (componentType is not None and |
| isinstance(componentType, base.SimpleAsn1Type)): |
| value = componentType.clone(value=value) |
| |
| elif (currentValue is not noValue and |
| isinstance(currentValue, base.SimpleAsn1Type)): |
| value = currentValue.clone(value=value) |
| |
| else: |
| raise error.PyAsn1Error( |
| 'Non-ASN.1 value %r and undefined component' |
| ' type at %r' % (value, self)) |
| |
| elif componentType is not None and (matchTags or matchConstraints): |
| subtypeChecker = ( |
| self.strictConstraints and |
| componentType.isSameTypeWith or |
| componentType.isSuperTypeOf) |
| |
| if not subtypeChecker(value, verifyConstraints and matchTags, |
| verifyConstraints and matchConstraints): |
| # TODO: we should wrap componentType with UnnamedType to carry |
| # additional properties associated with componentType |
| if componentType.typeId != Any.typeId: |
| raise error.PyAsn1Error( |
| 'Component value is tag-incompatible: %r vs ' |
| '%r' % (value, componentType)) |
| |
| componentValues[idx] = value |
| |
| self._componentValues = componentValues |
| |
| return self |
| |
| @property |
| def componentTagMap(self): |
| if self.componentType is not None: |
| return self.componentType.tagMap |
| |
| @property |
| def components(self): |
| return [self._componentValues[idx] |
| for idx in sorted(self._componentValues)] |
| |
| def clear(self): |
| """Remove all components and become an empty |ASN.1| value object. |
| |
| Has the same effect on |ASN.1| object as it does on :class:`list` |
| built-in. |
| """ |
| self._componentValues = {} |
| return self |
| |
| def reset(self): |
| """Remove all components and become a |ASN.1| schema object. |
| |
| See :meth:`isValue` property for more information on the |
| distinction between value and schema objects. |
| """ |
| self._componentValues = noValue |
| return self |
| |
| def prettyPrint(self, scope=0): |
| scope += 1 |
| representation = self.__class__.__name__ + ':\n' |
| |
| if not self.isValue: |
| return representation |
| |
| for idx, componentValue in enumerate(self): |
| representation += ' ' * scope |
| if (componentValue is noValue and |
| self.componentType is not None): |
| representation += '<empty>' |
| else: |
| representation += componentValue.prettyPrint(scope) |
| |
| return representation |
| |
| def prettyPrintType(self, scope=0): |
| scope += 1 |
| representation = '%s -> %s {\n' % (self.tagSet, self.__class__.__name__) |
| if self.componentType is not None: |
| representation += ' ' * scope |
| representation += self.componentType.prettyPrintType(scope) |
| return representation + '\n' + ' ' * (scope - 1) + '}' |
| |
| |
| @property |
| def isValue(self): |
| """Indicate that |ASN.1| object represents ASN.1 value. |
| |
| If *isValue* is :obj:`False` then this object represents just ASN.1 schema. |
| |
| If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features, |
| this object can also be used like a Python built-in object |
| (e.g. :class:`int`, :class:`str`, :class:`dict` etc.). |
| |
| Returns |
| ------- |
| : :class:`bool` |
| :obj:`False` if object represents just ASN.1 schema. |
| :obj:`True` if object represents ASN.1 schema and can be used as a normal value. |
| |
| Note |
| ---- |
| There is an important distinction between PyASN1 schema and value objects. |
| The PyASN1 schema objects can only participate in ASN.1 schema-related |
| operations (e.g. defining or testing the structure of the data). Most |
| obvious uses of ASN.1 schema is to guide serialisation codecs whilst |
| encoding/decoding serialised ASN.1 contents. |
| |
| The PyASN1 value objects can **additionally** participate in many operations |
| involving regular Python objects (e.g. arithmetic, comprehension etc). |
| """ |
| if self._componentValues is noValue: |
| return False |
| |
| if len(self._componentValues) != len(self): |
| return False |
| |
| for componentValue in self._componentValues.values(): |
| if componentValue is noValue or not componentValue.isValue: |
| return False |
| |
| return True |
| |
| @property |
| def isInconsistent(self): |
| """Run necessary checks to ensure |ASN.1| object consistency. |
| |
| Default action is to verify |ASN.1| object against constraints imposed |
| by `subtypeSpec`. |
| |
| Raises |
| ------ |
| :py:class:`~pyasn1.error.PyAsn1tError` on any inconsistencies found |
| """ |
| if self.componentType is noValue or not self.subtypeSpec: |
| return False |
| |
| if self._componentValues is noValue: |
| return True |
| |
| mapping = {} |
| |
| for idx, value in self._componentValues.items(): |
| # Absent fields are not in the mapping |
| if value is noValue: |
| continue |
| |
| mapping[idx] = value |
| |
| try: |
| # Represent SequenceOf/SetOf as a bare dict to constraints chain |
| self.subtypeSpec(mapping) |
| |
| except error.PyAsn1Error: |
| exc = sys.exc_info()[1] |
| return exc |
| |
| return False |
| |
| class SequenceOf(SequenceOfAndSetOfBase): |
| __doc__ = SequenceOfAndSetOfBase.__doc__ |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) |
| ) |
| |
| #: Default :py:class:`~pyasn1.type.base.PyAsn1Item` derivative |
| #: object representing ASN.1 type allowed within |ASN.1| type |
| componentType = None |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| # Disambiguation ASN.1 types identification |
| typeId = SequenceOfAndSetOfBase.getTypeId() |
| |
| |
| class SetOf(SequenceOfAndSetOfBase): |
| __doc__ = SequenceOfAndSetOfBase.__doc__ |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) |
| ) |
| |
| #: Default :py:class:`~pyasn1.type.base.PyAsn1Item` derivative |
| #: object representing ASN.1 type allowed within |ASN.1| type |
| componentType = None |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| # Disambiguation ASN.1 types identification |
| typeId = SequenceOfAndSetOfBase.getTypeId() |
| |
| |
| class SequenceAndSetBase(base.ConstructedAsn1Type): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`, |
| its objects are mutable and duck-type Python :class:`dict` objects. |
| |
| Keyword Args |
| ------------ |
| componentType: :py:class:`~pyasn1.type.namedtype.NamedType` |
| Object holding named ASN.1 types allowed within this collection |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s). Constraints |
| verification for |ASN.1| type can only occur on explicit |
| `.isInconsistent` call. |
| |
| Examples |
| -------- |
| |
| .. code-block:: python |
| |
| class Description(Sequence): # Set is similar |
| ''' |
| ASN.1 specification: |
| |
| Description ::= SEQUENCE { |
| surname IA5String, |
| first-name IA5String OPTIONAL, |
| age INTEGER DEFAULT 40 |
| } |
| ''' |
| componentType = NamedTypes( |
| NamedType('surname', IA5String()), |
| OptionalNamedType('first-name', IA5String()), |
| DefaultedNamedType('age', Integer(40)) |
| ) |
| |
| descr = Description() |
| descr['surname'] = 'Smith' |
| descr['first-name'] = 'John' |
| """ |
| #: Default :py:class:`~pyasn1.type.namedtype.NamedTypes` |
| #: object representing named ASN.1 types allowed within |ASN.1| type |
| componentType = namedtype.NamedTypes() |
| |
| |
| class DynamicNames(object): |
| """Fields names/positions mapping for component-less objects""" |
| def __init__(self): |
| self._keyToIdxMap = {} |
| self._idxToKeyMap = {} |
| |
| def __len__(self): |
| return len(self._keyToIdxMap) |
| |
| def __contains__(self, item): |
| return item in self._keyToIdxMap or item in self._idxToKeyMap |
| |
| def __iter__(self): |
| return (self._idxToKeyMap[idx] for idx in range(len(self._idxToKeyMap))) |
| |
| def __getitem__(self, item): |
| try: |
| return self._keyToIdxMap[item] |
| |
| except KeyError: |
| return self._idxToKeyMap[item] |
| |
| def getNameByPosition(self, idx): |
| try: |
| return self._idxToKeyMap[idx] |
| |
| except KeyError: |
| raise error.PyAsn1Error('Type position out of range') |
| |
| def getPositionByName(self, name): |
| try: |
| return self._keyToIdxMap[name] |
| |
| except KeyError: |
| raise error.PyAsn1Error('Name %s not found' % (name,)) |
| |
| def addField(self, idx): |
| self._keyToIdxMap['field-%d' % idx] = idx |
| self._idxToKeyMap[idx] = 'field-%d' % idx |
| |
| |
| def __init__(self, **kwargs): |
| base.ConstructedAsn1Type.__init__(self, **kwargs) |
| self._componentTypeLen = len(self.componentType) |
| if self._componentTypeLen: |
| self._componentValues = [] |
| else: |
| self._componentValues = noValue |
| self._dynamicNames = self._componentTypeLen or self.DynamicNames() |
| |
| def __getitem__(self, idx): |
| if octets.isStringType(idx): |
| try: |
| return self.getComponentByName(idx) |
| |
| except error.PyAsn1Error: |
| # duck-typing dict |
| raise KeyError(sys.exc_info()[1]) |
| |
| else: |
| try: |
| return self.getComponentByPosition(idx) |
| |
| except error.PyAsn1Error: |
| # duck-typing list |
| raise IndexError(sys.exc_info()[1]) |
| |
| def __setitem__(self, idx, value): |
| if octets.isStringType(idx): |
| try: |
| self.setComponentByName(idx, value) |
| |
| except error.PyAsn1Error: |
| # duck-typing dict |
| raise KeyError(sys.exc_info()[1]) |
| |
| else: |
| try: |
| self.setComponentByPosition(idx, value) |
| |
| except error.PyAsn1Error: |
| # duck-typing list |
| raise IndexError(sys.exc_info()[1]) |
| |
| def __contains__(self, key): |
| if self._componentTypeLen: |
| return key in self.componentType |
| else: |
| return key in self._dynamicNames |
| |
| def __len__(self): |
| return len(self._componentValues) |
| |
| def __iter__(self): |
| return iter(self.componentType or self._dynamicNames) |
| |
| # Python dict protocol |
| |
| def values(self): |
| for idx in range(self._componentTypeLen or len(self._dynamicNames)): |
| yield self[idx] |
| |
| def keys(self): |
| return iter(self) |
| |
| def items(self): |
| for idx in range(self._componentTypeLen or len(self._dynamicNames)): |
| if self._componentTypeLen: |
| yield self.componentType[idx].name, self[idx] |
| else: |
| yield self._dynamicNames[idx], self[idx] |
| |
| def update(self, *iterValue, **mappingValue): |
| for k, v in iterValue: |
| self[k] = v |
| for k in mappingValue: |
| self[k] = mappingValue[k] |
| |
| def clear(self): |
| """Remove all components and become an empty |ASN.1| value object. |
| |
| Has the same effect on |ASN.1| object as it does on :class:`dict` |
| built-in. |
| """ |
| self._componentValues = [] |
| self._dynamicNames = self.DynamicNames() |
| return self |
| |
| def reset(self): |
| """Remove all components and become a |ASN.1| schema object. |
| |
| See :meth:`isValue` property for more information on the |
| distinction between value and schema objects. |
| """ |
| self._componentValues = noValue |
| self._dynamicNames = self.DynamicNames() |
| return self |
| |
| @property |
| def components(self): |
| return self._componentValues |
| |
| def _cloneComponentValues(self, myClone, cloneValueFlag): |
| if self._componentValues is noValue: |
| return |
| |
| for idx, componentValue in enumerate(self._componentValues): |
| if componentValue is not noValue: |
| if isinstance(componentValue, base.ConstructedAsn1Type): |
| myClone.setComponentByPosition( |
| idx, componentValue.clone(cloneValueFlag=cloneValueFlag) |
| ) |
| else: |
| myClone.setComponentByPosition(idx, componentValue.clone()) |
| |
| def getComponentByName(self, name, default=noValue, instantiate=True): |
| """Returns |ASN.1| type component by name. |
| |
| Equivalent to Python :class:`dict` subscription operation (e.g. `[]`). |
| |
| Parameters |
| ---------- |
| name: :class:`str` |
| |ASN.1| type component name |
| |
| Keyword Args |
| ------------ |
| default: :class:`object` |
| If set and requested component is a schema object, return the `default` |
| object instead of the requested component. |
| |
| instantiate: :class:`bool` |
| If :obj:`True` (default), inner component will be automatically |
| instantiated. |
| If :obj:`False` either existing component or the :class:`NoValue` |
| object will be returned. |
| |
| Returns |
| ------- |
| : :py:class:`~pyasn1.type.base.PyAsn1Item` |
| Instantiate |ASN.1| component type or return existing |
| component value |
| """ |
| if self._componentTypeLen: |
| idx = self.componentType.getPositionByName(name) |
| else: |
| try: |
| idx = self._dynamicNames.getPositionByName(name) |
| |
| except KeyError: |
| raise error.PyAsn1Error('Name %s not found' % (name,)) |
| |
| return self.getComponentByPosition(idx, default=default, instantiate=instantiate) |
| |
| def setComponentByName(self, name, value=noValue, |
| verifyConstraints=True, |
| matchTags=True, |
| matchConstraints=True): |
| """Assign |ASN.1| type component by name. |
| |
| Equivalent to Python :class:`dict` item assignment operation (e.g. `[]`). |
| |
| Parameters |
| ---------- |
| name: :class:`str` |
| |ASN.1| type component name |
| |
| Keyword Args |
| ------------ |
| value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative |
| A Python value to initialize |ASN.1| component with (if *componentType* is set) |
| or ASN.1 value object to assign to |ASN.1| component. |
| If `value` is not given, schema object will be set as a component. |
| |
| verifyConstraints: :class:`bool` |
| If :obj:`False`, skip constraints validation |
| |
| matchTags: :class:`bool` |
| If :obj:`False`, skip component tags matching |
| |
| matchConstraints: :class:`bool` |
| If :obj:`False`, skip component constraints matching |
| |
| Returns |
| ------- |
| self |
| """ |
| if self._componentTypeLen: |
| idx = self.componentType.getPositionByName(name) |
| else: |
| try: |
| idx = self._dynamicNames.getPositionByName(name) |
| |
| except KeyError: |
| raise error.PyAsn1Error('Name %s not found' % (name,)) |
| |
| return self.setComponentByPosition( |
| idx, value, verifyConstraints, matchTags, matchConstraints |
| ) |
| |
| def getComponentByPosition(self, idx, default=noValue, instantiate=True): |
| """Returns |ASN.1| type component by index. |
| |
| Equivalent to Python sequence subscription operation (e.g. `[]`). |
| |
| Parameters |
| ---------- |
| idx: :class:`int` |
| Component index (zero-based). Must either refer to an existing |
| component or (if *componentType* is set) new ASN.1 schema object gets |
| instantiated. |
| |
| Keyword Args |
| ------------ |
| default: :class:`object` |
| If set and requested component is a schema object, return the `default` |
| object instead of the requested component. |
| |
| instantiate: :class:`bool` |
| If :obj:`True` (default), inner component will be automatically |
| instantiated. |
| If :obj:`False` either existing component or the :class:`NoValue` |
| object will be returned. |
| |
| Returns |
| ------- |
| : :py:class:`~pyasn1.type.base.PyAsn1Item` |
| a PyASN1 object |
| |
| Examples |
| -------- |
| |
| .. code-block:: python |
| |
| # can also be Set |
| class MySequence(Sequence): |
| componentType = NamedTypes( |
| NamedType('id', OctetString()) |
| ) |
| |
| s = MySequence() |
| |
| # returns component #0 with `.isValue` property False |
| s.getComponentByPosition(0) |
| |
| # returns None |
| s.getComponentByPosition(0, default=None) |
| |
| s.clear() |
| |
| # returns noValue |
| s.getComponentByPosition(0, instantiate=False) |
| |
| # sets component #0 to OctetString() ASN.1 schema |
| # object and returns it |
| s.getComponentByPosition(0, instantiate=True) |
| |
| # sets component #0 to ASN.1 value object |
| s.setComponentByPosition(0, 'ABCD') |
| |
| # returns OctetString('ABCD') value object |
| s.getComponentByPosition(0, instantiate=False) |
| |
| s.clear() |
| |
| # returns noValue |
| s.getComponentByPosition(0, instantiate=False) |
| """ |
| try: |
| if self._componentValues is noValue: |
| componentValue = noValue |
| |
| else: |
| componentValue = self._componentValues[idx] |
| |
| except IndexError: |
| componentValue = noValue |
| |
| if not instantiate: |
| if componentValue is noValue or not componentValue.isValue: |
| return default |
| else: |
| return componentValue |
| |
| if componentValue is noValue: |
| self.setComponentByPosition(idx) |
| |
| componentValue = self._componentValues[idx] |
| |
| if default is noValue or componentValue.isValue: |
| return componentValue |
| else: |
| return default |
| |
| def setComponentByPosition(self, idx, value=noValue, |
| verifyConstraints=True, |
| matchTags=True, |
| matchConstraints=True): |
| """Assign |ASN.1| type component by position. |
| |
| Equivalent to Python sequence item assignment operation (e.g. `[]`). |
| |
| Parameters |
| ---------- |
| idx : :class:`int` |
| Component index (zero-based). Must either refer to existing |
| component (if *componentType* is set) or to N+1 component |
| otherwise. In the latter case a new component of given ASN.1 |
| type gets instantiated and appended to |ASN.1| sequence. |
| |
| Keyword Args |
| ------------ |
| value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative |
| A Python value to initialize |ASN.1| component with (if *componentType* is set) |
| or ASN.1 value object to assign to |ASN.1| component. |
| If `value` is not given, schema object will be set as a component. |
| |
| verifyConstraints : :class:`bool` |
| If :obj:`False`, skip constraints validation |
| |
| matchTags: :class:`bool` |
| If :obj:`False`, skip component tags matching |
| |
| matchConstraints: :class:`bool` |
| If :obj:`False`, skip component constraints matching |
| |
| Returns |
| ------- |
| self |
| """ |
| componentType = self.componentType |
| componentTypeLen = self._componentTypeLen |
| |
| if self._componentValues is noValue: |
| componentValues = [] |
| |
| else: |
| componentValues = self._componentValues |
| |
| try: |
| currentValue = componentValues[idx] |
| |
| except IndexError: |
| currentValue = noValue |
| if componentTypeLen: |
| if componentTypeLen < idx: |
| raise error.PyAsn1Error('component index out of range') |
| |
| componentValues = [noValue] * componentTypeLen |
| |
| if value is noValue: |
| if componentTypeLen: |
| value = componentType.getTypeByPosition(idx) |
| if isinstance(value, base.ConstructedAsn1Type): |
| value = value.clone(cloneValueFlag=componentType[idx].isDefaulted) |
| |
| elif currentValue is noValue: |
| raise error.PyAsn1Error('Component type not defined') |
| |
| elif not isinstance(value, base.Asn1Item): |
| if componentTypeLen: |
| subComponentType = componentType.getTypeByPosition(idx) |
| if isinstance(subComponentType, base.SimpleAsn1Type): |
| value = subComponentType.clone(value=value) |
| |
| else: |
| raise error.PyAsn1Error('%s can cast only scalar values' % componentType.__class__.__name__) |
| |
| elif currentValue is not noValue and isinstance(currentValue, base.SimpleAsn1Type): |
| value = currentValue.clone(value=value) |
| |
| else: |
| raise error.PyAsn1Error('%s undefined component type' % componentType.__class__.__name__) |
| |
| elif ((verifyConstraints or matchTags or matchConstraints) and |
| componentTypeLen): |
| subComponentType = componentType.getTypeByPosition(idx) |
| if subComponentType is not noValue: |
| subtypeChecker = (self.strictConstraints and |
| subComponentType.isSameTypeWith or |
| subComponentType.isSuperTypeOf) |
| |
| if not subtypeChecker(value, verifyConstraints and matchTags, |
| verifyConstraints and matchConstraints): |
| if not componentType[idx].openType: |
| raise error.PyAsn1Error('Component value is tag-incompatible: %r vs %r' % (value, componentType)) |
| |
| if componentTypeLen or idx in self._dynamicNames: |
| componentValues[idx] = value |
| |
| elif len(componentValues) == idx: |
| componentValues.append(value) |
| self._dynamicNames.addField(idx) |
| |
| else: |
| raise error.PyAsn1Error('Component index out of range') |
| |
| self._componentValues = componentValues |
| |
| return self |
| |
| @property |
| def isValue(self): |
| """Indicate that |ASN.1| object represents ASN.1 value. |
| |
| If *isValue* is :obj:`False` then this object represents just ASN.1 schema. |
| |
| If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features, |
| this object can also be used like a Python built-in object (e.g. |
| :class:`int`, :class:`str`, :class:`dict` etc.). |
| |
| Returns |
| ------- |
| : :class:`bool` |
| :obj:`False` if object represents just ASN.1 schema. |
| :obj:`True` if object represents ASN.1 schema and can be used as a |
| normal value. |
| |
| Note |
| ---- |
| There is an important distinction between PyASN1 schema and value objects. |
| The PyASN1 schema objects can only participate in ASN.1 schema-related |
| operations (e.g. defining or testing the structure of the data). Most |
| obvious uses of ASN.1 schema is to guide serialisation codecs whilst |
| encoding/decoding serialised ASN.1 contents. |
| |
| The PyASN1 value objects can **additionally** participate in many operations |
| involving regular Python objects (e.g. arithmetic, comprehension etc). |
| |
| It is sufficient for |ASN.1| objects to have all non-optional and non-defaulted |
| components being value objects to be considered as a value objects as a whole. |
| In other words, even having one or more optional components not turned into |
| value objects, |ASN.1| object is still considered as a value object. Defaulted |
| components are normally value objects by default. |
| """ |
| if self._componentValues is noValue: |
| return False |
| |
| componentType = self.componentType |
| |
| if componentType: |
| for idx, subComponentType in enumerate(componentType.namedTypes): |
| if subComponentType.isDefaulted or subComponentType.isOptional: |
| continue |
| |
| if not self._componentValues: |
| return False |
| |
| componentValue = self._componentValues[idx] |
| if componentValue is noValue or not componentValue.isValue: |
| return False |
| |
| else: |
| for componentValue in self._componentValues: |
| if componentValue is noValue or not componentValue.isValue: |
| return False |
| |
| return True |
| |
| @property |
| def isInconsistent(self): |
| """Run necessary checks to ensure |ASN.1| object consistency. |
| |
| Default action is to verify |ASN.1| object against constraints imposed |
| by `subtypeSpec`. |
| |
| Raises |
| ------ |
| :py:class:`~pyasn1.error.PyAsn1tError` on any inconsistencies found |
| """ |
| if self.componentType is noValue or not self.subtypeSpec: |
| return False |
| |
| if self._componentValues is noValue: |
| return True |
| |
| mapping = {} |
| |
| for idx, value in enumerate(self._componentValues): |
| # Absent fields are not in the mapping |
| if value is noValue: |
| continue |
| |
| name = self.componentType.getNameByPosition(idx) |
| |
| mapping[name] = value |
| |
| try: |
| # Represent Sequence/Set as a bare dict to constraints chain |
| self.subtypeSpec(mapping) |
| |
| except error.PyAsn1Error: |
| exc = sys.exc_info()[1] |
| return exc |
| |
| return False |
| |
| def prettyPrint(self, scope=0): |
| """Return an object representation string. |
| |
| Returns |
| ------- |
| : :class:`str` |
| Human-friendly object representation. |
| """ |
| scope += 1 |
| representation = self.__class__.__name__ + ':\n' |
| for idx, componentValue in enumerate(self._componentValues): |
| if componentValue is not noValue and componentValue.isValue: |
| representation += ' ' * scope |
| if self.componentType: |
| representation += self.componentType.getNameByPosition(idx) |
| else: |
| representation += self._dynamicNames.getNameByPosition(idx) |
| representation = '%s=%s\n' % ( |
| representation, componentValue.prettyPrint(scope) |
| ) |
| return representation |
| |
| def prettyPrintType(self, scope=0): |
| scope += 1 |
| representation = '%s -> %s {\n' % (self.tagSet, self.__class__.__name__) |
| for idx, componentType in enumerate(self.componentType.values() or self._componentValues): |
| representation += ' ' * scope |
| if self.componentType: |
| representation += '"%s"' % self.componentType.getNameByPosition(idx) |
| else: |
| representation += '"%s"' % self._dynamicNames.getNameByPosition(idx) |
| representation = '%s = %s\n' % ( |
| representation, componentType.prettyPrintType(scope) |
| ) |
| return representation + '\n' + ' ' * (scope - 1) + '}' |
| |
| # backward compatibility |
| |
| def setDefaultComponents(self): |
| return self |
| |
| def getComponentType(self): |
| if self._componentTypeLen: |
| return self.componentType |
| |
| def getNameByPosition(self, idx): |
| if self._componentTypeLen: |
| return self.componentType[idx].name |
| |
| class Sequence(SequenceAndSetBase): |
| __doc__ = SequenceAndSetBase.__doc__ |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x10) |
| ) |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) |
| #: object imposing size constraint on |ASN.1| objects |
| componentType = namedtype.NamedTypes() |
| |
| # Disambiguation ASN.1 types identification |
| typeId = SequenceAndSetBase.getTypeId() |
| |
| # backward compatibility |
| |
| def getComponentTagMapNearPosition(self, idx): |
| if self.componentType: |
| return self.componentType.getTagMapNearPosition(idx) |
| |
| def getComponentPositionNearType(self, tagSet, idx): |
| if self.componentType: |
| return self.componentType.getPositionNearType(tagSet, idx) |
| else: |
| return idx |
| |
| |
| class Set(SequenceAndSetBase): |
| __doc__ = SequenceAndSetBase.__doc__ |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.initTagSet( |
| tag.Tag(tag.tagClassUniversal, tag.tagFormatConstructed, 0x11) |
| ) |
| |
| #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) |
| #: object representing ASN.1 type allowed within |ASN.1| type |
| componentType = namedtype.NamedTypes() |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| # Disambiguation ASN.1 types identification |
| typeId = SequenceAndSetBase.getTypeId() |
| |
| def getComponent(self, innerFlag=False): |
| return self |
| |
| def getComponentByType(self, tagSet, default=noValue, |
| instantiate=True, innerFlag=False): |
| """Returns |ASN.1| type component by ASN.1 tag. |
| |
| Parameters |
| ---------- |
| tagSet : :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing ASN.1 tags to identify one of |
| |ASN.1| object component |
| |
| Keyword Args |
| ------------ |
| default: :class:`object` |
| If set and requested component is a schema object, return the `default` |
| object instead of the requested component. |
| |
| instantiate: :class:`bool` |
| If :obj:`True` (default), inner component will be automatically |
| instantiated. |
| If :obj:`False` either existing component or the :class:`noValue` |
| object will be returned. |
| |
| Returns |
| ------- |
| : :py:class:`~pyasn1.type.base.PyAsn1Item` |
| a pyasn1 object |
| """ |
| componentValue = self.getComponentByPosition( |
| self.componentType.getPositionByType(tagSet), |
| default=default, instantiate=instantiate |
| ) |
| if innerFlag and isinstance(componentValue, Set): |
| # get inner component by inner tagSet |
| return componentValue.getComponent(innerFlag=True) |
| else: |
| # get outer component by inner tagSet |
| return componentValue |
| |
| def setComponentByType(self, tagSet, value=noValue, |
| verifyConstraints=True, |
| matchTags=True, |
| matchConstraints=True, |
| innerFlag=False): |
| """Assign |ASN.1| type component by ASN.1 tag. |
| |
| Parameters |
| ---------- |
| tagSet : :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing ASN.1 tags to identify one of |
| |ASN.1| object component |
| |
| Keyword Args |
| ------------ |
| value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative |
| A Python value to initialize |ASN.1| component with (if *componentType* is set) |
| or ASN.1 value object to assign to |ASN.1| component. |
| If `value` is not given, schema object will be set as a component. |
| |
| verifyConstraints : :class:`bool` |
| If :obj:`False`, skip constraints validation |
| |
| matchTags: :class:`bool` |
| If :obj:`False`, skip component tags matching |
| |
| matchConstraints: :class:`bool` |
| If :obj:`False`, skip component constraints matching |
| |
| innerFlag: :class:`bool` |
| If :obj:`True`, search for matching *tagSet* recursively. |
| |
| Returns |
| ------- |
| self |
| """ |
| idx = self.componentType.getPositionByType(tagSet) |
| |
| if innerFlag: # set inner component by inner tagSet |
| componentType = self.componentType.getTypeByPosition(idx) |
| |
| if componentType.tagSet: |
| return self.setComponentByPosition( |
| idx, value, verifyConstraints, matchTags, matchConstraints |
| ) |
| else: |
| componentType = self.getComponentByPosition(idx) |
| return componentType.setComponentByType( |
| tagSet, value, verifyConstraints, matchTags, matchConstraints, innerFlag=innerFlag |
| ) |
| else: # set outer component by inner tagSet |
| return self.setComponentByPosition( |
| idx, value, verifyConstraints, matchTags, matchConstraints |
| ) |
| |
| @property |
| def componentTagMap(self): |
| if self.componentType: |
| return self.componentType.tagMapUnique |
| |
| |
| class Choice(Set): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.ConstructedAsn1Type`, |
| its objects are mutable and duck-type Python :class:`list` objects. |
| |
| Keyword Args |
| ------------ |
| componentType: :py:class:`~pyasn1.type.namedtype.NamedType` |
| Object holding named ASN.1 types allowed within this collection |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s). Constraints |
| verification for |ASN.1| type can only occur on explicit |
| `.isInconsistent` call. |
| |
| Examples |
| -------- |
| |
| .. code-block:: python |
| |
| class Afters(Choice): |
| ''' |
| ASN.1 specification: |
| |
| Afters ::= CHOICE { |
| cheese [0] IA5String, |
| dessert [1] IA5String |
| } |
| ''' |
| componentType = NamedTypes( |
| NamedType('cheese', IA5String().subtype( |
| implicitTag=Tag(tagClassContext, tagFormatSimple, 0) |
| ), |
| NamedType('dessert', IA5String().subtype( |
| implicitTag=Tag(tagClassContext, tagFormatSimple, 1) |
| ) |
| ) |
| |
| afters = Afters() |
| afters['cheese'] = 'Mascarpone' |
| """ |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.TagSet() # untagged |
| |
| #: Default collection of ASN.1 types of component (e.g. :py:class:`~pyasn1.type.namedtype.NamedType`) |
| #: object representing ASN.1 type allowed within |ASN.1| type |
| componentType = namedtype.NamedTypes() |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection( |
| constraint.ValueSizeConstraint(1, 1) |
| ) |
| |
| # Disambiguation ASN.1 types identification |
| typeId = Set.getTypeId() |
| |
| _currentIdx = None |
| |
| def __eq__(self, other): |
| if self._componentValues: |
| return self._componentValues[self._currentIdx] == other |
| return NotImplemented |
| |
| def __ne__(self, other): |
| if self._componentValues: |
| return self._componentValues[self._currentIdx] != other |
| return NotImplemented |
| |
| def __lt__(self, other): |
| if self._componentValues: |
| return self._componentValues[self._currentIdx] < other |
| return NotImplemented |
| |
| def __le__(self, other): |
| if self._componentValues: |
| return self._componentValues[self._currentIdx] <= other |
| return NotImplemented |
| |
| def __gt__(self, other): |
| if self._componentValues: |
| return self._componentValues[self._currentIdx] > other |
| return NotImplemented |
| |
| def __ge__(self, other): |
| if self._componentValues: |
| return self._componentValues[self._currentIdx] >= other |
| return NotImplemented |
| |
| if sys.version_info[0] <= 2: |
| def __nonzero__(self): |
| return self._componentValues and True or False |
| else: |
| def __bool__(self): |
| return self._componentValues and True or False |
| |
| def __len__(self): |
| return self._currentIdx is not None and 1 or 0 |
| |
| def __contains__(self, key): |
| if self._currentIdx is None: |
| return False |
| return key == self.componentType[self._currentIdx].getName() |
| |
| def __iter__(self): |
| if self._currentIdx is None: |
| raise StopIteration |
| yield self.componentType[self._currentIdx].getName() |
| |
| # Python dict protocol |
| |
| def values(self): |
| if self._currentIdx is not None: |
| yield self._componentValues[self._currentIdx] |
| |
| def keys(self): |
| if self._currentIdx is not None: |
| yield self.componentType[self._currentIdx].getName() |
| |
| def items(self): |
| if self._currentIdx is not None: |
| yield self.componentType[self._currentIdx].getName(), self[self._currentIdx] |
| |
| def checkConsistency(self): |
| if self._currentIdx is None: |
| raise error.PyAsn1Error('Component not chosen') |
| |
| def _cloneComponentValues(self, myClone, cloneValueFlag): |
| try: |
| component = self.getComponent() |
| except error.PyAsn1Error: |
| pass |
| else: |
| if isinstance(component, Choice): |
| tagSet = component.effectiveTagSet |
| else: |
| tagSet = component.tagSet |
| if isinstance(component, base.ConstructedAsn1Type): |
| myClone.setComponentByType( |
| tagSet, component.clone(cloneValueFlag=cloneValueFlag) |
| ) |
| else: |
| myClone.setComponentByType(tagSet, component.clone()) |
| |
| def getComponentByPosition(self, idx, default=noValue, instantiate=True): |
| __doc__ = Set.__doc__ |
| |
| if self._currentIdx is None or self._currentIdx != idx: |
| return Set.getComponentByPosition(self, idx, default=default, |
| instantiate=instantiate) |
| |
| return self._componentValues[idx] |
| |
| def setComponentByPosition(self, idx, value=noValue, |
| verifyConstraints=True, |
| matchTags=True, |
| matchConstraints=True): |
| """Assign |ASN.1| type component by position. |
| |
| Equivalent to Python sequence item assignment operation (e.g. `[]`). |
| |
| Parameters |
| ---------- |
| idx: :class:`int` |
| Component index (zero-based). Must either refer to existing |
| component or to N+1 component. In the latter case a new component |
| type gets instantiated (if *componentType* is set, or given ASN.1 |
| object is taken otherwise) and appended to the |ASN.1| sequence. |
| |
| Keyword Args |
| ------------ |
| value: :class:`object` or :py:class:`~pyasn1.type.base.PyAsn1Item` derivative |
| A Python value to initialize |ASN.1| component with (if *componentType* is set) |
| or ASN.1 value object to assign to |ASN.1| component. Once a new value is |
| set to *idx* component, previous value is dropped. |
| If `value` is not given, schema object will be set as a component. |
| |
| verifyConstraints : :class:`bool` |
| If :obj:`False`, skip constraints validation |
| |
| matchTags: :class:`bool` |
| If :obj:`False`, skip component tags matching |
| |
| matchConstraints: :class:`bool` |
| If :obj:`False`, skip component constraints matching |
| |
| Returns |
| ------- |
| self |
| """ |
| oldIdx = self._currentIdx |
| Set.setComponentByPosition(self, idx, value, verifyConstraints, matchTags, matchConstraints) |
| self._currentIdx = idx |
| if oldIdx is not None and oldIdx != idx: |
| self._componentValues[oldIdx] = noValue |
| return self |
| |
| @property |
| def effectiveTagSet(self): |
| """Return a :class:`~pyasn1.type.tag.TagSet` object of the currently initialized component or self (if |ASN.1| is tagged).""" |
| if self.tagSet: |
| return self.tagSet |
| else: |
| component = self.getComponent() |
| return component.effectiveTagSet |
| |
| @property |
| def tagMap(self): |
| """"Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping |
| ASN.1 tags to ASN.1 objects contained within callee. |
| """ |
| if self.tagSet: |
| return Set.tagMap.fget(self) |
| else: |
| return self.componentType.tagMapUnique |
| |
| def getComponent(self, innerFlag=False): |
| """Return currently assigned component of the |ASN.1| object. |
| |
| Returns |
| ------- |
| : :py:class:`~pyasn1.type.base.PyAsn1Item` |
| a PyASN1 object |
| """ |
| if self._currentIdx is None: |
| raise error.PyAsn1Error('Component not chosen') |
| else: |
| c = self._componentValues[self._currentIdx] |
| if innerFlag and isinstance(c, Choice): |
| return c.getComponent(innerFlag) |
| else: |
| return c |
| |
| def getName(self, innerFlag=False): |
| """Return the name of currently assigned component of the |ASN.1| object. |
| |
| Returns |
| ------- |
| : :py:class:`str` |
| |ASN.1| component name |
| """ |
| if self._currentIdx is None: |
| raise error.PyAsn1Error('Component not chosen') |
| else: |
| if innerFlag: |
| c = self._componentValues[self._currentIdx] |
| if isinstance(c, Choice): |
| return c.getName(innerFlag) |
| return self.componentType.getNameByPosition(self._currentIdx) |
| |
| @property |
| def isValue(self): |
| """Indicate that |ASN.1| object represents ASN.1 value. |
| |
| If *isValue* is :obj:`False` then this object represents just ASN.1 schema. |
| |
| If *isValue* is :obj:`True` then, in addition to its ASN.1 schema features, |
| this object can also be used like a Python built-in object (e.g. |
| :class:`int`, :class:`str`, :class:`dict` etc.). |
| |
| Returns |
| ------- |
| : :class:`bool` |
| :obj:`False` if object represents just ASN.1 schema. |
| :obj:`True` if object represents ASN.1 schema and can be used as a normal |
| value. |
| |
| Note |
| ---- |
| There is an important distinction between PyASN1 schema and value objects. |
| The PyASN1 schema objects can only participate in ASN.1 schema-related |
| operations (e.g. defining or testing the structure of the data). Most |
| obvious uses of ASN.1 schema is to guide serialisation codecs whilst |
| encoding/decoding serialised ASN.1 contents. |
| |
| The PyASN1 value objects can **additionally** participate in many operations |
| involving regular Python objects (e.g. arithmetic, comprehension etc). |
| """ |
| if self._currentIdx is None: |
| return False |
| |
| componentValue = self._componentValues[self._currentIdx] |
| |
| return componentValue is not noValue and componentValue.isValue |
| |
| def clear(self): |
| self._currentIdx = None |
| return Set.clear(self) |
| |
| # compatibility stubs |
| |
| def getMinTagSet(self): |
| return self.minTagSet |
| |
| |
| class Any(OctetString): |
| """Create |ASN.1| schema or value object. |
| |
| |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`, |
| its objects are immutable and duck-type Python 2 :class:`str` or Python 3 |
| :class:`bytes`. When used in Unicode context, |ASN.1| type assumes |
| "|encoding|" serialisation. |
| |
| Keyword Args |
| ------------ |
| value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object |
| :class:`str` (Python 2) or :class:`bytes` (Python 3), alternatively |
| :class:`unicode` object (Python 2) or :class:`str` (Python 3) |
| representing character string to be serialised into octets (note |
| `encoding` parameter) or |ASN.1| object. |
| If `value` is not given, schema object will be created. |
| |
| tagSet: :py:class:`~pyasn1.type.tag.TagSet` |
| Object representing non-default ASN.1 tag(s) |
| |
| subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` |
| Object representing non-default ASN.1 subtype constraint(s). Constraints |
| verification for |ASN.1| type occurs automatically on object |
| instantiation. |
| |
| encoding: :py:class:`str` |
| Unicode codec ID to encode/decode :class:`unicode` (Python 2) or |
| :class:`str` (Python 3) the payload when |ASN.1| object is used |
| in text string context. |
| |
| binValue: :py:class:`str` |
| Binary string initializer to use instead of the *value*. |
| Example: '10110011'. |
| |
| hexValue: :py:class:`str` |
| Hexadecimal string initializer to use instead of the *value*. |
| Example: 'DEADBEEF'. |
| |
| Raises |
| ------ |
| ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error |
| On constraint violation or bad initializer. |
| |
| Examples |
| -------- |
| .. code-block:: python |
| |
| class Error(Sequence): |
| ''' |
| ASN.1 specification: |
| |
| Error ::= SEQUENCE { |
| code INTEGER, |
| parameter ANY DEFINED BY code -- Either INTEGER or REAL |
| } |
| ''' |
| componentType=NamedTypes( |
| NamedType('code', Integer()), |
| NamedType('parameter', Any(), |
| openType=OpenType('code', {1: Integer(), |
| 2: Real()})) |
| ) |
| |
| error = Error() |
| error['code'] = 1 |
| error['parameter'] = Integer(1234) |
| """ |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s) |
| #: associated with |ASN.1| type. |
| tagSet = tag.TagSet() # untagged |
| |
| #: Set (on class, not on instance) or return a |
| #: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection` object |
| #: imposing constraints on |ASN.1| type initialization values. |
| subtypeSpec = constraint.ConstraintsIntersection() |
| |
| # Disambiguation ASN.1 types identification |
| typeId = OctetString.getTypeId() |
| |
| @property |
| def tagMap(self): |
| """"Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping |
| ASN.1 tags to ASN.1 objects contained within callee. |
| """ |
| try: |
| return self._tagMap |
| |
| except AttributeError: |
| self._tagMap = tagmap.TagMap( |
| {self.tagSet: self}, |
| {eoo.endOfOctets.tagSet: eoo.endOfOctets}, |
| self |
| ) |
| |
| return self._tagMap |
| |
| # XXX |
| # coercion rules? |