xref: /linux/drivers/gpu/drm/drm_panic_qr.rs (revision 0074281bb6316108e0cff094bd4db78ab3eee236)
1cb5164acSJocelyn Falempe // SPDX-License-Identifier: MIT
2cb5164acSJocelyn Falempe 
3cb5164acSJocelyn Falempe //! This is a simple QR encoder for DRM panic.
4cb5164acSJocelyn Falempe //!
5cb5164acSJocelyn Falempe //! It is called from a panic handler, so it should't allocate memory and
6cb5164acSJocelyn Falempe //! does all the work on the stack or on the provided buffers. For
7cb5164acSJocelyn Falempe //! simplification, it only supports low error correction, and applies the
8cb5164acSJocelyn Falempe //! first mask (checkerboard). It will draw the smallest QR code that can
9cb5164acSJocelyn Falempe //! contain the string passed as parameter. To get the most compact
10cb5164acSJocelyn Falempe //! QR code, the start of the URL is encoded as binary, and the
11cb5164acSJocelyn Falempe //! compressed kmsg is encoded as numeric.
12cb5164acSJocelyn Falempe //!
13cb5164acSJocelyn Falempe //! The binary data must be a valid URL parameter, so the easiest way is
14cb5164acSJocelyn Falempe //! to use base64 encoding. But this wastes 25% of data space, so the
15cb5164acSJocelyn Falempe //! whole stack trace won't fit in the QR code. So instead it encodes
16dbed4a79SJocelyn Falempe //! every 7 bytes of input into 17 decimal digits, and then uses the
17cb5164acSJocelyn Falempe //! efficient numeric encoding, that encode 3 decimal digits into
18dbed4a79SJocelyn Falempe //! 10bits. This makes 168bits of compressed data into 51 decimal digits,
19dbed4a79SJocelyn Falempe //! into 170bits in the QR code, so wasting only 1.17%. And the numbers are
20cb5164acSJocelyn Falempe //! valid URL parameter, so the website can do the reverse, to get the
21dbed4a79SJocelyn Falempe //! binary data. This is the same algorithm used by Fido v2.2 QR-initiated
22dbed4a79SJocelyn Falempe //! authentication specification.
23cb5164acSJocelyn Falempe //!
24cb5164acSJocelyn Falempe //! Inspired by these 3 projects, all under MIT license:
25cb5164acSJocelyn Falempe //!
26cb5164acSJocelyn Falempe //! * <https://github.com/kennytm/qrcode-rust>
27cb5164acSJocelyn Falempe //! * <https://github.com/erwanvivien/fast_qr>
28cb5164acSJocelyn Falempe //! * <https://github.com/bjguillot/qr>
29cb5164acSJocelyn Falempe 
30*3d441474STamir Duberstein use kernel::prelude::*;
31cb5164acSJocelyn Falempe 
32cb5164acSJocelyn Falempe #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
33cb5164acSJocelyn Falempe struct Version(usize);
34cb5164acSJocelyn Falempe 
35cb5164acSJocelyn Falempe // Generator polynomials for ECC, only those that are needed for low quality.
36cb5164acSJocelyn Falempe const P7: [u8; 7] = [87, 229, 146, 149, 238, 102, 21];
37cb5164acSJocelyn Falempe const P10: [u8; 10] = [251, 67, 46, 61, 118, 70, 64, 94, 32, 45];
38cb5164acSJocelyn Falempe const P15: [u8; 15] = [
39cb5164acSJocelyn Falempe     8, 183, 61, 91, 202, 37, 51, 58, 58, 237, 140, 124, 5, 99, 105,
40cb5164acSJocelyn Falempe ];
41cb5164acSJocelyn Falempe const P18: [u8; 18] = [
42cb5164acSJocelyn Falempe     215, 234, 158, 94, 184, 97, 118, 170, 79, 187, 152, 148, 252, 179, 5, 98, 96, 153,
43cb5164acSJocelyn Falempe ];
44cb5164acSJocelyn Falempe const P20: [u8; 20] = [
45cb5164acSJocelyn Falempe     17, 60, 79, 50, 61, 163, 26, 187, 202, 180, 221, 225, 83, 239, 156, 164, 212, 212, 188, 190,
46cb5164acSJocelyn Falempe ];
47cb5164acSJocelyn Falempe const P22: [u8; 22] = [
48cb5164acSJocelyn Falempe     210, 171, 247, 242, 93, 230, 14, 109, 221, 53, 200, 74, 8, 172, 98, 80, 219, 134, 160, 105,
49cb5164acSJocelyn Falempe     165, 231,
50cb5164acSJocelyn Falempe ];
51cb5164acSJocelyn Falempe const P24: [u8; 24] = [
52cb5164acSJocelyn Falempe     229, 121, 135, 48, 211, 117, 251, 126, 159, 180, 169, 152, 192, 226, 228, 218, 111, 0, 117,
53cb5164acSJocelyn Falempe     232, 87, 96, 227, 21,
54cb5164acSJocelyn Falempe ];
55cb5164acSJocelyn Falempe const P26: [u8; 26] = [
56cb5164acSJocelyn Falempe     173, 125, 158, 2, 103, 182, 118, 17, 145, 201, 111, 28, 165, 53, 161, 21, 245, 142, 13, 102,
57cb5164acSJocelyn Falempe     48, 227, 153, 145, 218, 70,
58cb5164acSJocelyn Falempe ];
59cb5164acSJocelyn Falempe const P28: [u8; 28] = [
60cb5164acSJocelyn Falempe     168, 223, 200, 104, 224, 234, 108, 180, 110, 190, 195, 147, 205, 27, 232, 201, 21, 43, 245, 87,
61cb5164acSJocelyn Falempe     42, 195, 212, 119, 242, 37, 9, 123,
62cb5164acSJocelyn Falempe ];
63cb5164acSJocelyn Falempe const P30: [u8; 30] = [
64cb5164acSJocelyn Falempe     41, 173, 145, 152, 216, 31, 179, 182, 50, 48, 110, 86, 239, 96, 222, 125, 42, 173, 226, 193,
65cb5164acSJocelyn Falempe     224, 130, 156, 37, 251, 216, 238, 40, 192, 180,
66cb5164acSJocelyn Falempe ];
67cb5164acSJocelyn Falempe 
68cb5164acSJocelyn Falempe /// QR Code parameters for Low quality ECC:
69cb5164acSJocelyn Falempe /// - Error Correction polynomial.
70cb5164acSJocelyn Falempe /// - Number of blocks in group 1.
71cb5164acSJocelyn Falempe /// - Number of blocks in group 2.
72cb5164acSJocelyn Falempe /// - Block size in group 1.
73cb5164acSJocelyn Falempe ///
74cb5164acSJocelyn Falempe /// (Block size in group 2 is one more than group 1).
75cb5164acSJocelyn Falempe struct VersionParameter(&'static [u8], u8, u8, u8);
76cb5164acSJocelyn Falempe const VPARAM: [VersionParameter; 40] = [
77cb5164acSJocelyn Falempe     VersionParameter(&P7, 1, 0, 19),    // V1
78cb5164acSJocelyn Falempe     VersionParameter(&P10, 1, 0, 34),   // V2
79cb5164acSJocelyn Falempe     VersionParameter(&P15, 1, 0, 55),   // V3
80cb5164acSJocelyn Falempe     VersionParameter(&P20, 1, 0, 80),   // V4
81cb5164acSJocelyn Falempe     VersionParameter(&P26, 1, 0, 108),  // V5
82cb5164acSJocelyn Falempe     VersionParameter(&P18, 2, 0, 68),   // V6
83cb5164acSJocelyn Falempe     VersionParameter(&P20, 2, 0, 78),   // V7
84cb5164acSJocelyn Falempe     VersionParameter(&P24, 2, 0, 97),   // V8
85cb5164acSJocelyn Falempe     VersionParameter(&P30, 2, 0, 116),  // V9
86cb5164acSJocelyn Falempe     VersionParameter(&P18, 2, 2, 68),   // V10
87cb5164acSJocelyn Falempe     VersionParameter(&P20, 4, 0, 81),   // V11
88cb5164acSJocelyn Falempe     VersionParameter(&P24, 2, 2, 92),   // V12
89cb5164acSJocelyn Falempe     VersionParameter(&P26, 4, 0, 107),  // V13
90cb5164acSJocelyn Falempe     VersionParameter(&P30, 3, 1, 115),  // V14
91cb5164acSJocelyn Falempe     VersionParameter(&P22, 5, 1, 87),   // V15
92cb5164acSJocelyn Falempe     VersionParameter(&P24, 5, 1, 98),   // V16
93cb5164acSJocelyn Falempe     VersionParameter(&P28, 1, 5, 107),  // V17
94cb5164acSJocelyn Falempe     VersionParameter(&P30, 5, 1, 120),  // V18
95cb5164acSJocelyn Falempe     VersionParameter(&P28, 3, 4, 113),  // V19
96cb5164acSJocelyn Falempe     VersionParameter(&P28, 3, 5, 107),  // V20
97cb5164acSJocelyn Falempe     VersionParameter(&P28, 4, 4, 116),  // V21
98cb5164acSJocelyn Falempe     VersionParameter(&P28, 2, 7, 111),  // V22
99cb5164acSJocelyn Falempe     VersionParameter(&P30, 4, 5, 121),  // V23
100cb5164acSJocelyn Falempe     VersionParameter(&P30, 6, 4, 117),  // V24
101cb5164acSJocelyn Falempe     VersionParameter(&P26, 8, 4, 106),  // V25
102cb5164acSJocelyn Falempe     VersionParameter(&P28, 10, 2, 114), // V26
103cb5164acSJocelyn Falempe     VersionParameter(&P30, 8, 4, 122),  // V27
104cb5164acSJocelyn Falempe     VersionParameter(&P30, 3, 10, 117), // V28
105cb5164acSJocelyn Falempe     VersionParameter(&P30, 7, 7, 116),  // V29
106cb5164acSJocelyn Falempe     VersionParameter(&P30, 5, 10, 115), // V30
107cb5164acSJocelyn Falempe     VersionParameter(&P30, 13, 3, 115), // V31
108cb5164acSJocelyn Falempe     VersionParameter(&P30, 17, 0, 115), // V32
109cb5164acSJocelyn Falempe     VersionParameter(&P30, 17, 1, 115), // V33
110cb5164acSJocelyn Falempe     VersionParameter(&P30, 13, 6, 115), // V34
111cb5164acSJocelyn Falempe     VersionParameter(&P30, 12, 7, 121), // V35
112cb5164acSJocelyn Falempe     VersionParameter(&P30, 6, 14, 121), // V36
113cb5164acSJocelyn Falempe     VersionParameter(&P30, 17, 4, 122), // V37
114cb5164acSJocelyn Falempe     VersionParameter(&P30, 4, 18, 122), // V38
115cb5164acSJocelyn Falempe     VersionParameter(&P30, 20, 4, 117), // V39
116cb5164acSJocelyn Falempe     VersionParameter(&P30, 19, 6, 118), // V40
117cb5164acSJocelyn Falempe ];
118cb5164acSJocelyn Falempe 
119cb5164acSJocelyn Falempe const MAX_EC_SIZE: usize = 30;
120cb5164acSJocelyn Falempe const MAX_BLK_SIZE: usize = 123;
121cb5164acSJocelyn Falempe 
122cb5164acSJocelyn Falempe /// Position of the alignment pattern grid.
123cb5164acSJocelyn Falempe const ALIGNMENT_PATTERNS: [&[u8]; 40] = [
124cb5164acSJocelyn Falempe     &[],
125cb5164acSJocelyn Falempe     &[6, 18],
126cb5164acSJocelyn Falempe     &[6, 22],
127cb5164acSJocelyn Falempe     &[6, 26],
128cb5164acSJocelyn Falempe     &[6, 30],
129cb5164acSJocelyn Falempe     &[6, 34],
130cb5164acSJocelyn Falempe     &[6, 22, 38],
131cb5164acSJocelyn Falempe     &[6, 24, 42],
132cb5164acSJocelyn Falempe     &[6, 26, 46],
133cb5164acSJocelyn Falempe     &[6, 28, 50],
134cb5164acSJocelyn Falempe     &[6, 30, 54],
135cb5164acSJocelyn Falempe     &[6, 32, 58],
136cb5164acSJocelyn Falempe     &[6, 34, 62],
137cb5164acSJocelyn Falempe     &[6, 26, 46, 66],
138cb5164acSJocelyn Falempe     &[6, 26, 48, 70],
139cb5164acSJocelyn Falempe     &[6, 26, 50, 74],
140cb5164acSJocelyn Falempe     &[6, 30, 54, 78],
141cb5164acSJocelyn Falempe     &[6, 30, 56, 82],
142cb5164acSJocelyn Falempe     &[6, 30, 58, 86],
143cb5164acSJocelyn Falempe     &[6, 34, 62, 90],
144cb5164acSJocelyn Falempe     &[6, 28, 50, 72, 94],
145cb5164acSJocelyn Falempe     &[6, 26, 50, 74, 98],
146cb5164acSJocelyn Falempe     &[6, 30, 54, 78, 102],
147cb5164acSJocelyn Falempe     &[6, 28, 54, 80, 106],
148cb5164acSJocelyn Falempe     &[6, 32, 58, 84, 110],
149cb5164acSJocelyn Falempe     &[6, 30, 58, 86, 114],
150cb5164acSJocelyn Falempe     &[6, 34, 62, 90, 118],
151cb5164acSJocelyn Falempe     &[6, 26, 50, 74, 98, 122],
152cb5164acSJocelyn Falempe     &[6, 30, 54, 78, 102, 126],
153cb5164acSJocelyn Falempe     &[6, 26, 52, 78, 104, 130],
154cb5164acSJocelyn Falempe     &[6, 30, 56, 82, 108, 134],
155cb5164acSJocelyn Falempe     &[6, 34, 60, 86, 112, 138],
156cb5164acSJocelyn Falempe     &[6, 30, 58, 86, 114, 142],
157cb5164acSJocelyn Falempe     &[6, 34, 62, 90, 118, 146],
158cb5164acSJocelyn Falempe     &[6, 30, 54, 78, 102, 126, 150],
159cb5164acSJocelyn Falempe     &[6, 24, 50, 76, 102, 128, 154],
160cb5164acSJocelyn Falempe     &[6, 28, 54, 80, 106, 132, 158],
161cb5164acSJocelyn Falempe     &[6, 32, 58, 84, 110, 136, 162],
162cb5164acSJocelyn Falempe     &[6, 26, 54, 82, 110, 138, 166],
163cb5164acSJocelyn Falempe     &[6, 30, 58, 86, 114, 142, 170],
164cb5164acSJocelyn Falempe ];
165cb5164acSJocelyn Falempe 
166cb5164acSJocelyn Falempe /// Version information for format V7-V40.
167cb5164acSJocelyn Falempe const VERSION_INFORMATION: [u32; 34] = [
168cb5164acSJocelyn Falempe     0b00_0111_1100_1001_0100,
169cb5164acSJocelyn Falempe     0b00_1000_0101_1011_1100,
170cb5164acSJocelyn Falempe     0b00_1001_1010_1001_1001,
171cb5164acSJocelyn Falempe     0b00_1010_0100_1101_0011,
172cb5164acSJocelyn Falempe     0b00_1011_1011_1111_0110,
173cb5164acSJocelyn Falempe     0b00_1100_0111_0110_0010,
174cb5164acSJocelyn Falempe     0b00_1101_1000_0100_0111,
175cb5164acSJocelyn Falempe     0b00_1110_0110_0000_1101,
176cb5164acSJocelyn Falempe     0b00_1111_1001_0010_1000,
177cb5164acSJocelyn Falempe     0b01_0000_1011_0111_1000,
178cb5164acSJocelyn Falempe     0b01_0001_0100_0101_1101,
179cb5164acSJocelyn Falempe     0b01_0010_1010_0001_0111,
180cb5164acSJocelyn Falempe     0b01_0011_0101_0011_0010,
181cb5164acSJocelyn Falempe     0b01_0100_1001_1010_0110,
182cb5164acSJocelyn Falempe     0b01_0101_0110_1000_0011,
183cb5164acSJocelyn Falempe     0b01_0110_1000_1100_1001,
184cb5164acSJocelyn Falempe     0b01_0111_0111_1110_1100,
185cb5164acSJocelyn Falempe     0b01_1000_1110_1100_0100,
186cb5164acSJocelyn Falempe     0b01_1001_0001_1110_0001,
187cb5164acSJocelyn Falempe     0b01_1010_1111_1010_1011,
188cb5164acSJocelyn Falempe     0b01_1011_0000_1000_1110,
189cb5164acSJocelyn Falempe     0b01_1100_1100_0001_1010,
190cb5164acSJocelyn Falempe     0b01_1101_0011_0011_1111,
191cb5164acSJocelyn Falempe     0b01_1110_1101_0111_0101,
192cb5164acSJocelyn Falempe     0b01_1111_0010_0101_0000,
193cb5164acSJocelyn Falempe     0b10_0000_1001_1101_0101,
194cb5164acSJocelyn Falempe     0b10_0001_0110_1111_0000,
195cb5164acSJocelyn Falempe     0b10_0010_1000_1011_1010,
196cb5164acSJocelyn Falempe     0b10_0011_0111_1001_1111,
197cb5164acSJocelyn Falempe     0b10_0100_1011_0000_1011,
198cb5164acSJocelyn Falempe     0b10_0101_0100_0010_1110,
199cb5164acSJocelyn Falempe     0b10_0110_1010_0110_0100,
200cb5164acSJocelyn Falempe     0b10_0111_0101_0100_0001,
201cb5164acSJocelyn Falempe     0b10_1000_1100_0110_1001,
202cb5164acSJocelyn Falempe ];
203cb5164acSJocelyn Falempe 
204cb5164acSJocelyn Falempe /// Format info for low quality ECC.
205cb5164acSJocelyn Falempe const FORMAT_INFOS_QR_L: [u16; 8] = [
206cb5164acSJocelyn Falempe     0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976,
207cb5164acSJocelyn Falempe ];
208cb5164acSJocelyn Falempe 
209cb5164acSJocelyn Falempe impl Version {
210cb5164acSJocelyn Falempe     /// Returns the smallest QR version than can hold these segments.
from_segments(segments: &[&Segment<'_>]) -> Option<Version>211cb5164acSJocelyn Falempe     fn from_segments(segments: &[&Segment<'_>]) -> Option<Version> {
212c408dd81SThomas Böhler         (1..=40)
213c408dd81SThomas Böhler             .map(Version)
214c408dd81SThomas Böhler             .find(|&v| v.max_data() * 8 >= segments.iter().map(|s| s.total_size_bits(v)).sum())
215cb5164acSJocelyn Falempe     }
216cb5164acSJocelyn Falempe 
width(&self) -> u8217cb5164acSJocelyn Falempe     fn width(&self) -> u8 {
218cb5164acSJocelyn Falempe         (self.0 as u8) * 4 + 17
219cb5164acSJocelyn Falempe     }
220cb5164acSJocelyn Falempe 
max_data(&self) -> usize221cb5164acSJocelyn Falempe     fn max_data(&self) -> usize {
222cb5164acSJocelyn Falempe         self.g1_blk_size() * self.g1_blocks() + (self.g1_blk_size() + 1) * self.g2_blocks()
223cb5164acSJocelyn Falempe     }
224cb5164acSJocelyn Falempe 
ec_size(&self) -> usize225cb5164acSJocelyn Falempe     fn ec_size(&self) -> usize {
226cb5164acSJocelyn Falempe         VPARAM[self.0 - 1].0.len()
227cb5164acSJocelyn Falempe     }
228cb5164acSJocelyn Falempe 
g1_blocks(&self) -> usize229cb5164acSJocelyn Falempe     fn g1_blocks(&self) -> usize {
230cb5164acSJocelyn Falempe         VPARAM[self.0 - 1].1 as usize
231cb5164acSJocelyn Falempe     }
232cb5164acSJocelyn Falempe 
g2_blocks(&self) -> usize233cb5164acSJocelyn Falempe     fn g2_blocks(&self) -> usize {
234cb5164acSJocelyn Falempe         VPARAM[self.0 - 1].2 as usize
235cb5164acSJocelyn Falempe     }
236cb5164acSJocelyn Falempe 
g1_blk_size(&self) -> usize237cb5164acSJocelyn Falempe     fn g1_blk_size(&self) -> usize {
238cb5164acSJocelyn Falempe         VPARAM[self.0 - 1].3 as usize
239cb5164acSJocelyn Falempe     }
240cb5164acSJocelyn Falempe 
alignment_pattern(&self) -> &'static [u8]241cb5164acSJocelyn Falempe     fn alignment_pattern(&self) -> &'static [u8] {
2427b6de57eSThomas Böhler         ALIGNMENT_PATTERNS[self.0 - 1]
243cb5164acSJocelyn Falempe     }
244cb5164acSJocelyn Falempe 
poly(&self) -> &'static [u8]245cb5164acSJocelyn Falempe     fn poly(&self) -> &'static [u8] {
246cb5164acSJocelyn Falempe         VPARAM[self.0 - 1].0
247cb5164acSJocelyn Falempe     }
248cb5164acSJocelyn Falempe 
version_info(&self) -> u32249cb5164acSJocelyn Falempe     fn version_info(&self) -> u32 {
250cb5164acSJocelyn Falempe         if *self >= Version(7) {
251cb5164acSJocelyn Falempe             VERSION_INFORMATION[self.0 - 7]
252cb5164acSJocelyn Falempe         } else {
253cb5164acSJocelyn Falempe             0
254cb5164acSJocelyn Falempe         }
255cb5164acSJocelyn Falempe     }
256cb5164acSJocelyn Falempe }
257cb5164acSJocelyn Falempe 
258cb5164acSJocelyn Falempe /// Exponential table for Galois Field GF(256).
259cb5164acSJocelyn Falempe const EXP_TABLE: [u8; 256] = [
260cb5164acSJocelyn Falempe     1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117,
261cb5164acSJocelyn Falempe     234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181,
262cb5164acSJocelyn Falempe     119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161,
263cb5164acSJocelyn Falempe     95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187,
264cb5164acSJocelyn Falempe     107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136,
265cb5164acSJocelyn Falempe     13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197,
266cb5164acSJocelyn Falempe     151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168,
267cb5164acSJocelyn Falempe     77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198,
268cb5164acSJocelyn Falempe     145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149,
269cb5164acSJocelyn Falempe     55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167,
270cb5164acSJocelyn Falempe     83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72,
271cb5164acSJocelyn Falempe     144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207,
272cb5164acSJocelyn Falempe     131, 27, 54, 108, 216, 173, 71, 142, 1,
273cb5164acSJocelyn Falempe ];
274cb5164acSJocelyn Falempe 
275cb5164acSJocelyn Falempe /// Reverse exponential table for Galois Field GF(256).
276cb5164acSJocelyn Falempe const LOG_TABLE: [u8; 256] = [
277cb5164acSJocelyn Falempe     175, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141,
278cb5164acSJocelyn Falempe     239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142,
279cb5164acSJocelyn Falempe     218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114,
280cb5164acSJocelyn Falempe     166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148,
281cb5164acSJocelyn Falempe     206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126,
282cb5164acSJocelyn Falempe     110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172,
283cb5164acSJocelyn Falempe     115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24,
284cb5164acSJocelyn Falempe     227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149,
285cb5164acSJocelyn Falempe     188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132,
286cb5164acSJocelyn Falempe     60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12,
287cb5164acSJocelyn Falempe     111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95,
288cb5164acSJocelyn Falempe     176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173,
289cb5164acSJocelyn Falempe     232, 116, 214, 244, 234, 168, 80, 88, 175,
290cb5164acSJocelyn Falempe ];
291cb5164acSJocelyn Falempe 
292cb5164acSJocelyn Falempe // 4 bits segment header.
293cb5164acSJocelyn Falempe const MODE_STOP: u16 = 0;
294cb5164acSJocelyn Falempe const MODE_NUMERIC: u16 = 1;
295cb5164acSJocelyn Falempe const MODE_BINARY: u16 = 4;
296cb5164acSJocelyn Falempe /// Padding bytes.
297cb5164acSJocelyn Falempe const PADDING: [u8; 2] = [236, 17];
298cb5164acSJocelyn Falempe 
299cb5164acSJocelyn Falempe /// Number of bits to encode characters in numeric mode.
300cb5164acSJocelyn Falempe const NUM_CHARS_BITS: [usize; 4] = [0, 4, 7, 10];
301dbed4a79SJocelyn Falempe /// Number of decimal digits required to encode n bytes of binary data.
302dbed4a79SJocelyn Falempe /// eg: you need 15 decimal digits to fit 6 bytes of binary data.
303dbed4a79SJocelyn Falempe const BYTES_TO_DIGITS: [usize; 8] = [0, 3, 5, 8, 10, 13, 15, 17];
304cb5164acSJocelyn Falempe 
305cb5164acSJocelyn Falempe enum Segment<'a> {
306cb5164acSJocelyn Falempe     Numeric(&'a [u8]),
307cb5164acSJocelyn Falempe     Binary(&'a [u8]),
308cb5164acSJocelyn Falempe }
309cb5164acSJocelyn Falempe 
310cb5164acSJocelyn Falempe impl Segment<'_> {
get_header(&self) -> (u16, usize)311cb5164acSJocelyn Falempe     fn get_header(&self) -> (u16, usize) {
312cb5164acSJocelyn Falempe         match self {
313cb5164acSJocelyn Falempe             Segment::Binary(_) => (MODE_BINARY, 4),
314cb5164acSJocelyn Falempe             Segment::Numeric(_) => (MODE_NUMERIC, 4),
315cb5164acSJocelyn Falempe         }
316cb5164acSJocelyn Falempe     }
317cb5164acSJocelyn Falempe 
31874757ad1SMiguel Ojeda     /// Returns the size of the length field in bits, depending on QR Version.
length_bits_count(&self, version: Version) -> usize319cb5164acSJocelyn Falempe     fn length_bits_count(&self, version: Version) -> usize {
320cb5164acSJocelyn Falempe         let Version(v) = version;
321cb5164acSJocelyn Falempe         match self {
322cb5164acSJocelyn Falempe             Segment::Binary(_) => match v {
323cb5164acSJocelyn Falempe                 1..=9 => 8,
324cb5164acSJocelyn Falempe                 _ => 16,
325cb5164acSJocelyn Falempe             },
326cb5164acSJocelyn Falempe             Segment::Numeric(_) => match v {
327cb5164acSJocelyn Falempe                 1..=9 => 10,
328cb5164acSJocelyn Falempe                 10..=26 => 12,
329cb5164acSJocelyn Falempe                 _ => 14,
330cb5164acSJocelyn Falempe             },
331cb5164acSJocelyn Falempe         }
332cb5164acSJocelyn Falempe     }
333cb5164acSJocelyn Falempe 
33474757ad1SMiguel Ojeda     /// Number of characters in the segment.
character_count(&self) -> usize335cb5164acSJocelyn Falempe     fn character_count(&self) -> usize {
336cb5164acSJocelyn Falempe         match self {
337cb5164acSJocelyn Falempe             Segment::Binary(data) => data.len(),
338cb5164acSJocelyn Falempe             Segment::Numeric(data) => {
339dbed4a79SJocelyn Falempe                 let last_chars = BYTES_TO_DIGITS[data.len() % 7];
340dbed4a79SJocelyn Falempe                 // 17 decimal numbers per 7bytes + remainder.
341dbed4a79SJocelyn Falempe                 17 * (data.len() / 7) + last_chars
342cb5164acSJocelyn Falempe             }
343cb5164acSJocelyn Falempe         }
344cb5164acSJocelyn Falempe     }
345cb5164acSJocelyn Falempe 
get_length_field(&self, version: Version) -> (u16, usize)346cb5164acSJocelyn Falempe     fn get_length_field(&self, version: Version) -> (u16, usize) {
347cb5164acSJocelyn Falempe         (
348cb5164acSJocelyn Falempe             self.character_count() as u16,
349cb5164acSJocelyn Falempe             self.length_bits_count(version),
350cb5164acSJocelyn Falempe         )
351cb5164acSJocelyn Falempe     }
352cb5164acSJocelyn Falempe 
total_size_bits(&self, version: Version) -> usize353cb5164acSJocelyn Falempe     fn total_size_bits(&self, version: Version) -> usize {
354cb5164acSJocelyn Falempe         let data_size = match self {
355cb5164acSJocelyn Falempe             Segment::Binary(data) => data.len() * 8,
356cb5164acSJocelyn Falempe             Segment::Numeric(_) => {
357cb5164acSJocelyn Falempe                 let digits = self.character_count();
358cb5164acSJocelyn Falempe                 10 * (digits / 3) + NUM_CHARS_BITS[digits % 3]
359cb5164acSJocelyn Falempe             }
360cb5164acSJocelyn Falempe         };
361cb5164acSJocelyn Falempe         // header + length + data.
362cb5164acSJocelyn Falempe         4 + self.length_bits_count(version) + data_size
363cb5164acSJocelyn Falempe     }
364cb5164acSJocelyn Falempe 
iter(&self) -> SegmentIterator<'_>365cb5164acSJocelyn Falempe     fn iter(&self) -> SegmentIterator<'_> {
366cb5164acSJocelyn Falempe         SegmentIterator {
367cb5164acSJocelyn Falempe             segment: self,
368cb5164acSJocelyn Falempe             offset: 0,
369675008f1SJocelyn Falempe             decfifo: Default::default(),
370675008f1SJocelyn Falempe         }
371675008f1SJocelyn Falempe     }
372675008f1SJocelyn Falempe }
373675008f1SJocelyn Falempe 
374675008f1SJocelyn Falempe /// Max fifo size is 17 (max push) + 2 (max remaining)
375675008f1SJocelyn Falempe const MAX_FIFO_SIZE: usize = 19;
376675008f1SJocelyn Falempe 
377675008f1SJocelyn Falempe /// A simple Decimal digit FIFO
378675008f1SJocelyn Falempe #[derive(Default)]
379675008f1SJocelyn Falempe struct DecFifo {
380675008f1SJocelyn Falempe     decimals: [u8; MAX_FIFO_SIZE],
381675008f1SJocelyn Falempe     len: usize,
382675008f1SJocelyn Falempe }
383675008f1SJocelyn Falempe 
384675008f1SJocelyn Falempe impl DecFifo {
push(&mut self, data: u64, len: usize)385675008f1SJocelyn Falempe     fn push(&mut self, data: u64, len: usize) {
386675008f1SJocelyn Falempe         let mut chunk = data;
387675008f1SJocelyn Falempe         for i in (0..self.len).rev() {
388675008f1SJocelyn Falempe             self.decimals[i + len] = self.decimals[i];
389675008f1SJocelyn Falempe         }
390675008f1SJocelyn Falempe         for i in 0..len {
391675008f1SJocelyn Falempe             self.decimals[i] = (chunk % 10) as u8;
392675008f1SJocelyn Falempe             chunk /= 10;
393675008f1SJocelyn Falempe         }
394675008f1SJocelyn Falempe         self.len += len;
395675008f1SJocelyn Falempe     }
396675008f1SJocelyn Falempe 
397675008f1SJocelyn Falempe     /// Pop 3 decimal digits from the FIFO
pop3(&mut self) -> Option<(u16, usize)>398675008f1SJocelyn Falempe     fn pop3(&mut self) -> Option<(u16, usize)> {
399675008f1SJocelyn Falempe         if self.len == 0 {
400675008f1SJocelyn Falempe             None
401675008f1SJocelyn Falempe         } else {
402675008f1SJocelyn Falempe             let poplen = 3.min(self.len);
403675008f1SJocelyn Falempe             self.len -= poplen;
404675008f1SJocelyn Falempe             let mut out = 0;
405675008f1SJocelyn Falempe             let mut exp = 1;
406675008f1SJocelyn Falempe             for i in 0..poplen {
407b7c8d7a8STamir Duberstein                 out += u16::from(self.decimals[self.len + i]) * exp;
408675008f1SJocelyn Falempe                 exp *= 10;
409675008f1SJocelyn Falempe             }
410675008f1SJocelyn Falempe             Some((out, NUM_CHARS_BITS[poplen]))
411cb5164acSJocelyn Falempe         }
412cb5164acSJocelyn Falempe     }
413cb5164acSJocelyn Falempe }
414cb5164acSJocelyn Falempe 
415cb5164acSJocelyn Falempe struct SegmentIterator<'a> {
416cb5164acSJocelyn Falempe     segment: &'a Segment<'a>,
417cb5164acSJocelyn Falempe     offset: usize,
418675008f1SJocelyn Falempe     decfifo: DecFifo,
419cb5164acSJocelyn Falempe }
420cb5164acSJocelyn Falempe 
421cb5164acSJocelyn Falempe impl Iterator for SegmentIterator<'_> {
422cb5164acSJocelyn Falempe     type Item = (u16, usize);
423cb5164acSJocelyn Falempe 
next(&mut self) -> Option<Self::Item>424cb5164acSJocelyn Falempe     fn next(&mut self) -> Option<Self::Item> {
425cb5164acSJocelyn Falempe         match self.segment {
426cb5164acSJocelyn Falempe             Segment::Binary(data) => {
427cb5164acSJocelyn Falempe                 if self.offset < data.len() {
428b7c8d7a8STamir Duberstein                     let byte = u16::from(data[self.offset]);
429cb5164acSJocelyn Falempe                     self.offset += 1;
430cb5164acSJocelyn Falempe                     Some((byte, 8))
431cb5164acSJocelyn Falempe                 } else {
432cb5164acSJocelyn Falempe                     None
433cb5164acSJocelyn Falempe                 }
434cb5164acSJocelyn Falempe             }
435cb5164acSJocelyn Falempe             Segment::Numeric(data) => {
436675008f1SJocelyn Falempe                 if self.decfifo.len < 3 && self.offset < data.len() {
437675008f1SJocelyn Falempe                     // If there are less than 3 decimal digits in the fifo,
438675008f1SJocelyn Falempe                     // take the next 7 bytes of input, and push them to the fifo.
439dbed4a79SJocelyn Falempe                     let mut buf = [0u8; 8];
440dbed4a79SJocelyn Falempe                     let len = 7.min(data.len() - self.offset);
441dbed4a79SJocelyn Falempe                     buf[..len].copy_from_slice(&data[self.offset..self.offset + len]);
442dbed4a79SJocelyn Falempe                     let chunk = u64::from_le_bytes(buf);
443675008f1SJocelyn Falempe                     self.decfifo.push(chunk, BYTES_TO_DIGITS[len]);
444dbed4a79SJocelyn Falempe                     self.offset += len;
445cb5164acSJocelyn Falempe                 }
446675008f1SJocelyn Falempe                 self.decfifo.pop3()
447cb5164acSJocelyn Falempe             }
448cb5164acSJocelyn Falempe         }
449cb5164acSJocelyn Falempe     }
450cb5164acSJocelyn Falempe }
451cb5164acSJocelyn Falempe 
452cb5164acSJocelyn Falempe struct EncodedMsg<'a> {
453cb5164acSJocelyn Falempe     data: &'a mut [u8],
454cb5164acSJocelyn Falempe     ec_size: usize,
455cb5164acSJocelyn Falempe     g1_blocks: usize,
456cb5164acSJocelyn Falempe     g2_blocks: usize,
457cb5164acSJocelyn Falempe     g1_blk_size: usize,
458cb5164acSJocelyn Falempe     g2_blk_size: usize,
459cb5164acSJocelyn Falempe     poly: &'static [u8],
460cb5164acSJocelyn Falempe     version: Version,
461cb5164acSJocelyn Falempe }
462cb5164acSJocelyn Falempe 
463cb5164acSJocelyn Falempe /// Data to be put in the QR code, with correct segment encoding, padding, and
464cb5164acSJocelyn Falempe /// Error Code Correction.
465cb5164acSJocelyn Falempe impl EncodedMsg<'_> {
new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>>466ae75c401SThomas Böhler     fn new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> {
467cb5164acSJocelyn Falempe         let version = Version::from_segments(segments)?;
468cb5164acSJocelyn Falempe         let ec_size = version.ec_size();
469cb5164acSJocelyn Falempe         let g1_blocks = version.g1_blocks();
470cb5164acSJocelyn Falempe         let g2_blocks = version.g2_blocks();
471cb5164acSJocelyn Falempe         let g1_blk_size = version.g1_blk_size();
472cb5164acSJocelyn Falempe         let g2_blk_size = g1_blk_size + 1;
473cb5164acSJocelyn Falempe         let poly = version.poly();
474cb5164acSJocelyn Falempe 
475cb5164acSJocelyn Falempe         // clear the output.
476cb5164acSJocelyn Falempe         data.fill(0);
477cb5164acSJocelyn Falempe 
478cb5164acSJocelyn Falempe         let mut em = EncodedMsg {
479da13129aSThomas Böhler             data,
480cb5164acSJocelyn Falempe             ec_size,
481cb5164acSJocelyn Falempe             g1_blocks,
482cb5164acSJocelyn Falempe             g2_blocks,
483cb5164acSJocelyn Falempe             g1_blk_size,
484cb5164acSJocelyn Falempe             g2_blk_size,
485cb5164acSJocelyn Falempe             poly,
486cb5164acSJocelyn Falempe             version,
487cb5164acSJocelyn Falempe         };
488cb5164acSJocelyn Falempe         em.encode(segments);
489cb5164acSJocelyn Falempe         Some(em)
490cb5164acSJocelyn Falempe     }
491cb5164acSJocelyn Falempe 
492cb5164acSJocelyn Falempe     /// Push bits of data at an offset (in bits).
push(&mut self, offset: &mut usize, bits: (u16, usize))493cb5164acSJocelyn Falempe     fn push(&mut self, offset: &mut usize, bits: (u16, usize)) {
494cb5164acSJocelyn Falempe         let (number, len_bits) = bits;
495cb5164acSJocelyn Falempe         let byte_off = *offset / 8;
496cb5164acSJocelyn Falempe         let bit_off = *offset % 8;
497cb5164acSJocelyn Falempe         let b = bit_off + len_bits;
498cb5164acSJocelyn Falempe 
499cb5164acSJocelyn Falempe         match (bit_off, b) {
500cb5164acSJocelyn Falempe             (0, 0..=8) => {
501cb5164acSJocelyn Falempe                 self.data[byte_off] = (number << (8 - b)) as u8;
502cb5164acSJocelyn Falempe             }
503cb5164acSJocelyn Falempe             (0, _) => {
504cb5164acSJocelyn Falempe                 self.data[byte_off] = (number >> (b - 8)) as u8;
505cb5164acSJocelyn Falempe                 self.data[byte_off + 1] = (number << (16 - b)) as u8;
506cb5164acSJocelyn Falempe             }
507cb5164acSJocelyn Falempe             (_, 0..=8) => {
508cb5164acSJocelyn Falempe                 self.data[byte_off] |= (number << (8 - b)) as u8;
509cb5164acSJocelyn Falempe             }
510cb5164acSJocelyn Falempe             (_, 9..=16) => {
511cb5164acSJocelyn Falempe                 self.data[byte_off] |= (number >> (b - 8)) as u8;
512cb5164acSJocelyn Falempe                 self.data[byte_off + 1] = (number << (16 - b)) as u8;
513cb5164acSJocelyn Falempe             }
514cb5164acSJocelyn Falempe             _ => {
515cb5164acSJocelyn Falempe                 self.data[byte_off] |= (number >> (b - 8)) as u8;
516cb5164acSJocelyn Falempe                 self.data[byte_off + 1] = (number >> (b - 16)) as u8;
517cb5164acSJocelyn Falempe                 self.data[byte_off + 2] = (number << (24 - b)) as u8;
518cb5164acSJocelyn Falempe             }
519cb5164acSJocelyn Falempe         }
520cb5164acSJocelyn Falempe         *offset += len_bits;
521cb5164acSJocelyn Falempe     }
522cb5164acSJocelyn Falempe 
add_segments(&mut self, segments: &[&Segment<'_>])523cb5164acSJocelyn Falempe     fn add_segments(&mut self, segments: &[&Segment<'_>]) {
524cb5164acSJocelyn Falempe         let mut offset: usize = 0;
525cb5164acSJocelyn Falempe 
526cb5164acSJocelyn Falempe         for s in segments.iter() {
527cb5164acSJocelyn Falempe             self.push(&mut offset, s.get_header());
528cb5164acSJocelyn Falempe             self.push(&mut offset, s.get_length_field(self.version));
529cb5164acSJocelyn Falempe             for bits in s.iter() {
530cb5164acSJocelyn Falempe                 self.push(&mut offset, bits);
531cb5164acSJocelyn Falempe             }
532cb5164acSJocelyn Falempe         }
533cb5164acSJocelyn Falempe         self.push(&mut offset, (MODE_STOP, 4));
534cb5164acSJocelyn Falempe 
535986c2e9cSMiguel Ojeda         let pad_offset = offset.div_ceil(8);
536cb5164acSJocelyn Falempe         for i in pad_offset..self.version.max_data() {
537cb5164acSJocelyn Falempe             self.data[i] = PADDING[(i & 1) ^ (pad_offset & 1)];
538cb5164acSJocelyn Falempe         }
539cb5164acSJocelyn Falempe     }
540cb5164acSJocelyn Falempe 
error_code_for_blocks(&mut self, offset: usize, size: usize, ec_offset: usize)541cb5164acSJocelyn Falempe     fn error_code_for_blocks(&mut self, offset: usize, size: usize, ec_offset: usize) {
542cb5164acSJocelyn Falempe         let mut tmp: [u8; MAX_BLK_SIZE + MAX_EC_SIZE] = [0; MAX_BLK_SIZE + MAX_EC_SIZE];
543cb5164acSJocelyn Falempe 
544cb5164acSJocelyn Falempe         tmp[0..size].copy_from_slice(&self.data[offset..offset + size]);
545cb5164acSJocelyn Falempe         for i in 0..size {
546cb5164acSJocelyn Falempe             let lead_coeff = tmp[i] as usize;
547cb5164acSJocelyn Falempe             if lead_coeff == 0 {
548cb5164acSJocelyn Falempe                 continue;
549cb5164acSJocelyn Falempe             }
550cb5164acSJocelyn Falempe             let log_lead_coeff = usize::from(LOG_TABLE[lead_coeff]);
551cb5164acSJocelyn Falempe             for (u, &v) in tmp[i + 1..].iter_mut().zip(self.poly.iter()) {
552cb5164acSJocelyn Falempe                 *u ^= EXP_TABLE[(usize::from(v) + log_lead_coeff) % 255];
553cb5164acSJocelyn Falempe             }
554cb5164acSJocelyn Falempe         }
555cb5164acSJocelyn Falempe         self.data[ec_offset..ec_offset + self.ec_size]
556cb5164acSJocelyn Falempe             .copy_from_slice(&tmp[size..size + self.ec_size]);
557cb5164acSJocelyn Falempe     }
558cb5164acSJocelyn Falempe 
compute_error_code(&mut self)559cb5164acSJocelyn Falempe     fn compute_error_code(&mut self) {
560cb5164acSJocelyn Falempe         let mut offset = 0;
561cb5164acSJocelyn Falempe         let mut ec_offset = self.g1_blocks * self.g1_blk_size + self.g2_blocks * self.g2_blk_size;
562cb5164acSJocelyn Falempe 
563cb5164acSJocelyn Falempe         for _ in 0..self.g1_blocks {
564cb5164acSJocelyn Falempe             self.error_code_for_blocks(offset, self.g1_blk_size, ec_offset);
565cb5164acSJocelyn Falempe             offset += self.g1_blk_size;
566cb5164acSJocelyn Falempe             ec_offset += self.ec_size;
567cb5164acSJocelyn Falempe         }
568cb5164acSJocelyn Falempe         for _ in 0..self.g2_blocks {
569cb5164acSJocelyn Falempe             self.error_code_for_blocks(offset, self.g2_blk_size, ec_offset);
570cb5164acSJocelyn Falempe             offset += self.g2_blk_size;
571cb5164acSJocelyn Falempe             ec_offset += self.ec_size;
572cb5164acSJocelyn Falempe         }
573cb5164acSJocelyn Falempe     }
574cb5164acSJocelyn Falempe 
encode(&mut self, segments: &[&Segment<'_>])575cb5164acSJocelyn Falempe     fn encode(&mut self, segments: &[&Segment<'_>]) {
576cb5164acSJocelyn Falempe         self.add_segments(segments);
577cb5164acSJocelyn Falempe         self.compute_error_code();
578cb5164acSJocelyn Falempe     }
579cb5164acSJocelyn Falempe 
iter(&self) -> EncodedMsgIterator<'_>580cb5164acSJocelyn Falempe     fn iter(&self) -> EncodedMsgIterator<'_> {
581cb5164acSJocelyn Falempe         EncodedMsgIterator {
582cb5164acSJocelyn Falempe             em: self,
583cb5164acSJocelyn Falempe             offset: 0,
584cb5164acSJocelyn Falempe         }
585cb5164acSJocelyn Falempe     }
586cb5164acSJocelyn Falempe }
587cb5164acSJocelyn Falempe 
588cb5164acSJocelyn Falempe /// Iterator, to retrieve the data in the interleaved order needed by QR code.
589cb5164acSJocelyn Falempe struct EncodedMsgIterator<'a> {
590cb5164acSJocelyn Falempe     em: &'a EncodedMsg<'a>,
591cb5164acSJocelyn Falempe     offset: usize,
592cb5164acSJocelyn Falempe }
593cb5164acSJocelyn Falempe 
594cb5164acSJocelyn Falempe impl Iterator for EncodedMsgIterator<'_> {
595cb5164acSJocelyn Falempe     type Item = u8;
596cb5164acSJocelyn Falempe 
59774757ad1SMiguel Ojeda     /// Send the bytes in interleaved mode, first byte of first block of group1,
59874757ad1SMiguel Ojeda     /// then first byte of second block of group1, ...
next(&mut self) -> Option<Self::Item>599cb5164acSJocelyn Falempe     fn next(&mut self) -> Option<Self::Item> {
600cb5164acSJocelyn Falempe         let em = self.em;
601cb5164acSJocelyn Falempe         let blocks = em.g1_blocks + em.g2_blocks;
602cb5164acSJocelyn Falempe         let g1_end = em.g1_blocks * em.g1_blk_size;
603cb5164acSJocelyn Falempe         let g2_end = g1_end + em.g2_blocks * em.g2_blk_size;
604cb5164acSJocelyn Falempe         let ec_end = g2_end + em.ec_size * blocks;
605cb5164acSJocelyn Falempe 
606cb5164acSJocelyn Falempe         if self.offset >= ec_end {
607cb5164acSJocelyn Falempe             return None;
608cb5164acSJocelyn Falempe         }
609cb5164acSJocelyn Falempe 
610cb5164acSJocelyn Falempe         let offset = if self.offset < em.g1_blk_size * blocks {
611cb5164acSJocelyn Falempe             // group1 and group2 interleaved
612cb5164acSJocelyn Falempe             let blk = self.offset % blocks;
613cb5164acSJocelyn Falempe             let blk_off = self.offset / blocks;
614cb5164acSJocelyn Falempe             if blk < em.g1_blocks {
615cb5164acSJocelyn Falempe                 blk * em.g1_blk_size + blk_off
616cb5164acSJocelyn Falempe             } else {
617cb5164acSJocelyn Falempe                 g1_end + em.g2_blk_size * (blk - em.g1_blocks) + blk_off
618cb5164acSJocelyn Falempe             }
619cb5164acSJocelyn Falempe         } else if self.offset < g2_end {
620cb5164acSJocelyn Falempe             // last byte of group2 blocks
621cb5164acSJocelyn Falempe             let blk2 = self.offset - blocks * em.g1_blk_size;
622cb5164acSJocelyn Falempe             em.g1_blk_size * em.g1_blocks + blk2 * em.g2_blk_size + em.g2_blk_size - 1
623cb5164acSJocelyn Falempe         } else {
624cb5164acSJocelyn Falempe             // EC blocks
625cb5164acSJocelyn Falempe             let ec_offset = self.offset - g2_end;
626cb5164acSJocelyn Falempe             let blk = ec_offset % blocks;
627cb5164acSJocelyn Falempe             let blk_off = ec_offset / blocks;
628cb5164acSJocelyn Falempe 
629cb5164acSJocelyn Falempe             g2_end + blk * em.ec_size + blk_off
630cb5164acSJocelyn Falempe         };
631cb5164acSJocelyn Falempe         self.offset += 1;
632cb5164acSJocelyn Falempe         Some(em.data[offset])
633cb5164acSJocelyn Falempe     }
634cb5164acSJocelyn Falempe }
635cb5164acSJocelyn Falempe 
636cb5164acSJocelyn Falempe /// A QR code image, encoded as a linear binary framebuffer.
637cb5164acSJocelyn Falempe /// 1 bit per module (pixel), each new line start at next byte boundary.
638cb5164acSJocelyn Falempe /// Max width is 177 for V40 QR code, so `u8` is enough for coordinate.
639cb5164acSJocelyn Falempe struct QrImage<'a> {
640cb5164acSJocelyn Falempe     data: &'a mut [u8],
641cb5164acSJocelyn Falempe     width: u8,
642cb5164acSJocelyn Falempe     stride: u8,
643cb5164acSJocelyn Falempe     version: Version,
644cb5164acSJocelyn Falempe }
645cb5164acSJocelyn Falempe 
646cb5164acSJocelyn Falempe impl QrImage<'_> {
new<'a, 'b>(em: &'b EncodedMsg<'b>, qrdata: &'a mut [u8]) -> QrImage<'a>647cb5164acSJocelyn Falempe     fn new<'a, 'b>(em: &'b EncodedMsg<'b>, qrdata: &'a mut [u8]) -> QrImage<'a> {
648cb5164acSJocelyn Falempe         let width = em.version.width();
649986c2e9cSMiguel Ojeda         let stride = width.div_ceil(8);
650cb5164acSJocelyn Falempe         let data = qrdata;
651cb5164acSJocelyn Falempe 
652cb5164acSJocelyn Falempe         let mut qr_image = QrImage {
653cb5164acSJocelyn Falempe             data,
654cb5164acSJocelyn Falempe             width,
655cb5164acSJocelyn Falempe             stride,
656cb5164acSJocelyn Falempe             version: em.version,
657cb5164acSJocelyn Falempe         };
658cb5164acSJocelyn Falempe         qr_image.draw_all(em.iter());
659cb5164acSJocelyn Falempe         qr_image
660cb5164acSJocelyn Falempe     }
661cb5164acSJocelyn Falempe 
clear(&mut self)662cb5164acSJocelyn Falempe     fn clear(&mut self) {
663cb5164acSJocelyn Falempe         self.data.fill(0);
664cb5164acSJocelyn Falempe     }
665cb5164acSJocelyn Falempe 
66674757ad1SMiguel Ojeda     /// Set pixel to light color.
set(&mut self, x: u8, y: u8)667cb5164acSJocelyn Falempe     fn set(&mut self, x: u8, y: u8) {
668cb5164acSJocelyn Falempe         let off = y as usize * self.stride as usize + x as usize / 8;
669cb5164acSJocelyn Falempe         let mut v = self.data[off];
670cb5164acSJocelyn Falempe         v |= 0x80 >> (x % 8);
671cb5164acSJocelyn Falempe         self.data[off] = v;
672cb5164acSJocelyn Falempe     }
673cb5164acSJocelyn Falempe 
67474757ad1SMiguel Ojeda     /// Invert a module color.
xor(&mut self, x: u8, y: u8)675cb5164acSJocelyn Falempe     fn xor(&mut self, x: u8, y: u8) {
676cb5164acSJocelyn Falempe         let off = y as usize * self.stride as usize + x as usize / 8;
677cb5164acSJocelyn Falempe         self.data[off] ^= 0x80 >> (x % 8);
678cb5164acSJocelyn Falempe     }
679cb5164acSJocelyn Falempe 
68074757ad1SMiguel Ojeda     /// Draw a light square at (x, y) top left corner.
draw_square(&mut self, x: u8, y: u8, size: u8)681cb5164acSJocelyn Falempe     fn draw_square(&mut self, x: u8, y: u8, size: u8) {
682cb5164acSJocelyn Falempe         for k in 0..size {
683cb5164acSJocelyn Falempe             self.set(x + k, y);
684cb5164acSJocelyn Falempe             self.set(x, y + k + 1);
685cb5164acSJocelyn Falempe             self.set(x + size, y + k);
686cb5164acSJocelyn Falempe             self.set(x + k + 1, y + size);
687cb5164acSJocelyn Falempe         }
688cb5164acSJocelyn Falempe     }
689cb5164acSJocelyn Falempe 
690cb5164acSJocelyn Falempe     // Finder pattern: 3 8x8 square at the corners.
draw_finders(&mut self)691cb5164acSJocelyn Falempe     fn draw_finders(&mut self) {
692cb5164acSJocelyn Falempe         self.draw_square(1, 1, 4);
693cb5164acSJocelyn Falempe         self.draw_square(self.width - 6, 1, 4);
694cb5164acSJocelyn Falempe         self.draw_square(1, self.width - 6, 4);
695cb5164acSJocelyn Falempe         for k in 0..8 {
696cb5164acSJocelyn Falempe             self.set(k, 7);
697cb5164acSJocelyn Falempe             self.set(self.width - k - 1, 7);
698cb5164acSJocelyn Falempe             self.set(k, self.width - 8);
699cb5164acSJocelyn Falempe         }
700cb5164acSJocelyn Falempe         for k in 0..7 {
701cb5164acSJocelyn Falempe             self.set(7, k);
702cb5164acSJocelyn Falempe             self.set(self.width - 8, k);
703cb5164acSJocelyn Falempe             self.set(7, self.width - 1 - k);
704cb5164acSJocelyn Falempe         }
705cb5164acSJocelyn Falempe     }
706cb5164acSJocelyn Falempe 
is_finder(&self, x: u8, y: u8) -> bool707cb5164acSJocelyn Falempe     fn is_finder(&self, x: u8, y: u8) -> bool {
708cb5164acSJocelyn Falempe         let end = self.width - 8;
70927aef8a5SThomas Böhler         #[expect(clippy::nonminimal_bool)]
71027aef8a5SThomas Böhler         {
711cb5164acSJocelyn Falempe             (x < 8 && y < 8) || (x < 8 && y >= end) || (x >= end && y < 8)
712cb5164acSJocelyn Falempe         }
71327aef8a5SThomas Böhler     }
714cb5164acSJocelyn Falempe 
715cb5164acSJocelyn Falempe     // Alignment pattern: 5x5 squares in a grid.
draw_alignments(&mut self)716cb5164acSJocelyn Falempe     fn draw_alignments(&mut self) {
717cb5164acSJocelyn Falempe         let positions = self.version.alignment_pattern();
718cb5164acSJocelyn Falempe         for &x in positions.iter() {
719cb5164acSJocelyn Falempe             for &y in positions.iter() {
720cb5164acSJocelyn Falempe                 if !self.is_finder(x, y) {
721cb5164acSJocelyn Falempe                     self.draw_square(x - 1, y - 1, 2);
722cb5164acSJocelyn Falempe                 }
723cb5164acSJocelyn Falempe             }
724cb5164acSJocelyn Falempe         }
725cb5164acSJocelyn Falempe     }
726cb5164acSJocelyn Falempe 
is_alignment(&self, x: u8, y: u8) -> bool727cb5164acSJocelyn Falempe     fn is_alignment(&self, x: u8, y: u8) -> bool {
728cb5164acSJocelyn Falempe         let positions = self.version.alignment_pattern();
729cb5164acSJocelyn Falempe         for &ax in positions.iter() {
730cb5164acSJocelyn Falempe             for &ay in positions.iter() {
731cb5164acSJocelyn Falempe                 if self.is_finder(ax, ay) {
732cb5164acSJocelyn Falempe                     continue;
733cb5164acSJocelyn Falempe                 }
734cb5164acSJocelyn Falempe                 if x >= ax - 2 && x <= ax + 2 && y >= ay - 2 && y <= ay + 2 {
735cb5164acSJocelyn Falempe                     return true;
736cb5164acSJocelyn Falempe                 }
737cb5164acSJocelyn Falempe             }
738cb5164acSJocelyn Falempe         }
739cb5164acSJocelyn Falempe         false
740cb5164acSJocelyn Falempe     }
741cb5164acSJocelyn Falempe 
742cb5164acSJocelyn Falempe     // Timing pattern: 2 dotted line between the finder patterns.
draw_timing_patterns(&mut self)743cb5164acSJocelyn Falempe     fn draw_timing_patterns(&mut self) {
744cb5164acSJocelyn Falempe         let end = self.width - 8;
745cb5164acSJocelyn Falempe 
746cb5164acSJocelyn Falempe         for x in (9..end).step_by(2) {
747cb5164acSJocelyn Falempe             self.set(x, 6);
748cb5164acSJocelyn Falempe             self.set(6, x);
749cb5164acSJocelyn Falempe         }
750cb5164acSJocelyn Falempe     }
751cb5164acSJocelyn Falempe 
is_timing(&self, x: u8, y: u8) -> bool752cb5164acSJocelyn Falempe     fn is_timing(&self, x: u8, y: u8) -> bool {
753cb5164acSJocelyn Falempe         x == 6 || y == 6
754cb5164acSJocelyn Falempe     }
755cb5164acSJocelyn Falempe 
756cb5164acSJocelyn Falempe     // Mask info: 15 bits around the finders, written twice for redundancy.
draw_maskinfo(&mut self)757cb5164acSJocelyn Falempe     fn draw_maskinfo(&mut self) {
758cb5164acSJocelyn Falempe         let info: u16 = FORMAT_INFOS_QR_L[0];
759cb5164acSJocelyn Falempe         let mut skip = 0;
760cb5164acSJocelyn Falempe 
761cb5164acSJocelyn Falempe         for k in 0..7 {
762cb5164acSJocelyn Falempe             if k == 6 {
763cb5164acSJocelyn Falempe                 skip = 1;
764cb5164acSJocelyn Falempe             }
765cb5164acSJocelyn Falempe             if info & (1 << (14 - k)) == 0 {
766cb5164acSJocelyn Falempe                 self.set(k + skip, 8);
767cb5164acSJocelyn Falempe                 self.set(8, self.width - 1 - k);
768cb5164acSJocelyn Falempe             }
769cb5164acSJocelyn Falempe         }
770cb5164acSJocelyn Falempe         skip = 0;
771cb5164acSJocelyn Falempe         for k in 0..8 {
772cb5164acSJocelyn Falempe             if k == 2 {
773cb5164acSJocelyn Falempe                 skip = 1;
774cb5164acSJocelyn Falempe             }
775cb5164acSJocelyn Falempe             if info & (1 << (7 - k)) == 0 {
776cb5164acSJocelyn Falempe                 self.set(8, 8 - skip - k);
777cb5164acSJocelyn Falempe                 self.set(self.width - 8 + k, 8);
778cb5164acSJocelyn Falempe             }
779cb5164acSJocelyn Falempe         }
780cb5164acSJocelyn Falempe     }
781cb5164acSJocelyn Falempe 
is_maskinfo(&self, x: u8, y: u8) -> bool782cb5164acSJocelyn Falempe     fn is_maskinfo(&self, x: u8, y: u8) -> bool {
783cb5164acSJocelyn Falempe         let end = self.width - 8;
784cb5164acSJocelyn Falempe         // Count the dark module as mask info.
785cb5164acSJocelyn Falempe         (x <= 8 && y == 8) || (y <= 8 && x == 8) || (x == 8 && y >= end) || (x >= end && y == 8)
786cb5164acSJocelyn Falempe     }
787cb5164acSJocelyn Falempe 
788cb5164acSJocelyn Falempe     // Version info: 18bits written twice, close to the finders.
draw_version_info(&mut self)789cb5164acSJocelyn Falempe     fn draw_version_info(&mut self) {
790cb5164acSJocelyn Falempe         let vinfo = self.version.version_info();
791cb5164acSJocelyn Falempe         let pos = self.width - 11;
792cb5164acSJocelyn Falempe 
793cb5164acSJocelyn Falempe         if vinfo != 0 {
794cb5164acSJocelyn Falempe             for x in 0..3 {
795cb5164acSJocelyn Falempe                 for y in 0..6 {
796cb5164acSJocelyn Falempe                     if vinfo & (1 << (x + y * 3)) == 0 {
797cb5164acSJocelyn Falempe                         self.set(x + pos, y);
798cb5164acSJocelyn Falempe                         self.set(y, x + pos);
799cb5164acSJocelyn Falempe                     }
800cb5164acSJocelyn Falempe                 }
801cb5164acSJocelyn Falempe             }
802cb5164acSJocelyn Falempe         }
803cb5164acSJocelyn Falempe     }
804cb5164acSJocelyn Falempe 
is_version_info(&self, x: u8, y: u8) -> bool805cb5164acSJocelyn Falempe     fn is_version_info(&self, x: u8, y: u8) -> bool {
806cb5164acSJocelyn Falempe         let vinfo = self.version.version_info();
807cb5164acSJocelyn Falempe         let pos = self.width - 11;
808cb5164acSJocelyn Falempe 
809cb5164acSJocelyn Falempe         vinfo != 0 && ((x >= pos && x < pos + 3 && y < 6) || (y >= pos && y < pos + 3 && x < 6))
810cb5164acSJocelyn Falempe     }
811cb5164acSJocelyn Falempe 
81274757ad1SMiguel Ojeda     /// Returns true if the module is reserved (Not usable for data and EC).
is_reserved(&self, x: u8, y: u8) -> bool813cb5164acSJocelyn Falempe     fn is_reserved(&self, x: u8, y: u8) -> bool {
814cb5164acSJocelyn Falempe         self.is_alignment(x, y)
815cb5164acSJocelyn Falempe             || self.is_finder(x, y)
816cb5164acSJocelyn Falempe             || self.is_timing(x, y)
817cb5164acSJocelyn Falempe             || self.is_maskinfo(x, y)
818cb5164acSJocelyn Falempe             || self.is_version_info(x, y)
819cb5164acSJocelyn Falempe     }
820cb5164acSJocelyn Falempe 
82174757ad1SMiguel Ojeda     /// Last module to draw, at bottom left corner.
is_last(&self, x: u8, y: u8) -> bool822cb5164acSJocelyn Falempe     fn is_last(&self, x: u8, y: u8) -> bool {
823cb5164acSJocelyn Falempe         x == 0 && y == self.width - 1
824cb5164acSJocelyn Falempe     }
825cb5164acSJocelyn Falempe 
82674757ad1SMiguel Ojeda     /// Move to the next module according to QR code order.
82774757ad1SMiguel Ojeda     ///
82874757ad1SMiguel Ojeda     /// From bottom right corner, to bottom left corner.
next(&self, x: u8, y: u8) -> (u8, u8)829cb5164acSJocelyn Falempe     fn next(&self, x: u8, y: u8) -> (u8, u8) {
830cb5164acSJocelyn Falempe         let x_adj = if x <= 6 { x + 1 } else { x };
831cb5164acSJocelyn Falempe         let column_type = (self.width - x_adj) % 4;
832cb5164acSJocelyn Falempe 
833cb5164acSJocelyn Falempe         match column_type {
834cb5164acSJocelyn Falempe             2 if y > 0 => (x + 1, y - 1),
835cb5164acSJocelyn Falempe             0 if y < self.width - 1 => (x + 1, y + 1),
836cb5164acSJocelyn Falempe             0 | 2 if x == 7 => (x - 2, y),
837cb5164acSJocelyn Falempe             _ => (x - 1, y),
838cb5164acSJocelyn Falempe         }
839cb5164acSJocelyn Falempe     }
840cb5164acSJocelyn Falempe 
84174757ad1SMiguel Ojeda     /// Find next module that can hold data.
next_available(&self, x: u8, y: u8) -> (u8, u8)842cb5164acSJocelyn Falempe     fn next_available(&self, x: u8, y: u8) -> (u8, u8) {
843cb5164acSJocelyn Falempe         let (mut x, mut y) = self.next(x, y);
844cb5164acSJocelyn Falempe         while self.is_reserved(x, y) && !self.is_last(x, y) {
845cb5164acSJocelyn Falempe             (x, y) = self.next(x, y);
846cb5164acSJocelyn Falempe         }
847cb5164acSJocelyn Falempe         (x, y)
848cb5164acSJocelyn Falempe     }
849cb5164acSJocelyn Falempe 
draw_data(&mut self, data: impl Iterator<Item = u8>)850cb5164acSJocelyn Falempe     fn draw_data(&mut self, data: impl Iterator<Item = u8>) {
851cb5164acSJocelyn Falempe         let (mut x, mut y) = (self.width - 1, self.width - 1);
852cb5164acSJocelyn Falempe         for byte in data {
853cb5164acSJocelyn Falempe             for s in 0..8 {
854cb5164acSJocelyn Falempe                 if byte & (0x80 >> s) == 0 {
855cb5164acSJocelyn Falempe                     self.set(x, y);
856cb5164acSJocelyn Falempe                 }
857cb5164acSJocelyn Falempe                 (x, y) = self.next_available(x, y);
858cb5164acSJocelyn Falempe             }
859cb5164acSJocelyn Falempe         }
860cb5164acSJocelyn Falempe         // Set the remaining modules (0, 3 or 7 depending on version).
861cb5164acSJocelyn Falempe         // because 0 correspond to a light module.
862cb5164acSJocelyn Falempe         while !self.is_last(x, y) {
863cb5164acSJocelyn Falempe             if !self.is_reserved(x, y) {
864cb5164acSJocelyn Falempe                 self.set(x, y);
865cb5164acSJocelyn Falempe             }
866cb5164acSJocelyn Falempe             (x, y) = self.next(x, y);
867cb5164acSJocelyn Falempe         }
868cb5164acSJocelyn Falempe     }
869cb5164acSJocelyn Falempe 
87074757ad1SMiguel Ojeda     /// Apply checkerboard mask to all non-reserved modules.
apply_mask(&mut self)871cb5164acSJocelyn Falempe     fn apply_mask(&mut self) {
872cb5164acSJocelyn Falempe         for x in 0..self.width {
873cb5164acSJocelyn Falempe             for y in 0..self.width {
874cb5164acSJocelyn Falempe                 if (x ^ y) % 2 == 0 && !self.is_reserved(x, y) {
875cb5164acSJocelyn Falempe                     self.xor(x, y);
876cb5164acSJocelyn Falempe                 }
877cb5164acSJocelyn Falempe             }
878cb5164acSJocelyn Falempe         }
879cb5164acSJocelyn Falempe     }
880cb5164acSJocelyn Falempe 
88174757ad1SMiguel Ojeda     /// Draw the QR code with the provided data iterator.
draw_all(&mut self, data: impl Iterator<Item = u8>)882cb5164acSJocelyn Falempe     fn draw_all(&mut self, data: impl Iterator<Item = u8>) {
883cb5164acSJocelyn Falempe         // First clear the table, as it may have already some data.
884cb5164acSJocelyn Falempe         self.clear();
885cb5164acSJocelyn Falempe         self.draw_finders();
886cb5164acSJocelyn Falempe         self.draw_alignments();
887cb5164acSJocelyn Falempe         self.draw_timing_patterns();
888cb5164acSJocelyn Falempe         self.draw_version_info();
889cb5164acSJocelyn Falempe         self.draw_data(data);
890cb5164acSJocelyn Falempe         self.draw_maskinfo();
891cb5164acSJocelyn Falempe         self.apply_mask();
892cb5164acSJocelyn Falempe     }
893cb5164acSJocelyn Falempe }
894cb5164acSJocelyn Falempe 
895cb5164acSJocelyn Falempe /// C entry point for the rust QR Code generator.
896cb5164acSJocelyn Falempe ///
897cb5164acSJocelyn Falempe /// Write the QR code image in the data buffer, and return the QR code width,
898cb5164acSJocelyn Falempe /// or 0, if the data doesn't fit in a QR code.
899cb5164acSJocelyn Falempe ///
900cb5164acSJocelyn Falempe /// * `url`: The base URL of the QR code. It will be encoded as Binary segment.
901cb5164acSJocelyn Falempe /// * `data`: A pointer to the binary data, to be encoded. if URL is NULL, it
902cb5164acSJocelyn Falempe ///   will be encoded as binary segment, otherwise it will be encoded
903cb5164acSJocelyn Falempe ///   efficiently as a numeric segment, and appended to the URL.
904cb5164acSJocelyn Falempe /// * `data_len`: Length of the data, that needs to be encoded, must be less
905f8ae3507SMiguel Ojeda ///   than `data_size`.
906cb5164acSJocelyn Falempe /// * `data_size`: Size of data buffer, it should be at least 4071 bytes to hold
907cb5164acSJocelyn Falempe ///   a V40 QR code. It will then be overwritten with the QR code image.
908cb5164acSJocelyn Falempe /// * `tmp`: A temporary buffer that the QR code encoder will use, to write the
909cb5164acSJocelyn Falempe ///   segments and ECC.
910cb5164acSJocelyn Falempe /// * `tmp_size`: Size of the temporary buffer, it must be at least 3706 bytes
911cb5164acSJocelyn Falempe ///   long for V40.
912cb5164acSJocelyn Falempe ///
913cb5164acSJocelyn Falempe /// # Safety
914cb5164acSJocelyn Falempe ///
915cb5164acSJocelyn Falempe /// * `url` must be null or point at a nul-terminated string.
916cb5164acSJocelyn Falempe /// * `data` must be valid for reading and writing for `data_size` bytes.
917cb5164acSJocelyn Falempe /// * `tmp` must be valid for reading and writing for `tmp_size` bytes.
918cb5164acSJocelyn Falempe ///
919cb5164acSJocelyn Falempe /// They must remain valid for the duration of the function call.
920fc2f191fSAlice Ryhl #[export]
drm_panic_qr_generate( url: *const kernel::ffi::c_char, data: *mut u8, data_len: usize, data_size: usize, tmp: *mut u8, tmp_size: usize, ) -> u8921cb5164acSJocelyn Falempe pub unsafe extern "C" fn drm_panic_qr_generate(
92227c7518eSMiguel Ojeda     url: *const kernel::ffi::c_char,
923cb5164acSJocelyn Falempe     data: *mut u8,
924cb5164acSJocelyn Falempe     data_len: usize,
925cb5164acSJocelyn Falempe     data_size: usize,
926cb5164acSJocelyn Falempe     tmp: *mut u8,
927cb5164acSJocelyn Falempe     tmp_size: usize,
928cb5164acSJocelyn Falempe ) -> u8 {
929cb5164acSJocelyn Falempe     if data_size < 4071 || tmp_size < 3706 || data_len > data_size {
930cb5164acSJocelyn Falempe         return 0;
931cb5164acSJocelyn Falempe     }
932cb5164acSJocelyn Falempe     // SAFETY: The caller ensures that `data` is a valid pointer for reading and
933cb5164acSJocelyn Falempe     // writing `data_size` bytes.
934cb5164acSJocelyn Falempe     let data_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(data, data_size) };
935cb5164acSJocelyn Falempe     // SAFETY: The caller ensures that `tmp` is a valid pointer for reading and
936cb5164acSJocelyn Falempe     // writing `tmp_size` bytes.
937cb5164acSJocelyn Falempe     let tmp_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(tmp, tmp_size) };
938cb5164acSJocelyn Falempe     if url.is_null() {
939cb5164acSJocelyn Falempe         match EncodedMsg::new(&[&Segment::Binary(&data_slice[0..data_len])], tmp_slice) {
940cb5164acSJocelyn Falempe             None => 0,
941cb5164acSJocelyn Falempe             Some(em) => {
942cb5164acSJocelyn Falempe                 let qr_image = QrImage::new(&em, data_slice);
943cb5164acSJocelyn Falempe                 qr_image.width
944cb5164acSJocelyn Falempe             }
945cb5164acSJocelyn Falempe         }
946cb5164acSJocelyn Falempe     } else {
947cb5164acSJocelyn Falempe         // SAFETY: The caller ensures that `url` is a valid pointer to a
948cb5164acSJocelyn Falempe         // nul-terminated string.
949cb5164acSJocelyn Falempe         let url_cstr: &CStr = unsafe { CStr::from_char_ptr(url) };
950cb5164acSJocelyn Falempe         let segments = &[
951cb5164acSJocelyn Falempe             &Segment::Binary(url_cstr.as_bytes()),
952cb5164acSJocelyn Falempe             &Segment::Numeric(&data_slice[0..data_len]),
953cb5164acSJocelyn Falempe         ];
954cb5164acSJocelyn Falempe         match EncodedMsg::new(segments, tmp_slice) {
955cb5164acSJocelyn Falempe             None => 0,
956cb5164acSJocelyn Falempe             Some(em) => {
957cb5164acSJocelyn Falempe                 let qr_image = QrImage::new(&em, data_slice);
958cb5164acSJocelyn Falempe                 qr_image.width
959cb5164acSJocelyn Falempe             }
960cb5164acSJocelyn Falempe         }
961cb5164acSJocelyn Falempe     }
962cb5164acSJocelyn Falempe }
963cb5164acSJocelyn Falempe 
964cb5164acSJocelyn Falempe /// Returns the maximum data size that can fit in a QR code of this version.
965cb5164acSJocelyn Falempe /// * `version`: QR code version, between 1-40.
966cb5164acSJocelyn Falempe /// * `url_len`: Length of the URL.
967cb5164acSJocelyn Falempe ///
968cb5164acSJocelyn Falempe /// * If `url_len` > 0, remove the 2 segments header/length and also count the
969cb5164acSJocelyn Falempe ///   conversion to numeric segments.
970cb5164acSJocelyn Falempe /// * If `url_len` = 0, only removes 3 bytes for 1 binary segment.
971fc2f191fSAlice Ryhl ///
972fc2f191fSAlice Ryhl /// # Safety
973fc2f191fSAlice Ryhl ///
974fc2f191fSAlice Ryhl /// Always safe to call.
975fc2f191fSAlice Ryhl // Required to be unsafe due to the `#[export]` annotation.
976fc2f191fSAlice Ryhl #[export]
drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize977fc2f191fSAlice Ryhl pub unsafe extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize {
97806b919e3SThomas Böhler     #[expect(clippy::manual_range_contains)]
979cb5164acSJocelyn Falempe     if version < 1 || version > 40 {
980cb5164acSJocelyn Falempe         return 0;
981cb5164acSJocelyn Falempe     }
982cb5164acSJocelyn Falempe     let max_data = Version(version as usize).max_data();
983cb5164acSJocelyn Falempe 
984cb5164acSJocelyn Falempe     if url_len > 0 {
985cb5164acSJocelyn Falempe         // Binary segment (URL) 4 + 16 bits, numeric segment (kmsg) 4 + 12 bits => 5 bytes.
986cb5164acSJocelyn Falempe         if url_len + 5 >= max_data {
987cb5164acSJocelyn Falempe             0
988cb5164acSJocelyn Falempe         } else {
989cb5164acSJocelyn Falempe             let max = max_data - url_len - 5;
990cb5164acSJocelyn Falempe             (max * 39) / 40
991cb5164acSJocelyn Falempe         }
992cb5164acSJocelyn Falempe     } else {
993cb5164acSJocelyn Falempe         // Remove 3 bytes for the binary segment (header 4 bits, length 16 bits, stop 4bits).
994cb5164acSJocelyn Falempe         max_data - 3
995cb5164acSJocelyn Falempe     }
996cb5164acSJocelyn Falempe }
997