-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhex_parser.py
106 lines (80 loc) · 3.38 KB
/
hex_parser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from enum import Enum
import os
from typing import List, NamedTuple, Union
from parsers import ParserError, Record, RecordType, parse_line
class MemoryType(Enum):
BOOT = 0
EEPROM = 1
RAM = 2
SPIFI = 3
UNKNOWN = -1
class MemorySection(NamedTuple):
type: MemoryType
offset: int
length: int # Memory section length in bytes
class Segment:
offset: int
memory: Union[MemorySection, None] = None
data: List[int]
def __init__(self, offset: int, data: List[int], sections: List[MemorySection]):
self.offset = offset
self.data = data
self._locate_memory_section(sections)
def _locate_memory_section(self, sections: List[MemorySection]):
for section in sections:
if self._belongs_memory_section(section, self.offset):
self.memory = section
if self.memory is None:
raise ParserError(
f"segment with offset {self.offset:#0x} doesn't belong to any section")
if (self.offset + self.data.__len__()) > (self.memory.offset + self.memory.length):
raise ParserError(
f"ERROR: segment with offset {self.offset:#0x} "
f"and length {self.data.__len__()} "
f"overflows section {self.memory.type.name}"
)
def _belongs_memory_section(self, memory_section: MemorySection, offset: int) -> bool:
if offset < memory_section.offset:
return False
if offset >= (memory_section.offset + memory_section.length):
return False
return True
supported_text_formats = [".hex"]
class FirmwareFile:
file_name: str
file_extension: str
segments: List[Segment] = []
def __init__(self, path: str, sections: List[MemorySection]):
self.file_name, self.file_extension = os.path.splitext(path)
if self.file_extension in supported_text_formats:
with open(path) as f:
lines = f.readlines()
self._parse_hex(lines, sections)
elif self.file_extension == ".bin":
with open(path, "rb") as f:
bin_content = list(f.read())
self.segments.append(Segment(offset=0, data=bin_content, sections=sections))
else:
raise ParserError(f"Unsupported file format: {self.file_extension}")
def _parse_hex(self, lines: List[str], sections: List[MemorySection]):
segments: List[Segment] = []
lba: int = 0 # Linear Base Address
expect_address = 0 # Address of the next byte
for i, line in enumerate(lines):
record: Record = parse_line(line, i, self.file_extension)
if record.type == RecordType.DATA:
drlo: int = record.address # Data Record Load Offset
if (expect_address != lba+drlo) or (segments.__len__() == 0):
expect_address = lba+drlo
segments.append(Segment(
offset=expect_address, data=[], sections=sections))
for byte in record.data:
segments[-1].data.append(byte)
expect_address += 1
elif record.type == RecordType.EXTADDR:
lba = record.address
elif record.type == RecordType.EOF:
break
self.segments.extend(segments)
def get_segments(self) -> List[Segment]:
return self.segments