#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
#define RMQR_VERSION 41
#define MICROQR_VERSION 73
static int qr_is_alpha(const unsigned int glyph, const int gs1) {
if (z_is_chr(QR_ALPHA, glyph)) {
return 1;
}
if (gs1 && glyph == '\x1D') {
return 1;
}
return 0;
}
#define QR_MULT 6
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;
}
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 : digit_cnt == 2 ? 21 : 20 ;
return 1;
}
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;
if (in_posn < (int) *p_end) {
if (gs1) {
if (*p_pcent) {
two_alphas = !last && qr_is_alpha(ddata[in_posn + 1], gs1);
*p_cost = two_alphas || !(*p_pccnt & 1) ? 66 : 69 ;
*p_pcent = 0;
} else {
*p_cost = !last || !(*p_pccnt & 1) ? 33 : 36 ;
}
} else {
*p_cost = !last ? 33 : 36 ;
}
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] == '%') {
*p_end = in_posn + 1;
*p_pcent = 0;
(*p_pccnt)++;
*p_cost = two_alphas || !(*p_pccnt & 1) ? 66 : 69 ;
return 1;
}
*p_end = two_alphas ? in_posn + 2 : in_posn + 1;
if (gs1) {
*p_pcent = two_alphas && ddata[in_posn + 1] == '%';
*p_pccnt += *p_pcent;
*p_cost = two_alphas || !(*p_pccnt & 1) ? 33 : 36 ;
} else {
*p_cost = two_alphas ? 33 : 36 ;
}
return 1;
}
#if 0#endif
#define QR_N 0
#define QR_A 1
#define QR_B 2
#define QR_K 3
static const char qr_mode_types[] = { 'N', 'A', 'B', 'K', '\0' };
#define QR_NUM_MODES 4
#define QR_VER 4
#define QR_N_END 5
#define QR_N_COST 6
#define QR_A_END 7
#define QR_A_COST 8
#define QR_A_PCENT 9
#define QR_A_PCCNT 10
#define QR_MICROQR_MAX 774
static unsigned int *qr_head_costs(unsigned int state[11]) {
static const unsigned int head_costs[7][QR_NUM_MODES] = {
{ (10 + 4) * QR_MULT, (9 + 4) * QR_MULT, (8 + 4) * QR_MULT, (8 + 4) * QR_MULT, },
{ (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, },
{ (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;
version = state[QR_VER];
if (version < RMQR_VERSION) {
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) {
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 {
memcpy(state, head_costs[3 + (version - MICROQR_VERSION)], QR_NUM_MODES * sizeof(unsigned int));
}
return state;
}
static void qr_define_modes(char modes[], const unsigned int ddata[], const int length, const int gs1,
const int version, const int debug_print) {
unsigned int state[11] = {
0 , 0 , 0 , 0 ,
0 ,
0 , 0 , 0 , 0 , 0 , 0
};
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;
memset(char_modes, 0, QR_NUM_MODES * length);
memcpy(prev_costs, qr_head_costs(state), QR_NUM_MODES * sizeof(unsigned int));
#ifdef QR_DEBUG_DEFINE_MODES
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
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);
char_modes[i][QR_B] = 'B';
cur_costs[QR_K] = prev_costs[QR_K] + ((m1 || m2) ? QR_MICROQR_MAX : 78);
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);
char_modes[i][QR_B] = 'B';
}
for (j = 0; j < QR_NUM_MODES; j++) {
for (k = 0; k < QR_NUM_MODES; k++) {
if (j != k && char_modes[i][k]) {
const unsigned int new_cost = cur_costs[k] + state[j];
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_MODES
{
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));
}
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];
}
}
for (i = length - 1; i >= 0; i--) {
j = z_posn(qr_mode_types, cur_mode);
cur_mode = char_modes[i][j];
modes[i] = cur_mode;
}
if (debug_print) {
printf(" Modes: %.*s\n", length, modes);
}
}
static int qr_mode_indicator(const int version, const int mode) {
static const char mode_indicators[6][QR_NUM_MODES] = {
{ 1, 2, 4, 8, },
{ 1, 2, 3, 4, },
{ 0, 0, 0, 0, },
{ 0, 1, 0, 0, },
{ 0, 1, 2, 3, },
{ 0, 1, 2, 3, },
};
int mode_index = z_posn(qr_mode_types, (const char) mode);
if (version < RMQR_VERSION) {
return mode_indicators[0][mode_index];
}
if (version < MICROQR_VERSION) {
return mode_indicators[1][mode_index] ;
}
return mode_indicators[2 + version - MICROQR_VERSION][mode_index];
}
static int qr_mode_bits(const int version) {
if (version < RMQR_VERSION) {
return 4;
}
if (version < MICROQR_VERSION) {
return 3;
}
return version - MICROQR_VERSION;
}
static int qr_cci_bits(const int version, const int mode) {
static const char cci_bits[7][QR_NUM_MODES] = {
{ 10, 9, 8, 8, },
{ 12, 11, 16, 10, },
{ 14, 13, 16, 12, },
{ 3, 0, 0, 0, },
{ 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 = z_posn(qr_mode_types, (const char) mode);
if (version < RMQR_VERSION) {
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) {
return rmqr_ccis[mode_index][version - RMQR_VERSION];
}
return cci_bits[3 + (version - MICROQR_VERSION)][mode_index];
}
static int qr_terminator_bits(const int version) {
if (version < RMQR_VERSION) {
return 4;
}
if (version < MICROQR_VERSION) {
return 3;
}
return 3 + (version - MICROQR_VERSION) * 2;
}
static int qr_binary(char binary[], int bp, const int version, const char modes[],
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) {
bp = z_bin_append_posn(7, version < RMQR_VERSION ? 4 : 3, binary, bp);
if (eci <= 127) {
bp = z_bin_append_posn(eci, 8, binary, bp);
} else if (eci <= 16383) {
bp = z_bin_append_posn(0x8000 + eci, 16, binary, bp);
} else {
bp = z_bin_append_posn(0xC00000 + eci, 24, binary, bp);
}
}
modebits = qr_mode_bits(version);
do {
const char block_mode = modes[position];
int block_length = 0;
int double_byte = 0;
do {
if (block_mode == 'B' && ddata[position + block_length] > 0xFF) {
double_byte++;
}
block_length++;
} while (position + block_length < length && modes[position + block_length] == block_mode);
if (modebits) {
bp = z_bin_append_posn(qr_mode_indicator(version, block_mode), modebits, binary, bp);
}
switch (block_mode) {
case 'K':
bp = z_bin_append_posn(block_length, qr_cci_bits(version, block_mode), binary, bp);
if (debug_print) {
printf("Kanji block (length %d)\n\t", block_length);
}
for (i = 0; i < 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 = z_bin_append_posn(prod, 13, binary, bp);
if (debug_print) {
printf("0x%04X ", prod);
}
}
if (debug_print) {
fputc('\n', stdout);
}
break;
case 'B':
bp = z_bin_append_posn(block_length + double_byte, qr_cci_bits(version, block_mode), binary, bp);
if (debug_print) {
printf("Byte block (length %d)\n\t", block_length + double_byte);
}
for (i = 0; i < block_length; i++) {
unsigned int byte = ddata[position + i];
bp = z_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':
percent_count = 0;
if (gs1) {
for (i = 0; i < block_length; i++) {
if (ddata[position + i] == '%') {
percent_count++;
}
}
}
bp = z_bin_append_posn(block_length + percent_count, qr_cci_bits(version, block_mode), binary, bp);
if (debug_print) {
printf("Alpha block (length %d)\n\t", block_length + percent_count);
}
i = 0;
while (i < 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;
} else {
first = qr_alphanumeric[ddata[position + i] - 32];
}
count = 1;
i++;
prod = first;
if (i < block_length && modes[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;
} 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 < block_length && modes[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;
} else {
second = qr_alphanumeric[ddata[position + i] - 32];
}
count = 2;
i++;
prod = (first * 45) + second;
}
}
}
bp = z_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':
bp = z_bin_append_posn(block_length, qr_cci_bits(version, block_mode), binary, bp);
if (debug_print) {
printf("Number block (length %d)\n\t", block_length);
}
i = 0;
while (i < block_length) {
int count;
int first = 0, prod;
first = z_ctoi((const char) ddata[position + i]);
count = 1;
prod = first;
if (i + 1 < block_length && modes[position + i + 1] == 'N') {
int second = z_ctoi((const char) ddata[position + i + 1]);
count = 2;
prod = (prod * 10) + second;
if (i + 2 < block_length && modes[position + i + 2] == 'N') {
int third = z_ctoi((const char) ddata[position + i + 2]);
count = 3;
prod = (prod * 10) + third;
}
}
bp = z_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 += block_length;
} while (position < length);
return bp;
}
static int qr_binary_segs(unsigned char datastream[], const int version, const int target_codewords,
const char modes[], 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 *mds = modes;
int bp = 0;
int termbits, padbits;
int current_bytes;
int toggle;
char *binary = (char *) z_alloca(est_binlen + 12);
assert(seg_count > 0);
*binary = '\0';
if (p_structapp) {
bp = z_bin_append_posn(3, 4, binary, bp);
bp = z_bin_append_posn(p_structapp->index - 1, 4, binary, bp);
bp = z_bin_append_posn(p_structapp->count - 1, 4, binary, bp);
bp = z_bin_append_posn(z_to_int(ZCUCP(p_structapp->id), (int) strlen(p_structapp->id)), 8, binary,
bp);
}
if (gs1) {
if (version < RMQR_VERSION) {
bp = z_bin_append_posn(5, 4, binary, bp);
} else {
bp = z_bin_append_posn(5, 3, binary, bp);
}
}
for (i = 0; i < seg_count; i++) {
bp = qr_binary(binary, bp, version, mds, dd, segs[i].length, gs1, segs[i].eci, debug_print);
mds += segs[i].length;
dd += segs[i].length;
}
if (version >= MICROQR_VERSION && version < MICROQR_VERSION + 4) {
memcpy(datastream, binary, bp);
return bp;
}
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 = z_bin_append_posn(0, termbits, binary, bp);
}
padbits = 8 - bp % 8;
if (padbits == 8) {
padbits = 0;
}
if (padbits) {
current_bytes = (bp + padbits) / 8;
(void) z_bin_append_posn(0, padbits, binary, bp);
}
if (debug_print) printf("Terminated binary (%d): %.*s (padbits %d)\n", bp, bp, binary, padbits);
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);
}
}
}
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;
}
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_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;
}
assert(blocks > 0);
short_data_block_length = data_cw / blocks;
qty_short_blocks = blocks - data_cw % blocks;
ecc_block_length = ecc_cw / blocks;
assert(data_cw > 0);
assert(short_data_block_length >= 1 && short_data_block_length <= 122);
assert(qty_short_blocks > 0);
assert(ecc_block_length > 0);
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);
zint_rs_init_gf(&rs, 0x11d);
zint_rs_init_code(&rs, ecc_block_length, 0);
in_posn = 0;
for (i = 0; i < blocks; i++) {
length_this_block = short_data_block_length + (i >= qty_short_blocks);
for (j = 0; j < length_this_block; j++) {
data_block[j] = datastream[in_posn + j];
}
zint_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++) {
interleaved_data[(j * blocks) + i] = data_block[j];
}
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++) {
grid[((yp + y) * size) + (xp + x)] = 0x10 + !!(finder[yp] & (0x40 >> xp));
}
}
}
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;
for (xp = 0; xp < 5; xp++) {
for (yp = 0; yp < 5; yp++) {
grid[((yp + y) * size) + (xp + x)] = 0x10 + !!(alignment[yp] & (0x10 >> xp));
}
}
}
static void qr_setup_grid(unsigned char *grid, const int size, const int version) {
int i, toggle = 1;
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 13
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
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;
}
}
qr_place_finder(grid, size, 0, 0);
qr_place_finder(grid, size, 0, size - 7);
qr_place_finder(grid, size, size - 7, 0);
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
if (version != 1) {
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);
}
}
}
}
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;
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);
int direction = 1;
int row = 0;
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--;
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) {
row++;
y = 0;
direction = 0;
}
} else {
y++;
if (y == v_size) {
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);
(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
assert(size > 0);
#ifdef ZINTLOG
for (y = 0; y < size; y++) {
for (x = 0; x < size; x++) {
append_log(local[(y * size) + x]);
}
write_log("");
}
#endif
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;
}
}
dark_mods = 0;
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
sprintf(str, "%d", result);
result_b = result;
write_log(str);
#endif
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
sprintf(str, "%d", result - result_b);
result_b = result;
write_log(str);
#endif
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]) {
beforeCount = 0;
for (b = y - 1; b >= y - 4; b--) {
if (b < 0) {
beforeCount = 4;
break;
}
if (local[(b * size) + x]) {
break;
}
beforeCount++;
}
if (beforeCount == 4) {
result += 40;
} else {
afterCount = 0;
for (a = y + 7; a <= y + 10; a++) {
if (a >= size) {
afterCount = 4;
break;
}
if (local[(a * size) + x]) {
break;
}
afterCount++;
}
if (afterCount == 4) {
result += 40;
}
}
y += 3;
}
}
}
for (y = 0; y < size; y++) {
r = y * size;
for (x = 0; x <= (size - 7); x++) {
if (memcmp(local + r + x, h1011101, 7) == 0) {
beforeCount = 0;
for (b = x - 1; b >= x - 4; b--) {
if (b < 0) {
beforeCount = 4;
break;
}
if (local[r + b]) {
break;
}
beforeCount++;
}
if (beforeCount == 4) {
result += 40;
} else {
afterCount = 0;
for (a = x + 7; a <= x + 10; a++) {
if (a >= size) {
afterCount = 4;
break;
}
if (local[r + a]) {
break;
}
afterCount++;
}
if (afterCount == 4) {
result += 40;
}
}
x += 3;
}
}
}
#ifdef ZINTLOG
sprintf(str, "%d", result - result_b);
result_b = result;
write_log(str);
#endif
percentage = (100.0 * dark_mods) / (size * size);
k = (int) (fabs(percentage - 50.0) / 5.0);
result += 10 * k;
#ifdef ZINTLOG
sprintf(str, "%d", result - result_b);
write_log(str);
write_log("==========");
sprintf(str, "%d", result);
write_log(str);
#endif
return result;
}
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
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 + 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) {
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 {
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
if (!user_mask && best_pattern == 7) {
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;
}
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;
}
}
static int qr_blockLength(const int start, const char modes[], const int length) {
int i;
int count = 0;
char start_mode = modes[start];
i = start;
do {
count++;
} while (i + count < length && modes[i + count] == start_mode);
return count;
}
static int qr_calc_binlen(const int version, char modes[], 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_modes(modes, ddata, length, gs1, version, debug_print);
}
currentMode = ' ';
if (eci != 0) {
count += 4;
if (eci <= 127) {
count += 8;
} else if (eci <= 16383) {
count += 16;
} else {
count += 24;
}
}
for (i = 0; i < length; i++) {
if (modes[i] != currentMode) {
count += qr_mode_bits(version) + qr_cci_bits(version, modes[i]);
blocklength = qr_blockLength(i, modes, length);
switch (modes[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) {
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 = modes[i];
}
}
return count;
}
static int qr_calc_binlen_segs(const int version, char modes[], 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 *mds = modes;
if (p_structapp) {
count += 4 + 8 + 8;
}
if (gs1) {
if (version < RMQR_VERSION) {
count += 4;
} else {
count += 3;
}
}
for (i = 0; i < seg_count; i++) {
count += qr_calc_binlen(version, mds, dd, segs[i].length, mode_preset, gs1, segs[i].eci, debug_print);
mds += 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;
}
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;
const int full_multibyte = (symbol->option_3 & 0xFF) == ZINT_FULL_MULTIBYTE;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
if ((symbol->input_mode & 0x07) == DATA_MODE) {
zint_sjis_cpy_segs(segs, seg_count, ddata, full_multibyte);
} else {
unsigned int *dd = ddata;
for (i = 0; i < seg_count; i++) {
int done = 0, eci = segs[i].eci;
if (segs[i].eci != 20 || seg_count > 1) {
int error_number = zint_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 z_errtxtf(error_number, symbol, 575, "Invalid character in input for ECI '%d'",
segs[i].eci);
}
}
if (!done) {
int error_number = zint_sjis_utf8(symbol, segs[i].source, &segs[i].length, dd);
if (error_number != 0) {
return error_number;
}
if (segs[i].eci != 20) {
warn_number = z_errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 760,
"Converted to Shift JIS but no ECI specified");
}
eci = 20;
}
if (content_segs && eci) {
z_ct_set_seg_eci(symbol, i, eci);
}
dd += segs[i].length;
}
}
return warn_number;
}
INTERNAL int zint_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 = zint_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 *modes = (char *) z_alloca(eci_length_segs);
char *prev_modes = (char *) z_alloca(eci_length_segs);
unsigned char *datastream;
unsigned char *fullstream;
unsigned char *grid;
user_mask = (symbol->option_3 >> 8) & 0x0F;
if (user_mask > 8) {
user_mask = 0;
}
z_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;
}
if (symbol->structapp.count) {
if (symbol->structapp.count < 2 || symbol->structapp.count > 16) {
return z_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 ZEXT z_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) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 752,
"Structured Append ID length %d too long (3 digit maximum)", id_len);
}
id = z_to_int(ZCUCP(symbol->structapp.id), id_len);
if (id == -1) {
return z_errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 753, "Invalid Structured Append ID (digits only)");
}
if (id > 255) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 754,
"Structured Append ID value '%d' out of range (0 to 255)", id);
}
}
p_structapp = &symbol->structapp;
}
if (gs1 && warn_number == 0) {
for (i = 0; i < seg_count; i++) {
if (local_segs[i].eci) {
warn_number = z_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 = z_errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 756,
"Using Structured Append in GS1 mode not supported by GS1 standards");
}
}
est_binlen = qr_calc_binlen_segs(40, modes, ddata, local_segs, seg_count, p_structapp, 0 , 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 ZEXT z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 567,
"Input too long, requires %1$d codewords (maximum %2$d)", (est_binlen + 7) / 8,
max_cw);
}
return ZEXT z_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) {
prev_est_binlen = est_binlen;
est_binlen = qr_calc_binlen_segs(autosize, modes, ddata, local_segs, seg_count, p_structapp,
0 , gs1, debug_print);
if (prev_est_binlen < est_binlen) {
assert(0);
est_binlen = qr_calc_binlen_segs(40, modes, ddata, local_segs, seg_count, p_structapp, 0 ,
gs1, debug_print);
assert(est_binlen == prev_est_binlen);
}
}
canShrink = 1;
do {
if (autosize == 1) {
canShrink = 0;
} else {
prev_est_binlen = est_binlen;
memcpy(prev_modes, modes, eci_length_segs);
est_binlen = qr_calc_binlen_segs(autosize - 1, modes, ddata, local_segs, seg_count, p_structapp,
0 , gs1, debug_print);
if (8 * qr_data_codewords[ecc_level][autosize - 2] < est_binlen) {
canShrink = 0;
}
if (canShrink == 1) {
autosize--;
} else {
est_binlen = prev_est_binlen;
memcpy(modes, prev_modes, eci_length_segs);
}
}
} while (canShrink == 1);
version = autosize;
if (symbol->option_2 >= 1 && symbol->option_2 <= 40) {
if (symbol->option_2 > version) {
version = symbol->option_2;
est_binlen = qr_calc_binlen_segs(symbol->option_2, modes, ddata, local_segs, seg_count, p_structapp,
0 , gs1, debug_print);
}
if (symbol->option_2 < version) {
return ZEXT z_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]);
}
}
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, modes, ddata, local_segs, seg_count, p_structapp,
gs1, est_binlen, debug_print);
#ifdef ZINT_TEST
if (symbol->debug & ZINT_DEBUG_TEST) z_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;
assert(size >= 21);
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);
symbol->option_1 = ecc_level + 1;
symbol->option_2 = version;
symbol->option_3 = (symbol->option_3 & 0xFF) | ((bitmask + 1) << 8);
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) {
z_set_module(symbol, i, j);
}
}
symbol->row_height[i] = 1;
}
symbol->height = size;
return warn_number;
}
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;
bits_left = bits_total - bp;
if (bits_left <= terminator_bits) {
if (bits_left) {
bp = z_bin_append_posn(0, bits_left, binary_data, bp);
bits_left = 0;
}
} else {
bp = z_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);
}
if (bits_end == 4 && bits_left && bits_left <= 4) {
bp = z_bin_append_posn(0, bits_left, binary_data, bp);
bits_left = 0;
}
if (bits_left) {
int remainder = 8 - (bp % 8);
if (remainder != 8) {
bp = z_bin_append_posn(0, remainder, binary_data, bp);
bits_left -= remainder;
}
if (bits_end == 4 && bits_left > 4) {
bits_left -= 4;
}
remainder = bits_left / 8;
for (i = 0; i < remainder; i++) {
bp = z_bin_append_posn(i & 1 ? 0x11 : 0xEC, 8, binary_data, bp);
}
if (bits_end == 4) {
bp = z_bin_append_posn(0, 4, binary_data, bp);
}
}
assert((bp & 0x07) == 8 - bits_end);
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];
z_debug_test_codeword_dump(symbol, data_blocks, data_codewords);
sprintf(bp_buf, "%d", bp);
z_errtxt_adj(0, symbol, "%s (%s)", bp_buf);
}
#endif
zint_rs_init_gf(&rs, 0x11d);
zint_rs_init_code(&rs, ecc_codewords, 0);
zint_rs_encode(&rs, data_codewords, data_blocks, ecc_blocks);
for (i = 0; i < ecc_codewords; i++) {
bp = z_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;
for (i = 0; i < size; i++) {
grid[i] = 0x20 + toggle;
grid[i * size] = 0x20 + toggle;
toggle = !toggle;
}
qr_place_finder(grid, size, 0, 0);
for (i = 0; i < 7; i++) {
grid[(7 * size) + i] = 0x10;
grid[(i * size) + 7] = 0x10;
}
grid[(7 * size) + 7] = 0x10;
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;
int row = 0;
int i;
int y;
y = size - 1;
i = 0;
do {
int x = (size - 2) - (row * 2);
if (!(grid[(y * size) + (x + 1)] & 0xF0)) {
grid[(y * size) + (x + 1)] = full_stream[i] == '1';
i++;
}
if (i < bp) {
if (!(grid[(y * size) + x] & 0xF0)) {
grid[(y * size) + x] = full_stream[i] == '1';
i++;
}
}
if (direction) {
y--;
} else {
y++;
}
if (y == 0) {
row++;
y = 1;
direction = 0;
}
if (y == size) {
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);
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];
}
}
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);
}
bit = 1 << best_pattern;
for (k = 0; k < size_squared; k++) {
if (mask[k] & bit) {
grid[k] ^= 0x01;
}
}
return best_pattern;
}
INTERNAL int zint_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 modes[40];
int alpha_used = 0, byte_or_kanji_used = 0;
int eci = 0;
int version_valid[4];
int binary_count[4];
int ecc_level, version;
int bitmask, format, format_full;
int size_squared;
unsigned char *grid;
struct zint_seg segs[1];
const int seg_count = 1;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
if (length > 35) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 562, "Input length %d too long (maximum 35)", length);
}
ecc_level = QR_LEVEL_L;
if (symbol->option_1 >= 1 && symbol->option_1 <= 4) {
if (symbol->option_1 == 4) {
return z_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 z_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 z_errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 563,
"Error correction level Q requires Version M4");
}
}
ecc_level = symbol->option_1 - 1;
}
full_multibyte = (symbol->option_3 & 0xFF) == ZINT_FULL_MULTIBYTE;
user_mask = (symbol->option_3 >> 8) & 0x0F;
if (user_mask > 4) {
user_mask = 0;
}
if ((symbol->input_mode & 0x07) == DATA_MODE) {
zint_sjis_cpy(source, &length, ddata, full_multibyte);
} else {
int error_number = zint_sjis_utf8_to_eci(3, source, &length, ddata, full_multibyte);
if (error_number != 0) {
error_number = zint_sjis_utf8(symbol, source, &length, ddata);
if (error_number != 0) {
return error_number;
}
eci = 20;
}
}
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 )) {
alpha_used = 1;
} else {
byte_or_kanji_used = 1;
}
}
}
for (i = 0; i < 4; i++) {
version_valid[i] = 1;
}
if (byte_or_kanji_used) {
version_valid[0] = 0;
version_valid[1] = 0;
} else if (alpha_used) {
version_valid[0] = 0;
}
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;
if (content_segs && eci) {
z_ct_set_seg_eci(symbol, 0 , eci);
}
for (i = 0; i < 4; i++) {
if (version_valid[i]) {
binary_count[i] = qr_calc_binlen_segs(MICROQR_VERSION + i, modes, ddata, segs, seg_count,
NULL , 0 , 0 , debug_print);
} else {
binary_count[i] = 128 + 1;
}
}
if (binary_count[3] > microqr_data[ecc_level][3][0]) {
return ZEXT z_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;
}
}
version = 3;
if (version_valid[2]) {
version = 2;
}
if (version_valid[1]) {
version = 1;
}
if (version_valid[0]) {
version = 0;
}
if (symbol->option_2 >= 1 && symbol->option_2 <= 4) {
if (symbol->option_2 == 1 && (i = z_not_sane(NEON_F, source, length))) {
return z_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 && z_not_sane(QR_ALPHA, source, length)) {
return z_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 ZEXT z_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 (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_modes(modes, ddata, length, 0 , MICROQR_VERSION + version, debug_print);
bp = qr_binary_segs(ZUCP(full_stream), MICROQR_VERSION + version, 0 , modes, ddata,
segs, seg_count, NULL , 0 , 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);
symbol->option_1 = ecc_level + 1;
symbol->option_2 = version + 1;
symbol->option_3 = (symbol->option_3 & 0xFF) | ((bitmask + 1) << 8);
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) {
z_set_module(symbol, i, j);
}
}
symbol->row_height[i] = 1;
}
symbol->height = size;
return 0;
}
INTERNAL int zint_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 content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
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 *modes = (char *) z_alloca(length + 1);
unsigned char *preprocessed = (unsigned char *) z_alloca(length + 1);
user_mask = (symbol->option_3 >> 8) & 0x0F;
if (user_mask > 8) {
user_mask = 0;
}
switch (symbol->input_mode & 0x07) {
case DATA_MODE:
for (i = 0; i < length; i++) {
ddata[i] = source[i];
modes[i] = 'B';
}
break;
case GS1_MODE:
return z_errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 571,
"UPNQR does not support GS1 data");
break;
case UNICODE_MODE:
error_number = zint_utf8_to_eci(4, source, preprocessed, &length);
if (error_number != 0) {
return z_errtxt(error_number, symbol, 572, "Invalid character in input for ECI '4'");
}
for (i = 0; i < length; i++) {
ddata[i] = preprocessed[i];
modes[i] = 'B';
}
break;
}
segs[0].source = source;
segs[0].length = length;
segs[0].eci = 4;
if (content_segs) {
z_ct_set_seg_eci(symbol, 0 , segs[0].eci);
}
est_binlen = qr_calc_binlen_segs(15, modes, ddata, segs, seg_count, NULL , 1 ,
0 , debug_print);
ecc_level = QR_LEVEL_M;
if (est_binlen > 3320) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 573, "Input too long, requires %d codewords (maximum 415)",
(est_binlen + 7) / 8);
}
version = 15;
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, modes, ddata, segs, seg_count, NULL ,
0 , est_binlen, debug_print);
#ifdef ZINT_TEST
if (symbol->debug & ZINT_DEBUG_TEST) z_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);
symbol->option_1 = ecc_level + 1;
symbol->option_2 = version;
symbol->option_3 = (symbol->option_3 & 0xFF) | ((bitmask + 1) << 8);
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) {
z_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;
for (i = 0; i < h_size; i++) {
grid[i] = 0x20 + !(i & 1);
grid[((v_size - 1) * h_size) + i] = 0x20 + !(i & 1);
}
for (i = 0; i < v_size; i++) {
grid[i * h_size] = 0x20 + !(i & 1);
grid[(i * h_size) + (h_size - 1)] = 0x20 + !(i & 1);
}
qr_place_finder(grid, h_size, 0, 0);
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
grid[((i + v_size - 5) * h_size) + (h_size - 5) + j] = 0x10 + !!(alignment[j] & (0x10 >> i));
}
}
grid[(v_size - 2) * h_size] = 0x11;
grid[((v_size - 2) * h_size) + 1] = 0x10;
grid[((v_size - 1) * h_size) + 1] = 0x11;
grid[h_size - 2] = 0x11;
grid[(h_size * 2) - 2] = 0x10;
grid[(h_size * 2) - 1] = 0x11;
for (i = 0; i < 7; i++) {
grid[(i * h_size) + 7] = 0x20;
}
if (v_size > 7) {
for (i = 0; i < 8; i++) {
grid[(7 * h_size) + i] = 0x20;
}
}
if (h_size > 27) {
h_version = 0;
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++) {
grid[(j * h_size) + finder_position] = 0x10 + !(j & 1);
}
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;
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;
}
}
}
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;
}
INTERNAL int zint_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 = zint_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 *modes = (char *) z_alloca(eci_length_segs);
unsigned char *datastream;
unsigned char *fullstream;
unsigned char *grid;
if (symbol->option_1 == 1) {
return z_errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 576, "Error correction level L not available in rMQR");
}
if (symbol->option_1 == 3) {
return z_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 z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 579, "Version '%d' out of range (1 to 38)",
symbol->option_2);
}
z_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;
}
if (gs1 && warn_number == 0) {
for (i = 0; i < seg_count; i++) {
if (local_segs[i].eci) {
warn_number = z_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, modes, ddata, local_segs, seg_count, NULL ,
0 , 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 ZEXT z_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;
if (symbol->option_2 == 0) {
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, modes, ddata, local_segs, seg_count,
NULL , 0 , 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, modes, ddata, local_segs, seg_count,
NULL , 0 , gs1, debug_print);
}
if (symbol->option_2 >= 1 && symbol->option_2 <= 32) {
version = symbol->option_2 - 1;
est_binlen = qr_calc_binlen_segs(RMQR_VERSION + version, modes, ddata, local_segs, seg_count,
NULL , 0 , gs1, debug_print);
}
if (symbol->option_2 >= 33) {
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, modes, ddata, local_segs, seg_count,
NULL , 0 , 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, modes, ddata, local_segs, seg_count,
NULL , 0 , gs1, debug_print);
}
if (symbol->option_1 == -1) {
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) {
assert(symbol->option_2 > 0);
return ZEXT z_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);
}
symbol->option_1 = ecc_level + 1;
symbol->option_2 = version + 1;
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, modes, ddata, local_segs, seg_count,
NULL , gs1, est_binlen, debug_print);
#ifdef ZINT_TEST
if (symbol->debug & ZINT_DEBUG_TEST) z_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];
assert(h_size >= 27 && v_size >= 7);
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]);
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) {
if ((i / 2 + j / 3) % 2 == 0) {
grid[r + j] ^= 0x01;
}
}
}
}
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 * (i + v_size - 6)) + 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) {
z_set_module(symbol, i, j);
}
}
symbol->row_height[i] = 1;
}
symbol->height = v_size;
return warn_number;
}