diff --git a/asn1tools/codecs/__init__.py b/asn1tools/codecs/__init__.py
index 942027c..979d64a 100644
--- a/asn1tools/codecs/__init__.py
+++ b/asn1tools/codecs/__init__.py
@@ -1,6 +1,7 @@
import binascii
from datetime import datetime
from datetime import timedelta
+from functools import wraps
from ..errors import Error
from ..errors import EncodeError as _EncodeError
@@ -9,58 +10,99 @@
from .. import compat
-class EncodeError(_EncodeError):
- """General ASN.1 encode error.
-
+class BaseType(object):
+ """
+ Base Type class containing common functionality between all codecs
"""
- def __init__(self, message):
- super(EncodeError, self).__init__()
- self.message = message
- self.location = []
+ def __init__(self, name, type_name):
+ self.name = name
+ self.type_name = type_name
+ self.optional = False
+ self.default = None
- def __str__(self):
- if self.location:
- return "{}: {}".format(': '.join(self.location[::-1]),
- self.message)
- else:
- return self.message
+ def set_default(self, value):
+ self.default = value
+ def get_default(self):
+ return self.default
-class DecodeError(_DecodeError):
- """General ASN.1 decode error with error location in the message.
+ def has_default(self):
+ return self.default is not None
- """
+ def is_default(self, value):
+ return value == self.default
- def __init__(self, message):
- super(DecodeError, self).__init__()
+ def encode(self, *args, **kwargs):
+ raise NotImplementedError('To be implemented by subclasses.')
+
+ def decode(self, *args, **kwargs):
+ raise NotImplementedError('To be implemented by subclasses.')
+
+
+class ErrorWithLocation(Exception):
+ """
+ Mixin for Error classes which have location list
+ """
+ def __init__(self, message, location=None):
self.message = message
- self.location = []
+ self.location = [location] if location else []
+
+ def add_location(self, element_name):
+ self.location.append(element_name)
def __str__(self):
if self.location:
- return "{}: {}".format(': '.join(self.location[::-1]),
+ return "{}: {}".format('.'.join(self.location[::-1]),
self.message)
else:
return self.message
-class ConstraintsError(_ConstraintsError):
- """General ASN.1 constraints error with error location in the message.
+class EncodeError(ErrorWithLocation, _EncodeError):
+ """General ASN.1 encode error.
"""
+ pass
- def __init__(self, message):
- super(ConstraintsError, self).__init__()
- self.message = message
- self.location = []
+
+class DecodeError(ErrorWithLocation, _DecodeError):
+ """
+ General ASN.1 decode error with error location in the message.
+ """
+
+ def __init__(self, message, offset=None, location=None):
+ """
+
+ :param str message: Message for error
+ :param int offset: Data offset at which error occurred. Can be bits or bytes depending on codec
+ :param str location: Name of element in which error occured
+ """
+ super(DecodeError, self).__init__(message, location=location)
+ self.offset = offset
def __str__(self):
if self.location:
- return "{}: {}".format(': '.join(self.location[::-1]),
- self.message)
+ _str = "{}: {}".format('.'.join(self.location[::-1]), self.message)
else:
- return self.message
+ _str = self.message
+ if self.offset is not None:
+ _str += self.get_offset_message()
+ return _str
+
+ def get_offset_message(self):
+ """
+ Get offset details to add to error message
+ :return:
+ """
+ return ' (At offset: {})'.format(self.offset)
+
+
+class ConstraintsError(ErrorWithLocation, _ConstraintsError):
+ """
+ General ASN.1 constraints error with error location in the message.
+ """
+ pass
class DecodeTagError(DecodeError):
@@ -68,13 +110,16 @@ class DecodeTagError(DecodeError):
"""
- def __init__(self, type_name, expected_tag, actual_tag, offset):
- message = "Expected {} with tag '{}' at offset {}, but got '{}'.".format(
+ def __init__(self, type_name, expected_tag, actual_tag, offset=None, location=None):
+ message = "Expected {} with tag '{}', but got '{}'.".format(
type_name,
binascii.hexlify(expected_tag).decode('ascii'),
- offset,
binascii.hexlify(actual_tag).decode('ascii'))
- super(DecodeTagError, self).__init__(message)
+ super(DecodeTagError, self).__init__(message, offset=offset, location=location)
+
+ self.expected_tag = expected_tag
+ self.actual_tag = actual_tag
+ self.type_name = type_name
class DecodeContentsLengthError(DecodeError):
@@ -82,25 +127,46 @@ class DecodeContentsLengthError(DecodeError):
"""
- def __init__(self, length, offset, contents_max):
- message = ('Expected at least {} contents byte(s) at offset {}, '
- 'but got {}.').format(length,
- offset,
- contents_max - offset)
- super(DecodeContentsLengthError, self).__init__(message)
+ def __init__(self, length, offset, contents_max, location=None):
+ message = 'Expected at least {} contents byte(s), but got {}.'.format(length, contents_max - offset)
+ super(DecodeContentsLengthError, self).__init__(message, offset=offset, location=location)
self.length = length
- self.offset = offset
self.contents_max = contents_max
class OutOfDataError(DecodeError):
- def __init__(self, offset):
+ def __init__(self, offset_bits, location=None):
super(OutOfDataError, self).__init__(
- 'out of data at bit offset {} ({}.{} bytes)'.format(
- offset,
- *divmod(offset, 8)))
+ 'out of data', offset=offset_bits, location=location)
+
+ def get_offset_message(self):
+ """
+ Get offset details to add to error message
+ :return:
+ """
+ return ' (At bit offset: {})'.format(self.offset)
+
+
+def add_error_location(method):
+ """
+ Method decorator which catches ErrorWithLocation subclasses and adds element name to location
+ If decorator is applied to parent Type class method, this functionality can be disabled on a per-child
+ Type basis by setting no_error_location=True
+ :param method:
+ :return:
+ """
+ @wraps(method)
+ def new_method(self, *args, **kwargs):
+ try:
+ return method(self, *args, **kwargs)
+ except ErrorWithLocation as e:
+ # Don't add name if it is blank (for SEQUENCE OF, SET OF etc)
+ if self.name and not getattr(self, 'no_error_location', False):
+ e.add_location(self.name)
+ raise e
+ return new_method
def _generalized_time_to_datetime(string):
diff --git a/asn1tools/codecs/ber.py b/asn1tools/codecs/ber.py
index b0c4ddc..136ec22 100644
--- a/asn1tools/codecs/ber.py
+++ b/asn1tools/codecs/ber.py
@@ -10,9 +10,11 @@
from ..errors import Error
from ..parser import EXTENSION_MARKER
+from . import BaseType
from . import EncodeError
from . import DecodeError
from . import DecodeTagError
+from . import OutOfDataError
from . import DecodeContentsLengthError
from . import format_or
from . import compiler
@@ -20,6 +22,7 @@
from . import utc_time_from_datetime
from . import generalized_time_to_datetime
from . import generalized_time_from_datetime
+from . import add_error_location
from .compiler import enum_values_as_dict
from .compiler import clean_bit_string_value
@@ -72,10 +75,44 @@ class Tag(object):
END_OF_CONTENTS_OCTETS = b'\x00\x00'
+TAG_MISMATCH = object()
-class DecodeChoiceError(Error):
- pass
+def flatten(l):
+ """
+ Flatten irregular nested list
+ :param l:
+ :return:
+ """
+ if isinstance(l, (list, tuple)):
+ return [a for i in l for a in flatten(i)]
+ else:
+ return [l]
+
+
+def is_end_of_data(data, offset, end_offset):
+ # Detect end of data
+ if end_offset:
+ if offset >= end_offset:
+ return True, offset
+
+ elif data[offset:offset + 2] == END_OF_CONTENTS_OCTETS:
+ return True, offset + 2
+
+ return False, offset
+
+
+def check_decode_error(asn_type, decoded_value, data, offset):
+ """
+ Checks if decode result is TAG_MISMATCH, if so, raise DecodeTagError
+ :return:
+ """
+ if decoded_value == TAG_MISMATCH:
+ raise DecodeTagError(asn_type.type_name,
+ asn_type.tag,
+ data[offset:offset + asn_type.tag_len],
+ offset,
+ location=asn_type.name)
def encode_length_definite(length):
@@ -100,9 +137,7 @@ def decode_length_definite(encoded, offset):
if length > 127:
if length == 128:
- raise DecodeError(
- 'Expected definite length at offset {}, but got indefinite.'.format(
- offset - 1))
+ raise DecodeError('Expected definite length, but got indefinite.', offset-1)
number_of_bytes = (length & 0x7f)
encoded_length = encoded[offset:number_of_bytes + offset]
@@ -367,48 +402,56 @@ def decode_object_identifier_subidentifier(data, offset):
return decoded, offset + 1
-class Type(object):
+class Type(BaseType):
def __init__(self, name, type_name, number, flags=0):
- self.name = name
- self.type_name = type_name
-
+ """
+
+ :param str name: Name of type instance
+ :param str type_name: ASN1 Type name
+ :param int number: Tag number
+ :param flags:
+ """
+ super().__init__(name, type_name)
if number is None:
self.tag = None
+ self.tag_len = None
else:
self.tag = encode_tag(number, flags)
-
- self.optional = False
- self.default = None
+ self.tag_len = len(self.tag)
def set_tag(self, number, flags):
self.tag = encode_tag(number, flags)
+ self.tag_len = len(self.tag)
def set_size_range(self, minimum, maximum, has_extension_marker):
pass
- def decode_tag(self, data, offset):
- end_offset = offset + len(self.tag)
-
- if data[offset:end_offset] != self.tag:
- raise DecodeTagError(self.type_name,
- self.tag,
- data[offset:end_offset],
- offset)
-
- return end_offset
-
- def set_default(self, value):
- self.default = value
-
- def get_default(self):
- return self.default
-
- def is_default(self, value):
- return value == self.default
-
- def has_default(self):
- return self.default is not None
+ @add_error_location
+ def decode(self, data, offset, values=None):
+ """
+ Decode entry point, handles incorrect tag by returning DECODE_FAILED (Previously raised DecodeTagError)
+ :param bytearray data: Binary ASN1 data to decode
+ :param int offset: Current byte offset
+ :param dict values:
+ :return:
+ """
+ tag_end_offset = offset + self.tag_len
+
+ # Validate tag
+ if data[offset:tag_end_offset] != self.tag:
+ # return TAG_MISMATCH Instead of raising DecodeTagError for better performance so that MembersType does
+ # not have to catch exception for every missing optional type
+ return TAG_MISMATCH, offset
+
+ return self._decode(data, tag_end_offset)
+
+ def _decode(self, data, offset):
+ """
+ Type-specific decode logic
+ :return:
+ """
+ raise NotImplementedError('Type {} does not implement _decode() method'.format(type(self).__name__))
class PrimitiveOrConstructedType(Type):
@@ -426,23 +469,25 @@ def set_tag(self, number, flags):
self.tag = encode_tag(number, flags)
self.constructed_tag = copy(self.tag)
self.constructed_tag[0] |= Encoding.CONSTRUCTED
+ self.tag_len = len(self.tag)
- def decode_tag(self, data, offset):
- end_offset = offset + len(self.tag)
- tag = data[offset:end_offset]
+ @add_error_location
+ def decode(self, data, start_offset, values=None):
+ """
+ Custom decode logic to handle primitive or constructed types
+ """
+ offset = start_offset + self.tag_len
+ tag = data[start_offset:offset]
+
+ # Validate tag
if tag == self.tag:
- return True, end_offset
+ is_primitive = True
elif tag == self.constructed_tag:
- return False, end_offset
+ is_primitive = False
else:
- raise DecodeTagError(self.type_name,
- self.tag,
- data[offset:end_offset],
- offset)
-
- def decode(self, data, offset):
- is_primitive, offset = self.decode_tag(data, offset)
+ # Return DECODE_FAILED instead of raising DecodeError
+ return TAG_MISMATCH, start_offset
if is_primitive:
length, offset = decode_length_definite(data, offset)
@@ -451,22 +496,23 @@ def decode(self, data, offset):
return self.decode_primitive_contents(data, offset, length), end_offset
else:
length, offset = decode_length_constructed(data, offset)
- segments = []
+ return self.decode_constructed_contents(data, offset, length)
- if length is None:
- while data[offset:offset + 2] != END_OF_CONTENTS_OCTETS:
- decoded, offset = self.segment.decode(data, offset)
- segments.append(decoded)
+ def decode_constructed_contents(self, data, offset, length):
+ segments = []
- end_offset = offset + 2
- else:
- end_offset = offset + length
+ end_offset = None if length is None else offset + length
+
+ while True:
+ end_of_data, offset = is_end_of_data(data, offset, end_offset)
+ if end_of_data:
+ break
- while offset < end_offset:
- decoded, offset = self.segment.decode(data, offset)
- segments.append(decoded)
+ decoded, offset = self.segment.decode(data, offset)
+ check_decode_error(self.segment, decoded, data, offset)
+ segments.append(decoded)
- return self.decode_constructed_segments(segments), end_offset
+ return self.decode_constructed_segments(segments), offset
def decode_primitive_contents(self, data, offset, length):
raise NotImplementedError('To be implemented by subclasses.')
@@ -486,11 +532,12 @@ def __init__(self, name):
self.TAG,
OctetString(name))
- def encode(self, data, encoded):
+ @add_error_location
+ def encode(self, data, encoded, values=None):
data = data.encode(self.ENCODING)
- encoded.extend(self.tag)
- encoded.extend(encode_length_definite(len(data)))
- encoded.extend(data)
+ # encoded.extend(self.tag)
+ # encoded.extend(encode_length_definite(len(data)))
+ encoded.extend(self.tag + encode_length_definite(len(data)) + data)
def decode_primitive_contents(self, data, offset, length):
return data[offset:offset + length].decode(self.ENCODING)
@@ -517,7 +564,8 @@ def set_tag(self, number, flags):
super(MembersType, self).set_tag(number,
flags | Encoding.CONSTRUCTED)
- def encode(self, data, encoded):
+ @add_error_location
+ def encode(self, data, encoded, values=None):
encoded_members = bytearray()
for member in self.root_members:
@@ -526,9 +574,9 @@ def encode(self, data, encoded):
if self.additions:
self.encode_additions(data, encoded_members)
- encoded.extend(self.tag)
- encoded.extend(encode_length_definite(len(encoded_members)))
- encoded.extend(encoded_members)
+ # encoded.extend(self.tag)
+ # encoded.extend(encode_length_definite(len(encoded_members)))
+ encoded.extend(self.tag + encode_length_definite(len(encoded_members)) + encoded_members)
def encode_additions(self, data, encoded_members):
try:
@@ -553,14 +601,10 @@ def encode_member(self, member, data, encoded_members):
if name in data:
value = data[name]
- try:
- if isinstance(member, AnyDefinedBy):
- member.encode(value, encoded_members, data)
- elif not member.is_default(value):
- member.encode(value, encoded_members)
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ if isinstance(member, AnyDefinedBy):
+ member.encode(value, encoded_members, data)
+ elif not member.is_default(value):
+ member.encode(value, encoded_members)
elif member.optional:
pass
elif not member.has_default():
@@ -569,8 +613,7 @@ def encode_member(self, member, data, encoded_members):
name,
data))
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
if data[offset] == 0x80:
# Indefinite length field.
@@ -583,86 +626,89 @@ def decode(self, data, offset):
values = {}
- for member in self.root_members:
- # End of indefinite length sequence may be reached at any
- # time, but DecodeError will occur (instead of usual
- # IndexError) and so further members will be skipped.
- offset = self.decode_member(member,
- data,
- values,
- offset,
- end_offset)
+ offset, out_of_data = self.decode_members(self.root_members, data, values, offset, end_offset)
+ # Decode additions (even if out of data already, so defaults can be added)
if self.additions:
- offset = self.decode_additions(data,
- values,
- offset,
- end_offset)
-
- # Detect end of indefinite length constructed field.
- if end_offset is None:
- if data[offset:offset + 2] == END_OF_CONTENTS_OCTETS:
- end_offset = offset + 2
- else:
- raise DecodeError(
- 'Could not find end-of-contents tag for indefinite length '
- 'field.')
+ offset, out_of_data = self.decode_members(flatten(self.additions), data, values, offset, end_offset,
+ ignore_missing=True)
- return values, end_offset
+ if out_of_data:
+ return values, offset
- def decode_additions(self, data, values, offset, end_offset):
- try:
- for addition in self.additions:
- addition_values = {}
-
- if isinstance(addition, list):
- for member in addition:
- offset = self.decode_member(member,
- data,
- addition_values,
- offset,
- end_offset)
- else:
- offset = self.decode_member(addition,
- data,
- addition_values,
- offset,
- end_offset)
-
- values.update(addition_values)
- except DecodeError:
- pass
-
- return offset
-
- def decode_member(self, member, data, values, offset, end_offset):
- try:
- # If reached end of indefinite length field, member.decode
- # will raise DecodeTagError, and end of field will be
- # handled in MembersType.decode() method.
- if end_offset is None or offset < end_offset:
- if isinstance(member, AnyDefinedBy):
- value, offset = member.decode(data, offset, values)
+ if end_offset is None:
+ raise DecodeError('Could not find end-of-contents tag for indefinite length field.',
+ offset)
+ else:
+ # Extra data is allowed in cases of versioned additions
+ return values, end_offset
+
+ def decode_members(self, members, data, values, offset, end_offset, ignore_missing=False):
+ """
+ Decode values for members from data starting from offset
+ Supports member data encoded in different order than members specified
+ :param list members:
+ :param bytearray data:
+ :param dict values:
+ :param int offset:
+ :param int end_offset: End offset of member data (None if indefinite length field)
+ :param bool ignore_missing: Whether to not raise DecodeError for missing mandatory fields with no defaults
+ :return:
+ """
+ # Decode member values from data
+ remaining_members = members
+ while True:
+ undecoded_members = []
+ decode_success = False # Whether at least one member was successfully decoded
+
+ out_of_data, offset = is_end_of_data(data, offset, end_offset)
+ # Attempt to decode remaining members. If they are encoded in same order, should decode all in one loop
+ # Otherwise will require multiple iterations
+ for member in remaining_members:
+ # Dont attempt decode if already out of data, just add member to list of undecoded
+ if out_of_data:
+ undecoded_members.append(member)
+ continue
+
+ # Attempt decode
+ value, offset = member.decode(data, offset, values=values)
+
+ if value == TAG_MISMATCH:
+ undecoded_members.append(member)
else:
- value, offset = member.decode(data, offset)
- else:
- raise IndexError
- except (DecodeError, DecodeTagError, IndexError) as e:
- if member.optional:
- return offset
+ decode_success = True
+ values[member.name] = value
- if not member.has_default():
- if isinstance(e, IndexError):
- e = DecodeError('out of data at offset {}'.format(offset))
+ # Detect end of data
+ out_of_data, offset = is_end_of_data(data, offset, end_offset)
- e.location.append(member.name)
- raise e
+ remaining_members = undecoded_members
+ if out_of_data:
+ break
- value = member.get_default()
+ if not decode_success:
+ # No members are able to decode data, exit loop
+ break
- values[member.name] = value
+ # Handle remaining members that there is no data for
+ # (will raise error if member is not optional and has no default)
+ for member in remaining_members:
+ if member.optional:
+ continue
- return offset
+ if member.has_default():
+ values[member.name] = member.get_default()
+ elif ignore_missing:
+ break
+ elif out_of_data:
+ raise OutOfDataError(offset*8, location=member.name)
+ else:
+ raise DecodeTagError(member.type_name,
+ member.tag,
+ data[offset:offset + member.tag_len],
+ offset,
+ location=member.name)
+ return offset, out_of_data
def __repr__(self):
return '{}({}, [{}])'.format(
@@ -684,18 +730,19 @@ def set_tag(self, number, flags):
super(ArrayType, self).set_tag(number,
flags | Encoding.CONSTRUCTED)
+ @add_error_location
def encode(self, data, encoded):
encoded_elements = bytearray()
for entry in data:
self.element_type.encode(entry, encoded_elements)
- encoded.extend(self.tag)
- encoded.extend(encode_length_definite(len(encoded_elements)))
- encoded.extend(encoded_elements)
+ # encoded.extend(self.tag)
+ # encoded.extend(encode_length_definite(len(encoded_elements)))
+ encoded.extend(self.tag + encode_length_definite(len(encoded_elements)) + encoded_elements)
+
+ def _decode(self, data, offset):
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
if data[offset] == 0x80:
offset += 1
length = None # Indicates indefinite field.
@@ -715,6 +762,8 @@ def decode(self, data, offset):
# End of definite length sequence.
break
decoded_element, offset = self.element_type.decode(data, offset)
+ # Invalid Tag
+ check_decode_error(self.element_type, decoded_element, data, offset)
decoded.append(decoded_element)
return decoded, offset
@@ -732,20 +781,19 @@ def __init__(self, name):
'BOOLEAN',
Tag.BOOLEAN)
+ @add_error_location
def encode(self, data, encoded):
encoded.extend(self.tag)
encoded.append(1)
encoded.append(0xff * data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
length, contents_offset = decode_length_definite(data, offset)
if length != 1:
raise DecodeError(
- 'Expected BOOLEAN contents length 1 at offset {}, but '
- 'got {}.'.format(offset,
- length))
+ 'Expected BOOLEAN contents length 1, but '
+ 'got {}.'.format(length), offset)
return bool(data[contents_offset]), contents_offset + length
@@ -760,14 +808,15 @@ def __init__(self, name):
'INTEGER',
Tag.INTEGER)
+ @add_error_location
def encode(self, data, encoded):
- encoded.extend(self.tag)
+ # encoded.extend(self.tag)
value = encode_signed_integer(data)
- encoded.extend(encode_length_definite(len(value)))
- encoded.extend(value)
+ # encoded.extend(encode_length_definite(len(value)))
+ encoded.extend(self.tag + encode_length_definite(len(value)) + value)
+
+ def _decode(self, data, offset):
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
@@ -782,14 +831,14 @@ class Real(Type):
def __init__(self, name):
super(Real, self).__init__(name, 'REAL', Tag.REAL)
+ @add_error_location
def encode(self, data, encoded):
data = encode_real(data)
encoded.extend(self.tag)
encoded.append(len(data))
encoded.extend(data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
decoded = decode_real(data[offset:end_offset])
@@ -808,13 +857,12 @@ def __init__(self, name):
def is_default(self, value):
return False
+ @add_error_location
def encode(self, _, encoded):
encoded.extend(self.tag)
encoded.append(0)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
-
+ def _decode(self, data, offset):
return None, offset + 1
def __repr__(self):
@@ -841,6 +889,7 @@ def is_default(self, value):
return clean_value == clean_default
+ @add_error_location
def encode(self, data, encoded):
number_of_bytes, number_of_rest_bits = divmod(data[1], 8)
data = bytearray(data[0])
@@ -889,10 +938,11 @@ def __init__(self, name):
Tag.OCTET_STRING,
self)
+ @add_error_location
def encode(self, data, encoded):
- encoded.extend(self.tag)
- encoded.extend(encode_length_definite(len(data)))
- encoded.extend(data)
+ # encoded.extend(self.tag)
+ # encoded.extend(encode_length_definite(len(data)))
+ encoded.extend(self.tag + encode_length_definite(len(data)) + data)
def decode_primitive_contents(self, data, offset, length):
return bytes(data[offset:offset + length])
@@ -911,14 +961,15 @@ def __init__(self, name):
'OBJECT IDENTIFIER',
Tag.OBJECT_IDENTIFIER)
+ @add_error_location
def encode(self, data, encoded):
encoded_subidentifiers = encode_object_identifier(data)
encoded.extend(self.tag)
encoded.append(len(encoded_subidentifiers))
encoded.extend(encoded_subidentifiers)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
+
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
decoded = decode_object_identifier(data, offset, end_offset)
@@ -950,6 +1001,7 @@ def format_names(self):
def format_values(self):
return format_or(sorted(list(self.value_to_data)))
+ @add_error_location
def encode(self, data, encoded):
try:
value = self.data_to_value[data]
@@ -964,8 +1016,8 @@ def encode(self, data, encoded):
encoded.extend(encode_length_definite(len(value)))
encoded.extend(value)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
+
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
value = decode_signed_integer(data[offset:end_offset])
@@ -978,7 +1030,7 @@ def decode(self, data, offset):
raise DecodeError(
'Expected enumeration value {}, but got {}.'.format(
self.format_values(),
- value))
+ value), offset)
def __repr__(self):
return 'Enumerated({})'.format(self.name)
@@ -1087,6 +1139,7 @@ def format_tags(self):
def format_names(self):
return format_or(sorted([member.name for member in self.members]))
+ @add_error_location
def encode(self, data, encoded):
try:
member = self.name_to_member[data[0]]
@@ -1096,13 +1149,10 @@ def encode(self, data, encoded):
self.format_names(),
data[0]))
- try:
- member.encode(data[1], encoded)
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ member.encode(data[1], encoded)
- def decode(self, data, offset):
+ @add_error_location
+ def decode(self, data, offset, values=None):
tag = bytes(read_tag(data, offset))
if tag in self.tag_to_member:
@@ -1115,7 +1165,7 @@ def decode(self, data, offset):
raise DecodeError(
"Expected choice member tag {}, but got '{}'.".format(
self.format_tags(),
- self.format_tag(tag)))
+ self.format_tag(tag)), offset)
decoded, offset = member.decode(data, offset)
@@ -1199,14 +1249,15 @@ def __init__(self, name):
'UTCTime',
Tag.UTC_TIME)
+ @add_error_location
def encode(self, data, encoded):
data = utc_time_from_datetime(data).encode('ascii')
encoded.extend(self.tag)
encoded.append(len(data))
encoded.extend(data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
+
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
decoded = data[offset:end_offset].decode('ascii')
@@ -1224,14 +1275,15 @@ def __init__(self, name):
'GeneralizedTime',
Tag.GENERALIZED_TIME)
+ @add_error_location
def encode(self, data, encoded):
data = generalized_time_from_datetime(data).encode('ascii')
encoded.extend(self.tag)
encoded.append(len(data))
encoded.extend(data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
+
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
decoded = data[offset:end_offset].decode('ascii')
@@ -1247,14 +1299,15 @@ class Date(Type):
def __init__(self, name):
super(Date, self).__init__(name, 'DATE', Tag.DATE)
+ @add_error_location
def encode(self, data, encoded):
data = str(data).replace('-', '').encode('ascii')
encoded.extend(self.tag)
encoded.append(len(data))
encoded.extend(data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
+
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
decoded = data[offset:end_offset].decode('ascii')
@@ -1273,14 +1326,15 @@ def __init__(self, name):
'TIME-OF-DAY',
Tag.TIME_OF_DAY)
+ @add_error_location
def encode(self, data, encoded):
data = str(data).replace(':', '').encode('ascii')
encoded.extend(self.tag)
encoded.append(len(data))
encoded.extend(data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
+
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
decoded = data[offset:end_offset].decode('ascii')
@@ -1299,6 +1353,7 @@ def __init__(self, name):
'DATE-TIME',
Tag.DATE_TIME)
+ @add_error_location
def encode(self, data, encoded):
data = '{:04d}{:02d}{:02d}{:02d}{:02d}{:02d}'.format(*data.timetuple())
data = data.encode('ascii')
@@ -1306,8 +1361,8 @@ def encode(self, data, encoded):
encoded.append(len(data))
encoded.extend(data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
+
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
decoded = data[offset:end_offset].decode('ascii')
@@ -1324,10 +1379,12 @@ class Any(Type):
def __init__(self, name):
super(Any, self).__init__(name, 'ANY', None)
+ @add_error_location
def encode(self, data, encoded):
encoded.extend(data)
- def decode(self, data, offset):
+ @add_error_location
+ def decode(self, data, offset, values=None):
start = offset
offset = skip_tag(data, offset)
length, offset = decode_length_definite(data, offset)
@@ -1349,6 +1406,7 @@ def __init__(self, name, type_member, choices):
self.type_member = type_member
self.choices = choices
+ @add_error_location
def encode(self, data, encoded, values):
if self.choices:
try:
@@ -1359,14 +1417,23 @@ def encode(self, data, encoded, values):
else:
encoded.extend(data)
+ @add_error_location
def decode(self, data, offset, values):
+ """
+
+ :param data:
+ :param int offset: Byte offset in ASN1 data
+ :param dict values: Dictionary of already decoded values in containing type
+ :return:
+ """
if self.choices:
try:
return self.choices[values[self.type_member]].decode(data,
offset)
except KeyError:
raise DecodeError('Bad AnyDefinedBy choice {}.'.format(
- values[self.type_member]))
+ values[self.type_member]),
+ offset)
else:
start = offset
offset = skip_tag(data, offset)
@@ -1380,6 +1447,7 @@ def __repr__(self):
class ExplicitTag(Type):
+ no_error_location = True
def __init__(self, name, inner):
super(ExplicitTag, self).__init__(name, 'ExplicitTag', None)
@@ -1404,13 +1472,11 @@ def set_tag(self, number, flags):
def encode(self, data, encoded):
encoded_inner = bytearray()
self.inner.encode(data, encoded_inner)
- encoded.extend(self.tag)
- encoded.extend(encode_length_definite(len(encoded_inner)))
- encoded.extend(encoded_inner)
+ # encoded.extend(self.tag)
+ # encoded.extend(encode_length_definite(len(encoded_inner)))
+ encoded.extend(self.tag + encode_length_definite(len(encoded_inner)) + encoded_inner)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
- indefinite = False
+ def _decode(self, data, offset):
if data[offset] == 0x80:
# Indefinite length field
@@ -1418,16 +1484,16 @@ def decode(self, data, offset):
indefinite = True
else:
# Definite length field
+ indefinite = False
length, offset = decode_length_definite(data, offset)
values, end_offset = self.inner.decode(data, offset)
+ check_decode_error(self.inner, values, data, offset)
+
if indefinite:
if data[end_offset:end_offset + 2] != END_OF_CONTENTS_OCTETS:
- raise DecodeError(
- 'Expected end-of-contents tag at offset: {}.'.format(
- end_offset))
-
+ raise DecodeError('Expected end-of-contents tag.', end_offset, location=self.name)
end_offset += 2
return values, end_offset
@@ -1460,10 +1526,12 @@ def set_inner_type(self, inner):
for choice_parent in self.choice_parents:
choice_parent.add_tags([self])
+ @add_error_location
def encode(self, data, encoded):
self.inner.encode(data, encoded)
- def decode(self, data, offset):
+ @add_error_location
+ def decode(self, data, offset, values=None):
return self.inner.decode(data, offset)
def __repr__(self):
@@ -1479,10 +1547,18 @@ def encode(self, data):
return encoded
def decode(self, data):
- return self._type.decode(bytearray(data), 0)[0]
+ return self.decode_with_length(data)[0]
def decode_with_length(self, data):
- return self._type.decode(bytearray(data), 0)
+ """
+ Decode and return decoded values as well as length of binary data d ecoded
+ :param data:
+ :return:
+ """
+ result = self._type.decode(bytearray(data), 0)
+ # Raise DecodeError
+ check_decode_error(self._type, result[0], data, 0)
+ return result
def get_tag_no_encoding(member):
diff --git a/asn1tools/codecs/compiler.py b/asn1tools/codecs/compiler.py
index 044ec05..7ab3387 100644
--- a/asn1tools/codecs/compiler.py
+++ b/asn1tools/codecs/compiler.py
@@ -92,6 +92,10 @@ def __init__(self, type_):
def type(self):
return self._type
+ @property
+ def name(self):
+ return self._type.name
+
def check_types(self, data):
return self.type_checker.encode(data)
diff --git a/asn1tools/codecs/constraints_checker.py b/asn1tools/codecs/constraints_checker.py
index ba91066..dc2d8be 100644
--- a/asn1tools/codecs/constraints_checker.py
+++ b/asn1tools/codecs/constraints_checker.py
@@ -6,6 +6,7 @@
from copy import copy
from . import ConstraintsError
+from . import add_error_location
from . import compiler
from . import format_or
from .permitted_alphabet import NUMERIC_STRING
@@ -108,6 +109,7 @@ def __init__(self,
self.permitted_alphabet = permitted_alphabet
+ @add_error_location
def encode(self, data):
length = len(data)
@@ -142,6 +144,7 @@ class Integer(Type):
def __init__(self, name):
super(Integer, self).__init__(name)
+ @add_error_location
def encode(self, data):
if not self.is_in_range(data):
raise ConstraintsError(
@@ -169,6 +172,7 @@ def __init__(self, name, minimum, maximum, has_extension_marker):
super(BitString, self).__init__(name)
self.set_size_range(minimum, maximum, has_extension_marker)
+ @add_error_location
def encode(self, data):
number_of_bits = data[1]
@@ -192,6 +196,7 @@ def __init__(self, name, minimum, maximum, has_extension_marker):
super(Bytes, self).__init__(name)
self.set_size_range(minimum, maximum, has_extension_marker)
+ @add_error_location
def encode(self, data):
length = len(data)
@@ -209,16 +214,13 @@ def __init__(self, name, members):
super(Dict, self).__init__(name)
self.members = members
+ @add_error_location
def encode(self, data):
for member in self.members:
name = member.name
if name in data:
- try:
- member.encode(data[name])
- except ConstraintsError as e:
- e.location.append(member.name)
- raise
+ member.encode(data[name])
class List(Type):
@@ -228,6 +230,7 @@ def __init__(self, name, element_type, minimum, maximum, has_extension_marker):
self.element_type = element_type
self.set_size_range(minimum, maximum, has_extension_marker)
+ @add_error_location
def encode(self, data):
length = len(data)
@@ -253,6 +256,7 @@ def __init__(self, name, members, has_extension_marker):
def format_names(self):
return format_or(sorted(self.name_to_member))
+ @add_error_location
def encode(self, data):
value = data[0]
@@ -266,11 +270,7 @@ def encode(self, data):
self.format_names(),
value))
- try:
- member.encode(data[1])
- except ConstraintsError as e:
- e.location.append(member.name)
- raise
+ member.encode(data[1])
class NumericString(String):
@@ -321,6 +321,7 @@ def __init__(self, name, type_name, module_name):
def set_inner_type(self, inner):
self.inner = copy(inner)
+ @add_error_location
def encode(self, data):
self.inner.encode(data)
diff --git a/asn1tools/codecs/der.py b/asn1tools/codecs/der.py
index 3e23ab2..14c49b6 100644
--- a/asn1tools/codecs/der.py
+++ b/asn1tools/codecs/der.py
@@ -8,6 +8,7 @@
from . import restricted_utc_time_from_datetime
from . import restricted_generalized_time_to_datetime
from . import restricted_generalized_time_from_datetime
+from . import add_error_location
from .compiler import clean_bit_string_value
from .ber import Class
from .ber import Encoding
@@ -16,7 +17,6 @@
from .ber import decode_length_definite
from .ber import encode_signed_integer
from .ber import decode_signed_integer
-from .ber import encode_tag
from .ber import Boolean
from .ber import Real
from .ber import Null
@@ -32,56 +32,20 @@
from .ber import Date
from .ber import TimeOfDay
from .ber import DateTime
-from .ber import decode_length
+# These imports are not used in this module but referenced externally
+from .ber import encode_tag
from .ber import encode_real
+from .ber import decode_length
from .ber import decode_real
-class Type(object):
-
- def __init__(self, name, type_name, number, flags=0):
- self.name = name
- self.type_name = type_name
-
- if number is None:
- self.tag = None
- else:
- self.tag = encode_tag(number, flags)
-
- self.optional = False
- self.default = None
+class Type(ber.Type):
def set_tag(self, number, flags):
if not Class.APPLICATION & flags:
flags |= Class.CONTEXT_SPECIFIC
- self.tag = encode_tag(number, flags)
-
- def set_size_range(self, minimum, maximum, has_extension_marker):
- pass
-
- def decode_tag(self, data, offset):
- end_offset = offset + len(self.tag)
-
- if data[offset:end_offset] != self.tag:
- raise DecodeTagError(self.type_name,
- self.tag,
- data[offset:end_offset],
- offset)
-
- return end_offset
-
- def set_default(self, value):
- self.default = value
-
- def get_default(self):
- return self.default
-
- def is_default(self, value):
- return value == self.default
-
- def has_default(self):
- return self.default is not None
+ super().set_tag(number, flags)
class StringType(Type):
@@ -94,14 +58,14 @@ def __init__(self, name):
self.__class__.__name__,
self.TAG)
- def encode(self, data, encoded):
+ @add_error_location
+ def encode(self, data, encoded, values=None):
data = data.encode(self.ENCODING)
- encoded.extend(self.tag)
- encoded.extend(encode_length_definite(len(data)))
- encoded.extend(data)
+ # encoded.extend(self.tag)
+ # encoded.extend(encode_length_definite(len(data)))
+ encoded.extend(self.tag + encode_length_definite(len(data)) + data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
@@ -125,18 +89,19 @@ def set_tag(self, number, flags):
super(ArrayType, self).set_tag(number,
flags | Encoding.CONSTRUCTED)
- def encode(self, data, encoded):
+ @add_error_location
+ def encode(self, data, encoded, values=None):
encoded_elements = bytearray()
for entry in data:
self.element_type.encode(entry, encoded_elements)
- encoded.extend(self.tag)
- encoded.extend(encode_length_definite(len(encoded_elements)))
- encoded.extend(encoded_elements)
+ # encoded.extend(self.tag)
+ # encoded.extend(encode_length_definite(len(encoded_elements)))
+ encoded.extend(self.tag + encode_length_definite(len(encoded_elements))
+ + encoded_elements)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
length, offset = decode_length_definite(data, offset)
decoded = []
start_offset = offset
@@ -160,14 +125,14 @@ def __init__(self, name):
'INTEGER',
Tag.INTEGER)
- def encode(self, data, encoded):
- encoded.extend(self.tag)
+ @add_error_location
+ def encode(self, data, encoded, values=None):
+ # encoded.extend(self.tag)
value = encode_signed_integer(data)
- encoded.extend(encode_length_definite(len(value)))
- encoded.extend(value)
+ # encoded.extend(encode_length_definite(len(value)))
+ encoded.extend(self.tag + encode_length_definite(len(value)) + value)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
@@ -196,7 +161,8 @@ def is_default(self, value):
return clean_value == clean_default
- def encode(self, data, encoded):
+ @add_error_location
+ def encode(self, data, encoded, values=None):
number_of_bytes, number_of_rest_bits = divmod(data[1], 8)
data = bytearray(data[0])
@@ -215,8 +181,7 @@ def encode(self, data, encoded):
encoded.append(number_of_unused_bits)
encoded.extend(data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
number_of_bits = 8 * (length - 1) - data[offset]
@@ -235,13 +200,13 @@ def __init__(self, name):
'OCTET STRING',
Tag.OCTET_STRING)
- def encode(self, data, encoded):
- encoded.extend(self.tag)
- encoded.extend(encode_length_definite(len(data)))
- encoded.extend(data)
+ @add_error_location
+ def encode(self, data, encoded, values=None):
+ # encoded.extend(self.tag)
+ # encoded.extend(encode_length_definite(len(data)))
+ encoded.extend(self.tag + encode_length_definite(len(data)) + data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
@@ -336,14 +301,14 @@ def __init__(self, name):
'UTCTime',
Tag.UTC_TIME)
- def encode(self, data, encoded):
+ @add_error_location
+ def encode(self, data, encoded, values=None):
data = restricted_utc_time_from_datetime(data).encode('ascii')
encoded.extend(self.tag)
encoded.append(len(data))
encoded.extend(data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
decoded = data[offset:end_offset].decode('ascii')
@@ -361,14 +326,14 @@ def __init__(self, name):
'GeneralizedTime',
Tag.GENERALIZED_TIME)
- def encode(self, data, encoded):
+ @add_error_location
+ def encode(self, data, encoded, values=None):
data = restricted_generalized_time_from_datetime(data).encode('ascii')
encoded.extend(self.tag)
encoded.append(len(data))
encoded.extend(data)
- def decode(self, data, offset):
- offset = self.decode_tag(data, offset)
+ def _decode(self, data, offset):
length, offset = decode_length_definite(data, offset)
end_offset = offset + length
decoded = data[offset:end_offset].decode('ascii')
diff --git a/asn1tools/codecs/gser.py b/asn1tools/codecs/gser.py
index 221d347..abb0436 100644
--- a/asn1tools/codecs/gser.py
+++ b/asn1tools/codecs/gser.py
@@ -8,8 +8,10 @@
from copy import copy
import datetime
+from. import BaseType
from . import EncodeError
from . import DecodeError
+from . import add_error_location
from . import compiler
from . import format_or
from . import utc_time_from_datetime
@@ -17,23 +19,14 @@
from .compiler import enum_values_as_dict
-class Type(object):
+class Type(BaseType):
- def __init__(self, name, type_name):
- self.name = name
- self.type_name = type_name
- self.optional = False
- self.default = None
+ def encode(self, data, _separator, _indent):
+ raise NotImplementedError('To be implemented by subclasses.')
def set_size_range(self, minimum, maximum, has_extension_marker):
pass
- def set_default(self, value):
- self.default = value
-
- def has_default(self):
- return self.default is not None
-
class MembersType(Type):
@@ -41,6 +34,7 @@ def __init__(self, name, members, type_name):
super(MembersType, self).__init__(name, type_name)
self.members = members
+ @add_error_location
def encode(self, data, separator, indent):
encoded_members = []
member_separator = separator + ' ' * indent
@@ -49,13 +43,9 @@ def encode(self, data, separator, indent):
name = member.name
if name in data:
- try:
- encoded_member = member.encode(data[name],
- member_separator,
- indent)
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ encoded_member = member.encode(data[name],
+ member_separator,
+ indent)
encoded_member = u'{}{} {}'.format(member_separator,
member.name,
@@ -87,6 +77,7 @@ def __init__(self, name, type_name, element_type):
super(ArrayType, self).__init__(name, type_name)
self.element_type = element_type
+ @add_error_location
def encode(self, data, separator, indent):
encoded_elements = []
element_separator = separator + ' ' * indent
@@ -264,6 +255,7 @@ def __init__(self, name, members):
def format_names(self):
return format_or(sorted([member.name for member in self.members]))
+ @add_error_location
def encode(self, data, separator, indent):
try:
member = self.name_to_member[data[0]]
@@ -273,11 +265,7 @@ def encode(self, data, separator, indent):
self.format_names(),
data[0]))
- try:
- encoded = member.encode(data[1], separator, indent)
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ encoded = member.encode(data[1], separator, indent)
return u'{} : {}'.format(data[0], encoded)
@@ -489,6 +477,7 @@ def __init__(self, name, type_name, module_name):
def set_inner_type(self, inner):
self.inner = copy(inner)
+ @add_error_location
def encode(self, data, separator, indent):
return self.inner.encode(data, separator, indent)
diff --git a/asn1tools/codecs/jer.py b/asn1tools/codecs/jer.py
index 12199f0..aeee609 100644
--- a/asn1tools/codecs/jer.py
+++ b/asn1tools/codecs/jer.py
@@ -9,6 +9,7 @@
import datetime
from ..parser import EXTENSION_MARKER
+from . import BaseType
from . import EncodeError
from . import DecodeError
from . import compiler
@@ -17,29 +18,15 @@
from . import utc_time_from_datetime
from . import generalized_time_to_datetime
from . import generalized_time_from_datetime
+from . import add_error_location
from .compiler import enum_values_as_dict
-class Type(object):
-
- def __init__(self, name, type_name):
- self.name = name
- self.type_name = type_name
- self.optional = False
- self.default = None
+class Type(BaseType):
def set_size_range(self, minimum, maximum, has_extension_marker):
pass
- def set_default(self, value):
- self.default = value
-
- def get_default(self):
- return self.default
-
- def has_default(self):
- return self.default is not None
-
class StringType(Type):
@@ -67,6 +54,7 @@ def __init__(self,
super(MembersType, self).__init__(name, type_name)
self.members = members
+ @add_error_location
def encode(self, data):
values = {}
@@ -74,11 +62,7 @@ def encode(self, data):
name = member.name
if name in data:
- try:
- value = member.encode(data[name])
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ value = member.encode(data[name])
elif member.optional or member.has_default():
continue
else:
@@ -92,6 +76,7 @@ def encode(self, data):
return values
+ @add_error_location
def decode(self, data):
values = {}
@@ -271,6 +256,7 @@ def __init__(self, name, values, numeric):
def format_values(self):
return format_or(sorted(list(self.values)))
+ @add_error_location
def encode(self, data):
try:
value = self.values[data]
@@ -282,6 +268,7 @@ def encode(self, data):
return value
+ @add_error_location
def decode(self, data):
if data in self.values:
return self.values[data]
@@ -309,6 +296,7 @@ def __init__(self, name, element_type):
super(SequenceOf, self).__init__(name, 'SEQUENCE OF')
self.element_type = element_type
+ @add_error_location
def encode(self, data):
values = []
@@ -318,6 +306,7 @@ def encode(self, data):
return values
+ @add_error_location
def decode(self, data):
values = []
@@ -344,6 +333,7 @@ def __init__(self, name, element_type):
super(SetOf, self).__init__(name, 'SET OF')
self.element_type = element_type
+ @add_error_location
def encode(self, data):
values = []
@@ -353,6 +343,7 @@ def encode(self, data):
return values
+ @add_error_location
def decode(self, data):
values = []
@@ -378,6 +369,7 @@ def __init__(self, name, members, has_extension_marker):
def format_names(self):
return format_or(sorted([member.name for member in self.members]))
+ @add_error_location
def encode(self, data):
try:
member = self.name_to_member[data[0]]
@@ -387,12 +379,9 @@ def encode(self, data):
self.format_names(),
data[0]))
- try:
- return {member.name: member.encode(data[1])}
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ return {member.name: member.encode(data[1])}
+ @add_error_location
def decode(self, data):
name, value = list(data.items())[0]
@@ -529,9 +518,11 @@ def __init__(self, name, type_name, module_name):
def set_inner_type(self, inner):
self._inner = inner
+ @add_error_location
def encode(self, data):
return self._inner.encode(data)
+ @add_error_location
def decode(self, data):
return self._inner.decode(data)
diff --git a/asn1tools/codecs/oer.py b/asn1tools/codecs/oer.py
index 9b1b7fd..5e51b1e 100644
--- a/asn1tools/codecs/oer.py
+++ b/asn1tools/codecs/oer.py
@@ -9,6 +9,7 @@
import datetime
from ..parser import EXTENSION_MARKER
+from . import BaseType
from . import EncodeError
from . import DecodeError
from . import OutOfDataError
@@ -18,6 +19,7 @@
from . import utc_time_from_datetime
from . import generalized_time_to_datetime
from . import generalized_time_from_datetime
+from . import add_error_location
from .compiler import enum_values_as_dict
from .ber import Class
from .ber import Tag
@@ -289,11 +291,10 @@ def read_tag(self):
return bytes(tag)
-class Type(object):
+class Type(BaseType):
def __init__(self, name, type_name, number, flags=0):
- self.name = name
- self.type_name = type_name
+ super().__init__(name, type_name)
self.module_name = None
if number is None:
@@ -301,9 +302,6 @@ def __init__(self, name, type_name, number, flags=0):
else:
self.tag = encode_tag(number, flags)
- self.optional = False
- self.default = None
-
def set_tag(self, number, flags):
if not Class.APPLICATION & flags:
flags |= Class.CONTEXT_SPECIFIC
@@ -316,18 +314,6 @@ def set_size_range(self, minimum, maximum, has_extension_marker):
def set_restricted_to_range(self, minimum, maximum, has_extension_marker):
pass
- def set_default(self, value):
- self.default = value
-
- def get_default(self):
- return self.default
-
- def is_default(self, value):
- return value == self.default
-
- def has_default(self):
- return self.default is not None
-
class KnownMultiplierStringType(Type):
@@ -349,6 +335,7 @@ def __init__(self,
if minimum == maximum:
self.number_of_bytes = minimum
+ @add_error_location
def encode(self, data, encoder):
encoded = data.encode(self.ENCODING)
@@ -358,6 +345,7 @@ def encode(self, data, encoder):
else:
encoder.append_bytes(encoded)
+ @add_error_location
def decode(self, decoder):
if self.number_of_bytes is None:
number_of_bytes = decoder.read_length_determinant()
@@ -385,6 +373,7 @@ def __init__(self, name, type_name, tag, root_members, additions):
if member.optional or member.default is not None
]
+ @add_error_location
def encode(self, data, encoder):
if self.additions is not None:
offset = encoder.number_of_bits
@@ -454,14 +443,10 @@ def encode_member(self, member, data, encoder, encode_default=False):
name = member.name
if name in data:
- try:
- if member.default is None:
- member.encode(data[name], encoder)
- elif not member.is_default(data[name]) or encode_default:
- member.encode(data[name], encoder)
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ if member.default is None:
+ member.encode(data[name], encoder)
+ elif not member.is_default(data[name]) or encode_default:
+ member.encode(data[name], encoder)
elif member.optional or member.has_default():
pass
else:
@@ -471,6 +456,7 @@ def encode_member(self, member, data, encoder, encode_default=False):
name,
data))
+ @add_error_location
def decode(self, decoder):
if self.additions is not None:
if decoder.read_bit():
@@ -493,15 +479,11 @@ def decode_root(self, decoder):
decoder.align()
for member in self.root_members:
- try:
- if optionals.get(member, True):
- value = member.decode(decoder)
- values[member.name] = value
- elif member.has_default():
- values[member.name] = member.default
- except DecodeError as e:
- e.location.append(member.name)
- raise
+ if optionals.get(member, True):
+ value = member.decode(decoder)
+ values[member.name] = value
+ elif member.has_default():
+ values[member.name] = member.default
return values
@@ -521,12 +503,7 @@ def decode_additions(self, decoder):
if i < len(self.additions):
addition = self.additions[i]
-
- try:
- decoded[addition.name] = addition.decode(decoder)
- except DecodeError as e:
- e.location.append(addition.name)
- raise
+ decoded[addition.name] = addition.decode(decoder)
else:
decoder.skip_bits(8 * member_length)
@@ -547,12 +524,14 @@ def __init__(self, name, type_name, tag, element_type):
tag)
self.element_type = element_type
+ @add_error_location
def encode(self, data, encoder):
encoder.append_unsigned_integer(len(data))
for entry in data:
self.element_type.encode(entry, encoder)
+ @add_error_location
def decode(self, decoder):
length = decoder.read_unsigned_integer()
decoded = []
@@ -576,9 +555,11 @@ def __init__(self, name):
'BOOLEAN',
Tag.BOOLEAN)
+ @add_error_location
def encode(self, data, encoder):
encoder.append_non_negative_binary_integer(0xff * data, 8)
+ @add_error_location
def decode(self, decoder):
return bool(decoder.read_byte())
@@ -632,6 +613,7 @@ def set_restricted_to_range(self, minimum, maximum, has_extension_marker):
self.length = 8
self.fmt = '>q'
+ @add_error_location
def encode(self, data, encoder):
if self.fmt:
encoder.append_bytes(struct.pack(self.fmt, data))
@@ -640,6 +622,7 @@ def encode(self, data, encoder):
else:
encoder.append_unsigned_integer(data)
+ @add_error_location
def decode(self, decoder):
if self.fmt:
return struct.unpack(self.fmt, decoder.read_bytes(self.length))[0]
@@ -701,6 +684,7 @@ def is_binary64(self, mantissa, base, exponent):
and base == 2
and -1074 <= exponent[0] <= exponent[1] <= 971)
+ @add_error_location
def encode(self, data, encoder):
if self.fmt is None:
encoded = der.encode_real(data)
@@ -715,6 +699,7 @@ def encode(self, data, encoder):
'got {}.'.format(8 * self.length,
data))
+ @add_error_location
def decode(self, decoder):
if self.fmt is None:
length = decoder.read_length_determinant()
@@ -756,6 +741,7 @@ def __init__(self, name, named_bits, minimum, maximum, has_extension_marker):
if minimum == maximum:
self.number_of_bits = minimum
+ @add_error_location
def encode(self, data, encoder):
number_of_bytes, number_of_rest_bits = divmod(data[1], 8)
data = bytearray(data[0])
@@ -779,6 +765,7 @@ def encode(self, data, encoder):
else:
encoder.append_bytes(data)
+ @add_error_location
def decode(self, decoder):
if self.number_of_bits is None:
number_of_bytes = decoder.read_length_determinant()
@@ -810,6 +797,7 @@ def set_size_range(self, minimum, maximum, has_extension_marker):
if minimum == maximum:
self.number_of_bytes = minimum
+ @add_error_location
def encode(self, data, encoder):
if self.number_of_bytes is None:
encoder.append_length_determinant(len(data))
@@ -817,6 +805,7 @@ def encode(self, data, encoder):
else:
encoder.append_bytes(data)
+ @add_error_location
def decode(self, decoder):
if self.number_of_bytes is None:
number_of_bytes = decoder.read_length_determinant()
@@ -836,11 +825,13 @@ def __init__(self, name):
'OBJECT IDENTIFIER',
Tag.OBJECT_IDENTIFIER)
+ @add_error_location
def encode(self, data, encoder):
encoded_subidentifiers = encode_object_identifier(data)
encoder.append_length_determinant(len(encoded_subidentifiers))
encoder.append_bytes(bytearray(encoded_subidentifiers))
+ @add_error_location
def decode(self, decoder):
length = decoder.read_length_determinant()
data = decoder.read_bytes(length)
@@ -873,6 +864,7 @@ def format_names(self):
def format_values(self):
return format_or(sorted(list(self.value_to_data)))
+ @add_error_location
def encode(self, data, encoder):
try:
value = self.data_to_value[data]
@@ -889,6 +881,7 @@ def encode(self, data, encoder):
encoder.append_integer(value)
encoder.set_bit(offset)
+ @add_error_location
def decode(self, decoder):
if decoder.peek_bit():
decoder.clear_bit()
@@ -991,18 +984,19 @@ def format_tags(self):
def format_names(self):
return format_or(sorted([member.name for member in self.members]))
+ @add_error_location
def encode(self, data, encoder):
name = data[0]
if name in self.name_to_root_member:
member = self.name_to_root_member[name]
encoder.append_bytes(member.tag)
- self.encode_member(member, data[1], encoder)
+ member.encode(data[1], encoder)
elif name in self.name_to_addition:
member = self.name_to_addition[name]
encoder.append_bytes(member.tag)
addition_encoder = Encoder()
- self.encode_member(member, data[1], addition_encoder)
+ member.encode(data[1], addition_encoder)
encoder.append_length_determinant(addition_encoder.number_of_bytes())
encoder += addition_encoder
else:
@@ -1011,13 +1005,14 @@ def encode(self, data, encoder):
self.format_names(),
data[0]))
- def encode_member(self, member, data, encoder):
- try:
- member.encode(data, encoder)
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ # def encode_member(self, member, data, encoder):
+ # try:
+ # member.encode(data, encoder)
+ # except EncodeError as e:
+ # e.location.append(member.name)
+ # raise
+ @add_error_location
def decode(self, decoder):
tag = decoder.read_tag()
@@ -1155,6 +1150,7 @@ def __init__(self, name):
[year, month, day],
None)
+ @add_error_location
def encode(self, data, encoder):
data = {
'year': data.year,
@@ -1164,6 +1160,7 @@ def encode(self, data, encoder):
self._inner.encode(data, encoder)
+ @add_error_location
def decode(self, decoder):
decoded = self._inner.decode(decoder)
@@ -1186,6 +1183,7 @@ def __init__(self, name):
[hours, minutes, seconds],
None)
+ @add_error_location
def encode(self, data, encoder):
data = {
'hours': data.hour,
@@ -1195,6 +1193,7 @@ def encode(self, data, encoder):
self._inner.encode(data, encoder)
+ @add_error_location
def decode(self, decoder):
decoded = self._inner.decode(decoder)
@@ -1210,10 +1209,12 @@ def __init__(self, name):
self._date = Date('date')
self._time = TimeOfDay('time')
+ @add_error_location
def encode(self, data, encoder):
self._date.encode(data, encoder)
self._time.encode(data, encoder)
+ @add_error_location
def decode(self, decoder):
decoded_date = self._date.decode(decoder)
decoded_time = self._time.decode(decoder)
@@ -1277,9 +1278,11 @@ def set_inner_type(self, inner):
if self.tag_number is not None:
self.inner.set_tag(self.tag_number, self.tag_flags)
+ @add_error_location
def encode(self, data, encoder):
self.inner.encode(data, encoder)
+ @add_error_location
def decode(self, decoder):
return self.inner.decode(decoder)
diff --git a/asn1tools/codecs/per.py b/asn1tools/codecs/per.py
index 82f413e..c2e7ef0 100644
--- a/asn1tools/codecs/per.py
+++ b/asn1tools/codecs/per.py
@@ -9,6 +9,7 @@
import datetime
from ..parser import EXTENSION_MARKER
+from . import BaseType
from . import EncodeError
from . import DecodeError
from . import OutOfDataError
@@ -18,6 +19,7 @@
from . import restricted_utc_time_from_datetime
from . import restricted_generalized_time_to_datetime
from . import restricted_generalized_time_from_datetime
+from . import add_error_location
from .compiler import enum_values_split
from .compiler import enum_values_as_dict
from .compiler import clean_bit_string_value
@@ -538,14 +540,11 @@ def read_unconstrained_whole_number(self):
return decoded
-class Type(object):
+class Type(BaseType):
def __init__(self, name, type_name):
- self.name = name
- self.type_name = type_name
+ super().__init__(name, type_name)
self.module_name = None
- self.optional = False
- self.default = None
self.tag = None
def set_size_range(self, minimum, maximum, has_extension_marker):
@@ -554,18 +553,6 @@ def set_size_range(self, minimum, maximum, has_extension_marker):
def set_restricted_to_range(self, minimum, maximum, has_extension_marker):
pass
- def set_default(self, value):
- self.default = value
-
- def get_default(self):
- return self.default
-
- def is_default(self, value):
- return value == self.default
-
- def has_default(self):
- return self.default is not None
-
class KnownMultiplierStringType(Type):
@@ -603,6 +590,7 @@ def set_size_range(self, minimum, maximum, has_extension_marker):
size = maximum - minimum
self.number_of_bits = integer_as_number_of_bits(size)
+ @add_error_location
def encode(self, data, encoder):
if self.has_extension_marker:
@@ -641,6 +629,7 @@ def encode_unbound(self, data, encoder):
to_int(entry.encode(self.ENCODING))),
self.bits_per_character)
+ @add_error_location
def decode(self, decoder):
if self.has_extension_marker:
bit = decoder.read_bit()
@@ -702,6 +691,7 @@ class StringType(Type):
def __init__(self, name):
super(StringType, self).__init__(name, self.__class__.__name__)
+ @add_error_location
def encode(self, data, encoder):
encoded = data.encode(self.ENCODING)
encoder.align()
@@ -711,6 +701,7 @@ def encode(self, data, encoder):
data = encoded[offset:offset + self.LENGTH_MULTIPLIER * length]
encoder.append_bytes(data)
+ @add_error_location
def decode(self, decoder):
decoder.align()
encoded = []
@@ -741,6 +732,7 @@ def __init__(self,
if member.optional or member.default is not None
]
+ @add_error_location
def encode(self, data, encoder):
if self.additions is not None:
offset = encoder.offset()
@@ -824,14 +816,10 @@ def encode_member(self, member, data, encoder, encode_default=False):
name = member.name
if name in data:
- try:
- if member.default is None:
- member.encode(data[name], encoder)
- elif not member.is_default(data[name]) or encode_default:
- member.encode(data[name], encoder)
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ if member.default is None:
+ member.encode(data[name], encoder)
+ elif not member.is_default(data[name]) or encode_default:
+ member.encode(data[name], encoder)
elif member.optional or member.default is not None:
pass
else:
@@ -841,6 +829,7 @@ def encode_member(self, member, data, encoder, encode_default=False):
name,
data))
+ @add_error_location
def decode(self, decoder):
if self.additions is not None:
if decoder.read_bit():
@@ -861,15 +850,11 @@ def decode_root(self, decoder):
}
for member in self.root_members:
- try:
- if optionals.get(member, True):
- value = member.decode(decoder)
- values[member.name] = value
- elif member.has_default():
- values[member.name] = member.default
- except DecodeError as e:
- e.location.append(member.name)
- raise
+ if optionals.get(member, True):
+ value = member.decode(decoder)
+ values[member.name] = value
+ elif member.has_default():
+ values[member.name] = member.default
return values
@@ -892,11 +877,7 @@ def decode_additions(self, decoder):
if isinstance(addition, AdditionGroup):
decoded.update(addition.decode(decoder))
else:
- try:
- decoded[addition.name] = addition.decode(decoder)
- except DecodeError as e:
- e.location.append(addition.name)
- raise
+ decoded[addition.name] = addition.decode(decoder)
else:
decoder.skip_bits(8 * open_type_length)
@@ -935,6 +916,7 @@ def __init__(self,
size = maximum - minimum
self.number_of_bits = integer_as_number_of_bits(size)
+ @add_error_location
def encode(self, data, encoder):
if self.has_extension_marker:
if self.minimum <= len(data) <= self.maximum:
@@ -967,6 +949,7 @@ def encode_unbound(self, data, encoder):
for entry in data[offset:offset + length]:
self.element_type.encode(entry, encoder)
+ @add_error_location
def decode(self, decoder):
length = None
@@ -1018,9 +1001,11 @@ class Boolean(Type):
def __init__(self, name):
super(Boolean, self).__init__(name, 'BOOLEAN')
+ @add_error_location
def encode(self, data, encoder):
encoder.append_bit(bool(data))
+ @add_error_location
def decode(self, decoder):
return bool(decoder.read_bit())
@@ -1055,6 +1040,7 @@ def set_restricted_to_range(self, minimum, maximum, has_extension_marker):
number_of_bits = ((self.number_of_bits + 7) // 8 - 1).bit_length()
self.number_of_indefinite_bits = number_of_bits
+ @add_error_location
def encode(self, data, encoder):
if self.has_extension_marker:
if self.minimum <= data <= self.maximum:
@@ -1086,6 +1072,7 @@ def encode(self, data, encoder):
self.maximum,
number_of_bits)
+ @add_error_location
def decode(self, decoder):
if self.has_extension_marker:
if decoder.read_bit():
@@ -1122,12 +1109,14 @@ class Real(Type):
def __init__(self, name):
super(Real, self).__init__(name, 'REAL')
+ @add_error_location
def encode(self, data, encoder):
encoded = encode_real(data)
encoder.align()
encoder.append_length_determinant(len(encoded))
encoder.append_bytes(encoded)
+ @add_error_location
def decode(self, decoder):
decoder.align()
length = decoder.read_length_determinant()
@@ -1143,9 +1132,11 @@ class Null(Type):
def __init__(self, name):
super(Null, self).__init__(name, 'NULL')
+ @add_error_location
def encode(self, _, _encoder):
pass
+ @add_error_location
def decode(self, _):
return None
@@ -1193,6 +1184,7 @@ def rstrip_zeros(self, data, number_of_bits):
return (data, number_of_bits)
+ @add_error_location
def encode(self, data, encoder):
data, number_of_bits = data
@@ -1225,6 +1217,7 @@ def encode_unbound(self, data, number_of_bits, encoder):
for offset, length in encoder.append_length_determinant_chunks(number_of_bits):
encoder.append_bits(data[offset // 8:(offset + length + 7) // 8], length)
+ @add_error_location
def decode(self, decoder):
if self.has_extension_marker:
if decoder.read_bit():
@@ -1285,6 +1278,7 @@ def set_size_range(self, minimum, maximum, has_extension_marker):
else:
self.number_of_bits = integer_as_number_of_bits(size)
+ @add_error_location
def encode(self, data, encoder):
align = True
@@ -1321,6 +1315,7 @@ def encode_unbound(self, data, encoder):
encoder.align()
encoder.append_bytes(data[offset:offset + length])
+ @add_error_location
def decode(self, decoder):
align = True
@@ -1370,12 +1365,14 @@ class ObjectIdentifier(Type):
def __init__(self, name):
super(ObjectIdentifier, self).__init__(name, 'OBJECT IDENTIFIER')
+ @add_error_location
def encode(self, data, encoder):
encoded_subidentifiers = encode_object_identifier(data)
encoder.align()
encoder.append_length_determinant(len(encoded_subidentifiers))
encoder.append_bytes(bytearray(encoded_subidentifiers))
+ @add_error_location
def decode(self, decoder):
decoder.align()
length = decoder.read_length_determinant()
@@ -1439,6 +1436,7 @@ def create_maps(self, items, numeric):
def format_root_indexes(self):
return format_or(sorted(list(self.root_index_to_data)))
+ @add_error_location
def encode(self, data, encoder):
if self.additions_index_to_data is None:
index = self.root_data_to_index[data]
@@ -1455,6 +1453,7 @@ def encode(self, data, encoder):
index = self.additions_data_to_index[data]
encoder.append_normally_small_non_negative_whole_number(index)
+ @add_error_location
def decode(self, decoder):
if self.additions_index_to_data is None:
return self.decode_root(decoder)
@@ -1595,6 +1594,7 @@ def format_names(self):
return format_or(sorted([member.name for member in members]))
+ @add_error_location
def encode(self, data, encoder):
if self.additions_index_to_member is not None:
if data[0] in self.root_name_to_index:
@@ -1619,7 +1619,7 @@ def encode_root(self, data, encoder):
self.encode_root_index(index, encoder)
member = self.root_index_to_member[index]
- self.encode_member(member, data[1], encoder)
+ member.encode(data[1], encoder)
def encode_root_index(self, index, encoder):
if self.number_of_indefinite_bits is None:
@@ -1650,7 +1650,7 @@ def encode_additions(self, data, encoder):
addition_encoder = encoder.__class__()
addition = self.additions_index_to_member[index]
- self.encode_member(addition, data[1], addition_encoder)
+ addition.encode(data[1], addition_encoder)
# Embed encoded extension addition in an open type (add a
# length field and multiple of 8 bits).
@@ -1660,13 +1660,7 @@ def encode_additions(self, data, encoder):
encoder.append_length_determinant(addition_encoder.number_of_bytes())
encoder += addition_encoder
- def encode_member(self, member, data, encoder):
- try:
- member.encode(data, encoder)
- except EncodeError as e:
- e.location.append(member.name)
- raise
-
+ @add_error_location
def decode(self, decoder):
if self.additions_index_to_member is not None:
if decoder.read_bit():
@@ -1745,6 +1739,7 @@ class UTF8String(Type):
def __init__(self, name):
super(UTF8String, self).__init__(name, 'UTF8String')
+ @add_error_location
def encode(self, data, encoder):
encoded = data.encode('utf-8')
encoder.align()
@@ -1752,6 +1747,7 @@ def encode(self, data, encoder):
for offset, length in encoder.append_length_determinant_chunks(len(encoded)):
encoder.append_bytes(encoded[offset:offset + length])
+ @add_error_location
def decode(self, decoder):
decoder.align()
encoded = []
@@ -1882,6 +1878,7 @@ def __init__(self, name):
[year, month, day],
None)
+ @add_error_location
def encode(self, data, encoder):
if 2005 <= data.year <= 2020:
choice = 'immediate'
@@ -1900,6 +1897,7 @@ def encode(self, data, encoder):
return self._inner.encode(data, encoder)
+ @add_error_location
def decode(self, decoder):
decoded = self._inner.decode(decoder)
@@ -1922,6 +1920,7 @@ def __init__(self, name):
[hours, minutes, seconds],
None)
+ @add_error_location
def encode(self, data, encoder):
data = {
'hours': data.hour,
@@ -1931,6 +1930,7 @@ def encode(self, data, encoder):
return self._inner.encode(data, encoder)
+ @add_error_location
def decode(self, decoder):
decoded = self._inner.decode(decoder)
@@ -1947,6 +1947,7 @@ def __init__(self, name):
[Date('date'), TimeOfDay('time')],
None)
+ @add_error_location
def encode(self, data, encoder):
data = {
'date': data,
@@ -1955,6 +1956,7 @@ def encode(self, data, encoder):
return self._inner.encode(data, encoder)
+ @add_error_location
def decode(self, decoder):
decoded = self._inner.decode(decoder)
@@ -1971,11 +1973,13 @@ class OpenType(Type):
def __init__(self, name):
super(OpenType, self).__init__(name, 'OpenType')
+ @add_error_location
def encode(self, data, encoder):
encoder.align()
encoder.append_length_determinant(len(data))
encoder.append_bytes(data)
+ @add_error_location
def decode(self, decoder):
decoder.align()
length = decoder.read_length_determinant()
@@ -1991,9 +1995,11 @@ class Any(Type):
def __init__(self, name):
super(Any, self).__init__(name, 'ANY')
+ @add_error_location
def encode(self, _, _encoder):
raise NotImplementedError('ANY is not yet implemented.')
+ @add_error_location
def decode(self, _decoder):
raise NotImplementedError('ANY is not yet implemented.')
@@ -2012,9 +2018,11 @@ def __init__(self, name, type_name, module_name):
def set_inner_type(self, inner):
self._inner = inner
+ @add_error_location
def encode(self, data, encoder):
self._inner.encode(data, encoder)
+ @add_error_location
def decode(self, decoder):
return self._inner.decode(decoder)
diff --git a/asn1tools/codecs/type_checker.py b/asn1tools/codecs/type_checker.py
index 5304b53..05b0242 100644
--- a/asn1tools/codecs/type_checker.py
+++ b/asn1tools/codecs/type_checker.py
@@ -6,6 +6,7 @@
import datetime
from copy import copy
+from . import add_error_location
from . import EncodeError
from . import compiler
from . import format_or
@@ -40,6 +41,7 @@ def set_size_range(self, minimum, maximum, has_extension_marker):
def set_default(self, value):
pass
+ @add_error_location
def encode(self, data):
if not isinstance(data, self.TYPE):
raise EncodeError(
@@ -54,6 +56,7 @@ class Boolean(Type):
class Integer(Type):
+ @add_error_location
def encode(self, data):
if sys.version_info[0] > 2:
if not isinstance(data, (int, str)):
@@ -69,6 +72,7 @@ def encode(self, data):
class Float(Type):
+ @add_error_location
def encode(self, data):
if sys.version_info[0] > 2:
if not isinstance(data, (float, int)):
@@ -84,6 +88,7 @@ def encode(self, data):
class Null(Type):
+ @add_error_location
def encode(self, data):
if data is not None:
raise EncodeError('Expected None, but got {}.'.format(data))
@@ -91,6 +96,7 @@ def encode(self, data):
class BitString(Type):
+ @add_error_location
def encode(self, data):
if (not isinstance(data, tuple)
or len(data) != 2
@@ -109,6 +115,7 @@ def encode(self, data):
class Bytes(Type):
+ @add_error_location
def encode(self, data):
if not isinstance(data, (bytes, bytearray)):
raise EncodeError(
@@ -118,6 +125,7 @@ def encode(self, data):
class String(Type):
+ @add_error_location
def encode(self, data):
if sys.version_info[0] > 2:
if not isinstance(data, str):
@@ -139,16 +147,15 @@ def __init__(self, name, members):
def encode(self, data):
super(Dict, self).encode(data)
+ self.encode_members(data)
+ @add_error_location
+ def encode_members(self, data):
for member in self.members:
name = member.name
if name in data:
- try:
- member.encode(data[name])
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ member.encode(data[name])
class List(Type):
@@ -161,7 +168,10 @@ def __init__(self, name, element_type):
def encode(self, data):
super(List, self).encode(data)
+ self.encode_members(data)
+ @add_error_location
+ def encode_members(self, data):
for entry in data:
self.element_type.encode(entry)
@@ -172,6 +182,7 @@ def __init__(self, name, numeric_enums):
super(Enumerated, self).__init__(name)
self._numeric_enums = numeric_enums
+ @add_error_location
def encode(self, data):
if self._numeric_enums:
self.encode_integer(data)
@@ -211,6 +222,7 @@ def __init__(self, name, members):
def format_names(self):
return format_or(sorted([member.name for member in self.members]))
+ @add_error_location
def encode(self, data):
if sys.version_info[0] > 2:
if (not isinstance(data, tuple)
@@ -235,15 +247,12 @@ def encode(self, data):
self.format_names(),
data[0]))
- try:
- member.encode(data[1])
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ member.encode(data[1])
class Date(Type):
+ @add_error_location
def encode(self, data):
if not isinstance(data, datetime.date):
raise EncodeError(
@@ -253,6 +262,7 @@ def encode(self, data):
class TimeOfDay(Type):
+ @add_error_location
def encode(self, data):
if not isinstance(data, datetime.time):
raise EncodeError(
@@ -262,6 +272,7 @@ def encode(self, data):
class DateTime(Type):
+ @add_error_location
def encode(self, data):
if not isinstance(data, datetime.datetime):
raise EncodeError(
@@ -286,6 +297,7 @@ def __init__(self, name, type_name, module_name):
def set_inner_type(self, inner):
self.inner = copy(inner)
+ @add_error_location
def encode(self, data):
self.inner.encode(data)
diff --git a/asn1tools/codecs/uper.py b/asn1tools/codecs/uper.py
index ab71047..e744bd7 100644
--- a/asn1tools/codecs/uper.py
+++ b/asn1tools/codecs/uper.py
@@ -8,6 +8,7 @@
from . import restricted_utc_time_from_datetime
from . import restricted_generalized_time_to_datetime
from . import restricted_generalized_time_from_datetime
+from . import add_error_location
from .per import to_int
from .per import to_byte_array
from .per import integer_as_number_of_bits
@@ -69,6 +70,7 @@ def __init__(self,
self.bits_per_character = integer_as_number_of_bits(
len(permitted_alphabet) - 1)
+ @add_error_location
def encode(self, data, encoder):
if self.has_extension_marker:
encoder.append_bit(0)
@@ -85,6 +87,7 @@ def encode(self, data, encoder):
to_int(value.encode(self.ENCODING))),
self.bits_per_character)
+ @add_error_location
def decode(self, decoder):
if self.has_extension_marker:
bit = decoder.read_bit()
@@ -113,6 +116,7 @@ def decode(self, decoder):
class ArrayType(per.ArrayType):
+ @add_error_location
def encode(self, data, encoder):
if self.has_extension_marker:
if self.minimum <= len(data) <= self.maximum:
@@ -135,6 +139,7 @@ def encode(self, data, encoder):
for entry in data:
self.element_type.encode(entry, encoder)
+ @add_error_location
def decode(self, decoder):
length = None
@@ -184,6 +189,7 @@ def set_restricted_to_range(self, minimum, maximum, has_extension_marker):
size = self.maximum - self.minimum
self.number_of_bits = integer_as_number_of_bits(size)
+ @add_error_location
def encode(self, data, encoder):
if self.has_extension_marker:
if self.minimum <= data <= self.maximum:
@@ -199,6 +205,7 @@ def encode(self, data, encoder):
encoder.append_non_negative_binary_integer(data - self.minimum,
self.number_of_bits)
+ @add_error_location
def decode(self, decoder):
if self.has_extension_marker:
if decoder.read_bit():
@@ -217,6 +224,7 @@ def __repr__(self):
class BitString(per.BitString):
+ @add_error_location
def encode(self, data, encoder):
data, number_of_bits = data
@@ -239,6 +247,7 @@ def encode(self, data, encoder):
encoder.append_bits(data, number_of_bits)
+ @add_error_location
def decode(self, decoder):
if self.has_extension_marker:
if decoder.read_bit():
@@ -261,6 +270,7 @@ def decode(self, decoder):
class OctetString(per.OctetString):
+ @add_error_location
def encode(self, data, encoder):
if self.has_extension_marker:
if self.minimum <= len(data) <= self.maximum:
@@ -281,6 +291,7 @@ def encode(self, data, encoder):
encoder.append_bytes(data)
+ @add_error_location
def decode(self, decoder):
if self.has_extension_marker:
bit = decoder.read_bit()
diff --git a/asn1tools/codecs/xer.py b/asn1tools/codecs/xer.py
index abccc34..78b4a6f 100644
--- a/asn1tools/codecs/xer.py
+++ b/asn1tools/codecs/xer.py
@@ -9,8 +9,10 @@
import datetime
from ..parser import EXTENSION_MARKER
+from . import BaseType
from . import EncodeError
from . import DecodeError
+from . import add_error_location
from . import compiler
from . import format_or
from . import utc_time_to_datetime
@@ -40,36 +42,20 @@ def indent_xml(element, indent, level=0):
element.tail = i
-class Type(object):
+class Type(BaseType):
def __init__(self, name, type_name):
- self.name = name.replace(' ', '_')
- self.type_name = type_name
- self.optional = False
- self.default = None
+ super().__init__(name.replace(' ', '_'), type_name)
def set_size_range(self, minimum, maximum, has_extension_marker):
pass
- def set_default(self, value):
- self.default = value
-
- def get_default(self):
- return self.default
-
- def has_default(self):
- return self.default is not None
-
- def encode(self, data):
- raise NotImplementedError('To be implemented by subclasses.')
-
def encode_of(self, data):
+ # Used by ArrayType
return self.encode(data)
- def decode(self, element):
- raise NotImplementedError('To be implemented by subclasses.')
-
def decode_of(self, element):
+ # Used by ArrayType
return self.decode(element)
@@ -109,6 +95,7 @@ def __init__(self, name, members, type_name):
super(MembersType, self).__init__(name, type_name)
self.members = members
+ @add_error_location
def encode(self, data):
element = ElementTree.Element(self.name)
@@ -116,11 +103,7 @@ def encode(self, data):
name = member.name
if name in data:
- try:
- member_element = member.encode(data[name])
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ member_element = member.encode(data[name])
elif member.optional or member.has_default():
continue
else:
@@ -134,6 +117,7 @@ def encode(self, data):
return element
+ @add_error_location
def decode(self, element):
values = {}
@@ -164,6 +148,7 @@ def __init__(self, name, element_type, type_name):
super(ArrayType, self).__init__(name, type_name)
self.element_type = element_type
+ @add_error_location
def encode(self, data):
element = ElementTree.Element(self.name)
@@ -172,6 +157,7 @@ def encode(self, data):
return element
+ @add_error_location
def decode(self, element):
values = []
@@ -335,6 +321,7 @@ class ObjectIdentifier(StringType):
def __init__(self, name):
super(ObjectIdentifier, self).__init__(name, 'OBJECT IDENTIFIER')
+ @add_error_location
def decode(self, element):
if element.text is None:
raise DecodeError("Expected an OBJECT IDENTIFIER, but got ''.")
@@ -364,6 +351,7 @@ def format_names(self):
def format_values(self):
return format_or(sorted(list(self.value_to_data)))
+ @add_error_location
def encode(self, data):
try:
value = self.data_to_value[data]
@@ -378,6 +366,7 @@ def encode(self, data):
return element
+ @add_error_location
def decode(self, element):
value = element[0].tag
@@ -391,6 +380,7 @@ def decode(self, element):
self.format_values(),
value))
+ @add_error_location
def encode_of(self, data):
try:
value = self.data_to_value[data]
@@ -402,6 +392,7 @@ def encode_of(self, data):
return ElementTree.Element(value)
+ @add_error_location
def decode_of(self, element):
value = element.tag
@@ -456,6 +447,7 @@ def __init__(self, name, members, has_extension_marker):
def format_names(self):
return format_or(sorted([member.name for member in self.members]))
+ @add_error_location
def encode(self, data):
try:
member = self.name_to_member[data[0]]
@@ -467,14 +459,11 @@ def encode(self, data):
element = ElementTree.Element(self.name)
- try:
- element.append(member.encode(data[1]))
- except EncodeError as e:
- e.location.append(member.name)
- raise
+ element.append(member.encode(data[1]))
return element
+ @add_error_location
def decode(self, element):
member_element = element[0]
name = member_element.tag
@@ -495,10 +484,12 @@ def encode_of(self, data):
try:
member = self.name_to_member[data[0]]
except KeyError:
- raise EncodeError(
+ e = EncodeError(
"Expected choice {}, but got '{}'.".format(
self.format_names(),
data[0]))
+ # e.add_location(self.name)
+ raise e
return member.encode(data[1])
@@ -508,10 +499,12 @@ def decode_of(self, element):
try:
member = self.name_to_member[name]
except KeyError:
- raise DecodeError(
+ e = DecodeError(
"Expected choice {}, but got '{}'.".format(
self.format_names(),
name))
+ # e.add_location(self.name)
+ raise e
return (name, member.decode(element))
@@ -664,12 +657,14 @@ def __init__(self, name, type_name, module_name):
def set_inner_type(self, inner):
self._inner = inner
+ @add_error_location
def encode(self, data):
encoded = self._inner.encode(data)
encoded.tag = self.name
return encoded
+ @add_error_location
def decode(self, element):
return self._inner.decode(element)
diff --git a/tests/test_ber.py b/tests/test_ber.py
index 47ff996..ff026d6 100644
--- a/tests/test_ber.py
+++ b/tests/test_ber.py
@@ -60,7 +60,7 @@ def test_boolean_explicit_tags(self):
self.assertEqual(
str(cm.exception),
- "Expected ExplicitTag with tag 'a2' at offset 0, but got 'a3'.")
+ "Foo: Expected ExplicitTag with tag 'a2', but got 'a3'. (At offset: 0)")
# Bad tag.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -68,7 +68,7 @@ def test_boolean_explicit_tags(self):
self.assertEqual(
str(cm.exception),
- "Expected BOOLEAN with tag '01' at offset 2, but got '02'.")
+ "Foo: Expected BOOLEAN with tag '01', but got '02'. (At offset: 2)")
def test_boolean_implicit_tags(self):
"""Test implicit tags on booleans.
@@ -203,13 +203,13 @@ def test_real(self):
foo.decode('A', b'\x09\x01\x44')
self.assertEqual(str(cm.exception),
- 'Unsupported special REAL control word 0x44.')
+ 'A: Unsupported special REAL control word 0x44.')
with self.assertRaises(asn1tools.DecodeError) as cm:
foo.decode('A', b'\x09\x02\x82\x00')
self.assertEqual(str(cm.exception),
- 'Unsupported binary REAL control word 0x82.')
+ 'A: Unsupported binary REAL control word 0x82.')
# Decode 100.0 in decimal form (1.e2).
self.assertEqual(foo.decode('A', b'\x09\x05\x03\x31\x2e\x45\x32'),
@@ -420,7 +420,7 @@ def test_enumerated(self):
foo.decode('G', b'\x0a\x01\xff')
self.assertEqual(str(cm.exception),
- "Expected enumeration value 0, but got -1.")
+ "G: Expected enumeration value 0, but got -1. (At offset: 2)")
def test_sequence(self):
foo = asn1tools.compile_string(
@@ -672,14 +672,14 @@ def test_sequence(self):
self.assertEqual(
str(cm.exception),
- 'Could not find end-of-contents tag for indefinite length field.')
+ 'W: Could not find end-of-contents tag for indefinite length field. (At offset: 15)')
# Missing member.
with self.assertRaises(asn1tools.EncodeError) as cm:
foo.encode('C', {})
self.assertEqual(str(cm.exception),
- "Sequence member 'a' not found in {}.")
+ "C: Sequence member 'a' not found in {}.")
def test_sequence_of(self):
foo = asn1tools.compile_string(
@@ -739,7 +739,11 @@ def test_set(self):
self.assertEqual(
str(cm.exception),
- 'a: Could not find end-of-contents tag for indefinite length field.')
+ 'C.a: Could not find end-of-contents tag for indefinite length field. (At offset: 10)')
+
+ # Test data encoded in different field order
+ self.assertEqual(foo.decode('A', b'\x31\x06\x81\x01\x04\x80\x01\x03'), {'a': 3, 'b': 4})
+ self.assertEqual(foo.decode('A', b'\x31\x80\x81\x01\x00\x80\x01\x03\x00\x00'), {'a': 3, 'b': 0})
def test_choice(self):
foo = asn1tools.compile_string(
@@ -890,7 +894,7 @@ def test_choice(self):
('K', ('m31', None), b'\x9e\x00'),
('K', ('m32', None), b'\x9f\x1f\x00'),
('K', ('m33', None), b'\x9f\x20\x00'),
- ('M', ('a', ('b', True)), b'\xa0\x03\x80\x01\xff')
+ ('M', ('a', ('b', True)), b'\xa0\x03\x80\x01\xff'),
]
for type_name, decoded, encoded in datas:
@@ -904,7 +908,7 @@ def test_choice(self):
self.assertEqual(
str(cm.exception),
- "Expected choice member tag '80', but got '81'.")
+ "A: Expected choice member tag '80', but got '81'. (At offset: 0)")
# Test indefinite-length choice
self.assertEqual(foo.decode('M', b'\xa0\x80\x80\x01\xff\x00\x00'), ('a', ('b', True)))
@@ -945,6 +949,10 @@ def test_choice_implicit_tags(self):
" b INTEGER "
" } "
"} "
+ "N ::= CHOICE { "
+ " a [1] INTEGER, "
+ " b [2] INTEGER "
+ "} "
"END")
datas = [
@@ -958,7 +966,9 @@ def test_choice_implicit_tags(self):
('I', ('a', True), b'\x66\x03\x01\x01\xff'),
('J', ('a', True), b'\xa6\x03\x01\x01\xff'),
('K', ('a', ('a', True)), b'\xa3\x05\xa4\x03\x01\x01\xff'),
- ('K', ('b', ('b', 2)), b'\xa3\x05\xa5\x03\x02\x01\x02')
+ ('K', ('b', ('b', 2)), b'\xa3\x05\xa5\x03\x02\x01\x02'),
+ ('N', ('a', 5), b'\x81\x01\x05'),
+ ('N', ('b', 6), b'\x82\x01\x06'),
]
for type_name, decoded, encoded in datas:
@@ -969,6 +979,10 @@ def test_choice_implicit_tags(self):
# Test indefinite length
self.assertEqual(foo.decode('K', b'\xa3\x80\xa4\x80\x01\x01\x00\x00\x00\x00\x00'), ('a', ('a', False)))
+ # Choice decode fail
+ with self.assertRaises(asn1tools.DecodeError) as cm:
+ foo.decode('N', b'\xa1\x01\x05')
+
def test_utf8_string(self):
foo = asn1tools.compile_string(
"Foo DEFINITIONS AUTOMATIC TAGS ::= "
@@ -1187,7 +1201,7 @@ def test_complex(self):
self.assertEqual(
str(cm.exception),
- "enumerated: Expected enumeration value 'one' or 'two', but got "
+ "AllUniversalTypes.enumerated: Expected enumeration value 'one' or 'two', but got "
"'three'.")
def test_rrc_8_6_0(self):
@@ -1871,7 +1885,7 @@ def test_rfc1157(self):
self.assertEqual(
str(cm.exception),
- "data: set-request: variable-bindings: value: Expected choice "
+ "Message.data.set-request.variable-bindings.value: Expected choice "
"'application-wide' or 'simple', but got ''.")
def test_performance(self):
@@ -2396,7 +2410,7 @@ def test_rfc5280_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected SEQUENCE with tag '30' at offset 0, but got ''.")
+ "Certificate: Expected SEQUENCE with tag '30', but got ''. (At offset: 0)")
# Only tag and length, no contents.
encoded = b'\x30\x81\x9f'
@@ -2406,7 +2420,7 @@ def test_rfc5280_errors(self):
self.assertEqual(
str(cm.exception),
- 'Expected at least 159 contents byte(s) at offset 3, but got 0.')
+ 'Certificate: Expected at least 159 contents byte(s), but got 0. (At offset: 3)')
# Unexpected tag 'ff'.
encoded = b'\xff\x01\x00'
@@ -2416,7 +2430,7 @@ def test_rfc5280_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected SEQUENCE with tag '30' at offset 0, but got 'ff'.")
+ "Certificate: Expected SEQUENCE with tag '30', but got 'ff'. (At offset: 0)")
# Unexpected type '31' embedded in the data.
encoded = bytearray(
@@ -2464,8 +2478,8 @@ def test_rfc5280_errors(self):
rfc5280.decode('Certificate', encoded)
self.assertEqual(str(cm.exception),
- "tbsCertificate: issuer: Expected AttributeTypeAndValue "
- "with tag '30' at offset 150, but got '31'.")
+ "Certificate.tbsCertificate.issuer.rdnSequence: Expected AttributeTypeAndValue "
+ "with tag '30', but got '31'. (At offset: 150)")
def test_all_types(self):
all_types = asn1tools.compile_files('tests/files/all_types.asn')
@@ -2603,14 +2617,14 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected BOOLEAN with tag '01' at offset 0, but got 'ff'.")
+ "Boolean: Expected BOOLEAN with tag '01', but got 'ff'. (At offset: 0)")
with self.assertRaises(asn1tools.DecodeError) as cm:
all_types.decode('Boolean', b'\x01\x02\x01\x01')
self.assertEqual(
str(cm.exception),
- "Expected BOOLEAN contents length 1 at offset 1, but got 2.")
+ "Boolean: Expected BOOLEAN contents length 1, but got 2. (At offset: 1)")
# INTEGER.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2618,7 +2632,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected INTEGER with tag '02' at offset 0, but got 'fe'.")
+ "Integer: Expected INTEGER with tag '02', but got 'fe'. (At offset: 0)")
# BIT STRING.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2626,7 +2640,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected BIT STRING with tag '03' at offset 0, but got 'fd'.")
+ "Bitstring: Expected BIT STRING with tag '03', but got 'fd'. (At offset: 0)")
# OCTET STRING.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2634,7 +2648,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected OCTET STRING with tag '04' at offset 0, but got 'fc'.")
+ "Octetstring: Expected OCTET STRING with tag '04', but got 'fc'. (At offset: 0)")
# NULL.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2642,7 +2656,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected NULL with tag '05' at offset 0, but got 'fb'.")
+ "Null: Expected NULL with tag '05', but got 'fb'. (At offset: 0)")
# OBJECT IDENTIFIER.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2650,8 +2664,8 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected OBJECT IDENTIFIER with tag '06' at offset 0, "
- "but got 'fa'.")
+ "Objectidentifier: Expected OBJECT IDENTIFIER with tag '06', "
+ "but got 'fa'. (At offset: 0)")
# ENUMERATED.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2659,7 +2673,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected ENUMERATED with tag '0a' at offset 0, but got 'f9'.")
+ "Enumerated: Expected ENUMERATED with tag '0a', but got 'f9'. (At offset: 0)")
# UTF8String.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2667,7 +2681,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected UTF8String with tag '0c' at offset 0, but got 'f8'.")
+ "Utf8string: Expected UTF8String with tag '0c', but got 'f8'. (At offset: 0)")
# SEQUENCE.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2675,30 +2689,30 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected SEQUENCE with tag '30' at offset 0, but got 'f7'.")
+ "Sequence: Expected SEQUENCE with tag '30', but got 'f7'. (At offset: 0)")
# SET.
with self.assertRaises(asn1tools.DecodeError) as cm:
all_types.decode('Set', b'\xf6')
self.assertEqual(str(cm.exception),
- "Expected SET with tag '31' at offset 0, but got 'f6'.")
+ "Set: Expected SET with tag '31', but got 'f6'. (At offset: 0)")
# NumericString.
with self.assertRaises(asn1tools.DecodeError) as cm:
all_types.decode('Numericstring', b'\xf5')
self.assertEqual(str(cm.exception),
- "Expected NumericString with tag '12' at offset 0, "
- "but got 'f5'.")
+ "Numericstring: Expected NumericString with tag '12', "
+ "but got 'f5'. (At offset: 0)")
# PrintableString.
with self.assertRaises(asn1tools.DecodeError) as cm:
all_types.decode('Printablestring', b'\xf4')
self.assertEqual(str(cm.exception),
- "Expected PrintableString with tag '13' at offset 0, "
- "but got 'f4'.")
+ "Printablestring: Expected PrintableString with tag '13', "
+ "but got 'f4'. (At offset: 0)")
# IA5String.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2706,7 +2720,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected IA5String with tag '16' at offset 0, but got 'f3'.")
+ "Ia5string: Expected IA5String with tag '16', but got 'f3'. (At offset: 0)")
# UniversalString.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2714,7 +2728,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected UniversalString with tag '1c' at offset 0, but got 'f2'.")
+ "Universalstring: Expected UniversalString with tag '1c', but got 'f2'. (At offset: 0)")
# VisibleString.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2722,7 +2736,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected VisibleString with tag '1a' at offset 0, but got 'f1'.")
+ "Visiblestring: Expected VisibleString with tag '1a', but got 'f1'. (At offset: 0)")
# GeneralString.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2730,7 +2744,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected GeneralString with tag '1b' at offset 0, but got 'f1'.")
+ "Generalstring: Expected GeneralString with tag '1b', but got 'f1'. (At offset: 0)")
# BMPString.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2738,7 +2752,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected BMPString with tag '1e' at offset 0, but got 'f0'.")
+ "Bmpstring: Expected BMPString with tag '1e', but got 'f0'. (At offset: 0)")
# TeletexString.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2746,7 +2760,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected TeletexString with tag '14' at offset 0, but got 'ef'.")
+ "Teletexstring: Expected TeletexString with tag '14', but got 'ef'. (At offset: 0)")
# UTCTime.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2754,7 +2768,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected UTCTime with tag '17' at offset 0, but got 'ee'.")
+ "Utctime: Expected UTCTime with tag '17', but got 'ee'. (At offset: 0)")
# SequenceOf.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2762,7 +2776,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected SEQUENCE OF with tag '30' at offset 0, but got 'ed'.")
+ "SequenceOf: Expected SEQUENCE OF with tag '30', but got 'ed'. (At offset: 0)")
# SetOf.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -2770,7 +2784,7 @@ def test_decode_all_types_errors(self):
self.assertEqual(
str(cm.exception),
- "Expected SET OF with tag '31' at offset 0, but got 'ec'.")
+ "SetOf: Expected SET OF with tag '31', but got 'ec'. (At offset: 0)")
def test_repr_all_types(self):
all_types = asn1tools.compile_files('tests/files/all_types.asn')
@@ -3055,12 +3069,12 @@ def test_any_defined_by_integer(self):
with self.assertRaises(asn1tools.EncodeError) as cm:
foo.encode('Fie', decoded)
- self.assertEqual(str(cm.exception), "fum: Bad AnyDefinedBy choice 2.")
+ self.assertEqual(str(cm.exception), "Fie.fum: Bad AnyDefinedBy choice 2.")
with self.assertRaises(asn1tools.DecodeError) as cm:
decoded = foo.decode('Fie', encoded)
- self.assertEqual(str(cm.exception), "fum: Bad AnyDefinedBy choice 2.")
+ self.assertEqual(str(cm.exception), "Fie.fum: Bad AnyDefinedBy choice 2. (At offset: 5)")
def test_any_defined_by_object_identifier(self):
spec = """
@@ -3117,26 +3131,26 @@ def test_any_defined_by_object_identifier(self):
foo.encode('Fie', decoded)
self.assertEqual(str(cm.exception),
- "fum: Bad AnyDefinedBy choice 1.3.1000.8.")
+ "Fie.fum: Bad AnyDefinedBy choice 1.3.1000.8.")
with self.assertRaises(asn1tools.DecodeError) as cm:
decoded = foo.decode('Fie', encoded)
self.assertEqual(str(cm.exception),
- "fum: Bad AnyDefinedBy choice 1.3.1000.8.")
+ "Fie.fum: Bad AnyDefinedBy choice 1.3.1000.8. (At offset: 8)")
def test_decode_bad_length(self):
foo = asn1tools.compile_files('tests/files/foo.asn')
datas = [
(b'0\x0e\x02\x01\x01\x16\x09Is 1+1=3',
- 'Expected at least 14 contents byte(s) at offset 2, but got 13.'),
+ 'Question: Expected at least 14 contents byte(s), but got 13. (At offset: 2)'),
(b'0\x0f\x02\x01\x01\x16\x09Is 1+1=3?',
- 'Expected at least 15 contents byte(s) at offset 2, but got 14.'),
+ 'Question: Expected at least 15 contents byte(s), but got 14. (At offset: 2)'),
(b'0\x0e\x02\x01\x01\x16\x0aIs 1+1=3?',
- 'question: Expected at least 10 contents byte(s) at offset 7, but got 9.'),
+ 'Question.question: Expected at least 10 contents byte(s), but got 9. (At offset: 7)'),
(b'0\x0e\x02\x02\x01\x16\x09Is 1+1=3?',
- "question: Expected IA5String with tag '16' at offset 6, but got '09'.")
+ "Question.question: Expected IA5String with tag '16', but got '09'. (At offset: 6)")
]
for encoded, message in datas:
@@ -3217,7 +3231,7 @@ def test_decode_indefinite_length_in_primitive_encoding(self):
self.assertEqual(
str(cm.exception),
- 'Expected definite length at offset 1, but got indefinite.')
+ 'A: Expected definite length, but got indefinite. (At offset: 1)')
def test_versions(self):
foo = asn1tools.compile_files('tests/files/versions.asn')
diff --git a/tests/test_codecs_consistency.py b/tests/test_codecs_consistency.py
index 7402b55..a78818a 100644
--- a/tests/test_codecs_consistency.py
+++ b/tests/test_codecs_consistency.py
@@ -322,9 +322,8 @@ def test_error_location(self):
with self.assertRaises(asn1tools.EncodeError) as cm:
foo.encode('A', {'a': {'b': ('c', {})}})
-
self.assertEqual(str(cm.exception),
- "a: b: c: Sequence member 'd' not found in {}.")
+ "A.a.b.c: Sequence member 'd' not found in {}.")
def test_recursive(self):
spec = (
@@ -638,37 +637,37 @@ def test_named_numbers_errors(self):
(
'Constants',
-2,
- 'Expected an integer between -1 and 2, but got -2.'
+ 'Constants: Expected an integer between -1 and 2, but got -2.'
),
(
'Constants',
3,
- 'Expected an integer between -1 and 2, but got 3.'
+ 'Constants: Expected an integer between -1 and 2, but got 3.'
),
(
'A',
-2,
- 'Expected an integer between -1 and 1, but got -2.'
+ 'A: Expected an integer between -1 and 1, but got -2.'
),
(
'A',
2,
- 'Expected an integer between -1 and 1, but got 2.'
+ 'A: Expected an integer between -1 and 1, but got 2.'
),
(
'B',
1,
- 'Expected an integer between 2 and 2, but got 1.'
+ 'B: Expected an integer between 2 and 2, but got 1.'
),
(
'C',
-1,
- 'Expected an integer between 0 and 1, but got -1.'
+ 'C: Expected an integer between 0 and 1, but got -1.'
),
(
'C',
2,
- 'Expected an integer between 0 and 1, but got 2.'
+ 'C: Expected an integer between 0 and 1, but got 2.'
)
]
diff --git a/tests/test_command_line.py b/tests/test_command_line.py
index d2abe14..54e25c4 100644
--- a/tests/test_command_line.py
+++ b/tests/test_command_line.py
@@ -115,7 +115,7 @@ def test_command_line_convert_ber_foo_question_stdin(self):
"\n"
"2018-02-24 11:24:16\n"
"ff0e0201011609497320312b313d333f\n"
- "Expected SEQUENCE with tag '30' at offset 0, but got 'ff'.\n"
+ "Question: Expected SEQUENCE with tag '30', but got 'ff'. (At offset: 0)\n"
"2018-02-24 13:24:16\n"
"300e0201011609497320312b313d333\n"
)
diff --git a/tests/test_constraints_checker.py b/tests/test_constraints_checker.py
index 6b0b147..837d116 100644
--- a/tests/test_constraints_checker.py
+++ b/tests/test_constraints_checker.py
@@ -125,10 +125,10 @@ def test_integer(self):
datas = [
('K',
4,
- 'Expected an integer between 1 and 2, but got 4.'),
+ 'K: Expected an integer between 1 and 2, but got 4.'),
('K',
5,
- 'Expected an integer between 1 and 2, but got 5.')
+ 'K: Expected an integer between 1 and 2, but got 5.')
]
self.assert_encode_decode_bad(foo, datas)
@@ -137,32 +137,32 @@ def test_integer(self):
datas = [
('B',
4,
- 'Expected an integer between 5 and 99, but got 4.'),
+ 'B: Expected an integer between 5 and 99, but got 4.'),
('B',
100,
- 'Expected an integer between 5 and 99, but got 100.'),
+ 'B: Expected an integer between 5 and 99, but got 100.'),
('C',
-11,
- 'Expected an integer between -10 and 10, but got -11.'),
+ 'C: Expected an integer between -10 and 10, but got -11.'),
('C',
11,
- 'Expected an integer between -10 and 10, but got 11.'),
+ 'C: Expected an integer between -10 and 10, but got 11.'),
('E',
0,
- 'Expected an integer between 1000 and 1000, but got 0.'),
+ 'E: Expected an integer between 1000 and 1000, but got 0.'),
('F',
{'a': 4, 'b': 41, 'c': 400},
- 'b: Expected an integer between 40 and 40, but got 41.'),
+ 'F.b: Expected an integer between 40 and 40, but got 41.'),
('H',
11,
- 'Expected an integer between MIN and 10, but got 11.'),
+ 'H: Expected an integer between MIN and 10, but got 11.'),
('I',
9,
- 'Expected an integer between 10 and MAX, but got 9.'),
+ 'I: Expected an integer between 10 and MAX, but got 9.'),
# ToDo: 4..5 are allowed as well.
('K',
3,
- 'Expected an integer between 1 and 2, but got 3.')
+ 'K: Expected an integer between 1 and 2, but got 3.')
]
self.assert_encode_decode_bad(foo, datas)
@@ -221,7 +221,7 @@ def test_bit_string(self):
datas = [
('B',
(b'\x01\x23', 9),
- 'Expected between 10 and 10 bits, but got 9.')
+ 'B: Expected between 10 and 10 bits, but got 9.')
]
self.assert_encode_decode_bad(foo, datas)
@@ -250,10 +250,10 @@ def test_octet_string(self):
datas = [
('B',
11 * b'\x01',
- 'Expected between 10 and 10 bytes, but got 11.'),
+ 'B: Expected between 10 and 10 bytes, but got 11.'),
('D',
9 * b'\x01',
- 'Expected between 10 and MAX bytes, but got 9.')
+ 'D: Expected between 10 and MAX bytes, but got 9.')
]
self.assert_encode_decode_bad(foo, datas)
@@ -316,13 +316,13 @@ def test_sequence_of(self):
datas = [
('A',
[3, 4, 5],
- 'Expected a list of between 2 and 2 elements, but got 3.'),
+ 'A: Expected a list of between 2 and 2 elements, but got 3.'),
('A',
[3, 6],
- 'Expected an integer between 3 and 5, but got 6.'),
+ 'A: Expected an integer between 3 and 5, but got 6.'),
('C',
[3, 4, 5],
- 'Expected a list of between MIN and 2 elements, but got 3.')
+ 'C: Expected a list of between MIN and 2 elements, but got 3.')
]
self.assert_encode_decode_bad(foo, datas)
@@ -345,10 +345,10 @@ def test_numeric_string(self):
datas = [
('A',
'a',
- "Expected a character in ' 0123456789', but got 'a' (0x61)."),
+ "A: Expected a character in ' 0123456789', but got 'a' (0x61)."),
('A',
'-',
- "Expected a character in ' 0123456789', but got '-' (0x2d).")
+ "A: Expected a character in ' 0123456789', but got '-' (0x2d).")
]
self.assert_encode_decode_bad(foo, datas)
@@ -371,7 +371,7 @@ def test_printable_string(self):
datas = [
('A',
'{',
- "Expected a character in '"
+ "A: Expected a character in '"
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
" '()+,-./:=?', but got '{' (0x7b).")
]
@@ -396,7 +396,7 @@ def test_ia5_string(self):
datas = [
('A',
b'\x81'.decode('latin-1'),
- "Expected a character in '................................ !\"#$%"
+ "A: Expected a character in '................................ !\"#$%"
"&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcde"
"fghijklmnopqrstuvwxyz{|}~.', but got '.' (0x81).")
]
@@ -428,13 +428,13 @@ def test_visible_string(self):
datas = [
('B',
'1',
- 'Expected between 2 and 5 characters, but got 1.'),
+ 'B: Expected between 2 and 5 characters, but got 1.'),
('B',
'123456',
- 'Expected between 2 and 5 characters, but got 6.'),
+ 'B: Expected between 2 and 5 characters, but got 6.'),
('C',
'k',
- "Expected a character in 'abcdefghijuvw', but got 'k' (0x6b).")
+ "C: Expected a character in 'abcdefghijuvw', but got 'k' (0x6b).")
]
self.assert_encode_decode_bad(foo, datas)
@@ -460,10 +460,10 @@ def test_utf8_string(self):
datas = [
('B',
'1',
- 'Expected between 2 and 5 characters, but got 1.'),
+ 'B: Expected between 2 and 5 characters, but got 1.'),
('B',
'123456',
- 'Expected between 2 and 5 characters, but got 6.')
+ 'B: Expected between 2 and 5 characters, but got 6.')
]
self.assert_encode_decode_bad(foo, datas)
@@ -506,7 +506,7 @@ def test_choice(self):
datas = [
('A',
('a', 3),
- 'a: Expected an integer between 1 and 2, but got 3.')
+ 'A.a: Expected an integer between 1 and 2, but got 3.')
]
self.assert_encode_decode_bad(foo, datas)
diff --git a/tests/test_gser.py b/tests/test_gser.py
index 4ed4ba3..6402ee5 100644
--- a/tests/test_gser.py
+++ b/tests/test_gser.py
@@ -119,7 +119,7 @@ def test_sequence(self):
foo.encode('A', {})
self.assertEqual(str(cm.exception),
- "Sequence member 'a' not found in {}.")
+ "A: Sequence member 'a' not found in {}.")
def test_sequence_of(self):
foo = asn1tools.compile_string(
@@ -166,7 +166,7 @@ def test_set(self):
foo.encode('A', {})
self.assertEqual(str(cm.exception),
- "Set member 'a' not found in {}.")
+ "A: Set member 'a' not found in {}.")
def test_set_of(self):
foo = asn1tools.compile_string(
@@ -200,7 +200,7 @@ def test_choice(self):
foo.encode('A', ('b', None))
self.assertEqual(str(cm.exception),
- "Expected choice 'a', but got 'b'.")
+ "A: Expected choice 'a', but got 'b'.")
def test_utf8_string(self):
foo = asn1tools.compile_string(
diff --git a/tests/test_jer.py b/tests/test_jer.py
index 5592c27..f416987 100644
--- a/tests/test_jer.py
+++ b/tests/test_jer.py
@@ -142,14 +142,14 @@ def test_enumerated(self):
foo.encode('A', 'c')
self.assertEqual(str(cm.exception),
- "Expected enumeration value 'a' or 'b', but got 'c'.")
+ "A: Expected enumeration value 'a' or 'b', but got 'c'.")
# Decode error.
with self.assertRaises(asn1tools.DecodeError) as cm:
foo.decode('A', b'"c"')
self.assertEqual(str(cm.exception),
- "Expected enumeration value 'a' or 'b', but got 'c'.")
+ "A: Expected enumeration value 'a' or 'b', but got 'c'.")
def test_sequence(self):
foo = asn1tools.compile_string(
@@ -189,7 +189,7 @@ def test_sequence(self):
self.assertEqual(
str(cm.exception),
- "Sequence member 'b' not found in {'a': 1}.")
+ "C: Sequence member 'b' not found in {'a': 1}.")
def test_sequence_of(self):
foo = asn1tools.compile_string(
@@ -247,14 +247,14 @@ def test_choice(self):
foo.encode('A', ('c', None))
self.assertEqual(str(cm.exception),
- "Expected choice 'a' or 'b', but got 'c'.")
+ "A: Expected choice 'a' or 'b', but got 'c'.")
# Decode error.
with self.assertRaises(asn1tools.DecodeError) as cm:
foo.decode('A', b'{"c": null}')
self.assertEqual(str(cm.exception),
- "Expected choice 'a' or 'b', but got 'c'.")
+ "A: Expected choice 'a' or 'b', but got 'c'.")
def test_utf8_string(self):
foo = asn1tools.compile_string(
@@ -819,9 +819,9 @@ def test_error_out_of_data(self):
'uper')
datas = [
- ('A', b'', 'out of data at bit offset 0 (0.0 bytes)'),
- ('B', b'\x00', 'a: c: out of data at bit offset 1 (0.1 bytes)'),
- ('B', b'\x80\x80', 'a: c: out of data at bit offset 9 (1.1 bytes)')
+ ('A', b'', 'A: out of data (At bit offset: 0)'),
+ ('B', b'\x00', 'B.a.c: out of data (At bit offset: 1)'),
+ ('B', b'\x80\x80', 'B.a.c: out of data (At bit offset: 9)')
]
for type_name, encoded, message in datas:
diff --git a/tests/test_oer.py b/tests/test_oer.py
index 9e98098..c07dc37 100644
--- a/tests/test_oer.py
+++ b/tests/test_oer.py
@@ -136,7 +136,7 @@ def test_real(self):
self.assertEqual(
str(cm.exception),
- 'Expected an IEEE 754 32 bits floating point number, but got '
+ 'B: Expected an IEEE 754 32 bits floating point number, but got '
'340282366920938463463374607431768211456.')
with self.assertRaises(asn1tools.EncodeError) as cm:
@@ -144,7 +144,7 @@ def test_real(self):
self.assertEqual(
str(cm.exception),
- 'Expected an IEEE 754 64 bits floating point number, but got '
+ 'C: Expected an IEEE 754 64 bits floating point number, but got '
'17976931348623159077293051907890247336179769789423065727343008115'
'77326758055009631327084773224075360211201138798713933576587897688'
'14416622492847430639474124377767893424865485276302219601246094119'
@@ -157,7 +157,7 @@ def test_real(self):
self.assertEqual(
str(cm.exception),
- 'Expected an IEEE 754 64 bits floating point number, but got 35953'
+ 'C: Expected an IEEE 754 64 bits floating point number, but got 35953'
'86269724631815458610381578049467235953957884613145468601623154653'
'51611001926265416954644815072042240227759742786715317579537628833'
'24498569486127894824875553578684973097055260443920249218823890616'
@@ -295,14 +295,14 @@ def test_enumerated(self):
self.assertEqual(
str(cm.exception),
- "Expected enumeration value 'a' or 'b', but got 'c'.")
+ "C: Expected enumeration value 'a' or 'b', but got 'c'.")
# Decoding bad enumeration value.
with self.assertRaises(asn1tools.DecodeError) as cm:
foo.decode('A', b'\x02')
self.assertEqual(str(cm.exception),
- "Expected enumeration value 1, but got 2.")
+ "A: Expected enumeration value 1, but got 2.")
def test_sequence(self):
foo = asn1tools.compile_string(
@@ -416,14 +416,14 @@ def test_sequence(self):
foo.decode('M', b'\x80\xff\x02\x07\x80\x01')
self.assertEqual(str(cm.exception),
- "a: out of data at bit offset 48 (6.0 bytes)")
+ "M.a: out of data (At bit offset: 48)")
# Out of data decoding extension member a.b.
with self.assertRaises(asn1tools.DecodeError) as cm:
foo.decode('N', b'\x80\xff\x02\x07\x80\x01')
self.assertEqual(str(cm.exception),
- 'a: b: out of data at bit offset 48 (6.0 bytes)')
+ 'N.a.b: out of data (At bit offset: 48)')
def test_set(self):
foo = asn1tools.compile_string(
@@ -511,7 +511,7 @@ def test_choice(self):
foo.encode('B', ('foo', None))
self.assertEqual(str(cm.exception),
- "Expected choice 'a', 'b' or 'c', but got 'foo'.")
+ "B: Expected choice 'a', 'b' or 'c', but got 'foo'.")
# Decode bad value.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -519,7 +519,7 @@ def test_choice(self):
self.assertEqual(
str(cm.exception),
- "Expected choice member tag '80', but got '81'.")
+ "A: Expected choice member tag '80', but got '81'.")
def test_choice_default_tags(self):
foo = asn1tools.compile_string(
@@ -968,21 +968,21 @@ def test_out_of_data(self):
foo.decode('A', b'')
self.assertEqual(str(cm.exception),
- "out of data at bit offset 0 (0.0 bytes)")
+ "A: out of data (At bit offset: 0)")
# Fails trying to read 2 bytes, but only one available.
with self.assertRaises(asn1tools.DecodeError) as cm:
foo.decode('B', b'\x02\x00')
self.assertEqual(str(cm.exception),
- "out of data at bit offset 8 (1.0 bytes)")
+ "B: out of data (At bit offset: 8)")
# Fails trying to read the single additions present bit.
with self.assertRaises(asn1tools.DecodeError) as cm:
foo.decode('C', b'')
self.assertEqual(str(cm.exception),
- "out of data at bit offset 0 (0.0 bytes)")
+ "C: out of data (At bit offset: 0)")
def test_c_source(self):
files = [
diff --git a/tests/test_per.py b/tests/test_per.py
index bab5c30..f70e7da 100644
--- a/tests/test_per.py
+++ b/tests/test_per.py
@@ -49,7 +49,7 @@ def test_boolean(self):
foo.decode('A', b'')
self.assertEqual(str(cm.exception),
- 'out of data at bit offset 0 (0.0 bytes)')
+ 'A: out of data (At bit offset: 0)')
def test_integer(self):
foo = asn1tools.compile_string(
@@ -457,7 +457,7 @@ def test_enumerated(self):
foo.decode('C', b'\x70')
self.assertEqual(str(cm.exception),
- "Expected enumeration index 0, 1 or 2, but got 3.")
+ "C: Expected enumeration index 0, 1 or 2, but got 3.")
# Unknown additions index.
self.assertEqual(foo.decode('C', b'\x8f'), None)
@@ -680,14 +680,14 @@ def test_sequence(self):
foo.decode('U', b'\x80\x80\x03\x02\x05')
self.assertEqual(str(cm.exception),
- 'a: a: out of data at bit offset 32 (4.0 bytes)')
+ 'U.a.a: out of data (At bit offset: 32)')
# Missing root member.
with self.assertRaises(asn1tools.EncodeError) as cm:
foo.encode('K', {'b': True})
self.assertEqual(str(cm.exception),
- "Sequence member 'a' not found in {'b': True}.")
+ "K: Sequence member 'a' not found in {'b': True}.")
def test_sequence_of(self):
foo = asn1tools.compile_string(
@@ -875,7 +875,7 @@ def test_choice(self):
foo.decode('K', b'\x70')
self.assertEqual(str(cm.exception),
- "Expected choice index 0, 1 or 2, but got 3.")
+ "K: Expected choice index 0, 1 or 2, but got 3.")
# Bad additions index becomes None.
decoded = foo.decode('K', b'\x85\x01\x80')
@@ -887,7 +887,7 @@ def test_choice(self):
self.assertEqual(
str(cm.exception),
- "Expected choice 'a', 'b', 'c', 'd', 'e', 'f', 'g' or 'h', but "
+ "K: Expected choice 'a', 'b', 'c', 'd', 'e', 'f', 'g' or 'h', but "
"got 'i'.")
# Bad value.
@@ -897,7 +897,7 @@ def test_choice(self):
check_types=False,
check_constraints=False)
- self.assertEqual(str(cm.exception), "Expected choice 'a', but got 'b'.")
+ self.assertEqual(str(cm.exception), "A: Expected choice 'a', but got 'b'.")
def test_utf8_string(self):
foo = asn1tools.compile_string(
@@ -945,13 +945,13 @@ def test_utf8_string(self):
foo.decode('A', b'\x40\xc5\x00\x00\x00\x00')
self.assertEqual(str(cm.exception),
- 'b: Bad length determinant fragmentation value 0xc5.')
+ 'A.b: Bad length determinant fragmentation value 0xc5.')
with self.assertRaises(asn1tools.DecodeError) as cm:
foo.decode('A', b'\x40\xc1\x00\x00\x00\x00')
self.assertEqual(str(cm.exception),
- 'b: out of data at bit offset 16 (2.0 bytes)')
+ 'A.b: out of data (At bit offset: 16)')
def test_numeric_string(self):
foo = asn1tools.compile_string(
@@ -1130,7 +1130,7 @@ def test_visible_string(self):
self.assertEqual(
str(cm.exception),
- "Expected a character in ' !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEF"
+ "A: Expected a character in ' !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEF"
"GHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~', but got"
" '.' (0x19)'.")
@@ -1188,7 +1188,7 @@ def test_bmp_string(self):
valid_chars = [v for v in range(65536) if v < 0xd800 or v > 0xdfff]
self.assertEqual(str(cm.exception),
- "Expected a value in %s, but got %d." % (valid_chars,
+ "A: Expected a value in %s, but got %d." % (valid_chars,
0xd800,))
def test_graphic_string(self):
diff --git a/tests/test_type_checker.py b/tests/test_type_checker.py
index 8f8e9ef..9fda849 100644
--- a/tests/test_type_checker.py
+++ b/tests/test_type_checker.py
@@ -48,169 +48,169 @@ def assert_good_bad(self,
def test_boolean(self):
self.assert_good_bad('BOOLEAN',
- 'Expected data of type bool',
+ 'A: Expected data of type bool',
good_datas=[True, False],
bad_datas=[1, 'foo'])
def test_integer(self):
self.assert_good_bad('INTEGER',
- 'Expected data of type int or str',
+ 'A: Expected data of type int or str',
good_datas=[1, -1],
bad_datas=[[], None])
def test_real(self):
self.assert_good_bad('REAL',
- 'Expected data of type float or int',
+ 'A: Expected data of type float or int',
good_datas=[1, -1.0],
bad_datas=['1.0', None])
def test_null(self):
self.assert_good_bad('NULL',
- 'Expected None',
+ 'A: Expected None',
good_datas=[None],
bad_datas=['1.0', 1])
def test_bit_string(self):
self.assert_good_bad('BIT STRING',
- 'Expected data of type tuple(bytes, int)',
+ 'A: Expected data of type tuple(bytes, int)',
good_datas=[(b'', 0)],
bad_datas=[1, '101', (1, 0, 1), None])
self.assert_good_bad('BIT STRING',
- 'Expected at least 1 bit(s) data',
+ 'A: Expected at least 1 bit(s) data',
good_datas=[],
bad_datas=[(b'', 1)],
bad_datas_strings=['0'])
def test_bytes(self):
self.assert_good_bad('OCTET STRING',
- 'Expected data of type bytes or bytearray',
+ 'A: Expected data of type bytes or bytearray',
good_datas=[b'7', bytearray()],
bad_datas=[1, {}, None])
def test_object_identifier(self):
self.assert_good_bad('OBJECT IDENTIFIER',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_enumerated(self):
self.assert_good_bad('ENUMERATED { a(0) }',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_sequence(self):
self.assert_good_bad('SEQUENCE { a NULL }',
- 'Expected data of type dict',
+ 'A: Expected data of type dict',
good_datas=[{}],
bad_datas=[(1, ), 1, b'101', None])
self.assert_good_bad('SEQUENCE { a A OPTIONAL }',
- 'a: a: Expected data of type dict',
+ 'A.a.A.a.A: Expected data of type dict',
good_datas=[{'a': {'a': {}}}],
bad_datas=[{'a': {'a': []}}],
bad_datas_strings=['[]'])
def test_sequence_of(self):
self.assert_good_bad('SEQUENCE OF NULL',
- 'Expected data of type list',
+ 'A: Expected data of type list',
good_datas=[[None, None]],
bad_datas=[{}, None])
def test_set(self):
self.assert_good_bad('SET { a NULL }',
- 'Expected data of type dict',
+ 'A: Expected data of type dict',
good_datas=[{}],
bad_datas=[(1, ), 1, b'101', None])
def test_set_of(self):
self.assert_good_bad('SET OF NULL',
- 'Expected data of type list',
+ 'A: Expected data of type list',
good_datas=[[None, None]],
bad_datas=[{}, None])
def test_choice(self):
self.assert_good_bad('CHOICE { a NULL }',
- 'Expected data of type tuple(str, object)',
+ 'A: Expected data of type tuple(str, object)',
good_datas=[('a', None)],
bad_datas=[(1, None), {'a': 1}, None])
self.assert_good_bad('CHOICE { a CHOICE { b CHOICE { c NULL } } }',
- 'a: b: Expected data of type tuple(str, object)',
+ 'A.a.b: Expected data of type tuple(str, object)',
good_datas=[('a', ('b', ('c', None)))],
bad_datas=[('a', ('b', {}))],
bad_datas_strings=['{}'])
def test_utf8_string(self):
self.assert_good_bad('UTF8String',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_numeric_string(self):
self.assert_good_bad('NumericString',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_printable_string(self):
self.assert_good_bad('PrintableString',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_ia5_string(self):
self.assert_good_bad('IA5String',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_visible_string(self):
self.assert_good_bad('VisibleString',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_general_string(self):
self.assert_good_bad('GeneralString',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_bmp_string(self):
self.assert_good_bad('BMPString',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_graphic_string(self):
self.assert_good_bad('GraphicString',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_teletex_string(self):
self.assert_good_bad('TeletexString',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_universal_string(self):
self.assert_good_bad('UniversalString',
- 'Expected data of type str',
+ 'A: Expected data of type str',
good_datas=['5', u'6'],
bad_datas=[1, {}, None])
def test_utc_time(self):
self.assert_good_bad('UTCTime',
- 'Expected data of type datetime.datetime',
+ 'A: Expected data of type datetime.datetime',
good_datas=[datetime.datetime(1, 2, 3)],
bad_datas=[1.4, None])
def test_generalized_time(self):
self.assert_good_bad('GeneralizedTime',
- 'Expected data of type datetime.datetime',
+ 'A: Expected data of type datetime.datetime',
good_datas=[datetime.datetime(1, 2, 3)],
bad_datas=[1.4, None])
diff --git a/tests/test_uper.py b/tests/test_uper.py
index 37d709b..1e5e9a9 100644
--- a/tests/test_uper.py
+++ b/tests/test_uper.py
@@ -740,7 +740,7 @@ def test_sequence(self):
foo.decode('U', b'\x80\x81\x81\x02\xee')
self.assertEqual(str(cm.exception),
- 'a: a: out of data at bit offset 25 (3.1 bytes)')
+ 'U.a.a: out of data (At bit offset: 25)')
def test_sequence_of(self):
foo = asn1tools.compile_string(
@@ -912,7 +912,7 @@ def test_choice(self):
self.assertEqual(
str(cm.exception),
- "Expected choice 'a', 'b', 'c', 'd', 'e', 'f', 'g' or 'h', but "
+ "K: Expected choice 'a', 'b', 'c', 'd', 'e', 'f', 'g' or 'h', but "
"got 'i'.")
def test_utf8_string(self):
@@ -959,7 +959,7 @@ def test_utf8_string(self):
foo.decode('A', b'\x70\x00\x00\x00')
self.assertEqual(str(cm.exception),
- 'b: Bad length determinant fragmentation value 0xc0.')
+ 'A.b: Bad length determinant fragmentation value 0xc0.')
def test_numeric_string(self):
foo = asn1tools.compile_string(
@@ -999,7 +999,7 @@ def test_numeric_string(self):
self.assertEqual(
str(cm.exception),
- "Expected a character in ' 0123456789', but got 'a' (0x61)'.")
+ "A: Expected a character in ' 0123456789', but got 'a' (0x61)'.")
# Bad value 11 should raise an exception.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -1007,7 +1007,7 @@ def test_numeric_string(self):
self.assertEqual(
str(cm.exception),
- "Expected a value in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "
+ "A: Expected a value in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "
"but got 11.")
# Decode size extension is not yet supported.
@@ -1080,7 +1080,7 @@ def test_printable_string(self):
self.assertEqual(
str(cm.exception),
- "Expected a character in ' '()+,-./0123456789:=?ABCDEFGHIJKLMNO"
+ "A: Expected a character in ' '()+,-./0123456789:=?ABCDEFGHIJKLMNO"
"PQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', but got '[' (0x5b)'.")
def test_ia5_string(self):
@@ -1209,7 +1209,7 @@ def test_visible_string(self):
self.assertEqual(
str(cm.exception),
- "Expected a character in ' !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEF"
+ "A: Expected a character in ' !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEF"
"GHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~', but got"
" '.' (0x19)'.")
@@ -1466,7 +1466,7 @@ def test_foo(self):
self.assertEqual(
str(cm.exception),
- "Sequence member 'id' not found in {'question': 'Is 1+1=3?'}.")
+ "Question: Sequence member 'id' not found in {'question': 'Is 1+1=3?'}.")
def test_decode_length(self):
foo = asn1tools.compile_files('tests/files/foo.asn', 'uper')
@@ -2528,9 +2528,9 @@ def test_error_out_of_data(self):
'uper')
datas = [
- ('A', b'', 'out of data at bit offset 0 (0.0 bytes)'),
- ('B', b'\x00', 'a: c: out of data at bit offset 1 (0.1 bytes)'),
- ('B', b'\x80\x80', 'a: c: out of data at bit offset 9 (1.1 bytes)')
+ ('A', b'', 'A: out of data (At bit offset: 0)'),
+ ('B', b'\x00', 'B.a.c: out of data (At bit offset: 1)'),
+ ('B', b'\x80\x80', 'B.a.c: out of data (At bit offset: 9)')
]
for type_name, encoded, message in datas:
diff --git a/tests/test_xer.py b/tests/test_xer.py
index 4bacf4b..5c62659 100644
--- a/tests/test_xer.py
+++ b/tests/test_xer.py
@@ -115,7 +115,7 @@ def test_object_identifier(self):
foo.decode('A', b'')
self.assertEqual(str(cm.exception),
- "Expected an OBJECT IDENTIFIER, but got ''.")
+ "A: Expected an OBJECT IDENTIFIER, but got ''.")
def test_external(self):
foo = asn1tools.compile_string(
@@ -157,7 +157,7 @@ def test_enumerated(self):
self.assertEqual(
str(cm.exception),
- "Expected enumeration value 'r' or 't', but got 'foo'.")
+ "A: Expected enumeration value 'r' or 't', but got 'foo'.")
# Decode error.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -165,7 +165,7 @@ def test_enumerated(self):
self.assertEqual(
str(cm.exception),
- "Expected enumeration value 'r' or 't', but got 'bar'.")
+ "A: Expected enumeration value 'r' or 't', but got 'bar'.")
# Encode of error.
with self.assertRaises(asn1tools.EncodeError) as cm:
@@ -173,7 +173,7 @@ def test_enumerated(self):
self.assertEqual(
str(cm.exception),
- "Expected enumeration value 'a', but got 'foo'.")
+ "B.ENUMERATED: Expected enumeration value 'a', but got 'foo'.")
# Decode of error.
with self.assertRaises(asn1tools.DecodeError) as cm:
@@ -181,7 +181,7 @@ def test_enumerated(self):
self.assertEqual(
str(cm.exception),
- "Expected enumeration value 'a', but got 'bar'.")
+ "B.ENUMERATED: Expected enumeration value 'a', but got 'bar'.")
def test_sequence(self):
foo = asn1tools.compile_string(
@@ -285,28 +285,28 @@ def test_choice(self):
foo.encode('A', ('d', None))
self.assertEqual(str(cm.exception),
- "Expected choice 'a', 'b' or 'c', but got 'd'.")
+ "A: Expected choice 'a', 'b' or 'c', but got 'd'.")
# Decode error.
with self.assertRaises(asn1tools.DecodeError) as cm:
foo.decode('A', b'')
self.assertEqual(str(cm.exception),
- "Expected choice 'a', 'b' or 'c', but got 'd'.")
+ "A: Expected choice 'a', 'b' or 'c', but got 'd'.")
# Encode of error.
with self.assertRaises(asn1tools.EncodeError) as cm:
foo.encode('B', [('d', None)])
self.assertEqual(str(cm.exception),
- "Expected choice 'a', 'b' or 'c', but got 'd'.")
+ "B: Expected choice 'a', 'b' or 'c', but got 'd'.")
# Decode of error.
with self.assertRaises(asn1tools.DecodeError) as cm:
foo.decode('B', b'')
self.assertEqual(str(cm.exception),
- "Expected choice 'a', 'b' or 'c', but got 'd'.")
+ "B: Expected choice 'a', 'b' or 'c', but got 'd'.")
def test_utf8_string(self):
foo = asn1tools.compile_string(
@@ -429,7 +429,7 @@ def test_foo(self):
self.assertEqual(
str(cm.exception),
- "Sequence member 'id' not found in {'question': 'Is 1+1=3?'}.")
+ "Question: Sequence member 'id' not found in {'question': 'Is 1+1=3?'}.")
def test_decode_length(self):
foo = asn1tools.compile_files('tests/files/foo.asn', 'xer')