Cdroid/scripts/idgen.py

238 lines
8.2 KiB
Python
Raw Normal View History

2023-04-11 18:14:57 +08:00
#!/usr/bin/env python3
2022-01-22 11:44:09 +08:00
import xml.sax
from xml.dom import minidom
2023-03-09 23:01:05 +08:00
import xml.etree.ElementTree as xmltree
from xml.dom.minidom import parse, parseString
2022-01-22 14:38:04 +08:00
import os
import sys
import time
2023-06-12 13:21:08 +08:00
import tempfile
import filecmp
import shutil
2022-01-22 14:38:04 +08:00
2022-01-22 11:44:09 +08:00
class CDROIDHandler( xml.sax.ContentHandler ):
2023-03-09 23:01:05 +08:00
def __init__(self,namespace):
2022-01-22 14:38:04 +08:00
self.idlist=[]
self.strings=[]
2023-03-09 23:01:05 +08:00
self.namespace=namespace
2022-01-22 11:44:09 +08:00
2023-08-12 15:42:44 +08:00
def normalizeXMLString(self,xmlStr):
xmlStr.replace("\n", "
")
xmlStr.replace("\r", "&#0d;")
return xmlStr
def isMyNS(self,idname):#parse @android:id/ @+id/ @id/
ns=""
if idname.find(":")>0:
ns = idname.split(":")
ns =ns[0]
else:
pos = idname.find("id/")
ns = idname[0:pos]
ns= ns.replace("@","")
ns= ns.replace("+","")
#print(idname+"==>"+ns)
if ns.strip():#not empty
return (ns==namespace) or (ns=="android" and namespace=="cdroid") or (ns=="cdroid" and namespace=="android")
return True
2022-01-22 11:44:09 +08:00
def startElement(self, tag, attributes):
2022-01-22 14:38:04 +08:00
for attr in attributes.getNames():
2023-03-09 23:01:05 +08:00
value = attributes.get(attr)
2022-01-22 14:38:04 +08:00
if ':id' in attr:
if self.isMyNS(value):
self.addID(value)
if 'string/' in value:
self.addString(value)
2023-12-14 11:50:58 +08:00
if 'type' in attributes and 'name' in attributes:
self.addID("@id/"+attributes.get('name'))
2022-01-22 14:38:04 +08:00
def addID(self,name):
pos=name.find('/')
if pos<0:
return
name=name[pos+1:].strip()
if (name[0].isalpha() or (name[0]=='_')) and (name not in self.idlist) :
self.idlist.append(name)
def addString(self,value):
pos=value.find('/')
if pos<0 :
return
2023-08-12 15:42:44 +08:00
#value=value[pos+1:].strip()
if(value[0].isalpha() or (value[0]=='_')) and (value not in self.strings):
self.strings.append(value)
def groupby(self):
new_ids = []
for id in self.idlist:
if id not in new_ids:
new_ids.append(id)
self.idlist=new_ids
print(new_ids)
return new_ids
2022-01-22 14:38:04 +08:00
class IDGenerater(object):
2023-03-09 23:01:05 +08:00
def __init__(self,idstart,namespace):
2022-01-22 14:38:04 +08:00
self.idstart=idstart
2023-03-09 23:01:05 +08:00
self.namespace=namespace
2023-12-14 11:50:58 +08:00
self.processDirs=['layout','drawable','navigation','values']
2022-01-22 14:38:04 +08:00
self.parser = xml.sax.make_parser()
self.parser.setFeature(xml.sax.handler.feature_namespaces, 0)
2023-03-09 23:01:05 +08:00
self.Handler = CDROIDHandler(namespace)
2022-01-22 14:38:04 +08:00
self.parser.setContentHandler( self.Handler )
2022-01-22 11:44:09 +08:00
2023-03-09 23:01:05 +08:00
def dict2RH(self,filepath):
2022-01-22 11:44:09 +08:00
fr=open(filepath,"w")
fr.write("#pragma once\n\n")
fr.write("/*Generated by machine ,Do not edit !!!*/\n\n")
2023-03-09 23:01:05 +08:00
fr.write("namespace %s{\n\n"%(self.namespace))
fr.write("namespace R{\n")
fr.write(" namespace id{\n")
2022-01-22 11:44:09 +08:00
i=0
2023-03-09 23:01:05 +08:00
#print(self.Handler.idlist)
#print(self.Handler.strings)
2022-01-22 14:38:04 +08:00
for k in self.Handler.idlist:
fr.write("%8s static constexpr int %-24s= 0x%08X ;/*%d*/\n"%('',k,self.idstart+i,self.idstart+i))
i+=1
fr.write("%4s};/*namespace id*/\n\n"%(''))
fr.write(" namespace strings{\n")
i=0
#for ss in self.Handler.strings:
# fr.write("%8s static constexpr int %-24s= 0x%08X ;/*%d*/\n"%('',ss,self.idstart+i,self.idstart+i))
# i+=1
fr.write("%4s};/*namespace strings*/\n\n"%(''))
fr.write("};//endof namespace R\n\n")
fr.write("}//endof namespace\n\n")
2022-01-22 11:44:09 +08:00
fr.close()
2022-01-22 14:38:04 +08:00
def dict2ID(self,filepath):
2022-01-22 11:44:09 +08:00
fr=open(filepath,"w")
fr.write('<?xml version="1.0" encoding="utf-8"?>')
fr.write("<!--Generated by CDdroid's machine,Do not edit !!!-->\n")
fr.write("<resources xmlns:android=\"http://schemas.android.com/apk/res/android\">\n")
2022-01-22 14:38:04 +08:00
i=0;
for k in self.Handler.idlist:
fr.write(' <id name="%s">0x%08x</id>\n'%(k,self.idstart+i))
2022-01-22 14:38:04 +08:00
i+=1
fr.write("</resources>\n\n")
2022-01-22 11:44:09 +08:00
fr.close();
def elementExists(self,elements,tofind):
for e in elements:
if e.getAttribute('name')==tofind:
return 1
return 0
2023-03-09 23:01:05 +08:00
def fixed_writexml(self,writer,xmlroot): #, indent, addindent, newl,encoding):
indent=''
addindent='\t'
newl='\n'
encoding='utf-8'
writer.write(indent + "<" + xmlroot.tagName)
attrs = xmlroot._get_attributes()
a_names = attrs.keys()
for a_name in a_names:
writer.write(" %s=\"" % a_name)
minidom._write_data(writer, attrs[a_name].value)
writer.write("\"")
if xmlroot.childNodes:
if len(xmlroot.childNodes) == 1 \
and xmlroot.childNodes[0].nodeType == minidom.Node.TEXT_NODE:
writer.write(">")
xmlroot.childNodes[0].writexml(writer, "", "", "")
writer.write("</%s>%s" % (xmlroot.tagName, newl))
return
writer.write(">%s" % (newl))
for node in xmlroot.childNodes:
if node.nodeType is not minidom.Node.TEXT_NODE:
node.writexml(writer, indent + addindent, addindent, newl)
writer.write("%s</%s>%s" % (indent, xmlroot.tagName, newl))
else:
writer.write("/>%s" % (newl))
def strings2XML(self,filename):
print(self.Handler.strings)
try:
dom=parse(filename)
except:#(xml.parsers.expat.ExpatError)
print(filename+" open failed or syntax error")
dom=parseString('<?xml version="1.0" encoding="utf-8"?>\n<resources lang="zh_CN"></resources>')
root = dom.documentElement
stringsNodeInFile=root.getElementsByTagName('string')
for str in self.Handler.strings:
if self.elementExists(stringsNodeInFile,str):
continue
e=dom.createElement('string')
2023-03-09 23:01:05 +08:00
text = dom.createTextNode(str)
text.text=str
e.setAttribute('name',str)
e.appendChild(text)
root.appendChild(e)
fp = open(filename, mode='w')#, encoding='utf-8')
2023-03-09 23:01:05 +08:00
self.fixed_writexml(fp,root)# ,indent='', addindent='\t', newl='\n', encoding='utf-8')
fp.close()
def dirHasId(self,path):
for dir in self.processDirs:
if path.find(dir)>=0:
return 1
return -1;
2022-01-22 14:38:04 +08:00
def scanxml(self,scanPath):
lastmodifytime=0
2022-01-22 14:38:04 +08:00
for top, dirs, nondirs in os.walk(scanPath):
dirs.sort()
2022-02-16 18:52:25 +08:00
nondirs.sort()
2022-01-22 14:38:04 +08:00
for item in nondirs:
fname=os.path.join(top, item)
if (not item.endswith('.xml')) or (self.dirHasId(fname)<0):
continue
newestdate=os.stat(fname);
if(lastmodifytime<newestdate.st_mtime):
lastmodifytime=newestdate.st_mtime
self.parser.parse(fname)
return lastmodifytime
2022-01-22 14:38:04 +08:00
2022-01-22 11:44:09 +08:00
if ( __name__ == "__main__"):
#arg0 is myname(idgen.py)
#arg1 is namespace
#arg2 is resource directory
#arg3 is directory which R.h generate to
idstart=10000
if len(sys.argv)<3:
print(sys.argv[0])
print(sys.argv)
namespace=sys.argv[1]
if namespace=='cdroid':
idstart=1000
print("namespace="+namespace)
lastmodifytime=0
if os.path.exists(sys.argv[3]):
fstat=os.stat(sys.argv[3])
lastmodifytime=fstat.st_mtime
2023-03-09 23:01:05 +08:00
idgen=IDGenerater(idstart,namespace)
if not os.path.exists(sys.argv[2]+"/values"):
os.makedirs(sys.argv[2]+"/values")
2022-01-22 11:44:09 +08:00
2023-06-12 13:21:08 +08:00
idgen.scanxml(sys.argv[2])
fd,ftempids=tempfile.mkstemp(prefix=namespace+"_ID", suffix=".xml")
idgen.dict2ID(ftempids)
fidxml = sys.argv[2]+"/values/ID.xml"
isIDSame = os.path.exists(fidxml) and filecmp.cmp(ftempids,fidxml)
msg = "not changed "
2023-06-14 16:10:27 +08:00
if not isIDSame or not os.path.exists(sys.argv[3]):#True if same,otherwise False
2023-06-12 13:21:08 +08:00
#content is changed,we must copy ftempids to fidxml(sys.argv[2]+"/values/ID.xml)
shutil.copyfile(ftempids,fidxml)
idgen.dict2RH(sys.argv[3])
msg="changed "
2023-06-15 11:04:42 +08:00
print(namespace+"'s IDs is "+msg+ftempids+" : "+fidxml)
try:
os.remove(ftempids)
except OSError as e:
print("Remove File:{e}")