mirror of
https://github.com/holub/mame
synced 2025-07-04 17:38:08 +03:00
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:
parent
f7198793ee
commit
5eefcfdb68
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user