Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/zint/backend/qr.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/zint/backend/qr.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,2808 @@ +/* qr.c Handles QR Code, Micro QR Code, UPNQR and rMQR */ +/* + libzint - the open source barcode library + Copyright (C) 2009-2024 Robin Stuart <rstuart114@gmail.com> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include "common.h" +#include "eci.h" +#include "qr.h" +#include "reedsol.h" + +#define QR_ALPHA (IS_NUM_F | IS_UPR_F | IS_SPC_F | IS_AST_F | IS_PLS_F | IS_MNS_F | IS_SIL_F | IS_CLI_F) + +#define QR_LEVEL_L 0 +#define QR_LEVEL_M 1 +#define QR_LEVEL_Q 2 +#define QR_LEVEL_H 3 + +static const char qr_ecc_level_names[] = { 'L', 'M', 'Q', 'H' }; + +#define QR_PERCENT 38 /* Alphanumeric mode % */ + +#define RMQR_VERSION 41 +#define MICROQR_VERSION 73 + +/* Returns true if input glyph is in the Alphanumeric set or is GS1 FNC1 */ +static int qr_is_alpha(const unsigned int glyph, const int gs1) { + if (is_chr(QR_ALPHA, glyph)) { + return 1; + } + if (gs1 && glyph == '\x1D') { + return 1; + } + return 0; +} + +/* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */ +#define QR_MULT 6 + +/* Whether in numeric or not. If in numeric, *p_end is set to position after numeric, and *p_cost is set to + * per-numeric cost */ +static int qr_in_numeric(const unsigned int ddata[], const int length, const int in_posn, + unsigned int *p_end, unsigned int *p_cost) { + int i, digit_cnt; + + if (in_posn < (int) *p_end) { + return 1; + } + + /* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times QR_MULT) */ + for (i = in_posn; i < length && i < in_posn + 3 && z_isdigit(ddata[i]); i++); + + digit_cnt = i - in_posn; + + if (digit_cnt == 0) { + *p_end = 0; + return 0; + } + *p_end = i; + *p_cost = digit_cnt == 1 + ? 24 /* 4 * QR_MULT */ : digit_cnt == 2 ? 21 /* (7 / 2) * QR_MULT */ : 20 /* (10 / 3) * QR_MULT) */; + return 1; +} + +/* Whether in alpha or not. If in alpha, *p_end is set to position after alpha, and *p_cost is set to per-alpha cost. + * For GS1, *p_pcent set if 2nd char percent */ +static int qr_in_alpha(const unsigned int ddata[], const int length, const int in_posn, + unsigned int *p_end, unsigned int *p_cost, unsigned int *p_pcent, unsigned int *p_pccnt, + unsigned int gs1) { + const int last = in_posn + 1 == length; + int two_alphas; + + /* Attempt to calculate the average 'cost' of using alphanumeric mode in number of bits (times QR_MULT) */ + if (in_posn < (int) *p_end) { + if (gs1) { + if (*p_pcent) { + /* Previous 2nd char was a percent, so allow for second half of doubled-up percent here */ + two_alphas = !last && qr_is_alpha(ddata[in_posn + 1], gs1); + /* Uneven percents means this will fit evenly in alpha pair */ + *p_cost = two_alphas || !(*p_pccnt & 1) ? 66 /* 11 * QR_MULT */ : 69 /* (11 / 2 + 6) * QR_MULT */; + *p_pcent = 0; + } else { + /* As above, uneven percents means will fit in alpha pair */ + *p_cost = !last || !(*p_pccnt & 1) ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */; + } + } else { + *p_cost = !last ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */; + } + return 1; + } + + if (!qr_is_alpha(ddata[in_posn], gs1)) { + *p_end = 0; + *p_pcent = 0; + *p_pccnt = 0; + return 0; + } + + two_alphas = !last && qr_is_alpha(ddata[in_posn + 1], gs1); + + if (gs1 && ddata[in_posn] == '%') { /* Must double-up so counts as 2 chars */ + *p_end = in_posn + 1; + *p_pcent = 0; + (*p_pccnt)++; + /* Uneven percents means will fit in alpha pair */ + *p_cost = two_alphas || !(*p_pccnt & 1) ? 66 /* 11 * QR_MULT */ : 69 /* (11 / 2 + 6) * QR_MULT */; + return 1; + } + + *p_end = two_alphas ? in_posn + 2 : in_posn + 1; + if (gs1) { + *p_pcent = two_alphas && ddata[in_posn + 1] == '%'; /* 2nd char is percent */ + *p_pccnt += *p_pcent; + /* Uneven percents means will fit in alpha pair */ + *p_cost = two_alphas || !(*p_pccnt & 1) ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */; + } else { + *p_cost = two_alphas ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */; + } + return 1; +} + +#if 0 +#define QR_DEBUG_DEFINE_MODE /* For debugging costings */ +#endif + +/* Indexes into qr_mode_types array (and state array) */ +#define QR_N 0 /* Numeric */ +#define QR_A 1 /* Alphanumeric */ +#define QR_B 2 /* Byte */ +#define QR_K 3 /* Kanji */ + +static const char qr_mode_types[] = { 'N', 'A', 'B', 'K', '\0' }; /* Must be in same order as QR_N etc */ + +#define QR_NUM_MODES 4 + +/* Indexes into state array (0..3 head costs) */ +#define QR_VER 4 /* Version */ +#define QR_N_END 5 /* Numeric end index */ +#define QR_N_COST 6 /* Numeric cost */ +#define QR_A_END 7 /* Alpha end index */ +#define QR_A_COST 8 /* Alpha cost */ +#define QR_A_PCENT 9 /* Alpha 2nd char percent (GS1-specific) */ +#define QR_A_PCCNT 10 /* Alpha total percent count (GS1-specific) */ + +/* Costs set to this for invalid MICROQR modes for versions M1 and M2. + * 128 is the max number of data bits for M4-L (ISO/IEC 18004:2015 Table 7) */ +#define QR_MICROQR_MAX 774 /* (128 + 1) * QR_MULT */ + +/* Initial mode costs */ +static unsigned int *qr_head_costs(unsigned int state[11]) { + static const unsigned int head_costs[7][QR_NUM_MODES] = { + /* N A B K */ + { (10 + 4) * QR_MULT, (9 + 4) * QR_MULT, (8 + 4) * QR_MULT, (8 + 4) * QR_MULT, }, /* QR */ + { (12 + 4) * QR_MULT, (11 + 4) * QR_MULT, (16 + 4) * QR_MULT, (10 + 4) * QR_MULT, }, + { (14 + 4) * QR_MULT, (13 + 4) * QR_MULT, (16 + 4) * QR_MULT, (12 + 4) * QR_MULT, }, + { 3 * QR_MULT, QR_MICROQR_MAX, QR_MICROQR_MAX, QR_MICROQR_MAX, }, /* MICROQR */ + { (4 + 1) * QR_MULT, (3 + 1) * QR_MULT, QR_MICROQR_MAX, QR_MICROQR_MAX, }, + { (5 + 2) * QR_MULT, (4 + 2) * QR_MULT, (4 + 2) * QR_MULT, (3 + 2) * QR_MULT, }, + { (6 + 3) * QR_MULT, (5 + 3) * QR_MULT, (5 + 3) * QR_MULT, (4 + 3) * QR_MULT, } + }; + int version; + + /* Head costs kept in states 0..3 */ + + version = state[QR_VER]; + + if (version < RMQR_VERSION) { /* QRCODE */ + if (version < 10) { + memcpy(state, head_costs[0], QR_NUM_MODES * sizeof(unsigned int)); + } else if (version < 27) { + memcpy(state, head_costs[1], QR_NUM_MODES * sizeof(unsigned int)); + } else { + memcpy(state, head_costs[2], QR_NUM_MODES * sizeof(unsigned int)); + } + } else if (version < MICROQR_VERSION) { /* RMQR */ + version -= RMQR_VERSION; + state[QR_N] = (rmqr_numeric_cci[version] + 3) * QR_MULT; + state[QR_A] = (rmqr_alphanum_cci[version] + 3) * QR_MULT; + state[QR_B] = (rmqr_byte_cci[version] + 3) * QR_MULT; + state[QR_K] = (rmqr_kanji_cci[version] + 3) * QR_MULT; + } else { /* MICROQR */ + memcpy(state, head_costs[3 + (version - MICROQR_VERSION)], QR_NUM_MODES * sizeof(unsigned int)); + } + + return state; +} + +/* Calculate optimized encoding modes. Adapted from Project Nayuki */ +static void qr_define_mode(char mode[], const unsigned int ddata[], const int length, const int gs1, + const int version, const int debug_print) { + /* + * 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. + */ + unsigned int state[11] = { + 0 /*N*/, 0 /*A*/, 0 /*B*/, 0 /*K*/, /* Head/switch costs */ + 0 /*version*/, + 0 /*numeric_end*/, 0 /*numeric_cost*/, 0 /*alpha_end*/, 0 /*alpha_cost*/, 0 /*alpha_pcent*/, 0 /*alpha_pccnt*/ + }; + int m1, m2; + + int i, j, k; + unsigned int min_cost; + char cur_mode; + unsigned int prev_costs[QR_NUM_MODES]; + unsigned int cur_costs[QR_NUM_MODES]; + char (*char_modes)[QR_NUM_MODES] = (char (*)[QR_NUM_MODES]) z_alloca(QR_NUM_MODES * length); + + state[QR_VER] = (unsigned int) version; + + /* char_modes[i][j] represents the mode to encode the code point at index i such that the final segment + ends in qr_mode_types[j] and the total number of bits is minimized over all possible choices */ + memset(char_modes, 0, QR_NUM_MODES * length); + + /* At the beginning of each iteration of the loop below, prev_costs[j] is the minimum number of 1/6 (1/QR_MULT) + * bits needed to encode the entire string prefix of length i, and end in qr_mode_types[j] */ + memcpy(prev_costs, qr_head_costs(state), QR_NUM_MODES * sizeof(unsigned int)); + + #ifdef QR_DEBUG_DEFINE_MODE + printf(" head"); + for (j = 0; j < QR_NUM_MODES; j++) { + printf(" %c(%c)=%d", qr_mode_types[j], char_modes[0][j], prev_costs[j]); + } + printf("\n"); + #endif + + /* Calculate costs using dynamic programming */ + for (i = 0; i < length; i++) { + memset(cur_costs, 0, QR_NUM_MODES * sizeof(unsigned int)); + + m1 = version == MICROQR_VERSION; + m2 = version == MICROQR_VERSION + 1; + + if (ddata[i] > 0xFF) { + cur_costs[QR_B] = prev_costs[QR_B] + ((m1 || m2) ? QR_MICROQR_MAX : 96); /* 16 * QR_MULT */ + char_modes[i][QR_B] = 'B'; + cur_costs[QR_K] = prev_costs[QR_K] + ((m1 || m2) ? QR_MICROQR_MAX : 78); /* 13 * QR_MULT */ + char_modes[i][QR_K] = 'K'; + } else { + if (qr_in_numeric(ddata, length, i, &state[QR_N_END], &state[QR_N_COST])) { + cur_costs[QR_N] = prev_costs[QR_N] + state[QR_N_COST]; + char_modes[i][QR_N] = 'N'; + } + if (qr_in_alpha(ddata, length, i, &state[QR_A_END], &state[QR_A_COST], &state[QR_A_PCENT], + &state[QR_A_PCCNT], gs1)) { + cur_costs[QR_A] = prev_costs[QR_A] + (m1 ? QR_MICROQR_MAX : state[QR_A_COST]); + char_modes[i][QR_A] = 'A'; + } + cur_costs[QR_B] = prev_costs[QR_B] + ((m1 || m2) ? QR_MICROQR_MAX : 48); /* 8 * QR_MULT */ + char_modes[i][QR_B] = 'B'; + } + + /* Start new segment at the end to switch modes */ + for (j = 0; j < QR_NUM_MODES; j++) { /* To mode */ + for (k = 0; k < QR_NUM_MODES; k++) { /* From mode */ + if (j != k && char_modes[i][k]) { + const unsigned int new_cost = cur_costs[k] + state[j]; /* Switch costs same as head costs */ + if (!char_modes[i][j] || new_cost < cur_costs[j]) { + cur_costs[j] = new_cost; + char_modes[i][j] = qr_mode_types[k]; + } + } + } + } + + #ifdef QR_DEBUG_DEFINE_MODE + { + int min_j = 0; + printf(" % 4d: curr", i); + for (j = 0; j < QR_NUM_MODES; j++) { + printf(" %c(%c)=%d", qr_mode_types[j], char_modes[i][j], cur_costs[j]); + if (cur_costs[j] < cur_costs[min_j]) min_j = j; + } + printf(" min %c(%c)=%d\n", qr_mode_types[min_j], char_modes[i][min_j], cur_costs[min_j]); + } + #endif + memcpy(prev_costs, cur_costs, QR_NUM_MODES * sizeof(unsigned int)); + } + + /* Find optimal ending mode */ + min_cost = prev_costs[0]; + cur_mode = qr_mode_types[0]; + for (i = 1; i < QR_NUM_MODES; i++) { + if (prev_costs[i] < min_cost) { + min_cost = prev_costs[i]; + cur_mode = qr_mode_types[i]; + } + } + + /* Get optimal mode for each code point by tracing backwards */ + for (i = length - 1; i >= 0; i--) { + j = posn(qr_mode_types, cur_mode); + cur_mode = char_modes[i][j]; + mode[i] = cur_mode; + } + + if (debug_print) { + printf(" Mode: %.*s\n", length, mode); + } +} + +/* Returns mode indicator based on version and mode */ +static int qr_mode_indicator(const int version, const int mode) { + static const char mode_indicators[6][QR_NUM_MODES] = { + /*N A B K */ + { 1, 2, 4, 8, }, /* QRCODE */ + { 1, 2, 3, 4, }, /* RMQR */ + { 0, 0, 0, 0, }, /* MICROQR */ + { 0, 1, 0, 0, }, + { 0, 1, 2, 3, }, + { 0, 1, 2, 3, }, + }; + + int mode_index = posn(qr_mode_types, (const char) mode); + + if (version < RMQR_VERSION) { + return mode_indicators[0][mode_index]; /* QRCODE */ + } + if (version < MICROQR_VERSION) { + return mode_indicators[1][mode_index] /* RMQR */; + } + return mode_indicators[2 + version - MICROQR_VERSION][mode_index]; /* MICROQR */ +} + +/* Return mode indicator bits based on version */ +static int qr_mode_bits(const int version) { + if (version < RMQR_VERSION) { + return 4; /* QRCODE */ + } + if (version < MICROQR_VERSION) { + return 3; /* RMQR */ + } + return version - MICROQR_VERSION; /* MICROQR */ +} + +/* Return character count indicator bits based on version and mode */ +static int qr_cci_bits(const int version, const int mode) { + static const char cci_bits[7][QR_NUM_MODES] = { + /* N A B K */ + { 10, 9, 8, 8, }, /* QRCODE */ + { 12, 11, 16, 10, }, + { 14, 13, 16, 12, }, + { 3, 0, 0, 0, }, /* MICROQR */ + { 4, 3, 0, 0, }, + { 5, 4, 4, 3, }, + { 6, 5, 5, 4, } + }; + static const unsigned char *const rmqr_ccis[QR_NUM_MODES] = { + rmqr_numeric_cci, rmqr_alphanum_cci, rmqr_byte_cci, rmqr_kanji_cci, + }; + int mode_index = posn(qr_mode_types, (const char) mode); + + if (version < RMQR_VERSION) { /* QRCODE */ + if (version < 10) { + return cci_bits[0][mode_index]; + } + if (version < 27) { + return cci_bits[1][mode_index]; + } + return cci_bits[2][mode_index]; + } + if (version < MICROQR_VERSION) { /* RMQR */ + return rmqr_ccis[mode_index][version - RMQR_VERSION]; + } + return cci_bits[3 + (version - MICROQR_VERSION)][mode_index]; /* MICROQR */ +} + +/* Returns terminator bits based on version */ +static int qr_terminator_bits(const int version) { + if (version < RMQR_VERSION) { + return 4; /* QRCODE */ + } + if (version < MICROQR_VERSION) { + return 3; /* RMQR */ + } + return 3 + (version - MICROQR_VERSION) * 2; /* MICROQR */ +} + +/* Convert input data to a binary stream and add padding */ +static int qr_binary(char binary[], int bp, const int version, const char mode[], + const unsigned int ddata[], const int length, const int gs1, + const int eci, const int debug_print) { + int position = 0; + int i; + int modebits; + int percent = 0; + int percent_count; + + if (eci != 0) { /* Not applicable to MICROQR */ + bp = bin_append_posn(7, version < RMQR_VERSION ? 4 : 3, binary, bp); /* ECI (Table 4) */ + if (eci <= 127) { + bp = bin_append_posn(eci, 8, binary, bp); /* 000000 to 000127 */ + } else if (eci <= 16383) { + bp = bin_append_posn(0x8000 + eci, 16, binary, bp); /* 000128 to 016383 */ + } else { + bp = bin_append_posn(0xC00000 + eci, 24, binary, bp); /* 016384 to 999999 */ + } + } + + modebits = qr_mode_bits(version); + + do { + char data_block = mode[position]; + int short_data_block_length = 0; + int double_byte = 0; + do { + if (data_block == 'B' && ddata[position + short_data_block_length] > 0xFF) { + double_byte++; + } + short_data_block_length++; + } while (((short_data_block_length + position) < length) + && (mode[position + short_data_block_length] == data_block)); + + /* Mode indicator */ + if (modebits) { + bp = bin_append_posn(qr_mode_indicator(version, data_block), modebits, binary, bp); + } + + switch (data_block) { + case 'K': + /* Kanji mode */ + + /* Character count indicator */ + bp = bin_append_posn(short_data_block_length, qr_cci_bits(version, data_block), binary, bp); + + if (debug_print) { + printf("Kanji block (length %d)\n\t", short_data_block_length); + } + + /* Character representation */ + for (i = 0; i < short_data_block_length; i++) { + unsigned int jis = ddata[position + i]; + int prod; + + if (jis >= 0x8140 && jis <= 0x9ffc) + jis -= 0x8140; + + else if (jis >= 0xe040 && jis <= 0xebbf) + jis -= 0xc140; + + prod = ((jis >> 8) * 0xc0) + (jis & 0xff); + + bp = bin_append_posn(prod, 13, binary, bp); + + if (debug_print) { + printf("0x%04X ", prod); + } + } + + if (debug_print) { + fputc('\n', stdout); + } + + break; + case 'B': + /* Byte mode */ + + /* Character count indicator */ + bp = bin_append_posn(short_data_block_length + double_byte, qr_cci_bits(version, data_block), binary, + bp); + + if (debug_print) { + printf("Byte block (length %d)\n\t", short_data_block_length + double_byte); + } + + /* Character representation */ + for (i = 0; i < short_data_block_length; i++) { + unsigned int byte = ddata[position + i]; + + bp = bin_append_posn(byte, byte > 0xFF ? 16 : 8, binary, bp); + + if (debug_print) { + printf("0x%02X(%d) ", byte, (int) byte); + } + } + + if (debug_print) { + fputc('\n', stdout); + } + + break; + case 'A': + /* Alphanumeric mode */ + + percent_count = 0; + if (gs1) { + for (i = 0; i < short_data_block_length; i++) { + if (ddata[position + i] == '%') { + percent_count++; + } + } + } + + /* Character count indicator */ + bp = bin_append_posn(short_data_block_length + percent_count, qr_cci_bits(version, data_block), + binary, bp); + + if (debug_print) { + printf("Alpha block (length %d)\n\t", short_data_block_length + percent_count); + } + + /* Character representation */ + i = 0; + while (i < short_data_block_length) { + int count; + int first = 0, second = 0, prod; + + if (percent == 0) { + if (gs1 && (ddata[position + i] == '%')) { + first = QR_PERCENT; + second = QR_PERCENT; + count = 2; + prod = (first * 45) + second; + i++; + } else { + if (gs1 && ddata[position + i] == '\x1D') { + first = QR_PERCENT; /* FNC1 */ + } else { + first = qr_alphanumeric[ddata[position + i] - 32]; + } + count = 1; + i++; + prod = first; + + if (i < short_data_block_length && mode[position + i] == 'A') { + if (gs1 && (ddata[position + i] == '%')) { + second = QR_PERCENT; + count = 2; + prod = (first * 45) + second; + percent = 1; + } else { + if (gs1 && ddata[position + i] == '\x1D') { + second = QR_PERCENT; /* FNC1 */ + } else { + second = qr_alphanumeric[ddata[position + i] - 32]; + } + count = 2; + i++; + prod = (first * 45) + second; + } + } + } + } else { + first = QR_PERCENT; + count = 1; + i++; + prod = first; + percent = 0; + + if (i < short_data_block_length && mode[position + i] == 'A') { + if (gs1 && (ddata[position + i] == '%')) { + second = QR_PERCENT; + count = 2; + prod = (first * 45) + second; + percent = 1; + } else { + if (gs1 && ddata[position + i] == '\x1D') { + second = QR_PERCENT; /* FNC1 */ + } else { + second = qr_alphanumeric[ddata[position + i] - 32]; + } + count = 2; + i++; + prod = (first * 45) + second; + } + } + } + + bp = bin_append_posn(prod, 1 + (5 * count), binary, bp); + + if (debug_print) { + printf("0x%X ", prod); + } + } + + if (debug_print) { + fputc('\n', stdout); + } + + break; + case 'N': + /* Numeric mode */ + + /* Character count indicator */ + bp = bin_append_posn(short_data_block_length, qr_cci_bits(version, data_block), binary, bp); + + if (debug_print) { + printf("Number block (length %d)\n\t", short_data_block_length); + } + + /* Character representation */ + i = 0; + while (i < short_data_block_length) { + int count; + int first = 0, prod; + + first = ctoi((const char) ddata[position + i]); + count = 1; + prod = first; + + if (i + 1 < short_data_block_length && mode[position + i + 1] == 'N') { + int second = ctoi((const char) ddata[position + i + 1]); + count = 2; + prod = (prod * 10) + second; + + if (i + 2 < short_data_block_length && mode[position + i + 2] == 'N') { + int third = ctoi((const char) ddata[position + i + 2]); + count = 3; + prod = (prod * 10) + third; + } + } + + bp = bin_append_posn(prod, 1 + (3 * count), binary, bp); + + if (debug_print) { + printf("0x%X(%d) ", prod, prod); + } + + i += count; + }; + + if (debug_print) { + fputc('\n', stdout); + } + + break; + } + + position += short_data_block_length; + } while (position < length); + + return bp; +} + +/* Call `qr_binary()` for each segment, dealing with Structured Append and GS1 beforehand and padding afterwards */ +static int qr_binary_segs(unsigned char datastream[], const int version, const int target_codewords, + const char mode[], const unsigned int ddata[], const struct zint_seg segs[], const int seg_count, + const struct zint_structapp *p_structapp, const int gs1, const int est_binlen, const int debug_print) { + int i, j; + const unsigned int *dd = ddata; + const char *m = mode; + int bp = 0; + int termbits, padbits; + int current_bytes; + int toggle; + char *binary = (char *) z_alloca(est_binlen + 12); + + *binary = '\0'; + + if (p_structapp) { + bp = bin_append_posn(3, 4, binary, bp); /* Structured Append indicator */ + bp = bin_append_posn(p_structapp->index - 1, 4, binary, bp); + bp = bin_append_posn(p_structapp->count - 1, 4, binary, bp); + bp = bin_append_posn(to_int((const unsigned char *) p_structapp->id, (int) strlen(p_structapp->id)), 8, + binary, bp); /* Parity */ + } + + if (gs1) { /* Not applicable to MICROQR */ + if (version < RMQR_VERSION) { + bp = bin_append_posn(5, 4, binary, bp); /* FNC1 */ + } else { + bp = bin_append_posn(5, 3, binary, bp); + } + } + + for (i = 0; i < seg_count; i++) { + bp = qr_binary(binary, bp, version, m, dd, segs[i].length, gs1, segs[i].eci, debug_print); + m += segs[i].length; + dd += segs[i].length; + } + + if (version >= MICROQR_VERSION && version < MICROQR_VERSION + 4) { + /* MICROQR does its own terminating/padding */ + memcpy(datastream, binary, bp); + return bp; + } + + /* Terminator */ + termbits = 8 - bp % 8; + if (termbits == 8) { + termbits = 0; + } + current_bytes = (bp + termbits) / 8; + if (termbits || current_bytes < target_codewords) { + int max_termbits = qr_terminator_bits(version); + termbits = termbits < max_termbits && current_bytes == target_codewords ? termbits : max_termbits; + bp = bin_append_posn(0, termbits, binary, bp); + } + + /* Padding bits */ + padbits = 8 - bp % 8; + if (padbits == 8) { + padbits = 0; + } + if (padbits) { + current_bytes = (bp + padbits) / 8; + (void) bin_append_posn(0, padbits, binary, bp); /* Last use so not setting bp */ + } + + if (debug_print) printf("Terminated binary (%d): %.*s (padbits %d)\n", bp, bp, binary, padbits); + + /* Put data into 8-bit codewords */ + for (i = 0; i < current_bytes; i++) { + int p; + j = i * 8; + datastream[i] = 0x00; + for (p = 0; p < 8; p++) { + if (binary[j + p] == '1') { + datastream[i] |= (0x80 >> p); + } + } + } + + /* Add pad codewords */ + toggle = 0; + for (i = current_bytes; i < target_codewords; i++) { + if (toggle == 0) { + datastream[i] = 0xec; + toggle = 1; + } else { + datastream[i] = 0x11; + toggle = 0; + } + } + + if (debug_print) { + printf("Resulting codewords (%d):\n\t", target_codewords); + for (i = 0; i < target_codewords; i++) { + printf("0x%02X ", datastream[i]); + } + fputc('\n', stdout); + } + + return 0; /* Not used */ +} + +/* Split data into blocks, add error correction and then interleave the blocks and error correction data */ +static void qr_add_ecc(unsigned char fullstream[], const unsigned char datastream[], const int version, + const int data_cw, const int blocks, const int debug_print) { + int ecc_cw; + int short_data_block_length; + int qty_long_blocks; + int qty_short_blocks; + int ecc_block_length; + int i, j, length_this_block, in_posn; + rs_t rs; + unsigned char *data_block; + unsigned char *ecc_block; + unsigned char *interleaved_data; + unsigned char *interleaved_ecc; + + if (version < RMQR_VERSION) { + ecc_cw = qr_total_codewords[version - 1] - data_cw; + } else { + ecc_cw = rmqr_total_codewords[version - RMQR_VERSION] - data_cw; + } + + /* Suppress some clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult/uninitialized.Assign warnings */ + assert(blocks > 0); + + short_data_block_length = data_cw / blocks; + qty_long_blocks = data_cw % blocks; + qty_short_blocks = blocks - qty_long_blocks; + ecc_block_length = ecc_cw / blocks; + + /* Suppress some clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult/uninitialized.Assign warnings */ + assert(short_data_block_length > 0); + assert(qty_long_blocks || qty_short_blocks); + + data_block = (unsigned char *) z_alloca(short_data_block_length + 1); + ecc_block = (unsigned char *) z_alloca(ecc_block_length); + interleaved_data = (unsigned char *) z_alloca(data_cw); + interleaved_ecc = (unsigned char *) z_alloca(ecc_cw); + + rs_init_gf(&rs, 0x11d); + rs_init_code(&rs, ecc_block_length, 0); + + in_posn = 0; + + for (i = 0; i < blocks; i++) { + if (i < qty_short_blocks) { + length_this_block = short_data_block_length; + } else { + length_this_block = short_data_block_length + 1; + } + + for (j = 0; j < length_this_block; j++) { + /* This false-positive popped up with clang-tidy 14.0.1 */ + data_block[j] = datastream[in_posn + j]; /* NOLINT(clang-analyzer-core.uninitialized.Assign) */ + } + + rs_encode(&rs, length_this_block, data_block, ecc_block); + + if (debug_print) { + printf("Block %d: ", i + 1); + for (j = 0; j < length_this_block; j++) { + printf("%2X ", data_block[j]); + } + if (i < qty_short_blocks) { + fputs(" ", stdout); + } + fputs(" // ", stdout); + for (j = 0; j < ecc_block_length; j++) { + printf("%2X ", ecc_block[j]); + } + fputc('\n', stdout); + } + + for (j = 0; j < short_data_block_length; j++) { + /* And another with clang-tidy 14.0.6 */ + interleaved_data[(j * blocks) + i] = data_block[j]; /* NOLINT(clang-analyzer-core.uninitialized.Assign) */ + } + + if (i >= qty_short_blocks) { + interleaved_data[(short_data_block_length * blocks) + (i - qty_short_blocks)] + = data_block[short_data_block_length]; + } + + for (j = 0; j < ecc_block_length; j++) { + interleaved_ecc[(j * blocks) + i] = ecc_block[j]; + } + + in_posn += length_this_block; + } + + for (j = 0; j < data_cw; j++) { + fullstream[j] = interleaved_data[j]; + } + for (j = 0; j < ecc_cw; j++) { + fullstream[j + data_cw] = interleaved_ecc[j]; + } + + if (debug_print) { + printf("\nData Stream (%d): \n", data_cw + ecc_cw); + for (j = 0; j < (data_cw + ecc_cw); j++) { + printf("%2X ", fullstream[j]); + } + fputc('\n', stdout); + } +} + +static void qr_place_finder(unsigned char grid[], const int size, const int x, const int y) { + int xp, yp; + char finder[] = {0x7F, 0x41, 0x5D, 0x5D, 0x5D, 0x41, 0x7F}; + + for (xp = 0; xp < 7; xp++) { + for (yp = 0; yp < 7; yp++) { + if (finder[yp] & 0x40 >> xp) { + grid[((yp + y) * size) + (xp + x)] = 0x11; + } else { + grid[((yp + y) * size) + (xp + x)] = 0x10; + } + } + } +} + +static void qr_place_align(unsigned char grid[], const int size, int x, int y) { + int xp, yp; + char alignment[] = {0x1F, 0x11, 0x15, 0x11, 0x1F}; + + x -= 2; + y -= 2; /* Input values represent centre of pattern */ + + for (xp = 0; xp < 5; xp++) { + for (yp = 0; yp < 5; yp++) { + if (alignment[yp] & 0x10 >> xp) { + grid[((yp + y) * size) + (xp + x)] = 0x11; + } else { + grid[((yp + y) * size) + (xp + x)] = 0x10; + } + } + } +} + +static void qr_setup_grid(unsigned char *grid, const int size, const int version) { + int i, toggle = 1; + +/* Suppress false positive gcc >= 13 warning (when optimizing only) "writing 1 byte into a region of size 0" */ +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 13 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + + /* Add timing patterns */ + for (i = 0; i < size; i++) { + if (toggle == 1) { + grid[(6 * size) + i] = 0x21; + grid[(i * size) + 6] = 0x21; + toggle = 0; + } else { + grid[(6 * size) + i] = 0x20; + grid[(i * size) + 6] = 0x20; + toggle = 1; + } + } + + /* Add finder patterns */ + qr_place_finder(grid, size, 0, 0); + qr_place_finder(grid, size, 0, size - 7); + qr_place_finder(grid, size, size - 7, 0); + + /* Add separators */ + for (i = 0; i < 7; i++) { + grid[(7 * size) + i] = 0x10; + grid[(i * size) + 7] = 0x10; + grid[(7 * size) + (size - 1 - i)] = 0x10; + grid[(i * size) + (size - 8)] = 0x10; + grid[((size - 8) * size) + i] = 0x10; + grid[((size - 1 - i) * size) + 7] = 0x10; + } + grid[(7 * size) + 7] = 0x10; + grid[(7 * size) + (size - 8)] = 0x10; + grid[((size - 8) * size) + 7] = 0x10; + +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 13 +#pragma GCC diagnostic pop +#endif + + /* Add alignment patterns */ + if (version != 1) { + /* Version 1 does not have alignment patterns */ + + int loopsize = qr_align_loopsize[version - 1]; + int x, y; + for (x = 0; x < loopsize; x++) { + for (y = 0; y < loopsize; y++) { + int xcoord = qr_table_e1[((version - 2) * 7) + x]; + int ycoord = qr_table_e1[((version - 2) * 7) + y]; + + if (!(grid[(ycoord * size) + xcoord] & 0x10)) { + qr_place_align(grid, size, xcoord, ycoord); + } + } + } + } + + /* Reserve space for format information */ + for (i = 0; i < 8; i++) { + grid[(8 * size) + i] |= 0x20; + grid[(i * size) + 8] |= 0x20; + grid[(8 * size) + (size - 1 - i)] = 0x20; + grid[((size - 1 - i) * size) + 8] = 0x20; + } + grid[(8 * size) + 8] |= 0x20; + grid[((size - 1 - 7) * size) + 8] = 0x21; /* Dark Module from Figure 25 */ + + /* Reserve space for version information */ + if (version >= 7) { + for (i = 0; i < 6; i++) { + grid[((size - 9) * size) + i] = 0x20; + grid[((size - 10) * size) + i] = 0x20; + grid[((size - 11) * size) + i] = 0x20; + grid[(i * size) + (size - 9)] = 0x20; + grid[(i * size) + (size - 10)] = 0x20; + grid[(i * size) + (size - 11)] = 0x20; + } + } +} + +static int qr_cwbit(const unsigned char *fullstream, const int i) { + + if (fullstream[(i >> 3)] & (0x80 >> (i & 0x07))) { + return 1; + } + + return 0; +} + +static void qr_populate_grid(unsigned char *grid, const int h_size, const int v_size, const unsigned char *fullstream, + const int cw) { + const int not_rmqr = v_size == h_size; + const int x_start = h_size - (not_rmqr ? 2 : 3); /* For rMQR allow for righthand vertical timing pattern */ + int direction = 1; /* up */ + int row = 0; /* right hand side */ + + int i, n, y; + + n = cw * 8; + y = v_size - 1; + i = 0; + while (i < n) { + int x = x_start - (row * 2); + int r = y * h_size; + + if ((x < 6) && (not_rmqr)) + x--; /* skip over vertical timing pattern */ + + if (!(grid[r + (x + 1)] & 0xf0)) { + grid[r + (x + 1)] = qr_cwbit(fullstream, i); + i++; + } + + if (i < n) { + if (!(grid[r + x] & 0xf0)) { + grid[r + x] = qr_cwbit(fullstream, i); + i++; + } + } + + if (direction) { + y--; + if (y == -1) { + /* reached the top */ + row++; + y = 0; + direction = 0; + } + } else { + y++; + if (y == v_size) { + /* reached the bottom */ + row++; + y = v_size - 1; + direction = 1; + } + } + } +} + +#ifdef ZINTLOG +static void append_log(const unsigned char log) { + FILE *file; + + if ((file = fopen("zintlog.txt", "a+"))) { + fprintf(file, "%02X", log); + (void) fclose(file); + } +} + +static void write_log(const char log[]) { + FILE *file; + + if ((file = fopen("zintlog.txt", "a+"))) { + fprintf(file, "%s\n", log); /*writes*/ + (void) fclose(file); + } +} +#endif + +static int qr_evaluate(unsigned char *local, const int size) { + static const unsigned char h1011101[7] = { 1, 0, 1, 1, 1, 0, 1 }; + + int x, y, r, k, block; + int result = 0; + char state; + int dark_mods; + double percentage; + int a, b, afterCount, beforeCount; +#ifdef ZINTLOG + int result_b = 0; + char str[15]; +#endif + + /* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warnings */ + assert(size > 0); + +#ifdef ZINTLOG + /* bitmask output */ + for (y = 0; y < size; y++) { + for (x = 0; x < size; x++) { + append_log(local[(y * size) + x]); + } + write_log(""); + } +#endif + + /* Test 1: Adjacent modules in row/column in same colour */ + /* Vertical */ + for (x = 0; x < size; x++) { + block = 0; + state = 0; + for (y = 0; y < size; y++) { + if (local[(y * size) + x] == state) { + block++; + } else { + if (block >= 5) { + result += block - 2; + } + block = 1; + state = local[(y * size) + x]; + } + } + if (block >= 5) { + result += block - 2; + } + } + + /* Horizontal */ + dark_mods = 0; /* Count dark mods simultaneously (see Test 4 below) */ + for (y = 0; y < size; y++) { + r = y * size; + block = 0; + state = 0; + for (x = 0; x < size; x++) { + if (local[r + x] == state) { + block++; + } else { + if (block >= 5) { + result += block - 2; + } + block = 1; + state = local[r + x]; + } + if (state) { + dark_mods++; + } + } + if (block >= 5) { + result += block - 2; + } + } + +#ifdef ZINTLOG + /* output Test 1 */ + sprintf(str, "%d", result); + result_b = result; + write_log(str); +#endif + + /* Test 2: Block of modules in same color */ + for (x = 0; x < size - 1; x++) { + for (y = 0; y < size - 1; y++) { + k = local[(y * size) + x]; + if (((k == local[((y + 1) * size) + x]) && + (k == local[(y * size) + (x + 1)])) && + (k == local[((y + 1) * size) + (x + 1)])) { + result += 3; + } + } + } + +#ifdef ZINTLOG + /* output Test 2 */ + sprintf(str, "%d", result - result_b); + result_b = result; + write_log(str); +#endif + + /* Test 3: 1:1:3:1:1 ratio pattern in row/column */ + /* Vertical */ + for (x = 0; x < size; x++) { + for (y = 0; y <= (size - 7); y++) { + if (local[y * size + x] && !local[(y + 1) * size + x] && local[(y + 2) * size + x] && + local[(y + 3) * size + x] && local[(y + 4) * size + x] && + !local[(y + 5) * size + x] && local[(y + 6) * size + x]) { + /* Pattern found, check before and after */ + beforeCount = 0; + for (b = (y - 1); b >= (y - 4); b--) { + if (b < 0) { /* Count < edge as whitespace */ + beforeCount = 4; + break; + } + if (local[(b * size) + x]) { + break; + } + beforeCount++; + } + if (beforeCount == 4) { + /* Pattern is preceded by light area 4 modules wide */ + result += 40; + } else { + afterCount = 0; + for (a = (y + 7); a <= (y + 10); a++) { + if (a >= size) { /* Count > edge as whitespace */ + afterCount = 4; + break; + } + if (local[(a * size) + x]) { + break; + } + afterCount++; + } + if (afterCount == 4) { + /* Pattern is followed by light area 4 modules wide */ + result += 40; + } + } + y += 3; /* Skip to next possible match */ + } + } + } + + /* Horizontal */ + for (y = 0; y < size; y++) { + r = y * size; + for (x = 0; x <= (size - 7); x++) { + if (memcmp(local + r + x, h1011101, 7) == 0) { + /* Pattern found, check before and after */ + beforeCount = 0; + for (b = (x - 1); b >= (x - 4); b--) { + if (b < 0) { /* Count < edge as whitespace */ + beforeCount = 4; + break; + } + if (local[r + b]) { + break; + } + beforeCount++; + } + + if (beforeCount == 4) { + /* Pattern is preceded by light area 4 modules wide */ + result += 40; + } else { + afterCount = 0; + for (a = (x + 7); a <= (x + 10); a++) { + if (a >= size) { /* Count > edge as whitespace */ + afterCount = 4; + break; + } + if (local[r + a]) { + break; + } + afterCount++; + } + if (afterCount == 4) { + /* Pattern is followed by light area 4 modules wide */ + result += 40; + } + } + x += 3; /* Skip to next possible match */ + } + } + } + +#ifdef ZINTLOG + /* output Test 3 */ + sprintf(str, "%d", result - result_b); + result_b = result; + write_log(str); +#endif + + /* Test 4: Proportion of dark modules in entire symbol */ + percentage = (100.0 * dark_mods) / (size * size); + k = (int) (fabs(percentage - 50.0) / 5.0); + + result += 10 * k; + +#ifdef ZINTLOG + /* output Test 4+summary */ + sprintf(str, "%d", result - result_b); + write_log(str); + write_log("=========="); + sprintf(str, "%d", result); + write_log(str); +#endif + + return result; +} + +/* Add format information to grid */ +static void qr_add_format_info(unsigned char *grid, const int size, const int ecc_level, const int pattern) { + int format = pattern; + unsigned int seq; + int i; + + switch (ecc_level) { + case QR_LEVEL_L: format |= 0x08; + break; + case QR_LEVEL_Q: format |= 0x18; + break; + case QR_LEVEL_H: format |= 0x10; + break; + } + + seq = qr_annex_c[format]; + + for (i = 0; i < 6; i++) { + grid[(i * size) + 8] |= (seq >> i) & 0x01; + } + + for (i = 0; i < 8; i++) { + grid[(8 * size) + (size - i - 1)] |= (seq >> i) & 0x01; + } + + for (i = 0; i < 6; i++) { + grid[(8 * size) + (5 - i)] |= (seq >> (i + 9)) & 0x01; + } + + for (i = 0; i < 7; i++) { + grid[(((size - 7) + i) * size) + 8] |= (seq >> (i + 8)) & 0x01; + } + + grid[(7 * size) + 8] |= (seq >> 6) & 0x01; + grid[(8 * size) + 8] |= (seq >> 7) & 0x01; + grid[(8 * size) + 7] |= (seq >> 8) & 0x01; +} + +static int qr_apply_bitmask(unsigned char *grid, const int size, const int ecc_level, const int user_mask, + const int fast_encode, const int debug_print) { + int x, y; + int r, k; + int bit; + int pattern, penalty[8]; + int best_pattern; + int size_squared = size * size; + unsigned char *mask = (unsigned char *) z_alloca(size_squared); + unsigned char *local = (unsigned char *) z_alloca(size_squared); +#ifdef ZINTLOG + char str[15]; +#endif + + /* Perform data masking */ + memset(mask, 0, size_squared); + for (y = 0; y < size; y++) { + r = y * size; + for (x = 0; x < size; x++) { + + /* all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array. */ + if (!(grid[r + x] & 0xf0)) { /* exclude areas not to be masked. */ + if (((y + x) & 1) == 0) { + mask[r + x] |= 0x01; + } + if (!fast_encode) { + if ((y & 1) == 0) { + mask[r + x] |= 0x02; + } + } + if ((x % 3) == 0) { + mask[r + x] |= 0x04; + } + if (!fast_encode) { + if (((y + x) % 3) == 0) { + mask[r + x] |= 0x08; + } + } + if ((((y / 2) + (x / 3)) & 1) == 0) { + mask[r + x] |= 0x10; + } + if (!fast_encode) { + if ((y * x) % 6 == 0) { /* Equivalent to (y * x) % 2 + (y * x) % 3 == 0 */ + mask[r + x] |= 0x20; + } + if (((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { + mask[r + x] |= 0x40; + } + } + if (((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { + mask[r + x] |= 0x80; + } + } + } + } + + if (user_mask) { + best_pattern = user_mask - 1; + } else { + /* all eight bitmask variants have been encoded in the 8 bits of the bytes + * that make up the mask array. select them for evaluation according to the + * desired pattern.*/ + best_pattern = 0; + for (pattern = 0; pattern < 8; pattern++) { + if (fast_encode && pattern != 0 && pattern != 2 && pattern != 4 && pattern != 7) { + continue; + } + bit = 1 << pattern; + for (k = 0; k < size_squared; k++) { + if (mask[k] & bit) { + local[k] = grid[k] ^ 0x01; + } else { + local[k] = grid[k] & 0x0f; + } + } + qr_add_format_info(local, size, ecc_level, pattern); + + penalty[pattern] = qr_evaluate(local, size); + + if (penalty[pattern] < penalty[best_pattern]) { + best_pattern = pattern; + } + } + } + + if (debug_print) { + printf("Mask: %d (%s)", best_pattern, user_mask ? "specified" : fast_encode ? "fast automatic": "automatic"); + if (!user_mask) { + if (fast_encode) { + printf(" 0:%d 2:%d 4:%d 7:%d", penalty[0], penalty[2], penalty[4], penalty[7]); + } else { + for (pattern = 0; pattern < 8; pattern++) printf(" %d:%d", pattern, penalty[pattern]); + } + } + fputc('\n', stdout); + } + +#ifdef ZINTLOG + sprintf(str, "%d", best_pattern); + write_log("chose pattern:"); + write_log(str); +#endif + + /* Apply mask */ + if (!user_mask && best_pattern == 7) { /* Reuse last */ + memcpy(grid, local, size_squared); + } else { + bit = 1 << best_pattern; + for (y = 0; y < size_squared; y++) { + if (mask[y] & bit) { + grid[y] ^= 0x01; + } + } + } + + return best_pattern; +} + +/* Add version information */ +static void qr_add_version_info(unsigned char *grid, const int size, const int version) { + int i; + + unsigned int version_data = qr_annex_d[version - 7]; + for (i = 0; i < 6; i++) { + grid[((size - 11) * size) + i] |= (version_data >> (i * 3)) & 1; + grid[((size - 10) * size) + i] |= (version_data >> ((i * 3) + 1)) & 1; + grid[((size - 9) * size) + i] |= (version_data >> ((i * 3) + 2)) & 1; + grid[(i * size) + (size - 11)] |= (version_data >> (i * 3)) & 1; + grid[(i * size) + (size - 10)] |= (version_data >> ((i * 3) + 1)) & 1; + grid[(i * size) + (size - 9)] |= (version_data >> ((i * 3) + 2)) & 1; + } +} + +/* Find the length of the block starting from 'start' */ +static int qr_blockLength(const int start, const char mode[], const int length) { + int i; + int count = 0; + char start_mode = mode[start]; + + i = start; + + do { + count++; + } while (((i + count) < length) && (mode[i + count] == start_mode)); + + return count; +} + +/* Calculate the actual bitlength of the proposed binary string */ +static int qr_calc_binlen(const int version, char mode[], const unsigned int ddata[], const int length, + const int mode_preset, const int gs1, const int eci, const int debug_print) { + int i, j; + char currentMode; + int count = 0; + int alphalength; + int blocklength; + + if (!mode_preset) { + qr_define_mode(mode, ddata, length, gs1, version, debug_print); + } + + currentMode = ' '; /* Null */ + + if (eci != 0) { /* Not applicable to MICROQR */ + count += 4; + if (eci <= 127) { + count += 8; + } else if (eci <= 16383) { + count += 16; + } else { + count += 24; + } + } + + for (i = 0; i < length; i++) { + if (mode[i] != currentMode) { + count += qr_mode_bits(version) + qr_cci_bits(version, mode[i]); + blocklength = qr_blockLength(i, mode, length); + switch (mode[i]) { + case 'K': + count += (blocklength * 13); + break; + case 'B': + for (j = i; j < (i + blocklength); j++) { + if (ddata[j] > 0xff) { + count += 16; + } else { + count += 8; + } + } + break; + case 'A': + alphalength = blocklength; + if (gs1) { + /* In alphanumeric mode % becomes %% */ + for (j = i; j < (i + blocklength); j++) { + if (ddata[j] == '%') { + alphalength++; + } + } + } + switch (alphalength % 2) { + case 0: + count += (alphalength / 2) * 11; + break; + case 1: + count += ((alphalength - 1) / 2) * 11; + count += 6; + break; + } + break; + case 'N': + switch (blocklength % 3) { + case 0: + count += (blocklength / 3) * 10; + break; + case 1: + count += ((blocklength - 1) / 3) * 10; + count += 4; + break; + case 2: + count += ((blocklength - 2) / 3) * 10; + count += 7; + break; + } + break; + } + currentMode = mode[i]; + } + } + + return count; +} + +/* Call `qr_calc_binlen()` on each segment */ +static int qr_calc_binlen_segs(const int version, char mode[], const unsigned int ddata[], + const struct zint_seg segs[], const int seg_count, const struct zint_structapp *p_structapp, + const int mode_preset, const int gs1, const int debug_print) { + int i; + int count = 0; + const unsigned int *dd = ddata; + char *m = mode; + + if (p_structapp) { + count += 4 + 8 + 8; + } + + if (gs1) { /* Not applicable to MICROQR */ + if (version < RMQR_VERSION) { + count += 4; + } else { + count += 3; + } + } + + for (i = 0; i < seg_count; i++) { + count += qr_calc_binlen(version, m, dd, segs[i].length, mode_preset, gs1, segs[i].eci, debug_print); + m += segs[i].length; + dd += segs[i].length; + } + + if (debug_print) { + printf("Estimated Binary Length: %d (version %d, gs1 %d)\n", count, version, gs1); + } + + return count; +} + +/* Helper to process source data into `ddata` array */ +static int qr_prep_data(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count, + unsigned int ddata[]) { + int warn_number = 0; + int i; + /* If ZINT_FULL_MULTIBYTE use Kanji mode in DATA_MODE or for non-Shift JIS in UNICODE_MODE */ + const int full_multibyte = (symbol->option_3 & 0xFF) == ZINT_FULL_MULTIBYTE; + + if ((symbol->input_mode & 0x07) == DATA_MODE) { + sjis_cpy_segs(segs, seg_count, ddata, full_multibyte); + } else { + unsigned int *dd = ddata; + for (i = 0; i < seg_count; i++) { + int done = 0; + if (segs[i].eci != 20 || seg_count > 1) { /* Unless ECI 20 (Shift JIS) or have multiple segments */ + /* Try other encodings (ECI 0 defaults to ISO/IEC 8859-1) */ + int error_number = sjis_utf8_to_eci(segs[i].eci, segs[i].source, &segs[i].length, dd, full_multibyte); + if (error_number == 0) { + done = 1; + } else if (segs[i].eci || seg_count > 1) { + return errtxtf(error_number, symbol, 575, "Invalid character in input for ECI '%d'", segs[i].eci); + } + } + if (!done) { + /* Try Shift-JIS */ + int error_number = sjis_utf8(symbol, segs[i].source, &segs[i].length, dd); + if (error_number != 0) { + return error_number; + } + if (segs[i].eci != 20) { + warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 760, + "Converted to Shift JIS but no ECI specified"); + } + } + dd += segs[i].length; + } + } + + return warn_number; +} + +INTERNAL int qrcode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { + int warn_number; + int i, j, est_binlen, prev_est_binlen; + int ecc_level, autosize, version, max_cw, target_codewords, blocks, size; + int bitmask; + int user_mask; + int canShrink; + int size_squared; + const struct zint_structapp *p_structapp = NULL; + const int gs1 = ((symbol->input_mode & 0x07) == GS1_MODE); + const int fast_encode = symbol->input_mode & FAST_MODE; + const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; + const int eci_length_segs = get_eci_length_segs(segs, seg_count); + struct zint_seg *local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * seg_count); + unsigned int *ddata = (unsigned int *) z_alloca(sizeof(unsigned int) * eci_length_segs); + char *mode = (char *) z_alloca(eci_length_segs); + char *prev_mode = (char *) z_alloca(eci_length_segs); + unsigned char *datastream; + unsigned char *fullstream; + unsigned char *grid; + + user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is pattern + 1, so >= 1 and <= 8 */ + if (user_mask > 8) { + user_mask = 0; /* Ignore */ + } + + segs_cpy(symbol, segs, seg_count, local_segs); /* Shallow copy (needed to set default ECIs & protect lengths) */ + + warn_number = qr_prep_data(symbol, local_segs, seg_count, ddata); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + + if (symbol->structapp.count) { + if (symbol->structapp.count < 2 || symbol->structapp.count > 16) { + return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 750, + "Structured Append count '%d' out of range (2 to 16)", symbol->structapp.count); + } + if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) { + return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 751, + "Structured Append index '%1$d' out of range (1 to count %2$d)", + symbol->structapp.index, symbol->structapp.count); + } + if (symbol->structapp.id[0]) { + int id, id_len; + + for (id_len = 1; id_len < 4 && symbol->structapp.id[id_len]; id_len++); + + if (id_len > 3) { /* Max value 255 */ + return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 752, + "Structured Append ID length %d too long (3 digit maximum)", id_len); + } + + id = to_int((const unsigned char *) symbol->structapp.id, id_len); + if (id == -1) { + return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 753, "Invalid Structured Append ID (digits only)"); + } + if (id > 255) { + return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 754, + "Structured Append ID value '%d' out of range (0 to 255)", id); + } + } + p_structapp = &symbol->structapp; + } + + /* GS1 General Specifications 22.0 section 5.7.3 says Structured Append and ECIs not supported + for GS1 QR Code so check and return ZINT_WARN_NONCOMPLIANT if either true */ + if (gs1 && warn_number == 0) { + for (i = 0; i < seg_count; i++) { + if (local_segs[i].eci) { + warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 755, + "Using ECI in GS1 mode not supported by GS1 standards"); + break; + } + } + if (warn_number == 0 && p_structapp) { + warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 756, + "Using Structured Append in GS1 mode not supported by GS1 standards"); + } + } + + est_binlen = qr_calc_binlen_segs(40, mode, ddata, local_segs, seg_count, p_structapp, 0 /*mode_preset*/, gs1, + debug_print); + + if ((symbol->option_1 >= 1) && (symbol->option_1 <= 4)) { + ecc_level = symbol->option_1 - 1; + } else { + ecc_level = QR_LEVEL_L; + } + max_cw = qr_data_codewords[ecc_level][39]; + + if (est_binlen > (8 * max_cw)) { + if (ecc_level == QR_LEVEL_L) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 567, "Input too long, requires %1$d codewords (maximum %2$d)", + (est_binlen + 7) / 8, max_cw); + } + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 561, + "Input too long for ECC level %1$c, requires %2$d codewords (maximum %3$d)", + qr_ecc_level_names[ecc_level], (est_binlen + 7) / 8, max_cw); + } + + autosize = 40; + for (i = 39; i >= 0; i--) { + if ((8 * qr_data_codewords[ecc_level][i]) >= est_binlen) { + autosize = i + 1; + } + } + if (autosize != 40) { + /* Save version 40 estimate in case incorrect costings in `qr_define_mode()` lead to its `mode` being better + than current lower version one */ + prev_est_binlen = est_binlen; + est_binlen = qr_calc_binlen_segs(autosize, mode, ddata, local_segs, seg_count, p_structapp, 0 /*mode_preset*/, + gs1, debug_print); + if (prev_est_binlen < est_binlen) { /* Shouldn't happen */ + assert(0); /* Not reached (hopefully) */ + /* Defensively use version 40 `mode` to avoid crashes (ticket #300) */ + est_binlen = qr_calc_binlen_segs(40, mode, ddata, local_segs, seg_count, p_structapp, 0 /*mode_preset*/, + gs1, debug_print); + assert(est_binlen == prev_est_binlen); + } + } + + /* Now see if the optimised binary will fit in a smaller symbol. */ + canShrink = 1; + + do { + if (autosize == 1) { + canShrink = 0; + } else { + prev_est_binlen = est_binlen; + memcpy(prev_mode, mode, eci_length_segs); + est_binlen = qr_calc_binlen_segs(autosize - 1, mode, ddata, local_segs, seg_count, p_structapp, + 0 /*mode_preset*/, gs1, debug_print); + + if ((8 * qr_data_codewords[ecc_level][autosize - 2]) < est_binlen) { + canShrink = 0; + } + + if (canShrink == 1) { + /* Optimisation worked - data will fit in a smaller symbol */ + autosize--; + } else { + /* Data did not fit in the smaller symbol, revert to original size */ + est_binlen = prev_est_binlen; + memcpy(mode, prev_mode, eci_length_segs); + } + } + } while (canShrink == 1); + + version = autosize; + + if ((symbol->option_2 >= 1) && (symbol->option_2 <= 40)) { + /* If the user has selected a larger symbol than the smallest available, + then use the size the user has selected, and re-optimise for this + symbol size. + */ + if (symbol->option_2 > version) { + version = symbol->option_2; + est_binlen = qr_calc_binlen_segs(symbol->option_2, mode, ddata, local_segs, seg_count, p_structapp, + 0 /*mode_preset*/, gs1, debug_print); + } + + if (symbol->option_2 < version) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 569, + "Input too long for Version %1$d-%2$c, requires %3$d codewords (maximum %4$d)", + symbol->option_2, qr_ecc_level_names[ecc_level], (est_binlen + 7) / 8, + qr_data_codewords[ecc_level][symbol->option_2 - 1]); + } + } + + /* Ensure maxium error correction capacity unless user-specified */ + if (symbol->option_1 == -1 || symbol->option_1 - 1 != ecc_level) { + if (est_binlen <= qr_data_codewords[QR_LEVEL_H][version - 1] * 8) { + ecc_level = QR_LEVEL_H; + } else if (est_binlen <= qr_data_codewords[QR_LEVEL_Q][version - 1] * 8) { + ecc_level = QR_LEVEL_Q; + } else if (est_binlen <= qr_data_codewords[QR_LEVEL_M][version - 1] * 8) { + ecc_level = QR_LEVEL_M; + } + } + + target_codewords = qr_data_codewords[ecc_level][version - 1]; + blocks = qr_blocks[ecc_level][version - 1]; + + if (debug_print) { + printf("Minimum codewords: %d\n", (est_binlen + 7) / 8); + printf("Selected version: %d-%c (%dx%d)\n", + version, qr_ecc_level_names[ecc_level], qr_sizes[version - 1], qr_sizes[version - 1]); + printf("Number of data codewords in symbol: %d\n", target_codewords); + printf("Number of ECC blocks: %d\n", blocks); + } + + datastream = (unsigned char *) z_alloca(target_codewords + 1); + fullstream = (unsigned char *) z_alloca(qr_total_codewords[version - 1] + 1); + + (void) qr_binary_segs(datastream, version, target_codewords, mode, ddata, local_segs, seg_count, p_structapp, gs1, + est_binlen, debug_print); +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords); +#endif + qr_add_ecc(fullstream, datastream, version, target_codewords, blocks, debug_print); + + size = qr_sizes[version - 1]; + size_squared = size * size; + + grid = (unsigned char *) z_alloca(size_squared); + memset(grid, 0, size_squared); + + qr_setup_grid(grid, size, version); + qr_populate_grid(grid, size, size, fullstream, qr_total_codewords[version - 1]); + + if (version >= 7) { + qr_add_version_info(grid, size, version); + } + + bitmask = qr_apply_bitmask(grid, size, ecc_level, user_mask, fast_encode, debug_print); + + qr_add_format_info(grid, size, ecc_level, bitmask); + + symbol->width = size; + symbol->rows = size; + + for (i = 0; i < size; i++) { + int r = i * size; + for (j = 0; j < size; j++) { + if (grid[r + j] & 0x01) { + set_module(symbol, i, j); + } + } + symbol->row_height[i] = 1; + } + symbol->height = size; + + return warn_number; +} + +/* Write terminator, padding & ECC */ +static int microqr_end(struct zint_symbol *symbol, char binary_data[], int bp, const int ecc_level, + const int version) { + int i, j; + int bits_left; + unsigned char data_blocks[17]; + unsigned char ecc_blocks[15]; + rs_t rs; + + const int terminator_bits = qr_terminator_bits(MICROQR_VERSION + version); + const int bits_total = microqr_data[ecc_level][version][0]; + const int data_codewords = microqr_data[ecc_level][version][1]; + const int ecc_codewords = microqr_data[ecc_level][version][2]; + const int bits_end = version == 0 || version == 2 ? 4 : 8; + + /* Add terminator */ + bits_left = bits_total - bp; + if (bits_left <= terminator_bits) { + if (bits_left) { + bp = bin_append_posn(0, bits_left, binary_data, bp); + bits_left = 0; + } + } else { + bp = bin_append_posn(0, terminator_bits, binary_data, bp); + bits_left -= terminator_bits; + } + + if (symbol->debug & ZINT_DEBUG_PRINT) { + printf("M%d Terminated binary (%d): %.*s (bits_left %d)\n", version + 1, bp, bp, binary_data, bits_left); + } + + /* Manage last (4-bit) block */ + if (bits_end == 4 && bits_left && bits_left <= 4) { + bp = bin_append_posn(0, bits_left, binary_data, bp); + bits_left = 0; + } + + if (bits_left) { + /* Complete current byte */ + int remainder = 8 - (bp % 8); + if (remainder != 8) { + bp = bin_append_posn(0, remainder, binary_data, bp); + bits_left -= remainder; + } + + /* Add padding */ + if (bits_end == 4 && bits_left > 4) { + bits_left -= 4; + } + remainder = bits_left / 8; + for (i = 0; i < remainder; i++) { + bp = bin_append_posn(i & 1 ? 0x11 : 0xEC, 8, binary_data, bp); + } + if (bits_end == 4) { + bp = bin_append_posn(0, 4, binary_data, bp); + } + } + assert((bp & 0x07) == 8 - bits_end); + + /* Copy data into codewords */ + for (i = 0; i < data_codewords; i++) { + const int bits = i + 1 == data_codewords ? bits_end : 8; + data_blocks[i] = 0; + + for (j = 0; j < bits; j++) { + if (binary_data[(i * 8) + j] == '1') { + data_blocks[i] |= 0x80 >> j; + } + } + } +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) { + char bp_buf[10]; + debug_test_codeword_dump(symbol, data_blocks, data_codewords); + sprintf(bp_buf, "%d", bp); /* Append `bp` to detect padding errors */ + errtxt_adj(0, symbol, "%s (%s)", bp_buf); + } +#endif + + /* Calculate Reed-Solomon error codewords */ + rs_init_gf(&rs, 0x11d); + rs_init_code(&rs, ecc_codewords, 0); + rs_encode(&rs, data_codewords, data_blocks, ecc_blocks); + + /* Add Reed-Solomon codewords to binary data */ + for (i = 0; i < ecc_codewords; i++) { + bp = bin_append_posn(ecc_blocks[i], 8, binary_data, bp); + } + + return bp; +} + +static void microqr_setup_grid(unsigned char *grid, const int size) { + int i, toggle = 1; + + /* Add timing patterns */ + for (i = 0; i < size; i++) { + if (toggle == 1) { + grid[i] = 0x21; + grid[(i * size)] = 0x21; + toggle = 0; + } else { + grid[i] = 0x20; + grid[(i * size)] = 0x20; + toggle = 1; + } + } + + /* Add finder patterns */ + qr_place_finder(grid, size, 0, 0); + + /* Add separators */ + for (i = 0; i < 7; i++) { + grid[(7 * size) + i] = 0x10; + grid[(i * size) + 7] = 0x10; + } + grid[(7 * size) + 7] = 0x10; + + + /* Reserve space for format information */ + for (i = 0; i < 8; i++) { + grid[(8 * size) + i] |= 0x20; + grid[(i * size) + 8] |= 0x20; + } + grid[(8 * size) + 8] |= 20; +} + +static void microqr_populate_grid(unsigned char *grid, const int size, const char full_stream[], int bp) { + int direction = 1; /* up */ + int row = 0; /* right hand side */ + int i; + int y; + + y = size - 1; + i = 0; + do { + int x = (size - 2) - (row * 2); + + if (!(grid[(y * size) + (x + 1)] & 0xf0)) { + if (full_stream[i] == '1') { + grid[(y * size) + (x + 1)] = 0x01; + } else { + grid[(y * size) + (x + 1)] = 0x00; + } + i++; + } + + if (i < bp) { + if (!(grid[(y * size) + x] & 0xf0)) { + if (full_stream[i] == '1') { + grid[(y * size) + x] = 0x01; + } else { + grid[(y * size) + x] = 0x00; + } + i++; + } + } + + if (direction) { + y--; + } else { + y++; + } + if (y == 0) { + /* reached the top */ + row++; + y = 1; + direction = 0; + } + if (y == size) { + /* reached the bottom */ + row++; + y = size - 1; + direction = 1; + } + } while (i < bp); +} + +static int microqr_evaluate(const unsigned char *grid, const int size, const int pattern) { + int sum1, sum2, i, filter = 0, retval; + + switch (pattern) { + case 0: filter = 0x01; + break; + case 1: filter = 0x02; + break; + case 2: filter = 0x04; + break; + case 3: filter = 0x08; + break; + } + + sum1 = 0; + sum2 = 0; + for (i = 1; i < size; i++) { + if (grid[(i * size) + size - 1] & filter) { + sum1++; + } + if (grid[((size - 1) * size) + i] & filter) { + sum2++; + } + } + + if (sum1 <= sum2) { + retval = (sum1 * 16) + sum2; + } else { + retval = (sum2 * 16) + sum1; + } + + return retval; +} + +static int microqr_apply_bitmask(unsigned char *grid, const int size, const int user_mask, const int debug_print) { + int x, y; + int r, k; + int bit; + int pattern, value[4]; + int best_pattern; + int size_squared = size * size; + unsigned char *mask = (unsigned char *) z_alloca(size_squared); + unsigned char *eval = (unsigned char *) z_alloca(size_squared); + + /* Perform data masking */ + memset(mask, 0, size_squared); + for (y = 0; y < size; y++) { + r = y * size; + for (x = 0; x < size; x++) { + + if (!(grid[r + x] & 0xf0)) { + if ((y & 1) == 0) { + mask[r + x] |= 0x01; + } + + if ((((y / 2) + (x / 3)) & 1) == 0) { + mask[r + x] |= 0x02; + } + + if (((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { + mask[r + x] |= 0x04; + } + + if (((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { + mask[r + x] |= 0x08; + } + } + } + } + + if (user_mask) { + best_pattern = user_mask - 1; + } else { + for (k = 0; k < size_squared; k++) { + if (grid[k] & 0x01) { + eval[k] = mask[k] ^ 0xff; + } else { + eval[k] = mask[k]; + } + } + + + /* Evaluate result */ + best_pattern = 0; + for (pattern = 0; pattern < 4; pattern++) { + value[pattern] = microqr_evaluate(eval, size, pattern); + if (value[pattern] > value[best_pattern]) { + best_pattern = pattern; + } + } + } + + if (debug_print) { + printf("Mask: %d (%s)", best_pattern, user_mask ? "specified" : "automatic"); + if (!user_mask) { + for (pattern = 0; pattern < 4; pattern++) printf(" %d:%d", pattern, value[pattern]); + } + fputc('\n', stdout); + } + + /* Apply mask */ + bit = 1 << best_pattern; + for (k = 0; k < size_squared; k++) { + if (mask[k] & bit) { + grid[k] ^= 0x01; + } + } + + return best_pattern; +} + +INTERNAL int microqr(struct zint_symbol *symbol, unsigned char source[], int length) { + int i, size, j; + char full_stream[200]; + int bp; + int full_multibyte; + int user_mask; + + unsigned int ddata[40]; + char mode[40]; + int alpha_used = 0, byte_or_kanji_used = 0; + int version_valid[4]; + int binary_count[4]; + int ecc_level, version; + int bitmask, format, format_full; + int size_squared; + struct zint_seg segs[1]; + const int seg_count = 1; + const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; + unsigned char *grid; + + if (length > 35) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 562, "Input length %d too long (maximum 35)", length); + } + + /* Check option 1 in combination with option 2 */ + ecc_level = QR_LEVEL_L; + if (symbol->option_1 >= 1 && symbol->option_1 <= 4) { + if (symbol->option_1 == 4) { + return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 566, "Error correction level H not available"); + } + if (symbol->option_2 >= 1 && symbol->option_2 <= 4) { + if (symbol->option_2 == 1 && symbol->option_1 != 1) { + return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 574, + "Version M1 supports error correction level L only"); + } + if (symbol->option_2 != 4 && symbol->option_1 == 3) { + return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 563, "Error correction level Q requires Version M4"); + } + } + ecc_level = symbol->option_1 - 1; + } + + /* If ZINT_FULL_MULTIBYTE use Kanji mode in DATA_MODE or for non-Shift JIS in UNICODE_MODE */ + full_multibyte = (symbol->option_3 & 0xFF) == ZINT_FULL_MULTIBYTE; + user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is pattern + 1, so >= 1 and <= 4 */ + if (user_mask > 4) { + user_mask = 0; /* Ignore */ + } + + if ((symbol->input_mode & 0x07) == DATA_MODE) { + sjis_cpy(source, &length, ddata, full_multibyte); + } else { + /* Try ISO 8859-1 conversion first */ + int error_number = sjis_utf8_to_eci(3, source, &length, ddata, full_multibyte); + if (error_number != 0) { + /* Try Shift-JIS */ + error_number = sjis_utf8(symbol, source, &length, ddata); + if (error_number != 0) { + return error_number; + } + } + } + + /* Determine if alpha (excluding numerics), byte or kanji used */ + for (i = 0; i < length && (alpha_used == 0 || byte_or_kanji_used == 0); i++) { + if (!z_isdigit(ddata[i])) { + if (qr_is_alpha(ddata[i], 0 /*gs1*/)) { + alpha_used = 1; + } else { + byte_or_kanji_used = 1; + } + } + } + + for (i = 0; i < 4; i++) { + version_valid[i] = 1; + } + + /* Eliminate possible versions depending on type of content */ + if (byte_or_kanji_used) { + version_valid[0] = 0; + version_valid[1] = 0; + } else if (alpha_used) { + version_valid[0] = 0; + } + + /* Eliminate possible versions depending on error correction level specified */ + if (ecc_level == QR_LEVEL_Q) { + version_valid[0] = 0; + version_valid[1] = 0; + version_valid[2] = 0; + } else if (ecc_level == QR_LEVEL_M) { + version_valid[0] = 0; + } + + segs[0].source = source; + segs[0].length = length; + segs[0].eci = 0; + + /* Determine length of binary data */ + for (i = 0; i < 4; i++) { + if (version_valid[i]) { + binary_count[i] = qr_calc_binlen_segs(MICROQR_VERSION + i, mode, ddata, segs, seg_count, + NULL /*p_structapp*/, 0 /*mode_preset*/, 0 /*gs1*/, debug_print); + } else { + binary_count[i] = 128 + 1; + } + } + + /* Eliminate possible versions depending on binary length and error correction level specified */ + if (binary_count[3] > microqr_data[ecc_level][3][0]) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 565, + "Input too long for Version M4-%1$c, requires %2$d codewords (maximum %3$d)", + qr_ecc_level_names[ecc_level], (binary_count[3] + 7) / 8, microqr_data[ecc_level][3][1]); + } + for (i = 0; i < 3; i++) { + if (binary_count[i] > microqr_data[ecc_level][i][0]) { + version_valid[i] = 0; + } + } + + /* Auto-select lowest valid size */ + version = 3; + if (version_valid[2]) { + version = 2; + } + if (version_valid[1]) { + version = 1; + } + if (version_valid[0]) { + version = 0; + } + + /* Get version from user */ + if ((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) { + if (symbol->option_2 == 1 && (i = not_sane(NEON_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 758, + "Invalid character at position %d in input for Version M1 (digits only)", i); + } else if (symbol->option_2 == 2 && not_sane(QR_ALPHA, source, length)) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 759, + "Invalid character in input for Version M2 (digits, A-Z, space and \"$%*+-./:\" only)"); + } + if (symbol->option_2 - 1 >= version) { + version = symbol->option_2 - 1; + } else { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 570, + "Input too long for Version M%1$d-%2$c, requires %3$d codewords (maximum %4$d)", + symbol->option_2, qr_ecc_level_names[ecc_level], (binary_count[version] + 7) / 8, + microqr_data[ecc_level][symbol->option_2 - 1][1]); + } + } + + /* If there is enough unused space then increase the error correction level, unless user-specified */ + if (version && (symbol->option_1 == -1 || symbol->option_1 - 1 != ecc_level)) { + if (binary_count[version] <= microqr_data[QR_LEVEL_Q][version][0]) { + ecc_level = QR_LEVEL_Q; + } else if (binary_count[version] <= microqr_data[QR_LEVEL_M][version][0]) { + ecc_level = QR_LEVEL_M; + } + } + + qr_define_mode(mode, ddata, length, 0 /*gs1*/, MICROQR_VERSION + version, debug_print); + + bp = qr_binary_segs((unsigned char *) full_stream, MICROQR_VERSION + version, 0 /*target_codewords*/, mode, ddata, + segs, seg_count, NULL /*p_structapp*/, 0 /*gs1*/, binary_count[version], debug_print); + + if (debug_print) printf("Binary (%d): %.*s\n", bp, bp, full_stream); + + bp = microqr_end(symbol, full_stream, bp, ecc_level, version); + + size = microqr_sizes[version]; + size_squared = size * size; + + grid = (unsigned char *) z_alloca(size_squared); + memset(grid, 0, size_squared); + + microqr_setup_grid(grid, size); + microqr_populate_grid(grid, size, full_stream, bp); + bitmask = microqr_apply_bitmask(grid, size, user_mask, debug_print); + + /* Add format data */ + format = version ? (version - 1) * 2 + ecc_level + 1 : 0; + + if (debug_print) { + printf("Version: M%d-%c, Size: %dx%d, Format: %d\n", + version + 1, qr_ecc_level_names[ecc_level], size, size, format); + } + + format_full = qr_annex_c1[(format << 2) + bitmask]; + + for (i = 1; i <= 8; i++) { + grid[(8 * size) + i] |= (format_full >> (15 - i)) & 0x01; + } + for (i = 7; i >= 1; i--) { + grid[(i * size) + 8] |= (format_full >> (i - 1)) & 0x01; + } + + symbol->width = size; + symbol->rows = size; + + for (i = 0; i < size; i++) { + for (j = 0; j < size; j++) { + if (grid[(i * size) + j] & 0x01) { + set_module(symbol, i, j); + } + } + symbol->row_height[i] = 1; + } + symbol->height = size; + + return 0; +} + +/* For UPNQR the symbol size and error correction capacity is fixed */ +INTERNAL int upnqr(struct zint_symbol *symbol, unsigned char source[], int length) { + int i, j, r, est_binlen; + int ecc_level, version, target_codewords, blocks, size; + int bitmask, error_number; + int user_mask; + int size_squared; + struct zint_seg segs[1]; + const int seg_count = 1; + const int fast_encode = symbol->input_mode & FAST_MODE; + const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; + unsigned char *datastream; + unsigned char *fullstream; + unsigned char *grid; + unsigned int *ddata = (unsigned int *) z_alloca(sizeof(unsigned int) * length); + char *mode = (char *) z_alloca(length + 1); + unsigned char *preprocessed = (unsigned char *) z_alloca(length + 1); + + symbol->eci = 4; /* Set before any processing */ + + user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is pattern + 1, so >= 1 and <= 8 */ + if (user_mask > 8) { + user_mask = 0; /* Ignore */ + } + + switch (symbol->input_mode & 0x07) { + case DATA_MODE: + /* Input is already in ISO-8859-2 format */ + for (i = 0; i < length; i++) { + ddata[i] = source[i]; + mode[i] = 'B'; + } + break; + case GS1_MODE: /* Should never happen as checked before being called */ + return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 571, + "UPNQR does not support GS1 data"); /* Not reached */ + break; + case UNICODE_MODE: + error_number = utf8_to_eci(4, source, preprocessed, &length); + if (error_number != 0) { + return errtxt(error_number, symbol, 572, "Invalid character in input for ECI '4'"); + } + for (i = 0; i < length; i++) { + ddata[i] = preprocessed[i]; + mode[i] = 'B'; + } + break; + } + + segs[0].source = source; + segs[0].length = length; + segs[0].eci = 4; + + est_binlen = qr_calc_binlen_segs(15, mode, ddata, segs, seg_count, NULL /*p_structapp*/, 1 /*mode_preset*/, + 0 /*gs1*/, debug_print); + + ecc_level = QR_LEVEL_M; + + if (est_binlen > 3320) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 573, "Input too long, requires %d codewords (maximum 415)", + (est_binlen + 7) / 8); + } + + version = 15; /* 77 x 77 */ + + target_codewords = qr_data_codewords[ecc_level][version - 1]; + blocks = qr_blocks[ecc_level][version - 1]; + + datastream = (unsigned char *) z_alloca(target_codewords + 1); + fullstream = (unsigned char *) z_alloca(qr_total_codewords[version - 1] + 1); + + (void) qr_binary_segs(datastream, version, target_codewords, mode, ddata, segs, seg_count, NULL /*p_structapp*/, + 0 /*gs1*/, est_binlen, debug_print); +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords); +#endif + qr_add_ecc(fullstream, datastream, version, target_codewords, blocks, debug_print); + + size = qr_sizes[version - 1]; + size_squared = size * size; + + grid = (unsigned char *) z_alloca(size_squared); + memset(grid, 0, size_squared); + + qr_setup_grid(grid, size, version); + qr_populate_grid(grid, size, size, fullstream, qr_total_codewords[version - 1]); + + qr_add_version_info(grid, size, version); + + bitmask = qr_apply_bitmask(grid, size, ecc_level, user_mask, fast_encode, debug_print); + + qr_add_format_info(grid, size, ecc_level, bitmask); + + symbol->width = size; + symbol->rows = size; + + for (i = 0; i < size; i++) { + r = i * size; + for (j = 0; j < size; j++) { + if (grid[r + j] & 0x01) { + set_module(symbol, i, j); + } + } + symbol->row_height[i] = 1; + } + symbol->height = size; + + return 0; +} + +static const char rmqr_version_names[38][8] = { + "R7x43", "R7x59", "R7x77", "R7x99", "R7x139", "R9x43", "R9x59", "R9x77", + "R9x99", "R9x139", "R11x27", "R11x43", "R11x59", "R11x77", "R11x99", "R11x139", + "R13x27", "R13x43", "R13x59", "R13x77", "R13x99", "R13x139", "R15x43", "R15x59", + "R15x77", "R15x99", "R15x139", "R17x43", "R17x59", "R17x77", "R17x99", "R17x139", + "R7xW", "R9xW", "R11xW", "R13xW", "R15xW", "R17xW", +}; + +static void rmqr_setup_grid(unsigned char *grid, const int h_size, const int v_size) { + int i, j; + char alignment[] = {0x1F, 0x11, 0x15, 0x11, 0x1F}; + int h_version, finder_position; + + /* Add timing patterns - top and bottom */ + for (i = 0; i < h_size; i++) { + if (i % 2) { + grid[i] = 0x20; + grid[((v_size - 1) * h_size) + i] = 0x20; + } else { + grid[i] = 0x21; + grid[((v_size - 1) * h_size) + i] = 0x21; + } + } + + /* Add timing patterns - left and right */ + for (i = 0; i < v_size; i++) { + if (i % 2) { + grid[i * h_size] = 0x20; + grid[(i * h_size) + (h_size - 1)] = 0x20; + } else { + grid[i * h_size] = 0x21; + grid[(i * h_size) + (h_size - 1)] = 0x21; + } + } + + /* Add finder pattern */ + qr_place_finder(grid, h_size, 0, 0); /* This works because finder is always top left */ + + /* Add finder sub-pattern to bottom right */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (alignment[j] & 0x10 >> i) { + grid[((v_size - 5) * h_size) + (h_size * i) + (h_size - 5) + j] = 0x11; + } else { + grid[((v_size - 5) * h_size) + (h_size * i) + (h_size - 5) + j] = 0x10; + } + } + } + + /* Add corner finder pattern - bottom left */ + grid[(v_size - 2) * h_size] = 0x11; + grid[((v_size - 2) * h_size) + 1] = 0x10; + grid[((v_size - 1) * h_size) + 1] = 0x11; + + /* Add corner finder pattern - top right */ + grid[h_size - 2] = 0x11; + grid[(h_size * 2) - 2] = 0x10; + grid[(h_size * 2) - 1] = 0x11; + + /* Add seperator */ + for (i = 0; i < 7; i++) { + grid[(i * h_size) + 7] = 0x20; + } + if (v_size > 7) { + /* Note for v_size = 9 this overrides the bottom right corner finder pattern */ + for (i = 0; i < 8; i++) { + grid[(7 * h_size) + i] = 0x20; + } + } + + /* Add alignment patterns */ + if (h_size > 27) { + h_version = 0; /* Suppress compiler warning [-Wmaybe-uninitialized] */ + for (i = 0; i < 5; i++) { + if (h_size == rmqr_width[i]) { + h_version = i; + break; + } + } + + for (i = 0; i < 4; i++) { + finder_position = rmqr_table_d1[(h_version * 4) + i]; + + if (finder_position != 0) { + for (j = 0; j < v_size; j++) { + if (j % 2) { + grid[(j * h_size) + finder_position] = 0x10; + } else { + grid[(j * h_size) + finder_position] = 0x11; + } + } + + /* Top square */ + grid[h_size + finder_position - 1] = 0x11; + grid[(h_size * 2) + finder_position - 1] = 0x11; + grid[h_size + finder_position + 1] = 0x11; + grid[(h_size * 2) + finder_position + 1] = 0x11; + + /* Bottom square */ + grid[(h_size * (v_size - 3)) + finder_position - 1] = 0x11; + grid[(h_size * (v_size - 2)) + finder_position - 1] = 0x11; + grid[(h_size * (v_size - 3)) + finder_position + 1] = 0x11; + grid[(h_size * (v_size - 2)) + finder_position + 1] = 0x11; + } + } + } + + /* Reserve space for format information */ + for (i = 0; i < 5; i++) { + for (j = 0; j < 3; j++) { + grid[(h_size * (i + 1)) + j + 8] = 0x20; + grid[(h_size * (v_size - 6)) + (h_size * i) + j + (h_size - 8)] = 0x20; + } + } + grid[(h_size * 1) + 11] = 0x20; + grid[(h_size * 2) + 11] = 0x20; + grid[(h_size * 3) + 11] = 0x20; + grid[(h_size * (v_size - 6)) + (h_size - 5)] = 0x20; + grid[(h_size * (v_size - 6)) + (h_size - 4)] = 0x20; + grid[(h_size * (v_size - 6)) + (h_size - 3)] = 0x20; +} + +/* rMQR according to 2018 draft standard */ +INTERNAL int rmqr(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { + int warn_number; + int i, j, est_binlen; + int ecc_level, autosize, version, max_cw, target_codewords, blocks, h_size, v_size; + int footprint, best_footprint, format_data; + unsigned int left_format_info, right_format_info; + const int gs1 = ((symbol->input_mode & 0x07) == GS1_MODE); + const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; + const int eci_length_segs = get_eci_length_segs(segs, seg_count); + struct zint_seg *local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * seg_count); + unsigned int *ddata = (unsigned int *) z_alloca(sizeof(unsigned int) * eci_length_segs); + char *mode = (char *) z_alloca(eci_length_segs); + unsigned char *datastream; + unsigned char *fullstream; + unsigned char *grid; + + if (symbol->option_1 == 1) { + return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 576, "Error correction level L not available in rMQR"); + } + if (symbol->option_1 == 3) { + return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 577, "Error correction level Q not available in rMQR"); + } + + if ((symbol->option_2 < 0) || (symbol->option_2 > 38)) { + return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 579, "Version '%d' out of range (1 to 38)", + symbol->option_2); + } + + segs_cpy(symbol, segs, seg_count, local_segs); + + warn_number = qr_prep_data(symbol, local_segs, seg_count, ddata); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + + /* GS1 General Specifications 22.0 section 5.7.3 says ECIs not supported + for GS1 QR Code so check and return ZINT_WARN_NONCOMPLIANT if true */ + if (gs1 && warn_number == 0) { + for (i = 0; i < seg_count; i++) { + if (local_segs[i].eci) { + warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 757, + "Using ECI in GS1 mode not supported by GS1 standards"); + break; + } + } + } + + est_binlen = qr_calc_binlen_segs(RMQR_VERSION + 31, mode, ddata, local_segs, seg_count, NULL /*p_structapp*/, + 0 /*mode_preset*/, gs1, debug_print); + + ecc_level = symbol->option_1 == 4 ? QR_LEVEL_H : QR_LEVEL_M; + max_cw = rmqr_data_codewords[ecc_level >> 1][31]; + + if (est_binlen > (8 * max_cw)) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 578, + "Input too long for ECC level %1$c, requires %2$d codewords (maximum %3$d)", + qr_ecc_level_names[ecc_level], (est_binlen + 7) / 8, max_cw); + } + + version = 31; /* Set default to keep compiler happy */ + + if (symbol->option_2 == 0) { + /* Automatic symbol size */ + autosize = 31; + best_footprint = rmqr_height[31] * rmqr_width[31]; + for (version = 30; version >= 0; version--) { + est_binlen = qr_calc_binlen_segs(RMQR_VERSION + version, mode, ddata, local_segs, seg_count, + NULL /*p_structapp*/, 0 /*mode_preset*/, gs1, debug_print); + footprint = rmqr_height[version] * rmqr_width[version]; + if (8 * rmqr_data_codewords[ecc_level >> 1][version] >= est_binlen) { + if (footprint < best_footprint) { + autosize = version; + best_footprint = footprint; + } + } + } + version = autosize; + est_binlen = qr_calc_binlen_segs(RMQR_VERSION + version, mode, ddata, local_segs, seg_count, + NULL /*p_structapp*/, 0 /*mode_preset*/, gs1, debug_print); + } + + if ((symbol->option_2 >= 1) && (symbol->option_2 <= 32)) { + /* User specified symbol size */ + version = symbol->option_2 - 1; + est_binlen = qr_calc_binlen_segs(RMQR_VERSION + version, mode, ddata, local_segs, seg_count, + NULL /*p_structapp*/, 0 /*mode_preset*/, gs1, debug_print); + } + + if (symbol->option_2 >= 33) { + /* User has specified symbol height only */ + version = rmqr_fixed_height_upper_bound[symbol->option_2 - 32]; + for (i = version - 1; i > rmqr_fixed_height_upper_bound[symbol->option_2 - 33]; i--) { + est_binlen = qr_calc_binlen_segs(RMQR_VERSION + i, mode, ddata, local_segs, seg_count, + NULL /*p_structapp*/, 0 /*mode_preset*/, gs1, debug_print); + if (8 * rmqr_data_codewords[ecc_level >> 1][i] >= est_binlen) { + version = i; + } + } + est_binlen = qr_calc_binlen_segs(RMQR_VERSION + version, mode, ddata, local_segs, seg_count, + NULL /*p_structapp*/, 0 /*mode_preset*/, gs1, debug_print); + } + + if (symbol->option_1 == -1) { + /* Detect if there is enough free space to increase ECC level */ + if (est_binlen < rmqr_data_codewords[QR_LEVEL_H >> 1][version] * 8) { + ecc_level = QR_LEVEL_H; + } + } + + target_codewords = rmqr_data_codewords[ecc_level >> 1][version]; + blocks = rmqr_blocks[ecc_level >> 1][version]; + + if (est_binlen > (target_codewords * 8)) { + /* User has selected a symbol too small for the data */ + assert(symbol->option_2 > 0); + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 560, + "Input too long for Version %1$d %2$s-%3$c, requires %4$d codewords (maximum %5$d)", + symbol->option_2, rmqr_version_names[symbol->option_2 - 1], qr_ecc_level_names[ecc_level], + (est_binlen + 7) / 8, target_codewords); + } + + if (debug_print) { + printf("Minimum codewords: %d\n", (est_binlen + 7) / 8); + printf("Selected version: %d = R%dx%d-%c\n", + (version + 1), rmqr_height[version], rmqr_width[version], qr_ecc_level_names[ecc_level]); + printf("Number of data codewords in symbol: %d\n", target_codewords); + printf("Number of ECC blocks: %d\n", blocks); + } + + datastream = (unsigned char *) z_alloca(target_codewords + 1); + fullstream = (unsigned char *) z_alloca(rmqr_total_codewords[version] + 1); + + (void) qr_binary_segs(datastream, RMQR_VERSION + version, target_codewords, mode, ddata, local_segs, seg_count, + NULL /*p_structapp*/, gs1, est_binlen, debug_print); +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords); +#endif + qr_add_ecc(fullstream, datastream, RMQR_VERSION + version, target_codewords, blocks, debug_print); + + h_size = rmqr_width[version]; + v_size = rmqr_height[version]; + + grid = (unsigned char *) z_alloca(h_size * v_size); + memset(grid, 0, h_size * v_size); + + rmqr_setup_grid(grid, h_size, v_size); + qr_populate_grid(grid, h_size, v_size, fullstream, rmqr_total_codewords[version]); + + /* apply bitmask */ + for (i = 0; i < v_size; i++) { + int r = i * h_size; + for (j = 0; j < h_size; j++) { + if ((grid[r + j] & 0xf0) == 0) { + /* This is a data module */ + if (((i / 2) + (j / 3)) % 2 == 0) { /* < This is the data mask from section 7.8.2 */ + /* This module needs to be changed */ + grid[r + j] ^= 0x01; + } + } + } + } + + /* add format information */ + format_data = version; + if (ecc_level == QR_LEVEL_H) { + format_data += 32; + } + left_format_info = rmqr_format_info_left[format_data]; + right_format_info = rmqr_format_info_right[format_data]; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 3; j++) { + grid[(h_size * (i + 1)) + j + 8] = (left_format_info >> ((j * 5) + i)) & 0x01; + grid[(h_size * (v_size - 6)) + (h_size * i) + j + (h_size - 8)] + = (right_format_info >> ((j * 5) + i)) & 0x01; + } + } + grid[(h_size * 1) + 11] = (left_format_info >> 15) & 0x01; + grid[(h_size * 2) + 11] = (left_format_info >> 16) & 0x01; + grid[(h_size * 3) + 11] = (left_format_info >> 17) & 0x01; + grid[(h_size * (v_size - 6)) + (h_size - 5)] = (right_format_info >> 15) & 0x01; + grid[(h_size * (v_size - 6)) + (h_size - 4)] = (right_format_info >> 16) & 0x01; + grid[(h_size * (v_size - 6)) + (h_size - 3)] = (right_format_info >> 17) & 0x01; + + symbol->width = h_size; + symbol->rows = v_size; + + for (i = 0; i < v_size; i++) { + int r = i * h_size; + for (j = 0; j < h_size; j++) { + if (grid[r + j] & 0x01) { + set_module(symbol, i, j); + } + } + symbol->row_height[i] = 1; + } + symbol->height = v_size; + + return warn_number; +} + +/* vim: set ts=4 sw=4 et : */
