"""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