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:
print('Usage:')
print(' complay <source.lay> <output.h> <varname>')
print('')
sys.exit(0)
srcfile = sys.argv[1] class ErrorHandler(object):
dstfile = sys.argv[2] def __init__(self, **kwargs):
varname = sys.argv[3] super(ErrorHandler, self).__init__(**kwargs)
type = 'uint8_t' self.errors = 0
self.warnings = 0
try: def error(self, exception):
myfile = open(srcfile, 'rb') self.errors += 1
except IOError: sys.stderr.write('error: %s' % (exception))
sys.stderr.write("Unable to open source file '%s'\n" % srcfile)
sys.exit(-1)
byteCount = os.path.getsize(srcfile) def fatalError(self, exception):
compsize = 0 raise exception
compressiontype = 1
try: def warning(self, exception):
dst = open(dstfile,'w') self.warnings += 1
dst.write('const %s %s_data[] =\n{\n\t' % ( type, varname)) sys.stderr.write('warning: %s' % (exception))
offs = 0
with open(srcfile, "rb") as src:
while True: class Minifyer(object):
chunk = src.read(byteCount) def __init__(self, output, **kwargs):
if chunk: super(Minifyer, self).__init__(**kwargs)
compchunk = bytearray(zlib.compress(chunk, 9))
compsize = len(compchunk) self.output = output
for b in compchunk: self.incomplete_tag = False
dst.write('%d' % b) self.element_content = ''
offs += 1
if offs != compsize: def setDocumentLocator(self, locator):
dst.write(',') 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: else:
break dst(', ')
dst.write('\n\t') state[0] += 1
dst('%3u' % (ord(ch)))
dst.write('\n};\n') def output(text):
block = text.encode('UTF-8')
state[1] += len(block)
write(comp.compress(block))
except IOError: error_handler = ErrorHandler()
sys.stderr.write("Unable to open output file '%s'\n" % dstfile) content_handler = Minifyer(output)
sys.exit(-1) 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')
try: return state[1], state[0]
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() if __name__ == '__main__':
except IOError: if len(sys.argv) != 4:
sys.stderr.write("Unable to open output file '%s'\n" % dstfile) print('Usage:')
sys.exit(-1) print(' complay <source.lay> <output.h> <varname>')
sys.exit(0 if len(sys.argv) <= 1 else 1)
srcfile = sys.argv[1]
dstfile = sys.argv[2]
varname = sys.argv[3]
comp_type = 1
try:
dst = open(dstfile,'w')
dst.write('static const unsigned char %s_data[] = {\n' % (varname))
byte_count, comp_size = compressLayout(srcfile, lambda x: dst.write(x), zlib.compressobj())
dst.write('};\n\n')
dst.write('const internal_layout %s = {\n' % (varname))
dst.write('\t%d, sizeof(%s_data), %d, %s_data\n' % (byte_count, varname, comp_type, varname))
dst.write('};\n')
dst.close()
except XmlError:
dst.close()
os.remove(dstfile)
sys.exit(2)
except IOError:
sys.stderr.write("Unable to open output file '%s'\n" % dstfile)
os.remove(dstfile)
dst.close()
sys.exit(3)