fwtool package
Submodules
fwtool.cli module
Firmware header utility.
A command-line interface for working with a custom firmware header placed at the beginning of a binary image.
Header format
The first 16 bytes of the header contain metadata fields. The remaining bytes up to the configured header size are filled with 0xFF padding.
0x00..0x03 magic: b”XLAB” 0x04..0x07 version: little-endian bytes [0x00, patch, minor, major] 0x08..0x0B size: payload size in bytes, little-endian uint32 0x0C..0x0F crc32: CRC-32/MPEG-2 of payload, little-endian uint32 0x10..end padding: 0xFF
The total header size is configurable via --header-size and must be a
power of two so that the application vector table that follows it is
correctly aligned. The default is 512 bytes.
Supported operations
attach: prepend a new header to a raw firmware binary
edit: replace the header of an already packaged binary
inspect: print header contents
verify: verify header magic, payload size, and payload CRC
Examples
- Attach a header (default 512 bytes):
fwtool attach firmware.bin 1.2.3 out.bin
- Attach with custom header size:
fwtool attach firmware.bin 1.2.3 out.bin –header-size 1024
- Edit an existing header:
fwtool edit packaged.bin 1.2.4 out.bin
- Edit in place:
fwtool edit packaged.bin 1.2.4 –in-place
- Inspect header:
fwtool inspect packaged.bin
- Inspect as JSON:
fwtool inspect packaged.bin –json
- Verify header:
fwtool verify packaged.bin
- Verify quietly:
fwtool verify packaged.bin –quiet
- class fwtool.cli.HeaderInfo(magic, version, size, crc)[source]
Bases:
objectParsed header fields extracted from a packaged firmware binary.
- crc: int
- classmethod from_bytes(data)[source]
Parse header info fields from a binary blob.
Only the first
HEADER_INFO_SIZEbytes are read.- Parameters:
data (
bytes) – Byte buffer containing at least HEADER_INFO_SIZE bytes.- Return type:
- Returns:
Parsed HeaderInfo object.
- Raises:
ValueError – If fewer than HEADER_INFO_SIZE bytes are provided.
- magic: bytes
- size: int
- to_dict()[source]
Convert the header to a JSON-friendly dictionary.
- Return type:
dict- Returns:
Dictionary representation of the header.
- version: VersionInfo
- class fwtool.cli.VerificationResult(magic_ok, size_ok, crc_ok, header, header_size, payload_size, payload_crc)[source]
Bases:
objectVerification outcome for an existing packaged firmware binary.
- crc_ok: bool
- header: HeaderInfo
- header_size: int
- magic_ok: bool
- property ok: bool
Return whether all verification checks passed.
- Returns:
True if magic, size, and CRC checks all passed.
- payload_crc: int
- payload_size: int
- size_ok: bool
- class fwtool.cli.VersionInfo(major=0, minor=0, patch=0)[source]
Bases:
objectSemantic firmware version stored as major.minor.patch.
- classmethod from_bytes(data)[source]
Parse the 4-byte packed version field from the binary header.
- The byte layout is:
[0x00, patch, minor, major]
- Parameters:
data (
bytes) – 4-byte version field.- Return type:
- Returns:
Parsed VersionInfo object.
- Raises:
ValueError – If the input length is not 4 bytes.
- classmethod from_string(value)[source]
Parse a version string into a VersionInfo instance.
- Accepted formats include:
“1” “1.2” “1.2.3”
Missing components are padded with zero. Extra components are ignored.
- Parameters:
value (
str) – Version string.- Return type:
- Returns:
Parsed VersionInfo object.
- Raises:
ValueError – If version components are out of range or not integers.
ValueError – If version string is empty
- major: int = 0
- minor: int = 0
- patch: int = 0
- to_bytes()[source]
Convert the version into the 4-byte packed header representation.
- Return type:
bytes- Returns:
Packed version bytes as [0x00, patch, minor, major].
- fwtool.cli.add_binary_arg(parser)[source]
Add the
binarypositional argument to a subparser.- Parameters:
parser (
ArgumentParser) – Subparser to add the argument to.- Return type:
None
- fwtool.cli.add_header_size_arg(parser, default=None, help_suffix='')[source]
Add the
--header-sizeoption to a subparser.- Parameters:
parser (
ArgumentParser) – Subparser to add the argument to.default (
int|None) – Default value; None means “infer from file”.help_suffix (
str) – Extra text appended to the help string.
- Return type:
None
- fwtool.cli.add_json_arg(parser)[source]
Add the
--jsonflag to a subparser.- Parameters:
parser (
ArgumentParser) – Subparser to add the argument to.- Return type:
None
- fwtool.cli.add_output_args(parser)[source]
Add mutually exclusive
output/--in-placearguments to a subparser.- Parameters:
parser (
ArgumentParser) – Subparser to add the arguments to.- Return type:
None
- fwtool.cli.add_version_arg(parser)[source]
Add the
versionpositional argument to a subparser.- Parameters:
parser (
ArgumentParser) – Subparser to add the argument to.- Return type:
None
- fwtool.cli.build_header(payload, version, header_size)[source]
Build a new firmware header for the given payload and version.
The size and CRC are computed from the payload only. The header is padded with 0xFF to header_size bytes.
- Parameters:
payload (
bytes) – Firmware payload bytes.version (
VersionInfo) – Firmware version to store in the header.header_size (
int) – Total header size in bytes.
- Return type:
bytes- Returns:
Complete header of exactly header_size bytes.
- Raises:
RuntimeError – If the generated header size does not match.
- fwtool.cli.build_parser()[source]
Build the top-level argument parser with subcommands.
- Subcommands:
attach: attach a new header to a raw firmware binary edit: replace the header of a packaged binary inspect: print parsed header fields verify: verify header against the payload
- Return type:
ArgumentParser- Returns:
Configured ArgumentParser instance.
- fwtool.cli.handle_attach(args)[source]
Handle the
attachsubcommand.Reads a raw firmware binary, builds a new header, and writes the combined packaged binary.
- Parameters:
args (
Namespace) – Parsed CLI arguments for the attach subcommand.- Return type:
None
- fwtool.cli.handle_edit(args)[source]
Handle the
editsubcommand.Reads a packaged firmware binary, strips its existing header, builds a new header with the given version, and writes the result.
- Parameters:
args (
Namespace) – Parsed CLI arguments for the edit subcommand.- Return type:
None
- fwtool.cli.handle_inspect(args)[source]
Handle the
inspectsubcommand.Reads a packaged firmware binary and prints parsed header information.
- Parameters:
args (
Namespace) – Parsed CLI arguments for the inspect subcommand.- Return type:
None
- fwtool.cli.handle_verify(args)[source]
Handle the
verifysubcommand.Reads a packaged firmware binary, verifies its header against the payload, and exits with 0 on success or 1 on failure.
- Parameters:
args (
Namespace) – Parsed CLI arguments for the verify subcommand.- Return type:
None
- fwtool.cli.infer_header_size(data)[source]
Infer the header size of a packaged binary from its stored payload size field.
- The header size is calculated as:
len(data) - stored_payload_size
- Parameters:
data (
bytes) – Packaged binary data.- Return type:
int- Returns:
Inferred header size in bytes.
- Raises:
ValueError – If the file is too small, the stored payload size is invalid, or the inferred header size is unreasonable.
- fwtool.cli.main()[source]
Parse arguments and dispatch to the appropriate subcommand handler.
- Return type:
None
- fwtool.cli.parse_header(data)[source]
Parse and validate the header from a packaged firmware binary.
- Parameters:
data (
bytes) – Input binary data that should start with a valid header.- Return type:
- Returns:
Parsed HeaderInfo.
- Raises:
ValueError – If the input is too small or does not begin with the expected magic.
- fwtool.cli.print_header(info, as_json=False)[source]
Print parsed header information in text or JSON format.
- Parameters:
info (
HeaderInfo) – Parsed header information.as_json (
bool) – If True, print JSON instead of human-readable text.
- Return type:
None
- fwtool.cli.print_verification_result(result, as_json=False)[source]
Print a verification result in text or JSON format.
- Parameters:
result (
VerificationResult) – Verification result to print.as_json (
bool) – If True, print JSON instead of human-readable text.
- Return type:
None
- fwtool.cli.read_binary(path)[source]
Read the full contents of a binary file.
- Parameters:
path (
Path) – Input file path.- Return type:
bytes- Returns:
File contents as bytes.
- fwtool.cli.resolve_header_size_for_build(args, data=None)[source]
Determine and validate the header size for attach/edit operations.
For attach mode the default is
DEFAULT_HEADER_SIZE. For edit mode the size is inferred from the existing file when--header-sizeis not provided.- Parameters:
args (
Namespace) – Parsed CLI arguments (must containheader_size).data (
bytes|None) – Existing packaged binary data used for inference, or None.
- Return type:
int- Returns:
Validated header size.
- Raises:
ValueError – If the resolved size is invalid.
- fwtool.cli.resolve_header_size_for_verify(args, data)[source]
Determine the header size for verification.
If
--header-sizeis provided it is used directly; otherwise the size is inferred from the stored payload size.- Parameters:
args (
Namespace) – Parsed CLI arguments (must containheader_size).data (
bytes) – Packaged binary data.
- Return type:
int- Returns:
Header size in bytes.
- Raises:
ValueError – If inference fails and no explicit size was given.
- fwtool.cli.split_payload_from_packaged(data, header_size)[source]
Split a packaged binary into header and payload.
- Parameters:
data (
bytes) – Packaged binary data.header_size (
int) – Expected header size in bytes.
- Return type:
tuple[bytes,bytes]- Returns:
A tuple of (existing_header, payload).
- Raises:
ValueError – If the data is smaller than header_size.
- fwtool.cli.validate_header_size(size)[source]
Validate that a header size is acceptable.
The size must be at least
HEADER_INFO_SIZEbytes and must be a power of two so that the vector table following it in flash is correctly aligned.- Parameters:
size (
int) – Proposed header size in bytes.- Raises:
ValueError – If the size is too small or not a power of two.
- Return type:
None
- fwtool.cli.validate_input_file(path)[source]
Validate that the input path exists and refers to a regular file.
- Parameters:
path (
Path) – Input file path.- Raises:
FileNotFoundError – If the file does not exist.
ValueError – If the path exists but is not a regular file.
- Return type:
None
- fwtool.cli.verify_header(data, header_size)[source]
Verify the header of a packaged firmware binary against its payload.
- The following checks are performed:
magic matches
HEADER_MAGICstored size matches actual payload size
stored CRC matches CRC-32/MPEG-2 of payload
- Parameters:
data (
bytes) – Packaged firmware binary data.header_size (
int) – Header size in bytes used to locate the payload.
- Return type:
- Returns:
VerificationResult with parsed header fields and check results.
- Raises:
ValueError – If the input is too small to contain a header.
- fwtool.cli.write_binary(path, data)[source]
Write binary data to the given path, creating parent directories if needed.
- Parameters:
path (
Path) – Output file path.data (
bytes) – Data to write.
- Return type:
None
- fwtool.cli.write_binary_in_place(path, data)[source]
Safely replace an existing file with new binary data.
The replacement is done by writing to a temporary file in the same directory, flushing it to disk, and then atomically replacing the target file.
- Parameters:
path (
Path) – File to replace.data (
bytes) – New file contents.
- Raises:
OSError – If writing or replacement fails.
- Return type:
None
- fwtool.cli.write_output(path, data, in_place)[source]
Write output data to the appropriate destination.
- Parameters:
path (
Path|None) – Output file path, or None if in-place is used.data (
bytes) – Data to write.in_place (
Path|None) – Original input path for in-place replacement, or None.
- Return type:
None