hex_dump.py

#!/usr/bin/python3
# ==============================================================
# hex dump
# ==============================================================

# --------------------------------------------------------------
# ---- display a chunk of bytes in hex and ASCII
# ----
# ---- byte array chunk should 16 bytes or less
# ----
# ---- byte array is a slice of the original array
# ---- starting at the start index
# --------------------------------------------------------------

def print_chunk(byt_ary,start_index):

    ln = len(byt_ary)

    print(f'{start_index:08} ',end='')

    for i in range(16):
        if i < ln:
            byt = byt_ary[i]
            print(f'{byt:02x} ',end='')
        else:
            print('   ',end='')

    for i in range(16):
        if i < ln:
            byt = byt_ary[i]
            if byt < 32 or byt > 126:  # printable ASCII char?
                bchr = '.'
            else:
                bchr = chr(byt)
        else:
            bchr = ' '
        print(bchr,end='')

    print()

# --------------------------------------------------------------
# ---- print title
# --------------------------------------------------------------

def print_hex_dump_title():
    
    title = '-offset- ' +\
            '--------------------- hex ---------------------' +\
            ' ---- ascii -----'           
            
    print(title)

# --------------------------------------------------------------
# ---- hex_dump start index and length
# ----
# ---- byt_ary  byte array to hex dump
# ---- start    starting offset (index) to display
# ---- length   number of bytes to display
# --------------------------------------------------------------

def hex_dump_length(byt_ary,start,length):

    if start  < 0: return False
    if length < 1: return False

    end = start + length - 1

    if end < start: return False

    return hex_dump(byt_ary,start,end)

# --------------------------------------------------------------
# ---- hex_dump start/end index (inclusive)
# ----
# ---- byt_ary  byte array to hex dump
# ---- start    starting offset (index) to display
# ---- end      ending   offset (index) to display
# --------------------------------------------------------------

def hex_dump(byt_ary,start,end):

    byt_ary_len =len(byt_ary)

    # --- validate start,end array indexes

    if start > byt_ary_len - 1:
        start = byt_ary_len - 1 
    if end > byt_ary_len - 1:
        end = byt_ary_len - 1    
    if end < start:
        print(f'error: end < start  {end} < {start}')
        return False    

    # --- display hex dump chunks (16 bytes or less)

    print_hex_dump_title()
    
    while start <= end:

        print_chunk(byt_ary[start:end+1],start)

        start += 16

    return True
                
# --------------------------------------------------------------
# ---- main
# --------------------------------------------------------------

if __name__ ==  '__main__':
    
    import user_interface as ui

    jpeg_file_path = 'mona_lisa_small_a.jpg'

    with open(jpeg_file_path,'rb') as file:
        jpeg_bytes = file.read()

    def test_start_end():

        print()
        print(f'bytearray length = {len(jpeg_bytes)}')
        
        while True:

            # ---- test start/index
            
            print()
            s = ui.get_user_input('Enter start index: ')
            if not s: break
            
            tf,start = ui.is_integer(s)
            if tf is not True or start < 0:
                print(f'bad start index {s}')
                continue

            # ---- end index
                
            print()
            s = ui.get_user_input('Enter end index: ')
            if not s: break
            
            tf,end = ui.is_integer(s)
            if tf is not True or end < start:
                print(f'bad end index {s}')
                continue
                
            print()
            tf = hex_dump(jpeg_bytes,start,end)

            if tf is not True:
                print('OOPS!')

    def test_start_length():

        print()
        print(f'bytearray length = {len(jpeg_bytes)}')
        
        while True:

            # ---- test start/length
            
            print()
            s = ui.get_user_input('Enter start index: ')
            if not s: break
            
            tf,start = ui.is_integer(s)
            if tf is not True or start < 0:
                print(f'bad start index {s}')
                continue

            # ---- length
                
            print()
            s = ui.get_user_input('Enter length: ')
            if not s: break
            
            tf,length = ui.is_integer(s)
            if tf is not True or length < 1:
                print(f'bad length {s}')
                continue
                
            print()
            tf = hex_dump_length(jpeg_bytes,start,length)

            if tf is not True:
                print('OOPS!')

    # ---- which test

    print()
    s = ui.get_user_input('Test end or length [end,len]: ')
    if not s: exit()
    
    if s[0] =='l' or s[0] == 'L':
        test_start_length()
    elif s[0] == 'e' or s[0] == 'E':
        test_start_end()
    else:
        print()
        print('bad_selection')