#include <assert.h>
#include <stdio.h>
#include "common.h"
#include "reedsol.h"
#include "gridmtx.h"
#include "eci.h"
static const char EUROPIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ";
static const char EUROPIUM_UPR[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
static const char EUROPIUM_LWR[] = "abcdefghijklmnopqrstuvwxyz ";
#define GM_MULT 6
static const char gm_numeral_nondigits[] = " +-.,";
static int gm_in_numeral(const unsigned int ddata[], const int length, const int in_posn,
unsigned int *p_numeral_end, unsigned int *p_numeral_cost) {
int i, digit_cnt, nondigit, nondigit_posn;
if (in_posn < (int) *p_numeral_end) {
return 1;
}
for (i = in_posn, digit_cnt = 0, nondigit = 0, nondigit_posn = 0; i < length && i < in_posn + 4 && digit_cnt < 3;
i++) {
if (z_isdigit(ddata[i])) {
digit_cnt++;
} else if (z_posn(gm_numeral_nondigits, (const char) ddata[i]) != -1) {
if (nondigit) {
break;
}
nondigit = 1;
nondigit_posn = i;
} else if (i < length - 1 && ddata[i] == 13 && ddata[i + 1] == 10) {
if (nondigit) {
break;
}
i++;
nondigit = 2;
nondigit_posn = i;
} else {
break;
}
}
if (digit_cnt == 0) {
*p_numeral_end = 0;
return 0;
}
if (nondigit && nondigit_posn == i - 1) {
nondigit = 0;
}
*p_numeral_end = in_posn + digit_cnt + nondigit;
if (digit_cnt == 3) {
*p_numeral_cost = nondigit == 2 ? 24 : nondigit == 1 ? 30 : 20 ;
} else if (digit_cnt == 2) {
*p_numeral_cost = nondigit == 2 ? 30 : nondigit == 1 ? 40 : 30 ;
} else {
*p_numeral_cost = nondigit == 2 ? 40 : nondigit == 1 ? 60 : 60 ;
}
return 1;
}
#define GM_CHINESE 'H'
#define GM_NUMBER 'N'
#define GM_LOWER 'L'
#define GM_UPPER 'U'
#define GM_MIXED 'M'
#define GM_BYTE 'B'
#define GM_H 0
#define GM_N 1
#define GM_L 2
#define GM_U 3
#define GM_M 4
#define GM_B 5
#define GM_NUM_MODES 6
static void gm_define_modes(char *modes, const unsigned int ddata[], const int length, const int debug_print) {
static const char mode_types[] = { GM_CHINESE, GM_NUMBER, GM_LOWER, GM_UPPER, GM_MIXED, GM_BYTE, '\0' };
static const unsigned int head_costs[GM_NUM_MODES] = {
4 * GM_MULT, (4 + 2) * GM_MULT, 4 * GM_MULT, 4 * GM_MULT, 4 * GM_MULT, (4 + 9) * GM_MULT
};
static const unsigned char switch_costs[GM_NUM_MODES][GM_NUM_MODES] = {
{ 0, (13 + 2) * GM_MULT, 13 * GM_MULT, 13 * GM_MULT, 13 * GM_MULT, (13 + 9) * GM_MULT },
{ 10 * GM_MULT, 0, 10 * GM_MULT, 10 * GM_MULT, 10 * GM_MULT, (10 + 9) * GM_MULT },
{ 5 * GM_MULT, (5 + 2) * GM_MULT, 0, 5 * GM_MULT, 7 * GM_MULT, (7 + 9) * GM_MULT },
{ 5 * GM_MULT, (5 + 2) * GM_MULT, 5 * GM_MULT, 0, 7 * GM_MULT, (7 + 9) * GM_MULT },
{ 10 * GM_MULT, (10 + 2) * GM_MULT, 10 * GM_MULT, 10 * GM_MULT, 0, (10 + 9) * GM_MULT },
{ 4 * GM_MULT, (4 + 2) * GM_MULT, 4 * GM_MULT, 4 * GM_MULT, 4 * GM_MULT, 0 },
};
static const unsigned char eod_costs[GM_NUM_MODES] = {
13 * GM_MULT, 10 * GM_MULT, 5 * GM_MULT, 5 * GM_MULT, 10 * GM_MULT, 4 * GM_MULT
};
unsigned int numeral_end = 0, numeral_cost = 0, byte_count = 0;
int double_byte, space, numeric, lower, upper, control, double_digit, eol;
int i, j, k;
unsigned int min_cost;
char cur_mode;
unsigned int prev_costs[GM_NUM_MODES];
unsigned int cur_costs[GM_NUM_MODES];
char (*char_modes)[GM_NUM_MODES] = (char (*)[GM_NUM_MODES]) z_alloca(GM_NUM_MODES * length);
memset(char_modes, 0, length * GM_NUM_MODES);
memcpy(prev_costs, head_costs, GM_NUM_MODES * sizeof(unsigned int));
for (i = 0; i < length; i++) {
memset(cur_costs, 0, GM_NUM_MODES * sizeof(unsigned int));
space = numeric = lower = upper = control = double_digit = eol = 0;
double_byte = ddata[i] > 0xFF;
if (!double_byte) {
space = ddata[i] == ' ';
if (!space) {
numeric = z_isdigit(ddata[i]);
if (!numeric) {
lower = z_islower(ddata[i]);
if (!lower) {
upper = z_isupper(ddata[i]);
if (!upper) {
control = ddata[i] < 0x7F;
if (control && i + 1 < length) {
eol = ddata[i] == 13 && ddata[i + 1] == 10;
}
}
}
} else if (i + 1 < length) {
double_digit = z_isdigit(ddata[i + 1]);
}
}
}
cur_costs[GM_H] = prev_costs[GM_H] + (double_digit || eol ? 39 : 78);
char_modes[i][GM_H] = GM_CHINESE;
if (byte_count == 512 || (double_byte && byte_count == 511)) {
cur_costs[GM_B] = head_costs[GM_B];
if (double_byte && byte_count == 511) {
cur_costs[GM_B] += 48;
double_byte = 0;
}
byte_count = 0;
}
cur_costs[GM_B] += prev_costs[GM_B] + (double_byte ? 96 : 48);
char_modes[i][GM_B] = GM_BYTE;
byte_count += double_byte ? 2 : 1;
if (gm_in_numeral(ddata, length, i, &numeral_end, &numeral_cost)) {
cur_costs[GM_N] = prev_costs[GM_N] + numeral_cost;
char_modes[i][GM_N] = GM_NUMBER;
}
if (control) {
cur_costs[GM_L] = prev_costs[GM_L] + 78;
char_modes[i][GM_L] = GM_LOWER;
cur_costs[GM_U] = prev_costs[GM_U] + 78;
char_modes[i][GM_U] = GM_UPPER;
cur_costs[GM_M] = prev_costs[GM_M] + 96;
char_modes[i][GM_M] = GM_MIXED;
} else {
if (lower || space) {
cur_costs[GM_L] = prev_costs[GM_L] + 30;
char_modes[i][GM_L] = GM_LOWER;
}
if (upper || space) {
cur_costs[GM_U] = prev_costs[GM_U] + 30;
char_modes[i][GM_U] = GM_UPPER;
}
if (numeric || lower || upper || space) {
cur_costs[GM_M] = prev_costs[GM_M] + 36;
char_modes[i][GM_M] = GM_MIXED;
}
}
if (i == length - 1) {
for (j = 0; j < GM_NUM_MODES; j++) {
if (char_modes[i][j]) {
cur_costs[j] += eod_costs[j];
}
}
}
for (j = 0; j < GM_NUM_MODES; j++) {
for (k = 0; k < GM_NUM_MODES; k++) {
if (j != k && char_modes[i][k]) {
const unsigned int new_cost = cur_costs[k] + switch_costs[k][j];
if (!char_modes[i][j] || new_cost < cur_costs[j]) {
cur_costs[j] = new_cost;
char_modes[i][j] = mode_types[k];
}
}
}
}
memcpy(prev_costs, cur_costs, GM_NUM_MODES * sizeof(unsigned int));
}
min_cost = prev_costs[0];
cur_mode = mode_types[0];
for (i = 1; i < GM_NUM_MODES; i++) {
if (prev_costs[i] < min_cost) {
min_cost = prev_costs[i];
cur_mode = mode_types[i];
}
}
for (i = length - 1; i >= 0; i--) {
j = z_posn(mode_types, cur_mode);
cur_mode = char_modes[i][j];
modes[i] = cur_mode;
}
if (debug_print) {
printf(" Modes: %.*s\n", length, modes);
}
}
static void gm_add_byte_count(char binary[], const int byte_count_posn, const int byte_count) {
z_bin_append_posn(byte_count - 1, 9, binary, byte_count_posn);
}
static int gm_add_shift_char(char binary[], int bp, const int shifty, const int debug_print) {
int i;
int glyph = 0;
if (shifty < 32) {
glyph = shifty;
} else {
for (i = 32; i < 64; i++) {
if (gm_shift_set[i] == shifty) {
glyph = i;
break;
}
}
}
if (debug_print) {
printf("SHIFT [%d] ", glyph);
}
bp = z_bin_append_posn(glyph, 6, binary, bp);
return bp;
}
static int gm_encode(const unsigned int ddata[], const int length, char binary[], const int eci, int *p_bp,
const int debug_print) {
int sp = 0;
int current_mode = 0;
int last_mode;
unsigned int glyph = 0;
int c1, c2, done;
int p = 0, ppos;
int numbuf[3], punt = 0;
int number_pad_posn = 0;
int byte_count_posn = 0;
int byte_count = 0;
int shift;
int bp = *p_bp;
char *modes = (char *) z_alloca(length);
if (eci != 0) {
bp = z_bin_append_posn(12, 4, binary, bp);
if (eci <= 1023) {
bp = z_bin_append_posn(eci, 11, binary, bp);
} else if (eci <= 32767) {
bp = z_bin_append_posn(2, 2, binary, bp);
bp = z_bin_append_posn(eci, 15, binary, bp);
} else {
bp = z_bin_append_posn(3, 2, binary, bp);
bp = z_bin_append_posn(eci, 20, binary, bp);
}
}
gm_define_modes(modes, ddata, length, debug_print);
do {
const int next_mode = modes[sp];
if (next_mode != current_mode) {
switch (current_mode) {
case 0:
switch (next_mode) {
case GM_CHINESE: bp = z_bin_append_posn(1, 4, binary, bp); break;
case GM_NUMBER: bp = z_bin_append_posn(2, 4, binary, bp); break;
case GM_LOWER: bp = z_bin_append_posn(3, 4, binary, bp); break;
case GM_UPPER: bp = z_bin_append_posn(4, 4, binary, bp); break;
case GM_MIXED: bp = z_bin_append_posn(5, 4, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(6, 4, binary, bp); break;
}
break;
case GM_CHINESE:
switch (next_mode) {
case GM_NUMBER: bp = z_bin_append_posn(8161, 13, binary, bp); break;
case GM_LOWER: bp = z_bin_append_posn(8162, 13, binary, bp); break;
case GM_UPPER: bp = z_bin_append_posn(8163, 13, binary, bp); break;
case GM_MIXED: bp = z_bin_append_posn(8164, 13, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(8165, 13, binary, bp); break;
}
break;
case GM_NUMBER:
switch (p) {
case 1:
binary[number_pad_posn] = '1';
binary[number_pad_posn + 1] = '0';
break;
case 2:
binary[number_pad_posn] = '0';
binary[number_pad_posn + 1] = '1';
break;
case 3:
binary[number_pad_posn] = '0';
binary[number_pad_posn + 1] = '0';
break;
}
switch (next_mode) {
case GM_CHINESE: bp = z_bin_append_posn(1019, 10, binary, bp); break;
case GM_LOWER: bp = z_bin_append_posn(1020, 10, binary, bp); break;
case GM_UPPER: bp = z_bin_append_posn(1021, 10, binary, bp); break;
case GM_MIXED: bp = z_bin_append_posn(1022, 10, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(1023, 10, binary, bp); break;
}
break;
case GM_LOWER:
case GM_UPPER:
switch (next_mode) {
case GM_CHINESE: bp = z_bin_append_posn(28, 5, binary, bp); break;
case GM_NUMBER: bp = z_bin_append_posn(29, 5, binary, bp); break;
case GM_LOWER:
case GM_UPPER:
bp = z_bin_append_posn(30, 5, binary, bp);
break;
case GM_MIXED: bp = z_bin_append_posn(124, 7, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(126, 7, binary, bp); break;
}
break;
case GM_MIXED:
switch (next_mode) {
case GM_CHINESE: bp = z_bin_append_posn(1009, 10, binary, bp); break;
case GM_NUMBER: bp = z_bin_append_posn(1010, 10, binary, bp); break;
case GM_LOWER: bp = z_bin_append_posn(1011, 10, binary, bp); break;
case GM_UPPER: bp = z_bin_append_posn(1012, 10, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(1015, 10, binary, bp); break;
}
break;
case GM_BYTE:
gm_add_byte_count(binary, byte_count_posn, byte_count);
byte_count = 0;
switch (next_mode) {
case GM_CHINESE: bp = z_bin_append_posn(1, 4, binary, bp); break;
case GM_NUMBER: bp = z_bin_append_posn(2, 4, binary, bp); break;
case GM_LOWER: bp = z_bin_append_posn(3, 4, binary, bp); break;
case GM_UPPER: bp = z_bin_append_posn(4, 4, binary, bp); break;
case GM_MIXED: bp = z_bin_append_posn(5, 4, binary, bp); break;
}
break;
}
if (debug_print) {
switch (next_mode) {
case GM_CHINESE: fputs("CHIN ", stdout); break;
case GM_NUMBER: fputs("NUMB ", stdout); break;
case GM_LOWER: fputs("LOWR ", stdout); break;
case GM_UPPER: fputs("UPPR ", stdout); break;
case GM_MIXED: fputs("MIXD ", stdout); break;
case GM_BYTE: fputs("BYTE ", stdout); break;
}
}
}
last_mode = current_mode;
current_mode = next_mode;
switch (current_mode) {
case GM_CHINESE:
done = 0;
if (ddata[sp] > 0xFF) {
c1 = (ddata[sp] & 0xFF00) >> 8;
c2 = ddata[sp] & 0xFF;
if (c1 >= 0xA1 && c1 <= 0xA9) {
glyph = 0x60 * (c1 - 0xA1) + (c2 - 0xA0);
} else if (c1 >= 0xB0 && c1 <= 0xF7) {
glyph = 0x60 * (c1 - 0xB0 + 9) + (c2 - 0xA0);
}
done = 1;
}
if (!done) {
if (sp != length - 1) {
if (ddata[sp] == 13 && ddata[sp + 1] == 10) {
glyph = 7776;
sp++;
done = 1;
}
}
}
if (!done) {
if (sp != length - 1) {
if (z_isdigit(ddata[sp]) && z_isdigit(ddata[sp + 1])) {
glyph = 8033 + (10 * (ddata[sp] - '0')) + (ddata[sp + 1] - '0');
sp++;
done = 1;
}
}
}
if (!done) {
glyph = 7777 + ddata[sp];
}
if (debug_print) {
printf("[%d] ", (int) glyph);
}
bp = z_bin_append_posn(glyph, 13, binary, bp);
sp++;
break;
case GM_NUMBER:
if (last_mode != current_mode) {
number_pad_posn = bp;
bp = z_bin_append_posn(0, 2, binary, bp);
}
p = 0;
ppos = -1;
numbuf[0] = '0';
numbuf[1] = '0';
numbuf[2] = '0';
do {
if (z_isdigit(ddata[sp])) {
numbuf[p] = ddata[sp];
p++;
} else if (z_posn(gm_numeral_nondigits, (const char) ddata[sp]) != -1) {
if (ppos != -1) {
break;
}
punt = ddata[sp];
ppos = p;
} else if (sp < length - 1 && ddata[sp] == 13 && ddata[sp + 1] == 10) {
if (ppos != -1) {
break;
}
punt = ddata[sp];
sp++;
ppos = p;
} else {
break;
}
sp++;
} while (p < 3 && sp < length && modes[sp] == GM_NUMBER);
if (ppos != -1) {
switch (punt) {
case ' ': glyph = 0; break;
case '+': glyph = 3; break;
case '-': glyph = 6; break;
case '.': glyph = 9; break;
case ',': glyph = 12; break;
case 13: glyph = 15; break;
}
glyph += ppos;
glyph += 1000;
if (debug_print) {
printf("[%d] ", (int) glyph);
}
bp = z_bin_append_posn(glyph, 10, binary, bp);
}
glyph = (100 * (numbuf[0] - '0')) + (10 * (numbuf[1] - '0')) + (numbuf[2] - '0');
if (debug_print) {
printf("[%d] ", (int) glyph);
}
bp = z_bin_append_posn(glyph, 10, binary, bp);
break;
case GM_BYTE:
if (last_mode != current_mode) {
byte_count_posn = bp;
bp = z_bin_append_posn(0, 9, binary, bp);
}
glyph = ddata[sp];
if (byte_count == 512 || (glyph > 0xFF && byte_count == 511)) {
if (glyph > 0xFF && byte_count == 511) {
bp = z_bin_append_posn(glyph >> 8, 8, binary, bp);
glyph &= 0xFF;
byte_count++;
}
gm_add_byte_count(binary, byte_count_posn, byte_count);
bp = z_bin_append_posn(7, 4, binary, bp);
byte_count_posn = bp;
bp = z_bin_append_posn(0, 9, binary, bp);
byte_count = 0;
}
if (debug_print) {
printf("[%d] ", (int) glyph);
}
bp = z_bin_append_posn(glyph, glyph > 0xFF ? 16 : 8, binary, bp);
sp++;
byte_count++;
if (glyph > 0xFF) {
byte_count++;
}
break;
case GM_MIXED:
shift = 1;
if (z_isdigit(ddata[sp])) {
shift = 0;
} else if (z_isupper(ddata[sp])) {
shift = 0;
} else if (z_islower(ddata[sp])) {
shift = 0;
} else if (ddata[sp] == ' ') {
shift = 0;
}
if (shift == 0) {
glyph = z_posn(EUROPIUM, (const char) ddata[sp]);
if (debug_print) {
printf("[%d] ", (int) glyph);
}
bp = z_bin_append_posn(glyph, 6, binary, bp);
} else {
bp = z_bin_append_posn(1014, 10, binary, bp);
bp = gm_add_shift_char(binary, bp, ddata[sp], debug_print);
}
sp++;
break;
case GM_UPPER:
shift = 1;
if (z_isupper(ddata[sp])) {
shift = 0;
} else if (ddata[sp] == ' ') {
shift = 0;
}
if (shift == 0) {
glyph = z_posn(EUROPIUM_UPR, (const char) ddata[sp]);
if (debug_print) {
printf("[%d] ", (int) glyph);
}
bp = z_bin_append_posn(glyph, 5, binary, bp);
} else {
bp = z_bin_append_posn(125, 7, binary, bp);
bp = gm_add_shift_char(binary, bp, ddata[sp], debug_print);
}
sp++;
break;
case GM_LOWER:
shift = 1;
if (z_islower(ddata[sp])) {
shift = 0;
} else if (ddata[sp] == ' ') {
shift = 0;
}
if (shift == 0) {
glyph = z_posn(EUROPIUM_LWR, (const char) ddata[sp]);
if (debug_print) {
printf("[%d] ", (int) glyph);
}
bp = z_bin_append_posn(glyph, 5, binary, bp);
} else {
bp = z_bin_append_posn(125, 7, binary, bp);
bp = gm_add_shift_char(binary, bp, ddata[sp], debug_print);
}
sp++;
break;
}
if (bp > 9191) {
return ZINT_ERROR_TOO_LONG;
}
} while (sp < length);
if (current_mode == GM_NUMBER) {
switch (p) {
case 1:
binary[number_pad_posn] = '1';
binary[number_pad_posn + 1] = '0';
break;
case 2:
binary[number_pad_posn] = '0';
binary[number_pad_posn + 1] = '1';
break;
case 3:
binary[number_pad_posn] = '0';
binary[number_pad_posn + 1] = '0';
break;
}
}
if (current_mode == GM_BYTE) {
gm_add_byte_count(binary, byte_count_posn, byte_count);
}
switch (current_mode) {
case GM_CHINESE: bp = z_bin_append_posn(8160, 13, binary, bp); break;
case GM_NUMBER: bp = z_bin_append_posn(1018, 10, binary, bp); break;
case GM_LOWER:
case GM_UPPER:
bp = z_bin_append_posn(27, 5, binary, bp);
break;
case GM_MIXED: bp = z_bin_append_posn(1008, 10, binary, bp); break;
case GM_BYTE: bp = z_bin_append_posn(0, 4, binary, bp); break;
}
if (bp > 9191) {
return ZINT_ERROR_TOO_LONG;
}
*p_bp = bp;
if (debug_print) {
printf("\nBinary (%d): %.*s\n", bp, bp, binary);
}
return 0;
}
static int gm_encode_segs(const unsigned int ddata[], const struct zint_seg segs[], const int seg_count,
char binary[], const int reader, const struct zint_structapp *p_structapp, int *p_bin_len,
const int debug_print) {
int i;
const unsigned int *dd = ddata;
int bp = 0;
int p;
if (reader && (!p_structapp || p_structapp->index == 1)) {
bp = z_bin_append_posn(10, 4, binary, bp);
}
if (p_structapp) {
bp = z_bin_append_posn(9, 4, binary, bp);
bp = z_bin_append_posn(z_to_int(ZCUCP( p_structapp->id), (int) strlen(p_structapp->id)), 8,
binary, bp);
bp = z_bin_append_posn(p_structapp->count - 1, 4, binary, bp);
bp = z_bin_append_posn(p_structapp->index - 1, 4, binary, bp);
}
for (i = 0; i < seg_count; i++) {
int error_number = gm_encode(dd, segs[i].length, binary, segs[i].eci, &bp, debug_print);
if (error_number != 0) {
return error_number;
}
dd += segs[i].length;
}
p = 7 - (bp % 7);
if (p % 7) {
bp = z_bin_append_posn(0, p, binary, bp);
}
if (debug_print) {
printf("\nBinary (%d): %.*s\n", bp, bp, binary);
}
*p_bin_len = bp;
return 0;
}
static void gm_add_ecc(const char binary[], const int data_posn, const int layers, const int ecc_level,
unsigned char word[]) {
int data_cw, i, j, wp, p;
int n1, b1, n2, b2, e1, b3, e2;
int block_size, ecc_size;
unsigned char data[1320], block[130];
unsigned char data_block[115], ecc_block[70];
rs_t rs;
data_cw = gm_data_codewords[((layers - 1) * 5) + (ecc_level - 1)];
for (i = 0; i < 1320; i++) {
data[i] = 0;
}
for (i = 0; i < data_posn; i++) {
for (p = 0; p < 7; p++) {
if (binary[i * 7 + p] == '1') {
data[i] += (0x40 >> p);
}
}
}
data[data_posn] = 0x00;
for (i = (data_posn + 1); i < data_cw; i++) {
if (i & 1) {
data[i] = 0x7E;
} else {
data[i] = 0x00;
}
}
n1 = gm_n1[(layers - 1)];
b1 = gm_b1[(layers - 1)];
n2 = n1 - 1;
b2 = gm_b2[(layers - 1)];
e1 = gm_ebeb[((layers - 1) * 20) + ((ecc_level - 1) * 4)];
b3 = gm_ebeb[((layers - 1) * 20) + ((ecc_level - 1) * 4) + 1];
e2 = gm_ebeb[((layers - 1) * 20) + ((ecc_level - 1) * 4) + 2];
zint_rs_init_gf(&rs, 0x89);
wp = 0;
for (i = 0; i < (b1 + b2); i++) {
int data_size;
if (i < b1) {
block_size = n1;
} else {
block_size = n2;
}
if (i < b3) {
ecc_size = e1;
} else {
ecc_size = e2;
}
data_size = block_size - ecc_size;
for (j = 0; j < data_size; j++) {
data_block[j] = data[wp];
wp++;
}
zint_rs_init_code(&rs, ecc_size, 1);
zint_rs_encode(&rs, data_size, data_block, ecc_block);
for (j = 0; j < data_size; j++) {
block[j] = data_block[j];
}
for (j = 0; j < ecc_size; j++) {
block[j + data_size] = ecc_block[j];
}
for (j = 0; j < n2; j++) {
word[((b1 + b2) * j) + i] = block[j];
}
if (block_size == n1) {
word[((b1 + b2) * (n1 - 1)) + i] = block[(n1 - 1)];
}
}
}
static void gm_place_macromodule(char grid[], const int x, const int y, const int word1, const int word2,
const int size) {
const int i = (x * 6) + 1;
const int j = (y * 6) + 1;
if (word2 & 0x40) {
grid[(j * size) + i + 2] = '1';
}
if (word2 & 0x20) {
grid[(j * size) + i + 3] = '1';
}
if (word2 & 0x10) {
grid[((j + 1) * size) + i] = '1';
}
if (word2 & 0x08) {
grid[((j + 1) * size) + i + 1] = '1';
}
if (word2 & 0x04) {
grid[((j + 1) * size) + i + 2] = '1';
}
if (word2 & 0x02) {
grid[((j + 1) * size) + i + 3] = '1';
}
if (word2 & 0x01) {
grid[((j + 2) * size) + i] = '1';
}
if (word1 & 0x40) {
grid[((j + 2) * size) + i + 1] = '1';
}
if (word1 & 0x20) {
grid[((j + 2) * size) + i + 2] = '1';
}
if (word1 & 0x10) {
grid[((j + 2) * size) + i + 3] = '1';
}
if (word1 & 0x08) {
grid[((j + 3) * size) + i] = '1';
}
if (word1 & 0x04) {
grid[((j + 3) * size) + i + 1] = '1';
}
if (word1 & 0x02) {
grid[((j + 3) * size) + i + 2] = '1';
}
if (word1 & 0x01) {
grid[((j + 3) * size) + i + 3] = '1';
}
}
static void gm_place_data_in_grid(const unsigned char word[], char grid[], const int modules, const int size) {
int x, y, macromodule;
const int offset = 13 - ((modules - 1) / 2);
for (y = 0; y < modules; y++) {
for (x = 0; x < modules; x++) {
macromodule = gm_macro_matrix[((y + offset) * 27) + (x + offset)];
gm_place_macromodule(grid, x, y, word[macromodule * 2], word[(macromodule * 2) + 1], size);
}
}
}
static void gm_place_layer_id(char *grid, const int size, const int layers, const int ecc_level) {
int i, j, layer, start, stop;
const int modules = 1 + (layers << 1);
int *layerid = (int *) z_alloca(sizeof(int) * (layers + 1));
int *id = (int *) z_alloca(sizeof(int) * (modules * modules));
for (i = 0; i <= layers; i++) {
if (ecc_level == 1) {
layerid[i] = 3 - (i % 4);
} else {
layerid[i] = (i + 5 - ecc_level) % 4;
}
}
for (i = 0; i < modules; i++) {
for (j = 0; j < modules; j++) {
id[(i * modules) + j] = 0;
}
}
start = modules >> 1;
stop = modules >> 1;
for (layer = 0; layer <= layers; layer++) {
for (i = start; i <= stop; i++) {
id[(start * modules) + i] = layerid[layer];
id[(i * modules) + start] = layerid[layer];
id[((modules - start - 1) * modules) + i] = layerid[layer];
id[(i * modules) + (modules - start - 1)] = layerid[layer];
}
start--;
stop++;
}
for (i = 0; i < modules; i++) {
for (j = 0; j < modules; j++) {
if (id[(i * modules) + j] & 0x02) {
grid[(((i * 6) + 1) * size) + (j * 6) + 1] = '1';
}
if (id[(i * modules) + j] & 0x01) {
grid[(((i * 6) + 1) * size) + (j * 6) + 2] = '1';
}
}
}
}
INTERNAL int zint_gridmatrix(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
int warn_number = 0;
int size, modules, error_number;
int auto_layers, min_layers, layers, auto_ecc_level, min_ecc_level, ecc_level;
int x, y, i;
int full_multibyte;
char binary[9300];
int data_cw, input_latch = 0;
unsigned char word[1460] = {0};
int data_max, reader = 0;
const struct zint_structapp *p_structapp = NULL;
int size_squared;
int bin_len;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
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 *grid;
z_segs_cpy(symbol, segs, seg_count, local_segs);
full_multibyte = (symbol->option_3 & 0xFF) == ZINT_FULL_MULTIBYTE;
if ((symbol->input_mode & 0x07) == DATA_MODE) {
zint_gb2312_cpy_segs(symbol, local_segs, seg_count, ddata, full_multibyte);
} else {
unsigned int *dd = ddata;
for (i = 0; i < seg_count; i++) {
int eci = 0;
if (local_segs[i].eci != 0 && local_segs[i].eci != 29) {
error_number = zint_gb2312_utf8_to_eci(local_segs[i].eci, local_segs[i].source, &local_segs[i].length,
dd, full_multibyte);
if (error_number == 0) {
eci = local_segs[i].eci;
} else {
return z_errtxtf(error_number, symbol, 535, "Invalid character in input for ECI '%d'",
local_segs[i].eci);
}
}
if (!eci) {
error_number = zint_gb2312_utf8(symbol, local_segs[i].source, &local_segs[i].length, dd);
if (error_number != 0) {
return error_number;
}
eci = 29;
}
if (content_segs && eci) {
z_ct_set_seg_eci(symbol, i, eci);
}
dd += local_segs[i].length;
}
}
if (symbol->output_options & READER_INIT) reader = 1;
if (symbol->structapp.count) {
if (symbol->structapp.count < 2 || symbol->structapp.count > 16) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 536,
"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, 537,
"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, 538,
"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, 539, "Invalid Structured Append ID (digits only)");
}
if (id > 255) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 530,
"Structured Append ID value '%d' out of range (0 to 255)", id);
}
}
p_structapp = &symbol->structapp;
}
if (symbol->eci > 811799) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 533, "ECI code '%d' out of range (0 to 811799)",
symbol->eci);
}
error_number = gm_encode_segs(ddata, local_segs, seg_count, binary, reader, p_structapp, &bin_len, debug_print);
if (error_number != 0) {
return z_errtxt(error_number, symbol, 531, "Input too long, requires too many codewords (maximum 1313)");
}
data_cw = bin_len / 7;
auto_layers = 13;
for (i = 12; i > 0; i--) {
if (gm_recommend_cw[(i - 1)] >= data_cw) {
auto_layers = i;
}
}
min_layers = 13;
for (i = 12; i > 0; i--) {
if (gm_max_cw[(i - 1)] >= data_cw) {
min_layers = i;
}
}
layers = auto_layers;
if (symbol->option_2 >= 1 && symbol->option_2 <= 13) {
input_latch = 1;
if (symbol->option_2 >= min_layers) {
layers = symbol->option_2;
} else {
return ZEXT z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 534,
"Input too long for Version %1$d, requires %2$d codewords (maximum %3$d)",
symbol->option_2, data_cw, gm_max_cw[symbol->option_2 - 1]);
}
}
auto_ecc_level = 3;
if (layers == 1) {
auto_ecc_level = 5;
} else if (layers == 2 || layers == 3) {
auto_ecc_level = 4;
}
ecc_level = auto_ecc_level;
min_ecc_level = 1;
if (layers == 1) {
min_ecc_level = 4;
} else if (layers == 2) {
min_ecc_level = 2;
}
if (symbol->option_1 >= 1 && symbol->option_1 <= 5) {
if (symbol->option_1 >= min_ecc_level) {
ecc_level = symbol->option_1;
} else {
ecc_level = min_ecc_level;
}
}
if (data_cw > gm_data_codewords[5 * (layers - 1) + (ecc_level - 1)]) {
if (input_latch && ecc_level > min_ecc_level) {
do {
ecc_level--;
} while (data_cw > gm_data_codewords[5 * (layers - 1) + (ecc_level - 1)] && ecc_level > min_ecc_level);
}
while (data_cw > gm_data_codewords[5 * (layers - 1) + (ecc_level - 1)] && layers < 13) {
layers++;
}
while (data_cw > gm_data_codewords[5 * (layers - 1) + (ecc_level - 1)] && ecc_level > 1) {
ecc_level--;
}
}
data_max = 1313;
switch (ecc_level) {
case 2: data_max = 1167; break;
case 3: data_max = 1021; break;
case 4: data_max = 875; break;
case 5: data_max = 729; break;
}
if (data_cw > data_max) {
return ZEXT z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 532,
"Input too long for ECC level %1$d, requires %2$d codewords (maximum %3$d)",
ecc_level, data_cw, data_max);
}
if (debug_print) {
printf("Layers: %d, ECC level: %d, Data Codewords: %d\n", layers, ecc_level, data_cw);
}
symbol->option_1 = ecc_level;
symbol->option_2 = layers;
gm_add_ecc(binary, data_cw, layers, ecc_level, word);
#ifdef ZINT_TEST
if (symbol->debug & ZINT_DEBUG_TEST) z_debug_test_codeword_dump(symbol, word, data_cw);
#endif
size = 6 + (layers * 12);
modules = 1 + (layers * 2);
size_squared = size * size;
grid = (char *) z_alloca(size_squared);
memset(grid, '0', size_squared);
gm_place_data_in_grid(word, grid, modules, size);
gm_place_layer_id(grid, size, layers, ecc_level);
for (x = 0; x < modules; x++) {
const int x_offset = x * 6;
int dark = !(x & 1);
for (y = 0; y < modules; y++) {
if (dark) {
const int y_offset = y * 6 * size;
for (i = 0; i < 5; i++) {
grid[y_offset + x_offset + i] = '1';
grid[y_offset + 5 * size + x_offset + i] = '1';
grid[y_offset + i * size + x_offset] = '1';
grid[y_offset + i * size + x_offset + 5] = '1';
}
grid[y_offset + 5 * size + x_offset + 5] = '1';
}
dark = !dark;
}
}
symbol->width = size;
symbol->rows = size;
for (x = 0; x < size; x++) {
for (y = 0; y < size; y++) {
if (grid[(y * size) + x] == '1') {
z_set_module(symbol, y, x);
}
}
symbol->row_height[x] = 1;
}
symbol->height = size;
return warn_number;
}