diff --git a/rust-no-heap/Cargo.toml b/rust-no-heap/Cargo.toml new file mode 100644 index 0000000..9766378 --- /dev/null +++ b/rust-no-heap/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "qrcodegen" +version = "1.7.0" +authors = ["Project Nayuki"] +description = "High-quality QR Code generator library" +homepage = "https://www.nayuki.io/page/qr-code-generator-library" +repository = "https://github.com/nayuki/QR-Code-generator" +license = "MIT" diff --git a/rust-no-heap/examples/qrcodegen-demo.rs b/rust-no-heap/examples/qrcodegen-demo.rs new file mode 100644 index 0000000..49c167f --- /dev/null +++ b/rust-no-heap/examples/qrcodegen-demo.rs @@ -0,0 +1,267 @@ +/* + * QR Code generator demo (Rust, no heap) + * + * Run this command-line program with no arguments. The program computes a bunch of demonstration + * QR Codes and prints them to the console. Also, the SVG code for one QR Code is printed as a sample. + * + * Copyright (c) Project Nayuki. (MIT License) + * https://www.nayuki.io/page/qr-code-generator-library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * - The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * - The Software is provided "as is", without warranty of any kind, express or + * implied, including but not limited to the warranties of merchantability, + * fitness for a particular purpose and noninfringement. In no event shall the + * authors or copyright holders be liable for any claim, damages or other + * liability, whether in an action of contract, tort or otherwise, arising from, + * out of or in connection with the Software or the use or other dealings in the + * Software. + */ + +extern crate qrcodegen; +use qrcodegen::Mask; +use qrcodegen::QrCode; +use qrcodegen::QrCodeEcc; +use qrcodegen::QrSegment; +use qrcodegen::QrSegmentMode; +use qrcodegen::Version; + + +// The main application program. +fn main() { + do_basic_demo(); + do_variety_demo(); + do_segment_demo(); + do_mask_demo(); +} + + + +/*---- Demo suite ----*/ + +// Creates a single QR Code, then prints it to the console. +fn do_basic_demo() { + let text: &'static str = "Hello, world!"; // User-supplied Unicode text + let errcorlvl: QrCodeEcc = QrCodeEcc::Low; // Error correction level + + // Make and print the QR Code symbol + let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; + let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; + let qr: QrCode = QrCode::encode_text(text, &mut tempbuffer, &mut outbuffer, + errcorlvl, Version::MIN, Version::MAX, None, true).unwrap(); + // Note: qr has a reference to outbuffer, so outbuffer needs to outlive qr + std::mem::drop(tempbuffer); // Optional, because tempbuffer is only needed during encode_text() + print_qr(&qr); + println!("{}", to_svg_string(&qr, 4)); +} + + +// Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console. +fn do_variety_demo() { + { // Numeric mode encoding (3.33 bits per digit) + let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; + let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; + let qr = QrCode::encode_text("314159265358979323846264338327950288419716939937510", + &mut tempbuffer, &mut outbuffer, QrCodeEcc::Medium, Version::MIN, Version::MAX, None, true).unwrap(); + print_qr(&qr); + } + + { // Alphanumeric mode encoding (5.5 bits per character) + let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; + let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; + let qr = QrCode::encode_text("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", + &mut tempbuffer, &mut outbuffer, QrCodeEcc::High, Version::MIN, Version::MAX, None, true).unwrap(); + print_qr(&qr); + } + + { // Unicode text as UTF-8 + let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; + let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; + let qr = QrCode::encode_text("こんにちwa、世界! αβγδ", + &mut tempbuffer, &mut outbuffer, QrCodeEcc::Quartile, Version::MIN, Version::MAX, None, true).unwrap(); + print_qr(&qr); + } + + { // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland) + let text = concat!( + "Alice was beginning to get very tired of sitting by her sister on the bank, ", + "and of having nothing to do: once or twice she had peeped into the book her sister was reading, ", + "but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice ", + "'without pictures or conversations?' So she was considering in her own mind (as well as she could, ", + "for the hot day made her feel very sleepy and stupid), whether the pleasure of making a ", + "daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly ", + "a White Rabbit with pink eyes ran close by her."); + let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; + let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; + let qr = QrCode::encode_text(text, &mut tempbuffer, &mut outbuffer, + QrCodeEcc::High, Version::MIN, Version::MAX, None, true).unwrap(); + print_qr(&qr); + } +} + + +// Creates QR Codes with manually specified segments for better compactness. +fn do_segment_demo() { + { // Illustration "silver" + let silver0 = "THE SQUARE ROOT OF 2 IS 1."; + let silver1 = "41421356237309504880168872420969807856967187537694807317667973799"; + let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; + let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; + let qr = QrCode::encode_text(&[silver0, silver1].concat(), &mut tempbuffer, &mut outbuffer, + QrCodeEcc::Low, Version::MIN, Version::MAX, None, true).unwrap(); + print_qr(&qr); + + let (tempbuf0, tempbuf1) = tempbuffer.split_at_mut(QrSegment::calc_buffer_size(QrSegmentMode::Alphanumeric, silver0.len()).unwrap()); + let segs = [ + QrSegment::make_alphanumeric(silver0, tempbuf0), + QrSegment::make_numeric(silver1, tempbuf1), + ]; + let (datacodewordslen, ecl, version) = QrCode::encode_segments_to_codewords( + &segs, &mut outbuffer, QrCodeEcc::Low, Version::MIN, Version::MAX, true).unwrap(); + std::mem::drop(segs); // Implied, because segs has references to tempbuffer, but tempbuffer will be reused in encode_codewords() + let qr = QrCode::encode_codewords(&mut outbuffer, datacodewordslen, &mut tempbuffer, ecl, version, None); + print_qr(&qr); + } + + { // Illustration "golden" + let golden0 = "Golden ratio φ = 1."; + let golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374"; + let golden2 = "......"; + let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; + let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; + let qr = QrCode::encode_text(&[golden0, golden1, golden2].concat(), &mut tempbuffer, &mut outbuffer, + QrCodeEcc::Low, Version::MIN, Version::MAX, None, true).unwrap(); + print_qr(&qr); + + let (tempbuf1, tempbuf2) = tempbuffer.split_at_mut(QrSegment::calc_buffer_size(QrSegmentMode::Numeric, golden1.len()).unwrap()); + let segs = [ + QrSegment::make_bytes(golden0.as_bytes()), + QrSegment::make_numeric(golden1, tempbuf1), + QrSegment::make_alphanumeric(golden2, tempbuf2), + ]; + let (datacodewordslen, ecl, version) = QrCode::encode_segments_to_codewords( + &segs, &mut outbuffer, QrCodeEcc::Low, Version::MIN, Version::MAX, true).unwrap(); + let qr = QrCode::encode_codewords(&mut outbuffer, datacodewordslen, &mut tempbuffer, ecl, version, None); + print_qr(&qr); + } + + { // Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters + let madoka = "「魔法少女まどか☆マギカ」って、 ИАИ desu κα?"; + let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; + let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; + let qr = QrCode::encode_text(madoka, &mut outbuffer, &mut tempbuffer, + QrCodeEcc::Low, Version::MIN, Version::MAX, None, true).unwrap(); + print_qr(&qr); + + let kanjichars: Vec = vec![ // Kanji mode encoding (13 bits per character) + 0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7, + 0x015C, 0x0147, 0x0129, 0x0059, 0x01BD, + 0x018D, 0x018A, 0x0036, 0x0141, 0x0144, + 0x0001, 0x0000, 0x0249, 0x0240, 0x0249, + 0x0000, 0x0104, 0x0105, 0x0113, 0x0115, + 0x0000, 0x0208, 0x01FF, 0x0008, + ]; + let mut bb = qrcodegen::BitBuffer::new(&mut tempbuffer); + for &c in &kanjichars { + bb.append_bits(c, 13); + } + let segs = [ + { + let bitlen = bb.len(); + QrSegment::new(qrcodegen::QrSegmentMode::Kanji, kanjichars.len(), &tempbuffer, bitlen) + }, + ]; + let (datacodewordslen, ecl, version) = QrCode::encode_segments_to_codewords( + &segs, &mut outbuffer, QrCodeEcc::Low, Version::MIN, Version::MAX, true).unwrap(); + let qr = QrCode::encode_codewords(&mut outbuffer, datacodewordslen, &mut tempbuffer, ecl, version, None); + print_qr(&qr); + } +} + + +// Creates QR Codes with the same size and contents but different mask patterns. +fn do_mask_demo() { + { // Project Nayuki URL + let text = "https://www.nayuki.io/"; + let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; + let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; + + let qr = QrCode::encode_text(text, &mut tempbuffer, &mut outbuffer, QrCodeEcc::High, + Version::MIN, Version::MAX, None, true).unwrap(); // Automatic mask + print_qr(&qr); + let qr = QrCode::encode_text(text, &mut tempbuffer, &mut outbuffer, QrCodeEcc::High, + Version::MIN, Version::MAX, Some(Mask::new(3)), true).unwrap(); // Force mask 3 + print_qr(&qr); + } + + { // Chinese text as UTF-8 + let text = "維基百科(Wikipedia,聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫"; + let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; + let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; + + let qr = QrCode::encode_text(text, &mut tempbuffer, &mut outbuffer, QrCodeEcc::Medium, + Version::MIN, Version::MAX, Some(Mask::new(0)), true).unwrap(); // Force mask 0 + print_qr(&qr); + let qr = QrCode::encode_text(text, &mut tempbuffer, &mut outbuffer, QrCodeEcc::Medium, + Version::MIN, Version::MAX, Some(Mask::new(1)), true).unwrap(); // Force mask 1 + print_qr(&qr); + let qr = QrCode::encode_text(text, &mut tempbuffer, &mut outbuffer, QrCodeEcc::Medium, + Version::MIN, Version::MAX, Some(Mask::new(5)), true).unwrap(); // Force mask 5 + print_qr(&qr); + let qr = QrCode::encode_text(text, &mut tempbuffer, &mut outbuffer, QrCodeEcc::Medium, + Version::MIN, Version::MAX, Some(Mask::new(7)), true).unwrap(); // Force mask 7 + print_qr(&qr); + } +} + + + +/*---- Utilities ----*/ + +// Returns a string of SVG code for an image depicting +// the given QR Code, with the given number of border modules. +// The string always uses Unix newlines (\n), regardless of the platform. +fn to_svg_string(qr: &QrCode, border: i32) -> String { + assert!(border >= 0, "Border must be non-negative"); + let mut result = String::new(); + result += "\n"; + result += "\n"; + let dimension = qr.size().checked_add(border.checked_mul(2).unwrap()).unwrap(); + result += &format!( + "\n", dimension); + result += "\t\n"; + result += "\t\n"; + result += "\n"; + result +} + + +// Prints the given QrCode object to the console. +fn print_qr(qr: &QrCode) { + let border: i32 = 4; + for y in -border .. qr.size() + border { + for x in -border .. qr.size() + border { + let c: char = if qr.get_module(x, y) { '█' } else { ' ' }; + print!("{0}{0}", c); + } + println!(); + } + println!(); +} diff --git a/rust-no-heap/src/lib.rs b/rust-no-heap/src/lib.rs new file mode 100644 index 0000000..cbd8187 --- /dev/null +++ b/rust-no-heap/src/lib.rs @@ -0,0 +1,1454 @@ +/* + * QR Code generator library (Rust, no heap) + * + * Copyright (c) Project Nayuki. (MIT License) + * https://www.nayuki.io/page/qr-code-generator-library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * - The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * - The Software is provided "as is", without warranty of any kind, express or + * implied, including but not limited to the warranties of merchantability, + * fitness for a particular purpose and noninfringement. In no event shall the + * authors or copyright holders be liable for any claim, damages or other + * liability, whether in an action of contract, tort or otherwise, arising from, + * out of or in connection with the Software or the use or other dealings in the + * Software. + */ + + +//! Generates QR Codes from text strings and byte arrays. +//! +//! This project aims to be the best, clearest QR Code generator library. +//! The primary goals are flexible options and absolute correctness. +//! Secondary goals are compact implementation size and good documentation comments. +//! +//! Home page with live JavaScript demo, extensive descriptions, and competitor comparisons: +//! [https://www.nayuki.io/page/qr-code-generator-library](https://www.nayuki.io/page/qr-code-generator-library) +//! +//! # Features +//! +//! Core features: +//! +//! - Available in 6 programming languages, all with nearly equal functionality: Java, TypeScript/JavaScript, Python, Rust, C++, C +//! - Significantly shorter code but more documentation comments compared to competing libraries +//! - Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard +//! - Output format: Raw modules/pixels of the QR symbol +//! - Detects finder-like penalty patterns more accurately than other implementations +//! - Encodes numeric and special-alphanumeric text in less space than general text +//! - Open-source code under the permissive MIT License +//! +//! Manual parameters: +//! +//! - User can specify minimum and maximum version numbers allowed, then library will automatically choose smallest version in the range that fits the data +//! - User can specify mask pattern manually, otherwise library will automatically evaluate all 8 masks and select the optimal one +//! - User can specify absolute error correction level, or allow the library to boost it if it doesn't increase the version number +//! - User can create a list of data segments manually and add ECI segments +//! +//! # Examples +//! +//! ``` +//! extern crate qrcodegen; +//! use qrcodegen::Mask; +//! use qrcodegen::QrCode; +//! use qrcodegen::QrCodeEcc; +//! use qrcodegen::QrSegment; +//! use qrcodegen::QrSegmentMode; +//! use qrcodegen::Version; +//! ``` +//! +//! Text data: +//! +//! ``` +//! let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; +//! let mut tempbuffer = vec![0u8; Version::MAX.buffer_len()]; +//! let qr = QrCode::encode_text("Hello, world!", &mut tempbuffer, &mut outbuffer, +//! QrCodeEcc::Medium, Version::MIN, Version:MAX, None, true).unwrap(); +//! let svg = to_svg_string(&qr, 4); // See qrcodegen-demo +//! ``` +//! +//! Binary data: +//! +//! ``` +//! let mut dataandtemp = vec![0u8; Version::MAX.buffer_len()]; +//! let mut outbuffer = vec![0u8; Version::MAX.buffer_len()]; +//! dataandtemp[0] = 0xE3; +//! dataandtemp[1] = 0x81; +//! dataandtemp[2] = 0x82; +//! let qr = QrCode::encode_binary(&mut dataandtemp, 3, &mut outbuffer, QrCodeEcc::High, +//! Version::new(2), Version::new(7), Some(Mask::new(4)), false).unwrap(); +//! for y in 0 .. qr.size() { +//! for x in 0 .. qr.size() { +//! (... paint qr.get_module(x, y) ...) +//! } +//! } +//! ``` + + +#![no_std] +use core::convert::TryFrom; + + +/*---- QrCode functionality ----*/ + +/// A QR Code symbol, which is a type of two-dimension barcode. +/// +/// Invented by Denso Wave and described in the ISO/IEC 18004 standard. +/// +/// Instances of this struct represent an immutable square grid of dark and light cells. +/// The impl provides static factory functions to create a QR Code from text or binary data. +/// The struct and impl cover the QR Code Model 2 specification, supporting all versions +/// (sizes) from 1 to 40, all 4 error correction levels, and 4 character encoding modes. +/// +/// Ways to create a QR Code object: +/// +/// - High level: Take the payload data and call `QrCode::encode_text()` or `QrCode::encode_binary()`. +/// - Mid level: Custom-make the list of segments and call +/// `QrCode::encode_segments_to_codewords()` and then `QrCode::encode_codewords()`. +/// - Low level: Custom-make the array of data codeword bytes (including segment +/// headers and final padding, excluding error correction codewords), supply the +/// appropriate version number, and call the `QrCode::encode_codewords()` constructor. +/// +/// (Note that all ways require supplying the desired error correction level and various byte buffers.) +pub struct QrCode<'a> { + + // The width and height of this QR Code, measured in modules, between + // 21 and 177 (inclusive). This is equal to version * 4 + 17. + size: &'a mut u8, + + // The modules of this QR Code (0 = light, 1 = dark), packed bitwise into bytes. + // Immutable after constructor finishes. Accessed through get_module(). + modules: &'a mut [u8], + +} + + +impl<'a> QrCode<'a> { + + /*---- Static factory functions (high level) ----*/ + + /// Returns a QR Code representing the given Unicode text string with the given encoding parameters. + /// + /// The smallest possible QR Code version within the given range is automatically + /// chosen for the output. Iff boostecl is `true`, then the ECC level of the result + /// may be higher than the ecl argument if it can be done without increasing the + /// version. The mask number is either between 0 to 7 (inclusive) to force that + /// mask, or `None` to automatically choose an appropriate mask (which may be slow). + /// + /// The arrays tempbuffer and outbuffer must each have a length of at least maxversion.buffer_len(). + /// + /// In the most optimistic case, a QR Code at version 40 with low ECC + /// can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string + /// up to 4296 characters, or any digit string up to 7089 characters. + /// These numbers represent the hard upper limit of the QR Code standard. + /// + /// Please consult the QR Code specification for information on + /// data capacities per version, ECC level, and text encoding mode. + /// + /// After the function returns, tempbuffer contains no useful data. + /// + /// If successful, the resulting QR Code may use numeric, alphanumeric, or byte mode to encode the text. + /// + /// Returns a wrapped `QrCode` if successful, or `Err` if the + /// data is too long to fit in any version at the given ECC level. + pub fn encode_text<'b>(text: &str, tempbuffer: &'b mut [u8], mut outbuffer: &'a mut [u8], ecl: QrCodeEcc, + minversion: Version, maxversion: Version, mask: Option, boostecl: bool) -> Result,DataTooLong> { + + let minlen: usize = outbuffer.len().min(tempbuffer.len()); + outbuffer = &mut outbuffer[ .. minlen]; + + let textlen: usize = text.len(); // In bytes + if textlen == 0 { + let (datacodewordslen, ecl, version) = QrCode::encode_segments_to_codewords(&[], outbuffer, ecl, minversion, maxversion, boostecl)?; + return Ok(Self::encode_codewords(outbuffer, datacodewordslen, tempbuffer, ecl, version, mask)); + } + + use QrSegmentMode::*; + let buflen: usize = outbuffer.len(); + let seg: QrSegment = if QrSegment::is_numeric(text) && QrSegment::calc_buffer_size(Numeric, textlen).map_or(false, |x| x <= buflen) { + QrSegment::make_numeric(text, tempbuffer) + } else if QrSegment::is_alphanumeric(text) && QrSegment::calc_buffer_size(Alphanumeric, textlen).map_or(false, |x| x <= buflen) { + QrSegment::make_alphanumeric(text, tempbuffer) + } else if QrSegment::calc_buffer_size(Byte, textlen).map_or(false, |x| x <= buflen) { + QrSegment::make_bytes(text.as_bytes()) + } else { + return Err(DataTooLong::SegmentTooLong); + }; + let (datacodewordslen, ecl, version) = QrCode::encode_segments_to_codewords(&[seg], outbuffer, ecl, minversion, maxversion, boostecl)?; + Ok(Self::encode_codewords(outbuffer, datacodewordslen, tempbuffer, ecl, version, mask)) + } + + + /// Returns a QR Code representing the given binary data with the given encoding parameters. + /// + /// The arrays dataandtemp and outbuffer must each have a length of at least maxversion.buffer_len(). + /// + /// In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte + /// sequence up to length 2953. This is the hard upper limit of the QR Code standard. + /// + /// Please consult the QR Code specification for information on + /// data capacities per version, ECC level, and text encoding mode. + /// + /// After the function returns, the contents of dataandtemp may have changed, + /// and does not represent useful data anymore. + /// + /// If successful, the resulting QR Code will use byte mode to encode the data. + /// + /// Returns a wrapped `QrCode` if successful, or `Err` if the + /// data is too long to fit in any version at the given ECC level. + pub fn encode_binary<'b>(dataandtempbuffer: &'b mut [u8], datalen: usize, mut outbuffer: &'a mut [u8], ecl: QrCodeEcc, + minversion: Version, maxversion: Version, mask: Option, boostecl: bool) -> Result,DataTooLong> { + + assert!(datalen <= dataandtempbuffer.len(), "Invalid data length"); + let minlen: usize = outbuffer.len().min(dataandtempbuffer.len()); + outbuffer = &mut outbuffer[ .. minlen]; + + if QrSegment::calc_buffer_size(QrSegmentMode::Byte, datalen).map_or(true, |x| x > outbuffer.len()) { + return Err(DataTooLong::SegmentTooLong); + } + let seg: QrSegment = QrSegment::make_bytes(&dataandtempbuffer[ .. datalen]); + let (datacodewordslen, ecl, version) = QrCode::encode_segments_to_codewords(&[seg], outbuffer, ecl, minversion, maxversion, boostecl)?; + Ok(Self::encode_codewords(outbuffer, datacodewordslen, dataandtempbuffer, ecl, version, mask)) + } + + + /*---- Static factory functions (mid level) ----*/ + + /// Returns an intermediate state representing the given segments + /// with the given encoding parameters being encoded into codewords. + /// + /// This function exists to allow segments to use parts of a temporary buffer, + /// then have the segments be encoded to an output buffer, then invalidate all the segments, + /// and finally have the output buffer and temporary buffer be encoded to a QR Code. + pub fn encode_segments_to_codewords(segs: &[QrSegment], outbuffer: &'a mut [u8], + mut ecl: QrCodeEcc, minversion: Version, maxversion: Version, boostecl: bool) + -> Result<(usize,QrCodeEcc,Version),DataTooLong> { + + assert!(minversion <= maxversion, "Invalid value"); + assert!(outbuffer.len() >= QrCode::get_num_data_codewords(maxversion, ecl), "Invalid buffer length"); + + // Find the minimal version number to use + let mut version: Version = minversion; + let datausedbits: usize = loop { + let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8; // Number of data bits available + let dataused: Option = QrSegment::get_total_bits(segs, version); + if dataused.map_or(false, |n| n <= datacapacitybits) { + break dataused.unwrap(); // This version number is found to be suitable + } else if version >= maxversion { // All versions in the range could not fit the given data + return Err(match dataused { + None => DataTooLong::SegmentTooLong, + Some(n) => DataTooLong::DataOverCapacity(n, datacapacitybits), + }); + } else { + version = Version::new(version.value() + 1); + } + }; + + // Increase the error correction level while the data still fits in the current version number + for &newecl in &[QrCodeEcc::Medium, QrCodeEcc::Quartile, QrCodeEcc::High] { // From low to high + if boostecl && datausedbits <= QrCode::get_num_data_codewords(version, newecl) * 8 { + ecl = newecl; + } + } + + // Concatenate all segments to create the data bit string + let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8; + let mut bb = BitBuffer::new(&mut outbuffer[ .. datacapacitybits/8]); + for seg in segs { + bb.append_bits(seg.mode.mode_bits(), 4); + bb.append_bits(u32::try_from(seg.numchars).unwrap(), seg.mode.num_char_count_bits(version)); + for i in 0 .. seg.bitlength { + let bit: u8 = (seg.data[i >> 3] >> (7 - (i & 7))) & 1; + bb.append_bits(bit.into(), 1); + } + } + debug_assert_eq!(bb.length, datausedbits); + + // Add terminator and pad up to a byte if applicable + let numzerobits: usize = core::cmp::min(4, datacapacitybits - bb.length); + bb.append_bits(0, u8::try_from(numzerobits).unwrap()); + let numzerobits: usize = bb.length.wrapping_neg() & 7; + bb.append_bits(0, u8::try_from(numzerobits).unwrap()); + debug_assert_eq!(bb.length % 8, 0); + + // Pad with alternating bytes until data capacity is reached + for &padbyte in [0xEC, 0x11].iter().cycle() { + if bb.length >= datacapacitybits { + break; + } + bb.append_bits(padbyte, 8); + } + Ok((bb.length / 8, ecl, version)) + } + + + /*---- Constructor (low level) ----*/ + + /// Creates a new QR Code with the given version number, + /// error correction level, data codeword bytes, and mask number. + /// + /// This is a low-level API that most users should not use directly. + /// A mid-level API is the `encode_segments_to_codewords()` function. + pub fn encode_codewords<'b>(mut datacodewordsandoutbuffer: &'a mut [u8], datacodewordslen: usize, mut tempbuffer: &'b mut [u8], + ecl: QrCodeEcc, version: Version, mut msk: Option) -> QrCode<'a> { + + datacodewordsandoutbuffer = &mut datacodewordsandoutbuffer[ .. version.buffer_len()]; + tempbuffer = &mut tempbuffer [ .. version.buffer_len()]; + + // Compute ECC + let rawcodewords: usize = QrCode::get_num_raw_data_modules(version) / 8; + assert!(datacodewordslen <= rawcodewords); + let (data, temp) = datacodewordsandoutbuffer.split_at_mut(datacodewordslen); + let allcodewords = Self::add_ecc_and_interleave(data, version, ecl, temp, tempbuffer); + + // Draw modules + let mut result: QrCode = QrCode::<'a>::function_modules_marked(datacodewordsandoutbuffer, version); + result.draw_codewords(allcodewords); + result.draw_light_function_modules(); + let funcmods: QrCode = QrCode::<'b>::function_modules_marked(tempbuffer, version); // Just a grid, not a real QR Code + + // Do masking + if msk.is_none() { // Automatically choose best mask + let mut minpenalty = core::i32::MAX; + for i in 0u8 .. 8 { + let i = Mask::new(i); + result.apply_mask(&funcmods, i); + result.draw_format_bits(ecl, i); + let penalty: i32 = result.get_penalty_score(); + if penalty < minpenalty { + msk = Some(i); + minpenalty = penalty; + } + result.apply_mask(&funcmods, i); // Undoes the mask due to XOR + } + } + let msk: Mask = msk.unwrap(); + result.apply_mask(&funcmods, msk); // Apply the final choice of mask + result.draw_format_bits(ecl, msk); // Overwrite old format bits + result + } + + + /*---- Public methods ----*/ + + /// Returns this QR Code's version, in the range [1, 40]. + pub fn version(&self) -> Version { + Version::new((*self.size - 17) / 4) + } + + + /// Returns this QR Code's size, in the range [21, 177]. + pub fn size(&self) -> i32 { + i32::from(*self.size) + } + + + /// Returns this QR Code's error correction level. + pub fn error_correction_level(&self) -> QrCodeEcc { + let index = + usize::from(self.get_module_bounded(0, 8)) << 1 | + usize::from(self.get_module_bounded(1, 8)) << 0; + use QrCodeEcc::*; + [Medium, Low, High, Quartile][index] + } + + + /// Returns this QR Code's mask, in the range [0, 7]. + pub fn mask(&self) -> Mask { + Mask::new( + u8::from(self.get_module_bounded(2, 8)) << 2 | + u8::from(self.get_module_bounded(3, 8)) << 1 | + u8::from(self.get_module_bounded(4, 8)) << 0) + } + + + /// Returns the color of the module (pixel) at the given coordinates, + /// which is `false` for light or `true` for dark. + /// + /// The top left corner has the coordinates (x=0, y=0). If the given + /// coordinates are out of bounds, then `false` (light) is returned. + pub fn get_module(&self, x: i32, y: i32) -> bool { + let range = 0 .. self.size(); + range.contains(&x) && range.contains(&y) && self.get_module_bounded(x as u8, y as u8) + } + + + // Returns the color of the module at the given coordinates, which must be in bounds. + fn get_module_bounded(&self, x: u8, y: u8) -> bool { + let range = 0 .. *self.size; + assert!(range.contains(&x) && range.contains(&y)); + let index = usize::from(y) * usize::from(*self.size) + usize::from(x); + let byteindex: usize = index >> 3; + let bitindex: usize = index & 7; + get_bit(self.modules[byteindex].into(), bitindex as u8) + } + + + // Sets the color of the module at the given coordinates, doing nothing if out of bounds. + fn set_module_unbounded(&mut self, x: i32, y: i32, isdark: bool) { + let range = 0 .. self.size(); + if range.contains(&x) && range.contains(&y) { + self.set_module_bounded(x as u8, y as u8, isdark); + } + } + + + // Sets the color of the module at the given coordinates, which must be in bounds. + fn set_module_bounded(&mut self, x: u8, y: u8, isdark: bool) { + let range = 0 .. *self.size; + assert!(range.contains(&x) && range.contains(&y)); + let index = usize::from(y) * usize::from(*self.size) + usize::from(x); + let byteindex: usize = index >> 3; + let bitindex: usize = index & 7; + if isdark { + self.modules[byteindex] |= 1u8 << bitindex; + } else { + self.modules[byteindex] &= !(1u8 << bitindex); + } + } + + + /*---- Error correction code generation ----*/ + + // Appends error correction bytes to each block of the given data array, then interleaves + // bytes from the blocks, stores them in the output array, and returns a slice of resultbuf. + // temp is used as a temporary work area and will be clobbered by this function. + fn add_ecc_and_interleave<'b>(data: &[u8], ver: Version, ecl: QrCodeEcc, temp: &mut [u8], resultbuf: &'b mut [u8]) -> &'b [u8] { + assert_eq!(data.len(), QrCode::get_num_data_codewords(ver, ecl)); + + // Calculate parameter numbers + let numblocks: usize = QrCode::table_get(&NUM_ERROR_CORRECTION_BLOCKS, ver, ecl); + let blockecclen: usize = QrCode::table_get(&ECC_CODEWORDS_PER_BLOCK , ver, ecl); + let rawcodewords: usize = QrCode::get_num_raw_data_modules(ver) / 8; + let numshortblocks: usize = numblocks - rawcodewords % numblocks; + let shortblockdatalen: usize = rawcodewords / numblocks - blockecclen; + let result = &mut resultbuf[ .. rawcodewords]; + + // Split data into blocks, calculate ECC, and interleave + // (not concatenate) the bytes into a single sequence + let rs = ReedSolomonGenerator::new(blockecclen); + let mut dat: &[u8] = data; + let ecc: &mut [u8] = &mut temp[ .. blockecclen]; // Temporary storage + for i in 0 .. numblocks { + let datlen: usize = shortblockdatalen + usize::from(i >= numshortblocks); + rs.compute_remainder(&dat[ .. datlen], ecc); + let mut k: usize = i; + for j in 0 .. datlen { // Copy data + if j == shortblockdatalen { + k -= numshortblocks; + } + result[k] = dat[j]; + k += numblocks; + } + let mut k: usize = data.len() + i; + for j in 0 .. blockecclen { // Copy ECC + result[k] = ecc[j]; + k += numblocks; + } + dat = &dat[datlen .. ]; + } + debug_assert_eq!(dat.len(), 0); + result + } + + + /*---- Drawing function modules ----*/ + + // Creates a QR Code grid with light modules for the given + // version's size, then marks every function module as dark. + fn function_modules_marked(outbuffer: &'a mut [u8], ver: Version) -> Self { + assert_eq!(outbuffer.len(), ver.buffer_len()); + let parts: (&mut u8, &mut [u8]) = outbuffer.split_first_mut().unwrap(); + let mut result = Self { + size: parts.0, + modules: parts.1, + }; + let size: u8 = ver.value() * 4 + 17; + *result.size = size; + result.modules.fill(0); + + // Fill horizontal and vertical timing patterns + result.fill_rectangle(6, 0, 1, size); + result.fill_rectangle(0, 6, size, 1); + + // Fill 3 finder patterns (all corners except bottom right) and format bits + result.fill_rectangle(0, 0, 9, 9); + result.fill_rectangle(size - 8, 0, 8, 9); + result.fill_rectangle(0, size - 8, 9, 8); + + // Fill numerous alignment patterns + let mut alignpatposbuf = [0u8; 7]; + let alignpatpos: &[u8] = result.get_alignment_pattern_positions(&mut alignpatposbuf); + for (i, pos0) in alignpatpos.iter().enumerate() { + for (j, pos1) in alignpatpos.iter().enumerate() { + // Don't draw on the three finder corners + if !((i == 0 && j == 0) || (i == 0 && j == alignpatpos.len() - 1) || (i == alignpatpos.len() - 1 && j == 0)) { + result.fill_rectangle(pos0 - 2, pos1 - 2, 5, 5); + } + } + } + + // Fill version blocks + if ver.value() >= 7 { + result.fill_rectangle(size - 11, 0, 3, 6); + result.fill_rectangle(0, size - 11, 6, 3); + } + + result + } + + + // Draws light function modules and possibly some dark modules onto this QR Code, without changing + // non-function modules. This does not draw the format bits. This requires all function modules to be previously + // marked dark (namely by function_modules_marked()), because this may skip redrawing dark function modules. + fn draw_light_function_modules(&mut self) { + // Draw horizontal and vertical timing patterns + let size: u8 = *self.size; + for i in (7 .. size-7).step_by(2) { + self.set_module_bounded(6, i, false); + self.set_module_bounded(i, 6, false); + } + + // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) + for dy in -4i32 ..= 4 { + for dx in -4i32 ..= 4 { + let dist: i32 = dx.abs().max(dy.abs()); + if dist == 2 || dist == 4 { + self.set_module_unbounded(3 + dx, 3 + dy, false); + self.set_module_unbounded(i32::from(size) - 4 + dx, 3 + dy, false); + self.set_module_unbounded(3 + dx, i32::from(size) - 4 + dy, false); + } + } + } + + // Draw numerous alignment patterns + let mut alignpatposbuf = [0u8; 7]; + let alignpatpos: &[u8] = self.get_alignment_pattern_positions(&mut alignpatposbuf); + for (i, &pos0) in alignpatpos.iter().enumerate() { + for (j, &pos1) in alignpatpos.iter().enumerate() { + if (i == 0 && j == 0) || (i == 0 && j == alignpatpos.len() - 1) || (i == alignpatpos.len() - 1 && j == 0) { + continue; // Don't draw on the three finder corners + } + for dy in -1 ..= 1 { + for dx in -1 ..= 1 { + self.set_module_bounded((i32::from(pos0) + dx) as u8, (i32::from(pos1) + dy) as u8, dx == 0 && dy == 0); + } + } + } + } + + // Draw version blocks + let ver = u32::from(self.version().value()); // uint6, in the range [7, 40] + if ver >= 7 { + // Calculate error correction code and pack bits + let bits: u32 = { + let mut rem: u32 = ver; + for _ in 0 .. 12 { + rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); + } + ver << 12 | rem // uint18 + }; + debug_assert_eq!(bits >> 18, 0); + + // Draw two copies + for i in 0u8 .. 18 { + let bit: bool = get_bit(bits, i); + let a: u8 = size - 11 + i % 3; + let b: u8 = i / 3; + self.set_module_bounded(a, b, bit); + self.set_module_bounded(b, a, bit); + } + } + } + + + // Draws two copies of the format bits (with its own error correction code) based + // on the given mask and error correction level. This always draws all modules of + // the format bits, unlike draw_light_function_modules() which might skip dark modules. + fn draw_format_bits(&mut self, ecl: QrCodeEcc, mask: Mask) { + // Calculate error correction code and pack bits + let bits: u32 = { + // errcorrlvl is uint2, mask is uint3 + let data = u32::from(ecl.format_bits() << 3 | mask.value()); + let mut rem: u32 = data; + for _ in 0 .. 10 { + rem = (rem << 1) ^ ((rem >> 9) * 0x537); + } + (data << 10 | rem) ^ 0x5412 // uint15 + }; + debug_assert_eq!(bits >> 15, 0); + + // Draw first copy + for i in 0 .. 6 { + self.set_module_bounded(8, i, get_bit(bits, i)); + } + self.set_module_bounded(8, 7, get_bit(bits, 6)); + self.set_module_bounded(8, 8, get_bit(bits, 7)); + self.set_module_bounded(7, 8, get_bit(bits, 8)); + for i in 9 .. 15 { + self.set_module_bounded(14 - i, 8, get_bit(bits, i)); + } + + // Draw second copy + let size: u8 = *self.size; + for i in 0 .. 8 { + self.set_module_bounded(size - 1 - i, 8, get_bit(bits, i)); + } + for i in 8 .. 15 { + self.set_module_bounded(8, size - 15 + i, get_bit(bits, i)); + } + self.set_module_bounded(8, size - 8, true); // Always dark + } + + + // Sets every module in the range [left : left + width] * [top : top + height] to dark. + fn fill_rectangle(&mut self, left: u8, top: u8, width: u8, height: u8) { + for dy in 0 .. height { + for dx in 0 .. width { + self.set_module_bounded(left + dx, top + dy, true); + } + } + } + + + /*---- Drawing data modules and masking ----*/ + + // Draws the raw codewords (including data and ECC) onto this QR Code. This requires the initial state of + // the QR Code to be dark at function modules and light at codeword modules (including unused remainder bits). + fn draw_codewords(&mut self, data: &[u8]) { + assert_eq!(data.len(), QrCode::get_num_raw_data_modules(self.version()) / 8, "Illegal argument"); + + let size: i32 = self.size(); + let mut i: usize = 0; // Bit index into the data + // Do the funny zigzag scan + let mut right: i32 = size - 1; + while right >= 1 { // Index of right column in each column pair + if right == 6 { + right = 5; + } + for vert in 0 .. size { // Vertical counter + for j in 0 .. 2 { + let x = (right - j) as u8; // Actual x coordinate + let upward: bool = (right + 1) & 2 == 0; + let y = (if upward { size - 1 - vert } else { vert }) as u8; // Actual y coordinate + if !self.get_module_bounded(x, y) && i < data.len() * 8 { + self.set_module_bounded(x, y, get_bit(data[i >> 3].into(), 7 - ((i as u8) & 7))); + i += 1; + } + // If this QR Code has any remainder bits (0 to 7), they were assigned as + // 0/false/light by the constructor and are left unchanged by this method + } + } + right -= 2; + } + debug_assert_eq!(i, data.len() * 8); + } + + + // XORs the codeword modules in this QR Code with the given mask pattern + // and given pattern of function modules. The codeword bits must be drawn + // before masking. Due to the arithmetic of XOR, calling apply_mask() with + // the same mask value a second time will undo the mask. A final well-formed + // QR Code needs exactly one (not zero, two, etc.) mask applied. + fn apply_mask(&mut self, functionmodules: &QrCode, mask: Mask) { + for y in 0 .. *self.size { + for x in 0 .. *self.size { + if functionmodules.get_module_bounded(x, y) { + continue; + } + let invert: bool = { + let x = i32::from(x); + let y = i32::from(y); + match mask.value() { + 0 => (x + y) % 2 == 0, + 1 => y % 2 == 0, + 2 => x % 3 == 0, + 3 => (x + y) % 3 == 0, + 4 => (x / 3 + y / 2) % 2 == 0, + 5 => x * y % 2 + x * y % 3 == 0, + 6 => (x * y % 2 + x * y % 3) % 2 == 0, + 7 => ((x + y) % 2 + x * y % 3) % 2 == 0, + _ => unreachable!(), + } + }; + self.set_module_bounded(x, y, + self.get_module_bounded(x, y) ^ invert); + } + } + } + + + // Calculates and returns the penalty score based on state of this QR Code's current modules. + // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. + fn get_penalty_score(&self) -> i32 { + let mut result: i32 = 0; + let size: u8 = *self.size; + + // Adjacent modules in row having same color, and finder-like patterns + for y in 0 .. size { + let mut runcolor = false; + let mut runx: i32 = 0; + let mut runhistory = FinderPenalty::new(size); + for x in 0 .. size { + if self.get_module_bounded(x, y) == runcolor { + runx += 1; + if runx == 5 { + result += PENALTY_N1; + } else if runx > 5 { + result += 1; + } + } else { + runhistory.add_history(runx); + if !runcolor { + result += runhistory.count_patterns() * PENALTY_N3; + } + runcolor = self.get_module_bounded(x, y); + runx = 1; + } + } + result += runhistory.terminate_and_count(runcolor, runx) * PENALTY_N3; + } + // Adjacent modules in column having same color, and finder-like patterns + for x in 0 .. size { + let mut runcolor = false; + let mut runy: i32 = 0; + let mut runhistory = FinderPenalty::new(size); + for y in 0 .. size { + if self.get_module_bounded(x, y) == runcolor { + runy += 1; + if runy == 5 { + result += PENALTY_N1; + } else if runy > 5 { + result += 1; + } + } else { + runhistory.add_history(runy); + if !runcolor { + result += runhistory.count_patterns() * PENALTY_N3; + } + runcolor = self.get_module_bounded(x, y); + runy = 1; + } + } + result += runhistory.terminate_and_count(runcolor, runy) * PENALTY_N3; + } + + // 2*2 blocks of modules having same color + for y in 0 .. size-1 { + for x in 0 .. size-1 { + let color: bool = self.get_module_bounded(x, y); + if color == self.get_module_bounded(x + 1, y) && + color == self.get_module_bounded(x, y + 1) && + color == self.get_module_bounded(x + 1, y + 1) { + result += PENALTY_N2; + } + } + } + + // Balance of dark and light modules + let dark = self.modules.iter().map(|x| x.count_ones()).sum::() as i32; + let total = i32::from(size) * i32::from(size); // Note that size is odd, so dark/total != 1/2 + // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)% + let k: i32 = ((dark * 20 - total * 10).abs() + total - 1) / total - 1; + debug_assert!(0 <= k && k <= 9); + result += k * PENALTY_N4; + debug_assert!(0 <= result && result <= 2568888); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4 + result + } + + + /*---- Private helper functions ----*/ + + // Calculates and stores an ascending list of positions of alignment patterns + // for this version number, returning a slice of resultbuf. + // Each position is in the range [0,177), and are used on both the x and y axes. + // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. + fn get_alignment_pattern_positions<'b>(&self, resultbuf: &'b mut [u8; 7]) -> &'b [u8] { + let ver: u8 = self.version().value(); + if ver == 1 { + &resultbuf[ .. 0] + } else { + let numalign: u8 = ver / 7 + 2; + let step: u8 = if ver == 32 { 26 } else + {(ver * 4 + numalign * 2 + 1) / (numalign * 2 - 2) * 2}; + let result = &mut resultbuf[ .. usize::from(numalign)]; + for i in 0 .. numalign-1 { + result[usize::from(i)] = *self.size - 7 - i * step; + } + *result.last_mut().unwrap() = 6; + result.reverse(); + result + } + } + + + // Returns the number of data bits that can be stored in a QR Code of the given version number, after + // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. + // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. + fn get_num_raw_data_modules(ver: Version) -> usize { + let ver = usize::from(ver.value()); + let mut result: usize = (16 * ver + 128) * ver + 64; + if ver >= 2 { + let numalign: usize = ver / 7 + 2; + result -= (25 * numalign - 10) * numalign - 55; + if ver >= 7 { + result -= 36; + } + } + debug_assert!((208 ..= 29648).contains(&result)); + result + } + + + // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any + // QR Code of the given version number and error correction level, with remainder bits discarded. + // This stateless pure function could be implemented as a (40*4)-cell lookup table. + fn get_num_data_codewords(ver: Version, ecl: QrCodeEcc) -> usize { + QrCode::get_num_raw_data_modules(ver) / 8 + - QrCode::table_get(&ECC_CODEWORDS_PER_BLOCK , ver, ecl) + * QrCode::table_get(&NUM_ERROR_CORRECTION_BLOCKS, ver, ecl) + } + + + // Returns an entry from the given table based on the given values. + fn table_get(table: &'static [[i8; 41]; 4], ver: Version, ecl: QrCodeEcc) -> usize { + table[ecl.ordinal()][usize::from(ver.value())] as usize + } + +} + + +impl PartialEq for QrCode<'_> { + fn eq(&self, other: &QrCode<'_>) -> bool{ + *self.size == *other.size && + *self.modules == *other.modules + } +} + +impl Eq for QrCode<'_> {} + + +/*---- Helper struct for add_ecc_and_interleave() ----*/ + +struct ReedSolomonGenerator { + + // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. + // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array [255, 8, 93]. + divisor: [u8; 30], + + // The degree of the divisor polynomial, in the range [1, 30]. + degree: usize, + +} + + +impl ReedSolomonGenerator { + + // Creates a Reed-Solomon ECC generator polynomial for the given degree. This could be + // implemented as a lookup table over all possible parameter values, instead of as an algorithm. + fn new(degree: usize) -> Self { + let mut result = Self { + divisor: [0u8; 30], + degree: degree, + }; + assert!((1 ..= result.divisor.len()).contains(°ree), "Degree out of range"); + let divisor: &mut [u8] = &mut result.divisor[ .. degree]; + divisor[degree - 1] = 1; // Start off with the monomial x^0 + + // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), + // and drop the highest monomial term which is always 1x^degree. + // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). + let mut root: u8 = 1; + for _ in 0 .. degree { // Unused variable i + // Multiply the current product by (x - r^i) + for j in 0 .. degree { + divisor[j] = Self::multiply(divisor[j], root); + if j + 1 < divisor.len() { + divisor[j] ^= divisor[j + 1]; + } + } + root = Self::multiply(root, 0x02); + } + result + } + + + // Returns the Reed-Solomon error correction codeword for the given data polynomial and this divisor polynomial. + fn compute_remainder(&self, data: &[u8], result: &mut [u8]) { + assert_eq!(result.len(), self.degree); + result.fill(0); + for b in data { // Polynomial division + let factor: u8 = b ^ result[0]; + result.copy_within(1 .. , 0); + result[result.len() - 1] = 0; + for (x, &y) in result.iter_mut().zip(self.divisor.iter()) { + *x ^= Self::multiply(y, factor); + } + } + } + + + // Returns the product of the two given field elements modulo GF(2^8/0x11D). + // All inputs are valid. This could be implemented as a 256*256 lookup table. + fn multiply(x: u8, y: u8) -> u8 { + // Russian peasant multiplication + let mut z: u8 = 0; + for i in (0 .. 8).rev() { + z = (z << 1) ^ ((z >> 7) * 0x1D); + z ^= ((y >> i) & 1) * x; + } + z + } + +} + + +/*---- Helper struct for get_penalty_score() ----*/ + +struct FinderPenalty { + qr_size: i32, + run_history: [i32; 7], +} + + +impl FinderPenalty { + + pub fn new(size: u8) -> Self { + Self { + qr_size: i32::from(size), + run_history: [0; 7], + } + } + + + // Pushes the given value to the front and drops the last value. + pub fn add_history(&mut self, mut currentrunlength: i32) { + if self.run_history[0] == 0 { + currentrunlength += self.qr_size; // Add light border to initial run + } + let len: usize = self.run_history.len(); + self.run_history.copy_within(0 .. len-1, 1); + self.run_history[0] = currentrunlength; + } + + + // Can only be called immediately after a light run is added, and returns either 0, 1, or 2. + pub fn count_patterns(&self) -> i32 { + let rh = &self.run_history; + let n = rh[1]; + debug_assert!(n <= self.qr_size * 3); + let core = n > 0 && rh[2] == n && rh[3] == n * 3 && rh[4] == n && rh[5] == n; + ( i32::from(core && rh[0] >= n * 4 && rh[6] >= n) + + i32::from(core && rh[6] >= n * 4 && rh[0] >= n)) + } + + + // Must be called at the end of a line (row or column) of modules. + pub fn terminate_and_count(mut self, currentruncolor: bool, mut currentrunlength: i32) -> i32 { + if currentruncolor { // Terminate dark run + self.add_history(currentrunlength); + currentrunlength = 0; + } + currentrunlength += self.qr_size; // Add light border to final run + self.add_history(currentrunlength); + self.count_patterns() + } + +} + + +/*---- Constants and tables ----*/ + +// For use in get_penalty_score(), when evaluating which mask is best. +const PENALTY_N1: i32 = 3; +const PENALTY_N2: i32 = 3; +const PENALTY_N3: i32 = 40; +const PENALTY_N4: i32 = 10; + + +static ECC_CODEWORDS_PER_BLOCK: [[i8; 41]; 4] = [ + // Version: (note that index 0 is for padding, and is set to an illegal value) + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + [-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], // Low + [-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28], // Medium + [-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], // Quartile + [-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], // High +]; + +static NUM_ERROR_CORRECTION_BLOCKS: [[i8; 41]; 4] = [ + // Version: (note that index 0 is for padding, and is set to an illegal value) + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + [-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25], // Low + [-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49], // Medium + [-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68], // Quartile + [-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81], // High +]; + + + +/*---- QrCodeEcc functionality ----*/ + +/// The error correction level in a QR Code symbol. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub enum QrCodeEcc { + /// The QR Code can tolerate about 7% erroneous codewords. + Low , + /// The QR Code can tolerate about 15% erroneous codewords. + Medium , + /// The QR Code can tolerate about 25% erroneous codewords. + Quartile, + /// The QR Code can tolerate about 30% erroneous codewords. + High , +} + + +impl QrCodeEcc { + + // Returns an unsigned 2-bit integer (in the range 0 to 3). + fn ordinal(self) -> usize { + use QrCodeEcc::*; + match self { + Low => 0, + Medium => 1, + Quartile => 2, + High => 3, + } + } + + + // Returns an unsigned 2-bit integer (in the range 0 to 3). + fn format_bits(self) -> u8 { + use QrCodeEcc::*; + match self { + Low => 1, + Medium => 0, + Quartile => 3, + High => 2, + } + } + +} + + + +/*---- QrSegment functionality ----*/ + +/// A segment of character/binary/control data in a QR Code symbol. +/// +/// Instances of this struct are immutable. +/// +/// The mid-level way to create a segment is to take the payload data +/// and call a static factory function such as `QrSegment::make_numeric()`. +/// The low-level way to create a segment is to custom-make the bit buffer +/// and call the `QrSegment::new()` constructor with appropriate values. +/// +/// This segment struct imposes no length restrictions, but QR Codes have restrictions. +/// Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. +/// Any segment longer than this is meaningless for the purpose of generating QR Codes. +pub struct QrSegment<'a> { + + // The mode indicator of this segment. Accessed through mode(). + mode: QrSegmentMode, + + // The length of this segment's unencoded data. Measured in characters for + // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. + // Not the same as the data's bit length. Accessed through num_chars(). + numchars: usize, + + // The data bits of this segment, packed in bitwise big endian. + data: &'a [u8], + + // The number of valid data bits used in the buffer. Requires bitlength <= data.len() * 8. + // The character count (numchars) must agree with the mode and the bit buffer length. + bitlength: usize, + +} + + +impl<'a> QrSegment<'a> { + + /*---- Static factory functions (mid level) ----*/ + + /// Returns a segment representing the given binary data encoded in byte mode. + /// + /// All input byte slices are acceptable. + /// + /// Any text string can be converted to UTF-8 bytes and encoded as a byte mode segment. + pub fn make_bytes(data: &'a [u8]) -> Self { + QrSegment::new(QrSegmentMode::Byte, data.len(), data, data.len().checked_mul(8).unwrap()) + } + + + /// Returns a segment representing the given string of decimal digits encoded in numeric mode. + /// + /// Panics if the string contains non-digit characters. + pub fn make_numeric(text: &str, buf: &'a mut [u8]) -> Self { + let mut bb = BitBuffer::new(buf); + let mut accumdata: u32 = 0; + let mut accumcount: u8 = 0; + for b in text.bytes() { + assert!((b'0' ..= b'9').contains(&b), "String contains non-numeric characters"); + accumdata = accumdata * 10 + u32::from(b - b'0'); + accumcount += 1; + if accumcount == 3 { + bb.append_bits(accumdata, 10); + accumdata = 0; + accumcount = 0; + } + } + if accumcount > 0 { // 1 or 2 digits remaining + bb.append_bits(accumdata, accumcount * 3 + 1); + } + QrSegment::new(QrSegmentMode::Numeric, text.len(), bb.data, bb.length) + } + + + /// Returns a segment representing the given text string encoded in alphanumeric mode. + /// + /// The characters allowed are: 0 to 9, A to Z (uppercase only), space, + /// dollar, percent, asterisk, plus, hyphen, period, slash, colon. + /// + /// Panics if the string contains non-encodable characters. + pub fn make_alphanumeric(text: &str, buf: &'a mut [u8]) -> Self { + let mut bb = BitBuffer::new(buf); + let mut accumdata: u32 = 0; + let mut accumcount: u8 = 0; + for c in text.chars() { + let i: usize = ALPHANUMERIC_CHARSET.find(c) + .expect("String contains unencodable characters in alphanumeric mode"); + accumdata = accumdata * 45 + u32::try_from(i).unwrap(); + accumcount += 1; + if accumcount == 2 { + bb.append_bits(accumdata, 11); + accumdata = 0; + accumcount = 0; + } + } + if accumcount > 0 { // 1 character remaining + bb.append_bits(accumdata, 6); + } + QrSegment::new(QrSegmentMode::Alphanumeric, text.len(), bb.data, bb.length) + } + + + /// Returns a segment representing an Extended Channel Interpretation + /// (ECI) designator with the given assignment value. + pub fn make_eci(assignval: u32, buf: &'a mut [u8]) -> Self { + let mut bb = BitBuffer::new(buf); + if assignval < (1 << 7) { + bb.append_bits(assignval, 8); + } else if assignval < (1 << 14) { + bb.append_bits(0b10, 2); + bb.append_bits(assignval, 14); + } else if assignval < 1_000_000 { + bb.append_bits(0b110, 3); + bb.append_bits(assignval, 21); + } else { + panic!("ECI assignment value out of range"); + } + QrSegment::new(QrSegmentMode::Eci, 0, bb.data, bb.length) + } + + + /*---- Constructor (low level) ----*/ + + /// Creates a new QR Code segment with the given attributes and data. + /// + /// The character count (numchars) must agree with the mode and + /// the bit buffer length, but the constraint isn't checked. + pub fn new(mode: QrSegmentMode, numchars: usize, data: &'a [u8], bitlength: usize) -> Self { + assert!(bitlength == 0 || (bitlength - 1) / 8 < data.len()); + Self { mode, numchars, data, bitlength } + } + + + /*---- Instance field getters ----*/ + + /// Returns the mode indicator of this segment. + pub fn mode(&self) -> QrSegmentMode { + self.mode + } + + + /// Returns the character count field of this segment. + pub fn num_chars(&self) -> usize { + self.numchars + } + + + /*---- Other static functions ----*/ + + /// Returns the number of bytes needed for the data buffer of a segment + /// containing the given number of characters using the given mode, or None if the + /// internal calculation of the number of needed bits exceeds usize::MAX. Notes: + /// + /// - It is okay for the user to allocate more bytes for the buffer than needed. + /// - For byte mode, numchars measures the number of bytes, not Unicode code points. + /// - For ECI mode, numchars must be 0, and the worst-case number of bytes is returned. + /// An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. + pub fn calc_buffer_size(mode: QrSegmentMode, numchars: usize) -> Option { + let temp = Self::calc_bit_length(mode, numchars)?; + Some(temp / 8 + usize::from(temp % 8 != 0)) // ceil(temp / 8) + } + + + // Returns the number of data bits needed to represent a segment + // containing the given number of characters using the given mode, + // or None if the the number of needed bits exceeds usize::MAX. Notes: + // - For byte mode, numchars measures the number of bytes, not Unicode code points. + // - For ECI mode, numchars must be 0, and the worst-case number of bits is returned. + // An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. + fn calc_bit_length(mode: QrSegmentMode, numchars: usize) -> Option { + // Returns ceil((numer / denom) * numchars) + let mul_frac_ceil = |numer: usize, denom: usize| + Some(numchars) + .and_then(|x| x.checked_mul(numer)) + .and_then(|x| x.checked_add(denom - 1)) + .map(|x| x / denom); + + use QrSegmentMode::*; + match mode { + Numeric => mul_frac_ceil(10, 3), + Alphanumeric => mul_frac_ceil(11, 2), + Byte => mul_frac_ceil( 8, 1), + Kanji => mul_frac_ceil(13, 1), + Eci => { + assert_eq!(numchars, 0); + Some(3 * 8) + }, + } + } + + + // Calculates and returns the number of bits needed to encode the given + // segments at the given version. The result is None if a segment has too many + // characters to fit its length field, or the total bits exceeds usize::MAX. + fn get_total_bits(segs: &[Self], version: Version) -> Option { + let mut result: usize = 0; + for seg in segs { + let ccbits: u8 = seg.mode.num_char_count_bits(version); + // ccbits can be as large as 16, but usize can be as small as 16 + if let Some(limit) = 1usize.checked_shl(ccbits.into()) { + if seg.numchars >= limit { + return None; // The segment's length doesn't fit the field's bit width + } + } + result = result.checked_add(4 + usize::from(ccbits))?; + result = result.checked_add(seg.bitlength)?; + } + Some(result) + } + + + /// Tests whether the given string can be encoded as a segment in numeric mode. + /// A string is encodable iff each character is in the range 0 to 9. + pub fn is_numeric(text: &str) -> bool { + text.chars().all(|c| ('0' ..= '9').contains(&c)) + } + + + /// Tests whether the given string can be encoded as a segment in alphanumeric mode. + /// A string is encodable iff each character is in the following set: 0 to 9, A to Z + /// (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. + pub fn is_alphanumeric(text: &str) -> bool { + text.chars().all(|c| ALPHANUMERIC_CHARSET.contains(c)) + } + +} + + +// The set of all legal characters in alphanumeric mode, +// where each character value maps to the index in the string. +static ALPHANUMERIC_CHARSET: &str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; + + + +/*---- QrSegmentMode functionality ----*/ + +/// Describes how a segment's data bits are interpreted. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum QrSegmentMode { + Numeric, + Alphanumeric, + Byte, + Kanji, + Eci, +} + + +impl QrSegmentMode { + + // Returns an unsigned 4-bit integer value (range 0 to 15) + // representing the mode indicator bits for this mode object. + fn mode_bits(self) -> u32 { + use QrSegmentMode::*; + match self { + Numeric => 0x1, + Alphanumeric => 0x2, + Byte => 0x4, + Kanji => 0x8, + Eci => 0x7, + } + } + + + // Returns the bit width of the character count field for a segment in this mode + // in a QR Code at the given version number. The result is in the range [0, 16]. + fn num_char_count_bits(self, ver: Version) -> u8 { + use QrSegmentMode::*; + (match self { + Numeric => [10, 12, 14], + Alphanumeric => [ 9, 11, 13], + Byte => [ 8, 16, 16], + Kanji => [ 8, 10, 12], + Eci => [ 0, 0, 0], + })[usize::from((ver.value() + 7) / 17)] + } + +} + + +/*---- BitBuffer functionality ----*/ + +/// An appendable sequence of bits (0s and 1s). +/// +/// Mainly used by QrSegment. +pub struct BitBuffer<'a> { + + data: &'a mut [u8], + + length: usize, + +} + + +impl<'a> BitBuffer<'a> { + + // Creates a bit buffer based on the given byte array. + pub fn new(buffer: &'a mut [u8]) -> Self { + Self { + data: buffer, + length: 0, + } + } + + + // Returns the length of this bit buffer, in bits. + pub fn len(&self) -> usize { + self.length + } + + + // Appends the given number of low-order bits of the given value to this byte-based + // bit buffer, increasing the bit length. Requires 0 <= numBits <= 31 and val < 2^numBits. + pub fn append_bits(&mut self, val: u32, len: u8) { + assert!(len <= 31 && val >> len == 0); + assert!(usize::from(len) <= usize::MAX - self.length); + for i in (0 .. len).rev() { + let index: usize = self.length >> 3; + let shift: u8 = 7 - ((self.length as u8) & 7); + let bit: u8 = ((val >> i) as u8) & 1; + if shift == 7 { + self.data[index] = bit << shift; + } else { + self.data[index] |= bit << shift; + } + self.length += 1; + } + } + +} + + + +/*---- Miscellaneous values ----*/ + +/// The error type when the supplied data does not fit any QR Code version. +/// +/// Ways to handle this exception include: +/// +/// - Decrease the error correction level if it was greater than `QrCodeEcc::Low`. +/// - Increase the maxversion argument if it was less than `Version::MAX`. +/// - Split the text data into better or optimal segments in order to reduce the number of bits required. +/// - Change the text or binary data to be shorter. +/// - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric). +/// - Propagate the error upward to the caller/user. +#[derive(Debug, Clone)] +pub enum DataTooLong { + SegmentTooLong, + DataOverCapacity(usize, usize), +} + +impl core::fmt::Display for DataTooLong { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match *self { + Self::SegmentTooLong => write!(f, "Segment too long"), + Self::DataOverCapacity(datalen, maxcapacity) => + write!(f, "Data length = {} bits, Max capacity = {} bits", datalen, maxcapacity), + } + } +} + + +/// A number between 1 and 40 (inclusive). +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct Version(u8); + +impl Version { + /// The minimum version number supported in the QR Code Model 2 standard. + pub const MIN: Version = Version( 1); + + /// The maximum version number supported in the QR Code Model 2 standard. + pub const MAX: Version = Version(40); + + /// Creates a version object from the given number. + /// + /// Panics if the number is outside the range [1, 40]. + pub fn new(ver: u8) -> Self { + assert!((Version::MIN.value() ..= Version::MAX.value()).contains(&ver), "Version number out of range"); + Self(ver) + } + + /// Returns the value, which is in the range [1, 40]. + pub fn value(self) -> u8 { + self.0 + } + + /// Returns the minimum length required for the output and temporary + /// buffers when creating a QR Code of this version number. + pub const fn buffer_len(self) -> usize { + let sidelen = (self.0 as usize) * 4 + 17; + (sidelen * sidelen + 7) / 8 + 1 + } +} + + +/// A number between 0 and 7 (inclusive). +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct Mask(u8); + +impl Mask { + /// Creates a mask object from the given number. + /// + /// Panics if the number is outside the range [0, 7]. + pub fn new(mask: u8) -> Self { + assert!(mask <= 7, "Mask value out of range"); + Self(mask) + } + + /// Returns the value, which is in the range [0, 7]. + pub fn value(self) -> u8 { + self.0 + } +} + + +// Returns true iff the i'th bit of x is set to 1. +fn get_bit(x: u32, i: u8) -> bool { + (x >> i) & 1 != 0 +}