summaryrefslogtreecommitdiff
path: root/backend/qr.c
diff options
context:
space:
mode:
authorTae-Young Chung <ty83.chung@samsung.com>2020-06-22 11:16:33 +0900
committerTae-Young Chung <ty83.chung@samsung.com>2020-06-22 13:32:26 +0900
commit0428f8a17e78dae97a8774a0ec42f48f85abcb88 (patch)
tree100c5b5a6d1d6f996294ead7474f31703a456339 /backend/qr.c
parentf18ddd9e3e6afc1edf5d030dd32647b3eac5462b (diff)
downloadlibzint-0428f8a17e78dae97a8774a0ec42f48f85abcb88.tar.gz
libzint-0428f8a17e78dae97a8774a0ec42f48f85abcb88.tar.bz2
libzint-0428f8a17e78dae97a8774a0ec42f48f85abcb88.zip
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.c5195
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;
}