1use crate::error::{Error, Result};
10use crate::length;
11use crate::tag::ApduTag;
12
13pub mod application_info;
14pub mod ca_info;
15pub mod ca_pmt;
16pub mod ca_pmt_reply;
17pub mod date_time;
18pub mod host_control;
19pub mod low_speed_comms;
20pub mod mmi_close;
21pub mod mmi_display;
22pub mod mmi_high;
23pub mod resource_manager;
24
25pub(crate) fn parse_apdu_header<'a>(
28 bytes: &'a [u8],
29 expected: ApduTag,
30 what: &'static str,
31) -> Result<&'a [u8]> {
32 if bytes.len() < 3 {
33 return Err(Error::BufferTooShort {
34 need: 3,
35 have: bytes.len(),
36 what,
37 });
38 }
39 let got = ApduTag::from_bytes(bytes[0], bytes[1], bytes[2]);
40 if got != expected {
41 return Err(Error::UnexpectedApduTag {
42 got: got.as_u24(),
43 expected: expected.as_u24(),
44 what,
45 });
46 }
47 let (len_value, len_hdr) = length::decode(&bytes[3..])?;
48 let body_start = 3 + len_hdr;
49 let body_end = body_start + len_value;
50 if bytes.len() < body_end {
51 return Err(Error::LengthMismatch {
52 what,
53 declared: len_value,
54 actual: bytes.len().saturating_sub(body_start),
55 });
56 }
57 Ok(&bytes[body_start..body_end])
58}
59
60pub(crate) fn parse_empty_apdu(bytes: &[u8], expected: ApduTag, what: &'static str) -> Result<()> {
62 let body = parse_apdu_header(bytes, expected, what)?;
63 if !body.is_empty() {
64 return Err(Error::InvalidObject {
65 what,
66 reason: "expected empty body",
67 });
68 }
69 Ok(())
70}
71
72pub(crate) fn apdu_len(body_len: usize) -> usize {
74 3 + length::encoded_len(body_len) + body_len
75}
76
77pub(crate) fn empty_apdu_len() -> usize {
79 apdu_len(0)
80}
81
82pub(crate) fn write_apdu_header(tag: ApduTag, body_len: usize, buf: &mut [u8]) -> Result<usize> {
86 let total = apdu_len(body_len);
87 if buf.len() < total {
88 return Err(Error::OutputBufferTooSmall {
89 need: total,
90 have: buf.len(),
91 });
92 }
93 buf[..3].copy_from_slice(&tag.to_bytes());
94 let n = length::encode_into(body_len, &mut buf[3..])?;
95 Ok(3 + n)
96}
97
98pub(crate) fn serialize_empty_apdu(tag: ApduTag, buf: &mut [u8]) -> Result<usize> {
100 write_apdu_header(tag, 0, buf)
101}
102
103#[cfg(feature = "serde")]
105pub(crate) mod bytes_serde {
106 pub fn serialize<S: serde::Serializer>(bytes: &[u8], s: S) -> Result<S::Ok, S::Error> {
107 s.serialize_bytes(bytes)
108 }
109}