"""Objects for doing generic data-as-code encoding""" import string, cStringIO, zlib, types, os import resourcepackage HEADER = '''# -*- coding: ISO-8859-1 -*- """Resource %(module)s (from file %(source)s)""" # written by resourcepackage: %(resourcepackagev)r source = %(source)r package = %(packagen)r ''' class SimpleGenerator: """Simplistic generator""" def __repr__( self ): return "%s (singleton)"%( self.__class__.__name__) def __call__( self, source, destination, package=None ): """Encode source in destination for package""" header = self.getHeader( source, destination, package ) assert isinstance( header, types.StringType ), """Generator %s didn't return a String, returned %r"""%( self, header ) data = self.getDataRepr( source, destination, package ) assert isinstance( data, types.StringType ), """Generator %s didn't return a String, returned %r"""%( self, data ) footer = self.getFooter( source, destination, package ) assert isinstance( footer, types.StringType ), """Generator %s didn't return a String, returned %r"""%( self, footer ) file = open(destination,'w') try: file.write( header ) file.write( data ) file.write( footer ) finally: file.close() def getHeader( self, source, destination, package=None ): """Get the header, written before the data variable""" source = os.path.basename( source ) module = os.path.splitext(os.path.basename( destination ))[0] resourcepackagev = resourcepackage.__version__ packagen = package.packageName return HEADER % locals() def getDataRepr( self, source, destination, package=None ): """data as Python code assigning a value to variable "data" """ return """data = %s\n"""%( crunch_data( self.getData(source) ) ) def getFooter( self, source, destination, package=None ): """Get the footer, written after the data variable""" return """### end\n""" def getData( self, source, package=None ): """Get the data to be encoded in the package""" return open(source,'rb').read() class CompressedGenerator( SimpleGenerator ): """Adds Zlib compression and decompression to generator""" def getDataRepr( self, source, destination, package=None ): """data as Python code assigning a value to variable "data" """ return """data = zlib.decompress(%s)\n"""%( crunch_data( self.getData(source) ) ) def getData( self, source, package=None ): """Get the data to be encoded in the package""" data = SimpleGenerator.getData( self, source, package ) return zlib.compress( data, 9 ) def getHeader( self, source, destination, package=None ): """Get the header, written before the data variable""" base = SimpleGenerator.getHeader( self, source, destination, package ) return base + """\nimport zlib\n""" _char_map = { } for c in range(32): _char_map[ chr(c)] = '\\%03o'%(c) _char_map['"'] = '\\"' _char_map['\\'] = '\\\\' def crunch_data(source, chunkSize=60, charMap = _char_map ): """Try to get a minimal representation of a binary as Python code This is a re-implementation that tries to minimise the size of the data by embedding extended characters in the source code. """ result = [] lastIndex = 0 for index in xrange(0, len(source), chunkSize): sresult = "".join([ charMap.get( char, char) for char in source[index:index+chunkSize] ]) result.append( sresult ) return '"%s"'%( '\\\n'.join( result )) SIMPLE = SimpleGenerator() COMPRESSED = CompressedGenerator() generators = { "": SIMPLE, ".txt": COMPRESSED, ".html": COMPRESSED, ".htm": COMPRESSED, ".pdf":COMPRESSED, }