1#!/usr/bin/env python3 2# 3# Copyright (c) 2017 Intel Corporation 4# Copyright (c) 2025 Siemens AG 5# 6# SPDX-License-Identifier: Apache-2.0 7 8 9"""Convert a file to a list of hex characters 10 11The list of hex characters can then be included to a source file. Optionally, 12the output can be compressed. 13 14""" 15 16import argparse 17import codecs 18import gzip 19import io 20 21 22def parse_args(): 23 global args 24 25 parser = argparse.ArgumentParser( 26 description=__doc__, 27 formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) 28 29 parser.add_argument("-f", "--file", required=True, help="Input file") 30 parser.add_argument("-o", "--offset", type=lambda x: int(x, 0), default=0, 31 help="Byte offset in the input file") 32 parser.add_argument("-l", "--length", type=lambda x: int(x, 0), default=-1, 33 help="""Length in bytes to read from the input file. 34 Defaults to reading till the end of the input file.""") 35 parser.add_argument("-m", "--format", default="list", 36 help="Output format: 'list' (default) or 'literal' (string literal)") 37 parser.add_argument("-g", "--gzip", action="store_true", 38 help="Compress the file using gzip before output") 39 parser.add_argument("-t", "--gzip-mtime", type=int, default=0, 40 nargs='?', const=None, 41 help="""mtime seconds in the gzip header. 42 Defaults to zero to keep builds deterministic. For 43 current date and time (= "now") use this option 44 without any value.""") 45 args = parser.parse_args() 46 47 48def get_nice_string(list_or_iterator): 49 # Convert into comma separated list form. 50 s = ", ".join("0x" + str(x) for x in list_or_iterator) 51 52 # Format the list to eight values per line. 53 return "\n".join(s[i:i+47] for i in range(0, len(s), 48)) 54 55 56def make_hex(chunk): 57 hexdata = codecs.encode(chunk, 'hex').decode("utf-8") 58 hexlist = map(''.join, zip(*[iter(hexdata)] * 2)) 59 print(get_nice_string(hexlist) + ',') 60 61 62def make_string_literal(chunk): 63 hexdata = codecs.encode(chunk, 'hex').decode("utf-8") 64 hexlist = map(''.join, zip(*[iter(hexdata)] * 2)) 65 print(''.join("\\x" + str(x) for x in hexlist), end='') 66 67 68def main(): 69 parse_args() 70 71 if args.gzip: 72 with io.BytesIO() as content: 73 with open(args.file, 'rb') as fg: 74 fg.seek(args.offset) 75 with gzip.GzipFile(fileobj=content, mode='w', 76 mtime=args.gzip_mtime, 77 compresslevel=9) as gz_obj: 78 gz_obj.write(fg.read(args.length)) 79 80 content.seek(0) 81 if args.format == "literal": 82 print('"', end='') 83 for chunk in iter(lambda: content.read(1024), b''): 84 make_string_literal(chunk) 85 print('"', end='') 86 else: 87 for chunk in iter(lambda: content.read(1024), b''): 88 make_hex(chunk) 89 else: 90 with open(args.file, "rb") as fp: 91 fp.seek(args.offset) 92 93 if args.format == "literal": 94 if args.length < 0: 95 print('"', end='') 96 for chunk in iter(lambda: fp.read(1024), b''): 97 make_string_literal(chunk) 98 print('"', end='') 99 else: 100 print('"', end='') 101 remainder = args.length 102 for chunk in iter(lambda: fp.read(min(1024, remainder)), b''): 103 make_string_literal(chunk) 104 remainder = remainder - len(chunk) 105 print('"', end='') 106 107 else: 108 if args.length < 0: 109 for chunk in iter(lambda: fp.read(1024), b''): 110 make_hex(chunk) 111 else: 112 remainder = args.length 113 for chunk in iter(lambda: fp.read(min(1024, remainder)), b''): 114 make_hex(chunk) 115 remainder = remainder - len(chunk) 116 117 118if __name__ == "__main__": 119 main() 120