///|
fn streaming_error(
code : FirmwareErrorCode,
message : String,
line_index : Int,
column_index : Int,
) -> FirmwareError {
FirmwareError::new(
code,
message,
SourcePosition::column(line_index, column_index),
)
}
///|
fn join_stream_lines(lines : Array[String]) -> String {
let mut text = ""
for index, line in lines {
if index > 0 {
text = text + "\n"
}
text = text + line
}
text
}
///|
/// Decode caller-provided byte chunks without depending on chunk boundaries.
/// Input must be ASCII and each logical record is bounded independently.
pub fn decode_firmware_chunks(
chunks : Array[Bytes],
format? : FirmwareFormat? = None,
policy? : OverlapPolicy = RejectOverlap,
max_line_bytes? : Int = 1024,
) -> Result[ParsedFirmware, FirmwareError] {
if max_line_bytes <= 0 {
return Err(
streaming_error(
ImageInvalidRange,
"maximum record length must be positive",
0,
0,
),
)
}
let lines : Array[String] = []
let mut current = ""
let mut line_index = 0
let mut previous_was_cr = false
for chunk in chunks {
for byte in chunk {
let code = byte.to_int()
if code == 13 {
if current.length() == 0 {
return Err(
streaming_error(
RecordEmpty,
"firmware stream contains an empty record",
line_index,
0,
),
)
}
lines.push(current)
current = ""
line_index = line_index + 1
previous_was_cr = true
} else if code == 10 {
if previous_was_cr {
previous_was_cr = false
} else {
if current.length() == 0 {
return Err(
streaming_error(
RecordEmpty,
"firmware stream contains an empty record",
line_index,
0,
),
)
}
lines.push(current)
current = ""
line_index = line_index + 1
}
} else {
previous_was_cr = false
if code > 127 {
return Err(
streaming_error(
RecordInvalidPrefix,
"firmware stream must contain ASCII text",
line_index,
current.length(),
),
)
}
if current.length() >= max_line_bytes {
return Err(
streaming_error(
RecordTooLong,
"firmware record exceeds the configured byte limit",
line_index,
current.length(),
),
)
}
let character = match code.to_char() {
Some(value) => value.to_string()
None => ""
}
current = current + character
}
}
}
if current.length() > 0 {
lines.push(current)
}
parse_firmware_image(join_stream_lines(lines), format~, policy~)
}