xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/qr_code-2.0.0/src/structured.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 //! Utility methods to support structured append (multiple QR codes)
2 
3 use crate::bits::{Bits, ExtendedMode};
4 use crate::structured::StructuredQrError::*;
5 use crate::types::QrError::Structured;
6 use crate::{bits, EcLevel, QrCode, QrResult, Version};
7 use std::convert::TryFrom;
8 use std::fmt::{Display, Formatter};
9 
10 /// Error variants regarding structured append
11 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
12 pub enum StructuredQrError {
13     /// Structured append mode should contain at least two qrcodes
14     AtLeast2Pieces,
15     /// Encoded number of pieces does not match real number of pieces
16     TotalMismatch(usize),
17     /// Not all the QR codes parts are present
18     MissingParts,
19     /// Computed parity byte does not match
20     Parity,
21     /// QR code data shorter than 5 bytes
22     TooShort,
23     /// QR code mode is not structured append
24     StructuredWrongMode,
25     /// QR code encoding is not the one supported in structured append
26     StructuredWrongEnc,
27     /// QR code sequence number is greater than total
28     SeqGreaterThanTotal(u8, u8),
29     /// QR code length mismatch
30     LengthMismatch(usize, usize),
31     /// Unsupported version
32     UnsupportedVersion(i16),
33     /// Maximum supported pieces in structured append is 16
34     SplitMax16(usize),
35 }
36 
37 impl Display for StructuredQrError {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result38     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39         match self {
40             AtLeast2Pieces => write!(f, "Need at least 2 different pieces to merge structured QR"),
41             TotalMismatch(i) => write!(f, "Total pieces in input {} does not match the encoded total, or different encoded totals", i),
42             MissingParts => write!(f, "Not all the part are present"),
43             Parity => write!(f, "Invalid parities while merging"),
44             TooShort => write!(f, "QR data shorter than 5 bytes"),
45             StructuredWrongMode => write!(f, "Structured append QR must have mode 3"),
46             StructuredWrongEnc => write!(f, "Structured append QR must have encoding 4"),
47             SeqGreaterThanTotal(s, t) => write!(f, "QR sequence {} greater than total {}", s, t),
48             LengthMismatch(calc, exp) => write!(f, "calculated end {} greater than effective length {}", calc, exp),
49             UnsupportedVersion(ver) => write!(f, "Unsupported version {}", ver),
50             SplitMax16(req) => write!(f, "Could split into max 16 qr, requested {}", req),
51         }
52     }
53 }
54 
55 /// Merge multiple structured QR codes content into the original content
merge_qrs(mut bytes: Vec<Vec<u8>>) -> QrResult<Vec<u8>>56 pub fn merge_qrs(mut bytes: Vec<Vec<u8>>) -> QrResult<Vec<u8>> {
57     use std::collections::HashSet;
58     use std::convert::TryInto;
59 
60     let mut vec_structured = vec![];
61 
62     bytes.sort();
63     bytes.dedup();
64 
65     if bytes.len() < 2 {
66         return Err(Structured(AtLeast2Pieces));
67     }
68 
69     for vec in bytes {
70         let current: StructuredQr = vec.try_into()?;
71         vec_structured.push(current);
72     }
73 
74     let total = (vec_structured.len() - 1) as u8;
75     let totals_same = vec_structured.iter().map(|q| q.total).all(|t| t == total);
76     if !totals_same {
77         return Err(Structured(TotalMismatch(vec_structured.len())));
78     }
79 
80     let sequences: HashSet<u8> = vec_structured.iter().map(|q| q.seq).collect();
81     let all_sequence = sequences.len() == vec_structured.len();
82     if !all_sequence {
83         return Err(Structured(MissingParts));
84     }
85 
86     vec_structured.sort_by(|a, b| a.seq.cmp(&b.seq)); // allows to merge out of order by reordering here
87     let result: Vec<u8> = vec_structured
88         .iter()
89         .flat_map(|q| q.content.clone())
90         .collect();
91 
92     let final_parity = result.iter().fold(0u8, |acc, &x| acc ^ x);
93     if vec_structured
94         .iter()
95         .map(|q| q.parity)
96         .all(|p| p == final_parity)
97     {
98         Ok(result)
99     } else {
100         Err(Structured(Parity))
101     }
102 }
103 
104 struct StructuredQr {
105     pub seq: u8,   // u4
106     pub total: u8, // u4
107     pub parity: u8,
108     pub content: Vec<u8>,
109 }
110 
111 impl TryFrom<Vec<u8>> for StructuredQr {
112     type Error = crate::types::QrError;
113 
try_from(value: Vec<u8>) -> QrResult<Self>114     fn try_from(value: Vec<u8>) -> QrResult<Self> {
115         if value.len() < 5 {
116             return Err(Structured(TooShort));
117         }
118         let qr_mode = value[0] >> 4;
119         if qr_mode != 3 {
120             return Err(Structured(StructuredWrongMode));
121         }
122         let seq = value[0] & 0x0f;
123         let total = value[1] >> 4;
124         if seq > total {
125             return Err(Structured(SeqGreaterThanTotal(seq, total)));
126         }
127         let parity = ((value[1] & 0x0f) << 4) + (value[2] >> 4);
128         let enc_mode = value[2] & 0x0f;
129         if enc_mode != 4 {
130             return Err(Structured(StructuredWrongEnc));
131         }
132 
133         let (length, from) = if value.len() < u8::max_value() as usize + 4 {
134             // 4 is header size, TODO recheck boundary
135             (value[3] as u16, 4usize)
136         } else {
137             (((value[3] as u16) << 8) + (value[4] as u16), 5usize)
138         };
139         let end = from + length as usize;
140         if value.len() < end {
141             return Err(Structured(LengthMismatch(end, value.len())));
142         }
143         let content = value[from..end].to_vec();
144         //TODO check padding
145 
146         Ok(StructuredQr {
147             seq,
148             total,
149             parity,
150             content,
151         })
152     }
153 }
154 
155 /// Represent a QR code that could be splitted in `total_qr` QR codes
156 pub struct SplittedQr {
157     /// QR code version
158     pub version: i16,
159     /// QR code parity (will be the same in any QR code of the sequence)
160     pub parity: u8,
161     /// Total QR codes necessary to encode `bytes` with `version` QR codes
162     pub total_qr: usize,
163     /// QR code content
164     pub bytes: Vec<u8>,
165 }
166 
167 impl SplittedQr {
168     /// Creates a new `SplittedQr` if possible given `bytes` len and max QR code `version` to use
new(bytes: Vec<u8>, version: i16) -> QrResult<Self>169     pub fn new(bytes: Vec<u8>, version: i16) -> QrResult<Self> {
170         let parity = bytes.iter().fold(0u8, |acc, &x| acc ^ x);
171         if version == 0 {
172             return Err(Structured(UnsupportedVersion(version)));
173         }
174         let max_bytes = *MAX_BYTES
175             .get(version as usize)
176             .ok_or(Structured(UnsupportedVersion(version)))?;
177         let extra = if bytes.len() % max_bytes == 0 { 0 } else { 1 };
178         let total_qr = bytes.len() / max_bytes + extra;
179         if total_qr > 16 {
180             return Err(Structured(SplitMax16(total_qr)));
181         }
182 
183         Ok(SplittedQr {
184             bytes,
185             version,
186             parity,
187             total_qr,
188         })
189     }
190 
split_to_bits(&self) -> QrResult<Vec<Bits>>191     fn split_to_bits(&self) -> QrResult<Vec<Bits>> {
192         let max_bytes = MAX_BYTES[self.version as usize];
193         if self.total_qr == 1 {
194             let bits = bits::encode_auto(&self.bytes, LEVEL)?;
195             Ok(vec![bits])
196         } else {
197             let mut result = vec![];
198             for (i, chunk) in self.bytes.chunks(max_bytes).enumerate() {
199                 let bits = self.make_chunk(i, chunk)?;
200                 result.push(bits);
201             }
202             Ok(result)
203         }
204     }
205 
206     /// Creates the sequence of QR codes that merged back would produce `self.bytes`
split(&self) -> QrResult<Vec<QrCode>>207     pub fn split(&self) -> QrResult<Vec<QrCode>> {
208         self.split_to_bits()?
209             .into_iter()
210             .map(|bits| QrCode::with_bits(bits, LEVEL))
211             .collect()
212     }
213 
make_chunk(&self, i: usize, chunk: &[u8]) -> QrResult<Bits>214     fn make_chunk(&self, i: usize, chunk: &[u8]) -> QrResult<Bits> {
215         //println!("chunk len : {} version: {}", chunk.len(), self.version);
216         //println!("chunk : {}", hex::encode(chunk) );
217         let mut bits = Bits::new(Version::Normal(self.version));
218         bits.push_mode_indicator(ExtendedMode::StructuredAppend)?;
219         bits.push_number_checked(4, i)?;
220         bits.push_number_checked(4, self.total_qr - 1)?;
221         bits.push_number_checked(8, self.parity as usize)?;
222         bits.push_byte_data(chunk)?;
223         bits.push_terminator(LEVEL)?;
224 
225         //println!("bits: {}\n", hex::encode(bits.clone().into_bytes()));
226 
227         Ok(bits)
228     }
229 }
230 
231 const LEVEL: crate::types::EcLevel = EcLevel::L;
232 
233 /// Max bytes encodable in a structured append qr code, given Qr code version as array index
234 const MAX_BYTES: [usize; 33] = [
235     0, 15, 30, 51, 76, 104, 132, 152, 190, 228, 269, 319, 365, 423, 456, 518, 584, 642, 716, 790,
236     856, 927, 1001, 1089, 1169, 1271, 1365, 1463, 1526, 1626, 1730, 1838, 1950,
237 ];
238 
239 #[cfg(test)]
240 mod tests {
241     use crate::bits::{Bits, ExtendedMode};
242     use crate::structured::StructuredQrError::*;
243     use crate::structured::{merge_qrs, SplittedQr, StructuredQr, LEVEL};
244     use crate::{QrCode, Version};
245     use rand::Rng;
246     use std::convert::TryInto;
247 
248     // from example https://segno.readthedocs.io/en/stable/structured-append.html#structured-append
249     /*
250     I read the news today oh boy
251     4 1c 49207265616420746865206e6577 7320746f646179206f6820626f79 000ec11ec
252 
253     I read the new
254     3 0 1 39 4 0e 49207265616420746865206e6577 00
255 
256     s today oh boy
257     3 1 1 39 4 0e 7320746f646179206f6820626f79 00
258 
259     MODE SEQ TOTAL PARITY MODE LENGTH
260     */
261 
262     const _FULL: &str = "41c49207265616420746865206e65777320746f646179206f6820626f79000ec11ec";
263     const FULL_CONTENT: &str = "49207265616420746865206e65777320746f646179206f6820626f79";
264     const FIRST: &str = "3013940e49207265616420746865206e657700";
265     const FIRST_CONTENT: &str = "49207265616420746865206e6577";
266     const SECOND: &str = "3113940e7320746f646179206f6820626f7900";
267     const SECOND_CONTENT: &str = "7320746f646179206f6820626f79";
268 
269     #[test]
test_try_into_structured()270     fn test_try_into_structured() {
271         let bytes = hex::decode(FIRST).unwrap();
272         let content = hex::decode(FIRST_CONTENT).unwrap();
273         let structured: StructuredQr = bytes.try_into().unwrap();
274         assert_eq!(structured.seq, 0);
275         assert_eq!(structured.total, 1);
276         assert_eq!(structured.parity, 57);
277         assert_eq!(structured.content, content);
278 
279         let bytes = hex::decode(SECOND).unwrap();
280         let content = hex::decode(SECOND_CONTENT).unwrap();
281         let structured_2: StructuredQr = bytes.try_into().unwrap();
282         assert_eq!(structured_2.seq, 1);
283         assert_eq!(structured_2.total, 1);
284         assert_eq!(structured_2.parity, 57);
285         assert_eq!(structured_2.content, content);
286     }
287 
288     #[test]
test_merge()289     fn test_merge() {
290         let first = hex::decode(FIRST).unwrap();
291         let second = hex::decode(SECOND).unwrap();
292         let full_content = hex::decode(FULL_CONTENT).unwrap();
293         let vec = vec![first.clone(), second.clone()];
294         let result = merge_qrs(vec).unwrap();
295         assert_eq!(hex::encode(result), FULL_CONTENT);
296 
297         let vec = vec![second.clone(), first.clone()];
298         let result = merge_qrs(vec).unwrap(); //merge out of order
299         assert_eq!(hex::encode(result), FULL_CONTENT);
300 
301         let vec = vec![second.clone(), first.clone(), second.clone()];
302         let result = merge_qrs(vec).unwrap(); //merge duplicates
303         assert_eq!(hex::encode(result), FULL_CONTENT);
304 
305         let vec = vec![first.clone(), first.clone()];
306         let result = merge_qrs(vec);
307         assert_eq!(result.unwrap_err().to_string(), AtLeast2Pieces.to_string());
308 
309         let vec = vec![first.clone(), full_content];
310         let result = merge_qrs(vec);
311         assert_eq!(
312             result.unwrap_err().to_string(),
313             StructuredWrongMode.to_string()
314         );
315 
316         let mut first_mut = first.clone();
317         first_mut[15] = 14u8;
318         let vec = vec![first.clone(), first_mut.clone()];
319         let result = merge_qrs(vec);
320         assert_eq!(result.unwrap_err().to_string(), MissingParts.to_string());
321 
322         let vec = vec![first, first_mut.clone(), second];
323         let result = merge_qrs(vec);
324         assert_eq!(
325             result.unwrap_err().to_string(),
326             TotalMismatch(3).to_string(),
327         );
328     }
329 
330     #[test]
test_structured_append()331     fn test_structured_append() {
332         let data = "I read the news today oh boy".as_bytes();
333         let data_half = "I read the new".as_bytes();
334         let parity = data.iter().fold(0u8, |acc, &x| acc ^ x);
335         let mut bits = Bits::new(Version::Normal(1));
336         bits.push_mode_indicator(ExtendedMode::StructuredAppend)
337             .unwrap();
338         bits.push_number_checked(4, 0).unwrap(); // first element of the sequence
339         bits.push_number_checked(4, 1).unwrap(); // total length of the sequence (means 2)
340         bits.push_number_checked(8, parity as usize).unwrap(); //parity of the complete data
341         bits.push_byte_data(data_half).unwrap();
342         bits.push_terminator(LEVEL).unwrap();
343         assert_eq!(
344             hex::encode(bits.into_bytes()),
345             "3013940e49207265616420746865206e657700"
346         ); // raw bytes of the first qr code of the example
347     }
348 
349     #[test]
test_split_merge_qr()350     fn test_split_merge_qr() {
351         // consider using https://rust-fuzz.github.io/book/introduction.html
352         let mut rng = rand::thread_rng();
353         let random_bytes: Vec<u8> = (0..4000).map(|_| rand::random::<u8>()).collect();
354         for _ in 0..1_000 {
355             let len = rng.gen_range(100, 4000);
356             let ver = rng.gen_range(10, 20);
357             let data = random_bytes[0..len].to_vec();
358             let split_qr = SplittedQr::new(data.clone(), ver).unwrap();
359             let bits = split_qr.split_to_bits().unwrap();
360             if bits.len() > 1 {
361                 let bytes: Vec<Vec<u8>> = bits.into_iter().map(|b| b.into_bytes()).collect();
362                 let result = merge_qrs(bytes).unwrap();
363                 assert_eq!(result, data);
364             }
365         }
366     }
367 
368     #[test]
test_print_qr()369     fn test_print_qr() {
370         let qr = QrCode::new(b"01234567").unwrap();
371         let printed = qr.to_string(false, 3);
372         assert_eq!(hex::encode(printed.as_bytes()),"2020202020202020202020202020202020202020202020202020200a2020202020202020202020202020202020202020202020202020200a202020e29688e29680e29680e29680e29680e29680e296882020e29688e29684e29688e2968820e29688e29680e29680e29680e29680e29680e296882020200a202020e2968820e29688e29688e2968820e2968820e29688e2968420202020e2968820e29688e29688e2968820e296882020200a202020e2968820e29680e29680e2968020e2968820e2968820e29680e29680e2968820e2968820e29680e29680e2968020e296882020200a202020e29680e29680e29680e29680e29680e29680e2968020e2968820e29680e29684e2968820e29680e29680e29680e29680e29680e29680e296802020200a202020e2968020e29680e29688e29680e29688e29680e29684e29684e29680e2968420e2968820e29680e29688e29680e29688e2968820202020200a2020202020e2968020e2968420e29680e2968020e2968820e2968020e2968020e29684e29688e29688e29688e29680e296802020200a202020202020e29680e29680e29680e29680e29680e2968820e29684e29688e29684e29688e2968420e29680e29684e2968420202020200a202020e29688e29680e29680e29680e29680e29680e2968820e29684e29680e29688e29684e29688e29684e29688e296802020e2968420e296842020200a202020e2968820e29688e29688e2968820e2968820e29688e296842020e296882020e2968820e29680e2968020202020200a202020e2968820e29680e29680e2968020e2968820e2968020e29680e2968020e2968020e29684e2968820e29688e29684202020200a202020e29680e29680e29680e29680e29680e29680e2968020e29680e29680e29680e2968020e296802020e2968020e2968020202020200a2020202020202020202020202020202020202020202020202020200a0a");
373     }
374 }
375