1extern crate alloc;
6
7use alloc::vec::Vec;
8
9use broadcast_common::{Parse, Serialize};
10
11use crate::ber::{ber_length_size, decode_ber_length, encode_ber_length};
12use crate::error::{Error, Result};
13use crate::types::{UlBytes, ul_bytes_from_prefix};
14
15const PRIMER_KEY_PREFIX: [u8; 7] = [0x06, 0x0E, 0x2B, 0x34, 0x02, 0x05, 0x01];
18const PRIMER_KEY_MID: [u8; 4] = [0x0D, 0x01, 0x02, 0x01];
19const PRIMER_KEY_TAIL: [u8; 2] = [0x05, 0x01];
21
22const LOCAL_TAG_ENTRY_LEN: u32 = 18;
25
26#[derive(Debug, Clone, PartialEq, Eq, Default)]
30pub struct PrimerPack {
31 pub entries: Vec<(u16, UlBytes)>,
34}
35
36impl PrimerPack {
37 #[must_use]
39 pub fn key() -> UlBytes {
40 let mut key = [0u8; 16];
41 key[0..7].copy_from_slice(&PRIMER_KEY_PREFIX);
42 key[7] = 0x01; key[8..12].copy_from_slice(&PRIMER_KEY_MID);
44 key[12] = 0x01; key[13..15].copy_from_slice(&PRIMER_KEY_TAIL);
46 key[15] = 0x00; key
48 }
49
50 #[must_use]
53 pub fn is_primer_key(key: &UlBytes) -> bool {
54 key[0..7] == PRIMER_KEY_PREFIX
55 && key[8..12] == PRIMER_KEY_MID
56 && key[12] == 0x01
57 && key[13..15] == PRIMER_KEY_TAIL
58 }
59
60 fn check_key(key: &UlBytes) -> Result<()> {
61 if Self::is_primer_key(key) {
62 Ok(())
63 } else {
64 Err(Error::KeyPrefixMismatch {
65 what: "Primer Pack (Table 13)",
66 })
67 }
68 }
69
70 #[must_use]
75 pub fn resolve_ul(&self, ul: &UlBytes) -> Option<u16> {
76 self.entries.iter().find(|(_, u)| u == ul).map(|(t, _)| *t)
77 }
78
79 #[must_use]
81 pub fn resolve_tag(&self, tag: u16) -> Option<UlBytes> {
82 self.entries
83 .iter()
84 .find(|(t, _)| *t == tag)
85 .map(|(_, u)| *u)
86 }
87
88 pub fn parse_prefix(bytes: &[u8]) -> Result<(Self, usize)> {
92 if bytes.len() < 16 {
93 return Err(Error::BufferTooShort {
94 need: 16,
95 have: bytes.len(),
96 what: "Primer Pack key",
97 });
98 }
99 let key: UlBytes = ul_bytes_from_prefix(bytes);
100 Self::check_key(&key)?;
101
102 let (len, len_size) = decode_ber_length(&bytes[16..])?;
103 let value_start = 16 + len_size;
104 let len = len as usize;
105 let value_end = value_start.checked_add(len).ok_or(Error::BufferTooShort {
106 need: usize::MAX,
107 have: bytes.len(),
108 what: "Primer Pack value (length overflow)",
109 })?;
110 if bytes.len() < value_end {
111 return Err(Error::BufferTooShort {
112 need: value_end,
113 have: bytes.len(),
114 what: "Primer Pack value",
115 });
116 }
117 let v = &bytes[value_start..value_end];
118 if v.len() < 8 {
119 return Err(Error::InvalidBatchHeader {
120 count: 0,
121 item_len: 0,
122 buffer_len: v.len(),
123 });
124 }
125 let count = u32::from_be_bytes([v[0], v[1], v[2], v[3]]);
126 let item_len = u32::from_be_bytes([v[4], v[5], v[6], v[7]]);
127 let body = &v[8..];
128 if item_len != LOCAL_TAG_ENTRY_LEN || body.len() != count as usize * 18 {
129 return Err(Error::InvalidBatchHeader {
130 count,
131 item_len,
132 buffer_len: body.len(),
133 });
134 }
135 let mut entries = Vec::with_capacity(count as usize);
136 for chunk in body.chunks_exact(18) {
137 let tag = u16::from_be_bytes([chunk[0], chunk[1]]);
138 let uid: UlBytes = ul_bytes_from_prefix(&chunk[2..]);
139 entries.push((tag, uid));
140 }
141 Ok((PrimerPack { entries }, value_end))
142 }
143}
144
145impl<'a> Parse<'a> for PrimerPack {
146 type Error = Error;
147
148 fn parse(bytes: &'a [u8]) -> Result<Self> {
149 let (pack, consumed) = Self::parse_prefix(bytes)?;
150 if consumed != bytes.len() {
151 return Err(Error::BufferTooShort {
152 need: consumed,
153 have: bytes.len(),
154 what: "Primer Pack (trailing bytes after exact-fit parse)",
155 });
156 }
157 Ok(pack)
158 }
159}
160
161impl Serialize for PrimerPack {
162 type Error = Error;
163
164 fn serialized_len(&self) -> usize {
165 let value_len = 8 + self.entries.len() * 18;
166 16 + ber_length_size(value_len as u64) + value_len
167 }
168
169 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
170 let total = self.serialized_len();
171 if buf.len() < total {
172 return Err(Error::BufferTooShort {
173 need: total,
174 have: buf.len(),
175 what: "Primer Pack",
176 });
177 }
178 buf[0..16].copy_from_slice(&Self::key());
179 let value_len = 8 + self.entries.len() * 18;
180 let len_size = encode_ber_length(value_len as u64, &mut buf[16..])?;
181 let mut pos = 16 + len_size;
182 buf[pos..pos + 4].copy_from_slice(&(self.entries.len() as u32).to_be_bytes());
183 pos += 4;
184 buf[pos..pos + 4].copy_from_slice(&LOCAL_TAG_ENTRY_LEN.to_be_bytes());
185 pos += 4;
186 for (tag, uid) in &self.entries {
187 buf[pos..pos + 2].copy_from_slice(&tag.to_be_bytes());
188 pos += 2;
189 buf[pos..pos + 16].copy_from_slice(uid);
190 pos += 16;
191 }
192 Ok(pos)
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn primer_pack_round_trip() {
202 let pack = PrimerPack {
203 entries: alloc::vec![(0x3B02, [0xAAu8; 16]), (0x3B05, [0xBBu8; 16])],
204 };
205 let mut buf = alloc::vec![0u8; pack.serialized_len()];
206 pack.serialize_into(&mut buf).unwrap();
207 let parsed = PrimerPack::parse(&buf).unwrap();
208 assert_eq!(parsed, pack);
209 assert_eq!(parsed.resolve_tag(0x3B02), Some([0xAAu8; 16]));
210 assert_eq!(parsed.resolve_ul(&[0xBBu8; 16]), Some(0x3B05));
211 assert_eq!(parsed.resolve_tag(0x9999), None);
212 }
213
214 #[test]
215 fn empty_primer_pack_round_trip() {
216 let pack = PrimerPack::default();
217 let mut buf = alloc::vec![0u8; pack.serialized_len()];
218 pack.serialize_into(&mut buf).unwrap();
219 assert_eq!(PrimerPack::parse(&buf).unwrap(), pack);
220 }
221
222 #[test]
223 fn wrong_key_rejected() {
224 let mut bytes = alloc::vec![0u8; 17];
225 bytes[16] = 0; assert!(matches!(
227 PrimerPack::parse(&bytes),
228 Err(Error::KeyPrefixMismatch { .. })
229 ));
230 }
231}