///|
fn hex_address(value : UInt64) -> String {
"0x" + value.to_string(radix=16)
}
///|
fn optional_address_json(value : UInt64?) -> Json {
match value {
Some(address) => Json::string(hex_address(address))
None => Json::null()
}
}
///|
fn audit_severity_name(value : AuditSeverity) -> String {
match value {
AuditInfo => "info"
AuditWarning => "warning"
AuditError => "error"
}
}
///|
fn difference_kind_name(value : ByteDifferenceKind) -> String {
match value {
ByteAdded => "added"
ByteRemoved => "removed"
ByteChanged => "changed"
}
}
///|
fn optional_byte_json(value : Byte?) -> Json {
match value {
Some(byte) => Json::number(byte.to_double())
None => Json::null()
}
}
///|
/// Render a compact deterministic human-readable image audit.
pub fn render_image_text(image : FirmwareImage, audit : ImageAudit) -> String {
let mut result = "firmware-image segments=" +
audit.segment_count().to_string() +
" bytes=" +
audit.total_bytes().to_string() +
" gaps=" +
audit.gap_count().to_string() +
" errors=" +
audit.error_count().to_string() +
" warnings=" +
audit.warning_count().to_string()
match image.lowest_address() {
Some(value) => result = result + " lowest=" + hex_address(value)
None => ()
}
match image.highest_address() {
Some(value) => result = result + " highest=" + hex_address(value)
None => ()
}
match image.entry_point() {
Some(value) => result = result + " entry=" + hex_address(value)
None => ()
}
for finding in audit.findings() {
result = result +
"\n" +
audit_severity_name(finding.severity()) +
" " +
finding.code() +
": " +
finding.message()
match finding.address() {
Some(value) => result = result + " address=" + hex_address(value)
None => ()
}
}
result
}
///|
/// Render image structure and audit findings using the standard JSON type.
pub fn render_image_json(image : FirmwareImage, audit : ImageAudit) -> String {
let segments : Array[Json] = []
for segment in image.segments() {
segments.push(
Json::object({
"address": Json::string(hex_address(segment.address())),
"end_exclusive": Json::string(hex_address(segment.end_exclusive())),
"length": Json::number(segment.length().to_double()),
}),
)
}
let gaps : Array[Json] = []
for gap in image.gaps() {
gaps.push(
Json::object({
"start": Json::string(hex_address(gap.start())),
"end_exclusive": Json::string(hex_address(gap.end_exclusive())),
"length": Json::string(gap.length().to_string()),
}),
)
}
let findings : Array[Json] = []
for finding in audit.findings() {
findings.push(
Json::object({
"code": Json::string(finding.code()),
"severity": Json::string(audit_severity_name(finding.severity())),
"message": Json::string(finding.message()),
"address": optional_address_json(finding.address()),
}),
)
}
Json::object({
"type": Json::string("firmware_image"),
"segment_count": Json::number(audit.segment_count().to_double()),
"total_bytes": Json::number(audit.total_bytes().to_double()),
"gap_count": Json::number(audit.gap_count().to_double()),
"lowest_address": optional_address_json(image.lowest_address()),
"highest_address": optional_address_json(image.highest_address()),
"entry_point": optional_address_json(image.entry_point()),
"accepted": Json::boolean(audit.accepted()),
"segments": Json::array(segments),
"gaps": Json::array(gaps),
"findings": Json::array(findings),
}).stringify()
}
///|
/// Render byte-level comparison evidence using the standard JSON type.
pub fn render_comparison_json(comparison : ImageComparison) -> String {
let differences : Array[Json] = []
for difference in comparison.differences() {
differences.push(
Json::object({
"address": Json::string(hex_address(difference.address())),
"kind": Json::string(difference_kind_name(difference.kind())),
"left": optional_byte_json(difference.left()),
"right": optional_byte_json(difference.right()),
}),
)
}
Json::object({
"type": Json::string("firmware_image_comparison"),
"identical": Json::boolean(comparison.identical()),
"added": Json::number(comparison.added_count().to_double()),
"removed": Json::number(comparison.removed_count().to_double()),
"changed": Json::number(comparison.changed_count().to_double()),
"differences": Json::array(differences),
}).stringify()
}