imgtool save to format of given output filename
Updates imgtool to infer, based on output image filename, which format
should be use for output file. Filenames that end with extension `.hex`
are saved in Intel HEX, otherwise saves a binary image.
Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py
index 6116420..3ccd86f 100644
--- a/scripts/imgtool/image.py
+++ b/scripts/imgtool/image.py
@@ -81,40 +81,24 @@
header = struct.pack(e + 'HH', TLV_INFO_MAGIC, TLV_INFO_SIZE + len(self.buf))
return header + bytes(self.buf)
+
class Image():
- @classmethod
- def load(cls, path, pad_header=False, **kwargs):
- """Load an image from a given file"""
- ext = os.path.splitext(path)[1][1:].lower()
- if ext == INTEL_HEX_EXT:
- cls = HexImage
- else:
- cls = BinImage
- obj = cls(**kwargs)
- obj.payload, obj.base_addr = obj.load(path)
-
- # Add the image header if needed.
- if pad_header and obj.header_size > 0:
- if obj.base_addr:
- # Adjust base_addr for new header
- obj.base_addr -= obj.header_size
- obj.payload = (b'\000' * obj.header_size) + obj.payload
-
- obj.check()
- return obj
-
- def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, pad=0,
- align=1, slot_size=0, max_sectors=DEFAULT_MAX_SECTORS,
- overwrite_only=False, endian="little"):
+ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE,
+ pad_header=False, pad=False, align=1, slot_size=0,
+ max_sectors=DEFAULT_MAX_SECTORS, overwrite_only=False,
+ endian="little"):
self.version = version or versmod.decode_version("0")
- self.header_size = header_size or IMAGE_HEADER_SIZE
+ self.header_size = header_size
+ self.pad_header = pad_header
self.pad = pad
self.align = align
self.slot_size = slot_size
self.max_sectors = max_sectors
self.overwrite_only = overwrite_only
self.endian = endian
+ self.base_addr = None
+ self.payload = []
def __repr__(self):
return "<Image version={}, header_size={}, base_addr={}, \
@@ -131,6 +115,43 @@
self.__class__.__name__,
len(self.payload))
+ def load(self, path):
+ """Load an image from a given file"""
+ ext = os.path.splitext(path)[1][1:].lower()
+ if ext == INTEL_HEX_EXT:
+ ih = IntelHex(path)
+ self.payload = ih.tobinarray()
+ self.base_addr = ih.minaddr()
+ else:
+ with open(path, 'rb') as f:
+ self.payload = f.read()
+
+ # Add the image header if needed.
+ if self.pad_header and self.header_size > 0:
+ if self.base_addr:
+ # Adjust base_addr for new header
+ self.base_addr -= self.header_size
+ self.payload = (b'\000' * self.header_size) + self.payload
+
+ self.check()
+
+ def save(self, path):
+ """Save an image from a given file"""
+ if self.pad:
+ self.pad_to(self.slot_size)
+
+ ext = os.path.splitext(path)[1][1:].lower()
+ if ext == INTEL_HEX_EXT:
+ # input was in binary format, but HEX needs to know the base addr
+ if self.base_addr is None:
+ raise Exception("Input file does not provide a base address")
+ h = IntelHex()
+ h.frombytes(bytes=self.payload, offset=self.base_addr)
+ h.tofile(path, 'hex')
+ else:
+ with open(path, 'wb') as f:
+ f.write(self.payload)
+
def check(self):
"""Perform some sanity checking of the image."""
# If there is a header requested, make sure that the image
@@ -243,25 +264,3 @@
pbytes += b'\xff' * (tsize - len(boot_magic))
pbytes += boot_magic
self.payload += pbytes
-
-
-class HexImage(Image):
-
- def load(self, path):
- ih = IntelHex(path)
- return ih.tobinarray(), ih.minaddr()
-
- def save(self, path):
- h = IntelHex()
- h.frombytes(bytes = self.payload, offset = self.base_addr)
- h.tofile(path, 'hex')
-
-class BinImage(Image):
-
- def load(self, path):
- with open(path, 'rb') as f:
- return f.read(), None
-
- def save(self, path):
- with open(path, 'wb') as f:
- f.write(self.payload)
diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py
index 1917a97..a03a164 100755
--- a/scripts/imgtool/main.py
+++ b/scripts/imgtool/main.py
@@ -142,15 +142,16 @@
@click.option('--align', type=click.Choice(['1', '2', '4', '8']),
required=True)
@click.option('-k', '--key', metavar='filename')
-@click.command(help='Create a signed or unsigned image')
+@click.command(help='''Create a signed or unsigned image\n
+ INFILE and OUTFILE are parsed as Intel HEX if the params have
+ .hex extension, othewise binary format is used''')
def sign(key, align, version, header_size, pad_header, slot_size, pad,
max_sectors, overwrite_only, endian, encrypt, infile, outfile):
- img = image.Image.load(infile, version=decode_version(version),
- header_size=header_size, pad_header=pad_header,
- pad=pad, align=int(align), slot_size=slot_size,
- max_sectors=max_sectors,
- overwrite_only=overwrite_only,
- endian=endian)
+ img = image.Image(version=decode_version(version), header_size=header_size,
+ pad_header=pad_header, pad=pad, align=int(align),
+ slot_size=slot_size, max_sectors=max_sectors,
+ overwrite_only=overwrite_only, endian=endian)
+ img.load(infile)
key = load_key(key) if key else None
enckey = load_key(encrypt) if encrypt else None
if enckey:
@@ -159,10 +160,6 @@
if key and not isinstance(key, (keys.RSA2048, keys.RSA2048Public)):
raise Exception("Encryption with sign only available with RSA")
img.create(key, enckey)
-
- if pad:
- img.pad_to(slot_size)
-
img.save(outfile)