bin2html.py

'''\
Binary file to HTML "Hex" Dump file.

commands:
    main            - Main function (normal use)
    test            - Test function (development)

usage:
    module.dispatch({command}, args={arguments})    -- calling module from code

    $PYTHON module_name {command} {arguments}       -- executing module externally

Developer@Sonnack.com
April 2016
'''
####################################################################################################
from __future__ import print_function
from sys import argvexc_info
from traceback import extract_tb
from os import path
from htmlpage import htmlpage
from logger import loggerinfodebugtrace
####################################################################################################
Log = logger('BIN2HTML')

BasePath = r'C:\CJS\prj\Python\app'
HtmlPath = r'C:\CJS\www\root\tmp'

##------------------------------------------------------------------------------------------------##
HtmlCss = '''\
<style type="text/css">
#PageBody h3 {
    font-size: 11pt;
    font-weight: bold;
    margin-bottom: 3pt;
}
#PageBody h4 {
    font-size: 11pt;
    font-weight: normal;
    text-decoration: underline;
    margin-top: 3pt;
    margin-bottom: 18pt;
}
#PageBody table {
    background-color: #3f3f3f;
    text-height: 1.0;
    border-spacing: 3px 0;
    padding: 0 2px;
    border: 2px solid black;
    margin: 18pt auto 18pt 24pt;
}
#PageBody table thead th {
    background-color: #000000;
    color: #ffffff;
    font-family: serif;
    font-size: 13pt;
    font-weight: bold;
    font-style: normal;
    text-align: center;
    vertical-align: bottom;
    padding: 3px auto 5px auto;
}
#PageBody table tbody tr {
    background-color: #7f7f7f;
}
#PageBody table tbody td {
    font-family: monospace;
    font-size: 10pt;
    font-weight: bold;
    font-style: normal;
    border-bottom: 1px solid black;
}
#PageBody table tbody td.Addrs {
    white-space: nowrap;
    background-color: #ffffbf;
}
#PageBody table tbody td.Bytes {
    background-color: #f0fff0;
}
#PageBody table tbody td.Chars {
    white-space: nowrap;
    background-color: #f0f0ff;
}
</style>
'''
##================================================================================================##
def HtmlCssSender (objfp):
    fp.write(HtmlCss)

##================================================================================================##
def SafeChar (c):
    if c <= 32: return '.'
    if c in [127129141143144157160173]: return '.'
    if 127 < c: return ('&#%d;' % c)
    ch = chr(c)
    if ch == '&': return '&amp;'
    if ch == '<': return '&lt;'
    if ch == '>': return '&gt;'
    if ch == '"': return '&quot;'
    return ch


##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class BinDumpPage (object):

    def __init__ (selfdatafname):
        self.data = data
        self.fname = fname
        self.dcols = 16
        self.fmt_addr = lambda n:('%08d' % n)
        self.fmt_data = lambda n:('%02x' % n)

    def writepage (selffp):
        try:
            Log.trace('WritePage::ENTER')
            self.my_writepage(fp)
        except:
            raise
        finally:
            Log.trace('WritePage::EXIT')

    def my_writepage (selffp):
        fp.write('<h4>%s</h4>\n' % self.fname)
        fp.write('\n')
        self.my_write_byte_block(fp)
        fp.write('\n')

    def my_write_byte_block (selffp):
        fp.write('<table>\n')
        fp.write('<thead>\n')
        fp.write('<tr><th>Address</th><th>Bytes</th><th>Chars</th></tr>\n')
        fp.write('</thead><tbody>\n')
        for bx in range(0len(self.data), self.dcols):
            # Address...
            fp.write('<tr><td class="Addrs">%s</td>' % self.fmt_addr(bx))
            # Data...
            buf = self.data[bx:bx+self.dcols]
            # ...Bytes...
            bt = [self.fmt_data(ord(b)) for b in buf]
            fp.write('<td class="Bytes">%s</td>' % (' '.join(bt)))
            # ...Chars...
            ct = [SafeChar(ord(c)) for c in buf]
            fp.write('<td class="Chars">%s</td></tr>\n' % ''.join(ct))
        fp.write('</tbody></table>\n')

##================================================================================================##
def binary_file_to_html_file (infilenameoutfilename):
    Log.info('bin2html::ifname: %s' % infilename)
    Log.info('bin2html::ofname: %s' % outfilename)

    fp = open(infilename'rb')
    try:
        bs = fp.read()
        Log.debug('read: %s' % infilename)
    except:
        raise
    finally:
        fp.close()

    # HTML Page...
    pw = BinDumpPage(bs,infilename)
    pg = htmlpage('Bin2HTML'h2='Python WebApps')
    pg.cb_htmlhead = HtmlCssSender
    pg.writefile(outfilenamepw)
    Log.debug('wrote: %s' % outfilename)



##================================================================================================##
def do_test (*args):
    Log.info('test:: %s' % str(args))
    ifname = args[0if 0 < len(argselse path.join(BasePath'img.png')
    ofname = args[1if 1 < len(argselse path.join(HtmlPath'bin2html.html')
    #
    binary_file_to_html_file(ifnameofname)
    return 'Done!'
##================================================================================================##
def do_main (*args):
    Log.info('main:: %s' % str(args))
    ifname = args[0]
    ofname = args[1if 1 < len(argselse path.join(HtmlPath'bin2html.html')
    #
    binary_file_to_html_file(ifnameofname)
    return 'Done!'
####################################################################################################
def dispatch (cmd, *args):
    Log.info('command: %s' % cmd)
    Log.info('arguments: %d' % len(args))
    if cmd == 'test': return do_test(*args)
    if cmd == 'main': return do_main(*args)
    return 'Nothing to do!'
####################################################################################################
if __name__ == '__main__':
    print('autorun: %s' % argv[0])
    Log.start(path.join(BasePath,'bin2html.log'))
    Log.level(trace())
    cmd = argv[1if 1 < len(argvelse 'test'
    etc = argv[2:if 2 < len(argvelse []
    try:
        obj = dispatch(cmd, *etc)
        print(obj)
        Log.info(obj)
    except:
        etypeevaluetb = exc_info()
        ts = extract_tb(tb)
        Log.error('%s: %s' % (etype.__name__,str(evalue)))
        for t in ts[-3:]:
            Log.error('[%d] %s  (%s)' % (t[1], t[2], t[0]))
            Log.error('    %s' % t[3])
        raise
    finally:
        Log.end()
####################################################################################################
'''eof'''