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