use crate::error::{Error, Result};
use crate::length::{self, LengthForm};
use crate::tag::ApduTag;
use broadcast_common::len::need_out;
pub mod application_info;
pub mod ca_info;
pub mod ca_pmt;
pub mod ca_pmt_reply;
pub mod date_time;
pub mod host_control;
pub mod low_speed_comms;
pub mod mmi_close;
pub mod mmi_display;
pub mod mmi_high;
pub mod resource_manager;
pub(crate) fn reject_trailing_body(body: &[u8], expected: usize, what: &'static str) -> Result<()> {
if body.len() > expected {
return Err(Error::InvalidObject {
what,
reason: "trailing bytes after the fixed body",
});
}
Ok(())
}
pub(crate) fn parse_apdu_header<'a>(
bytes: &'a [u8],
expected: ApduTag,
what: &'static str,
) -> Result<(LengthForm, &'a [u8])> {
if bytes.len() < 3 {
return Err(Error::BufferTooShort(
broadcast_common::error::BufferTooShort {
need: 3,
have: bytes.len(),
what,
},
));
}
let got = ApduTag::from_bytes(bytes[0], bytes[1], bytes[2]);
if got != expected {
return Err(Error::UnexpectedApduTag {
got: got.as_u24(),
expected: expected.as_u24(),
what,
});
}
let (len_value, len_hdr, form) = length::decode_form(&bytes[3..])?;
let body_start = 3 + len_hdr;
let body_end = body_start + len_value;
if bytes.len() < body_end {
return Err(Error::LengthMismatch(
broadcast_common::error::LengthMismatch {
what,
declared: len_value,
actual: bytes.len().saturating_sub(body_start),
},
));
}
Ok((form, &bytes[body_start..body_end]))
}
pub(crate) fn parse_empty_apdu(
bytes: &[u8],
expected: ApduTag,
what: &'static str,
) -> Result<LengthForm> {
let (form, body) = parse_apdu_header(bytes, expected, what)?;
if !body.is_empty() {
return Err(Error::InvalidObject {
what,
reason: "expected empty body",
});
}
Ok(form)
}
pub(crate) fn apdu_len(body_len: usize, form: LengthForm) -> usize {
3 + length::encoded_len_with(body_len, form) + body_len
}
pub(crate) fn empty_apdu_len(form: LengthForm) -> usize {
apdu_len(0, form)
}
pub(crate) fn write_apdu_header(
tag: ApduTag,
body_len: usize,
form: LengthForm,
buf: &mut [u8],
) -> Result<usize> {
let total = apdu_len(body_len, form);
need_out(buf, total)?;
buf[..3].copy_from_slice(&tag.to_bytes());
let n = length::encode_with(body_len, form, &mut buf[3..])?;
Ok(3 + n)
}
pub(crate) fn serialize_empty_apdu(
tag: ApduTag,
form: LengthForm,
buf: &mut [u8],
) -> Result<usize> {
write_apdu_header(tag, 0, form, buf)
}
pub(crate) fn fit_bits(value: u64, bits: u32, what: &'static str) -> Result<u64> {
broadcast_common::len::fit_bits(value, bits, what).map_err(|_| Error::InvalidObject {
what,
reason: overflow_reason(bits),
})
}
const fn overflow_reason(bits: u32) -> &'static str {
match bits {
4 => "exceeds 4-bit range (0x0F)",
5 => "exceeds 5-bit range (0x1F)",
7 => "exceeds 7-bit range (0x7F)",
8 => "exceeds 8-bit range (0xFF)",
12 => "exceeds 12-bit range (0x0FFF)",
13 => "exceeds 13-bit PID range (0x1FFF)",
14 => "exceeds 14-bit range (0x3FFF)",
16 => "exceeds 16-bit range (0xFFFF)",
24 => "exceeds 24-bit range (0xFFFFFF)",
_ => "exceeds field width",
}
}
pub(crate) struct Redacted(pub(crate) usize);
impl core::fmt::Debug for Redacted {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "<{} bytes redacted>", self.0)
}
}
#[cfg(feature = "serde")]
pub(crate) mod bytes_serde {
pub fn serialize<S: serde::Serializer>(bytes: &[u8], s: S) -> Result<S::Ok, S::Error> {
s.serialize_bytes(bytes)
}
}