use crate::error::{Error, Result};
use crate::length;
use crate::tag::ApduTag;
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<&'a [u8]> {
if bytes.len() < 3 {
return Err(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) = length::decode(&bytes[3..])?;
let body_start = 3 + len_hdr;
let body_end = body_start + len_value;
if bytes.len() < body_end {
return Err(Error::LengthMismatch {
what,
declared: len_value,
actual: bytes.len().saturating_sub(body_start),
});
}
Ok(&bytes[body_start..body_end])
}
pub(crate) fn parse_empty_apdu(bytes: &[u8], expected: ApduTag, what: &'static str) -> Result<()> {
let body = parse_apdu_header(bytes, expected, what)?;
if !body.is_empty() {
return Err(Error::InvalidObject {
what,
reason: "expected empty body",
});
}
Ok(())
}
pub(crate) fn apdu_len(body_len: usize) -> usize {
3 + length::encoded_len(body_len) + body_len
}
pub(crate) fn empty_apdu_len() -> usize {
apdu_len(0)
}
pub(crate) fn write_apdu_header(tag: ApduTag, body_len: usize, buf: &mut [u8]) -> Result<usize> {
let total = apdu_len(body_len);
if buf.len() < total {
return Err(Error::OutputBufferTooSmall {
need: total,
have: buf.len(),
});
}
buf[..3].copy_from_slice(&tag.to_bytes());
let n = length::encode_into(body_len, &mut buf[3..])?;
Ok(3 + n)
}
pub(crate) fn serialize_empty_apdu(tag: ApduTag, buf: &mut [u8]) -> Result<usize> {
write_apdu_header(tag, 0, 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)
}
}