-
Notifications
You must be signed in to change notification settings - Fork 5
/
xmlToYax.py
98 lines (80 loc) · 2.58 KB
/
xmlToYax.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
from __future__ import annotations
from io import BufferedReader, BufferedWriter
import struct
import sys
from typing import Dict, List, Set
from xml.etree.ElementTree import XMLParser, fromstring as xmlFromString, Element
import zlib
def writeString(string: str, file: BufferedWriter):
file.write(string.encode('shift-jis'))
file.write(b'\x00')
def writeUint8(value: int, file: BufferedWriter):
file.write(struct.pack('<B', value))
def writeUint32(value: int, file: BufferedWriter):
file.write(struct.pack('<I', value))
def crc32(text: str) -> int:
return zlib.crc32(text.encode('ascii')) & 0xFFFFFFFF
def getTagId(tag: Element) -> int:
return int(tag.get("id"), 16) if tag.tag == "UNKNOWN" else crc32(tag.tag)
class XmlNode:
indentation: int
tagId: int
valueOffset: int
value: str
def __init__(self, indentation: int, tagId: int, value: str):
self.indentation = indentation
self.tagId = tagId
self.value = value
def writeToFile(self, file: BufferedWriter):
writeUint8(self.indentation, file)
writeUint32(self.tagId, file)
writeUint32(self.valueOffset, file)
def xmlToYax(xmlFile: str, outFile: str|None = None):
with open(xmlFile, "r", encoding="utf-8") as file:
xmlBytes = file.read()
xmlFileContents = xmlBytes
xmlRoot = xmlFromString(xmlFileContents)
stringSet: List[str] = []
stringOffsets: Dict[str, int] = {}
lastOffset = 0
def putStringGetOffset(string: str) -> int:
nonlocal lastOffset
if not string:
return 0
if string in stringSet:
return stringOffsets[string]
stringSet.append(string)
stringOffsets[string] = lastOffset
retOff = lastOffset
strByteLength = len(string.encode('shift-jis')) + 1
lastOffset += strByteLength
return retOff
# read flat tree, create nodes
nodes: List[XmlNode] = []
def addNodeToList(node: Element, indentation: int):
tagId = getTagId(node)
nodeText = node.text.strip() if node.text else ""
nodes.append(XmlNode(indentation, tagId, nodeText))
for child in node:
addNodeToList(child, indentation + 1)
for child in xmlRoot:
addNodeToList(child, 0)
# make string set
lastOffset = 4 + len(nodes) * 9
for node in nodes:
node.valueOffset = putStringGetOffset(node.value)
outFileName = outFile or xmlFile.replace(".xml", ".yax") if ".xml" in xmlFile else xmlFile + ".yax"
with open(outFileName, "wb") as f:
# node length
writeUint32(len(nodes), f)
# nodes
for node in nodes:
node.writeToFile(f)
# strings
for string in stringSet:
writeString(string, f)
if __name__ == "__main__":
xmlFiles = sys.argv[1:]
for xmlFile in xmlFiles:
xmlToYax(xmlFile)
print(f"Converted {xmlFile} to yax")