From d2ac6e7cb678622bc70654b2b56007355ff3dfe0 Mon Sep 17 00:00:00 2001 From: hooper114 Date: Wed, 5 Nov 2008 08:43:13 +0000 Subject: [PATCH] Add Data Matrix ECC 000-140 and MicroQR --- backend/Makefile | 8 +- backend/code128.c | 3 +- backend/dmatrix.c | 1265 +++++++++++++++++++++++++++++++++++++++++++- backend/dmatrix.h | 671 +++++++++++++++++++++++ backend/library.c | 9 +- backend/micqr.c | 867 ++++++++++++++++++++++++++++++ backend/micqr.h | 103 ++++ docs/backend.html | 13 +- docs/frontend.html | 10 +- docs/index.html | 8 +- docs/microqr.png | Bin 0 -> 214 bytes docs/twodims.html | 144 ++++- 12 files changed, 3070 insertions(+), 31 deletions(-) create mode 100644 backend/dmatrix.h create mode 100644 backend/micqr.c create mode 100644 backend/micqr.h create mode 100644 docs/microqr.png diff --git a/backend/Makefile b/backend/Makefile index 17a712d7..23d51dbc 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -25,8 +25,8 @@ ONEDIM:= code.c code128.c 2of5.c upcean.c telepen.c medical.c plessey.c rss.c ONEDIM_OBJ:= code.o code128.o 2of5.o upcean.o telepen.o medical.o plessey.o rss.o POSTAL:= postal.c auspost.c imail.c POSTAL_OBJ:= postal.o auspost.o imail.o -TWODIM:= code16k.c blockf.c dmatrix.c dm200.c pdf417.c qr.c maxicode.c composite.c aztec.c -TWODIM_OBJ:= code16k.o blockf.o dmatrix.o dm200.o pdf417.o qr.o maxicode.o composite.o aztec.o +TWODIM:= code16k.c blockf.c dmatrix.c dm200.c pdf417.c qr.c maxicode.c composite.c aztec.c micqr.c +TWODIM_OBJ:= code16k.o blockf.o dmatrix.o dm200.o pdf417.o qr.o maxicode.o composite.o aztec.o micqr.o LIBS:= `libpng12-config --I_opts --L_opts --ldflags` -lz -lm ifeq ($(NO_QR),true) @@ -36,12 +36,12 @@ DEFINES:= LIBS+= -lqrencode endif -libzint: code.c code128.c 2of5.c upcean.c medical.c telepen.c plessey.c postal.c auspost.c imail.c code16k.c dmatrix.c dm200.c reedsol.c pdf417.c maxicode.c rss.c common.c png.c library.c ps.c qr.c large.c composite.c aztec.c blockf.c +libzint: code.c code128.c 2of5.c upcean.c medical.c telepen.c plessey.c postal.c auspost.c imail.c code16k.c dmatrix.c dm200.c reedsol.c pdf417.c maxicode.c rss.c common.c png.c library.c ps.c qr.c large.c composite.c aztec.c blockf.c micqr.c $(CC) -Wall -fPIC $(CFLAGS) $(ZINT_VERSION) -c $(ONEDIM) $(CC) -Wall -fPIC $(CFLAGS) $(ZINT_VERSION) -c $(POSTAL) $(CC) -Wall -fPIC $(DEFINES) $(CFLAGS) $(ZINT_VERSION) -c $(TWODIM) $(CC) -Wall -fPIC $(CFLAGS) $(ZINT_VERSION) -c $(COMMON) - $(CC) $(CFLAGS) $(ZINT_VERSION) -shared -Wl,-soname,libzint.so -o libzint.so.1.6.3 $(INCLUDE) $(COMMON_OBJ) $(ONEDIM_OBJ) $(TWODIM_OBJ) $(POSTAL_OBJ) $(LIBS) + $(CC) $(CFLAGS) $(ZINT_VERSION) -shared -Wl,-soname,libzint.so -o libzint.so.2.0.0 $(INCLUDE) $(COMMON_OBJ) $(ONEDIM_OBJ) $(TWODIM_OBJ) $(POSTAL_OBJ) $(LIBS) ln -s libzint.so.* libzint.so .PHONY: install uninstall clean dist diff --git a/backend/code128.c b/backend/code128.c index 1e11c17d..2920b164 100644 --- a/backend/code128.c +++ b/backend/code128.c @@ -36,6 +36,8 @@ #define AORB 96 #define ABORC 97 +#define DPDSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*" + int list[2][170]; /* Code 128 tables checked against ISO/IEC 15417:2007 */ @@ -965,4 +967,3 @@ int ean_14(struct zint_symbol *symbol, unsigned char source[]) return error_number; } - diff --git a/backend/dmatrix.c b/backend/dmatrix.c index 325a012c..e69725d8 100644 --- a/backend/dmatrix.c +++ b/backend/dmatrix.c @@ -1,4 +1,4 @@ -/* dmatrix.c - Handles Data Matrix 2-D symbology (IEC16022 ecc 200) */ +/* dmatrix.c - Handles Data Matrix 2-D symbology */ /* libzint - the open source barcode library @@ -20,24 +20,1271 @@ */ #include +#include #include "dm200.h" +#include "dmatrix.h" #include "common.h" +#define B11SET " 0123456789" +#define B27SET " ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define B37SET " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" +#define B41SET " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,-/" + +void crc_machine(char data_prefix_bitstream[], int scheme, unsigned char source[]) +{ + int input_length, i; + input_length = ustrlen(source); + char xor_register[17]; + char precrc_bitstream[(input_length * 8) + 16]; + char precrc_bitstream_reversed[(input_length * 8) + 16]; + int machine_cycles; + char input_bit, out1, out2, out3; + + switch(scheme) { + case 11: strcpy(precrc_bitstream, "0000000100000000"); break; + case 27: strcpy(precrc_bitstream, "0000001000000000"); break; + case 41: strcpy(precrc_bitstream, "0000001100000000"); break; + case 37: strcpy(precrc_bitstream, "0000010000000000"); break; + default: strcpy(precrc_bitstream, "0000010100000000"); break; + } + + for(i = 0; i < input_length; i++) { + if(source[i] & 0x80) { concat(precrc_bitstream, "1"); } else { concat(precrc_bitstream, "0"); } + if(source[i] & 0x40) { concat(precrc_bitstream, "1"); } else { concat(precrc_bitstream, "0"); } + if(source[i] & 0x20) { concat(precrc_bitstream, "1"); } else { concat(precrc_bitstream, "0"); } + if(source[i] & 0x10) { concat(precrc_bitstream, "1"); } else { concat(precrc_bitstream, "0"); } + if(source[i] & 0x08) { concat(precrc_bitstream, "1"); } else { concat(precrc_bitstream, "0"); } + if(source[i] & 0x04) { concat(precrc_bitstream, "1"); } else { concat(precrc_bitstream, "0"); } + if(source[i] & 0x02) { concat(precrc_bitstream, "1"); } else { concat(precrc_bitstream, "0"); } + if(source[i] & 0x01) { concat(precrc_bitstream, "1"); } else { concat(precrc_bitstream, "0"); } + } + + /* pre-CRC bit stream byte reversal */ + for(i = 0; i < (input_length + 2); i++) { + precrc_bitstream_reversed[0 + (i * 8)] = precrc_bitstream[7 + (i * 8)]; + precrc_bitstream_reversed[1 + (i * 8)] = precrc_bitstream[6 + (i * 8)]; + precrc_bitstream_reversed[2 + (i * 8)] = precrc_bitstream[5 + (i * 8)]; + precrc_bitstream_reversed[3 + (i * 8)] = precrc_bitstream[4 + (i * 8)]; + precrc_bitstream_reversed[4 + (i * 8)] = precrc_bitstream[3 + (i * 8)]; + precrc_bitstream_reversed[5 + (i * 8)] = precrc_bitstream[2 + (i * 8)]; + precrc_bitstream_reversed[6 + (i * 8)] = precrc_bitstream[1 + (i * 8)]; + precrc_bitstream_reversed[7 + (i * 8)] = precrc_bitstream[0 + (i * 8)]; + } + precrc_bitstream_reversed[strlen(precrc_bitstream)] = '\0'; + machine_cycles = strlen(precrc_bitstream_reversed); + + /* Start up the machine */ + for(i = 0; i < 16; i++) { + xor_register[i] = '0'; + } + input_bit = precrc_bitstream_reversed[0]; + if(input_bit != xor_register[15]) { out1 = '1'; } else { out1 = '0'; } + if(input_bit != xor_register[11]) { out2 = '1'; } else { out2 = '0'; } + if(input_bit != xor_register[4]) { out3 = '1'; } else { out3 = '0'; } + + for(i = 0; i < machine_cycles; i++) { + xor_register[15] = xor_register[14]; + xor_register[14] = xor_register[13]; + xor_register[13] = xor_register[12]; + xor_register[12] = out2; + xor_register[11] = xor_register[10]; + xor_register[10] = xor_register[9]; + xor_register[9] = xor_register[8]; + xor_register[8] = xor_register[7]; + xor_register[7] = xor_register[6]; + xor_register[6] = xor_register[5]; + xor_register[5] = out3; + xor_register[4] = xor_register[3]; + xor_register[3] = xor_register[2]; + xor_register[2] = xor_register[1]; + xor_register[1] = xor_register[0]; + xor_register[0] = out1; + input_bit = precrc_bitstream_reversed[(i + 1)]; + if(input_bit != xor_register[15]) { out1 = '1'; } else { out1 = '0'; } + if(out1 != xor_register[11]) { out2 = '1'; } else { out2 = '0'; } + if(out1 != xor_register[4]) { out3 = '1'; } else { out3 = '0'; } + } + + for(i = 0; i < 16; i++) { + data_prefix_bitstream[i + 5] = xor_register[15 - i]; + } + data_prefix_bitstream[16 + 5] = '\0'; + + return; +} + +void i1_base11(char binary_string[], unsigned char source[]) +{ + int input_length, blocks, remainder, i, j; + char block_binary[22]; + int block_value, c[6], weight[6]; + int binary_posn; + + input_length = ustrlen(source); + binary_posn = strlen(binary_string); + blocks = input_length / 6; + remainder = input_length % 6; + + weight[0] = 1; + weight[1] = 11; + weight[2] = 121; + weight[3] = 1331; + weight[4] = 14641; + weight[5] = 161051; + + for(i = 0; i < blocks; i++) { + strcpy(block_binary, ""); + block_value = 0; + binary_posn = strlen(binary_string); + for(j = 0; j < 6; j++) { + c[j] = posn(B11SET, source[(i * 6) + j]); + c[j] *= weight[j]; + block_value += c[j]; + } + + if(block_value & 0x100000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x8000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x4000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x2000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x1000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x800) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x400) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x200) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + + for(j = 0; j < strlen(block_binary); j++) { + binary_string[strlen(block_binary) + binary_posn - j - 1] = block_binary[j]; + } + binary_string[strlen(block_binary) + binary_posn] = '\0'; + binary_posn = strlen(binary_string); + } + + strcpy(block_binary, ""); + block_value = 0; + binary_posn = strlen(binary_string); + for(j = 0; j < remainder; j++) { + c[j] = posn(B11SET, source[(i * 6) + j]); + c[j] *= weight[j]; + block_value += c[j]; + } + + switch(remainder) { + case 5: + if(block_value & 0x20000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x8000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x4000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 4: + if(block_value & 0x2000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x1000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x800) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 3: + if(block_value & 0x400) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x200) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 2: + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 1: + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + default: + break; + } + + for(j = 0; j < strlen(block_binary); j++) { + binary_string[strlen(block_binary) + binary_posn - j - 1] = block_binary[j]; + } + binary_string[strlen(block_binary) + binary_posn] = '\0'; + binary_posn = strlen(binary_string); + + return; +} + +void i2_base27(char binary_string[], unsigned char source[]) +{ + int input_length, blocks, remainder, i, j; + char block_binary[25]; + int block_value, c[5], weight[5]; + int binary_posn; + + input_length = ustrlen(source); + blocks = input_length / 5; + remainder = input_length % 5; + binary_posn = strlen(binary_string); + + weight[0] = 1; + weight[1] = 27; + weight[2] = 729; + weight[3] = 19683; + weight[4] = 531441; + + for(i = 0; i < blocks; i++) { + strcpy(block_binary, ""); + block_value = 0; + for(j = 0; j < 5; j++) { + c[j] = posn(B27SET, source[(i * 5) + j]); + c[j] *= weight[j]; + block_value += c[j]; + } + + if(block_value & 0x800000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x400000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x200000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x8000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x4000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x2000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x1000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x800) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x400) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x200) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + + for(j = 0; j < strlen(block_binary); j++) { + binary_string[strlen(block_binary) + binary_posn - j - 1] = block_binary[j]; + } + binary_string[strlen(block_binary) + binary_posn] = '\0'; + binary_posn = strlen(binary_string); + } + + strcpy(block_binary, ""); + block_value = 0; + for(j = 0; j < remainder; j++) { + c[j] = posn(B27SET, source[(i * 5) + j]); + c[j] *= weight[j]; + block_value += c[j]; + } + + switch(remainder) { + case 4: + if(block_value & 0x80000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x8000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 3: + if(block_value & 0x4000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x2000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x1000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x800) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x400) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 2: + if(block_value & 0x200) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 1: + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + default: + break; + } + + for(j = 0; j < strlen(block_binary); j++) { + binary_string[strlen(block_binary) + binary_posn - j - 1] = block_binary[j]; + } + binary_string[strlen(block_binary) + binary_posn] = '\0'; + binary_posn = strlen(binary_string); + + return; +} + +void i3_base37(char binary_string[], unsigned char source[]) +{ + int input_length, blocks, remainder, i, j; + char block_binary[22]; + int block_value, c[6], weight[6]; + int binary_posn; + + input_length = ustrlen(source); + blocks = input_length / 4; + remainder = input_length % 4; + binary_posn = strlen(binary_string); + + weight[0] = 1; + weight[1] = 37; + weight[2] = 1369; + weight[3] = 50653; + + for(i = 0; i < blocks; i++) { + strcpy(block_binary, ""); + block_value = 0; + for(j = 0; j < 4; j++) { + c[j] = posn(B37SET, source[(i * 4) + j]); + c[j] *= weight[j]; + block_value += c[j]; + } + + if(block_value & 0x100000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x8000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x4000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x2000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x1000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x800) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x400) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x200) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + + for(j = 0; j < strlen(block_binary); j++) { + binary_string[strlen(block_binary) + binary_posn - j - 1] = block_binary[j]; + } + binary_string[strlen(block_binary) + binary_posn] = '\0'; + binary_posn = strlen(binary_string); + } + + strcpy(block_binary, ""); + block_value = 0; + for(j = 0; j < remainder; j++) { + c[j] = posn(B37SET, source[(i * 4) + j]); + c[j] *= weight[j]; + block_value += c[j]; + } + + switch(remainder) { + case 3: + if(block_value & 0x8000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x4000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x2000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x1000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x800) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 2: + if(block_value & 0x400) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x200) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 1: + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + default: + break; + } + + for(j = 0; j < strlen(block_binary); j++) { + binary_string[strlen(block_binary) + binary_posn - j - 1] = block_binary[j]; + } + binary_string[strlen(block_binary) + binary_posn] = '\0'; + binary_posn = strlen(binary_string); + + return; +} + +void i4_base41(char binary_string[], unsigned char source[]) +{ + int input_length, blocks, remainder, i, j; + char block_binary[23]; + int block_value, c[6], weight[6]; + int binary_posn; + + input_length = ustrlen(source); + blocks = input_length / 4; + remainder = input_length % 4; + binary_posn = strlen(binary_string); + + weight[0] = 1; + weight[1] = 41; + weight[2] = 1681; + weight[3] = 68921; + + for(i = 0; i < blocks; i++) { + strcpy(block_binary, ""); + block_value = 0; + for(j = 0; j < 4; j++) { + c[j] = posn(B41SET, source[(i * 4) + j]); + c[j] *= weight[j]; + block_value += c[j]; + } + + if(block_value & 0x200000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x8000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x4000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x2000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x1000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x800) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x400) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x200) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + + for(j = 0; j < strlen(block_binary); j++) { + binary_string[strlen(block_binary) + binary_posn - j - 1] = block_binary[j]; + } + binary_string[strlen(block_binary) + binary_posn] = '\0'; + binary_posn = strlen(binary_string); + } + + strcpy(block_binary, ""); + block_value = 0; + for(j = 0; j < remainder; j++) { + c[j] = posn(B41SET, source[(i * 4) + j]); + c[j] *= weight[j]; + block_value += c[j]; + } + + switch(remainder) { + case 3: + if(block_value & 0x10000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x8000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x4000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x2000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x1000) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x800) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 2: + if(block_value & 0x400) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x200) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 1: + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + default: + break; + } + + for(j = 0; j < strlen(block_binary); j++) { + binary_string[strlen(block_binary) + binary_posn - j - 1] = block_binary[j]; + } + binary_string[strlen(block_binary) + binary_posn] = '\0'; + binary_posn = strlen(binary_string); + + return; +} + +void base128(char binary_string[], unsigned char source[]) +{ + int i, j, input_length; + char block_binary[9]; + int binary_posn; + + input_length = ustrlen(source); + binary_posn = strlen(binary_string); + + for(i = 0; i < input_length; i++) { + strcpy(block_binary, ""); + + if(source[i] & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(source[i] & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(source[i] & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(source[i] & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(source[i] & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(source[i] & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(source[i] & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + + for(j = 0; j < strlen(block_binary); j++) { + binary_string[strlen(block_binary) + binary_posn - j - 1] = block_binary[j]; + } + binary_string[strlen(block_binary) + binary_posn] = '\0'; + binary_posn = strlen(binary_string); + } + + return; +} + +void protect_ecc000(char protected_stream[], char unprotected_stream[]) +{ + /* ECC 000 - No processing needed */ + + strcpy(protected_stream, unprotected_stream); +} + +void protect_ecc050(char protected_stream[], char unprotected_stream[]) +{ + /* ECC 050 - 4-3-3 convolutional code */ + /* State machine illustrated in figure K1 */ + char top_reg[4]; + char mid_reg[4]; + char low_reg[4]; + char u1, u2, u3; + char output[4]; + char gate_input[8]; + int i, blocks, j, count; + + strcpy(protected_stream, ""); + + for(i = 0; i < 3; i++) { + top_reg[i] = '0'; + mid_reg[i] = '0'; + low_reg[i] = '0'; + } + + for(i = 0; i < (strlen(unprotected_stream) % 3); i++){ + concat(unprotected_stream, "0"); + } + blocks = strlen(unprotected_stream) / 3; + blocks += 3; + for(i = 0; i < blocks; i++) { + if(i < (blocks - 3)) { + u1 = unprotected_stream[3 * i]; + u2 = unprotected_stream[(3 * i) + 1]; + u3 = unprotected_stream[(3 * i) + 2]; + } else { + u1 = '0'; + u2 = '0'; + u3 = '0'; + } + + /* Gate 1 */ + for(j = 0; j < 8; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = u1; + gate_input[1] = mid_reg[2]; + gate_input[2] = low_reg[0]; + gate_input[3] = low_reg[1]; + gate_input[4] = low_reg[2]; + + count = 0; + for(j = 0; j < 5; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[0] = '1'; } else { output[0] = '0'; } + + /* Gate 2 */ + for(j = 0; j < 8; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = top_reg[1]; + gate_input[1] = top_reg[2]; + gate_input[2] = u2; + gate_input[3] = mid_reg[0]; + gate_input[4] = mid_reg[2]; + + count = 0; + for(j = 0; j < 5; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[1] = '1'; } else { output[1] = '0'; } + + /* Gate 3 */ + for(j = 0; j < 8; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = top_reg[0]; + gate_input[1] = top_reg[1]; + gate_input[2] = top_reg[2]; + gate_input[3] = mid_reg[0]; + gate_input[4] = u3; + gate_input[5] = low_reg[0]; + + count = 0; + for(j = 0; j < 6; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[2] = '1'; } else { output[2] = '0'; } + + /* Gate 4 */ + for(j = 0; j < 8; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = u1; + gate_input[1] = top_reg[0]; + gate_input[2] = u2; + gate_input[3] = mid_reg[0]; + gate_input[4] = mid_reg[1]; + gate_input[5] = u3; + gate_input[6] = low_reg[0]; + gate_input[7] = low_reg[2]; + + count = 0; + for(j = 0; j < 8; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[3] = '1'; } else { output[3] = '0'; } + + output[4] = '\0'; + + concat(protected_stream, output); + + /* Shift registers right */ + top_reg[2] = top_reg[1]; + top_reg[1] = top_reg[0]; + top_reg[0] = u1; + mid_reg[2] = mid_reg[1]; + mid_reg[1] = mid_reg[0]; + mid_reg[0] = u2; + low_reg[2] = low_reg[1]; + low_reg[1] = low_reg[0]; + low_reg[0] = u3; + } +} + +void protect_ecc080(char protected_stream[], char unprotected_stream[]) +{ + /* ECC 080 - 3-2-11 convolutional code */ + /* State machine illustrated in figure K2 */ + /* NOTE: Figure K.2 of ISO/IEC 16022:2006 has an error in that input 2 of gate 1 and input 1 of gate 2 are + both connected to module 2 _and_ module 3 of the top register. This is obviously not correct so I have + made a guess at the correct interpretation and made a comment where a correction may be needed if this + guess is not correct */ + char top_reg[12]; + char low_reg[12]; + char u1, u2; + char output[4]; + char gate_input[12]; + int i, j, count, blocks; + + strcpy(protected_stream, ""); + + for(i = 0; i < 12; i++) { + top_reg[i] = '0'; + low_reg[i] = '0'; + } + + for(i = 0; i < (strlen(unprotected_stream) % 2); i++){ + concat(unprotected_stream, "0"); + } + blocks = strlen(unprotected_stream) / 2; + blocks += 11; + for(i = 0; i < blocks; i++) { + if(i < (blocks - 11)) { + u1 = unprotected_stream[2 * i]; + u2 = unprotected_stream[(2 * i) + 1]; + } else { + u1 = '0'; + u2 = '0'; + } + + /* Gate 1 */ + for(j = 0; j < 12; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = u1; + gate_input[1] = top_reg[0]; + gate_input[2] = top_reg[3]; /* ? top_reg[2] ? */ + gate_input[3] = top_reg[4]; + gate_input[4] = top_reg[5]; + gate_input[5] = top_reg[6]; + gate_input[6] = top_reg[9]; + gate_input[7] = low_reg[2]; + gate_input[8] = low_reg[6]; + gate_input[9] = low_reg[7]; + gate_input[10] = low_reg[10]; + + count = 0; + for(j = 0; j < 11; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[0] = '1'; } else { output[0] = '0'; } + + /* Gate 2 */ + for(j = 0; j < 12; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = top_reg[0]; + gate_input[1] = top_reg[2]; /* ? top_reg[3] ? */ + gate_input[2] = top_reg[4]; + gate_input[3] = top_reg[7]; + gate_input[4] = top_reg[8]; + gate_input[5] = top_reg[9]; + gate_input[6] = u2; + gate_input[7] = low_reg[2]; + gate_input[8] = low_reg[5]; + gate_input[9] = low_reg[7]; + gate_input[10] = low_reg[8]; + + count = 0; + for(j = 0; j < 11; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[1] = '1'; } else { output[1] = '0'; } + + /* Gate 3 */ + for(j = 0; j < 12; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = u1; + gate_input[1] = top_reg[4]; + gate_input[2] = top_reg[5]; + gate_input[3] = top_reg[6]; + gate_input[4] = u2; + gate_input[5] = low_reg[0]; + gate_input[6] = low_reg[1]; + gate_input[7] = low_reg[3]; + gate_input[8] = low_reg[6]; + gate_input[9] = low_reg[8]; + gate_input[10] = low_reg[10]; + + count = 0; + for(j = 0; j < 11; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[2] = '1'; } else { output[2] = '0'; } + + output[3] = '\0'; + + concat(protected_stream, output); + + /* Shift registers right */ + top_reg[9] = top_reg[8]; + top_reg[8] = top_reg[7]; + top_reg[7] = top_reg[6]; + top_reg[6] = top_reg[5]; + top_reg[5] = top_reg[4]; + top_reg[4] = top_reg[3]; + top_reg[3] = top_reg[2]; + top_reg[2] = top_reg[1]; + top_reg[1] = top_reg[0]; + top_reg[0] = u1; + low_reg[10] = low_reg[9]; + low_reg[9] = low_reg[8]; + low_reg[8] = low_reg[7]; + low_reg[7] = low_reg[6]; + low_reg[6] = low_reg[5]; + low_reg[5] = low_reg[4]; + low_reg[4] = low_reg[3]; + low_reg[3] = low_reg[2]; + low_reg[2] = low_reg[1]; + low_reg[1] = low_reg[0]; + low_reg[0] = u2; + + } +} + +void protect_ecc100(char protected_stream[], char unprotected_stream[]) +{ + /* ECC 100 - 2-1-15 convolutional code */ + /* State machine illustrated in figure k3 */ + char reg[16]; + char u; + char output[3]; + char gate_input[10]; + int i, j, count, blocks; + + strcpy(protected_stream, ""); + + for(i = 0; i < 16; i++) { + reg[i] = '0'; + } + + blocks = strlen(unprotected_stream); + blocks += 15; + for(i = 0; i < blocks; i++) { + if(i < (blocks - 15)) { + u = unprotected_stream[i]; + } else { + u = '0'; + } + + /* Gate 1 */ + for(j = 0; j < 10; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = u; + gate_input[1] = reg[1]; + gate_input[2] = reg[4]; + gate_input[3] = reg[5]; + gate_input[4] = reg[6]; + gate_input[5] = reg[7]; + gate_input[6] = reg[8]; + gate_input[7] = reg[9]; + gate_input[8] = reg[14]; + + count = 0; + for(j = 0; j < 9; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[0] = '1'; } else { output[0] = '0'; } + + /* Gate 2 */ + for(j = 0; j < 10; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = u; + gate_input[1] = reg[0]; + gate_input[2] = reg[2]; + gate_input[3] = reg[3]; + gate_input[4] = reg[5]; + gate_input[5] = reg[10]; + gate_input[6] = reg[12]; + gate_input[7] = reg[13]; + gate_input[8] = reg[14]; + + count = 0; + for(j = 0; j < 9; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[1] = '1'; } else { output[1] = '0'; } + + output[2] = '\0'; + + concat(protected_stream, output); + + /* Shift register right */ + reg[14] = reg[13]; + reg[13] = reg[12]; + reg[12] = reg[11]; + reg[11] = reg[10]; + reg[10] = reg[9]; + reg[9] = reg[8]; + reg[8] = reg[7]; + reg[7] = reg[6]; + reg[6] = reg[5]; + reg[5] = reg[4]; + reg[4] = reg[3]; + reg[3] = reg[2]; + reg[2] = reg[1]; + reg[1] = reg[0]; + reg[0] = u; + } +} + +void protect_ecc140(char protected_stream[], char unprotected_stream[]) +{ + /* ECC 140 - 4-1-13 convolutional coding */ + /* State machine illustrated in figure k3 */ + char reg[13]; + char u; + char output[5]; + char gate_input[12]; + int i, j, count, blocks; + + strcpy(protected_stream, ""); + + for(i = 0; i < 13; i++) { + reg[i] = '0'; + } + + blocks = strlen(unprotected_stream); + blocks += 13; + for(i = 0; i < blocks; i++) { + if(i < (blocks - 13)) { + u = unprotected_stream[i]; + } else { + u = '0'; + } + + /* Gate 1 */ + for(j = 0; j < 12; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = u; + gate_input[1] = reg[3]; + gate_input[2] = reg[6]; + gate_input[3] = reg[9]; + gate_input[4] = reg[11]; + gate_input[5] = reg[12]; + + count = 0; + for(j = 0; j < 6; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[0] = '1'; } else { output[0] = '0'; } + + /* Gate 2 */ + for(j = 0; j < 12; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = u; + gate_input[1] = reg[2]; + gate_input[2] = reg[3]; + gate_input[3] = reg[6]; + gate_input[4] = reg[7]; + gate_input[5] = reg[8]; + gate_input[6] = reg[9]; + gate_input[7] = reg[10]; + gate_input[8] = reg[12]; + + count = 0; + for(j = 0; j < 9; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[1] = '1'; } else { output[1] = '0'; } + + /* Gate 3 */ + for(j = 0; j < 12; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = u; + gate_input[1] = reg[0]; + gate_input[2] = reg[1]; + gate_input[3] = reg[3]; + gate_input[4] = reg[4]; + gate_input[5] = reg[6]; + gate_input[6] = reg[8]; + gate_input[7] = reg[10]; + gate_input[8] = reg[11]; + gate_input[9] = reg[12]; + + count = 0; + for(j = 0; j < 10; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[2] = '1'; } else { output[2] = '0'; } + + /* Gate 4 */ + for(j = 0; j < 12; j++) { + gate_input[j] = '0'; + } + + gate_input[0] = u; + gate_input[1] = reg[0]; + gate_input[2] = reg[1]; + gate_input[3] = reg[3]; + gate_input[4] = reg[4]; + gate_input[5] = reg[6]; + gate_input[6] = reg[8]; + gate_input[7] = reg[9]; + gate_input[8] = reg[10]; + gate_input[9] = reg[11]; + gate_input[10] = reg[12]; + + count = 0; + for(j = 0; j < 11; j++) { + if(gate_input[j] == '1') { + count++; + } + } + if((count & 0x01) == 0x01) { output[3] = '1'; } else { output[3] = '0'; } + + output[4] = '\0'; + + concat(protected_stream, output); + + /* Shift register right */ + reg[12] = reg[11]; + reg[11] = reg[10]; + reg[10] = reg[9]; + reg[9] = reg[8]; + reg[8] = reg[7]; + reg[7] = reg[6]; + reg[6] = reg[5]; + reg[5] = reg[4]; + reg[4] = reg[3]; + reg[3] = reg[2]; + reg[2] = reg[1]; + reg[1] = reg[0]; + reg[0] = u; + } + +} + +int matrix89(struct zint_symbol *symbol, unsigned char source[]) +{ + int i, j, input_length, scheme; + input_length = ustrlen(source); + char unprotected_stream[2210]; + char data_prefix_bitstream[31]; + char protected_stream[6630]; + char unrandomized_stream[2210]; + char master_random_stream[2214]; + char randomized_stream[2210]; + char header[20]; + int symbol_size, hex_segment, width; + + for(i = 0; i < input_length; i++) { + if(source[i] > 127) { + strcpy(symbol->errtxt, "Data Matrix ECC 000 - 140 doesn't support extended ASCII"); + return ERROR_INVALID_DATA; + } + } + + /* Decide which encoding scheme to use */ + scheme = 128; + if(!(is_sane(B41SET, source))) { scheme = 41; } + if(!(is_sane(B37SET, source))) { scheme = 37; } + if(!(is_sane(B27SET, source))) { scheme = 27; } + if(!(is_sane(B11SET, source))) { scheme = 11; } + + /* Data Prefix Bit Stream = Format ID + CRC + Data Length */ + + /* Format ID (5 bits) */ + switch(scheme) { + case 11: strcpy(data_prefix_bitstream, "00000"); break; + case 27: strcpy(data_prefix_bitstream, "00001"); break; + case 37: strcpy(data_prefix_bitstream, "00011"); break; + case 41: strcpy(data_prefix_bitstream, "00010"); break; + default: strcpy(data_prefix_bitstream, "00100"); break; + } + + /* CRC Value (16 bit) */ + crc_machine(data_prefix_bitstream, scheme, source); + + /* Data length (9 bit) */ + if(input_length & 0x01) { concat(data_prefix_bitstream, "1"); } else { concat(data_prefix_bitstream, "0"); } + if(input_length & 0x02) { concat(data_prefix_bitstream, "1"); } else { concat(data_prefix_bitstream, "0"); } + if(input_length & 0x04) { concat(data_prefix_bitstream, "1"); } else { concat(data_prefix_bitstream, "0"); } + if(input_length & 0x08) { concat(data_prefix_bitstream, "1"); } else { concat(data_prefix_bitstream, "0"); } + if(input_length & 0x10) { concat(data_prefix_bitstream, "1"); } else { concat(data_prefix_bitstream, "0"); } + if(input_length & 0x20) { concat(data_prefix_bitstream, "1"); } else { concat(data_prefix_bitstream, "0"); } + if(input_length & 0x40) { concat(data_prefix_bitstream, "1"); } else { concat(data_prefix_bitstream, "0"); } + if(input_length & 0x80) { concat(data_prefix_bitstream, "1"); } else { concat(data_prefix_bitstream, "0"); } + if(input_length & 0x100) { concat(data_prefix_bitstream, "1"); } else { concat(data_prefix_bitstream, "0"); } + + /* Unprotected Bit Stream = Data Prefix Bitstream + Encoded Data */ + + strcpy(unprotected_stream, data_prefix_bitstream); + + switch(scheme) { + case 11: + if(input_length >= 618) { + strcpy(symbol->errtxt, "Input data too long"); return ERROR_TOO_LONG; + } + break; + case 27: + if(input_length >= 450) { + strcpy(symbol->errtxt, "Input data too long"); return ERROR_TOO_LONG; + } + break; + case 37: + if(input_length >= 412) { + strcpy(symbol->errtxt, "Input data too long"); return ERROR_TOO_LONG; + } + break; + case 41: + if(input_length >= 396) { + strcpy(symbol->errtxt, "Input data too long"); return ERROR_TOO_LONG; + } + break; + case 128: + if(input_length >= 311) { + strcpy(symbol->errtxt, "Input data too long"); return ERROR_TOO_LONG; + } + break; + } + + switch(scheme) { + case 11: i1_base11(unprotected_stream, source); break; + case 27: i2_base27(unprotected_stream, source); break; + case 37: i3_base37(unprotected_stream, source); break; + case 41: i4_base41(unprotected_stream, source); break; + default: base128(unprotected_stream, source); break; + } + + /* Header (ECC Bit field) LSB first */ + switch(symbol->option_1) { + case 2: strcpy(header, "0111111"); break; /* ECC 000 */ + case 3: strcpy(header, "0111000000000111000"); break; /* ECC 050 */ + case 4: strcpy(header, "0111000000111000111"); break; /* ECC 080 */ + case 5: strcpy(header, "0111000000111111111"); break; /* ECC 100 */ + case 6: strcpy(header, "0111000111000111111"); break; /* ECC 140 */ + } + + /* Generate Protected Bit Stream */ + switch(symbol->option_1) { + case 2: protect_ecc000(protected_stream, unprotected_stream); break; + case 3: protect_ecc050(protected_stream, unprotected_stream); break; + case 4: protect_ecc080(protected_stream, unprotected_stream); break; + case 5: protect_ecc100(protected_stream, unprotected_stream); break; + case 6: protect_ecc140(protected_stream, unprotected_stream); break; + } + + if((strlen(protected_stream) + strlen(header)) > 2209) { + strcpy(symbol->errtxt, "Input data too long"); + return ERROR_TOO_LONG; + } + + /* Construct Unrandomized Bit Stream */ + strcpy(unrandomized_stream, header); + concat(unrandomized_stream, protected_stream); + + for(i = 20; i >= 0; i--) { + if(MatrixMaxCapacities[i] > strlen(unrandomized_stream)) { + symbol_size = i; + } + } + + /* Add trailer (pad bits) */ + input_length = strlen(unrandomized_stream); + for(i = input_length; i < MatrixMaxCapacities[symbol_size]; i++) { + concat(unrandomized_stream, "0"); + } + + /* Load master random stream */ + strcpy(master_random_stream, ""); + for(i = 0; i < 277; i++) { + hex_segment = MasterRandomStream[i]; + if(hex_segment & 0x80) { concat(master_random_stream, "1"); } else { concat(master_random_stream, "0"); } + if(hex_segment & 0x40) { concat(master_random_stream, "1"); } else { concat(master_random_stream, "0"); } + if(hex_segment & 0x20) { concat(master_random_stream, "1"); } else { concat(master_random_stream, "0"); } + if(hex_segment & 0x10) { concat(master_random_stream, "1"); } else { concat(master_random_stream, "0"); } + if(hex_segment & 0x08) { concat(master_random_stream, "1"); } else { concat(master_random_stream, "0"); } + if(hex_segment & 0x04) { concat(master_random_stream, "1"); } else { concat(master_random_stream, "0"); } + if(hex_segment & 0x02) { concat(master_random_stream, "1"); } else { concat(master_random_stream, "0"); } + if(hex_segment & 0x01) { concat(master_random_stream, "1"); } else { concat(master_random_stream, "0"); } + } + + /* Randomizing Algorithm */ + + strcpy(randomized_stream, ""); + for(i = 0; i < strlen(unrandomized_stream); i++) { + if(unrandomized_stream[i] != master_random_stream[i]) { + concat(randomized_stream, "1"); + } else { + concat(randomized_stream, "0"); + } + } + + /* Placement Algorithm */ + width = (symbol_size * 2) + 7; + + symbol->row_height[0] = 1; + /* Fill corners */ + symbol->encoded_data[0][0] = '1'; + symbol->encoded_data[0][width + 1] = '1'; + symbol->encoded_data[width + 1][0] = '1'; + symbol->encoded_data[width + 1][width + 1] = '1'; + for(i = 0; i < width; i++) { + /* Fill sides */ + symbol->encoded_data[i + 1][0] = '1'; + symbol->encoded_data[width + 1][i + 1] = '1'; + if((i % 2) == 0) { + symbol->encoded_data[i][width + 1] = '1'; + symbol->encoded_data[0][i] = '1'; + } + for(j = 0; j < width; j++) { + switch(symbol_size) { + case 0: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh1[(i * width) + j]]; break; + case 1: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh2[(i * width) + j]]; break; + case 2: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh3[(i * width) + j]]; break; + case 3: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh4[(i * width) + j]]; break; + case 4: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh5[(i * width) + j]]; break; + case 5: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh6[(i * width) + j]]; break; + case 6: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh7[(i * width) + j]]; break; + case 7: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh8[(i * width) + j]]; break; + case 8: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh9[(i * width) + j]]; break; + case 9: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh10[(i * width) + j]]; break; + case 10: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh11[(i * width) + j]]; break; + case 11: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh12[(i * width) + j]]; break; + case 12: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh13[(i * width) + j]]; break; + case 13: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh14[(i * width) + j]]; break; + case 14: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh15[(i * width) + j]]; break; + case 15: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh16[(i * width) + j]]; break; + case 16: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh17[(i * width) + j]]; break; + case 17: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh18[(i * width) + j]]; break; + case 18: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh19[(i * width) + j]]; break; + case 19: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh20[(i * width) + j]]; break; + case 20: symbol->encoded_data[i + 1][j + 1] = randomized_stream[tableh21[(i * width) + j]]; break; + } + } + symbol->row_height[i + 1] = 1; + } + + symbol->row_height[width + 1] = 1; + symbol->rows = width + 2; + symbol->width = width + 2; + + return 0; +} + int dmatrix(struct zint_symbol *symbol, unsigned char source[]) { - /* In later versions of this code this procedure will redirect control - dependent on the version of Data Matrix symbol required - for now it is - just a place holder */ int barcodelen; int error_number; barcodelen = ustrlen(source); - if(barcodelen > 780) { - strcpy(symbol->errtxt, "Input too long [711]"); - return ERROR_TOO_LONG; + if((symbol->option_1 < 1) || (symbol->option_1 > 6)) { + symbol->option_1 = 1; + } + + if(symbol->option_1 == 1) { + /* ECC 200 */ + error_number = iec16022ecc200(source, barcodelen, symbol); + } else { + /* ECC 000 - 140 */ + error_number = matrix89(symbol, source); } - - error_number = iec16022ecc200(source, barcodelen, symbol); return error_number; } diff --git a/backend/dmatrix.h b/backend/dmatrix.h new file mode 100644 index 00000000..872351b9 --- /dev/null +++ b/backend/dmatrix.h @@ -0,0 +1,671 @@ +/* dmatrix.h - Data Matrix ECC 000 - 150 tables */ + +/* + libzint - the open source barcode library + Copyright (C) 2008 Robin Stuart + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/* Data taken from ISO/IEC 16022:2006 Annex H "ECC 000 - 140 data module placement grids" */ + +int tableh1[] = { /* 7 x 7 data */ + 2,45,10,38,24,21,1, + 12,40,26,5,33,19,47, + 22,31,29,15,43,8,36, + 34,20,48,13,41,27,6, + 44,9,37,23,17,30,16, + 39,25,4,32,18,46,11, + 0,28,14,42,7,35,3 +}; + +int tableh2[] = { /* 9 x 9 data */ + 2,19,55,10,46,28,64,73,1, + 62,17,53,35,71,8,80,44,26, + 49,31,67,4,76,40,22,58,13, + 69,6,78,42,24,60,15,51,33, + 74,38,20,56,11,47,29,65,37, + 25,61,16,52,34,70,7,79,43, + 12,48,30,66,63,75,39,21,57, + 32,68,5,77,41,23,59,14,50, + 0,72,36,18,54,9,45,27,3 +}; + +int tableh3[] = { /* 11 x 11 data */ + 2,26,114,70,15,103,59,37,81,4,1, + 117,73,18,106,62,40,84,7,95,51,29, + 12,100,56,34,78,92,89,45,23,111,67, + 65,43,87,10,98,54,32,120,76,21,109, + 82,5,93,49,27,115,71,16,104,60,38, + 96,52,30,118,74,19,107,63,41,85,8, + 24,112,68,13,101,57,35,79,48,90,46, + 75,20,108,64,42,86,9,97,53,31,119, + 102,58,36,80,77,91,47,25,113,69,14, + 39,83,6,94,50,28,116,72,17,105,61, + 0,88,44,22,110,66,11,99,55,33,3 +}; + +int tableh4[] = { /* 13 x 13 data */ + 2,159,29,133,81,16,120,68,42,146,94,91,1, + 37,141,89,24,128,76,50,154,102,11,115,63,167, + 83,18,122,70,44,148,96,5,109,57,161,31,135, + 125,73,47,151,99,8,112,60,164,34,138,86,21, + 40,144,92,107,105,53,157,27,131,79,14,118,66, + 103,12,116,64,168,38,142,90,25,129,77,51,155, + 110,58,162,32,136,84,19,123,71,45,149,97,6, + 165,35,139,87,22,126,74,48,152,100,9,113,61, + 132,80,15,119,67,41,145,93,55,106,54,158,28, + 23,127,75,49,153,101,10,114,62,166,36,140,88, + 69,43,147,95,4,108,56,160,30,134,82,17,121, + 150,98,7,111,59,163,33,137,85,20,124,72,46, + 0,104,52,156,26,130,78,13,117,65,39,143,3 +}; + +int tableh5[] = { /* 15 x 15 data */ + 2,187,37,157,97,217,22,142,82,202,52,172,112,7,1, + 41,161,101,221,26,146,86,206,56,176,116,11,131,71,191, + 93,213,18,138,78,198,48,168,108,105,123,63,183,33,153, + 28,148,88,208,58,178,118,13,133,73,193,43,163,103,223, + 80,200,50,170,110,5,125,65,185,35,155,95,215,20,140, + 54,174,114,9,129,69,189,39,159,99,219,24,144,84,204, + 106,127,121,61,181,31,151,91,211,16,136,76,196,46,166, + 134,74,194,44,164,104,224,29,149,89,209,59,179,119,14, + 186,36,156,96,216,21,141,81,201,51,171,111,6,126,66, + 160,100,220,25,145,85,205,55,175,115,10,130,70,190,40, + 212,17,137,77,197,47,167,107,67,122,62,182,32,152,92, + 147,87,207,57,177,117,12,132,72,192,42,162,102,222,27, + 199,49,169,109,4,124,64,184,34,154,94,214,19,139,79, + 173,113,8,128,68,188,38,158,98,218,23,143,83,203,53, + 0,120,60,180,30,150,90,210,15,135,75,195,45,165,3 +}; + +int tableh6[] = { /* 17 x 17 data */ + 2,69,205,35,171,103,239,18,154,86,222,52,188,120,256,273,1, + 220,50,186,118,254,33,169,101,237,67,203,135,271,16,288,152,84, + 178,110,246,25,161,93,229,59,195,127,263,8,280,144,76,212,42, + 250,29,165,97,233,63,199,131,267,12,284,148,80,216,46,182,114, + 157,89,225,55,191,123,259,4,276,140,72,208,38,174,106,242,21, + 235,65,201,133,269,14,286,150,82,218,48,184,116,252,31,167,99, + 193,125,261,6,278,142,74,210,40,176,108,244,23,159,91,227,57, + 265,10,282,146,78,214,44,180,112,248,27,163,95,231,61,197,129, + 274,138,70,206,36,172,104,240,19,155,87,223,53,189,121,257,137, + 83,219,49,185,117,253,32,168,100,236,66,202,134,270,15,287,151, + 41,177,109,245,24,160,92,228,58,194,126,262,7,279,143,75,211, + 113,249,28,164,96,232,62,198,130,266,11,283,147,79,215,45,181, + 20,156,88,224,54,190,122,258,255,275,139,71,207,37,173,105,241, + 98,234,64,200,132,268,13,285,149,81,217,47,183,115,251,30,166, + 56,192,124,260,5,277,141,73,209,39,175,107,243,22,158,90,226, + 128,264,9,281,145,77,213,43,179,111,247,26,162,94,230,60,196, + 0,272,136,68,204,34,170,102,238,17,153,85,221,51,187,119,3 +}; + +int tableh7[] = { /* 19 x 19 data */ + 2,82,234,44,348,196,120,272,25,329,177,101,253,63,215,139,291,6,1, + 239,49,353,201,125,277,30,334,182,106,258,68,220,144,296,11,315,163,87, + 343,191,115,267,20,324,172,96,248,58,210,134,286,310,305,153,77,229,39, + 132,284,37,341,189,113,265,75,227,151,303,18,322,170,94,246,56,360,208, + 28,332,180,104,256,66,218,142,294,9,313,161,85,237,47,351,199,123,275, + 185,109,261,71,223,147,299,14,318,166,90,242,52,356,204,128,280,33,337, + 251,61,213,137,289,4,308,156,80,232,42,346,194,118,270,23,327,175,99, + 225,149,301,16,320,168,92,244,54,358,206,130,282,35,339,187,111,263,73, + 292,7,311,159,83,235,45,349,197,121,273,26,330,178,102,254,64,216,140, + 316,164,88,240,50,354,202,126,278,31,335,183,107,259,69,221,145,297,12, + 78,230,40,344,192,116,268,21,325,173,97,249,59,211,135,287,158,306,154, + 55,359,207,131,283,36,340,188,112,264,74,226,150,302,17,321,169,93,245, + 198,122,274,27,331,179,103,255,65,217,141,293,8,312,160,84,236,46,350, + 279,32,336,184,108,260,70,222,146,298,13,317,165,89,241,51,355,203,127, + 326,174,98,250,60,212,136,288,285,307,155,79,231,41,345,193,117,269,22, + 110,262,72,224,148,300,15,319,167,91,243,53,357,205,129,281,34,338,186, + 62,214,138,290,5,309,157,81,233,43,347,195,119,271,24,328,176,100,252, + 143,295,10,314,162,86,238,48,352,200,124,276,29,333,181,105,257,67,219, + 0,304,152,76,228,38,342,190,114,266,19,323,171,95,247,57,209,133,3 +}; + +int tableh8[] = { /* 21 x 21 data */ + 2,88,424,256,46,382,214,130,298,25,361,193,109,277,67,403,235,151,319,4,1, + 437,269,59,395,227,143,311,38,374,206,122,290,80,416,248,164,332,17,353,185,101, + 49,385,217,133,301,28,364,196,112,280,70,406,238,154,322,7,343,175,91,427,259, + 222,138,306,33,369,201,117,285,75,411,243,159,327,12,348,180,96,432,264,54,390, + 295,22,358,190,106,274,64,400,232,148,316,340,337,169,85,421,253,43,379,211,127, + 377,209,125,293,83,419,251,167,335,20,356,188,104,440,272,62,398,230,146,314,41, + 115,283,73,409,241,157,325,10,346,178,94,430,262,52,388,220,136,304,31,367,199, + 78,414,246,162,330,15,351,183,99,435,267,57,393,225,141,309,36,372,204,120,288, + 236,152,320,5,341,173,89,425,257,47,383,215,131,299,26,362,194,110,278,68,404, + 333,18,354,186,102,438,270,60,396,228,144,312,39,375,207,123,291,81,417,249,165, + 344,176,92,428,260,50,386,218,134,302,29,365,197,113,281,71,407,239,155,323,8, + 97,433,265,55,391,223,139,307,34,370,202,118,286,76,412,244,160,328,13,349,181, + 254,44,380,212,128,296,23,359,191,107,275,65,401,233,149,317,172,338,170,86,422, + 397,229,145,313,40,376,208,124,292,82,418,250,166,334,19,355,187,103,439,271,61, + 135,303,30,366,198,114,282,72,408,240,156,324,9,345,177,93,429,261,51,387,219, + 35,371,203,119,287,77,413,245,161,329,14,350,182,98,434,266,56,392,224,140,308, + 192,108,276,66,402,234,150,318,315,339,171,87,423,255,45,381,213,129,297,24,360, + 289,79,415,247,163,331,16,352,184,100,436,268,58,394,226,142,310,37,373,205,121, + 405,237,153,321,6,342,174,90,426,258,48,384,216,132,300,27,363,195,111,279,69, + 158,326,11,347,179,95,431,263,53,389,221,137,305,32,368,200,116,284,74,410,242, + 0,336,168,84,420,252,42,378,210,126,294,21,357,189,105,273,63,399,231,147,3 +}; + +int tableh9[] = { /* 23 x 23 data */ + 2,102,470,286,56,424,240,148,516,332,33,401,217,125,493,309,79,447,263,171,355,10,1, + 476,292,62,430,246,154,522,338,39,407,223,131,499,315,85,453,269,177,361,16,384,200,108, + 50,418,234,142,510,326,27,395,211,119,487,303,73,441,257,165,349,4,372,188,96,464,280, + 249,157,525,341,42,410,226,134,502,318,88,456,272,180,364,19,387,203,111,479,295,65,433, + 513,329,30,398,214,122,490,306,76,444,260,168,352,7,375,191,99,467,283,53,421,237,145, + 36,404,220,128,496,312,82,450,266,174,358,13,381,197,105,473,289,59,427,243,151,519,335, + 208,116,484,300,70,438,254,162,346,378,369,185,93,461,277,47,415,231,139,507,323,24,392, + 505,321,91,459,275,183,367,22,390,206,114,482,298,68,436,252,160,528,344,45,413,229,137, + 80,448,264,172,356,11,379,195,103,471,287,57,425,241,149,517,333,34,402,218,126,494,310, + 270,178,362,17,385,201,109,477,293,63,431,247,155,523,339,40,408,224,132,500,316,86,454, + 350,5,373,189,97,465,281,51,419,235,143,511,327,28,396,212,120,488,304,74,442,258,166, + 388,204,112,480,296,66,434,250,158,526,342,43,411,227,135,503,319,89,457,273,181,365,20, + 100,468,284,54,422,238,146,514,330,31,399,215,123,491,307,77,445,261,169,353,8,376,192, + 290,60,428,244,152,520,336,37,405,221,129,497,313,83,451,267,175,359,14,382,198,106,474, + 416,232,140,508,324,25,393,209,117,485,301,71,439,255,163,347,194,370,186,94,462,278,48, + 159,527,343,44,412,228,136,504,320,90,458,274,182,366,21,389,205,113,481,297,67,435,251, + 331,32,400,216,124,492,308,78,446,262,170,354,9,377,193,101,469,285,55,423,239,147,515, + 406,222,130,498,314,84,452,268,176,360,15,383,199,107,475,291,61,429,245,153,521,337,38, + 118,486,302,72,440,256,164,348,345,371,187,95,463,279,49,417,233,141,509,325,26,394,210, + 317,87,455,271,179,363,18,386,202,110,478,294,64,432,248,156,524,340,41,409,225,133,501, + 443,259,167,351,6,374,190,98,466,282,52,420,236,144,512,328,29,397,213,121,489,305,75, + 173,357,12,380,196,104,472,288,58,426,242,150,518,334,35,403,219,127,495,311,81,449,265, + 0,368,184,92,460,276,46,414,230,138,506,322,23,391,207,115,483,299,69,437,253,161,3 +}; + +int tableh10[] = { /* 25 x 25 data */ + 2,603,103,503,303,53,453,253,153,553,353,28,428,228,128,528,328,78,478,278,178,578,378,375,1, + 123,523,323,73,473,273,173,573,373,48,448,248,148,548,348,98,498,298,198,598,398,23,423,223,623, + 311,61,461,261,161,561,361,36,436,236,136,536,336,86,486,286,186,586,386,11,411,211,611,111,511, + 467,267,167,567,367,42,442,242,142,542,342,92,492,292,192,592,392,17,417,217,617,117,517,317,67, + 155,555,355,30,430,230,130,530,330,80,480,280,180,580,380,5,405,205,605,105,505,305,55,455,255, + 370,45,445,245,145,545,345,95,495,295,195,595,395,20,420,220,620,120,520,320,70,470,270,170,570, + 433,233,133,533,333,83,483,283,183,583,383,8,408,208,608,108,508,308,58,458,258,158,558,358,33, + 139,539,339,89,489,289,189,589,389,14,414,214,614,114,514,314,64,464,264,164,564,364,39,439,239, + 326,76,476,276,176,576,376,403,401,201,601,101,501,301,51,451,251,151,551,351,26,426,226,126,526, + 499,299,199,599,399,24,424,224,624,124,524,324,74,474,274,174,574,374,49,449,249,149,549,349,99, + 187,587,387,12,412,212,612,112,512,312,62,462,262,162,562,362,37,437,237,137,537,337,87,487,287, + 393,18,418,218,618,118,518,318,68,468,268,168,568,368,43,443,243,143,543,343,93,493,293,193,593, + 406,206,606,106,506,306,56,456,256,156,556,356,31,431,231,131,531,331,81,481,281,181,581,381,6, + 621,121,521,321,71,471,271,171,571,371,46,446,246,146,546,346,96,496,296,196,596,396,21,421,221, + 509,309,59,459,259,159,559,359,34,434,234,134,534,334,84,484,284,184,584,384,9,409,209,609,109, + 65,465,265,165,565,365,40,440,240,140,540,340,90,490,290,190,590,390,15,415,215,615,115,515,315, + 252,152,552,352,27,427,227,127,527,327,77,477,277,177,577,377,203,402,202,602,102,502,302,52,452, + 572,372,47,447,247,147,547,347,97,497,297,197,597,397,22,422,222,622,122,522,322,72,472,272,172, + 35,435,235,135,535,335,85,485,285,185,585,385,10,410,210,610,110,510,310,60,460,260,160,560,360, + 241,141,541,341,91,491,291,191,591,391,16,416,216,616,116,516,316,66,466,266,166,566,366,41,441, + 529,329,79,479,279,179,579,379,4,404,204,604,104,504,304,54,454,254,154,554,354,29,429,229,129, + 94,494,294,194,594,394,19,419,219,619,119,519,319,69,469,269,169,569,369,44,444,244,144,544,344, + 282,182,582,382,7,407,207,607,107,507,307,57,457,257,157,557,357,32,432,232,132,532,332,82,482, + 588,388,13,413,213,613,113,513,313,63,463,263,163,563,363,38,438,238,138,538,338,88,488,288,188, + 0,400,200,600,100,500,300,50,450,250,150,550,350,25,425,225,125,525,325,75,475,275,175,575,3 +}; + +int tableh11[] = { /* 27 x 27 data */ + 2,658,118,550,334,64,496,280,712,172,604,388,37,469,253,685,145,577,361,91,523,307,199,631,415,10,1, + 125,557,341,71,503,287,719,179,611,395,44,476,260,692,152,584,368,98,530,314,206,638,422,17,449,233,665, + 327,57,489,273,705,165,597,381,30,462,246,678,138,570,354,84,516,300,192,624,408,405,435,219,651,111,543, + 511,295,727,187,619,403,52,484,268,700,160,592,376,106,538,322,214,646,430,25,457,241,673,133,565,349,79, + 714,174,606,390,39,471,255,687,147,579,363,93,525,309,201,633,417,12,444,228,660,120,552,336,66,498,282, + 613,397,46,478,262,694,154,586,370,100,532,316,208,640,424,19,451,235,667,127,559,343,73,505,289,721,181, + 32,464,248,680,140,572,356,86,518,302,194,626,410,5,437,221,653,113,545,329,59,491,275,707,167,599,383, + 265,697,157,589,373,103,535,319,211,643,427,22,454,238,670,130,562,346,76,508,292,724,184,616,400,49,481, + 143,575,359,89,521,305,197,629,413,8,440,224,656,116,548,332,62,494,278,710,170,602,386,35,467,251,683, + 366,96,528,312,204,636,420,15,447,231,663,123,555,339,69,501,285,717,177,609,393,42,474,258,690,150,582, + 514,298,190,622,406,442,433,217,649,109,541,325,55,487,271,703,163,595,379,28,460,244,676,136,568,352,82, + 215,647,431,26,458,242,674,134,566,350,80,512,296,728,188,620,404,53,485,269,701,161,593,377,107,539,323, + 418,13,445,229,661,121,553,337,67,499,283,715,175,607,391,40,472,256,688,148,580,364,94,526,310,202,634, + 452,236,668,128,560,344,74,506,290,722,182,614,398,47,479,263,695,155,587,371,101,533,317,209,641,425,20, + 654,114,546,330,60,492,276,708,168,600,384,33,465,249,681,141,573,357,87,519,303,195,627,411,6,438,222, + 563,347,77,509,293,725,185,617,401,50,482,266,698,158,590,374,104,536,320,212,644,428,23,455,239,671,131, + 63,495,279,711,171,603,387,36,468,252,684,144,576,360,90,522,306,198,630,414,9,441,225,657,117,549,333, + 286,718,178,610,394,43,475,259,691,151,583,367,97,529,313,205,637,421,16,448,232,664,124,556,340,70,502, + 164,596,380,29,461,245,677,137,569,353,83,515,299,191,623,407,226,434,218,650,110,542,326,56,488,272,704, + 402,51,483,267,699,159,591,375,105,537,321,213,645,429,24,456,240,672,132,564,348,78,510,294,726,186,618, + 470,254,686,146,578,362,92,524,308,200,632,416,11,443,227,659,119,551,335,65,497,281,713,173,605,389,38, + 693,153,585,369,99,531,315,207,639,423,18,450,234,666,126,558,342,72,504,288,720,180,612,396,45,477,261, + 571,355,85,517,301,193,625,409,4,436,220,652,112,544,328,58,490,274,706,166,598,382,31,463,247,679,139, + 102,534,318,210,642,426,21,453,237,669,129,561,345,75,507,291,723,183,615,399,48,480,264,696,156,588,372, + 304,196,628,412,7,439,223,655,115,547,331,61,493,277,709,169,601,385,34,466,250,682,142,574,358,88,520, + 635,419,14,446,230,662,122,554,338,68,500,284,716,176,608,392,41,473,257,689,149,581,365,95,527,311,203, + 0,432,216,648,108,540,324,54,486,270,702,162,594,378,27,459,243,675,135,567,351,81,513,297,189,621,3 +}; + +int tableh12[] = { /* 29 x 29 data */ + 2,703,123,587,355,819,65,529,297,761,181,645,413,36,500,268,732,152,616,384,94,558,326,790,210,674,442,7,1, + 141,605,373,837,83,547,315,779,199,663,431,54,518,286,750,170,634,402,112,576,344,808,228,692,460,25,489,257,721, + 359,823,69,533,301,765,185,649,417,40,504,272,736,156,620,388,98,562,330,794,214,678,446,11,475,243,707,127,591, + 76,540,308,772,192,656,424,47,511,279,743,163,627,395,105,569,337,801,221,685,453,18,482,250,714,134,598,366,830, + 293,757,177,641,409,32,496,264,728,148,612,380,90,554,322,786,206,670,438,435,467,235,699,119,583,351,815,61,525, + 201,665,433,56,520,288,752,172,636,404,114,578,346,810,230,694,462,27,491,259,723,143,607,375,839,85,549,317,781, + 419,42,506,274,738,158,622,390,100,564,332,796,216,680,448,13,477,245,709,129,593,361,825,71,535,303,767,187,651, + 513,281,745,165,629,397,107,571,339,803,223,687,455,20,484,252,716,136,600,368,832,78,542,310,774,194,658,426,49, + 730,150,614,382,92,556,324,788,208,672,440,5,469,237,701,121,585,353,817,63,527,295,759,179,643,411,34,498,266, + 632,400,110,574,342,806,226,690,458,23,487,255,719,139,603,371,835,81,545,313,777,197,661,429,52,516,284,748,168, + 96,560,328,792,212,676,444,9,473,241,705,125,589,357,821,67,531,299,763,183,647,415,38,502,270,734,154,618,386, + 335,799,219,683,451,16,480,248,712,132,596,364,828,74,538,306,770,190,654,422,45,509,277,741,161,625,393,103,567, + 204,668,436,471,465,233,697,117,581,349,813,59,523,291,755,175,639,407,30,494,262,726,146,610,378,88,552,320,784, + 463,28,492,260,724,144,608,376,840,86,550,318,782,202,666,434,57,521,289,753,173,637,405,115,579,347,811,231,695, + 478,246,710,130,594,362,826,72,536,304,768,188,652,420,43,507,275,739,159,623,391,101,565,333,797,217,681,449,14, + 717,137,601,369,833,79,543,311,775,195,659,427,50,514,282,746,166,630,398,108,572,340,804,224,688,456,21,485,253, + 586,354,818,64,528,296,760,180,644,412,35,499,267,731,151,615,383,93,557,325,789,209,673,441,6,470,238,702,122, + 836,82,546,314,778,198,662,430,53,517,285,749,169,633,401,111,575,343,807,227,691,459,24,488,256,720,140,604,372, + 532,300,764,184,648,416,39,503,271,735,155,619,387,97,561,329,793,213,677,445,10,474,242,706,126,590,358,822,68, + 771,191,655,423,46,510,278,742,162,626,394,104,568,336,800,220,684,452,17,481,249,713,133,597,365,829,75,539,307, + 640,408,31,495,263,727,147,611,379,89,553,321,785,205,669,437,239,466,234,698,118,582,350,814,60,524,292,756,176, + 55,519,287,751,171,635,403,113,577,345,809,229,693,461,26,490,258,722,142,606,374,838,84,548,316,780,200,664,432, + 273,737,157,621,389,99,563,331,795,215,679,447,12,476,244,708,128,592,360,824,70,534,302,766,186,650,418,41,505, + 164,628,396,106,570,338,802,222,686,454,19,483,251,715,135,599,367,831,77,541,309,773,193,657,425,48,512,280,744, + 381,91,555,323,787,207,671,439,4,468,236,700,120,584,352,816,62,526,294,758,178,642,410,33,497,265,729,149,613, + 573,341,805,225,689,457,22,486,254,718,138,602,370,834,80,544,312,776,196,660,428,51,515,283,747,167,631,399,109, + 791,211,675,443,8,472,240,704,124,588,356,820,66,530,298,762,182,646,414,37,501,269,733,153,617,385,95,559,327, + 682,450,15,479,247,711,131,595,363,827,73,537,305,769,189,653,421,44,508,276,740,160,624,392,102,566,334,798,218, + 0,464,232,696,116,580,348,812,58,522,290,754,174,638,406,29,493,261,725,145,609,377,87,551,319,783,203,667,3 +}; + +int tableh13[] = { /* 31 x 31 data */ + 2,759,139,635,387,883,77,573,325,821,201,697,449,945,46,542,294,790,170,666,418,914,108,604,356,852,232,728,480,15,1, + 147,643,395,891,85,581,333,829,209,705,457,953,54,550,302,798,178,674,426,922,116,612,364,860,240,736,488,23,519,271,767, + 379,875,69,565,317,813,193,689,441,937,38,534,286,782,162,658,410,906,100,596,348,844,224,720,472,7,503,255,751,131,627, + 89,585,337,833,213,709,461,957,58,554,306,802,182,678,430,926,120,616,368,864,244,740,492,27,523,275,771,151,647,399,895, + 321,817,197,693,445,941,42,538,290,786,166,662,414,910,104,600,352,848,228,724,476,11,507,259,755,135,631,383,879,73,569, + 205,701,453,949,50,546,298,794,174,670,422,918,112,608,360,856,236,732,484,19,515,267,763,143,639,391,887,81,577,329,825, + 437,933,34,530,282,778,158,654,406,902,96,592,344,840,220,716,468,465,499,251,747,127,623,375,871,65,561,313,809,189,685, + 60,556,308,804,184,680,432,928,122,618,370,866,246,742,494,29,525,277,773,153,649,401,897,91,587,339,835,215,711,463,959, + 292,788,168,664,416,912,106,602,354,850,230,726,478,13,509,261,757,137,633,385,881,75,571,323,819,199,695,447,943,44,540, + 176,672,424,920,114,610,362,858,238,734,486,21,517,269,765,145,641,393,889,83,579,331,827,207,703,455,951,52,548,300,796, + 408,904,98,594,346,842,222,718,470,5,501,253,749,129,625,377,873,67,563,315,811,191,687,439,935,36,532,284,780,160,656, + 118,614,366,862,242,738,490,25,521,273,769,149,645,397,893,87,583,335,831,211,707,459,955,56,552,304,800,180,676,428,924, + 350,846,226,722,474,9,505,257,753,133,629,381,877,71,567,319,815,195,691,443,939,40,536,288,784,164,660,412,908,102,598, + 234,730,482,17,513,265,761,141,637,389,885,79,575,327,823,203,699,451,947,48,544,296,792,172,668,420,916,110,606,358,854, + 466,511,497,249,745,125,621,373,869,63,559,311,807,187,683,435,931,32,528,280,776,156,652,404,900,94,590,342,838,218,714, + 526,278,774,154,650,402,898,92,588,340,836,216,712,464,960,61,557,309,805,185,681,433,929,123,619,371,867,247,743,495,30, + 758,138,634,386,882,76,572,324,820,200,696,448,944,45,541,293,789,169,665,417,913,107,603,355,851,231,727,479,14,510,262, + 642,394,890,84,580,332,828,208,704,456,952,53,549,301,797,177,673,425,921,115,611,363,859,239,735,487,22,518,270,766,146, + 874,68,564,316,812,192,688,440,936,37,533,285,781,161,657,409,905,99,595,347,843,223,719,471,6,502,254,750,130,626,378, + 584,336,832,212,708,460,956,57,553,305,801,181,677,429,925,119,615,367,863,243,739,491,26,522,274,770,150,646,398,894,88, + 816,196,692,444,940,41,537,289,785,165,661,413,909,103,599,351,847,227,723,475,10,506,258,754,134,630,382,878,72,568,320, + 700,452,948,49,545,297,793,173,669,421,917,111,607,359,855,235,731,483,18,514,266,762,142,638,390,886,80,576,328,824,204, + 932,33,529,281,777,157,653,405,901,95,591,343,839,219,715,467,263,498,250,746,126,622,374,870,64,560,312,808,188,684,436, + 555,307,803,183,679,431,927,121,617,369,865,245,741,493,28,524,276,772,152,648,400,896,90,586,338,834,214,710,462,958,59, + 787,167,663,415,911,105,601,353,849,229,725,477,12,508,260,756,136,632,384,880,74,570,322,818,198,694,446,942,43,539,291, + 671,423,919,113,609,361,857,237,733,485,20,516,268,764,144,640,392,888,82,578,330,826,206,702,454,950,51,547,299,795,175, + 903,97,593,345,841,221,717,469,4,500,252,748,128,624,376,872,66,562,314,810,190,686,438,934,35,531,283,779,159,655,407, + 613,365,861,241,737,489,24,520,272,768,148,644,396,892,86,582,334,830,210,706,458,954,55,551,303,799,179,675,427,923,117, + 845,225,721,473,8,504,256,752,132,628,380,876,70,566,318,814,194,690,442,938,39,535,287,783,163,659,411,907,101,597,349, + 729,481,16,512,264,760,140,636,388,884,78,574,326,822,202,698,450,946,47,543,295,791,171,667,419,915,109,605,357,853,233, + 0,496,248,744,124,620,372,868,62,558,310,806,186,682,434,930,31,527,279,775,155,651,403,899,93,589,341,837,217,713,3 +}; + +int tableh14[] = { /* 33 x 33 data */ + 2,265,793,133,661,397,925,67,595,331,859,199,727,463,991,34,562,298,826,166,694,430,958,100,628,364,892,232,760,496,1024,1057,1, + 824,164,692,428,956,98,626,362,890,230,758,494,1022,65,593,329,857,197,725,461,989,131,659,395,923,263,791,527,1055,32,1088,560,296, + 676,412,940,82,610,346,874,214,742,478,1006,49,577,313,841,181,709,445,973,115,643,379,907,247,775,511,1039,16,1072,544,280,808,148, + 948,90,618,354,882,222,750,486,1014,57,585,321,849,189,717,453,981,123,651,387,915,255,783,519,1047,24,1080,552,288,816,156,684,420, + 602,338,866,206,734,470,998,41,569,305,833,173,701,437,965,107,635,371,899,239,767,503,1031,8,1064,536,272,800,140,668,404,932,74, + 886,226,754,490,1018,61,589,325,853,193,721,457,985,127,655,391,919,259,787,523,1051,28,1084,556,292,820,160,688,424,952,94,622,358, + 738,474,1002,45,573,309,837,177,705,441,969,111,639,375,903,243,771,507,1035,12,1068,540,276,804,144,672,408,936,78,606,342,870,210, + 1010,53,581,317,845,185,713,449,977,119,647,383,911,251,779,515,1043,20,1076,548,284,812,152,680,416,944,86,614,350,878,218,746,482, + 565,301,829,169,697,433,961,103,631,367,895,235,763,499,1027,4,1060,532,268,796,136,664,400,928,70,598,334,862,202,730,466,994,37, + 855,195,723,459,987,129,657,393,921,261,789,525,1053,30,1086,558,294,822,162,690,426,954,96,624,360,888,228,756,492,1020,63,591,327, + 707,443,971,113,641,377,905,245,773,509,1037,14,1070,542,278,806,146,674,410,938,80,608,344,872,212,740,476,1004,47,575,311,839,179, + 979,121,649,385,913,253,781,517,1045,22,1078,550,286,814,154,682,418,946,88,616,352,880,220,748,484,1012,55,583,319,847,187,715,451, + 633,369,897,237,765,501,1029,6,1062,534,270,798,138,666,402,930,72,600,336,864,204,732,468,996,39,567,303,831,171,699,435,963,105, + 917,257,785,521,1049,26,1082,554,290,818,158,686,422,950,92,620,356,884,224,752,488,1016,59,587,323,851,191,719,455,983,125,653,389, + 769,505,1033,10,1066,538,274,802,142,670,406,934,76,604,340,868,208,736,472,1000,43,571,307,835,175,703,439,967,109,637,373,901,241, + 1041,18,1074,546,282,810,150,678,414,942,84,612,348,876,216,744,480,1008,51,579,315,843,183,711,447,975,117,645,381,909,249,777,513, + 1058,530,266,794,134,662,398,926,68,596,332,860,200,728,464,992,35,563,299,827,167,695,431,959,101,629,365,893,233,761,497,1025,529, + 295,823,163,691,427,955,97,625,361,889,229,757,493,1021,64,592,328,856,196,724,460,988,130,658,394,922,262,790,526,1054,31,1087,559, + 147,675,411,939,81,609,345,873,213,741,477,1005,48,576,312,840,180,708,444,972,114,642,378,906,246,774,510,1038,15,1071,543,279,807, + 419,947,89,617,353,881,221,749,485,1013,56,584,320,848,188,716,452,980,122,650,386,914,254,782,518,1046,23,1079,551,287,815,155,683, + 73,601,337,865,205,733,469,997,40,568,304,832,172,700,436,964,106,634,370,898,238,766,502,1030,7,1063,535,271,799,139,667,403,931, + 357,885,225,753,489,1017,60,588,324,852,192,720,456,984,126,654,390,918,258,786,522,1050,27,1083,555,291,819,159,687,423,951,93,621, + 209,737,473,1001,44,572,308,836,176,704,440,968,110,638,374,902,242,770,506,1034,11,1067,539,275,803,143,671,407,935,77,605,341,869, + 481,1009,52,580,316,844,184,712,448,976,118,646,382,910,250,778,514,1042,19,1075,547,283,811,151,679,415,943,85,613,349,877,217,745, + 36,564,300,828,168,696,432,960,102,630,366,894,234,762,498,1026,1023,1059,531,267,795,135,663,399,927,69,597,333,861,201,729,465,993, + 326,854,194,722,458,986,128,656,392,920,260,788,524,1052,29,1085,557,293,821,161,689,425,953,95,623,359,887,227,755,491,1019,62,590, + 178,706,442,970,112,640,376,904,244,772,508,1036,13,1069,541,277,805,145,673,409,937,79,607,343,871,211,739,475,1003,46,574,310,838, + 450,978,120,648,384,912,252,780,516,1044,21,1077,549,285,813,153,681,417,945,87,615,351,879,219,747,483,1011,54,582,318,846,186,714, + 104,632,368,896,236,764,500,1028,5,1061,533,269,797,137,665,401,929,71,599,335,863,203,731,467,995,38,566,302,830,170,698,434,962, + 388,916,256,784,520,1048,25,1081,553,289,817,157,685,421,949,91,619,355,883,223,751,487,1015,58,586,322,850,190,718,454,982,124,652, + 240,768,504,1032,9,1065,537,273,801,141,669,405,933,75,603,339,867,207,735,471,999,42,570,306,834,174,702,438,966,108,636,372,900, + 512,1040,17,1073,545,281,809,149,677,413,941,83,611,347,875,215,743,479,1007,50,578,314,842,182,710,446,974,116,644,380,908,248,776, + 0,1056,528,264,792,132,660,396,924,66,594,330,858,198,726,462,990,33,561,297,825,165,693,429,957,99,627,363,891,231,759,495,3 +}; + +int tableh15[] = { /* 35 x 35 data */ + 2,290,850,150,710,430,990,80,1200,640,360,920,220,780,500,1060,45,1165,605,325,885,185,745,465,1025,115,675,395,955,255,815,535,1095,10,1, + 859,159,719,439,999,89,1209,649,369,929,229,789,509,1069,54,1174,614,334,894,194,754,474,1034,124,684,404,964,264,824,544,1104,19,1139,579,299, + 701,421,981,71,1191,631,351,911,211,771,491,1051,36,1156,596,316,876,176,736,456,1016,106,666,386,946,246,806,526,1086,1130,1121,561,281,841,141, + 1014,104,1224,664,384,944,244,804,524,1084,69,1189,629,349,909,209,769,489,1049,139,699,419,979,279,839,559,1119,34,1154,594,314,874,174,734,454, + 1207,647,367,927,227,787,507,1067,52,1172,612,332,892,192,752,472,1032,122,682,402,962,262,822,542,1102,17,1137,577,297,857,157,717,437,997,87, + 376,936,236,796,516,1076,61,1181,621,341,901,201,761,481,1041,131,691,411,971,271,831,551,1111,26,1146,586,306,866,166,726,446,1006,96,1216,656, + 218,778,498,1058,43,1163,603,323,883,183,743,463,1023,113,673,393,953,253,813,533,1093,8,1128,568,288,848,148,708,428,988,78,1198,638,358,918, + 520,1080,65,1185,625,345,905,205,765,485,1045,135,695,415,975,275,835,555,1115,30,1150,590,310,870,170,730,450,1010,100,1220,660,380,940,240,800, + 48,1168,608,328,888,188,748,468,1028,118,678,398,958,258,818,538,1098,13,1133,573,293,853,153,713,433,993,83,1203,643,363,923,223,783,503,1063, + 617,337,897,197,757,477,1037,127,687,407,967,267,827,547,1107,22,1142,582,302,862,162,722,442,1002,92,1212,652,372,932,232,792,512,1072,57,1177, + 879,179,739,459,1019,109,669,389,949,249,809,529,1089,4,1124,564,284,844,144,704,424,984,74,1194,634,354,914,214,774,494,1054,39,1159,599,319, + 767,487,1047,137,697,417,977,277,837,557,1117,32,1152,592,312,872,172,732,452,1012,102,1222,662,382,942,242,802,522,1082,67,1187,627,347,907,207, + 1030,120,680,400,960,260,820,540,1100,15,1135,575,295,855,155,715,435,995,85,1205,645,365,925,225,785,505,1065,50,1170,610,330,890,190,750,470, + 689,409,969,269,829,549,1109,24,1144,584,304,864,164,724,444,1004,94,1214,654,374,934,234,794,514,1074,59,1179,619,339,899,199,759,479,1039,129, + 951,251,811,531,1091,6,1126,566,286,846,146,706,426,986,76,1196,636,356,916,216,776,496,1056,41,1161,601,321,881,181,741,461,1021,111,671,391, + 833,553,1113,28,1148,588,308,868,168,728,448,1008,98,1218,658,378,938,238,798,518,1078,63,1183,623,343,903,203,763,483,1043,133,693,413,973,273, + 1096,11,1131,571,291,851,151,711,431,991,81,1201,641,361,921,221,781,501,1061,46,1166,606,326,886,186,746,466,1026,116,676,396,956,256,816,536, + 1140,580,300,860,160,720,440,1000,90,1210,650,370,930,230,790,510,1070,55,1175,615,335,895,195,755,475,1035,125,685,405,965,265,825,545,1105,20, + 282,842,142,702,422,982,72,1192,632,352,912,212,772,492,1052,37,1157,597,317,877,177,737,457,1017,107,667,387,947,247,807,527,1087,570,1122,562, + 173,733,453,1013,103,1223,663,383,943,243,803,523,1083,68,1188,628,348,908,208,768,488,1048,138,698,418,978,278,838,558,1118,33,1153,593,313,873, + 436,996,86,1206,646,366,926,226,786,506,1066,51,1171,611,331,891,191,751,471,1031,121,681,401,961,261,821,541,1101,16,1136,576,296,856,156,716, + 95,1215,655,375,935,235,795,515,1075,60,1180,620,340,900,200,760,480,1040,130,690,410,970,270,830,550,1110,25,1145,585,305,865,165,725,445,1005, + 637,357,917,217,777,497,1057,42,1162,602,322,882,182,742,462,1022,112,672,392,952,252,812,532,1092,7,1127,567,287,847,147,707,427,987,77,1197, + 939,239,799,519,1079,64,1184,624,344,904,204,764,484,1044,134,694,414,974,274,834,554,1114,29,1149,589,309,869,169,729,449,1009,99,1219,659,379, + 782,502,1062,47,1167,607,327,887,187,747,467,1027,117,677,397,957,257,817,537,1097,12,1132,572,292,852,152,712,432,992,82,1202,642,362,922,222, + 1071,56,1176,616,336,896,196,756,476,1036,126,686,406,966,266,826,546,1106,21,1141,581,301,861,161,721,441,1001,91,1211,651,371,931,231,791,511, + 1158,598,318,878,178,738,458,1018,108,668,388,948,248,808,528,1088,1085,1123,563,283,843,143,703,423,983,73,1193,633,353,913,213,773,493,1053,38, + 346,906,206,766,486,1046,136,696,416,976,276,836,556,1116,31,1151,591,311,871,171,731,451,1011,101,1221,661,381,941,241,801,521,1081,66,1186,626, + 189,749,469,1029,119,679,399,959,259,819,539,1099,14,1134,574,294,854,154,714,434,994,84,1204,644,364,924,224,784,504,1064,49,1169,609,329,889, + 478,1038,128,688,408,968,268,828,548,1108,23,1143,583,303,863,163,723,443,1003,93,1213,653,373,933,233,793,513,1073,58,1178,618,338,898,198,758, + 110,670,390,950,250,810,530,1090,5,1125,565,285,845,145,705,425,985,75,1195,635,355,915,215,775,495,1055,40,1160,600,320,880,180,740,460,1020, + 412,972,272,832,552,1112,27,1147,587,307,867,167,727,447,1007,97,1217,657,377,937,237,797,517,1077,62,1182,622,342,902,202,762,482,1042,132,692, + 254,814,534,1094,9,1129,569,289,849,149,709,429,989,79,1199,639,359,919,219,779,499,1059,44,1164,604,324,884,184,744,464,1024,114,674,394,954, + 543,1103,18,1138,578,298,858,158,718,438,998,88,1208,648,368,928,228,788,508,1068,53,1173,613,333,893,193,753,473,1033,123,683,403,963,263,823, + 0,1120,560,280,840,140,700,420,980,70,1190,630,350,910,210,770,490,1050,35,1155,595,315,875,175,735,455,1015,105,665,385,945,245,805,525,3 +}; + +int tableh16[] = { /* 37 x 37 data */ + 2,302,894,154,1338,746,450,1042,80,1264,672,376,968,228,820,524,1116,43,1227,635,339,931,191,783,487,1079,117,1301,709,413,1005,265,857,561,1153,6,1, + 917,177,1361,769,473,1065,103,1287,695,399,991,251,843,547,1139,66,1250,658,362,954,214,806,510,1102,140,1324,732,436,1028,288,880,584,1176,29,1213,621,325, + 1343,751,455,1047,85,1269,677,381,973,233,825,529,1121,48,1232,640,344,936,196,788,492,1084,122,1306,714,418,1010,270,862,566,1158,11,1195,603,307,899,159, + 464,1056,94,1278,686,390,982,242,834,538,1130,57,1241,649,353,945,205,797,501,1093,131,1315,723,427,1019,279,871,575,1167,20,1204,612,316,908,168,1352,760, + 75,1259,667,371,963,223,815,519,1111,38,1222,630,334,926,186,778,482,1074,112,1296,704,408,1000,260,852,556,1148,1190,1185,593,297,889,149,1333,741,445,1037, + 702,406,998,258,850,554,1146,73,1257,665,369,961,221,813,517,1109,147,1331,739,443,1035,295,887,591,1183,36,1220,628,332,924,184,1368,776,480,1072,110,1294, + 980,240,832,536,1128,55,1239,647,351,943,203,795,499,1091,129,1313,721,425,1017,277,869,573,1165,18,1202,610,314,906,166,1350,758,462,1054,92,1276,684,388, + 841,545,1137,64,1248,656,360,952,212,804,508,1100,138,1322,730,434,1026,286,878,582,1174,27,1211,619,323,915,175,1359,767,471,1063,101,1285,693,397,989,249, + 1119,46,1230,638,342,934,194,786,490,1082,120,1304,712,416,1008,268,860,564,1156,9,1193,601,305,897,157,1341,749,453,1045,83,1267,675,379,971,231,823,527, + 1253,661,365,957,217,809,513,1105,143,1327,735,439,1031,291,883,587,1179,32,1216,624,328,920,180,1364,772,476,1068,106,1290,698,402,994,254,846,550,1142,69, + 347,939,199,791,495,1087,125,1309,717,421,1013,273,865,569,1161,14,1198,606,310,902,162,1346,754,458,1050,88,1272,680,384,976,236,828,532,1124,51,1235,643, + 208,800,504,1096,134,1318,726,430,1022,282,874,578,1170,23,1207,615,319,911,171,1355,763,467,1059,97,1281,689,393,985,245,837,541,1133,60,1244,652,356,948, + 485,1077,115,1299,707,411,1003,263,855,559,1151,4,1188,596,300,892,152,1336,744,448,1040,78,1262,670,374,966,226,818,522,1114,41,1225,633,337,929,189,781, + 145,1329,737,441,1033,293,885,589,1181,34,1218,626,330,922,182,1366,774,478,1070,108,1292,700,404,996,256,848,552,1144,71,1255,663,367,959,219,811,515,1107, + 719,423,1015,275,867,571,1163,16,1200,608,312,904,164,1348,756,460,1052,90,1274,682,386,978,238,830,534,1126,53,1237,645,349,941,201,793,497,1089,127,1311, + 1024,284,876,580,1172,25,1209,617,321,913,173,1357,765,469,1061,99,1283,691,395,987,247,839,543,1135,62,1246,654,358,950,210,802,506,1098,136,1320,728,432, + 858,562,1154,7,1191,599,303,895,155,1339,747,451,1043,81,1265,673,377,969,229,821,525,1117,44,1228,636,340,932,192,784,488,1080,118,1302,710,414,1006,266, + 1177,30,1214,622,326,918,178,1362,770,474,1066,104,1288,696,400,992,252,844,548,1140,67,1251,659,363,955,215,807,511,1103,141,1325,733,437,1029,289,881,585, + 1196,604,308,900,160,1344,752,456,1048,86,1270,678,382,974,234,826,530,1122,49,1233,641,345,937,197,789,493,1085,123,1307,715,419,1011,271,863,567,1159,12, + 317,909,169,1353,761,465,1057,95,1279,687,391,983,243,835,539,1131,58,1242,650,354,946,206,798,502,1094,132,1316,724,428,1020,280,872,576,1168,21,1205,613, + 150,1334,742,446,1038,76,1260,668,372,964,224,816,520,1112,39,1223,631,335,927,187,779,483,1075,113,1297,705,409,1001,261,853,557,1149,598,1186,594,298,890, + 775,479,1071,109,1293,701,405,997,257,849,553,1145,72,1256,664,368,960,220,812,516,1108,146,1330,738,442,1034,294,886,590,1182,35,1219,627,331,923,183,1367, + 1053,91,1275,683,387,979,239,831,535,1127,54,1238,646,350,942,202,794,498,1090,128,1312,720,424,1016,276,868,572,1164,17,1201,609,313,905,165,1349,757,461, + 1284,692,396,988,248,840,544,1136,63,1247,655,359,951,211,803,507,1099,137,1321,729,433,1025,285,877,581,1173,26,1210,618,322,914,174,1358,766,470,1062,100, + 378,970,230,822,526,1118,45,1229,637,341,933,193,785,489,1081,119,1303,711,415,1007,267,859,563,1155,8,1192,600,304,896,156,1340,748,452,1044,82,1266,674, + 253,845,549,1141,68,1252,660,364,956,216,808,512,1104,142,1326,734,438,1030,290,882,586,1178,31,1215,623,327,919,179,1363,771,475,1067,105,1289,697,401,993, + 531,1123,50,1234,642,346,938,198,790,494,1086,124,1308,716,420,1012,272,864,568,1160,13,1197,605,309,901,161,1345,753,457,1049,87,1271,679,383,975,235,827, + 59,1243,651,355,947,207,799,503,1095,133,1317,725,429,1021,281,873,577,1169,22,1206,614,318,910,170,1354,762,466,1058,96,1280,688,392,984,244,836,540,1132, + 632,336,928,188,780,484,1076,114,1298,706,410,1002,262,854,558,1150,1147,1187,595,299,891,151,1335,743,447,1039,77,1261,669,373,965,225,817,521,1113,40,1224, + 958,218,810,514,1106,144,1328,736,440,1032,292,884,588,1180,33,1217,625,329,921,181,1365,773,477,1069,107,1291,699,403,995,255,847,551,1143,70,1254,662,366, + 792,496,1088,126,1310,718,422,1014,274,866,570,1162,15,1199,607,311,903,163,1347,755,459,1051,89,1273,681,385,977,237,829,533,1125,52,1236,644,348,940,200, + 1097,135,1319,727,431,1023,283,875,579,1171,24,1208,616,320,912,172,1356,764,468,1060,98,1282,690,394,986,246,838,542,1134,61,1245,653,357,949,209,801,505, + 1300,708,412,1004,264,856,560,1152,5,1189,597,301,893,153,1337,745,449,1041,79,1263,671,375,967,227,819,523,1115,42,1226,634,338,930,190,782,486,1078,116, + 435,1027,287,879,583,1175,28,1212,620,324,916,176,1360,768,472,1064,102,1286,694,398,990,250,842,546,1138,65,1249,657,361,953,213,805,509,1101,139,1323,731, + 269,861,565,1157,10,1194,602,306,898,158,1342,750,454,1046,84,1268,676,380,972,232,824,528,1120,47,1231,639,343,935,195,787,491,1083,121,1305,713,417,1009, + 574,1166,19,1203,611,315,907,167,1351,759,463,1055,93,1277,685,389,981,241,833,537,1129,56,1240,648,352,944,204,796,500,1092,130,1314,722,426,1018,278,870, + 0,1184,592,296,888,148,1332,740,444,1036,74,1258,666,370,962,222,814,518,1110,37,1221,629,333,925,185,777,481,1073,111,1295,703,407,999,259,851,555,3 +}; + +int tableh17[] = { /* 39 x 39 data */ + 2,328,952,172,1420,796,484,1108,94,1342,718,406,1030,250,1498,874,562,1186,55,1303,679,367,991,211,1459,835,523,1147,133,1381,757,445,1069,289,913,601,1225,16,1, + 962,182,1430,806,494,1118,104,1352,728,416,1040,260,1508,884,572,1196,65,1313,689,377,1001,221,1469,845,533,1157,143,1391,767,455,1079,299,923,611,1235,26,1274,650,338, + 1410,786,474,1098,84,1332,708,396,1020,240,1488,864,552,1176,45,1293,669,357,981,201,1449,825,513,1137,123,1371,747,435,1059,279,903,591,1215,6,1254,630,318,942,162, + 499,1123,109,1357,733,421,1045,265,1513,889,577,1201,70,1318,694,382,1006,226,1474,850,538,1162,148,1396,772,460,1084,304,928,616,1240,31,1279,655,343,967,187,1435,811, + 89,1337,713,401,1025,245,1493,869,557,1181,50,1298,674,362,986,206,1454,830,518,1142,128,1376,752,440,1064,284,908,596,1220,11,1259,635,323,947,167,1415,791,479,1103, + 723,411,1035,255,1503,879,567,1191,60,1308,684,372,996,216,1464,840,528,1152,138,1386,762,450,1074,294,918,606,1230,21,1269,645,333,957,177,1425,801,489,1113,99,1347, + 1015,235,1483,859,547,1171,40,1288,664,352,976,196,1444,820,508,1132,118,1366,742,430,1054,274,898,586,1210,1264,1249,625,313,937,157,1405,781,469,1093,79,1327,703,391, + 1520,896,584,1208,77,1325,701,389,1013,233,1481,857,545,1169,155,1403,779,467,1091,311,935,623,1247,38,1286,662,350,974,194,1442,818,506,1130,116,1364,740,428,1052,272, + 565,1189,58,1306,682,370,994,214,1462,838,526,1150,136,1384,760,448,1072,292,916,604,1228,19,1267,643,331,955,175,1423,799,487,1111,97,1345,721,409,1033,253,1501,877, + 68,1316,692,380,1004,224,1472,848,536,1160,146,1394,770,458,1082,302,926,614,1238,29,1277,653,341,965,185,1433,809,497,1121,107,1355,731,419,1043,263,1511,887,575,1199, + 672,360,984,204,1452,828,516,1140,126,1374,750,438,1062,282,906,594,1218,9,1257,633,321,945,165,1413,789,477,1101,87,1335,711,399,1023,243,1491,867,555,1179,48,1296, + 1009,229,1477,853,541,1165,151,1399,775,463,1087,307,931,619,1243,34,1282,658,346,970,190,1438,814,502,1126,112,1360,736,424,1048,268,1516,892,580,1204,73,1321,697,385, + 1457,833,521,1145,131,1379,755,443,1067,287,911,599,1223,14,1262,638,326,950,170,1418,794,482,1106,92,1340,716,404,1028,248,1496,872,560,1184,53,1301,677,365,989,209, + 531,1155,141,1389,765,453,1077,297,921,609,1233,24,1272,648,336,960,180,1428,804,492,1116,102,1350,726,414,1038,258,1506,882,570,1194,63,1311,687,375,999,219,1467,843, + 121,1369,745,433,1057,277,901,589,1213,4,1252,628,316,940,160,1408,784,472,1096,82,1330,706,394,1018,238,1486,862,550,1174,43,1291,667,355,979,199,1447,823,511,1135, + 777,465,1089,309,933,621,1245,36,1284,660,348,972,192,1440,816,504,1128,114,1362,738,426,1050,270,1518,894,582,1206,75,1323,699,387,1011,231,1479,855,543,1167,153,1401, + 1070,290,914,602,1226,17,1265,641,329,953,173,1421,797,485,1109,95,1343,719,407,1031,251,1499,875,563,1187,56,1304,680,368,992,212,1460,836,524,1148,134,1382,758,446, + 924,612,1236,27,1275,651,339,963,183,1431,807,495,1119,105,1353,729,417,1041,261,1509,885,573,1197,66,1314,690,378,1002,222,1470,846,534,1158,144,1392,768,456,1080,300, + 1216,7,1255,631,319,943,163,1411,787,475,1099,85,1333,709,397,1021,241,1489,865,553,1177,46,1294,670,358,982,202,1450,826,514,1138,124,1372,748,436,1060,280,904,592, + 1280,656,344,968,188,1436,812,500,1124,110,1358,734,422,1046,266,1514,890,578,1202,71,1319,695,383,1007,227,1475,851,539,1163,149,1397,773,461,1085,305,929,617,1241,32, + 324,948,168,1416,792,480,1104,90,1338,714,402,1026,246,1494,870,558,1182,51,1299,675,363,987,207,1455,831,519,1143,129,1377,753,441,1065,285,909,597,1221,12,1260,636, + 178,1426,802,490,1114,100,1348,724,412,1036,256,1504,880,568,1192,61,1309,685,373,997,217,1465,841,529,1153,139,1387,763,451,1075,295,919,607,1231,22,1270,646,334,958, + 782,470,1094,80,1328,704,392,1016,236,1484,860,548,1172,41,1289,665,353,977,197,1445,821,509,1133,119,1367,743,431,1055,275,899,587,1211,640,1250,626,314,938,158,1406, + 1129,115,1363,739,427,1051,271,1519,895,583,1207,76,1324,700,388,1012,232,1480,856,544,1168,154,1402,778,466,1090,310,934,622,1246,37,1285,661,349,973,193,1441,817,505, + 1344,720,408,1032,252,1500,876,564,1188,57,1305,681,369,993,213,1461,837,525,1149,135,1383,759,447,1071,291,915,603,1227,18,1266,642,330,954,174,1422,798,486,1110,96, + 418,1042,262,1510,886,574,1198,67,1315,691,379,1003,223,1471,847,535,1159,145,1393,769,457,1081,301,925,613,1237,28,1276,652,340,964,184,1432,808,496,1120,106,1354,730, + 242,1490,866,554,1178,47,1295,671,359,983,203,1451,827,515,1139,125,1373,749,437,1061,281,905,593,1217,8,1256,632,320,944,164,1412,788,476,1100,86,1334,710,398,1022, + 891,579,1203,72,1320,696,384,1008,228,1476,852,540,1164,150,1398,774,462,1086,306,930,618,1242,33,1281,657,345,969,189,1437,813,501,1125,111,1359,735,423,1047,267,1515, + 1183,52,1300,676,364,988,208,1456,832,520,1144,130,1378,754,442,1066,286,910,598,1222,13,1261,637,325,949,169,1417,793,481,1105,91,1339,715,403,1027,247,1495,871,559, + 1310,686,374,998,218,1466,842,530,1154,140,1388,764,452,1076,296,920,608,1232,23,1271,647,335,959,179,1427,803,491,1115,101,1349,725,413,1037,257,1505,881,569,1193,62, + 354,978,198,1446,822,510,1134,120,1368,744,432,1056,276,900,588,1212,1209,1251,627,315,939,159,1407,783,471,1095,81,1329,705,393,1017,237,1485,861,549,1173,42,1290,666, + 230,1478,854,542,1166,152,1400,776,464,1088,308,932,620,1244,35,1283,659,347,971,191,1439,815,503,1127,113,1361,737,425,1049,269,1517,893,581,1205,74,1322,698,386,1010, + 834,522,1146,132,1380,756,444,1068,288,912,600,1224,15,1263,639,327,951,171,1419,795,483,1107,93,1341,717,405,1029,249,1497,873,561,1185,54,1302,678,366,990,210,1458, + 1156,142,1390,766,454,1078,298,922,610,1234,25,1273,649,337,961,181,1429,805,493,1117,103,1351,727,415,1039,259,1507,883,571,1195,64,1312,688,376,1000,220,1468,844,532, + 1370,746,434,1058,278,902,590,1214,5,1253,629,317,941,161,1409,785,473,1097,83,1331,707,395,1019,239,1487,863,551,1175,44,1292,668,356,980,200,1448,824,512,1136,122, + 459,1083,303,927,615,1239,30,1278,654,342,966,186,1434,810,498,1122,108,1356,732,420,1044,264,1512,888,576,1200,69,1317,693,381,1005,225,1473,849,537,1161,147,1395,771, + 283,907,595,1219,10,1258,634,322,946,166,1414,790,478,1102,88,1336,712,400,1024,244,1492,868,556,1180,49,1297,673,361,985,205,1453,829,517,1141,127,1375,751,439,1063, + 605,1229,20,1268,644,332,956,176,1424,800,488,1112,98,1346,722,410,1034,254,1502,878,566,1190,59,1307,683,371,995,215,1463,839,527,1151,137,1385,761,449,1073,293,917, + 0,1248,624,312,936,156,1404,780,468,1092,78,1326,702,390,1014,234,1482,858,546,1170,39,1287,663,351,975,195,1443,819,507,1131,117,1365,741,429,1053,273,897,585,3 +}; + +int tableh18[] = { /* 41 x 41 data */ + 2,332,1644,988,168,1480,824,496,1152,86,1398,742,414,1070,250,1562,906,578,1234,45,1357,701,373,1029,209,1521,865,537,1193,127,1439,783,455,1111,291,1603,947,619,1275,4,1, + 1677,1021,201,1513,857,529,1185,119,1431,775,447,1103,283,1595,939,611,1267,78,1390,734,406,1062,242,1554,898,570,1226,160,1472,816,488,1144,324,1636,980,652,1308,37,1349,693,365, + 181,1493,837,509,1165,99,1411,755,427,1083,263,1575,919,591,1247,58,1370,714,386,1042,222,1534,878,550,1206,140,1452,796,468,1124,304,1616,960,632,1288,17,1329,673,345,1657,1001, + 847,519,1175,109,1421,765,437,1093,273,1585,929,601,1257,68,1380,724,396,1052,232,1544,888,560,1216,150,1462,806,478,1134,314,1626,970,642,1298,27,1339,683,355,1667,1011,191,1503, + 1155,89,1401,745,417,1073,253,1565,909,581,1237,48,1360,704,376,1032,212,1524,868,540,1196,130,1442,786,458,1114,294,1606,950,622,1278,7,1319,663,335,1647,991,171,1483,827,499, + 1426,770,442,1098,278,1590,934,606,1262,73,1385,729,401,1057,237,1549,893,565,1221,155,1467,811,483,1139,319,1631,975,647,1303,32,1344,688,360,1672,1016,196,1508,852,524,1180,114, + 422,1078,258,1570,914,586,1242,53,1365,709,381,1037,217,1529,873,545,1201,135,1447,791,463,1119,299,1611,955,627,1283,12,1324,668,340,1652,996,176,1488,832,504,1160,94,1406,750, + 268,1580,924,596,1252,63,1375,719,391,1047,227,1539,883,555,1211,145,1457,801,473,1129,309,1621,965,637,1293,22,1334,678,350,1662,1006,186,1498,842,514,1170,104,1416,760,432,1088, + 903,575,1231,42,1354,698,370,1026,206,1518,862,534,1190,124,1436,780,452,1108,288,1600,944,616,1272,1316,1313,657,329,1641,985,165,1477,821,493,1149,83,1395,739,411,1067,247,1559, + 1270,81,1393,737,409,1065,245,1557,901,573,1229,163,1475,819,491,1147,327,1639,983,655,1311,40,1352,696,368,1680,1024,204,1516,860,532,1188,122,1434,778,450,1106,286,1598,942,614, + 1373,717,389,1045,225,1537,881,553,1209,143,1455,799,471,1127,307,1619,963,635,1291,20,1332,676,348,1660,1004,184,1496,840,512,1168,102,1414,758,430,1086,266,1578,922,594,1250,61, + 399,1055,235,1547,891,563,1219,153,1465,809,481,1137,317,1629,973,645,1301,30,1342,686,358,1670,1014,194,1506,850,522,1178,112,1424,768,440,1096,276,1588,932,604,1260,71,1383,727, + 215,1527,871,543,1199,133,1445,789,461,1117,297,1609,953,625,1281,10,1322,666,338,1650,994,174,1486,830,502,1158,92,1404,748,420,1076,256,1568,912,584,1240,51,1363,707,379,1035, + 896,568,1224,158,1470,814,486,1142,322,1634,978,650,1306,35,1347,691,363,1675,1019,199,1511,855,527,1183,117,1429,773,445,1101,281,1593,937,609,1265,76,1388,732,404,1060,240,1552, + 1204,138,1450,794,466,1122,302,1614,958,630,1286,15,1327,671,343,1655,999,179,1491,835,507,1163,97,1409,753,425,1081,261,1573,917,589,1245,56,1368,712,384,1040,220,1532,876,548, + 1460,804,476,1132,312,1624,968,640,1296,25,1337,681,353,1665,1009,189,1501,845,517,1173,107,1419,763,435,1091,271,1583,927,599,1255,66,1378,722,394,1050,230,1542,886,558,1214,148, + 456,1112,292,1604,948,620,1276,5,1317,661,333,1645,989,169,1481,825,497,1153,87,1399,743,415,1071,251,1563,907,579,1235,46,1358,702,374,1030,210,1522,866,538,1194,128,1440,784, + 325,1637,981,653,1309,38,1350,694,366,1678,1022,202,1514,858,530,1186,120,1432,776,448,1104,284,1596,940,612,1268,79,1391,735,407,1063,243,1555,899,571,1227,161,1473,817,489,1145, + 961,633,1289,18,1330,674,346,1658,1002,182,1494,838,510,1166,100,1412,756,428,1084,264,1576,920,592,1248,59,1371,715,387,1043,223,1535,879,551,1207,141,1453,797,469,1125,305,1617, + 1299,28,1340,684,356,1668,1012,192,1504,848,520,1176,110,1422,766,438,1094,274,1586,930,602,1258,69,1381,725,397,1053,233,1545,889,561,1217,151,1463,807,479,1135,315,1627,971,643, + 1320,664,336,1648,992,172,1484,828,500,1156,90,1402,746,418,1074,254,1566,910,582,1238,49,1361,705,377,1033,213,1525,869,541,1197,131,1443,787,459,1115,295,1607,951,623,1279,8, + 361,1673,1017,197,1509,853,525,1181,115,1427,771,443,1099,279,1591,935,607,1263,74,1386,730,402,1058,238,1550,894,566,1222,156,1468,812,484,1140,320,1632,976,648,1304,33,1345,689, + 997,177,1489,833,505,1161,95,1407,751,423,1079,259,1571,915,587,1243,54,1366,710,382,1038,218,1530,874,546,1202,136,1448,792,464,1120,300,1612,956,628,1284,13,1325,669,341,1653, + 1499,843,515,1171,105,1417,761,433,1089,269,1581,925,597,1253,64,1376,720,392,1048,228,1540,884,556,1212,146,1458,802,474,1130,310,1622,966,638,1294,23,1335,679,351,1663,1007,187, + 494,1150,84,1396,740,412,1068,248,1560,904,576,1232,43,1355,699,371,1027,207,1519,863,535,1191,125,1437,781,453,1109,289,1601,945,617,1273,660,1314,658,330,1642,986,166,1478,822, + 121,1433,777,449,1105,285,1597,941,613,1269,80,1392,736,408,1064,244,1556,900,572,1228,162,1474,818,490,1146,326,1638,982,654,1310,39,1351,695,367,1679,1023,203,1515,859,531,1187, + 757,429,1085,265,1577,921,593,1249,60,1372,716,388,1044,224,1536,880,552,1208,142,1454,798,470,1126,306,1618,962,634,1290,19,1331,675,347,1659,1003,183,1495,839,511,1167,101,1413, + 1095,275,1587,931,603,1259,70,1382,726,398,1054,234,1546,890,562,1218,152,1464,808,480,1136,316,1628,972,644,1300,29,1341,685,357,1669,1013,193,1505,849,521,1177,111,1423,767,439, + 1567,911,583,1239,50,1362,706,378,1034,214,1526,870,542,1198,132,1444,788,460,1116,296,1608,952,624,1280,9,1321,665,337,1649,993,173,1485,829,501,1157,91,1403,747,419,1075,255, + 608,1264,75,1387,731,403,1059,239,1551,895,567,1223,157,1469,813,485,1141,321,1633,977,649,1305,34,1346,690,362,1674,1018,198,1510,854,526,1182,116,1428,772,444,1100,280,1592,936, + 55,1367,711,383,1039,219,1531,875,547,1203,137,1449,793,465,1121,301,1613,957,629,1285,14,1326,670,342,1654,998,178,1490,834,506,1162,96,1408,752,424,1080,260,1572,916,588,1244, + 721,393,1049,229,1541,885,557,1213,147,1459,803,475,1131,311,1623,967,639,1295,24,1336,680,352,1664,1008,188,1500,844,516,1172,106,1418,762,434,1090,270,1582,926,598,1254,65,1377, + 1028,208,1520,864,536,1192,126,1438,782,454,1110,290,1602,946,618,1274,1271,1315,659,331,1643,987,167,1479,823,495,1151,85,1397,741,413,1069,249,1561,905,577,1233,44,1356,700,372, + 1553,897,569,1225,159,1471,815,487,1143,323,1635,979,651,1307,36,1348,692,364,1676,1020,200,1512,856,528,1184,118,1430,774,446,1102,282,1594,938,610,1266,77,1389,733,405,1061,241, + 549,1205,139,1451,795,467,1123,303,1615,959,631,1287,16,1328,672,344,1656,1000,180,1492,836,508,1164,98,1410,754,426,1082,262,1574,918,590,1246,57,1369,713,385,1041,221,1533,877, + 149,1461,805,477,1133,313,1625,969,641,1297,26,1338,682,354,1666,1010,190,1502,846,518,1174,108,1420,764,436,1092,272,1584,928,600,1256,67,1379,723,395,1051,231,1543,887,559,1215, + 785,457,1113,293,1605,949,621,1277,6,1318,662,334,1646,990,170,1482,826,498,1154,88,1400,744,416,1072,252,1564,908,580,1236,47,1359,703,375,1031,211,1523,867,539,1195,129,1441, + 1138,318,1630,974,646,1302,31,1343,687,359,1671,1015,195,1507,851,523,1179,113,1425,769,441,1097,277,1589,933,605,1261,72,1384,728,400,1056,236,1548,892,564,1220,154,1466,810,482, + 1610,954,626,1282,11,1323,667,339,1651,995,175,1487,831,503,1159,93,1405,749,421,1077,257,1569,913,585,1241,52,1364,708,380,1036,216,1528,872,544,1200,134,1446,790,462,1118,298, + 636,1292,21,1333,677,349,1661,1005,185,1497,841,513,1169,103,1415,759,431,1087,267,1579,923,595,1251,62,1374,718,390,1046,226,1538,882,554,1210,144,1456,800,472,1128,308,1620,964, + 0,1312,656,328,1640,984,164,1476,820,492,1148,82,1394,738,410,1066,246,1558,902,574,1230,41,1353,697,369,1025,205,1517,861,533,1189,123,1435,779,451,1107,287,1599,943,615,3 +}; + +int tableh19[] = { /* 43 x 43 data */ + 2,359,1735,1047,187,1563,875,531,1219,101,1477,789,445,1821,1133,273,1649,961,617,1305,58,1434,746,402,1778,1090,230,1606,918,574,1262,144,1520,832,488,1176,316,1692,1004,660,1348,15,1, + 1746,1058,198,1574,886,542,1230,112,1488,800,456,1832,1144,284,1660,972,628,1316,69,1445,757,413,1789,1101,241,1617,929,585,1273,155,1531,843,499,1187,327,1703,1015,671,1359,26,1402,714,370, + 176,1552,864,520,1208,90,1466,778,434,1810,1122,262,1638,950,606,1294,47,1423,735,391,1767,1079,219,1595,907,563,1251,133,1509,821,477,1165,305,1681,993,649,1337,4,1380,692,348,1724,1036, + 899,555,1243,125,1501,813,469,1845,1157,297,1673,985,641,1329,82,1458,770,426,1802,1114,254,1630,942,598,1286,168,1544,856,512,1200,340,1716,1028,684,1372,39,1415,727,383,1759,1071,211,1587, + 1222,104,1480,792,448,1824,1136,276,1652,964,620,1308,61,1437,749,405,1781,1093,233,1609,921,577,1265,147,1523,835,491,1179,319,1695,1007,663,1351,18,1394,706,362,1738,1050,190,1566,878,534, + 1491,803,459,1835,1147,287,1663,975,631,1319,72,1448,760,416,1792,1104,244,1620,932,588,1276,158,1534,846,502,1190,330,1706,1018,674,1362,29,1405,717,373,1749,1061,201,1577,889,545,1233,115, + 437,1813,1125,265,1641,953,609,1297,50,1426,738,394,1770,1082,222,1598,910,566,1254,136,1512,824,480,1168,308,1684,996,652,1340,7,1383,695,351,1727,1039,179,1555,867,523,1211,93,1469,781, + 1152,292,1668,980,636,1324,77,1453,765,421,1797,1109,249,1625,937,593,1281,163,1539,851,507,1195,335,1711,1023,679,1367,34,1410,722,378,1754,1066,206,1582,894,550,1238,120,1496,808,464,1840, + 1646,958,614,1302,55,1431,743,399,1775,1087,227,1603,915,571,1259,141,1517,829,485,1173,313,1689,1001,657,1345,12,1388,700,356,1732,1044,184,1560,872,528,1216,98,1474,786,442,1818,1130,270, + 625,1313,66,1442,754,410,1786,1098,238,1614,926,582,1270,152,1528,840,496,1184,324,1700,1012,668,1356,23,1399,711,367,1743,1055,195,1571,883,539,1227,109,1485,797,453,1829,1141,281,1657,969, + 44,1420,732,388,1764,1076,216,1592,904,560,1248,130,1506,818,474,1162,302,1678,990,646,1334,1391,1377,689,345,1721,1033,173,1549,861,517,1205,87,1463,775,431,1807,1119,259,1635,947,603,1291, + 773,429,1805,1117,257,1633,945,601,1289,171,1547,859,515,1203,343,1719,1031,687,1375,42,1418,730,386,1762,1074,214,1590,902,558,1246,128,1504,816,472,1848,1160,300,1676,988,644,1332,85,1461, + 1784,1096,236,1612,924,580,1268,150,1526,838,494,1182,322,1698,1010,666,1354,21,1397,709,365,1741,1053,193,1569,881,537,1225,107,1483,795,451,1827,1139,279,1655,967,623,1311,64,1440,752,408, + 247,1623,935,591,1279,161,1537,849,505,1193,333,1709,1021,677,1365,32,1408,720,376,1752,1064,204,1580,892,548,1236,118,1494,806,462,1838,1150,290,1666,978,634,1322,75,1451,763,419,1795,1107, + 913,569,1257,139,1515,827,483,1171,311,1687,999,655,1343,10,1386,698,354,1730,1042,182,1558,870,526,1214,96,1472,784,440,1816,1128,268,1644,956,612,1300,53,1429,741,397,1773,1085,225,1601, + 1284,166,1542,854,510,1198,338,1714,1026,682,1370,37,1413,725,381,1757,1069,209,1585,897,553,1241,123,1499,811,467,1843,1155,295,1671,983,639,1327,80,1456,768,424,1800,1112,252,1628,940,596, + 1521,833,489,1177,317,1693,1005,661,1349,16,1392,704,360,1736,1048,188,1564,876,532,1220,102,1478,790,446,1822,1134,274,1650,962,618,1306,59,1435,747,403,1779,1091,231,1607,919,575,1263,145, + 500,1188,328,1704,1016,672,1360,27,1403,715,371,1747,1059,199,1575,887,543,1231,113,1489,801,457,1833,1145,285,1661,973,629,1317,70,1446,758,414,1790,1102,242,1618,930,586,1274,156,1532,844, + 306,1682,994,650,1338,5,1381,693,349,1725,1037,177,1553,865,521,1209,91,1467,779,435,1811,1123,263,1639,951,607,1295,48,1424,736,392,1768,1080,220,1596,908,564,1252,134,1510,822,478,1166, + 1029,685,1373,40,1416,728,384,1760,1072,212,1588,900,556,1244,126,1502,814,470,1846,1158,298,1674,986,642,1330,83,1459,771,427,1803,1115,255,1631,943,599,1287,169,1545,857,513,1201,341,1717, + 1352,19,1395,707,363,1739,1051,191,1567,879,535,1223,105,1481,793,449,1825,1137,277,1653,965,621,1309,62,1438,750,406,1782,1094,234,1610,922,578,1266,148,1524,836,492,1180,320,1696,1008,664, + 1406,718,374,1750,1062,202,1578,890,546,1234,116,1492,804,460,1836,1148,288,1664,976,632,1320,73,1449,761,417,1793,1105,245,1621,933,589,1277,159,1535,847,503,1191,331,1707,1019,675,1363,30, + 352,1728,1040,180,1556,868,524,1212,94,1470,782,438,1814,1126,266,1642,954,610,1298,51,1427,739,395,1771,1083,223,1599,911,567,1255,137,1513,825,481,1169,309,1685,997,653,1341,8,1384,696, + 1067,207,1583,895,551,1239,121,1497,809,465,1841,1153,293,1669,981,637,1325,78,1454,766,422,1798,1110,250,1626,938,594,1282,164,1540,852,508,1196,336,1712,1024,680,1368,35,1411,723,379,1755, + 1561,873,529,1217,99,1475,787,443,1819,1131,271,1647,959,615,1303,56,1432,744,400,1776,1088,228,1604,916,572,1260,142,1518,830,486,1174,314,1690,1002,658,1346,13,1389,701,357,1733,1045,185, + 540,1228,110,1486,798,454,1830,1142,282,1658,970,626,1314,67,1443,755,411,1787,1099,239,1615,927,583,1271,153,1529,841,497,1185,325,1701,1013,669,1357,24,1400,712,368,1744,1056,196,1572,884, + 88,1464,776,432,1808,1120,260,1636,948,604,1292,45,1421,733,389,1765,1077,217,1593,905,561,1249,131,1507,819,475,1163,303,1679,991,647,1335,703,1378,690,346,1722,1034,174,1550,862,518,1206, + 815,471,1847,1159,299,1675,987,643,1331,84,1460,772,428,1804,1116,256,1632,944,600,1288,170,1546,858,514,1202,342,1718,1030,686,1374,41,1417,729,385,1761,1073,213,1589,901,557,1245,127,1503, + 1826,1138,278,1654,966,622,1310,63,1439,751,407,1783,1095,235,1611,923,579,1267,149,1525,837,493,1181,321,1697,1009,665,1353,20,1396,708,364,1740,1052,192,1568,880,536,1224,106,1482,794,450, + 289,1665,977,633,1321,74,1450,762,418,1794,1106,246,1622,934,590,1278,160,1536,848,504,1192,332,1708,1020,676,1364,31,1407,719,375,1751,1063,203,1579,891,547,1235,117,1493,805,461,1837,1149, + 955,611,1299,52,1428,740,396,1772,1084,224,1600,912,568,1256,138,1514,826,482,1170,310,1686,998,654,1342,9,1385,697,353,1729,1041,181,1557,869,525,1213,95,1471,783,439,1815,1127,267,1643, + 1326,79,1455,767,423,1799,1111,251,1627,939,595,1283,165,1541,853,509,1197,337,1713,1025,681,1369,36,1412,724,380,1756,1068,208,1584,896,552,1240,122,1498,810,466,1842,1154,294,1670,982,638, + 1433,745,401,1777,1089,229,1605,917,573,1261,143,1519,831,487,1175,315,1691,1003,659,1347,14,1390,702,358,1734,1046,186,1562,874,530,1218,100,1476,788,444,1820,1132,272,1648,960,616,1304,57, + 412,1788,1100,240,1616,928,584,1272,154,1530,842,498,1186,326,1702,1014,670,1358,25,1401,713,369,1745,1057,197,1573,885,541,1229,111,1487,799,455,1831,1143,283,1659,971,627,1315,68,1444,756, + 1078,218,1594,906,562,1250,132,1508,820,476,1164,304,1680,992,648,1336,1333,1379,691,347,1723,1035,175,1551,863,519,1207,89,1465,777,433,1809,1121,261,1637,949,605,1293,46,1422,734,390,1766, + 1629,941,597,1285,167,1543,855,511,1199,339,1715,1027,683,1371,38,1414,726,382,1758,1070,210,1586,898,554,1242,124,1500,812,468,1844,1156,296,1672,984,640,1328,81,1457,769,425,1801,1113,253, + 576,1264,146,1522,834,490,1178,318,1694,1006,662,1350,17,1393,705,361,1737,1049,189,1565,877,533,1221,103,1479,791,447,1823,1135,275,1651,963,619,1307,60,1436,748,404,1780,1092,232,1608,920, + 157,1533,845,501,1189,329,1705,1017,673,1361,28,1404,716,372,1748,1060,200,1576,888,544,1232,114,1490,802,458,1834,1146,286,1662,974,630,1318,71,1447,759,415,1791,1103,243,1619,931,587,1275, + 823,479,1167,307,1683,995,651,1339,6,1382,694,350,1726,1038,178,1554,866,522,1210,92,1468,780,436,1812,1124,264,1640,952,608,1296,49,1425,737,393,1769,1081,221,1597,909,565,1253,135,1511, + 1194,334,1710,1022,678,1366,33,1409,721,377,1753,1065,205,1581,893,549,1237,119,1495,807,463,1839,1151,291,1667,979,635,1323,76,1452,764,420,1796,1108,248,1624,936,592,1280,162,1538,850,506, + 1688,1000,656,1344,11,1387,699,355,1731,1043,183,1559,871,527,1215,97,1473,785,441,1817,1129,269,1645,957,613,1301,54,1430,742,398,1774,1086,226,1602,914,570,1258,140,1516,828,484,1172,312, + 667,1355,22,1398,710,366,1742,1054,194,1570,882,538,1226,108,1484,796,452,1828,1140,280,1656,968,624,1312,65,1441,753,409,1785,1097,237,1613,925,581,1269,151,1527,839,495,1183,323,1699,1011, + 0,1376,688,344,1720,1032,172,1548,860,516,1204,86,1462,774,430,1806,1118,258,1634,946,602,1290,43,1419,731,387,1763,1075,215,1591,903,559,1247,129,1505,817,473,1161,301,1677,989,645,3 +}; + +int tableh20[] = { /* 45 x 45 data */ + 2,370,1810,1090,190,1630,910,550,1990,1270,100,1540,820,460,1900,1180,280,1720,1000,640,1360,55,1495,775,415,1855,1135,235,1675,955,595,1315,145,1585,865,505,1945,1225,325,1765,1045,685,1405,10,1, + 1838,1118,218,1658,938,578,2018,1298,128,1568,848,488,1928,1208,308,1748,1028,668,1388,83,1523,803,443,1883,1163,263,1703,983,623,1343,173,1613,893,533,1973,1253,353,1793,1073,713,1433,38,1478,758,398, + 196,1636,916,556,1996,1276,106,1546,826,466,1906,1186,286,1726,1006,646,1366,61,1501,781,421,1861,1141,241,1681,961,601,1321,151,1591,871,511,1951,1231,331,1771,1051,691,1411,16,1456,736,376,1816,1096, + 927,567,2007,1287,117,1557,837,477,1917,1197,297,1737,1017,657,1377,72,1512,792,432,1872,1152,252,1692,972,612,1332,162,1602,882,522,1962,1242,342,1782,1062,702,1422,27,1467,747,387,1827,1107,207,1647, + 1984,1264,94,1534,814,454,1894,1174,274,1714,994,634,1354,49,1489,769,409,1849,1129,229,1669,949,589,1309,139,1579,859,499,1939,1219,319,1759,1039,679,1399,4,1444,724,364,1804,1084,184,1624,904,544, + 131,1571,851,491,1931,1211,311,1751,1031,671,1391,86,1526,806,446,1886,1166,266,1706,986,626,1346,176,1616,896,536,1976,1256,356,1796,1076,716,1436,41,1481,761,401,1841,1121,221,1661,941,581,2021,1301, + 829,469,1909,1189,289,1729,1009,649,1369,64,1504,784,424,1864,1144,244,1684,964,604,1324,154,1594,874,514,1954,1234,334,1774,1054,694,1414,19,1459,739,379,1819,1099,199,1639,919,559,1999,1279,109,1549, + 1920,1200,300,1740,1020,660,1380,75,1515,795,435,1875,1155,255,1695,975,615,1335,165,1605,885,525,1965,1245,345,1785,1065,705,1425,30,1470,750,390,1830,1110,210,1650,930,570,2010,1290,120,1560,840,480, + 277,1717,997,637,1357,52,1492,772,412,1852,1132,232,1672,952,592,1312,142,1582,862,502,1942,1222,322,1762,1042,682,1402,7,1447,727,367,1807,1087,187,1627,907,547,1987,1267,97,1537,817,457,1897,1177, + 1025,665,1385,80,1520,800,440,1880,1160,260,1700,980,620,1340,170,1610,890,530,1970,1250,350,1790,1070,710,1430,35,1475,755,395,1835,1115,215,1655,935,575,2015,1295,125,1565,845,485,1925,1205,305,1745, + 1363,58,1498,778,418,1858,1138,238,1678,958,598,1318,148,1588,868,508,1948,1228,328,1768,1048,688,1408,13,1453,733,373,1813,1093,193,1633,913,553,1993,1273,103,1543,823,463,1903,1183,283,1723,1003,643, + 1509,789,429,1869,1149,249,1689,969,609,1329,159,1599,879,519,1959,1239,339,1779,1059,699,1419,24,1464,744,384,1824,1104,204,1644,924,564,2004,1284,114,1554,834,474,1914,1194,294,1734,1014,654,1374,69, + 406,1846,1126,226,1666,946,586,1306,136,1576,856,496,1936,1216,316,1756,1036,676,1396,1450,1441,721,361,1801,1081,181,1621,901,541,1981,1261,91,1531,811,451,1891,1171,271,1711,991,631,1351,46,1486,766, + 1169,269,1709,989,629,1349,179,1619,899,539,1979,1259,359,1799,1079,719,1439,44,1484,764,404,1844,1124,224,1664,944,584,2024,1304,134,1574,854,494,1934,1214,314,1754,1034,674,1394,89,1529,809,449,1889, + 1687,967,607,1327,157,1597,877,517,1957,1237,337,1777,1057,697,1417,22,1462,742,382,1822,1102,202,1642,922,562,2002,1282,112,1552,832,472,1912,1192,292,1732,1012,652,1372,67,1507,787,427,1867,1147,247, + 618,1338,168,1608,888,528,1968,1248,348,1788,1068,708,1428,33,1473,753,393,1833,1113,213,1653,933,573,2013,1293,123,1563,843,483,1923,1203,303,1743,1023,663,1383,78,1518,798,438,1878,1158,258,1698,978, + 146,1586,866,506,1946,1226,326,1766,1046,686,1406,11,1451,731,371,1811,1091,191,1631,911,551,1991,1271,101,1541,821,461,1901,1181,281,1721,1001,641,1361,56,1496,776,416,1856,1136,236,1676,956,596,1316, + 894,534,1974,1254,354,1794,1074,714,1434,39,1479,759,399,1839,1119,219,1659,939,579,2019,1299,129,1569,849,489,1929,1209,309,1749,1029,669,1389,84,1524,804,444,1884,1164,264,1704,984,624,1344,174,1614, + 1952,1232,332,1772,1052,692,1412,17,1457,737,377,1817,1097,197,1637,917,557,1997,1277,107,1547,827,467,1907,1187,287,1727,1007,647,1367,62,1502,782,422,1862,1142,242,1682,962,602,1322,152,1592,872,512, + 343,1783,1063,703,1423,28,1468,748,388,1828,1108,208,1648,928,568,2008,1288,118,1558,838,478,1918,1198,298,1738,1018,658,1378,73,1513,793,433,1873,1153,253,1693,973,613,1333,163,1603,883,523,1963,1243, + 1040,680,1400,5,1445,725,365,1805,1085,185,1625,905,545,1985,1265,95,1535,815,455,1895,1175,275,1715,995,635,1355,50,1490,770,410,1850,1130,230,1670,950,590,1310,140,1580,860,500,1940,1220,320,1760, + 1437,42,1482,762,402,1842,1122,222,1662,942,582,2022,1302,132,1572,852,492,1932,1212,312,1752,1032,672,1392,87,1527,807,447,1887,1167,267,1707,987,627,1347,177,1617,897,537,1977,1257,357,1797,1077,717, + 1460,740,380,1820,1100,200,1640,920,560,2000,1280,110,1550,830,470,1910,1190,290,1730,1010,650,1370,65,1505,785,425,1865,1145,245,1685,965,605,1325,155,1595,875,515,1955,1235,335,1775,1055,695,1415,20, + 391,1831,1111,211,1651,931,571,2011,1291,121,1561,841,481,1921,1201,301,1741,1021,661,1381,76,1516,796,436,1876,1156,256,1696,976,616,1336,166,1606,886,526,1966,1246,346,1786,1066,706,1426,31,1471,751, + 1088,188,1628,908,548,1988,1268,98,1538,818,458,1898,1178,278,1718,998,638,1358,53,1493,773,413,1853,1133,233,1673,953,593,1313,143,1583,863,503,1943,1223,323,1763,1043,683,1403,8,1448,728,368,1808, + 1656,936,576,2016,1296,126,1566,846,486,1926,1206,306,1746,1026,666,1386,81,1521,801,441,1881,1161,261,1701,981,621,1341,171,1611,891,531,1971,1251,351,1791,1071,711,1431,36,1476,756,396,1836,1116,216, + 554,1994,1274,104,1544,824,464,1904,1184,284,1724,1004,644,1364,59,1499,779,419,1859,1139,239,1679,959,599,1319,149,1589,869,509,1949,1229,329,1769,1049,689,1409,14,1454,734,374,1814,1094,194,1634,914, + 1285,115,1555,835,475,1915,1195,295,1735,1015,655,1375,70,1510,790,430,1870,1150,250,1690,970,610,1330,160,1600,880,520,1960,1240,340,1780,1060,700,1420,25,1465,745,385,1825,1105,205,1645,925,565,2005, + 1532,812,452,1892,1172,272,1712,992,632,1352,47,1487,767,407,1847,1127,227,1667,947,587,1307,137,1577,857,497,1937,1217,317,1757,1037,677,1397,730,1442,722,362,1802,1082,182,1622,902,542,1982,1262,92, + 493,1933,1213,313,1753,1033,673,1393,88,1528,808,448,1888,1168,268,1708,988,628,1348,178,1618,898,538,1978,1258,358,1798,1078,718,1438,43,1483,763,403,1843,1123,223,1663,943,583,2023,1303,133,1573,853, + 1191,291,1731,1011,651,1371,66,1506,786,426,1866,1146,246,1686,966,606,1326,156,1596,876,516,1956,1236,336,1776,1056,696,1416,21,1461,741,381,1821,1101,201,1641,921,561,2001,1281,111,1551,831,471,1911, + 1742,1022,662,1382,77,1517,797,437,1877,1157,257,1697,977,617,1337,167,1607,887,527,1967,1247,347,1787,1067,707,1427,32,1472,752,392,1832,1112,212,1652,932,572,2012,1292,122,1562,842,482,1922,1202,302, + 639,1359,54,1494,774,414,1854,1134,234,1674,954,594,1314,144,1584,864,504,1944,1224,324,1764,1044,684,1404,9,1449,729,369,1809,1089,189,1629,909,549,1989,1269,99,1539,819,459,1899,1179,279,1719,999, + 82,1522,802,442,1882,1162,262,1702,982,622,1342,172,1612,892,532,1972,1252,352,1792,1072,712,1432,37,1477,757,397,1837,1117,217,1657,937,577,2017,1297,127,1567,847,487,1927,1207,307,1747,1027,667,1387, + 780,420,1860,1140,240,1680,960,600,1320,150,1590,870,510,1950,1230,330,1770,1050,690,1410,15,1455,735,375,1815,1095,195,1635,915,555,1995,1275,105,1545,825,465,1905,1185,285,1725,1005,645,1365,60,1500, + 1871,1151,251,1691,971,611,1331,161,1601,881,521,1961,1241,341,1781,1061,701,1421,26,1466,746,386,1826,1106,206,1646,926,566,2006,1286,116,1556,836,476,1916,1196,296,1736,1016,656,1376,71,1511,791,431, + 228,1668,948,588,1308,138,1578,858,498,1938,1218,318,1758,1038,678,1398,1395,1443,723,363,1803,1083,183,1623,903,543,1983,1263,93,1533,813,453,1893,1173,273,1713,993,633,1353,48,1488,768,408,1848,1128, + 985,625,1345,175,1615,895,535,1975,1255,355,1795,1075,715,1435,40,1480,760,400,1840,1120,220,1660,940,580,2020,1300,130,1570,850,490,1930,1210,310,1750,1030,670,1390,85,1525,805,445,1885,1165,265,1705, + 1323,153,1593,873,513,1953,1233,333,1773,1053,693,1413,18,1458,738,378,1818,1098,198,1638,918,558,1998,1278,108,1548,828,468,1908,1188,288,1728,1008,648,1368,63,1503,783,423,1863,1143,243,1683,963,603, + 1604,884,524,1964,1244,344,1784,1064,704,1424,29,1469,749,389,1829,1109,209,1649,929,569,2009,1289,119,1559,839,479,1919,1199,299,1739,1019,659,1379,74,1514,794,434,1874,1154,254,1694,974,614,1334,164, + 501,1941,1221,321,1761,1041,681,1401,6,1446,726,366,1806,1086,186,1626,906,546,1986,1266,96,1536,816,456,1896,1176,276,1716,996,636,1356,51,1491,771,411,1851,1131,231,1671,951,591,1311,141,1581,861, + 1249,349,1789,1069,709,1429,34,1474,754,394,1834,1114,214,1654,934,574,2014,1294,124,1564,844,484,1924,1204,304,1744,1024,664,1384,79,1519,799,439,1879,1159,259,1699,979,619,1339,169,1609,889,529,1969, + 1767,1047,687,1407,12,1452,732,372,1812,1092,192,1632,912,552,1992,1272,102,1542,822,462,1902,1182,282,1722,1002,642,1362,57,1497,777,417,1857,1137,237,1677,957,597,1317,147,1587,867,507,1947,1227,327, + 698,1418,23,1463,743,383,1823,1103,203,1643,923,563,2003,1283,113,1553,833,473,1913,1193,293,1733,1013,653,1373,68,1508,788,428,1868,1148,248,1688,968,608,1328,158,1598,878,518,1958,1238,338,1778,1058, + 0,1440,720,360,1800,1080,180,1620,900,540,1980,1260,90,1530,810,450,1890,1170,270,1710,990,630,1350,45,1485,765,405,1845,1125,225,1665,945,585,1305,135,1575,855,495,1935,1215,315,1755,1035,675,3 +}; + +int tableh21[] = { /* 47 x 47 data */ + 2,398,1902,1150,210,1714,962,586,2090,1338,116,1620,868,492,1996,1244,304,1808,1056,680,2184,1432,69,1573,821,445,1949,1197,257,1761,1009,633,2137,1385,163,1667,915,539,2043,1291,351,1855,1103,727,1479,22,1, + 1914,1162,222,1726,974,598,2102,1350,128,1632,880,504,2008,1256,316,1820,1068,692,2196,1444,81,1585,833,457,1961,1209,269,1773,1021,645,2149,1397,175,1679,927,551,2055,1303,363,1867,1115,739,1491,34,1538,786,410, + 198,1702,950,574,2078,1326,104,1608,856,480,1984,1232,292,1796,1044,668,2172,1420,57,1561,809,433,1937,1185,245,1749,997,621,2125,1373,151,1655,903,527,2031,1279,339,1843,1091,715,1467,10,1514,762,386,1890,1138, + 980,604,2108,1356,134,1638,886,510,2014,1262,322,1826,1074,698,2202,1450,87,1591,839,463,1967,1215,275,1779,1027,651,2155,1403,181,1685,933,557,2061,1309,369,1873,1121,745,1497,40,1544,792,416,1920,1168,228,1732, + 2084,1332,110,1614,862,486,1990,1238,298,1802,1050,674,2178,1426,63,1567,815,439,1943,1191,251,1755,1003,627,2131,1379,157,1661,909,533,2037,1285,345,1849,1097,721,1473,16,1520,768,392,1896,1144,204,1708,956,580, + 122,1626,874,498,2002,1250,310,1814,1062,686,2190,1438,75,1579,827,451,1955,1203,263,1767,1015,639,2143,1391,169,1673,921,545,2049,1297,357,1861,1109,733,1485,28,1532,780,404,1908,1156,216,1720,968,592,2096,1344, + 850,474,1978,1226,286,1790,1038,662,2166,1414,51,1555,803,427,1931,1179,239,1743,991,615,2119,1367,145,1649,897,521,2025,1273,333,1837,1085,709,1461,4,1508,756,380,1884,1132,192,1696,944,568,2072,1320,98,1602, + 2017,1265,325,1829,1077,701,2205,1453,90,1594,842,466,1970,1218,278,1782,1030,654,2158,1406,184,1688,936,560,2064,1312,372,1876,1124,748,1500,43,1547,795,419,1923,1171,231,1735,983,607,2111,1359,137,1641,889,513, + 301,1805,1053,677,2181,1429,66,1570,818,442,1946,1194,254,1758,1006,630,2134,1382,160,1664,912,536,2040,1288,348,1852,1100,724,1476,19,1523,771,395,1899,1147,207,1711,959,583,2087,1335,113,1617,865,489,1993,1241, + 1065,689,2193,1441,78,1582,830,454,1958,1206,266,1770,1018,642,2146,1394,172,1676,924,548,2052,1300,360,1864,1112,736,1488,31,1535,783,407,1911,1159,219,1723,971,595,2099,1347,125,1629,877,501,2005,1253,313,1817, + 2169,1417,54,1558,806,430,1934,1182,242,1746,994,618,2122,1370,148,1652,900,524,2028,1276,336,1840,1088,712,1464,7,1511,759,383,1887,1135,195,1699,947,571,2075,1323,101,1605,853,477,1981,1229,289,1793,1041,665, + 84,1588,836,460,1964,1212,272,1776,1024,648,2152,1400,178,1682,930,554,2058,1306,366,1870,1118,742,1494,37,1541,789,413,1917,1165,225,1729,977,601,2105,1353,131,1635,883,507,2011,1259,319,1823,1071,695,2199,1447, + 812,436,1940,1188,248,1752,1000,624,2128,1376,154,1658,906,530,2034,1282,342,1846,1094,718,1470,13,1517,765,389,1893,1141,201,1705,953,577,2081,1329,107,1611,859,483,1987,1235,295,1799,1047,671,2175,1423,60,1564, + 1952,1200,260,1764,1012,636,2140,1388,166,1670,918,542,2046,1294,354,1858,1106,730,1482,25,1529,777,401,1905,1153,213,1717,965,589,2093,1341,119,1623,871,495,1999,1247,307,1811,1059,683,2187,1435,72,1576,824,448, + 236,1740,988,612,2116,1364,142,1646,894,518,2022,1270,330,1834,1082,706,1458,1526,1505,753,377,1881,1129,189,1693,941,565,2069,1317,95,1599,847,471,1975,1223,283,1787,1035,659,2163,1411,48,1552,800,424,1928,1176, + 1033,657,2161,1409,187,1691,939,563,2067,1315,375,1879,1127,751,1503,46,1550,798,422,1926,1174,234,1738,986,610,2114,1362,140,1644,892,516,2020,1268,328,1832,1080,704,2208,1456,93,1597,845,469,1973,1221,281,1785, + 2138,1386,164,1668,916,540,2044,1292,352,1856,1104,728,1480,23,1527,775,399,1903,1151,211,1715,963,587,2091,1339,117,1621,869,493,1997,1245,305,1809,1057,681,2185,1433,70,1574,822,446,1950,1198,258,1762,1010,634, + 176,1680,928,552,2056,1304,364,1868,1116,740,1492,35,1539,787,411,1915,1163,223,1727,975,599,2103,1351,129,1633,881,505,2009,1257,317,1821,1069,693,2197,1445,82,1586,834,458,1962,1210,270,1774,1022,646,2150,1398, + 904,528,2032,1280,340,1844,1092,716,1468,11,1515,763,387,1891,1139,199,1703,951,575,2079,1327,105,1609,857,481,1985,1233,293,1797,1045,669,2173,1421,58,1562,810,434,1938,1186,246,1750,998,622,2126,1374,152,1656, + 2062,1310,370,1874,1122,746,1498,41,1545,793,417,1921,1169,229,1733,981,605,2109,1357,135,1639,887,511,2015,1263,323,1827,1075,699,2203,1451,88,1592,840,464,1968,1216,276,1780,1028,652,2156,1404,182,1686,934,558, + 346,1850,1098,722,1474,17,1521,769,393,1897,1145,205,1709,957,581,2085,1333,111,1615,863,487,1991,1239,299,1803,1051,675,2179,1427,64,1568,816,440,1944,1192,252,1756,1004,628,2132,1380,158,1662,910,534,2038,1286, + 1110,734,1486,29,1533,781,405,1909,1157,217,1721,969,593,2097,1345,123,1627,875,499,2003,1251,311,1815,1063,687,2191,1439,76,1580,828,452,1956,1204,264,1768,1016,640,2144,1392,170,1674,922,546,2050,1298,358,1862, + 1462,5,1509,757,381,1885,1133,193,1697,945,569,2073,1321,99,1603,851,475,1979,1227,287,1791,1039,663,2167,1415,52,1556,804,428,1932,1180,240,1744,992,616,2120,1368,146,1650,898,522,2026,1274,334,1838,1086,710, + 1548,796,420,1924,1172,232,1736,984,608,2112,1360,138,1642,890,514,2018,1266,326,1830,1078,702,2206,1454,91,1595,843,467,1971,1219,279,1783,1031,655,2159,1407,185,1689,937,561,2065,1313,373,1877,1125,749,1501,44, + 396,1900,1148,208,1712,960,584,2088,1336,114,1618,866,490,1994,1242,302,1806,1054,678,2182,1430,67,1571,819,443,1947,1195,255,1759,1007,631,2135,1383,161,1665,913,537,2041,1289,349,1853,1101,725,1477,20,1524,772, + 1160,220,1724,972,596,2100,1348,126,1630,878,502,2006,1254,314,1818,1066,690,2194,1442,79,1583,831,455,1959,1207,267,1771,1019,643,2147,1395,173,1677,925,549,2053,1301,361,1865,1113,737,1489,32,1536,784,408,1912, + 1700,948,572,2076,1324,102,1606,854,478,1982,1230,290,1794,1042,666,2170,1418,55,1559,807,431,1935,1183,243,1747,995,619,2123,1371,149,1653,901,525,2029,1277,337,1841,1089,713,1465,8,1512,760,384,1888,1136,196, + 602,2106,1354,132,1636,884,508,2012,1260,320,1824,1072,696,2200,1448,85,1589,837,461,1965,1213,273,1777,1025,649,2153,1401,179,1683,931,555,2059,1307,367,1871,1119,743,1495,38,1542,790,414,1918,1166,226,1730,978, + 1330,108,1612,860,484,1988,1236,296,1800,1048,672,2176,1424,61,1565,813,437,1941,1189,249,1753,1001,625,2129,1377,155,1659,907,531,2035,1283,343,1847,1095,719,1471,14,1518,766,390,1894,1142,202,1706,954,578,2082, + 1624,872,496,2000,1248,308,1812,1060,684,2188,1436,73,1577,825,449,1953,1201,261,1765,1013,637,2141,1389,167,1671,919,543,2047,1295,355,1859,1107,731,1483,26,1530,778,402,1906,1154,214,1718,966,590,2094,1342,120, + 472,1976,1224,284,1788,1036,660,2164,1412,49,1553,801,425,1929,1177,237,1741,989,613,2117,1365,143,1647,895,519,2023,1271,331,1835,1083,707,1459,774,1506,754,378,1882,1130,190,1694,942,566,2070,1318,96,1600,848, + 1267,327,1831,1079,703,2207,1455,92,1596,844,468,1972,1220,280,1784,1032,656,2160,1408,186,1690,938,562,2066,1314,374,1878,1126,750,1502,45,1549,797,421,1925,1173,233,1737,985,609,2113,1361,139,1643,891,515,2019, + 1807,1055,679,2183,1431,68,1572,820,444,1948,1196,256,1760,1008,632,2136,1384,162,1666,914,538,2042,1290,350,1854,1102,726,1478,21,1525,773,397,1901,1149,209,1713,961,585,2089,1337,115,1619,867,491,1995,1243,303, + 691,2195,1443,80,1584,832,456,1960,1208,268,1772,1020,644,2148,1396,174,1678,926,550,2054,1302,362,1866,1114,738,1490,33,1537,785,409,1913,1161,221,1725,973,597,2101,1349,127,1631,879,503,2007,1255,315,1819,1067, + 1419,56,1560,808,432,1936,1184,244,1748,996,620,2124,1372,150,1654,902,526,2030,1278,338,1842,1090,714,1466,9,1513,761,385,1889,1137,197,1701,949,573,2077,1325,103,1607,855,479,1983,1231,291,1795,1043,667,2171, + 1590,838,462,1966,1214,274,1778,1026,650,2154,1402,180,1684,932,556,2060,1308,368,1872,1120,744,1496,39,1543,791,415,1919,1167,227,1731,979,603,2107,1355,133,1637,885,509,2013,1261,321,1825,1073,697,2201,1449,86, + 438,1942,1190,250,1754,1002,626,2130,1378,156,1660,908,532,2036,1284,344,1848,1096,720,1472,15,1519,767,391,1895,1143,203,1707,955,579,2083,1331,109,1613,861,485,1989,1237,297,1801,1049,673,2177,1425,62,1566,814, + 1202,262,1766,1014,638,2142,1390,168,1672,920,544,2048,1296,356,1860,1108,732,1484,27,1531,779,403,1907,1155,215,1719,967,591,2095,1343,121,1625,873,497,2001,1249,309,1813,1061,685,2189,1437,74,1578,826,450,1954, + 1742,990,614,2118,1366,144,1648,896,520,2024,1272,332,1836,1084,708,1460,1457,1507,755,379,1883,1131,191,1695,943,567,2071,1319,97,1601,849,473,1977,1225,285,1789,1037,661,2165,1413,50,1554,802,426,1930,1178,238, + 653,2157,1405,183,1687,935,559,2063,1311,371,1875,1123,747,1499,42,1546,794,418,1922,1170,230,1734,982,606,2110,1358,136,1640,888,512,2016,1264,324,1828,1076,700,2204,1452,89,1593,841,465,1969,1217,277,1781,1029, + 1381,159,1663,911,535,2039,1287,347,1851,1099,723,1475,18,1522,770,394,1898,1146,206,1710,958,582,2086,1334,112,1616,864,488,1992,1240,300,1804,1052,676,2180,1428,65,1569,817,441,1945,1193,253,1757,1005,629,2133, + 1675,923,547,2051,1299,359,1863,1111,735,1487,30,1534,782,406,1910,1158,218,1722,970,594,2098,1346,124,1628,876,500,2004,1252,312,1816,1064,688,2192,1440,77,1581,829,453,1957,1205,265,1769,1017,641,2145,1393,171, + 523,2027,1275,335,1839,1087,711,1463,6,1510,758,382,1886,1134,194,1698,946,570,2074,1322,100,1604,852,476,1980,1228,288,1792,1040,664,2168,1416,53,1557,805,429,1933,1181,241,1745,993,617,2121,1369,147,1651,899, + 1305,365,1869,1117,741,1493,36,1540,788,412,1916,1164,224,1728,976,600,2104,1352,130,1634,882,506,2010,1258,318,1822,1070,694,2198,1446,83,1587,835,459,1963,1211,271,1775,1023,647,2151,1399,177,1681,929,553,2057, + 1845,1093,717,1469,12,1516,764,388,1892,1140,200,1704,952,576,2080,1328,106,1610,858,482,1986,1234,294,1798,1046,670,2174,1422,59,1563,811,435,1939,1187,247,1751,999,623,2127,1375,153,1657,905,529,2033,1281,341, + 729,1481,24,1528,776,400,1904,1152,212,1716,964,588,2092,1340,118,1622,870,494,1998,1246,306,1810,1058,682,2186,1434,71,1575,823,447,1951,1199,259,1763,1011,635,2139,1387,165,1669,917,541,2045,1293,353,1857,1105, + 0,1504,752,376,1880,1128,188,1692,940,564,2068,1316,94,1598,846,470,1974,1222,282,1786,1034,658,2162,1410,47,1551,799,423,1927,1175,235,1739,987,611,2115,1363,141,1645,893,517,2021,1269,329,1833,1081,705,3 +}; + +int MatrixMaxCapacities[21] = { 49, 81, 121, 169, 225, 289, 361, 441, 529, 625, 729, 841, 961, 1089, 1225, 1369, 1521, 1681, 1849, 2025, 2209 }; + +int MasterRandomStream[] = { /* From Annex L */ + 0x05,0xff,0xc7,0x31,0x88,0xa8,0x83,0x9c,0x64,0x87,0x9f,0x64,0xb3,0xe0,0x4d,0x9c,0x80,0x29,0x3a,0x90, + 0xb3,0x8b,0x9e,0x90,0x45,0xbf,0xf5,0x68,0x4b,0x08,0xcf,0x44,0xb8,0xd4,0x4c,0x5b,0xa0,0xab,0x72,0x52, + 0x1c,0xe4,0xd2,0x74,0xa4,0xda,0x8a,0x08,0xfa,0xa7,0xc7,0xdd,0x00,0x30,0xa9,0xe6,0x64,0xab,0xd5,0x8b, + 0xed,0x9c,0x79,0xf8,0x08,0xd1,0x8b,0xc6,0x22,0x64,0x0b,0x33,0x43,0xd0,0x80,0xd4,0x44,0x95,0x2e,0x6f, + 0x5e,0x13,0x8d,0x47,0x62,0x06,0xeb,0x80,0x82,0xc9,0x41,0xd5,0x73,0x8a,0x30,0x23,0x24,0xe3,0x7f,0xb2, + 0xa8,0x0b,0xed,0x38,0x42,0x4c,0xd7,0xb0,0xce,0x98,0xbd,0xe1,0xd5,0xe4,0xc3,0x1d,0x15,0x4a,0xcf,0xd1, + 0x1f,0x39,0x26,0x18,0x93,0xfc,0x19,0xb2,0x2d,0xab,0xf2,0x6e,0xa1,0x9f,0xaf,0xd0,0x8a,0x2b,0xa0,0x56, + 0xb0,0x41,0x6d,0x43,0xa4,0x63,0xf3,0xaa,0x7d,0xaf,0x35,0x57,0xc2,0x94,0x4a,0x65,0x0b,0x41,0xde,0xb8, + 0xe2,0x30,0x12,0x27,0x9b,0x66,0x2b,0x34,0x5b,0xb8,0x99,0xe8,0x28,0x71,0xd0,0x95,0x6b,0x07,0x4d,0x3c, + 0x7a,0xb3,0xe5,0x29,0xb3,0xba,0x8c,0xcc,0x2d,0xe0,0xc9,0xc0,0x22,0xec,0x4c,0xde,0xf8,0x58,0x07,0xfc, + 0x19,0xf2,0x64,0xe2,0xc3,0xe2,0xd8,0xb9,0xfd,0x67,0xa0,0xbc,0xf5,0x2e,0xc9,0x49,0x75,0x62,0x82,0x27, + 0x10,0xf4,0x19,0x6f,0x49,0xf7,0xb3,0x84,0x14,0xea,0xeb,0xe1,0x2a,0x31,0xab,0x47,0x7d,0x08,0x29,0xac, + 0xbb,0x72,0xfa,0xfa,0x62,0xb8,0xc8,0xd3,0x86,0x89,0x95,0xfd,0xdf,0xcc,0x9c,0xad,0xf1,0xd4,0x6c,0x64, + 0x23,0x24,0x2a,0x56,0x1f,0x36,0xeb,0xb7,0xd6,0xff,0xda,0x57,0xf4,0x50,0x79,0x08,0x00 +}; \ No newline at end of file diff --git a/backend/library.c b/backend/library.c index c384d17c..f52753e7 100644 --- a/backend/library.c +++ b/backend/library.c @@ -109,6 +109,7 @@ extern int codablock(struct zint_symbol *symbol, unsigned char source[]); /* Cod extern int daft_code(struct zint_symbol *symbol, unsigned char source[]); /* DAFT Code */ extern int ean_14(struct zint_symbol *symbol, unsigned char source[]); /* EAN-14 */ extern int nve_18(struct zint_symbol *symbol, unsigned char source[]); /* NVE-18 */ +extern int microqr(struct zint_symbol *symbol, unsigned char source[]); /* Micro QR Code */ #ifndef NO_PNG int png_handle(struct zint_symbol *symbol, int rotate_angle); @@ -171,12 +172,11 @@ int ZBarcode_Encode(struct zint_symbol *symbol, unsigned char *input) if(symbol->symbology == 77) { strcpy(symbol->errtxt, "Korean Postal Code not supported [Z08]"); error_number = ERROR_INVALID_OPTION; } if(symbol->symbology == 78) { symbol->symbology = BARCODE_RSS14; } if(symbol->symbology == 83) { symbol->symbology = BARCODE_PLANET; } - /* NOTE: Tbarcode v8 needs sorting out */ if(symbol->symbology == 88) { symbol->symbology = BARCODE_EAN128; } if(symbol->symbology == 91) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128 [Z09]"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; } - /* leave a gap for future expansion of tbarcode */ - if((symbol->symbology >= 94) && (symbol->symbology <= 128)) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128 [Z10]"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; } - /* Everything from 100 up is Zint-specific */ + if((symbol->symbology >= 94) && (symbol->symbology <= 96)) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128 [Z10]"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; } + if((symbol->symbology >= 98) && (symbol->symbology <= 128)) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128 [Z10]"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; } + /* Everything from 128 up is Zint-specific */ if(symbol->symbology >= 140) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128 [Z11]"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; } if(error_number > 4) { @@ -267,6 +267,7 @@ int ZBarcode_Encode(struct zint_symbol *symbol, unsigned char *input) case BARCODE_CODABLOCKF: error_number = codablock(symbol, input); break; case BARCODE_DAFT: error_number = daft_code(symbol, input); break; case BARCODE_EAN14: error_number = ean_14(symbol, input); break; + case BARCODE_MICROQR: error_number = microqr(symbol, input); break; } if(error_number == 0) { error_number = error_buffer; diff --git a/backend/micqr.c b/backend/micqr.c new file mode 100644 index 00000000..3aecbebe --- /dev/null +++ b/backend/micqr.c @@ -0,0 +1,867 @@ +/* micqr.c - Handles Micro QR Code versions M1 - M4 */ + +/* + libzint - the open source barcode library + Copyright (C) 2008 Robin Stuart + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include +#include "common.h" +#include "micqr.h" +#include "reedsol.h" + +#define NUMERIC 1 +#define ALPHANUM 2 +#define BYTE 3 + +#define QRSET "0123456789ABCDEFGHIJKLNMOPQRSTUVWXYZ $%*+-./:" + +void qrnumeric_encode(char binary[], unsigned char source[]) +{ /* Encodes numeric data according to section 6.4.3 */ + + int input_length, blocks, remainder, i; + char block_binary[11]; + int block_value; + + input_length = ustrlen(source); + blocks = input_length / 3; + remainder = input_length % 3; + + for(i = 0; i < blocks; i++) { + block_value = ctoi(source[(i * 3)]) * 100; + block_value += ctoi(source[(i * 3) + 1]) * 10; + block_value += ctoi(source[(i * 3) + 2]); + + strcpy(block_binary, ""); + if(block_value & 0x200) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + concat(binary, block_binary); + } + + if(remainder == 2) { + block_value = ctoi(source[(i * 3)]) * 10; + block_value += ctoi(source[(i * 3) + 1]); + } + if(remainder == 1) { + block_value = ctoi(source[(i * 3)]); + } + + strcpy(block_binary, ""); + switch(remainder) { + case 2: + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + case 1: + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + break; + } + concat(binary, block_binary); + + return; +} + +void qralpha_encode(char binary[], unsigned char source[]) +{ /* Encodes alphanumeric data according to 6.4.4 */ + + int input_length, blocks, remainder, i; + char block_binary[12]; + int block_value; + + input_length = ustrlen(source); + blocks = input_length / 2; + remainder = input_length % 2; + + for(i = 0; i < blocks; i++) { + block_value = posn(QRSET, source[i * 2]) * 45; + block_value += posn(QRSET, source[(i * 2) + 1]); + + strcpy(block_binary, ""); + if(block_value & 0x400) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x200) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x100) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x80) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x40) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + concat(binary, block_binary); + } + + if(remainder == 1) { + block_value = posn(QRSET, source[i * 2]); + + strcpy(block_binary, ""); + if(block_value & 0x20) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x10) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x08) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x04) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x02) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + if(block_value & 0x01) { concat(block_binary, "1"); } else { concat(block_binary, "0"); } + concat(binary, block_binary); + } + + return; +} + +void qrbyte_encode(char binary[], unsigned char source[]) +{ /* Encodes byte mode data according to 6.4.5 */ + + int input_length, i; + + input_length = ustrlen(source); + + for(i = 0; i < input_length; i++) { + if(source[i] & 0x80) { concat(binary, "1"); } else { concat(binary, "0"); } + if(source[i] & 0x40) { concat(binary, "1"); } else { concat(binary, "0"); } + if(source[i] & 0x20) { concat(binary, "1"); } else { concat(binary, "0"); } + if(source[i] & 0x10) { concat(binary, "1"); } else { concat(binary, "0"); } + if(source[i] & 0x08) { concat(binary, "1"); } else { concat(binary, "0"); } + if(source[i] & 0x04) { concat(binary, "1"); } else { concat(binary, "0"); } + if(source[i] & 0x02) { concat(binary, "1"); } else { concat(binary, "0"); } + if(source[i] & 0x01) { concat(binary, "1"); } else { concat(binary, "0"); } + } + + return; +} + +void versionm1(char binary_data[], unsigned char source[]) +{ + int input_length, i, latch; + int bits_total, bits_left, remainder; + int data_codewords, ecc_codewords; + unsigned char data_blocks[4], ecc_blocks[3]; + + input_length = ustrlen(source); + bits_total = 20; + latch = 0; + + /* Character count indicator */ + if(input_length & 0x04) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x02) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x01) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + + qrnumeric_encode(binary_data, source); + + /* 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++) { + if((i % 2) == 0) { concat(binary_data, "11101100"); } + if((i % 2) == 1) { concat(binary_data, "00010001"); } + } + } + 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, 1); + rs_encode(data_codewords,data_blocks,ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for(i = 0; i < ecc_codewords; i++) { + if(ecc_blocks[i] & 0x80) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x40) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x20) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x10) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x08) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x04) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x02) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x01) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + } + + return; +} + +void versionm2(char binary_data[], unsigned char source[], int char_system, int ecc_mode) +{ + int input_length, i, latch; + int bits_total, bits_left, remainder; + int data_codewords, ecc_codewords; + unsigned char data_blocks[6], ecc_blocks[7]; + + input_length = ustrlen(source); + latch = 0; + + if(ecc_mode == 1) { bits_total = 40; } + if(ecc_mode == 2) { bits_total = 32; } + + /* Mode indicator */ + if(char_system == NUMERIC) { concat(binary_data, "0"); } + if(char_system == ALPHANUM) { concat(binary_data, "1"); } + + /* Character count indicator */ + if(char_system == NUMERIC) { + if(input_length & 0x08) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + } + if(input_length & 0x04) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x02) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x01) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + + if(char_system == NUMERIC) { qrnumeric_encode(binary_data, source); } + if(char_system == ALPHANUM) { qralpha_encode(binary_data, source); } + + /* 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++) { + if((i % 2) == 0) { concat(binary_data, "11101100"); } + if((i % 2) == 1) { concat(binary_data, "00010001"); } + } + } + + if(ecc_mode == 1) { data_codewords = 5; ecc_codewords = 5; } + if(ecc_mode == 2) { 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, 1); + rs_encode(data_codewords,data_blocks,ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for(i = 0; i < ecc_codewords; i++) { + if(ecc_blocks[i] & 0x80) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x40) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x20) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x10) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x08) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x04) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x02) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x01) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + } + + return; +} + +void versionm3(char binary_data[], unsigned char source[], int char_system, int ecc_mode) +{ + int input_length, i, latch; + int bits_total, bits_left, remainder; + int data_codewords, ecc_codewords; + unsigned char data_blocks[12], ecc_blocks[9]; + + input_length = ustrlen(source); + latch = 0; + + if(ecc_mode == 1) { bits_total = 84; } + if(ecc_mode == 2) { bits_total = 68; } + + /* Mode indicator */ + if(char_system == NUMERIC) { concat(binary_data, "00"); } + if(char_system == ALPHANUM) { concat(binary_data, "01"); } + if(char_system == BYTE) { concat(binary_data, "10"); } + + /* Character count indicator */ + if(char_system == NUMERIC) { + if(input_length & 0x10) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + } + if(input_length & 0x08) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x04) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x02) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x01) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + + if(char_system == NUMERIC) { qrnumeric_encode(binary_data, source); } + if(char_system == ALPHANUM) { qralpha_encode(binary_data, source); } + if(char_system == BYTE) { qrbyte_encode(binary_data, source); } + + /* 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++) { + if((i % 2) == 0) { concat(binary_data, "11101100"); } + if((i % 2) == 1) { concat(binary_data, "00010001"); } + } + } + concat(binary_data, "0000"); + } + + if(ecc_mode == 1) { data_codewords = 11; ecc_codewords = 6; } + if(ecc_mode == 2) { 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 == 1) { + 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 == 2) { + 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, 1); + rs_encode(data_codewords,data_blocks,ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for(i = 0; i < ecc_codewords; i++) { + if(ecc_blocks[i] & 0x80) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x40) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x20) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x10) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x08) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x04) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x02) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x01) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + } + + return; +} + +void versionm4(char binary_data[], unsigned char source[], int char_system, int ecc_mode) +{ + int input_length, i, latch; + int bits_total, bits_left, remainder; + int data_codewords, ecc_codewords; + unsigned char data_blocks[17], ecc_blocks[15]; + + input_length = ustrlen(source); + latch = 0; + + if(ecc_mode == 1) { bits_total = 128; } + if(ecc_mode == 2) { bits_total = 112; } + if(ecc_mode == 3) { bits_total = 80; } + + /* Mode indicator */ + if(char_system == NUMERIC) { concat(binary_data, "000"); } + if(char_system == ALPHANUM) { concat(binary_data, "001"); } + if(char_system == BYTE) { concat(binary_data, "010"); } + + /* Character count indicator */ + if(char_system == NUMERIC) { + if(input_length & 0x20) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + } + if(input_length & 0x10) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x08) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x04) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x02) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(input_length & 0x01) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + + if(char_system == NUMERIC) { qrnumeric_encode(binary_data, source); } + if(char_system == ALPHANUM) { qralpha_encode(binary_data, source); } + if(char_system == BYTE) { qrbyte_encode(binary_data, source); } + + /* 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++) { + if((i % 2) == 0) { concat(binary_data, "11101100"); } + if((i % 2) == 1) { concat(binary_data, "00010001"); } + } + } + + if(ecc_mode == 1) { data_codewords = 16; ecc_codewords = 8; } + if(ecc_mode == 2) { data_codewords = 14; ecc_codewords = 10; } + if(ecc_mode == 3) { 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, 1); + rs_encode(data_codewords,data_blocks,ecc_blocks); + rs_free(); + + /* Add Reed-Solomon codewords to binary data */ + for(i = 0; i < ecc_codewords; i++) { + if(ecc_blocks[i] & 0x80) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x40) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x20) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x10) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x08) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x04) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x02) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + if(ecc_blocks[i] & 0x01) { concat(binary_data, "1"); } else { concat(binary_data, "0"); } + } + + return; +} + +int microqr(struct zint_symbol *symbol, unsigned char source[]) +{ + int symbol_size; + int char_system, input_length; + char binary_data[200]; + int latch; + char bitmask[17][17]; + char imagemap[17][17]; + char candidate[17][17]; + char pattern_bit; + int width, i, j, pattern_no; + int sum1, sum2, evaluation[4], format, format_full; + char formatstr[16]; + + /* Analise input data and select encoding method - zint does not attempt to + optimise the symbol by switching encoding method part way through the symbol, + but merely chooses an encoding method for the whole symbol */ + input_length = ustrlen(source); + char_system = BYTE; + symbol_size = 0; + if(is_sane(QRSET, source) == 0) { char_system = ALPHANUM; } + if(is_sane(NESET, source) == 0) { char_system = NUMERIC; } + + if(symbol->option_1 == 4) { + strcpy(symbol->errtxt, "Error correction level H not available for Micro QR symbols"); + return ERROR_INVALID_OPTION; + } + + if((symbol->option_1 < 1) || (symbol->option_1 > 4)) { + symbol->option_1 = 1; + } + + /* Check that the data is not too long */ + /* Note that there is no switching between error correction levels - this decision is left + to the user: invalid combinations fail */ + latch = 0; + switch(symbol->option_1) { + case 1: /* ECC Level L */ + switch(char_system) { + case NUMERIC: if(input_length > 35) latch = 1; break; + case ALPHANUM: if(input_length > 21) latch = 1; break; + case BYTE: if(input_length > 15) latch = 1; break; + } + break; + case 2: /* ECC Level M */ + switch(char_system) { + case NUMERIC: if(input_length > 30) latch = 1; break; + case ALPHANUM: if(input_length > 18) latch = 1; break; + case BYTE: if(input_length > 13) latch = 1; break; + } + break; + case 3: /* ECC Level Q */ + symbol_size = 4; /* Only size M4 supports level Q */ + switch(char_system) { + case NUMERIC: if(input_length > 21) latch = 1; break; + case ALPHANUM: if(input_length > 13) latch = 1; break; + case BYTE: if(input_length > 9) latch = 1; break; + } + break; + } + + if(latch == 1) { + strcpy(symbol->errtxt, "Input data too long"); + return ERROR_TOO_LONG; + } + + /* Decide symbol size */ + if(symbol_size == 0) { + if(symbol->option_1 == 1) { /* ECC Level L */ + switch(char_system) { + case NUMERIC: + symbol_size = 4; + if(input_length <= 23) { symbol_size = 3; } + if(input_length <= 10) { symbol_size = 2; } + if(input_length <= 5) { symbol_size = 1; } + break; + case ALPHANUM: + symbol_size = 4; + if(input_length <= 14) { symbol_size = 3; } + if(input_length <= 6) { symbol_size = 2; } + break; + case BYTE: + symbol_size = 4; + if(input_length <= 9) { symbol_size = 3; } + break; + } + } else { /* ECC Level M */ + switch(char_system) { + case NUMERIC: + symbol_size = 4; + if(input_length <= 18) { symbol_size = 3; } + if(input_length <= 8) { symbol_size = 2; } + break; + case ALPHANUM: + symbol_size = 4; + if(input_length <= 11) { symbol_size = 3; } + if(input_length <= 5) { symbol_size = 2; } + break; + case BYTE: + symbol_size = 4; + if(input_length <= 7) { symbol_size = 3; } + break; + } + } + } + + strcpy(binary_data, ""); + switch(symbol_size) { + case 1: versionm1(binary_data, source); break; + case 2: versionm2(binary_data, source, char_system, symbol->option_1); break; + case 3: versionm3(binary_data, source, char_system, symbol->option_1); break; + case 4: versionm4(binary_data, source, char_system, symbol->option_1); break; + } + + switch(symbol_size) { + case 1: width = 11; break; + case 2: width = 13; break; + case 3: width = 15; break; + case 4: width = 17; break; + } + + for(i = 0; i < 17; i++) { + for(j = 0; j < 17; j++) { + bitmask[i][j] = '0'; + imagemap[i][j] = '0'; + candidate[i][j] = '0'; + } + } + + + /* "bitmask" seperates data area */ + for(i = 1; i < width; i++) { + for(j = 1; j < width; j++) { + bitmask[i][j] = '1'; + } + } + + for(i = 1; i < 9; i++) { + for(j = 1; j < 9; j++) { + bitmask[i][j] = '0'; + } + } + + /* Copy data into symbol grid */ + for(i = 0; i < width; i++) { + for(j = 0; j < width; j++) { + if(bitmask[i][j] == '1') { + switch(symbol_size) { + case 1: imagemap[i][j] = binary_data[fig11m1[(i * width) + j]]; break; + case 2: imagemap[i][j] = binary_data[fig11m2[(i * width) + j]]; break; + case 3: imagemap[i][j] = binary_data[fig11m3[(i * width) + j]]; break; + case 4: imagemap[i][j] = binary_data[fig11m4[(i * width) + j]]; break; + } + } + } + } + + /* XOR with data masks and evaluate */ + for(pattern_no = 0; pattern_no < 4; pattern_no++) { + for(i = 0; i < width; i++) { + for(j = 0; j < width; j++) { + pattern_bit = '0'; + candidate[i][j] = '0'; + switch(pattern_no) { + case 0: if((i % 2) == 0) { pattern_bit = '1'; } break; + case 1: if((((i / 2) + (j / 3)) % 2) == 0) { pattern_bit = '1'; } break; + case 2: if((((i * j) % 2 + (i * j) % 3) % 2) == 0) { pattern_bit = '1'; } break; + case 3: if((((i + j) % 2 + (i * j) % 3) % 2) == 0) { pattern_bit = '1'; } break; + } + if(bitmask[i][j] == '1') { + if(pattern_bit != imagemap[i][j]) { candidate[i][j] = '1'; } + } + } + } + + sum1 = 0; + sum2 = 0; + for(i = 1; i < width; i++) { + if(candidate[i][width - 1] == '1') { sum1++; } + if(candidate[width - 1][i] == '1') { sum2++; } + } + + if(sum1 <= sum2) { evaluation[pattern_no] = (sum1 * 16) + sum2; } else { evaluation[pattern_no] = (sum2 * 16) + sum1; } + } + + /* Choose best data mask */ + j = evaluation[0]; + pattern_no = 0; + for(i = 1; i < 4; i++) { + if(evaluation[i] > j) { + pattern_no = i; + j = evaluation[i]; + } + } + + /* Apply data mask */ + for(i = 0; i < width; i++) { + for(j = 0; j < width; j++) { + pattern_bit = '0'; + candidate[i][j] = '0'; + switch(pattern_no) { + case 0: if((i % 2) == 0) { pattern_bit = '1'; } break; + case 1: if((((i / 2) + (j / 3)) % 2) == 0) { pattern_bit = '1'; } break; + case 2: if((((i * j) % 2 + (i * j) % 3) % 2) == 0) { pattern_bit = '1'; } break; + case 3: if((((i + j) % 2 + (i * j) % 3) % 2) == 0) { pattern_bit = '1'; } break; + } + if(bitmask[i][j] == '1') { + if(pattern_bit != imagemap[i][j]) { candidate[i][j] = '1'; } + } + } + } + + /* Calculate format data */ + switch(symbol_size) { + case 1: format = 0; + break; + case 2: switch(symbol->option_1) { + case 1: format = 1; break; + case 2: format = 2; break; + } + break; + case 3: switch(symbol->option_1) { + case 1: format = 3; break; + case 2: format = 4; break; + } + break; + case 4: switch(symbol->option_1) { + case 1: format = 5; break; + case 2: format = 6; break; + case 3: format = 7; break; + } + break; + } + + format *= 4; + format += pattern_no; + format_full = tablec1[format]; + + strcpy(formatstr, ""); + if(format_full & 0x2000) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x1000) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x800) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x400) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x200) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x100) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x80) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x80) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x40) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x20) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x10) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x08) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x04) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x02) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + if(format_full & 0x01) { concat(formatstr, "1"); } else { concat(formatstr, "0"); } + + /* Add format data to symbol */ + for(i = 0; i < 8; i++) { + candidate[i + 1][8] = formatstr[i]; + } + for(i = 0; i < 7; i++) { + candidate[8][7 - i] = formatstr[i + 8]; + } + + /* Add timer pattern */ + for(i = 0; i < width; i += 2) { + candidate[i][0] = '1'; + candidate[0][i] = '1'; + } + + /* Add finder pattern */ + for(i = 0; i < 7; i ++) { + for(j = 0; j < 7; j++) { + if(finder[(i * 7) + j] == 1) { + candidate[i][j] = '1'; + } + } + } + + /* Copy data into symbol */ + for(i = 0; i < width; i++) { + for(j = 0; j < width; j++) { + symbol->encoded_data[i][j] = candidate[i][j]; + } + symbol->row_height[i] = 1; + } + symbol->rows = width; + symbol->width = width; + + return 0; +} \ No newline at end of file diff --git a/backend/micqr.h b/backend/micqr.h new file mode 100644 index 00000000..f34b133d --- /dev/null +++ b/backend/micqr.h @@ -0,0 +1,103 @@ +/* micqr.h - Bit placement for Micro QR Code versions M1 - M4 */ + +/* + libzint - the open source barcode library + Copyright (C) 2008 Robin Stuart + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +int fig11m1[] = { + 0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,19,18, + 0,0,0,0,0,0,0,0,0,17,16, + 0,0,0,0,0,0,0,0,0,15,14, + 0,0,0,0,0,0,0,0,0,13,12, + 0,0,0,0,0,0,0,0,0,11,10, + 0,0,0,0,0,0,0,0,0,9,8, + 0,0,0,0,0,0,0,0,0,7,6, + 0,0,0,0,0,0,0,0,0,5,4, + 0,35,33,29,28,27,26,21,20,3,2, + 0,34,32,31,30,25,24,23,22,1,0 +}; + +int fig11m2[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,25,24,23,22, + 0,0,0,0,0,0,0,0,0,27,26,21,20, + 0,0,0,0,0,0,0,0,0,29,28,19,18, + 0,0,0,0,0,0,0,0,0,31,30,17,16, + 0,0,0,0,0,0,0,0,0,33,32,15,14, + 0,0,0,0,0,0,0,0,0,35,34,13,12, + 0,0,0,0,0,0,0,0,0,37,36,11,10, + 0,0,0,0,0,0,0,0,0,39,38,9,8, + 0,73,72,71,70,57,56,55,54,41,40,7,6, + 0,75,74,69,68,59,58,53,52,43,42,5,4, + 0,77,76,67,66,61,60,51,50,45,44,3,2, + 0,79,78,65,64,63,62,49,48,47,46,1,0 +}; + +int fig11m3[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,83,82,29,28,27,26, + 0,0,0,0,0,0,0,0,0,81,80,31,30,25,24, + 0,0,0,0,0,0,0,0,0,79,78,33,32,23,22, + 0,0,0,0,0,0,0,0,0,77,76,35,34,21,20, + 0,0,0,0,0,0,0,0,0,75,74,37,36,19,18, + 0,0,0,0,0,0,0,0,0,73,72,39,38,17,16, + 0,0,0,0,0,0,0,0,0,71,70,41,40,15,14, + 0,0,0,0,0,0,0,0,0,69,68,43,42,13,12, + 0,131,130,109,108,107,106,85,84,67,66,45,44,11,10, + 0,129,128,111,110,105,104,87,86,65,64,47,46,9,8, + 0,127,126,113,112,103,102,89,88,63,62,49,48,7,6, + 0,125,124,115,114,101,100,91,90,61,60,51,50,5,4, + 0,123,122,117,116,99,98,93,92,59,58,53,52,3,2, + 0,121,120,119,118,97,96,95,94,57,56,55,54,1,0 +}; + +int fig11m4[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,97,96,95,94,33,32,31,30, + 0,0,0,0,0,0,0,0,0,99,98,93,92,35,34,29,28, + 0,0,0,0,0,0,0,0,0,101,100,91,90,37,36,27,26, + 0,0,0,0,0,0,0,0,0,103,102,89,88,39,38,25,24, + 0,0,0,0,0,0,0,0,0,105,104,87,86,41,40,23,22, + 0,0,0,0,0,0,0,0,0,107,106,85,84,43,42,21,20, + 0,0,0,0,0,0,0,0,0,109,108,83,82,45,44,19,18, + 0,0,0,0,0,0,0,0,0,111,110,81,80,47,46,17,16, + 0,177,176,175,174,145,144,143,142,113,112,79,78,49,48,15,14, + 0,179,178,173,172,147,146,141,140,115,114,77,76,51,50,13,12, + 0,181,180,171,170,149,148,139,138,117,116,75,74,53,52,11,10, + 0,183,182,169,168,151,150,137,136,119,118,73,72,55,54,9,8, + 0,185,184,167,166,153,152,135,134,121,120,70,69,57,56,7,6, + 0,187,186,165,164,155,154,133,132,123,122,68,67,59,58,5,4, + 0,189,188,163,162,157,156,131,130,125,124,66,65,61,60,3,2, + 0,191,190,161,160,159,158,129,128,127,126,64,63,62,0,1,0 +}; + +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 +}; + +int tablec1[] = { 0x4445, 0x4172, 0x4e2b, 0x4b1c, 0x55ae, 0x5099, 0x5fc0, 0x5af7, 0x6793, 0x62a4, 0x6dfd, 0x68ca, 0x7678, 0x734f, + 0x7c16, 0x7921, 0x06de, 0x03e9, 0x0cb0, 0x0987, 0x1735, 0x1202, 0x1d5b, 0x186c, 0x2508, 0x203f, 0x2f66, 0x2a51, 0x34e3, + 0x31d4, 0x3e8d, 0x3bba +}; diff --git a/docs/backend.html b/docs/backend.html index f8963445..9e4abbdb 100644 --- a/docs/backend.html +++ b/docs/backend.html @@ -5,7 +5,7 @@ Using the API - +