1use crate::error::Error;
6use alloc::vec::Vec;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10#[repr(u8)]
11#[allow(missing_docs)]
12pub enum BioType {
13 NotSpecified = 0x00,
14 RightThumb = 0x01,
15 RightIndex = 0x02,
16 RightMiddle = 0x03,
17 RightRing = 0x04,
18 RightLittle = 0x05,
19 LeftThumb = 0x06,
20 LeftIndex = 0x07,
21 LeftMiddle = 0x08,
22 LeftRing = 0x09,
23 LeftLittle = 0x0A,
24 RightIris = 0x0B,
25 RightRetina = 0x0C,
26 LeftIris = 0x0D,
27 LeftRetina = 0x0E,
28 Face = 0x0F,
29 RightHandGeometry = 0x10,
30 LeftHandGeometry = 0x11,
31}
32
33impl BioType {
34 pub const fn from_byte(b: u8) -> Self {
37 match b {
38 0x00 => Self::NotSpecified,
39 0x01 => Self::RightThumb,
40 0x02 => Self::RightIndex,
41 0x03 => Self::RightMiddle,
42 0x04 => Self::RightRing,
43 0x05 => Self::RightLittle,
44 0x06 => Self::LeftThumb,
45 0x07 => Self::LeftIndex,
46 0x08 => Self::LeftMiddle,
47 0x09 => Self::LeftRing,
48 0x0A => Self::LeftLittle,
49 0x0B => Self::RightIris,
50 0x0C => Self::RightRetina,
51 0x0D => Self::LeftIris,
52 0x0E => Self::LeftRetina,
53 0x0F => Self::Face,
54 0x10 => Self::RightHandGeometry,
55 0x11 => Self::LeftHandGeometry,
56 _ => Self::NotSpecified,
57 }
58 }
59
60 pub const fn as_byte(self) -> u8 {
62 self as u8
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
68#[repr(u8)]
69#[allow(missing_docs)]
70pub enum BioFormat {
71 NotSpecified = 0x00,
72 FingerprintRawPgm = 0x01,
73 FingerprintAnsi378 = 0x02,
74}
75
76impl BioFormat {
77 pub const fn from_byte(b: u8) -> Self {
79 match b {
80 0x01 => Self::FingerprintRawPgm,
81 0x02 => Self::FingerprintAnsi378,
82 _ => Self::NotSpecified,
83 }
84 }
85
86 pub const fn as_byte(self) -> u8 {
88 self as u8
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub struct BioRead {
95 pub reader: u8,
97 pub bio_type: BioType,
99 pub bio_format: BioFormat,
101 pub quality: u8,
103}
104
105impl BioRead {
106 pub fn encode(&self) -> Result<Vec<u8>, Error> {
108 Ok(alloc::vec![
109 self.reader,
110 self.bio_type.as_byte(),
111 self.bio_format.as_byte(),
112 self.quality,
113 ])
114 }
115
116 pub fn decode(data: &[u8]) -> Result<Self, Error> {
118 if data.len() != 4 {
119 return Err(Error::MalformedPayload {
120 code: 0x73,
121 reason: "BIOREAD requires 4 bytes",
122 });
123 }
124 Ok(Self {
125 reader: data[0],
126 bio_type: BioType::from_byte(data[1]),
127 bio_format: BioFormat::from_byte(data[2]),
128 quality: data[3],
129 })
130 }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
135pub struct BioMatch {
136 pub reader: u8,
138 pub bio_type: BioType,
140 pub bio_format: BioFormat,
142 pub quality: u8,
144 pub template: Vec<u8>,
146}
147
148impl BioMatch {
149 pub fn encode(&self) -> Result<Vec<u8>, Error> {
151 if self.template.len() > u16::MAX as usize {
152 return Err(Error::MalformedPayload {
153 code: 0x74,
154 reason: "BIOMATCH template > 65535 bytes",
155 });
156 }
157 let mut out = Vec::with_capacity(6 + self.template.len());
158 out.push(self.reader);
159 out.push(self.bio_type.as_byte());
160 out.push(self.bio_format.as_byte());
161 out.push(self.quality);
162 out.extend_from_slice(&(self.template.len() as u16).to_le_bytes());
163 out.extend_from_slice(&self.template);
164 Ok(out)
165 }
166
167 pub fn decode(data: &[u8]) -> Result<Self, Error> {
169 if data.len() < 6 {
170 return Err(Error::MalformedPayload {
171 code: 0x74,
172 reason: "BIOMATCH requires at least 6 bytes",
173 });
174 }
175 let length = u16::from_le_bytes([data[4], data[5]]) as usize;
176 if data.len() != 6 + length {
177 return Err(Error::MalformedPayload {
178 code: 0x74,
179 reason: "BIOMATCH length disagrees with payload",
180 });
181 }
182 Ok(Self {
183 reader: data[0],
184 bio_type: BioType::from_byte(data[1]),
185 bio_format: BioFormat::from_byte(data[2]),
186 quality: data[3],
187 template: data[6..6 + length].to_vec(),
188 })
189 }
190}