15317bbafSopenharmony_ci/*
25317bbafSopenharmony_ci * QR Code generator library (C++)
35317bbafSopenharmony_ci *
45317bbafSopenharmony_ci * Copyright (c) Project Nayuki. (MIT License)
55317bbafSopenharmony_ci * https://www.nayuki.io/page/qr-code-generator-library
65317bbafSopenharmony_ci *
75317bbafSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy of
85317bbafSopenharmony_ci * this software and associated documentation files (the "Software"), to deal in
95317bbafSopenharmony_ci * the Software without restriction, including without limitation the rights to
105317bbafSopenharmony_ci * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
115317bbafSopenharmony_ci * the Software, and to permit persons to whom the Software is furnished to do so,
125317bbafSopenharmony_ci * subject to the following conditions:
135317bbafSopenharmony_ci * - The above copyright notice and this permission notice shall be included in
145317bbafSopenharmony_ci *   all copies or substantial portions of the Software.
155317bbafSopenharmony_ci * - The Software is provided "as is", without warranty of any kind, express or
165317bbafSopenharmony_ci *   implied, including but not limited to the warranties of merchantability,
175317bbafSopenharmony_ci *   fitness for a particular purpose and noninfringement. In no event shall the
185317bbafSopenharmony_ci *   authors or copyright holders be liable for any claim, damages or other
195317bbafSopenharmony_ci *   liability, whether in an action of contract, tort or otherwise, arising from,
205317bbafSopenharmony_ci *   out of or in connection with the Software or the use or other dealings in the
215317bbafSopenharmony_ci *   Software.
225317bbafSopenharmony_ci */
235317bbafSopenharmony_ci
245317bbafSopenharmony_ci#include <algorithm>
255317bbafSopenharmony_ci#include <cassert>
265317bbafSopenharmony_ci#include <climits>
275317bbafSopenharmony_ci#include <cstddef>
285317bbafSopenharmony_ci#include <cstdlib>
295317bbafSopenharmony_ci#include <cstring>
305317bbafSopenharmony_ci#include <sstream>
315317bbafSopenharmony_ci#include <utility>
325317bbafSopenharmony_ci#include "qrcodegen.hpp"
335317bbafSopenharmony_ci
345317bbafSopenharmony_ciusing std::int8_t;
355317bbafSopenharmony_ciusing std::uint8_t;
365317bbafSopenharmony_ciusing std::size_t;
375317bbafSopenharmony_ciusing std::vector;
385317bbafSopenharmony_ci
395317bbafSopenharmony_ci
405317bbafSopenharmony_cinamespace qrcodegen {
415317bbafSopenharmony_ci
425317bbafSopenharmony_ci/*---- Class QrSegment ----*/
435317bbafSopenharmony_ci
445317bbafSopenharmony_ciQrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) :
455317bbafSopenharmony_ci		modeBits(mode) {
465317bbafSopenharmony_ci	numBitsCharCount[0] = cc0;
475317bbafSopenharmony_ci	numBitsCharCount[1] = cc1;
485317bbafSopenharmony_ci	numBitsCharCount[2] = cc2;
495317bbafSopenharmony_ci}
505317bbafSopenharmony_ci
515317bbafSopenharmony_ci
525317bbafSopenharmony_ciint QrSegment::Mode::getModeBits() const {
535317bbafSopenharmony_ci	return modeBits;
545317bbafSopenharmony_ci}
555317bbafSopenharmony_ci
565317bbafSopenharmony_ci
575317bbafSopenharmony_ciint QrSegment::Mode::numCharCountBits(int ver) const {
585317bbafSopenharmony_ci	return numBitsCharCount[(ver + 7) / 17];
595317bbafSopenharmony_ci}
605317bbafSopenharmony_ci
615317bbafSopenharmony_ci
625317bbafSopenharmony_ciconst QrSegment::Mode QrSegment::Mode::NUMERIC     (0x1, 10, 12, 14);
635317bbafSopenharmony_ciconst QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2,  9, 11, 13);
645317bbafSopenharmony_ciconst QrSegment::Mode QrSegment::Mode::BYTE        (0x4,  8, 16, 16);
655317bbafSopenharmony_ciconst QrSegment::Mode QrSegment::Mode::KANJI       (0x8,  8, 10, 12);
665317bbafSopenharmony_ciconst QrSegment::Mode QrSegment::Mode::ECI         (0x7,  0,  0,  0);
675317bbafSopenharmony_ci
685317bbafSopenharmony_ci
695317bbafSopenharmony_ciQrSegment QrSegment::makeBytes(const vector<uint8_t> &data) {
705317bbafSopenharmony_ci	if (data.size() > static_cast<unsigned int>(INT_MAX))
715317bbafSopenharmony_ci		throw std::length_error("Data too long");
725317bbafSopenharmony_ci	BitBuffer bb;
735317bbafSopenharmony_ci	for (uint8_t b : data)
745317bbafSopenharmony_ci		bb.appendBits(b, 8);
755317bbafSopenharmony_ci	return QrSegment(Mode::BYTE, static_cast<int>(data.size()), std::move(bb));
765317bbafSopenharmony_ci}
775317bbafSopenharmony_ci
785317bbafSopenharmony_ci
795317bbafSopenharmony_ciQrSegment QrSegment::makeNumeric(const char *digits) {
805317bbafSopenharmony_ci	BitBuffer bb;
815317bbafSopenharmony_ci	int accumData = 0;
825317bbafSopenharmony_ci	int accumCount = 0;
835317bbafSopenharmony_ci	int charCount = 0;
845317bbafSopenharmony_ci	for (; *digits != '\0'; digits++, charCount++) {
855317bbafSopenharmony_ci		char c = *digits;
865317bbafSopenharmony_ci		if (c < '0' || c > '9')
875317bbafSopenharmony_ci			throw std::domain_error("String contains non-numeric characters");
885317bbafSopenharmony_ci		accumData = accumData * 10 + (c - '0');
895317bbafSopenharmony_ci		accumCount++;
905317bbafSopenharmony_ci		if (accumCount == 3) {
915317bbafSopenharmony_ci			bb.appendBits(static_cast<uint32_t>(accumData), 10);
925317bbafSopenharmony_ci			accumData = 0;
935317bbafSopenharmony_ci			accumCount = 0;
945317bbafSopenharmony_ci		}
955317bbafSopenharmony_ci	}
965317bbafSopenharmony_ci	if (accumCount > 0)  // 1 or 2 digits remaining
975317bbafSopenharmony_ci		bb.appendBits(static_cast<uint32_t>(accumData), accumCount * 3 + 1);
985317bbafSopenharmony_ci	return QrSegment(Mode::NUMERIC, charCount, std::move(bb));
995317bbafSopenharmony_ci}
1005317bbafSopenharmony_ci
1015317bbafSopenharmony_ci
1025317bbafSopenharmony_ciQrSegment QrSegment::makeAlphanumeric(const char *text) {
1035317bbafSopenharmony_ci	BitBuffer bb;
1045317bbafSopenharmony_ci	int accumData = 0;
1055317bbafSopenharmony_ci	int accumCount = 0;
1065317bbafSopenharmony_ci	int charCount = 0;
1075317bbafSopenharmony_ci	for (; *text != '\0'; text++, charCount++) {
1085317bbafSopenharmony_ci		const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text);
1095317bbafSopenharmony_ci		if (temp == nullptr)
1105317bbafSopenharmony_ci			throw std::domain_error("String contains unencodable characters in alphanumeric mode");
1115317bbafSopenharmony_ci		accumData = accumData * 45 + static_cast<int>(temp - ALPHANUMERIC_CHARSET);
1125317bbafSopenharmony_ci		accumCount++;
1135317bbafSopenharmony_ci		if (accumCount == 2) {
1145317bbafSopenharmony_ci			bb.appendBits(static_cast<uint32_t>(accumData), 11);
1155317bbafSopenharmony_ci			accumData = 0;
1165317bbafSopenharmony_ci			accumCount = 0;
1175317bbafSopenharmony_ci		}
1185317bbafSopenharmony_ci	}
1195317bbafSopenharmony_ci	if (accumCount > 0)  // 1 character remaining
1205317bbafSopenharmony_ci		bb.appendBits(static_cast<uint32_t>(accumData), 6);
1215317bbafSopenharmony_ci	return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb));
1225317bbafSopenharmony_ci}
1235317bbafSopenharmony_ci
1245317bbafSopenharmony_ci
1255317bbafSopenharmony_civector<QrSegment> QrSegment::makeSegments(const char *text) {
1265317bbafSopenharmony_ci	// Select the most efficient segment encoding automatically
1275317bbafSopenharmony_ci	vector<QrSegment> result;
1285317bbafSopenharmony_ci	if (*text == '\0');  // Leave result empty
1295317bbafSopenharmony_ci	else if (isNumeric(text))
1305317bbafSopenharmony_ci		result.push_back(makeNumeric(text));
1315317bbafSopenharmony_ci	else if (isAlphanumeric(text))
1325317bbafSopenharmony_ci		result.push_back(makeAlphanumeric(text));
1335317bbafSopenharmony_ci	else {
1345317bbafSopenharmony_ci		vector<uint8_t> bytes;
1355317bbafSopenharmony_ci		for (; *text != '\0'; text++)
1365317bbafSopenharmony_ci			bytes.push_back(static_cast<uint8_t>(*text));
1375317bbafSopenharmony_ci		result.push_back(makeBytes(bytes));
1385317bbafSopenharmony_ci	}
1395317bbafSopenharmony_ci	return result;
1405317bbafSopenharmony_ci}
1415317bbafSopenharmony_ci
1425317bbafSopenharmony_ci
1435317bbafSopenharmony_ciQrSegment QrSegment::makeEci(long assignVal) {
1445317bbafSopenharmony_ci	BitBuffer bb;
1455317bbafSopenharmony_ci	if (assignVal < 0)
1465317bbafSopenharmony_ci		throw std::domain_error("ECI assignment value out of range");
1475317bbafSopenharmony_ci	else if (assignVal < (1 << 7))
1485317bbafSopenharmony_ci		bb.appendBits(static_cast<uint32_t>(assignVal), 8);
1495317bbafSopenharmony_ci	else if (assignVal < (1 << 14)) {
1505317bbafSopenharmony_ci		bb.appendBits(2, 2);
1515317bbafSopenharmony_ci		bb.appendBits(static_cast<uint32_t>(assignVal), 14);
1525317bbafSopenharmony_ci	} else if (assignVal < 1000000L) {
1535317bbafSopenharmony_ci		bb.appendBits(6, 3);
1545317bbafSopenharmony_ci		bb.appendBits(static_cast<uint32_t>(assignVal), 21);
1555317bbafSopenharmony_ci	} else
1565317bbafSopenharmony_ci		throw std::domain_error("ECI assignment value out of range");
1575317bbafSopenharmony_ci	return QrSegment(Mode::ECI, 0, std::move(bb));
1585317bbafSopenharmony_ci}
1595317bbafSopenharmony_ci
1605317bbafSopenharmony_ci
1615317bbafSopenharmony_ciQrSegment::QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt) :
1625317bbafSopenharmony_ci		mode(&md),
1635317bbafSopenharmony_ci		numChars(numCh),
1645317bbafSopenharmony_ci		data(dt) {
1655317bbafSopenharmony_ci	if (numCh < 0)
1665317bbafSopenharmony_ci		throw std::domain_error("Invalid value");
1675317bbafSopenharmony_ci}
1685317bbafSopenharmony_ci
1695317bbafSopenharmony_ci
1705317bbafSopenharmony_ciQrSegment::QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt) :
1715317bbafSopenharmony_ci		mode(&md),
1725317bbafSopenharmony_ci		numChars(numCh),
1735317bbafSopenharmony_ci		data(std::move(dt)) {
1745317bbafSopenharmony_ci	if (numCh < 0)
1755317bbafSopenharmony_ci		throw std::domain_error("Invalid value");
1765317bbafSopenharmony_ci}
1775317bbafSopenharmony_ci
1785317bbafSopenharmony_ci
1795317bbafSopenharmony_ciint QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) {
1805317bbafSopenharmony_ci	int result = 0;
1815317bbafSopenharmony_ci	for (const QrSegment &seg : segs) {
1825317bbafSopenharmony_ci		int ccbits = seg.mode->numCharCountBits(version);
1835317bbafSopenharmony_ci		if (seg.numChars >= (1L << ccbits))
1845317bbafSopenharmony_ci			return -1;  // The segment's length doesn't fit the field's bit width
1855317bbafSopenharmony_ci		if (4 + ccbits > INT_MAX - result)
1865317bbafSopenharmony_ci			return -1;  // The sum will overflow an int type
1875317bbafSopenharmony_ci		result += 4 + ccbits;
1885317bbafSopenharmony_ci		if (seg.data.size() > static_cast<unsigned int>(INT_MAX - result))
1895317bbafSopenharmony_ci			return -1;  // The sum will overflow an int type
1905317bbafSopenharmony_ci		result += static_cast<int>(seg.data.size());
1915317bbafSopenharmony_ci	}
1925317bbafSopenharmony_ci	return result;
1935317bbafSopenharmony_ci}
1945317bbafSopenharmony_ci
1955317bbafSopenharmony_ci
1965317bbafSopenharmony_cibool QrSegment::isNumeric(const char *text) {
1975317bbafSopenharmony_ci	for (; *text != '\0'; text++) {
1985317bbafSopenharmony_ci		char c = *text;
1995317bbafSopenharmony_ci		if (c < '0' || c > '9')
2005317bbafSopenharmony_ci			return false;
2015317bbafSopenharmony_ci	}
2025317bbafSopenharmony_ci	return true;
2035317bbafSopenharmony_ci}
2045317bbafSopenharmony_ci
2055317bbafSopenharmony_ci
2065317bbafSopenharmony_cibool QrSegment::isAlphanumeric(const char *text) {
2075317bbafSopenharmony_ci	for (; *text != '\0'; text++) {
2085317bbafSopenharmony_ci		if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr)
2095317bbafSopenharmony_ci			return false;
2105317bbafSopenharmony_ci	}
2115317bbafSopenharmony_ci	return true;
2125317bbafSopenharmony_ci}
2135317bbafSopenharmony_ci
2145317bbafSopenharmony_ci
2155317bbafSopenharmony_ciconst QrSegment::Mode &QrSegment::getMode() const {
2165317bbafSopenharmony_ci	return *mode;
2175317bbafSopenharmony_ci}
2185317bbafSopenharmony_ci
2195317bbafSopenharmony_ci
2205317bbafSopenharmony_ciint QrSegment::getNumChars() const {
2215317bbafSopenharmony_ci	return numChars;
2225317bbafSopenharmony_ci}
2235317bbafSopenharmony_ci
2245317bbafSopenharmony_ci
2255317bbafSopenharmony_ciconst std::vector<bool> &QrSegment::getData() const {
2265317bbafSopenharmony_ci	return data;
2275317bbafSopenharmony_ci}
2285317bbafSopenharmony_ci
2295317bbafSopenharmony_ci
2305317bbafSopenharmony_ciconst char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
2315317bbafSopenharmony_ci
2325317bbafSopenharmony_ci
2335317bbafSopenharmony_ci
2345317bbafSopenharmony_ci/*---- Class QrCode ----*/
2355317bbafSopenharmony_ci
2365317bbafSopenharmony_ciint QrCode::getFormatBits(Ecc ecl) {
2375317bbafSopenharmony_ci	switch (ecl) {
2385317bbafSopenharmony_ci		case Ecc::LOW     :  return 1;
2395317bbafSopenharmony_ci		case Ecc::MEDIUM  :  return 0;
2405317bbafSopenharmony_ci		case Ecc::QUARTILE:  return 3;
2415317bbafSopenharmony_ci		case Ecc::HIGH    :  return 2;
2425317bbafSopenharmony_ci		default:  throw std::logic_error("Unreachable");
2435317bbafSopenharmony_ci	}
2445317bbafSopenharmony_ci}
2455317bbafSopenharmony_ci
2465317bbafSopenharmony_ci
2475317bbafSopenharmony_ciQrCode QrCode::encodeText(const char *text, Ecc ecl) {
2485317bbafSopenharmony_ci	vector<QrSegment> segs = QrSegment::makeSegments(text);
2495317bbafSopenharmony_ci	return encodeSegments(segs, ecl);
2505317bbafSopenharmony_ci}
2515317bbafSopenharmony_ci
2525317bbafSopenharmony_ci
2535317bbafSopenharmony_ciQrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) {
2545317bbafSopenharmony_ci	vector<QrSegment> segs{QrSegment::makeBytes(data)};
2555317bbafSopenharmony_ci	return encodeSegments(segs, ecl);
2565317bbafSopenharmony_ci}
2575317bbafSopenharmony_ci
2585317bbafSopenharmony_ci
2595317bbafSopenharmony_ciQrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
2605317bbafSopenharmony_ci		int minVersion, int maxVersion, int mask, bool boostEcl) {
2615317bbafSopenharmony_ci	if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
2625317bbafSopenharmony_ci		throw std::invalid_argument("Invalid value");
2635317bbafSopenharmony_ci
2645317bbafSopenharmony_ci	// Find the minimal version number to use
2655317bbafSopenharmony_ci	int version, dataUsedBits;
2665317bbafSopenharmony_ci	for (version = minVersion; ; version++) {
2675317bbafSopenharmony_ci		int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;  // Number of data bits available
2685317bbafSopenharmony_ci		dataUsedBits = QrSegment::getTotalBits(segs, version);
2695317bbafSopenharmony_ci		if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
2705317bbafSopenharmony_ci			break;  // This version number is found to be suitable
2715317bbafSopenharmony_ci		if (version >= maxVersion) {  // All versions in the range could not fit the given data
2725317bbafSopenharmony_ci			std::ostringstream sb;
2735317bbafSopenharmony_ci			if (dataUsedBits == -1)
2745317bbafSopenharmony_ci				sb << "Segment too long";
2755317bbafSopenharmony_ci			else {
2765317bbafSopenharmony_ci				sb << "Data length = " << dataUsedBits << " bits, ";
2775317bbafSopenharmony_ci				sb << "Max capacity = " << dataCapacityBits << " bits";
2785317bbafSopenharmony_ci			}
2795317bbafSopenharmony_ci			throw data_too_long(sb.str());
2805317bbafSopenharmony_ci		}
2815317bbafSopenharmony_ci	}
2825317bbafSopenharmony_ci	assert(dataUsedBits != -1);
2835317bbafSopenharmony_ci
2845317bbafSopenharmony_ci	// Increase the error correction level while the data still fits in the current version number
2855317bbafSopenharmony_ci	for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) {  // From low to high
2865317bbafSopenharmony_ci		if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
2875317bbafSopenharmony_ci			ecl = newEcl;
2885317bbafSopenharmony_ci	}
2895317bbafSopenharmony_ci
2905317bbafSopenharmony_ci	// Concatenate all segments to create the data bit string
2915317bbafSopenharmony_ci	BitBuffer bb;
2925317bbafSopenharmony_ci	for (const QrSegment &seg : segs) {
2935317bbafSopenharmony_ci		bb.appendBits(static_cast<uint32_t>(seg.getMode().getModeBits()), 4);
2945317bbafSopenharmony_ci		bb.appendBits(static_cast<uint32_t>(seg.getNumChars()), seg.getMode().numCharCountBits(version));
2955317bbafSopenharmony_ci		bb.insert(bb.end(), seg.getData().begin(), seg.getData().end());
2965317bbafSopenharmony_ci	}
2975317bbafSopenharmony_ci	assert(bb.size() == static_cast<unsigned int>(dataUsedBits));
2985317bbafSopenharmony_ci
2995317bbafSopenharmony_ci	// Add terminator and pad up to a byte if applicable
3005317bbafSopenharmony_ci	size_t dataCapacityBits = static_cast<size_t>(getNumDataCodewords(version, ecl)) * 8;
3015317bbafSopenharmony_ci	assert(bb.size() <= dataCapacityBits);
3025317bbafSopenharmony_ci	bb.appendBits(0, std::min(4, static_cast<int>(dataCapacityBits - bb.size())));
3035317bbafSopenharmony_ci	bb.appendBits(0, (8 - static_cast<int>(bb.size() % 8)) % 8);
3045317bbafSopenharmony_ci	assert(bb.size() % 8 == 0);
3055317bbafSopenharmony_ci
3065317bbafSopenharmony_ci	// Pad with alternating bytes until data capacity is reached
3075317bbafSopenharmony_ci	for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
3085317bbafSopenharmony_ci		bb.appendBits(padByte, 8);
3095317bbafSopenharmony_ci
3105317bbafSopenharmony_ci	// Pack bits into bytes in big endian
3115317bbafSopenharmony_ci	vector<uint8_t> dataCodewords(bb.size() / 8);
3125317bbafSopenharmony_ci	for (size_t i = 0; i < bb.size(); i++)
3135317bbafSopenharmony_ci		dataCodewords.at(i >> 3) |= (bb.at(i) ? 1 : 0) << (7 - (i & 7));
3145317bbafSopenharmony_ci
3155317bbafSopenharmony_ci	// Create the QR Code object
3165317bbafSopenharmony_ci	return QrCode(version, ecl, dataCodewords, mask);
3175317bbafSopenharmony_ci}
3185317bbafSopenharmony_ci
3195317bbafSopenharmony_ci
3205317bbafSopenharmony_ciQrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk) :
3215317bbafSopenharmony_ci		// Initialize fields and check arguments
3225317bbafSopenharmony_ci		version(ver),
3235317bbafSopenharmony_ci		errorCorrectionLevel(ecl) {
3245317bbafSopenharmony_ci	if (ver < MIN_VERSION || ver > MAX_VERSION)
3255317bbafSopenharmony_ci		throw std::domain_error("Version value out of range");
3265317bbafSopenharmony_ci	if (msk < -1 || msk > 7)
3275317bbafSopenharmony_ci		throw std::domain_error("Mask value out of range");
3285317bbafSopenharmony_ci	size = ver * 4 + 17;
3295317bbafSopenharmony_ci	size_t sz = static_cast<size_t>(size);
3305317bbafSopenharmony_ci	modules    = vector<vector<bool> >(sz, vector<bool>(sz));  // Initially all light
3315317bbafSopenharmony_ci	isFunction = vector<vector<bool> >(sz, vector<bool>(sz));
3325317bbafSopenharmony_ci
3335317bbafSopenharmony_ci	// Compute ECC, draw modules
3345317bbafSopenharmony_ci	drawFunctionPatterns();
3355317bbafSopenharmony_ci	const vector<uint8_t> allCodewords = addEccAndInterleave(dataCodewords);
3365317bbafSopenharmony_ci	drawCodewords(allCodewords);
3375317bbafSopenharmony_ci
3385317bbafSopenharmony_ci	// Do masking
3395317bbafSopenharmony_ci	if (msk == -1) {  // Automatically choose best mask
3405317bbafSopenharmony_ci		long minPenalty = LONG_MAX;
3415317bbafSopenharmony_ci		for (int i = 0; i < 8; i++) {
3425317bbafSopenharmony_ci			applyMask(i);
3435317bbafSopenharmony_ci			drawFormatBits(i);
3445317bbafSopenharmony_ci			long penalty = getPenaltyScore();
3455317bbafSopenharmony_ci			if (penalty < minPenalty) {
3465317bbafSopenharmony_ci				msk = i;
3475317bbafSopenharmony_ci				minPenalty = penalty;
3485317bbafSopenharmony_ci			}
3495317bbafSopenharmony_ci			applyMask(i);  // Undoes the mask due to XOR
3505317bbafSopenharmony_ci		}
3515317bbafSopenharmony_ci	}
3525317bbafSopenharmony_ci	assert(0 <= msk && msk <= 7);
3535317bbafSopenharmony_ci	mask = msk;
3545317bbafSopenharmony_ci	applyMask(msk);  // Apply the final choice of mask
3555317bbafSopenharmony_ci	drawFormatBits(msk);  // Overwrite old format bits
3565317bbafSopenharmony_ci
3575317bbafSopenharmony_ci	isFunction.clear();
3585317bbafSopenharmony_ci	isFunction.shrink_to_fit();
3595317bbafSopenharmony_ci}
3605317bbafSopenharmony_ci
3615317bbafSopenharmony_ci
3625317bbafSopenharmony_ciint QrCode::getVersion() const {
3635317bbafSopenharmony_ci	return version;
3645317bbafSopenharmony_ci}
3655317bbafSopenharmony_ci
3665317bbafSopenharmony_ci
3675317bbafSopenharmony_ciint QrCode::getSize() const {
3685317bbafSopenharmony_ci	return size;
3695317bbafSopenharmony_ci}
3705317bbafSopenharmony_ci
3715317bbafSopenharmony_ci
3725317bbafSopenharmony_ciQrCode::Ecc QrCode::getErrorCorrectionLevel() const {
3735317bbafSopenharmony_ci	return errorCorrectionLevel;
3745317bbafSopenharmony_ci}
3755317bbafSopenharmony_ci
3765317bbafSopenharmony_ci
3775317bbafSopenharmony_ciint QrCode::getMask() const {
3785317bbafSopenharmony_ci	return mask;
3795317bbafSopenharmony_ci}
3805317bbafSopenharmony_ci
3815317bbafSopenharmony_ci
3825317bbafSopenharmony_cibool QrCode::getModule(int x, int y) const {
3835317bbafSopenharmony_ci	return 0 <= x && x < size && 0 <= y && y < size && module(x, y);
3845317bbafSopenharmony_ci}
3855317bbafSopenharmony_ci
3865317bbafSopenharmony_ci
3875317bbafSopenharmony_civoid QrCode::drawFunctionPatterns() {
3885317bbafSopenharmony_ci	// Draw horizontal and vertical timing patterns
3895317bbafSopenharmony_ci	for (int i = 0; i < size; i++) {
3905317bbafSopenharmony_ci		setFunctionModule(6, i, i % 2 == 0);
3915317bbafSopenharmony_ci		setFunctionModule(i, 6, i % 2 == 0);
3925317bbafSopenharmony_ci	}
3935317bbafSopenharmony_ci
3945317bbafSopenharmony_ci	// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
3955317bbafSopenharmony_ci	drawFinderPattern(3, 3);
3965317bbafSopenharmony_ci	drawFinderPattern(size - 4, 3);
3975317bbafSopenharmony_ci	drawFinderPattern(3, size - 4);
3985317bbafSopenharmony_ci
3995317bbafSopenharmony_ci	// Draw numerous alignment patterns
4005317bbafSopenharmony_ci	const vector<int> alignPatPos = getAlignmentPatternPositions();
4015317bbafSopenharmony_ci	size_t numAlign = alignPatPos.size();
4025317bbafSopenharmony_ci	for (size_t i = 0; i < numAlign; i++) {
4035317bbafSopenharmony_ci		for (size_t j = 0; j < numAlign; j++) {
4045317bbafSopenharmony_ci			// Don't draw on the three finder corners
4055317bbafSopenharmony_ci			if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))
4065317bbafSopenharmony_ci				drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j));
4075317bbafSopenharmony_ci		}
4085317bbafSopenharmony_ci	}
4095317bbafSopenharmony_ci
4105317bbafSopenharmony_ci	// Draw configuration data
4115317bbafSopenharmony_ci	drawFormatBits(0);  // Dummy mask value; overwritten later in the constructor
4125317bbafSopenharmony_ci	drawVersion();
4135317bbafSopenharmony_ci}
4145317bbafSopenharmony_ci
4155317bbafSopenharmony_ci
4165317bbafSopenharmony_civoid QrCode::drawFormatBits(int msk) {
4175317bbafSopenharmony_ci	// Calculate error correction code and pack bits
4185317bbafSopenharmony_ci	int data = getFormatBits(errorCorrectionLevel) << 3 | msk;  // errCorrLvl is uint2, msk is uint3
4195317bbafSopenharmony_ci	int rem = data;
4205317bbafSopenharmony_ci	for (int i = 0; i < 10; i++)
4215317bbafSopenharmony_ci		rem = (rem << 1) ^ ((rem >> 9) * 0x537);
4225317bbafSopenharmony_ci	int bits = (data << 10 | rem) ^ 0x5412;  // uint15
4235317bbafSopenharmony_ci	assert(bits >> 15 == 0);
4245317bbafSopenharmony_ci
4255317bbafSopenharmony_ci	// Draw first copy
4265317bbafSopenharmony_ci	for (int i = 0; i <= 5; i++)
4275317bbafSopenharmony_ci		setFunctionModule(8, i, getBit(bits, i));
4285317bbafSopenharmony_ci	setFunctionModule(8, 7, getBit(bits, 6));
4295317bbafSopenharmony_ci	setFunctionModule(8, 8, getBit(bits, 7));
4305317bbafSopenharmony_ci	setFunctionModule(7, 8, getBit(bits, 8));
4315317bbafSopenharmony_ci	for (int i = 9; i < 15; i++)
4325317bbafSopenharmony_ci		setFunctionModule(14 - i, 8, getBit(bits, i));
4335317bbafSopenharmony_ci
4345317bbafSopenharmony_ci	// Draw second copy
4355317bbafSopenharmony_ci	for (int i = 0; i < 8; i++)
4365317bbafSopenharmony_ci		setFunctionModule(size - 1 - i, 8, getBit(bits, i));
4375317bbafSopenharmony_ci	for (int i = 8; i < 15; i++)
4385317bbafSopenharmony_ci		setFunctionModule(8, size - 15 + i, getBit(bits, i));
4395317bbafSopenharmony_ci	setFunctionModule(8, size - 8, true);  // Always dark
4405317bbafSopenharmony_ci}
4415317bbafSopenharmony_ci
4425317bbafSopenharmony_ci
4435317bbafSopenharmony_civoid QrCode::drawVersion() {
4445317bbafSopenharmony_ci	if (version < 7)
4455317bbafSopenharmony_ci		return;
4465317bbafSopenharmony_ci
4475317bbafSopenharmony_ci	// Calculate error correction code and pack bits
4485317bbafSopenharmony_ci	int rem = version;  // version is uint6, in the range [7, 40]
4495317bbafSopenharmony_ci	for (int i = 0; i < 12; i++)
4505317bbafSopenharmony_ci		rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
4515317bbafSopenharmony_ci	long bits = static_cast<long>(version) << 12 | rem;  // uint18
4525317bbafSopenharmony_ci	assert(bits >> 18 == 0);
4535317bbafSopenharmony_ci
4545317bbafSopenharmony_ci	// Draw two copies
4555317bbafSopenharmony_ci	for (int i = 0; i < 18; i++) {
4565317bbafSopenharmony_ci		bool bit = getBit(bits, i);
4575317bbafSopenharmony_ci		int a = size - 11 + i % 3;
4585317bbafSopenharmony_ci		int b = i / 3;
4595317bbafSopenharmony_ci		setFunctionModule(a, b, bit);
4605317bbafSopenharmony_ci		setFunctionModule(b, a, bit);
4615317bbafSopenharmony_ci	}
4625317bbafSopenharmony_ci}
4635317bbafSopenharmony_ci
4645317bbafSopenharmony_ci
4655317bbafSopenharmony_civoid QrCode::drawFinderPattern(int x, int y) {
4665317bbafSopenharmony_ci	for (int dy = -4; dy <= 4; dy++) {
4675317bbafSopenharmony_ci		for (int dx = -4; dx <= 4; dx++) {
4685317bbafSopenharmony_ci			int dist = std::max(std::abs(dx), std::abs(dy));  // Chebyshev/infinity norm
4695317bbafSopenharmony_ci			int xx = x + dx, yy = y + dy;
4705317bbafSopenharmony_ci			if (0 <= xx && xx < size && 0 <= yy && yy < size)
4715317bbafSopenharmony_ci				setFunctionModule(xx, yy, dist != 2 && dist != 4);
4725317bbafSopenharmony_ci		}
4735317bbafSopenharmony_ci	}
4745317bbafSopenharmony_ci}
4755317bbafSopenharmony_ci
4765317bbafSopenharmony_ci
4775317bbafSopenharmony_civoid QrCode::drawAlignmentPattern(int x, int y) {
4785317bbafSopenharmony_ci	for (int dy = -2; dy <= 2; dy++) {
4795317bbafSopenharmony_ci		for (int dx = -2; dx <= 2; dx++)
4805317bbafSopenharmony_ci			setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1);
4815317bbafSopenharmony_ci	}
4825317bbafSopenharmony_ci}
4835317bbafSopenharmony_ci
4845317bbafSopenharmony_ci
4855317bbafSopenharmony_civoid QrCode::setFunctionModule(int x, int y, bool isDark) {
4865317bbafSopenharmony_ci	size_t ux = static_cast<size_t>(x);
4875317bbafSopenharmony_ci	size_t uy = static_cast<size_t>(y);
4885317bbafSopenharmony_ci	modules   .at(uy).at(ux) = isDark;
4895317bbafSopenharmony_ci	isFunction.at(uy).at(ux) = true;
4905317bbafSopenharmony_ci}
4915317bbafSopenharmony_ci
4925317bbafSopenharmony_ci
4935317bbafSopenharmony_cibool QrCode::module(int x, int y) const {
4945317bbafSopenharmony_ci	return modules.at(static_cast<size_t>(y)).at(static_cast<size_t>(x));
4955317bbafSopenharmony_ci}
4965317bbafSopenharmony_ci
4975317bbafSopenharmony_ci
4985317bbafSopenharmony_civector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const {
4995317bbafSopenharmony_ci	if (data.size() != static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel)))
5005317bbafSopenharmony_ci		throw std::invalid_argument("Invalid argument");
5015317bbafSopenharmony_ci
5025317bbafSopenharmony_ci	// Calculate parameter numbers
5035317bbafSopenharmony_ci	int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(errorCorrectionLevel)][version];
5045317bbafSopenharmony_ci	int blockEccLen = ECC_CODEWORDS_PER_BLOCK  [static_cast<int>(errorCorrectionLevel)][version];
5055317bbafSopenharmony_ci	int rawCodewords = getNumRawDataModules(version) / 8;
5065317bbafSopenharmony_ci	int numShortBlocks = numBlocks - rawCodewords % numBlocks;
5075317bbafSopenharmony_ci	int shortBlockLen = rawCodewords / numBlocks;
5085317bbafSopenharmony_ci
5095317bbafSopenharmony_ci	// Split data into blocks and append ECC to each block
5105317bbafSopenharmony_ci	vector<vector<uint8_t> > blocks;
5115317bbafSopenharmony_ci	const vector<uint8_t> rsDiv = reedSolomonComputeDivisor(blockEccLen);
5125317bbafSopenharmony_ci	for (int i = 0, k = 0; i < numBlocks; i++) {
5135317bbafSopenharmony_ci		vector<uint8_t> dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
5145317bbafSopenharmony_ci		k += static_cast<int>(dat.size());
5155317bbafSopenharmony_ci		const vector<uint8_t> ecc = reedSolomonComputeRemainder(dat, rsDiv);
5165317bbafSopenharmony_ci		if (i < numShortBlocks)
5175317bbafSopenharmony_ci			dat.push_back(0);
5185317bbafSopenharmony_ci		dat.insert(dat.end(), ecc.cbegin(), ecc.cend());
5195317bbafSopenharmony_ci		blocks.push_back(std::move(dat));
5205317bbafSopenharmony_ci	}
5215317bbafSopenharmony_ci
5225317bbafSopenharmony_ci	// Interleave (not concatenate) the bytes from every block into a single sequence
5235317bbafSopenharmony_ci	vector<uint8_t> result;
5245317bbafSopenharmony_ci	for (size_t i = 0; i < blocks.at(0).size(); i++) {
5255317bbafSopenharmony_ci		for (size_t j = 0; j < blocks.size(); j++) {
5265317bbafSopenharmony_ci			// Skip the padding byte in short blocks
5275317bbafSopenharmony_ci			if (i != static_cast<unsigned int>(shortBlockLen - blockEccLen) || j >= static_cast<unsigned int>(numShortBlocks))
5285317bbafSopenharmony_ci				result.push_back(blocks.at(j).at(i));
5295317bbafSopenharmony_ci		}
5305317bbafSopenharmony_ci	}
5315317bbafSopenharmony_ci	assert(result.size() == static_cast<unsigned int>(rawCodewords));
5325317bbafSopenharmony_ci	return result;
5335317bbafSopenharmony_ci}
5345317bbafSopenharmony_ci
5355317bbafSopenharmony_ci
5365317bbafSopenharmony_civoid QrCode::drawCodewords(const vector<uint8_t> &data) {
5375317bbafSopenharmony_ci	if (data.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8))
5385317bbafSopenharmony_ci		throw std::invalid_argument("Invalid argument");
5395317bbafSopenharmony_ci
5405317bbafSopenharmony_ci	size_t i = 0;  // Bit index into the data
5415317bbafSopenharmony_ci	// Do the funny zigzag scan
5425317bbafSopenharmony_ci	for (int right = size - 1; right >= 1; right -= 2) {  // Index of right column in each column pair
5435317bbafSopenharmony_ci		if (right == 6)
5445317bbafSopenharmony_ci			right = 5;
5455317bbafSopenharmony_ci		for (int vert = 0; vert < size; vert++) {  // Vertical counter
5465317bbafSopenharmony_ci			for (int j = 0; j < 2; j++) {
5475317bbafSopenharmony_ci				size_t x = static_cast<size_t>(right - j);  // Actual x coordinate
5485317bbafSopenharmony_ci				bool upward = ((right + 1) & 2) == 0;
5495317bbafSopenharmony_ci				size_t y = static_cast<size_t>(upward ? size - 1 - vert : vert);  // Actual y coordinate
5505317bbafSopenharmony_ci				if (!isFunction.at(y).at(x) && i < data.size() * 8) {
5515317bbafSopenharmony_ci					modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast<int>(i & 7));
5525317bbafSopenharmony_ci					i++;
5535317bbafSopenharmony_ci				}
5545317bbafSopenharmony_ci				// If this QR Code has any remainder bits (0 to 7), they were assigned as
5555317bbafSopenharmony_ci				// 0/false/light by the constructor and are left unchanged by this method
5565317bbafSopenharmony_ci			}
5575317bbafSopenharmony_ci		}
5585317bbafSopenharmony_ci	}
5595317bbafSopenharmony_ci	assert(i == data.size() * 8);
5605317bbafSopenharmony_ci}
5615317bbafSopenharmony_ci
5625317bbafSopenharmony_ci
5635317bbafSopenharmony_civoid QrCode::applyMask(int msk) {
5645317bbafSopenharmony_ci	if (msk < 0 || msk > 7)
5655317bbafSopenharmony_ci		throw std::domain_error("Mask value out of range");
5665317bbafSopenharmony_ci	size_t sz = static_cast<size_t>(size);
5675317bbafSopenharmony_ci	for (size_t y = 0; y < sz; y++) {
5685317bbafSopenharmony_ci		for (size_t x = 0; x < sz; x++) {
5695317bbafSopenharmony_ci			bool invert;
5705317bbafSopenharmony_ci			switch (msk) {
5715317bbafSopenharmony_ci				case 0:  invert = (x + y) % 2 == 0;                    break;
5725317bbafSopenharmony_ci				case 1:  invert = y % 2 == 0;                          break;
5735317bbafSopenharmony_ci				case 2:  invert = x % 3 == 0;                          break;
5745317bbafSopenharmony_ci				case 3:  invert = (x + y) % 3 == 0;                    break;
5755317bbafSopenharmony_ci				case 4:  invert = (x / 3 + y / 2) % 2 == 0;            break;
5765317bbafSopenharmony_ci				case 5:  invert = x * y % 2 + x * y % 3 == 0;          break;
5775317bbafSopenharmony_ci				case 6:  invert = (x * y % 2 + x * y % 3) % 2 == 0;    break;
5785317bbafSopenharmony_ci				case 7:  invert = ((x + y) % 2 + x * y % 3) % 2 == 0;  break;
5795317bbafSopenharmony_ci				default:  throw std::logic_error("Unreachable");
5805317bbafSopenharmony_ci			}
5815317bbafSopenharmony_ci			modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
5825317bbafSopenharmony_ci		}
5835317bbafSopenharmony_ci	}
5845317bbafSopenharmony_ci}
5855317bbafSopenharmony_ci
5865317bbafSopenharmony_ci
5875317bbafSopenharmony_cilong QrCode::getPenaltyScore() const {
5885317bbafSopenharmony_ci	long result = 0;
5895317bbafSopenharmony_ci
5905317bbafSopenharmony_ci	// Adjacent modules in row having same color, and finder-like patterns
5915317bbafSopenharmony_ci	for (int y = 0; y < size; y++) {
5925317bbafSopenharmony_ci		bool runColor = false;
5935317bbafSopenharmony_ci		int runX = 0;
5945317bbafSopenharmony_ci		std::array<int,7> runHistory = {};
5955317bbafSopenharmony_ci		for (int x = 0; x < size; x++) {
5965317bbafSopenharmony_ci			if (module(x, y) == runColor) {
5975317bbafSopenharmony_ci				runX++;
5985317bbafSopenharmony_ci				if (runX == 5)
5995317bbafSopenharmony_ci					result += PENALTY_N1;
6005317bbafSopenharmony_ci				else if (runX > 5)
6015317bbafSopenharmony_ci					result++;
6025317bbafSopenharmony_ci			} else {
6035317bbafSopenharmony_ci				finderPenaltyAddHistory(runX, runHistory);
6045317bbafSopenharmony_ci				if (!runColor)
6055317bbafSopenharmony_ci					result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
6065317bbafSopenharmony_ci				runColor = module(x, y);
6075317bbafSopenharmony_ci				runX = 1;
6085317bbafSopenharmony_ci			}
6095317bbafSopenharmony_ci		}
6105317bbafSopenharmony_ci		result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3;
6115317bbafSopenharmony_ci	}
6125317bbafSopenharmony_ci	// Adjacent modules in column having same color, and finder-like patterns
6135317bbafSopenharmony_ci	for (int x = 0; x < size; x++) {
6145317bbafSopenharmony_ci		bool runColor = false;
6155317bbafSopenharmony_ci		int runY = 0;
6165317bbafSopenharmony_ci		std::array<int,7> runHistory = {};
6175317bbafSopenharmony_ci		for (int y = 0; y < size; y++) {
6185317bbafSopenharmony_ci			if (module(x, y) == runColor) {
6195317bbafSopenharmony_ci				runY++;
6205317bbafSopenharmony_ci				if (runY == 5)
6215317bbafSopenharmony_ci					result += PENALTY_N1;
6225317bbafSopenharmony_ci				else if (runY > 5)
6235317bbafSopenharmony_ci					result++;
6245317bbafSopenharmony_ci			} else {
6255317bbafSopenharmony_ci				finderPenaltyAddHistory(runY, runHistory);
6265317bbafSopenharmony_ci				if (!runColor)
6275317bbafSopenharmony_ci					result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
6285317bbafSopenharmony_ci				runColor = module(x, y);
6295317bbafSopenharmony_ci				runY = 1;
6305317bbafSopenharmony_ci			}
6315317bbafSopenharmony_ci		}
6325317bbafSopenharmony_ci		result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
6335317bbafSopenharmony_ci	}
6345317bbafSopenharmony_ci
6355317bbafSopenharmony_ci	// 2*2 blocks of modules having same color
6365317bbafSopenharmony_ci	for (int y = 0; y < size - 1; y++) {
6375317bbafSopenharmony_ci		for (int x = 0; x < size - 1; x++) {
6385317bbafSopenharmony_ci			bool  color = module(x, y);
6395317bbafSopenharmony_ci			if (  color == module(x + 1, y) &&
6405317bbafSopenharmony_ci			      color == module(x, y + 1) &&
6415317bbafSopenharmony_ci			      color == module(x + 1, y + 1))
6425317bbafSopenharmony_ci				result += PENALTY_N2;
6435317bbafSopenharmony_ci		}
6445317bbafSopenharmony_ci	}
6455317bbafSopenharmony_ci
6465317bbafSopenharmony_ci	// Balance of dark and light modules
6475317bbafSopenharmony_ci	int dark = 0;
6485317bbafSopenharmony_ci	for (const vector<bool> &row : modules) {
6495317bbafSopenharmony_ci		for (bool color : row) {
6505317bbafSopenharmony_ci			if (color)
6515317bbafSopenharmony_ci				dark++;
6525317bbafSopenharmony_ci		}
6535317bbafSopenharmony_ci	}
6545317bbafSopenharmony_ci	int total = size * size;  // Note that size is odd, so dark/total != 1/2
6555317bbafSopenharmony_ci	// Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%
6565317bbafSopenharmony_ci	int k = static_cast<int>((std::abs(dark * 20L - total * 10L) + total - 1) / total) - 1;
6575317bbafSopenharmony_ci	assert(0 <= k && k <= 9);
6585317bbafSopenharmony_ci	result += k * PENALTY_N4;
6595317bbafSopenharmony_ci	assert(0 <= result && result <= 2568888L);  // Non-tight upper bound based on default values of PENALTY_N1, ..., N4
6605317bbafSopenharmony_ci	return result;
6615317bbafSopenharmony_ci}
6625317bbafSopenharmony_ci
6635317bbafSopenharmony_ci
6645317bbafSopenharmony_civector<int> QrCode::getAlignmentPatternPositions() const {
6655317bbafSopenharmony_ci	if (version == 1)
6665317bbafSopenharmony_ci		return vector<int>();
6675317bbafSopenharmony_ci	else {
6685317bbafSopenharmony_ci		int numAlign = version / 7 + 2;
6695317bbafSopenharmony_ci		int step = (version == 32) ? 26 :
6705317bbafSopenharmony_ci			(version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2;
6715317bbafSopenharmony_ci		vector<int> result;
6725317bbafSopenharmony_ci		for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step)
6735317bbafSopenharmony_ci			result.insert(result.begin(), pos);
6745317bbafSopenharmony_ci		result.insert(result.begin(), 6);
6755317bbafSopenharmony_ci		return result;
6765317bbafSopenharmony_ci	}
6775317bbafSopenharmony_ci}
6785317bbafSopenharmony_ci
6795317bbafSopenharmony_ci
6805317bbafSopenharmony_ciint QrCode::getNumRawDataModules(int ver) {
6815317bbafSopenharmony_ci	if (ver < MIN_VERSION || ver > MAX_VERSION)
6825317bbafSopenharmony_ci		throw std::domain_error("Version number out of range");
6835317bbafSopenharmony_ci	int result = (16 * ver + 128) * ver + 64;
6845317bbafSopenharmony_ci	if (ver >= 2) {
6855317bbafSopenharmony_ci		int numAlign = ver / 7 + 2;
6865317bbafSopenharmony_ci		result -= (25 * numAlign - 10) * numAlign - 55;
6875317bbafSopenharmony_ci		if (ver >= 7)
6885317bbafSopenharmony_ci			result -= 36;
6895317bbafSopenharmony_ci	}
6905317bbafSopenharmony_ci	assert(208 <= result && result <= 29648);
6915317bbafSopenharmony_ci	return result;
6925317bbafSopenharmony_ci}
6935317bbafSopenharmony_ci
6945317bbafSopenharmony_ci
6955317bbafSopenharmony_ciint QrCode::getNumDataCodewords(int ver, Ecc ecl) {
6965317bbafSopenharmony_ci	return getNumRawDataModules(ver) / 8
6975317bbafSopenharmony_ci		- ECC_CODEWORDS_PER_BLOCK    [static_cast<int>(ecl)][ver]
6985317bbafSopenharmony_ci		* NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(ecl)][ver];
6995317bbafSopenharmony_ci}
7005317bbafSopenharmony_ci
7015317bbafSopenharmony_ci
7025317bbafSopenharmony_civector<uint8_t> QrCode::reedSolomonComputeDivisor(int degree) {
7035317bbafSopenharmony_ci	if (degree < 1 || degree > 255)
7045317bbafSopenharmony_ci		throw std::domain_error("Degree out of range");
7055317bbafSopenharmony_ci	// Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
7065317bbafSopenharmony_ci	// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
7075317bbafSopenharmony_ci	vector<uint8_t> result(static_cast<size_t>(degree));
7085317bbafSopenharmony_ci	result.at(result.size() - 1) = 1;  // Start off with the monomial x^0
7095317bbafSopenharmony_ci
7105317bbafSopenharmony_ci	// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
7115317bbafSopenharmony_ci	// and drop the highest monomial term which is always 1x^degree.
7125317bbafSopenharmony_ci	// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
7135317bbafSopenharmony_ci	uint8_t root = 1;
7145317bbafSopenharmony_ci	for (int i = 0; i < degree; i++) {
7155317bbafSopenharmony_ci		// Multiply the current product by (x - r^i)
7165317bbafSopenharmony_ci		for (size_t j = 0; j < result.size(); j++) {
7175317bbafSopenharmony_ci			result.at(j) = reedSolomonMultiply(result.at(j), root);
7185317bbafSopenharmony_ci			if (j + 1 < result.size())
7195317bbafSopenharmony_ci				result.at(j) ^= result.at(j + 1);
7205317bbafSopenharmony_ci		}
7215317bbafSopenharmony_ci		root = reedSolomonMultiply(root, 0x02);
7225317bbafSopenharmony_ci	}
7235317bbafSopenharmony_ci	return result;
7245317bbafSopenharmony_ci}
7255317bbafSopenharmony_ci
7265317bbafSopenharmony_ci
7275317bbafSopenharmony_civector<uint8_t> QrCode::reedSolomonComputeRemainder(const vector<uint8_t> &data, const vector<uint8_t> &divisor) {
7285317bbafSopenharmony_ci	vector<uint8_t> result(divisor.size());
7295317bbafSopenharmony_ci	for (uint8_t b : data) {  // Polynomial division
7305317bbafSopenharmony_ci		uint8_t factor = b ^ result.at(0);
7315317bbafSopenharmony_ci		result.erase(result.begin());
7325317bbafSopenharmony_ci		result.push_back(0);
7335317bbafSopenharmony_ci		for (size_t i = 0; i < result.size(); i++)
7345317bbafSopenharmony_ci			result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor);
7355317bbafSopenharmony_ci	}
7365317bbafSopenharmony_ci	return result;
7375317bbafSopenharmony_ci}
7385317bbafSopenharmony_ci
7395317bbafSopenharmony_ci
7405317bbafSopenharmony_ciuint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) {
7415317bbafSopenharmony_ci	// Russian peasant multiplication
7425317bbafSopenharmony_ci	int z = 0;
7435317bbafSopenharmony_ci	for (int i = 7; i >= 0; i--) {
7445317bbafSopenharmony_ci		z = (z << 1) ^ ((z >> 7) * 0x11D);
7455317bbafSopenharmony_ci		z ^= ((y >> i) & 1) * x;
7465317bbafSopenharmony_ci	}
7475317bbafSopenharmony_ci	assert(z >> 8 == 0);
7485317bbafSopenharmony_ci	return static_cast<uint8_t>(z);
7495317bbafSopenharmony_ci}
7505317bbafSopenharmony_ci
7515317bbafSopenharmony_ci
7525317bbafSopenharmony_ciint QrCode::finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const {
7535317bbafSopenharmony_ci	int n = runHistory.at(1);
7545317bbafSopenharmony_ci	assert(n <= size * 3);
7555317bbafSopenharmony_ci	bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n;
7565317bbafSopenharmony_ci	return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0)
7575317bbafSopenharmony_ci	     + (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0);
7585317bbafSopenharmony_ci}
7595317bbafSopenharmony_ci
7605317bbafSopenharmony_ci
7615317bbafSopenharmony_ciint QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const {
7625317bbafSopenharmony_ci	if (currentRunColor) {  // Terminate dark run
7635317bbafSopenharmony_ci		finderPenaltyAddHistory(currentRunLength, runHistory);
7645317bbafSopenharmony_ci		currentRunLength = 0;
7655317bbafSopenharmony_ci	}
7665317bbafSopenharmony_ci	currentRunLength += size;  // Add light border to final run
7675317bbafSopenharmony_ci	finderPenaltyAddHistory(currentRunLength, runHistory);
7685317bbafSopenharmony_ci	return finderPenaltyCountPatterns(runHistory);
7695317bbafSopenharmony_ci}
7705317bbafSopenharmony_ci
7715317bbafSopenharmony_ci
7725317bbafSopenharmony_civoid QrCode::finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const {
7735317bbafSopenharmony_ci	if (runHistory.at(0) == 0)
7745317bbafSopenharmony_ci		currentRunLength += size;  // Add light border to initial run
7755317bbafSopenharmony_ci	std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end());
7765317bbafSopenharmony_ci	runHistory.at(0) = currentRunLength;
7775317bbafSopenharmony_ci}
7785317bbafSopenharmony_ci
7795317bbafSopenharmony_ci
7805317bbafSopenharmony_cibool QrCode::getBit(long x, int i) {
7815317bbafSopenharmony_ci	return ((x >> i) & 1) != 0;
7825317bbafSopenharmony_ci}
7835317bbafSopenharmony_ci
7845317bbafSopenharmony_ci
7855317bbafSopenharmony_ci/*---- Tables of constants ----*/
7865317bbafSopenharmony_ci
7875317bbafSopenharmony_ciconst int QrCode::PENALTY_N1 =  3;
7885317bbafSopenharmony_ciconst int QrCode::PENALTY_N2 =  3;
7895317bbafSopenharmony_ciconst int QrCode::PENALTY_N3 = 40;
7905317bbafSopenharmony_ciconst int QrCode::PENALTY_N4 = 10;
7915317bbafSopenharmony_ci
7925317bbafSopenharmony_ci
7935317bbafSopenharmony_ciconst int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = {
7945317bbafSopenharmony_ci	// Version: (note that index 0 is for padding, and is set to an illegal value)
7955317bbafSopenharmony_ci	//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
7965317bbafSopenharmony_ci	{-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
7975317bbafSopenharmony_ci	{-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
7985317bbafSopenharmony_ci	{-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
7995317bbafSopenharmony_ci	{-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
8005317bbafSopenharmony_ci};
8015317bbafSopenharmony_ci
8025317bbafSopenharmony_ciconst int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
8035317bbafSopenharmony_ci	// Version: (note that index 0 is for padding, and is set to an illegal value)
8045317bbafSopenharmony_ci	//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
8055317bbafSopenharmony_ci	{-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
8065317bbafSopenharmony_ci	{-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
8075317bbafSopenharmony_ci	{-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
8085317bbafSopenharmony_ci	{-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
8095317bbafSopenharmony_ci};
8105317bbafSopenharmony_ci
8115317bbafSopenharmony_ci
8125317bbafSopenharmony_cidata_too_long::data_too_long(const std::string &msg) :
8135317bbafSopenharmony_ci	std::length_error(msg) {}
8145317bbafSopenharmony_ci
8155317bbafSopenharmony_ci
8165317bbafSopenharmony_ci
8175317bbafSopenharmony_ci/*---- Class BitBuffer ----*/
8185317bbafSopenharmony_ci
8195317bbafSopenharmony_ciBitBuffer::BitBuffer()
8205317bbafSopenharmony_ci	: std::vector<bool>() {}
8215317bbafSopenharmony_ci
8225317bbafSopenharmony_ci
8235317bbafSopenharmony_civoid BitBuffer::appendBits(std::uint32_t val, int len) {
8245317bbafSopenharmony_ci	if (len < 0 || len > 31 || val >> len != 0)
8255317bbafSopenharmony_ci		throw std::domain_error("Value out of range");
8265317bbafSopenharmony_ci	for (int i = len - 1; i >= 0; i--)  // Append bit by bit
8275317bbafSopenharmony_ci		this->push_back(((val >> i) & 1) != 0);
8285317bbafSopenharmony_ci}
8295317bbafSopenharmony_ci
8305317bbafSopenharmony_ci}
831