diff --git a/scripts/build/complay.py b/scripts/build/complay.py index c8a61396dce..c44cc1e678f 100644 --- a/scripts/build/complay.py +++ b/scripts/build/complay.py @@ -1,69 +1,152 @@ #!/usr/bin/python ## ## license:BSD-3-Clause -## copyright-holders:Aaron Giles, Andrew Gardner +## copyright-holders:Vas Crabb -from __future__ import with_statement - -import sys import os +import sys +import xml.sax +import xml.sax.saxutils import zlib -if len(sys.argv) < 4: - print('Usage:') - print(' complay ') - print('') - sys.exit(0) -srcfile = sys.argv[1] -dstfile = sys.argv[2] -varname = sys.argv[3] -type = 'uint8_t' +class ErrorHandler(object): + def __init__(self, **kwargs): + super(ErrorHandler, self).__init__(**kwargs) + self.errors = 0 + self.warnings = 0 -try: - myfile = open(srcfile, 'rb') -except IOError: - sys.stderr.write("Unable to open source file '%s'\n" % srcfile) - sys.exit(-1) + def error(self, exception): + self.errors += 1 + sys.stderr.write('error: %s' % (exception)) -byteCount = os.path.getsize(srcfile) -compsize = 0 -compressiontype = 1 + def fatalError(self, exception): + raise exception -try: - dst = open(dstfile,'w') - dst.write('const %s %s_data[] =\n{\n\t' % ( type, varname)) - offs = 0 - with open(srcfile, "rb") as src: - while True: - chunk = src.read(byteCount) - if chunk: - compchunk = bytearray(zlib.compress(chunk, 9)) - compsize = len(compchunk) - for b in compchunk: - dst.write('%d' % b) - offs += 1 - if offs != compsize: - dst.write(',') + 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('') + + 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('' % (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: - break - dst.write('\n\t') + dst(', ') + 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: - sys.stderr.write("Unable to open output file '%s'\n" % dstfile) - sys.exit(-1) + 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') -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') + return state[1], state[0] - dst.close() -except IOError: - sys.stderr.write("Unable to open output file '%s'\n" % dstfile) - sys.exit(-1) +if __name__ == '__main__': + if len(sys.argv) != 4: + print('Usage:') + print(' complay ') + 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)