brintos

brintos / linux-shallow public Read only

0
0
Text · 33.4 KiB · 1ef56cb Raw
1004 lines · rust
1// SPDX-License-Identifier: MIT2 3//! This is a simple QR encoder for DRM panic.4//!5//! It is called from a panic handler, so it should't allocate memory and6//! does all the work on the stack or on the provided buffers. For7//! simplification, it only supports low error correction, and applies the8//! first mask (checkerboard). It will draw the smallest QRcode that can9//! contain the string passed as parameter. To get the most compact10//! QR code, the start of the URL is encoded as binary, and the11//! compressed kmsg is encoded as numeric.12//!13//! The binary data must be a valid URL parameter, so the easiest way is14//! to use base64 encoding. But this wastes 25% of data space, so the15//! whole stack trace won't fit in the QR code. So instead it encodes16//! every 13bits of input into 4 decimal digits, and then uses the17//! efficient numeric encoding, that encode 3 decimal digits into18//! 10bits. This makes 39bits of compressed data into 12 decimal digits,19//! into 40bits in the QR code, so wasting only 2.5%. And the numbers are20//! valid URL parameter, so the website can do the reverse, to get the21//! binary data.22//!23//! Inspired by these 3 projects, all under MIT license:24//!25//! * <https://github.com/kennytm/qrcode-rust>26//! * <https://github.com/erwanvivien/fast_qr>27//! * <https://github.com/bjguillot/qr>28 29use core::cmp;30use kernel::str::CStr;31 32#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]33struct Version(usize);34 35// Generator polynomials for ECC, only those that are needed for low quality.36const P7: [u8; 7] = [87, 229, 146, 149, 238, 102, 21];37const P10: [u8; 10] = [251, 67, 46, 61, 118, 70, 64, 94, 32, 45];38const P15: [u8; 15] = [39    8, 183, 61, 91, 202, 37, 51, 58, 58, 237, 140, 124, 5, 99, 105,40];41const P18: [u8; 18] = [42    215, 234, 158, 94, 184, 97, 118, 170, 79, 187, 152, 148, 252, 179, 5, 98, 96, 153,43];44const P20: [u8; 20] = [45    17, 60, 79, 50, 61, 163, 26, 187, 202, 180, 221, 225, 83, 239, 156, 164, 212, 212, 188, 190,46];47const P22: [u8; 22] = [48    210, 171, 247, 242, 93, 230, 14, 109, 221, 53, 200, 74, 8, 172, 98, 80, 219, 134, 160, 105,49    165, 231,50];51const P24: [u8; 24] = [52    229, 121, 135, 48, 211, 117, 251, 126, 159, 180, 169, 152, 192, 226, 228, 218, 111, 0, 117,53    232, 87, 96, 227, 21,54];55const P26: [u8; 26] = [56    173, 125, 158, 2, 103, 182, 118, 17, 145, 201, 111, 28, 165, 53, 161, 21, 245, 142, 13, 102,57    48, 227, 153, 145, 218, 70,58];59const P28: [u8; 28] = [60    168, 223, 200, 104, 224, 234, 108, 180, 110, 190, 195, 147, 205, 27, 232, 201, 21, 43, 245, 87,61    42, 195, 212, 119, 242, 37, 9, 123,62];63const P30: [u8; 30] = [64    41, 173, 145, 152, 216, 31, 179, 182, 50, 48, 110, 86, 239, 96, 222, 125, 42, 173, 226, 193,65    224, 130, 156, 37, 251, 216, 238, 40, 192, 180,66];67 68/// QR Code parameters for Low quality ECC:69/// - Error Correction polynomial.70/// - Number of blocks in group 1.71/// - Number of blocks in group 2.72/// - Block size in group 1.73///74/// (Block size in group 2 is one more than group 1).75struct VersionParameter(&'static [u8], u8, u8, u8);76const VPARAM: [VersionParameter; 40] = [77    VersionParameter(&P7, 1, 0, 19),    // V178    VersionParameter(&P10, 1, 0, 34),   // V279    VersionParameter(&P15, 1, 0, 55),   // V380    VersionParameter(&P20, 1, 0, 80),   // V481    VersionParameter(&P26, 1, 0, 108),  // V582    VersionParameter(&P18, 2, 0, 68),   // V683    VersionParameter(&P20, 2, 0, 78),   // V784    VersionParameter(&P24, 2, 0, 97),   // V885    VersionParameter(&P30, 2, 0, 116),  // V986    VersionParameter(&P18, 2, 2, 68),   // V1087    VersionParameter(&P20, 4, 0, 81),   // V1188    VersionParameter(&P24, 2, 2, 92),   // V1289    VersionParameter(&P26, 4, 0, 107),  // V1390    VersionParameter(&P30, 3, 1, 115),  // V1491    VersionParameter(&P22, 5, 1, 87),   // V1592    VersionParameter(&P24, 5, 1, 98),   // V1693    VersionParameter(&P28, 1, 5, 107),  // V1794    VersionParameter(&P30, 5, 1, 120),  // V1895    VersionParameter(&P28, 3, 4, 113),  // V1996    VersionParameter(&P28, 3, 5, 107),  // V2097    VersionParameter(&P28, 4, 4, 116),  // V2198    VersionParameter(&P28, 2, 7, 111),  // V2299    VersionParameter(&P30, 4, 5, 121),  // V23100    VersionParameter(&P30, 6, 4, 117),  // V24101    VersionParameter(&P26, 8, 4, 106),  // V25102    VersionParameter(&P28, 10, 2, 114), // V26103    VersionParameter(&P30, 8, 4, 122),  // V27104    VersionParameter(&P30, 3, 10, 117), // V28105    VersionParameter(&P30, 7, 7, 116),  // V29106    VersionParameter(&P30, 5, 10, 115), // V30107    VersionParameter(&P30, 13, 3, 115), // V31108    VersionParameter(&P30, 17, 0, 115), // V32109    VersionParameter(&P30, 17, 1, 115), // V33110    VersionParameter(&P30, 13, 6, 115), // V34111    VersionParameter(&P30, 12, 7, 121), // V35112    VersionParameter(&P30, 6, 14, 121), // V36113    VersionParameter(&P30, 17, 4, 122), // V37114    VersionParameter(&P30, 4, 18, 122), // V38115    VersionParameter(&P30, 20, 4, 117), // V39116    VersionParameter(&P30, 19, 6, 118), // V40117];118 119const MAX_EC_SIZE: usize = 30;120const MAX_BLK_SIZE: usize = 123;121 122/// Position of the alignment pattern grid.123const ALIGNMENT_PATTERNS: [&[u8]; 40] = [124    &[],125    &[6, 18],126    &[6, 22],127    &[6, 26],128    &[6, 30],129    &[6, 34],130    &[6, 22, 38],131    &[6, 24, 42],132    &[6, 26, 46],133    &[6, 28, 50],134    &[6, 30, 54],135    &[6, 32, 58],136    &[6, 34, 62],137    &[6, 26, 46, 66],138    &[6, 26, 48, 70],139    &[6, 26, 50, 74],140    &[6, 30, 54, 78],141    &[6, 30, 56, 82],142    &[6, 30, 58, 86],143    &[6, 34, 62, 90],144    &[6, 28, 50, 72, 94],145    &[6, 26, 50, 74, 98],146    &[6, 30, 54, 78, 102],147    &[6, 28, 54, 80, 106],148    &[6, 32, 58, 84, 110],149    &[6, 30, 58, 86, 114],150    &[6, 34, 62, 90, 118],151    &[6, 26, 50, 74, 98, 122],152    &[6, 30, 54, 78, 102, 126],153    &[6, 26, 52, 78, 104, 130],154    &[6, 30, 56, 82, 108, 134],155    &[6, 34, 60, 86, 112, 138],156    &[6, 30, 58, 86, 114, 142],157    &[6, 34, 62, 90, 118, 146],158    &[6, 30, 54, 78, 102, 126, 150],159    &[6, 24, 50, 76, 102, 128, 154],160    &[6, 28, 54, 80, 106, 132, 158],161    &[6, 32, 58, 84, 110, 136, 162],162    &[6, 26, 54, 82, 110, 138, 166],163    &[6, 30, 58, 86, 114, 142, 170],164];165 166/// Version information for format V7-V40.167const VERSION_INFORMATION: [u32; 34] = [168    0b00_0111_1100_1001_0100,169    0b00_1000_0101_1011_1100,170    0b00_1001_1010_1001_1001,171    0b00_1010_0100_1101_0011,172    0b00_1011_1011_1111_0110,173    0b00_1100_0111_0110_0010,174    0b00_1101_1000_0100_0111,175    0b00_1110_0110_0000_1101,176    0b00_1111_1001_0010_1000,177    0b01_0000_1011_0111_1000,178    0b01_0001_0100_0101_1101,179    0b01_0010_1010_0001_0111,180    0b01_0011_0101_0011_0010,181    0b01_0100_1001_1010_0110,182    0b01_0101_0110_1000_0011,183    0b01_0110_1000_1100_1001,184    0b01_0111_0111_1110_1100,185    0b01_1000_1110_1100_0100,186    0b01_1001_0001_1110_0001,187    0b01_1010_1111_1010_1011,188    0b01_1011_0000_1000_1110,189    0b01_1100_1100_0001_1010,190    0b01_1101_0011_0011_1111,191    0b01_1110_1101_0111_0101,192    0b01_1111_0010_0101_0000,193    0b10_0000_1001_1101_0101,194    0b10_0001_0110_1111_0000,195    0b10_0010_1000_1011_1010,196    0b10_0011_0111_1001_1111,197    0b10_0100_1011_0000_1011,198    0b10_0101_0100_0010_1110,199    0b10_0110_1010_0110_0100,200    0b10_0111_0101_0100_0001,201    0b10_1000_1100_0110_1001,202];203 204/// Format info for low quality ECC.205const FORMAT_INFOS_QR_L: [u16; 8] = [206    0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976,207];208 209impl Version {210    /// Returns the smallest QR version than can hold these segments.211    fn from_segments(segments: &[&Segment<'_>]) -> Option<Version> {212        for v in (1..=40).map(|k| Version(k)) {213            if v.max_data() * 8 >= segments.iter().map(|s| s.total_size_bits(v)).sum() {214                return Some(v);215            }216        }217        None218    }219 220    fn width(&self) -> u8 {221        (self.0 as u8) * 4 + 17222    }223 224    fn max_data(&self) -> usize {225        self.g1_blk_size() * self.g1_blocks() + (self.g1_blk_size() + 1) * self.g2_blocks()226    }227 228    fn ec_size(&self) -> usize {229        VPARAM[self.0 - 1].0.len()230    }231 232    fn g1_blocks(&self) -> usize {233        VPARAM[self.0 - 1].1 as usize234    }235 236    fn g2_blocks(&self) -> usize {237        VPARAM[self.0 - 1].2 as usize238    }239 240    fn g1_blk_size(&self) -> usize {241        VPARAM[self.0 - 1].3 as usize242    }243 244    fn alignment_pattern(&self) -> &'static [u8] {245        &ALIGNMENT_PATTERNS[self.0 - 1]246    }247 248    fn poly(&self) -> &'static [u8] {249        VPARAM[self.0 - 1].0250    }251 252    fn version_info(&self) -> u32 {253        if *self >= Version(7) {254            VERSION_INFORMATION[self.0 - 7]255        } else {256            0257        }258    }259}260 261/// Exponential table for Galois Field GF(256).262const EXP_TABLE: [u8; 256] = [263    1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117,264    234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181,265    119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161,266    95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187,267    107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136,268    13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197,269    151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168,270    77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198,271    145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149,272    55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167,273    83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72,274    144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207,275    131, 27, 54, 108, 216, 173, 71, 142, 1,276];277 278/// Reverse exponential table for Galois Field GF(256).279const LOG_TABLE: [u8; 256] = [280    175, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141,281    239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142,282    218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114,283    166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148,284    206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126,285    110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172,286    115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24,287    227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149,288    188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132,289    60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12,290    111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95,291    176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173,292    232, 116, 214, 244, 234, 168, 80, 88, 175,293];294 295// 4 bits segment header.296const MODE_STOP: u16 = 0;297const MODE_NUMERIC: u16 = 1;298const MODE_BINARY: u16 = 4;299/// Padding bytes.300const PADDING: [u8; 2] = [236, 17];301 302/// Get the next 13 bits of data, starting at specified offset (in bits).303fn get_next_13b(data: &[u8], offset: usize) -> Option<(u16, usize)> {304    if offset < data.len() * 8 {305        let size = cmp::min(13, data.len() * 8 - offset);306        let byte_off = offset / 8;307        let bit_off = offset % 8;308        // `b` is 20 at max (`bit_off` <= 7 and `size` <= 13).309        let b = (bit_off + size) as u16;310 311        let first_byte = (data[byte_off] << bit_off >> bit_off) as u16;312 313        let number = match b {314            0..=8 => first_byte >> (8 - b),315            9..=16 => (first_byte << (b - 8)) + (data[byte_off + 1] >> (16 - b)) as u16,316            _ => {317                (first_byte << (b - 8))318                    + ((data[byte_off + 1] as u16) << (b - 16))319                    + (data[byte_off + 2] >> (24 - b)) as u16320            }321        };322        Some((number, size))323    } else {324        None325    }326}327 328/// Number of bits to encode characters in numeric mode.329const NUM_CHARS_BITS: [usize; 4] = [0, 4, 7, 10];330const POW10: [u16; 4] = [1, 10, 100, 1000];331 332enum Segment<'a> {333    Numeric(&'a [u8]),334    Binary(&'a [u8]),335}336 337impl Segment<'_> {338    fn get_header(&self) -> (u16, usize) {339        match self {340            Segment::Binary(_) => (MODE_BINARY, 4),341            Segment::Numeric(_) => (MODE_NUMERIC, 4),342        }343    }344 345    // Returns the size of the length field in bits, depending on QR Version.346    fn length_bits_count(&self, version: Version) -> usize {347        let Version(v) = version;348        match self {349            Segment::Binary(_) => match v {350                1..=9 => 8,351                _ => 16,352            },353            Segment::Numeric(_) => match v {354                1..=9 => 10,355                10..=26 => 12,356                _ => 14,357            },358        }359    }360 361    // Number of characters in the segment.362    fn character_count(&self) -> usize {363        match self {364            Segment::Binary(data) => data.len(),365            Segment::Numeric(data) => {366                let data_bits = data.len() * 8;367                let last_chars = match data_bits % 13 {368                    1 => 1,369                    k => (k + 1) / 3,370                };371                // 4 decimal numbers per 13bits + remainder.372                4 * (data_bits / 13) + last_chars373            }374        }375    }376 377    fn get_length_field(&self, version: Version) -> (u16, usize) {378        (379            self.character_count() as u16,380            self.length_bits_count(version),381        )382    }383 384    fn total_size_bits(&self, version: Version) -> usize {385        let data_size = match self {386            Segment::Binary(data) => data.len() * 8,387            Segment::Numeric(_) => {388                let digits = self.character_count();389                10 * (digits / 3) + NUM_CHARS_BITS[digits % 3]390            }391        };392        // header + length + data.393        4 + self.length_bits_count(version) + data_size394    }395 396    fn iter(&self) -> SegmentIterator<'_> {397        SegmentIterator {398            segment: self,399            offset: 0,400            carry: 0,401            carry_len: 0,402        }403    }404}405 406struct SegmentIterator<'a> {407    segment: &'a Segment<'a>,408    offset: usize,409    carry: u16,410    carry_len: usize,411}412 413impl Iterator for SegmentIterator<'_> {414    type Item = (u16, usize);415 416    fn next(&mut self) -> Option<Self::Item> {417        match self.segment {418            Segment::Binary(data) => {419                if self.offset < data.len() {420                    let byte = data[self.offset] as u16;421                    self.offset += 1;422                    Some((byte, 8))423                } else {424                    None425                }426            }427            Segment::Numeric(data) => {428                if self.carry_len == 3 {429                    let out = (self.carry, NUM_CHARS_BITS[self.carry_len]);430                    self.carry_len = 0;431                    self.carry = 0;432                    Some(out)433                } else if let Some((bits, size)) = get_next_13b(data, self.offset) {434                    self.offset += size;435                    let new_chars = match size {436                        1 => 1,437                        k => (k + 1) / 3,438                    };439                    if self.carry_len + new_chars > 3 {440                        self.carry_len = new_chars + self.carry_len - 3;441                        let out = (442                            self.carry * POW10[new_chars - self.carry_len]443                                + bits / POW10[self.carry_len],444                            NUM_CHARS_BITS[3],445                        );446                        self.carry = bits % POW10[self.carry_len];447                        Some(out)448                    } else {449                        let out = (450                            self.carry * POW10[new_chars] + bits,451                            NUM_CHARS_BITS[self.carry_len + new_chars],452                        );453                        self.carry_len = 0;454                        Some(out)455                    }456                } else if self.carry_len > 0 {457                    let out = (self.carry, NUM_CHARS_BITS[self.carry_len]);458                    self.carry_len = 0;459                    Some(out)460                } else {461                    None462                }463            }464        }465    }466}467 468struct EncodedMsg<'a> {469    data: &'a mut [u8],470    ec_size: usize,471    g1_blocks: usize,472    g2_blocks: usize,473    g1_blk_size: usize,474    g2_blk_size: usize,475    poly: &'static [u8],476    version: Version,477}478 479/// Data to be put in the QR code, with correct segment encoding, padding, and480/// Error Code Correction.481impl EncodedMsg<'_> {482    fn new<'a, 'b>(segments: &[&Segment<'b>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> {483        let version = Version::from_segments(segments)?;484        let ec_size = version.ec_size();485        let g1_blocks = version.g1_blocks();486        let g2_blocks = version.g2_blocks();487        let g1_blk_size = version.g1_blk_size();488        let g2_blk_size = g1_blk_size + 1;489        let poly = version.poly();490 491        // clear the output.492        data.fill(0);493 494        let mut em = EncodedMsg {495            data: data,496            ec_size,497            g1_blocks,498            g2_blocks,499            g1_blk_size,500            g2_blk_size,501            poly,502            version,503        };504        em.encode(segments);505        Some(em)506    }507 508    /// Push bits of data at an offset (in bits).509    fn push(&mut self, offset: &mut usize, bits: (u16, usize)) {510        let (number, len_bits) = bits;511        let byte_off = *offset / 8;512        let bit_off = *offset % 8;513        let b = bit_off + len_bits;514 515        match (bit_off, b) {516            (0, 0..=8) => {517                self.data[byte_off] = (number << (8 - b)) as u8;518            }519            (0, _) => {520                self.data[byte_off] = (number >> (b - 8)) as u8;521                self.data[byte_off + 1] = (number << (16 - b)) as u8;522            }523            (_, 0..=8) => {524                self.data[byte_off] |= (number << (8 - b)) as u8;525            }526            (_, 9..=16) => {527                self.data[byte_off] |= (number >> (b - 8)) as u8;528                self.data[byte_off + 1] = (number << (16 - b)) as u8;529            }530            _ => {531                self.data[byte_off] |= (number >> (b - 8)) as u8;532                self.data[byte_off + 1] = (number >> (b - 16)) as u8;533                self.data[byte_off + 2] = (number << (24 - b)) as u8;534            }535        }536        *offset += len_bits;537    }538 539    fn add_segments(&mut self, segments: &[&Segment<'_>]) {540        let mut offset: usize = 0;541 542        for s in segments.iter() {543            self.push(&mut offset, s.get_header());544            self.push(&mut offset, s.get_length_field(self.version));545            for bits in s.iter() {546                self.push(&mut offset, bits);547            }548        }549        self.push(&mut offset, (MODE_STOP, 4));550 551        let pad_offset = (offset + 7) / 8;552        for i in pad_offset..self.version.max_data() {553            self.data[i] = PADDING[(i & 1) ^ (pad_offset & 1)];554        }555    }556 557    fn error_code_for_blocks(&mut self, offset: usize, size: usize, ec_offset: usize) {558        let mut tmp: [u8; MAX_BLK_SIZE + MAX_EC_SIZE] = [0; MAX_BLK_SIZE + MAX_EC_SIZE];559 560        tmp[0..size].copy_from_slice(&self.data[offset..offset + size]);561        for i in 0..size {562            let lead_coeff = tmp[i] as usize;563            if lead_coeff == 0 {564                continue;565            }566            let log_lead_coeff = usize::from(LOG_TABLE[lead_coeff]);567            for (u, &v) in tmp[i + 1..].iter_mut().zip(self.poly.iter()) {568                *u ^= EXP_TABLE[(usize::from(v) + log_lead_coeff) % 255];569            }570        }571        self.data[ec_offset..ec_offset + self.ec_size]572            .copy_from_slice(&tmp[size..size + self.ec_size]);573    }574 575    fn compute_error_code(&mut self) {576        let mut offset = 0;577        let mut ec_offset = self.g1_blocks * self.g1_blk_size + self.g2_blocks * self.g2_blk_size;578 579        for _ in 0..self.g1_blocks {580            self.error_code_for_blocks(offset, self.g1_blk_size, ec_offset);581            offset += self.g1_blk_size;582            ec_offset += self.ec_size;583        }584        for _ in 0..self.g2_blocks {585            self.error_code_for_blocks(offset, self.g2_blk_size, ec_offset);586            offset += self.g2_blk_size;587            ec_offset += self.ec_size;588        }589    }590 591    fn encode(&mut self, segments: &[&Segment<'_>]) {592        self.add_segments(segments);593        self.compute_error_code();594    }595 596    fn iter(&self) -> EncodedMsgIterator<'_> {597        EncodedMsgIterator {598            em: self,599            offset: 0,600        }601    }602}603 604/// Iterator, to retrieve the data in the interleaved order needed by QR code.605struct EncodedMsgIterator<'a> {606    em: &'a EncodedMsg<'a>,607    offset: usize,608}609 610impl Iterator for EncodedMsgIterator<'_> {611    type Item = u8;612 613    // Send the bytes in interleaved mode, first byte of first block of group1,614    // then first byte of second block of group1, ...615    fn next(&mut self) -> Option<Self::Item> {616        let em = self.em;617        let blocks = em.g1_blocks + em.g2_blocks;618        let g1_end = em.g1_blocks * em.g1_blk_size;619        let g2_end = g1_end + em.g2_blocks * em.g2_blk_size;620        let ec_end = g2_end + em.ec_size * blocks;621 622        if self.offset >= ec_end {623            return None;624        }625 626        let offset = if self.offset < em.g1_blk_size * blocks {627            // group1 and group2 interleaved628            let blk = self.offset % blocks;629            let blk_off = self.offset / blocks;630            if blk < em.g1_blocks {631                blk * em.g1_blk_size + blk_off632            } else {633                g1_end + em.g2_blk_size * (blk - em.g1_blocks) + blk_off634            }635        } else if self.offset < g2_end {636            // last byte of group2 blocks637            let blk2 = self.offset - blocks * em.g1_blk_size;638            em.g1_blk_size * em.g1_blocks + blk2 * em.g2_blk_size + em.g2_blk_size - 1639        } else {640            // EC blocks641            let ec_offset = self.offset - g2_end;642            let blk = ec_offset % blocks;643            let blk_off = ec_offset / blocks;644 645            g2_end + blk * em.ec_size + blk_off646        };647        self.offset += 1;648        Some(em.data[offset])649    }650}651 652/// A QR code image, encoded as a linear binary framebuffer.653/// 1 bit per module (pixel), each new line start at next byte boundary.654/// Max width is 177 for V40 QR code, so `u8` is enough for coordinate.655struct QrImage<'a> {656    data: &'a mut [u8],657    width: u8,658    stride: u8,659    version: Version,660}661 662impl QrImage<'_> {663    fn new<'a, 'b>(em: &'b EncodedMsg<'b>, qrdata: &'a mut [u8]) -> QrImage<'a> {664        let width = em.version.width();665        let stride = (width + 7) / 8;666        let data = qrdata;667 668        let mut qr_image = QrImage {669            data,670            width,671            stride,672            version: em.version,673        };674        qr_image.draw_all(em.iter());675        qr_image676    }677 678    fn clear(&mut self) {679        self.data.fill(0);680    }681 682    // Set pixel to light color.683    fn set(&mut self, x: u8, y: u8) {684        let off = y as usize * self.stride as usize + x as usize / 8;685        let mut v = self.data[off];686        v |= 0x80 >> (x % 8);687        self.data[off] = v;688    }689 690    // Invert a module color.691    fn xor(&mut self, x: u8, y: u8) {692        let off = y as usize * self.stride as usize + x as usize / 8;693        self.data[off] ^= 0x80 >> (x % 8);694    }695 696    // Draw a light square at (x, y) top left corner.697    fn draw_square(&mut self, x: u8, y: u8, size: u8) {698        for k in 0..size {699            self.set(x + k, y);700            self.set(x, y + k + 1);701            self.set(x + size, y + k);702            self.set(x + k + 1, y + size);703        }704    }705 706    // Finder pattern: 3 8x8 square at the corners.707    fn draw_finders(&mut self) {708        self.draw_square(1, 1, 4);709        self.draw_square(self.width - 6, 1, 4);710        self.draw_square(1, self.width - 6, 4);711        for k in 0..8 {712            self.set(k, 7);713            self.set(self.width - k - 1, 7);714            self.set(k, self.width - 8);715        }716        for k in 0..7 {717            self.set(7, k);718            self.set(self.width - 8, k);719            self.set(7, self.width - 1 - k);720        }721    }722 723    fn is_finder(&self, x: u8, y: u8) -> bool {724        let end = self.width - 8;725        (x < 8 && y < 8) || (x < 8 && y >= end) || (x >= end && y < 8)726    }727 728    // Alignment pattern: 5x5 squares in a grid.729    fn draw_alignments(&mut self) {730        let positions = self.version.alignment_pattern();731        for &x in positions.iter() {732            for &y in positions.iter() {733                if !self.is_finder(x, y) {734                    self.draw_square(x - 1, y - 1, 2);735                }736            }737        }738    }739 740    fn is_alignment(&self, x: u8, y: u8) -> bool {741        let positions = self.version.alignment_pattern();742        for &ax in positions.iter() {743            for &ay in positions.iter() {744                if self.is_finder(ax, ay) {745                    continue;746                }747                if x >= ax - 2 && x <= ax + 2 && y >= ay - 2 && y <= ay + 2 {748                    return true;749                }750            }751        }752        false753    }754 755    // Timing pattern: 2 dotted line between the finder patterns.756    fn draw_timing_patterns(&mut self) {757        let end = self.width - 8;758 759        for x in (9..end).step_by(2) {760            self.set(x, 6);761            self.set(6, x);762        }763    }764 765    fn is_timing(&self, x: u8, y: u8) -> bool {766        x == 6 || y == 6767    }768 769    // Mask info: 15 bits around the finders, written twice for redundancy.770    fn draw_maskinfo(&mut self) {771        let info: u16 = FORMAT_INFOS_QR_L[0];772        let mut skip = 0;773 774        for k in 0..7 {775            if k == 6 {776                skip = 1;777            }778            if info & (1 << (14 - k)) == 0 {779                self.set(k + skip, 8);780                self.set(8, self.width - 1 - k);781            }782        }783        skip = 0;784        for k in 0..8 {785            if k == 2 {786                skip = 1;787            }788            if info & (1 << (7 - k)) == 0 {789                self.set(8, 8 - skip - k);790                self.set(self.width - 8 + k, 8);791            }792        }793    }794 795    fn is_maskinfo(&self, x: u8, y: u8) -> bool {796        let end = self.width - 8;797        // Count the dark module as mask info.798        (x <= 8 && y == 8) || (y <= 8 && x == 8) || (x == 8 && y >= end) || (x >= end && y == 8)799    }800 801    // Version info: 18bits written twice, close to the finders.802    fn draw_version_info(&mut self) {803        let vinfo = self.version.version_info();804        let pos = self.width - 11;805 806        if vinfo != 0 {807            for x in 0..3 {808                for y in 0..6 {809                    if vinfo & (1 << (x + y * 3)) == 0 {810                        self.set(x + pos, y);811                        self.set(y, x + pos);812                    }813                }814            }815        }816    }817 818    fn is_version_info(&self, x: u8, y: u8) -> bool {819        let vinfo = self.version.version_info();820        let pos = self.width - 11;821 822        vinfo != 0 && ((x >= pos && x < pos + 3 && y < 6) || (y >= pos && y < pos + 3 && x < 6))823    }824 825    // Returns true if the module is reserved (Not usable for data and EC).826    fn is_reserved(&self, x: u8, y: u8) -> bool {827        self.is_alignment(x, y)828            || self.is_finder(x, y)829            || self.is_timing(x, y)830            || self.is_maskinfo(x, y)831            || self.is_version_info(x, y)832    }833 834    // Last module to draw, at bottom left corner.835    fn is_last(&self, x: u8, y: u8) -> bool {836        x == 0 && y == self.width - 1837    }838 839    // Move to the next module according to QR code order.840    // From bottom right corner, to bottom left corner.841    fn next(&self, x: u8, y: u8) -> (u8, u8) {842        let x_adj = if x <= 6 { x + 1 } else { x };843        let column_type = (self.width - x_adj) % 4;844 845        match column_type {846            2 if y > 0 => (x + 1, y - 1),847            0 if y < self.width - 1 => (x + 1, y + 1),848            0 | 2 if x == 7 => (x - 2, y),849            _ => (x - 1, y),850        }851    }852 853    // Find next module that can hold data.854    fn next_available(&self, x: u8, y: u8) -> (u8, u8) {855        let (mut x, mut y) = self.next(x, y);856        while self.is_reserved(x, y) && !self.is_last(x, y) {857            (x, y) = self.next(x, y);858        }859        (x, y)860    }861 862    fn draw_data(&mut self, data: impl Iterator<Item = u8>) {863        let (mut x, mut y) = (self.width - 1, self.width - 1);864        for byte in data {865            for s in 0..8 {866                if byte & (0x80 >> s) == 0 {867                    self.set(x, y);868                }869                (x, y) = self.next_available(x, y);870            }871        }872        // Set the remaining modules (0, 3 or 7 depending on version).873        // because 0 correspond to a light module.874        while !self.is_last(x, y) {875            if !self.is_reserved(x, y) {876                self.set(x, y);877            }878            (x, y) = self.next(x, y);879        }880    }881 882    // Apply checkerboard mask to all non-reserved modules.883    fn apply_mask(&mut self) {884        for x in 0..self.width {885            for y in 0..self.width {886                if (x ^ y) % 2 == 0 && !self.is_reserved(x, y) {887                    self.xor(x, y);888                }889            }890        }891    }892 893    // Draw the QR code with the provided data iterator.894    fn draw_all(&mut self, data: impl Iterator<Item = u8>) {895        // First clear the table, as it may have already some data.896        self.clear();897        self.draw_finders();898        self.draw_alignments();899        self.draw_timing_patterns();900        self.draw_version_info();901        self.draw_data(data);902        self.draw_maskinfo();903        self.apply_mask();904    }905}906 907/// C entry point for the rust QR Code generator.908///909/// Write the QR code image in the data buffer, and return the QR code width,910/// or 0, if the data doesn't fit in a QR code.911///912/// * `url`: The base URL of the QR code. It will be encoded as Binary segment.913/// * `data`: A pointer to the binary data, to be encoded. if URL is NULL, it914///    will be encoded as binary segment, otherwise it will be encoded915///    efficiently as a numeric segment, and appended to the URL.916/// * `data_len`: Length of the data, that needs to be encoded, must be less917///    than data_size.918/// * `data_size`: Size of data buffer, it should be at least 4071 bytes to hold919///    a V40 QR code. It will then be overwritten with the QR code image.920/// * `tmp`: A temporary buffer that the QR code encoder will use, to write the921///    segments and ECC.922/// * `tmp_size`: Size of the temporary buffer, it must be at least 3706 bytes923///    long for V40.924///925/// # Safety926///927/// * `url` must be null or point at a nul-terminated string.928/// * `data` must be valid for reading and writing for `data_size` bytes.929/// * `tmp` must be valid for reading and writing for `tmp_size` bytes.930///931/// They must remain valid for the duration of the function call.932 933#[no_mangle]934pub unsafe extern "C" fn drm_panic_qr_generate(935    url: *const i8,936    data: *mut u8,937    data_len: usize,938    data_size: usize,939    tmp: *mut u8,940    tmp_size: usize,941) -> u8 {942    if data_size < 4071 || tmp_size < 3706 || data_len > data_size {943        return 0;944    }945    // SAFETY: The caller ensures that `data` is a valid pointer for reading and946    // writing `data_size` bytes.947    let data_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(data, data_size) };948    // SAFETY: The caller ensures that `tmp` is a valid pointer for reading and949    // writing `tmp_size` bytes.950    let tmp_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(tmp, tmp_size) };951    if url.is_null() {952        match EncodedMsg::new(&[&Segment::Binary(&data_slice[0..data_len])], tmp_slice) {953            None => 0,954            Some(em) => {955                let qr_image = QrImage::new(&em, data_slice);956                qr_image.width957            }958        }959    } else {960        // SAFETY: The caller ensures that `url` is a valid pointer to a961        // nul-terminated string.962        let url_cstr: &CStr = unsafe { CStr::from_char_ptr(url) };963        let segments = &[964            &Segment::Binary(url_cstr.as_bytes()),965            &Segment::Numeric(&data_slice[0..data_len]),966        ];967        match EncodedMsg::new(segments, tmp_slice) {968            None => 0,969            Some(em) => {970                let qr_image = QrImage::new(&em, data_slice);971                qr_image.width972            }973        }974    }975}976 977/// Returns the maximum data size that can fit in a QR code of this version.978/// * `version`: QR code version, between 1-40.979/// * `url_len`: Length of the URL.980///981/// * If `url_len` > 0, remove the 2 segments header/length and also count the982/// conversion to numeric segments.983/// * If `url_len` = 0, only removes 3 bytes for 1 binary segment.984#[no_mangle]985pub extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize {986    if version < 1 || version > 40 {987        return 0;988    }989    let max_data = Version(version as usize).max_data();990 991    if url_len > 0 {992        // Binary segment (URL) 4 + 16 bits, numeric segment (kmsg) 4 + 12 bits => 5 bytes.993        if url_len + 5 >= max_data {994            0995        } else {996            let max = max_data - url_len - 5;997            (max * 39) / 40998        }999    } else {1000        // Remove 3 bytes for the binary segment (header 4 bits, length 16 bits, stop 4bits).1001        max_data - 31002    }1003}1004