diff options
author | Tae-Young Chung <ty83.chung@samsung.com> | 2020-06-22 11:16:33 +0900 |
---|---|---|
committer | Tae-Young Chung <ty83.chung@samsung.com> | 2020-06-22 13:32:26 +0900 |
commit | 0428f8a17e78dae97a8774a0ec42f48f85abcb88 (patch) | |
tree | 100c5b5a6d1d6f996294ead7474f31703a456339 /backend/qr.c | |
parent | f18ddd9e3e6afc1edf5d030dd32647b3eac5462b (diff) | |
download | libzint-0428f8a17e78dae97a8774a0ec42f48f85abcb88.tar.gz libzint-0428f8a17e78dae97a8774a0ec42f48f85abcb88.tar.bz2 libzint-0428f8a17e78dae97a8774a0ec42f48f85abcb88.zip |
Bump to version 2.7.1submit/tizen/20200708.035054submit/tizen/20200706.003724submit/tizen/20200702.015201submit/tizen/20200701.041707accepted/tizen/unified/20200708.125323
zint is originally GPL v3 for an whole package
but backend can be used as BSD-3 as
The backed part of zint-code is updated to version 2.7.1
https://sourceforge.net/p/zint/code/ci/master/tree/
Change-Id: I779a9f70f93f0202affe41a7644d9e4bfb810123
Signed-off-by: Tae-Young Chung <ty83.chung@samsung.com>
Diffstat (limited to 'backend/qr.c')
-rw-r--r-- | backend/qr.c | 5195 |
1 files changed, 2965 insertions, 2230 deletions
diff --git a/backend/qr.c b/backend/qr.c index 2fe6412..40a1c32 100644 --- a/backend/qr.c +++ b/backend/qr.c @@ -1,8 +1,7 @@ -/* qr.c Handles QR Code */ +/* qr.c Handles QR Code, Micro QR Code, UPNQR and rMQR -/* libzint - the open source barcode library - Copyright (C) 2009 Robin Stuart <robin@zint.org.uk> + Copyright (C) 2009 - 2020 Robin Stuart <rstuart114@gmail.com> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -28,7 +27,8 @@ 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. -*/ + */ +/* vim: set ts=4 sw=4 et : */ #include <string.h> #ifdef _MSC_VER @@ -39,2334 +39,3069 @@ #include "sjis.h" #include "qr.h" #include "reedsol.h" +#include <assert.h> + +INTERNAL int utf_to_eci(const int eci, const unsigned char source[], unsigned char dest[], size_t *length); /* Convert Unicode to other encodings */ + +/* Returns true if input glyph is in the Alphanumeric set */ +static int is_alpha(const unsigned int glyph, const int gs1) { + int retval = 0; + + if ((glyph >= '0') && (glyph <= '9')) { + retval = 1; + } else if ((glyph >= 'A') && (glyph <= 'Z')) { + retval = 1; + } else if (gs1 && glyph == '[') { + retval = 1; + } else { + switch (glyph) { + case ' ': + case '$': + case '%': + case '*': + case '+': + case '-': + case '.': + case '/': + case ':': + retval = 1; + break; + } + } + + return retval; +} + +/* 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 in_numeric(const unsigned int jisdata[], const size_t length, const unsigned int posn, unsigned int* p_end, unsigned int* p_cost) { + unsigned int i, digit_cnt; + + if (posn < *p_end) { + return 1; + } + + /* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times QR_MULT) */ + for (i = posn; i < length && i < posn + 4 && jisdata[i] >= '0' && jisdata[i] <= '9'; i++); + + digit_cnt = i - 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 in_alpha(const unsigned int jisdata[], const size_t length, const unsigned int posn, unsigned int* p_end, unsigned int* p_cost, unsigned int* p_pcent, unsigned int gs1) { + int two_alphas; + + if (posn < *p_end) { + if (gs1 && *p_pcent) { + /* Previous 2nd char was a percent, so allow for second half of doubled-up percent here */ + two_alphas = posn < length - 1 && is_alpha(jisdata[posn + 1], gs1); + *p_cost = two_alphas ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */; + *p_pcent = 0; + } + return 1; + } + + /* Attempt to calculate the average 'cost' of using alphanumeric mode in number of bits (times QR_MULT) */ + if (!is_alpha(jisdata[posn], gs1)) { + *p_end = 0; + *p_pcent = 0; + return 0; + } + + if (gs1 && jisdata[posn] == '%') { /* Must double-up so counts as 2 chars */ + *p_end = posn + 1; + *p_cost = 66; /* 11 * QR_MULT */ + *p_pcent = 0; + return 1; + } + + two_alphas = posn < length - 1 && is_alpha(jisdata[posn + 1], gs1); + + *p_end = two_alphas ? posn + 2 : posn + 1; + *p_cost = two_alphas ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */; + *p_pcent = two_alphas && gs1 && jisdata[posn + 1] == '%'; /* 2nd char is percent */ + return 1; +} -int in_alpha(int glyph) { - /* Returns true if input glyph is in the Alphanumeric set */ - int retval = 0; - char cglyph = (char) glyph; - - if((cglyph >= '0') && (cglyph <= '9')) { - retval = 1; - } - if((cglyph >= 'A') && (cglyph <= 'Z')) { - retval = 1; - } - switch (cglyph) { - case ' ': - case '$': - case '%': - case '*': - case '+': - case '-': - case '.': - case '/': - case ':': - retval = 1; - break; - } - - return retval; +/* Indexes into 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 mode_types[] = { 'N', 'A', 'B', 'K', }; /* 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_GS1 5 /* GS1 mode (boolean) */ +#define QR_N_END 6 /* Numeric end index */ +#define QR_N_COST 7 /* Numeric cost */ +#define QR_A_END 8 /* Alpha end index */ +#define QR_A_COST 9 /* Alpha cost */ +#define QR_A_PCENT 10 /* Alpha 2nd char percent (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[]) { + static const 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 */ + if (state[QR_N] != 0) { /* Numeric non-zero in all configs */ + return state; /* Already set */ + } + + version = state[QR_VER]; + + if (version < RMQR_VERSION) { /* QRCODE */ + if (version < 10) { + memcpy(state, head_costs, 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; } -void define_mode(char mode[], int jisdata[], int length, int gs1) -{ - /* Values placed into mode[] are: K = Kanji, B = Binary, A = Alphanumeric, N = Numeric */ - int i, mlen, j; - - for(i = 0; i < length; i++) { - if(jisdata[i] > 0xff) { - mode[i] = 'K'; - } else { - mode[i] = 'B'; - if(in_alpha(jisdata[i])) { mode[i] = 'A'; } - if(gs1 && (jisdata[i] == '[')) { mode[i] = 'A'; } - if((jisdata[i] >= '0') && (jisdata[i] <= '9')) { mode[i] = 'N'; } - } - } - - /* If less than 6 numeric digits together then don't use numeric mode */ - for(i = 0; i < length; i++) { - if(mode[i] == 'N') { - if(((i != 0) && (mode[i - 1] != 'N')) || (i == 0)) { - mlen = 0; - while (((mlen + i) < length) && (mode[mlen + i] == 'N')) { - mlen++; - }; - if(mlen < 6) { - for(j = 0; j < mlen; j++) { - mode[i + j] = 'A'; - } - } - } - } - } - - /* If less than 4 alphanumeric characters together then don't use alphanumeric mode */ - for(i = 0; i < length; i++) { - if(mode[i] == 'A') { - if(((i != 0) && (mode[i - 1] != 'A')) || (i == 0)) { - mlen = 0; - while (((mlen + i) < length) && (mode[mlen + i] == 'A')) { - mlen++; - }; - if(mlen < 6) { - for(j = 0; j < mlen; j++) { - mode[i + j] = 'B'; - } - } - } - } - } +/* Costs of switching modes from k to j */ +static unsigned int qr_switch_cost(unsigned int state[], const int k, const int j) { + (void)k; /* Unused */ + return state[j]; /* Same as head cost */ } -int estimate_binary_length(char mode[], int length, int gs1) -{ - /* Make an estimate (worst case scenario) of how long the binary string will be */ - int i, count = 0; - char current = 0; - int a_count = 0; - int n_count = 0; - - if(gs1) { count += 4; } - - for(i = 0; i < length; i++) { - if(mode[i] != current) { - switch(mode[i]) { - case 'K': count += 12 + 4; current = 'K'; break; - case 'B': count += 16 + 4; current = 'B'; break; - case 'A': count += 13 + 4; current = 'A'; a_count = 0; break; - case 'N': count += 14 + 4; current = 'N'; n_count = 0; break; - } - } - - switch(mode[i]) { - case 'K': count += 13; break; - case 'B': count += 8; break; - case 'A': - a_count++; - if((a_count & 1) == 0) { - count += 5; // 11 in total - a_count = 0; - } - else - count += 6; - break; - case 'N': - n_count++; - if((n_count % 3) == 0) { - count += 3; // 10 in total - n_count = 0; - } - else if ((n_count & 1) == 0) - count += 3; // 7 in total - else - count += 4; - break; - } - } - - return count; +/* Calculate cost of encoding character */ +static void qr_cur_cost(unsigned int state[], const unsigned int jisdata[], const size_t length, const int i, char* char_modes, unsigned int prev_costs[], unsigned int cur_costs[]) { + int cm_i = i * QR_NUM_MODES, m1, m2; + unsigned int version = state[QR_VER]; + unsigned int gs1 = state[QR_GS1]; + unsigned int* p_numeric_end = &state[QR_N_END]; + unsigned int* p_numeric_cost = &state[QR_N_COST]; + unsigned int* p_alpha_end = &state[QR_A_END]; + unsigned int* p_alpha_cost = &state[QR_A_COST]; + unsigned int* p_alpha_pcent = &state[QR_A_PCENT]; + + m1 = version == MICROQR_VERSION; + m2 = version == MICROQR_VERSION + 1; + + if (jisdata[i] > 0xFF) { + cur_costs[QR_B] = prev_costs[QR_B] + ((m1 || m2) ? QR_MICROQR_MAX : 96); /* 16 * QR_MULT */ + char_modes[cm_i + QR_B] = 'B'; + cur_costs[QR_K] = prev_costs[QR_K] + ((m1 || m2) ? QR_MICROQR_MAX : 78); /* 13 * QR_MULT */ + char_modes[cm_i + QR_K] = 'K'; + } else { + if (in_numeric(jisdata, length, i, p_numeric_end, p_numeric_cost)) { + cur_costs[QR_N] = prev_costs[QR_N] + *p_numeric_cost; + char_modes[cm_i + QR_N] = 'N'; + } + if (in_alpha(jisdata, length, i, p_alpha_end, p_alpha_cost, p_alpha_pcent, gs1)) { + cur_costs[QR_A] = prev_costs[QR_A] + (m1 ? QR_MICROQR_MAX : *p_alpha_cost); + char_modes[cm_i + QR_A] = 'A'; + } + cur_costs[QR_B] = prev_costs[QR_B] + ((m1 || m2) ? QR_MICROQR_MAX : 48); /* 8 * QR_MULT */ + char_modes[cm_i + QR_B] = 'B'; + } } -static inline void qr_bscan(char *binary, int data, int h) -{ - for (; h; h>>=1) { - concat(binary, data & h ? "1" : "0"); - } +static void qr_define_mode(char mode[], const unsigned int jisdata[], const size_t length, const int gs1, const int version, const int debug) { + unsigned int state[11] = { + 0 /*N*/, 0 /*A*/, 0 /*B*/, 0 /*K*/, + (unsigned int) version, (unsigned int) gs1, + 0 /*numeric_end*/, 0 /*numeric_cost*/, 0 /*alpha_end*/, 0 /*alpha_cost*/, 0 /*alpha_pcent*/ + }; + + pn_define_mode(mode, jisdata, length, debug, state, mode_types, QR_NUM_MODES, qr_head_costs, qr_switch_cost, NULL, qr_cur_cost); +} + +/* Return mode indicator bits based on version */ +static int 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 cci_bits(const int version, const int mode) { + static const int 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 short int* rmqr_ccis[QR_NUM_MODES] = { + rmqr_numeric_cci, rmqr_alphanum_cci, rmqr_byte_cci, rmqr_kanji_cci, + }; + int mode_index = strchr(mode_types, mode) - mode_types; + + 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 */ } -void qr_binary(int datastream[], int version, int target_binlen, char mode[], int jisdata[], int length, int gs1, int est_binlen) -{ - /* Convert input data to a binary stream and add padding */ - int position = 0; - int short_data_block_length, i, scheme = 1; - char data_block, padbits; - int current_binlen, current_bytes; - int toggle, percent; - +/* Returns mode indicator based on version and mode */ +static const char* mode_indicator(const int version, const int mode) { + static const char* mode_indicators[6][QR_NUM_MODES] = { + /* N A B K */ + { "0001", "0010", "0100", "1000", }, /* QRCODE */ + { "001", "010", "011", "100", }, /* RMQR */ + { "", "", "", "", }, /* MICROQR */ + { "0", "1", "", "", }, + { "00", "01", "10", "11", }, + { "000", "001", "010", "011", }, + }; + + int mode_index = strchr(mode_types, mode) - mode_types; + + 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 */ +} + +/* Returns terminator bits based on version */ +static int 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 (Note not actually using this at the moment) */ +} + +/* Convert input data to a binary stream and add padding */ +static void qr_binary(unsigned char datastream[], const int version, const int target_codewords, const char mode[], const unsigned int jisdata[], const size_t length, + const int gs1, const int eci, const int est_binlen, const int debug) { + unsigned int position = 0; + int i; + int termbits, padbits; + int current_binlen, current_bytes; + int toggle, percent; + int percent_count; + #ifndef _MSC_VER - char binary[est_binlen + 12]; + char binary[est_binlen + 12]; #else - char* binary = (char *)_alloca(est_binlen + 12); -#endif - strcpy(binary, ""); - - if(gs1) { - concat(binary, "0101"); /* FNC1 */ - } - - if(version <= 9) { - scheme = 1; - } else if((version >= 10) && (version <= 26)) { - scheme = 2; - } else if(version >= 27) { - scheme = 3; - } - -#ifdef _DEBUG_MODE_ - for(i = 0; i < length; i++) { - printf("%c", mode[i]); - } - printf("\n"); + char* binary = (char *) _alloca(est_binlen + 12); #endif + strcpy(binary, ""); + + if (gs1) { /* Not applicable to MICROQR */ + if (version < RMQR_VERSION) { + strcat(binary, "0101"); /* FNC1 */ + } else { + strcat(binary, "101"); + } + } + + if (eci != 0) { /* Not applicable to RMQR or MICROQR */ + strcat(binary, "0111"); /* ECI (Table 4) */ + if (eci <= 127) { + bin_append(eci, 8, binary); /* 000000 to 000127 */ + } else if (eci <= 16383) { + bin_append(0x8000 + eci, 16, binary); /* 000000 to 016383 */ + } else { + bin_append(0xC00000 + eci, 24, binary); /* 000000 to 999999 */ + } + } + + if (debug & ZINT_DEBUG_PRINT) { + for (i = 0; i < (int) length; i++) { + printf("%c", mode[i]); + } + printf("\n"); + } + + percent = 0; + + do { + char data_block = mode[position]; + int short_data_block_length = 0; + int double_byte = 0; + do { + if (data_block == 'B' && jisdata[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)); + + switch (data_block) { + case 'K': + /* Kanji mode */ + /* Mode indicator */ + strcat(binary, mode_indicator(version, data_block)); + + /* Character count indicator */ + bin_append(short_data_block_length, cci_bits(version, data_block), binary); + + if (debug & ZINT_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 = jisdata[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); + + bin_append(prod, 13, binary); + + if (debug & ZINT_DEBUG_PRINT) { + printf("0x%04X ", prod); + } + } + + if (debug & ZINT_DEBUG_PRINT) { + printf("\n"); + } + + break; + case 'B': + /* Byte mode */ + /* Mode indicator */ + strcat(binary, mode_indicator(version, data_block)); + + /* Character count indicator */ + bin_append(short_data_block_length + double_byte, cci_bits(version, data_block), binary); + + if (debug & ZINT_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 = jisdata[position + i]; + + if (gs1 && (byte == '[')) { + byte = 0x1d; /* FNC1 */ + } + + bin_append(byte, byte > 0xFF ? 16 : 8, binary); + + if (debug & ZINT_DEBUG_PRINT) { + printf("0x%02X(%d) ", byte, byte); + } + } + + if (debug & ZINT_DEBUG_PRINT) { + printf("\n"); + } + + break; + case 'A': + /* Alphanumeric mode */ + /* Mode indicator */ + strcat(binary, mode_indicator(version, data_block)); + + percent_count = 0; + if (gs1) { + for (i = 0; i < short_data_block_length; i++) { + if (jisdata[position + i] == '%') { + percent_count++; + } + } + } + + /* Character count indicator */ + bin_append(short_data_block_length + percent_count, cci_bits(version, data_block), binary); + + if (debug & ZINT_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 && (jisdata[position + i] == '%')) { + first = posn(RHODIUM, '%'); + second = posn(RHODIUM, '%'); + count = 2; + prod = (first * 45) + second; + i++; + } else { + if (gs1 && (jisdata[position + i] == '[')) { + first = posn(RHODIUM, '%'); /* FNC1 */ + } else { + first = posn(RHODIUM, (char) jisdata[position + i]); + } + count = 1; + i++; + prod = first; + + if (i < short_data_block_length && mode[position + i] == 'A') { + if (gs1 && (jisdata[position + i] == '%')) { + second = posn(RHODIUM, '%'); + count = 2; + prod = (first * 45) + second; + percent = 1; + } else { + if (gs1 && (jisdata[position + i] == '[')) { + second = posn(RHODIUM, '%'); /* FNC1 */ + } else { + second = posn(RHODIUM, (char) jisdata[position + i]); + } + count = 2; + i++; + prod = (first * 45) + second; + } + } + } + } else { + first = posn(RHODIUM, '%'); + count = 1; + i++; + prod = first; + percent = 0; + + if (i < short_data_block_length && mode[position + i] == 'A') { + if (gs1 && (jisdata[position + i] == '%')) { + second = posn(RHODIUM, '%'); + count = 2; + prod = (first * 45) + second; + percent = 1; + } else { + if (gs1 && (jisdata[position + i] == '[')) { + second = posn(RHODIUM, '%'); /* FNC1 */ + } else { + second = posn(RHODIUM, (char) jisdata[position + i]); + } + count = 2; + i++; + prod = (first * 45) + second; + } + } + } + + bin_append(prod, 1 + (5 * count), binary); + + if (debug & ZINT_DEBUG_PRINT) { + printf("0x%X ", prod); + } + } + + if (debug & ZINT_DEBUG_PRINT) { + printf("\n"); + } + + break; + case 'N': + /* Numeric mode */ + /* Mode indicator */ + strcat(binary, mode_indicator(version, data_block)); + + /* Character count indicator */ + bin_append(short_data_block_length, cci_bits(version, data_block), binary); + + if (debug & ZINT_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 = posn(NEON, (char) jisdata[position + i]); + count = 1; + prod = first; + + if (i + 1 < short_data_block_length && mode[position + i + 1] == 'N') { + int second = posn(NEON, (char) jisdata[position + i + 1]); + count = 2; + prod = (prod * 10) + second; + + if (i + 2 < short_data_block_length && mode[position + i + 2] == 'N') { + int third = posn(NEON, (char) jisdata[position + i + 2]); + count = 3; + prod = (prod * 10) + third; + } + } + + bin_append(prod, 1 + (3 * count), binary); + + if (debug & ZINT_DEBUG_PRINT) { + printf("0x%X(%d) ", prod, prod); + } + + i += count; + }; + + if (debug & ZINT_DEBUG_PRINT) { + printf("\n"); + } + + break; + } + + position += short_data_block_length; + } while (position < length); + + if (version >= MICROQR_VERSION && version < MICROQR_VERSION + 4) { + /* MICROQR does its own terminating/padding */ + strcpy((char*)datastream, binary); + return; + } + + /* Terminator */ + current_binlen = (int)strlen(binary); + termbits = 8 - current_binlen % 8; + if (termbits == 8) { + termbits = 0; + } + current_bytes = (current_binlen + termbits) / 8; + if (termbits || current_bytes < target_codewords) { + int max_termbits = terminator_bits(version); + termbits = termbits < max_termbits && current_bytes == target_codewords ? termbits : max_termbits; + bin_append(0, termbits, binary); + current_binlen += termbits; + } + + /* Padding bits */ + padbits = 8 - current_binlen % 8; + if (padbits == 8) { + padbits = 0; + } + if (padbits) { + current_bytes = (current_binlen + padbits) / 8; + bin_append(0, padbits, binary); + } + + /* Put data into 8-bit codewords */ + for (i = 0; i < current_bytes; i++) { + int p; + datastream[i] = 0x00; + for (p = 0; p < 8; p++) { + if (binary[i * 8 + 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 & ZINT_DEBUG_PRINT) { + printf("Resulting codewords:\n\t"); + for (i = 0; i < target_codewords; i++) { + printf("0x%02X ", datastream[i]); + } + printf("\n"); + } +} - percent = 0; - - do { - data_block = mode[position]; - short_data_block_length = 0; - do { - short_data_block_length++; - } while (((short_data_block_length + position) < length) && (mode[position + short_data_block_length] == data_block)); - - switch(data_block) { - case 'K': - /* Kanji mode */ - /* Mode indicator */ - concat(binary, "1000"); - - /* Character count indicator */ - qr_bscan(binary, short_data_block_length, 0x20 << (scheme*2)); /* scheme = 1..3 */ -#ifdef _DEBUG_MODE_ - printf("Kanji block (length %d)\n\t", short_data_block_length); -#endif - - /* Character representation */ - for(i = 0; i < short_data_block_length; i++) { - int jis = jisdata[position + i]; - int msb, lsb, prod; - - if(jis > 0x9fff) { jis -= 0xc140; } - msb = (jis & 0xff00) >> 4; - lsb = (jis & 0xff); - prod = (msb * 0xc0) + lsb; - - qr_bscan(binary, prod, 0x1000); -#ifdef _DEBUG_MODE_ - printf("0x%4X ", prod); -#endif - } -#ifdef _DEBUG_MODE_ - printf("\n"); +/* Split data into blocks, add error correction and then interleave the blocks and error correction data */ +static void add_ecc(unsigned char fullstream[], const unsigned char datastream[], const int version, const int data_cw, const int blocks, int debug) { + 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, posn; +#ifdef _MSC_VER + unsigned char* data_block; + unsigned char* ecc_block; + unsigned char* interleaved_data; + unsigned char* interleaved_ecc; #endif - - break; - case 'B': - /* Byte mode */ - /* Mode indicator */ - concat(binary, "0100"); - - /* Character count indicator */ - qr_bscan(binary, short_data_block_length, scheme > 1 ? 0x8000 : 0x80); /* scheme = 1..3 */ -#ifdef _DEBUG_MODE_ - printf("Byte block (length %d)\n\t", short_data_block_length); + + if (version < RMQR_VERSION) { + ecc_cw = qr_total_codewords[version - 1] - data_cw; + } else { + ecc_cw = rmqr_total_codewords[version - RMQR_VERSION] - data_cw; + } + + 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; + + +#ifndef _MSC_VER + unsigned char data_block[short_data_block_length + 1]; + unsigned char ecc_block[ecc_block_length]; + unsigned char interleaved_data[data_cw]; + unsigned char interleaved_ecc[ecc_cw]; +#else + data_block = (unsigned char *) _alloca(short_data_block_length + 1); + ecc_block = (unsigned char *) _alloca(ecc_block_length); + interleaved_data = (unsigned char *) _alloca(data_cw); + interleaved_ecc = (unsigned char *) _alloca(ecc_cw); #endif - /* Character representation */ - for(i = 0; i < short_data_block_length; i++) { - int byte = jisdata[position + i]; - - if(gs1 && (byte == '[')) { - byte = 0x1d; /* FNC1 */ - } - - qr_bscan(binary, byte, 0x80); -#ifdef _DEBUG_MODE_ - printf("0x%2X(%d) ", byte, byte); + + 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 < ecc_block_length; j++) { + ecc_block[j] = 0; + } + + for (j = 0; j < length_this_block; j++) { + data_block[j] = datastream[posn + j]; + } + + rs_init_gf(0x11d); + rs_init_code(ecc_block_length, 0); + rs_encode(length_this_block, data_block, ecc_block); + rs_free(); + + if (debug & ZINT_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) { + printf(" "); + } + printf(" // "); + for (j = 0; j < ecc_block_length; j++) { + printf("%2X ", ecc_block[ecc_block_length - j - 1]); + } + printf("\n"); + } + + for (j = 0; j < short_data_block_length; j++) { + interleaved_data[(j * blocks) + i] = data_block[j]; + } + + if (i >= qty_short_blocks) { + /* NOLINT suppress clang-tidy warning: data_block[short_data_block_length] set for i >= qty_short_blocks */ + interleaved_data[(short_data_block_length * blocks) + (i - qty_short_blocks)] = data_block[short_data_block_length]; // NOLINT + } + + for (j = 0; j < ecc_block_length; j++) { + interleaved_ecc[(j * blocks) + i] = ecc_block[ecc_block_length - j - 1]; + } + + posn += length_this_block; + } + + for (j = 0; j < data_cw; j++) { + fullstream[j] = interleaved_data[j]; // NOLINT suppress clang-tidy warning: interleaved_data[data_cw] fully set + } + for (j = 0; j < ecc_cw; j++) { + fullstream[j + data_cw] = interleaved_ecc[j]; // NOLINT suppress clang-tidy warning: interleaved_ecc[ecc_cw] fully set + } + + if (debug & ZINT_DEBUG_PRINT) { + printf("\nData Stream: \n"); + for (j = 0; j < (data_cw + ecc_cw); j++) { + printf("%2X ", fullstream[j]); + } + printf("\n"); + } +} + +static void 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 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 setup_grid(unsigned char* grid,const int size,const int version) { + int i, toggle = 1; + + /* 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 */ + place_finder(grid, size, 0, 0); + place_finder(grid, size, 0, size - 7); + 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; + + /* 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)) { + 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 cwbit(const unsigned char* fullstream, const int i) { + int resultant = 0; + + if (fullstream[(i / 8)] & (0x80 >> (i % 8))) { + resultant = 1; + } + + return resultant; +} + +static void populate_grid(unsigned char* grid, const int h_size, const int v_size, const unsigned char* fullstream, const int cw) { + 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 = (h_size - 2) - (row * 2); + + if ((x < 6) && (v_size == h_size)) + x--; /* skip over vertical timing pattern */ + + if (!(grid[(y * h_size) + (x + 1)] & 0xf0)) { + if (cwbit(fullstream, i)) { + grid[(y * h_size) + (x + 1)] = 0x01; + } else { + grid[(y * h_size) + (x + 1)] = 0x00; + } + i++; + } + + if (i < n) { + if (!(grid[(y * h_size) + x] & 0xf0)) { + if (cwbit(fullstream, i)) { + grid[(y * h_size) + x] = 0x01; + } else { + grid[(y * h_size) + x] = 0x00; + } + i++; + } + } + + if (direction) { + y--; + } else { + y++; + } + if (y == -1) { + /* reached the top */ + row++; + y = 0; + direction = 0; + } + if (y == v_size) { + /* reached the bottom */ + row++; + y = v_size - 1; + direction = 1; + } + } +} + +#ifdef ZINTLOG + +static int append_log(char log) { + FILE *file; + + file = fopen("zintlog.txt", "a+"); + fprintf(file, "%c", log); + fclose(file); + return 0; +} + +static int write_log(char log[]) { + FILE *file; + + file = fopen("zintlog.txt", "a+"); + fprintf(file, log); /*writes*/ + fprintf(file, "\r\n"); /*writes*/ + fclose(file); + return 0; +} #endif - } -#ifdef _DEBUG_MODE_ - printf("\n"); + +static int evaluate(unsigned char *eval,const int size,const int pattern) { + int x, y, block, weight; + int result = 0; + char state; + int p; + int dark_mods; + int percentage, k; + int a, b, afterCount, beforeCount; +#ifdef ZINTLOG + int result_b = 0; + char str[15]; #endif - break; - case 'A': - /* Alphanumeric mode */ - /* Mode indicator */ - concat(binary, "0010"); - - /* Character count indicator */ - qr_bscan(binary, short_data_block_length, 0x40 << (2 * scheme)); /* scheme = 1..3 */ -#ifdef _DEBUG_MODE_ - printf("Alpha block (length %d)\n\t", short_data_block_length); + +#ifndef _MSC_VER + char local[size * size]; +#else + char* local = (char *) _alloca((size * size) * sizeof (char)); #endif - /* Character representation */ - i = 0; - while ( i < short_data_block_length ) { - int count; - int first = 0, second = 0, prod; - - if(percent == 0) { - if(gs1 && (jisdata[position + i] == '%')) { - first = posn(RHODIUM, '%'); - second = posn(RHODIUM, '%'); - count = 2; - prod = (first * 45) + second; - i++; - } else { - if(gs1 && (jisdata[position + i] == '[')) { - first = posn(RHODIUM, '%'); /* FNC1 */ - } else { - first = posn(RHODIUM, (char) jisdata[position + i]); - } - count = 1; - i++; - prod = first; - - if(mode[position + i] == 'A') { - if(gs1 && (jisdata[position + i] == '%')) { - second = posn(RHODIUM, '%'); - count = 2; - prod = (first * 45) + second; - percent = 1; - } else { - if(gs1 && (jisdata[position + i] == '[')) { - second = posn(RHODIUM, '%'); /* FNC1 */ - } else { - second = posn(RHODIUM, (char) jisdata[position + i]); - } - count = 2; - i++; - prod = (first * 45) + second; - } - } - } - } else { - first = posn(RHODIUM, '%'); - count = 1; - i++; - prod = first; - percent = 0; - - if(mode[position + i] == 'A') { - if(gs1 && (jisdata[position + i] == '%')) { - second = posn(RHODIUM, '%'); - count = 2; - prod = (first * 45) + second; - percent = 1; - } else { - if(gs1 && (jisdata[position + i] == '[')) { - second = posn(RHODIUM, '%'); /* FNC1 */ - } else { - second = posn(RHODIUM, (char) jisdata[position + i]); - } - count = 2; - i++; - prod = (first * 45) + second; - } - } - } - - qr_bscan(binary, prod, count == 2 ? 0x400 : 0x20); /* count = 1..2 */ -#ifdef _DEBUG_MODE_ - printf("0x%4X ", prod); + + +#ifdef ZINTLOG + write_log(""); + sprintf(str, "%d", pattern); + write_log(str); #endif - }; -#ifdef _DEBUG_MODE_ - printf("\n"); + + /* all eight bitmask variants have been encoded in the 8 bits of the bytes + * that make up the grid array. select them for evaluation according to the + * desired pattern.*/ + for (x = 0; x < size; x++) { + for (y = 0; y < size; y++) { + if ((eval[(y * size) + x] & (0x01 << pattern)) != 0) { + local[(y * size) + x] = '1'; + } else { + local[(y * size) + x] = '0'; + } + } + } + +#ifdef ZINTLOG + //bitmask output + for (y = 0; y < size; y++) { + strcpy(str, ""); + for (x = 0; x < size; x++) { + state = local[(y * size) + x]; + append_log(state); + } + write_log(""); + } + write_log(""); #endif - - break; - case 'N': - /* Numeric mode */ - /* Mode indicator */ - concat(binary, "0001"); - - /* Character count indicator */ - qr_bscan(binary, short_data_block_length, 0x80 << (2 * scheme)); /* scheme = 1..3 */ -#ifdef _DEBUG_MODE_ - printf("Number block (length %d)\n\t", short_data_block_length); + + /* Test 1: Adjacent modules in row/column in same colour */ + /* Vertical */ + for (x = 0; x < size; x++) { + state = local[x]; + block = 0; + for (y = 0; y < size; y++) { + if (local[(y * size) + x] == state) { + block++; + } else { + if (block > 5) { + result += (3 + (block - 5)); + } + block = 0; + state = local[(y * size) + x]; + } + } + if (block > 5) { + result += (3 + (block - 5)); + } + } + + /* Horizontal */ + for (y = 0; y < size; y++) { + state = local[y * size]; + block = 0; + for (x = 0; x < size; x++) { + if (local[(y * size) + x] == state) { + block++; + } else { + if (block > 5) { + result += (3 + (block - 5)); + } + block = 0; + state = local[(y * size) + x]; + } + } + if (block > 5) { + result += (3 + (block - 5)); + } + } + +#ifdef ZINTLOG + /* output Test 1 */ + sprintf(str, "%d", result); + result_b = result; + write_log(str); #endif - /* Character representation */ - i = 0; - while ( i < short_data_block_length ) { - int count; - int first = 0, second = 0, third = 0, prod; - - first = posn(NEON, (char) jisdata[position + i]); - count = 1; - prod = first; - - if(mode[position + i + 1] == 'N') { - second = posn(NEON, (char) jisdata[position + i + 1]); - count = 2; - prod = (prod * 10) + second; - - if(mode[position + i + 2] == 'N') { - third = posn(NEON, (char) jisdata[position + i + 2]); - count = 3; - prod = (prod * 10) + third; - } - } - - qr_bscan(binary, prod, 1 << (3 * count)); /* count = 1..3 */ -#ifdef _DEBUG_MODE_ - printf("0x%4X (%d)", prod, prod); + + /* Test 2: Block of modules in same color */ + for (x = 0; x < size - 1; x++) { + for (y = 0; y < size - 1; y++) { + /* NOLINT suppress clang-tidy warning: local[size * size] fully set */ + if (((local[(y * size) + x] == local[((y + 1) * size) + x]) && // NOLINT + (local[(y * size) + x] == local[(y * size) + (x + 1)])) && + (local[(y * size) + x] == local[((y + 1) * size) + (x + 1)])) { // NOLINT + result += 3; + } + } + } + +#ifdef ZINTLOG + /* output Test 2 */ + sprintf(str, "%d", result - result_b); + result_b = result; + write_log(str); #endif - - i += count; - }; -#ifdef _DEBUG_MODE_ - printf("\n"); + + /* 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++) { + p = 0; + for (weight = 0; weight < 7; weight++) { + if (local[((y + weight) * size) + x] == '1') { + p += (0x40 >> weight); + } + } + if (p == 0x5d) { + /* Pattern found, check before and after */ + beforeCount = 0; + for (b = (y - 4); b < y; b++) { + if (b < 0) { + beforeCount++; + } else { + if (local[(b * size) + x] == '0') { + beforeCount++; + } else { + beforeCount = 0; + } + } + } + + afterCount = 0; + for (a = (y + 7); a <= (y + 10); a++) { + if (a >= size) { + afterCount++; + } else { + if (local[(a * size) + x] == '0') { + afterCount++; + } else { + afterCount = 0; + } + } + } + + if ((beforeCount == 4) || (afterCount == 4)) { + /* Pattern is preceeded or followed by light area + 4 modules wide */ + result += 40; + } + } + } + } + + /* Horizontal */ + for (y = 0; y < size; y++) { + for (x = 0; x < (size - 7); x++) { + p = 0; + for (weight = 0; weight < 7; weight++) { + if (local[(y * size) + x + weight] == '1') { + p += (0x40 >> weight); + } + } + if (p == 0x5d) { + /* Pattern found, check before and after */ + beforeCount = 0; + for (b = (x - 4); b < x; b++) { + if (b < 0) { + beforeCount++; + } else { + if (local[(y * size) + b] == '0') { + beforeCount++; + } else { + beforeCount = 0; + } + } + } + + afterCount = 0; + for (a = (x + 7); a <= (x + 10); a++) { + if (a >= size) { + afterCount++; + } else { + if (local[(y * size) + a] == '0') { + afterCount++; + } else { + afterCount = 0; + } + } + } + + if ((beforeCount == 4) || (afterCount == 4)) { + /* Pattern is preceeded or followed by light area + 4 modules wide */ + result += 40; + } + } + } + } + +#ifdef ZINTLOG + /* output Test 3 */ + sprintf(str, "%d", result - result_b); + result_b = result; + write_log(str); #endif - - break; - } - - position += short_data_block_length; - } while (position < length) ; - - /* Terminator */ - concat(binary, "0000"); - - current_binlen = strlen(binary); - padbits = 8 - (current_binlen % 8); - if(padbits == 8) { padbits = 0; } - current_bytes = (current_binlen + padbits) / 8; - - /* Padding bits */ - for(i = 0; i < padbits; i++) { - concat(binary, "0"); - } - - /* Put data into 8-bit codewords */ - for(i = 0; i < current_bytes; i++) { - datastream[i] = 0x00; - if(binary[i * 8] == '1') { datastream[i] += 0x80; } - if(binary[i * 8 + 1] == '1') { datastream[i] += 0x40; } - if(binary[i * 8 + 2] == '1') { datastream[i] += 0x20; } - if(binary[i * 8 + 3] == '1') { datastream[i] += 0x10; } - if(binary[i * 8 + 4] == '1') { datastream[i] += 0x08; } - if(binary[i * 8 + 5] == '1') { datastream[i] += 0x04; } - if(binary[i * 8 + 6] == '1') { datastream[i] += 0x02; } - if(binary[i * 8 + 7] == '1') { datastream[i] += 0x01; } - } - - /* Add pad codewords */ - toggle = 0; - for(i = current_bytes; i < target_binlen; i++) { - if(toggle == 0) { - datastream[i] = 0xec; - toggle = 1; - } else { - datastream[i] = 0x11; - toggle = 0; - } - } - -#ifdef _DEBUG_MODE_ - printf("Resulting codewords:\n\t"); - for(i = 0; i < target_binlen; i++) { - printf("0x%2X ", datastream[i]); - } - printf("\n"); + + /* Test 4: Proportion of dark modules in entire symbol */ + dark_mods = 0; + for (x = 0; x < size; x++) { + for (y = 0; y < size; y++) { + if (local[(y * size) + x] == '1') { + dark_mods++; + } + } + } + percentage = 100 * (dark_mods / (size * size)); + if (percentage <= 50) { + k = ((100 - percentage) - 50) / 5; + } else { + k = (percentage - 50) / 5; + } + + 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; } -void add_ecc(int fullstream[], int datastream[], int version, int data_cw, int blocks) -{ - /* Split data into blocks, add error correction and then interleave the blocks and error correction data */ - int ecc_cw = qr_total_codewords[version - 1] - data_cw; - int short_data_block_length = data_cw / blocks; - int qty_long_blocks = data_cw % blocks; - int qty_short_blocks = blocks - qty_long_blocks; - int ecc_block_length = ecc_cw / blocks; - int i, j, length_this_block, posn; - - +static void add_format_info_eval(unsigned char *eval,const int size,const int ecc_level,const int pattern) { + /* Add format information to grid */ + + int format = pattern; + unsigned int seq; + int i; + + switch (ecc_level) { + case LEVEL_L: format += 0x08; + break; + case LEVEL_Q: format += 0x18; + break; + case LEVEL_H: format += 0x10; + break; + } + + seq = qr_annex_c[format]; + + for (i = 0; i < 6; i++) { + eval[(i * size) + 8] = ((seq >> i) & 0x01) ? (0x01 >> pattern) : 0x00; + } + + for (i = 0; i < 8; i++) { + eval[(8 * size) + (size - i - 1)] = ((seq >> i) & 0x01) ? (0x01 >> pattern) : 0x00; + } + + for (i = 0; i < 6; i++) { + eval[(8 * size) + (5 - i)] = ((seq >> (i + 9)) & 0x01) ? (0x01 >> pattern) : 0x00; + } + + for (i = 0; i < 7; i++) { + eval[(((size - 7) + i) * size) + 8] = ((seq >> (i + 8)) & 0x01) ? (0x01 >> pattern) : 0x00; + } + + eval[(7 * size) + 8] = ((seq >> 6) & 0x01) ? (0x01 >> pattern) : 0x00; + eval[(8 * size) + 8] = ((seq >> 7) & 0x01) ? (0x01 >> pattern) : 0x00; + eval[(8 * size) + 7] = ((seq >> 8) & 0x01) ? (0x01 >> pattern) : 0x00; +} + +static int apply_bitmask(unsigned char *grid,const int size,const int ecc_level) { + int x, y; + unsigned char p; + int pattern, penalty[8]; + int best_val, best_pattern; + #ifndef _MSC_VER - unsigned char data_block[short_data_block_length + 2]; - unsigned char ecc_block[ecc_block_length + 2]; - int interleaved_data[data_cw + 2]; - int interleaved_ecc[ecc_cw + 2]; + unsigned char mask[size * size]; + unsigned char eval[size * size]; #else - unsigned char* data_block = (unsigned char *)_alloca(short_data_block_length + 2); - unsigned char* ecc_block = (unsigned char *)_alloca(ecc_block_length + 2); - int* interleaved_data = (int *)_alloca((data_cw + 2) * sizeof(int)); - int* interleaved_ecc = (int *)_alloca((ecc_cw + 2) * sizeof(int)); + unsigned char* mask = (unsigned char *) _alloca((size * size) * sizeof (unsigned char)); + unsigned char* eval = (unsigned char *) _alloca((size * size) * sizeof (unsigned char)); #endif - 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 < ecc_block_length; j++) { - ecc_block[j] = 0; - } - - for(j = 0; j < length_this_block; j++) { - data_block[j] = (unsigned char) datastream[posn + j]; - } - - rs_init_gf(0x11d); - rs_init_code(ecc_block_length, 0); - rs_encode(length_this_block, data_block, ecc_block); - rs_free(); - -#ifdef _DEBUG_MODE_ - printf("Block %d: ", i + 1); - for(j = 0; j < length_this_block; j++) { - printf("%2X ", data_block[j]); - } - if(i < qty_short_blocks) { - printf(" "); - } - printf(" // "); - for(j = 0; j < ecc_block_length; j++) { - printf("%2X ", ecc_block[ecc_block_length - j - 1]); - } - printf("\n"); + /* Perform data masking */ + for (x = 0; x < size; x++) { + for (y = 0; y < size; y++) { + mask[(y * size) + x] = 0x00; + + // all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array. + if (!(grid[(y * size) + x] & 0xf0)) { // exclude areas not to be masked. + if (((y + x) & 1) == 0) { + mask[(y * size) + x] += 0x01; + } + if ((y & 1) == 0) { + mask[(y * size) + x] += 0x02; + } + if ((x % 3) == 0) { + mask[(y * size) + x] += 0x04; + } + if (((y + x) % 3) == 0) { + mask[(y * size) + x] += 0x08; + } + if ((((y / 2) + (x / 3)) & 1) == 0) { + mask[(y * size) + x] += 0x10; + } + if ((((y * x) & 1) + ((y * x) % 3)) == 0) { + mask[(y * size) + x] += 0x20; + } + if (((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { + mask[(y * size) + x] += 0x40; + } + if (((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { + mask[(y * size) + x] += 0x80; + } + } + } + } + + // apply data masks to grid, result in eval + for (x = 0; x < size; x++) { + for (y = 0; y < size; y++) { + if (grid[(y * size) + x] & 0x01) { + p = 0xff; + } else { + p = 0x00; + } + + eval[(y * size) + x] = mask[(y * size) + x] ^ p; + } + } + + + /* Evaluate result */ + for (pattern = 0; pattern < 8; pattern++) { + + add_format_info_eval(eval, size, ecc_level, pattern); + + penalty[pattern] = evaluate(eval, size, pattern); + } + + best_pattern = 0; + best_val = penalty[0]; + for (pattern = 1; pattern < 8; pattern++) { + if (penalty[pattern] < best_val) { + best_pattern = pattern; + best_val = penalty[pattern]; + } + } + +#ifdef ZINTLOG + char str[15]; + sprintf(str, "%d", best_val); + write_log("choosed pattern:"); + write_log(str); #endif - - for(j = 0; j < short_data_block_length; j++) { - interleaved_data[(j * blocks) + i] = (int) data_block[j]; - } - - if(i >= qty_short_blocks){ - interleaved_data[(short_data_block_length * blocks) + (i - qty_short_blocks)] = (int) data_block[short_data_block_length]; - } - - for(j = 0; j < ecc_block_length; j++) { - interleaved_ecc[(j * blocks) + i] = (int) ecc_block[ecc_block_length - j - 1]; - } - - 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]; - } - -#ifdef _DEBUG_MODE_ - printf("\nData Stream: \n"); - for(j = 0; j < (data_cw + ecc_cw); j++) { - printf("%2X ", fullstream[j]); - } - printf("\n"); -#endif -} -void place_finder(unsigned char grid[], int size, int x, int y) -{ - int xp, yp; - - int finder[] = { - 1, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 1, - 1, 0, 1, 1, 1, 0, 1, - 1, 0, 1, 1, 1, 0, 1, - 1, 0, 1, 1, 1, 0, 1, - 1, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 1, 1, 1, 1 - }; - - for(xp = 0; xp < 7; xp++) { - for(yp = 0; yp < 7; yp++) { - if (finder[xp + (7 * yp)] == 1) { - grid[((yp + y) * size) + (xp + x)] = 0x11; - } else { - grid[((yp + y) * size) + (xp + x)] = 0x10; - } - } - } + /* Apply mask */ + for (x = 0; x < size; x++) { + for (y = 0; y < size; y++) { + if (mask[(y * size) + x] & (0x01 << best_pattern)) { + if (grid[(y * size) + x] & 0x01) { + grid[(y * size) + x] = 0x00; + } else { + grid[(y * size) + x] = 0x01; + } + } + } + } + + return best_pattern; } -void place_align(unsigned char grid[], int size, int x, int y) -{ - int xp, yp; - - int alignment[] = { - 1, 1, 1, 1, 1, - 1, 0, 0, 0, 1, - 1, 0, 1, 0, 1, - 1, 0, 0, 0, 1, - 1, 1, 1, 1, 1 - }; - - x -= 2; - y -= 2; /* Input values represent centre of pattern */ - - for(xp = 0; xp < 5; xp++) { - for(yp = 0; yp < 5; yp++) { - if (alignment[xp + (5 * yp)] == 1) { - grid[((yp + y) * size) + (xp + x)] = 0x11; - } else { - grid[((yp + y) * size) + (xp + x)] = 0x10; - } - } - } +/* Add format information to grid */ +static void 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 LEVEL_L: format += 0x08; + break; + case LEVEL_Q: format += 0x18; + break; + case 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; } -void setup_grid(unsigned char* grid, int size, int version) -{ - int i, toggle = 1; - int loopsize, x, y, xcoord, ycoord; - - /* 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 */ - place_finder(grid, size, 0, 0); - place_finder(grid, size, 0, size - 7); - 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; - - /* Add alignment patterns */ - if(version != 1) { - /* Version 1 does not have alignment patterns */ - - loopsize = qr_align_loopsize[version - 1]; - for(x = 0; x < loopsize; x++) { - for(y = 0; y < loopsize; y++) { - xcoord = qr_table_e1[((version - 2) * 7) + x]; - ycoord = qr_table_e1[((version - 2) * 7) + y]; - - if(!(grid[(ycoord * size) + xcoord] & 0x10)) { - 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] += 20; - 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; - } - } +/* Add version information */ +static void add_version_info(unsigned char *grid,const int size,const int version) { + int i; + + long int version_data = qr_annex_d[version - 7]; + for (i = 0; i < 6; i++) { + grid[((size - 11) * size) + i] += (version_data >> (i * 3)) & 0x41; + grid[((size - 10) * size) + i] += (version_data >> ((i * 3) + 1)) & 0x41; + grid[((size - 9) * size) + i] += (version_data >> ((i * 3) + 2)) & 0x41; + grid[(i * size) + (size - 11)] += (version_data >> (i * 3)) & 0x41; + grid[(i * size) + (size - 10)] += (version_data >> ((i * 3) + 1)) & 0x41; + grid[(i * size) + (size - 9)] += (version_data >> ((i * 3) + 2)) & 0x41; + } } -int cwbit(int* datastream, int i) { - int word = i / 8; - int bit = i % 8; - int resultant = 0; - - switch(bit) { - case 0: if(datastream[word] & 0x80) { resultant = 1; } else { resultant = 0; } break; - case 1: if(datastream[word] & 0x40) { resultant = 1; } else { resultant = 0; } break; - case 2: if(datastream[word] & 0x20) { resultant = 1; } else { resultant = 0; } break; - case 3: if(datastream[word] & 0x10) { resultant = 1; } else { resultant = 0; } break; - case 4: if(datastream[word] & 0x08) { resultant = 1; } else { resultant = 0; } break; - case 5: if(datastream[word] & 0x04) { resultant = 1; } else { resultant = 0; } break; - case 6: if(datastream[word] & 0x02) { resultant = 1; } else { resultant = 0; } break; - case 7: if(datastream[word] & 0x01) { resultant = 1; } else { resultant = 0; } break; - } - - return resultant; +static size_t blockLength(const size_t start,const char inputMode[],const size_t inputLength) { + /* Find the length of the block starting from 'start' */ + size_t i; + int count; + char mode = inputMode[start]; + + count = 0; + i = start; + + do { + count++; + } while (((i + count) < inputLength) && (inputMode[i + count] == mode)); + + return count; } -void populate_grid(unsigned char* grid, int size, int* datastream, int cw) -{ - int direction = 1; /* up */ - int row = 0; /* right hand side */ - - int i, n, x, y; - - n = cw * 8; - y = size - 1; - i = 0; - do { - x = (size - 2) - (row * 2); - if(x < 6) - x--; /* skip over vertical timing pattern */ - - if(!(grid[(y * size) + (x + 1)] & 0xf0)) { - if (cwbit(datastream, i)) { - grid[(y * size) + (x + 1)] = 0x01; - } else { - grid[(y * size) + (x + 1)] = 0x00; - } - i++; - } - - if(i < n) { - if(!(grid[(y * size) + x] & 0xf0)) { - if (cwbit(datastream, i)) { - grid[(y * size) + x] = 0x01; - } else { - grid[(y * size) + x] = 0x00; - } - i++; - } - } - - if(direction) { y--; } else { y++; } - if(y == -1) { - /* reached the top */ - row++; - y = 0; - direction = 0; - } - if(y == size) { - /* reached the bottom */ - row++; - y = size - 1; - direction = 1; - } - } while (i < n); +static int getBinaryLength(const int version, char inputMode[], const unsigned int inputData[], const size_t inputLength, const int gs1, const int eci, const int debug) { + /* Calculate the actual bitlength of the proposed binary string */ + size_t i, j; + char currentMode; + int count = 0; + int alphalength; + int blocklength; + + qr_define_mode(inputMode, inputData, inputLength, gs1, version, debug); + + currentMode = ' '; // Null + + if (gs1 == 1) { /* Not applicable to MICROQR */ + if (version < RMQR_VERSION) { + count += 4; + } else { + count += 3; + } + } + + if (eci != 0) { // RMQR and MICROQR do not support ECI + count += 4; + if (eci <= 127) { + count += 8; + } else if (eci <= 16383) { + count += 16; + } else { + count += 24; + } + } + + for (i = 0; i < inputLength; i++) { + if (inputMode[i] != currentMode) { + count += mode_bits(version) + cci_bits(version, inputMode[i]); + blocklength = blockLength(i, inputMode, inputLength); + switch (inputMode[i]) { + case 'K': + count += (blocklength * 13); + break; + case 'B': + for (j = i; j < (i + blocklength); j++) { + if (inputData[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 (inputData[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 = inputMode[i]; + } + } + + if (debug & ZINT_DEBUG_PRINT) { + printf("Estimated Binary Length: %d (version %d, eci %d, gs1 %d)\n", count, version, eci, gs1); + } + + return count; } -int evaluate(unsigned char *grid, int size, int pattern) -{ - int x, y, block; - int result = 0; - char state; - int p; - int dark_mods; - int percentage, k, k2; +INTERNAL int qr_code(struct zint_symbol *symbol, const unsigned char source[], size_t length) { + int i, j, est_binlen; + int ecc_level, autosize, version, max_cw, target_codewords, blocks, size; + int bitmask, gs1; + int full_multibyte; + int canShrink; #ifndef _MSC_VER - char local[size * size]; + unsigned int jisdata[length + 1]; + char mode[length + 1]; #else - char* local = (char *)_alloca((size * size) * sizeof(char)); + unsigned char* datastream; + unsigned char* fullstream; + unsigned char* grid; + unsigned int* jisdata = (unsigned int *) _alloca((length + 1) * sizeof (unsigned int)); + char* mode = (char *) _alloca(length + 1); #endif - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - switch(pattern) { - case 0: if (grid[(y * size) + x] & 0x01) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 1: if (grid[(y * size) + x] & 0x02) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 2: if (grid[(y * size) + x] & 0x04) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 3: if (grid[(y * size) + x] & 0x08) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 4: if (grid[(y * size) + x] & 0x10) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 5: if (grid[(y * size) + x] & 0x20) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 6: if (grid[(y * size) + x] & 0x40) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - case 7: if (grid[(y * size) + x] & 0x80) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break; - } - } - } - - /* Test 1: Adjacent modules in row/column in same colour */ - /* Vertical */ - for(x = 0; x < size; x++) { - state = local[x]; - block = 0; - for(y = 0; y < size; y++) { - if(local[(y * size) + x] == state) { - block++; - if(block ==5) - result += 3; - - if(block>5) - result +=1; - } else { - block=0; - } - } - } - - /* Horizontal */ - for(y = 0; y < size; y++) { - state = local[y * size]; - block = 0; - for(x = 0; x < size; x++) { - if(local[(y * size) + x] == state) { - block++; - if(block ==5) - result += 3; - - if(block>5) - result +=1; - } else { - block=0; - } - } - } - - /* Test 2 fd02131114 */ - for(x = 0; x < size-1; x++) { - for(y = 0; y < (size - 7) -1; y++) { - // y + 1??? - if((local[((y + 1) * size) + x] == '1') && - (local[((y + 1) * size) + x+1] == '1') && - (local[(((y + 1)+1) * size) + x] == '1') && - (local[(((y + 1)+1) * size) + x+1] == '1') - ) { result += 3; } - - if((local[((y + 1) * size) + x] == '0') && - (local[((y + 1) * size) + x+1] == '0') && - (local[(((y + 1)+1) * size) + x] == '0') && - (local[(((y + 1)+1) * size) + x+1] == '0') - ) { result += 3; } - } - } - - /* Test 3: fd02131114 */ - /*pattern 10111010000 */ - /* Vertical */ - for(x = 0; x < size; x++) { - for(y = 0; y < (size - 11); y++) { - p = 0; - if(local[(y * size) + x] == '1') { p += 1; } - if(local[((y + 1) * size) + x] == '0') { p += 1; } - if(local[((y + 2) * size) + x] == '1') { p += 1; } - if(local[((y + 3) * size) + x] == '1') { p += 1; } - if(local[((y + 4) * size) + x] == '1') { p += 1; } - if(local[((y + 5) * size) + x] == '0') { p += 1; } - if(local[((y + 6) * size) + x] == '1') { p += 1; } - if(local[((y + 7) * size) + x] == '0') { p += 1; } - if(local[((y + 8) * size) + x] == '0') { p += 1; } - if(local[((y + 9) * size) + x] == '0') { p += 1; } - if(local[((y + 10) * size) + x] == '0') { p += 1; } - if(p == 11) { - result += 40; - } - } - } - - /* Horizontal */ - for(y = 0; y < size; y++) { - for(x = 0; x < (size - 11); x++) { - p = 0; - if(local[(y * size) + x] == '1') { p += 1; } - if(local[(y * size) + x + 1] == '0') { p += 1; } - if(local[(y * size) + x + 2] == '1') { p += 1; } - if(local[(y * size) + x + 3] == '1') { p += 1; } - if(local[(y * size) + x + 4] == '1') { p += 1; } - if(local[(y * size) + x + 5] == '0') { p += 1; } - if(local[(y * size) + x + 6] == '1') { p += 1; } - if(local[(y * size) + x + 7] == '0') { p += 1; } - if(local[(y * size) + x + 8] == '0') { p += 1; } - if(local[(y * size) + x + 9] == '0') { p += 1; } - if(local[(y * size) + x + 10] == '0') { p += 1; } - if(p == 11) { - result += 40; - } - } - } - - /*pattern 00001011101 */ - /* Vertical */ - for(x = 0; x < size; x++) { - for(y = 0; y < (size - 11); y++) { - p = 0; - if(local[(y * size) + x] == '0') { p += 1; } - if(local[((y + 1) * size) + x] == '0') { p += 1; } - if(local[((y + 2) * size) + x] == '0') { p += 1; } - if(local[((y + 3) * size) + x] == '0') { p += 1; } - if(local[((y + 4) * size) + x] == '1') { p += 1; } - if(local[((y + 5) * size) + x] == '0') { p += 1; } - if(local[((y + 6) * size) + x] == '1') { p += 1; } - if(local[((y + 7) * size) + x] == '1') { p += 1; } - if(local[((y + 8) * size) + x] == '1') { p += 1; } - if(local[((y + 9) * size) + x] == '0') { p += 1; } - if(local[((y + 10) * size) + x] == '1') { p += 1; } - if(p == 11) { - result += 40; - } - } - } - - /* Horizontal */ - for(y = 0; y < size; y++) { - for(x = 0; x < (size - 11); x++) { - p = 0; - if(local[(y * size) + x] == '0') { p += 1; } - if(local[(y * size) + x + 1] == '0') { p += 1; } - if(local[(y * size) + x + 2] == '0') { p += 1; } - if(local[(y * size) + x + 3] == '0') { p += 1; } - if(local[(y * size) + x + 4] == '1') { p += 1; } - if(local[(y * size) + x + 5] == '0') { p += 1; } - if(local[(y * size) + x + 6] == '1') { p += 1; } - if(local[(y * size) + x + 7] == '1') { p += 1; } - if(local[(y * size) + x + 8] == '1') { p += 1; } - if(local[(y * size) + x + 9] == '0') { p += 1; } - if(local[(y * size) + x + 10] == '1') { p += 1; } - if(p == 11) { - result += 40; - } - } - } - - /* Test 4: Proportion of dark modules in entire symbol */ - dark_mods = 0; - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - if(local[(y * size) + x] == '1') { - dark_mods++; - } - } - } - percentage = 100 * (dark_mods / (size * size)); - int m=0; - for(x = 0; x < 100; x+=5) { - if(x<percentage) - m=x; - } - - k=abs((m-50)/5); - k2=abs((m+5-50)/5); - - int smallest=k; - if(k2<smallest) - smallest=k2; - - result += 10 * smallest; - - return result; -} + gs1 = ((symbol->input_mode & 0x07) == GS1_MODE); + full_multibyte = symbol->option_3 == ZINT_FULL_MULTIBYTE; /* If set use Kanji mode in DATA_MODE or for single-byte Latin */ + + if ((symbol->input_mode & 0x07) == DATA_MODE) { + sjis_cpy(source, &length, jisdata, full_multibyte); + } else { + int done = 0; + if (symbol->eci != 20) { /* Unless ECI 20 (Shift JIS) */ + /* Try single byte (Latin) conversion first */ + int error_number = sjis_utf8tosb(symbol->eci && symbol->eci <= 899 ? symbol->eci : 3, source, &length, jisdata, full_multibyte); + if (error_number == 0) { + done = 1; + } else if (symbol->eci && symbol->eci <= 899) { + strcpy(symbol->errtxt, "575: Invalid characters in input data"); + return error_number; + } + } + if (!done) { + /* Try Shift-JIS */ + int error_number = sjis_utf8tomb(symbol, source, &length, jisdata); + if (error_number != 0) { + return error_number; + } + } + } + + est_binlen = getBinaryLength(40, mode, jisdata, length, gs1, symbol->eci, symbol->debug); + + ecc_level = LEVEL_L; + max_cw = 2956; + if ((symbol->option_1 >= 1) && (symbol->option_1 <= 4)) { + switch (symbol->option_1) { + case 1: + break; + case 2: ecc_level = LEVEL_M; + max_cw = 2334; + break; + case 3: ecc_level = LEVEL_Q; + max_cw = 1666; + break; + case 4: ecc_level = LEVEL_H; + max_cw = 1276; + break; + } + } + + if (est_binlen > (8 * max_cw)) { + strcpy(symbol->errtxt, "561: Input too long for selected error correction level"); + return ZINT_ERROR_TOO_LONG; + } + + autosize = 40; + for (i = 39; i >= 0; i--) { + switch (ecc_level) { + case LEVEL_L: + if ((8 * qr_data_codewords_L[i]) >= est_binlen) { + autosize = i + 1; + } + break; + case LEVEL_M: + if ((8 * qr_data_codewords_M[i]) >= est_binlen) { + autosize = i + 1; + } + break; + case LEVEL_Q: + if ((8 * qr_data_codewords_Q[i]) >= est_binlen) { + autosize = i + 1; + } + break; + case LEVEL_H: + if ((8 * qr_data_codewords_H[i]) >= est_binlen) { + autosize = i + 1; + } + break; + } + } + if (autosize != 40) { + est_binlen = getBinaryLength(autosize, mode, jisdata, length, gs1, symbol->eci, symbol->debug); + } + + // Now see if the optimised binary will fit in a smaller symbol. + canShrink = 1; + + do { + if (autosize == 1) { + canShrink = 0; + } else { + est_binlen = getBinaryLength(autosize - 1, mode, jisdata, length, gs1, symbol->eci, symbol->debug); + + switch (ecc_level) { + case LEVEL_L: + if ((8 * qr_data_codewords_L[autosize - 2]) < est_binlen) { + canShrink = 0; + } + break; + case LEVEL_M: + if ((8 * qr_data_codewords_M[autosize - 2]) < est_binlen) { + canShrink = 0; + } + break; + case LEVEL_Q: + if ((8 * qr_data_codewords_Q[autosize - 2]) < est_binlen) { + canShrink = 0; + } + break; + case LEVEL_H: + if ((8 * qr_data_codewords_H[autosize - 2]) < est_binlen) { + canShrink = 0; + } + break; + } + + 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 = getBinaryLength(autosize, mode, jisdata, length, gs1, symbol->eci, symbol->debug); + } + } + } 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 = getBinaryLength(symbol->option_2, mode, jisdata, length, gs1, symbol->eci, symbol->debug); + } + + if (symbol->option_2 < version) { + strcpy(symbol->errtxt, "569: Input too long for selected symbol size"); + return ZINT_ERROR_TOO_LONG; + } + } + + /* Ensure maxium error correction capacity unless user-specified */ + if (symbol->option_1 == -1 || symbol->option_1 != ecc_level) { + if (est_binlen <= qr_data_codewords_M[version - 1] * 8) { + ecc_level = LEVEL_M; + } + if (est_binlen <= qr_data_codewords_Q[version - 1] * 8) { + ecc_level = LEVEL_Q; + } + if (est_binlen <= qr_data_codewords_H[version - 1] * 8) { + ecc_level = LEVEL_H; + } + } + + target_codewords = qr_data_codewords_L[version - 1]; + blocks = qr_blocks_L[version - 1]; + switch (ecc_level) { + case LEVEL_M: target_codewords = qr_data_codewords_M[version - 1]; + blocks = qr_blocks_M[version - 1]; + break; + case LEVEL_Q: target_codewords = qr_data_codewords_Q[version - 1]; + blocks = qr_blocks_Q[version - 1]; + break; + case LEVEL_H: target_codewords = qr_data_codewords_H[version - 1]; + blocks = qr_blocks_H[version - 1]; + break; + } + +#ifndef _MSC_VER + unsigned char datastream[target_codewords + 1]; + unsigned char fullstream[qr_total_codewords[version - 1] + 1]; +#else + datastream = (unsigned char *) _alloca(target_codewords + 1); + fullstream = (unsigned char *) _alloca(qr_total_codewords[version - 1] + 1); +#endif + + qr_binary(datastream, version, target_codewords, mode, jisdata, length, gs1, symbol->eci, est_binlen, symbol->debug); +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords); +#endif + add_ecc(fullstream, datastream, version, target_codewords, blocks, symbol->debug); -void add_format_info_eval(unsigned char *eval, int size, int ecc_level, int pattern) -{ - /* Add format information to grid */ + size = qr_sizes[version - 1]; +#ifndef _MSC_VER + unsigned char grid[size * size]; +#else + grid = (unsigned char *) _alloca((size * size) * sizeof (unsigned char)); +#endif - int format = pattern; - unsigned int seq; - int i; + for (i = 0; i < size; i++) { + for (j = 0; j < size; j++) { + grid[(i * size) + j] = 0; + } + } - switch(ecc_level) { - case LEVEL_L: format += 0x08; break; - case LEVEL_Q: format += 0x18; break; - case LEVEL_H: format += 0x10; break; - } + setup_grid(grid, size, version); + populate_grid(grid, size, size, fullstream, qr_total_codewords[version - 1]); - seq = qr_annex_c[format]; + if (version >= 7) { + add_version_info(grid, size, version); + } - for(i = 0; i < 6; i++) { - eval[(i * size) + 8] = (seq >> i) & 0x01 ? (0x01 >> pattern) : 0x00; - } + bitmask = apply_bitmask(grid, size, ecc_level); - for(i = 0; i < 8; i++) { - eval[(8 * size) + (size - i - 1)] = (seq >> i) & 0x01 ? (0x01 >> pattern) : 0x00; - } + add_format_info(grid, size, ecc_level, bitmask); - for(i = 0; i < 6; i++) { - eval[(8 * size) + (5 - i)] = (seq >> (i + 9)) & 0x01 ? (0x01 >> pattern) : 0x00; - } + symbol->width = size; + symbol->rows = size; - for(i = 0; i < 7; i++) { - eval[(((size - 7) + i) * size) + 8] = (seq >> (i + 8)) & 0x01 ? (0x01 >> pattern) : 0x00; - } + 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; + } - eval[(7 * size) + 8] = (seq >> 6) & 0x01 ? (0x01 >> pattern) : 0x00; - eval[(8 * size) + 8] = (seq >> 7) & 0x01 ? (0x01 >> pattern) : 0x00; - eval[(8 * size) + 7] = (seq >> 8) & 0x01 ? (0x01 >> pattern) : 0x00; + return 0; } -int apply_bitmask(unsigned char *grid, int size, int ecc_level) -{ - int x, y; - unsigned char p; - int pattern, penalty[8]; - int best_val, best_pattern; - int bit; - -#ifndef _MSC_VER - unsigned char mask[size * size]; - unsigned char eval[size * size]; +static void micro_qr_m1(struct zint_symbol *symbol, char binary_data[]) { + int i, j, latch; + int bits_total, bits_left; + int data_codewords, ecc_codewords; + unsigned char data_blocks[4], ecc_blocks[3]; + + bits_total = 20; + latch = 0; + + /* Add terminator */ + bits_left = bits_total - (int)strlen(binary_data); + if (bits_left <= 3) { + for (i = 0; i < bits_left; i++) { + strcat(binary_data, "0"); + } + latch = 1; + } else { + strcat(binary_data, "000"); + } + + if (latch == 0) { + /* Manage last (4-bit) block */ + bits_left = bits_total - (int)strlen(binary_data); + if (bits_left <= 4) { + for (i = 0; i < bits_left; i++) { + strcat(binary_data, "0"); + } + latch = 1; + } + } + + if (latch == 0) { + /* Complete current byte */ + int remainder = 8 - (strlen(binary_data) % 8); + if (remainder == 8) { + remainder = 0; + } + for (i = 0; i < remainder; i++) { + strcat(binary_data, "0"); + } + + /* Add padding */ + bits_left = bits_total - (int)strlen(binary_data); + if (bits_left > 4) { + remainder = (bits_left - 4) / 8; + for (i = 0; i < remainder; i++) { + strcat(binary_data, (i & 1) ? "00010001" : "11101100"); + } + } + bin_append(0, 4, binary_data); + } + + data_codewords = 3; + ecc_codewords = 2; + + /* Copy data into codewords */ + for (i = 0; i < (data_codewords - 1); i++) { + data_blocks[i] = 0; + for (j = 0; j < 8; j++) { + if (binary_data[(i * 8) + j] == '1') { + data_blocks[i] += 0x80 >> j; + } + } + } + data_blocks[2] = 0; + for (j = 0; j < 4; j++) { + if (binary_data[16 + j] == '1') { + data_blocks[2] += 0x80 >> j; + } + } +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, data_blocks, data_codewords); #else - unsigned char* mask = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); - unsigned char* eval = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); + (void)symbol; /* Unused */ #endif - /* Perform data masking */ - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - mask[(y * size) + x] = 0x00; - - // all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array. - if (!(grid[(y * size) + x] & 0xf0)) { // exclude areas not to be masked. - if(((y + x) & 1) == 0) { mask[(y * size) + x] += 0x01; } - if((y & 1) == 0) { mask[(y * size) + x] += 0x02; } - if((x % 3) == 0) { mask[(y * size) + x] += 0x04; } - if(((y + x) % 3) == 0) { mask[(y * size) + x] += 0x08; } - if((((y / 2) + (x / 3)) & 1) == 0) { mask[(y * size) + x] += 0x10; } - if((((y * x) & 1) + ((y * x) % 3)) == 0) { mask[(y * size) + x] += 0x20; } - if(((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { mask[(y * size) + x] += 0x40; } - if(((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { mask[(y * size) + x] += 0x80; } - } - } - } - - // apply data masks to grid, result in eval - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - if(grid[(y * size) + x] & 0x01) { p = 0xff; } else { p = 0x00; } - - eval[(y * size) + x] = mask[(y * size) + x] ^ p; - } - } - - /* Evaluate result */ - for(pattern = 0; pattern < 8; pattern++) { - add_format_info_eval(eval, size, ecc_level, pattern); - - penalty[pattern] = evaluate(eval, size, pattern); - } - - best_pattern = 0; - best_val = penalty[0]; - for(pattern = 1; pattern < 8; pattern++) { - if(penalty[pattern] < best_val) { - best_pattern = pattern; - best_val = penalty[pattern]; - } - } - - /* Apply mask */ - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - bit = 0; - switch(best_pattern) { - case 0: if(mask[(y * size) + x] & 0x01) { bit = 1; } break; - case 1: if(mask[(y * size) + x] & 0x02) { bit = 1; } break; - case 2: if(mask[(y * size) + x] & 0x04) { bit = 1; } break; - case 3: if(mask[(y * size) + x] & 0x08) { bit = 1; } break; - case 4: if(mask[(y * size) + x] & 0x10) { bit = 1; } break; - case 5: if(mask[(y * size) + x] & 0x20) { bit = 1; } break; - case 6: if(mask[(y * size) + x] & 0x40) { bit = 1; } break; - case 7: if(mask[(y * size) + x] & 0x80) { bit = 1; } break; - } - if(bit == 1) { - if(grid[(y * size) + x] & 0x01) { - grid[(y * size) + x] = 0x00; - } else { - grid[(y * size) + x] = 0x01; - } - } - } - } - - return best_pattern; -} + /* Calculate Reed-Solomon error codewords */ + rs_init_gf(0x11d); + rs_init_code(ecc_codewords, 0); + rs_encode(data_codewords, data_blocks, ecc_blocks); + rs_free(); -void add_format_info(unsigned char *grid, int size, int ecc_level, int pattern) -{ - /* Add format information to grid */ - - int format = pattern; - unsigned int seq; - int i; - - switch(ecc_level) { - case LEVEL_L: format += 0x08; break; - case LEVEL_Q: format += 0x18; break; - case 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; + /* Add Reed-Solomon codewords to binary data */ + for (i = 0; i < ecc_codewords; i++) { + bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data); + } } -void add_version_info(unsigned char *grid, int size, int version) -{ - /* Add version information */ - int i; - - long int version_data = qr_annex_d[version - 7]; - for(i = 0; i < 6; i++) { - grid[((size - 11) * size) + i] += (version_data >> (i * 3)) & 0x41; - grid[((size - 10) * size) + i] += (version_data >> ((i * 3) + 1)) & 0x41; - grid[((size - 9) * size) + i] += (version_data >> ((i * 3) + 2)) & 0x41; - grid[(i * size) + (size - 11)] += (version_data >> (i * 3)) & 0x41; - grid[(i * size) + (size - 10)] += (version_data >> ((i * 3) + 1)) & 0x41; - grid[(i * size) + (size - 9)] += (version_data >> ((i * 3) + 2)) & 0x41; - } +static void micro_qr_m2(struct zint_symbol *symbol, char binary_data[], const int ecc_mode) { + int i, j, latch; + int bits_total=0, bits_left; + int data_codewords=0, ecc_codewords=0; + unsigned char data_blocks[6], ecc_blocks[7]; + + latch = 0; + + if (ecc_mode == LEVEL_L) { + bits_total = 40; + } + else if (ecc_mode == LEVEL_M) { + bits_total = 32; + } + else assert(0); + + /* Add terminator */ + bits_left = bits_total - (int)strlen(binary_data); + if (bits_left <= 5) { + for (i = 0; i < bits_left; i++) { + strcat(binary_data, "0"); + } + latch = 1; + } else { + bin_append(0, 5, binary_data); + } + + if (latch == 0) { + /* Complete current byte */ + int remainder = 8 - (strlen(binary_data) % 8); + if (remainder == 8) { + remainder = 0; + } + for (i = 0; i < remainder; i++) { + strcat(binary_data, "0"); + } + + /* Add padding */ + bits_left = bits_total - (int)strlen(binary_data); + remainder = bits_left / 8; + for (i = 0; i < remainder; i++) { + strcat(binary_data, (i & 1) ? "00010001" : "11101100"); + } + } + + if (ecc_mode == LEVEL_L) { + data_codewords = 5; + ecc_codewords = 5; + } + else if (ecc_mode == LEVEL_M) { + data_codewords = 4; + ecc_codewords = 6; + } + else assert(0); + + /* Copy data into codewords */ + for (i = 0; i < data_codewords; i++) { + data_blocks[i] = 0; + + for (j = 0; j < 8; j++) { + if (binary_data[(i * 8) + j] == '1') { + data_blocks[i] += 0x80 >> j; + } + } + } +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, data_blocks, data_codewords); +#else + (void)symbol; /* Unused */ +#endif + + /* Calculate Reed-Solomon error codewords */ + rs_init_gf(0x11d); + rs_init_code(ecc_codewords, 0); + rs_encode(data_codewords, data_blocks, ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for (i = 0; i < ecc_codewords; i++) { + bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data); + } + + return; } -int qr_code(struct zint_symbol *symbol, unsigned char source[], int length) -{ - int error_number, i, j, glyph, est_binlen; - int ecc_level, autosize, version, max_cw, target_binlen, blocks, size; - int bitmask, gs1; - -#ifndef _MSC_VER - int utfdata[length + 1]; - int jisdata[length + 1]; - char mode[length + 1]; +static void micro_qr_m3(struct zint_symbol *symbol, char binary_data[], const int ecc_mode) { + int i, j, latch; + int bits_total=0, bits_left; + int data_codewords=0, ecc_codewords=0; + unsigned char data_blocks[12], ecc_blocks[9]; + + latch = 0; + + if (ecc_mode == LEVEL_L) { + bits_total = 84; + } + else if (ecc_mode == LEVEL_M) { + bits_total = 68; + } + else assert(0); + + /* Add terminator */ + bits_left = bits_total - (int)strlen(binary_data); + if (bits_left <= 7) { + for (i = 0; i < bits_left; i++) { + strcat(binary_data, "0"); + } + latch = 1; + } else { + bin_append(0, 7, binary_data); + } + + if (latch == 0) { + /* Manage last (4-bit) block */ + bits_left = bits_total - (int)strlen(binary_data); + if (bits_left <= 4) { + for (i = 0; i < bits_left; i++) { + strcat(binary_data, "0"); + } + latch = 1; + } + } + + if (latch == 0) { + /* Complete current byte */ + int remainder = 8 - (strlen(binary_data) % 8); + if (remainder == 8) { + remainder = 0; + } + for (i = 0; i < remainder; i++) { + strcat(binary_data, "0"); + } + + /* Add padding */ + bits_left = bits_total - (int)strlen(binary_data); + if (bits_left > 4) { + remainder = (bits_left - 4) / 8; + for (i = 0; i < remainder; i++) { + strcat(binary_data, (i & 1) ? "00010001" : "11101100"); + } + } + bin_append(0, 4, binary_data); + } + + if (ecc_mode == LEVEL_L) { + data_codewords = 11; + ecc_codewords = 6; + } + else if (ecc_mode == LEVEL_M) { + data_codewords = 9; + ecc_codewords = 8; + } + else assert(0); + + /* Copy data into codewords */ + for (i = 0; i < (data_codewords - 1); i++) { + data_blocks[i] = 0; + + for (j = 0; j < 8; j++) { + if (binary_data[(i * 8) + j] == '1') { + data_blocks[i] += 0x80 >> j; + } + } + } + + if (ecc_mode == LEVEL_L) { + data_blocks[10] = 0; + for (j = 0; j < 4; j++) { + if (binary_data[80 + j] == '1') { + data_blocks[10] += 0x80 >> j; + } + } + } + + if (ecc_mode == LEVEL_M) { + data_blocks[8] = 0; + for (j = 0; j < 4; j++) { + if (binary_data[64 + j] == '1') { + data_blocks[8] += 0x80 >> j; + } + } + } +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, data_blocks, data_codewords); #else - int* utfdata = (int *)_alloca((length + 1) * sizeof(int)); - int* jisdata = (int *)_alloca((length + 1) * sizeof(int)); - char* mode = (char *)_alloca(length + 1); + (void)symbol; /* Unused */ #endif - - gs1 = (symbol->input_mode == GS1_MODE); - - switch(symbol->input_mode) { - case DATA_MODE: - for(i = 0; i < length; i++) { - jisdata[i] = (int)source[i]; - } - break; - default: - /* Convert Unicode input to Shift-JIS */ - error_number = utf8toutf16(symbol, source, utfdata, &length); - if(error_number != 0) { return error_number; } - - for(i = 0; i < length; i++) { - if(utfdata[i] <= 0xff) { - jisdata[i] = utfdata[i]; - } else { - j = 0; - glyph = 0; - do { - if(sjis_lookup[j * 2] == utfdata[i]) { - glyph = sjis_lookup[(j * 2) + 1]; - } - j++; - } while ((j < 6843) && (glyph == 0)); - if(glyph == 0) { - strcpy(symbol->errtxt, "Invalid character in input data"); - return ERROR_INVALID_DATA; - } - jisdata[i] = glyph; - } - } - break; - } - - define_mode(mode, jisdata, length, gs1); - est_binlen = estimate_binary_length(mode, length, gs1); - - ecc_level = LEVEL_L; - max_cw = 2956; - if((symbol->option_1 >= 1) && (symbol->option_1 <= 4)) { - switch (symbol->option_1) { - case 1: ecc_level = LEVEL_L; max_cw = 2956; break; - case 2: ecc_level = LEVEL_M; max_cw = 2334; break; - case 3: ecc_level = LEVEL_Q; max_cw = 1666; break; - case 4: ecc_level = LEVEL_H; max_cw = 1276; break; - } - } - - if(est_binlen > (8 * max_cw)) { - strcpy(symbol->errtxt, "Input too long for selected error correction level"); - return ERROR_TOO_LONG; - } - - autosize = 40; - for(i = 39; i >= 0; i--) { - switch(ecc_level) { - case LEVEL_L: - if ((8 * qr_data_codewords_L[i]) >= est_binlen) { - autosize = i + 1; - } - break; - case LEVEL_M: - if ((8 * qr_data_codewords_M[i]) >= est_binlen) { - autosize = i + 1; - } - break; - case LEVEL_Q: - if ((8 * qr_data_codewords_Q[i]) >= est_binlen) { - autosize = i + 1; - } - break; - case LEVEL_H: - if ((8 * qr_data_codewords_H[i]) >= est_binlen) { - autosize = i + 1; - } - break; - } - } - - if((symbol->option_2 >= 1) && (symbol->option_2 <= 40)) { - if (symbol->option_2 > autosize) { - version = symbol->option_2; - } else { - version = autosize; - } - } else { - version = autosize; - } - - /* Ensure maxium error correction capacity */ - if(est_binlen <= qr_data_codewords_M[version - 1]) { ecc_level = LEVEL_M; } - if(est_binlen <= qr_data_codewords_Q[version - 1]) { ecc_level = LEVEL_Q; } - if(est_binlen <= qr_data_codewords_H[version - 1]) { ecc_level = LEVEL_H; } - - target_binlen = qr_data_codewords_L[version - 1]; blocks = qr_blocks_L[version - 1]; - switch(ecc_level) { - case LEVEL_M: target_binlen = qr_data_codewords_M[version - 1]; blocks = qr_blocks_M[version - 1]; break; - case LEVEL_Q: target_binlen = qr_data_codewords_Q[version - 1]; blocks = qr_blocks_Q[version - 1]; break; - case LEVEL_H: target_binlen = qr_data_codewords_H[version - 1]; blocks = qr_blocks_H[version - 1]; break; - } - -#ifndef _MSC_VER - int datastream[target_binlen + 1]; - int fullstream[qr_total_codewords[version - 1] + 1]; + + /* Calculate Reed-Solomon error codewords */ + rs_init_gf(0x11d); + rs_init_code(ecc_codewords, 0); + rs_encode(data_codewords, data_blocks, ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for (i = 0; i < ecc_codewords; i++) { + bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data); + } + + return; +} + +static void micro_qr_m4(struct zint_symbol *symbol, char binary_data[], const int ecc_mode) { + int i, j, latch; + int bits_total=0, bits_left; + int data_codewords=0, ecc_codewords=0; + unsigned char data_blocks[17], ecc_blocks[15]; + + latch = 0; + + if (ecc_mode == LEVEL_L) { + bits_total = 128; + } + else if (ecc_mode == LEVEL_M) { + bits_total = 112; + } + else if (ecc_mode == LEVEL_Q) { + bits_total = 80; + } + else assert(0); + + /* Add terminator */ + bits_left = bits_total - (int)strlen(binary_data); + if (bits_left <= 9) { + for (i = 0; i < bits_left; i++) { + strcat(binary_data, "0"); + } + latch = 1; + } else { + bin_append(0, 9, binary_data); + } + + if (latch == 0) { + /* Complete current byte */ + int remainder = 8 - (strlen(binary_data) % 8); + if (remainder == 8) { + remainder = 0; + } + for (i = 0; i < remainder; i++) { + strcat(binary_data, "0"); + } + + /* Add padding */ + bits_left = bits_total - (int)strlen(binary_data); + remainder = bits_left / 8; + for (i = 0; i < remainder; i++) { + strcat(binary_data, (i & 1) ? "00010001" : "11101100"); + } + } + + if (ecc_mode == LEVEL_L) { + data_codewords = 16; + ecc_codewords = 8; + } + else if (ecc_mode == LEVEL_M) { + data_codewords = 14; + ecc_codewords = 10; + } + else if (ecc_mode == LEVEL_Q) { + data_codewords = 10; + ecc_codewords = 14; + } + else assert(0); + + /* Copy data into codewords */ + for (i = 0; i < data_codewords; i++) { + data_blocks[i] = 0; + + for (j = 0; j < 8; j++) { + if (binary_data[(i * 8) + j] == '1') { + data_blocks[i] += 0x80 >> j; + } + } + } +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, data_blocks, data_codewords); #else - int* datastream = (int *)_alloca((target_binlen + 1) * sizeof(int)); - int* fullstream = (int *)_alloca((qr_total_codewords[version - 1] + 1) * sizeof(int)); + (void)symbol; /* Unused */ #endif - qr_binary(datastream, version, target_binlen, mode, jisdata, length, gs1, est_binlen); - add_ecc(fullstream, datastream, version, target_binlen, blocks); - - size = qr_sizes[version - 1]; + /* Calculate Reed-Solomon error codewords */ + rs_init_gf(0x11d); + rs_init_code(ecc_codewords, 0); + rs_encode(data_codewords, data_blocks, ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for (i = 0; i < ecc_codewords; i++) { + bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data); + } +} + +static void micro_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 */ + 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 micro_populate_grid(unsigned char* grid,const int size,const char full_stream[]) { + int direction = 1; /* up */ + int row = 0; /* right hand side */ + size_t n, i; + int y; + + n = strlen(full_stream); + 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 < n) { + 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 < n); +} + +static int micro_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 micro_apply_bitmask(unsigned char *grid,const int size) { + int x, y; + unsigned char p; + int pattern, value[8]; + int best_val, best_pattern; + #ifndef _MSC_VER - unsigned char grid[size * size]; + unsigned char mask[size * size]; + unsigned char eval[size * size]; #else - unsigned char* grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); + unsigned char* mask = (unsigned char *) _alloca((size * size) * sizeof (unsigned char)); + unsigned char* eval = (unsigned char *) _alloca((size * size) * sizeof (unsigned char)); #endif - - for(i = 0; i < size; i++) { - for(j = 0; j < size; j++) { - grid[(i * size) + j] = 0; - } - } - - setup_grid(grid, size, version); - populate_grid(grid, size, fullstream, qr_total_codewords[version - 1]); - - if(version >= 7) { - add_version_info(grid, size, version); - } - - bitmask = apply_bitmask(grid, size, ecc_level); - - add_format_info(grid, size, ecc_level, bitmask); - - 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; - } - - return 0; + + /* Perform data masking */ + for (x = 0; x < size; x++) { + for (y = 0; y < size; y++) { + mask[(y * size) + x] = 0x00; + + if (!(grid[(y * size) + x] & 0xf0)) { + if ((y & 1) == 0) { + mask[(y * size) + x] += 0x01; + } + + if ((((y / 2) + (x / 3)) & 1) == 0) { + mask[(y * size) + x] += 0x02; + } + + if (((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { + mask[(y * size) + x] += 0x04; + } + + if (((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { + mask[(y * size) + x] += 0x08; + } + } + } + } + + for (x = 0; x < size; x++) { + for (y = 0; y < size; y++) { + if (grid[(y * size) + x] & 0x01) { + p = 0xff; + } else { + p = 0x00; + } + + eval[(y * size) + x] = mask[(y * size) + x] ^ p; + } + } + + + /* Evaluate result */ + for (pattern = 0; pattern < 8; pattern++) { + value[pattern] = micro_evaluate(eval, size, pattern); + } + + best_pattern = 0; + best_val = value[0]; + for (pattern = 1; pattern < 4; pattern++) { + if (value[pattern] > best_val) { + best_pattern = pattern; + best_val = value[pattern]; + } + } + + /* Apply mask */ + for (x = 0; x < size; x++) { + for (y = 0; y < size; y++) { + if (mask[(y * size) + x] & (0x01 << best_pattern)) { + if (grid[(y * size) + x] & 0x01) { + grid[(y * size) + x] = 0x00; + } else { + grid[(y * size) + x] = 0x01; + } + } + } + } + + return best_pattern; } -/* NOTE: From this point forward concerns Micro QR Code only */ - -int micro_qr_intermediate(char binary[], int jisdata[], char mode[], int length, int *kanji_used, int *alphanum_used, int *byte_used) -{ - /* Convert input data to an "intermediate stage" where data is binary encoded but - control information is not */ - int position = 0; - int short_data_block_length, i; - char data_block; - char buffer[2]; - - strcpy(binary, ""); - -#ifdef _DEBUG_MODE_ - for(i = 0; i < length; i++) { - printf("%c", mode[i]); - } - printf("\n"); +INTERNAL int microqr(struct zint_symbol *symbol, const unsigned char source[], size_t length) { + size_t i, size, j; + char full_stream[200]; + int full_multibyte; + + unsigned int jisdata[40]; + char mode[40]; + int alpha_used = 0, byte_or_kanji_used = 0; + int version_valid[4]; + int binary_count[4]; + int ecc_level, autoversion, version; + int bitmask, format, format_full; +#ifdef _MSC_VER + unsigned char* grid; #endif - do { - if(strlen(binary) > 128) { - return ERROR_TOO_LONG; - } - - data_block = mode[position]; - short_data_block_length = 0; - do { - short_data_block_length++; - } while (((short_data_block_length + position) < length) && (mode[position + short_data_block_length] == data_block)); - - switch(data_block) { - case 'K': - /* Kanji mode */ - /* Mode indicator */ - concat(binary, "K"); - *kanji_used = 1; - - /* Character count indicator */ - buffer[0] = short_data_block_length; - buffer[1] = '\0'; - concat(binary, buffer); -#ifdef _DEBUG_MODE_ - printf("Kanji block (length %d)\n\t", short_data_block_length); -#endif - - /* Character representation */ - for(i = 0; i < short_data_block_length; i++) { - int jis = jisdata[position + i]; - int msb, lsb, prod; - - if(jis > 0x9fff) { jis -= 0xc140; } - msb = (jis & 0xff00) >> 4; - lsb = (jis & 0xff); - prod = (msb * 0xc0) + lsb; - - qr_bscan(binary, prod, 0x1000); -#ifdef _DEBUG_MODE_ - printf("0x%4X ", prod); -#endif - if(strlen(binary) > 128) { - return ERROR_TOO_LONG; - } - } -#ifdef _DEBUG_MODE_ - printf("\n"); -#endif - - break; - case 'B': - /* Byte mode */ - /* Mode indicator */ - concat(binary, "B"); - *byte_used = 1; - - /* Character count indicator */ - buffer[0] = short_data_block_length; - buffer[1] = '\0'; - concat(binary, buffer); -#ifdef _DEBUG_MODE_ - printf("Byte block (length %d)\n\t", short_data_block_length); -#endif - - /* Character representation */ - for(i = 0; i < short_data_block_length; i++) { - int byte = jisdata[position + i]; - - qr_bscan(binary, byte, 0x80); -#ifdef _DEBUG_MODE_ - printf("0x%4X ", byte); -#endif - if(strlen(binary) > 128) { - return ERROR_TOO_LONG; - } - } -#ifdef _DEBUG_MODE_ - printf("\n"); -#endif - break; - case 'A': - /* Alphanumeric mode */ - /* Mode indicator */ - concat(binary, "A"); - *alphanum_used = 1; - - /* Character count indicator */ - buffer[0] = short_data_block_length; - buffer[1] = '\0'; - concat(binary, buffer); -#ifdef _DEBUG_MODE_ - printf("Alpha block (length %d)\n\t", short_data_block_length); + if (length > 35) { + strcpy(symbol->errtxt, "562: Input data too long"); + return ZINT_ERROR_TOO_LONG; + } + + /* Check option 1 in combination with option 2 */ + ecc_level = LEVEL_L; + if (symbol->option_1 >= 1 && symbol->option_1 <= 4) { + if (symbol->option_1 == 4) { + strcpy(symbol->errtxt, "566: Error correction level H not available"); + return ZINT_ERROR_INVALID_OPTION; + } + if (symbol->option_2 >= 1 && symbol->option_2 <= 4) { + if (symbol->option_2 == 1 && symbol->option_1 != 1) { + strcpy(symbol->errtxt, "574: Version M1 supports error correction level L only"); + return ZINT_ERROR_INVALID_OPTION; + } + if (symbol->option_2 != 4 && symbol->option_1 == 3) { + strcpy(symbol->errtxt, "575: Error correction level Q requires Version M4"); + return ZINT_ERROR_INVALID_OPTION; + } + } + ecc_level = symbol->option_1; + } + + full_multibyte = symbol->option_3 == ZINT_FULL_MULTIBYTE; /* If set use Kanji mode in DATA_MODE or for single-byte Latin */ + + if ((symbol->input_mode & 0x07) == DATA_MODE) { + sjis_cpy(source, &length, jisdata, full_multibyte); + } else { + /* Try ISO 8859-1 conversion first */ + int error_number = sjis_utf8tosb(3, source, &length, jisdata, full_multibyte); + if (error_number != 0) { + /* Try Shift-JIS */ + error_number = sjis_utf8tomb(symbol, source, &length, jisdata); + 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 (jisdata[i] < '0' || jisdata[i] > '9') { + if (is_alpha(jisdata[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 == LEVEL_Q) { + version_valid[0] = 0; + version_valid[1] = 0; + version_valid[2] = 0; + } else if (ecc_level == LEVEL_M) { + version_valid[0] = 0; + } + + /* Determine length of binary data */ + for (i = 0; i < 4; i++) { + if (version_valid[i]) { + binary_count[i] = getBinaryLength(MICROQR_VERSION + i, mode, jisdata, length, 0 /*gs1*/, 0 /*eci*/, symbol->debug); + } else { + binary_count[i] = 128 + 1; + } + } + + /* Eliminate possible versions depending on length of binary data */ + if (binary_count[0] > 20) { + version_valid[0] = 0; + } + if (binary_count[1] > 40) { + version_valid[1] = 0; + } + if (binary_count[2] > 84) { + version_valid[2] = 0; + } + if (binary_count[3] > 128) { + strcpy(symbol->errtxt, "565: Input data too long"); + return ZINT_ERROR_TOO_LONG; + } + + /* Eliminate possible versions depending on binary length and error correction level specified */ + if (ecc_level == LEVEL_Q) { + if (binary_count[3] > 80) { + strcpy(symbol->errtxt, "567: Input data too long"); + return ZINT_ERROR_TOO_LONG; + } + } else if (ecc_level == LEVEL_M) { + if (binary_count[1] > 32) { + version_valid[1] = 0; + } + if (binary_count[2] > 68) { + version_valid[2] = 0; + } + if (binary_count[3] > 112) { + strcpy(symbol->errtxt, "568: Input data too long"); + return ZINT_ERROR_TOO_LONG; + } + } + + autoversion = 3; + if (version_valid[2]) { + autoversion = 2; + } + if (version_valid[1]) { + autoversion = 1; + } + if (version_valid[0]) { + autoversion = 0; + } + + version = autoversion; + /* Get version from user */ + if ((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) { + if (symbol->option_2 - 1 >= autoversion) { + version = symbol->option_2 - 1; + } else { + strcpy(symbol->errtxt, "570: Input too long for selected symbol size"); + return ZINT_ERROR_TOO_LONG; + } + } + + /* If there is enough unused space then increase the error correction level, unless user-specified */ + if (symbol->option_1 == -1 || symbol->option_1 != ecc_level) { + if (version == 3) { + if (binary_count[3] <= 112) { + ecc_level = LEVEL_M; + } + if (binary_count[3] <= 80) { + ecc_level = LEVEL_Q; + } + } else if (version == 2) { + if (binary_count[2] <= 68) { + ecc_level = LEVEL_M; + } + } else if (version == 1) { + if (binary_count[1] <= 32) { + ecc_level = LEVEL_M; + } + } + } + + qr_define_mode(mode, jisdata, length, 0 /*gs1*/, MICROQR_VERSION + version, symbol->debug); + + qr_binary((unsigned char*)full_stream, MICROQR_VERSION + version, 0 /*target_codewords*/, mode, jisdata, length, 0 /*gs1*/, 0 /*eci*/, binary_count[version], symbol->debug); + + switch (version) { + case 0: micro_qr_m1(symbol, full_stream); + break; + case 1: micro_qr_m2(symbol, full_stream, ecc_level); + break; + case 2: micro_qr_m3(symbol, full_stream, ecc_level); + break; + case 3: micro_qr_m4(symbol, full_stream, ecc_level); + break; + } + + size = micro_qr_sizes[version]; +#ifndef _MSC_VER + unsigned char grid[size * size]; +#else + grid = (unsigned char *) _alloca((size * size) * sizeof (unsigned char)); #endif - /* Character representation */ - i = 0; - while ( i < short_data_block_length ) { - int count; - int first = 0, second = 0, prod; - - first = posn(RHODIUM, (char) jisdata[position + i]); - count = 1; - prod = first; - - if(mode[position + i + 1] == 'A') { - second = posn(RHODIUM, (char) jisdata[position + i + 1]); - count = 2; - prod = (first * 45) + second; - } - - qr_bscan(binary, prod, 1 << (5 * count)); /* count = 1..2 */ -#ifdef _DEBUG_MODE_ - printf("0x%4X ", prod); + + for (i = 0; i < size; i++) { + for (j = 0; j < size; j++) { + grid[(i * size) + j] = 0; + } + } + + micro_setup_grid(grid, size); + micro_populate_grid(grid, size, full_stream); + bitmask = micro_apply_bitmask(grid, size); + + /* Add format data */ + format = 0; + switch (version) { + case 1: switch (ecc_level) { + case 1: format = 1; + break; + case 2: format = 2; + break; + } + break; + case 2: switch (ecc_level) { + case 1: format = 3; + break; + case 2: format = 4; + break; + } + break; + case 3: switch (ecc_level) { + case 1: format = 5; + break; + case 2: format = 6; + break; + case 3: format = 7; + break; + } + break; + } + + format_full = qr_annex_c1[(format << 2) + bitmask]; + + if (format_full & 0x4000) { + grid[(8 * size) + 1] += 0x01; + } + if (format_full & 0x2000) { + grid[(8 * size) + 2] += 0x01; + } + if (format_full & 0x1000) { + grid[(8 * size) + 3] += 0x01; + } + if (format_full & 0x800) { + grid[(8 * size) + 4] += 0x01; + } + if (format_full & 0x400) { + grid[(8 * size) + 5] += 0x01; + } + if (format_full & 0x200) { + grid[(8 * size) + 6] += 0x01; + } + if (format_full & 0x100) { + grid[(8 * size) + 7] += 0x01; + } + if (format_full & 0x80) { + grid[(8 * size) + 8] += 0x01; + } + if (format_full & 0x40) { + grid[(7 * size) + 8] += 0x01; + } + if (format_full & 0x20) { + grid[(6 * size) + 8] += 0x01; + } + if (format_full & 0x10) { + grid[(5 * size) + 8] += 0x01; + } + if (format_full & 0x08) { + grid[(4 * size) + 8] += 0x01; + } + if (format_full & 0x04) { + grid[(3 * size) + 8] += 0x01; + } + if (format_full & 0x02) { + grid[(2 * size) + 8] += 0x01; + } + if (format_full & 0x01) { + grid[(1 * size) + 8] += 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; + } + + return 0; +} + +/* For UPNQR the symbol size and error correction capacity is fixed */ +INTERNAL int upnqr(struct zint_symbol *symbol, const unsigned char source[], size_t length) { + int i, j, est_binlen; + int ecc_level, version, target_codewords, blocks, size; + int bitmask, error_number; + +#ifndef _MSC_VER + unsigned int jisdata[length + 1]; + char mode[length + 1]; +#else + unsigned char* datastream; + unsigned char* fullstream; + unsigned char* grid; + unsigned int* jisdata = (unsigned int *) _alloca((length + 1) * sizeof (unsigned int)); + char* mode = (char *) _alloca(length + 1); #endif - if(strlen(binary) > 128) { - return ERROR_TOO_LONG; - } - - i += 2; - }; -#ifdef _DEBUG_MODE_ - printf("\n"); + +#ifndef _MSC_VER + unsigned char preprocessed[length + 1]; +#else + unsigned char* preprocessed = (unsigned char*) _alloca(length + 1); #endif - break; - case 'N': - /* Numeric mode */ - /* Mode indicator */ - concat(binary, "N"); - - /* Character count indicator */ - buffer[0] = short_data_block_length; - buffer[1] = '\0'; - concat(binary, buffer); -#ifdef _DEBUG_MODE_ - printf("Number block (length %d)\n\t", short_data_block_length); + + symbol->eci = 4; /* Set before any processing */ + + switch (symbol->input_mode & 0x07) { + case DATA_MODE: + /* Input is already in ISO-8859-2 format */ + for (i = 0; i < (int) length; i++) { + jisdata[i] = source[i]; + mode[i] = 'B'; + } + break; + case GS1_MODE: + strcpy(symbol->errtxt, "571: UPNQR does not support GS-1 encoding"); + return ZINT_ERROR_INVALID_OPTION; + break; + case UNICODE_MODE: + error_number = utf_to_eci(4, source, preprocessed, &length); + if (error_number != 0) { + strcpy(symbol->errtxt, "572: Invalid characters in input data"); + return error_number; + } + for (i = 0; i < (int) length; i++) { + jisdata[i] = preprocessed[i]; + mode[i] = 'B'; + } + break; + } + + est_binlen = getBinaryLength(15, mode, jisdata, length, 0, symbol->eci, symbol->debug); + + ecc_level = LEVEL_M; + + if (est_binlen > 3320) { + strcpy(symbol->errtxt, "573: Input too long for selected symbol"); + return ZINT_ERROR_TOO_LONG; + } + + version = 15; // 77 x 77 + + target_codewords = qr_data_codewords_M[version - 1]; + blocks = qr_blocks_M[version - 1]; +#ifndef _MSC_VER + unsigned char datastream[target_codewords + 1]; + unsigned char fullstream[qr_total_codewords[version - 1] + 1]; +#else + datastream = (unsigned char *) _alloca(target_codewords + 1); + fullstream = (unsigned char *) _alloca(qr_total_codewords[version - 1] + 1); #endif - /* Character representation */ - i = 0; - while ( i < short_data_block_length ) { - int count; - int first = 0, second = 0, third = 0, prod; - - first = posn(NEON, (char) jisdata[position + i]); - count = 1; - prod = first; - - if(mode[position + i + 1] == 'N') { - second = posn(NEON, (char) jisdata[position + i + 1]); - count = 2; - prod = (prod * 10) + second; - } - - if(mode[position + i + 2] == 'N') { - third = posn(NEON, (char) jisdata[position + i + 2]); - count = 3; - prod = (prod * 10) + third; - } - - qr_bscan(binary, prod, 1 << (3 * count)); /* count = 1..3 */ -#ifdef _DEBUG_MODE_ - printf("0x%4X (%d)", prod, prod); + + qr_binary(datastream, version, target_codewords, mode, jisdata, length, 0, symbol->eci, est_binlen, symbol->debug); +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords); #endif - if(strlen(binary) > 128) { - return ERROR_TOO_LONG; - } - - i += 3; - }; -#ifdef _DEBUG_MODE_ - printf("\n"); + add_ecc(fullstream, datastream, version, target_codewords, blocks, symbol->debug); + + size = qr_sizes[version - 1]; +#ifndef _MSC_VER + unsigned char grid[size * size]; +#else + grid = (unsigned char *) _alloca((size * size) * sizeof (unsigned char)); #endif - break; - } - - position += short_data_block_length; - } while (position < length - 1) ; - - return 0; -} -void get_bitlength(int count[], char stream[]) { - int length, i; - - length = strlen(stream); - - for(i = 0; i < 4; i++) { - count[i] = 0; - } - - i = 0; - do { - if((stream[i] == '0') || (stream[i] == '1')) { - count[0]++; - count[1]++; - count[2]++; - count[3]++; - i++; - } else { - switch(stream[i]) { - case 'K': - count[2] += 5; - count[3] += 7; - i += 2; - break; - case 'B': - count[2] += 6; - count[3] += 8; - i += 2; - break; - case 'A': - count[1] += 4; - count[2] += 6; - count[3] += 8; - i += 2; - break; - case 'N': - count[0] += 3; - count[1] += 5; - count[2] += 7; - count[3] += 9; - i += 2; - break; - } - } - } while (i < length); -} + for (i = 0; i < size; i++) { + for (j = 0; j < size; j++) { + grid[(i * size) + j] = 0; + } + } -void microqr_expand_binary(char binary_stream[], char full_stream[], int version) -{ - int i, length; - - length = strlen(binary_stream); - - i = 0; - do { - switch(binary_stream[i]) { - case '1': concat(full_stream, "1"); i++; break; - case '0': concat(full_stream, "0"); i++; break; - case 'N': - /* Numeric Mode */ - /* Mode indicator */ - switch(version) { - case 1: concat(full_stream, "0"); break; - case 2: concat(full_stream, "00"); break; - case 3: concat(full_stream, "000"); break; - } - - /* Character count indicator */ - qr_bscan(full_stream, binary_stream[i + 1], 4 << version); /* version = 0..3 */ - - i += 2; - break; - case 'A': - /* Alphanumeric Mode */ - /* Mode indicator */ - switch(version) { - case 1: concat(full_stream, "1"); break; - case 2: concat(full_stream, "01"); break; - case 3: concat(full_stream, "001"); break; - } - - /* Character count indicator */ - qr_bscan(full_stream, binary_stream[i + 1], 2 << version); /* version = 1..3 */ - - i += 2; - break; - case 'B': - /* Byte Mode */ - /* Mode indicator */ - switch(version) { - case 2: concat(full_stream, "10"); break; - case 3: concat(full_stream, "010"); break; - } - - /* Character count indicator */ - qr_bscan(full_stream, binary_stream[i + 1], 2 << version); /* version = 2..3 */ - - i += 2; - break; - case 'K': - /* Kanji Mode */ - /* Mode indicator */ - switch(version) { - case 2: concat(full_stream, "11"); break; - case 3: concat(full_stream, "011"); break; - } - - /* Character count indicator */ - qr_bscan(full_stream, binary_stream[i + 1], 1 << version); /* version = 2..3 */ - - i += 2; - break; - } - - } while (i < length); -} + setup_grid(grid, size, version); + populate_grid(grid, size, size, fullstream, qr_total_codewords[version - 1]); -void micro_qr_m1(char binary_data[]) -{ - int i, latch; - int bits_total, bits_left, remainder; - int data_codewords, ecc_codewords; - unsigned char data_blocks[4], ecc_blocks[3]; - - bits_total = 20; - latch = 0; - - /* Add terminator */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 3) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } else { - concat(binary_data, "000"); - } - - if(latch == 0) { - /* Manage last (4-bit) block */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 4) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } - } - - if(latch == 0) { - /* Complete current byte */ - remainder = 8 - (strlen(binary_data) % 8); - if(remainder == 8) { remainder = 0; } - for(i = 0; i < remainder; i++) { - concat(binary_data, "0"); - } - - /* Add padding */ - bits_left = bits_total - strlen(binary_data); - if(bits_left > 4) { - remainder = (bits_left - 4) / 8; - for(i = 0; i < remainder; i++) { - concat(binary_data, i & 1 ? "00010001" : "11101100"); - } - } - concat(binary_data, "0000"); - } - - data_codewords = 3; - ecc_codewords = 2; - - /* Copy data into codewords */ - for(i = 0; i < (data_codewords - 1); i++) { - data_blocks[i] = 0; - if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } - if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } - if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } - if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } - if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } - if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } - if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } - if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } - } - data_blocks[2] = 0; - if(binary_data[16] == '1') { data_blocks[2] += 0x08; } - if(binary_data[17] == '1') { data_blocks[2] += 0x04; } - if(binary_data[18] == '1') { data_blocks[2] += 0x02; } - if(binary_data[19] == '1') { data_blocks[2] += 0x01; } - - /* Calculate Reed-Solomon error codewords */ - rs_init_gf(0x11d); - rs_init_code(ecc_codewords, 0); - rs_encode(data_codewords,data_blocks,ecc_blocks); - rs_free(); - - /* Add Reed-Solomon codewords to binary data */ - for(i = 0; i < ecc_codewords; i++) { - qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); - } -} + add_version_info(grid, size, version); -void micro_qr_m2(char binary_data[], int ecc_mode) -{ - int i, latch; - int bits_total, bits_left, remainder; - int data_codewords, ecc_codewords; - unsigned char data_blocks[6], ecc_blocks[7]; - - latch = 0; - - if(ecc_mode == LEVEL_L) { bits_total = 40; } - if(ecc_mode == LEVEL_M) { bits_total = 32; } - - /* Add terminator */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 5) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } else { - concat(binary_data, "00000"); - } - - if(latch == 0) { - /* Complete current byte */ - remainder = 8 - (strlen(binary_data) % 8); - if(remainder == 8) { remainder = 0; } - for(i = 0; i < remainder; i++) { - concat(binary_data, "0"); - } - - /* Add padding */ - bits_left = bits_total - strlen(binary_data); - remainder = bits_left / 8; - for(i = 0; i < remainder; i++) { - concat(binary_data, i & 1 ? "00010001" : "11101100"); - } - } - - if(ecc_mode == LEVEL_L) { data_codewords = 5; ecc_codewords = 5; } - if(ecc_mode == LEVEL_M) { data_codewords = 4; ecc_codewords = 6; } - - /* Copy data into codewords */ - for(i = 0; i < data_codewords; i++) { - data_blocks[i] = 0; - if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } - if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } - if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } - if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } - if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } - if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } - if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } - if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } - } - - /* Calculate Reed-Solomon error codewords */ - rs_init_gf(0x11d); - rs_init_code(ecc_codewords, 0); - rs_encode(data_codewords,data_blocks,ecc_blocks); - rs_free(); - - /* Add Reed-Solomon codewords to binary data */ - for(i = 0; i < ecc_codewords; i++) { - qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); - } - - return; -} + bitmask = apply_bitmask(grid, size, ecc_level); -void micro_qr_m3(char binary_data[], int ecc_mode) -{ - int i, latch; - int bits_total, bits_left, remainder; - int data_codewords, ecc_codewords; - unsigned char data_blocks[12], ecc_blocks[9]; - - latch = 0; - - if(ecc_mode == LEVEL_L) { bits_total = 84; } - if(ecc_mode == LEVEL_M) { bits_total = 68; } - - /* Add terminator */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 7) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } else { - concat(binary_data, "0000000"); - } - - if(latch == 0) { - /* Manage last (4-bit) block */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 4) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } - } - - if(latch == 0) { - /* Complete current byte */ - remainder = 8 - (strlen(binary_data) % 8); - if(remainder == 8) { remainder = 0; } - for(i = 0; i < remainder; i++) { - concat(binary_data, "0"); - } - - /* Add padding */ - bits_left = bits_total - strlen(binary_data); - if(bits_left > 4) { - remainder = (bits_left - 4) / 8; - for(i = 0; i < remainder; i++) { - concat(binary_data, i & 1 ? "00010001" : "11101100"); - } - } - concat(binary_data, "0000"); - } - - if(ecc_mode == LEVEL_L) { data_codewords = 11; ecc_codewords = 6; } - if(ecc_mode == LEVEL_M) { data_codewords = 9; ecc_codewords = 8; } - - /* Copy data into codewords */ - for(i = 0; i < (data_codewords - 1); i++) { - data_blocks[i] = 0; - if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } - if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } - if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } - if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } - if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } - if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } - if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } - if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } - } - - if(ecc_mode == LEVEL_L) { - data_blocks[11] = 0; - if(binary_data[80] == '1') { data_blocks[2] += 0x08; } - if(binary_data[81] == '1') { data_blocks[2] += 0x04; } - if(binary_data[82] == '1') { data_blocks[2] += 0x02; } - if(binary_data[83] == '1') { data_blocks[2] += 0x01; } - } - - if(ecc_mode == LEVEL_M) { - data_blocks[9] = 0; - if(binary_data[64] == '1') { data_blocks[2] += 0x08; } - if(binary_data[65] == '1') { data_blocks[2] += 0x04; } - if(binary_data[66] == '1') { data_blocks[2] += 0x02; } - if(binary_data[67] == '1') { data_blocks[2] += 0x01; } - } - - /* Calculate Reed-Solomon error codewords */ - rs_init_gf(0x11d); - rs_init_code(ecc_codewords, 0); - rs_encode(data_codewords,data_blocks,ecc_blocks); - rs_free(); - - /* Add Reed-Solomon codewords to binary data */ - for(i = 0; i < ecc_codewords; i++) { - qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); - } - - return; -} + add_format_info(grid, size, ecc_level, bitmask); -void micro_qr_m4(char binary_data[], int ecc_mode) -{ - int i, latch; - int bits_total, bits_left, remainder; - int data_codewords, ecc_codewords; - unsigned char data_blocks[17], ecc_blocks[15]; - - latch = 0; - - if(ecc_mode == LEVEL_L) { bits_total = 128; } - if(ecc_mode == LEVEL_M) { bits_total = 112; } - if(ecc_mode == LEVEL_Q) { bits_total = 80; } - - /* Add terminator */ - bits_left = bits_total - strlen(binary_data); - if(bits_left <= 9) { - for(i = 0; i < bits_left; i++) { - concat(binary_data, "0"); - } - latch = 1; - } else { - concat(binary_data, "000000000"); - } - - if(latch == 0) { - /* Complete current byte */ - remainder = 8 - (strlen(binary_data) % 8); - if(remainder == 8) { remainder = 0; } - for(i = 0; i < remainder; i++) { - concat(binary_data, "0"); - } - - /* Add padding */ - bits_left = bits_total - strlen(binary_data); - remainder = bits_left / 8; - for(i = 0; i < remainder; i++) { - concat(binary_data, i & 1 ? "00010001" : "11101100"); - } - } - - if(ecc_mode == LEVEL_L) { data_codewords = 16; ecc_codewords = 8; } - if(ecc_mode == LEVEL_M) { data_codewords = 14; ecc_codewords = 10; } - if(ecc_mode == LEVEL_Q) { data_codewords = 10; ecc_codewords = 14; } - - /* Copy data into codewords */ - for(i = 0; i < data_codewords; i++) { - data_blocks[i] = 0; - if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; } - if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; } - if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; } - if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; } - if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; } - if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; } - if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; } - if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; } - } - - /* Calculate Reed-Solomon error codewords */ - rs_init_gf(0x11d); - rs_init_code(ecc_codewords, 0); - rs_encode(data_codewords,data_blocks,ecc_blocks); - rs_free(); - - /* Add Reed-Solomon codewords to binary data */ - for(i = 0; i < ecc_codewords; i++) { - qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80); - } -} + symbol->width = size; + symbol->rows = size; -void micro_setup_grid(unsigned char* grid, 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 */ - 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; -} + 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; + } -void micro_populate_grid(unsigned char* grid, int size, char full_stream[]) -{ - int direction = 1; /* up */ - int row = 0; /* right hand side */ - - int i, n, x, y; - - n = strlen(full_stream); - y = size - 1; - i = 0; - do { - 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 < n) { - 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 < n); + return 0; } -int micro_evaluate(unsigned char *grid, int size, 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 void setup_rmqr_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 */ + 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) { + for(i = 0; i < 5; i++) { + if (h_size == rmqr_width[i]) { + h_version = i; + } + } + + 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; } -int micro_apply_bitmask(unsigned char *grid, int size) -{ - int x, y; - unsigned char p; - int pattern, value[8]; - int best_val, best_pattern; - int bit; - +/* rMQR according to 2018 draft standard */ +INTERNAL int rmqr(struct zint_symbol *symbol, const unsigned char source[], size_t length) { + int i, j, est_binlen; + int ecc_level, autosize, version, max_cw, target_codewords, blocks, h_size, v_size; + int gs1; + int full_multibyte; + int footprint, best_footprint, format_data; + unsigned int left_format_info, right_format_info; + #ifndef _MSC_VER - unsigned char mask[size * size]; - unsigned char eval[size * size]; + unsigned int jisdata[length + 1]; + char mode[length + 1]; #else - unsigned char* mask = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); - unsigned char* eval = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); + unsigned char* datastream; + unsigned char* fullstream; + unsigned char* grid; + unsigned int* jisdata = (unsigned int *) _alloca((length + 1) * sizeof (unsigned int)); + char* mode = (char *) _alloca(length + 1); #endif - /* Perform data masking */ - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - mask[(y * size) + x] = 0x00; - - if (!(grid[(y * size) + x] & 0xf0)) { - if((y & 1) == 0) { - mask[(y * size) + x] += 0x01; - } - - if((((y / 2) + (x / 3)) & 1) == 0) { - mask[(y * size) + x] += 0x02; - } - - if(((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { - mask[(y * size) + x] += 0x04; - } - - if(((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { - mask[(y * size) + x] += 0x08; - } - } - } - } - - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - if(grid[(y * size) + x] & 0x01) { p = 0xff; } else { p = 0x00; } - - eval[(y * size) + x] = mask[(y * size) + x] ^ p; - } - } - - - /* Evaluate result */ - for(pattern = 0; pattern < 8; pattern++) { - value[pattern] = micro_evaluate(eval, size, pattern); - } - - best_pattern = 0; - best_val = value[0]; - for(pattern = 1; pattern < 4; pattern++) { - if(value[pattern] > best_val) { - best_pattern = pattern; - best_val = value[pattern]; - } - } - - /* Apply mask */ - for(x = 0; x < size; x++) { - for(y = 0; y < size; y++) { - bit = 0; - switch(best_pattern) { - case 0: if(mask[(y * size) + x] & 0x01) { bit = 1; } break; - case 1: if(mask[(y * size) + x] & 0x02) { bit = 1; } break; - case 2: if(mask[(y * size) + x] & 0x04) { bit = 1; } break; - case 3: if(mask[(y * size) + x] & 0x08) { bit = 1; } break; - } - if(bit == 1) { - if(grid[(y * size) + x] & 0x01) { - grid[(y * size) + x] = 0x00; - } else { - grid[(y * size) + x] = 0x01; - } - } - } - } - - return best_pattern; -} + gs1 = ((symbol->input_mode & 0x07) == GS1_MODE); + full_multibyte = symbol->option_3 == ZINT_FULL_MULTIBYTE; /* If set use Kanji mode in DATA_MODE or for single-byte Latin */ + + if ((symbol->input_mode & 0x07) == DATA_MODE) { + sjis_cpy(source, &length, jisdata, full_multibyte); + } else { + /* Try ISO 8859-1 conversion first */ + int error_number = sjis_utf8tosb(3, source, &length, jisdata, full_multibyte); + if (error_number != 0) { + /* Try Shift-JIS */ + error_number = sjis_utf8tomb(symbol, source, &length, jisdata); + if (error_number != 0) { + return error_number; + } + } + } + + est_binlen = getBinaryLength(RMQR_VERSION + 31, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug); + + ecc_level = LEVEL_M; + max_cw = 152; + if (symbol->option_1 == 1) { + strcpy(symbol->errtxt, "576: Error correction level L not available in rMQR"); + return ZINT_ERROR_INVALID_OPTION; + } + + if (symbol->option_1 == 3) { + strcpy(symbol->errtxt, "577: Error correction level Q not available in rMQR"); + return ZINT_ERROR_INVALID_OPTION; + } + + if (symbol->option_1 == 4) { + ecc_level = LEVEL_H; + max_cw = 76; + } + + if (est_binlen > (8 * max_cw)) { + strcpy(symbol->errtxt, "578: Input too long for selected error correction level"); + return ZINT_ERROR_TOO_LONG; + } + + if ((symbol->option_2 < 0) || (symbol->option_2 > 38)) { + strcpy(symbol->errtxt, "579: Invalid rMQR symbol size"); + return ZINT_ERROR_INVALID_OPTION; + } + + 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 = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug); + footprint = rmqr_height[version] * rmqr_width[version]; + if (ecc_level == LEVEL_M) { + if (8 * rmqr_data_codewords_M[version] >= est_binlen) { + if (footprint < best_footprint) { + autosize = version; + best_footprint = footprint; + } + } + } else { + if (8 * rmqr_data_codewords_H[version] >= est_binlen) { + if (footprint < best_footprint) { + autosize = version; + best_footprint = footprint; + } + } + } + } + version = autosize; + est_binlen = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug); + } + + if ((symbol->option_2 >= 1) && (symbol->option_2 <= 32)) { + // User specified symbol size + version = symbol->option_2 - 1; + est_binlen = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug); + } + + 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 = getBinaryLength(RMQR_VERSION + i, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug); + if (ecc_level == LEVEL_M) { + if (8 * rmqr_data_codewords_M[i] >= est_binlen) { + version = i; + } + } else { + if (8 * rmqr_data_codewords_H[i] >= est_binlen) { + version = i; + } + } + } + est_binlen = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug); + } + + if (symbol->option_1 == -1) { + // Detect if there is enough free space to increase ECC level + if (est_binlen < (rmqr_data_codewords_H[version] * 8)) { + ecc_level = LEVEL_H; + } + } + + if (ecc_level == LEVEL_M) { + target_codewords = rmqr_data_codewords_M[version]; + blocks = rmqr_blocks_M[version]; + } else { + target_codewords = rmqr_data_codewords_H[version]; + blocks = rmqr_blocks_H[version]; + } + + if (est_binlen > (target_codewords * 8)) { + // User has selected a symbol too small for the data + strcpy(symbol->errtxt, "580: Input too long for selected symbol size"); + return ZINT_ERROR_TOO_LONG; + } + + if (symbol->debug & ZINT_DEBUG_PRINT) { + printf("Minimum codewords = %d\n", est_binlen / 8); + printf("Selected version: %d = R%dx%d-", (version + 1), rmqr_height[version], rmqr_width[version]); + if (ecc_level == LEVEL_M) { + printf("M\n"); + } else { + printf("H\n"); + } + printf("Number of data codewords in symbol = %d\n", target_codewords); + printf("Number of ECC blocks = %d\n", blocks); + } -int microqr(struct zint_symbol *symbol, unsigned char source[], int length) -{ - int i, j, glyph, size; - char binary_stream[200]; - char full_stream[200]; - int utfdata[40]; - int jisdata[40]; - char mode[40]; - int error_number, kanji_used = 0, alphanum_used = 0, byte_used = 0; - int version_valid[4]; - int binary_count[4]; - int ecc_level, autoversion, version; - int n_count, a_count, bitmask, format, format_full; - - if(length > 35) { - strcpy(symbol->errtxt, "Input data too long"); - return ERROR_TOO_LONG; - } - - for(i = 0; i < 4; i++) { - version_valid[i] = 1; - } - - switch(symbol->input_mode) { - case DATA_MODE: - for(i = 0; i < length; i++) { - jisdata[i] = (int)source[i]; - } - break; - default: - /* Convert Unicode input to Shift-JIS */ - error_number = utf8toutf16(symbol, source, utfdata, &length); - if(error_number != 0) { return error_number; } - - for(i = 0; i < length; i++) { - if(utfdata[i] <= 0xff) { - jisdata[i] = utfdata[i]; - } else { - j = 0; - glyph = 0; - do { - if(sjis_lookup[j * 2] == utfdata[i]) { - glyph = sjis_lookup[(j * 2) + 1]; - } - j++; - } while ((j < 6843) && (glyph == 0)); - if(glyph == 0) { - strcpy(symbol->errtxt, "Invalid character in input data"); - return ERROR_INVALID_DATA; - } - jisdata[i] = glyph; - } - } - break; - } - - define_mode(mode, jisdata, length, 0); - - n_count = 0; - a_count = 0; - for(i = 0; i < length; i++) { - if((jisdata[i] >= '0') && (jisdata[i] <= '9')) { n_count++; } - if(in_alpha(jisdata[i])) { a_count++; } - } - - if(a_count == length) { - /* All data can be encoded in Alphanumeric mode */ - for(i = 0; i < length; i++) { - mode[i] = 'A'; - } - } - - if(n_count == length) { - /* All data can be encoded in Numeric mode */ - for(i = 0; i < length; i++) { - mode[i] = 'N'; - } - } - - error_number = micro_qr_intermediate(binary_stream, jisdata, mode, length, &kanji_used, &alphanum_used, &byte_used); - if(error_number != 0) { - strcpy(symbol->errtxt, "Input data too long"); - return error_number; - } - - get_bitlength(binary_count, binary_stream); - - /* Eliminate possivle versions depending on type of content */ - if(byte_used) { - version_valid[0] = 0; - version_valid[1] = 0; - } - - if(alphanum_used) { - version_valid[0] = 0; - } - - if(kanji_used) { - version_valid[0] = 0; - version_valid[1] = 0; - } - - /* Eliminate possible versions depending on length of binary data */ - if(binary_count[0] > 20) { version_valid[0] = 0; } - if(binary_count[1] > 40) { version_valid[1] = 0; } - if(binary_count[2] > 84) { version_valid[2] = 0; } - if(binary_count[3] > 128) { - strcpy(symbol->errtxt, "Input data too long"); - return ERROR_TOO_LONG; - } - - /* Eliminate possible versions depending on error correction level specified */ - ecc_level = LEVEL_L; - if((symbol->option_1 >= 1) && (symbol->option_2 <= 4)) { - ecc_level = symbol->option_1; - } - - if(ecc_level == LEVEL_H) { - strcpy(symbol->errtxt, "Error correction level H not available"); - return ERROR_INVALID_OPTION; - } - - if(ecc_level == LEVEL_Q) { - version_valid[0] = 0; - version_valid[1] = 0; - version_valid[2] = 0; - if(binary_count[3] > 80) { - strcpy(symbol->errtxt, "Input data too long"); - return ERROR_TOO_LONG; - } - } - - if(ecc_level == LEVEL_M) { - version_valid[0] = 0; - if(binary_count[1] > 32) { version_valid[1] = 0; } - if(binary_count[2] > 68) { version_valid[2] = 0; } - if(binary_count[3] > 112) { - strcpy(symbol->errtxt, "Input data too long"); - return ERROR_TOO_LONG; - } - } - - autoversion = 3; - if(version_valid[2]) { autoversion = 2; } - if(version_valid[1]) { autoversion = 1; } - if(version_valid[0]) { autoversion = 0; } - - version = autoversion; - /* Get version from user */ - if((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) { - if((symbol->option_2 - 1) >= autoversion) { - version = symbol->option_2 - 1; - } - } - - /* If there is enough unused space then increase the error correction level */ - if(version == 3) { - if(binary_count[3] <= 112) { ecc_level = LEVEL_M; } - if(binary_count[3] <= 80) { ecc_level = LEVEL_Q; } - } - - if(version == 2) { - if(binary_count[2] <= 68) { ecc_level = LEVEL_M; } - } - - if(version == 1) { - if(binary_count[1] <= 32) { ecc_level = LEVEL_M; } - } - - strcpy(full_stream, ""); - microqr_expand_binary(binary_stream, full_stream, version); - - switch(version) { - case 0: micro_qr_m1(full_stream); break; - case 1: micro_qr_m2(full_stream, ecc_level); break; - case 2: micro_qr_m3(full_stream, ecc_level); break; - case 3: micro_qr_m4(full_stream, ecc_level); break; - } - - size = micro_qr_sizes[version]; #ifndef _MSC_VER - unsigned char grid[size * size]; + unsigned char datastream[target_codewords + 1]; + unsigned char fullstream[rmqr_total_codewords[version] + 1]; #else - unsigned char* grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char)); + datastream = (unsigned char *) _alloca((target_codewords + 1) * sizeof (unsigned char)); + fullstream = (unsigned char *) _alloca((rmqr_total_codewords[version] + 1) * sizeof (unsigned char)); +#endif + + qr_binary(datastream, RMQR_VERSION + version, target_codewords, mode, jisdata, length, gs1, 0 /*eci*/, est_binlen, symbol->debug); +#ifdef ZINT_TEST + if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords); #endif - - for(i = 0; i < size; i++) { - for(j = 0; j < size; j++) { - grid[(i * size) + j] = 0; - } - } - - micro_setup_grid(grid, size); - micro_populate_grid(grid, size, full_stream); - bitmask = micro_apply_bitmask(grid, size); - - /* Add format data */ - format = 0; - switch(version) { - case 1: switch(ecc_level) { - case 1: format = 1; break; - case 2: format = 2; break; - } - break; - case 2: switch(ecc_level) { - case 1: format = 3; break; - case 2: format = 4; break; - } - break; - case 3: switch(ecc_level) { - case 1: format = 5; break; - case 2: format = 6; break; - case 3: format = 7; break; - } - break; - } - - format_full = qr_annex_c1[(format << 2) + bitmask]; - - if(format_full & 0x4000) { grid[(8 * size) + 1] += 0x01; } - if(format_full & 0x2000) { grid[(8 * size) + 2] += 0x01; } - if(format_full & 0x1000) { grid[(8 * size) + 3] += 0x01; } - if(format_full & 0x800) { grid[(8 * size) + 4] += 0x01; } - if(format_full & 0x400) { grid[(8 * size) + 5] += 0x01; } - if(format_full & 0x200) { grid[(8 * size) + 6] += 0x01; } - if(format_full & 0x100) { grid[(8 * size) + 7] += 0x01; } - if(format_full & 0x80) { grid[(8 * size) + 8] += 0x01; } - if(format_full & 0x40) { grid[(7 * size) + 8] += 0x01; } - if(format_full & 0x20) { grid[(6 * size) + 8] += 0x01; } - if(format_full & 0x10) { grid[(5 * size) + 8] += 0x01; } - if(format_full & 0x08) { grid[(4 * size) + 8] += 0x01; } - if(format_full & 0x04) { grid[(3 * size) + 8] += 0x01; } - if(format_full & 0x02) { grid[(2 * size) + 8] += 0x01; } - if(format_full & 0x01) { grid[(1 * size) + 8] += 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; - } - - return 0; + add_ecc(fullstream, datastream, RMQR_VERSION + version, target_codewords, blocks, symbol->debug); + + h_size = rmqr_width[version]; + v_size = rmqr_height[version]; + +#ifndef _MSC_VER + unsigned char grid[h_size * v_size]; +#else + grid = (unsigned char *) _alloca((h_size * v_size) * sizeof (unsigned char)); +#endif + + for (i = 0; i < v_size; i++) { + for (j = 0; j < h_size; j++) { + grid[(i * h_size) + j] = 0; + } + } + + setup_rmqr_grid(grid, h_size, v_size); + populate_grid(grid, h_size, v_size, fullstream, rmqr_total_codewords[version]); + + /* apply bitmask */ + for (i = 0; i < v_size; i++) { + for (j = 0; j < h_size; j++) { + if ((grid[(i * h_size) + 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 + if (grid[(i * h_size) + j] == 0x01) { + grid[(i * h_size) + j] = 0x00; + } else { + grid[(i * h_size) + j] = 0x01; + } + } + } + } + } + + /* add format information */ + format_data = version; + if (ecc_level == 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++) { + for (j = 0; j < h_size; j++) { + if (grid[(i * h_size) + j] & 0x01) { + set_module(symbol, i, j); + } + } + symbol->row_height[i] = 1; + } + + return 0; } |