"""Document-level helpers for a Sedona app: the packed 'meta' property and component paths. Pure XML and bit work, deliberately free of Tk so the rules stay testable headless. """ import xml.etree.ElementTree as ET def read_meta_property(meta_str): """Parses 32-bit meta property integer fields via structured byte extraction rules.""" if meta_str is None or not meta_str: return 0, 0, 0, True, False, False, False, 0 try: if meta_str.startswith("0x") or meta_str.startswith("0X"): meta_val = int(meta_str, 16) else: meta_val = int(meta_str) raw_x = (meta_val >> 24) & 0xFF raw_y = (meta_val >> 16) & 0xFF reserved = (meta_val >> 8) & 0xFF user_group_byte = meta_val & 0xFF group1 = bool(user_group_byte & 0x01) group2 = bool(user_group_byte & 0x02) group3 = bool(user_group_byte & 0x04) group4 = bool(user_group_byte & 0x08) user_group_reserved = (user_group_byte >> 4) & 0x0F return raw_x, raw_y, reserved, group1, group2, group3, group4, user_group_reserved except Exception: return 0, 0, 0, True, False, False, False, 0 def update_meta_property(element, meta_str, raw_x, raw_y): """Re-encodes coordinates back into meta, completely preserving existing lower and consecutive bytes.""" _, _, reserved, g1, g2, g3, g4, ug_res = read_meta_property(meta_str) user_group_byte = 0 if g1: user_group_byte |= 0x01 if g2: user_group_byte |= 0x02 if g3: user_group_byte |= 0x04 if g4: user_group_byte |= 0x08 user_group_byte |= (ug_res & 0x0F) << 4 new_val = ( ((raw_x & 0xFF) << 24) | ((raw_y & 0xFF) << 16) | ((reserved & 0xFF) << 8) | (user_group_byte & 0xFF) ) meta_prop = element.find("prop[@name='meta']") if meta_prop is None: meta_prop = ET.SubElement(element, "prop", name="meta") meta_prop.set("val", str(new_val)) def find_parent_element(root_elem, child_to_find): """Traverses the XML DOM tree recursively to find the parent element of a given element.""" for parent in root_elem.iter(): if child_to_find in list(parent): return parent return None def get_component_path(element, root_elem): """Computes the absolute path of a component within the application tree hierarchy.""" path_parts = [] curr = element while curr is not None and curr.tag == "comp": path_parts.append(curr.get("name", "")) curr = find_parent_element(root_elem, curr) path_parts.reverse() return "/" + "/".join(path_parts)