Skip to content

Instantly share code, notes, and snippets.

@lioncash
Last active September 11, 2018 08:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lioncash/d0e1fd8f8390f2462ba4361ed0236f16 to your computer and use it in GitHub Desktop.
Save lioncash/d0e1fd8f8390f2462ba4361ed0236f16 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import argparse
import io
import ntpath
import os
parser = argparse.ArgumentParser()
parser.add_argument("-ns", "--namespace", type=str, help="An optional namespace to enclose the data within.")
parser.add_argument("--std_array", action="store_true", help="Use std::array as the array type enclosing the output data.")
parser.add_argument("files", nargs="+", help="List of files to create output files for.")
args = parser.parse_args()
# Takes a sequence and subdivides it into n-sized tuples
# if the last tuple doesn't have n elements to fit within it
# then it is not an n-sized tuple.
#
# e.g. Given seq = [0, 1, 2, 3, 4, 5, 6, 7]
# group(seq, 4) will be a generator that returns:
# (0, 1, 2, 3) and (4, 5, 6, 7)
#
# but group(seq, 5) will be a generator that returns:
# (0, 1, 2, 3, 4) and (5, 6, 7)
#
def group(lst, n):
for i in range(0, len(lst), n):
val = lst[i:i+n]
if len(val) <= n:
yield tuple(val)
def make_header_string(file_name: str, file_size: int):
header = "#pragma once\n\n"
if args.std_array:
header += "#include <array>\n\n"
if args.namespace is not None:
header += f"namespace {args.namespace} {{\n\n"
name, ext = os.path.splitext(ntpath.basename(file_name))
if args.std_array:
header += f"extern const std::array<unsigned char, {file_size}> {name};\n\n"
else:
header += f"extern const unsigned char {name}[{file_size}];\n\n"
if args.namespace is not None:
header += f"}} // namespace {args.namespace}\n"
return header
def make_and_write_source_file_string(source: io.IOBase, file_name: str, file_size: int):
source.write(f"#include \"{file_name}.h\"\n\n")
if args.namespace is not None:
source.write(f"namespace {args.namespace} {{\n\n")
name, ext = os.path.splitext(ntpath.basename(file_name))
if args.std_array:
source.write(f"const std::array<unsigned char, {file_size}> {name}{{{{\n")
else:
source.write(f"const unsigned char {name}[{file_size}] = {{\n")
with open(file_name, mode="rb", buffering=8192) as binary:
data = binary.read()
while data:
gr = group(data, 12)
for entry in gr:
source.write(" ")
for e in entry:
source.write(f"0x{e:02x},")
source.write("\n")
data = binary.read()
if args.std_array:
source.write("}};\n\n")
else:
source.write("};\n\n")
if args.namespace is not None:
source.write(f"}} // namespace {args.namespace}\n")
def write_header_file(file_name: str, file_size: int):
with open("{}.h".format(file_name), "w") as header:
header.write(make_header_string(file_name, file_size))
def write_source_file(file_name: str, file_size: int):
ext = ".cpp" if args.std_array else ".c"
with open(f"{file_name}{ext}", "w") as source:
make_and_write_source_file_string(source, file_name, file_size)
def convert_file(file_name: str):
file_size = os.stat(file_name).st_size
write_header_file(file_name, file_size)
write_source_file(file_name, file_size)
for file_name in args.files:
try:
convert_file(file_name)
except IOError as e:
print(f"Unable to open file \"{file}\": {e.strerror}")
@lioncash
Copy link
Author

Examples of running the script:

./data_to_hex.py --std_array File1, File2, File3, File4, File5

will produce cpp and h files for all of the files passed to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment