Files
2025-09-29 00:52:08 +02:00

168 lines
6.9 KiB
Python
Executable File

from lib2to3.pgen2.parse import ParseError
from xml.etree import ElementTree as ET
import os
import argparse
import copy
# Duplicate the Item with the given filename value replacing filename value
dataFiles = ".//dataFiles/Item/filename/[.='{file}']" # /filename
# Duplicate the Item with the given Item value replacing Item value
filesToInvalidate = ".//contentChangeSets/Item/filesToInvalidate/Item/[.='{file}']"
# Duplicate the Item with the given Item value replacing Item value
filesToEnable = ".//contentChangeSets/Item/filesToEnable/Item/[.='{file}']"
# Duplicate the Item with the given Item value replacing Item value
filesToDisable = ".//contentChangeSets/Item/filesToDisable/Item/[.='{file}']"
# Duplicate the Item with the given Item value replacing Item value
mapfilesToInvalidate = ".//contentChangeSets/Item/mapChangeSetData/Item/filesToInvalidate/Item/[.='{file}']"
# Duplicate the Item with the given Item value replacing Item value
mapfilesToEnable = ".//contentChangeSets/Item/mapChangeSetData/Item/filesToEnable/Item/[.='{file}']"
# Duplicate the Item with the given Item value replacing Item value
mapfilesToDisable = ".//contentChangeSets/Item/mapChangeSetData/Item/filesToDisable/Item/[.='{file}']"
changeset_paths = [filesToInvalidate, filesToEnable, filesToDisable, mapfilesToInvalidate, mapfilesToEnable, mapfilesToDisable]
# class doop:
# pass
# args = doop()
# args.in_file = "content.xml"
# args.copy_insert = "dlc_lev_des.rpf,dlc_lev_des_bvh.rpf,dlc_lev_des_bvh.rpf,dlc_lev_des_doop.rpf"
# args.insert = "dlc_lev_des_bvh.rpf"
# args.out_file = "dupe.xml"
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-i", '--in_file', metavar='IN', type=str, required=True,
help='The input file "IN", used to parse for file entries and insertions if out_file is supplied. e.g. path/to/content.xml')
parser.add_argument("-c", '--copy_insert', metavar='CP,INS,...', type=str, required=True,
help='The file to be copied "CP" followed by the file to insert "INS", within the content.xml document. e.g. copy.rpf,insert.rpf')
parser.add_argument("-o", '--out_file', metavar='OUT', type=str, required=True,
help='The output file "OUT", if not set input file is used. e.g. path/to/content.xml')
args = parser.parse_args()
if not os.path.exists(args.in_file):
print("Error: in_file '"+args.in_file+"' doesn't exist")
exit(1)
print("Begin parsing "+args.in_file)
try:
with open(args.in_file, encoding="utf-8") as config:
xml = ET.fromstring(config.read())
except ParseError as e:
print(e)
exit(1)
# Bit of a hack here for getting parents. element.parent doesn't exist in python xml.
parents = {c:p for p in xml.iter() for c in p}
args.copy_insert = args.copy_insert.split(",")
if len(args.copy_insert) % 2 == 1:
print(f"Error: '{args.copy_insert}' is not even!")
exit(1)
# layout pairs e.g. [[copy,insert],[copy,insert]]
args.copy_insert = [args.copy_insert[f:f+2] for f in range(0, len(args.copy_insert), 2)]
# print(args.copy_insert)
for duplicate, insert in args.copy_insert:
print("========================")
print(f"Finding: {duplicate} Inserting: {insert}")
skip_insert = False
found = False
for elem in xml.iter():
if not found and elem != None and elem.text != None and duplicate.lower() in elem.text.lower():
swap = duplicate.lower()
duplicate = elem.text
insert = elem.text.lower().replace(swap, insert)
found = True
elif elem != None and elem.text != None and insert.lower() in elem.text.lower():
print(f"Error: '{insert}' already exists!")
skip_insert = True
break
if not found:
print(f"Error: Could not find '{duplicate}'")
print(f"It's not referenced in {args.in_file}")
skip_insert = True
if skip_insert:
print(f"Skipping '{insert}'")
continue
all_instances = xml.findall(f".//*[.='{duplicate}']")
print("Copying '{file}': "+duplicate)
print(f"Number: {len(all_instances)}")
print("Inserting: "+insert)
print("========================")
# Handle dataFiles (special case)
found = dataFiles.format(file=duplicate)
found = xml.find(found)
if found != None:
item = parents[found]
parent = parents[item]
dupe = copy.deepcopy(item)
dupe.find("filename").text = insert
index = list(parent).index(item)
parent.insert(index+1, dupe)
all_instances.remove(found)
# update parents, merge parent dict of dupe with parents and add parents[dupe] = parent
parents = {**parents, **{c:p for p in dupe.iter() for c in p}}
parents[dupe] = parent
elem = ET.tostring(dupe).decode().strip()
print(f"Copied {dataFiles}: \n{elem}")
print("===")
# Handle changesets
for cs_path in changeset_paths:
found = cs_path.format(file=duplicate)
found = xml.findall(found)
for f in found:
parent = parents[f]
dupe = copy.deepcopy(f)
dupe.text = insert
index = list(parent).index(f)
parent.insert(index+1, dupe)
all_instances.remove(f)
# update parents, merge parent dict of dupe with parents and add parents[dupe] = parent
parents = {**parents, **{c:p for p in dupe.iter() for c in p}}
parents[dupe] = parent
cs = parents[parent]
while cs.find("changeSetName") == None:
cs = parents[cs]
changeset = cs.find("changeSetName").text
elem = ET.tostring(dupe).decode().strip()
print(f"Copied {cs_path} '{changeset}':\n"+elem)
print("===")
if len(all_instances) != 0:
print(f"Error: not all references to '{duplicate}' handled.")
print("The script needs to be updated with the missing xpaths/instances.")
print("Element/s:")
for e in all_instances:
parent = parents[e]
elem = ET.tostring(parent).decode().strip()
print(elem)
exit(1)
print("========================\n")
if args.out_file:
ET.ElementTree(xml).write(args.out_file, encoding="utf-8", xml_declaration=True)
else:
ET.ElementTree(xml).write(args.in_file, encoding="utf-8", xml_declaration=True)
pass
if __name__ == "__main__":
main()
pass