Rewrite complay.py to parse/minify layout XML

Doesn't make much difference to executable size, but it catches XML errors at build time rather than waiting for you to try the system (nw)
This commit is contained in:
Vas Crabb 2016-11-20 20:54:10 +11:00
parent f7198793ee
commit 5eefcfdb68

View File

@ -1,69 +1,152 @@
#!/usr/bin/python #!/usr/bin/python
## ##
## license:BSD-3-Clause ## license:BSD-3-Clause
## copyright-holders:Aaron Giles, Andrew Gardner ## copyright-holders:Vas Crabb
from __future__ import with_statement
import sys
import os import os
import sys
import xml.sax
import xml.sax.saxutils
import zlib import zlib
if len(sys.argv) < 4:
class ErrorHandler(object):
def __init__(self, **kwargs):
super(ErrorHandler, self).__init__(**kwargs)
self.errors = 0
self.warnings = 0
def error(self, exception):
self.errors += 1
sys.stderr.write('error: %s' % (exception))
def fatalError(self, exception):
raise exception
def warning(self, exception):
self.warnings += 1
sys.stderr.write('warning: %s' % (exception))
class Minifyer(object):
def __init__(self, output, **kwargs):
super(Minifyer, self).__init__(**kwargs)
self.output = output
self.incomplete_tag = False
self.element_content = ''
def setDocumentLocator(self, locator):
pass
def startDocument(self):
self.output('<?xml version="1.0"?>')
def endDocument(self):
self.output('\n')
def startElement(self, name, attrs):
self.flushElementContent()
if self.incomplete_tag:
self.output('>')
self.output('<%s' % (name))
for name in attrs.getNames():
self.output(' %s=%s' % (name, xml.sax.saxutils.quoteattr(attrs[name])))
self.incomplete_tag = True
def endElement(self, name):
self.flushElementContent()
if self.incomplete_tag:
self.output('/>')
else:
self.output('</%s>' % (name))
self.incomplete_tag = False
def characters(self, content):
self.element_content += content
def ignorableWhitespace(self, whitespace):
pass
def processingInstruction(self, target, data):
pass
def flushElementContent(self):
self.element_content = self.element_content.strip()
if self.element_content:
if self.incomplete_tag:
self.output('>')
self.incomplete_tag = False
self.output(xml.sax.saxutils.escape(self.element_content))
self.element_content = ''
class XmlError(Exception):
pass
def compressLayout(src, dst, comp):
state = [0, 0]
def write(block):
for ch in block:
if 0 == state[0]:
dst('\t')
elif 0 == (state[0] % 32):
dst(',\n\t')
else:
dst(', ')
state[0] += 1
dst('%3u' % (ord(ch)))
def output(text):
block = text.encode('UTF-8')
state[1] += len(block)
write(comp.compress(block))
error_handler = ErrorHandler()
content_handler = Minifyer(output)
parser = xml.sax.make_parser()
parser.setErrorHandler(error_handler)
parser.setContentHandler(content_handler)
try:
parser.parse(src)
write(comp.flush())
dst('\n')
except xml.sax.SAXException as exception:
print('fatal error: %s' % (exception))
raise XmlError('Fatal error parsing XML')
if (error_handler.errors > 0) or (error_handler.warnings > 0):
raise XmlError('Error(s) and/or warning(s) parsing XML')
return state[1], state[0]
if __name__ == '__main__':
if len(sys.argv) != 4:
print('Usage:') print('Usage:')
print(' complay <source.lay> <output.h> <varname>') print(' complay <source.lay> <output.h> <varname>')
print('') sys.exit(0 if len(sys.argv) <= 1 else 1)
sys.exit(0)
srcfile = sys.argv[1] srcfile = sys.argv[1]
dstfile = sys.argv[2] dstfile = sys.argv[2]
varname = sys.argv[3] varname = sys.argv[3]
type = 'uint8_t'
try: comp_type = 1
myfile = open(srcfile, 'rb') try:
except IOError:
sys.stderr.write("Unable to open source file '%s'\n" % srcfile)
sys.exit(-1)
byteCount = os.path.getsize(srcfile)
compsize = 0
compressiontype = 1
try:
dst = open(dstfile,'w') dst = open(dstfile,'w')
dst.write('const %s %s_data[] =\n{\n\t' % ( type, varname)) dst.write('static const unsigned char %s_data[] = {\n' % (varname))
offs = 0 byte_count, comp_size = compressLayout(srcfile, lambda x: dst.write(x), zlib.compressobj())
with open(srcfile, "rb") as src: dst.write('};\n\n')
while True: dst.write('const internal_layout %s = {\n' % (varname))
chunk = src.read(byteCount) dst.write('\t%d, sizeof(%s_data), %d, %s_data\n' % (byte_count, varname, comp_type, varname))
if chunk: dst.write('};\n')
compchunk = bytearray(zlib.compress(chunk, 9))
compsize = len(compchunk)
for b in compchunk:
dst.write('%d' % b)
offs += 1
if offs != compsize:
dst.write(',')
else:
break
dst.write('\n\t')
dst.write('\n};\n')
except IOError:
sys.stderr.write("Unable to open output file '%s'\n" % dstfile)
sys.exit(-1)
try:
dst.write('extern const internal_layout %s;\n' % ( varname ))
dst.write('const internal_layout %s = { \n\t' % ( varname ))
dst.write('%d,%d,%d,%s_data\n' % ( byteCount, compsize, compressiontype, varname ))
dst.write('\n};\n')
dst.close() dst.close()
except IOError: except XmlError:
dst.close()
os.remove(dstfile)
sys.exit(2)
except IOError:
sys.stderr.write("Unable to open output file '%s'\n" % dstfile) sys.stderr.write("Unable to open output file '%s'\n" % dstfile)
sys.exit(-1) os.remove(dstfile)
dst.close()
sys.exit(3)