Source code for mltk.utils.bin2header

"""Utilities for generating a "C" header file from binary data

See the source code on Github: `mltk/utils/bin2header.py <https://github.com/siliconlabs/mltk/blob/master/mltk/utils/bin2header.py>`_
"""
import argparse
import sys
import os
import io
from typing import Union, List



[docs]def bin2header( input:Union[str,bytes,List[int],List[float]], # pylint: disable=redefined-builtin output_path:Union[bool, str, io.IOBase]=None, var_name:str='DATA', length_var_name:str='DATA_LENGTH', dtype:str='const unsigned char', attributes:str=None, prepend_lines:List[int]=None, fmt_str:str=None, prepend_header=True ) -> str: """Generate C header file from binary input file Arguments: input: Either path to binary file or binary contents of previously loaded file, or list of integers or floats output_path: Output file path or io stream. Use input with .h appended if True var_name: Name of C array length_var_name: Name of variable to hold length of C array in bytes attributes: Attributes to prepend C array variable dtype: The data type of the C array prepend_lines: List of C lines of code to prepend before the generated array data e.g.: #include <stdint.h> fmt_str: The formatting string to use for each entry in the data, e.g.: 0x{:02X} If omitted then it is automatically determined based on the given data Returns: Generated header as a string """ def _get_ascii(c): if c >= 32 and c < 127 and chr(c) not in '*#\\': return chr(c) return '.' if attributes is None: attributes = '' if isinstance(input, str): if output_path is True: output_path = input + '.h' with open(input, 'rb') as f: data = f.read() else: data = input out = '' if prepend_header: out += 'pragma once\n' out += '// The following was automatically generated by bin2header.py\n\n' if prepend_lines: if isinstance(prepend_lines, str): prepend_lines = list(prepend_lines) for line in prepend_lines: if not line.endswith(('\n', '\r')): line += '\n' out += line out += '\n' out += f'const unsigned int {length_var_name} = {len(data)};\n' out += f'{dtype} {var_name}[{len(data)}] {attributes} =\n{{\n' l = [ data[i:i+16] for i in range(0, len(data), 16) ] if fmt_str is None: if isinstance(data, (bytes,bytearray)): fmt_str = '0x{:02X}' elif isinstance(data[0], float): fmt_str = '{:6.3f}' else: fmt_str = '{:5d}' max_line_len = 0 for i, x in enumerate(l): line = ','.join([fmt_str.format(c) for c in x ]) if len(line) > max_line_len: max_line_len = len(line) + 1 out += line if i < len(l) -1: out += ',' else: out += ' ' * (max_line_len - len(line)) if isinstance(data, (bytes,bytearray)): out += f' /* {i*16:6d}: ' out += ''.join([_get_ascii(c) for c in x]) out += ' */' out += '\n' out += '};\n' if output_path: if isinstance(output_path, str): with open(output_path, 'w') as f: f.write(out) elif isinstance(output_path, io.IOBase): output_path.write(out) return out
[docs]def main(): parser = argparse.ArgumentParser(description='Generate C header file from binary input file') parser.add_argument('input', help='Input file') parser.add_argument('-o', '--output', required=False , help='Output file. Use input with .h appended if omitted') parser.add_argument('-n', '--name', required=False , help='Name of C array. Use input filename if omitted') parser.add_argument('-a', '--attributes', default=None, help='Attributes to prepend C array variable') args = parser.parse_args() if not args: return 1 if not args.name: args.name = os.path.splitext(os.path.basename(args.input))[0].upper().replace('-', '_').replace(' ', '_').replace('.', '_') bin2header( input=args.input, output_path=args.output, var_name=args.name, attributes=args.attributes, ) return 0
if __name__ == '__main__': sys.exit(main())