Issues (17)

src/field.py (1 issue)

1
# MIT License
2
#
3
# Copyright (c) 2017 Matt Boyer
4
#
5
# Permission is hereby granted, free of charge, to any person obtaining a copy
6
# of this software and associated documentation files (the "Software"), to deal
7
# in the Software without restriction, including without limitation the rights
8
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
# copies of the Software, and to permit persons to whom the Software is
10
# furnished to do so, subject to the following conditions:
11
#
12
# The above copyright notice and this permission notice shall be included in
13
# all copies or substantial portions of the Software.
14
#
15
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
# SOFTWARE.
22
23
import struct
24
25
from .utils import decode_twos_complement
26
27
28
class MalformedField(Exception):
29
    pass
30
31
32 View Code Duplication
class Field(object):
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
33
    def __init__(self, idx, serial_type, serial_bytes):
34
        self._index = idx
35
        self._type = serial_type
36
        self._bytes = serial_bytes
37
        self._value = None
38
        self._parse()
39
40
    def _check_length(self, expected_length):
41
        if len(self) != expected_length:
42
            raise MalformedField
43
44
    # TODO Raise a specific exception when bad bytes are encountered for the
45
    # fields and then use this to weed out bad freeblock records
46
    def _parse(self):
47
        if self._type == 0:
48
            self._value = None
49
        # Integer types
50
        elif self._type == 1:
51
            self._check_length(1)
52
            self._value = decode_twos_complement(bytes(self)[0:1], 8)
53
        elif self._type == 2:
54
            self._check_length(2)
55
            self._value = decode_twos_complement(bytes(self)[0:2], 16)
56
        elif self._type == 3:
57
            self._check_length(3)
58
            self._value = decode_twos_complement(bytes(self)[0:3], 24)
59
        elif self._type == 4:
60
            self._check_length(4)
61
            self._value = decode_twos_complement(bytes(self)[0:4], 32)
62
        elif self._type == 5:
63
            self._check_length(6)
64
            self._value = decode_twos_complement(bytes(self)[0:6], 48)
65
        elif self._type == 6:
66
            self._check_length(8)
67
            self._value = decode_twos_complement(bytes(self)[0:8], 64)
68
69
        elif self._type == 7:
70
            self._value = struct.unpack(r'>d', bytes(self)[0:8])[0]
71
        elif self._type == 8:
72
            self._value = 0
73
        elif self._type == 9:
74
            self._value = 1
75
        elif self._type >= 13 and (1 == self._type % 2):
76
            try:
77
                self._value = bytes(self).decode('utf-8')
78
            except UnicodeDecodeError as ex:
79
                raise MalformedField from ex
80
81
        elif self._type >= 12 and (0 == self._type % 2):
82
            self._value = bytes(self)
83
84
    def __bytes__(self):
85
        return self._bytes
86
87
    def __repr__(self):
88
        return "<Field {}: {} ({} bytes)>".format(
89
            self._index, self._value, len(bytes(self))
90
        )
91
92
    def __len__(self):
93
        return len(bytes(self))
94
95
    @property
96
    def index(self):
97
        return self._index
98
99
    @property
100
    def value(self):
101
        return self._value
102
103
    @property
104
    def serial_type(self):
105
        return self._type
106