Import Cobalt 16.154703
diff --git a/src/third_party/QR-Code-generator/Readme.markdown b/src/third_party/QR-Code-generator/Readme.markdown
new file mode 100644
index 0000000..7b1e7cc
--- /dev/null
+++ b/src/third_party/QR-Code-generator/Readme.markdown
@@ -0,0 +1,195 @@
+QR Code generator library
+=========================
+
+
+Introduction
+------------
+
+This project aims to be the best, clearest QR Code generator library in multiple languages. 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, JavaScript, Python, C++, C, Rust
+* 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 formats: Raw modules/pixels of the QR symbol (all languages), SVG XML string (all languages except C), `BufferedImage` raster bitmap (Java only), HTML5 canvas (JavaScript only)
+* 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 (all languages except C)
+
+Optional advanced features (Java only):
+
+* Encodes Japanese Unicode text in kanji mode to save a lot of space compared to UTF-8 bytes
+* Computes optimal segment mode switching for text with mixed numeric/alphanumeric/general parts
+
+
+Examples
+--------
+
+Java language:
+
+ import java.awt.image.BufferedImage;
+ import java.io.File;
+ import javax.imageio.ImageIO;
+ import io.nayuki.qrcodegen.*;
+
+ // Simple operation
+ QrCode qr0 = QrCode.encodeText("Hello, world!", QrCode.Ecc.MEDIUM);
+ BufferedImage img = qr0.toImage(4, 10);
+ ImageIO.write(img, "png", new File("qr-code.png"));
+
+ // Manual operation
+ List<QrSegment> segs = QrSegment.makeSegments("3141592653589793238462643383");
+ QrCode qr1 = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, 5, 5, 2, false);
+ for (int y = 0; y < qr1.size; y++) {
+ for (int x = 0; x < qr1.size; x++) {
+ (... paint qr1.getModule(x, y) ...)
+ }
+ }
+
+JavaScript language:
+
+ // Name abbreviated for the sake of these examples here
+ var QRC = qrcodegen.QrCode;
+
+ // Simple operation
+ var qr0 = QRC.encodeText("Hello, world!", QRC.Ecc.MEDIUM);
+ var svg = qr0.toSvgString(4);
+
+ // Manual operation
+ var segs = qrcodegen.QrSegment.makeSegments("3141592653589793238462643383");
+ var qr1 = QRC.encodeSegments(segs, QRC.Ecc.HIGH, 5, 5, 2, false);
+ for (var y = 0; y < qr1.size; y++) {
+ for (var x = 0; x < qr1.size; x++) {
+ (... paint qr1.getModule(x, y) ...)
+ }
+ }
+
+Python language:
+
+ from qrcodegen import *
+
+ # Simple operation
+ qr0 = QrCode.encode_text("Hello, world!", QrCode.Ecc.MEDIUM)
+ svg = qr0.to_svg_str(4)
+
+ # Manual operation
+ segs = QrSegment.make_segments("3141592653589793238462643383")
+ qr1 = QrCode.encode_segments(segs, QrCode.Ecc.HIGH, 5, 5, 2, False)
+ for y in range(qr1.get_size()):
+ for x in range(qr1.get_size()):
+ (... paint qr1.get_module(x, y) ...)
+
+C++ language:
+
+ #include <string>
+ #include <vector>
+ #include "QrCode.hpp"
+ using namespace qrcodegen;
+
+ // Simple operation
+ QrCode qr0 = QrCode::encodeText("Hello, world!", QrCode::Ecc::MEDIUM);
+ std::string svg = qr0.toSvgString(4);
+
+ // Manual operation
+ std::vector<QrSegment> segs =
+ QrSegment::makeSegments("3141592653589793238462643383");
+ QrCode qr1 = QrCode::encodeSegments(
+ segs, QrCode::Ecc::HIGH, 5, 5, 2, false);
+ for (int y = 0; y < qr1.getSize(); y++) {
+ for (int x = 0; x < qr1.getSize(); x++) {
+ (... paint qr1.getModule(x, y) ...)
+ }
+ }
+
+C language:
+
+ #include <stdbool.h>
+ #include <stdint.h>
+ #include "qrcodegen.h"
+
+ // Text data
+ uint8_t qr0[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok = qrcodegen_encodeText("Hello, world!",
+ tempBuffer, qr0, qrcodegen_Ecc_MEDIUM,
+ qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
+ qrcodegen_Mask_AUTO, true);
+ if (!ok)
+ return;
+
+ int size = qrcodegen_getSize(qr0);
+ for (int y = 0; y < size; y++) {
+ for (int x = 0; x < size; x++) {
+ (... paint qrcodegen_getModule(qr0, x, y) ...)
+ }
+ }
+
+ // Binary data
+ uint8_t dataAndTemp[qrcodegen_BUFFER_LEN_FOR_VERSION(7)]
+ = {0xE3, 0x81, 0x82};
+ uint8_t qr1[qrcodegen_BUFFER_LEN_FOR_VERSION(7)];
+ ok = qrcodegen_encodeBinary(dataAndTemp, 3, qr1,
+ qrcodegen_Ecc_HIGH, 2, 7, qrcodegen_Mask_4, false);
+
+Rust language:
+
+ extern crate qrcodegen;
+ use qrcodegen::QrCode;
+ use qrcodegen::QrCodeEcc;
+ use qrcodegen::QrSegment;
+
+ // Simple operation
+ let qr0 = QrCode::encode_text("Hello, world!",
+ QrCodeEcc::Medium).unwrap();
+ let svg = qr0.to_svg_string(4);
+
+ // Manual operation
+ let chrs: Vec<char> = "3141592653589793238462643383".chars().collect();
+ let segs = QrSegment::make_segments(&chrs);
+ let qr1 = QrCode::encode_segments_advanced(
+ &segs, QrCodeEcc::High, 5, 5, Some(2), false).unwrap();
+ for y in 0 .. qr1.size() {
+ for x in 0 .. qr1.size() {
+ (... paint qr1.get_module(x, y) ...)
+ }
+ }
+
+More information about QR Code technology and this library's design can be found on the project home page.
+
+
+License
+-------
+
+Copyright © 2017 Project Nayuki. (MIT License)
+[https://www.nayuki.io/page/qr-code-generator-library](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.
diff --git a/src/third_party/QR-Code-generator/c/Makefile b/src/third_party/QR-Code-generator/c/Makefile
new file mode 100644
index 0000000..a33f8d2
--- /dev/null
+++ b/src/third_party/QR-Code-generator/c/Makefile
@@ -0,0 +1,75 @@
+#
+# Makefile for QR Code generator (C)
+#
+# 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.
+#
+
+
+# ---- Configuration options ----
+
+# External/implicit variables:
+# - CC: The C compiler, such as gcc or clang.
+# - CFLAGS: Any extra user-specified compiler flags (can be blank).
+
+# Mandatory compiler flags
+CFLAGS += -std=c99
+# Diagnostics. Adding '-fsanitize=address' is helpful for most versions of Clang and newer versions of GCC.
+CFLAGS += -Wall -fsanitize=undefined
+# Optimization level
+CFLAGS += -O1
+
+
+# ---- Controlling make ----
+
+# Clear default suffix rules
+.SUFFIXES:
+
+# Don't delete object files
+.SECONDARY:
+
+# Stuff concerning goals
+.DEFAULT_GOAL = all
+.PHONY: all clean
+
+
+# ---- Targets to build ----
+
+LIBSRC = qrcodegen
+LIBFILE = libqrcodegen.so
+MAINS = qrcodegen-demo qrcodegen-test qrcodegen-worker
+
+# Build all binaries
+all: $(LIBFILE) $(MAINS)
+
+# Delete build output
+clean:
+ rm -f -- $(LIBFILE) $(MAINS)
+
+# Shared library
+$(LIBFILE): $(LIBSRC:=.c) $(LIBSRC:=.h)
+ $(CC) $(CFLAGS) -fPIC -shared -o $@ $(LIBSRC:=.c)
+
+# Executable files
+%: %.c $(LIBFILE)
+ $(CC) $(CFLAGS) -o $@ $^
+
+# Special executable
+qrcodegen-test: qrcodegen-test.c $(LIBSRC:=.c) $(LIBSRC:=.h)
+ $(CC) $(CFLAGS) -DQRCODEGEN_TEST -o $@ $< $(LIBSRC:=.c)
diff --git a/src/third_party/QR-Code-generator/c/qrcodegen-demo.c b/src/third_party/QR-Code-generator/c/qrcodegen-demo.c
new file mode 100644
index 0000000..c06e2f7
--- /dev/null
+++ b/src/third_party/QR-Code-generator/c/qrcodegen-demo.c
@@ -0,0 +1,310 @@
+/*
+ * QR Code generator demo (C)
+ *
+ * Run this command-line program with no arguments. The program
+ * computes a demonstration QR Codes and print it to the console.
+ *
+ * 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.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "qrcodegen.h"
+
+
+// Function prototypes
+static void doBasicDemo(void);
+static void doVarietyDemo(void);
+static void doSegmentDemo(void);
+static void doMaskDemo(void);
+static void printQr(const uint8_t qrcode[]);
+
+
+// The main application program.
+int main(void) {
+ doBasicDemo();
+ doVarietyDemo();
+ doSegmentDemo();
+ doMaskDemo();
+ return EXIT_SUCCESS;
+}
+
+
+
+/*---- Demo suite ----*/
+
+// Creates a single QR Code, then prints it to the console.
+static void doBasicDemo(void) {
+ const char *text = "Hello, world!"; // User-supplied text
+ enum qrcodegen_Ecc errCorLvl = qrcodegen_Ecc_LOW; // Error correction level
+
+ // Make and print the QR Code symbol
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok = qrcodegen_encodeText(text, tempBuffer, qrcode, errCorLvl,
+ qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
+ if (ok)
+ printQr(qrcode);
+}
+
+
+// Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console.
+static void doVarietyDemo(void) {
+ { // Numeric mode encoding (3.33 bits per digit)
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok = qrcodegen_encodeText("314159265358979323846264338327950288419716939937510", tempBuffer, qrcode,
+ qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
+ if (ok)
+ printQr(qrcode);
+ }
+
+ { // Alphanumeric mode encoding (5.5 bits per character)
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok = qrcodegen_encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", tempBuffer, qrcode,
+ qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
+ if (ok)
+ printQr(qrcode);
+ }
+
+ { // Unicode text as UTF-8
+ const char *text = "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4";
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
+ qrcodegen_Ecc_QUARTILE, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
+ if (ok)
+ printQr(qrcode);
+ }
+
+ { // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
+ const char *text =
+ "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.";
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
+ qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
+ if (ok)
+ printQr(qrcode);
+ }
+}
+
+
+// Creates QR Codes with manually specified segments for better compactness.
+static void doSegmentDemo(void) {
+ { // Illustration "silver"
+ const char *silver0 = "THE SQUARE ROOT OF 2 IS 1.";
+ const char *silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok;
+ {
+ char *concat = calloc(strlen(silver0) + strlen(silver1) + 1, sizeof(char));
+ strcat(concat, silver0);
+ strcat(concat, silver1);
+ ok = qrcodegen_encodeText(concat, tempBuffer, qrcode, qrcodegen_Ecc_LOW,
+ qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
+ if (ok)
+ printQr(qrcode);
+ free(concat);
+ }
+ {
+ uint8_t *segBuf0 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, strlen(silver0)) * sizeof(uint8_t));
+ uint8_t *segBuf1 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, strlen(silver1)) * sizeof(uint8_t));
+ struct qrcodegen_Segment segs[] = {
+ qrcodegen_makeAlphanumeric(silver0, segBuf0),
+ qrcodegen_makeNumeric(silver1, segBuf1),
+ };
+ ok = qrcodegen_encodeSegments(segs, sizeof(segs) / sizeof(segs[0]), qrcodegen_Ecc_LOW, tempBuffer, qrcode);
+ free(segBuf0);
+ free(segBuf1);
+ if (ok)
+ printQr(qrcode);
+ }
+ }
+
+ { // Illustration "golden"
+ const char *golden0 = "Golden ratio \xCF\x86 = 1.";
+ const char *golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
+ const char *golden2 = "......";
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok;
+ {
+ char *concat = calloc(strlen(golden0) + strlen(golden1) + strlen(golden2) + 1, sizeof(char));
+ strcat(concat, golden0);
+ strcat(concat, golden1);
+ strcat(concat, golden2);
+ ok = qrcodegen_encodeText(concat, tempBuffer, qrcode, qrcodegen_Ecc_LOW,
+ qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
+ if (ok)
+ printQr(qrcode);
+ free(concat);
+ }
+ {
+ uint8_t *bytes = malloc(strlen(golden0) * sizeof(uint8_t));
+ for (size_t i = 0, len = strlen(golden0); i < len; i++)
+ bytes[i] = (uint8_t)golden0[i];
+ uint8_t *segBuf0 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_BYTE, strlen(golden0)) * sizeof(uint8_t));
+ uint8_t *segBuf1 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, strlen(golden1)) * sizeof(uint8_t));
+ uint8_t *segBuf2 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, strlen(golden2)) * sizeof(uint8_t));
+ struct qrcodegen_Segment segs[] = {
+ qrcodegen_makeBytes(bytes, strlen(golden0), segBuf0),
+ qrcodegen_makeNumeric(golden1, segBuf1),
+ qrcodegen_makeAlphanumeric(golden2, segBuf2),
+ };
+ free(bytes);
+ ok = qrcodegen_encodeSegments(segs, sizeof(segs) / sizeof(segs[0]), qrcodegen_Ecc_LOW, tempBuffer, qrcode);
+ free(segBuf0);
+ free(segBuf1);
+ free(segBuf2);
+ if (ok)
+ printQr(qrcode);
+ }
+ }
+
+ { // Illustration "Madoka": kanji, kana, Greek, Cyrillic, full-width Latin characters
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok;
+ {
+ const char *madoka = // Encoded in UTF-8
+ "\xE3\x80\x8C\xE9\xAD\x94\xE6\xB3\x95\xE5"
+ "\xB0\x91\xE5\xA5\xB3\xE3\x81\xBE\xE3\x81"
+ "\xA9\xE3\x81\x8B\xE2\x98\x86\xE3\x83\x9E"
+ "\xE3\x82\xAE\xE3\x82\xAB\xE3\x80\x8D\xE3"
+ "\x81\xA3\xE3\x81\xA6\xE3\x80\x81\xE3\x80"
+ "\x80\xD0\x98\xD0\x90\xD0\x98\xE3\x80\x80"
+ "\xEF\xBD\x84\xEF\xBD\x85\xEF\xBD\x93\xEF"
+ "\xBD\x95\xE3\x80\x80\xCE\xBA\xCE\xB1\xEF"
+ "\xBC\x9F";
+ ok = qrcodegen_encodeText(madoka, tempBuffer, qrcode, qrcodegen_Ecc_LOW,
+ qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
+ if (ok)
+ printQr(qrcode);
+ }
+ {
+ const int kanjiChars[] = { // 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,
+ };
+ size_t len = sizeof(kanjiChars) / sizeof(kanjiChars[0]);
+ uint8_t *segBuf = calloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_KANJI, len), sizeof(uint8_t));
+ struct qrcodegen_Segment seg;
+ seg.mode = qrcodegen_Mode_KANJI;
+ seg.numChars = len;
+ seg.bitLength = 0;
+ for (size_t i = 0; i < len; i++) {
+ for (int j = 12; j >= 0; j--, seg.bitLength++)
+ segBuf[seg.bitLength >> 3] |= ((kanjiChars[i] >> j) & 1) << (7 - (seg.bitLength & 7));
+ }
+ seg.data = segBuf;
+ ok = qrcodegen_encodeSegments(&seg, 1, qrcodegen_Ecc_LOW, tempBuffer, qrcode);
+ free(segBuf);
+ if (ok)
+ printQr(qrcode);
+ }
+ }
+}
+
+
+// Creates QR Codes with the same size and contents but different mask patterns.
+static void doMaskDemo(void) {
+ { // Project Nayuki URL
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok;
+
+ ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode,
+ qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
+ if (ok)
+ printQr(qrcode);
+
+ ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode,
+ qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_3, true);
+ if (ok)
+ printQr(qrcode);
+ }
+
+ { // Chinese text as UTF-8
+ const char *text =
+ "\xE7\xB6\xAD\xE5\x9F\xBA\xE7\x99\xBE\xE7\xA7\x91\xEF\xBC\x88\x57\x69\x6B\x69\x70"
+ "\x65\x64\x69\x61\xEF\xBC\x8C\xE8\x81\x86\xE8\x81\xBD\x69\x2F\xCB\x8C\x77\xC9\xAA"
+ "\x6B\xE1\xB5\xBB\xCB\x88\x70\x69\xCB\x90\x64\x69\x2E\xC9\x99\x2F\xEF\xBC\x89\xE6"
+ "\x98\xAF\xE4\xB8\x80\xE5\x80\x8B\xE8\x87\xAA\xE7\x94\xB1\xE5\x85\xA7\xE5\xAE\xB9"
+ "\xE3\x80\x81\xE5\x85\xAC\xE9\x96\x8B\xE7\xB7\xA8\xE8\xBC\xAF\xE4\xB8\x94\xE5\xA4"
+ "\x9A\xE8\xAA\x9E\xE8\xA8\x80\xE7\x9A\x84\xE7\xB6\xB2\xE8\xB7\xAF\xE7\x99\xBE\xE7"
+ "\xA7\x91\xE5\x85\xA8\xE6\x9B\xB8\xE5\x8D\x94\xE4\xBD\x9C\xE8\xA8\x88\xE7\x95\xAB";
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
+ uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
+ bool ok;
+
+ ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
+ qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_0, true);
+ if (ok)
+ printQr(qrcode);
+
+ ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
+ qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_1, true);
+ if (ok)
+ printQr(qrcode);
+
+ ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
+ qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_5, true);
+ if (ok)
+ printQr(qrcode);
+
+ ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
+ qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_7, true);
+ if (ok)
+ printQr(qrcode);
+ }
+}
+
+
+
+/*---- Utilities ----*/
+
+// Prints the given QR Code to the console.
+static void printQr(const uint8_t qrcode[]) {
+ int size = qrcodegen_getSize(qrcode);
+ int border = 4;
+ for (int y = -border; y < size + border; y++) {
+ for (int x = -border; x < size + border; x++) {
+ fputs((qrcodegen_getModule(qrcode, x, y) ? "##" : " "), stdout);
+ }
+ fputs("\n", stdout);
+ }
+ fputs("\n", stdout);
+}
diff --git a/src/third_party/QR-Code-generator/c/qrcodegen-test.c b/src/third_party/QR-Code-generator/c/qrcodegen-test.c
new file mode 100644
index 0000000..4f9c5c0
--- /dev/null
+++ b/src/third_party/QR-Code-generator/c/qrcodegen-test.c
@@ -0,0 +1,1081 @@
+/*
+ * QR Code generator test suite (C)
+ *
+ * When compiling this program, the library qrcodegen.c needs QRCODEGEN_TEST
+ * to be defined. Run this command line program with no arguments.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "qrcodegen.h"
+
+#define ARRAY_LENGTH(name) (sizeof(name) / sizeof(name[0]))
+
+#ifndef __cplusplus
+ #define MALLOC(num, type) malloc((num) * sizeof(type))
+#else
+ #define MALLOC(num, type) static_cast<type*>(malloc((num) * sizeof(type)))
+#endif
+
+
+// Global variables
+static int numTestCases = 0;
+
+
+// Prototypes of private functions under test
+extern const int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
+extern const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
+void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
+void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
+int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
+int getNumRawDataModules(int version);
+void calcReedSolomonGenerator(int degree, uint8_t result[]);
+void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]);
+uint8_t finiteFieldMultiply(uint8_t x, uint8_t y);
+void initializeFunctionModules(int version, uint8_t qrcode[]);
+int getAlignmentPatternPositions(int version, uint8_t result[7]);
+bool getModule(const uint8_t qrcode[], int x, int y);
+void setModule(uint8_t qrcode[], int x, int y, bool isBlack);
+void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack);
+int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars);
+int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version);
+
+
+/*---- Test cases ----*/
+
+static void testAppendBitsToBuffer(void) {
+ {
+ uint8_t buf[1] = {0};
+ int bitLen = 0;
+ appendBitsToBuffer(0, 0, buf, &bitLen);
+ assert(bitLen == 0);
+ assert(buf[0] == 0);
+ appendBitsToBuffer(1, 1, buf, &bitLen);
+ assert(bitLen == 1);
+ assert(buf[0] == 0x80);
+ appendBitsToBuffer(0, 1, buf, &bitLen);
+ assert(bitLen == 2);
+ assert(buf[0] == 0x80);
+ appendBitsToBuffer(5, 3, buf, &bitLen);
+ assert(bitLen == 5);
+ assert(buf[0] == 0xA8);
+ appendBitsToBuffer(6, 3, buf, &bitLen);
+ assert(bitLen == 8);
+ assert(buf[0] == 0xAE);
+ numTestCases++;
+ }
+ {
+ uint8_t buf[6] = {0};
+ int bitLen = 0;
+ appendBitsToBuffer(16942, 16, buf, &bitLen);
+ assert(bitLen == 16);
+ assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x00 && buf[3] == 0x00 && buf[4] == 0x00 && buf[5] == 0x00);
+ appendBitsToBuffer(10, 7, buf, &bitLen);
+ assert(bitLen == 23);
+ assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x14 && buf[3] == 0x00 && buf[4] == 0x00 && buf[5] == 0x00);
+ appendBitsToBuffer(15, 4, buf, &bitLen);
+ assert(bitLen == 27);
+ assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x15 && buf[3] == 0xE0 && buf[4] == 0x00 && buf[5] == 0x00);
+ appendBitsToBuffer(26664, 15, buf, &bitLen);
+ assert(bitLen == 42);
+ assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x15 && buf[3] == 0xFA && buf[4] == 0x0A && buf[5] == 0x00);
+ numTestCases++;
+ }
+}
+
+
+// Ported from the Java version of the code.
+static uint8_t *appendErrorCorrectionReference(const uint8_t *data, int version, enum qrcodegen_Ecc ecl) {
+ // Calculate parameter numbers
+ int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];
+ int blockEccLen = ECC_CODEWORDS_PER_BLOCK[(int)ecl][version];
+ int rawCodewords = getNumRawDataModules(version) / 8;
+ int numShortBlocks = numBlocks - rawCodewords % numBlocks;
+ int shortBlockLen = rawCodewords / numBlocks;
+
+ // Split data into blocks and append ECC to each block
+ uint8_t **blocks = MALLOC(numBlocks, uint8_t*);
+ uint8_t *generator = MALLOC(blockEccLen, uint8_t);
+ calcReedSolomonGenerator(blockEccLen, generator);
+ for (int i = 0, k = 0; i < numBlocks; i++) {
+ uint8_t *block = MALLOC(shortBlockLen + 1, uint8_t);
+ int blockDataLen = shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1);
+ memcpy(block, &data[k], blockDataLen * sizeof(uint8_t));
+ calcReedSolomonRemainder(&data[k], blockDataLen, generator, blockEccLen, &block[shortBlockLen + 1 - blockEccLen]);
+ k += blockDataLen;
+ blocks[i] = block;
+ }
+ free(generator);
+
+ // Interleave (not concatenate) the bytes from every block into a single sequence
+ uint8_t *result = MALLOC(rawCodewords, uint8_t);
+ for (int i = 0, k = 0; i < shortBlockLen + 1; i++) {
+ for (int j = 0; j < numBlocks; j++) {
+ // Skip the padding byte in short blocks
+ if (i != shortBlockLen - blockEccLen || j >= numShortBlocks) {
+ result[k] = blocks[j][i];
+ k++;
+ }
+ }
+ }
+ for (int i = 0; i < numBlocks; i++)
+ free(blocks[i]);
+ free(blocks);
+ return result;
+}
+
+
+static void testAppendErrorCorrection(void) {
+ for (int version = 1; version <= 40; version++) {
+ for (int ecl = 0; ecl < 4; ecl++) {
+ int dataLen = getNumDataCodewords(version, (enum qrcodegen_Ecc)ecl);
+ uint8_t *pureData = MALLOC(dataLen, uint8_t);
+ for (int i = 0; i < dataLen; i++)
+ pureData[i] = rand() % 256;
+ uint8_t *expectOutput = appendErrorCorrectionReference(pureData, version, (enum qrcodegen_Ecc)ecl);
+
+ int dataAndEccLen = getNumRawDataModules(version) / 8;
+ uint8_t *paddedData = MALLOC(dataAndEccLen, uint8_t);
+ memcpy(paddedData, pureData, dataLen * sizeof(uint8_t));
+ uint8_t *actualOutput = MALLOC(dataAndEccLen, uint8_t);
+ appendErrorCorrection(paddedData, version, (enum qrcodegen_Ecc)ecl, actualOutput);
+
+ assert(memcmp(actualOutput, expectOutput, dataAndEccLen * sizeof(uint8_t)) == 0);
+ free(pureData);
+ free(expectOutput);
+ free(paddedData);
+ free(actualOutput);
+ numTestCases++;
+ }
+ }
+}
+
+
+static void testGetNumDataCodewords(void) {
+ const int cases[][3] = {
+ { 3, 1, 44},
+ { 3, 2, 34},
+ { 3, 3, 26},
+ { 6, 0, 136},
+ { 7, 0, 156},
+ { 9, 0, 232},
+ { 9, 1, 182},
+ {12, 3, 158},
+ {15, 0, 523},
+ {16, 2, 325},
+ {19, 3, 341},
+ {21, 0, 932},
+ {22, 0, 1006},
+ {22, 1, 782},
+ {22, 3, 442},
+ {24, 0, 1174},
+ {24, 3, 514},
+ {28, 0, 1531},
+ {30, 3, 745},
+ {32, 3, 845},
+ {33, 0, 2071},
+ {33, 3, 901},
+ {35, 0, 2306},
+ {35, 1, 1812},
+ {35, 2, 1286},
+ {36, 3, 1054},
+ {37, 3, 1096},
+ {39, 1, 2216},
+ {40, 1, 2334},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ const int *tc = cases[i];
+ assert(getNumDataCodewords(tc[0], (enum qrcodegen_Ecc)tc[1]) == tc[2]);
+ numTestCases++;
+ }
+}
+
+
+static void testGetNumRawDataModules(void) {
+ const int cases[][2] = {
+ { 1, 208},
+ { 2, 359},
+ { 3, 567},
+ { 6, 1383},
+ { 7, 1568},
+ {12, 3728},
+ {15, 5243},
+ {18, 7211},
+ {22, 10068},
+ {26, 13652},
+ {32, 19723},
+ {37, 25568},
+ {40, 29648},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ const int *tc = cases[i];
+ assert(getNumRawDataModules(tc[0]) == tc[1]);
+ numTestCases++;
+ }
+}
+
+
+static void testCalcReedSolomonGenerator(void) {
+ uint8_t generator[30];
+
+ calcReedSolomonGenerator(1, generator);
+ assert(generator[0] == 0x01);
+ numTestCases++;
+
+ calcReedSolomonGenerator(2, generator);
+ assert(generator[0] == 0x03);
+ assert(generator[1] == 0x02);
+ numTestCases++;
+
+ calcReedSolomonGenerator(5, generator);
+ assert(generator[0] == 0x1F);
+ assert(generator[1] == 0xC6);
+ assert(generator[2] == 0x3F);
+ assert(generator[3] == 0x93);
+ assert(generator[4] == 0x74);
+ numTestCases++;
+
+ calcReedSolomonGenerator(30, generator);
+ assert(generator[ 0] == 0xD4);
+ assert(generator[ 1] == 0xF6);
+ assert(generator[ 5] == 0xC0);
+ assert(generator[12] == 0x16);
+ assert(generator[13] == 0xD9);
+ assert(generator[20] == 0x12);
+ assert(generator[27] == 0x6A);
+ assert(generator[29] == 0x96);
+ numTestCases++;
+}
+
+
+static void testCalcReedSolomonRemainder(void) {
+ {
+ uint8_t data[1];
+ uint8_t generator[3];
+ uint8_t remainder[ARRAY_LENGTH(generator)];
+ calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
+ calcReedSolomonRemainder(data, 0, generator, ARRAY_LENGTH(generator), remainder);
+ assert(remainder[0] == 0);
+ assert(remainder[1] == 0);
+ assert(remainder[2] == 0);
+ numTestCases++;
+ }
+ {
+ uint8_t data[2] = {0, 1};
+ uint8_t generator[4];
+ uint8_t remainder[ARRAY_LENGTH(generator)];
+ calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
+ calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
+ assert(remainder[0] == generator[0]);
+ assert(remainder[1] == generator[1]);
+ assert(remainder[2] == generator[2]);
+ assert(remainder[3] == generator[3]);
+ numTestCases++;
+ }
+ {
+ uint8_t data[5] = {0x03, 0x3A, 0x60, 0x12, 0xC7};
+ uint8_t generator[5];
+ uint8_t remainder[ARRAY_LENGTH(generator)];
+ calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
+ calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
+ assert(remainder[0] == 0xCB);
+ assert(remainder[1] == 0x36);
+ assert(remainder[2] == 0x16);
+ assert(remainder[3] == 0xFA);
+ assert(remainder[4] == 0x9D);
+ numTestCases++;
+ }
+ {
+ uint8_t data[43] = {
+ 0x38, 0x71, 0xDB, 0xF9, 0xD7, 0x28, 0xF6, 0x8E, 0xFE, 0x5E,
+ 0xE6, 0x7D, 0x7D, 0xB2, 0xA5, 0x58, 0xBC, 0x28, 0x23, 0x53,
+ 0x14, 0xD5, 0x61, 0xC0, 0x20, 0x6C, 0xDE, 0xDE, 0xFC, 0x79,
+ 0xB0, 0x8B, 0x78, 0x6B, 0x49, 0xD0, 0x1A, 0xAD, 0xF3, 0xEF,
+ 0x52, 0x7D, 0x9A,
+ };
+ uint8_t generator[30];
+ uint8_t remainder[ARRAY_LENGTH(generator)];
+ calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
+ calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
+ assert(remainder[ 0] == 0xCE);
+ assert(remainder[ 1] == 0xF0);
+ assert(remainder[ 2] == 0x31);
+ assert(remainder[ 3] == 0xDE);
+ assert(remainder[ 8] == 0xE1);
+ assert(remainder[12] == 0xCA);
+ assert(remainder[17] == 0xE3);
+ assert(remainder[19] == 0x85);
+ assert(remainder[20] == 0x50);
+ assert(remainder[24] == 0xBE);
+ assert(remainder[29] == 0xB3);
+ numTestCases++;
+ }
+}
+
+
+static void testFiniteFieldMultiply(void) {
+ const uint8_t cases[][3] = {
+ {0x00, 0x00, 0x00},
+ {0x01, 0x01, 0x01},
+ {0x02, 0x02, 0x04},
+ {0x00, 0x6E, 0x00},
+ {0xB2, 0xDD, 0xE6},
+ {0x41, 0x11, 0x25},
+ {0xB0, 0x1F, 0x11},
+ {0x05, 0x75, 0xBC},
+ {0x52, 0xB5, 0xAE},
+ {0xA8, 0x20, 0xA4},
+ {0x0E, 0x44, 0x9F},
+ {0xD4, 0x13, 0xA0},
+ {0x31, 0x10, 0x37},
+ {0x6C, 0x58, 0xCB},
+ {0xB6, 0x75, 0x3E},
+ {0xFF, 0xFF, 0xE2},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ const uint8_t *tc = cases[i];
+ assert(finiteFieldMultiply(tc[0], tc[1]) == tc[2]);
+ numTestCases++;
+ }
+}
+
+
+static void testInitializeFunctionModulesEtc(void) {
+ for (int ver = 1; ver <= 40; ver++) {
+ uint8_t *qrcode = MALLOC(qrcodegen_BUFFER_LEN_FOR_VERSION(ver), uint8_t);
+ assert(qrcode != NULL);
+ initializeFunctionModules(ver, qrcode);
+
+ int size = qrcodegen_getSize(qrcode);
+ if (ver == 1)
+ assert(size == 21);
+ else if (ver == 40)
+ assert(size == 177);
+ else
+ assert(size == ver * 4 + 17);
+
+ bool hasWhite = false;
+ bool hasBlack = false;
+ for (int y = 0; y < size; y++) {
+ for (int x = 0; x < size; x++) {
+ bool color = qrcodegen_getModule(qrcode, x, y);
+ if (color)
+ hasBlack = true;
+ else
+ hasWhite = true;
+ }
+ }
+ assert(hasWhite && hasBlack);
+ free(qrcode);
+ numTestCases++;
+ }
+}
+
+
+static void testGetAlignmentPatternPositions(void) {
+ const int cases[][9] = {
+ { 1, 0, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 2, 6, 18, -1, -1, -1, -1, -1},
+ { 3, 2, 6, 22, -1, -1, -1, -1, -1},
+ { 6, 2, 6, 34, -1, -1, -1, -1, -1},
+ { 7, 3, 6, 22, 38, -1, -1, -1, -1},
+ { 8, 3, 6, 24, 42, -1, -1, -1, -1},
+ {16, 4, 6, 26, 50, 74, -1, -1, -1},
+ {25, 5, 6, 32, 58, 84, 110, -1, -1},
+ {32, 6, 6, 34, 60, 86, 112, 138, -1},
+ {33, 6, 6, 30, 58, 86, 114, 142, -1},
+ {39, 7, 6, 26, 54, 82, 110, 138, 166},
+ {40, 7, 6, 30, 58, 86, 114, 142, 170},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ const int *tc = cases[i];
+ uint8_t pos[7];
+ int num = getAlignmentPatternPositions(tc[0], pos);
+ assert(num == tc[1]);
+ for (int j = 0; j < num; j++)
+ assert(pos[j] == tc[2 + j]);
+ numTestCases++;
+ }
+}
+
+
+static void testGetSetModule(void) {
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(23)];
+ initializeFunctionModules(23, qrcode);
+ int size = qrcodegen_getSize(qrcode);
+
+ for (int y = 0; y < size; y++) { // Clear all to white
+ for (int x = 0; x < size; x++)
+ setModule(qrcode, x, y, false);
+ }
+ for (int y = 0; y < size; y++) { // Check all white
+ for (int x = 0; x < size; x++)
+ assert(qrcodegen_getModule(qrcode, x, y) == false);
+ }
+ for (int y = 0; y < size; y++) { // Set all to black
+ for (int x = 0; x < size; x++)
+ setModule(qrcode, x, y, true);
+ }
+ for (int y = 0; y < size; y++) { // Check all black
+ for (int x = 0; x < size; x++)
+ assert(qrcodegen_getModule(qrcode, x, y) == true);
+ }
+
+ // Set some out of bounds modules to white
+ setModuleBounded(qrcode, -1, -1, false);
+ setModuleBounded(qrcode, -1, 0, false);
+ setModuleBounded(qrcode, 0, -1, false);
+ setModuleBounded(qrcode, size, 5, false);
+ setModuleBounded(qrcode, 72, size, false);
+ setModuleBounded(qrcode, size, size, false);
+ for (int y = 0; y < size; y++) { // Check all black
+ for (int x = 0; x < size; x++)
+ assert(qrcodegen_getModule(qrcode, x, y) == true);
+ }
+
+ // Set some modules to white
+ setModule(qrcode, 3, 8, false);
+ setModule(qrcode, 61, 49, false);
+ for (int y = 0; y < size; y++) { // Check most black
+ for (int x = 0; x < size; x++) {
+ bool white = (x == 3 && y == 8) || (x == 61 && y == 49);
+ assert(qrcodegen_getModule(qrcode, x, y) != white);
+ }
+ }
+ numTestCases++;
+}
+
+
+static void testGetSetModuleRandomly(void) {
+ uint8_t qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(1)];
+ initializeFunctionModules(1, qrcode);
+ int size = qrcodegen_getSize(qrcode);
+
+ bool modules[21][21];
+ for (int y = 0; y < size; y++) {
+ for (int x = 0; x < size; x++)
+ modules[y][x] = qrcodegen_getModule(qrcode, x, y);
+ }
+
+ long trials = 100000;
+ for (long i = 0; i < trials; i++) {
+ int x = rand() % (size * 2) - size / 2;
+ int y = rand() % (size * 2) - size / 2;
+ bool isInBounds = 0 <= x && x < size && 0 <= y && y < size;
+ bool oldColor = isInBounds && modules[y][x];
+ if (isInBounds)
+ assert(getModule(qrcode, x, y) == oldColor);
+ assert(qrcodegen_getModule(qrcode, x, y) == oldColor);
+
+ bool newColor = rand() % 2 == 0;
+ if (isInBounds)
+ modules[y][x] = newColor;
+ if (isInBounds && rand() % 2 == 0)
+ setModule(qrcode, x, y, newColor);
+ else
+ setModuleBounded(qrcode, x, y, newColor);
+ }
+ numTestCases++;
+}
+
+
+static void testIsAlphanumeric(void) {
+ struct TestCase {
+ bool answer;
+ const char *text;
+ };
+ const struct TestCase cases[] = {
+ {true, ""},
+ {true, "0"},
+ {true, "A"},
+ {false, "a"},
+ {true, " "},
+ {true, "."},
+ {true, "*"},
+ {false, ","},
+ {false, "|"},
+ {false, "@"},
+ {true, "XYZ"},
+ {false, "XYZ!"},
+ {true, "79068"},
+ {true, "+123 ABC$"},
+ {false, "\x01"},
+ {false, "\x7F"},
+ {false, "\x80"},
+ {false, "\xC0"},
+ {false, "\xFF"},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ assert(qrcodegen_isAlphanumeric(cases[i].text) == cases[i].answer);
+ numTestCases++;
+ }
+}
+
+
+static void testIsNumeric(void) {
+ struct TestCase {
+ bool answer;
+ const char *text;
+ };
+ const struct TestCase cases[] = {
+ {true, ""},
+ {true, "0"},
+ {false, "A"},
+ {false, "a"},
+ {false, " "},
+ {false, "."},
+ {false, "*"},
+ {false, ","},
+ {false, "|"},
+ {false, "@"},
+ {false, "XYZ"},
+ {false, "XYZ!"},
+ {true, "79068"},
+ {false, "+123 ABC$"},
+ {false, "\x01"},
+ {false, "\x7F"},
+ {false, "\x80"},
+ {false, "\xC0"},
+ {false, "\xFF"},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ assert(qrcodegen_isNumeric(cases[i].text) == cases[i].answer);
+ numTestCases++;
+ }
+}
+
+
+static void testCalcSegmentBufferSize(void) {
+ {
+ const size_t cases[][2] = {
+ {0, 0},
+ {1, 1},
+ {2, 1},
+ {3, 2},
+ {4, 2},
+ {5, 3},
+ {6, 3},
+ {1472, 614},
+ {2097, 874},
+ {5326, 2220},
+ {9828, 4095},
+ {9829, 4096},
+ {9830, 4096},
+ {9831, SIZE_MAX},
+ {9832, SIZE_MAX},
+ {12000, SIZE_MAX},
+ {28453, SIZE_MAX},
+ {55555, SIZE_MAX},
+ {SIZE_MAX / 6, SIZE_MAX},
+ {SIZE_MAX / 4, SIZE_MAX},
+ {SIZE_MAX / 2, SIZE_MAX},
+ {SIZE_MAX / 1, SIZE_MAX},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, cases[i][0]) == cases[i][1]);
+ numTestCases++;
+ }
+ }
+ {
+ const size_t cases[][2] = {
+ {0, 0},
+ {1, 1},
+ {2, 2},
+ {3, 3},
+ {4, 3},
+ {5, 4},
+ {6, 5},
+ {1472, 1012},
+ {2097, 1442},
+ {5326, 3662},
+ {5955, 4095},
+ {5956, 4095},
+ {5957, 4096},
+ {5958, SIZE_MAX},
+ {5959, SIZE_MAX},
+ {12000, SIZE_MAX},
+ {28453, SIZE_MAX},
+ {55555, SIZE_MAX},
+ {SIZE_MAX / 10, SIZE_MAX},
+ {SIZE_MAX / 8, SIZE_MAX},
+ {SIZE_MAX / 5, SIZE_MAX},
+ {SIZE_MAX / 2, SIZE_MAX},
+ {SIZE_MAX / 1, SIZE_MAX},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, cases[i][0]) == cases[i][1]);
+ numTestCases++;
+ }
+ }
+ {
+ const size_t cases[][2] = {
+ {0, 0},
+ {1, 1},
+ {2, 2},
+ {3, 3},
+ {1472, 1472},
+ {2097, 2097},
+ {4094, 4094},
+ {4095, 4095},
+ {4096, SIZE_MAX},
+ {4097, SIZE_MAX},
+ {5957, SIZE_MAX},
+ {12000, SIZE_MAX},
+ {28453, SIZE_MAX},
+ {55555, SIZE_MAX},
+ {SIZE_MAX / 16 + 1, SIZE_MAX},
+ {SIZE_MAX / 14, SIZE_MAX},
+ {SIZE_MAX / 9, SIZE_MAX},
+ {SIZE_MAX / 7, SIZE_MAX},
+ {SIZE_MAX / 4, SIZE_MAX},
+ {SIZE_MAX / 3, SIZE_MAX},
+ {SIZE_MAX / 2, SIZE_MAX},
+ {SIZE_MAX / 1, SIZE_MAX},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_BYTE, cases[i][0]) == cases[i][1]);
+ numTestCases++;
+ }
+ }
+ {
+ const size_t cases[][2] = {
+ {0, 0},
+ {1, 2},
+ {2, 4},
+ {3, 5},
+ {1472, 2392},
+ {2097, 3408},
+ {2519, 4094},
+ {2520, 4095},
+ {2521, SIZE_MAX},
+ {5957, SIZE_MAX},
+ {2522, SIZE_MAX},
+ {12000, SIZE_MAX},
+ {28453, SIZE_MAX},
+ {55555, SIZE_MAX},
+ {SIZE_MAX / 13 + 1, SIZE_MAX},
+ {SIZE_MAX / 12, SIZE_MAX},
+ {SIZE_MAX / 9, SIZE_MAX},
+ {SIZE_MAX / 4, SIZE_MAX},
+ {SIZE_MAX / 3, SIZE_MAX},
+ {SIZE_MAX / 2, SIZE_MAX},
+ {SIZE_MAX / 1, SIZE_MAX},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_KANJI, cases[i][0]) == cases[i][1]);
+ numTestCases++;
+ }
+ }
+ {
+ assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ECI, 0) == 3);
+ numTestCases++;
+ }
+}
+
+
+static void testCalcSegmentBitLength(void) {
+ {
+ const int cases[][2] = {
+ {0, 0},
+ {1, 4},
+ {2, 7},
+ {3, 10},
+ {4, 14},
+ {5, 17},
+ {6, 20},
+ {1472, 4907},
+ {2097, 6990},
+ {5326, 17754},
+ {9828, 32760},
+ {9829, 32764},
+ {9830, 32767},
+ {9831, -1},
+ {9832, -1},
+ {12000, -1},
+ {28453, -1},
+ {INT_MAX / 3, -1},
+ {INT_MAX / 2, -1},
+ {INT_MAX / 1, -1},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ assert(calcSegmentBitLength(qrcodegen_Mode_NUMERIC, cases[i][0]) == cases[i][1]);
+ numTestCases++;
+ }
+ }
+ {
+ const int cases[][2] = {
+ {0, 0},
+ {1, 6},
+ {2, 11},
+ {3, 17},
+ {4, 22},
+ {5, 28},
+ {6, 33},
+ {1472, 8096},
+ {2097, 11534},
+ {5326, 29293},
+ {5955, 32753},
+ {5956, 32758},
+ {5957, 32764},
+ {5958, -1},
+ {5959, -1},
+ {12000, -1},
+ {28453, -1},
+ {INT_MAX / 5, -1},
+ {INT_MAX / 4, -1},
+ {INT_MAX / 3, -1},
+ {INT_MAX / 2, -1},
+ {INT_MAX / 1, -1},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ assert(calcSegmentBitLength(qrcodegen_Mode_ALPHANUMERIC, cases[i][0]) == cases[i][1]);
+ numTestCases++;
+ }
+ }
+ {
+ const int cases[][2] = {
+ {0, 0},
+ {1, 8},
+ {2, 16},
+ {3, 24},
+ {1472, 11776},
+ {2097, 16776},
+ {4094, 32752},
+ {4095, 32760},
+ {4096, -1},
+ {4097, -1},
+ {5957, -1},
+ {12000, -1},
+ {28453, -1},
+ {INT_MAX / 8 + 1, -1},
+ {INT_MAX / 7, -1},
+ {INT_MAX / 6, -1},
+ {INT_MAX / 5, -1},
+ {INT_MAX / 4, -1},
+ {INT_MAX / 3, -1},
+ {INT_MAX / 2, -1},
+ {INT_MAX / 1, -1},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ assert(calcSegmentBitLength(qrcodegen_Mode_BYTE, cases[i][0]) == cases[i][1]);
+ numTestCases++;
+ }
+ }
+ {
+ const int cases[][2] = {
+ {0, 0},
+ {1, 13},
+ {2, 26},
+ {3, 39},
+ {1472, 19136},
+ {2097, 27261},
+ {2519, 32747},
+ {2520, 32760},
+ {2521, -1},
+ {5957, -1},
+ {2522, -1},
+ {12000, -1},
+ {28453, -1},
+ {INT_MAX / 13 + 1, -1},
+ {INT_MAX / 12, -1},
+ {INT_MAX / 9, -1},
+ {INT_MAX / 4, -1},
+ {INT_MAX / 3, -1},
+ {INT_MAX / 2, -1},
+ {INT_MAX / 1, -1},
+ };
+ for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
+ assert(calcSegmentBitLength(qrcodegen_Mode_KANJI, cases[i][0]) == cases[i][1]);
+ numTestCases++;
+ }
+ }
+ {
+ assert(calcSegmentBitLength(qrcodegen_Mode_ECI, 0) == 24);
+ numTestCases++;
+ }
+}
+
+
+static void testMakeBytes(void) {
+ {
+ struct qrcodegen_Segment seg = qrcodegen_makeBytes(NULL, 0, NULL);
+ assert(seg.mode == qrcodegen_Mode_BYTE);
+ assert(seg.numChars == 0);
+ assert(seg.bitLength == 0);
+ numTestCases++;
+ }
+ {
+ const uint8_t data[] = {0x00};
+ uint8_t buf[1];
+ struct qrcodegen_Segment seg = qrcodegen_makeBytes(data, 1, buf);
+ assert(seg.numChars == 1);
+ assert(seg.bitLength == 8);
+ assert(seg.data[0] == 0x00);
+ numTestCases++;
+ }
+ {
+ const uint8_t data[] = {0xEF, 0xBB, 0xBF};
+ uint8_t buf[3];
+ struct qrcodegen_Segment seg = qrcodegen_makeBytes(data, 3, buf);
+ assert(seg.numChars == 3);
+ assert(seg.bitLength == 24);
+ assert(seg.data[0] == 0xEF);
+ assert(seg.data[1] == 0xBB);
+ assert(seg.data[2] == 0xBF);
+ numTestCases++;
+ }
+}
+
+
+static void testMakeNumeric(void) {
+ {
+ struct qrcodegen_Segment seg = qrcodegen_makeNumeric("", NULL);
+ assert(seg.mode == qrcodegen_Mode_NUMERIC);
+ assert(seg.numChars == 0);
+ assert(seg.bitLength == 0);
+ numTestCases++;
+ }
+ {
+ uint8_t buf[1];
+ struct qrcodegen_Segment seg = qrcodegen_makeNumeric("9", buf);
+ assert(seg.numChars == 1);
+ assert(seg.bitLength == 4);
+ assert(seg.data[0] == 0x90);
+ numTestCases++;
+ }
+ {
+ uint8_t buf[1];
+ struct qrcodegen_Segment seg = qrcodegen_makeNumeric("81", buf);
+ assert(seg.numChars == 2);
+ assert(seg.bitLength == 7);
+ assert(seg.data[0] == 0xA2);
+ numTestCases++;
+ }
+ {
+ uint8_t buf[2];
+ struct qrcodegen_Segment seg = qrcodegen_makeNumeric("673", buf);
+ assert(seg.numChars == 3);
+ assert(seg.bitLength == 10);
+ assert(seg.data[0] == 0xA8);
+ assert(seg.data[1] == 0x40);
+ numTestCases++;
+ }
+ {
+ uint8_t buf[5];
+ struct qrcodegen_Segment seg = qrcodegen_makeNumeric("3141592653", buf);
+ assert(seg.numChars == 10);
+ assert(seg.bitLength == 34);
+ assert(seg.data[0] == 0x4E);
+ assert(seg.data[1] == 0x89);
+ assert(seg.data[2] == 0xF4);
+ assert(seg.data[3] == 0x24);
+ assert(seg.data[4] == 0xC0);
+ numTestCases++;
+ }
+}
+
+
+static void testMakeAlphanumeric(void) {
+ {
+ struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("", NULL);
+ assert(seg.mode == qrcodegen_Mode_ALPHANUMERIC);
+ assert(seg.numChars == 0);
+ assert(seg.bitLength == 0);
+ numTestCases++;
+ }
+ {
+ uint8_t buf[1];
+ struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("A", buf);
+ assert(seg.numChars == 1);
+ assert(seg.bitLength == 6);
+ assert(seg.data[0] == 0x28);
+ numTestCases++;
+ }
+ {
+ uint8_t buf[2];
+ struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("%:", buf);
+ assert(seg.numChars == 2);
+ assert(seg.bitLength == 11);
+ assert(seg.data[0] == 0xDB);
+ assert(seg.data[1] == 0x40);
+ numTestCases++;
+ }
+ {
+ uint8_t buf[3];
+ struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("Q R", buf);
+ assert(seg.numChars == 3);
+ assert(seg.bitLength == 17);
+ assert(seg.data[0] == 0x96);
+ assert(seg.data[1] == 0xCD);
+ assert(seg.data[2] == 0x80);
+ numTestCases++;
+ }
+}
+
+
+static void testMakeEci(void) {
+ {
+ uint8_t buf[1];
+ struct qrcodegen_Segment seg = qrcodegen_makeEci(127, buf);
+ assert(seg.mode == qrcodegen_Mode_ECI);
+ assert(seg.numChars == 0);
+ assert(seg.bitLength == 8);
+ assert(seg.data[0] == 0x7F);
+ numTestCases++;
+ }
+ {
+ uint8_t buf[2];
+ struct qrcodegen_Segment seg = qrcodegen_makeEci(10345, buf);
+ assert(seg.numChars == 0);
+ assert(seg.bitLength == 16);
+ assert(seg.data[0] == 0xA8);
+ assert(seg.data[1] == 0x69);
+ numTestCases++;
+ }
+ {
+ uint8_t buf[3];
+ struct qrcodegen_Segment seg = qrcodegen_makeEci(999999, buf);
+ assert(seg.numChars == 0);
+ assert(seg.bitLength == 24);
+ assert(seg.data[0] == 0xCF);
+ assert(seg.data[1] == 0x42);
+ assert(seg.data[2] == 0x3F);
+ numTestCases++;
+ }
+}
+
+
+static void testGetTotalBits(void) {
+ {
+ assert(getTotalBits(NULL, 0, 1) == 0);
+ numTestCases++;
+ assert(getTotalBits(NULL, 0, 40) == 0);
+ numTestCases++;
+ }
+ {
+ struct qrcodegen_Segment segs[] = {
+ {qrcodegen_Mode_BYTE, 3, NULL, 24},
+ };
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 2) == 36);
+ numTestCases++;
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 10) == 44);
+ numTestCases++;
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 39) == 44);
+ numTestCases++;
+ }
+ {
+ struct qrcodegen_Segment segs[] = {
+ {qrcodegen_Mode_ECI, 0, NULL, 8},
+ {qrcodegen_Mode_NUMERIC, 7, NULL, 24},
+ {qrcodegen_Mode_ALPHANUMERIC, 1, NULL, 6},
+ {qrcodegen_Mode_KANJI, 4, NULL, 52},
+ };
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 9) == 133);
+ numTestCases++;
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 21) == 139);
+ numTestCases++;
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 27) == 145);
+ numTestCases++;
+ }
+ {
+ struct qrcodegen_Segment segs[] = {
+ {qrcodegen_Mode_BYTE, 4093, NULL, 32744},
+ };
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 1) == -1);
+ numTestCases++;
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 10) == 32764);
+ numTestCases++;
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 27) == 32764);
+ numTestCases++;
+ }
+ {
+ struct qrcodegen_Segment segs[] = {
+ {qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
+ {qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
+ {qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
+ {qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
+ {qrcodegen_Mode_NUMERIC, 1617, NULL, 5390},
+ };
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 1) == -1);
+ numTestCases++;
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 10) == 32766);
+ numTestCases++;
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 27) == -1);
+ numTestCases++;
+ }
+ {
+ struct qrcodegen_Segment segs[] = {
+ {qrcodegen_Mode_KANJI, 255, NULL, 3315},
+ {qrcodegen_Mode_KANJI, 255, NULL, 3315},
+ {qrcodegen_Mode_KANJI, 255, NULL, 3315},
+ {qrcodegen_Mode_KANJI, 255, NULL, 3315},
+ {qrcodegen_Mode_KANJI, 255, NULL, 3315},
+ {qrcodegen_Mode_KANJI, 255, NULL, 3315},
+ {qrcodegen_Mode_KANJI, 255, NULL, 3315},
+ {qrcodegen_Mode_KANJI, 255, NULL, 3315},
+ {qrcodegen_Mode_KANJI, 255, NULL, 3315},
+ {qrcodegen_Mode_ALPHANUMERIC, 511, NULL, 2811},
+ };
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 9) == 32767);
+ numTestCases++;
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 26) == -1);
+ numTestCases++;
+ assert(getTotalBits(segs, ARRAY_LENGTH(segs), 40) == -1);
+ numTestCases++;
+ }
+}
+
+
+/*---- Main runner ----*/
+
+int main(void) {
+ srand(time(NULL));
+ testAppendBitsToBuffer();
+ testAppendErrorCorrection();
+ testGetNumDataCodewords();
+ testGetNumRawDataModules();
+ testCalcReedSolomonGenerator();
+ testCalcReedSolomonRemainder();
+ testFiniteFieldMultiply();
+ testInitializeFunctionModulesEtc();
+ testGetAlignmentPatternPositions();
+ testGetSetModule();
+ testGetSetModuleRandomly();
+ testIsAlphanumeric();
+ testIsNumeric();
+ testCalcSegmentBufferSize();
+ testCalcSegmentBitLength();
+ testMakeBytes();
+ testMakeNumeric();
+ testMakeAlphanumeric();
+ testMakeEci();
+ testGetTotalBits();
+ printf("All %d test cases passed\n", numTestCases);
+ return EXIT_SUCCESS;
+}
diff --git a/src/third_party/QR-Code-generator/c/qrcodegen-worker.c b/src/third_party/QR-Code-generator/c/qrcodegen-worker.c
new file mode 100644
index 0000000..9fa6433
--- /dev/null
+++ b/src/third_party/QR-Code-generator/c/qrcodegen-worker.c
@@ -0,0 +1,116 @@
+/*
+ * QR Code generator test worker (C)
+ *
+ * This program reads data and encoding parameters from standard input and writes
+ * QR Code bitmaps to standard output. The I/O format is one integer per line.
+ * Run with no command line arguments. The program is intended for automated
+ * batch testing of end-to-end functionality of this QR Code generator library.
+ *
+ * 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.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "qrcodegen.h"
+
+#ifndef __cplusplus
+ #define MALLOC(num, type) malloc((num) * sizeof(type))
+#else
+ #define MALLOC(num, type) static_cast<type*>(malloc((num) * sizeof(type)))
+#endif
+
+
+int main(void) {
+ while (true) {
+
+ // Read data length or exit
+ int length;
+ if (scanf("%d", &length) != 1)
+ return EXIT_FAILURE;
+ if (length == -1)
+ break;
+
+ // Read data bytes
+ bool isAscii = true;
+ uint8_t *data = MALLOC(length, uint8_t);
+ if (data == NULL) {
+ perror("malloc");
+ return EXIT_FAILURE;
+ }
+ for (int i = 0; i < length; i++) {
+ int b;
+ if (scanf("%d", &b) != 1)
+ return EXIT_FAILURE;
+ data[i] = (uint8_t)b;
+ isAscii &= 0 < b && b < 128;
+ }
+
+ // Read encoding parameters
+ int errCorLvl, minVersion, maxVersion, mask, boostEcl;
+ if (scanf("%d %d %d %d %d", &errCorLvl, &minVersion, &maxVersion, &mask, &boostEcl) != 5)
+ return EXIT_FAILURE;
+
+ // Allocate memory for QR Code
+ int bufferLen = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion);
+ uint8_t *qrcode = MALLOC(bufferLen, uint8_t);
+ uint8_t *tempBuffer = MALLOC(bufferLen, uint8_t);
+ if (qrcode == NULL || tempBuffer == NULL) {
+ perror("malloc");
+ return EXIT_FAILURE;
+ }
+
+ // Try to make QR Code symbol
+ bool ok;
+ if (isAscii) {
+ char *text = MALLOC(length + 1, char);
+ for (int i = 0; i < length; i++)
+ text[i] = (char)data[i];
+ text[length] = '\0';
+ ok = qrcodegen_encodeText(text, tempBuffer, qrcode, (enum qrcodegen_Ecc)errCorLvl,
+ minVersion, maxVersion, (enum qrcodegen_Mask)mask, boostEcl == 1);
+ free(text);
+ } else if (length <= bufferLen) {
+ memcpy(tempBuffer, data, length * sizeof(data[0]));
+ ok = qrcodegen_encodeBinary(tempBuffer, (size_t)length, qrcode, (enum qrcodegen_Ecc)errCorLvl,
+ minVersion, maxVersion, (enum qrcodegen_Mask)mask, boostEcl == 1);
+ } else
+ ok = false;
+ free(data);
+ free(tempBuffer);
+
+ if (ok) {
+ // Print grid of modules
+ int size = qrcodegen_getSize(qrcode);
+ printf("%d\n", (size - 17) / 4);
+ for (int y = 0; y < size; y++) {
+ for (int x = 0; x < size; x++)
+ printf("%d\n", qrcodegen_getModule(qrcode, x, y) ? 1 : 0);
+ }
+ } else
+ printf("-1\n");
+ free(qrcode);
+ fflush(stdout);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/src/third_party/QR-Code-generator/c/qrcodegen.c b/src/third_party/QR-Code-generator/c/qrcodegen.c
new file mode 100644
index 0000000..d448f91
--- /dev/null
+++ b/src/third_party/QR-Code-generator/c/qrcodegen.c
@@ -0,0 +1,1024 @@
+/*
+ * QR Code generator library (C)
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include "qrcodegen.h"
+
+#ifndef QRCODEGEN_TEST
+ #define testable static // Keep functions private
+#else
+ // Expose private functions
+ #ifndef __cplusplus
+ #define testable
+ #else
+ // Needed for const variables because they are treated as implicitly 'static' in C++
+ #define testable extern
+ #endif
+#endif
+
+
+/*---- Forward declarations for private functions ----*/
+
+// Regarding all public and private functions defined in this source file:
+// - They require all pointer/array arguments to be not null.
+// - They only read input scalar/array arguments, write to output pointer/array
+// arguments, and return scalar values; they are "pure" functions.
+// - They don't read mutable global variables or write to any global variables.
+// - They don't perform I/O, read the clock, print to console, etc.
+// - They allocate a small and constant amount of stack memory.
+// - They don't allocate or free any memory on the heap.
+// - They don't recurse or mutually recurse. All the code
+// could be inlined into the top-level public functions.
+// - They run in at most quadratic time with respect to input arguments.
+// Most functions run in linear time, and some in constant time.
+// There are no unbounded loops or non-obvious termination conditions.
+// - They are completely thread-safe if the caller does not give the
+// same writable buffer to concurrent calls to these functions.
+
+testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
+
+testable void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
+testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
+testable int getNumRawDataModules(int version);
+
+testable void calcReedSolomonGenerator(int degree, uint8_t result[]);
+testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen,
+ const uint8_t generator[], int degree, uint8_t result[]);
+testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y);
+
+testable void initializeFunctionModules(int version, uint8_t qrcode[]);
+static void drawWhiteFunctionModules(uint8_t qrcode[], int version);
+static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]);
+testable int getAlignmentPatternPositions(int version, uint8_t result[7]);
+static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]);
+
+static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]);
+static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask);
+static long getPenaltyScore(const uint8_t qrcode[]);
+
+testable bool getModule(const uint8_t qrcode[], int x, int y);
+testable void setModule(uint8_t qrcode[], int x, int y, bool isBlack);
+testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack);
+
+testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars);
+testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version);
+static int numCharCountBits(enum qrcodegen_Mode mode, int version);
+
+
+
+/*---- Private tables of constants ----*/
+
+// For checking text and encoding segments.
+static const char *ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
+
+// For generating error correction codes.
+testable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = {
+ // 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
+};
+
+// For generating error correction codes.
+testable const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
+ // 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
+};
+
+// For automatic mask pattern selection.
+static const int PENALTY_N1 = 3;
+static const int PENALTY_N2 = 3;
+static const int PENALTY_N3 = 40;
+static const int PENALTY_N4 = 10;
+
+
+
+/*---- High-level QR Code encoding functions ----*/
+
+// Public function - see documentation comment in header file.
+bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[],
+ enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) {
+
+ size_t textLen = strlen(text);
+ if (textLen == 0)
+ return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode);
+ size_t bufLen = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion);
+
+ struct qrcodegen_Segment seg;
+ if (qrcodegen_isNumeric(text)) {
+ if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen)
+ goto fail;
+ seg = qrcodegen_makeNumeric(text, tempBuffer);
+ } else if (qrcodegen_isAlphanumeric(text)) {
+ if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, textLen) > bufLen)
+ goto fail;
+ seg = qrcodegen_makeAlphanumeric(text, tempBuffer);
+ } else {
+ if (textLen > bufLen)
+ goto fail;
+ for (size_t i = 0; i < textLen; i++)
+ tempBuffer[i] = (uint8_t)text[i];
+ seg.mode = qrcodegen_Mode_BYTE;
+ seg.bitLength = calcSegmentBitLength(seg.mode, textLen);
+ if (seg.bitLength == -1)
+ goto fail;
+ seg.numChars = (int)textLen;
+ seg.data = tempBuffer;
+ }
+ return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode);
+
+fail:
+ qrcode[0] = 0; // Set size to invalid value for safety
+ return false;
+}
+
+
+// Public function - see documentation comment in header file.
+bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[],
+ enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) {
+
+ struct qrcodegen_Segment seg;
+ seg.mode = qrcodegen_Mode_BYTE;
+ seg.bitLength = calcSegmentBitLength(seg.mode, dataLen);
+ if (seg.bitLength == -1) {
+ qrcode[0] = 0; // Set size to invalid value for safety
+ return false;
+ }
+ seg.numChars = (int)dataLen;
+ seg.data = dataAndTemp;
+ return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, dataAndTemp, qrcode);
+}
+
+
+// Appends the given sequence of bits to the given byte-based bit buffer, increasing the bit length.
+testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen) {
+ assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0);
+ for (int i = numBits - 1; i >= 0; i--, (*bitLen)++)
+ buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7));
+}
+
+
+
+/*---- Error correction code generation functions ----*/
+
+// Appends error correction bytes to each block of the given data array, then interleaves bytes
+// from the blocks and stores them in the result array. data[0 : rawCodewords - totalEcc] contains
+// the input data. data[rawCodewords - totalEcc : rawCodewords] is used as a temporary work area
+// and will be clobbered by this function. The final answer is stored in result[0 : rawCodewords].
+testable void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]) {
+ // Calculate parameter numbers
+ assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
+ int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];
+ int blockEccLen = ECC_CODEWORDS_PER_BLOCK[(int)ecl][version];
+ int rawCodewords = getNumRawDataModules(version) / 8;
+ int dataLen = rawCodewords - blockEccLen * numBlocks;
+ int numShortBlocks = numBlocks - rawCodewords % numBlocks;
+ int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen;
+
+ // Split data into blocks and append ECC after all data
+ uint8_t generator[30];
+ calcReedSolomonGenerator(blockEccLen, generator);
+ for (int i = 0, j = dataLen, k = 0; i < numBlocks; i++) {
+ int blockLen = shortBlockDataLen;
+ if (i >= numShortBlocks)
+ blockLen++;
+ calcReedSolomonRemainder(&data[k], blockLen, generator, blockEccLen, &data[j]);
+ j += blockEccLen;
+ k += blockLen;
+ }
+
+ // Interleave (not concatenate) the bytes from every block into a single sequence
+ for (int i = 0, k = 0; i < numBlocks; i++) {
+ for (int j = 0, l = i; j < shortBlockDataLen; j++, k++, l += numBlocks)
+ result[l] = data[k];
+ if (i >= numShortBlocks)
+ k++;
+ }
+ for (int i = numShortBlocks, k = (numShortBlocks + 1) * shortBlockDataLen, l = numBlocks * shortBlockDataLen;
+ i < numBlocks; i++, k += shortBlockDataLen + 1, l++)
+ result[l] = data[k];
+ for (int i = 0, k = dataLen; i < numBlocks; i++) {
+ for (int j = 0, l = dataLen + i; j < blockEccLen; j++, k++, l += numBlocks)
+ result[l] = data[k];
+ }
+}
+
+
+// Returns the number of 8-bit codewords that can be used for storing data (not ECC),
+// for the given version number and error correction level. The result is in the range [9, 2956].
+testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) {
+ int v = version, e = (int)ecl;
+ assert(0 <= e && e < 4 && qrcodegen_VERSION_MIN <= v && v <= qrcodegen_VERSION_MAX);
+ return getNumRawDataModules(v) / 8 - ECC_CODEWORDS_PER_BLOCK[e][v] * NUM_ERROR_CORRECTION_BLOCKS[e][v];
+}
+
+
+// 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.
+testable int getNumRawDataModules(int version) {
+ assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
+ int result = (16 * version + 128) * version + 64;
+ if (version >= 2) {
+ int numAlign = version / 7 + 2;
+ result -= (25 * numAlign - 10) * numAlign - 55;
+ if (version >= 7)
+ result -= 18 * 2; // Subtract version information
+ }
+ return result;
+}
+
+
+
+/*---- Reed-Solomon ECC generator functions ----*/
+
+// Calculates the Reed-Solomon generator polynomial of the given degree, storing in result[0 : degree].
+testable void calcReedSolomonGenerator(int degree, uint8_t result[]) {
+ // Start with the monomial x^0
+ assert(1 <= degree && degree <= 30);
+ memset(result, 0, degree * sizeof(result[0]));
+ result[degree - 1] = 1;
+
+ // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
+ // drop the highest term, and store the rest of the coefficients in order of descending powers.
+ // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
+ uint8_t root = 1;
+ for (int i = 0; i < degree; i++) {
+ // Multiply the current product by (x - r^i)
+ for (int j = 0; j < degree; j++) {
+ result[j] = finiteFieldMultiply(result[j], root);
+ if (j + 1 < degree)
+ result[j] ^= result[j + 1];
+ }
+ root = finiteFieldMultiply(root, 0x02);
+ }
+}
+
+
+// Calculates the remainder of the polynomial data[0 : dataLen] when divided by the generator[0 : degree], where all
+// polynomials are in big endian and the generator has an implicit leading 1 term, storing the result in result[0 : degree].
+testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen,
+ const uint8_t generator[], int degree, uint8_t result[]) {
+
+ // Perform polynomial division
+ assert(1 <= degree && degree <= 30);
+ memset(result, 0, degree * sizeof(result[0]));
+ for (int i = 0; i < dataLen; i++) {
+ uint8_t factor = data[i] ^ result[0];
+ memmove(&result[0], &result[1], (degree - 1) * sizeof(result[0]));
+ result[degree - 1] = 0;
+ for (int j = 0; j < degree; j++)
+ result[j] ^= finiteFieldMultiply(generator[j], 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.
+testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y) {
+ // Russian peasant multiplication
+ uint8_t z = 0;
+ for (int i = 7; i >= 0; i--) {
+ z = (z << 1) ^ ((z >> 7) * 0x11D);
+ z ^= ((y >> i) & 1) * x;
+ }
+ return z;
+}
+
+
+
+/*---- Drawing function modules ----*/
+
+// Clears the given QR Code grid with white modules for the given
+// version's size, then marks every function module as black.
+testable void initializeFunctionModules(int version, uint8_t qrcode[]) {
+ // Initialize QR Code
+ int qrsize = version * 4 + 17;
+ memset(qrcode, 0, ((qrsize * qrsize + 7) / 8 + 1) * sizeof(qrcode[0]));
+ qrcode[0] = (uint8_t)qrsize;
+
+ // Fill horizontal and vertical timing patterns
+ fillRectangle(6, 0, 1, qrsize, qrcode);
+ fillRectangle(0, 6, qrsize, 1, qrcode);
+
+ // Fill 3 finder patterns (all corners except bottom right) and format bits
+ fillRectangle(0, 0, 9, 9, qrcode);
+ fillRectangle(qrsize - 8, 0, 8, 9, qrcode);
+ fillRectangle(0, qrsize - 8, 9, 8, qrcode);
+
+ // Fill numerous alignment patterns
+ uint8_t alignPatPos[7] = {0};
+ int numAlign = getAlignmentPatternPositions(version, alignPatPos);
+ for (int i = 0; i < numAlign; i++) {
+ for (int j = 0; j < numAlign; j++) {
+ if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))
+ continue; // Skip the three finder corners
+ else
+ fillRectangle(alignPatPos[i] - 2, alignPatPos[j] - 2, 5, 5, qrcode);
+ }
+ }
+
+ // Fill version blocks
+ if (version >= 7) {
+ fillRectangle(qrsize - 11, 0, 3, 6, qrcode);
+ fillRectangle(0, qrsize - 11, 6, 3, qrcode);
+ }
+}
+
+
+// Draws white function modules and possibly some black modules onto the given QR Code, without changing
+// non-function modules. This does not draw the format bits. This requires all function modules to be previously
+// marked black (namely by initializeFunctionModules()), because this may skip redrawing black function modules.
+static void drawWhiteFunctionModules(uint8_t qrcode[], int version) {
+ // Draw horizontal and vertical timing patterns
+ int qrsize = qrcodegen_getSize(qrcode);
+ for (int i = 7; i < qrsize - 7; i += 2) {
+ setModule(qrcode, 6, i, false);
+ setModule(qrcode, i, 6, false);
+ }
+
+ // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
+ for (int i = -4; i <= 4; i++) {
+ for (int j = -4; j <= 4; j++) {
+ int dist = abs(i);
+ if (abs(j) > dist)
+ dist = abs(j);
+ if (dist == 2 || dist == 4) {
+ setModuleBounded(qrcode, 3 + j, 3 + i, false);
+ setModuleBounded(qrcode, qrsize - 4 + j, 3 + i, false);
+ setModuleBounded(qrcode, 3 + j, qrsize - 4 + i, false);
+ }
+ }
+ }
+
+ // Draw numerous alignment patterns
+ uint8_t alignPatPos[7] = {0};
+ int numAlign = getAlignmentPatternPositions(version, alignPatPos);
+ for (int i = 0; i < numAlign; i++) {
+ for (int j = 0; j < numAlign; j++) {
+ if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))
+ continue; // Skip the three finder corners
+ else {
+ for (int k = -1; k <= 1; k++) {
+ for (int l = -1; l <= 1; l++)
+ setModule(qrcode, alignPatPos[i] + l, alignPatPos[j] + k, k == 0 && l == 0);
+ }
+ }
+ }
+ }
+
+ // Draw version blocks
+ if (version >= 7) {
+ // Calculate error correction code and pack bits
+ int rem = version; // version is uint6, in the range [7, 40]
+ for (int i = 0; i < 12; i++)
+ rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
+ long data = (long)version << 12 | rem; // uint18
+ assert(data >> 18 == 0);
+
+ // Draw two copies
+ for (int i = 0; i < 6; i++) {
+ for (int j = 0; j < 3; j++) {
+ int k = qrsize - 11 + j;
+ setModule(qrcode, k, i, (data & 1) != 0);
+ setModule(qrcode, i, k, (data & 1) != 0);
+ data >>= 1;
+ }
+ }
+ }
+}
+
+
+// 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 drawWhiteFunctionModules() which might skip black modules.
+static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]) {
+ // Calculate error correction code and pack bits
+ assert(0 <= (int)mask && (int)mask <= 7);
+ int data = -1; // Dummy value
+ switch (ecl) {
+ case qrcodegen_Ecc_LOW : data = 1; break;
+ case qrcodegen_Ecc_MEDIUM : data = 0; break;
+ case qrcodegen_Ecc_QUARTILE: data = 3; break;
+ case qrcodegen_Ecc_HIGH : data = 2; break;
+ default: assert(false);
+ }
+ data = data << 3 | (int)mask; // ecl-derived value is uint2, mask is uint3
+ int rem = data;
+ for (int i = 0; i < 10; i++)
+ rem = (rem << 1) ^ ((rem >> 9) * 0x537);
+ data = data << 10 | rem;
+ data ^= 0x5412; // uint15
+ assert(data >> 15 == 0);
+
+ // Draw first copy
+ for (int i = 0; i <= 5; i++)
+ setModule(qrcode, 8, i, ((data >> i) & 1) != 0);
+ setModule(qrcode, 8, 7, ((data >> 6) & 1) != 0);
+ setModule(qrcode, 8, 8, ((data >> 7) & 1) != 0);
+ setModule(qrcode, 7, 8, ((data >> 8) & 1) != 0);
+ for (int i = 9; i < 15; i++)
+ setModule(qrcode, 14 - i, 8, ((data >> i) & 1) != 0);
+
+ // Draw second copy
+ int qrsize = qrcodegen_getSize(qrcode);
+ for (int i = 0; i <= 7; i++)
+ setModule(qrcode, qrsize - 1 - i, 8, ((data >> i) & 1) != 0);
+ for (int i = 8; i < 15; i++)
+ setModule(qrcode, 8, qrsize - 15 + i, ((data >> i) & 1) != 0);
+ setModule(qrcode, 8, qrsize - 8, true);
+}
+
+
+// Calculates the positions of alignment patterns in ascending order for the given version number,
+// storing them to the given array and returning an array length in the range [0, 7].
+testable int getAlignmentPatternPositions(int version, uint8_t result[7]) {
+ if (version == 1)
+ return 0;
+ int numAlign = version / 7 + 2;
+ int step;
+ if (version != 32) {
+ // ceil((size - 13) / (2*numAlign - 2)) * 2
+ step = (version * 4 + numAlign * 2 + 1) / (2 * numAlign - 2) * 2;
+ } else // C-C-C-Combo breaker!
+ step = 26;
+ for (int i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step)
+ result[i] = pos;
+ result[0] = 6;
+ return numAlign;
+}
+
+
+// Sets every pixel in the range [left : left + width] * [top : top + height] to black.
+static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]) {
+ for (int dy = 0; dy < height; dy++) {
+ for (int dx = 0; dx < width; dx++)
+ setModule(qrcode, left + dx, top + dy, true);
+ }
+}
+
+
+
+/*---- Drawing data modules and masking ----*/
+
+// Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of
+// the QR Code to be black at function modules and white at codeword modules (including unused remainder bits).
+static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) {
+ int qrsize = qrcodegen_getSize(qrcode);
+ int i = 0; // Bit index into the data
+ // Do the funny zigzag scan
+ for (int right = qrsize - 1; right >= 1; right -= 2) { // Index of right column in each column pair
+ if (right == 6)
+ right = 5;
+ for (int vert = 0; vert < qrsize; vert++) { // Vertical counter
+ for (int j = 0; j < 2; j++) {
+ int x = right - j; // Actual x coordinate
+ bool upward = ((right + 1) & 2) == 0;
+ int y = upward ? qrsize - 1 - vert : vert; // Actual y coordinate
+ if (!getModule(qrcode, x, y) && i < dataLen * 8) {
+ bool black = ((data[i >> 3] >> (7 - (i & 7))) & 1) != 0;
+ setModule(qrcode, x, y, black);
+ i++;
+ }
+ // If there are any remainder bits (0 to 7), they are already
+ // set to 0/false/white when the grid of modules was initialized
+ }
+ }
+ }
+ assert(i == dataLen * 8);
+}
+
+
+// XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical
+// properties, calling applyMask(..., m) twice with the same value is equivalent to no change at all.
+// This means it is possible to apply a mask, undo it, and try another mask. Note that a final
+// well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.).
+static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask) {
+ assert(0 <= (int)mask && (int)mask <= 7); // Disallows qrcodegen_Mask_AUTO
+ int qrsize = qrcodegen_getSize(qrcode);
+ for (int y = 0; y < qrsize; y++) {
+ for (int x = 0; x < qrsize; x++) {
+ if (getModule(functionModules, x, y))
+ continue;
+ bool invert = false; // Dummy value
+ switch ((int)mask) {
+ case 0: invert = (x + y) % 2 == 0; break;
+ case 1: invert = y % 2 == 0; break;
+ case 2: invert = x % 3 == 0; break;
+ case 3: invert = (x + y) % 3 == 0; break;
+ case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
+ case 5: invert = x * y % 2 + x * y % 3 == 0; break;
+ case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
+ case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
+ default: assert(false);
+ }
+ bool val = getModule(qrcode, x, y);
+ setModule(qrcode, x, y, val ^ invert);
+ }
+ }
+}
+
+
+// Calculates and returns the penalty score based on state of the given QR Code's current modules.
+// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
+static long getPenaltyScore(const uint8_t qrcode[]) {
+ int qrsize = qrcodegen_getSize(qrcode);
+ long result = 0;
+
+ // Adjacent modules in row having same color
+ for (int y = 0; y < qrsize; y++) {
+ bool colorX = false;
+ for (int x = 0, runX = -1; x < qrsize; x++) {
+ if (x == 0 || getModule(qrcode, x, y) != colorX) {
+ colorX = getModule(qrcode, x, y);
+ runX = 1;
+ } else {
+ runX++;
+ if (runX == 5)
+ result += PENALTY_N1;
+ else if (runX > 5)
+ result++;
+ }
+ }
+ }
+ // Adjacent modules in column having same color
+ for (int x = 0; x < qrsize; x++) {
+ bool colorY = false;
+ for (int y = 0, runY = -1; y < qrsize; y++) {
+ if (y == 0 || getModule(qrcode, x, y) != colorY) {
+ colorY = getModule(qrcode, x, y);
+ runY = 1;
+ } else {
+ runY++;
+ if (runY == 5)
+ result += PENALTY_N1;
+ else if (runY > 5)
+ result++;
+ }
+ }
+ }
+
+ // 2*2 blocks of modules having same color
+ for (int y = 0; y < qrsize - 1; y++) {
+ for (int x = 0; x < qrsize - 1; x++) {
+ bool color = getModule(qrcode, x, y);
+ if ( color == getModule(qrcode, x + 1, y) &&
+ color == getModule(qrcode, x, y + 1) &&
+ color == getModule(qrcode, x + 1, y + 1))
+ result += PENALTY_N2;
+ }
+ }
+
+ // Finder-like pattern in rows
+ for (int y = 0; y < qrsize; y++) {
+ for (int x = 0, bits = 0; x < qrsize; x++) {
+ bits = ((bits << 1) & 0x7FF) | (getModule(qrcode, x, y) ? 1 : 0);
+ if (x >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
+ result += PENALTY_N3;
+ }
+ }
+ // Finder-like pattern in columns
+ for (int x = 0; x < qrsize; x++) {
+ for (int y = 0, bits = 0; y < qrsize; y++) {
+ bits = ((bits << 1) & 0x7FF) | (getModule(qrcode, x, y) ? 1 : 0);
+ if (y >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
+ result += PENALTY_N3;
+ }
+ }
+
+ // Balance of black and white modules
+ int black = 0;
+ for (int y = 0; y < qrsize; y++) {
+ for (int x = 0; x < qrsize; x++) {
+ if (getModule(qrcode, x, y))
+ black++;
+ }
+ }
+ int total = qrsize * qrsize;
+ // Find smallest k such that (45-5k)% <= dark/total <= (55+5k)%
+ for (int k = 0; black*20L < (9L-k)*total || black*20L > (11L+k)*total; k++)
+ result += PENALTY_N4;
+ return result;
+}
+
+
+
+/*---- Basic QR Code information ----*/
+
+// Public function - see documentation comment in header file.
+int qrcodegen_getSize(const uint8_t qrcode[]) {
+ assert(qrcode != NULL);
+ int result = qrcode[0];
+ assert((qrcodegen_VERSION_MIN * 4 + 17) <= result
+ && result <= (qrcodegen_VERSION_MAX * 4 + 17));
+ return result;
+}
+
+
+// Public function - see documentation comment in header file.
+bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) {
+ assert(qrcode != NULL);
+ int qrsize = qrcode[0];
+ return (0 <= x && x < qrsize && 0 <= y && y < qrsize) && getModule(qrcode, x, y);
+}
+
+
+// Gets the module at the given coordinates, which must be in bounds.
+testable bool getModule(const uint8_t qrcode[], int x, int y) {
+ int qrsize = qrcode[0];
+ assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
+ int index = y * qrsize + x;
+ int bitIndex = index & 7;
+ int byteIndex = (index >> 3) + 1;
+ return ((qrcode[byteIndex] >> bitIndex) & 1) != 0;
+}
+
+
+// Sets the module at the given coordinates, which must be in bounds.
+testable void setModule(uint8_t qrcode[], int x, int y, bool isBlack) {
+ int qrsize = qrcode[0];
+ assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
+ int index = y * qrsize + x;
+ int bitIndex = index & 7;
+ int byteIndex = (index >> 3) + 1;
+ if (isBlack)
+ qrcode[byteIndex] |= 1 << bitIndex;
+ else
+ qrcode[byteIndex] &= (1 << bitIndex) ^ 0xFF;
+}
+
+
+// Sets the module at the given coordinates, doing nothing if out of bounds.
+testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack) {
+ int qrsize = qrcode[0];
+ if (0 <= x && x < qrsize && 0 <= y && y < qrsize)
+ setModule(qrcode, x, y, isBlack);
+}
+
+
+
+/*---- Segment handling ----*/
+
+// Public function - see documentation comment in header file.
+bool qrcodegen_isAlphanumeric(const char *text) {
+ assert(text != NULL);
+ for (; *text != '\0'; text++) {
+ if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL)
+ return false;
+ }
+ return true;
+}
+
+
+// Public function - see documentation comment in header file.
+bool qrcodegen_isNumeric(const char *text) {
+ assert(text != NULL);
+ for (; *text != '\0'; text++) {
+ if (*text < '0' || *text > '9')
+ return false;
+ }
+ return true;
+}
+
+
+// Public function - see documentation comment in header file.
+size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars) {
+ int temp = calcSegmentBitLength(mode, numChars);
+ if (temp == -1)
+ return SIZE_MAX;
+ assert(0 <= temp && temp <= INT16_MAX);
+ return ((size_t)temp + 7) / 8;
+}
+
+
+// Returns the number of data bits needed to represent a segment
+// containing the given number of characters using the given mode. Notes:
+// - Returns -1 on failure, i.e. numChars > INT16_MAX or
+// the number of needed bits exceeds INT16_MAX (i.e. 32767).
+// - Otherwise, all valid results are in the range [0, INT16_MAX].
+// - 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.
+testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) {
+ const int LIMIT = INT16_MAX; // Can be configured as high as INT_MAX
+ if (numChars > (unsigned int)LIMIT)
+ return -1;
+ int n = (int)numChars;
+
+ int result = -2;
+ if (mode == qrcodegen_Mode_NUMERIC) {
+ // n * 3 + ceil(n / 3)
+ if (n > LIMIT / 3)
+ goto overflow;
+ result = n * 3;
+ int temp = n / 3 + (n % 3 == 0 ? 0 : 1);
+ if (temp > LIMIT - result)
+ goto overflow;
+ result += temp;
+ } else if (mode == qrcodegen_Mode_ALPHANUMERIC) {
+ // n * 5 + ceil(n / 2)
+ if (n > LIMIT / 5)
+ goto overflow;
+ result = n * 5;
+ int temp = n / 2 + n % 2;
+ if (temp > LIMIT - result)
+ goto overflow;
+ result += temp;
+ } else if (mode == qrcodegen_Mode_BYTE) {
+ if (n > LIMIT / 8)
+ goto overflow;
+ result = n * 8;
+ } else if (mode == qrcodegen_Mode_KANJI) {
+ if (n > LIMIT / 13)
+ goto overflow;
+ result = n * 13;
+ } else if (mode == qrcodegen_Mode_ECI && numChars == 0)
+ result = 3 * 8;
+ assert(0 <= result && result <= LIMIT);
+ return result;
+overflow:
+ return -1;
+}
+
+
+// Public function - see documentation comment in header file.
+struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]) {
+ assert(data != NULL || len == 0);
+ struct qrcodegen_Segment result;
+ result.mode = qrcodegen_Mode_BYTE;
+ result.bitLength = calcSegmentBitLength(result.mode, len);
+ assert(result.bitLength != -1);
+ result.numChars = (int)len;
+ if (len > 0)
+ memcpy(buf, data, len * sizeof(buf[0]));
+ result.data = buf;
+ return result;
+}
+
+
+// Public function - see documentation comment in header file.
+struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]) {
+ assert(digits != NULL);
+ struct qrcodegen_Segment result;
+ size_t len = strlen(digits);
+ result.mode = qrcodegen_Mode_NUMERIC;
+ int bitLen = calcSegmentBitLength(result.mode, len);
+ assert(bitLen != -1);
+ result.numChars = (int)len;
+ if (bitLen > 0)
+ memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0]));
+ result.bitLength = 0;
+
+ unsigned int accumData = 0;
+ int accumCount = 0;
+ for (; *digits != '\0'; digits++) {
+ char c = *digits;
+ assert('0' <= c && c <= '9');
+ accumData = accumData * 10 + (c - '0');
+ accumCount++;
+ if (accumCount == 3) {
+ appendBitsToBuffer(accumData, 10, buf, &result.bitLength);
+ accumData = 0;
+ accumCount = 0;
+ }
+ }
+ if (accumCount > 0) // 1 or 2 digits remaining
+ appendBitsToBuffer(accumData, accumCount * 3 + 1, buf, &result.bitLength);
+ assert(result.bitLength == bitLen);
+ result.data = buf;
+ return result;
+}
+
+
+// Public function - see documentation comment in header file.
+struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]) {
+ assert(text != NULL);
+ struct qrcodegen_Segment result;
+ size_t len = strlen(text);
+ result.mode = qrcodegen_Mode_ALPHANUMERIC;
+ int bitLen = calcSegmentBitLength(result.mode, len);
+ assert(bitLen != -1);
+ result.numChars = (int)len;
+ if (bitLen > 0)
+ memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0]));
+ result.bitLength = 0;
+
+ unsigned int accumData = 0;
+ int accumCount = 0;
+ for (; *text != '\0'; text++) {
+ const char *temp = strchr(ALPHANUMERIC_CHARSET, *text);
+ assert(temp != NULL);
+ accumData = accumData * 45 + (temp - ALPHANUMERIC_CHARSET);
+ accumCount++;
+ if (accumCount == 2) {
+ appendBitsToBuffer(accumData, 11, buf, &result.bitLength);
+ accumData = 0;
+ accumCount = 0;
+ }
+ }
+ if (accumCount > 0) // 1 character remaining
+ appendBitsToBuffer(accumData, 6, buf, &result.bitLength);
+ assert(result.bitLength == bitLen);
+ result.data = buf;
+ return result;
+}
+
+
+// Public function - see documentation comment in header file.
+struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) {
+ struct qrcodegen_Segment result;
+ result.mode = qrcodegen_Mode_ECI;
+ result.numChars = 0;
+ result.bitLength = 0;
+ if (0 <= assignVal && assignVal < (1 << 7)) {
+ memset(buf, 0, 1 * sizeof(buf[0]));
+ appendBitsToBuffer(assignVal, 8, buf, &result.bitLength);
+ } else if ((1 << 7) <= assignVal && assignVal < (1 << 14)) {
+ memset(buf, 0, 2 * sizeof(buf[0]));
+ appendBitsToBuffer(2, 2, buf, &result.bitLength);
+ appendBitsToBuffer(assignVal, 14, buf, &result.bitLength);
+ } else if ((1 << 14) <= assignVal && assignVal < 1000000L) {
+ memset(buf, 0, 3 * sizeof(buf[0]));
+ appendBitsToBuffer(6, 3, buf, &result.bitLength);
+ appendBitsToBuffer(assignVal >> 10, 11, buf, &result.bitLength);
+ appendBitsToBuffer(assignVal & 0x3FF, 10, buf, &result.bitLength);
+ } else
+ assert(false);
+ result.data = buf;
+ return result;
+}
+
+
+// Public function - see documentation comment in header file.
+bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len,
+ enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]) {
+ return qrcodegen_encodeSegmentsAdvanced(segs, len, ecl,
+ qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, -1, true, tempBuffer, qrcode);
+}
+
+
+// Public function - see documentation comment in header file.
+bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl,
+ int minVersion, int maxVersion, int mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]) {
+ assert(segs != NULL || len == 0);
+ assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX);
+ assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7);
+
+ // Find the minimal version number to use
+ int version, dataUsedBits;
+ for (version = minVersion; ; version++) {
+ int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
+ dataUsedBits = getTotalBits(segs, len, version);
+ if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
+ break; // This version number is found to be suitable
+ if (version >= maxVersion) { // All versions in the range could not fit the given data
+ qrcode[0] = 0; // Set size to invalid value for safety
+ return false;
+ }
+ }
+ assert(dataUsedBits != -1);
+
+ // Increase the error correction level while the data still fits in the current version number
+ for (int i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) {
+ if (boostEcl && dataUsedBits <= getNumDataCodewords(version, (enum qrcodegen_Ecc)i) * 8)
+ ecl = (enum qrcodegen_Ecc)i;
+ }
+
+ // Create the data bit string by concatenating all segments
+ int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
+ memset(qrcode, 0, qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
+ int bitLen = 0;
+ for (size_t i = 0; i < len; i++) {
+ const struct qrcodegen_Segment *seg = &segs[i];
+ unsigned int modeBits = 0; // Dummy value
+ switch (seg->mode) {
+ case qrcodegen_Mode_NUMERIC : modeBits = 0x1; break;
+ case qrcodegen_Mode_ALPHANUMERIC: modeBits = 0x2; break;
+ case qrcodegen_Mode_BYTE : modeBits = 0x4; break;
+ case qrcodegen_Mode_KANJI : modeBits = 0x8; break;
+ case qrcodegen_Mode_ECI : modeBits = 0x7; break;
+ default: assert(false);
+ }
+ appendBitsToBuffer(modeBits, 4, qrcode, &bitLen);
+ appendBitsToBuffer(seg->numChars, numCharCountBits(seg->mode, version), qrcode, &bitLen);
+ for (int j = 0; j < seg->bitLength; j++)
+ appendBitsToBuffer((seg->data[j >> 3] >> (7 - (j & 7))) & 1, 1, qrcode, &bitLen);
+ }
+
+ // Add terminator and pad up to a byte if applicable
+ int terminatorBits = dataCapacityBits - bitLen;
+ if (terminatorBits > 4)
+ terminatorBits = 4;
+ appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen);
+ appendBitsToBuffer(0, (8 - bitLen % 8) % 8, qrcode, &bitLen);
+
+ // Pad with alternate bytes until data capacity is reached
+ for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
+ appendBitsToBuffer(padByte, 8, qrcode, &bitLen);
+ assert(bitLen % 8 == 0);
+
+ // Draw function and data codeword modules
+ appendErrorCorrection(qrcode, version, ecl, tempBuffer);
+ initializeFunctionModules(version, qrcode);
+ drawCodewords(tempBuffer, getNumRawDataModules(version) / 8, qrcode);
+ drawWhiteFunctionModules(qrcode, version);
+ initializeFunctionModules(version, tempBuffer);
+
+ // Handle masking
+ if (mask == qrcodegen_Mask_AUTO) { // Automatically choose best mask
+ long minPenalty = LONG_MAX;
+ for (int i = 0; i < 8; i++) {
+ drawFormatBits(ecl, (enum qrcodegen_Mask)i, qrcode);
+ applyMask(tempBuffer, qrcode, (enum qrcodegen_Mask)i);
+ long penalty = getPenaltyScore(qrcode);
+ if (penalty < minPenalty) {
+ mask = (enum qrcodegen_Mask)i;
+ minPenalty = penalty;
+ }
+ applyMask(tempBuffer, qrcode, (enum qrcodegen_Mask)i); // Undoes the mask due to XOR
+ }
+ }
+ assert(0 <= (int)mask && (int)mask <= 7);
+ drawFormatBits(ecl, mask, qrcode);
+ applyMask(tempBuffer, qrcode, mask);
+ return true;
+}
+
+
+// Returns the number of bits needed to encode the given list of segments at the given version.
+// The result is in the range [0, 32767] if successful. Otherwise, -1 is returned if any segment
+// has more characters than allowed by that segment's mode's character count field at the version,
+// or if the actual answer exceeds INT16_MAX.
+testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version) {
+ assert(segs != NULL || len == 0);
+ assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
+ int result = 0;
+ for (size_t i = 0; i < len; i++) {
+ int numChars = segs[i].numChars;
+ int bitLength = segs[i].bitLength;
+ assert(0 <= numChars && numChars <= INT16_MAX);
+ assert(0 <= bitLength && bitLength <= INT16_MAX);
+ int ccbits = numCharCountBits(segs[i].mode, version);
+ assert(0 <= ccbits && ccbits <= 16);
+ // Fail if segment length value doesn't fit in the length field's bit-width
+ if (numChars >= (1L << ccbits))
+ return -1;
+ long temp = 4L + ccbits + bitLength;
+ if (temp > INT16_MAX - result)
+ return -1;
+ result += temp;
+ }
+ assert(0 <= result && result <= INT16_MAX);
+ return result;
+}
+
+
+// Returns the bit width of the segment character count field for the
+// given mode at the given version number. The result is in the range [0, 16].
+static int numCharCountBits(enum qrcodegen_Mode mode, int version) {
+ assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
+ int i = -1; // Dummy value
+ if ( 1 <= version && version <= 9) i = 0;
+ else if (10 <= version && version <= 26) i = 1;
+ else if (27 <= version && version <= 40) i = 2;
+ else assert(false);
+
+ switch (mode) {
+ case qrcodegen_Mode_NUMERIC : { static const int temp[] = {10, 12, 14}; return temp[i]; }
+ case qrcodegen_Mode_ALPHANUMERIC: { static const int temp[] = { 9, 11, 13}; return temp[i]; }
+ case qrcodegen_Mode_BYTE : { static const int temp[] = { 8, 16, 16}; return temp[i]; }
+ case qrcodegen_Mode_KANJI : { static const int temp[] = { 8, 10, 12}; return temp[i]; }
+ case qrcodegen_Mode_ECI : return 0;
+ default: assert(false);
+ }
+ return -1; // Dummy value
+}
diff --git a/src/third_party/QR-Code-generator/c/qrcodegen.h b/src/third_party/QR-Code-generator/c/qrcodegen.h
new file mode 100644
index 0000000..899feae
--- /dev/null
+++ b/src/third_party/QR-Code-generator/c/qrcodegen.h
@@ -0,0 +1,267 @@
+/*
+ * QR Code generator library (C)
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+
+/*---- Enum and struct types----*/
+
+/*
+ * The error correction level used in a QR Code symbol.
+ */
+enum qrcodegen_Ecc {
+ qrcodegen_Ecc_LOW = 0,
+ qrcodegen_Ecc_MEDIUM,
+ qrcodegen_Ecc_QUARTILE,
+ qrcodegen_Ecc_HIGH,
+};
+
+
+/*
+ * The mask pattern used in a QR Code symbol.
+ */
+enum qrcodegen_Mask {
+ // A special value to tell the QR Code encoder to
+ // automatically select an appropriate mask pattern
+ qrcodegen_Mask_AUTO = -1,
+ // The eight actual mask patterns
+ qrcodegen_Mask_0 = 0,
+ qrcodegen_Mask_1,
+ qrcodegen_Mask_2,
+ qrcodegen_Mask_3,
+ qrcodegen_Mask_4,
+ qrcodegen_Mask_5,
+ qrcodegen_Mask_6,
+ qrcodegen_Mask_7,
+};
+
+
+/*
+ * The mode field of a segment.
+ */
+enum qrcodegen_Mode {
+ qrcodegen_Mode_NUMERIC,
+ qrcodegen_Mode_ALPHANUMERIC,
+ qrcodegen_Mode_BYTE,
+ qrcodegen_Mode_KANJI,
+ qrcodegen_Mode_ECI,
+};
+
+
+/*
+ * A segment of user/application data that a QR Code symbol can convey.
+ * Each segment has a mode, a character count, and character/general data that is
+ * already encoded as a sequence of bits. The maximum allowed bit length is 32767,
+ * because even the largest QR Code (version 40) has only 31329 modules.
+ */
+struct qrcodegen_Segment {
+ // The mode indicator for this segment.
+ enum qrcodegen_Mode mode;
+
+ // The length of this segment's unencoded data. Always in the range [0, 32767].
+ // For numeric, alphanumeric, and kanji modes, this measures in Unicode code points.
+ // For byte mode, this measures in bytes (raw binary data, text in UTF-8, or other encodings).
+ // For ECI mode, this is always zero.
+ int numChars;
+
+ // The data bits of this segment, packed in bitwise big endian.
+ // Can be null if the bit length is zero.
+ uint8_t *data;
+
+ // The number of valid data bits used in the buffer. Requires
+ // 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8.
+ int bitLength;
+};
+
+
+
+/*---- Macro constants and functions ----*/
+
+// The minimum and maximum defined QR Code version numbers for Model 2.
+#define qrcodegen_VERSION_MIN 1
+#define qrcodegen_VERSION_MAX 40
+
+// Calculates the number of bytes needed to store any QR Code up to and including the given version number,
+// as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];'
+// can store any single QR Code from version 1 to 25, inclusive.
+// Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX.
+#define qrcodegen_BUFFER_LEN_FOR_VERSION(n) ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1)
+
+// The worst-case number of bytes needed to store one QR Code, up to and including
+// version 40. This value equals 3918, which is just under 4 kilobytes.
+// Use this more convenient value to avoid calculating tighter memory bounds for buffers.
+#define qrcodegen_BUFFER_LEN_MAX qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX)
+
+
+
+/*---- Functions to generate QR Codes ----*/
+
+/*
+ * Encodes the given text string to a QR Code symbol, returning true if encoding succeeded.
+ * If the data is too long to fit in any version in the given range
+ * at the given ECC level, then false is returned.
+ * - The input text must be encoded in UTF-8 and contain no NULs.
+ * - The variables ecl and mask must correspond to enum constant values.
+ * - Requires 1 <= minVersion <= maxVersion <= 40.
+ * - The arrays tempBuffer and qrcode must each have a length
+ * of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).
+ * - 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.
+ * - 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.
+ */
+bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[],
+ enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl);
+
+
+/*
+ * Encodes the given binary data to a QR Code symbol, returning true if encoding succeeded.
+ * If the data is too long to fit in any version in the given range
+ * at the given ECC level, then false is returned.
+ * - The input array range dataAndTemp[0 : dataLen] should normally be
+ * valid UTF-8 text, but is not required by the QR Code standard.
+ * - The variables ecl and mask must correspond to enum constant values.
+ * - Requires 1 <= minVersion <= maxVersion <= 40.
+ * - The arrays dataAndTemp and qrcode must each have a length
+ * of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).
+ * - 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.
+ * - 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.
+ */
+bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[],
+ enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl);
+
+
+/*
+ * Tests whether the given string can be encoded as a segment in alphanumeric mode.
+ */
+bool qrcodegen_isAlphanumeric(const char *text);
+
+
+/*
+ * Tests whether the given string can be encoded as a segment in numeric mode.
+ */
+bool qrcodegen_isNumeric(const char *text);
+
+
+/*
+ * Returns the number of bytes (uint8_t) needed for the data buffer of a segment
+ * containing the given number of characters using the given mode. Notes:
+ * - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or
+ * the number of needed bits exceeds INT16_MAX (i.e. 32767).
+ * - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096.
+ * - 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.
+ */
+size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars);
+
+
+/*
+ * Returns a segment representing the given binary data encoded in byte mode.
+ */
+struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]);
+
+
+/*
+ * Returns a segment representing the given string of decimal digits encoded in numeric mode.
+ */
+struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]);
+
+
+/*
+ * 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.
+ */
+struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]);
+
+
+/*
+ * Returns a segment representing an Extended Channel Interpretation
+ * (ECI) designator with the given assignment value.
+ */
+struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]);
+
+
+/*
+ * Renders a QR Code symbol representing the given data segments at the given error correction
+ * level or higher. The smallest possible QR Code version is automatically chosen for the output.
+ * Returns true if QR Code creation succeeded, or false if the data is too long to fit in any version.
+ * This function allows the user to create a custom sequence of segments that switches
+ * between modes (such as alphanumeric and binary) to encode text more efficiently.
+ * This function is considered to be lower level than simply encoding text or binary data.
+ * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will
+ * result in them being clobbered, but the QR Code output will still be correct.
+ * But the qrcode array must not overlap tempBuffer or any segment's data buffer.
+ */
+bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len,
+ enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]);
+
+
+/*
+ * Renders a QR Code symbol representing the given data segments with the given encoding parameters.
+ * Returns true if QR Code creation succeeded, or false if the data is too long to fit in the range of versions.
+ * The smallest possible QR Code version within the given range is automatically chosen for the output.
+ * This function allows the user to create a custom sequence of segments that switches
+ * between modes (such as alphanumeric and binary) to encode text more efficiently.
+ * This function is considered to be lower level than simply encoding text or binary data.
+ * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will
+ * result in them being clobbered, but the QR Code output will still be correct.
+ * But the qrcode array must not overlap tempBuffer or any segment's data buffer.
+ */
+bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl,
+ int minVersion, int maxVersion, int mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]);
+
+
+/*---- Functions to extract raw data from QR Codes ----*/
+
+/*
+ * Returns the side length of the given QR Code, assuming that encoding succeeded.
+ * The result is in the range [21, 177]. Note that the length of the array buffer
+ * is related to the side length - every 'uint8_t qrcode[]' must have length at least
+ * qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1).
+ */
+int qrcodegen_getSize(const uint8_t qrcode[]);
+
+
+/*
+ * Returns the color of the module (pixel) at the given coordinates, which is either
+ * false for white or true for black. The top left corner has the coordinates (x=0, y=0).
+ * If the given coordinates are out of bounds, then false (white) is returned.
+ */
+bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y);
diff --git a/src/third_party/QR-Code-generator/cpp/BitBuffer.cpp b/src/third_party/QR-Code-generator/cpp/BitBuffer.cpp
new file mode 100644
index 0000000..d6e8cb2
--- /dev/null
+++ b/src/third_party/QR-Code-generator/cpp/BitBuffer.cpp
@@ -0,0 +1,48 @@
+/*
+ * QR Code generator library (C++)
+ *
+ * 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.
+ */
+
+#include "BitBuffer.hpp"
+
+
+namespace qrcodegen {
+
+BitBuffer::BitBuffer()
+ : std::vector<bool>() {}
+
+
+std::vector<std::uint8_t> BitBuffer::getBytes() const {
+ std::vector<std::uint8_t> result(size() / 8 + (size() % 8 == 0 ? 0 : 1));
+ for (std::size_t i = 0; i < size(); i++)
+ result[i >> 3] |= (*this)[i] ? 1 << (7 - (i & 7)) : 0;
+ return result;
+}
+
+
+void BitBuffer::appendBits(std::uint32_t val, int len) {
+ if (len < 0 || len > 31 || val >> len != 0)
+ throw "Value out of range";
+ for (int i = len - 1; i >= 0; i--) // Append bit by bit
+ this->push_back(((val >> i) & 1) != 0);
+}
+
+}
diff --git a/src/third_party/QR-Code-generator/cpp/BitBuffer.hpp b/src/third_party/QR-Code-generator/cpp/BitBuffer.hpp
new file mode 100644
index 0000000..be00ee4
--- /dev/null
+++ b/src/third_party/QR-Code-generator/cpp/BitBuffer.hpp
@@ -0,0 +1,57 @@
+/*
+ * QR Code generator library (C++)
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+
+namespace qrcodegen {
+
+/*
+ * An appendable sequence of bits (0's and 1's).
+ */
+class BitBuffer final : public std::vector<bool> {
+
+ /*---- Constructor ----*/
+
+ // Creates an empty bit buffer (length 0).
+ public: BitBuffer();
+
+
+
+ /*---- Methods ----*/
+
+ // Packs this buffer's bits into bytes in big endian,
+ // padding with '0' bit values, and returns the new vector.
+ public: std::vector<std::uint8_t> getBytes() const;
+
+
+ // Appends the given number of low bits of the given value
+ // to this sequence. Requires 0 <= val < 2^len.
+ public: void appendBits(std::uint32_t val, int len);
+
+};
+
+}
diff --git a/src/third_party/QR-Code-generator/cpp/Makefile b/src/third_party/QR-Code-generator/cpp/Makefile
new file mode 100644
index 0000000..151a4da
--- /dev/null
+++ b/src/third_party/QR-Code-generator/cpp/Makefile
@@ -0,0 +1,66 @@
+#
+# Makefile for QR Code generator (C++)
+#
+# 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.
+#
+
+
+# ---- Configuration options ----
+
+# External/implicit variables:
+# - CXX: The C++ compiler, such as g++ or clang++.
+# - CXXFLAGS: Any extra user-specified compiler flags (can be blank).
+
+# Mandatory compiler flags
+CXXFLAGS += -std=c++11
+# Diagnostics. Adding '-fsanitize=address' is helpful for most versions of Clang and newer versions of GCC.
+CXXFLAGS += -Wall -fsanitize=undefined
+# Optimization level
+CXXFLAGS += -O1
+
+
+# ---- Controlling make ----
+
+# Clear default suffix rules
+.SUFFIXES:
+
+# Don't delete object files
+.SECONDARY:
+
+# Stuff concerning goals
+.DEFAULT_GOAL = all
+.PHONY: all clean
+
+
+# ---- Targets to build ----
+
+LIBSRC = BitBuffer QrCode QrSegment
+MAINS = QrCodeGeneratorDemo QrCodeGeneratorWorker
+
+# Build all binaries
+all: $(MAINS)
+
+# Delete build output
+clean:
+ rm -f -- $(MAINS)
+
+# Executable files
+%: %.cpp $(LIBSRC:=.cpp) $(LIBSRC:=.hpp)
+ $(CXX) $(CXXFLAGS) -o $@ $< $(LIBSRC:=.cpp)
diff --git a/src/third_party/QR-Code-generator/cpp/QrCode.cpp b/src/third_party/QR-Code-generator/cpp/QrCode.cpp
new file mode 100644
index 0000000..75a5473
--- /dev/null
+++ b/src/third_party/QR-Code-generator/cpp/QrCode.cpp
@@ -0,0 +1,616 @@
+/*
+ * QR Code generator library (C++)
+ *
+ * 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.
+ */
+
+#include <algorithm>
+#include <climits>
+#include <cstddef>
+#include <cstdlib>
+#include <sstream>
+#include <utility>
+#include "BitBuffer.hpp"
+#include "QrCode.hpp"
+
+using std::int8_t;
+using std::uint8_t;
+using std::size_t;
+using std::vector;
+
+
+namespace qrcodegen {
+
+int QrCode::getFormatBits(Ecc ecl) {
+ switch (ecl) {
+ case Ecc::LOW : return 1;
+ case Ecc::MEDIUM : return 0;
+ case Ecc::QUARTILE: return 3;
+ case Ecc::HIGH : return 2;
+ default: throw "Assertion error";
+ }
+}
+
+
+QrCode QrCode::encodeText(const char *text, Ecc ecl) {
+ vector<QrSegment> segs = QrSegment::makeSegments(text);
+ return encodeSegments(segs, ecl);
+}
+
+
+QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) {
+ vector<QrSegment> segs{QrSegment::makeBytes(data)};
+ return encodeSegments(segs, ecl);
+}
+
+
+QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
+ int minVersion, int maxVersion, int mask, bool boostEcl) {
+ if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
+ throw "Invalid value";
+
+ // Find the minimal version number to use
+ int version, dataUsedBits;
+ for (version = minVersion; ; version++) {
+ int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
+ dataUsedBits = QrSegment::getTotalBits(segs, version);
+ if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
+ break; // This version number is found to be suitable
+ if (version >= maxVersion) // All versions in the range could not fit the given data
+ throw "Data too long";
+ }
+ if (dataUsedBits == -1)
+ throw "Assertion error";
+
+ // Increase the error correction level while the data still fits in the current version number
+ for (Ecc newEcl : vector<Ecc>{Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) {
+ if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
+ ecl = newEcl;
+ }
+
+ // Create the data bit string by concatenating all segments
+ size_t dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
+ BitBuffer bb;
+ for (const QrSegment &seg : segs) {
+ bb.appendBits(seg.getMode().getModeBits(), 4);
+ bb.appendBits(seg.getNumChars(), seg.getMode().numCharCountBits(version));
+ bb.insert(bb.end(), seg.getData().begin(), seg.getData().end());
+ }
+
+ // Add terminator and pad up to a byte if applicable
+ bb.appendBits(0, std::min<size_t>(4, dataCapacityBits - bb.size()));
+ bb.appendBits(0, (8 - bb.size() % 8) % 8);
+
+ // Pad with alternate bytes until data capacity is reached
+ for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
+ bb.appendBits(padByte, 8);
+ if (bb.size() % 8 != 0)
+ throw "Assertion error";
+
+ // Create the QR Code symbol
+ return QrCode(version, ecl, bb.getBytes(), mask);
+}
+
+
+QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int mask) :
+ // Initialize fields
+ version(ver),
+ size(MIN_VERSION <= ver && ver <= MAX_VERSION ? ver * 4 + 17 : -1), // Avoid signed overflow undefined behavior
+ errorCorrectionLevel(ecl),
+ modules(size, vector<bool>(size)), // Entirely white grid
+ isFunction(size, vector<bool>(size)) {
+
+ // Check arguments
+ if (ver < MIN_VERSION || ver > MAX_VERSION || mask < -1 || mask > 7)
+ throw "Value out of range";
+
+ // Draw function patterns, draw all codewords, do masking
+ drawFunctionPatterns();
+ const vector<uint8_t> allCodewords = appendErrorCorrection(dataCodewords);
+ drawCodewords(allCodewords);
+ this->mask = handleConstructorMasking(mask);
+}
+
+
+int QrCode::getVersion() const {
+ return version;
+}
+
+
+int QrCode::getSize() const {
+ return size;
+}
+
+
+QrCode::Ecc QrCode::getErrorCorrectionLevel() const {
+ return errorCorrectionLevel;
+}
+
+
+int QrCode::getMask() const {
+ return mask;
+}
+
+
+bool QrCode::getModule(int x, int y) const {
+ return 0 <= x && x < size && 0 <= y && y < size && module(x, y);
+}
+
+
+std::string QrCode::toSvgString(int border) const {
+ if (border < 0)
+ throw "Border must be non-negative";
+ if (border > INT_MAX / 2 || border * 2 > INT_MAX - size)
+ throw "Border too large";
+
+ std::ostringstream sb;
+ sb << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ sb << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
+ sb << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 ";
+ sb << (size + border * 2) << " " << (size + border * 2) << "\" stroke=\"none\">\n";
+ sb << "\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n";
+ sb << "\t<path d=\"";
+ bool head = true;
+ for (int y = -border; y < size + border; y++) {
+ for (int x = -border; x < size + border; x++) {
+ if (getModule(x, y)) {
+ if (head)
+ head = false;
+ else
+ sb << " ";
+ sb << "M" << (x + border) << "," << (y + border) << "h1v1h-1z";
+ }
+ }
+ }
+ sb << "\" fill=\"#000000\"/>\n";
+ sb << "</svg>\n";
+ return sb.str();
+}
+
+
+void QrCode::drawFunctionPatterns() {
+ // Draw horizontal and vertical timing patterns
+ for (int i = 0; i < size; i++) {
+ setFunctionModule(6, i, i % 2 == 0);
+ setFunctionModule(i, 6, i % 2 == 0);
+ }
+
+ // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
+ drawFinderPattern(3, 3);
+ drawFinderPattern(size - 4, 3);
+ drawFinderPattern(3, size - 4);
+
+ // Draw numerous alignment patterns
+ const vector<int> alignPatPos = getAlignmentPatternPositions(version);
+ int numAlign = alignPatPos.size();
+ for (int i = 0; i < numAlign; i++) {
+ for (int j = 0; j < numAlign; j++) {
+ if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))
+ continue; // Skip the three finder corners
+ else
+ drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j));
+ }
+ }
+
+ // Draw configuration data
+ drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
+ drawVersion();
+}
+
+
+void QrCode::drawFormatBits(int mask) {
+ // Calculate error correction code and pack bits
+ int data = getFormatBits(errorCorrectionLevel) << 3 | mask; // errCorrLvl is uint2, mask is uint3
+ int rem = data;
+ for (int i = 0; i < 10; i++)
+ rem = (rem << 1) ^ ((rem >> 9) * 0x537);
+ data = data << 10 | rem;
+ data ^= 0x5412; // uint15
+ if (data >> 15 != 0)
+ throw "Assertion error";
+
+ // Draw first copy
+ for (int i = 0; i <= 5; i++)
+ setFunctionModule(8, i, ((data >> i) & 1) != 0);
+ setFunctionModule(8, 7, ((data >> 6) & 1) != 0);
+ setFunctionModule(8, 8, ((data >> 7) & 1) != 0);
+ setFunctionModule(7, 8, ((data >> 8) & 1) != 0);
+ for (int i = 9; i < 15; i++)
+ setFunctionModule(14 - i, 8, ((data >> i) & 1) != 0);
+
+ // Draw second copy
+ for (int i = 0; i <= 7; i++)
+ setFunctionModule(size - 1 - i, 8, ((data >> i) & 1) != 0);
+ for (int i = 8; i < 15; i++)
+ setFunctionModule(8, size - 15 + i, ((data >> i) & 1) != 0);
+ setFunctionModule(8, size - 8, true);
+}
+
+
+void QrCode::drawVersion() {
+ if (version < 7)
+ return;
+
+ // Calculate error correction code and pack bits
+ int rem = version; // version is uint6, in the range [7, 40]
+ for (int i = 0; i < 12; i++)
+ rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
+ long data = (long)version << 12 | rem; // uint18
+ if (data >> 18 != 0)
+ throw "Assertion error";
+
+ // Draw two copies
+ for (int i = 0; i < 18; i++) {
+ bool bit = ((data >> i) & 1) != 0;
+ int a = size - 11 + i % 3, b = i / 3;
+ setFunctionModule(a, b, bit);
+ setFunctionModule(b, a, bit);
+ }
+}
+
+
+void QrCode::drawFinderPattern(int x, int y) {
+ for (int i = -4; i <= 4; i++) {
+ for (int j = -4; j <= 4; j++) {
+ int dist = std::max(std::abs(i), std::abs(j)); // Chebyshev/infinity norm
+ int xx = x + j, yy = y + i;
+ if (0 <= xx && xx < size && 0 <= yy && yy < size)
+ setFunctionModule(xx, yy, dist != 2 && dist != 4);
+ }
+ }
+}
+
+
+void QrCode::drawAlignmentPattern(int x, int y) {
+ for (int i = -2; i <= 2; i++) {
+ for (int j = -2; j <= 2; j++)
+ setFunctionModule(x + j, y + i, std::max(std::abs(i), std::abs(j)) != 1);
+ }
+}
+
+
+void QrCode::setFunctionModule(int x, int y, bool isBlack) {
+ modules.at(y).at(x) = isBlack;
+ isFunction.at(y).at(x) = true;
+}
+
+
+bool QrCode::module(int x, int y) const {
+ return modules.at(y).at(x);
+}
+
+
+vector<uint8_t> QrCode::appendErrorCorrection(const vector<uint8_t> &data) const {
+ if (data.size() != static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel)))
+ throw "Invalid argument";
+
+ // Calculate parameter numbers
+ int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(errorCorrectionLevel)][version];
+ int blockEccLen = ECC_CODEWORDS_PER_BLOCK[static_cast<int>(errorCorrectionLevel)][version];
+ int rawCodewords = getNumRawDataModules(version) / 8;
+ int numShortBlocks = numBlocks - rawCodewords % numBlocks;
+ int shortBlockLen = rawCodewords / numBlocks;
+
+ // Split data into blocks and append ECC to each block
+ vector<vector<uint8_t> > blocks;
+ const ReedSolomonGenerator rs(blockEccLen);
+ for (int i = 0, k = 0; i < numBlocks; i++) {
+ vector<uint8_t> dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
+ k += dat.size();
+ const vector<uint8_t> ecc = rs.getRemainder(dat);
+ if (i < numShortBlocks)
+ dat.push_back(0);
+ dat.insert(dat.end(), ecc.cbegin(), ecc.cend());
+ blocks.push_back(std::move(dat));
+ }
+
+ // Interleave (not concatenate) the bytes from every block into a single sequence
+ vector<uint8_t> result;
+ for (int i = 0; static_cast<unsigned int>(i) < blocks.at(0).size(); i++) {
+ for (int j = 0; static_cast<unsigned int>(j) < blocks.size(); j++) {
+ // Skip the padding byte in short blocks
+ if (i != shortBlockLen - blockEccLen || j >= numShortBlocks)
+ result.push_back(blocks.at(j).at(i));
+ }
+ }
+ if (result.size() != static_cast<unsigned int>(rawCodewords))
+ throw "Assertion error";
+ return result;
+}
+
+
+void QrCode::drawCodewords(const vector<uint8_t> &data) {
+ if (data.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8))
+ throw "Invalid argument";
+
+ size_t i = 0; // Bit index into the data
+ // Do the funny zigzag scan
+ for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
+ if (right == 6)
+ right = 5;
+ for (int vert = 0; vert < size; vert++) { // Vertical counter
+ for (int j = 0; j < 2; j++) {
+ int x = right - j; // Actual x coordinate
+ bool upward = ((right + 1) & 2) == 0;
+ int y = upward ? size - 1 - vert : vert; // Actual y coordinate
+ if (!isFunction.at(y).at(x) && i < data.size() * 8) {
+ modules.at(y).at(x) = ((data.at(i >> 3) >> (7 - (i & 7))) & 1) != 0;
+ i++;
+ }
+ // If there are any remainder bits (0 to 7), they are already
+ // set to 0/false/white when the grid of modules was initialized
+ }
+ }
+ }
+ if (static_cast<unsigned int>(i) != data.size() * 8)
+ throw "Assertion error";
+}
+
+
+void QrCode::applyMask(int mask) {
+ if (mask < 0 || mask > 7)
+ throw "Mask value out of range";
+ for (int y = 0; y < size; y++) {
+ for (int x = 0; x < size; x++) {
+ bool invert;
+ switch (mask) {
+ case 0: invert = (x + y) % 2 == 0; break;
+ case 1: invert = y % 2 == 0; break;
+ case 2: invert = x % 3 == 0; break;
+ case 3: invert = (x + y) % 3 == 0; break;
+ case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
+ case 5: invert = x * y % 2 + x * y % 3 == 0; break;
+ case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
+ case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
+ default: throw "Assertion error";
+ }
+ modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
+ }
+ }
+}
+
+
+int QrCode::handleConstructorMasking(int mask) {
+ if (mask == -1) { // Automatically choose best mask
+ long minPenalty = LONG_MAX;
+ for (int i = 0; i < 8; i++) {
+ drawFormatBits(i);
+ applyMask(i);
+ long penalty = getPenaltyScore();
+ if (penalty < minPenalty) {
+ mask = i;
+ minPenalty = penalty;
+ }
+ applyMask(i); // Undoes the mask due to XOR
+ }
+ }
+ if (mask < 0 || mask > 7)
+ throw "Assertion error";
+ drawFormatBits(mask); // Overwrite old format bits
+ applyMask(mask); // Apply the final choice of mask
+ return mask; // The caller shall assign this value to the final-declared field
+}
+
+
+long QrCode::getPenaltyScore() const {
+ long result = 0;
+
+ // Adjacent modules in row having same color
+ for (int y = 0; y < size; y++) {
+ bool colorX = false;
+ for (int x = 0, runX = -1; x < size; x++) {
+ if (x == 0 || module(x, y) != colorX) {
+ colorX = module(x, y);
+ runX = 1;
+ } else {
+ runX++;
+ if (runX == 5)
+ result += PENALTY_N1;
+ else if (runX > 5)
+ result++;
+ }
+ }
+ }
+ // Adjacent modules in column having same color
+ for (int x = 0; x < size; x++) {
+ bool colorY = false;
+ for (int y = 0, runY = -1; y < size; y++) {
+ if (y == 0 || module(x, y) != colorY) {
+ colorY = module(x, y);
+ runY = 1;
+ } else {
+ runY++;
+ if (runY == 5)
+ result += PENALTY_N1;
+ else if (runY > 5)
+ result++;
+ }
+ }
+ }
+
+ // 2*2 blocks of modules having same color
+ for (int y = 0; y < size - 1; y++) {
+ for (int x = 0; x < size - 1; x++) {
+ bool color = module(x, y);
+ if ( color == module(x + 1, y) &&
+ color == module(x, y + 1) &&
+ color == module(x + 1, y + 1))
+ result += PENALTY_N2;
+ }
+ }
+
+ // Finder-like pattern in rows
+ for (int y = 0; y < size; y++) {
+ for (int x = 0, bits = 0; x < size; x++) {
+ bits = ((bits << 1) & 0x7FF) | (module(x, y) ? 1 : 0);
+ if (x >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
+ result += PENALTY_N3;
+ }
+ }
+ // Finder-like pattern in columns
+ for (int x = 0; x < size; x++) {
+ for (int y = 0, bits = 0; y < size; y++) {
+ bits = ((bits << 1) & 0x7FF) | (module(x, y) ? 1 : 0);
+ if (y >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
+ result += PENALTY_N3;
+ }
+ }
+
+ // Balance of black and white modules
+ int black = 0;
+ for (const vector<bool> &row : modules) {
+ for (bool color : row) {
+ if (color)
+ black++;
+ }
+ }
+ int total = size * size;
+ // Find smallest k such that (45-5k)% <= dark/total <= (55+5k)%
+ for (int k = 0; black*20L < (9L-k)*total || black*20L > (11L+k)*total; k++)
+ result += PENALTY_N4;
+ return result;
+}
+
+
+vector<int> QrCode::getAlignmentPatternPositions(int ver) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw "Version number out of range";
+ else if (ver == 1)
+ return vector<int>();
+ else {
+ int numAlign = ver / 7 + 2;
+ int step;
+ if (ver != 32) {
+ // ceil((size - 13) / (2*numAlign - 2)) * 2
+ step = (ver * 4 + numAlign * 2 + 1) / (2 * numAlign - 2) * 2;
+ } else // C-C-C-Combo breaker!
+ step = 26;
+
+ vector<int> result;
+ for (int i = 0, pos = ver * 4 + 10; i < numAlign - 1; i++, pos -= step)
+ result.insert(result.begin(), pos);
+ result.insert(result.begin(), 6);
+ return result;
+ }
+}
+
+
+int QrCode::getNumRawDataModules(int ver) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw "Version number out of range";
+ int result = (16 * ver + 128) * ver + 64;
+ if (ver >= 2) {
+ int numAlign = ver / 7 + 2;
+ result -= (25 * numAlign - 10) * numAlign - 55;
+ if (ver >= 7)
+ result -= 18 * 2; // Subtract version information
+ }
+ return result;
+}
+
+
+int QrCode::getNumDataCodewords(int ver, Ecc ecl) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw "Version number out of range";
+ return getNumRawDataModules(ver) / 8
+ - ECC_CODEWORDS_PER_BLOCK[static_cast<int>(ecl)][ver]
+ * NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(ecl)][ver];
+}
+
+
+/*---- Tables of constants ----*/
+
+const int QrCode::PENALTY_N1 = 3;
+const int QrCode::PENALTY_N2 = 3;
+const int QrCode::PENALTY_N3 = 40;
+const int QrCode::PENALTY_N4 = 10;
+
+
+const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = {
+ // 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
+};
+
+const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
+ // 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
+};
+
+
+QrCode::ReedSolomonGenerator::ReedSolomonGenerator(int degree) :
+ coefficients() {
+ if (degree < 1 || degree > 255)
+ throw "Degree out of range";
+
+ // Start with the monomial x^0
+ coefficients.resize(degree);
+ coefficients.at(degree - 1) = 1;
+
+ // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
+ // drop the highest term, and store the rest of the coefficients in order of descending powers.
+ // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
+ uint8_t root = 1;
+ for (int i = 0; i < degree; i++) {
+ // Multiply the current product by (x - r^i)
+ for (size_t j = 0; j < coefficients.size(); j++) {
+ coefficients.at(j) = multiply(coefficients.at(j), root);
+ if (j + 1 < coefficients.size())
+ coefficients.at(j) ^= coefficients.at(j + 1);
+ }
+ root = multiply(root, 0x02);
+ }
+}
+
+
+vector<uint8_t> QrCode::ReedSolomonGenerator::getRemainder(const vector<uint8_t> &data) const {
+ // Compute the remainder by performing polynomial division
+ vector<uint8_t> result(coefficients.size());
+ for (uint8_t b : data) {
+ uint8_t factor = b ^ result.at(0);
+ result.erase(result.begin());
+ result.push_back(0);
+ for (size_t j = 0; j < result.size(); j++)
+ result.at(j) ^= multiply(coefficients.at(j), factor);
+ }
+ return result;
+}
+
+
+uint8_t QrCode::ReedSolomonGenerator::multiply(uint8_t x, uint8_t y) {
+ // Russian peasant multiplication
+ int z = 0;
+ for (int i = 7; i >= 0; i--) {
+ z = (z << 1) ^ ((z >> 7) * 0x11D);
+ z ^= ((y >> i) & 1) * x;
+ }
+ if (z >> 8 != 0)
+ throw "Assertion error";
+ return static_cast<uint8_t>(z);
+}
+
+}
diff --git a/src/third_party/QR-Code-generator/cpp/QrCode.hpp b/src/third_party/QR-Code-generator/cpp/QrCode.hpp
new file mode 100644
index 0000000..14a3f61
--- /dev/null
+++ b/src/third_party/QR-Code-generator/cpp/QrCode.hpp
@@ -0,0 +1,306 @@
+/*
+ * QR Code generator library (C++)
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include <vector>
+#include "QrSegment.hpp"
+
+
+namespace qrcodegen {
+
+/*
+ * Represents an immutable square grid of black and white cells for a QR Code symbol, and
+ * provides static functions to create a QR Code from user-supplied textual or binary data.
+ * This class covers the QR Code model 2 specification, supporting all versions (sizes)
+ * from 1 to 40, all 4 error correction levels, and only 3 character encoding modes.
+ */
+class QrCode final {
+
+ /*---- Public helper enumeration ----*/
+
+ /*
+ * Represents the error correction level used in a QR Code symbol.
+ */
+ public: enum class Ecc {
+ // Constants declared in ascending order of error protection.
+ LOW = 0, MEDIUM = 1, QUARTILE = 2, HIGH = 3
+ };
+
+
+ // Returns a value in the range 0 to 3 (unsigned 2-bit integer).
+ private: static int getFormatBits(Ecc ecl);
+
+
+
+ /*---- Public static factory functions ----*/
+
+ /*
+ * Returns a QR Code symbol representing the specified Unicode text string at the specified error correction level.
+ * As a conservative upper bound, this function is guaranteed to succeed for strings that have 2953 or fewer
+ * UTF-8 code units (not Unicode code points) if the low error correction level is used. The smallest possible
+ * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than
+ * the ecl argument if it can be done without increasing the version.
+ */
+ public: static QrCode encodeText(const char *text, Ecc ecl);
+
+
+ /*
+ * Returns a QR Code symbol representing the given binary data string at the given error correction level.
+ * This function always encodes using the binary segment mode, not any text mode. The maximum number of
+ * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
+ * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
+ */
+ public: static QrCode encodeBinary(const std::vector<std::uint8_t> &data, Ecc ecl);
+
+
+ /*
+ * Returns a QR Code symbol representing the given data segments with the given encoding parameters.
+ * The smallest possible QR Code version within the given range is automatically chosen for the output.
+ * This function allows the user to create a custom sequence of segments that switches
+ * between modes (such as alphanumeric and binary) to encode text more efficiently.
+ * This function is considered to be lower level than simply encoding text or binary data.
+ */
+ public: static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl,
+ int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters
+
+
+
+ /*---- Public constants ----*/
+
+ public: static constexpr int MIN_VERSION = 1;
+ public: static constexpr int MAX_VERSION = 40;
+
+
+
+ /*---- Instance fields ----*/
+
+ // Immutable scalar parameters
+
+ /* This QR Code symbol's version number, which is always between 1 and 40 (inclusive). */
+ private: int version;
+
+ /* The width and height of this QR Code symbol, measured in modules.
+ * Always equal to version × 4 + 17, in the range 21 to 177. */
+ private: int size;
+
+ /* The error correction level used in this QR Code symbol. */
+ private: Ecc errorCorrectionLevel;
+
+ /* The mask pattern used in this QR Code symbol, in the range 0 to 7 (i.e. unsigned 3-bit integer).
+ * Note that even if a constructor was called with automatic masking requested
+ * (mask = -1), the resulting object will still have a mask value between 0 and 7. */
+ private: int mask;
+
+ // Private grids of modules/pixels (conceptually immutable)
+ private: std::vector<std::vector<bool> > modules; // The modules of this QR Code symbol (false = white, true = black)
+ private: std::vector<std::vector<bool> > isFunction; // Indicates function modules that are not subjected to masking
+
+
+
+ /*---- Constructors ----*/
+
+ /*
+ * Creates a new QR Code symbol with the given version number, error correction level, binary data array,
+ * and mask number. This is a cumbersome low-level constructor that should not be invoked directly by the user.
+ * To go one level up, see the encodeSegments() function.
+ */
+ public: QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int mask);
+
+
+
+ /*---- Public instance methods ----*/
+
+ public: int getVersion() const;
+
+
+ public: int getSize() const;
+
+
+ public: Ecc getErrorCorrectionLevel() const;
+
+
+ public: int getMask() const;
+
+
+ /*
+ * Returns the color of the module (pixel) at the given coordinates, which is either
+ * false for white or true for black. The top left corner has the coordinates (x=0, y=0).
+ * If the given coordinates are out of bounds, then false (white) is returned.
+ */
+ public: bool getModule(int x, int y) const;
+
+
+ /*
+ * Based on the given number of border modules to add as padding, this returns a
+ * string whose contents represents an SVG XML file that depicts this QR Code symbol.
+ * Note that Unix newlines (\n) are always used, regardless of the platform.
+ */
+ public: std::string toSvgString(int border) const;
+
+
+
+ /*---- Private helper methods for constructor: Drawing function modules ----*/
+
+ private: void drawFunctionPatterns();
+
+
+ // Draws two copies of the format bits (with its own error correction code)
+ // based on the given mask and this object's error correction level field.
+ private: void drawFormatBits(int mask);
+
+
+ // Draws two copies of the version bits (with its own error correction code),
+ // based on this object's version field (which only has an effect for 7 <= version <= 40).
+ private: void drawVersion();
+
+
+ // Draws a 9*9 finder pattern including the border separator, with the center module at (x, y).
+ private: void drawFinderPattern(int x, int y);
+
+
+ // Draws a 5*5 alignment pattern, with the center module at (x, y).
+ private: void drawAlignmentPattern(int x, int y);
+
+
+ // Sets the color of a module and marks it as a function module.
+ // Only used by the constructor. Coordinates must be in range.
+ private: void setFunctionModule(int x, int y, bool isBlack);
+
+
+ // Returns the color of the module at the given coordinates, which must be in range.
+ private: bool module(int x, int y) const;
+
+
+ /*---- Private helper methods for constructor: Codewords and masking ----*/
+
+ // Returns a new byte string representing the given data with the appropriate error correction
+ // codewords appended to it, based on this object's version and error correction level.
+ private: std::vector<std::uint8_t> appendErrorCorrection(const std::vector<std::uint8_t> &data) const;
+
+
+ // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
+ // data area of this QR Code symbol. Function modules need to be marked off before this is called.
+ private: void drawCodewords(const std::vector<std::uint8_t> &data);
+
+
+ // XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical
+ // properties, calling applyMask(m) twice with the same value is equivalent to no change at all.
+ // This means it is possible to apply a mask, undo it, and try another mask. Note that a final
+ // well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.).
+ private: void applyMask(int mask);
+
+
+ // A messy helper function for the constructors. This QR Code must be in an unmasked state when this
+ // method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
+ // This method applies and returns the actual mask chosen, from 0 to 7.
+ private: int handleConstructorMasking(int mask);
+
+
+ // 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.
+ private: long getPenaltyScore() const;
+
+
+
+ /*---- Private static helper functions ----*/
+
+ // Returns a set of positions of the alignment patterns in ascending order. These positions are
+ // used on both the x and y axes. Each value in the resulting array is in the range [0, 177).
+ // This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes.
+ private: static std::vector<int> getAlignmentPatternPositions(int ver);
+
+
+ // 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.
+ private: static int getNumRawDataModules(int ver);
+
+
+ // 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.
+ private: static int getNumDataCodewords(int ver, Ecc ecl);
+
+
+ /*---- Private tables of constants ----*/
+
+ // For use in getPenaltyScore(), when evaluating which mask is best.
+ private: static const int PENALTY_N1;
+ private: static const int PENALTY_N2;
+ private: static const int PENALTY_N3;
+ private: static const int PENALTY_N4;
+
+ private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
+ private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
+
+
+
+ /*---- Private helper class ----*/
+
+ /*
+ * Computes the Reed-Solomon error correction codewords for a sequence of data codewords
+ * at a given degree. Objects are immutable, and the state only depends on the degree.
+ * This class exists because each data block in a QR Code shares the same the divisor polynomial.
+ */
+ private: class ReedSolomonGenerator final {
+
+ /*-- Immutable field --*/
+
+ // Coefficients of the divisor polynomial, 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}.
+ private: std::vector<std::uint8_t> coefficients;
+
+
+ /*-- Constructor --*/
+
+ /*
+ * Creates a Reed-Solomon ECC generator for the given degree. This could be implemented
+ * as a lookup table over all possible parameter values, instead of as an algorithm.
+ */
+ public: explicit ReedSolomonGenerator(int degree);
+
+
+ /*-- Method --*/
+
+ /*
+ * Computes and returns the Reed-Solomon error correction codewords for the given
+ * sequence of data codewords. The returned object is always a new byte array.
+ * This method does not alter this object's state (because it is immutable).
+ */
+ public: std::vector<std::uint8_t> getRemainder(const std::vector<std::uint8_t> &data) const;
+
+
+ /*-- Static function --*/
+
+ // 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.
+ private: static std::uint8_t multiply(std::uint8_t x, std::uint8_t y);
+
+ };
+
+};
+
+}
diff --git a/src/third_party/QR-Code-generator/cpp/QrCodeGeneratorDemo.cpp b/src/third_party/QR-Code-generator/cpp/QrCodeGeneratorDemo.cpp
new file mode 100644
index 0000000..5c78b51
--- /dev/null
+++ b/src/third_party/QR-Code-generator/cpp/QrCodeGeneratorDemo.cpp
@@ -0,0 +1,199 @@
+/*
+ * QR Code generator demo (C++)
+ *
+ * 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.
+ */
+
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <vector>
+#include "BitBuffer.hpp"
+#include "QrCode.hpp"
+
+using std::uint8_t;
+using qrcodegen::QrCode;
+using qrcodegen::QrSegment;
+
+
+// Function prototypes
+static void doBasicDemo();
+static void doVarietyDemo();
+static void doSegmentDemo();
+static void doMaskDemo();
+static void printQr(const QrCode &qr);
+
+
+// The main application program.
+int main() {
+ doBasicDemo();
+ doVarietyDemo();
+ doSegmentDemo();
+ doMaskDemo();
+ return EXIT_SUCCESS;
+}
+
+
+
+/*---- Demo suite ----*/
+
+// Creates a single QR Code, then prints it to the console.
+static void doBasicDemo() {
+ const char *text = "Hello, world!"; // User-supplied text
+ const QrCode::Ecc errCorLvl = QrCode::Ecc::LOW; // Error correction level
+
+ // Make and print the QR Code symbol
+ const QrCode qr = QrCode::encodeText(text, errCorLvl);
+ printQr(qr);
+ std::cout << qr.toSvgString(4) << std::endl;
+}
+
+
+// Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console.
+static void doVarietyDemo() {
+ // Numeric mode encoding (3.33 bits per digit)
+ const QrCode qr1 = QrCode::encodeText("314159265358979323846264338327950288419716939937510", QrCode::Ecc::MEDIUM);
+ printQr(qr1);
+
+ // Alphanumeric mode encoding (5.5 bits per character)
+ const QrCode qr2 = QrCode::encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode::Ecc::HIGH);
+ printQr(qr2);
+
+ // Unicode text as UTF-8
+ const QrCode qr3 = QrCode::encodeText("\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4", QrCode::Ecc::QUARTILE);
+ printQr(qr3);
+
+ // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
+ const QrCode qr4 = QrCode::encodeText(
+ "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.", QrCode::Ecc::HIGH);
+ printQr(qr4);
+}
+
+
+// Creates QR Codes with manually specified segments for better compactness.
+static void doSegmentDemo() {
+ // Illustration "silver"
+ const char *silver0 = "THE SQUARE ROOT OF 2 IS 1.";
+ const char *silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
+ const QrCode qr0 = QrCode::encodeText(
+ (std::string(silver0) + silver1).c_str(),
+ QrCode::Ecc::LOW);
+ printQr(qr0);
+
+ const QrCode qr1 = QrCode::encodeSegments(
+ {QrSegment::makeAlphanumeric(silver0), QrSegment::makeNumeric(silver1)},
+ QrCode::Ecc::LOW);
+ printQr(qr1);
+
+ // Illustration "golden"
+ const char *golden0 = "Golden ratio \xCF\x86 = 1.";
+ const char *golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
+ const char *golden2 = "......";
+ const QrCode qr2 = QrCode::encodeText(
+ (std::string(golden0) + golden1 + golden2).c_str(),
+ QrCode::Ecc::LOW);
+ printQr(qr2);
+
+ std::vector<uint8_t> bytes(golden0, golden0 + std::strlen(golden0));
+ const QrCode qr3 = QrCode::encodeSegments(
+ {QrSegment::makeBytes(bytes), QrSegment::makeNumeric(golden1), QrSegment::makeAlphanumeric(golden2)},
+ QrCode::Ecc::LOW);
+ printQr(qr3);
+
+ // Illustration "Madoka": kanji, kana, Greek, Cyrillic, full-width Latin characters
+ const char *madoka = // Encoded in UTF-8
+ "\xE3\x80\x8C\xE9\xAD\x94\xE6\xB3\x95\xE5"
+ "\xB0\x91\xE5\xA5\xB3\xE3\x81\xBE\xE3\x81"
+ "\xA9\xE3\x81\x8B\xE2\x98\x86\xE3\x83\x9E"
+ "\xE3\x82\xAE\xE3\x82\xAB\xE3\x80\x8D\xE3"
+ "\x81\xA3\xE3\x81\xA6\xE3\x80\x81\xE3\x80"
+ "\x80\xD0\x98\xD0\x90\xD0\x98\xE3\x80\x80"
+ "\xEF\xBD\x84\xEF\xBD\x85\xEF\xBD\x93\xEF"
+ "\xBD\x95\xE3\x80\x80\xCE\xBA\xCE\xB1\xEF"
+ "\xBC\x9F";
+ const QrCode qr4 = QrCode::encodeText(madoka, QrCode::Ecc::LOW);
+ printQr(qr4);
+
+ const std::vector<int> kanjiChars{ // 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,
+ };
+ qrcodegen::BitBuffer bb;
+ for (int c : kanjiChars)
+ bb.appendBits(c, 13);
+ const QrCode qr5 = QrCode::encodeSegments(
+ {QrSegment(QrSegment::Mode::KANJI, kanjiChars.size(), bb)},
+ QrCode::Ecc::LOW);
+ printQr(qr5);
+}
+
+
+// Creates QR Codes with the same size and contents but different mask patterns.
+static void doMaskDemo() {
+ // Project Nayuki URL
+ std::vector<QrSegment> segs0 = QrSegment::makeSegments("https://www.nayuki.io/");
+ printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, -1, true)); // Automatic mask
+ printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 3, true)); // Force mask 3
+
+ // Chinese text as UTF-8
+ std::vector<QrSegment> segs1 = QrSegment::makeSegments(
+ "\xE7\xB6\xAD\xE5\x9F\xBA\xE7\x99\xBE\xE7\xA7\x91\xEF\xBC\x88\x57\x69\x6B\x69\x70"
+ "\x65\x64\x69\x61\xEF\xBC\x8C\xE8\x81\x86\xE8\x81\xBD\x69\x2F\xCB\x8C\x77\xC9\xAA"
+ "\x6B\xE1\xB5\xBB\xCB\x88\x70\x69\xCB\x90\x64\x69\x2E\xC9\x99\x2F\xEF\xBC\x89\xE6"
+ "\x98\xAF\xE4\xB8\x80\xE5\x80\x8B\xE8\x87\xAA\xE7\x94\xB1\xE5\x85\xA7\xE5\xAE\xB9"
+ "\xE3\x80\x81\xE5\x85\xAC\xE9\x96\x8B\xE7\xB7\xA8\xE8\xBC\xAF\xE4\xB8\x94\xE5\xA4"
+ "\x9A\xE8\xAA\x9E\xE8\xA8\x80\xE7\x9A\x84\xE7\xB6\xB2\xE8\xB7\xAF\xE7\x99\xBE\xE7"
+ "\xA7\x91\xE5\x85\xA8\xE6\x9B\xB8\xE5\x8D\x94\xE4\xBD\x9C\xE8\xA8\x88\xE7\x95\xAB");
+ printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 0, true)); // Force mask 0
+ printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 1, true)); // Force mask 1
+ printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 5, true)); // Force mask 5
+ printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 7, true)); // Force mask 7
+}
+
+
+
+/*---- Utilities ----*/
+
+// Prints the given QR Code to the console.
+static void printQr(const QrCode &qr) {
+ int border = 4;
+ for (int y = -border; y < qr.getSize() + border; y++) {
+ for (int x = -border; x < qr.getSize() + border; x++) {
+ std::cout << (qr.getModule(x, y) ? "##" : " ");
+ }
+ std::cout << std::endl;
+ }
+ std::cout << std::endl;
+}
diff --git a/src/third_party/QR-Code-generator/cpp/QrCodeGeneratorWorker.cpp b/src/third_party/QR-Code-generator/cpp/QrCodeGeneratorWorker.cpp
new file mode 100644
index 0000000..2e14607
--- /dev/null
+++ b/src/third_party/QR-Code-generator/cpp/QrCodeGeneratorWorker.cpp
@@ -0,0 +1,104 @@
+/*
+ * QR Code generator test worker (C++)
+ *
+ * This program reads data and encoding parameters from standard input and writes
+ * QR Code bitmaps to standard output. The I/O format is one integer per line.
+ * Run with no command line arguments. The program is intended for automated
+ * batch testing of end-to-end functionality of this QR Code generator library.
+ *
+ * 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.
+ */
+
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <vector>
+#include "QrCode.hpp"
+
+using qrcodegen::QrCode;
+using qrcodegen::QrSegment;
+
+
+static const std::vector<QrCode::Ecc> ECC_LEVELS{
+ QrCode::Ecc::LOW,
+ QrCode::Ecc::MEDIUM,
+ QrCode::Ecc::QUARTILE,
+ QrCode::Ecc::HIGH,
+};
+
+
+int main() {
+ while (true) {
+
+ // Read data length or exit
+ int length;
+ std::cin >> length;
+ if (length == -1)
+ break;
+
+ // Read data bytes
+ bool isAscii = true;
+ std::vector<uint8_t> data;
+ for (int i = 0; i < length; i++) {
+ int b;
+ std::cin >> b;
+ data.push_back(static_cast<uint8_t>(b));
+ isAscii &= 0 < b && b < 128;
+ }
+
+ // Read encoding parameters
+ int errCorLvl, minVersion, maxVersion, mask, boostEcl;
+ std::cin >> errCorLvl;
+ std::cin >> minVersion;
+ std::cin >> maxVersion;
+ std::cin >> mask;
+ std::cin >> boostEcl;
+
+ // Make list of segments
+ std::vector<QrSegment> segs;
+ if (isAscii) {
+ std::vector<char> text(data.cbegin(), data.cend());
+ text.push_back('\0');
+ segs = QrSegment::makeSegments(text.data());
+ } else
+ segs.push_back(QrSegment::makeBytes(data));
+
+ try { // Try to make QR Code symbol
+ const QrCode qr = QrCode::encodeSegments(segs,
+ ECC_LEVELS.at(errCorLvl), minVersion, maxVersion, mask, boostEcl == 1);
+ // Print grid of modules
+ std::cout << qr.getVersion() << std::endl;
+ for (int y = 0; y < qr.getSize(); y++) {
+ for (int x = 0; x < qr.getSize(); x++)
+ std::cout << (qr.getModule(x, y) ? 1 : 0) << std::endl;
+ }
+
+ } catch (const char *msg) {
+ if (strcmp(msg, "Data too long") != 0) {
+ std::cerr << msg << std::endl;
+ return EXIT_FAILURE;
+ }
+ std::cout << -1 << std::endl;
+ }
+ std::cout << std::flush;
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/src/third_party/QR-Code-generator/cpp/QrSegment.cpp b/src/third_party/QR-Code-generator/cpp/QrSegment.cpp
new file mode 100644
index 0000000..f711461
--- /dev/null
+++ b/src/third_party/QR-Code-generator/cpp/QrSegment.cpp
@@ -0,0 +1,228 @@
+/*
+ * QR Code generator library (C++)
+ *
+ * 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.
+ */
+
+#include <climits>
+#include <cstring>
+#include <utility>
+#include "QrSegment.hpp"
+
+using std::uint8_t;
+using std::vector;
+
+
+namespace qrcodegen {
+
+QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) :
+ modeBits(mode) {
+ numBitsCharCount[0] = cc0;
+ numBitsCharCount[1] = cc1;
+ numBitsCharCount[2] = cc2;
+}
+
+
+int QrSegment::Mode::getModeBits() const {
+ return modeBits;
+}
+
+
+int QrSegment::Mode::numCharCountBits(int ver) const {
+ if ( 1 <= ver && ver <= 9) return numBitsCharCount[0];
+ else if (10 <= ver && ver <= 26) return numBitsCharCount[1];
+ else if (27 <= ver && ver <= 40) return numBitsCharCount[2];
+ else throw "Version number out of range";
+}
+
+
+const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14);
+const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13);
+const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16);
+const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12);
+const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0);
+
+
+
+QrSegment QrSegment::makeBytes(const vector<uint8_t> &data) {
+ if (data.size() > INT_MAX)
+ throw "Data too long";
+ BitBuffer bb;
+ for (uint8_t b : data)
+ bb.appendBits(b, 8);
+ return QrSegment(Mode::BYTE, static_cast<int>(data.size()), std::move(bb));
+}
+
+
+QrSegment QrSegment::makeNumeric(const char *digits) {
+ BitBuffer bb;
+ int accumData = 0;
+ int accumCount = 0;
+ int charCount = 0;
+ for (; *digits != '\0'; digits++, charCount++) {
+ char c = *digits;
+ if (c < '0' || c > '9')
+ throw "String contains non-numeric characters";
+ accumData = accumData * 10 + (c - '0');
+ accumCount++;
+ if (accumCount == 3) {
+ bb.appendBits(accumData, 10);
+ accumData = 0;
+ accumCount = 0;
+ }
+ }
+ if (accumCount > 0) // 1 or 2 digits remaining
+ bb.appendBits(accumData, accumCount * 3 + 1);
+ return QrSegment(Mode::NUMERIC, charCount, std::move(bb));
+}
+
+
+QrSegment QrSegment::makeAlphanumeric(const char *text) {
+ BitBuffer bb;
+ int accumData = 0;
+ int accumCount = 0;
+ int charCount = 0;
+ for (; *text != '\0'; text++, charCount++) {
+ const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text);
+ if (temp == nullptr)
+ throw "String contains unencodable characters in alphanumeric mode";
+ accumData = accumData * 45 + (temp - ALPHANUMERIC_CHARSET);
+ accumCount++;
+ if (accumCount == 2) {
+ bb.appendBits(accumData, 11);
+ accumData = 0;
+ accumCount = 0;
+ }
+ }
+ if (accumCount > 0) // 1 character remaining
+ bb.appendBits(accumData, 6);
+ return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb));
+}
+
+
+vector<QrSegment> QrSegment::makeSegments(const char *text) {
+ // Select the most efficient segment encoding automatically
+ vector<QrSegment> result;
+ if (*text == '\0'); // Leave result empty
+ else if (isNumeric(text))
+ result.push_back(makeNumeric(text));
+ else if (isAlphanumeric(text))
+ result.push_back(makeAlphanumeric(text));
+ else {
+ vector<uint8_t> bytes;
+ for (; *text != '\0'; text++)
+ bytes.push_back(static_cast<uint8_t>(*text));
+ result.push_back(makeBytes(bytes));
+ }
+ return result;
+}
+
+
+QrSegment QrSegment::makeEci(long assignVal) {
+ BitBuffer bb;
+ if (0 <= assignVal && assignVal < (1 << 7))
+ bb.appendBits(assignVal, 8);
+ else if ((1 << 7) <= assignVal && assignVal < (1 << 14)) {
+ bb.appendBits(2, 2);
+ bb.appendBits(assignVal, 14);
+ } else if ((1 << 14) <= assignVal && assignVal < 1000000L) {
+ bb.appendBits(6, 3);
+ bb.appendBits(assignVal, 21);
+ } else
+ throw "ECI assignment value out of range";
+ return QrSegment(Mode::ECI, 0, std::move(bb));
+}
+
+
+QrSegment::QrSegment(Mode md, int numCh, const std::vector<bool> &dt) :
+ mode(md),
+ numChars(numCh),
+ data(dt) {
+ if (numCh < 0)
+ throw "Invalid value";
+}
+
+
+QrSegment::QrSegment(Mode md, int numCh, std::vector<bool> &&dt) :
+ mode(md),
+ numChars(numCh),
+ data(std::move(dt)) {
+ if (numCh < 0)
+ throw "Invalid value";
+}
+
+
+int QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) {
+ if (version < 1 || version > 40)
+ throw "Version number out of range";
+ int result = 0;
+ for (const QrSegment &seg : segs) {
+ int ccbits = seg.mode.numCharCountBits(version);
+ // Fail if segment length value doesn't fit in the length field's bit-width
+ if (seg.numChars >= (1L << ccbits))
+ return -1;
+ if (4 + ccbits > INT_MAX - result)
+ return -1;
+ result += 4 + ccbits;
+ if (seg.data.size() > static_cast<unsigned int>(INT_MAX - result))
+ return -1;
+ result += static_cast<int>(seg.data.size());
+ }
+ return result;
+}
+
+
+bool QrSegment::isAlphanumeric(const char *text) {
+ for (; *text != '\0'; text++) {
+ if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr)
+ return false;
+ }
+ return true;
+}
+
+
+bool QrSegment::isNumeric(const char *text) {
+ for (; *text != '\0'; text++) {
+ char c = *text;
+ if (c < '0' || c > '9')
+ return false;
+ }
+ return true;
+}
+
+
+QrSegment::Mode QrSegment::getMode() const {
+ return mode;
+}
+
+
+int QrSegment::getNumChars() const {
+ return numChars;
+}
+
+
+const std::vector<bool> &QrSegment::getData() const {
+ return data;
+}
+
+
+const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
+
+}
diff --git a/src/third_party/QR-Code-generator/cpp/QrSegment.hpp b/src/third_party/QR-Code-generator/cpp/QrSegment.hpp
new file mode 100644
index 0000000..2b9eb66
--- /dev/null
+++ b/src/third_party/QR-Code-generator/cpp/QrSegment.hpp
@@ -0,0 +1,186 @@
+/*
+ * QR Code generator library (C++)
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+#include "BitBuffer.hpp"
+
+
+namespace qrcodegen {
+
+/*
+ * Represents a character string to be encoded in a QR Code symbol. Each segment has
+ * a mode, and a sequence of characters that is already encoded as a sequence of bits.
+ * Instances of this class are immutable.
+ * This segment class 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.
+ */
+class QrSegment final {
+
+ /*---- Public helper enumeration ----*/
+
+ /*
+ * The mode field of a segment. Immutable. Provides methods to retrieve closely related values.
+ */
+ public: class Mode final {
+
+ /*-- Constants --*/
+
+ public: static const Mode NUMERIC;
+ public: static const Mode ALPHANUMERIC;
+ public: static const Mode BYTE;
+ public: static const Mode KANJI;
+ public: static const Mode ECI;
+
+
+ /*-- Fields --*/
+
+ private: int modeBits;
+
+ private: int numBitsCharCount[3];
+
+
+ /*-- Constructor --*/
+
+ private: Mode(int mode, int cc0, int cc1, int cc2);
+
+
+ /*-- Methods --*/
+
+ /*
+ * (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 to 15).
+ */
+ public: int getModeBits() const;
+
+ /*
+ * (Package-private) Returns the bit width of the segment character count field for this mode object at the given version number.
+ */
+ public: int numCharCountBits(int ver) const;
+
+ };
+
+
+
+ /*---- Public static factory functions ----*/
+
+ /*
+ * Returns a segment representing the given binary data encoded in byte mode.
+ */
+ public: static QrSegment makeBytes(const std::vector<std::uint8_t> &data);
+
+
+ /*
+ * Returns a segment representing the given string of decimal digits encoded in numeric mode.
+ */
+ public: static QrSegment makeNumeric(const char *digits);
+
+
+ /*
+ * 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.
+ */
+ public: static QrSegment makeAlphanumeric(const char *text);
+
+
+ /*
+ * Returns a list of zero or more segments to represent the given text string.
+ * The result may use various segment modes and switch modes to optimize the length of the bit stream.
+ */
+ public: static std::vector<QrSegment> makeSegments(const char *text);
+
+
+ /*
+ * Returns a segment representing an Extended Channel Interpretation
+ * (ECI) designator with the given assignment value.
+ */
+ public: static QrSegment makeEci(long assignVal);
+
+
+ /*---- Public static helper functions ----*/
+
+ /*
+ * Tests whether the given string can be encoded as a segment in alphanumeric mode.
+ */
+ public: static bool isAlphanumeric(const char *text);
+
+
+ /*
+ * Tests whether the given string can be encoded as a segment in numeric mode.
+ */
+ public: static bool isNumeric(const char *text);
+
+
+
+ /*---- Instance fields ----*/
+
+ /* The mode indicator for this segment. */
+ private: Mode mode;
+
+ /* The length of this segment's unencoded data, measured in characters. Always zero or positive. */
+ private: int numChars;
+
+ /* The data bits of this segment. */
+ private: std::vector<bool> data;
+
+
+ /*---- Constructors ----*/
+
+ /*
+ * Creates a new QR Code data segment with the given parameters and data.
+ */
+ public: QrSegment(Mode md, int numCh, const std::vector<bool> &dt);
+
+
+ /*
+ * Creates a new QR Code data segment with the given parameters and data.
+ */
+ public: QrSegment(Mode md, int numCh, std::vector<bool> &&dt);
+
+
+ /*---- Methods ----*/
+
+ public: Mode getMode() const;
+
+
+ public: int getNumChars() const;
+
+
+ public: const std::vector<bool> &getData() const;
+
+
+ // Package-private helper function.
+ public: static int getTotalBits(const std::vector<QrSegment> &segs, int version);
+
+
+ /*---- Private constant ----*/
+
+ /* The set of all legal characters in alphanumeric mode, where each character value maps to the index in the string. */
+ private: static const char *ALPHANUMERIC_CHARSET;
+
+};
+
+}
diff --git a/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/BitBuffer.java b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/BitBuffer.java
new file mode 100644
index 0000000..f43cc12
--- /dev/null
+++ b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/BitBuffer.java
@@ -0,0 +1,133 @@
+/*
+ * QR Code generator library (Java)
+ *
+ * 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.
+ */
+
+package io.nayuki.qrcodegen;
+
+import java.util.BitSet;
+import java.util.Objects;
+
+
+/**
+ * An appendable sequence of bits (0's and 1's).
+ */
+public final class BitBuffer implements Cloneable {
+
+ /*---- Fields ----*/
+
+ private BitSet data;
+
+ private int bitLength;
+
+
+
+ /*---- Constructor ----*/
+
+ /**
+ * Constructs an empty bit buffer (length 0).
+ */
+ public BitBuffer() {
+ data = new BitSet();
+ bitLength = 0;
+ }
+
+
+
+ /*---- Methods ----*/
+
+ /**
+ * Returns the length of this sequence, which is a non-negative value.
+ * @return the length of this sequence
+ */
+ public int bitLength() {
+ return bitLength;
+ }
+
+
+ /**
+ * Returns the bit at the specified index, yielding 0 or 1.
+ * @param index the index to get the bit at
+ * @return the bit at the specified index
+ * @throws IndexOutOfBoundsException if index < 0 or index ≥ bitLength
+ */
+ public int getBit(int index) {
+ if (index < 0 || index >= bitLength)
+ throw new IndexOutOfBoundsException();
+ return data.get(index) ? 1 : 0;
+ }
+
+
+ /**
+ * Packs this buffer's bits into bytes in big endian,
+ * padding with '0' bit values, and returns the new array.
+ * @return this sequence as a new array of bytes (not {@code null})
+ */
+ public byte[] getBytes() {
+ byte[] result = new byte[(bitLength + 7) / 8];
+ for (int i = 0; i < bitLength; i++)
+ result[i >>> 3] |= data.get(i) ? 1 << (7 - (i & 7)) : 0;
+ return result;
+ }
+
+
+ /**
+ * Appends the specified number of low bits of the specified value
+ * to this sequence. Requires 0 ≤ val < 2<sup>len</sup>.
+ * @param val the value to append
+ * @param len the number of low bits in the value to take
+ */
+ public void appendBits(int val, int len) {
+ if (len < 0 || len > 31 || val >>> len != 0)
+ throw new IllegalArgumentException("Value out of range");
+ for (int i = len - 1; i >= 0; i--, bitLength++) // Append bit by bit
+ data.set(bitLength, ((val >>> i) & 1) != 0);
+ }
+
+
+ /**
+ * Appends the bit data of the specified segment to this bit buffer.
+ * @param seg the segment whose data to append (not {@code null})
+ * @throws NullPointerException if the segment is {@code null}
+ */
+ public void appendData(QrSegment seg) {
+ Objects.requireNonNull(seg);
+ BitBuffer bb = seg.data;
+ for (int i = 0; i < bb.bitLength; i++, bitLength++) // Append bit by bit
+ data.set(bitLength, bb.data.get(i));
+ }
+
+
+ /**
+ * Returns a copy of this bit buffer object.
+ * @return a copy of this bit buffer object
+ */
+ public BitBuffer clone() {
+ try {
+ BitBuffer result = (BitBuffer)super.clone();
+ result.data = (BitSet)result.data.clone();
+ return result;
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+}
diff --git a/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrCode.java b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrCode.java
new file mode 100644
index 0000000..5f64ca2
--- /dev/null
+++ b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrCode.java
@@ -0,0 +1,849 @@
+/*
+ * QR Code generator library (Java)
+ *
+ * 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.
+ */
+
+package io.nayuki.qrcodegen;
+
+import java.awt.image.BufferedImage;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+
+/**
+ * Represents an immutable square grid of black and white cells for a QR Code symbol, and
+ * provides static functions to create a QR Code from user-supplied textual or binary data.
+ * <p>This class covers the QR Code model 2 specification, supporting all versions (sizes)
+ * from 1 to 40, all 4 error correction levels, and only 3 character encoding modes.</p>
+ */
+public final class QrCode {
+
+ /*---- Public static factory functions ----*/
+
+ /**
+ * Returns a QR Code symbol representing the specified Unicode text string at the specified error correction level.
+ * As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer
+ * Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
+ * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the
+ * ecl argument if it can be done without increasing the version.
+ * @param text the text to be encoded, which can be any Unicode string
+ * @param ecl the error correction level to use (will be boosted)
+ * @return a QR Code representing the text
+ * @throws NullPointerException if the text or error correction level is {@code null}
+ * @throws IllegalArgumentException if the text fails to fit in the largest version QR Code, which means it is too long
+ */
+ public static QrCode encodeText(String text, Ecc ecl) {
+ Objects.requireNonNull(text);
+ Objects.requireNonNull(ecl);
+ List<QrSegment> segs = QrSegment.makeSegments(text);
+ return encodeSegments(segs, ecl);
+ }
+
+
+ /**
+ * Returns a QR Code symbol representing the specified binary data string at the specified error correction level.
+ * This function always encodes using the binary segment mode, not any text mode. The maximum number of
+ * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
+ * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
+ * @param data the binary data to encode
+ * @param ecl the error correction level to use (will be boosted)
+ * @return a QR Code representing the binary data
+ * @throws NullPointerException if the data or error correction level is {@code null}
+ * @throws IllegalArgumentException if the data fails to fit in the largest version QR Code, which means it is too long
+ */
+ public static QrCode encodeBinary(byte[] data, Ecc ecl) {
+ Objects.requireNonNull(data);
+ Objects.requireNonNull(ecl);
+ QrSegment seg = QrSegment.makeBytes(data);
+ return encodeSegments(Arrays.asList(seg), ecl);
+ }
+
+
+ /**
+ * Returns a QR Code symbol representing the specified data segments at the specified error correction
+ * level or higher. The smallest possible QR Code version is automatically chosen for the output.
+ * <p>This function allows the user to create a custom sequence of segments that switches
+ * between modes (such as alphanumeric and binary) to encode text more efficiently.
+ * This function is considered to be lower level than simply encoding text or binary data.</p>
+ * @param segs the segments to encode
+ * @param ecl the error correction level to use (will be boosted)
+ * @return a QR Code representing the segments
+ * @throws NullPointerException if the list of segments, a segment, or the error correction level is {@code null}
+ * @throws IllegalArgumentException if the data is too long to fit in the largest version QR Code at the ECL
+ */
+ public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl) {
+ return encodeSegments(segs, ecl, MIN_VERSION, MAX_VERSION, -1, true);
+ }
+
+
+ /**
+ * Returns a QR Code symbol representing the specified data segments with the specified encoding parameters.
+ * The smallest possible QR Code version within the specified range is automatically chosen for the output.
+ * <p>This function allows the user to create a custom sequence of segments that switches
+ * between modes (such as alphanumeric and binary) to encode text more efficiently.
+ * This function is considered to be lower level than simply encoding text or binary data.</p>
+ * @param segs the segments to encode
+ * @param ecl the error correction level to use (may be boosted)
+ * @param minVersion the minimum allowed version of the QR symbol (at least 1)
+ * @param maxVersion the maximum allowed version of the QR symbol (at most 40)
+ * @param mask the mask pattern to use, which is either -1 for automatic choice or from 0 to 7 for fixed choice
+ * @param boostEcl increases the error correction level if it can be done without increasing the version number
+ * @return a QR Code representing the segments
+ * @throws NullPointerException if the list of segments, a segment, or the error correction level is {@code null}
+ * @throws IllegalArgumentException if 1 ≤ minVersion ≤ maxVersion ≤ 40 is violated, or if mask
+ * < −1 or mask > 7, or if the data is too long to fit in a QR Code at maxVersion at the ECL
+ */
+ public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl) {
+ Objects.requireNonNull(segs);
+ Objects.requireNonNull(ecl);
+ if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
+ throw new IllegalArgumentException("Invalid value");
+
+ // Find the minimal version number to use
+ int version, dataUsedBits;
+ for (version = minVersion; ; version++) {
+ int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
+ dataUsedBits = QrSegment.getTotalBits(segs, version);
+ if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
+ break; // This version number is found to be suitable
+ if (version >= maxVersion) // All versions in the range could not fit the given data
+ throw new IllegalArgumentException("Data too long");
+ }
+ if (dataUsedBits == -1)
+ throw new AssertionError();
+
+ // Increase the error correction level while the data still fits in the current version number
+ for (Ecc newEcl : Ecc.values()) {
+ if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
+ ecl = newEcl;
+ }
+
+ // Create the data bit string by concatenating all segments
+ int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
+ BitBuffer bb = new BitBuffer();
+ for (QrSegment seg : segs) {
+ bb.appendBits(seg.mode.modeBits, 4);
+ bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
+ bb.appendData(seg);
+ }
+
+ // Add terminator and pad up to a byte if applicable
+ bb.appendBits(0, Math.min(4, dataCapacityBits - bb.bitLength()));
+ bb.appendBits(0, (8 - bb.bitLength() % 8) % 8);
+
+ // Pad with alternate bytes until data capacity is reached
+ for (int padByte = 0xEC; bb.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
+ bb.appendBits(padByte, 8);
+ if (bb.bitLength() % 8 != 0)
+ throw new AssertionError();
+
+ // Create the QR Code symbol
+ return new QrCode(version, ecl, bb.getBytes(), mask);
+ }
+
+
+
+ /*---- Public constants ----*/
+
+ public static final int MIN_VERSION = 1;
+ public static final int MAX_VERSION = 40;
+
+
+
+ /*---- Instance fields ----*/
+
+ // Public immutable scalar parameters
+
+ /** This QR Code symbol's version number, which is always between 1 and 40 (inclusive). */
+ public final int version;
+
+ /** The width and height of this QR Code symbol, measured in modules.
+ * Always equal to version × 4 + 17, in the range 21 to 177. */
+ public final int size;
+
+ /** The error correction level used in this QR Code symbol. Never {@code null}. */
+ public final Ecc errorCorrectionLevel;
+
+ /** The mask pattern used in this QR Code symbol, in the range 0 to 7 (i.e. unsigned 3-bit integer).
+ * Note that even if a constructor was called with automatic masking requested
+ * (mask = -1), the resulting object will still have a mask value between 0 and 7. */
+ public final int mask;
+
+ // Private grids of modules/pixels (conceptually immutable)
+ private boolean[][] modules; // The modules of this QR Code symbol (false = white, true = black)
+ private boolean[][] isFunction; // Indicates function modules that are not subjected to masking
+
+
+
+ /*---- Constructors ----*/
+
+ /**
+ * Creates a new QR Code symbol with the specified version number, error correction level, binary data array, and mask number.
+ * <p>This is a cumbersome low-level constructor that should not be invoked directly by the user.
+ * To go one level up, see the {@link #encodeSegments(List,Ecc)} function.</p>
+ * @param ver the version number to use, which must be in the range 1 to 40, inclusive
+ * @param ecl the error correction level to use
+ * @param dataCodewords the raw binary user data to encode
+ * @param mask the mask pattern to use, which is either -1 for automatic choice or from 0 to 7 for fixed choice
+ * @throws NullPointerException if the byte array or error correction level is {@code null}
+ * @throws IllegalArgumentException if the version or mask value is out of range
+ */
+ public QrCode(int ver, Ecc ecl, byte[] dataCodewords, int mask) {
+ // Check arguments
+ Objects.requireNonNull(ecl);
+ if (ver < MIN_VERSION || ver > MAX_VERSION || mask < -1 || mask > 7)
+ throw new IllegalArgumentException("Value out of range");
+ Objects.requireNonNull(dataCodewords);
+
+ // Initialize fields
+ version = ver;
+ size = ver * 4 + 17;
+ errorCorrectionLevel = ecl;
+ modules = new boolean[size][size]; // Entirely white grid
+ isFunction = new boolean[size][size];
+
+ // Draw function patterns, draw all codewords, do masking
+ drawFunctionPatterns();
+ byte[] allCodewords = appendErrorCorrection(dataCodewords);
+ drawCodewords(allCodewords);
+ this.mask = handleConstructorMasking(mask);
+ }
+
+
+
+ /*---- Public instance methods ----*/
+
+ /**
+ * Returns the color of the module (pixel) at the specified coordinates, which is either
+ * false for white or true for black. The top left corner has the coordinates (x=0, y=0).
+ * If the specified coordinates are out of bounds, then false (white) is returned.
+ * @param x the x coordinate, where 0 is the left edge and size−1 is the right edge
+ * @param y the y coordinate, where 0 is the top edge and size−1 is the bottom edge
+ * @return the module's color, which is either false (white) or true (black)
+ */
+ public boolean getModule(int x, int y) {
+ return 0 <= x && x < size && 0 <= y && y < size && modules[y][x];
+ }
+
+
+ /**
+ * Returns a new image object representing this QR Code, with the specified module scale and number
+ * of border modules. For example, the arguments scale=10, border=4 means to pad the QR Code symbol
+ * with 4 white border modules on all four edges, then use 10*10 pixels to represent each module.
+ * The resulting image only contains the hex colors 000000 and FFFFFF.
+ * @param scale the module scale factor, which must be positive
+ * @param border the number of border modules to add, which must be non-negative
+ * @return an image representing this QR Code, with padding and scaling
+ * @throws IllegalArgumentException if the scale or border is out of range
+ */
+ public BufferedImage toImage(int scale, int border) {
+ if (scale <= 0 || border < 0)
+ throw new IllegalArgumentException("Value out of range");
+ if (border > Integer.MAX_VALUE / 2 || size + border * 2L > Integer.MAX_VALUE / scale)
+ throw new IllegalArgumentException("Scale or border too large");
+
+ BufferedImage result = new BufferedImage((size + border * 2) * scale, (size + border * 2) * scale, BufferedImage.TYPE_INT_RGB);
+ for (int y = 0; y < result.getHeight(); y++) {
+ for (int x = 0; x < result.getWidth(); x++) {
+ boolean val = getModule(x / scale - border, y / scale - border);
+ result.setRGB(x, y, val ? 0x000000 : 0xFFFFFF);
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Based on the specified number of border modules to add as padding, this returns a
+ * string whose contents represents an SVG XML file that depicts this QR Code symbol.
+ * Note that Unix newlines (\n) are always used, regardless of the platform.
+ * @param border the number of border modules to add, which must be non-negative
+ * @return a string representing this QR Code as an SVG document
+ */
+ public String toSvgString(int border) {
+ if (border < 0)
+ throw new IllegalArgumentException("Border must be non-negative");
+ if (size + border * 2L > Integer.MAX_VALUE)
+ throw new IllegalArgumentException("Border too large");
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ sb.append("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+ sb.append(String.format(
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 %1$d %1$d\" stroke=\"none\">\n",
+ size + border * 2));
+ sb.append("\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n");
+ sb.append("\t<path d=\"");
+ boolean head = true;
+ for (int y = -border; y < size + border; y++) {
+ for (int x = -border; x < size + border; x++) {
+ if (getModule(x, y)) {
+ if (head)
+ head = false;
+ else
+ sb.append(" ");
+ sb.append(String.format("M%d,%dh1v1h-1z", x + border, y + border));
+ }
+ }
+ }
+ sb.append("\" fill=\"#000000\"/>\n");
+ sb.append("</svg>\n");
+ return sb.toString();
+ }
+
+
+
+ /*---- Private helper methods for constructor: Drawing function modules ----*/
+
+ private void drawFunctionPatterns() {
+ // Draw horizontal and vertical timing patterns
+ for (int i = 0; i < size; i++) {
+ setFunctionModule(6, i, i % 2 == 0);
+ setFunctionModule(i, 6, i % 2 == 0);
+ }
+
+ // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
+ drawFinderPattern(3, 3);
+ drawFinderPattern(size - 4, 3);
+ drawFinderPattern(3, size - 4);
+
+ // Draw numerous alignment patterns
+ int[] alignPatPos = getAlignmentPatternPositions(version);
+ int numAlign = alignPatPos.length;
+ for (int i = 0; i < numAlign; i++) {
+ for (int j = 0; j < numAlign; j++) {
+ if (i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0)
+ continue; // Skip the three finder corners
+ else
+ drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
+ }
+ }
+
+ // Draw configuration data
+ drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
+ drawVersion();
+ }
+
+
+ // Draws two copies of the format bits (with its own error correction code)
+ // based on the given mask and this object's error correction level field.
+ private void drawFormatBits(int mask) {
+ // Calculate error correction code and pack bits
+ int data = errorCorrectionLevel.formatBits << 3 | mask; // errCorrLvl is uint2, mask is uint3
+ int rem = data;
+ for (int i = 0; i < 10; i++)
+ rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
+ data = data << 10 | rem;
+ data ^= 0x5412; // uint15
+ if (data >>> 15 != 0)
+ throw new AssertionError();
+
+ // Draw first copy
+ for (int i = 0; i <= 5; i++)
+ setFunctionModule(8, i, ((data >>> i) & 1) != 0);
+ setFunctionModule(8, 7, ((data >>> 6) & 1) != 0);
+ setFunctionModule(8, 8, ((data >>> 7) & 1) != 0);
+ setFunctionModule(7, 8, ((data >>> 8) & 1) != 0);
+ for (int i = 9; i < 15; i++)
+ setFunctionModule(14 - i, 8, ((data >>> i) & 1) != 0);
+
+ // Draw second copy
+ for (int i = 0; i <= 7; i++)
+ setFunctionModule(size - 1 - i, 8, ((data >>> i) & 1) != 0);
+ for (int i = 8; i < 15; i++)
+ setFunctionModule(8, size - 15 + i, ((data >>> i) & 1) != 0);
+ setFunctionModule(8, size - 8, true);
+ }
+
+
+ // Draws two copies of the version bits (with its own error correction code),
+ // based on this object's version field (which only has an effect for 7 <= version <= 40).
+ private void drawVersion() {
+ if (version < 7)
+ return;
+
+ // Calculate error correction code and pack bits
+ int rem = version; // version is uint6, in the range [7, 40]
+ for (int i = 0; i < 12; i++)
+ rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25);
+ int data = version << 12 | rem; // uint18
+ if (data >>> 18 != 0)
+ throw new AssertionError();
+
+ // Draw two copies
+ for (int i = 0; i < 18; i++) {
+ boolean bit = ((data >>> i) & 1) != 0;
+ int a = size - 11 + i % 3, b = i / 3;
+ setFunctionModule(a, b, bit);
+ setFunctionModule(b, a, bit);
+ }
+ }
+
+
+ // Draws a 9*9 finder pattern including the border separator, with the center module at (x, y).
+ private void drawFinderPattern(int x, int y) {
+ for (int i = -4; i <= 4; i++) {
+ for (int j = -4; j <= 4; j++) {
+ int dist = Math.max(Math.abs(i), Math.abs(j)); // Chebyshev/infinity norm
+ int xx = x + j, yy = y + i;
+ if (0 <= xx && xx < size && 0 <= yy && yy < size)
+ setFunctionModule(xx, yy, dist != 2 && dist != 4);
+ }
+ }
+ }
+
+
+ // Draws a 5*5 alignment pattern, with the center module at (x, y).
+ private void drawAlignmentPattern(int x, int y) {
+ for (int i = -2; i <= 2; i++) {
+ for (int j = -2; j <= 2; j++)
+ setFunctionModule(x + j, y + i, Math.max(Math.abs(i), Math.abs(j)) != 1);
+ }
+ }
+
+
+ // Sets the color of a module and marks it as a function module.
+ // Only used by the constructor. Coordinates must be in range.
+ private void setFunctionModule(int x, int y, boolean isBlack) {
+ modules[y][x] = isBlack;
+ isFunction[y][x] = true;
+ }
+
+
+ /*---- Private helper methods for constructor: Codewords and masking ----*/
+
+ // Returns a new byte string representing the given data with the appropriate error correction
+ // codewords appended to it, based on this object's version and error correction level.
+ private byte[] appendErrorCorrection(byte[] data) {
+ if (data.length != getNumDataCodewords(version, errorCorrectionLevel))
+ throw new IllegalArgumentException();
+
+ // Calculate parameter numbers
+ int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[errorCorrectionLevel.ordinal()][version];
+ int blockEccLen = ECC_CODEWORDS_PER_BLOCK[errorCorrectionLevel.ordinal()][version];
+ int rawCodewords = getNumRawDataModules(version) / 8;
+ int numShortBlocks = numBlocks - rawCodewords % numBlocks;
+ int shortBlockLen = rawCodewords / numBlocks;
+
+ // Split data into blocks and append ECC to each block
+ byte[][] blocks = new byte[numBlocks][];
+ ReedSolomonGenerator rs = new ReedSolomonGenerator(blockEccLen);
+ for (int i = 0, k = 0; i < numBlocks; i++) {
+ byte[] dat = Arrays.copyOfRange(data, k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
+ byte[] block = Arrays.copyOf(dat, shortBlockLen + 1);
+ k += dat.length;
+ byte[] ecc = rs.getRemainder(dat);
+ System.arraycopy(ecc, 0, block, block.length - blockEccLen, ecc.length);
+ blocks[i] = block;
+ }
+
+ // Interleave (not concatenate) the bytes from every block into a single sequence
+ byte[] result = new byte[rawCodewords];
+ for (int i = 0, k = 0; i < blocks[0].length; i++) {
+ for (int j = 0; j < blocks.length; j++) {
+ // Skip the padding byte in short blocks
+ if (i != shortBlockLen - blockEccLen || j >= numShortBlocks) {
+ result[k] = blocks[j][i];
+ k++;
+ }
+ }
+ }
+ return result;
+ }
+
+
+ // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
+ // data area of this QR Code symbol. Function modules need to be marked off before this is called.
+ private void drawCodewords(byte[] data) {
+ Objects.requireNonNull(data);
+ if (data.length != getNumRawDataModules(version) / 8)
+ throw new IllegalArgumentException();
+
+ int i = 0; // Bit index into the data
+ // Do the funny zigzag scan
+ for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
+ if (right == 6)
+ right = 5;
+ for (int vert = 0; vert < size; vert++) { // Vertical counter
+ for (int j = 0; j < 2; j++) {
+ int x = right - j; // Actual x coordinate
+ boolean upward = ((right + 1) & 2) == 0;
+ int y = upward ? size - 1 - vert : vert; // Actual y coordinate
+ if (!isFunction[y][x] && i < data.length * 8) {
+ modules[y][x] = ((data[i >>> 3] >>> (7 - (i & 7))) & 1) != 0;
+ i++;
+ }
+ // If there are any remainder bits (0 to 7), they are already
+ // set to 0/false/white when the grid of modules was initialized
+ }
+ }
+ }
+ if (i != data.length * 8)
+ throw new AssertionError();
+ }
+
+
+ // XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical
+ // properties, calling applyMask(m) twice with the same value is equivalent to no change at all.
+ // This means it is possible to apply a mask, undo it, and try another mask. Note that a final
+ // well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.).
+ private void applyMask(int mask) {
+ if (mask < 0 || mask > 7)
+ throw new IllegalArgumentException("Mask value out of range");
+ for (int y = 0; y < size; y++) {
+ for (int x = 0; x < size; x++) {
+ boolean invert;
+ switch (mask) {
+ case 0: invert = (x + y) % 2 == 0; break;
+ case 1: invert = y % 2 == 0; break;
+ case 2: invert = x % 3 == 0; break;
+ case 3: invert = (x + y) % 3 == 0; break;
+ case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
+ case 5: invert = x * y % 2 + x * y % 3 == 0; break;
+ case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
+ case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
+ default: throw new AssertionError();
+ }
+ modules[y][x] ^= invert & !isFunction[y][x];
+ }
+ }
+ }
+
+
+ // A messy helper function for the constructors. This QR Code must be in an unmasked state when this
+ // method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
+ // This method applies and returns the actual mask chosen, from 0 to 7.
+ private int handleConstructorMasking(int mask) {
+ if (mask == -1) { // Automatically choose best mask
+ int minPenalty = Integer.MAX_VALUE;
+ for (int i = 0; i < 8; i++) {
+ drawFormatBits(i);
+ applyMask(i);
+ int penalty = getPenaltyScore();
+ if (penalty < minPenalty) {
+ mask = i;
+ minPenalty = penalty;
+ }
+ applyMask(i); // Undoes the mask due to XOR
+ }
+ }
+ if (mask < 0 || mask > 7)
+ throw new AssertionError();
+ drawFormatBits(mask); // Overwrite old format bits
+ applyMask(mask); // Apply the final choice of mask
+ return mask; // The caller shall assign this value to the final-declared field
+ }
+
+
+ // 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.
+ private int getPenaltyScore() {
+ int result = 0;
+
+ // Adjacent modules in row having same color
+ for (int y = 0; y < size; y++) {
+ boolean colorX = false;
+ for (int x = 0, runX = 0; x < size; x++) {
+ if (x == 0 || modules[y][x] != colorX) {
+ colorX = modules[y][x];
+ runX = 1;
+ } else {
+ runX++;
+ if (runX == 5)
+ result += PENALTY_N1;
+ else if (runX > 5)
+ result++;
+ }
+ }
+ }
+ // Adjacent modules in column having same color
+ for (int x = 0; x < size; x++) {
+ boolean colorY = false;
+ for (int y = 0, runY = 0; y < size; y++) {
+ if (y == 0 || modules[y][x] != colorY) {
+ colorY = modules[y][x];
+ runY = 1;
+ } else {
+ runY++;
+ if (runY == 5)
+ result += PENALTY_N1;
+ else if (runY > 5)
+ result++;
+ }
+ }
+ }
+
+ // 2*2 blocks of modules having same color
+ for (int y = 0; y < size - 1; y++) {
+ for (int x = 0; x < size - 1; x++) {
+ boolean color = modules[y][x];
+ if ( color == modules[y][x + 1] &&
+ color == modules[y + 1][x] &&
+ color == modules[y + 1][x + 1])
+ result += PENALTY_N2;
+ }
+ }
+
+ // Finder-like pattern in rows
+ for (int y = 0; y < size; y++) {
+ for (int x = 0, bits = 0; x < size; x++) {
+ bits = ((bits << 1) & 0x7FF) | (modules[y][x] ? 1 : 0);
+ if (x >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
+ result += PENALTY_N3;
+ }
+ }
+ // Finder-like pattern in columns
+ for (int x = 0; x < size; x++) {
+ for (int y = 0, bits = 0; y < size; y++) {
+ bits = ((bits << 1) & 0x7FF) | (modules[y][x] ? 1 : 0);
+ if (y >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
+ result += PENALTY_N3;
+ }
+ }
+
+ // Balance of black and white modules
+ int black = 0;
+ for (boolean[] row : modules) {
+ for (boolean color : row) {
+ if (color)
+ black++;
+ }
+ }
+ int total = size * size;
+ // Find smallest k such that (45-5k)% <= dark/total <= (55+5k)%
+ for (int k = 0; black*20 < (9-k)*total || black*20 > (11+k)*total; k++)
+ result += PENALTY_N4;
+ return result;
+ }
+
+
+
+ /*---- Private static helper functions ----*/
+
+ // Returns a set of positions of the alignment patterns in ascending order. These positions are
+ // used on both the x and y axes. Each value in the resulting array is in the range [0, 177).
+ // This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes.
+ private static int[] getAlignmentPatternPositions(int ver) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw new IllegalArgumentException("Version number out of range");
+ else if (ver == 1)
+ return new int[]{};
+ else {
+ int numAlign = ver / 7 + 2;
+ int step;
+ if (ver != 32) {
+ // ceil((size - 13) / (2*numAlign - 2)) * 2
+ step = (ver * 4 + numAlign * 2 + 1) / (2 * numAlign - 2) * 2;
+ } else // C-C-C-Combo breaker!
+ step = 26;
+
+ int[] result = new int[numAlign];
+ result[0] = 6;
+ for (int i = result.length - 1, pos = ver * 4 + 10; i >= 1; i--, pos -= step)
+ result[i] = pos;
+ return 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.
+ private static int getNumRawDataModules(int ver) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw new IllegalArgumentException("Version number out of range");
+
+ int size = ver * 4 + 17;
+ int result = size * size; // Number of modules in the whole QR symbol square
+ result -= 64 * 3; // Subtract the three finders with separators
+ result -= 15 * 2 + 1; // Subtract the format information and black module
+ result -= (size - 16) * 2; // Subtract the timing patterns
+ // The five lines above are equivalent to: int result = (16 * ver + 128) * ver + 64;
+ if (ver >= 2) {
+ int numAlign = ver / 7 + 2;
+ result -= (numAlign - 1) * (numAlign - 1) * 25; // Subtract alignment patterns not overlapping with timing patterns
+ result -= (numAlign - 2) * 2 * 20; // Subtract alignment patterns that overlap with timing patterns
+ // The two lines above are equivalent to: result -= (25 * numAlign - 10) * numAlign - 55;
+ if (ver >= 7)
+ result -= 18 * 2; // Subtract version information
+ }
+ return 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.
+ static int getNumDataCodewords(int ver, Ecc ecl) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw new IllegalArgumentException("Version number out of range");
+ return getNumRawDataModules(ver) / 8
+ - ECC_CODEWORDS_PER_BLOCK[ecl.ordinal()][ver]
+ * NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal()][ver];
+ }
+
+
+ /*---- Private tables of constants ----*/
+
+ // For use in getPenaltyScore(), when evaluating which mask is best.
+ private static final int PENALTY_N1 = 3;
+ private static final int PENALTY_N2 = 3;
+ private static final int PENALTY_N3 = 40;
+ private static final int PENALTY_N4 = 10;
+
+
+ private static final byte[][] ECC_CODEWORDS_PER_BLOCK = {
+ // 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
+ };
+
+ private static final byte[][] NUM_ERROR_CORRECTION_BLOCKS = {
+ // 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
+ };
+
+
+
+ /*---- Public helper enumeration ----*/
+
+ /**
+ * Represents the error correction level used in a QR Code symbol.
+ */
+ public enum Ecc {
+ // These enum constants must be declared in ascending order of error protection,
+ // for the sake of the implicit ordinal() method and values() function.
+ LOW(1), MEDIUM(0), QUARTILE(3), HIGH(2);
+
+ // In the range 0 to 3 (unsigned 2-bit integer).
+ final int formatBits;
+
+ // Constructor.
+ private Ecc(int fb) {
+ formatBits = fb;
+ }
+ }
+
+
+
+ /*---- Private helper class ----*/
+
+ /**
+ * Computes the Reed-Solomon error correction codewords for a sequence of data codewords
+ * at a given degree. Objects are immutable, and the state only depends on the degree.
+ * This class exists because each data block in a QR Code shares the same the divisor polynomial.
+ */
+ private static final class ReedSolomonGenerator {
+
+ /*-- Immutable field --*/
+
+ // Coefficients of the divisor polynomial, 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}.
+ private final byte[] coefficients;
+
+
+ /*-- Constructor --*/
+
+ /**
+ * Creates a Reed-Solomon ECC generator for the specified degree. This could be implemented
+ * as a lookup table over all possible parameter values, instead of as an algorithm.
+ * @param degree the divisor polynomial degree, which must be between 1 and 255
+ * @throws IllegalArgumentException if degree < 1 or degree > 255
+ */
+ public ReedSolomonGenerator(int degree) {
+ if (degree < 1 || degree > 255)
+ throw new IllegalArgumentException("Degree out of range");
+
+ // Start with the monomial x^0
+ coefficients = new byte[degree];
+ coefficients[degree - 1] = 1;
+
+ // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
+ // drop the highest term, and store the rest of the coefficients in order of descending powers.
+ // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
+ int root = 1;
+ for (int i = 0; i < degree; i++) {
+ // Multiply the current product by (x - r^i)
+ for (int j = 0; j < coefficients.length; j++) {
+ coefficients[j] = (byte)multiply(coefficients[j] & 0xFF, root);
+ if (j + 1 < coefficients.length)
+ coefficients[j] ^= coefficients[j + 1];
+ }
+ root = multiply(root, 0x02);
+ }
+ }
+
+
+ /*-- Method --*/
+
+ /**
+ * Computes and returns the Reed-Solomon error correction codewords for the specified
+ * sequence of data codewords. The returned object is always a new byte array.
+ * This method does not alter this object's state (because it is immutable).
+ * @param data the sequence of data codewords
+ * @return the Reed-Solomon error correction codewords
+ * @throws NullPointerException if the data is {@code null}
+ */
+ public byte[] getRemainder(byte[] data) {
+ Objects.requireNonNull(data);
+
+ // Compute the remainder by performing polynomial division
+ byte[] result = new byte[coefficients.length];
+ for (byte b : data) {
+ int factor = (b ^ result[0]) & 0xFF;
+ System.arraycopy(result, 1, result, 0, result.length - 1);
+ result[result.length - 1] = 0;
+ for (int i = 0; i < result.length; i++)
+ result[i] ^= multiply(coefficients[i] & 0xFF, factor);
+ }
+ return result;
+ }
+
+
+ /*-- Static function --*/
+
+ // Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
+ // are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
+ private static int multiply(int x, int y) {
+ if (x >>> 8 != 0 || y >>> 8 != 0)
+ throw new IllegalArgumentException("Byte out of range");
+ // Russian peasant multiplication
+ int z = 0;
+ for (int i = 7; i >= 0; i--) {
+ z = (z << 1) ^ ((z >>> 7) * 0x11D);
+ z ^= ((y >>> i) & 1) * x;
+ }
+ if (z >>> 8 != 0)
+ throw new AssertionError();
+ return z;
+ }
+
+ }
+
+}
diff --git a/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java
new file mode 100644
index 0000000..b05c2b2
--- /dev/null
+++ b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrCodeGeneratorDemo.java
@@ -0,0 +1,190 @@
+/*
+ * QR Code generator demo (Java)
+ *
+ * Run this command-line program with no arguments. The program creates/overwrites a bunch of
+ * PNG and SVG files in the current working directory to demonstrate the creation of QR Codes.
+ *
+ * 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.
+ */
+
+package io.nayuki.qrcodegen;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+import javax.imageio.ImageIO;
+
+
+public final class QrCodeGeneratorDemo {
+
+ // The main application program.
+ public static void main(String[] args) throws IOException {
+ doBasicDemo();
+ doVarietyDemo();
+ doSegmentDemo();
+ doMaskDemo();
+ }
+
+
+
+ /*---- Demo suite ----*/
+
+ // Creates a single QR Code, then writes it to a PNG file and an SVG file.
+ private static void doBasicDemo() throws IOException {
+ String text = "Hello, world!"; // User-supplied Unicode text
+ QrCode.Ecc errCorLvl = QrCode.Ecc.LOW; // Error correction level
+
+ QrCode qr = QrCode.encodeText(text, errCorLvl); // Make the QR Code symbol
+
+ BufferedImage img = qr.toImage(10, 4); // Convert to bitmap image
+ File imgFile = new File("hello-world-QR.png"); // File path for output
+ ImageIO.write(img, "png", imgFile); // Write image to file
+
+ String svg = qr.toSvgString(4); // Convert to SVG XML code
+ try (Writer out = new OutputStreamWriter(
+ new FileOutputStream("hello-world-QR.svg"),
+ StandardCharsets.UTF_8)) {
+ out.write(svg); // Create/overwrite file and write SVG data
+ }
+ }
+
+
+ // Creates a variety of QR Codes that exercise different features of the library, and writes each one to file.
+ private static void doVarietyDemo() throws IOException {
+ QrCode qr;
+
+ // Numeric mode encoding (3.33 bits per digit)
+ qr = QrCode.encodeText("314159265358979323846264338327950288419716939937510", QrCode.Ecc.MEDIUM);
+ writePng(qr.toImage(13, 1), "pi-digits-QR.png");
+
+ // Alphanumeric mode encoding (5.5 bits per character)
+ qr = QrCode.encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode.Ecc.HIGH);
+ writePng(qr.toImage(10, 2), "alphanumeric-QR.png");
+
+ // Unicode text as UTF-8
+ qr = QrCode.encodeText("こんにちwa、世界! αβγδ", QrCode.Ecc.QUARTILE);
+ writePng(qr.toImage(10, 3), "unicode-QR.png");
+
+ // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
+ qr = QrCode.encodeText(
+ "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.", QrCode.Ecc.HIGH);
+ writePng(qr.toImage(6, 10), "alice-wonderland-QR.png");
+ }
+
+
+ // Creates QR Codes with manually specified segments for better compactness.
+ private static void doSegmentDemo() throws IOException {
+ QrCode qr;
+ List<QrSegment> segs;
+
+ // Illustration "silver"
+ String silver0 = "THE SQUARE ROOT OF 2 IS 1.";
+ String silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
+ qr = QrCode.encodeText(silver0 + silver1, QrCode.Ecc.LOW);
+ writePng(qr.toImage(10, 3), "sqrt2-monolithic-QR.png");
+
+ segs = Arrays.asList(
+ QrSegment.makeAlphanumeric(silver0),
+ QrSegment.makeNumeric(silver1));
+ qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW);
+ writePng(qr.toImage(10, 3), "sqrt2-segmented-QR.png");
+
+ // Illustration "golden"
+ String golden0 = "Golden ratio φ = 1.";
+ String golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
+ String golden2 = "......";
+ qr = QrCode.encodeText(golden0 + golden1 + golden2, QrCode.Ecc.LOW);
+ writePng(qr.toImage(8, 5), "phi-monolithic-QR.png");
+
+ segs = Arrays.asList(
+ QrSegment.makeBytes(golden0.getBytes(StandardCharsets.UTF_8)),
+ QrSegment.makeNumeric(golden1),
+ QrSegment.makeAlphanumeric(golden2));
+ qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW);
+ writePng(qr.toImage(8, 5), "phi-segmented-QR.png");
+
+ // Illustration "Madoka": kanji, kana, Greek, Cyrillic, full-width Latin characters
+ String madoka = "「魔法少女まどか☆マギカ」って、 ИАИ desu κα?";
+ qr = QrCode.encodeText(madoka, QrCode.Ecc.LOW);
+ writePng(qr.toImage(9, 4), "madoka-utf8-QR.png");
+
+ int[] kanjiChars = { // 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,
+ };
+ BitBuffer bb = new BitBuffer();
+ for (int c : kanjiChars)
+ bb.appendBits(c, 13);
+ segs = Arrays.asList(new QrSegment(QrSegment.Mode.KANJI, kanjiChars.length, bb));
+ qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW);
+ writePng(qr.toImage(9, 4), "madoka-kanji-QR.png");
+ }
+
+
+ // Creates QR Codes with the same size and contents but different mask patterns.
+ private static void doMaskDemo() throws IOException {
+ QrCode qr;
+ List<QrSegment> segs;
+
+ // Project Nayuki URL
+ segs = QrSegment.makeSegments("https://www.nayuki.io/");
+ qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, -1, true); // Automatic mask
+ writePng(qr.toImage(8, 6), "project-nayuki-automask-QR.png");
+ qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 3, true); // Force mask 3
+ writePng(qr.toImage(8, 6), "project-nayuki-mask3-QR.png");
+
+ // Chinese text as UTF-8
+ segs = QrSegment.makeSegments("維基百科(Wikipedia,聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫");
+ qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 0, true); // Force mask 0
+ writePng(qr.toImage(10, 3), "unicode-mask0-QR.png");
+ qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 1, true); // Force mask 1
+ writePng(qr.toImage(10, 3), "unicode-mask1-QR.png");
+ qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 5, true); // Force mask 5
+ writePng(qr.toImage(10, 3), "unicode-mask5-QR.png");
+ qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 7, true); // Force mask 7
+ writePng(qr.toImage(10, 3), "unicode-mask7-QR.png");
+ }
+
+
+
+ /*---- Utilities ----*/
+
+ // Helper function to reduce code duplication.
+ private static void writePng(BufferedImage img, String filepath) throws IOException {
+ ImageIO.write(img, "png", new File(filepath));
+ }
+
+}
diff --git a/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrCodeGeneratorWorker.java b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrCodeGeneratorWorker.java
new file mode 100644
index 0000000..e9d7ecc
--- /dev/null
+++ b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrCodeGeneratorWorker.java
@@ -0,0 +1,103 @@
+/*
+ * QR Code generator test worker (Java)
+ *
+ * This program reads data and encoding parameters from standard input and writes
+ * QR Code bitmaps to standard output. The I/O format is one integer per line.
+ * Run with no command line arguments. The program is intended for automated
+ * batch testing of end-to-end functionality of this QR Code generator library.
+ *
+ * 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.
+ */
+
+package io.nayuki.qrcodegen;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+
+
+public final class QrCodeGeneratorWorker {
+
+ public static void main(String[] args) {
+ // Set up input stream and start loop
+ try (Scanner input = new Scanner(System.in, "US-ASCII")) {
+ input.useDelimiter("\r\n|\n|\r");
+ while (processCase(input));
+ }
+ }
+
+
+ private static boolean processCase(Scanner input) {
+ // Read data length or exit
+ int length = input.nextInt();
+ if (length == -1)
+ return false;
+ if (length > Short.MAX_VALUE)
+ throw new RuntimeException();
+
+ // Read data bytes
+ boolean isAscii = true;
+ byte[] data = new byte[length];
+ for (int i = 0; i < data.length; i++) {
+ int b = input.nextInt();
+ if (b < 0 || b > 255)
+ throw new RuntimeException();
+ data[i] = (byte)b;
+ isAscii &= b < 128;
+ }
+
+ // Read encoding parameters
+ int errCorLvl = input.nextInt();
+ int minVersion = input.nextInt();
+ int maxVersion = input.nextInt();
+ int mask = input.nextInt();
+ int boostEcl = input.nextInt();
+ if (!(0 <= errCorLvl && errCorLvl <= 3) || !(-1 <= mask && mask <= 7) || (boostEcl >>> 1) != 0
+ || !(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION))
+ throw new RuntimeException();
+
+ // Make segments for encoding
+ List<QrSegment> segs;
+ if (isAscii)
+ segs = QrSegment.makeSegments(new String(data, StandardCharsets.US_ASCII));
+ else
+ segs = Arrays.asList(QrSegment.makeBytes(data));
+
+
+ try { // Try to make QR Code symbol
+ QrCode qr = QrCode.encodeSegments(segs, QrCode.Ecc.values()[errCorLvl], minVersion, maxVersion, mask, boostEcl != 0);
+ // Print grid of modules
+ System.out.println(qr.version);
+ for (int y = 0; y < qr.size; y++) {
+ for (int x = 0; x < qr.size; x++)
+ System.out.println(qr.getModule(x, y) ? 1 : 0);
+ }
+
+ } catch (IllegalArgumentException e) {
+ if (!e.getMessage().equals("Data too long"))
+ throw e;
+ System.out.println(-1);
+ }
+ System.out.flush();
+ return true;
+ }
+
+}
diff --git a/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrSegment.java b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrSegment.java
new file mode 100644
index 0000000..a4e8a2a
--- /dev/null
+++ b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrSegment.java
@@ -0,0 +1,284 @@
+/*
+ * QR Code generator library (Java)
+ *
+ * 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.
+ */
+
+package io.nayuki.qrcodegen;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+
+/**
+ * Represents a character string to be encoded in a QR Code symbol. Each segment has
+ * a mode, and a sequence of characters that is already encoded as a sequence of bits.
+ * Instances of this class are immutable.
+ * <p>This segment class 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.</p>
+ */
+public final class QrSegment {
+
+ /*---- Static factory functions ----*/
+
+ /**
+ * Returns a segment representing the specified binary data encoded in byte mode.
+ * @param data the binary data
+ * @return a segment containing the data
+ * @throws NullPointerException if the array is {@code null}
+ */
+ public static QrSegment makeBytes(byte[] data) {
+ Objects.requireNonNull(data);
+ BitBuffer bb = new BitBuffer();
+ for (byte b : data)
+ bb.appendBits(b & 0xFF, 8);
+ return new QrSegment(Mode.BYTE, data.length, bb);
+ }
+
+
+ /**
+ * Returns a segment representing the specified string of decimal digits encoded in numeric mode.
+ * @param digits a string consisting of digits from 0 to 9
+ * @return a segment containing the data
+ * @throws NullPointerException if the string is {@code null}
+ * @throws IllegalArgumentException if the string contains non-digit characters
+ */
+ public static QrSegment makeNumeric(String digits) {
+ Objects.requireNonNull(digits);
+ if (!NUMERIC_REGEX.matcher(digits).matches())
+ throw new IllegalArgumentException("String contains non-numeric characters");
+
+ BitBuffer bb = new BitBuffer();
+ int i;
+ for (i = 0; i + 3 <= digits.length(); i += 3) // Process groups of 3
+ bb.appendBits(Integer.parseInt(digits.substring(i, i + 3)), 10);
+ int rem = digits.length() - i;
+ if (rem > 0) // 1 or 2 digits remaining
+ bb.appendBits(Integer.parseInt(digits.substring(i)), rem * 3 + 1);
+ return new QrSegment(Mode.NUMERIC, digits.length(), bb);
+ }
+
+
+ /**
+ * Returns a segment representing the specified 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.
+ * @param text a string of text, with only certain characters allowed
+ * @return a segment containing the data
+ * @throws NullPointerException if the string is {@code null}
+ * @throws IllegalArgumentException if the string contains non-encodable characters
+ */
+ public static QrSegment makeAlphanumeric(String text) {
+ Objects.requireNonNull(text);
+ if (!ALPHANUMERIC_REGEX.matcher(text).matches())
+ throw new IllegalArgumentException("String contains unencodable characters in alphanumeric mode");
+
+ BitBuffer bb = new BitBuffer();
+ int i;
+ for (i = 0; i + 2 <= text.length(); i += 2) { // Process groups of 2
+ int temp = ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45;
+ temp += ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));
+ bb.appendBits(temp, 11);
+ }
+ if (i < text.length()) // 1 character remaining
+ bb.appendBits(ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6);
+ return new QrSegment(Mode.ALPHANUMERIC, text.length(), bb);
+ }
+
+
+ /**
+ * Returns a new mutable list of zero or more segments to represent the specified Unicode text string.
+ * The result may use various segment modes and switch modes to optimize the length of the bit stream.
+ * @param text the text to be encoded, which can be any Unicode string
+ * @return a list of segments containing the text
+ * @throws NullPointerException if the text is {@code null}
+ */
+ public static List<QrSegment> makeSegments(String text) {
+ Objects.requireNonNull(text);
+
+ // Select the most efficient segment encoding automatically
+ List<QrSegment> result = new ArrayList<>();
+ if (text.equals("")); // Leave result empty
+ else if (NUMERIC_REGEX.matcher(text).matches())
+ result.add(makeNumeric(text));
+ else if (ALPHANUMERIC_REGEX.matcher(text).matches())
+ result.add(makeAlphanumeric(text));
+ else
+ result.add(makeBytes(text.getBytes(StandardCharsets.UTF_8)));
+ return result;
+ }
+
+
+ /**
+ * Returns a segment representing an Extended Channel Interpretation
+ * (ECI) designator with the specified assignment value.
+ * @param assignVal the ECI assignment number (see the AIM ECI specification)
+ * @return a segment containing the data
+ * @throws IllegalArgumentException if the value is outside the range [0, 10<sup>6</sup>)
+ */
+ public static QrSegment makeEci(int assignVal) {
+ BitBuffer bb = new BitBuffer();
+ if (0 <= assignVal && assignVal < (1 << 7))
+ bb.appendBits(assignVal, 8);
+ else if ((1 << 7) <= assignVal && assignVal < (1 << 14)) {
+ bb.appendBits(2, 2);
+ bb.appendBits(assignVal, 14);
+ } else if ((1 << 14) <= assignVal && assignVal < 1000000) {
+ bb.appendBits(6, 3);
+ bb.appendBits(assignVal, 21);
+ } else
+ throw new IllegalArgumentException("ECI assignment value out of range");
+ return new QrSegment(Mode.ECI, 0, bb);
+ }
+
+
+
+ /*---- Instance fields ----*/
+
+ /** The mode indicator for this segment. Never {@code null}. */
+ public final Mode mode;
+
+ /** The length of this segment's unencoded data, measured in characters. Always zero or positive. */
+ public final int numChars;
+
+ /** The data bits of this segment. Accessed through {@link getBits()}. Not {@code null}. */
+ final BitBuffer data;
+
+
+ /*---- Constructor ----*/
+
+ /**
+ * Creates a new QR Code data segment with the specified parameters and data.
+ * @param md the mode, which is not {@code null}
+ * @param numCh the data length in characters, which is non-negative
+ * @param data the data bits of this segment, which is not {@code null}
+ * @throws NullPointerException if the mode or bit buffer is {@code null}
+ * @throws IllegalArgumentException if the character count is negative
+ */
+ public QrSegment(Mode md, int numCh, BitBuffer data) {
+ Objects.requireNonNull(md);
+ Objects.requireNonNull(data);
+ if (numCh < 0)
+ throw new IllegalArgumentException("Invalid value");
+ mode = md;
+ numChars = numCh;
+ this.data = data.clone(); // Make defensive copy
+ }
+
+
+ /*---- Methods ----*/
+
+ /**
+ * Returns the data bits of this segment.
+ * @return the data bits of this segment (not {@code null})
+ */
+ public BitBuffer getBits() {
+ return data.clone(); // Make defensive copy
+ }
+
+
+ // Package-private helper function.
+ static int getTotalBits(List<QrSegment> segs, int version) {
+ Objects.requireNonNull(segs);
+ if (version < 1 || version > 40)
+ throw new IllegalArgumentException("Version number out of range");
+
+ long result = 0;
+ for (QrSegment seg : segs) {
+ Objects.requireNonNull(seg);
+ int ccbits = seg.mode.numCharCountBits(version);
+ // Fail if segment length value doesn't fit in the length field's bit-width
+ if (seg.numChars >= (1 << ccbits))
+ return -1;
+ result += 4L + ccbits + seg.data.bitLength();
+ if (result > Integer.MAX_VALUE)
+ return -1;
+ }
+ return (int)result;
+ }
+
+
+ /*---- Constants ----*/
+
+ /** Can test whether a string is encodable in numeric mode (such as by using {@link #makeNumeric(String)}). */
+ public static final Pattern NUMERIC_REGEX = Pattern.compile("[0-9]*");
+
+ /** Can test whether a string is encodable in alphanumeric mode (such as by using {@link #makeAlphanumeric(String)}). */
+ public static final Pattern ALPHANUMERIC_REGEX = Pattern.compile("[A-Z0-9 $%*+./:-]*");
+
+ /** The set of all legal characters in alphanumeric mode, where each character value maps to the index in the string. */
+ private static final String ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
+
+
+
+ /*---- Public helper enumeration ----*/
+
+ /**
+ * The mode field of a segment. Immutable. Provides methods to retrieve closely related values.
+ */
+ public enum Mode {
+
+ /*-- Constants --*/
+
+ NUMERIC (0x1, 10, 12, 14),
+ ALPHANUMERIC(0x2, 9, 11, 13),
+ BYTE (0x4, 8, 16, 16),
+ KANJI (0x8, 8, 10, 12),
+ ECI (0x7, 0, 0, 0);
+
+
+ /*-- Fields --*/
+
+ /** An unsigned 4-bit integer value (range 0 to 15) representing the mode indicator bits for this mode object. */
+ final int modeBits;
+
+ private final int[] numBitsCharCount;
+
+
+ /*-- Constructor --*/
+
+ private Mode(int mode, int... ccbits) {
+ this.modeBits = mode;
+ numBitsCharCount = ccbits;
+ }
+
+
+ /*-- Method --*/
+
+ /**
+ * Returns the bit width of the segment character count field for this mode object at the specified version number.
+ * @param ver the version number, which is between 1 to 40, inclusive
+ * @return the number of bits for the character count, which is between 8 to 16, inclusive
+ * @throws IllegalArgumentException if the version number is out of range
+ */
+ int numCharCountBits(int ver) {
+ if ( 1 <= ver && ver <= 9) return numBitsCharCount[0];
+ else if (10 <= ver && ver <= 26) return numBitsCharCount[1];
+ else if (27 <= ver && ver <= 40) return numBitsCharCount[2];
+ else throw new IllegalArgumentException("Version number out of range");
+ }
+
+ }
+
+}
diff --git a/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
new file mode 100644
index 0000000..34847e4
--- /dev/null
+++ b/src/third_party/QR-Code-generator/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
@@ -0,0 +1,402 @@
+/*
+ * QR Code generator library - Optional advanced logic (Java)
+ *
+ * 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.
+ */
+
+package io.nayuki.qrcodegen;
+
+import static io.nayuki.qrcodegen.QrSegment.Mode.ALPHANUMERIC;
+import static io.nayuki.qrcodegen.QrSegment.Mode.BYTE;
+import static io.nayuki.qrcodegen.QrSegment.Mode.NUMERIC;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.List;
+import java.util.Objects;
+
+
+public final class QrSegmentAdvanced {
+
+ /*---- Optimal list of segments encoder ----*/
+
+ /**
+ * Returns a new mutable list of zero or more segments to represent the specified Unicode text string.
+ * The resulting list optimally minimizes the total encoded bit length, subjected to the constraints given
+ * by the specified {error correction level, minimum version number, maximum version number}, plus the additional
+ * constraint that the segment modes {NUMERIC, ALPHANUMERIC, BYTE} can be used but KANJI cannot be used.
+ * <p>This function can be viewed as a significantly more sophisticated and slower replacement
+ * for {@link QrSegment#makeSegments(String)}, but requiring more input parameters in a way
+ * that overlaps with {@link QrCode#encodeSegments(List,QrCode.Ecc,int,int,int,boolean)}.</p>
+ * @param text the text to be encoded, which can be any Unicode string
+ * @param ecl the error correction level to use
+ * @param minVersion the minimum allowed version of the QR symbol (at least 1)
+ * @param maxVersion the maximum allowed version of the QR symbol (at most 40)
+ * @return a list of segments containing the text, minimizing the bit length with respect to the constraints
+ * @throws NullPointerException if the data or error correction level is {@code null}
+ * @throws IllegalArgumentException if 1 ≤ minVersion ≤ maxVersion ≤ 40 is violated,
+ * or if the data is too long to fit in a QR Code at maxVersion at the ECL
+ */
+ public static List<QrSegment> makeSegmentsOptimally(String text, QrCode.Ecc ecl, int minVersion, int maxVersion) {
+ // Check arguments
+ Objects.requireNonNull(text);
+ Objects.requireNonNull(ecl);
+ if (!(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40))
+ throw new IllegalArgumentException("Invalid value");
+
+ // Iterate through version numbers, and make tentative segments
+ List<QrSegment> segs = null;
+ for (int version = minVersion; version <= maxVersion; version++) {
+ if (version == minVersion || version == 10 || version == 27)
+ segs = makeSegmentsOptimally(text, version);
+
+ // Check if the segments fit
+ int dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8;
+ int dataUsedBits = QrSegment.getTotalBits(segs, version);
+ if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
+ return segs;
+ }
+ throw new IllegalArgumentException("Data too long");
+ }
+
+
+ // Returns a list of segments that is optimal for the given text at the given version number.
+ private static List<QrSegment> makeSegmentsOptimally(String text, int version) {
+ byte[] data = text.getBytes(StandardCharsets.UTF_8);
+ int[][] bitCosts = computeBitCosts(data, version);
+ QrSegment.Mode[] charModes = computeCharacterModes(data, version, bitCosts);
+ return splitIntoSegments(data, charModes);
+ }
+
+
+ private static int[][] computeBitCosts(byte[] data, int version) {
+ // Segment header sizes, measured in 1/6 bits
+ int bytesCost = (4 + BYTE .numCharCountBits(version)) * 6;
+ int alphnumCost = (4 + ALPHANUMERIC.numCharCountBits(version)) * 6;
+ int numberCost = (4 + NUMERIC .numCharCountBits(version)) * 6;
+
+ // result[mode][len] is the number of 1/6 bits to encode the first len characters of the text, ending in the mode
+ int[][] result = new int[3][data.length + 1];
+ Arrays.fill(result[1], Integer.MAX_VALUE / 2);
+ Arrays.fill(result[2], Integer.MAX_VALUE / 2);
+ result[0][0] = bytesCost;
+ result[1][0] = alphnumCost;
+ result[2][0] = numberCost;
+
+ // Calculate the cost table using dynamic programming
+ for (int i = 0; i < data.length; i++) {
+ // Encode a character
+ int j = i + 1;
+ char c = (char)data[i];
+ result[0][j] = result[0][i] + 48; // 8 bits per byte
+ if (isAlphanumeric(c))
+ result[1][j] = result[1][i] + 33; // 5.5 bits per alphanumeric char
+ if (isNumeric(c))
+ result[2][j] = result[2][i] + 20; // 3.33 bits per digit
+
+ // Switch modes, rounding up fractional bits
+ result[0][j] = Math.min((Math.min(result[1][j], result[2][j]) + 5) / 6 * 6 + bytesCost , result[0][j]);
+ result[1][j] = Math.min((Math.min(result[2][j], result[0][j]) + 5) / 6 * 6 + alphnumCost, result[1][j]);
+ result[2][j] = Math.min((Math.min(result[0][j], result[1][j]) + 5) / 6 * 6 + numberCost , result[2][j]);
+ }
+ return result;
+ }
+
+
+ private static QrSegment.Mode[] computeCharacterModes(byte[] data, int version, int[][] bitCosts) {
+ // Segment header sizes, measured in 1/6 bits
+ int bytesCost = (4 + BYTE .numCharCountBits(version)) * 6;
+ int alphnumCost = (4 + ALPHANUMERIC.numCharCountBits(version)) * 6;
+ int numberCost = (4 + NUMERIC .numCharCountBits(version)) * 6;
+
+ // Infer the mode used for last character by taking the minimum
+ QrSegment.Mode curMode;
+ int end = bitCosts[0].length - 1;
+ if (bitCosts[0][end] <= Math.min(bitCosts[1][end], bitCosts[2][end]))
+ curMode = BYTE;
+ else if (bitCosts[1][end] <= bitCosts[2][end])
+ curMode = ALPHANUMERIC;
+ else
+ curMode = NUMERIC;
+
+ // Work backwards to calculate optimal encoding mode for each character
+ QrSegment.Mode[] result = new QrSegment.Mode[data.length];
+ if (data.length == 0)
+ return result;
+ result[data.length - 1] = curMode;
+ for (int i = data.length - 2; i >= 0; i--) {
+ char c = (char)data[i];
+ if (curMode == NUMERIC) {
+ if (isNumeric(c))
+ curMode = NUMERIC;
+ else if (isAlphanumeric(c) && (bitCosts[1][i] + 33 + 5) / 6 * 6 + numberCost == bitCosts[2][i + 1])
+ curMode = ALPHANUMERIC;
+ else
+ curMode = BYTE;
+ } else if (curMode == ALPHANUMERIC) {
+ if (isNumeric(c) && (bitCosts[2][i] + 20 + 5) / 6 * 6 + alphnumCost == bitCosts[1][i + 1])
+ curMode = NUMERIC;
+ else if (isAlphanumeric(c))
+ curMode = ALPHANUMERIC;
+ else
+ curMode = BYTE;
+ } else if (curMode == BYTE) {
+ if (isNumeric(c) && (bitCosts[2][i] + 20 + 5) / 6 * 6 + bytesCost == bitCosts[0][i + 1])
+ curMode = NUMERIC;
+ else if (isAlphanumeric(c) && (bitCosts[1][i] + 33 + 5) / 6 * 6 + bytesCost == bitCosts[0][i + 1])
+ curMode = ALPHANUMERIC;
+ else
+ curMode = BYTE;
+ } else
+ throw new AssertionError();
+ result[i] = curMode;
+ }
+ return result;
+ }
+
+
+ private static List<QrSegment> splitIntoSegments(byte[] data, QrSegment.Mode[] charModes) {
+ List<QrSegment> result = new ArrayList<>();
+ if (data.length == 0)
+ return result;
+
+ // Accumulate run of modes
+ QrSegment.Mode curMode = charModes[0];
+ int start = 0;
+ for (int i = 1; i < data.length; i++) {
+ if (charModes[i] != curMode) {
+ if (curMode == BYTE)
+ result.add(QrSegment.makeBytes(Arrays.copyOfRange(data, start, i)));
+ else {
+ String temp = new String(data, start, i - start, StandardCharsets.US_ASCII);
+ if (curMode == NUMERIC)
+ result.add(QrSegment.makeNumeric(temp));
+ else if (curMode == ALPHANUMERIC)
+ result.add(QrSegment.makeAlphanumeric(temp));
+ else
+ throw new AssertionError();
+ }
+ curMode = charModes[i];
+ start = i;
+ }
+ }
+
+ // Final segment
+ if (curMode == BYTE)
+ result.add(QrSegment.makeBytes(Arrays.copyOfRange(data, start, data.length)));
+ else {
+ String temp = new String(data, start, data.length - start, StandardCharsets.US_ASCII);
+ if (curMode == NUMERIC)
+ result.add(QrSegment.makeNumeric(temp));
+ else if (curMode == ALPHANUMERIC)
+ result.add(QrSegment.makeAlphanumeric(temp));
+ else
+ throw new AssertionError();
+ }
+ return result;
+ }
+
+
+ private static boolean isAlphanumeric(char c) {
+ return isNumeric(c) || 'A' <= c && c <= 'Z' || " $%*+./:-".indexOf(c) != -1;
+ }
+
+ private static boolean isNumeric(char c) {
+ return '0' <= c && c <= '9';
+ }
+
+
+ /*---- Kanji mode segment encoder ----*/
+
+ /**
+ * Returns a segment representing the specified string encoded in kanji mode.
+ * <p>Note that broadly speaking, the set of encodable characters are {kanji used in Japan, hiragana, katakana,
+ * Asian punctuation, full-width ASCII}.<br/>
+ * In particular, non-encodable characters are {normal ASCII, half-width katakana, more extensive Chinese hanzi}.
+ * @param text the text to be encoded, which must fall in the kanji mode subset of characters
+ * @return a segment containing the data
+ * @throws NullPointerException if the string is {@code null}
+ * @throws IllegalArgumentException if the string contains non-kanji-mode characters
+ * @see #isEncodableAsKanji(String)
+ */
+ public static QrSegment makeKanjiSegment(String text) {
+ Objects.requireNonNull(text);
+ BitBuffer bb = new BitBuffer();
+ for (int i = 0; i < text.length(); i++) {
+ int val = UNICODE_TO_QR_KANJI[text.charAt(i)];
+ if (val == -1)
+ throw new IllegalArgumentException("String contains non-kanji-mode characters");
+ bb.appendBits(val, 13);
+ }
+ return new QrSegment(QrSegment.Mode.KANJI, text.length(), bb);
+ }
+
+
+ /**
+ * Tests whether the specified text string can be encoded as a segment in kanji mode.
+ * <p>Note that broadly speaking, the set of encodable characters are {kanji used in Japan, hiragana, katakana,
+ * Asian punctuation, full-width ASCII}.<br/>
+ * In particular, non-encodable characters are {normal ASCII, half-width katakana, more extensive Chinese hanzi}.
+ * @param text the string to test for encodability
+ * @return {@code true} if and only if the string can be encoded in kanji mode
+ * @throws NullPointerException if the string is {@code null}
+ * @see #makeKanjiSegment(String)
+ */
+ public static boolean isEncodableAsKanji(String text) {
+ Objects.requireNonNull(text);
+ for (int i = 0; i < text.length(); i++) {
+ if (UNICODE_TO_QR_KANJI[text.charAt(i)] == -1)
+ return false;
+ }
+ return true;
+ }
+
+
+ // Data derived from ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT
+ private static final String PACKED_QR_KANJI_TO_UNICODE =
+ "MAAwATAC/wz/DjD7/xr/G/8f/wEwmzCcALT/QACo/z7/4/8/MP0w/jCdMJ4wA07dMAUwBjAHMPwgFSAQ/w8AXDAcIBb/XCAmICUgGCAZIBwgHf8I/wkwFDAV/zv/Pf9b/10wCDAJMAowCzAMMA0wDjAPMBAwEf8LIhIAsQDX//8A9/8dImD/HP8eImYiZyIeIjQmQiZA" +
+ "ALAgMiAzIQP/5f8EAKIAo/8F/wP/Bv8K/yAApyYGJgUlyyXPJc4lxyXGJaEloCWzJbIlvSW8IDswEiGSIZAhkSGTMBP/////////////////////////////IggiCyKGIocigiKDIioiKf////////////////////8iJyIoAKwh0iHUIgAiA///////////////////" +
+ "//////////8iICKlIxIiAiIHImEiUiJqImsiGiI9Ih0iNSIrIiz//////////////////yErIDAmbyZtJmogICAhALb//////////yXv/////////////////////////////////////////////////xD/Ef8S/xP/FP8V/xb/F/8Y/xn///////////////////8h" +
+ "/yL/I/8k/yX/Jv8n/yj/Kf8q/yv/LP8t/y7/L/8w/zH/Mv8z/zT/Nf82/zf/OP85/zr///////////////////9B/0L/Q/9E/0X/Rv9H/0j/Sf9K/0v/TP9N/07/T/9Q/1H/Uv9T/1T/Vf9W/1f/WP9Z/1r//////////zBBMEIwQzBEMEUwRjBHMEgwSTBKMEswTDBN" +
+ "ME4wTzBQMFEwUjBTMFQwVTBWMFcwWDBZMFowWzBcMF0wXjBfMGAwYTBiMGMwZDBlMGYwZzBoMGkwajBrMGwwbTBuMG8wcDBxMHIwczB0MHUwdjB3MHgweTB6MHswfDB9MH4wfzCAMIEwgjCDMIQwhTCGMIcwiDCJMIowizCMMI0wjjCPMJAwkTCSMJP/////////////" +
+ "////////////////////////MKEwojCjMKQwpTCmMKcwqDCpMKowqzCsMK0wrjCvMLAwsTCyMLMwtDC1MLYwtzC4MLkwujC7MLwwvTC+ML8wwDDBMMIwwzDEMMUwxjDHMMgwyTDKMMswzDDNMM4wzzDQMNEw0jDTMNQw1TDWMNcw2DDZMNow2zDcMN0w3jDf//8w4DDh" +
+ "MOIw4zDkMOUw5jDnMOgw6TDqMOsw7DDtMO4w7zDwMPEw8jDzMPQw9TD2/////////////////////wORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDowOkA6UDpgOnA6gDqf////////////////////8DsQOyA7MDtAO1A7YDtwO4A7kDugO7A7wDvQO+" +
+ "A78DwAPBA8MDxAPFA8YDxwPIA8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////BBAEEQQSBBMEFAQVBAEEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQm" +
+ "BCcEKAQpBCoEKwQsBC0ELgQv////////////////////////////////////////BDAEMQQyBDMENAQ1BFEENgQ3BDgEOQQ6BDsEPAQ9//8EPgQ/BEAEQQRCBEMERARFBEYERwRIBEkESgRLBEwETQROBE///////////////////////////////////yUAJQIlDCUQ" +
+ "JRglFCUcJSwlJCU0JTwlASUDJQ8lEyUbJRclIyUzJSslOyVLJSAlLyUoJTclPyUdJTAlJSU4JUL/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "/////////////////////////////////////06cVRZaA5Y/VMBhG2MoWfaQIoR1gxx6UGCqY+FuJWXthGaCppv1aJNXJ2WhYnFbm1nQhnuY9H1ifb6bjmIWfJ+It1uJXrVjCWaXaEiVx5eNZ09O5U8KT01PnVBJVvJZN1nUWgFcCWDfYQ9hcGYTaQVwunVPdXB5+32t" +
+ "fe+Aw4QOiGOLApBVkHpTO06VTqVX34CykMF4704AWPFuopA4ejKDKIKLnC9RQVNwVL1U4VbgWftfFZjybeuA5IUt////////lmKWcJagl/tUC1PzW4dwz3+9j8KW6FNvnVx6uk4ReJOB/G4mVhhVBGsdhRqcO1nlU6ltZnTclY9WQk6RkEuW8oNPmQxT4VW2WzBfcWYg" +
+ "ZvNoBGw4bPNtKXRbdsh6Tpg0gvGIW4pgku1tsnWrdsqZxWCmiwGNipWyaY5TrVGG//9XElgwWURbtF72YChjqWP0bL9vFHCOcRRxWXHVcz9+AYJ2gtGFl5BgkludG1hpZbxsWnUlUflZLlllX4Bf3GK8ZfpqKmsna7Rzi3/BiVadLJ0OnsRcoWyWg3tRBFxLYbaBxmh2" +
+ "cmFOWU/6U3hgaW4pek+X804LUxZO7k9VTz1PoU9zUqBT71YJWQ9awVu2W+F50WaHZ5xntmtMbLNwa3PCeY15vno8e4eCsYLbgwSDd4Pvg9OHZoqyVimMqI/mkE6XHoaKT8Rc6GIRcll1O4Hlgr2G/ozAlsWZE5nVTstPGonjVt5YSljKXvtf62AqYJRgYmHQYhJi0GU5" +
+ "////////m0FmZmiwbXdwcHVMdoZ9dYKlh/mVi5aOjJ1R8VK+WRZUs1uzXRZhaGmCba94jYTLiFeKcpOnmrhtbJmohtlXo2f/hs6SDlKDVodUBF7TYuFkuWg8aDhru3NyeLp6a4maidKNa48DkO2Vo5aUl2lbZlyzaX2YTZhOY5t7IGor//9qf2i2nA1vX1JyVZ1gcGLs" +
+ "bTtuB27RhFuJEI9EThScOVP2aRtqOpeEaCpRXHrDhLKR3JOMVludKGgigwWEMXylUgiCxXTmTn5Pg1GgW9JSClLYUudd+1WaWCpZ5luMW5hb215yXnlgo2EfYWNhvmPbZWJn0WhTaPprPmtTbFdvIm+Xb0V0sHUYduN3C3r/e6F8IX3pfzZ/8ICdgmaDnomzisyMq5CE" +
+ "lFGVk5WRlaKWZZfTmSiCGE44VCtcuF3Mc6l2THc8XKl/640LlsGYEZhUmFhPAU8OU3FVnFZoV/pZR1sJW8RckF4MXn5fzGPuZzpl12XiZx9oy2jE////////al9eMGvFbBdsfXV/eUhbY3oAfQBfvYmPihiMtI13jsyPHZjimg6bPE6AUH1RAFmTW5xiL2KAZOxrOnKg" +
+ "dZF5R3+ph/uKvItwY6yDypegVAlUA1WraFRqWIpweCdndZ7NU3RbooEahlCQBk4YTkVOx08RU8pUOFuuXxNgJWVR//9nPWxCbHJs43B4dAN6dnquewh9Gnz+fWZl53JbU7tcRV3oYtJi4GMZbiCGWooxjd2S+G8BeaabWk6oTqtOrE+bT6BQ0VFHevZRcVH2U1RTIVN/" +
+ "U+tVrFiDXOFfN19KYC9gUGBtYx9lWWpLbMFywnLtd++A+IEFggiFTpD3k+GX/5lXmlpO8FHdXC1mgWltXEBm8ml1c4loUHyBUMVS5FdHXf6TJmWkayNrPXQ0eYF5vXtLfcqCuYPMiH+JX4s5j9GR0VQfkoBOXVA2U+VTOnLXc5Z36YLmjq+ZxpnImdJRd2Eahl5VsHp6" +
+ "UHZb05BHloVOMmrbkedcUVxI////////Y5h6n2yTl3SPYXqqcYqWiHyCaBd+cGhRk2xS8lQbhauKE3+kjs2Q4VNmiIh5QU/CUL5SEVFEVVNXLXPqV4tZUV9iX4RgdWF2YWdhqWOyZDplbGZvaEJuE3Vmej18+31MfZl+S39rgw6DSobNigiKY4tmjv2YGp2PgriPzpvo" +
+ "//9Sh2IfZINvwJaZaEFQkWsgbHpvVHp0fVCIQIojZwhO9lA5UCZQZVF8UjhSY1WnVw9YBVrMXvphsmH4YvNjcmkcailyfXKscy54FHhvfXl3DICpiYuLGYzijtKQY5N1lnqYVZoTnnhRQ1OfU7Nee18mbhtukHOEc/59Q4I3igCK+pZQTk5QC1PkVHxW+lnRW2Rd8V6r" +
+ "XydiOGVFZ69uVnLQfMqItIChgOGD8IZOioeN6JI3lseYZ58TTpROkk8NU0hUSVQ+Wi9fjF+hYJ9op2qOdFp4gYqeiqSLd5GQTl6byU6kT3xPr1AZUBZRSVFsUp9SuVL+U5pT41QR////////VA5ViVdRV6JZfVtUW11bj13lXedd9154XoNeml63XxhgUmFMYpdi2GOn" +
+ "ZTtmAmZDZvRnbWghaJdpy2xfbSptaW4vbp11MnaHeGx6P3zgfQV9GH1efbGAFYADgK+AsYFUgY+CKoNSiEyIYYsbjKKM/JDKkXWScXg/kvyVpJZN//+YBZmZmtidO1JbUqtT91QIWNVi92/gjGqPX565UUtSO1RKVv16QJF3nWCe0nNEbwmBcHURX/1g2pqoctuPvGtk" +
+ "mANOylbwV2RYvlpaYGhhx2YPZgZoOWixbfd11X06gm6bQk6bT1BTyVUGXW9d5l3uZ/tsmXRzeAKKUJOWiN9XUF6nYytQtVCsUY1nAFTJWF5Zu1uwX2liTWOhaD1rc24IcH2Rx3KAeBV4JnltZY59MIPciMGPCZabUmRXKGdQf2qMoVG0V0KWKlg6aYqAtFSyXQ5X/HiV" +
+ "nfpPXFJKVItkPmYoZxRn9XqEe1Z9IpMvaFybrXs5UxlRilI3////////W99i9mSuZOZnLWu6hamW0XaQm9ZjTJMGm6t2v2ZSTglQmFPCXHFg6GSSZWNoX3Hmc8p1I3uXfoKGlYuDjNuReJkQZaxmq2uLTtVO1E86T39SOlP4U/JV41bbWOtZy1nJWf9bUFxNXgJeK1/X" +
+ "YB1jB2UvW1xlr2W9ZehnnWti//9re2wPc0V5SXnBfPh9GX0rgKKBAoHziZaKXoppimaKjIrujMeM3JbMmPxrb06LTzxPjVFQW1db+mFIYwFmQmshbstsu3I+dL111HjBeTqADIAzgeqElI+ebFCef18Pi1idK3r6jvhbjZbrTgNT8Vf3WTFayVukYIluf28Gdb6M6luf" +
+ "hQB74FByZ/SCnVxhhUp+HoIOUZlcBGNojWZlnHFueT59F4AFix2OypBuhseQqlAfUvpcOmdTcHxyNZFMkciTK4LlW8JfMWD5TjtT1luIYktnMWuKculz4HougWuNo5FSmZZRElPXVGpb/2OIajl9rJcAVtpTzlRo////////W5dcMV3eT+5hAWL+bTJ5wHnLfUJ+TX/S" +
+ "ge2CH4SQiEaJcouQjnSPL5AxkUuRbJbGkZxOwE9PUUVTQV+TYg5n1GxBbgtzY34mkc2Sg1PUWRlbv23ReV1+LnybWH5xn1H6iFOP8E/KXPtmJXeseuOCHJn/UcZfqmXsaW9riW3z//9ulm9kdv59FF3hkHWRh5gGUeZSHWJAZpFm2W4aXrZ90n9yZviFr4X3ivhSqVPZ" +
+ "WXNej1+QYFWS5JZkULdRH1LdUyBTR1PsVOhVRlUxVhdZaFm+WjxbtVwGXA9cEVwaXoReil7gX3Bif2KEYttjjGN3ZgdmDGYtZnZnfmiiah9qNWy8bYhuCW5YcTxxJnFndcd3AXhdeQF5ZXnweuB7EXynfTmAloPWhIuFSYhdiPOKH4o8ilSKc4xhjN6RpJJmk36UGJac" +
+ "l5hOCk4ITh5OV1GXUnBXzlg0WMxbIl44YMVk/mdhZ1ZtRHK2dXN6Y4S4i3KRuJMgVjFX9Jj+////////Yu1pDWuWce1+VIB3gnKJ5pjfh1WPsVw7TzhP4U+1VQdaIFvdW+lfw2FOYy9lsGZLaO5pm214bfF1M3W5dx95XnnmfTOB44KvhaqJqoo6jquPm5Aykd2XB066" +
+ "TsFSA1h1WOxcC3UaXD2BTooKj8WWY5dteyWKz5gIkWJW81Oo//+QF1Q5V4JeJWOobDRwindhfIt/4IhwkEKRVJMQkxiWj3RemsRdB11pZXBnoo2olttjbmdJaRmDxZgXlsCI/m+EZHpb+E4WcCx1XWYvUcRSNlLiWdNfgWAnYhBlP2V0Zh9mdGjyaBZrY24FcnJ1H3bb" +
+ "fL6AVljwiP2Jf4qgipOKy5AdkZKXUpdZZYl6DoEGlrteLWDcYhplpWYUZ5B383pNfE1+PoEKjKyNZI3hjl94qVIHYtljpWRCYpiKLXqDe8CKrJbqfXaCDIdJTtlRSFNDU2Bbo1wCXBZd3WImYkdksGgTaDRsyW1FbRdn029ccU5xfWXLen97rX3a////////fkp/qIF6" +
+ "ghuCOYWmim6Mzo31kHiQd5KtkpGVg5uuUk1VhG84cTZRaHmFflWBs3zOVkxYUVyoY6pm/mb9aVpy2XWPdY55DnlWed98l30gfUSGB4o0ljuQYZ8gUOdSdVPMU+JQCVWqWO5ZT3I9W4tcZFMdYONg82NcY4NjP2O7//9kzWXpZvld42nNaf1vFXHlTol16Xb4epN8333P" +
+ "fZyAYYNJg1iEbIS8hfuIxY1wkAGQbZOXlxyaElDPWJdhjoHThTWNCJAgT8NQdFJHU3Ngb2NJZ19uLI2zkB9P11xejMplz32aU1KIllF2Y8NbWFtrXApkDWdRkFxO1lkaWSpscIpRVT5YFVmlYPBiU2fBgjVpVZZAmcSaKE9TWAZb/oAQXLFeL1+FYCBhS2I0Zv9s8G7e" +
+ "gM6Bf4LUiIuMuJAAkC6Wip7bm9tO41PwWSd7LJGNmEyd+W7dcCdTU1VEW4ViWGKeYtNsom/vdCKKF5Q4b8GK/oM4UeeG+FPq////////U+lPRpBUj7BZaoExXf166o+/aNqMN3L4nEhqPYqwTjlTWFYGV2ZixWOiZeZrTm3hbltwrXfteu97qn27gD2AxobLipWTW1bj" +
+ "WMdfPmWtZpZqgGu1dTeKx1Akd+VXMF8bYGVmemxgdfR6Gn9ugfSHGJBFmbN7yXVcevl7UYTE//+QEHnpepKDNlrhd0BOLU7yW5lf4GK9Zjxn8WzohmuId4o7kU6S85nQahdwJnMqgueEV4yvTgFRRlHLVYtb9V4WXjNegV8UXzVfa1+0YfJjEWaiZx1vbnJSdTp3OoB0" +
+ "gTmBeId2ir+K3I2FjfOSmpV3mAKc5VLFY1d29GcVbIhzzYzDk66Wc20lWJxpDmnMj/2TmnXbkBpYWmgCY7Rp+09Dbyxn2I+7hSZ9tJNUaT9vcFdqWPdbLH0scipUCpHjnbROrU9OUFxQdVJDjJ5USFgkW5peHV6VXq1e918fYIxitWM6Y9Bor2xAeId5jnoLfeCCR4oC" +
+ "iuaORJAT////////kLiRLZHYnw5s5WRYZOJldW70doR7G5Bpk9FuulTyX7lkpI9Nj+2SRFF4WGtZKVxVXpdt+36PdRyMvI7imFtwuU8da79vsXUwlvtRTlQQWDVYV1msXGBfkmWXZ1xuIXZ7g9+M7ZAUkP2TTXgleDpSql6mVx9ZdGASUBJRWlGs//9RzVIAVRBYVFhY" +
+ "WVdblVz2XYtgvGKVZC1ncWhDaLxo33bXbdhub22bcG9xyF9Tddh5d3tJe1R7UnzWfXFSMIRjhWmF5IoOiwSMRo4PkAOQD5QZlnaYLZowldhQzVLVVAxYAlwOYadknm0ed7N65YD0hASQU5KFXOCdB1M/X5dfs22ccnl3Y3m/e+Rr0nLsiq1oA2phUfh6gWk0XEqc9oLr" +
+ "W8WRSXAeVnhcb2DHZWZsjIxakEGYE1RRZseSDVlIkKNRhU5NUeqFmYsOcFhjepNLaWKZtH4EdXdTV2lgjt+W42xdToxcPF8Qj+lTAozRgImGeV7/ZeVOc1Fl////////WYJcP5fuTvtZil/Nio1v4XmweWJb54RxcytxsV50X/Vje2SaccN8mE5DXvxOS1fcVqJgqW/D" +
+ "fQ2A/YEzgb+PsomXhqRd9GKKZK2Jh2d3bOJtPnQ2eDRaRn91gq2ZrE/zXsNi3WOSZVdnb3bDckyAzIC6jymRTVANV/lakmiF//9pc3Fkcv2Mt1jyjOCWapAZh3955HfnhClPL1JlU1pizWfPbMp2fXuUfJWCNoWEj+tm3W8gcgZ+G4OrmcGeplH9e7F4cnu4gId7SGro" +
+ "XmGAjHVRdWBRa5Jibox2epGXmupPEH9wYpx7T5WlnOlWelhZhuSWvE80UiRTSlPNU9teBmQsZZFnf2w+bE5ySHKvc+11VH5BgiyF6Yype8SRxnFpmBKY72M9Zml1anbkeNCFQ4buUypTUVQmWYNeh198YLJiSWJ5YqtlkGvUbMx1snaueJF52H3Lf3eApYirirmMu5B/" +
+ "l16Y22oLfDhQmVw+X65nh2vYdDV3CX+O////////nztnynoXUzl1i5rtX2aBnYPxgJhfPF/FdWJ7RpA8aGdZ61qbfRB2fossT/VfamoZbDdvAnTieWiIaIpVjHle32PPdcV50oLXkyiS8oSchu2cLVTBX2xljG1ccBWMp4zTmDtlT3T2Tg1O2FfgWStaZlvMUaheA16c" +
+ "YBZidmV3//9lp2ZubW5yNnsmgVCBmoKZi1yMoIzmjXSWHJZET65kq2tmgh6EYYVqkOhcAWlTmKiEeoVXTw9Sb1+pXkVnDXmPgXmJB4mGbfVfF2JVbLhOz3Jpm5JSBlQ7VnRYs2GkYm5xGllufIl83n0blvBlh4BeThlPdVF1WEBeY15zXwpnxE4mhT2ViZZbfHOYAVD7" +
+ "WMF2VninUiV3pYURe4ZQT1kJckd7x33oj7qP1JBNT79SyVopXwGXrU/dgheS6lcDY1VraXUriNyPFHpCUt9Yk2FVYgpmrmvNfD+D6VAjT/hTBVRGWDFZSVudXPBc710pXpZisWNnZT5luWcL////////bNVs4XD5eDJ+K4DegrOEDITshwKJEooqjEqQppLSmP2c851s" +
+ "Tk9OoVCNUlZXSlmoXj1f2F/ZYj9mtGcbZ9Bo0lGSfSGAqoGoiwCMjIy/kn6WMlQgmCxTF1DVU1xYqGSyZzRyZ3dmekaR5lLDbKFrhlgAXkxZVGcsf/tR4XbG//9kaXjom1Seu1fLWblmJ2eaa85U6WnZXlWBnGeVm6pn/pxSaF1Opk/jU8hiuWcrbKuPxE+tfm2ev04H" +
+ "YWJugG8rhRNUc2cqm0Vd83uVXKxbxoccbkqE0XoUgQhZmXyNbBF3IFLZWSJxIXJfd9uXJ51haQtaf1oYUaVUDVR9Zg5234/3kpic9Fnqcl1uxVFNaMl9v33sl2KeumR4aiGDAlmEW19r23MbdvJ9soAXhJlRMmcontl27mdiUv+ZBVwkYjt8foywVU9gtn0LlYBTAU5f" +
+ "UbZZHHI6gDaRzl8ld+JThF95fQSFrIozjo2XVmfzha6UU2EJYQhsuXZS////////iu2POFUvT1FRKlLHU8tbpV59YKBhgmPWZwln2m5nbYxzNnM3dTF5UIjVipiQSpCRkPWWxIeNWRVOiE9ZTg6KiY8/mBBQrV58WZZbuV64Y9pj+mTBZtxpSmnYbQtutnGUdSh6r3+K" +
+ "gACESYTJiYGLIY4KkGWWfZkKYX5ikWsy//9sg210f8x//G3Af4WHuoj4Z2WDsZg8lvdtG31hhD2Rak5xU3VdUGsEb+uFzYYtiadSKVQPXGVnTmiodAZ0g3XiiM+I4ZHMluKWeF+Lc4d6y4ROY6B1ZVKJbUFunHQJdVl4a3ySloZ63J+NT7ZhbmXFhlxOhk6uUNpOIVHM" +
+ "W+5lmWiBbbxzH3ZCd616HHzngm+K0pB8kc+WdZgYUpt90VArU5hnl23LcdB0M4HojyqWo5xXnp90YFhBbZl9L5heTuRPNk+LUbdSsV26YBxzsnk8gtOSNJa3lvaXCp6Xn2Jmpmt0UhdSo3DIiMJeyWBLYZBvI3FJfD599IBv////////hO6QI5MsVEKbb2rTcImMwo3v" +
+ "lzJStFpBXspfBGcXaXxplG1qbw9yYnL8e+2AAYB+h0uQzlFtnpN5hICLkzKK1lAtVIyKcWtqjMSBB2DRZ6Cd8k6ZTpicEIprhcGFaGkAbn54l4FV////////////////////////////////////////////////////////////////////////////////////////" +
+ "/////////////////////////////18MThBOFU4qTjFONk48Tj9OQk5WTlhOgk6FjGtOioISXw1Ojk6eTp9OoE6iTrBOs062Ts5OzU7ETsZOwk7XTt5O7U7fTvdPCU9aTzBPW09dT1dPR092T4hPj0+YT3tPaU9wT5FPb0+GT5ZRGE/UT99Pzk/YT9tP0U/aT9BP5E/l" +
+ "UBpQKFAUUCpQJVAFTxxP9lAhUClQLE/+T+9QEVAGUENQR2cDUFVQUFBIUFpQVlBsUHhQgFCaUIVQtFCy////////UMlQylCzUMJQ1lDeUOVQ7VDjUO5Q+VD1UQlRAVECURZRFVEUURpRIVE6UTdRPFE7UT9RQFFSUUxRVFFievhRaVFqUW5RgFGCVthRjFGJUY9RkVGT" +
+ "UZVRllGkUaZRolGpUapRq1GzUbFRslGwUbVRvVHFUclR21HghlVR6VHt//9R8FH1Uf5SBFILUhRSDlInUipSLlIzUjlST1JEUktSTFJeUlRSalJ0UmlSc1J/Un1SjVKUUpJScVKIUpGPqI+nUqxSrVK8UrVSwVLNUtdS3lLjUuaY7VLgUvNS9VL4UvlTBlMIdThTDVMQ" +
+ "Uw9TFVMaUyNTL1MxUzNTOFNAU0ZTRU4XU0lTTVHWU15TaVNuWRhTe1N3U4JTllOgU6ZTpVOuU7BTtlPDfBKW2VPfZvxx7lPuU+hT7VP6VAFUPVRAVCxULVQ8VC5UNlQpVB1UTlSPVHVUjlRfVHFUd1RwVJJUe1SAVHZUhFSQVIZUx1SiVLhUpVSsVMRUyFSo////////" +
+ "VKtUwlSkVL5UvFTYVOVU5lUPVRRU/VTuVO1U+lTiVTlVQFVjVUxVLlVcVUVVVlVXVThVM1VdVZlVgFSvVYpVn1V7VX5VmFWeVa5VfFWDValVh1WoVdpVxVXfVcRV3FXkVdRWFFX3VhZV/lX9VhtV+VZOVlBx31Y0VjZWMlY4//9Wa1ZkVi9WbFZqVoZWgFaKVqBWlFaP" +
+ "VqVWrla2VrRWwla8VsFWw1bAVshWzlbRVtNW11buVvlXAFb/VwRXCVcIVwtXDVcTVxhXFlXHVxxXJlc3VzhXTlc7V0BXT1dpV8BXiFdhV39XiVeTV6BXs1ekV6pXsFfDV8ZX1FfSV9NYClfWV+NYC1gZWB1YclghWGJYS1hwa8BYUlg9WHlYhVi5WJ9Yq1i6WN5Yu1i4" +
+ "WK5YxVjTWNFY11jZWNhY5VjcWORY31jvWPpY+Vj7WPxY/VkCWQpZEFkbaKZZJVksWS1ZMlk4WT560llVWVBZTllaWVhZYllgWWdZbFlp////////WXhZgVmdT15Pq1mjWbJZxlnoWdxZjVnZWdpaJVofWhFaHFoJWhpaQFpsWklaNVo2WmJaalqaWrxavlrLWsJavVrj" +
+ "Wtda5lrpWtZa+lr7WwxbC1sWWzJa0FsqWzZbPltDW0VbQFtRW1VbWltbW2VbaVtwW3NbdVt4ZYhbeluA//9bg1umW7hbw1vHW8lb1FvQW+Rb5lviW95b5VvrW/Bb9lvzXAVcB1wIXA1cE1wgXCJcKFw4XDlcQVxGXE5cU1xQXE9bcVxsXG5OYlx2XHlcjFyRXJRZm1yr" +
+ "XLtctly8XLdcxVy+XMdc2VzpXP1c+lztXYxc6l0LXRVdF11cXR9dG10RXRRdIl0aXRldGF1MXVJdTl1LXWxdc112XYddhF2CXaJdnV2sXa5dvV2QXbddvF3JXc1d013SXdZd213rXfJd9V4LXhpeGV4RXhteNl43XkReQ15AXk5eV15UXl9eYl5kXkdedV52XnqevF5/" +
+ "XqBewV7CXshe0F7P////////XtZe417dXtpe217iXuFe6F7pXuxe8V7zXvBe9F74Xv5fA18JX11fXF8LXxFfFl8pXy1fOF9BX0hfTF9OXy9fUV9WX1dfWV9hX21fc193X4Nfgl9/X4pfiF+RX4dfnl+ZX5hfoF+oX61fvF/WX/tf5F/4X/Ff3WCzX/9gIWBg//9gGWAQ" +
+ "YClgDmAxYBtgFWArYCZgD2A6YFpgQWBqYHdgX2BKYEZgTWBjYENgZGBCYGxga2BZYIFgjWDnYINgmmCEYJtglmCXYJJgp2CLYOFguGDgYNNgtF/wYL1gxmC1YNhhTWEVYQZg9mD3YQBg9GD6YQNhIWD7YPFhDWEOYUdhPmEoYSdhSmE/YTxhLGE0YT1hQmFEYXNhd2FY" +
+ "YVlhWmFrYXRhb2FlYXFhX2FdYVNhdWGZYZZhh2GsYZRhmmGKYZFhq2GuYcxhymHJYfdhyGHDYcZhumHLf3lhzWHmYeNh9mH6YfRh/2H9Yfxh/mIAYghiCWINYgxiFGIb////////Yh5iIWIqYi5iMGIyYjNiQWJOYl5iY2JbYmBiaGJ8YoJiiWJ+YpJik2KWYtRig2KU" +
+ "Ytdi0WK7Ys9i/2LGZNRiyGLcYsxiymLCYsdim2LJYwxi7mLxYydjAmMIYu9i9WNQYz5jTWQcY09jlmOOY4Bjq2N2Y6Njj2OJY59jtWNr//9jaWO+Y+ljwGPGY+NjyWPSY/ZjxGQWZDRkBmQTZCZkNmUdZBdkKGQPZGdkb2R2ZE5lKmSVZJNkpWSpZIhkvGTaZNJkxWTH" +
+ "ZLtk2GTCZPFk54IJZOBk4WKsZONk72UsZPZk9GTyZPplAGT9ZRhlHGUFZSRlI2UrZTRlNWU3ZTZlOHVLZUhlVmVVZU1lWGVeZV1lcmV4ZYJlg4uKZZtln2WrZbdlw2XGZcFlxGXMZdJl22XZZeBl4WXxZ3JmCmYDZftnc2Y1ZjZmNGYcZk9mRGZJZkFmXmZdZmRmZ2Zo" +
+ "Zl9mYmZwZoNmiGaOZolmhGaYZp1mwWa5Zslmvma8////////ZsRmuGbWZtpm4GY/ZuZm6WbwZvVm92cPZxZnHmcmZyeXOGcuZz9nNmdBZzhnN2dGZ15nYGdZZ2NnZGeJZ3BnqWd8Z2pnjGeLZ6ZnoWeFZ7dn72e0Z+xns2fpZ7hn5GfeZ91n4mfuZ7lnzmfGZ+dqnGge" +
+ "aEZoKWhAaE1oMmhO//9os2graFloY2h3aH9on2iPaK1olGidaJtog2quaLlodGi1aKBoumkPaI1ofmkBaMppCGjYaSJpJmjhaQxozWjUaOdo1Wk2aRJpBGjXaONpJWj5aOBo72koaSppGmkjaSFoxml5aXdpXGl4aWtpVGl+aW5pOWl0aT1pWWkwaWFpXmldaYFpammy" +
+ "aa5p0Gm/acFp02m+ac5b6GnKad1pu2nDaadqLmmRaaBpnGmVabRp3mnoagJqG2n/awpp+WnyaedqBWmxah5p7WoUaetqCmoSasFqI2oTakRqDGpyajZqeGpHamJqWWpmakhqOGoiapBqjWqgaoRqomqj////////apeGF2q7asNqwmq4arNqrGreatFq32qqatpq6mr7" +
+ "awWGFmr6axJrFpsxax9rOGs3dtxrOZjua0drQ2tJa1BrWWtUa1trX2tha3hreWt/a4BrhGuDa41rmGuVa55rpGuqa6trr2uya7Frs2u3a7xrxmvLa9Nr32vsa+tr82vv//+evmwIbBNsFGwbbCRsI2xebFVsYmxqbIJsjWyabIFsm2x+bGhsc2ySbJBsxGzxbNNsvWzX" +
+ "bMVs3WyubLFsvmy6bNts72zZbOptH4hNbTZtK209bThtGW01bTNtEm0MbWNtk21kbVpteW1ZbY5tlW/kbYVt+W4VbgpttW3HbeZtuG3Gbext3m3Mbeht0m3Fbfpt2W3kbdVt6m3ubi1ubm4ubhlucm5fbj5uI25rbitudm5Nbh9uQ246bk5uJG7/bh1uOG6CbqpumG7J" +
+ "brdu0269bq9uxG6ybtRu1W6PbqVuwm6fb0FvEXBMbuxu+G7+bz9u8m8xbu9vMm7M////////bz5vE273b4Zvem94b4FvgG9vb1tv829tb4JvfG9Yb45vkW/Cb2Zvs2+jb6FvpG+5b8Zvqm/fb9Vv7G/Ub9hv8W/ub9twCXALb/pwEXABcA9v/nAbcBpvdHAdcBhwH3Aw" +
+ "cD5wMnBRcGNwmXCScK9w8XCscLhws3CucN9wy3Dd//9w2XEJcP1xHHEZcWVxVXGIcWZxYnFMcVZxbHGPcftxhHGVcahxrHHXcblxvnHScclx1HHOceBx7HHncfVx/HH5cf9yDXIQchtyKHItcixyMHIycjtyPHI/ckByRnJLclhydHJ+coJygXKHcpJylnKicqdyuXKy" +
+ "csNyxnLEcs5y0nLicuBy4XL5cvdQD3MXcwpzHHMWcx1zNHMvcylzJXM+c05zT57Yc1dzanNoc3BzeHN1c3tzenPIc7NzznO7c8Bz5XPuc950onQFdG90JXP4dDJ0OnRVdD90X3RZdEF0XHRpdHB0Y3RqdHZ0fnSLdJ50p3TKdM901HPx////////dOB043TndOl07nTy" +
+ "dPB08XT4dPd1BHUDdQV1DHUOdQ11FXUTdR51JnUsdTx1RHVNdUp1SXVbdUZ1WnVpdWR1Z3VrdW11eHV2dYZ1h3V0dYp1iXWCdZR1mnWddaV1o3XCdbN1w3W1db11uHW8dbF1zXXKddJ12XXjdd51/nX///91/HYBdfB1+nXydfN2C3YNdgl2H3YndiB2IXYidiR2NHYw" +
+ "djt2R3ZIdkZ2XHZYdmF2YnZodml2anZndmx2cHZydnZ2eHZ8doB2g3aIdot2jnaWdpN2mXaadrB2tHa4drl2unbCds121nbSdt524Xbldud26oYvdvt3CHcHdwR3KXckdx53JXcmdxt3N3c4d0d3Wndod2t3W3dld393fnd5d453i3eRd6B3nnewd7Z3uXe/d7x3vXe7" +
+ "d8d3zXfXd9p33Hfjd+53/HgMeBJ5JnggeSp4RXiOeHR4hnh8eJp4jHijeLV4qniveNF4xnjLeNR4vni8eMV4ynjs////////eOd42nj9ePR5B3kSeRF5GXkseSt5QHlgeVd5X3laeVV5U3l6eX95inmdeaefS3mqea55s3m5ebp5yXnVeed57HnheeN6CHoNehh6GXog" +
+ "eh95gHoxejt6Pno3ekN6V3pJemF6Ynppn516cHp5en16iHqXepV6mHqWeql6yHqw//96tnrFesR6v5CDesd6ynrNes961XrTetl62nrdeuF64nrmeu168HsCew97CnsGezN7GHsZex57NXsoezZ7UHt6ewR7TXsLe0x7RXt1e2V7dHtne3B7cXtse257nXuYe597jXuc" +
+ "e5p7i3uSe497XXuZe8t7wXvMe897tHvGe9176XwRfBR75nvlfGB8AHwHfBN783v3fBd8DXv2fCN8J3wqfB98N3wrfD18THxDfFR8T3xAfFB8WHxffGR8VnxlfGx8dXyDfJB8pHytfKJ8q3yhfKh8s3yyfLF8rny5fL18wHzFfMJ82HzSfNx84ps7fO988nz0fPZ8+n0G" +
+ "////////fQJ9HH0VfQp9RX1LfS59Mn0/fTV9Rn1zfVZ9Tn1yfWh9bn1PfWN9k32JfVt9j319fZt9un2ufaN9tX3Hfb19q349faJ9r33cfbh9n32wfdh93X3kfd59+33yfeF+BX4KfiN+IX4SfjF+H34Jfgt+In5GfmZ+O341fjl+Q343//9+Mn46fmd+XX5Wfl5+WX5a" +
+ "fnl+an5pfnx+e36DfdV+fY+ufn9+iH6Jfox+kn6QfpN+lH6Wfo5+m36cfzh/On9Ff0x/TX9Of1B/UX9Vf1R/WH9ff2B/aH9pf2d/eH+Cf4Z/g3+If4d/jH+Uf55/nX+af6N/r3+yf7l/rn+2f7iLcX/Ff8Z/yn/Vf9R/4X/mf+l/83/5mNyABoAEgAuAEoAYgBmAHIAh" +
+ "gCiAP4A7gEqARoBSgFiAWoBfgGKAaIBzgHKAcIB2gHmAfYB/gISAhoCFgJuAk4CagK1RkICsgNuA5YDZgN2AxIDagNaBCYDvgPGBG4EpgSOBL4FL////////louBRoE+gVOBUYD8gXGBboFlgWaBdIGDgYiBioGAgYKBoIGVgaSBo4FfgZOBqYGwgbWBvoG4gb2BwIHC" +
+ "gbqByYHNgdGB2YHYgciB2oHfgeCB54H6gfuB/oIBggKCBYIHggqCDYIQghaCKYIrgjiCM4JAglmCWIJdglqCX4Jk//+CYoJogmqCa4IugnGCd4J4gn6CjYKSgquCn4K7gqyC4YLjgt+C0oL0gvOC+oOTgwOC+4L5gt6DBoLcgwmC2YM1gzSDFoMygzGDQIM5g1CDRYMv" +
+ "gyuDF4MYg4WDmoOqg5+DooOWgyODjoOHg4qDfIO1g3ODdYOgg4mDqIP0hBOD64POg/2EA4PYhAuDwYP3hAeD4IPyhA2EIoQgg72EOIUGg/uEbYQqhDyFWoSEhHeEa4SthG6EgoRphEaELIRvhHmENYTKhGKEuYS/hJ+E2YTNhLuE2oTQhMGExoTWhKGFIYT/hPSFF4UY" +
+ "hSyFH4UVhRSE/IVAhWOFWIVI////////hUGGAoVLhVWFgIWkhYiFkYWKhaiFbYWUhZuF6oWHhZyFd4V+hZCFyYW6hc+FuYXQhdWF3YXlhdyF+YYKhhOGC4X+hfqGBoYihhqGMIY/hk1OVYZUhl+GZ4ZxhpOGo4aphqqGi4aMhraGr4bEhsaGsIbJiCOGq4bUht6G6Ybs" +
+ "//+G34bbhu+HEocGhwiHAIcDhvuHEYcJhw2G+YcKhzSHP4c3hzuHJYcphxqHYIdfh3iHTIdOh3SHV4doh26HWYdTh2OHaogFh6KHn4eCh6+Hy4e9h8CH0JbWh6uHxIezh8eHxoe7h++H8ofgiA+IDYf+h/aH94gOh9KIEYgWiBWIIoghiDGINog5iCeIO4hEiEKIUohZ" +
+ "iF6IYohriIGIfoieiHWIfYi1iHKIgoiXiJKIroiZiKKIjYikiLCIv4ixiMOIxIjUiNiI2YjdiPmJAoj8iPSI6IjyiQSJDIkKiROJQ4keiSWJKokriUGJRIk7iTaJOIlMiR2JYIle////////iWaJZIltiWqJb4l0iXeJfomDiYiJiomTiZiJoYmpiaaJrImvibKJuom9" +
+ "ib+JwInaidyJ3YnnifSJ+IoDihaKEIoMihuKHYolijaKQYpbilKKRopIinyKbYpsimKKhYqCioSKqIqhipGKpYqmipqKo4rEis2KworaiuuK84rn//+K5IrxixSK4IriiveK3orbiwyLB4saiuGLFosQixeLIIszl6uLJosriz6LKItBi0yLT4tOi0mLVotbi1qLa4tf" +
+ "i2yLb4t0i32LgIuMi46LkouTi5aLmYuajDqMQYw/jEiMTIxOjFCMVYxijGyMeIx6jIKMiYyFjIqMjYyOjJSMfIyYYh2MrYyqjL2MsoyzjK6MtozIjMGM5IzjjNqM/Yz6jPuNBI0FjQqNB40PjQ2NEJ9OjROMzY0UjRaNZ41tjXGNc42BjZmNwo2+jbqNz43ajdaNzI3b" +
+ "jcuN6o3rjd+N4438jgiOCY3/jh2OHo4Qjh+OQo41jjCONI5K////////jkeOSY5MjlCOSI5ZjmSOYI4qjmOOVY52jnKOfI6BjoeOhY6EjouOio6TjpGOlI6ZjqqOoY6sjrCOxo6xjr6OxY7IjsuO247jjvyO+47rjv6PCo8FjxWPEo8ZjxOPHI8fjxuPDI8mjzOPO485" +
+ "j0WPQo8+j0yPSY9Gj06PV49c//+PYo9jj2SPnI+fj6OPrY+vj7eP2o/lj+KP6o/vkIeP9JAFj/mP+pARkBWQIZANkB6QFpALkCeQNpA1kDmP+JBPkFCQUZBSkA6QSZA+kFaQWJBekGiQb5B2lqiQcpCCkH2QgZCAkIqQiZCPkKiQr5CxkLWQ4pDkYkiQ25ECkRKRGZEy" +
+ "kTCRSpFWkViRY5FlkWmRc5FykYuRiZGCkaKRq5GvkaqRtZG0kbqRwJHBkcmRy5HQkdaR35HhkduR/JH1kfaSHpH/khSSLJIVkhGSXpJXkkWSSZJkkkiSlZI/kkuSUJKckpaSk5KbklqSz5K5kreS6ZMPkvqTRJMu////////kxmTIpMakyOTOpM1kzuTXJNgk3yTbpNW" +
+ "k7CTrJOtk5STuZPWk9eT6JPlk9iTw5Pdk9CTyJPklBqUFJQTlAOUB5QQlDaUK5Q1lCGUOpRBlFKURJRblGCUYpRelGqSKZRwlHWUd5R9lFqUfJR+lIGUf5WClYeVipWUlZaVmJWZ//+VoJWolaeVrZW8lbuVuZW+lcpv9pXDlc2VzJXVldSV1pXcleGV5ZXiliGWKJYu" +
+ "li+WQpZMlk+WS5Z3llyWXpZdll+WZpZylmyWjZaYlpWWl5aqlqeWsZaylrCWtJa2lriWuZbOlsuWyZbNiU2W3JcNltWW+ZcElwaXCJcTlw6XEZcPlxaXGZcklyqXMJc5lz2XPpdEl0aXSJdCl0mXXJdgl2SXZpdoUtKXa5dxl3mXhZd8l4GXepeGl4uXj5eQl5yXqJem" +
+ "l6OXs5e0l8OXxpfIl8uX3Jftn0+X8nrfl/aX9ZgPmAyYOJgkmCGYN5g9mEaYT5hLmGuYb5hw////////mHGYdJhzmKqYr5ixmLaYxJjDmMaY6ZjrmQOZCZkSmRSZGJkhmR2ZHpkkmSCZLJkumT2ZPplCmUmZRZlQmUuZUZlSmUyZVZmXmZiZpZmtma6ZvJnfmduZ3ZnY" +
+ "mdGZ7ZnumfGZ8pn7mfiaAZoPmgWZ4poZmiuaN5pFmkKaQJpD//+aPppVmk2aW5pXml+aYpplmmSaaZprmmqarZqwmryawJrPmtGa05rUmt6a35rimuOa5prvmuua7pr0mvGa95r7mwabGJsamx+bIpsjmyWbJ5somymbKpsumy+bMptEm0ObT5tNm06bUZtYm3Sbk5uD" +
+ "m5GblpuXm5+boJuom7SbwJvKm7mbxpvPm9Gb0pvjm+Kb5JvUm+GcOpvym/Gb8JwVnBScCZwTnAycBpwInBKcCpwEnC6cG5wlnCScIZwwnEecMpxGnD6cWpxgnGecdpx4nOec7JzwnQmdCJzrnQOdBp0qnSadr50jnR+dRJ0VnRKdQZ0/nT6dRp1I////////nV2dXp1k" +
+ "nVGdUJ1ZnXKdiZ2Hnaudb516nZqdpJ2pnbKdxJ3BnbuduJ26ncadz53Cndmd0534nead7Z3vnf2eGp4bnh6edZ55nn2egZ6InouejJ6SnpWekZ6dnqWeqZ64nqqerZdhnsyezp7PntCe1J7cnt6e3Z7gnuWe6J7v//+e9J72nvee+Z77nvye/Z8Hnwh2t58VnyGfLJ8+" +
+ "n0qfUp9Un2OfX59gn2GfZp9nn2yfap93n3Kfdp+Vn5yfoFgvaceQWXRkUdxxmf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
+ "/////////////////////////////////////////////w==";
+
+
+ private static short[] UNICODE_TO_QR_KANJI = new short[65536];
+
+ static { // Unpack the Shift JIS table into a more computation-friendly form
+ Arrays.fill(UNICODE_TO_QR_KANJI, (short)-1);
+ byte[] bytes = Base64.getDecoder().decode(PACKED_QR_KANJI_TO_UNICODE);
+ for (int i = 0; i < bytes.length; i += 2) {
+ int j = ((bytes[i] & 0xFF) << 8) | (bytes[i + 1] & 0xFF);
+ if (j == 0xFFFF)
+ continue;
+ if (UNICODE_TO_QR_KANJI[j] != -1)
+ throw new AssertionError();
+ UNICODE_TO_QR_KANJI[j] = (short)(i / 2);
+ }
+ }
+
+}
diff --git a/src/third_party/QR-Code-generator/javascript/qrcodegen-demo.js b/src/third_party/QR-Code-generator/javascript/qrcodegen-demo.js
new file mode 100644
index 0000000..e75e689
--- /dev/null
+++ b/src/third_party/QR-Code-generator/javascript/qrcodegen-demo.js
@@ -0,0 +1,154 @@
+/*
+ * QR Code generator demo (JavaScript)
+ *
+ * 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.
+ */
+
+"use strict";
+
+
+function redrawQrCode() {
+ // Show/hide rows based on bitmap/vector image output
+ var bitmapOutput = document.getElementById("output-format-bitmap").checked;
+ var scaleRow = document.getElementById("scale-row");
+ var svgXmlRow = document.getElementById("svg-xml-row");
+ if (bitmapOutput) {
+ scaleRow.style.removeProperty("display");
+ svgXmlRow.style.display = "none";
+ } else {
+ scaleRow.style.display = "none";
+ svgXmlRow.style.removeProperty("display");
+ }
+ var svgXml = document.getElementById("svg-xml-output");
+ svgXml.value = "";
+
+ // Reset output images in case of early termination
+ var canvas = document.getElementById("qrcode-canvas");
+ var svg = document.getElementById("qrcode-svg");
+ canvas.style.display = "none";
+ svg.style.display = "none";
+
+ // Returns a QrCode.Ecc object based on the radio buttons in the HTML form.
+ function getInputErrorCorrectionLevel() {
+ if (document.getElementById("errcorlvl-medium").checked)
+ return qrcodegen.QrCode.Ecc.MEDIUM;
+ else if (document.getElementById("errcorlvl-quartile").checked)
+ return qrcodegen.QrCode.Ecc.QUARTILE;
+ else if (document.getElementById("errcorlvl-high").checked)
+ return qrcodegen.QrCode.Ecc.HIGH;
+ else // In case no radio button is depressed
+ return qrcodegen.QrCode.Ecc.LOW;
+ }
+
+ // Get form inputs and compute QR Code
+ var ecl = getInputErrorCorrectionLevel();
+ var text = document.getElementById("text-input").value;
+ var segs = qrcodegen.QrSegment.makeSegments(text);
+ var minVer = parseInt(document.getElementById("version-min-input").value, 10);
+ var maxVer = parseInt(document.getElementById("version-max-input").value, 10);
+ var mask = parseInt(document.getElementById("mask-input").value, 10);
+ var boostEcc = document.getElementById("boost-ecc-input").checked;
+ var qr = qrcodegen.QrCode.encodeSegments(segs, ecl, minVer, maxVer, mask, boostEcc);
+
+ // Draw image output
+ var border = parseInt(document.getElementById("border-input").value, 10);
+ if (border < 0 || border > 100)
+ return;
+ if (bitmapOutput) {
+ var scale = parseInt(document.getElementById("scale-input").value, 10);
+ if (scale <= 0 || scale > 30)
+ return;
+ qr.drawCanvas(scale, border, canvas);
+ canvas.style.removeProperty("display");
+ } else {
+ var code = qr.toSvgString(border);
+ svg.setAttribute("viewBox", / viewBox="([^"]*)"/.exec(code)[1]);
+ svg.querySelector("path").setAttribute("d", / d="([^"]*)"/.exec(code)[1]);
+ svg.style.removeProperty("display");
+ svgXml.value = qr.toSvgString(border);
+ }
+
+
+ // Returns a string to describe the given list of segments.
+ function describeSegments(segs) {
+ if (segs.length == 0)
+ return "none";
+ else if (segs.length == 1) {
+ var mode = segs[0].mode;
+ var Mode = qrcodegen.QrSegment.Mode;
+ if (mode == Mode.NUMERIC ) return "numeric";
+ if (mode == Mode.ALPHANUMERIC) return "alphanumeric";
+ if (mode == Mode.BYTE ) return "byte";
+ if (mode == Mode.KANJI ) return "kanji";
+ return "unknown";
+ } else
+ return "multiple";
+ }
+
+ // Returns the number of Unicode code points in the given UTF-16 string.
+ function countUnicodeChars(str) {
+ var result = 0;
+ for (var i = 0; i < str.length; i++, result++) {
+ var c = str.charCodeAt(i);
+ if (c < 0xD800 || c >= 0xE000)
+ continue;
+ else if (0xD800 <= c && c < 0xDC00) { // High surrogate
+ i++;
+ var d = str.charCodeAt(i);
+ if (0xDC00 <= d && d < 0xE000) // Low surrogate
+ continue;
+ }
+ throw "Invalid UTF-16 string";
+ }
+ return result;
+ }
+
+ // Show the QR Code symbol's statistics as a string
+ var stats = "QR Code version = " + qr.version + ", ";
+ stats += "mask pattern = " + qr.mask + ", ";
+ stats += "character count = " + countUnicodeChars(text) + ",\n";
+ stats += "encoding mode = " + describeSegments(segs) + ", ";
+ stats += "error correction = level " + "LMQH".charAt(qr.errorCorrectionLevel.ordinal) + ", ";
+ stats += "data bits = " + qrcodegen.QrSegment.getTotalBits(segs, qr.version) + ".";
+ var elem = document.getElementById("statistics-output");
+ while (elem.firstChild != null)
+ elem.removeChild(elem.firstChild);
+ elem.appendChild(document.createTextNode(stats));
+}
+
+
+function handleVersionMinMax(which) {
+ var minElem = document.getElementById("version-min-input");
+ var maxElem = document.getElementById("version-max-input");
+ var minVal = parseInt(minElem.value, 10);
+ var maxVal = parseInt(maxElem.value, 10);
+ minVal = Math.max(Math.min(minVal, qrcodegen.QrCode.MAX_VERSION), qrcodegen.QrCode.MIN_VERSION);
+ maxVal = Math.max(Math.min(maxVal, qrcodegen.QrCode.MAX_VERSION), qrcodegen.QrCode.MIN_VERSION);
+ if (which == "min" && minVal > maxVal)
+ maxVal = minVal;
+ else if (which == "max" && maxVal < minVal)
+ minVal = maxVal;
+ minElem.value = minVal.toString();
+ maxElem.value = maxVal.toString();
+ redrawQrCode();
+}
+
+
+redrawQrCode();
diff --git a/src/third_party/QR-Code-generator/javascript/qrcodegen-js-demo.html b/src/third_party/QR-Code-generator/javascript/qrcodegen-js-demo.html
new file mode 100644
index 0000000..0b1ba15
--- /dev/null
+++ b/src/third_party/QR-Code-generator/javascript/qrcodegen-js-demo.html
@@ -0,0 +1,121 @@
+<!--
+ - QR Code generator demo (HTML+JavaScript)
+ -
+ - 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.
+ -->
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>QR Code generator library demo (JavaScript)</title>
+ <style type="text/css">
+ html {
+ font-family: sans-serif;
+ }
+ td {
+ vertical-align: top;
+ padding-top: 0.2em;
+ padding-bottom: 0.2em;
+ }
+ td:first-child {
+ white-space: pre;
+ }
+ input[type=radio] + label, input[type=checkbox] + label {
+ margin-left: 0.1em;
+ margin-right: 0.7em;
+ }
+ </style>
+</head>
+
+<body>
+<h1>QR Code generator demo library (JavaScript)</h1>
+<form action="#" method="get" onsubmit="return false;">
+ <table class="noborder" style="width:100%">
+ <tbody>
+ <tr>
+ <td><strong>Text string:</strong></td>
+ <td style="width:100%"><textarea placeholder="Enter your text to be put into the QR Code" id="text-input" style="width:100%; max-width:30em; height:5em; font-family:inherit" oninput="redrawQrCode();"></textarea></td>
+ </tr>
+ <tr>
+ <td><strong>QR Code:</strong></td>
+ <td>
+ <canvas id="qrcode-canvas" style="padding:1em; background-color:#E8E8E8"></canvas>
+ <svg id="qrcode-svg" style="width:30em; height:30em; padding:1em; background-color:#E8E8E8">
+ <rect width="100%" height="100%" fill="#FFFFFF" stroke-width="0"></rect>
+ <path d="" fill="#000000" stroke-width="0"></path>
+ </svg>
+ </td>
+ </tr>
+ <tr>
+ <td><strong>Error correction:</strong></td>
+ <td>
+ <input type="radio" name="errcorlvl" id="errcorlvl-low" onchange="redrawQrCode();" checked="checked"><label for="errcorlvl-low">Low</label>
+ <input type="radio" name="errcorlvl" id="errcorlvl-medium" onchange="redrawQrCode();"><label for="errcorlvl-medium">Medium</label>
+ <input type="radio" name="errcorlvl" id="errcorlvl-quartile" onchange="redrawQrCode();"><label for="errcorlvl-quartile">Quartile</label>
+ <input type="radio" name="errcorlvl" id="errcorlvl-high" onchange="redrawQrCode();"><label for="errcorlvl-high">High</label>
+ </td>
+ </tr>
+ <tr>
+ <td>Output format:</td>
+ <td>
+ <input type="radio" name="output-format" id="output-format-bitmap" onchange="redrawQrCode();" checked="checked"><label for="output-format-bitmap">Bitmap</label>
+ <input type="radio" name="output-format" id="output-format-vector" onchange="redrawQrCode();"><label for="output-format-vector">Vector</label>
+ </td>
+ </tr>
+ <tr>
+ <td>Border:</td>
+ <td><input type="number" value="4" min="0" max="100" step="1" id="border-input" style="width:4em" oninput="redrawQrCode();"> modules</td>
+ </tr>
+ <tr id="scale-row">
+ <td>Scale:</td>
+ <td><input type="number" value="8" min="1" max="30" step="1" id="scale-input" style="width:4em" oninput="redrawQrCode();"> pixels per module</td>
+ </tr>
+ <tr>
+ <td>Version range:</td>
+ <td>Minimum = <input type="number" value="1" min="1" max="40" step="1" id="version-min-input" style="width:4em" oninput="handleVersionMinMax('min');">, maximum = <input type="number" value="40" min="1" max="40" step="1" id="version-max-input" style="width:4em" oninput="handleVersionMinMax('max');"></td>
+ </tr>
+ <tr>
+ <td>Mask pattern:</td>
+ <td><input type="number" value="-1" min="-1" max="7" step="1" id="mask-input" style="width:4em" oninput="redrawQrCode();"> (−1 for automatic, 0 to 7 for manual)</td>
+ </tr>
+ <tr>
+ <td>Boost ECC:</td>
+ <td><input type="checkbox" checked="checked" id="boost-ecc-input" onchange="redrawQrCode();"><label for="boost-ecc-input">Increase <abbr title="error-correcting code">ECC</abbr> level within same version</label></td>
+ </tr>
+ <tr>
+ <td>Statistics:</td>
+ <td id="statistics-output" style="white-space:pre"></td>
+ </tr>
+ <tr id="svg-xml-row">
+ <td>SVG XML code:</td>
+ <td>
+ <textarea id="svg-xml-output" readonly="readonly" style="width:100%; max-width:50em; height:15em; font-family:monospace"></textarea>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</form>
+<script type="application/javascript" src="qrcodegen.js"></script>
+<script type="application/javascript" src="qrcodegen-demo.js"></script>
+
+<hr>
+<p>Copyright © Project Nayuki – <a href="https://www.nayuki.io/page/qr-code-generator-library">https://www.nayuki.io/page/qr-code-generator-library</a></p>
+</body>
+</html>
diff --git a/src/third_party/QR-Code-generator/javascript/qrcodegen.js b/src/third_party/QR-Code-generator/javascript/qrcodegen.js
new file mode 100644
index 0000000..19ae3a8
--- /dev/null
+++ b/src/third_party/QR-Code-generator/javascript/qrcodegen.js
@@ -0,0 +1,1004 @@
+/*
+ * QR Code generator library (JavaScript)
+ *
+ * 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.
+ */
+
+"use strict";
+
+
+/*
+ * Module "qrcodegen", public members:
+ * - Class QrCode:
+ * - Function encodeText(str text, QrCode.Ecc ecl) -> QrCode
+ * - Function encodeBinary(list<byte> data, QrCode.Ecc ecl) -> QrCode
+ * - Function encodeSegments(list<QrSegment> segs, QrCode.Ecc ecl,
+ * int minVersion=1, int maxVersion=40, mask=-1, boostEcl=true) -> QrCode
+ * - Constants int MIN_VERSION, MAX_VERSION
+ * - Constructor QrCode(list<int> datacodewords, int mask, int version, QrCode.Ecc ecl)
+ * - Fields int version, size, mask
+ * - Field QrCode.Ecc errorCorrectionLevel
+ * - Method getModule(int x, int y) -> bool
+ * - Method drawCanvas(int scale, int border, HTMLCanvasElement canvas) -> void
+ * - Method toSvgString(int border) -> str
+ * - Enum Ecc:
+ * - Constants LOW, MEDIUM, QUARTILE, HIGH
+ * - Field int ordinal
+ * - Class QrSegment:
+ * - Function makeBytes(list<int> data) -> QrSegment
+ * - Function makeNumeric(str data) -> QrSegment
+ * - Function makeAlphanumeric(str data) -> QrSegment
+ * - Function makeSegments(str text) -> list<QrSegment>
+ * - Function makeEci(int assignVal) -> QrSegment
+ * - Constructor QrSegment(QrSegment.Mode mode, int numChars, list<int> bitData)
+ * - Field QrSegment.Mode mode
+ * - Field int numChars
+ * - Method getBits() -> list<int>
+ * - Constants RegExp NUMERIC_REGEX, ALPHANUMERIC_REGEX
+ * - Enum Mode:
+ * - Constants NUMERIC, ALPHANUMERIC, BYTE, KANJI, ECI
+ */
+var qrcodegen = new function() {
+
+ /*---- QR Code symbol class ----*/
+
+ /*
+ * A class that represents an immutable square grid of black and white cells for a QR Code symbol,
+ * with associated static functions to create a QR Code from user-supplied textual or binary data.
+ * This class covers the QR Code model 2 specification, supporting all versions (sizes)
+ * from 1 to 40, all 4 error correction levels.
+ * This constructor creates a new QR Code symbol with the given version number, error correction level, binary data array,
+ * and mask number. mask = -1 is for automatic choice, or 0 to 7 for fixed choice. This is a cumbersome low-level constructor
+ * that should not be invoked directly by the user. To go one level up, see the QrCode.encodeSegments() function.
+ */
+ this.QrCode = function(datacodewords, mask, version, errCorLvl) {
+
+ /*---- Constructor ----*/
+
+ // Check arguments and handle simple scalar fields
+ if (mask < -1 || mask > 7)
+ throw "Mask value out of range";
+ if (version < MIN_VERSION || version > MAX_VERSION)
+ throw "Version value out of range";
+ var size = version * 4 + 17;
+
+ // Initialize both grids to be size*size arrays of Boolean false
+ var row = [];
+ for (var i = 0; i < size; i++)
+ row.push(false);
+ var modules = [];
+ var isFunction = [];
+ for (var i = 0; i < size; i++) {
+ modules.push(row.slice());
+ isFunction.push(row.slice());
+ }
+
+ // Handle grid fields, draw function patterns, draw all codewords
+ drawFunctionPatterns();
+ var allCodewords = appendErrorCorrection(datacodewords);
+ drawCodewords(allCodewords);
+
+ // Handle masking
+ if (mask == -1) { // Automatically choose best mask
+ var minPenalty = Infinity;
+ for (var i = 0; i < 8; i++) {
+ drawFormatBits(i);
+ applyMask(i);
+ var penalty = getPenaltyScore();
+ if (penalty < minPenalty) {
+ mask = i;
+ minPenalty = penalty;
+ }
+ applyMask(i); // Undoes the mask due to XOR
+ }
+ }
+ if (mask < 0 || mask > 7)
+ throw "Assertion error";
+ drawFormatBits(mask); // Overwrite old format bits
+ applyMask(mask); // Apply the final choice of mask
+
+
+ /*---- Read-only instance properties ----*/
+
+ // This QR Code symbol's version number, which is always between 1 and 40 (inclusive).
+ Object.defineProperty(this, "version", {value:version});
+
+ // The width and height of this QR Code symbol, measured in modules.
+ // Always equal to version * 4 + 17, in the range 21 to 177.
+ Object.defineProperty(this, "size", {value:size});
+
+ // The error correction level used in this QR Code symbol.
+ Object.defineProperty(this, "errorCorrectionLevel", {value:errCorLvl});
+
+ // The mask pattern used in this QR Code symbol, in the range 0 to 7 (i.e. unsigned 3-bit integer).
+ // Note that even if the constructor was called with automatic masking requested
+ // (mask = -1), the resulting object will still have a mask value between 0 and 7.
+ Object.defineProperty(this, "mask", {value:mask});
+
+
+ /*---- Accessor methods ----*/
+
+ // (Public) Returns the color of the module (pixel) at the given coordinates, which is either
+ // false for white or true for black. The top left corner has the coordinates (x=0, y=0).
+ // If the given coordinates are out of bounds, then false (white) is returned.
+ this.getModule = function(x, y) {
+ return 0 <= x && x < size && 0 <= y && y < size && modules[y][x];
+ };
+
+ // (Package-private) Tests whether the module at the given coordinates is a function module (true) or not (false).
+ // The top left corner has the coordinates (x=0, y=0). If the given coordinates are out of bounds, then false is returned.
+ // The JavaScript version of this library has this method because it is impossible to access private variables of another object.
+ this.isFunctionModule = function(x, y) {
+ if (0 <= x && x < size && 0 <= y && y < size)
+ return isFunction[y][x];
+ else
+ return false; // Infinite border
+ };
+
+
+ /*---- Public instance methods ----*/
+
+ // Draws this QR Code symbol with the given module scale and number of modules onto the given HTML canvas element.
+ // The canvas will be resized to a width and height of (this.size + border * 2) * scale. The painted image will be purely
+ // black and white with no transparent regions. The scale must be a positive integer, and the border must be a non-negative integer.
+ this.drawCanvas = function(scale, border, canvas) {
+ if (scale <= 0 || border < 0)
+ throw "Value out of range";
+ var width = (size + border * 2) * scale;
+ canvas.width = width;
+ canvas.height = width;
+ var ctx = canvas.getContext("2d");
+ for (var y = -border; y < size + border; y++) {
+ for (var x = -border; x < size + border; x++) {
+ ctx.fillStyle = this.getModule(x, y) ? "#000000" : "#FFFFFF";
+ ctx.fillRect((x + border) * scale, (y + border) * scale, scale, scale);
+ }
+ }
+ };
+
+ // Based on the given number of border modules to add as padding, this returns a
+ // string whose contents represents an SVG XML file that depicts this QR Code symbol.
+ // Note that Unix newlines (\n) are always used, regardless of the platform.
+ this.toSvgString = function(border) {
+ if (border < 0)
+ throw "Border must be non-negative";
+ var result = '<?xml version="1.0" encoding="UTF-8"?>\n';
+ result += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n';
+ result += '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 ' +
+ (size + border * 2) + ' ' + (size + border * 2) + '" stroke="none">\n';
+ result += '\t<rect width="100%" height="100%" fill="#FFFFFF"/>\n';
+ result += '\t<path d="';
+ var head = true;
+ for (var y = -border; y < size + border; y++) {
+ for (var x = -border; x < size + border; x++) {
+ if (this.getModule(x, y)) {
+ if (head)
+ head = false;
+ else
+ result += " ";
+ result += "M" + (x + border) + "," + (y + border) + "h1v1h-1z";
+ }
+ }
+ }
+ result += '" fill="#000000"/>\n';
+ result += '</svg>\n';
+ return result;
+ };
+
+
+ /*---- Private helper methods for constructor: Drawing function modules ----*/
+
+ function drawFunctionPatterns() {
+ // Draw horizontal and vertical timing patterns
+ for (var i = 0; i < size; i++) {
+ setFunctionModule(6, i, i % 2 == 0);
+ setFunctionModule(i, 6, i % 2 == 0);
+ }
+
+ // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
+ drawFinderPattern(3, 3);
+ drawFinderPattern(size - 4, 3);
+ drawFinderPattern(3, size - 4);
+
+ // Draw numerous alignment patterns
+ var alignPatPos = QrCode.getAlignmentPatternPositions(version);
+ var numAlign = alignPatPos.length;
+ for (var i = 0; i < numAlign; i++) {
+ for (var j = 0; j < numAlign; j++) {
+ if (i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0)
+ continue; // Skip the three finder corners
+ else
+ drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
+ }
+ }
+
+ // Draw configuration data
+ drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
+ drawVersion();
+ }
+
+
+ // Draws two copies of the format bits (with its own error correction code)
+ // based on the given mask and this object's error correction level field.
+ function drawFormatBits(mask) {
+ // Calculate error correction code and pack bits
+ var data = errCorLvl.formatBits << 3 | mask; // errCorrLvl is uint2, mask is uint3
+ var rem = data;
+ for (var i = 0; i < 10; i++)
+ rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
+ data = data << 10 | rem;
+ data ^= 0x5412; // uint15
+ if (data >>> 15 != 0)
+ throw "Assertion error";
+
+ // Draw first copy
+ for (var i = 0; i <= 5; i++)
+ setFunctionModule(8, i, ((data >>> i) & 1) != 0);
+ setFunctionModule(8, 7, ((data >>> 6) & 1) != 0);
+ setFunctionModule(8, 8, ((data >>> 7) & 1) != 0);
+ setFunctionModule(7, 8, ((data >>> 8) & 1) != 0);
+ for (var i = 9; i < 15; i++)
+ setFunctionModule(14 - i, 8, ((data >>> i) & 1) != 0);
+
+ // Draw second copy
+ for (var i = 0; i <= 7; i++)
+ setFunctionModule(size - 1 - i, 8, ((data >>> i) & 1) != 0);
+ for (var i = 8; i < 15; i++)
+ setFunctionModule(8, size - 15 + i, ((data >>> i) & 1) != 0);
+ setFunctionModule(8, size - 8, true);
+ }
+
+
+ // Draws two copies of the version bits (with its own error correction code),
+ // based on this object's version field (which only has an effect for 7 <= version <= 40).
+ function drawVersion() {
+ if (version < 7)
+ return;
+
+ // Calculate error correction code and pack bits
+ var rem = version; // version is uint6, in the range [7, 40]
+ for (var i = 0; i < 12; i++)
+ rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25);
+ var data = version << 12 | rem; // uint18
+ if (data >>> 18 != 0)
+ throw "Assertion error";
+
+ // Draw two copies
+ for (var i = 0; i < 18; i++) {
+ var bit = ((data >>> i) & 1) != 0;
+ var a = size - 11 + i % 3, b = Math.floor(i / 3);
+ setFunctionModule(a, b, bit);
+ setFunctionModule(b, a, bit);
+ }
+ }
+
+
+ // Draws a 9*9 finder pattern including the border separator, with the center module at (x, y).
+ function drawFinderPattern(x, y) {
+ for (var i = -4; i <= 4; i++) {
+ for (var j = -4; j <= 4; j++) {
+ var dist = Math.max(Math.abs(i), Math.abs(j)); // Chebyshev/infinity norm
+ var xx = x + j, yy = y + i;
+ if (0 <= xx && xx < size && 0 <= yy && yy < size)
+ setFunctionModule(xx, yy, dist != 2 && dist != 4);
+ }
+ }
+ }
+
+
+ // Draws a 5*5 alignment pattern, with the center module at (x, y).
+ function drawAlignmentPattern(x, y) {
+ for (var i = -2; i <= 2; i++) {
+ for (var j = -2; j <= 2; j++)
+ setFunctionModule(x + j, y + i, Math.max(Math.abs(i), Math.abs(j)) != 1);
+ }
+ }
+
+
+ // Sets the color of a module and marks it as a function module.
+ // Only used by the constructor. Coordinates must be in range.
+ function setFunctionModule(x, y, isBlack) {
+ modules[y][x] = isBlack;
+ isFunction[y][x] = true;
+ }
+
+
+ /*---- Private helper methods for constructor: Codewords and masking ----*/
+
+ // Returns a new byte string representing the given data with the appropriate error correction
+ // codewords appended to it, based on this object's version and error correction level.
+ function appendErrorCorrection(data) {
+ if (data.length != QrCode.getNumDataCodewords(version, errCorLvl))
+ throw "Invalid argument";
+
+ // Calculate parameter numbers
+ var numBlocks = QrCode.NUM_ERROR_CORRECTION_BLOCKS[errCorLvl.ordinal][version];
+ var blockEccLen = QrCode.ECC_CODEWORDS_PER_BLOCK[errCorLvl.ordinal][version];
+ var rawCodewords = Math.floor(QrCode.getNumRawDataModules(version) / 8);
+ var numShortBlocks = numBlocks - rawCodewords % numBlocks;
+ var shortBlockLen = Math.floor(rawCodewords / numBlocks);
+
+ // Split data into blocks and append ECC to each block
+ var blocks = [];
+ var rs = new ReedSolomonGenerator(blockEccLen);
+ for (var i = 0, k = 0; i < numBlocks; i++) {
+ var dat = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
+ k += dat.length;
+ var ecc = rs.getRemainder(dat);
+ if (i < numShortBlocks)
+ dat.push(0);
+ ecc.forEach(function(b) {
+ dat.push(b);
+ });
+ blocks.push(dat);
+ }
+
+ // Interleave (not concatenate) the bytes from every block into a single sequence
+ var result = [];
+ for (var i = 0; i < blocks[0].length; i++) {
+ for (var j = 0; j < blocks.length; j++) {
+ // Skip the padding byte in short blocks
+ if (i != shortBlockLen - blockEccLen || j >= numShortBlocks)
+ result.push(blocks[j][i]);
+ }
+ }
+ if (result.length != rawCodewords)
+ throw "Assertion error";
+ return result;
+ }
+
+
+ // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
+ // data area of this QR Code symbol. Function modules need to be marked off before this is called.
+ function drawCodewords(data) {
+ if (data.length != Math.floor(QrCode.getNumRawDataModules(version) / 8))
+ throw "Invalid argument";
+ var i = 0; // Bit index into the data
+ // Do the funny zigzag scan
+ for (var right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
+ if (right == 6)
+ right = 5;
+ for (var vert = 0; vert < size; vert++) { // Vertical counter
+ for (var j = 0; j < 2; j++) {
+ var x = right - j; // Actual x coordinate
+ var upward = ((right + 1) & 2) == 0;
+ var y = upward ? size - 1 - vert : vert; // Actual y coordinate
+ if (!isFunction[y][x] && i < data.length * 8) {
+ modules[y][x] = ((data[i >>> 3] >>> (7 - (i & 7))) & 1) != 0;
+ i++;
+ }
+ // If there are any remainder bits (0 to 7), they are already
+ // set to 0/false/white when the grid of modules was initialized
+ }
+ }
+ }
+ if (i != data.length * 8)
+ throw "Assertion error";
+ }
+
+
+ // XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical
+ // properties, calling applyMask(m) twice with the same value is equivalent to no change at all.
+ // This means it is possible to apply a mask, undo it, and try another mask. Note that a final
+ // well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.).
+ function applyMask(mask) {
+ if (mask < 0 || mask > 7)
+ throw "Mask value out of range";
+ for (var y = 0; y < size; y++) {
+ for (var x = 0; x < size; x++) {
+ var invert;
+ switch (mask) {
+ case 0: invert = (x + y) % 2 == 0; break;
+ case 1: invert = y % 2 == 0; break;
+ case 2: invert = x % 3 == 0; break;
+ case 3: invert = (x + y) % 3 == 0; break;
+ case 4: invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 == 0; break;
+ case 5: invert = x * y % 2 + x * y % 3 == 0; break;
+ case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
+ case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
+ default: throw "Assertion error";
+ }
+ modules[y][x] ^= invert & !isFunction[y][x];
+ }
+ }
+ }
+
+
+ // 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.
+ function getPenaltyScore() {
+ var result = 0;
+
+ // Adjacent modules in row having same color
+ for (var y = 0; y < size; y++) {
+ for (var x = 0, runX, colorX; x < size; x++) {
+ if (x == 0 || modules[y][x] != colorX) {
+ colorX = modules[y][x];
+ runX = 1;
+ } else {
+ runX++;
+ if (runX == 5)
+ result += QrCode.PENALTY_N1;
+ else if (runX > 5)
+ result++;
+ }
+ }
+ }
+ // Adjacent modules in column having same color
+ for (var x = 0; x < size; x++) {
+ for (var y = 0, runY, colorY; y < size; y++) {
+ if (y == 0 || modules[y][x] != colorY) {
+ colorY = modules[y][x];
+ runY = 1;
+ } else {
+ runY++;
+ if (runY == 5)
+ result += QrCode.PENALTY_N1;
+ else if (runY > 5)
+ result++;
+ }
+ }
+ }
+
+ // 2*2 blocks of modules having same color
+ for (var y = 0; y < size - 1; y++) {
+ for (var x = 0; x < size - 1; x++) {
+ var color = modules[y][x];
+ if ( color == modules[y][x + 1] &&
+ color == modules[y + 1][x] &&
+ color == modules[y + 1][x + 1])
+ result += QrCode.PENALTY_N2;
+ }
+ }
+
+ // Finder-like pattern in rows
+ for (var y = 0; y < size; y++) {
+ for (var x = 0, bits = 0; x < size; x++) {
+ bits = ((bits << 1) & 0x7FF) | (modules[y][x] ? 1 : 0);
+ if (x >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
+ result += QrCode.PENALTY_N3;
+ }
+ }
+ // Finder-like pattern in columns
+ for (var x = 0; x < size; x++) {
+ for (var y = 0, bits = 0; y < size; y++) {
+ bits = ((bits << 1) & 0x7FF) | (modules[y][x] ? 1 : 0);
+ if (y >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
+ result += QrCode.PENALTY_N3;
+ }
+ }
+
+ // Balance of black and white modules
+ var black = 0;
+ modules.forEach(function(row) {
+ row.forEach(function(color) {
+ if (color)
+ black++;
+ });
+ });
+ var total = size * size;
+ // Find smallest k such that (45-5k)% <= dark/total <= (55+5k)%
+ for (var k = 0; black*20 < (9-k)*total || black*20 > (11+k)*total; k++)
+ result += QrCode.PENALTY_N4;
+ return result;
+ }
+ };
+
+
+ /*---- Public static factory functions for QrCode ----*/
+
+ /*
+ * Returns a QR Code symbol representing the specified Unicode text string at the specified error correction level.
+ * As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer
+ * Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
+ * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the
+ * ecl argument if it can be done without increasing the version.
+ */
+ this.QrCode.encodeText = function(text, ecl) {
+ var segs = qrcodegen.QrSegment.makeSegments(text);
+ return this.encodeSegments(segs, ecl);
+ };
+
+
+ /*
+ * Returns a QR Code symbol representing the given binary data string at the given error correction level.
+ * This function always encodes using the binary segment mode, not any text mode. The maximum number of
+ * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
+ * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
+ */
+ this.QrCode.encodeBinary = function(data, ecl) {
+ var seg = qrcodegen.QrSegment.makeBytes(data);
+ return this.encodeSegments([seg], ecl);
+ };
+
+
+ /*
+ * Returns a QR Code symbol representing the given data segments with the given encoding parameters.
+ * The smallest possible QR Code version within the given range is automatically chosen for the output.
+ * This function allows the user to create a custom sequence of segments that switches
+ * between modes (such as alphanumeric and binary) to encode text more efficiently.
+ * This function is considered to be lower level than simply encoding text or binary data.
+ */
+ this.QrCode.encodeSegments = function(segs, ecl, minVersion, maxVersion, mask, boostEcl) {
+ if (minVersion == undefined) minVersion = MIN_VERSION;
+ if (maxVersion == undefined) maxVersion = MAX_VERSION;
+ if (mask == undefined) mask = -1;
+ if (boostEcl == undefined) boostEcl = true;
+ if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
+ throw "Invalid value";
+
+ // Find the minimal version number to use
+ var version, dataUsedBits;
+ for (version = minVersion; ; version++) {
+ var dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; // Number of data bits available
+ dataUsedBits = qrcodegen.QrSegment.getTotalBits(segs, version);
+ if (dataUsedBits != null && dataUsedBits <= dataCapacityBits)
+ break; // This version number is found to be suitable
+ if (version >= maxVersion) // All versions in the range could not fit the given data
+ throw "Data too long";
+ }
+
+ // Increase the error correction level while the data still fits in the current version number
+ [this.Ecc.MEDIUM, this.Ecc.QUARTILE, this.Ecc.HIGH].forEach(function(newEcl) {
+ if (boostEcl && dataUsedBits <= QrCode.getNumDataCodewords(version, newEcl) * 8)
+ ecl = newEcl;
+ });
+
+ // Create the data bit string by concatenating all segments
+ var dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8;
+ var bb = new BitBuffer();
+ segs.forEach(function(seg) {
+ bb.appendBits(seg.mode.modeBits, 4);
+ bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
+ seg.getBits().forEach(function(bit) {
+ bb.push(bit);
+ });
+ });
+
+ // Add terminator and pad up to a byte if applicable
+ bb.appendBits(0, Math.min(4, dataCapacityBits - bb.length));
+ bb.appendBits(0, (8 - bb.length % 8) % 8);
+
+ // Pad with alternate bytes until data capacity is reached
+ for (var padByte = 0xEC; bb.length < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
+ bb.appendBits(padByte, 8);
+ if (bb.length % 8 != 0)
+ throw "Assertion error";
+
+ // Create the QR Code symbol
+ return new this(bb.getBytes(), mask, version, ecl);
+ };
+
+
+ /*---- Public constants for QrCode ----*/
+
+ var MIN_VERSION = 1;
+ var MAX_VERSION = 40;
+ Object.defineProperty(this.QrCode, "MIN_VERSION", {value:MIN_VERSION});
+ Object.defineProperty(this.QrCode, "MAX_VERSION", {value:MAX_VERSION});
+
+
+ /*---- Private static helper functions QrCode ----*/
+
+ var QrCode = {}; // Private object to assign properties to. Not the same object as 'this.QrCode'.
+
+
+ // Returns a sequence of positions of the alignment patterns in ascending order. These positions are
+ // used on both the x and y axes. Each value in the resulting sequence is in the range [0, 177).
+ // This stateless pure function could be implemented as table of 40 variable-length lists of integers.
+ QrCode.getAlignmentPatternPositions = function(ver) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw "Version number out of range";
+ else if (ver == 1)
+ return [];
+ else {
+ var size = ver * 4 + 17;
+ var numAlign = Math.floor(ver / 7) + 2;
+ var step;
+ if (ver != 32)
+ step = Math.ceil((size - 13) / (2 * numAlign - 2)) * 2;
+ else // C-C-C-Combo breaker!
+ step = 26;
+
+ var result = [6];
+ for (var i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step)
+ result.splice(1, 0, pos);
+ return 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.
+ QrCode.getNumRawDataModules = function(ver) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw "Version number out of range";
+ var result = (16 * ver + 128) * ver + 64;
+ if (ver >= 2) {
+ var numAlign = Math.floor(ver / 7) + 2;
+ result -= (25 * numAlign - 10) * numAlign - 55;
+ if (ver >= 7)
+ result -= 18 * 2; // Subtract version information
+ }
+ return 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.
+ QrCode.getNumDataCodewords = function(ver, ecl) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw "Version number out of range";
+ return Math.floor(QrCode.getNumRawDataModules(ver) / 8) -
+ QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] *
+ QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
+ };
+
+
+ /*---- Private tables of constants for QrCode ----*/
+
+ // For use in getPenaltyScore(), when evaluating which mask is best.
+ QrCode.PENALTY_N1 = 3;
+ QrCode.PENALTY_N2 = 3;
+ QrCode.PENALTY_N3 = 40;
+ QrCode.PENALTY_N4 = 10;
+
+ QrCode.ECC_CODEWORDS_PER_BLOCK = [
+ // 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
+ [null, 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
+ [null, 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
+ [null, 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
+ [null, 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
+ ];
+
+ QrCode.NUM_ERROR_CORRECTION_BLOCKS = [
+ // 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
+ [null, 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
+ [null, 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
+ [null, 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
+ [null, 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
+ ];
+
+
+ /*---- Public helper enumeration ----*/
+
+ /*
+ * Represents the error correction level used in a QR Code symbol.
+ */
+ this.QrCode.Ecc = {
+ // Constants declared in ascending order of error protection
+ LOW : new Ecc(0, 1),
+ MEDIUM : new Ecc(1, 0),
+ QUARTILE: new Ecc(2, 3),
+ HIGH : new Ecc(3, 2),
+ };
+
+
+ // Private constructor.
+ function Ecc(ord, fb) {
+ // (Public) In the range 0 to 3 (unsigned 2-bit integer)
+ Object.defineProperty(this, "ordinal", {value:ord});
+
+ // (Package-private) In the range 0 to 3 (unsigned 2-bit integer)
+ Object.defineProperty(this, "formatBits", {value:fb});
+ }
+
+
+
+ /*---- Data segment class ----*/
+
+ /*
+ * A public class that represents a character string to be encoded in a QR Code symbol.
+ * Each segment has a mode, and a sequence of characters that is already encoded as
+ * a sequence of bits. Instances of this class are immutable.
+ * This segment class 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.
+ */
+ this.QrSegment = function(mode, numChars, bitData) {
+ if (numChars < 0 || !(mode instanceof Mode))
+ throw "Invalid argument";
+ bitData = bitData.slice(); // Make defensive copy
+
+ // The mode indicator for this segment.
+ Object.defineProperty(this, "mode", {value:mode});
+
+ // The length of this segment's unencoded data, measured in characters. Always zero or positive.
+ Object.defineProperty(this, "numChars", {value:numChars});
+
+ // Returns a copy of all bits, which is an array of 0s and 1s.
+ this.getBits = function() {
+ return bitData.slice(); // Make defensive copy
+ };
+ };
+
+
+ /*---- Public static factory functions for QrSegment ----*/
+
+ /*
+ * Returns a segment representing the given binary data encoded in byte mode.
+ */
+ this.QrSegment.makeBytes = function(data) {
+ var bb = new BitBuffer();
+ data.forEach(function(b) {
+ bb.appendBits(b, 8);
+ });
+ return new this(this.Mode.BYTE, data.length, bb);
+ };
+
+
+ /*
+ * Returns a segment representing the given string of decimal digits encoded in numeric mode.
+ */
+ this.QrSegment.makeNumeric = function(digits) {
+ if (!this.NUMERIC_REGEX.test(digits))
+ throw "String contains non-numeric characters";
+ var bb = new BitBuffer();
+ var i;
+ for (i = 0; i + 3 <= digits.length; i += 3) // Process groups of 3
+ bb.appendBits(parseInt(digits.substr(i, 3), 10), 10);
+ var rem = digits.length - i;
+ if (rem > 0) // 1 or 2 digits remaining
+ bb.appendBits(parseInt(digits.substring(i), 10), rem * 3 + 1);
+ return new this(this.Mode.NUMERIC, digits.length, bb);
+ };
+
+
+ /*
+ * 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.
+ */
+ this.QrSegment.makeAlphanumeric = function(text) {
+ if (!this.ALPHANUMERIC_REGEX.test(text))
+ throw "String contains unencodable characters in alphanumeric mode";
+ var bb = new BitBuffer();
+ var i;
+ for (i = 0; i + 2 <= text.length; i += 2) { // Process groups of 2
+ var temp = QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45;
+ temp += QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));
+ bb.appendBits(temp, 11);
+ }
+ if (i < text.length) // 1 character remaining
+ bb.appendBits(QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6);
+ return new this(this.Mode.ALPHANUMERIC, text.length, bb);
+ };
+
+
+ /*
+ * Returns a new mutable list of zero or more segments to represent the given Unicode text string.
+ * The result may use various segment modes and switch modes to optimize the length of the bit stream.
+ */
+ this.QrSegment.makeSegments = function(text) {
+ // Select the most efficient segment encoding automatically
+ if (text == "")
+ return [];
+ else if (this.NUMERIC_REGEX.test(text))
+ return [this.makeNumeric(text)];
+ else if (this.ALPHANUMERIC_REGEX.test(text))
+ return [this.makeAlphanumeric(text)];
+ else
+ return [this.makeBytes(toUtf8ByteArray(text))];
+ };
+
+
+ /*
+ * Returns a segment representing an Extended Channel Interpretation
+ * (ECI) designator with the given assignment value.
+ */
+ this.QrSegment.makeEci = function(assignVal) {
+ var bb = new BitBuffer();
+ if (0 <= assignVal && assignVal < (1 << 7))
+ bb.appendBits(assignVal, 8);
+ else if ((1 << 7) <= assignVal && assignVal < (1 << 14)) {
+ bb.appendBits(2, 2);
+ bb.appendBits(assignVal, 14);
+ } else if ((1 << 14) <= assignVal && assignVal < 1000000) {
+ bb.appendBits(6, 3);
+ bb.appendBits(assignVal, 21);
+ } else
+ throw "ECI assignment value out of range";
+ return new this(this.Mode.ECI, 0, bb);
+ };
+
+
+ // Package-private helper function.
+ this.QrSegment.getTotalBits = function(segs, version) {
+ if (version < MIN_VERSION || version > MAX_VERSION)
+ throw "Version number out of range";
+ var result = 0;
+ for (var i = 0; i < segs.length; i++) {
+ var seg = segs[i];
+ var ccbits = seg.mode.numCharCountBits(version);
+ // Fail if segment length value doesn't fit in the length field's bit-width
+ if (seg.numChars >= (1 << ccbits))
+ return null;
+ result += 4 + ccbits + seg.getBits().length;
+ }
+ return result;
+ };
+
+
+ /*---- Constants for QrSegment ----*/
+
+ var QrSegment = {}; // Private object to assign properties to. Not the same object as 'this.QrSegment'.
+
+ // (Public) Can test whether a string is encodable in numeric mode (such as by using QrSegment.makeNumeric()).
+ this.QrSegment.NUMERIC_REGEX = /^[0-9]*$/;
+
+ // (Public) Can test whether a string is encodable in alphanumeric mode (such as by using QrSegment.makeAlphanumeric()).
+ this.QrSegment.ALPHANUMERIC_REGEX = /^[A-Z0-9 $%*+.\/:-]*$/;
+
+ // (Private) The set of all legal characters in alphanumeric mode, where each character value maps to the index in the string.
+ QrSegment.ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
+
+
+ /*---- Public helper enumeration ----*/
+
+ /*
+ * Represents the mode field of a segment. Immutable.
+ */
+ this.QrSegment.Mode = { // Constants
+ NUMERIC : new Mode(0x1, [10, 12, 14]),
+ ALPHANUMERIC: new Mode(0x2, [ 9, 11, 13]),
+ BYTE : new Mode(0x4, [ 8, 16, 16]),
+ KANJI : new Mode(0x8, [ 8, 10, 12]),
+ ECI : new Mode(0x7, [ 0, 0, 0]),
+ };
+
+
+ // Private constructor.
+ function Mode(mode, ccbits) {
+ // (Package-private) An unsigned 4-bit integer value (range 0 to 15) representing the mode indicator bits for this mode object.
+ Object.defineProperty(this, "modeBits", {value:mode});
+
+ // (Package-private) Returns the bit width of the segment character count field for this mode object at the given version number.
+ this.numCharCountBits = function(ver) {
+ if ( 1 <= ver && ver <= 9) return ccbits[0];
+ else if (10 <= ver && ver <= 26) return ccbits[1];
+ else if (27 <= ver && ver <= 40) return ccbits[2];
+ else throw "Version number out of range";
+ };
+ }
+
+
+
+ /*---- Private helper functions and classes ----*/
+
+ // Returns a new array of bytes representing the given string encoded in UTF-8.
+ function toUtf8ByteArray(str) {
+ str = encodeURI(str);
+ var result = [];
+ for (var i = 0; i < str.length; i++) {
+ if (str.charAt(i) != "%")
+ result.push(str.charCodeAt(i));
+ else {
+ result.push(parseInt(str.substr(i + 1, 2), 16));
+ i += 2;
+ }
+ }
+ return result;
+ }
+
+
+
+ /*
+ * A private helper class that computes the Reed-Solomon error correction codewords for a sequence of
+ * data codewords at a given degree. Objects are immutable, and the state only depends on the degree.
+ * This class exists because each data block in a QR Code shares the same the divisor polynomial.
+ * This constructor creates a Reed-Solomon ECC generator for the given degree. This could be implemented
+ * as a lookup table over all possible parameter values, instead of as an algorithm.
+ */
+ function ReedSolomonGenerator(degree) {
+ if (degree < 1 || degree > 255)
+ throw "Degree out of range";
+
+ // Coefficients of the divisor polynomial, 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}.
+ var coefficients = [];
+
+ // Start with the monomial x^0
+ for (var i = 0; i < degree - 1; i++)
+ coefficients.push(0);
+ coefficients.push(1);
+
+ // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
+ // drop the highest term, and store the rest of the coefficients in order of descending powers.
+ // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
+ var root = 1;
+ for (var i = 0; i < degree; i++) {
+ // Multiply the current product by (x - r^i)
+ for (var j = 0; j < coefficients.length; j++) {
+ coefficients[j] = ReedSolomonGenerator.multiply(coefficients[j], root);
+ if (j + 1 < coefficients.length)
+ coefficients[j] ^= coefficients[j + 1];
+ }
+ root = ReedSolomonGenerator.multiply(root, 0x02);
+ }
+
+ // Computes and returns the Reed-Solomon error correction codewords for the given
+ // sequence of data codewords. The returned object is always a new byte array.
+ // This method does not alter this object's state (because it is immutable).
+ this.getRemainder = function(data) {
+ // Compute the remainder by performing polynomial division
+ var result = coefficients.map(function() { return 0; });
+ data.forEach(function(b) {
+ var factor = b ^ result.shift();
+ result.push(0);
+ for (var i = 0; i < result.length; i++)
+ result[i] ^= ReedSolomonGenerator.multiply(coefficients[i], factor);
+ });
+ return result;
+ };
+ }
+
+ // This static function returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and
+ // result are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
+ ReedSolomonGenerator.multiply = function(x, y) {
+ if (x >>> 8 != 0 || y >>> 8 != 0)
+ throw "Byte out of range";
+ // Russian peasant multiplication
+ var z = 0;
+ for (var i = 7; i >= 0; i--) {
+ z = (z << 1) ^ ((z >>> 7) * 0x11D);
+ z ^= ((y >>> i) & 1) * x;
+ }
+ if (z >>> 8 != 0)
+ throw "Assertion error";
+ return z;
+ };
+
+
+
+ /*
+ * A private helper class that represents an appendable sequence of bits.
+ * This constructor creates an empty bit buffer (length 0).
+ */
+ function BitBuffer() {
+
+ // Packs this buffer's bits into bytes in big endian,
+ // padding with '0' bit values, and returns the new array.
+ this.getBytes = function() {
+ var result = [];
+ while (result.length * 8 < this.length)
+ result.push(0);
+ this.forEach(function(bit, i) {
+ result[i >>> 3] |= bit << (7 - (i & 7));
+ });
+ return result;
+ };
+
+ // Appends the given number of low bits of the given value
+ // to this sequence. Requires 0 <= val < 2^len.
+ this.appendBits = function(val, len) {
+ if (len < 0 || len > 31 || val >>> len != 0)
+ throw "Value out of range";
+ for (var i = len - 1; i >= 0; i--) // Append bit by bit
+ this.push((val >>> i) & 1);
+ };
+ }
+
+ BitBuffer.prototype = Object.create(Array.prototype);
+
+};
diff --git a/src/third_party/QR-Code-generator/python/qrcodegen-batch-test.py b/src/third_party/QR-Code-generator/python/qrcodegen-batch-test.py
new file mode 100644
index 0000000..fa92e52
--- /dev/null
+++ b/src/third_party/QR-Code-generator/python/qrcodegen-batch-test.py
@@ -0,0 +1,137 @@
+#
+# QR Code generator batch test (Python 3)
+#
+# Runs various versions of the QR Code generator test worker as subprocesses,
+# feeds each one the same random input, and compares their output for equality.
+#
+# 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.
+#
+
+from __future__ import print_function
+import itertools, random, subprocess, sys, time
+if sys.version_info.major < 3:
+ raise RuntimeError("Requires Python 3+")
+
+
+CHILD_PROGRAMS = [
+ ["python2", "../python/qrcodegen-worker.py"], # Python 2 program
+ ["python3", "../python/qrcodegen-worker.py"], # Python 3 program
+ ["java", "-cp", "../java", "io/nayuki/qrcodegen/QrCodeGeneratorWorker"], # Java program
+ ["../c/qrcodegen-worker"], # C program
+ ["../cpp/QrCodeGeneratorWorker"], # C++ program
+ ["../rust/target/debug/examples/qrcodegen-worker"], # Rust program
+]
+
+
+subprocs = []
+
+def main():
+ # Launch workers
+ global subprocs
+ try:
+ for args in CHILD_PROGRAMS:
+ subprocs.append(subprocess.Popen(args, universal_newlines=True,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE))
+ except FileNotFoundError:
+ write_all(-1)
+ raise
+
+ # Check if any died
+ time.sleep(0.3)
+ if any(proc.poll() is not None for proc in subprocs):
+ for proc in subprocs:
+ if proc.poll() is None:
+ print(-1, file=proc.stdin)
+ proc.stdin.flush()
+ sys.exit("Error: One or more workers failed to start")
+
+ # Do tests
+ for i in itertools.count():
+ print("Trial {}: ".format(i), end="")
+ do_trial()
+ print()
+
+
+def do_trial():
+ mode = random.randrange(4)
+ if mode == 0: # Numeric
+ length = round((2 * 7089) ** random.random())
+ data = [random.randrange(48, 58) for _ in range(length)]
+ elif mode == 1: # Alphanumeric
+ length = round((2 * 4296) ** random.random())
+ data = [ord(random.choice("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")) for _ in range(length)]
+ elif mode == 2: # ASCII
+ length = round((2 * 2953) ** random.random())
+ data = [random.randrange(128) for _ in range(length)]
+ elif mode == 3: # Byte
+ length = round((2 * 2953) ** random.random())
+ data = [random.randrange(256) for _ in range(length)]
+ else:
+ raise AssertionError()
+
+ write_all(length)
+ for b in data:
+ write_all(b)
+
+ errcorlvl = random.randrange(4)
+ minversion = random.randint(1, 40)
+ maxversion = random.randint(1, 40)
+ if minversion > maxversion:
+ minversion, maxversion = maxversion, minversion
+ mask = -1
+ if random.random() < 0.5:
+ mask = random.randrange(8)
+ boostecl = int(random.random() < 0.2)
+ print("mode={} len={} ecl={} minv={} maxv={} mask={} boost={}".format(mode, length, errcorlvl, minversion, maxversion, mask, boostecl), end="")
+
+ write_all(errcorlvl)
+ write_all(minversion)
+ write_all(maxversion)
+ write_all(mask)
+ write_all(boostecl)
+ flush_all()
+
+ version = read_verify()
+ print(" version={}".format(version), end="")
+ if version == -1:
+ return
+ size = version * 4 + 17
+ for _ in range(size**2):
+ read_verify()
+
+
+def write_all(val):
+ for proc in subprocs:
+ print(val, file=proc.stdin)
+
+def flush_all():
+ for proc in subprocs:
+ proc.stdin.flush()
+
+def read_verify():
+ val = subprocs[0].stdout.readline().rstrip("\r\n")
+ for proc in subprocs[1 : ]:
+ if proc.stdout.readline().rstrip("\r\n") != val:
+ raise ValueError("Mismatch")
+ return int(val)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/third_party/QR-Code-generator/python/qrcodegen-demo.py b/src/third_party/QR-Code-generator/python/qrcodegen-demo.py
new file mode 100644
index 0000000..50e975e
--- /dev/null
+++ b/src/third_party/QR-Code-generator/python/qrcodegen-demo.py
@@ -0,0 +1,186 @@
+#
+# QR Code generator demo (Python 2, 3)
+#
+# 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.
+#
+
+from __future__ import print_function
+from qrcodegen import QrCode, QrSegment
+
+
+def main():
+ """The main application program."""
+ do_basic_demo()
+ do_variety_demo()
+ do_segment_demo()
+ do_mask_demo()
+
+
+
+# ---- Demo suite ----
+
+def do_basic_demo():
+ """Creates a single QR Code, then prints it to the console."""
+ text = u"Hello, world!" # User-supplied Unicode text
+ errcorlvl = QrCode.Ecc.LOW # Error correction level
+
+ # Make and print the QR Code symbol
+ qr = QrCode.encode_text(text, errcorlvl)
+ print_qr(qr)
+ print(qr.to_svg_str(4))
+
+
+def do_variety_demo():
+ """Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console."""
+
+ # Numeric mode encoding (3.33 bits per digit)
+ qr = QrCode.encode_text("314159265358979323846264338327950288419716939937510", QrCode.Ecc.MEDIUM)
+ print_qr(qr)
+
+ # Alphanumeric mode encoding (5.5 bits per character)
+ qr = QrCode.encode_text("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode.Ecc.HIGH)
+ print_qr(qr)
+
+ # Unicode text as UTF-8
+ qr = QrCode.encode_text(u"\u3053\u3093\u306B\u3061\u0077\u0061\u3001\u4E16\u754C\uFF01\u0020\u03B1\u03B2\u03B3\u03B4", QrCode.Ecc.QUARTILE)
+ print_qr(qr)
+
+ # Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
+ qr = QrCode.encode_text(
+ "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.", QrCode.Ecc.HIGH)
+ print_qr(qr)
+
+
+def do_segment_demo():
+ """Creates QR Codes with manually specified segments for better compactness."""
+
+ # Illustration "silver"
+ silver0 = "THE SQUARE ROOT OF 2 IS 1."
+ silver1 = "41421356237309504880168872420969807856967187537694807317667973799"
+ qr = QrCode.encode_text(silver0 + silver1, QrCode.Ecc.LOW)
+ print_qr(qr)
+
+ segs = [
+ QrSegment.make_alphanumeric(silver0),
+ QrSegment.make_numeric(silver1)]
+ qr = QrCode.encode_segments(segs, QrCode.Ecc.LOW)
+ print_qr(qr)
+
+ # Illustration "golden"
+ golden0 = u"Golden ratio \u03C6 = 1."
+ golden1 = u"6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374"
+ golden2 = u"......"
+ qr = QrCode.encode_text(golden0 + golden1 + golden2, QrCode.Ecc.LOW)
+ print_qr(qr)
+
+ segs = [
+ QrSegment.make_bytes(golden0.encode("UTF-8")),
+ QrSegment.make_numeric(golden1),
+ QrSegment.make_alphanumeric(golden2)]
+ qr = QrCode.encode_segments(segs, QrCode.Ecc.LOW)
+ print_qr(qr)
+
+ # Illustration "Madoka": kanji, kana, Greek, Cyrillic, full-width Latin characters
+ madoka = u"\u300C\u9B54\u6CD5\u5C11\u5973\u307E\u3069\u304B\u2606\u30DE\u30AE\u30AB\u300D\u3063\u3066\u3001\u3000\u0418\u0410\u0418\u3000\uFF44\uFF45\uFF53\uFF55\u3000\u03BA\u03B1\uFF1F"
+ qr = QrCode.encode_text(madoka, QrCode.Ecc.LOW)
+ print_qr(qr)
+
+ kanjiCharBits = [ # Kanji mode encoding (13 bits per character)
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1,
+ 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1,
+ 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1,
+ 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1,
+ 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1,
+ 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ ]
+ segs = [QrSegment(QrSegment.Mode.KANJI, len(kanjiCharBits) // 13, kanjiCharBits)]
+ qr = QrCode.encode_segments(segs, QrCode.Ecc.LOW)
+ print_qr(qr)
+
+
+def do_mask_demo():
+ """Creates QR Codes with the same size and contents but different mask patterns."""
+
+ # Project Nayuki URL
+ segs = QrSegment.make_segments("https://www.nayuki.io/")
+ print_qr(QrCode.encode_segments(segs, QrCode.Ecc.HIGH, mask=-1)) # Automatic mask
+ print_qr(QrCode.encode_segments(segs, QrCode.Ecc.HIGH, mask=3)) # Force mask 3
+
+ # Chinese text as UTF-8
+ segs = QrSegment.make_segments(
+ u"\u7DAD\u57FA\u767E\u79D1\uFF08\u0057\u0069\u006B\u0069\u0070\u0065\u0064\u0069\u0061\uFF0C"
+ "\u8046\u807D\u0069\u002F\u02CC\u0077\u026A\u006B\u1D7B\u02C8\u0070\u0069\u02D0\u0064\u0069"
+ "\u002E\u0259\u002F\uFF09\u662F\u4E00\u500B\u81EA\u7531\u5167\u5BB9\u3001\u516C\u958B\u7DE8"
+ "\u8F2F\u4E14\u591A\u8A9E\u8A00\u7684\u7DB2\u8DEF\u767E\u79D1\u5168\u66F8\u5354\u4F5C\u8A08"
+ "\u756B")
+ print_qr(QrCode.encode_segments(segs, QrCode.Ecc.MEDIUM, mask=0)) # Force mask 0
+ print_qr(QrCode.encode_segments(segs, QrCode.Ecc.MEDIUM, mask=1)) # Force mask 1
+ print_qr(QrCode.encode_segments(segs, QrCode.Ecc.MEDIUM, mask=5)) # Force mask 5
+ print_qr(QrCode.encode_segments(segs, QrCode.Ecc.MEDIUM, mask=7)) # Force mask 7
+
+
+
+# ---- Utilities ----
+
+def print_qr(qrcode):
+ """Prints the given QrCode object to the console."""
+ border = 4
+ for y in range(-border, qrcode.get_size() + border):
+ for x in range(-border, qrcode.get_size() + border):
+ print(u"\u2588 "[1 if qrcode.get_module(x,y) else 0] * 2, end="")
+ print()
+ print()
+
+
+# Run the main program
+if __name__ == "__main__":
+ main()
diff --git a/src/third_party/QR-Code-generator/python/qrcodegen-worker.py b/src/third_party/QR-Code-generator/python/qrcodegen-worker.py
new file mode 100644
index 0000000..c52548d
--- /dev/null
+++ b/src/third_party/QR-Code-generator/python/qrcodegen-worker.py
@@ -0,0 +1,87 @@
+#
+# QR Code generator test worker (Python 2, 3)
+#
+# This program reads data and encoding parameters from standard input and writes
+# QR Code bitmaps to standard output. The I/O format is one integer per line.
+# Run with no command line arguments. The program is intended for automated
+# batch testing of end-to-end functionality of this QR Code generator library.
+#
+# 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.
+#
+
+from __future__ import print_function
+import sys
+import qrcodegen
+py3 = sys.version_info.major >= 3
+
+
+def read_int():
+ return int((input if py3 else raw_input)())
+
+
+def main():
+ while True:
+
+ # Read data or exit
+ length = read_int()
+ if length == -1:
+ break
+ data = [read_int() for _ in range(length)]
+
+ # Read encoding parameters
+ errcorlvl = read_int()
+ minversion = read_int()
+ maxversion = read_int()
+ mask = read_int()
+ boostecl = read_int()
+
+ # Make segments for encoding
+ if all((b < 128) for b in data): # Is ASCII
+ segs = qrcodegen.QrSegment.make_segments("".join(chr(b) for b in data))
+ elif py3:
+ segs = [qrcodegen.QrSegment.make_bytes(bytes(data))]
+ else:
+ segs = [qrcodegen.QrSegment.make_bytes("".join(chr(b) for b in data))]
+
+ try: # Try to make QR Code symbol
+ qr = qrcodegen.QrCode.encode_segments(segs, ECC_LEVELS[errcorlvl], minversion, maxversion, mask, boostecl != 0)
+ # Print grid of modules
+ print(qr.get_version())
+ for y in range(qr.get_size()):
+ for x in range(qr.get_size()):
+ print(1 if qr.get_module(x, y) else 0)
+
+ except ValueError as e:
+ if e.args[0] != "Data too long":
+ raise
+ print(-1)
+ sys.stdout.flush()
+
+
+ECC_LEVELS = (
+ qrcodegen.QrCode.Ecc.LOW,
+ qrcodegen.QrCode.Ecc.MEDIUM,
+ qrcodegen.QrCode.Ecc.QUARTILE,
+ qrcodegen.QrCode.Ecc.HIGH,
+)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/third_party/QR-Code-generator/python/qrcodegen.py b/src/third_party/QR-Code-generator/python/qrcodegen.py
new file mode 100644
index 0000000..9a5b32c
--- /dev/null
+++ b/src/third_party/QR-Code-generator/python/qrcodegen.py
@@ -0,0 +1,839 @@
+#
+# QR Code generator library (Python 2, 3)
+#
+# 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.
+#
+
+import itertools, re, sys
+
+
+"""
+This module "qrcodegen", public members:
+- Class QrCode:
+ - Function encode_text(str text, QrCode.Ecc ecl) -> QrCode
+ - Function encode_binary(bytes data, QrCode.Ecc ecl) -> QrCode
+ - Function encode_segments(list<QrSegment> segs, QrCode.Ecc ecl,
+ int minversion=1, int maxversion=40, mask=-1, boostecl=true) -> QrCode
+ - Constants int MIN_VERSION, MAX_VERSION
+ - Constructor QrCode(bytes datacodewords, int mask, int version, QrCode.Ecc ecl)
+ - Method get_version() -> int
+ - Method get_size() -> int
+ - Method get_error_correction_level() -> QrCode.Ecc
+ - Method get_mask() -> int
+ - Method get_module(int x, int y) -> bool
+ - Method to_svg_str(int border) -> str
+ - Enum Ecc:
+ - Constants LOW, MEDIUM, QUARTILE, HIGH
+ - Field int ordinal
+- Class QrSegment:
+ - Function make_bytes(bytes data) -> QrSegment
+ - Function make_numeric(str digits) -> QrSegment
+ - Function make_alphanumeric(str text) -> QrSegment
+ - Function make_segments(str text) -> list<QrSegment>
+ - Function make_eci(int assignval) -> QrSegment
+ - Constructor QrSegment(QrSegment.Mode mode, int numch, list<int> bitdata)
+ - Method get_mode() -> QrSegment.Mode
+ - Method get_num_chars() -> int
+ - Method get_bits() -> list<int>
+ - Constants regex NUMERIC_REGEX, ALPHANUMERIC_REGEX
+ - Enum Mode:
+ - Constants NUMERIC, ALPHANUMERIC, BYTE, KANJI, ECI
+"""
+
+
+# ---- QR Code symbol class ----
+
+class QrCode(object):
+ """Represents an immutable square grid of black or white cells for a QR Code symbol. This class covers the
+ QR Code model 2 specification, supporting all versions (sizes) from 1 to 40, all 4 error correction levels."""
+
+ # ---- Public static factory functions ----
+
+ @staticmethod
+ def encode_text(text, ecl):
+ """Returns a QR Code symbol representing the specified Unicode text string at the specified error correction level.
+ As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer
+ Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
+ QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the
+ ecl argument if it can be done without increasing the version."""
+ segs = QrSegment.make_segments(text)
+ return QrCode.encode_segments(segs, ecl)
+
+
+ @staticmethod
+ def encode_binary(data, ecl):
+ """Returns a QR Code symbol representing the given binary data string at the given error correction level.
+ This function always encodes using the binary segment mode, not any text mode. The maximum number of
+ bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
+ The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version."""
+ if not isinstance(data, (bytes, bytearray)):
+ raise TypeError("Byte string/list expected")
+ return QrCode.encode_segments([QrSegment.make_bytes(data)], ecl)
+
+
+ @staticmethod
+ def encode_segments(segs, ecl, minversion=1, maxversion=40, mask=-1, boostecl=True):
+ """Returns a QR Code symbol representing the given data segments with the given encoding parameters.
+ The smallest possible QR Code version within the given range is automatically chosen for the output.
+ This function allows the user to create a custom sequence of segments that switches
+ between modes (such as alphanumeric and binary) to encode text more efficiently.
+ This function is considered to be lower level than simply encoding text or binary data."""
+
+ if not (QrCode.MIN_VERSION <= minversion <= maxversion <= QrCode.MAX_VERSION) or not (-1 <= mask <= 7):
+ raise ValueError("Invalid value")
+
+ # Find the minimal version number to use
+ for version in range(minversion, maxversion + 1):
+ datacapacitybits = QrCode._get_num_data_codewords(version, ecl) * 8 # Number of data bits available
+ datausedbits = QrSegment.get_total_bits(segs, version)
+ if datausedbits is not None and datausedbits <= datacapacitybits:
+ break # This version number is found to be suitable
+ if version >= maxversion: # All versions in the range could not fit the given data
+ raise ValueError("Data too long")
+ if datausedbits is None:
+ raise AssertionError()
+
+ # Increase the error correction level while the data still fits in the current version number
+ for newecl in (QrCode.Ecc.MEDIUM, QrCode.Ecc.QUARTILE, QrCode.Ecc.HIGH):
+ if boostecl and datausedbits <= QrCode._get_num_data_codewords(version, newecl) * 8:
+ ecl = newecl
+
+ # Create the data bit string by concatenating all segments
+ datacapacitybits = QrCode._get_num_data_codewords(version, ecl) * 8
+ bb = _BitBuffer()
+ for seg in segs:
+ bb.append_bits(seg.get_mode().get_mode_bits(), 4)
+ bb.append_bits(seg.get_num_chars(), seg.get_mode().num_char_count_bits(version))
+ bb.extend(seg._bitdata)
+
+ # Add terminator and pad up to a byte if applicable
+ bb.append_bits(0, min(4, datacapacitybits - len(bb)))
+ bb.append_bits(0, -len(bb) % 8) # Note: Python's modulo on negative numbers behaves better than C family languages
+
+ # Pad with alternate bytes until data capacity is reached
+ for padbyte in itertools.cycle((0xEC, 0x11)):
+ if len(bb) >= datacapacitybits:
+ break
+ bb.append_bits(padbyte, 8)
+ assert len(bb) % 8 == 0
+
+ # Create the QR Code symbol
+ return QrCode(bb.get_bytes(), mask, version, ecl)
+
+
+ # ---- Public constants ----
+
+ MIN_VERSION = 1
+ MAX_VERSION = 40
+
+
+ # ---- Constructor ----
+
+ def __init__(self, datacodewords, mask, version, errcorlvl):
+ """Creates a new QR Code symbol with the given version number, error correction level, binary data array,
+ and mask number. mask = -1 is for automatic choice, or 0 to 7 for fixed choice. This is a cumbersome low-level constructor
+ that should not be invoked directly by the user. To go one level up, see the QrCode.encode_segments() function."""
+
+ # Check arguments and handle simple scalar fields
+ if not (-1 <= mask <= 7):
+ raise ValueError("Mask value out of range")
+ if not (QrCode.MIN_VERSION <= version <= QrCode.MAX_VERSION):
+ raise ValueError("Version value out of range")
+ if not isinstance(errcorlvl, QrCode.Ecc):
+ raise TypeError("QrCode.Ecc expected")
+ self._version = version
+ self._errcorlvl = errcorlvl
+ self._size = version * 4 + 17
+
+ if len(datacodewords) != QrCode._get_num_data_codewords(version, errcorlvl):
+ raise ValueError("Invalid array length")
+ # Initialize grids of modules
+ self._modules = [[False] * self._size for _ in range(self._size)] # The modules of the QR symbol; start with entirely white grid
+ self._isfunction = [[False] * self._size for _ in range(self._size)] # Indicates function modules that are not subjected to masking
+ # Draw function patterns, draw all codewords
+ self._draw_function_patterns()
+ allcodewords = self._append_error_correction(datacodewords)
+ self._draw_codewords(allcodewords)
+
+ # Handle masking
+ if mask == -1: # Automatically choose best mask
+ minpenalty = 1 << 32
+ for i in range(8):
+ self._draw_format_bits(i)
+ self._apply_mask(i)
+ penalty = self._get_penalty_score()
+ if penalty < minpenalty:
+ mask = i
+ minpenalty = penalty
+ self._apply_mask(i) # Undoes the mask due to XOR
+ assert 0 <= mask <= 7
+ self._draw_format_bits(mask) # Overwrite old format bits
+ self._apply_mask(mask) # Apply the final choice of mask
+ self._mask = mask
+
+
+ # ---- Accessor methods ----
+
+ def get_version(self):
+ """Returns this QR Code symbol's version number, which is always between 1 and 40 (inclusive)."""
+ return self._version
+
+ def get_size(self):
+ """Returns the width and height of this QR Code symbol, measured in modules.
+ Always equal to version * 4 + 17, in the range 21 to 177."""
+ return self._size
+
+ def get_error_correction_level(self):
+ """Returns the error correction level used in this QR Code symbol."""
+ return self._errcorlvl
+
+ def get_mask(self):
+ """Returns the mask pattern used in this QR Code symbol, in the range 0 to 7 (i.e. unsigned 3-bit integer).
+ Note that even if a constructor was called with automatic masking requested
+ (mask = -1), the resulting object will still have a mask value between 0 and 7."""
+ return self._mask
+
+ def get_module(self, x, y):
+ """Returns the color of the module (pixel) at the given coordinates, which is either
+ False for white or True for black. The top left corner has the coordinates (x=0, y=0).
+ If the given coordinates are out of bounds, then False (white) is returned."""
+ return (0 <= x < self._size) and (0 <= y < self._size) and self._modules[y][x]
+
+
+ # ---- Public instance methods ----
+
+ def to_svg_str(self, border):
+ """Based on the given number of border modules to add as padding, this returns a
+ string whose contents represents an SVG XML file that depicts this QR Code symbol."""
+ if border < 0:
+ raise ValueError("Border must be non-negative")
+ parts = []
+ for y in range(-border, self._size + border):
+ for x in range(-border, self._size + border):
+ if self.get_module(x, y):
+ parts.append("M{},{}h1v1h-1z".format(x + border, y + border))
+ return """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 {0} {0}" stroke="none">
+ <rect width="100%" height="100%" fill="#FFFFFF"/>
+ <path d="{1}" fill="#000000"/>
+</svg>
+""".format(self._size + border * 2, " ".join(parts))
+
+
+ # ---- Private helper methods for constructor: Drawing function modules ----
+
+ def _draw_function_patterns(self):
+ # Draw horizontal and vertical timing patterns
+ for i in range(self._size):
+ self._set_function_module(6, i, i % 2 == 0)
+ self._set_function_module(i, 6, i % 2 == 0)
+
+ # Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
+ self._draw_finder_pattern(3, 3)
+ self._draw_finder_pattern(self._size - 4, 3)
+ self._draw_finder_pattern(3, self._size - 4)
+
+ # Draw numerous alignment patterns
+ alignpatpos = QrCode._get_alignment_pattern_positions(self._version)
+ numalign = len(alignpatpos)
+ skips = ((0, 0), (0, numalign - 1), (numalign - 1, 0)) # Skip the three finder corners
+ for i in range(numalign):
+ for j in range(numalign):
+ if (i, j) not in skips:
+ self._draw_alignment_pattern(alignpatpos[i], alignpatpos[j])
+
+ # Draw configuration data
+ self._draw_format_bits(0) # Dummy mask value; overwritten later in the constructor
+ self._draw_version()
+
+
+ def _draw_format_bits(self, mask):
+ """Draws two copies of the format bits (with its own error correction code)
+ based on the given mask and this object's error correction level field."""
+ # Calculate error correction code and pack bits
+ data = self._errcorlvl.formatbits << 3 | mask # errCorrLvl is uint2, mask is uint3
+ rem = data
+ for _ in range(10):
+ rem = (rem << 1) ^ ((rem >> 9) * 0x537)
+ data = data << 10 | rem
+ data ^= 0x5412 # uint15
+ assert data >> 15 == 0
+
+ # Draw first copy
+ for i in range(0, 6):
+ self._set_function_module(8, i, (data >> i) & 1 != 0)
+ self._set_function_module(8, 7, (data >> 6) & 1 != 0)
+ self._set_function_module(8, 8, (data >> 7) & 1 != 0)
+ self._set_function_module(7, 8, (data >> 8) & 1 != 0)
+ for i in range(9, 15):
+ self._set_function_module(14 - i, 8, (data >> i) & 1 != 0)
+
+ # Draw second copy
+ for i in range(0, 8):
+ self._set_function_module(self._size - 1 - i, 8, (data >> i) & 1 != 0)
+ for i in range(8, 15):
+ self._set_function_module(8, self._size - 15 + i, (data >> i) & 1 != 0)
+ self._set_function_module(8, self._size - 8, True)
+
+
+ def _draw_version(self):
+ """Draws two copies of the version bits (with its own error correction code),
+ based on this object's version field (which only has an effect for 7 <= version <= 40)."""
+ if self._version < 7:
+ return
+
+ # Calculate error correction code and pack bits
+ rem = self._version # version is uint6, in the range [7, 40]
+ for _ in range(12):
+ rem = (rem << 1) ^ ((rem >> 11) * 0x1F25)
+ data = self._version << 12 | rem # uint18
+ assert data >> 18 == 0
+
+ # Draw two copies
+ for i in range(18):
+ bit = (data >> i) & 1 != 0
+ a, b = self._size - 11 + i % 3, i // 3
+ self._set_function_module(a, b, bit)
+ self._set_function_module(b, a, bit)
+
+
+ def _draw_finder_pattern(self, x, y):
+ """Draws a 9*9 finder pattern including the border separator, with the center module at (x, y)."""
+ for i in range(-4, 5):
+ for j in range(-4, 5):
+ xx, yy = x + j, y + i
+ if (0 <= xx < self._size) and (0 <= yy < self._size):
+ # Chebyshev/infinity norm
+ self._set_function_module(xx, yy, max(abs(i), abs(j)) not in (2, 4))
+
+
+ def _draw_alignment_pattern(self, x, y):
+ """Draws a 5*5 alignment pattern, with the center module at (x, y)."""
+ for i in range(-2, 3):
+ for j in range(-2, 3):
+ self._set_function_module(x + j, y + i, max(abs(i), abs(j)) != 1)
+
+
+ def _set_function_module(self, x, y, isblack):
+ """Sets the color of a module and marks it as a function module.
+ Only used by the constructor. Coordinates must be in range."""
+ assert type(isblack) is bool
+ self._modules[y][x] = isblack
+ self._isfunction[y][x] = True
+
+
+ # ---- Private helper methods for constructor: Codewords and masking ----
+
+ def _append_error_correction(self, data):
+ """Returns a new byte string representing the given data with the appropriate error correction
+ codewords appended to it, based on this object's version and error correction level."""
+ version = self._version
+ assert len(data) == QrCode._get_num_data_codewords(version, self._errcorlvl)
+
+ # Calculate parameter numbers
+ numblocks = QrCode._NUM_ERROR_CORRECTION_BLOCKS[self._errcorlvl.ordinal][version]
+ blockecclen = QrCode._ECC_CODEWORDS_PER_BLOCK[self._errcorlvl.ordinal][version]
+ rawcodewords = QrCode._get_num_raw_data_modules(version) // 8
+ numshortblocks = numblocks - rawcodewords % numblocks
+ shortblocklen = rawcodewords // numblocks
+
+ # Split data into blocks and append ECC to each block
+ blocks = []
+ rs = _ReedSolomonGenerator(blockecclen)
+ k = 0
+ for i in range(numblocks):
+ dat = data[k : k + shortblocklen - blockecclen + (0 if i < numshortblocks else 1)]
+ k += len(dat)
+ ecc = rs.get_remainder(dat)
+ if i < numshortblocks:
+ dat.append(0)
+ dat.extend(ecc)
+ blocks.append(dat)
+ assert k == len(data)
+
+ # Interleave (not concatenate) the bytes from every block into a single sequence
+ result = []
+ for i in range(len(blocks[0])):
+ for (j, blk) in enumerate(blocks):
+ # Skip the padding byte in short blocks
+ if i != shortblocklen - blockecclen or j >= numshortblocks:
+ result.append(blk[i])
+ assert len(result) == rawcodewords
+ return result
+
+
+ def _draw_codewords(self, data):
+ """Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
+ data area of this QR Code symbol. Function modules need to be marked off before this is called."""
+ assert len(data) == QrCode._get_num_raw_data_modules(self._version) // 8
+
+ i = 0 # Bit index into the data
+ # Do the funny zigzag scan
+ for right in range(self._size - 1, 0, -2): # Index of right column in each column pair
+ if right <= 6:
+ right -= 1
+ for vert in range(self._size): # Vertical counter
+ for j in range(2):
+ x = right - j # Actual x coordinate
+ upward = (right + 1) & 2 == 0
+ y = (self._size - 1 - vert) if upward else vert # Actual y coordinate
+ if not self._isfunction[y][x] and i < len(data) * 8:
+ self._modules[y][x] = (data[i >> 3] >> (7 - (i & 7))) & 1 != 0
+ i += 1
+ # If there are any remainder bits (0 to 7), they are already
+ # set to 0/false/white when the grid of modules was initialized
+ assert i == len(data) * 8
+
+
+ def _apply_mask(self, mask):
+ """XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical
+ properties, calling applyMask(m) twice with the same value is equivalent to no change at all.
+ This means it is possible to apply a mask, undo it, and try another mask. Note that a final
+ well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.)."""
+ if not (0 <= mask <= 7):
+ raise ValueError("Mask value out of range")
+ masker = QrCode._MASK_PATTERNS[mask]
+ for y in range(self._size):
+ for x in range(self._size):
+ self._modules[y][x] ^= (masker(x, y) == 0) and (not self._isfunction[y][x])
+
+
+ def _get_penalty_score(self):
+ """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."""
+ result = 0
+ size = self._size
+ modules = self._modules
+
+ # Adjacent modules in row having same color
+ for y in range(size):
+ for x in range(size):
+ if x == 0 or modules[y][x] != colorx:
+ colorx = modules[y][x]
+ runx = 1
+ else:
+ runx += 1
+ if runx == 5:
+ result += QrCode._PENALTY_N1
+ elif runx > 5:
+ result += 1
+ # Adjacent modules in column having same color
+ for x in range(size):
+ for y in range(size):
+ if y == 0 or modules[y][x] != colory:
+ colory = modules[y][x]
+ runy = 1
+ else:
+ runy += 1
+ if runy == 5:
+ result += QrCode._PENALTY_N1
+ elif runy > 5:
+ result += 1
+
+ # 2*2 blocks of modules having same color
+ for y in range(size - 1):
+ for x in range(size - 1):
+ if modules[y][x] == modules[y][x + 1] == modules[y + 1][x] == modules[y + 1][x + 1]:
+ result += QrCode._PENALTY_N2
+
+ # Finder-like pattern in rows
+ for y in range(size):
+ bits = 0
+ for x in range(size):
+ bits = ((bits << 1) & 0x7FF) | (1 if modules[y][x] else 0)
+ if x >= 10 and bits in (0x05D, 0x5D0): # Needs 11 bits accumulated
+ result += QrCode._PENALTY_N3
+ # Finder-like pattern in columns
+ for x in range(size):
+ bits = 0
+ for y in range(size):
+ bits = ((bits << 1) & 0x7FF) | (1 if modules[y][x] else 0)
+ if y >= 10 and bits in (0x05D, 0x5D0): # Needs 11 bits accumulated
+ result += QrCode._PENALTY_N3
+
+ # Balance of black and white modules
+ black = sum((1 if cell else 0) for row in modules for cell in row)
+ total = size**2
+ # Find smallest k such that (45-5k)% <= dark/total <= (55+5k)%
+ for k in itertools.count():
+ if (9-k)*total <= black*20 <= (11+k)*total:
+ break
+ result += QrCode._PENALTY_N4
+ return result
+
+
+ # ---- Private static helper functions ----
+
+ @staticmethod
+ def _get_alignment_pattern_positions(ver):
+ """Returns a sequence of positions of the alignment patterns in ascending order. These positions are
+ used on both the x and y axes. Each value in the resulting sequence is in the range [0, 177).
+ This stateless pure function could be implemented as table of 40 variable-length lists of integers."""
+ if not (QrCode.MIN_VERSION <= ver <= QrCode.MAX_VERSION):
+ raise ValueError("Version number out of range")
+ elif ver == 1:
+ return []
+ else:
+ numalign = ver // 7 + 2
+ if ver != 32:
+ # ceil((size - 13) / (2*numalign - 2)) * 2
+ step = (ver * 4 + numalign * 2 + 1) // (2 * numalign - 2) * 2
+ else: # C-C-C-Combo breaker!
+ step = 26
+ result = [6]
+ pos = ver * 4 + 10
+ for _ in range(numalign - 1):
+ result.insert(1, pos)
+ pos -= step
+ return result
+
+
+ @staticmethod
+ def _get_num_raw_data_modules(ver):
+ """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."""
+ if not (QrCode.MIN_VERSION <= ver <= QrCode.MAX_VERSION):
+ raise ValueError("Version number out of range")
+ result = (16 * ver + 128) * ver + 64
+ if ver >= 2:
+ numalign = ver // 7 + 2
+ result -= (25 * numalign - 10) * numalign - 55
+ if ver >= 7:
+ result -= 18 * 2 # Subtract version information
+ return result
+
+
+ @staticmethod
+ def _get_num_data_codewords(ver, ecl):
+ """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."""
+ if not (QrCode.MIN_VERSION <= ver <= QrCode.MAX_VERSION):
+ raise ValueError("Version number out of range")
+ return QrCode._get_num_raw_data_modules(ver) // 8 \
+ - QrCode._ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] \
+ * QrCode._NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver]
+
+
+ # ---- Private tables of constants ----
+
+ # For use in getPenaltyScore(), when evaluating which mask is best.
+ _PENALTY_N1 = 3
+ _PENALTY_N2 = 3
+ _PENALTY_N3 = 40
+ _PENALTY_N4 = 10
+
+ _ECC_CODEWORDS_PER_BLOCK = (
+ # 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
+ (None, 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
+ (None, 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
+ (None, 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
+ (None, 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
+
+ _NUM_ERROR_CORRECTION_BLOCKS = (
+ # 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
+ (None, 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
+ (None, 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
+ (None, 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
+ (None, 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
+
+ _MASK_PATTERNS = (
+ (lambda x, y: (x + y) % 2 ),
+ (lambda x, y: y % 2 ),
+ (lambda x, y: x % 3 ),
+ (lambda x, y: (x + y) % 3 ),
+ (lambda x, y: (x // 3 + y // 2) % 2 ),
+ (lambda x, y: x * y % 2 + x * y % 3 ),
+ (lambda x, y: (x * y % 2 + x * y % 3) % 2 ),
+ (lambda x, y: ((x + y) % 2 + x * y % 3) % 2),
+ )
+
+
+ # ---- Public helper enumeration ----
+
+ class Ecc(object):
+ """Represents the error correction level used in a QR Code symbol."""
+ # Private constructor
+ def __init__(self, i, fb):
+ self.ordinal = i # (Public) In the range 0 to 3 (unsigned 2-bit integer)
+ self.formatbits = fb # (Package-private) In the range 0 to 3 (unsigned 2-bit integer)
+
+ # Public constants. Create them outside the class.
+ Ecc.LOW = Ecc(0, 1)
+ Ecc.MEDIUM = Ecc(1, 0)
+ Ecc.QUARTILE = Ecc(2, 3)
+ Ecc.HIGH = Ecc(3, 2)
+
+
+
+# ---- Data segment class ----
+
+class QrSegment(object):
+ """Represents a character string to be encoded in a QR Code symbol. Each segment has
+ a mode, and a sequence of characters that is already encoded as a sequence of bits.
+ Instances of this class are immutable.
+ This segment class 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."""
+
+ # ---- Public static factory functions ----
+
+ @staticmethod
+ def make_bytes(data):
+ """Returns a segment representing the given binary data encoded in byte mode."""
+ py3 = sys.version_info.major >= 3
+ if (py3 and isinstance(data, str)) or (not py3 and isinstance(data, unicode)):
+ raise TypeError("Byte string/list expected")
+ if not py3 and isinstance(data, str):
+ data = bytearray(data)
+ bb = _BitBuffer()
+ for b in data:
+ bb.append_bits(b, 8)
+ return QrSegment(QrSegment.Mode.BYTE, len(data), bb)
+
+
+ @staticmethod
+ def make_numeric(digits):
+ """Returns a segment representing the given string of decimal digits encoded in numeric mode."""
+ if QrSegment.NUMERIC_REGEX.match(digits) is None:
+ raise ValueError("String contains non-numeric characters")
+ bb = _BitBuffer()
+ for i in range(0, len(digits) - 2, 3): # Process groups of 3
+ bb.append_bits(int(digits[i : i + 3]), 10)
+ rem = len(digits) % 3
+ if rem > 0: # 1 or 2 digits remaining
+ bb.append_bits(int(digits[-rem : ]), rem * 3 + 1)
+ return QrSegment(QrSegment.Mode.NUMERIC, len(digits), bb)
+
+
+ @staticmethod
+ def make_alphanumeric(text):
+ """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."""
+ if QrSegment.ALPHANUMERIC_REGEX.match(text) is None:
+ raise ValueError("String contains unencodable characters in alphanumeric mode")
+ bb = _BitBuffer()
+ for i in range(0, len(text) - 1, 2): # Process groups of 2
+ temp = QrSegment._ALPHANUMERIC_ENCODING_TABLE[text[i]] * 45
+ temp += QrSegment._ALPHANUMERIC_ENCODING_TABLE[text[i + 1]]
+ bb.append_bits(temp, 11)
+ if len(text) % 2 > 0: # 1 character remaining
+ bb.append_bits(QrSegment._ALPHANUMERIC_ENCODING_TABLE[text[-1]], 6)
+ return QrSegment(QrSegment.Mode.ALPHANUMERIC, len(text), bb)
+
+
+ @staticmethod
+ def make_segments(text):
+ """Returns a new mutable list of zero or more segments to represent the given Unicode text string.
+ The result may use various segment modes and switch modes to optimize the length of the bit stream."""
+ if not (isinstance(text, str) or (sys.version_info.major < 3 and isinstance(text, unicode))):
+ raise TypeError("Text string expected")
+
+ # Select the most efficient segment encoding automatically
+ if text == "":
+ return []
+ elif QrSegment.NUMERIC_REGEX.match(text) is not None:
+ return [QrSegment.make_numeric(text)]
+ elif QrSegment.ALPHANUMERIC_REGEX.match(text) is not None:
+ return [QrSegment.make_alphanumeric(text)]
+ else:
+ return [QrSegment.make_bytes(text.encode("UTF-8"))]
+
+
+ @staticmethod
+ def make_eci(assignval):
+ """Returns a segment representing an Extended Channel Interpretation
+ (ECI) designator with the given assignment value."""
+ bb = _BitBuffer()
+ if 0 <= assignval < (1 << 7):
+ bb.append_bits(assignval, 8)
+ elif (1 << 7) <= assignval < (1 << 14):
+ bb.append_bits(2, 2)
+ bb.append_bits(assignval, 14)
+ elif (1 << 14) <= assignval < 1000000:
+ bb.append_bits(6, 3)
+ bb.append_bits(assignval, 21)
+ else:
+ raise ValueError("ECI assignment value out of range")
+ return QrSegment(QrSegment.Mode.ECI, 0, bb)
+
+
+ # ---- Constructor ----
+
+ def __init__(self, mode, numch, bitdata):
+ if numch < 0 or not isinstance(mode, QrSegment.Mode):
+ raise ValueError()
+ self._mode = mode
+ self._numchars = numch
+ self._bitdata = list(bitdata) # Make defensive copy
+
+
+ # ---- Accessor methods ----
+
+ def get_mode(self):
+ return self._mode
+
+ def get_num_chars(self):
+ return self._numchars
+
+ def get_bits(self):
+ return list(self._bitdata) # Make defensive copy
+
+
+ # Package-private helper function.
+ @staticmethod
+ def get_total_bits(segs, version):
+ if not (QrCode.MIN_VERSION <= version <= QrCode.MAX_VERSION):
+ raise ValueError("Version number out of range")
+ result = 0
+ for seg in segs:
+ ccbits = seg.get_mode().num_char_count_bits(version)
+ # Fail if segment length value doesn't fit in the length field's bit-width
+ if seg.get_num_chars() >= (1 << ccbits):
+ return None
+ result += 4 + ccbits + len(seg._bitdata)
+ return result
+
+
+ # ---- Constants ----
+
+ # (Public) Can test whether a string is encodable in numeric mode (such as by using make_numeric())
+ NUMERIC_REGEX = re.compile(r"[0-9]*\Z")
+
+ # (Public) Can test whether a string is encodable in alphanumeric mode (such as by using make_alphanumeric())
+ ALPHANUMERIC_REGEX = re.compile(r"[A-Z0-9 $%*+./:-]*\Z")
+
+ # (Private) Dictionary of "0"->0, "A"->10, "$"->37, etc.
+ _ALPHANUMERIC_ENCODING_TABLE = {ch: i for (i, ch) in enumerate("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")}
+
+
+ # ---- Public helper enumeration ----
+
+ class Mode(object):
+ """The mode field of a segment. Immutable."""
+
+ # Private constructor
+ def __init__(self, modebits, charcounts):
+ self._modebits = modebits
+ self._charcounts = charcounts
+
+ # Package-private method
+ def get_mode_bits(self):
+ """Returns an unsigned 4-bit integer value (range 0 to 15) representing the mode indicator bits for this mode object."""
+ return self._modebits
+
+ # Package-private method
+ def num_char_count_bits(self, ver):
+ """Returns the bit width of the segment character count field for this mode object at the given version number."""
+ if 1 <= ver <= 9: return self._charcounts[0]
+ elif 10 <= ver <= 26: return self._charcounts[1]
+ elif 27 <= ver <= 40: return self._charcounts[2]
+ else: raise ValueError("Version number out of range")
+
+ # Public constants. Create them outside the class.
+ Mode.NUMERIC = Mode(0x1, (10, 12, 14))
+ Mode.ALPHANUMERIC = Mode(0x2, ( 9, 11, 13))
+ Mode.BYTE = Mode(0x4, ( 8, 16, 16))
+ Mode.KANJI = Mode(0x8, ( 8, 10, 12))
+ Mode.ECI = Mode(0x7, ( 0, 0, 0))
+
+
+
+# ---- Private helper classes ----
+
+class _ReedSolomonGenerator(object):
+ """Computes the Reed-Solomon error correction codewords for a sequence of data codewords
+ at a given degree. Objects are immutable, and the state only depends on the degree.
+ This class exists because each data block in a QR Code shares the same the divisor polynomial."""
+
+ def __init__(self, degree):
+ """Creates a Reed-Solomon ECC generator for the given degree. This could be implemented
+ as a lookup table over all possible parameter values, instead of as an algorithm."""
+ if degree < 1 or degree > 255:
+ raise ValueError("Degree out of range")
+
+ # Start with the monomial x^0
+ self.coefficients = [0] * (degree - 1) + [1]
+
+ # Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
+ # drop the highest term, and store the rest of the coefficients in order of descending powers.
+ # Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
+ root = 1
+ for _ in range(degree): # Unused variable i
+ # Multiply the current product by (x - r^i)
+ for j in range(degree):
+ self.coefficients[j] = _ReedSolomonGenerator._multiply(self.coefficients[j], root)
+ if j + 1 < degree:
+ self.coefficients[j] ^= self.coefficients[j + 1]
+ root = _ReedSolomonGenerator._multiply(root, 0x02)
+
+
+ def get_remainder(self, data):
+ """Computes and returns the Reed-Solomon error correction codewords for the given
+ sequence of data codewords. The returned object is always a new byte list.
+ This method does not alter this object's state (because it is immutable)."""
+ # Compute the remainder by performing polynomial division
+ result = [0] * len(self.coefficients)
+ for b in data:
+ factor = b ^ result.pop(0)
+ result.append(0)
+ for i in range(len(result)):
+ result[i] ^= _ReedSolomonGenerator._multiply(self.coefficients[i], factor)
+ return result
+
+
+ @staticmethod
+ def _multiply(x, y):
+ """Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
+ are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8."""
+ if x >> 8 != 0 or y >> 8 != 0:
+ raise ValueError("Byte out of range")
+ # Russian peasant multiplication
+ z = 0
+ for i in reversed(range(8)):
+ z = (z << 1) ^ ((z >> 7) * 0x11D)
+ z ^= ((y >> i) & 1) * x
+ assert z >> 8 == 0
+ return z
+
+
+
+class _BitBuffer(list):
+ """An appendable sequence of bits (0's and 1's)."""
+
+ def get_bytes(self):
+ """Packs this buffer's bits into bytes in big endian,
+ padding with '0' bit values, and returns the new list."""
+ result = [0] * ((len(self) + 7) // 8)
+ for (i, bit) in enumerate(self):
+ result[i >> 3] |= bit << (7 - (i & 7))
+ return result
+
+ def append_bits(self, val, n):
+ """Appends the given number of low bits of the given value
+ to this sequence. Requires 0 <= val < 2^n."""
+ if n < 0 or val >> n != 0:
+ raise ValueError("Value out of range")
+ self.extend(((val >> i) & 1) for i in reversed(range(n)))
diff --git a/src/third_party/QR-Code-generator/python/setup.cfg b/src/third_party/QR-Code-generator/python/setup.cfg
new file mode 100644
index 0000000..2a9acf1
--- /dev/null
+++ b/src/third_party/QR-Code-generator/python/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal = 1
diff --git a/src/third_party/QR-Code-generator/python/setup.py b/src/third_party/QR-Code-generator/python/setup.py
new file mode 100644
index 0000000..6026451
--- /dev/null
+++ b/src/third_party/QR-Code-generator/python/setup.py
@@ -0,0 +1,113 @@
+#
+# QR Code generator Distutils script (Python 2, 3)
+#
+# 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.
+#
+
+import setuptools
+
+
+setuptools.setup(
+ name = "qrcodegen",
+ description = "High quality QR Code generator library for Python 2 and 3",
+ version = "1.2.0",
+ platforms = "OS Independent",
+ license = "MIT License",
+
+ author = "Project Nayuki",
+ author_email = "me@nayuki.io",
+ url = "https://www.nayuki.io/page/qr-code-generator-library",
+
+ classifiers = [
+ "Development Status :: 5 - Production/Stable",
+ "Intended Audience :: Developers",
+ "Intended Audience :: Information Technology",
+ "License :: OSI Approved :: MIT License",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 2",
+ "Programming Language :: Python :: 3",
+ "Topic :: Multimedia :: Graphics",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ ],
+
+ long_description = """=========================
+QR Code generator library
+=========================
+
+
+Introduction
+------------
+
+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
+
+
+Features
+--------
+
+Core features:
+
+* Available in 6 programming languages, all with nearly equal functionality: Java, JavaScript, Python, C++, C, Rust
+* 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 formats: Raw modules/pixels of the QR symbol, SVG XML string
+* 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
+
+
+Usage
+-----
+
+Install this package by downloading the source code ZIP file from PyPI_, or by running ``pip install qrcodegen``.
+
+Examples:
+
+ from qrcodegen import *
+
+ # Simple operation
+ qr0 = QrCode.encode_text("Hello, world!", QrCode.Ecc.MEDIUM)
+ svg = qr0.to_svg_str(4)
+
+ # Manual operation
+ segs = QrSegment.make_segments("3141592653589793238462643383")
+ qr1 = QrCode.encode_segments(segs, QrCode.Ecc.HIGH, 5, 5, 2, False)
+ border = 4
+ for y in range(-border, qr1.get_size() + border):
+ for x in range(-border, qr1.get_size() + border):
+ color = qr1.get_module(x, y) # False for white, True for black
+ # (... paint the module onto pixels ...)
+
+More complete set of examples: https://github.com/nayuki/QR-Code-generator/blob/master/python/qrcodegen-demo.py .
+
+API documentation is in the source file itself, with a summary comment at the top: https://github.com/nayuki/QR-Code-generator/blob/master/python/qrcodegen.py .
+
+.. _PyPI: https://pypi.python.org/pypi/qrcodegen""",
+
+ py_modules = ["qrcodegen"],
+)
diff --git a/src/third_party/QR-Code-generator/rust/Cargo.toml b/src/third_party/QR-Code-generator/rust/Cargo.toml
new file mode 100644
index 0000000..4fe927c
--- /dev/null
+++ b/src/third_party/QR-Code-generator/rust/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "qrcodegen"
+version = "1.2.1"
+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"
+readme = "Readme.markdown"
+keywords = ["qr-code", "barcode", "encoder", "image"]
+categories = ["encoding", "multimedia::images"]
+license = "MIT"
diff --git a/src/third_party/QR-Code-generator/rust/Readme.markdown b/src/third_party/QR-Code-generator/rust/Readme.markdown
new file mode 100644
index 0000000..fd8cb50
--- /dev/null
+++ b/src/third_party/QR-Code-generator/rust/Readme.markdown
@@ -0,0 +1,57 @@
+QR Code generator library
+=========================
+
+
+Introduction
+------------
+
+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
+
+
+Features
+--------
+
+Core features:
+
+* Available in 6 programming languages, all with nearly equal functionality: Java, JavaScript, Python, C++, C, Rust
+* 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 formats: Raw modules/pixels of the QR symbol, SVG XML string
+* 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::QrCode;
+ use qrcodegen::QrCodeEcc;
+ use qrcodegen::QrSegment;
+
+ // Simple operation
+ let qr0 = QrCode::encode_text("Hello, world!",
+ QrCodeEcc::Medium).unwrap();
+ let svg = qr0.to_svg_string(4);
+
+ // Manual operation
+ let chrs: Vec<char> = "3141592653589793238462643383".chars().collect();
+ let segs = QrSegment::make_segments(&chrs);
+ let qr1 = QrCode::encode_segments_advanced(
+ &segs, QrCodeEcc::High, 5, 5, Some(2), false).unwrap();
+ for y in 0 .. qr1.size() {
+ for x in 0 .. qr1.size() {
+ (... paint qr1.get_module(x, y) ...)
+ }
+ }
+
+More complete set of examples: https://github.com/nayuki/QR-Code-generator/blob/master/rust/examples/qrcodegen-demo.rs .
diff --git a/src/third_party/QR-Code-generator/rust/examples/qrcodegen-demo.rs b/src/third_party/QR-Code-generator/rust/examples/qrcodegen-demo.rs
new file mode 100644
index 0000000..1fa2d3f
--- /dev/null
+++ b/src/third_party/QR-Code-generator/rust/examples/qrcodegen-demo.rs
@@ -0,0 +1,184 @@
+/*
+ * QR Code generator demo (Rust)
+ *
+ * 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::QrCode_MAX_VERSION;
+use qrcodegen::QrCode_MIN_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 qr: QrCode = QrCode::encode_text(text, errcorlvl).unwrap();
+ print_qr(&qr);
+ println!("{}", qr.to_svg_string(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 qr = QrCode::encode_text("314159265358979323846264338327950288419716939937510", QrCodeEcc::Medium).unwrap();
+ print_qr(&qr);
+
+ // Alphanumeric mode encoding (5.5 bits per character)
+ let qr = QrCode::encode_text("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCodeEcc::High).unwrap();
+ print_qr(&qr);
+
+ // Unicode text as UTF-8
+ let qr = QrCode::encode_text("こんにちwa、世界! αβγδ", QrCodeEcc::Quartile).unwrap();
+ print_qr(&qr);
+
+ // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
+ let qr = QrCode::encode_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."), QrCodeEcc::High).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 qr = QrCode::encode_text(&[silver0, silver1].concat(), QrCodeEcc::Low).unwrap();
+ print_qr(&qr);
+
+ let segs = vec![
+ QrSegment::make_alphanumeric(&to_chars(silver0)),
+ QrSegment::make_numeric(&to_chars(silver1)),
+ ];
+ let qr = QrCode::encode_segments(&segs, QrCodeEcc::Low).unwrap();
+ print_qr(&qr);
+
+ // Illustration "golden"
+ let golden0 = "Golden ratio φ = 1.";
+ let golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
+ let golden2 = "......";
+ let qr = QrCode::encode_text(&[golden0, golden1, golden2].concat(), QrCodeEcc::Low).unwrap();
+ print_qr(&qr);
+
+ let segs = vec![
+ QrSegment::make_bytes(golden0.as_bytes()),
+ QrSegment::make_numeric(&to_chars(golden1)),
+ QrSegment::make_alphanumeric(&to_chars(golden2)),
+ ];
+ let qr = QrCode::encode_segments(&segs, QrCodeEcc::Low).unwrap();
+ print_qr(&qr);
+
+ // Illustration "Madoka": kanji, kana, Greek, Cyrillic, full-width Latin characters
+ let madoka = "「魔法少女まどか☆マギカ」って、 ИАИ desu κα?";
+ let qr = QrCode::encode_text(madoka, QrCodeEcc::Low).unwrap();
+ print_qr(&qr);
+
+ let kanjichars: Vec<u32> = 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(Vec::new());
+ for c in &kanjichars {
+ bb.append_bits(*c, 13);
+ }
+ let segs = vec![
+ QrSegment::new(qrcodegen::QrSegmentMode::Kanji, kanjichars.len(), bb.0),
+ ];
+ let qr = QrCode::encode_segments(&segs, QrCodeEcc::Low).unwrap();
+ print_qr(&qr);
+}
+
+
+// Creates QR Codes with the same size and contents but different mask patterns.
+fn do_mask_demo() {
+ // Project Nayuki URL
+ let segs = QrSegment::make_segments(&to_chars("https://www.nayuki.io/"));
+ let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, QrCode_MIN_VERSION, QrCode_MAX_VERSION, None, true).unwrap(); // Automatic mask
+ print_qr(&qr);
+ let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(3)), true).unwrap(); // Force mask 3
+ print_qr(&qr);
+
+ // Chinese text as UTF-8
+ let segs = QrSegment::make_segments(&to_chars("維基百科(Wikipedia,聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫"));
+ let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(0)), true).unwrap(); // Force mask 0
+ print_qr(&qr);
+ let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(1)), true).unwrap(); // Force mask 1
+ print_qr(&qr);
+ let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(5)), true).unwrap(); // Force mask 5
+ print_qr(&qr);
+ let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(7)), true).unwrap(); // Force mask 7
+ print_qr(&qr);
+}
+
+
+
+/*---- Utilities ----*/
+
+// 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!();
+}
+
+
+// Converts the given borrowed string slice to a new character vector.
+fn to_chars(text: &str) -> Vec<char> {
+ text.chars().collect()
+}
diff --git a/src/third_party/QR-Code-generator/rust/examples/qrcodegen-worker.rs b/src/third_party/QR-Code-generator/rust/examples/qrcodegen-worker.rs
new file mode 100644
index 0000000..5537f19
--- /dev/null
+++ b/src/third_party/QR-Code-generator/rust/examples/qrcodegen-worker.rs
@@ -0,0 +1,117 @@
+/*
+ * QR Code generator test worker (Rust)
+ *
+ * This program reads data and encoding parameters from standard input and writes
+ * QR Code bitmaps to standard output. The I/O format is one integer per line.
+ * Run with no command line arguments. The program is intended for automated
+ * batch testing of end-to-end functionality of this QR Code generator library.
+ *
+ * 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::Version;
+
+
+fn main() {
+ loop {
+
+ // Read data length or exit
+ let length: i16 = read_int();
+ if length == -1 {
+ break;
+ }
+
+ // Read data bytes
+ let mut data = Vec::<u8>::with_capacity(length as usize);
+ for _ in 0 .. length {
+ let b: i16 = read_int();
+ assert_eq!((b as u8) as i16, b, "Byte value out of range");
+ data.push(b as u8);
+ }
+ let isascii: bool = data.iter().all(|b| *b < 128);
+
+ // Read encoding parameters
+ let errcorlvl = read_int();
+ let minversion = read_int();
+ let maxversion = read_int();
+ let mask = read_int();
+ let boostecl = read_int();
+ assert!(0 <= errcorlvl && errcorlvl <= 3);
+ assert!((qrcodegen::QrCode_MIN_VERSION.value() as i16) <= minversion
+ && minversion <= maxversion
+ && maxversion <= (qrcodegen::QrCode_MAX_VERSION.value() as i16));
+ assert!(-1 <= mask && mask <= 7);
+ assert!(boostecl >> 1 == 0);
+
+ // Make segments for encoding
+ let segs: Vec<QrSegment>;
+ if isascii {
+ let chrs: Vec<char> = std::str::from_utf8(&data).unwrap().chars().collect();
+ segs = QrSegment::make_segments(&chrs);
+ } else {
+ segs = vec![QrSegment::make_bytes(&data)];
+ }
+
+ // Try to make QR Code symbol
+ let msk = if mask == -1 { None } else { Some(Mask::new(mask as u8)) };
+ match QrCode::encode_segments_advanced(&segs, ECC_LEVELS[errcorlvl as usize],
+ Version::new(minversion as u8), Version::new(maxversion as u8), msk, boostecl != 0) {
+
+ Some(qr) => {
+ // Print grid of modules
+ println!("{}", qr.version().value());
+ for y in 0 .. qr.size() {
+ for x in 0 .. qr.size() {
+ println!("{}", qr.get_module(x, y) as i8);
+ }
+ }
+ },
+ None => println!("-1"),
+ }
+ use std::io::Write;
+ std::io::stdout().flush().unwrap();
+ }
+}
+
+
+fn read_int() -> i16 {
+ let mut line = String::new();
+ std::io::stdin().read_line(&mut line).unwrap();
+ let mut chrs: Vec<char> = line.chars().collect();
+ assert_eq!(chrs.pop().unwrap(), '\n');
+ let line: String = chrs.iter().cloned().collect();
+ match line.parse::<i16>() {
+ Ok(x) => x,
+ Err(_) => panic!("Invalid number"),
+ }
+}
+
+
+static ECC_LEVELS: [QrCodeEcc; 4] = [
+ QrCodeEcc::Low,
+ QrCodeEcc::Medium,
+ QrCodeEcc::Quartile,
+ QrCodeEcc::High,
+];
diff --git a/src/third_party/QR-Code-generator/rust/src/lib.rs b/src/third_party/QR-Code-generator/rust/src/lib.rs
new file mode 100644
index 0000000..d4b41ae
--- /dev/null
+++ b/src/third_party/QR-Code-generator/rust/src/lib.rs
@@ -0,0 +1,1117 @@
+/*
+ * QR Code generator library (Rust)
+ *
+ * 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.
+ */
+
+
+/*---- QrCode functionality ----*/
+
+// Represents an immutable square grid of black and white cells for a QR Code symbol, and
+// provides static functions to create a QR Code from user-supplied textual or binary data.
+// This struct covers the QR Code model 2 specification, supporting all versions (sizes)
+// from 1 to 40, all 4 error correction levels, and only 3 character encoding modes.
+pub struct QrCode {
+
+ // This QR Code symbol's version number, which is always between 1 and 40 (inclusive).
+ version: Version,
+
+ // The width and height of this QR Code symbol, measured in modules.
+ // Always equal to version × 4 + 17, in the range 21 to 177.
+ size: i32,
+
+ // The error correction level used in this QR Code symbol.
+ errorcorrectionlevel: QrCodeEcc,
+
+ // The mask pattern used in this QR Code symbol, in the range 0 to 7 (i.e. unsigned 3-bit integer).
+ // Note that even if a constructor was called with automatic masking requested
+ // (mask = -1), the resulting object will still have a mask value between 0 and 7.
+ mask: Mask,
+
+ // The modules of this QR Code symbol (false = white, true = black)
+ modules: Vec<bool>,
+
+ // Indicates function modules that are not subjected to masking
+ isfunction: Vec<bool>,
+
+}
+
+
+impl QrCode {
+
+ /*---- Public static factory functions ----*/
+
+ // Returns a QR Code symbol representing the given Unicode text string at the given error correction level.
+ // As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer Unicode
+ // code points (not UTF-8 code units) if the low error correction level is used. The smallest possible
+ // QR Code version is automatically chosen for the output. The ECC level of the result may be higher than
+ // the ecl argument if it can be done without increasing the version. Returns a wrapped QrCode if successful,
+ // or None if the data is too long to fit in any version at the given ECC level.
+ pub fn encode_text(text: &str, ecl: QrCodeEcc) -> Option<QrCode> {
+ let chrs: Vec<char> = text.chars().collect();
+ let segs: Vec<QrSegment> = QrSegment::make_segments(&chrs);
+ QrCode::encode_segments(&segs, ecl)
+ }
+
+
+ // Returns a QR Code symbol representing the given binary data string at the given error correction level.
+ // This function always encodes using the binary segment mode, not any text mode. The maximum number of
+ // bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
+ // The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
+ // Returns a wrapped QrCode if successful, or None if the data is too long to fit in any version at the given ECC level.
+ pub fn encode_binary(data: &[u8], ecl: QrCodeEcc) -> Option<QrCode> {
+ let segs: Vec<QrSegment> = vec![QrSegment::make_bytes(data)];
+ QrCode::encode_segments(&segs, ecl)
+ }
+
+
+ // Returns a QR Code symbol representing the given data segments at the given error correction
+ // level or higher. The smallest possible QR Code version is automatically chosen for the output.
+ // This function allows the user to create a custom sequence of segments that switches
+ // between modes (such as alphanumeric and binary) to encode text more efficiently.
+ // This function is considered to be lower level than simply encoding text or binary data.
+ // Returns a wrapped QrCode if successful, or None if the data is too long to fit in any version at the given ECC level.
+ pub fn encode_segments(segs: &[QrSegment], ecl: QrCodeEcc) -> Option<QrCode> {
+ QrCode::encode_segments_advanced(segs, ecl, QrCode_MIN_VERSION, QrCode_MAX_VERSION, None, true)
+ }
+
+
+ // Returns a QR Code symbol representing the given data segments with the given encoding parameters.
+ // The smallest possible QR Code version within the given range is automatically chosen for the output.
+ // This function allows the user to create a custom sequence of segments that switches
+ // between modes (such as alphanumeric and binary) to encode text more efficiently.
+ // This function is considered to be lower level than simply encoding text or binary data.
+ // Returns a wrapped QrCode if successful, or None if the data is too long to fit
+ // in any version in the given range at the given ECC level.
+ pub fn encode_segments_advanced(segs: &[QrSegment], mut ecl: QrCodeEcc,
+ minversion: Version, maxversion: Version, mask: Option<Mask>, boostecl: bool) -> Option<QrCode> {
+ assert!(minversion.value() <= maxversion.value(), "Invalid value");
+
+ // Find the minimal version number to use
+ let mut version = minversion;
+ let datausedbits: usize;
+ loop {
+ // Number of data bits available
+ let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8;
+ if let Some(n) = QrSegment::get_total_bits(segs, version) {
+ if n <= datacapacitybits {
+ datausedbits = n;
+ break; // This version number is found to be suitable
+ }
+ }
+ if version.value() >= maxversion.value() { // All versions in the range could not fit the given data
+ return None;
+ }
+ 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] {
+ if boostecl && datausedbits <= QrCode::get_num_data_codewords(version, *newecl) * 8 {
+ ecl = *newecl;
+ }
+ }
+
+ // Create the data bit string by concatenating all segments
+ let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8;
+ let mut bb = BitBuffer(Vec::new());
+ for seg in segs {
+ bb.append_bits(seg.mode.mode_bits(), 4);
+ bb.append_bits(seg.numchars as u32, seg.mode.num_char_count_bits(version));
+ bb.0.extend_from_slice(&seg.data);
+ }
+
+ // Add terminator and pad up to a byte if applicable
+ let numzerobits = std::cmp::min(4, datacapacitybits - bb.0.len());
+ bb.append_bits(0, numzerobits as u8);
+ let numzerobits = bb.0.len().wrapping_neg() & 7;
+ bb.append_bits(0, numzerobits as u8);
+
+ // Pad with alternate bytes until data capacity is reached
+ let mut padbyte: u32 = 0xEC;
+ while bb.0.len() < datacapacitybits {
+ bb.append_bits(padbyte, 8);
+ padbyte ^= 0xEC ^ 0x11;
+ }
+ assert_eq!(bb.0.len() % 8, 0, "Assertion error");
+
+ let mut bytes = vec![0u8; bb.0.len() / 8];
+ for (i, bit) in bb.0.iter().enumerate() {
+ bytes[i >> 3] |= (*bit as u8) << (7 - (i & 7));
+ }
+
+ // Create the QR Code symbol
+ Some(QrCode::encode_codewords(version, ecl, &bytes, mask))
+ }
+
+
+ /*---- Constructors ----*/
+
+ // Creates a new QR Code symbol with the given version number, error correction level,
+ // binary data array, and mask number. This is a cumbersome low-level constructor that
+ // should not be invoked directly by the user. To go one level up, see the encode_segments() function.
+ pub fn encode_codewords(ver: Version, ecl: QrCodeEcc, datacodewords: &[u8], mask: Option<Mask>) -> QrCode {
+ // Initialize fields
+ let size: usize = (ver.value() as usize) * 4 + 17;
+ let mut result = QrCode {
+ version: ver,
+ size: size as i32,
+ mask: Mask::new(0), // Dummy value
+ errorcorrectionlevel: ecl,
+ modules: vec![false; size * size], // Entirely white grid
+ isfunction: vec![false; size * size],
+ };
+
+ // Draw function patterns, draw all codewords, do masking
+ result.draw_function_patterns();
+ let allcodewords: Vec<u8> = result.append_error_correction(datacodewords);
+ result.draw_codewords(&allcodewords);
+ result.handle_constructor_masking(mask);
+ result
+ }
+
+
+ // Returns this QR Code's version, in the range [1, 40].
+ pub fn version(&self) -> Version {
+ self.version
+ }
+
+
+ // Returns this QR Code's size, in the range [21, 177].
+ pub fn size(&self) -> i32 {
+ self.size
+ }
+
+
+ // Returns this QR Code's error correction level.
+ pub fn error_correction_level(&self) -> QrCodeEcc {
+ self.errorcorrectionlevel
+ }
+
+
+ // Returns this QR Code's mask, in the range [0, 7].
+ pub fn mask(&self) -> Mask {
+ self.mask
+ }
+
+
+ // Returns the color of the module (pixel) at the given coordinates, which is either
+ // false for white or true for black. The top left corner has the coordinates (x=0, y=0).
+ // If the given coordinates are out of bounds, then 0 (white) is returned.
+ pub fn get_module(&self, x: i32, y: i32) -> bool {
+ 0 <= x && x < self.size && 0 <= y && y < self.size && self.module(x, y)
+ }
+
+
+ // Returns the color of the module at the given coordinates, which must be in bounds.
+ fn module(&self, x: i32, y: i32) -> bool {
+ self.modules[(y * self.size + x) as usize]
+ }
+
+
+ // Returns a mutable reference to the module's color at the given coordinates, which must be in bounds.
+ fn module_mut(&mut self, x: i32, y: i32) -> &mut bool {
+ &mut self.modules[(y * self.size + x) as usize]
+ }
+
+
+ // Based on the given number of border modules to add as padding, this returns a
+ // string whose contents represents an SVG XML file that depicts this QR Code symbol.
+ // Note that Unix newlines (\n) are always used, regardless of the platform.
+ pub fn to_svg_string(&self, border: i32) -> String {
+ assert!(border >= 0, "Border must be non-negative");
+ let mut result: String = String::new();
+ result.push_str("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ result.push_str("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+ let dimension = self.size.checked_add(border.checked_mul(2).unwrap()).unwrap();
+ result.push_str(&format!(
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 {0} {0}\" stroke=\"none\">\n", dimension));
+ result.push_str("\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n");
+ result.push_str("\t<path d=\"");
+ let mut head: bool = true;
+ for y in -border .. self.size + border {
+ for x in -border .. self.size + border {
+ if self.get_module(x, y) {
+ if head {
+ head = false;
+ } else {
+ result.push_str(" ");
+ }
+ result.push_str(&format!("M{},{}h1v1h-1z", x + border, y + border));
+ }
+ }
+ }
+ result.push_str("\" fill=\"#000000\"/>\n");
+ result.push_str("</svg>\n");
+ result
+ }
+
+
+ /*---- Private helper methods for constructor: Drawing function modules ----*/
+
+ fn draw_function_patterns(&mut self) {
+ // Draw horizontal and vertical timing patterns
+ let size: i32 = self.size;
+ for i in 0 .. size {
+ self.set_function_module(6, i, i % 2 == 0);
+ self.set_function_module(i, 6, i % 2 == 0);
+ }
+
+ // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
+ self.draw_finder_pattern(3, 3);
+ self.draw_finder_pattern(size - 4, 3);
+ self.draw_finder_pattern(3, size - 4);
+
+ // Draw numerous alignment patterns
+ let alignpatpos: Vec<i32> = QrCode::get_alignment_pattern_positions(self.version);
+ let numalign: usize = alignpatpos.len();
+ for i in 0 .. numalign {
+ for j in 0 .. numalign {
+ if i == 0 && j == 0 || i == 0 && j == numalign - 1 || i == numalign - 1 && j == 0 {
+ continue; // Skip the three finder corners
+ } else {
+ self.draw_alignment_pattern(alignpatpos[i], alignpatpos[j]);
+ }
+ }
+ }
+
+ // Draw configuration data
+ self.draw_format_bits(Mask::new(0)); // Dummy mask value; overwritten later in the constructor
+ self.draw_version();
+ }
+
+
+ // Draws two copies of the format bits (with its own error correction code)
+ // based on the given mask and this object's error correction level field.
+ fn draw_format_bits(&mut self, mask: Mask) {
+ // Calculate error correction code and pack bits
+ let size: i32 = self.size;
+ // errcorrlvl is uint2, mask is uint3
+ let mut data: u32 = self.errorcorrectionlevel.format_bits() << 3 | (mask.value() as u32);
+ let mut rem: u32 = data;
+ for _ in 0 .. 10 {
+ rem = (rem << 1) ^ ((rem >> 9) * 0x537);
+ }
+ data = data << 10 | rem;
+ data ^= 0x5412; // uint15
+ assert_eq!(data >> 15, 0, "Assertion error");
+
+ // Draw first copy
+ for i in 0 .. 6 {
+ self.set_function_module(8, i, (data >> i) & 1 != 0);
+ }
+ self.set_function_module(8, 7, (data >> 6) & 1 != 0);
+ self.set_function_module(8, 8, (data >> 7) & 1 != 0);
+ self.set_function_module(7, 8, (data >> 8) & 1 != 0);
+ for i in 9 .. 15 {
+ self.set_function_module(14 - i, 8, (data >> i) & 1 != 0);
+ }
+
+ // Draw second copy
+ for i in 0 .. 8 {
+ self.set_function_module(size - 1 - i, 8, (data >> i) & 1 != 0);
+ }
+ for i in 8 .. 15 {
+ self.set_function_module(8, size - 15 + i, (data >> i) & 1 != 0);
+ }
+ self.set_function_module(8, size - 8, true);
+ }
+
+
+ // Draws two copies of the version bits (with its own error correction code),
+ // based on this object's version field (which only has an effect for 7 <= version <= 40).
+ fn draw_version(&mut self) {
+ if self.version.value() < 7 {
+ return;
+ }
+
+ // Calculate error correction code and pack bits
+ let mut rem: u32 = self.version.value() as u32; // version is uint6, in the range [7, 40]
+ for _ in 0 .. 12 {
+ rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
+ }
+ let data: u32 = (self.version.value() as u32) << 12 | rem; // uint18
+ assert!(data >> 18 == 0, "Assertion error");
+
+ // Draw two copies
+ for i in 0 .. 18 {
+ let bit: bool = (data >> i) & 1 != 0;
+ let a: i32 = self.size - 11 + i % 3;
+ let b: i32 = i / 3;
+ self.set_function_module(a, b, bit);
+ self.set_function_module(b, a, bit);
+ }
+ }
+
+
+ // Draws a 9*9 finder pattern including the border separator, with the center module at (x, y).
+ fn draw_finder_pattern(&mut self, x: i32, y: i32) {
+ for i in -4 .. 5 {
+ for j in -4 .. 5 {
+ let xx: i32 = x + j;
+ let yy: i32 = y + i;
+ if 0 <= xx && xx < self.size && 0 <= yy && yy < self.size {
+ let dist: i32 = std::cmp::max(i.abs(), j.abs()); // Chebyshev/infinity norm
+ self.set_function_module(xx, yy, dist != 2 && dist != 4);
+ }
+ }
+ }
+ }
+
+
+ // Draws a 5*5 alignment pattern, with the center module at (x, y).
+ fn draw_alignment_pattern(&mut self, x: i32, y: i32) {
+ for i in -2 .. 3 {
+ for j in -2 .. 3 {
+ self.set_function_module(x + j, y + i, std::cmp::max(i.abs(), j.abs()) != 1);
+ }
+ }
+ }
+
+
+ // Sets the color of a module and marks it as a function module.
+ // Only used by the constructor. Coordinates must be in range.
+ fn set_function_module(&mut self, x: i32, y: i32, isblack: bool) {
+ *self.module_mut(x, y) = isblack;
+ self.isfunction[(y * self.size + x) as usize] = true;
+ }
+
+
+ /*---- Private helper methods for constructor: Codewords and masking ----*/
+
+ // Returns a new byte string representing the given data with the appropriate error correction
+ // codewords appended to it, based on this object's version and error correction level.
+ fn append_error_correction(&self, data: &[u8]) -> Vec<u8> {
+ assert_eq!(data.len(), QrCode::get_num_data_codewords(self.version, self.errorcorrectionlevel), "Illegal argument");
+
+ // Calculate parameter numbers
+ let numblocks: usize = QrCode::table_get(&NUM_ERROR_CORRECTION_BLOCKS, self.version, self.errorcorrectionlevel);
+ let blockecclen: usize = QrCode::table_get(&ECC_CODEWORDS_PER_BLOCK, self.version, self.errorcorrectionlevel);
+ let rawcodewords: usize = QrCode::get_num_raw_data_modules(self.version) / 8;
+ let numshortblocks: usize = numblocks - rawcodewords % numblocks;
+ let shortblocklen: usize = rawcodewords / numblocks;
+
+ // Split data into blocks and append ECC to each block
+ let mut blocks = Vec::<Vec<u8>>::with_capacity(numblocks);
+ let rs = ReedSolomonGenerator::new(blockecclen);
+ let mut k: usize = 0;
+ for i in 0 .. numblocks {
+ let mut dat = Vec::<u8>::with_capacity(shortblocklen + 1);
+ dat.extend_from_slice(&data[k .. k + shortblocklen - blockecclen + ((i >= numshortblocks) as usize)]);
+ k += dat.len();
+ let ecc: Vec<u8> = rs.get_remainder(&dat);
+ if i < numshortblocks {
+ dat.push(0);
+ }
+ dat.extend_from_slice(&ecc);
+ blocks.push(dat);
+ }
+
+ // Interleave (not concatenate) the bytes from every block into a single sequence
+ let mut result = Vec::<u8>::with_capacity(rawcodewords);
+ for i in 0 .. shortblocklen + 1 {
+ for j in 0 .. numblocks {
+ // Skip the padding byte in short blocks
+ if i != shortblocklen - blockecclen || j >= numshortblocks {
+ result.push(blocks[j][i]);
+ }
+ }
+ }
+ result
+ }
+
+
+ // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
+ // data area of this QR Code symbol. Function modules need to be marked off before this is called.
+ fn draw_codewords(&mut self, data: &[u8]) {
+ assert_eq!(data.len(), QrCode::get_num_raw_data_modules(self.version) / 8, "Illegal argument");
+
+ let mut i: usize = 0; // Bit index into the data
+ // Do the funny zigzag scan
+ let mut right: i32 = self.size - 1;
+ while right >= 1 { // Index of right column in each column pair
+ if right == 6 {
+ right = 5;
+ }
+ for vert in 0 .. self.size { // Vertical counter
+ for j in 0 .. 2 {
+ let x: i32 = right - j; // Actual x coordinate
+ let upward: bool = (right + 1) & 2 == 0;
+ let y: i32 = if upward { self.size - 1 - vert } else { vert }; // Actual y coordinate
+ if !self.isfunction[(y * self.size + x) as usize] && i < data.len() * 8 {
+ *self.module_mut(x, y) = (data[i >> 3] >> (7 - (i & 7))) & 1 != 0;
+ i += 1;
+ }
+ // If there are any remainder bits (0 to 7), they are already
+ // set to 0/false/white when the grid of modules was initialized
+ }
+ }
+ right -= 2;
+ }
+ assert_eq!(i, data.len() * 8, "Assertion error");
+ }
+
+
+ // XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical
+ // properties, calling applyMask(m) twice with the same value is equivalent to no change at all.
+ // This means it is possible to apply a mask, undo it, and try another mask. Note that a final
+ // well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.).
+ fn apply_mask(&mut self, mask: Mask) {
+ let mask = mask.value();
+ for y in 0 .. self.size {
+ for x in 0 .. self.size {
+ let invert: bool = match mask {
+ 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.module_mut(x, y) ^= invert & !self.isfunction[(y * self.size + x) as usize];
+ }
+ }
+ }
+
+
+ // A messy helper function for the constructors. This QR Code must be in an unmasked state when this
+ // method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
+ // This method applies and returns the actual mask chosen, from 0 to 7.
+ fn handle_constructor_masking(&mut self, mut mask: Option<Mask>) {
+ if mask.is_none() { // Automatically choose best mask
+ let mut minpenalty: i32 = std::i32::MAX;
+ for i in 0u8 .. 8 {
+ let newmask = Mask::new(i);
+ self.draw_format_bits(newmask);
+ self.apply_mask(newmask);
+ let penalty: i32 = self.get_penalty_score();
+ if penalty < minpenalty {
+ mask = Some(newmask);
+ minpenalty = penalty;
+ }
+ self.apply_mask(newmask); // Undoes the mask due to XOR
+ }
+ }
+ let msk: Mask = mask.unwrap();
+ self.draw_format_bits(msk); // Overwrite old format bits
+ self.apply_mask(msk); // Apply the final choice of mask
+ self.mask = msk;
+ }
+
+
+ // 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: i32 = self.size;
+
+ // Adjacent modules in row having same color
+ for y in 0 .. size {
+ let mut colorx: bool = false;
+ let mut runx: i32 = 0;
+ for x in 0 .. size {
+ if x == 0 || self.module(x, y) != colorx {
+ colorx = self.module(x, y);
+ runx = 1;
+ } else {
+ runx += 1;
+ if runx == 5 {
+ result += PENALTY_N1;
+ } else if runx > 5 {
+ result += 1;
+ }
+ }
+ }
+ }
+ // Adjacent modules in column having same color
+ for x in 0 .. size {
+ let mut colory: bool = false;
+ let mut runy: i32 = 0;
+ for y in 0 .. size {
+ if y == 0 || self.module(x, y) != colory {
+ colory = self.module(x, y);
+ runy = 1;
+ } else {
+ runy += 1;
+ if runy == 5 {
+ result += PENALTY_N1;
+ } else if runy > 5 {
+ result += 1;
+ }
+ }
+ }
+ }
+
+ // 2*2 blocks of modules having same color
+ for y in 0 .. size - 1 {
+ for x in 0 .. size - 1 {
+ let color: bool = self.module(x, y);
+ if color == self.module(x + 1, y) &&
+ color == self.module(x, y + 1) &&
+ color == self.module(x + 1, y + 1) {
+ result += PENALTY_N2;
+ }
+ }
+ }
+
+ // Finder-like pattern in rows
+ for y in 0 .. size {
+ let mut bits: u32 = 0;
+ for x in 0 .. size {
+ bits = ((bits << 1) & 0x7FF) | (self.module(x, y) as u32);
+ if x >= 10 && (bits == 0x05D || bits == 0x5D0) { // Needs 11 bits accumulated
+ result += PENALTY_N3;
+ }
+ }
+ }
+ // Finder-like pattern in columns
+ for x in 0 .. size {
+ let mut bits: u32 = 0;
+ for y in 0 .. size {
+ bits = ((bits << 1) & 0x7FF) | (self.module(x, y) as u32);
+ if y >= 10 && (bits == 0x05D || bits == 0x5D0) { // Needs 11 bits accumulated
+ result += PENALTY_N3;
+ }
+ }
+ }
+
+ // Balance of black and white modules
+ let mut black: i32 = 0;
+ for color in &self.modules {
+ black += *color as i32;
+ }
+ let total: i32 = size * size;
+ // Find smallest k such that (45-5k)% <= dark/total <= (55+5k)%
+ let mut k: i32 = 0;
+ while black*20 < (9-k)*total || black*20 > (11+k)*total {
+ result += PENALTY_N4;
+ k += 1;
+ }
+ result
+ }
+
+
+ /*---- Private static helper functions ----*/
+
+ // Returns a set of positions of the alignment patterns in ascending order. These positions are
+ // used on both the x and y axes. Each value in the resulting list is in the range [0, 177).
+ // This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes.
+ fn get_alignment_pattern_positions(ver: Version) -> Vec<i32> {
+ let ver = ver.value();
+ if ver == 1 {
+ vec![]
+ } else {
+ let numalign: i32 = (ver as i32) / 7 + 2;
+ let step: i32 = if ver != 32 {
+ // ceil((size - 13) / (2*numAlign - 2)) * 2
+ ((ver as i32) * 4 + numalign * 2 + 1) / (2 * numalign - 2) * 2
+ } else { // C-C-C-Combo breaker!
+ 26
+ };
+ let mut result = vec![6i32];
+ let mut pos: i32 = (ver as i32) * 4 + 10;
+ for _ in 0 .. numalign - 1 {
+ result.insert(1, pos);
+ pos -= step;
+ }
+ 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 = ver.value();
+ let mut result: usize = (16 * (ver as usize) + 128) * (ver as usize) + 64;
+ if ver >= 2 {
+ let numalign: usize = (ver as usize) / 7 + 2;
+ result -= (25 * numalign - 10) * numalign - 55;
+ if ver >= 7 {
+ result -= 18 * 2; // Subtract version information
+ }
+ }
+ 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()][ver.value() as usize] as usize
+ }
+
+}
+
+
+/*---- Public constants ----*/
+
+pub const QrCode_MIN_VERSION: Version = Version( 1);
+pub const QrCode_MAX_VERSION: Version = Version(40);
+
+
+/*---- Private tables of constants ----*/
+
+// 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 ----*/
+
+// Represents the error correction level used in a QR Code symbol. Immutable.
+#[derive(Clone, Copy)]
+pub enum QrCodeEcc {
+ Low,
+ Medium,
+ Quartile,
+ High,
+}
+
+
+impl QrCodeEcc {
+
+ // Returns an unsigned 2-bit integer (in the range 0 to 3).
+ fn ordinal(&self) -> usize {
+ match *self {
+ QrCodeEcc::Low => 0,
+ QrCodeEcc::Medium => 1,
+ QrCodeEcc::Quartile => 2,
+ QrCodeEcc::High => 3,
+ }
+ }
+
+
+ // Returns an unsigned 2-bit integer (in the range 0 to 3).
+ fn format_bits(&self) -> u32 {
+ match *self {
+ QrCodeEcc::Low => 1,
+ QrCodeEcc::Medium => 0,
+ QrCodeEcc::Quartile => 3,
+ QrCodeEcc::High => 2,
+ }
+ }
+
+}
+
+
+
+/*---- ReedSolomonGenerator functionality ----*/
+
+// Computes the Reed-Solomon error correction codewords for a sequence of data codewords
+// at a given degree. Objects are immutable, and the state only depends on the degree.
+// This class exists because each data block in a QR Code shares the same the divisor polynomial.
+struct ReedSolomonGenerator {
+
+ // Coefficients of the divisor polynomial, 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}.
+ coefficients: Vec<u8>,
+
+}
+
+
+impl ReedSolomonGenerator {
+
+ // Creates a Reed-Solomon ECC generator 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) -> ReedSolomonGenerator {
+ assert!(1 <= degree && degree <= 255, "Degree out of range");
+ // Start with the monomial x^0
+ let mut coefs = vec![0u8; degree - 1];
+ coefs.push(1);
+
+ // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
+ // drop the highest term, and store the rest of the coefficients in order of descending powers.
+ // 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 {
+ coefs[j] = ReedSolomonGenerator::multiply(coefs[j], root);
+ if j + 1 < coefs.len() {
+ coefs[j] ^= coefs[j + 1];
+ }
+ }
+ root = ReedSolomonGenerator::multiply(root, 0x02);
+ }
+ ReedSolomonGenerator {
+ coefficients: coefs
+ }
+ }
+
+
+ // Computes and returns the Reed-Solomon error correction codewords for the given sequence of data codewords.
+ fn get_remainder(&self, data: &[u8]) -> Vec<u8> {
+ // Compute the remainder by performing polynomial division
+ let mut result = vec![0u8; self.coefficients.len()];
+ for b in data {
+ let factor: u8 = b ^ result.remove(0);
+ result.push(0);
+ for (x, y) in result.iter_mut().zip(self.coefficients.iter()) {
+ *x ^= ReedSolomonGenerator::multiply(*y, factor);
+ }
+ }
+ result
+ }
+
+
+ // Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
+ // are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
+ 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
+ }
+
+}
+
+
+
+/*---- QrSegment functionality ----*/
+
+// Represents a character string to be encoded in a QR Code symbol.
+// Each segment has a mode, and a sequence of characters that is already
+// encoded as a sequence of bits. Instances of this struct are immutable.
+pub struct QrSegment {
+
+ // The mode indicator for this segment.
+ mode: QrSegmentMode,
+
+ // The length of this segment's unencoded data, measured in characters.
+ numchars: usize,
+
+ // The bits of this segment.
+ data: Vec<bool>,
+
+}
+
+
+impl QrSegment {
+
+ /*---- Static factory functions ----*/
+
+ // Returns a segment representing the given binary data encoded in byte mode.
+ pub fn make_bytes(data: &[u8]) -> QrSegment {
+ let mut bb = BitBuffer(Vec::with_capacity(data.len() * 8));
+ for b in data {
+ bb.append_bits(*b as u32, 8);
+ }
+ QrSegment::new(QrSegmentMode::Byte, data.len(), bb.0)
+ }
+
+
+ // 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: &[char]) -> QrSegment {
+ let mut bb = BitBuffer(Vec::with_capacity(text.len() * 3 + (text.len() + 2) / 3));
+ let mut accumdata: u32 = 0;
+ let mut accumcount: u32 = 0;
+ for c in text {
+ assert!('0' <= *c && *c <= '9', "String contains non-numeric characters");
+ accumdata = accumdata * 10 + ((*c as u32) - ('0' as u32));
+ 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 as u8) * 3 + 1);
+ }
+ QrSegment::new(QrSegmentMode::Numeric, text.len(), bb.0)
+ }
+
+
+ // 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: &[char]) -> QrSegment {
+ let mut bb = BitBuffer(Vec::with_capacity(text.len() * 5 + (text.len() + 1) / 2));
+ let mut accumdata: u32 = 0;
+ let mut accumcount: u32 = 0;
+ for c in text {
+ let i = match ALPHANUMERIC_CHARSET.iter().position(|x| *x == *c) {
+ None => panic!("String contains unencodable characters in alphanumeric mode"),
+ Some(j) => j,
+ };
+ accumdata = accumdata * 45 + (i as u32);
+ 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.0)
+ }
+
+
+ // Returns a new mutable list of zero or more segments to represent the given Unicode text string.
+ // The result may use various segment modes and switch modes to optimize the length of the bit stream.
+ pub fn make_segments(text: &[char]) -> Vec<QrSegment> {
+ if text.is_empty() {
+ vec![]
+ } else if QrSegment::is_numeric(text) {
+ vec![QrSegment::make_numeric(text)]
+ } else if QrSegment::is_alphanumeric(text) {
+ vec![QrSegment::make_alphanumeric(text)]
+ } else {
+ let s: String = text.iter().cloned().collect();
+ vec![QrSegment::make_bytes(s.as_bytes())]
+ }
+ }
+
+
+ // Returns a segment representing an Extended Channel Interpretation
+ // (ECI) designator with the given assignment value.
+ pub fn make_eci(assignval: u32) -> QrSegment {
+ let mut bb = BitBuffer(Vec::with_capacity(24));
+ if assignval < (1 << 7) {
+ bb.append_bits(assignval, 8);
+ } else if assignval < (1 << 14) {
+ bb.append_bits(2, 2);
+ bb.append_bits(assignval, 14);
+ } else if assignval < 1_000_000 {
+ bb.append_bits(6, 3);
+ bb.append_bits(assignval, 21);
+ } else {
+ panic!("ECI assignment value out of range");
+ }
+ QrSegment::new(QrSegmentMode::Eci, 0, bb.0)
+ }
+
+
+ // Creates a new QR Code data segment with the given parameters and data.
+ pub fn new(mode: QrSegmentMode, numchars: usize, data: Vec<bool>) -> QrSegment {
+ QrSegment {
+ mode: mode,
+ numchars: numchars,
+ data: data,
+ }
+ }
+
+
+ /*---- Instance field getters ----*/
+
+ // Returns the mode indicator for this segment.
+ pub fn mode(&self) -> QrSegmentMode {
+ self.mode
+ }
+
+
+ // Returns the length of this segment's unencoded data, measured in characters.
+ pub fn num_chars(&self) -> usize {
+ self.numchars
+ }
+
+
+ // Returns a view of the bits of this segment.
+ pub fn data(&self) -> &Vec<bool> {
+ &self.data
+ }
+
+
+ /*---- Other static functions ----*/
+
+ // Package-private helper function.
+ fn get_total_bits(segs: &[QrSegment], version: Version) -> Option<usize> {
+ let mut result: usize = 0;
+ for seg in segs {
+ let ccbits = seg.mode.num_char_count_bits(version);
+ if seg.numchars >= 1 << ccbits {
+ return None;
+ }
+ match result.checked_add(4 + (ccbits as usize) + seg.data.len()) {
+ None => return None,
+ Some(val) => result = val,
+ }
+ }
+ Some(result)
+ }
+
+
+ // Tests whether the given string can be encoded as a segment in alphanumeric mode.
+ fn is_alphanumeric(text: &[char]) -> bool {
+ text.iter().all(|c| ALPHANUMERIC_CHARSET.contains(c))
+ }
+
+
+ // Tests whether the given string can be encoded as a segment in numeric mode.
+ fn is_numeric(text: &[char]) -> bool {
+ text.iter().all(|c| '0' <= *c && *c <= '9')
+ }
+
+}
+
+
+// The set of all legal characters in alphanumeric mode,
+// where each character value maps to the index in the string.
+static ALPHANUMERIC_CHARSET: [char; 45] = ['0','1','2','3','4','5','6','7','8','9',
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
+ ' ','$','%','*','+','-','.','/',':'];
+
+
+
+/*---- QrSegmentMode functionality ----*/
+
+// The mode field of a segment. Immutable.
+#[derive(Clone, Copy)]
+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 {
+ match *self {
+ QrSegmentMode::Numeric => 0x1,
+ QrSegmentMode::Alphanumeric => 0x2,
+ QrSegmentMode::Byte => 0x4,
+ QrSegmentMode::Kanji => 0x8,
+ QrSegmentMode::Eci => 0x7,
+ }
+ }
+
+
+ // Returns the bit width of the segment character count field
+ // for this mode object at the given version number.
+ pub fn num_char_count_bits(&self, ver: Version) -> u8 {
+ let array: [u8; 3] = match *self {
+ QrSegmentMode::Numeric => [10, 12, 14],
+ QrSegmentMode::Alphanumeric => [ 9, 11, 13],
+ QrSegmentMode::Byte => [ 8, 16, 16],
+ QrSegmentMode::Kanji => [ 8, 10, 12],
+ QrSegmentMode::Eci => [ 0, 0, 0],
+ };
+
+ let ver = ver.value();
+ if 1 <= ver && ver <= 9 {
+ array[0]
+ } else if 10 <= ver && ver <= 26 {
+ array[1]
+ } else if 27 <= ver && ver <= 40 {
+ array[2]
+ } else {
+ panic!("Version number out of range");
+ }
+ }
+
+}
+
+
+
+/*---- Bit buffer functionality ----*/
+
+pub struct BitBuffer(pub Vec<bool>);
+
+
+impl BitBuffer {
+ // Appends the given number of low bits of the given value
+ // to this sequence. Requires 0 <= val < 2^len.
+ pub fn append_bits(&mut self, val: u32, len: u8) {
+ assert!(len < 32 && (val >> len) == 0 || len == 32, "Value out of range");
+ for i in (0 .. len).rev() { // Append bit by bit
+ self.0.push((val >> i) & 1 != 0);
+ }
+ }
+}
+
+
+
+/*---- Miscellaneous values ----*/
+
+#[derive(Copy, Clone)]
+pub struct Version(u8);
+
+impl Version {
+ pub fn new(ver: u8) -> Self {
+ assert!(QrCode_MIN_VERSION.value() <= ver && ver <= QrCode_MAX_VERSION.value(), "Version number out of range");
+ Version(ver)
+ }
+
+ pub fn value(&self) -> u8 {
+ self.0
+ }
+}
+
+
+#[derive(Copy, Clone)]
+pub struct Mask(u8);
+
+impl Mask {
+ pub fn new(mask: u8) -> Self {
+ assert!(mask <= 7, "Mask value out of range");
+ Mask(mask)
+ }
+
+ pub fn value(&self) -> u8 {
+ self.0
+ }
+}