72 lines
2.3 KiB
Python
Executable File
72 lines
2.3 KiB
Python
Executable File
"""Read the supplied XLSX matrix using the standard OOXML structures."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
import zipfile
|
|
from pathlib import Path
|
|
from typing import Any
|
|
from xml.etree import ElementTree
|
|
|
|
|
|
MAIN_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
CELL_REFERENCE = re.compile(r"([A-Z]+)([0-9]+)")
|
|
|
|
|
|
def _column_index(reference: str) -> int:
|
|
match = CELL_REFERENCE.fullmatch(reference)
|
|
if not match:
|
|
raise ValueError(f"Invalid XLSX cell reference: {reference}")
|
|
result = 0
|
|
for character in match.group(1):
|
|
result = result * 26 + ord(character) - ord("A") + 1
|
|
return result - 1
|
|
|
|
|
|
def _shared_strings(archive: zipfile.ZipFile) -> list[str]:
|
|
root = ElementTree.fromstring(archive.read("xl/sharedStrings.xml"))
|
|
return [
|
|
"".join(node.text or "" for node in item.iter(f"{{{MAIN_NS}}}t"))
|
|
for item in root.findall(f"{{{MAIN_NS}}}si")
|
|
]
|
|
|
|
|
|
def read_source_signals(path: Path) -> list[dict[str, Any]]:
|
|
"""Return the 23 signal rows needed for source-to-normalized contract checks."""
|
|
|
|
with zipfile.ZipFile(path) as archive:
|
|
strings = _shared_strings(archive)
|
|
worksheet = ElementTree.fromstring(archive.read("xl/worksheets/sheet1.xml"))
|
|
|
|
rows: list[list[str]] = []
|
|
for row_node in worksheet.iter(f"{{{MAIN_NS}}}row"):
|
|
values: dict[int, str] = {}
|
|
for cell in row_node.findall(f"{{{MAIN_NS}}}c"):
|
|
value_node = cell.find(f"{{{MAIN_NS}}}v")
|
|
if value_node is None or value_node.text is None:
|
|
continue
|
|
value = value_node.text
|
|
if cell.get("t") == "s":
|
|
value = strings[int(value)]
|
|
values[_column_index(str(cell.get("r")))] = value
|
|
if values:
|
|
width = max(values) + 1
|
|
rows.append([values.get(index, "") for index in range(width)])
|
|
|
|
records = []
|
|
for row in rows[1:]:
|
|
if len(row) < 6 or not row[0]:
|
|
continue
|
|
records.append(
|
|
{
|
|
"name": row[0],
|
|
"description": row[1],
|
|
"frame_id": int(row[2], 16),
|
|
"sub_id": None if row[3] in {"", "null"} else int(row[3], 16),
|
|
"start_bit": int(float(row[4])),
|
|
"bit_length": int(float(row[5])),
|
|
}
|
|
)
|
|
return records
|
|
|