1#!/usr/bin/env python3 2# GStreamer 3# Copyright (C) 2020 Matthew Waters <matthew@centricular.com> 4# 5# This library is free software; you can redistribute it and/or 6# modify it under the terms of the GNU Library General Public 7# License as published by the Free Software Foundation; either 8# version 2 of the License, or (at your option) any later version. 9# 10# This library is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13# Library General Public License for more details. 14# 15# You should have received a copy of the GNU Library General Public 16# License along with this library; if not, write to the 17# Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18# Boston, MA 02111-1307, USA. 19# 20 21import binascii 22import sys 23import os 24import argparse 25 26autogenerated_notice = """/* 27 * This file is autogenerated by bin2array.py 28 */ 29""" 30 31def make_sublist_group (lst: list, grp: int) -> list: 32 """ 33 Group list elements into sublists. 34 make_sublist_group([1, 2, 3, 4, 5, 6, 7], 3) = [[1, 2, 3], [4, 5, 6], 7] 35 """ 36 return [lst[i:i+grp] for i in range(0, len(lst), grp)] 37 38def generate_c_array_data (bindata: bytes, 39 element_prefix: str, 40 element_size: int, 41 element_suffix: str, 42 newline_value: str, 43 newline_after: int, 44 element_separator: str) -> str: 45 """ 46 Generate the contents of a C array as a hex string 47 e.g: 48 0x10, 0x20, 0x30, 0x40, 49 0x50, 0x60, 0x70, 0x80, 50 """ 51 hexstr = binascii.hexlify(bindata).decode("UTF-8") 52 array = [] 53 for i in range(0, len(hexstr), 2 * element_size): 54 array += [element_prefix + hexstr[i:i + 2 * element_size] + element_suffix] 55 56 if newline_after: 57 array = make_sublist_group(array, newline_after) 58 else: 59 array = [array,] 60 61 return newline_value.join([element_separator.join(e) + element_separator for e in array]) 62 63def decorate_c_array_data (hexdata: str, 64 var_name: str, 65 var_type: str, 66 newline_value: str): 67 """ 68 Place @hexdata into a valid C array named @var_name of C type @var_type. 69 """ 70 ret = var_type + " " + var_name + "[] = {" + newline_value 71 ret += hexdata + newline_value 72 ret += "};" + newline_value 73 return ret 74 75def main(args): 76 parser = argparse.ArgumentParser(description='Convert binary file to C-style array initializer.') 77 parser.add_argument("-i", "--input", help="the file to be converted") 78 parser.add_argument("--output", help="c source file location") 79 parser.add_argument("--header-output", help="c header file location") 80 parser.add_argument("--linebreak", type=int, help="add linebreak after every N element") 81 parser.add_argument("--linebreak-value", default="\n", help="use what sequence to break lines, defaults to \"\\n\"") 82 parser.add_argument("--separator", default=", ", help="use what to separate elements, defaults to \", \"") 83 parser.add_argument("--array-name", default="array_data", help="name of the resulting array") 84 parser.add_argument("--element-type", default="char", help="C type for the array") 85 parser.add_argument("--element-size", type=int, default=1, help="how many bytes per element") 86 parser.add_argument("--element-prefix", default="0x", help="string to be added to the head of element, defaults to \"0x\"") 87 parser.add_argument("--element-suffix", default="", help="string to be added to the tail of element, defaults to none") 88 parser.add_argument("--c-include", help="header to include") 89 args = parser.parse_args(args) 90 91 with open(args.input, 'rb') as f: 92 file_content = f.read() 93 94 # don't deal with unaligned content 95 assert len(file_content) % args.element_size == 0 96 97 # get a relative path from the source file to the header to use in an #include 98 source_to_header = os.path.relpath (os.path.dirname (args.header_output), 99 os.path.dirname (args.output)) 100 101 ret = autogenerated_notice 102 ret += "#include \"" 103 ret += os.path.join (source_to_header, 104 os.path.basename (args.header_output)) 105 ret += "\"" + args.linebreak_value 106 107 arr_data = generate_c_array_data (file_content, 108 args.element_prefix, 109 args.element_size, 110 args.element_suffix, 111 args.linebreak_value, 112 args.linebreak, 113 args.separator) 114 ret += decorate_c_array_data (arr_data, 115 args.array_name, 116 args.element_type, 117 args.linebreak_value) 118 119 with open (args.output, 'w') as f: 120 f.write (ret) 121 122 # write companion header 123 with open(args.header_output, 'w') as f: 124 f.write (autogenerated_notice) 125 if args.c_include: 126 f.write ("#include <" + args.c_include + ">" + args.linebreak_value) 127 f.write ("extern " + args.element_type + " " + args.array_name + "[];" + args.linebreak_value) 128 f.write ("#define " + args.array_name + "_size " + str(len(file_content) // args.element_size)) 129 130if __name__ == "__main__": 131 sys.exit(main(sys.argv[1:])) 132