2021-10-03 15:39:32 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
import os, re, sys, struct
|
|
|
|
import textwrap
|
|
|
|
import traceback
|
|
|
|
|
|
|
|
|
|
|
|
def sanitize_name(name):
|
|
|
|
# replace special characters with underscores
|
|
|
|
name = re.sub('[^a-zA-Z0-9_]', '_', name)
|
|
|
|
# clean up
|
|
|
|
name = name.strip('_')
|
|
|
|
|
|
|
|
# not needed: 'DATA_' prefix
|
|
|
|
#if name[0] in "0123456789": name = '_' + name
|
|
|
|
|
|
|
|
return name
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
description="Convert data files into byte arrays in a C header")
|
|
|
|
|
2021-12-07 03:16:01 +00:00
|
|
|
parser.add_argument('--width', type=int, default=8, help="data width")
|
2021-10-03 15:39:32 +00:00
|
|
|
parser.add_argument('input', nargs='*', action='append',
|
|
|
|
help="Input data file to convert to a header file. If "
|
|
|
|
+"none are specified, data is read from standard input.")
|
|
|
|
parser.add_argument('--output', type=str, default=None,
|
|
|
|
help="Output header file path, standard output if none specified")
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
#print(repr(args), file=sys.stderr)
|
|
|
|
|
|
|
|
inputfiles = args.input[0]
|
|
|
|
datafiles = {}
|
|
|
|
|
|
|
|
if len(inputfiles) == 0:
|
|
|
|
# need to read from stdio
|
|
|
|
datafiles['data'] = sys.stdin.buffer.read()
|
|
|
|
else:
|
|
|
|
for path in inputfiles:
|
|
|
|
# cannot use os.access, POSIX-only
|
|
|
|
if not os.path.exists(path) or os.path.isdir(path):
|
|
|
|
print("ERROR: input path '%s' does not exist, or is not a file" % path)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
# get base name of the path (no folder names, no extension)
|
|
|
|
name = os.path.splitext(os.path.split(path)[1])[0]
|
|
|
|
# make it usable for C code names
|
|
|
|
name = sanitize_name(name)
|
|
|
|
|
|
|
|
# now read the data
|
|
|
|
data = None
|
|
|
|
try:
|
|
|
|
with open(path, 'rb') as f:
|
|
|
|
data = f.read()
|
|
|
|
except IOError:
|
|
|
|
print("ERROR: input file '%s' not readable" % path)
|
|
|
|
traceback.print_exc()
|
|
|
|
sys.exit(1)
|
|
|
|
|
2021-11-15 14:31:56 +00:00
|
|
|
wlut = {8:'B',16:'H',32:'I',64:'Q'}
|
|
|
|
denom= args.width//8
|
|
|
|
data = struct.unpack('<'+((wlut[args.width])*(len(data)//denom)), data)
|
2021-10-03 15:39:32 +00:00
|
|
|
|
|
|
|
# add it to the list
|
|
|
|
datafiles[name] = data
|
|
|
|
|
|
|
|
#print(repr(datafiles), file=sys.stderr)
|
|
|
|
|
|
|
|
outname = "hardcoded_data"
|
|
|
|
if args.output is not None:
|
|
|
|
outname = os.path.splitext(os.path.split(args.output)[1])[0]
|
|
|
|
outname = sanitize_name(outname)
|
|
|
|
|
|
|
|
# generate the C source code: one uint8_t array for each data file
|
|
|
|
# variable name is "DATA_<datafile>"
|
|
|
|
# (width=84 is the equivalent of 16 bytes/line)
|
|
|
|
headersrc = '\n\n'.join(
|
2021-11-15 14:31:56 +00:00
|
|
|
"static uint%d_t DATA_%s[%d] = {\n%s\n};" % (args.width, name, len(data), \
|
|
|
|
textwrap.fill(', '.join(("0x%0"+str(args.width//4)+"x") % b for b in data), width=81,
|
2021-10-03 15:39:32 +00:00
|
|
|
initial_indent=" ", subsequent_indent=" ")
|
|
|
|
) for name, data in datafiles.items()
|
|
|
|
)
|
|
|
|
|
|
|
|
# a C header needs include guards
|
|
|
|
headersrc = """
|
|
|
|
#ifndef AUTOGEN_{0}_H_
|
|
|
|
#define AUTOGEN_{0}_H_
|
|
|
|
|
|
|
|
{1}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
""".format(outname.upper(), headersrc)
|
|
|
|
|
|
|
|
#print(headersrc, file=sys.stderr)
|
|
|
|
|
|
|
|
if args.output is None:
|
|
|
|
# no output specified -> output to stdout
|
|
|
|
sys.stdout.write(headersrc)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
with open(args.output, 'w') as f:
|
|
|
|
f.write(headersrc)
|
|
|
|
except IOError:
|
|
|
|
print("ERROR: output file '%s' not writable" % args.output)
|
|
|
|
traceback.print_exc()
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|
|
|
|
|