from typing_extensions import Optional from copy import deepcopy from lxml import etree def insert_after_public(anchor_name: str, elem_name: str) -> Optional[int]: file_path = "./decompiled/res/values/public.xml" parser = etree.XMLParser(remove_blank_text=True) tree = etree.parse(file_path, parser) root = tree.getroot() anchor = None types = {} for elem in root: assert elem.tag == "public" assert elem.keys() == ["type", "name", "id"] attrs = dict(zip(elem.keys(), elem.values())) if attrs["name"] == anchor_name: assert anchor == None anchor = (elem, attrs) types[attrs["type"]] = types.get(attrs["type"], []) + [int(attrs["id"], 16)] assert anchor != None free_ids = set() group = types[anchor[1]["type"]] for i in range(min(group), max(group) + 1): if i not in group: free_ids.add(i) new_id = None for i in free_ids: if i > int(anchor[1]["id"], 16): new_id = i break if new_id == None: new_id = max(group) + 1 for name, group in types.items(): if name == anchor[1]["type"]: continue if new_id in group: assert False, f"ID {new_id} already exists in group {name}" new_elem = deepcopy(anchor[0]) new_elem.set("id", hex(new_id)) new_elem.set("name", elem_name) anchor[0].addnext(new_elem) tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8") return new_id def insert_after_id(anchor_name: str, elem_name: str) -> None: file_path = "./decompiled/res/values/ids.xml" parser = etree.XMLParser(remove_blank_text=True) tree = etree.parse(file_path, parser) root = tree.getroot() anchor = None for elem in root: assert elem.tag == "item" assert elem.keys() == ["type", "name"] attrs = dict(zip(elem.keys(), elem.values())) if attrs["name"] == anchor_name: assert anchor == None anchor = (elem, attrs) assert anchor != None new_elem = deepcopy(anchor[0]) new_elem.set("name", elem_name) anchor[0].addnext(new_elem) tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8") def change_color(name: str, value: str) -> None: file_path = "./decompiled/res/values/colors.xml" parser = etree.XMLParser(remove_blank_text=True) tree = etree.parse(file_path, parser) root = tree.getroot() replacements = 0 for elem in root: assert elem.tag == "color" assert elem.keys() == ["name"] attrs = dict(zip(elem.keys(), elem.values())) if attrs["name"] == name: elem.set("name", name) elem.text = value replacements += 1 assert replacements >= 1 tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8") def insert_after_color(anchor_name: str, elem_name: str, elem_value: str) -> None: file_path = "./decompiled/res/values/colors.xml" parser = etree.XMLParser(remove_blank_text=True) tree = etree.parse(file_path, parser) root = tree.getroot() anchor = None for elem in root: assert elem.tag == "color" assert elem.keys() == ["name"] attrs = dict(zip(elem.keys(), elem.values())) if attrs["name"] == anchor_name: assert anchor == None anchor = (elem, attrs) assert anchor != None new_elem = deepcopy(anchor[0]) new_elem.set("name", elem_name) anchor[0].addnext(new_elem) tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")