summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTae-Young Chung <ty83.chung@samsung.com>2020-06-22 02:16:33 (GMT)
committerTae-Young Chung <ty83.chung@samsung.com>2020-06-22 04:32:26 (GMT)
commit0428f8a17e78dae97a8774a0ec42f48f85abcb88 (patch)
tree100c5b5a6d1d6f996294ead7474f31703a456339
parentf18ddd9e3e6afc1edf5d030dd32647b3eac5462b (diff)
downloadlibzint-accepted/tizen_unified.zip
libzint-accepted/tizen_unified.tar.gz
libzint-accepted/tizen_unified.tar.bz2
zint is originally GPL v3 for an whole package but backend can be used as BSD-3 as The backed part of zint-code is updated to version 2.7.1 https://sourceforge.net/p/zint/code/ci/master/tree/ Change-Id: I779a9f70f93f0202affe41a7644d9e4bfb810123 Signed-off-by: Tae-Young Chung <ty83.chung@samsung.com>
-rw-r--r--backend/2of5.c377
-rw-r--r--backend/CMakeLists.txt12
-rw-r--r--backend/DEVELOPER88
-rw-r--r--backend/Makefile54
-rw-r--r--backend/Makefile.mingw40
-rw-r--r--backend/auspost.c250
-rw-r--r--backend/aztec.c1686
-rw-r--r--backend/aztec.h146
-rw-r--r--backend/bmp.c181
-rw-r--r--backend/bmp.h77
-rw-r--r--backend/channel_precalcs.h106
-rw-r--r--backend/codablock.c988
-rw-r--r--backend/code.c907
-rw-r--r--backend/code1.c1770
-rw-r--r--backend/code1.h102
-rw-r--r--backend/code128.c1926
-rw-r--r--backend/code128.h57
-rw-r--r--backend/code16k.c504
-rw-r--r--backend/code49.c361
-rw-r--r--backend/code49.h558
-rw-r--r--backend/common.c726
-rw-r--r--backend/common.h89
-rw-r--r--backend/composite.c1668
-rw-r--r--backend/composite.h67
-rw-r--r--backend/dllversion.c10
-rw-r--r--backend/dmatrix.c1342
-rw-r--r--backend/dmatrix.h248
-rw-r--r--backend/dotcode.c1569
-rw-r--r--backend/eci.c273
-rw-r--r--backend/eci.h254
-rw-r--r--backend/emf.c655
-rw-r--r--backend/emf.h223
-rw-r--r--backend/font.h2055
-rw-r--r--backend/gb18030.c2968
-rw-r--r--backend/gb18030.h49
-rw-r--r--backend/gb2312.c1624
-rw-r--r--backend/gb2312.h7471
-rw-r--r--backend/general_field.c187
-rw-r--r--backend/general_field.h47
-rw-r--r--backend/gif.c584
-rw-r--r--backend/gridmtx.c1123
-rw-r--r--backend/gridmtx.h178
-rw-r--r--backend/gs1.c924
-rw-r--r--backend/gs1.h10
-rw-r--r--backend/hanxin.c1665
-rw-r--r--backend/hanxin.h460
-rw-r--r--backend/imail.c442
-rw-r--r--backend/large.c459
-rw-r--r--backend/large.h45
-rw-r--r--backend/library.c2120
-rw-r--r--backend/libzint.rc14
-rw-r--r--backend/mailmark.c498
-rw-r--r--backend/maxicode.c736
-rw-r--r--backend/maxicode.h104
-rw-r--r--backend/maxipng.h149
-rw-r--r--backend/medical.c334
-rw-r--r--backend/ms_stdint.h235
-rw-r--r--backend/output.c114
-rw-r--r--backend/output.h47
-rw-r--r--backend/pcx.c222
-rw-r--r--backend/pcx.h77
-rw-r--r--backend/pdf417.c1327
-rw-r--r--backend/pdf417.h514
-rw-r--r--backend/plessey.c494
-rw-r--r--backend/png.c1235
-rw-r--r--backend/postal.c596
-rw-r--r--backend/ps.c1030
-rw-r--r--backend/qr.c5195
-rw-r--r--backend/qr.h392
-rw-r--r--backend/raster.c1170
-rw-r--r--backend/reedsol.c183
-rw-r--r--backend/reedsol.h16
-rw-r--r--backend/render.c792
-rw-r--r--backend/rss.c1765
-rw-r--r--backend/rss.h293
-rw-r--r--backend/sjis.c1591
-rw-r--r--backend/sjis.h6877
-rw-r--r--backend/stdint_msvc.h54
-rw-r--r--backend/svg.c248
-rw-r--r--backend/telepen.c168
-rw-r--r--backend/tif.c346
-rw-r--r--backend/tif.h88
-rw-r--r--backend/ultra.c1115
-rw-r--r--backend/upcean.c1587
-rw-r--r--backend/vector.c823
-rw-r--r--backend/zint.def27
-rw-r--r--backend/zint.h497
-rw-r--r--packaging/zint.spec6
88 files changed, 45824 insertions, 24860 deletions
diff --git a/backend/2of5.c b/backend/2of5.c
index df07f46..c3c795d 100644
--- a/backend/2of5.c
+++ b/backend/2of5.c
@@ -2,7 +2,7 @@
/*
libzint - the open source barcode library
- Copyright (C) 2008 Robin Stuart <robin@zint.org.uk>
+ Copyright (C) 2008 - 2020 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -28,90 +28,329 @@
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
-*/
+ */
+/* vim: set ts=4 sw=4 et : */
-#include <string.h>
#include <stdio.h>
-#include <stdlib.h>
#include "common.h"
#ifdef _MSC_VER
#include <malloc.h>
+#define inline _inline
#endif
-static const char *C25MatrixTable[10] = {"113311", "311131", "131131", "331111", "113131", "313111",
- "133111", "111331", "311311", "131311"};
+static const char *C25MatrixTable[10] = {
+ "113311", "311131", "131131", "331111", "113131", "313111",
+ "133111", "111331", "311311", "131311"
+};
-static const char *C25IndustTable[10] = {"1111313111", "3111111131", "1131111131", "3131111111", "1111311131",
- "3111311111", "1131311111", "1111113131", "3111113111", "1131113111"};
+static const char *C25IndustTable[10] = {
+ "1111313111", "3111111131", "1131111131", "3131111111", "1111311131",
+ "3111311111", "1131311111", "1111113131", "3111113111", "1131113111"
+};
-static const char *C25InterTable[10] = {"11331", "31113", "13113", "33111", "11313", "31311", "13311", "11133",
- "31131", "13131"};
+static const char *C25InterTable[10] = {
+ "11331", "31113", "13113", "33111", "11313", "31311", "13311", "11133",
+ "31131", "13131"
+};
-static inline char check_digit(unsigned int count)
-{
- return itoc((10 - (count % 10)) % 10);
+static inline char check_digit(unsigned int count) {
+ return itoc((10 - (count % 10)) % 10);
}
-int interleaved_two_of_five(struct zint_symbol *symbol, unsigned char source[], int length)
-{ /* Code 2 of 5 Interleaved */
+/* Code 2 of 5 Standard (Code 2 of 5 Matrix) */
+INTERNAL int matrix_two_of_five(struct zint_symbol *symbol, unsigned char source[], int length) {
- int i, j, k, error_number;
- char bars[7], spaces[7], mixed[14], dest[1000];
+ int i, error_number;
+ char dest[512]; /* 6 + 80 * 6 + 6 + 1 ~ 512*/
+
+ if (length > 80) {
+ strcpy(symbol->errtxt, "301: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "302: Invalid characters in data");
+ return error_number;
+ }
+
+ /* start character */
+ strcpy(dest, "411111");
+
+ for (i = 0; i < length; i++) {
+ lookup(NEON, C25MatrixTable, source[i], dest);
+ }
+
+ /* Stop character */
+ strcat(dest, "41111");
+
+ expand(symbol, dest);
+ ustrcpy(symbol->text, source);
+ return error_number;
+}
+
+/* Code 2 of 5 Industrial */
+INTERNAL int industrial_two_of_five(struct zint_symbol *symbol, unsigned char source[], int length) {
+
+ int i, error_number;
+ char dest[512]; /* 6 + 40 * 10 + 6 + 1 */
+
+ if (length > 45) {
+ strcpy(symbol->errtxt, "303: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "304: Invalid character in data");
+ return error_number;
+ }
+
+ /* start character */
+ strcpy(dest, "313111");
+
+ for (i = 0; i < length; i++) {
+ lookup(NEON, C25IndustTable, source[i], dest);
+ }
+
+ /* Stop character */
+ strcat(dest, "31113");
+
+ expand(symbol, dest);
+ ustrcpy(symbol->text, source);
+ return error_number;
+}
+
+/* Code 2 of 5 IATA */
+INTERNAL int iata_two_of_five(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int i, error_number;
+ char dest[512]; /* 4 + 45 * 10 + 3 + 1 */
+
+ if (length > 45) {
+ strcpy(symbol->errtxt, "305: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "306: Invalid characters in data");
+ return error_number;
+ }
+
+ /* start */
+ strcpy(dest, "1111");
+
+ for (i = 0; i < length; i++) {
+ lookup(NEON, C25IndustTable, source[i], dest);
+ }
+
+ /* stop */
+ strcat(dest, "311");
+
+ expand(symbol, dest);
+ ustrcpy(symbol->text, source);
+ return error_number;
+}
+
+/* Code 2 of 5 Data Logic */
+INTERNAL int logic_two_of_five(struct zint_symbol *symbol, unsigned char source[], int length) {
+
+ int i, error_number;
+ char dest[512]; /* 4 + 80 * 6 + 3 + 1 */
+
+ if (length > 80) {
+ strcpy(symbol->errtxt, "307: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "308: Invalid characters in data");
+ return error_number;
+ }
+
+ /* start character */
+ strcpy(dest, "1111");
+
+ for (i = 0; i < length; i++) {
+ lookup(NEON, C25MatrixTable, source[i], dest);
+ }
+
+ /* Stop character */
+ strcat(dest, "311");
+
+ expand(symbol, dest);
+ ustrcpy(symbol->text, source);
+ return error_number;
+}
+
+/* Code 2 of 5 Interleaved */
+INTERNAL int interleaved_two_of_five(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
+
+ int i, j, error_number;
+ char bars[7], spaces[7], mixed[14], dest[1000];
#ifndef _MSC_VER
- unsigned char temp[length + 2];
+ unsigned char temp[length + 2];
#else
- unsigned char* temp = (unsigned char *)_alloca((length + 2) * sizeof(unsigned char));
+ unsigned char* temp = (unsigned char *) _alloca((length + 2) * sizeof (unsigned char));
#endif
- error_number = 0;
-
- if(length > 89) {
- strcpy(symbol->errtxt, "Input too long");
- return ERROR_TOO_LONG;
- }
- error_number = is_sane(NEON, source, length);
- if (error_number == ERROR_INVALID_DATA) {
- strcpy(symbol->errtxt, "Invalid characters in data");
- return error_number;
- }
-
- ustrcpy(temp, (unsigned char *) "");
- /* Input must be an even number of characters for Interlaced 2 of 5 to work:
- if an odd number of characters has been entered then add a leading zero */
- if (length & 1)
- {
- ustrcpy(temp, (unsigned char *) "0");
- length++;
- }
- uconcat(temp, source);
-
- /* start character */
- strcpy(dest, "1111");
-
- for(i = 0; i < length; i+=2 )
- {
- /* look up the bars and the spaces and put them in two strings */
- strcpy(bars, "");
- lookup(NEON, C25InterTable, temp[i], bars);
- strcpy(spaces, "");
- lookup(NEON, C25InterTable, temp[i + 1], spaces);
-
- /* then merge (interlace) the strings together */
- k = 0;
- for(j = 0; j <= 4; j++)
- {
- mixed[k] = bars[j]; k++;
- mixed[k] = spaces[j]; k++;
- }
- mixed[k] = '\0';
- concat (dest, mixed);
- }
-
- /* Stop character */
- concat (dest, "311");
-
- expand(symbol, dest);
- ustrcpy(symbol->text, temp);
- return error_number;
+ if (length > 89) {
+ strcpy(symbol->errtxt, "309: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "310: Invalid characters in data");
+ return error_number;
+ }
+
+ ustrcpy(temp, "");
+ /* Input must be an even number of characters for Interlaced 2 of 5 to work:
+ if an odd number of characters has been entered then add a leading zero */
+ if (length & 1) {
+ ustrcpy(temp, "0");
+ length++;
+ }
+ ustrcat(temp, source);
+
+ /* start character */
+ strcpy(dest, "1111");
+
+ for (i = 0; i < (int) length; i += 2) {
+ int k = 0;
+ /* look up the bars and the spaces and put them in two strings */
+ strcpy(bars, "");
+ lookup(NEON, C25InterTable, temp[i], bars);
+ strcpy(spaces, "");
+ lookup(NEON, C25InterTable, temp[i + 1], spaces);
+
+ /* then merge (interlace) the strings together */
+ for (j = 0; j <= 4; j++) {
+ mixed[k] = bars[j];
+ k++;
+ mixed[k] = spaces[j];
+ k++;
+ }
+ mixed[k] = '\0';
+ strcat(dest, mixed);
+ }
+
+ /* Stop character */
+ strcat(dest, "311");
+
+ expand(symbol, dest);
+ ustrcpy(symbol->text, temp);
+ return error_number;
+
+}
+
+/* Interleaved 2-of-5 (ITF) */
+INTERNAL int itf14(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int i, error_number, zeroes;
+ unsigned int count;
+ char localstr[16];
+
+ count = 0;
+
+ if (length > 13) {
+ strcpy(symbol->errtxt, "311: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "312: Invalid character in data");
+ return error_number;
+ }
+
+ /* Add leading zeros as required */
+ zeroes = 13 - length;
+ for (i = 0; i < zeroes; i++) {
+ localstr[i] = '0';
+ }
+ ustrcpy(localstr + zeroes, source);
+
+ /* Calculate the check digit - the same method used for EAN-13 */
+ for (i = 12; i >= 0; i--) {
+ count += ctoi(localstr[i]);
+
+ if (!(i & 1)) {
+ count += 2 * ctoi(localstr[i]);
+ }
+ }
+ localstr[13] = check_digit(count);
+ localstr[14] = '\0';
+ error_number = interleaved_two_of_five(symbol, (unsigned char *) localstr, strlen(localstr));
+ ustrcpy(symbol->text, localstr);
+ return error_number;
+}
+
+/* Deutshe Post Leitcode */
+INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int i, error_number;
+ unsigned int count;
+ char localstr[16];
+ int zeroes;
+
+ count = 0;
+ if (length > 13) {
+ strcpy(symbol->errtxt, "313: Input wrong length");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "314: Invalid characters in data");
+ return error_number;
+ }
+
+ zeroes = 13 - length;
+ for (i = 0; i < zeroes; i++)
+ localstr[i] = '0';
+ ustrcpy(localstr + zeroes, source);
+
+ for (i = 12; i >= 0; i--) {
+ count += 4 * ctoi(localstr[i]);
+
+ if (i & 1) {
+ count += 5 * ctoi(localstr[i]);
+ }
+ }
+ localstr[13] = check_digit(count);
+ localstr[14] = '\0';
+ error_number = interleaved_two_of_five(symbol, (unsigned char *) localstr, strlen(localstr));
+ ustrcpy(symbol->text, localstr);
+ return error_number;
+}
+
+/* Deutsche Post Identcode */
+INTERNAL int dpident(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int i, error_number, zeroes;
+ unsigned int count;
+ char localstr[16];
+
+ count = 0;
+ if (length > 11) {
+ strcpy(symbol->errtxt, "315: Input wrong length");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "316: Invalid characters in data");
+ return error_number;
+ }
+
+ zeroes = 11 - length;
+ for (i = 0; i < zeroes; i++)
+ localstr[i] = '0';
+ ustrcpy(localstr + zeroes, source);
+
+ for (i = 10; i >= 0; i--) {
+ count += 4 * ctoi(localstr[i]);
+ if (i & 1) {
+ count += 5 * ctoi(localstr[i]);
+ }
+ }
+ localstr[11] = check_digit(count);
+ localstr[12] = '\0';
+ error_number = interleaved_two_of_five(symbol, (unsigned char *) localstr, strlen(localstr));
+ ustrcpy(symbol->text, localstr);
+ return error_number;
}
diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt
index 64d88f1..e7baa0b 100644
--- a/backend/CMakeLists.txt
+++ b/backend/CMakeLists.txt
@@ -2,12 +2,12 @@
project(zint)
-set(zint_COMMON_SRCS common.c library.c render.c ps.c large.c reedsol.c gs1.c png.c)
-set(zint_ONEDIM_SRCS code.c code128.c 2of5.c upcean.c)
-set(zint_TWODIM_SRCS qr.c)
-set(zint_SRCS ${zint_COMMON_SRCS} ${zint_ONEDIM_SRCS} ${zint_TWODIM_SRCS} )
-
-add_definitions (-DNO_PNG)
+set(zint_COMMON_SRCS common.c library.c large.c reedsol.c gs1.c eci.c general_field.c sjis.c gb2312.c gb18030.c)
+set(zint_ONEDIM_SRCS code.c code128.c 2of5.c upcean.c telepen.c medical.c plessey.c rss.c)
+set(zint_POSTAL_SRCS postal.c auspost.c imail.c mailmark.c)
+set(zint_TWODIM_SRCS code16k.c codablock.c dmatrix.c pdf417.c qr.c maxicode.c composite.c aztec.c code49.c code1.c gridmtx.c hanxin.c dotcode.c ultra.c)
+set(zint_OUTPUT_SRCS vector.c ps.c svg.c emf.c bmp.c pcx.c gif.c png.c tif.c raster.c output.c)
+set(zint_SRCS ${zint_OUTPUT_SRCS} ${zint_COMMON_SRCS} ${zint_ONEDIM_SRCS} ${zint_POSTAL_SRCS} ${zint_TWODIM_SRCS})
add_library(zint SHARED ${zint_SRCS})
diff --git a/backend/DEVELOPER b/backend/DEVELOPER
index 7db3a77..8f50755 100644
--- a/backend/DEVELOPER
+++ b/backend/DEVELOPER
@@ -13,6 +13,22 @@ Here is a guide to which bit of source code does what.
Deutche Post Leitcode
Deutche Post Identcode
+auspost.c:
+ Australia Post Standard Customer Barcode
+ Australia Post Customer Barcode 2
+ Australia Post Customer Barcode 3
+ Australia Post Reply Paid Barcode
+ Australia Post Routing Barcode
+ Australia Post Redirect Barcode
+
+aztec.c:
+ Aztec Code
+ Compact Aztec Code
+ Aztec Runes
+
+blockf.c:
+ Codablock-F
+
code128.c:
Code 128
Code 128 Subset B
@@ -20,6 +36,9 @@ code128.c:
GS1-128 (UCC/EAN-128)
EAN-14
+code16k.c:
+ Code 16k
+
code.c:
Code 11
Code 39
@@ -29,9 +48,78 @@ code.c:
LOGMARS
Channel Code
+code1.c:
+ Code One
+
+code49.c:
+ Code 49
+
+composite.c:
+ CC-A Composite Symbology
+ CC-B Composite Symbology
+ CC-C Composite Symbology
+
+dotcode.c:
+ Dot Code
+
+dm200.c:
+ Data Matrix ECC 200
+
+gridmtx.c:
+ Grid Matrix
+
+hanxin.c:
+ Han Xin Code
+
+imail.c:
+ USPS OneCode (Intelligent Mail)
+
+maxicode.c:
+ UPS Maxicode
+
+medical.c:
+ Pharma Code
+ Two Track Pharma Code
+ Codabar
+ Code 32
+
+pdf417.c:
+ PDF417
+ Truncated PDF417
+ MicroPDF417
+
+plessey.c:
+ UK Plessey Code (bidirectional)
+ MSI Plessey
+
+postal.c:
+ PostNet
+ PLANET
+ Facing Identification Mark (FIM)
+ Royal Mail 4-State Country Code (RM4SCC)
+ KIX Code
+ DAFT Code
+ Flattermarken
+ Korean Postal Code
+ Japanese Postal Code
+
qr.c:
QR Code
Micro QR Code
+ UPNQR
+
+rss.c:
+ GS1 DataBar (DataBar-14) (RSS-14)
+ GS1 DataBar Stacked (RSS-14 Stacked)
+ GS1 DataBar Stacked Omnidirectional (DataBar-14 Stacked Omnidirectional)
+ (RSS-14 Stacked Omnidirectional)
+ GS1 DataBar Limited (RSS Limited)
+ GS1 DataBar Expanded (RSS Expanded)
+ GS1 DataBar Expanded Stacked (RSS Expanded Stacked)
+
+telepen.c:
+ Telepen ASCII
+ Telepen Numeric
upcean.c:
UPC-A
diff --git a/backend/Makefile b/backend/Makefile
deleted file mode 100644
index 2f339dd..0000000
--- a/backend/Makefile
+++ /dev/null
@@ -1,54 +0,0 @@
-# Linux makefile for libzint
-#
-# make compiles
-# make install copies to /usr/local/lib
-# make uninstall removes library
-# make clean cleans up a previous compilation and any object or editor files
-#
-
-ZINT_VERSION:=-DZINT_VERSION=\"2.4.3.0\"
-
-
-CC := gcc
-INCLUDE := -I/usr/include
-CFLAGS := -g
-
-prefix := /usr
-includedir := $(prefix)/include
-libdir := $(prefix)/lib
-DESTDIR :=
-
-COMMON:= common.c render.c png.c library.c ps.c large.c reedsol.c gs1.c svg.c
-COMMON_OBJ:= common.o render.o png.o library.o ps.o large.o reedsol.o gs1.o svg.o
-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 dmatrix.c pdf417.c qr.c maxicode.c composite.c aztec.c code49.c code1.c gridmtx.c
-TWODIM_OBJ:= code16k.o dmatrix.o pdf417.o qr.o maxicode.o composite.o aztec.o code49.o code1.o gridmtx.o
-LIBS:= `libpng15-config --I_opts --L_opts --ldflags` -lz -lm
-
-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 reedsol.c pdf417.c maxicode.c rss.c common.c render.c png.c library.c ps.c qr.c large.c composite.c aztec.c gs1.c svg.c code49.c code1.c gridmtx.c
- $(CC) -Wall -fPIC $(CFLAGS) $(ZINT_VERSION) -c $(ONEDIM)
- $(CC) -Wall -fPIC $(CFLAGS) $(ZINT_VERSION) -c $(POSTAL)
- $(CC) -Wall -fPIC $(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.2.4.3 $(INCLUDE) $(COMMON_OBJ) $(ONEDIM_OBJ) $(TWODIM_OBJ) $(POSTAL_OBJ) $(LIBS)
- ln -s libzint.so.* libzint.so
-
-.PHONY: install uninstall clean dist
-
-install:
- test "$(UID)" = "0" && ldconfig -n $(PWD) || true
- install -d $(DESTDIR)$(libdir)
- mv libzint.* $(DESTDIR)$(libdir)
- install -D -p --mode=0644 zint.h $(DESTDIR)$(includedir)/zint.h
-
-uninstall:
- rm $(DESTDIR)$(libdir)/libzint.*
- rm $(DESTDIR)$(includedir)/zint.h
-
-clean:
- rm -f libzint.* *.o *.a *~
-
-
diff --git a/backend/Makefile.mingw b/backend/Makefile.mingw
index 87fc946..e79a912 100644
--- a/backend/Makefile.mingw
+++ b/backend/Makefile.mingw
@@ -6,18 +6,14 @@
# make clean cleans up a previous compilation and any object or editor files
#
-ZINT_VERSION:=-DZINT_VERSION=\"2.4.3.0\"
+ZINT_VERSION:=-DZINT_VERSION=\"2.3.2\"
-CC:= gcc -m32
-LD:= ld
+CC:= gcc
AR:= ar rc
RANLIB:= ranlib
INCLUDE:= -I/mingw/include
-CFLAGS:= -O2 -fms-extensions -mms-bitfields -fno-exceptions -fomit-frame-pointer -Wall
-LDFLAGS = -Wl,--major-image-version=2 -Wl,--minor-image-version=43
-RC:= windres
-RCFLAGS:= -v -F pe-i386 --define GCC_WINDRES
+CFLAGS:= -D_WIN32 -O2 -fms-extensions -mms-bitfields -fno-exceptions -fomit-frame-pointer -Wall
prefix := /mingw
includedir := $(prefix)/include
@@ -26,11 +22,11 @@ bindir := $(prefix)/bin
DESTDIR :=
APP:=zint
DLL:=$(APP).dll
-DLLIMP:=lib$(DLL).a
STATLIB:=lib$(APP).a
-TOOLLIB:=lib$(APP).la
-COMMON_OBJ:= common.o render.o png.o library.o ps.o large.o reedsol.o gs1.o svg.o
+COMMON_OBJ:= common.o render.o png.o library.o ps.o large.o reedsol.o gs1.o svg.o \
+ hanxin.o mailmark.o dotcode.o codablock.o emf.o eci.o \
+ raster.o tif.o gif.o pcx.o bmp.o
ONEDIM_OBJ:= code.o code128.o 2of5.o upcean.o telepen.o medical.o plessey.o rss.o
POSTAL_OBJ:= postal.o auspost.o imail.o
TWODIM_OBJ:= code16k.o dmatrix.o pdf417.o qr.o maxicode.o composite.o aztec.o code49.o code1.o gridmtx.o
@@ -38,6 +34,7 @@ TWODIM_OBJ:= code16k.o dmatrix.o pdf417.o qr.o maxicode.o composite.o aztec.o co
LIB_OBJ:= $(COMMON_OBJ) $(ONEDIM_OBJ) $(TWODIM_OBJ) $(POSTAL_OBJ)
DLL_OBJ:= $(LIB_OBJ:.o=.lo) dllversion.lo
+
ifeq ($(NO_PNG),true)
DEFINES+= -DNO_PNG
else
@@ -48,8 +45,6 @@ endif
LIBS+= -lm
all: $(DLL) $(STATLIB)
-DLL: $(DLL)
-static: $(STATLIB)
%.lo:%.c
@echo Compiling $< ...
@@ -59,12 +54,9 @@ static: $(STATLIB)
@echo Compiling $< ...
$(CC) $(CFLAGS) $(DEFINES) $(ZINT_VERSION) -c -o $@ $<
-libzint.o: libzint.rc
- $(RC) $(RCFLAGS) -o $@ $<
-
-$(DLL):$(DLL_OBJ) libzint.o
+$(DLL):$(DLL_OBJ)
@echo Linking $@...
- $(CC) -shared -Wl,--out-implib,$(DLLIMP) $(LDFLAGS) -o $@ zint.def $(DLL_OBJ) libzint.o $(LIBS)
+ o2dll.sh -o $@ $(DLL_OBJ) $(LIBS)
$(STATLIB): $(LIB_OBJ)
@echo Linking $@...
@@ -74,20 +66,16 @@ $(STATLIB): $(LIB_OBJ)
.PHONY: install uninstall clean dist
install:
- cp -fp $(DLLIMP) $(DESTDIR)$(libdir)
- cp -fp $(STATLIB) $(DESTDIR)$(libdir)
- cp -fp $(TOOLLIB) $(DESTDIR)$(libdir)
+ cp -fp libzint.* $(DESTDIR)$(libdir)
cp -fp zint.h $(DESTDIR)$(includedir)/zint.h
- cp -fp $(DLL) $(DESTDIR)$(bindir)
+ cp -fp zint.dll $(DESTDIR)$(bindir)
uninstall:
- rm $(DESTDIR)$(libdir)/$(DLLIMP)
- rm $(DESTDIR)$(libdir)/$(STATLIB)
- rm $(DESTDIR)$(libdir)/$(TOOLLIB)
+ rm $(DESTDIR)$(libdir)/libzint.*
rm $(DESTDIR)$(includedir)/zint.h
- rm $(DESTDIR)$(bindir)/$(DLL)
+ rm $(DESTDIR)$(bindir)/zint.dll
clean:
- rm -f *.lib *.dll *.o *.a *~ *.res *.exe *.lo *.bak
+ rm -f *.lib *.dll *.o *.a *~ *.res *.exe *.def *.lo *.bak
diff --git a/backend/auspost.c b/backend/auspost.c
new file mode 100644
index 0000000..39d3414
--- /dev/null
+++ b/backend/auspost.c
@@ -0,0 +1,250 @@
+/* auspost.c - Handles Australia Post 4-State Barcode */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2008-2017 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+#define GDSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz #"
+
+static const char *AusNTable[10] = {
+ "00", "01", "02", "10", "11", "12", "20", "21", "22", "30"
+};
+
+static const char *AusCTable[64] = {
+ "222", "300", "301", "302", "310", "311", "312", "320", "321", "322",
+ "000", "001", "002", "010", "011", "012", "020", "021", "022", "100", "101", "102", "110",
+ "111", "112", "120", "121", "122", "200", "201", "202", "210", "211", "212", "220", "221",
+ "023", "030", "031", "032", "033", "103", "113", "123", "130", "131", "132", "133", "203",
+ "213", "223", "230", "231", "232", "233", "303", "313", "323", "330", "331", "332", "333",
+ "003", "013"
+};
+
+static const char *AusBarTable[64] = {
+ "000", "001", "002", "003", "010", "011", "012", "013", "020", "021",
+ "022", "023", "030", "031", "032", "033", "100", "101", "102", "103", "110", "111", "112",
+ "113", "120", "121", "122", "123", "130", "131", "132", "133", "200", "201", "202", "203",
+ "210", "211", "212", "213", "220", "221", "222", "223", "230", "231", "232", "233", "300",
+ "301", "302", "303", "310", "311", "312", "313", "320", "321", "322", "323", "330", "331",
+ "332", "333"
+};
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "common.h"
+#include "reedsol.h"
+#ifdef _MSC_VER
+#define inline _inline
+#endif
+
+static inline char convert_pattern(char data, int shift) {
+ return (data - '0') << shift;
+}
+
+/* Adds Reed-Solomon error correction to auspost */
+static void rs_error(char data_pattern[]) {
+ size_t reader, triple_writer = 0;
+ char triple[31];
+ unsigned char result[5];
+
+ for (reader = 2; reader < strlen(data_pattern); reader += 3, triple_writer++) {
+ triple[triple_writer] = convert_pattern(data_pattern[reader], 4)
+ + convert_pattern(data_pattern[reader + 1], 2)
+ + convert_pattern(data_pattern[reader + 2], 0);
+ }
+
+ rs_init_gf(0x43);
+ rs_init_code(4, 1);
+ rs_encode(triple_writer, (unsigned char*) triple, result);
+
+ for (reader = 4; reader > 0; reader--) {
+ strcat(data_pattern, AusBarTable[(int) result[reader - 1]]);
+ }
+ rs_free();
+}
+
+/* Handles Australia Posts's 4 State Codes */
+INTERNAL int australia_post(struct zint_symbol *symbol, unsigned char source[], int length) {
+ /* Customer Standard Barcode, Barcode 2 or Barcode 3 system determined automatically
+ (i.e. the FCC doesn't need to be specified by the user) dependent
+ on the length of the input string */
+
+ /* The contents of data_pattern conform to the following standard:
+ 0 = Tracker, Ascender and Descender
+ 1 = Tracker and Ascender
+ 2 = Tracker and Descender
+ 3 = Tracker only */
+ int error_number;
+ int writer;
+ unsigned int loopey, reader;
+ size_t h;
+
+ char data_pattern[200];
+ char fcc[3] = {0, 0, 0}, dpid[10];
+ char localstr[30];
+
+ /* Check input immediately to catch nuls */
+ error_number = is_sane(GDSET, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "404: Invalid characters in data");
+ return error_number;
+ }
+ strcpy(localstr, "");
+
+ /* Do all of the length checking first to avoid stack smashing */
+ if (symbol->symbology == BARCODE_AUSPOST) {
+ /* Format control code (FCC) */
+ switch (length) {
+ case 8:
+ strcpy(fcc, "11");
+ break;
+ case 13:
+ strcpy(fcc, "59");
+ break;
+ case 16:
+ strcpy(fcc, "59");
+ error_number = is_sane(NEON, source, length);
+ break;
+ case 18:
+ strcpy(fcc, "62");
+ break;
+ case 23:
+ strcpy(fcc, "62");
+ error_number = is_sane(NEON, source, length);
+ break;
+ default:
+ strcpy(symbol->errtxt, "401: Auspost input is wrong length");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "402: Invalid characters in data");
+ return error_number;
+ }
+ } else {
+ int zeroes;
+ if (length > 8) {
+ strcpy(symbol->errtxt, "403: Auspost input is too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ switch (symbol->symbology) {
+ case BARCODE_AUSREPLY: strcpy(fcc, "45");
+ break;
+ case BARCODE_AUSROUTE: strcpy(fcc, "87");
+ break;
+ case BARCODE_AUSREDIRECT: strcpy(fcc, "92");
+ break;
+ }
+
+ /* Add leading zeros as required */
+ zeroes = 8 - length;
+ memset(localstr, '0', zeroes);
+ localstr[zeroes] = '\0';
+ }
+
+ strcat(localstr, (char*) source);
+ h = strlen(localstr);
+ /* Verifiy that the first 8 characters are numbers */
+ memcpy(dpid, localstr, 8);
+ dpid[8] = '\0';
+ error_number = is_sane(NEON, (unsigned char *) dpid, strlen(dpid));
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "405: Invalid characters in DPID");
+ return error_number;
+ }
+
+ /* Start character */
+ strcpy(data_pattern, "13");
+
+ /* Encode the FCC */
+ for (reader = 0; reader < 2; reader++) {
+ lookup(NEON, AusNTable, fcc[reader], data_pattern);
+ }
+
+ /* printf("AUSPOST FCC: %s ", fcc); */
+
+ /* Delivery Point Identifier (DPID) */
+ for (reader = 0; reader < 8; reader++) {
+ lookup(NEON, AusNTable, dpid[reader], data_pattern);
+ }
+
+ /* Customer Information */
+ if (h > 8) {
+ if ((h == 13) || (h == 18)) {
+ for (reader = 8; reader < h; reader++) {
+ lookup(GDSET, AusCTable, localstr[reader], data_pattern);
+ }
+ } else if ((h == 16) || (h == 23)) {
+ for (reader = 8; reader < h; reader++) {
+ lookup(NEON, AusNTable, localstr[reader], data_pattern);
+ }
+ }
+ }
+
+ /* Filler bar */
+ h = strlen(data_pattern);
+ switch (h) {
+ case 22:
+ case 37:
+ case 52:
+ strcat(data_pattern, "3");
+ break;
+ default:
+ break;
+ }
+
+ /* Reed Solomon error correction */
+ rs_error(data_pattern);
+
+ /* Stop character */
+ strcat(data_pattern, "13");
+
+ /* Turn the symbol into a bar pattern ready for plotting */
+ writer = 0;
+ h = strlen(data_pattern);
+ for (loopey = 0; loopey < h; loopey++) {
+ if ((data_pattern[loopey] == '1') || (data_pattern[loopey] == '0')) {
+ set_module(symbol, 0, writer);
+ }
+ set_module(symbol, 1, writer);
+ if ((data_pattern[loopey] == '2') || (data_pattern[loopey] == '0')) {
+ set_module(symbol, 2, writer);
+ }
+ writer += 2;
+ }
+
+ symbol->row_height[0] = 3;
+ symbol->row_height[1] = 2;
+ symbol->row_height[2] = 3;
+
+ symbol->rows = 3;
+ symbol->width = writer - 1;
+
+ return error_number;
+}
diff --git a/backend/aztec.c b/backend/aztec.c
new file mode 100644
index 0000000..f5e88bd
--- /dev/null
+++ b/backend/aztec.c
@@ -0,0 +1,1686 @@
+/* aztec.c - Handles Aztec 2D Symbols */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2009-2020 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "aztec.h"
+#include "reedsol.h"
+
+#define AZTEC_MAX_CAPACITY 19968 /* ISO/IEC 24778:2008 5.3 Table 1 Maximum Symbol Bit Capacity */
+#define AZTEC_BIN_CAPACITY 17940 /* Above less 169 * 12 = 2028 bits (169 = 10% of 1664 + 3) */
+
+static int AztecMap[22801];
+
+static int count_doubles(const unsigned char source[], const int posn, const size_t src_len) {
+ int c = 0;
+ int i = posn;
+ int cond = 1;
+
+ do {
+ if (((source[i] == '.') || (source[i] == ',')) && (source[i + 1] == ' ')) {
+ c++;
+ } else {
+ cond = 0;
+ }
+ i += 2;
+ } while ((i < (int) src_len) && cond);
+
+ return c;
+}
+
+static int count_cr(unsigned char source[], int posn, int length) {
+ int c = 0;
+ int i = posn;
+ int cond = 1;
+
+ do {
+ if (source[i] == 13) {
+ c++;
+ } else {
+ cond = 0;
+ }
+ i++;
+ } while ((i < length) && cond);
+
+ return c;
+}
+
+static int count_dotcomma(unsigned char source[], int posn, int length) {
+ int c = 0;
+ int i = posn;
+ int cond = 1;
+
+ do {
+ if ((source[i] == '.') || (source[i] == ',')) {
+ c++;
+ } else {
+ cond = 0;
+ }
+ i++;
+ } while ((i < length) && cond);
+
+ return c;
+}
+
+static int count_spaces(unsigned char source[], int posn, int length) {
+ int c = 0;
+ int i = posn;
+ int cond = 1;
+
+ do {
+ if (source[i] == ' ') {
+ c++;
+ } else {
+ cond = 0;
+ }
+ i++;
+ } while ((i < length) && cond);
+
+ return c;
+}
+
+static char get_next_mode(char encode_mode[], const size_t src_len, const int posn) {
+ int i = posn;
+
+ do {
+ i++;
+ } while ((i < (int) src_len) && (encode_mode[i] == encode_mode[posn]));
+ if (i >= (int) src_len) {
+ return 'E';
+ } else {
+ return encode_mode[i];
+ }
+}
+
+static int az_bin_append(const int arg, const int length, char *binary) {
+ size_t posn = strlen(binary);
+
+ if (posn + length > AZTEC_BIN_CAPACITY) {
+ return 0; /* Fail */
+ }
+ bin_append_posn(arg, length, binary, posn);
+
+ binary[posn + length] = '\0';
+
+ return 1; /* Success */
+}
+
+static int aztec_text_process(const unsigned char source[], const size_t src_len, char binary_string[], const int gs1, const int eci, const int debug) {
+
+ int i, j;
+ char current_mode;
+ int count;
+ char next_mode;
+ int reduced_length;
+ int byte_mode = 0;
+
+#ifndef _MSC_VER
+ char encode_mode[src_len + 1];
+ unsigned char reduced_source[src_len + 1];
+ char reduced_encode_mode[src_len + 1];
+#else
+ char *encode_mode = (char *) _alloca(src_len + 1);
+ unsigned char *reduced_source = (unsigned char *) _alloca(src_len + 1);
+ char *reduced_encode_mode = (char *) _alloca(src_len + 1);
+#endif
+
+ for (i = 0; i < (int) src_len; i++) {
+ if (source[i] >= 128) {
+ encode_mode[i] = 'B';
+ } else {
+ encode_mode[i] = AztecModes[(int) source[i]];
+ }
+ }
+
+ // Deal first with letter combinations which can be combined to one codeword
+ // Combinations are (CR LF) (. SP) (, SP) (: SP) in Punct mode
+ current_mode = 'U';
+ for (i = 0; i < (int) src_len - 1; i++) {
+ // Combination (CR LF) should always be in Punct mode
+ if ((source[i] == 13) && (source[i + 1] == 10)) {
+ encode_mode[i] = 'P';
+ encode_mode[i + 1] = 'P';
+ }
+
+ // Combination (: SP) should always be in Punct mode
+ if ((source[i] == ':') && (source[i + 1] == ' ')) {
+ encode_mode[i + 1] = 'P';
+ }
+
+ // Combinations (. SP) and (, SP) sometimes use fewer bits in Digit mode
+ if (((source[i] == '.') || (source[i] == ',')) && (source[i + 1] == ' ') && (encode_mode[i] == 'X')) {
+ count = count_doubles(source, i, src_len);
+ next_mode = get_next_mode(encode_mode, src_len, i);
+
+ if (current_mode == 'U') {
+ if ((next_mode == 'D') && (count <= 5)) {
+ for (j = 0; j < (2 * count); j++) {
+ encode_mode[i + j] = 'D';
+ }
+ }
+ }
+
+ if (current_mode == 'L') {
+ if ((next_mode == 'U') && (count == 1)) {
+ encode_mode[i] = 'D';
+ encode_mode[i + 1] = 'D';
+ }
+ if ((next_mode == 'D') && (count <= 4)) {
+ for (j = 0; j < (2 * count); j++) {
+ encode_mode[i + j] = 'D';
+ }
+ }
+ }
+
+ if (current_mode == 'M') {
+ if ((next_mode == 'D') && (count == 1)) {
+ encode_mode[i] = 'D';
+ encode_mode[i + 1] = 'D';
+ }
+ }
+
+ if (current_mode == 'D') {
+ if ((next_mode != 'D') && (count <= 4)) {
+ for (j = 0; j < (2 * count); j++) {
+ encode_mode[i + j] = 'D';
+ }
+ }
+ if ((next_mode == 'D') && (count <= 7)) {
+ for (j = 0; j < (2 * count); j++) {
+ encode_mode[i + j] = 'D';
+ }
+ }
+ }
+
+ // Default is Punct mode
+ if (encode_mode[i] == 'X') {
+ encode_mode[i] = 'P';
+ encode_mode[i + 1] = 'P';
+ }
+ }
+
+ if ((encode_mode[i] != 'X') && (encode_mode[i] != 'B')) {
+ current_mode = encode_mode[i];
+ }
+ }
+
+ if (debug) {
+ printf("First Pass:\n");
+ for (i = 0; i < (int) src_len; i++) {
+ printf("%c", encode_mode[i]);
+ }
+ printf("\n");
+ }
+
+ // Reduce two letter combinations to one codeword marked as [abcd] in Punct mode
+ i = 0;
+ j = 0;
+ while (i < (int) src_len) {
+ if ((source[i] == 13) && (source[i + 1] == 10)) { // CR LF
+ reduced_source[j] = 'a';
+ reduced_encode_mode[j] = encode_mode[i];
+ i += 2;
+ } else if (((source[i] == '.') && (source[i + 1] == ' ')) && (encode_mode[i] == 'P')) {
+ reduced_source[j] = 'b';
+ reduced_encode_mode[j] = encode_mode[i];
+ i += 2;
+ } else if (((source[i] == ',') && (source[i + 1] == ' ')) && (encode_mode[i] == 'P')) {
+ reduced_source[j] = 'c';
+ reduced_encode_mode[j] = encode_mode[i];
+ i += 2;
+ } else if ((source[i] == ':') && (source[i + 1] == ' ')) {
+ reduced_source[j] = 'd';
+ reduced_encode_mode[j] = encode_mode[i];
+ i += 2;
+ } else {
+ reduced_source[j] = source[i];
+ reduced_encode_mode[j] = encode_mode[i];
+ i++;
+ }
+ j++;
+ }
+
+ reduced_length = j;
+
+ current_mode = 'U';
+ for(i = 0; i < reduced_length; i++) {
+ // Resolve Carriage Return (CR) which can be Punct or Mixed mode
+ if (reduced_source[i] == 13) {
+ count = count_cr(reduced_source, i, reduced_length);
+ next_mode = get_next_mode(reduced_encode_mode, reduced_length, i);
+
+ if ((current_mode == 'U') && ((next_mode == 'U') || (next_mode == 'B')) && (count == 1)) {
+ reduced_encode_mode[i] = 'P';
+ }
+
+ if ((current_mode == 'L') && ((next_mode == 'L') || (next_mode == 'B')) && (count == 1)) {
+ reduced_encode_mode[i] = 'P';
+ }
+
+ if ((current_mode == 'P') || (next_mode == 'P')) {
+ reduced_encode_mode[i] = 'P';
+ }
+
+ if (current_mode == 'D') {
+ if (((next_mode == 'E') || (next_mode == 'U') || (next_mode == 'D') || (next_mode == 'B')) && (count <= 2)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'P';
+ }
+ }
+ if ((next_mode == 'L') && (count == 1)) {
+ reduced_encode_mode[i] = 'P';
+ }
+ }
+
+ // Default is Mixed mode
+ if (reduced_encode_mode[i] == 'X') {
+ reduced_encode_mode[i] = 'M';
+ }
+ }
+
+ // Resolve full stop and comma which can be in Punct or Digit mode
+ if ((reduced_source[i] == '.') || (reduced_source[i] == ',')) {
+ count = count_dotcomma(reduced_source, i, reduced_length);
+ next_mode = get_next_mode(reduced_encode_mode, reduced_length, i);
+
+ if (current_mode == 'U') {
+ if (((next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M') || (next_mode == 'B')) && (count == 1)) {
+ reduced_encode_mode[i] = 'P';
+ }
+ }
+
+ if (current_mode == 'L') {
+ if ((next_mode == 'L') && (count <= 2)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'P';
+ }
+ }
+ if (((next_mode == 'M') || (next_mode == 'B')) && (count == 1)) {
+ reduced_encode_mode[i] = 'P';
+ }
+ }
+
+ if (current_mode == 'M') {
+ if (((next_mode == 'E') || (next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M')) && (count <= 4)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'P';
+ }
+ }
+ if ((next_mode == 'B') && (count <= 2)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'P';
+ }
+ }
+ }
+
+ if ((current_mode == 'P') && (next_mode != 'D') && (count <= 9)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'P';
+ }
+ }
+
+ // Default is Digit mode
+ if (reduced_encode_mode[i] == 'X') {
+ reduced_encode_mode[i] = 'D';
+ }
+ }
+
+ // Resolve Space (SP) which can be any mode except Punct
+ if (reduced_source[i] == ' ') {
+ count = count_spaces(reduced_source, i, reduced_length);
+ next_mode = get_next_mode(reduced_encode_mode, reduced_length, i);
+
+ if (current_mode == 'U') {
+ if ((next_mode == 'E') && (count <= 5)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'U';
+ }
+ }
+ if (((next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M') || (next_mode == 'P') || (next_mode == 'B')) && (count <= 9)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'U';
+ }
+ }
+ }
+
+ if (current_mode == 'L') {
+ if ((next_mode == 'E') && (count <= 5)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'L';
+ }
+ }
+ if ((next_mode == 'U') && (count == 1)) {
+ reduced_encode_mode[i] = 'L';
+ }
+ if ((next_mode == 'L') && (count <= 14)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'L';
+ }
+ }
+ if (((next_mode == 'M') || (next_mode == 'P') || (next_mode == 'B')) && (count <= 9)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'L';
+ }
+ }
+ }
+
+ if (current_mode == 'M') {
+ if (((next_mode == 'E') || (next_mode == 'U')) && (count <= 9)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'M';
+ }
+ }
+
+ if (((next_mode == 'L') || (next_mode == 'B')) && (count <= 14)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'M';
+ }
+ }
+
+ if (((next_mode == 'M') || (next_mode == 'P')) && (count <= 19)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'M';
+ }
+ }
+ }
+
+ if (current_mode == 'P') {
+ if ((next_mode == 'E') && (count <= 5)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'U';
+ }
+ }
+
+ if (((next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M') || (next_mode == 'P') || (next_mode == 'B')) && (count <= 9)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'U';
+ }
+ }
+ }
+
+ // Default is Digit mode
+ if (reduced_encode_mode[i] == 'X') {
+ reduced_encode_mode[i] = 'D';
+ }
+ }
+
+ if (reduced_encode_mode[i] != 'B') {
+ current_mode = reduced_encode_mode[i];
+ }
+ }
+
+ // Decide when to use P/S instead of P/L and U/S instead of U/L
+ current_mode = 'U';
+ for(i = 0; i < reduced_length; i++) {
+
+ if (reduced_encode_mode[i] != current_mode) {
+
+ for (count = 0; ((i + count) < reduced_length) && (reduced_encode_mode[i + count] == reduced_encode_mode[i]); count++);
+ next_mode = get_next_mode(reduced_encode_mode, reduced_length, i);
+
+ if (reduced_encode_mode[i] == 'P') {
+ if ((current_mode == 'U') && (count <= 2)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'p';
+ }
+ }
+
+ if ((current_mode == 'L') && (next_mode != 'U') && (count <= 2)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'p';
+ }
+ }
+
+ if ((current_mode == 'L') && (next_mode == 'U') && (count == 1)) {
+ reduced_encode_mode[i] = 'p';
+ }
+
+ if ((current_mode == 'M') && (next_mode != 'M') && (count == 1)) {
+ reduced_encode_mode[i] = 'p';
+ }
+
+ if ((current_mode == 'M') && (next_mode == 'M') && (count <= 2)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'p';
+ }
+ }
+
+ if ((current_mode == 'D') && (next_mode != 'D') && (count <= 3)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'p';
+ }
+ }
+
+ if ((current_mode == 'D') && (next_mode == 'D') && (count <= 6)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'p';
+ }
+ }
+ }
+
+ if (reduced_encode_mode[i] == 'U') {
+ if ((current_mode == 'L') && ((next_mode == 'L') || (next_mode == 'M')) && (count <= 2)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'u';
+ }
+ }
+
+ if ((current_mode == 'L') && ((next_mode == 'E') || (next_mode == 'D') || (next_mode == 'B') || (next_mode == 'P')) && (count == 1)) {
+ reduced_encode_mode[i] = 'u';
+ }
+
+ if ((current_mode == 'D') && (next_mode == 'D') && (count == 1)) {
+ reduced_encode_mode[i] = 'u';
+ }
+
+ if ((current_mode == 'D') && (next_mode == 'P') && (count <= 2)) {
+ for (j = 0; j < count; j++) {
+ reduced_encode_mode[i + j] = 'u';
+ }
+ }
+ }
+ }
+
+ if ((reduced_encode_mode[i] != 'p') && (reduced_encode_mode[i] != 'u') && (reduced_encode_mode[i] != 'B')) {
+ current_mode = reduced_encode_mode[i];
+ }
+ }
+
+ if (debug) {
+ for (i = 0; i < reduced_length; i++) {
+ printf("%c", reduced_source[i]);
+ }
+ printf("\n");
+ for (i = 0; i < reduced_length; i++) {
+ printf("%c", reduced_encode_mode[i]);
+ }
+ printf("\n");
+ }
+
+ strcpy(binary_string, "");
+
+ if (gs1) {
+ bin_append(0, 5, binary_string); // P/S
+ bin_append(0, 5, binary_string); // FLG(n)
+ bin_append(0, 3, binary_string); // FLG(0)
+ }
+
+ if (eci != 0) {
+ bin_append(0, 5, binary_string); // P/S
+ bin_append(0, 5, binary_string); // FLG(n)
+ if (eci < 10) {
+ bin_append(1, 3, binary_string); // FLG(1)
+ bin_append(2 + eci, 4, binary_string);
+ }
+ if ((eci >= 10) && (eci <= 99)) {
+ bin_append(2, 3, binary_string); // FLG(2)
+ bin_append(2 + (eci / 10), 4, binary_string);
+ bin_append(2 + (eci % 10), 4, binary_string);
+ }
+ if ((eci >= 100) && (eci <= 999)) {
+ bin_append(3, 3, binary_string); // FLG(3)
+ bin_append(2 + (eci / 100), 4, binary_string);
+ bin_append(2 + ((eci % 100) / 10), 4, binary_string);
+ bin_append(2 + (eci % 10), 4, binary_string);
+ }
+ if ((eci >= 1000) && (eci <= 9999)) {
+ bin_append(4, 3, binary_string); // FLG(4)
+ bin_append(2 + (eci / 1000), 4, binary_string);
+ bin_append(2 + ((eci % 1000) / 100), 4, binary_string);
+ bin_append(2 + ((eci % 100) / 10), 4, binary_string);
+ bin_append(2 + (eci % 10), 4, binary_string);
+ }
+ if ((eci >= 10000) && (eci <= 99999)) {
+ bin_append(5, 3, binary_string); // FLG(5)
+ bin_append(2 + (eci / 10000), 4, binary_string);
+ bin_append(2 + ((eci % 10000) / 1000), 4, binary_string);
+ bin_append(2 + ((eci % 1000) / 100), 4, binary_string);
+ bin_append(2 + ((eci % 100) / 10), 4, binary_string);
+ bin_append(2 + (eci % 10), 4, binary_string);
+ }
+ if (eci >= 100000) {
+ bin_append(6, 3, binary_string); // FLG(6)
+ bin_append(2 + (eci / 100000), 4, binary_string);
+ bin_append(2 + ((eci % 100000) / 10000), 4, binary_string);
+ bin_append(2 + ((eci % 10000) / 1000), 4, binary_string);
+ bin_append(2 + ((eci % 1000) / 100), 4, binary_string);
+ bin_append(2 + ((eci % 100) / 10), 4, binary_string);
+ bin_append(2 + (eci % 10), 4, binary_string);
+ }
+ }
+
+ current_mode = 'U';
+ for (i = 0; i < reduced_length; i++) {
+
+ if (reduced_encode_mode[i] != 'B') {
+ byte_mode = 0;
+ }
+
+ if ((reduced_encode_mode[i] != current_mode) && (!byte_mode)) {
+ // Change mode
+ if (current_mode == 'U') {
+ switch (reduced_encode_mode[i]) {
+ case 'L':
+ if (!az_bin_append(28, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // L/L
+ break;
+ case 'M':
+ if (!az_bin_append(29, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // M/L
+ break;
+ case 'P':
+ if (!az_bin_append(29, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // M/L
+ if (!az_bin_append(30, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // P/L
+ break;
+ case 'p':
+ if (!az_bin_append(0, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // P/S
+ break;
+ case 'D':
+ if (!az_bin_append(30, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // D/L
+ break;
+ case 'B':
+ if (!az_bin_append(31, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // B/S
+ break;
+ }
+ }
+
+ if (current_mode == 'L') {
+ switch (reduced_encode_mode[i]) {
+ case 'U':
+ if (!az_bin_append(30, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // D/L
+ if (!az_bin_append(14, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ break;
+ case 'u':
+ if (!az_bin_append(28, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // U/S
+ break;
+ case 'M':
+ if (!az_bin_append(29, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // M/L
+ break;
+ case 'P':
+ if (!az_bin_append(29, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // M/L
+ if (!az_bin_append(30, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // P/L
+ break;
+ case 'p':
+ if (!az_bin_append(0, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // P/S
+ break;
+ case 'D':
+ if (!az_bin_append(30, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // D/L
+ break;
+ case 'B':
+ if (!az_bin_append(31, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // B/S
+ break;
+ }
+ }
+
+ if (current_mode == 'M') {
+ switch (reduced_encode_mode[i]) {
+ case 'U':
+ if (!az_bin_append(29, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ break;
+ case 'L':
+ if (!az_bin_append(28, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // L/L
+ break;
+ case 'P':
+ if (!az_bin_append(30, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // P/L
+ break;
+ case 'p':
+ if (!az_bin_append(0, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // P/S
+ break;
+ case 'D':
+ if (!az_bin_append(29, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ if (!az_bin_append(30, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // D/L
+ break;
+ case 'B':
+ if (!az_bin_append(31, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // B/S
+ break;
+ }
+ }
+
+ if (current_mode == 'P') {
+ switch (reduced_encode_mode[i]) {
+ case 'U':
+ if (!az_bin_append(31, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ break;
+ case 'L':
+ if (!az_bin_append(31, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ if (!az_bin_append(28, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // L/L
+ break;
+ case 'M':
+ if (!az_bin_append(31, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ if (!az_bin_append(29, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // M/L
+ break;
+ case 'D':
+ if (!az_bin_append(31, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ if (!az_bin_append(30, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // D/L
+ break;
+ case 'B':
+ if (!az_bin_append(31, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ current_mode = 'U';
+ if (!az_bin_append(31, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // B/S
+ break;
+ }
+ }
+
+ if (current_mode == 'D') {
+ switch (reduced_encode_mode[i]) {
+ case 'U':
+ if (!az_bin_append(14, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ break;
+ case 'u':
+ if (!az_bin_append(15, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // U/S
+ break;
+ case 'L':
+ if (!az_bin_append(14, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ if (!az_bin_append(28, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // L/L
+ break;
+ case 'M':
+ if (!az_bin_append(14, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ if (!az_bin_append(29, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // M/L
+ break;
+ case 'P':
+ if (!az_bin_append(14, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ if (!az_bin_append(29, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // M/L
+ if (!az_bin_append(30, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // P/L
+ break;
+ case 'p':
+ if (!az_bin_append(0, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // P/S
+ break;
+ case 'B':
+ if (!az_bin_append(14, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // U/L
+ current_mode = 'U';
+ if (!az_bin_append(31, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // B/S
+ break;
+ }
+ }
+
+ // Byte mode length descriptor
+ if ((reduced_encode_mode[i] == 'B') && (!byte_mode)) {
+ for (count = 0; ((i + count) < reduced_length) && (reduced_encode_mode[i + count] == 'B'); count++);
+
+ if (count > 2079) {
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ if (count > 31) {
+ /* Put 00000 followed by 11-bit number of bytes less 31 */
+ if (!az_bin_append(0, 5, binary_string)) return ZINT_ERROR_TOO_LONG;
+ if (!az_bin_append(count - 31, 11, binary_string)) return ZINT_ERROR_TOO_LONG;
+ } else {
+ /* Put 5-bit number of bytes */
+ if (!az_bin_append(count, 5, binary_string)) return ZINT_ERROR_TOO_LONG;
+ }
+ byte_mode = 1;
+ }
+
+ if ((reduced_encode_mode[i] != 'B') && (reduced_encode_mode[i] != 'u') && (reduced_encode_mode[i] != 'p')) {
+ current_mode = reduced_encode_mode[i];
+ }
+ }
+
+ if ((reduced_encode_mode[i] == 'U') || (reduced_encode_mode[i] == 'u')) {
+ if (reduced_source[i] == ' ') {
+ if (!az_bin_append(1, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // SP
+ } else {
+ if (!az_bin_append(AztecSymbolChar[(int) reduced_source[i]], 5, binary_string)) return ZINT_ERROR_TOO_LONG;
+ }
+ }
+
+ if (reduced_encode_mode[i] == 'L') {
+ if (reduced_source[i] == ' ') {
+ if (!az_bin_append(1, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // SP
+ } else {
+ if (!az_bin_append(AztecSymbolChar[(int) reduced_source[i]], 5, binary_string)) return ZINT_ERROR_TOO_LONG;
+ }
+ }
+
+ if (reduced_encode_mode[i] == 'M') {
+ if (reduced_source[i] == ' ') {
+ if (!az_bin_append(1, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // SP
+ } else if (reduced_source[i] == 13) {
+ if (!az_bin_append(14, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // CR
+ } else {
+ if (!az_bin_append(AztecSymbolChar[(int) reduced_source[i]], 5, binary_string)) return ZINT_ERROR_TOO_LONG;
+ }
+ }
+
+ if ((reduced_encode_mode[i] == 'P') || (reduced_encode_mode[i] == 'p')) {
+ if (gs1 && (reduced_source[i] == '[')) {
+ if (!az_bin_append(0, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // FLG(n)
+ if (!az_bin_append(0, 3, binary_string)) return ZINT_ERROR_TOO_LONG; // FLG(0) = FNC1
+ } else if (reduced_source[i] == 13) {
+ if (!az_bin_append(1, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // CR
+ } else if (reduced_source[i] == 'a') {
+ if (!az_bin_append(2, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // CR LF
+ } else if (reduced_source[i] == 'b') {
+ if (!az_bin_append(3, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // . SP
+ } else if (reduced_source[i] == 'c') {
+ if (!az_bin_append(4, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // , SP
+ } else if (reduced_source[i] == 'd') {
+ if (!az_bin_append(5, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // : SP
+ } else if (reduced_source[i] == ',') {
+ if (!az_bin_append(17, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // Comma
+ } else if (reduced_source[i] == '.') {
+ if (!az_bin_append(19, 5, binary_string)) return ZINT_ERROR_TOO_LONG; // Full stop
+ } else {
+ if (!az_bin_append(AztecSymbolChar[(int) reduced_source[i]], 5, binary_string)) return ZINT_ERROR_TOO_LONG;
+ }
+ }
+
+ if (reduced_encode_mode[i] == 'D') {
+ if (reduced_source[i] == ' ') {
+ if (!az_bin_append(1, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // SP
+ } else if (reduced_source[i] == ',') {
+ if (!az_bin_append(12, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // Comma
+ } else if (reduced_source[i] == '.') {
+ if (!az_bin_append(13, 4, binary_string)) return ZINT_ERROR_TOO_LONG; // Full stop
+ } else {
+ if (!az_bin_append(AztecSymbolChar[(int) reduced_source[i]], 4, binary_string)) return ZINT_ERROR_TOO_LONG;
+ }
+ }
+
+ if (reduced_encode_mode[i] == 'B') {
+ if (!az_bin_append(reduced_source[i], 8, binary_string)) return ZINT_ERROR_TOO_LONG;
+ }
+ }
+
+ if (debug) {
+ printf("Binary String:\n");
+ printf("%s\n", binary_string);
+ }
+
+ return 0;
+}
+
+/* Prevent data from obscuring reference grid */
+static int avoidReferenceGrid(int output) {
+
+ if (output > 10) {
+ output++;
+ }
+ if (output > 26) {
+ output++;
+ }
+ if (output > 42) {
+ output++;
+ }
+ if (output > 58) {
+ output++;
+ }
+ if (output > 74) {
+ output++;
+ }
+ if (output > 90) {
+ output++;
+ }
+ if (output > 106) {
+ output++;
+ }
+ if (output > 122) {
+ output++;
+ }
+ if (output > 138) {
+ output++;
+ }
+
+ return output;
+}
+
+/* Calculate the position of the bits in the grid */
+static void populate_map() {
+ int layer, n, i;
+ int x, y;
+
+ for (x = 0; x < 151; x++) {
+ for (y = 0; y < 151; y++) {
+ AztecMap[(x * 151) + y] = 0;
+ }
+ }
+
+ for (layer = 1; layer < 33; layer++) {
+ const int start = (112 * (layer - 1)) + (16 * (layer - 1) * (layer - 1)) + 2;
+ const int length = 28 + ((layer - 1) * 4) + (layer * 4);
+ /* Top */
+ i = 0;
+ x = 64 - ((layer - 1) * 2);
+ y = 63 - ((layer - 1) * 2);
+ for (n = start; n < (start + length); n += 2) {
+ AztecMap[(avoidReferenceGrid(y) * 151) + avoidReferenceGrid(x + i)] = n;
+ AztecMap[(avoidReferenceGrid(y - 1) * 151) + avoidReferenceGrid(x + i)] = n + 1;
+ i++;
+ }
+ /* Right */
+ i = 0;
+ x = 78 + ((layer - 1) * 2);
+ y = 64 - ((layer - 1) * 2);
+ for (n = start + length; n < (start + (length * 2)); n += 2) {
+ AztecMap[(avoidReferenceGrid(y + i) * 151) + avoidReferenceGrid(x)] = n;
+ AztecMap[(avoidReferenceGrid(y + i) * 151) + avoidReferenceGrid(x + 1)] = n + 1;
+ i++;
+ }
+ /* Bottom */
+ i = 0;
+ x = 77 + ((layer - 1) * 2);
+ y = 78 + ((layer - 1) * 2);
+ for (n = start + (length * 2); n < (start + (length * 3)); n += 2) {
+ AztecMap[(avoidReferenceGrid(y) * 151) + avoidReferenceGrid(x - i)] = n;
+ AztecMap[(avoidReferenceGrid(y + 1) * 151) + avoidReferenceGrid(x - i)] = n + 1;
+ i++;
+ }
+ /* Left */
+ i = 0;
+ x = 63 - ((layer - 1) * 2);
+ y = 77 + ((layer - 1) * 2);
+ for (n = start + (length * 3); n < (start + (length * 4)); n += 2) {
+ AztecMap[(avoidReferenceGrid(y - i) * 151) + avoidReferenceGrid(x)] = n;
+ AztecMap[(avoidReferenceGrid(y - i) * 151) + avoidReferenceGrid(x - 1)] = n + 1;
+ i++;
+ }
+ }
+
+ /* Central finder pattern */
+ for (y = 69; y <= 81; y++) {
+ for (x = 69; x <= 81; x++) {
+ AztecMap[(x * 151) + y] = 1;
+ }
+ }
+ for (y = 70; y <= 80; y++) {
+ for (x = 70; x <= 80; x++) {
+ AztecMap[(x * 151) + y] = 0;
+ }
+ }
+ for (y = 71; y <= 79; y++) {
+ for (x = 71; x <= 79; x++) {
+ AztecMap[(x * 151) + y] = 1;
+ }
+ }
+ for (y = 72; y <= 78; y++) {
+ for (x = 72; x <= 78; x++) {
+ AztecMap[(x * 151) + y] = 0;
+ }
+ }
+ for (y = 73; y <= 77; y++) {
+ for (x = 73; x <= 77; x++) {
+ AztecMap[(x * 151) + y] = 1;
+ }
+ }
+ for (y = 74; y <= 76; y++) {
+ for (x = 74; x <= 76; x++) {
+ AztecMap[(x * 151) + y] = 0;
+ }
+ }
+
+ /* Guide bars */
+ for (y = 11; y < 151; y += 16) {
+ for (x = 1; x < 151; x += 2) {
+ AztecMap[(x * 151) + y] = 1;
+ AztecMap[(y * 151) + x] = 1;
+ }
+ }
+
+ /* Descriptor */
+ for (i = 0; i < 10; i++) {
+ /* Top */
+ AztecMap[(avoidReferenceGrid(64) * 151) + avoidReferenceGrid(66 + i)] = 20000 + i;
+ }
+ for (i = 0; i < 10; i++) {
+ /* Right */
+ AztecMap[(avoidReferenceGrid(66 + i) * 151) + avoidReferenceGrid(77)] = 20010 + i;
+ }
+ for (i = 0; i < 10; i++) {
+ /* Bottom */
+ AztecMap[(avoidReferenceGrid(77) * 151) + avoidReferenceGrid(75 - i)] = 20020 + i;
+ }
+ for (i = 0; i < 10; i++) {
+ /* Left */
+ AztecMap[(avoidReferenceGrid(75 - i) * 151) + avoidReferenceGrid(64)] = 20030 + i;
+ }
+
+ /* Orientation */
+ AztecMap[(avoidReferenceGrid(64) * 151) + avoidReferenceGrid(64)] = 1;
+ AztecMap[(avoidReferenceGrid(65) * 151) + avoidReferenceGrid(64)] = 1;
+ AztecMap[(avoidReferenceGrid(64) * 151) + avoidReferenceGrid(65)] = 1;
+ AztecMap[(avoidReferenceGrid(64) * 151) + avoidReferenceGrid(77)] = 1;
+ AztecMap[(avoidReferenceGrid(65) * 151) + avoidReferenceGrid(77)] = 1;
+ AztecMap[(avoidReferenceGrid(76) * 151) + avoidReferenceGrid(77)] = 1;
+}
+
+INTERNAL int aztec(struct zint_symbol *symbol, unsigned char source[], const size_t length) {
+ int x, y, i, j, p, data_blocks, ecc_blocks, layers, total_bits;
+ char binary_string[AZTEC_BIN_CAPACITY + 1], bit_pattern[20045], descriptor[42];
+ char adjusted_string[AZTEC_MAX_CAPACITY + 1];
+ unsigned char desc_data[4], desc_ecc[6];
+ int err_code, ecc_level, compact, data_length, data_maxsize, codeword_size, adjusted_length;
+ int remainder, padbits, count, gs1, adjustment_size;
+ int debug = (symbol->debug & ZINT_DEBUG_PRINT), reader = 0;
+ int comp_loop = 4;
+
+#ifdef _MSC_VER
+ unsigned int* data_part;
+ unsigned int* ecc_part;
+#endif
+
+ memset(binary_string, 0, AZTEC_BIN_CAPACITY + 1);
+ memset(adjusted_string, 0, AZTEC_MAX_CAPACITY + 1);
+
+ if ((symbol->input_mode & 0x07) == GS1_MODE) {
+ gs1 = 1;
+ } else {
+ gs1 = 0;
+ }
+ if (symbol->output_options & READER_INIT) {
+ reader = 1;
+ comp_loop = 1;
+ }
+ if (gs1 && reader) {
+ strcpy(symbol->errtxt, "501: Cannot encode in GS1 and Reader Initialisation mode at the same time");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+
+ populate_map();
+
+ err_code = aztec_text_process(source, length, binary_string, gs1, symbol->eci, symbol->debug);
+
+ if (err_code != 0) {
+ strcpy(symbol->errtxt, "502: Input too long or too many extended ASCII characters");
+ return err_code;
+ }
+
+ if (!((symbol->option_1 >= -1) && (symbol->option_1 <= 4))) {
+ strcpy(symbol->errtxt, "503: Invalid error correction level - using default instead");
+ err_code = ZINT_WARN_INVALID_OPTION;
+ symbol->option_1 = -1;
+ }
+
+ ecc_level = symbol->option_1;
+
+ if ((ecc_level == -1) || (ecc_level == 0)) {
+ ecc_level = 2;
+ }
+
+ data_length = (int) strlen(binary_string);
+
+ layers = 0; /* Keep compiler happy! */
+ data_maxsize = 0; /* Keep compiler happy! */
+ adjustment_size = 0;
+ if (symbol->option_2 == 0) { /* The size of the symbol can be determined by Zint */
+ do {
+ /* Decide what size symbol to use - the smallest that fits the data */
+ compact = 0; /* 1 = Aztec Compact, 0 = Normal Aztec */
+ layers = 0;
+
+ switch (ecc_level) {
+ /* For each level of error correction work out the smallest symbol which
+ the data will fit in */
+ case 1: for (i = 32; i > 0; i--) {
+ if ((data_length + adjustment_size) < Aztec10DataSizes[i - 1]) {
+ layers = i;
+ compact = 0;
+ data_maxsize = Aztec10DataSizes[i - 1];
+ }
+ }
+ for (i = comp_loop; i > 0; i--) {
+ if ((data_length + adjustment_size) < AztecCompact10DataSizes[i - 1]) {
+ layers = i;
+ compact = 1;
+ data_maxsize = AztecCompact10DataSizes[i - 1];
+ }
+ }
+ break;
+ case 2: for (i = 32; i > 0; i--) {
+ if ((data_length + adjustment_size) < Aztec23DataSizes[i - 1]) {
+ layers = i;
+ compact = 0;
+ data_maxsize = Aztec23DataSizes[i - 1];
+ }
+ }
+ for (i = comp_loop; i > 0; i--) {
+ if ((data_length + adjustment_size) < AztecCompact23DataSizes[i - 1]) {
+ layers = i;
+ compact = 1;
+ data_maxsize = AztecCompact23DataSizes[i - 1];
+ }
+ }
+ break;
+ case 3: for (i = 32; i > 0; i--) {
+ if ((data_length + adjustment_size) < Aztec36DataSizes[i - 1]) {
+ layers = i;
+ compact = 0;
+ data_maxsize = Aztec36DataSizes[i - 1];
+ }
+ }
+ for (i = comp_loop; i > 0; i--) {
+ if ((data_length + adjustment_size) < AztecCompact36DataSizes[i - 1]) {
+ layers = i;
+ compact = 1;
+ data_maxsize = AztecCompact36DataSizes[i - 1];
+ }
+ }
+ break;
+ case 4: for (i = 32; i > 0; i--) {
+ if ((data_length + adjustment_size) < Aztec50DataSizes[i - 1]) {
+ layers = i;
+ compact = 0;
+ data_maxsize = Aztec50DataSizes[i - 1];
+ }
+ }
+ for (i = comp_loop; i > 0; i--) {
+ if ((data_length + adjustment_size) < AztecCompact50DataSizes[i - 1]) {
+ layers = i;
+ compact = 1;
+ data_maxsize = AztecCompact50DataSizes[i - 1];
+ }
+ }
+ break;
+ }
+
+ if (layers == 0) { /* Couldn't find a symbol which fits the data */
+ strcpy(symbol->errtxt, "504: Input too long (too many bits for selected ECC)");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* Determine codeword bitlength - Table 3 */
+ codeword_size = 6; /* if (layers <= 2) */
+ if ((layers >= 3) && (layers <= 8)) {
+ codeword_size = 8;
+ }
+ if ((layers >= 9) && (layers <= 22)) {
+ codeword_size = 10;
+ }
+ if (layers >= 23) {
+ codeword_size = 12;
+ }
+
+ j = 0;
+ count = 0;
+ for (i = 0; i < data_length; i++) {
+
+ if ((j + 1) % codeword_size == 0) {
+ // Last bit of codeword
+ /* 7.3.1.2 "whenever the first B-1 bits ... are all “0”s, then a dummy “1” is inserted..."
+ * "Similarly a message codeword that starts with B-1 “1”s has a dummy “0” inserted..." */
+
+ if (count == (codeword_size - 1)) {
+ // Codeword of B-1 '1's
+ adjusted_string[j] = '0';
+ j++;
+ }
+
+ if (count == 0) {
+ // Codeword of B-1 '0's
+ adjusted_string[j] = '1';
+ j++;
+ }
+
+ count = 0;
+ } else if (binary_string[i] == '1') { /* Skip B so only counting B-1 */
+ count++;
+ }
+
+ adjusted_string[j] = binary_string[i];
+ j++;
+ }
+ adjusted_string[j] = '\0';
+ adjusted_length = j;
+ adjustment_size = adjusted_length - data_length;
+
+ /* Add padding */
+ remainder = adjusted_length % codeword_size;
+
+ padbits = codeword_size - remainder;
+ if (padbits == codeword_size) {
+ padbits = 0;
+ }
+
+ for (i = 0; i < padbits; i++) {
+ strcat(adjusted_string, "1");
+ }
+ adjusted_length = (int) strlen(adjusted_string);
+
+ count = 0;
+ for (i = (adjusted_length - codeword_size); i < adjusted_length; i++) {
+ if (adjusted_string[i] == '1') {
+ count++;
+ }
+ }
+ if (count == codeword_size) {
+ adjusted_string[adjusted_length - 1] = '0';
+ }
+
+ if (debug) {
+ printf("Codewords:\n");
+ for (i = 0; i < (adjusted_length / codeword_size); i++) {
+ for (j = 0; j < codeword_size; j++) {
+ printf("%c", adjusted_string[(i * codeword_size) + j]);
+ }
+ printf(" ");
+ }
+ printf("\n");
+ }
+
+ } while (adjusted_length > data_maxsize);
+ /* This loop will only repeat on the rare occasions when the rule about not having all 1s or all 0s
+ means that the binary string has had to be lengthened beyond the maximum number of bits that can
+ be encoded in a symbol of the selected size */
+
+ } else { /* The size of the symbol has been specified by the user */
+ if ((reader == 1) && ((symbol->option_2 >= 2) && (symbol->option_2 <= 4))) {
+ symbol->option_2 = 5;
+ }
+ if ((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) {
+ compact = 1;
+ layers = symbol->option_2;
+ }
+ if ((symbol->option_2 >= 5) && (symbol->option_2 <= 36)) {
+ compact = 0;
+ layers = symbol->option_2 - 4;
+ }
+ if ((symbol->option_2 < 0) || (symbol->option_2 > 36)) {
+ strcpy(symbol->errtxt, "510: Invalid Aztec Code size");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+
+ /* Determine codeword bitlength - Table 3 */
+ if ((layers >= 0) && (layers <= 2)) {
+ codeword_size = 6;
+ }
+ if ((layers >= 3) && (layers <= 8)) {
+ codeword_size = 8;
+ }
+ if ((layers >= 9) && (layers <= 22)) {
+ codeword_size = 10;
+ }
+ if (layers >= 23) {
+ codeword_size = 12;
+ }
+
+ j = 0;
+ count = 0;
+ for (i = 0; i < data_length; i++) {
+
+ if ((j + 1) % codeword_size == 0) {
+ // Last bit of codeword
+
+ if (count == (codeword_size - 1)) {
+ // Codeword of B-1 '1's
+ adjusted_string[j] = '0';
+ j++;
+ }
+
+ if (count == 0) {
+ // Codeword of B-1 '0's
+ adjusted_string[j] = '1';
+ j++;
+ }
+
+ count = 0;
+ } else if (binary_string[i] == '1') { /* Skip B so only counting B-1 */
+ count++;
+ }
+
+ adjusted_string[j] = binary_string[i];
+ j++;
+ }
+ adjusted_string[j] = '\0';
+ adjusted_length = j;
+
+ remainder = adjusted_length % codeword_size;
+
+ padbits = codeword_size - remainder;
+ if (padbits == codeword_size) {
+ padbits = 0;
+ }
+
+ for (i = 0; i < padbits; i++) {
+ strcat(adjusted_string, "1");
+ }
+ adjusted_length = (int) strlen(adjusted_string);
+
+ count = 0;
+ for (i = (adjusted_length - codeword_size); i < adjusted_length; i++) {
+ if (adjusted_string[i] == '1') {
+ count++;
+ }
+ }
+ if (count == codeword_size) {
+ adjusted_string[adjusted_length - 1] = '0';
+ }
+
+ /* Check if the data actually fits into the selected symbol size */
+ if (compact) {
+ data_maxsize = codeword_size * (AztecCompactSizes[layers - 1] - 3);
+ } else {
+ data_maxsize = codeword_size * (AztecSizes[layers - 1] - 3);
+ }
+
+ if (adjusted_length > data_maxsize) {
+ strcpy(symbol->errtxt, "505: Data too long for specified Aztec Code symbol size");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ if (debug) {
+ printf("Codewords:\n");
+ for (i = 0; i < (adjusted_length / codeword_size); i++) {
+ for (j = 0; j < codeword_size; j++) {
+ printf("%c", adjusted_string[(i * codeword_size) + j]);
+ }
+ printf(" ");
+ }
+ printf("\n");
+ }
+
+ }
+
+ if (reader && (layers > 22)) {
+ strcpy(symbol->errtxt, "506: Data too long for reader initialisation symbol");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ data_blocks = adjusted_length / codeword_size;
+
+ if (compact) {
+ ecc_blocks = AztecCompactSizes[layers - 1] - data_blocks;
+ } else {
+ ecc_blocks = AztecSizes[layers - 1] - data_blocks;
+ }
+
+ if (debug) {
+ printf("Generating a ");
+ if (compact) {
+ printf("compact");
+ } else {
+ printf("full-size");
+ }
+ printf(" symbol with %d layers\n", layers);
+ printf("Requires ");
+ if (compact) {
+ printf("%d", AztecCompactSizes[layers - 1]);
+ } else {
+ printf("%d", AztecSizes[layers - 1]);
+ }
+ printf(" codewords of %d-bits\n", codeword_size);
+ printf(" (%d data words, %d ecc words)\n", data_blocks, ecc_blocks);
+ }
+
+#ifndef _MSC_VER
+ unsigned int data_part[data_blocks + 3], ecc_part[ecc_blocks + 3];
+#else
+ data_part = (unsigned int*) _alloca((data_blocks + 3) * sizeof (unsigned int));
+ ecc_part = (unsigned int*) _alloca((ecc_blocks + 3) * sizeof (unsigned int));
+#endif
+ /* Copy across data into separate integers */
+ memset(data_part, 0, (data_blocks + 2) * sizeof (int));
+ memset(ecc_part, 0, (ecc_blocks + 2) * sizeof (int));
+
+ /* Split into codewords and calculate reed-solomon error correction codes */
+ for (i = 0; i < data_blocks; i++) {
+ for (p = 0; p < codeword_size; p++) {
+ if (adjusted_string[i * codeword_size + p] == '1') {
+ data_part[i] += 0x01 << (codeword_size - (p + 1));
+ }
+ }
+ }
+
+ switch (codeword_size) {
+ case 6:
+ rs_init_gf(0x43);
+ break;
+ case 8:
+ rs_init_gf(0x12d);
+ break;
+ case 10:
+ rs_init_gf(0x409);
+ break;
+ case 12:
+ rs_init_gf(0x1069);
+ break;
+ }
+
+ rs_init_code(ecc_blocks, 1);
+ rs_encode_long(data_blocks, data_part, ecc_part);
+ for (i = (ecc_blocks - 1); i >= 0; i--) {
+ bin_append(ecc_part[i], codeword_size, adjusted_string);
+ }
+ rs_free();
+
+ /* Invert the data so that actual data is on the outside and reed-solomon on the inside */
+ memset(bit_pattern, '0', 20045);
+
+ total_bits = (data_blocks + ecc_blocks) * codeword_size;
+ for (i = 0; i < total_bits; i++) {
+ bit_pattern[i] = adjusted_string[total_bits - i - 1];
+ }
+
+ /* Now add the symbol descriptor */
+ memset(desc_data, 0, 4);
+ memset(desc_ecc, 0, 6);
+ memset(descriptor, 0, 42);
+
+ if (compact) {
+ /* The first 2 bits represent the number of layers minus 1 */
+ if ((layers - 1) & 0x02) {
+ descriptor[0] = '1';
+ } else {
+ descriptor[0] = '0';
+ }
+ if ((layers - 1) & 0x01) {
+ descriptor[1] = '1';
+ } else {
+ descriptor[1] = '0';
+ }
+ /* The next 6 bits represent the number of data blocks minus 1 */
+ if (reader) {
+ descriptor[2] = '1';
+ } else {
+ if ((data_blocks - 1) & 0x20) {
+ descriptor[2] = '1';
+ } else {
+ descriptor[2] = '0';
+ }
+ }
+
+ for (i = 3; i < 8; i++) {
+ if ((data_blocks - 1) & (0x10 >> (i - 3))) {
+ descriptor[i] = '1';
+ } else {
+ descriptor[i] = '0';
+ }
+ }
+
+ descriptor[8] = '\0';
+ if (debug) printf("Mode Message = %s\n", descriptor);
+ } else {
+ /* The first 5 bits represent the number of layers minus 1 */
+ for (i = 0; i < 5; i++) {
+ if ((layers - 1) & (0x10 >> i)) {
+ descriptor[i] = '1';
+ } else {
+ descriptor[i] = '0';
+ }
+ }
+
+ /* The next 11 bits represent the number of data blocks minus 1 */
+ if (reader) {
+ descriptor[5] = '1';
+ } else {
+ if ((data_blocks - 1) & 0x400) {
+ descriptor[5] = '1';
+ } else {
+ descriptor[5] = '0';
+ }
+ }
+ for (i = 6; i < 16; i++) {
+ if ((data_blocks - 1) & (0x200 >> (i - 6))) {
+ descriptor[i] = '1';
+ } else {
+ descriptor[i] = '0';
+ }
+ }
+ descriptor[16] = '\0';
+ if (debug) printf("Mode Message = %s\n", descriptor);
+ }
+
+ /* Split into 4-bit codewords */
+ for (i = 0; i < 4; i++) {
+ if (descriptor[i * 4] == '1') {
+ desc_data[i] += 8;
+ }
+ if (descriptor[(i * 4) + 1] == '1') {
+ desc_data[i] += 4;
+ }
+ if (descriptor[(i * 4) + 2] == '1') {
+ desc_data[i] += 2;
+ }
+ if (descriptor[(i * 4) + 3] == '1') {
+ desc_data[i] += 1;
+ }
+ }
+
+ /* Add reed-solomon error correction with Galois field GF(16) and prime modulus
+ x^4 + x + 1 (section 7.2.3)*/
+
+ rs_init_gf(0x13);
+ if (compact) {
+ rs_init_code(5, 1);
+ rs_encode(2, desc_data, desc_ecc);
+ for (i = 0; i < 5; i++) {
+ if (desc_ecc[4 - i] & 0x08) {
+ descriptor[(i * 4) + 8] = '1';
+ } else {
+ descriptor[(i * 4) + 8] = '0';
+ }
+ if (desc_ecc[4 - i] & 0x04) {
+ descriptor[(i * 4) + 9] = '1';
+ } else {
+ descriptor[(i * 4) + 9] = '0';
+ }
+ if (desc_ecc[4 - i] & 0x02) {
+ descriptor[(i * 4) + 10] = '1';
+ } else {
+ descriptor[(i * 4) + 10] = '0';
+ }
+ if (desc_ecc[4 - i] & 0x01) {
+ descriptor[(i * 4) + 11] = '1';
+ } else {
+ descriptor[(i * 4) + 11] = '0';
+ }
+ }
+ } else {
+ rs_init_code(6, 1);
+ rs_encode(4, desc_data, desc_ecc);
+ for (i = 0; i < 6; i++) {
+ if (desc_ecc[5 - i] & 0x08) {
+ descriptor[(i * 4) + 16] = '1';
+ } else {
+ descriptor[(i * 4) + 16] = '0';
+ }
+ if (desc_ecc[5 - i] & 0x04) {
+ descriptor[(i * 4) + 17] = '1';
+ } else {
+ descriptor[(i * 4) + 17] = '0';
+ }
+ if (desc_ecc[5 - i] & 0x02) {
+ descriptor[(i * 4) + 18] = '1';
+ } else {
+ descriptor[(i * 4) + 18] = '0';
+ }
+ if (desc_ecc[5 - i] & 0x01) {
+ descriptor[(i * 4) + 19] = '1';
+ } else {
+ descriptor[(i * 4) + 19] = '0';
+ }
+ }
+ }
+ rs_free();
+
+ /* Merge descriptor with the rest of the symbol */
+ for (i = 0; i < 40; i++) {
+ if (compact) {
+ bit_pattern[2000 + i - 2] = descriptor[i];
+ } else {
+ bit_pattern[20000 + i - 2] = descriptor[i];
+ }
+ }
+
+ /* Plot all of the data into the symbol in pre-defined spiral pattern */
+ if (compact) {
+
+ for (y = AztecCompactOffset[layers - 1]; y < (27 - AztecCompactOffset[layers - 1]); y++) {
+ for (x = AztecCompactOffset[layers - 1]; x < (27 - AztecCompactOffset[layers - 1]); x++) {
+ if (CompactAztecMap[(y * 27) + x] == 1) {
+ set_module(symbol, y - AztecCompactOffset[layers - 1], x - AztecCompactOffset[layers - 1]);
+ }
+ if (CompactAztecMap[(y * 27) + x] >= 2) {
+ if (bit_pattern[CompactAztecMap[(y * 27) + x] - 2] == '1') {
+ set_module(symbol, y - AztecCompactOffset[layers - 1], x - AztecCompactOffset[layers - 1]);
+ }
+ }
+ }
+ symbol->row_height[y - AztecCompactOffset[layers - 1]] = 1;
+ }
+ symbol->rows = 27 - (2 * AztecCompactOffset[layers - 1]);
+ symbol->width = 27 - (2 * AztecCompactOffset[layers - 1]);
+ } else {
+
+ for (y = AztecOffset[layers - 1]; y < (151 - AztecOffset[layers - 1]); y++) {
+ for (x = AztecOffset[layers - 1]; x < (151 - AztecOffset[layers - 1]); x++) {
+ if (AztecMap[(y * 151) + x] == 1) {
+ set_module(symbol, y - AztecOffset[layers - 1], x - AztecOffset[layers - 1]);
+ }
+ if (AztecMap[(y * 151) + x] >= 2) {
+ if (bit_pattern[AztecMap[(y * 151) + x] - 2] == '1') {
+ set_module(symbol, y - AztecOffset[layers - 1], x - AztecOffset[layers - 1]);
+ }
+ }
+ }
+ symbol->row_height[y - AztecOffset[layers - 1]] = 1;
+ }
+ symbol->rows = 151 - (2 * AztecOffset[layers - 1]);
+ symbol->width = 151 - (2 * AztecOffset[layers - 1]);
+ }
+
+ return err_code;
+}
+
+/* Encodes Aztec runes as specified in ISO/IEC 24778:2008 Annex A */
+INTERNAL int aztec_runes(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int input_value, error_number, i, y, x;
+ char binary_string[28];
+ unsigned char data_codewords[3], ecc_codewords[6];
+
+ error_number = 0;
+ input_value = 0;
+ if (length > 3) {
+ strcpy(symbol->errtxt, "507: Input too large");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ error_number = is_sane(NEON, source, length);
+ if (error_number != 0) {
+ strcpy(symbol->errtxt, "508: Invalid characters in input");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ switch (length) {
+ case 3: input_value = 100 * ctoi(source[0]);
+ input_value += 10 * ctoi(source[1]);
+ input_value += ctoi(source[2]);
+ break;
+ case 2: input_value = 10 * ctoi(source[0]);
+ input_value += ctoi(source[1]);
+ break;
+ case 1: input_value = ctoi(source[0]);
+ break;
+ }
+
+ if (input_value > 255) {
+ strcpy(symbol->errtxt, "509: Input too large");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ strcpy(binary_string, "");
+ bin_append(input_value, 8, binary_string);
+
+ data_codewords[0] = 0;
+ data_codewords[1] = 0;
+
+ for (i = 0; i < 2; i++) {
+ if (binary_string[i * 4] == '1') {
+ data_codewords[i] += 8;
+ }
+ if (binary_string[(i * 4) + 1] == '1') {
+ data_codewords[i] += 4;
+ }
+ if (binary_string[(i * 4) + 2] == '1') {
+ data_codewords[i] += 2;
+ }
+ if (binary_string[(i * 4) + 3] == '1') {
+ data_codewords[i] += 1;
+ }
+ }
+
+ rs_init_gf(0x13);
+ rs_init_code(5, 1);
+ rs_encode(2, data_codewords, ecc_codewords);
+ rs_free();
+
+ strcpy(binary_string, "");
+
+ for (i = 0; i < 5; i++) {
+ if (ecc_codewords[4 - i] & 0x08) {
+ binary_string[(i * 4) + 8] = '1';
+ } else {
+ binary_string[(i * 4) + 8] = '0';
+ }
+ if (ecc_codewords[4 - i] & 0x04) {
+ binary_string[(i * 4) + 9] = '1';
+ } else {
+ binary_string[(i * 4) + 9] = '0';
+ }
+ if (ecc_codewords[4 - i] & 0x02) {
+ binary_string[(i * 4) + 10] = '1';
+ } else {
+ binary_string[(i * 4) + 10] = '0';
+ }
+ if (ecc_codewords[4 - i] & 0x01) {
+ binary_string[(i * 4) + 11] = '1';
+ } else {
+ binary_string[(i * 4) + 11] = '0';
+ }
+ }
+
+ for (i = 0; i < 28; i += 2) {
+ if (binary_string[i] == '1') {
+ binary_string[i] = '0';
+ } else {
+ binary_string[i] = '1';
+ }
+ }
+
+ for (y = 8; y < 19; y++) {
+ for (x = 8; x < 19; x++) {
+ if (CompactAztecMap[(y * 27) + x] == 1) {
+ set_module(symbol, y - 8, x - 8);
+ }
+ if (CompactAztecMap[(y * 27) + x] >= 2) {
+ if (binary_string[CompactAztecMap[(y * 27) + x] - 2000] == '1') {
+ set_module(symbol, y - 8, x - 8);
+ }
+ }
+ }
+ symbol->row_height[y - 8] = 1;
+ }
+ symbol->rows = 11;
+ symbol->width = 11;
+
+ return 0;
+}
diff --git a/backend/aztec.h b/backend/aztec.h
new file mode 100644
index 0000000..69b55fc
--- /dev/null
+++ b/backend/aztec.h
@@ -0,0 +1,146 @@
+/* aztec.c - Handles Aztec Mesa 2D Symbols */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2008-2017 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+
+#define UPPER 1
+#define LOWER 2
+#define MIXED 4
+#define PUNC 8
+#define DIGIT 16
+#define BINARY 32
+
+static const unsigned short int CompactAztecMap[] = {
+ /* 27 x 27 data grid */
+ 609, 608, 411, 413, 415, 417, 419, 421, 423, 425, 427, 429, 431, 433, 435, 437, 439, 441, 443, 445, 447, 449, 451, 453, 455, 457, 459,
+ 607, 606, 410, 412, 414, 416, 418, 420, 422, 424, 426, 428, 430, 432, 434, 436, 438, 440, 442, 444, 446, 448, 450, 452, 454, 456, 458,
+ 605, 604, 409, 408, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 460, 461,
+ 603, 602, 407, 406, 242, 244, 246, 248, 250, 252, 254, 256, 258, 260, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 462, 463,
+ 601, 600, 405, 404, 241, 240, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 284, 285, 464, 465,
+ 599, 598, 403, 402, 239, 238, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 286, 287, 466, 467,
+ 597, 596, 401, 400, 237, 236, 105, 104, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 140, 141, 288, 289, 468, 469,
+ 595, 594, 399, 398, 235, 234, 103, 102, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 142, 143, 290, 291, 470, 471,
+ 593, 592, 397, 396, 233, 232, 101, 100, 1, 1, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 0, 1, 28, 29, 144, 145, 292, 293, 472, 473,
+ 591, 590, 395, 394, 231, 230, 99, 98, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 31, 146, 147, 294, 295, 474, 475,
+ 589, 588, 393, 392, 229, 228, 97, 96, 2027, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2007, 32, 33, 148, 149, 296, 297, 476, 477,
+ 587, 586, 391, 390, 227, 226, 95, 94, 2026, 1, 0, 1, 1, 1, 1, 1, 0, 1, 2008, 34, 35, 150, 151, 298, 299, 478, 479,
+ 585, 584, 389, 388, 225, 224, 93, 92, 2025, 1, 0, 1, 0, 0, 0, 1, 0, 1, 2009, 36, 37, 152, 153, 300, 301, 480, 481,
+ 583, 582, 387, 386, 223, 222, 91, 90, 2024, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2010, 38, 39, 154, 155, 302, 303, 482, 483,
+ 581, 580, 385, 384, 221, 220, 89, 88, 2023, 1, 0, 1, 0, 0, 0, 1, 0, 1, 2011, 40, 41, 156, 157, 304, 305, 484, 485,
+ 579, 578, 383, 382, 219, 218, 87, 86, 2022, 1, 0, 1, 1, 1, 1, 1, 0, 1, 2012, 42, 43, 158, 159, 306, 307, 486, 487,
+ 577, 576, 381, 380, 217, 216, 85, 84, 2021, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2013, 44, 45, 160, 161, 308, 309, 488, 489,
+ 575, 574, 379, 378, 215, 214, 83, 82, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 46, 47, 162, 163, 310, 311, 490, 491,
+ 573, 572, 377, 376, 213, 212, 81, 80, 0, 0, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 0, 0, 48, 49, 164, 165, 312, 313, 492, 493,
+ 571, 570, 375, 374, 211, 210, 78, 76, 74, 72, 70, 68, 66, 64, 62, 60, 58, 56, 54, 50, 51, 166, 167, 314, 315, 494, 495,
+ 569, 568, 373, 372, 209, 208, 79, 77, 75, 73, 71, 69, 67, 65, 63, 61, 59, 57, 55, 52, 53, 168, 169, 316, 317, 496, 497,
+ 567, 566, 371, 370, 206, 204, 202, 200, 198, 196, 194, 192, 190, 188, 186, 184, 182, 180, 178, 176, 174, 170, 171, 318, 319, 498, 499,
+ 565, 564, 369, 368, 207, 205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185, 183, 181, 179, 177, 175, 172, 173, 320, 321, 500, 501,
+ 563, 562, 366, 364, 362, 360, 358, 356, 354, 352, 350, 348, 346, 344, 342, 340, 338, 336, 334, 332, 330, 328, 326, 322, 323, 502, 503,
+ 561, 560, 367, 365, 363, 361, 359, 357, 355, 353, 351, 349, 347, 345, 343, 341, 339, 337, 335, 333, 331, 329, 327, 324, 325, 504, 505,
+ 558, 556, 554, 552, 550, 548, 546, 544, 542, 540, 538, 536, 534, 532, 530, 528, 526, 524, 522, 520, 518, 516, 514, 512, 510, 506, 507,
+ 559, 557, 555, 553, 551, 549, 547, 545, 543, 541, 539, 537, 535, 533, 531, 529, 527, 525, 523, 521, 519, 517, 515, 513, 511, 508, 509
+};
+
+static const char AztecSymbolChar[128] = {
+ /* From Table 2 */
+ 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 19, 1, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 0, 18, 0, 20, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 21, 22,
+ 23, 24, 25, 26, 20, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 27, 21, 28, 22, 23, 24, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 29, 25, 30, 26, 27
+};
+
+static const char AztecModes[129] = "BMMMMMMMMMMMMXBBBBBBBBBBBBBMMMMMXPPPPPPPPPPPXPXPDDDDDDDDDDPPPPPPMUUUUUUUUUUUUUUUUUUUUUUUUUUPMPMMMLLLLLLLLLLLLLLLLLLLLLLLLLLPMPMM";
+
+static const unsigned short int AztecSizes[32] = {
+ /* Codewords per symbol */
+ 21, 48, 60, 88, 120, 156, 196, 240, 230, 272, 316, 364, 416, 470, 528, 588, 652, 720, 790,
+ 864, 940, 1020, 920, 992, 1066, 1144, 1224, 1306, 1392, 1480, 1570, 1664
+};
+
+static const int AztecCompactSizes[4] = {
+ 17, 40, 51, 76
+};
+
+static const unsigned short int Aztec10DataSizes[32] = {
+ /* Data bits per symbol maximum with 10% error correction */
+ 96, 246, 408, 616, 840, 1104, 1392, 1704, 2040, 2420, 2820, 3250, 3720, 4200, 4730,
+ 5270, 5840, 6450, 7080, 7750, 8430, 9150, 9900, 10680, 11484, 12324, 13188, 14076,
+ 15000, 15948, 16920, 17940
+};
+
+static const unsigned short int Aztec23DataSizes[32] = {
+ /* Data bits per symbol maximum with 23% error correction */
+ 84, 204, 352, 520, 720, 944, 1184, 1456, 1750, 2070, 2410, 2780, 3180, 3590, 4040,
+ 4500, 5000, 5520, 6060, 6630, 7210, 7830, 8472, 9132, 9816, 10536, 11280, 12036,
+ 12828, 13644, 14472, 15348
+};
+
+static const unsigned short int Aztec36DataSizes[32] = {
+ /* Data bits per symbol maximum with 36% error correction */
+ 66, 168, 288, 432, 592, 776, 984, 1208, 1450, 1720, 2000, 2300, 2640, 2980, 3350,
+ 3740, 4150, 4580, 5030, 5500, 5990, 6500, 7032, 7584, 8160, 8760, 9372, 9996, 10656,
+ 11340, 12024, 12744
+};
+
+static const unsigned short int Aztec50DataSizes[32] = {
+ /* Data bits per symbol maximum with 50% error correction */
+ 48, 126, 216, 328, 456, 600, 760, 936, 1120, 1330, 1550, 1790, 2050, 2320, 2610,
+ 2910, 3230, 3570, 3920, 4290, 4670, 5070, 5484, 5916, 6360, 6828, 7308, 7800, 8316,
+ 8844, 9384, 9948
+};
+
+static const unsigned short int AztecCompact10DataSizes [4] = {
+ 78, 198, 336, 520
+};
+
+static const unsigned short int AztecCompact23DataSizes [4] = {
+ 66, 168, 288, 440
+};
+
+static const unsigned short int AztecCompact36DataSizes [4] = {
+ 48, 138, 232, 360
+};
+
+static const unsigned short int AztecCompact50DataSizes [4] = {
+ 36, 102, 176, 280
+};
+
+static const char AztecOffset[32] = {
+ 66, 64, 62, 60, 57, 55, 53, 51, 49, 47, 45, 42, 40, 38, 36, 34, 32, 30, 28, 25, 23, 21,
+ 19, 17, 15, 13, 10, 8, 6, 4, 2, 0
+};
+
+static const char AztecCompactOffset[4] = {
+ 6, 4, 2, 0
+};
+
diff --git a/backend/bmp.c b/backend/bmp.c
new file mode 100644
index 0000000..240c697
--- /dev/null
+++ b/backend/bmp.c
@@ -0,0 +1,181 @@
+/* bmp.c - Handles output to Windows Bitmap file */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2009 - 2020 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+#include <stdio.h>
+#include "common.h"
+#include "bmp.h" /* Bitmap header structure */
+#ifdef _MSC_VER
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+INTERNAL int bmp_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) {
+ int i, row, column;
+ unsigned int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
+ int row_size;
+ unsigned int data_offset, data_size, file_size;
+ unsigned char *bitmap_file_start, *bmp_posn;
+ unsigned char *bitmap;
+ FILE *bmp_file;
+ bitmap_file_header_t file_header;
+ bitmap_info_header_t info_header;
+
+ row_size = 4 * ((24 * symbol->bitmap_width + 31) / 32);
+ data_size = symbol->bitmap_height * row_size;
+ data_offset = sizeof (bitmap_file_header_t) + sizeof (bitmap_info_header_t);
+ file_size = data_offset + data_size;
+
+ bitmap_file_start = (unsigned char *) malloc(file_size);
+ if (bitmap_file_start == NULL) {
+ strcpy(symbol->errtxt, "602: Out of memory");
+ return ZINT_ERROR_MEMORY;
+ }
+ memset(bitmap_file_start, 0, file_size); /* Not required but keeps padding bytes consistent */
+
+ bitmap = bitmap_file_start + data_offset;
+
+ fgred = (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]);
+ fggrn = (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]);
+ fgblu = (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]);
+ bgred = (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]);
+ bggrn = (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]);
+ bgblu = (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]);
+
+ /* Pixel Plotting */
+ for (row = 0; row < symbol->bitmap_height; row++) {
+ for (column = 0; column < symbol->bitmap_width; column++) {
+ i = (3 * column) + (row * row_size);
+ switch (*(pixelbuf + (symbol->bitmap_width * (symbol->bitmap_height - row - 1)) + column)) {
+ case 'W': // White
+ bitmap[i] = 255;
+ bitmap[i + 1] = 255;
+ bitmap[i + 2] = 255;
+ break;
+ case 'C': // Cyan
+ bitmap[i] = 255;
+ bitmap[i + 1] = 255;
+ bitmap[i + 2] = 0;
+ break;
+ case 'B': // Blue
+ bitmap[i] = 255;
+ bitmap[i + 1] = 0;
+ bitmap[i + 2] = 0;
+ break;
+ case 'M': // Magenta
+ bitmap[i] = 255;
+ bitmap[i + 1] = 0;
+ bitmap[i + 2] = 255;
+ break;
+ case 'R': // Red
+ bitmap[i] = 0;
+ bitmap[i + 1] = 0;
+ bitmap[i + 2] = 255;
+ break;
+ case 'Y': // Yellow
+ bitmap[i] = 0;
+ bitmap[i + 1] = 255;
+ bitmap[i + 2] = 255;
+ break;
+ case 'G': // Green
+ bitmap[i] = 0;
+ bitmap[i + 1] = 255;
+ bitmap[i + 2] = 0;
+ break;
+ case 'K': // Black
+ bitmap[i] = 0;
+ bitmap[i + 1] = 0;
+ bitmap[i + 2] = 0;
+ break;
+ case '1':
+ bitmap[i] = fgblu;
+ bitmap[i + 1] = fggrn;
+ bitmap[i + 2] = fgred;
+ break;
+ default:
+ bitmap[i] = bgblu;
+ bitmap[i + 1] = bggrn;
+ bitmap[i + 2] = bgred;
+ break;
+
+ }
+ }
+ }
+
+ symbol->bitmap_byte_length = data_size;
+
+ file_header.header_field = 0x4d42; // "BM"
+ file_header.file_size = file_size;
+ file_header.reserved = 0;
+ file_header.data_offset = data_offset;
+
+ info_header.header_size = sizeof (bitmap_info_header_t);
+ info_header.width = symbol->bitmap_width;
+ info_header.height = symbol->bitmap_height;
+ info_header.colour_planes = 1;
+ info_header.bits_per_pixel = 24;
+ info_header.compression_method = 0; // BI_RGB
+ info_header.image_size = 0;
+ info_header.horiz_res = 0;
+ info_header.vert_res = 0;
+ info_header.colours = 0;
+ info_header.important_colours = 0;
+
+ bmp_posn = bitmap_file_start;
+ memcpy(bitmap_file_start, &file_header, sizeof (bitmap_file_header_t));
+ bmp_posn += sizeof (bitmap_file_header_t);
+ memcpy(bmp_posn, &info_header, sizeof (bitmap_info_header_t));
+
+ /* Open output file in binary mode */
+ if ((symbol->output_options & BARCODE_STDOUT) != 0) {
+#ifdef _MSC_VER
+ if (-1 == _setmode(_fileno(stdout), _O_BINARY)) {
+ strcpy(symbol->errtxt, "600: Can't open output file");
+ free(bitmap_file_start);
+ return ZINT_ERROR_FILE_ACCESS;
+ }
+#endif
+ bmp_file = stdout;
+ } else {
+ if (!(bmp_file = fopen(symbol->outfile, "wb"))) {
+ free(bitmap_file_start);
+ strcpy(symbol->errtxt, "601: Can't open output file");
+ return ZINT_ERROR_FILE_ACCESS;
+ }
+ }
+
+ fwrite(bitmap_file_start, file_header.file_size, 1, bmp_file);
+ fclose(bmp_file);
+
+ free(bitmap_file_start);
+ return 0;
+}
diff --git a/backend/bmp.h b/backend/bmp.h
new file mode 100644
index 0000000..3a6ab34
--- /dev/null
+++ b/backend/bmp.h
@@ -0,0 +1,77 @@
+/* bmp.h - header structure for Windows bitmap files
+
+ libzint - the open source barcode library
+ Copyright (C) 2009-2017 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+
+#ifndef BMP_H
+#define BMP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _MSC_VER
+#include <windows.h>
+#include "stdint_msvc.h"
+#else
+#include <stdint.h>
+#endif
+
+#pragma pack (1)
+
+ typedef struct bitmap_file_header {
+ uint16_t header_field;
+ uint32_t file_size;
+ uint32_t reserved;
+ uint32_t data_offset;
+ } bitmap_file_header_t;
+
+ typedef struct bitmap_info_header {
+ uint32_t header_size;
+ int32_t width;
+ int32_t height;
+ uint16_t colour_planes;
+ uint16_t bits_per_pixel;
+ uint32_t compression_method;
+ uint32_t image_size;
+ int32_t horiz_res;
+ int32_t vert_res;
+ uint32_t colours;
+ uint32_t important_colours;
+ } bitmap_info_header_t;
+
+#pragma pack ()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BMP_H */
+
+
diff --git a/backend/channel_precalcs.h b/backend/channel_precalcs.h
new file mode 100644
index 0000000..f979e1a
--- /dev/null
+++ b/backend/channel_precalcs.h
@@ -0,0 +1,106 @@
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2020 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+/* Channel code precalculated values to avoid excessive looping */
+/* To generate uncomment CHANNEL_GENERATE_PRECALCS define and run "./test_channel -f generate -g" */
+/* Paste result below here */
+static channel_precalc channel_precalcs7[] = {
+ { 115338, { 1, 3, 1, 1, 1, 1, 5, 1, }, { 1, 1, 1, 2, 1, 2, 3, 3, }, { 1, 7, 5, 5, 5, 5, 5, }, { 1, 7, 7, 7, 6, 6, 5, }, },
+ { 230676, { 1, 1, 2, 2, 4, 1, 1, 2, }, { 1, 2, 1, 3, 2, 1, 3, 1, }, { 1, 7, 7, 6, 5, 2, 2, }, { 1, 7, 6, 6, 4, 3, 3, }, },
+ { 346014, { 1, 2, 3, 1, 1, 1, 3, 2, }, { 1, 2, 2, 1, 1, 3, 1, 3, }, { 1, 7, 6, 4, 4, 4, 4, }, { 1, 7, 6, 5, 5, 5, 3, }, },
+ { 461352, { 1, 2, 1, 1, 1, 2, 2, 4, }, { 1, 3, 1, 1, 3, 2, 2, 1, }, { 1, 7, 6, 6, 6, 6, 5, }, { 1, 7, 5, 5, 5, 3, 2, }, },
+};
+static channel_precalc channel_precalcs8[] = {
+ { 119121, { 2, 1, 3, 2, 1, 3, 2, 1, }, { 1, 1, 1, 4, 3, 2, 1, 2, }, { 8, 7, 7, 5, 4, 4, 2, }, { 8, 8, 8, 8, 5, 3, 2, }, },
+ { 238242, { 2, 1, 1, 2, 2, 2, 1, 4, }, { 1, 1, 3, 1, 1, 2, 4, 2, }, { 8, 7, 7, 7, 6, 5, 4, }, { 8, 8, 8, 6, 6, 6, 5, }, },
+ { 357363, { 2, 2, 1, 4, 1, 1, 1, 3, }, { 1, 1, 1, 1, 3, 2, 5, 1, }, { 8, 7, 6, 6, 3, 3, 3, }, { 8, 8, 8, 8, 8, 6, 5, }, },
+ { 476484, { 2, 2, 1, 1, 3, 2, 3, 1, }, { 1, 1, 3, 1, 2, 2, 3, 2, }, { 8, 7, 6, 6, 6, 4, 3, }, { 8, 8, 8, 6, 6, 5, 4, }, },
+ { 595605, { 2, 3, 3, 2, 1, 1, 1, 2, }, { 1, 1, 2, 1, 1, 1, 5, 3, }, { 8, 7, 5, 3, 2, 2, 2, }, { 8, 8, 8, 7, 7, 7, 7, }, },
+ { 714726, { 2, 1, 1, 6, 1, 1, 2, 1, }, { 1, 2, 1, 3, 1, 4, 1, 2, }, { 8, 7, 7, 7, 2, 2, 2, }, { 8, 8, 7, 7, 5, 5, 2, }, },
+ { 833847, { 2, 1, 1, 3, 1, 3, 3, 1, }, { 1, 2, 3, 1, 1, 3, 2, 2, }, { 8, 7, 7, 7, 5, 5, 3, }, { 8, 8, 7, 5, 5, 5, 3, }, },
+ { 952968, { 2, 2, 2, 3, 2, 1, 2, 1, }, { 1, 2, 2, 1, 2, 2, 2, 3, }, { 8, 7, 6, 5, 3, 2, 2, }, { 8, 8, 7, 6, 6, 5, 4, }, },
+ { 1072089, { 2, 5, 1, 1, 2, 2, 1, 1, }, { 1, 2, 1, 3, 1, 3, 3, 1, }, { 8, 7, 3, 3, 3, 2, 1, }, { 8, 8, 7, 7, 5, 5, 3, }, },
+ { 1191210, { 2, 2, 1, 2, 1, 1, 3, 3, }, { 1, 3, 1, 1, 5, 1, 1, 2, }, { 8, 7, 6, 6, 5, 5, 5, }, { 8, 8, 6, 6, 6, 2, 2, }, },
+ { 1310331, { 2, 1, 2, 1, 2, 3, 2, 2, }, { 1, 4, 1, 3, 1, 1, 2, 2, }, { 8, 7, 7, 6, 6, 5, 3, }, { 8, 8, 5, 5, 3, 3, 3, }, },
+ { 1429452, { 2, 2, 1, 2, 2, 3, 2, 1, }, { 1, 5, 3, 1, 2, 1, 1, 1, }, { 8, 7, 6, 6, 5, 4, 2, }, { 8, 8, 4, 2, 2, 1, 1, }, },
+ { 1548573, { 3, 1, 1, 2, 5, 1, 1, 1, }, { 1, 1, 2, 2, 1, 2, 5, 1, }, { 8, 6, 6, 6, 5, 1, 1, }, { 8, 8, 8, 7, 6, 6, 5, }, },
+ { 1667694, { 3, 2, 2, 1, 1, 3, 2, 1, }, { 1, 1, 1, 1, 2, 4, 3, 2, }, { 8, 6, 5, 4, 4, 4, 2, }, { 8, 8, 8, 8, 8, 7, 4, }, },
+ { 1786815, { 3, 4, 2, 1, 2, 1, 1, 1, }, { 1, 1, 2, 1, 1, 2, 1, 6, }, { 8, 6, 3, 2, 2, 1, 1, }, { 8, 8, 8, 7, 7, 7, 6, }, },
+ { 1905936, { 3, 2, 1, 3, 1, 3, 1, 1, }, { 1, 2, 1, 1, 1, 4, 2, 3, }, { 8, 6, 5, 5, 3, 3, 1, }, { 8, 8, 7, 7, 7, 7, 4, }, },
+ { 2025057, { 3, 1, 2, 2, 1, 1, 4, 1, }, { 1, 3, 2, 1, 1, 1, 5, 1, }, { 8, 6, 6, 5, 4, 4, 4, }, { 8, 8, 6, 5, 5, 5, 5, }, },
+ { 2144178, { 3, 1, 2, 1, 2, 2, 2, 2, }, { 1, 5, 1, 1, 4, 1, 1, 1, }, { 8, 6, 6, 5, 5, 4, 3, }, { 8, 8, 4, 4, 4, 1, 1, }, },
+ { 2263299, { 4, 2, 1, 2, 1, 1, 1, 3, }, { 1, 1, 1, 1, 3, 3, 3, 2, }, { 8, 5, 4, 4, 3, 3, 3, }, { 8, 8, 8, 8, 8, 6, 4, }, },
+ { 2382420, { 4, 2, 1, 1, 1, 1, 4, 1, }, { 1, 2, 2, 2, 2, 2, 2, 2, }, { 8, 5, 4, 4, 4, 4, 4, }, { 8, 8, 7, 6, 5, 4, 3, }, },
+ { 2501541, { 5, 1, 1, 2, 2, 1, 1, 2, }, { 1, 1, 2, 3, 3, 1, 1, 3, }, { 8, 4, 4, 4, 3, 2, 2, }, { 8, 8, 8, 7, 5, 3, 3, }, },
+ { 2620662, { 6, 1, 1, 1, 2, 1, 1, 2, }, { 1, 2, 4, 1, 2, 3, 1, 1, }, { 8, 3, 3, 3, 3, 2, 2, }, { 8, 8, 7, 4, 4, 3, 1, }, },
+ { 2739783, { 1, 1, 1, 1, 3, 3, 4, 1, }, { 2, 1, 2, 1, 6, 1, 1, 1, }, { 8, 8, 8, 8, 8, 6, 4, }, { 8, 7, 7, 6, 6, 1, 1, }, },
+ { 2858904, { 1, 1, 2, 3, 3, 1, 3, 1, }, { 2, 1, 3, 1, 3, 1, 2, 2, }, { 8, 8, 8, 7, 5, 3, 3, }, { 8, 7, 7, 5, 5, 3, 3, }, },
+ { 2978025, { 1, 2, 2, 4, 1, 2, 1, 2, }, { 2, 1, 1, 1, 1, 3, 4, 2, }, { 8, 8, 7, 6, 3, 3, 2, }, { 8, 7, 7, 7, 7, 7, 5, }, },
+ { 3097146, { 1, 2, 2, 1, 3, 3, 2, 1, }, { 2, 1, 3, 3, 2, 2, 1, 1, }, { 8, 8, 7, 6, 6, 4, 2, }, { 8, 7, 7, 5, 3, 2, 1, }, },
+ { 3216267, { 1, 3, 1, 1, 1, 3, 1, 4, }, { 2, 1, 3, 2, 3, 2, 1, 1, }, { 8, 8, 6, 6, 6, 6, 4, }, { 8, 7, 7, 5, 4, 2, 1, }, },
+ { 3335388, { 1, 1, 1, 4, 4, 1, 2, 1, }, { 2, 2, 1, 1, 1, 1, 3, 4, }, { 8, 8, 8, 8, 5, 2, 2, }, { 8, 7, 6, 6, 6, 6, 6, }, },
+ { 3454509, { 1, 1, 2, 4, 3, 1, 2, 1, }, { 2, 2, 2, 5, 1, 1, 1, 1, }, { 8, 8, 8, 7, 4, 2, 2, }, { 8, 7, 6, 5, 1, 1, 1, }, },
+ { 3573630, { 1, 2, 1, 3, 1, 2, 3, 2, }, { 2, 2, 2, 1, 1, 4, 2, 1, }, { 8, 8, 7, 7, 5, 5, 4, }, { 8, 7, 6, 5, 5, 5, 2, }, },
+ { 3692751, { 1, 4, 2, 3, 2, 1, 1, 1, }, { 2, 2, 1, 1, 2, 1, 2, 4, }, { 8, 8, 5, 4, 2, 1, 1, }, { 8, 7, 6, 6, 6, 5, 5, }, },
+ { 3811872, { 1, 1, 2, 1, 3, 5, 1, 1, }, { 2, 3, 3, 2, 2, 1, 1, 1, }, { 8, 8, 8, 7, 7, 5, 1, }, { 8, 7, 5, 3, 2, 1, 1, }, },
+ { 3930993, { 1, 1, 1, 1, 6, 2, 2, 1, }, { 2, 4, 1, 2, 1, 3, 1, 1, }, { 8, 8, 8, 8, 8, 3, 2, }, { 8, 7, 4, 4, 3, 3, 1, }, },
+ { 4050114, { 1, 3, 3, 2, 2, 1, 2, 1, }, { 2, 6, 2, 1, 1, 1, 1, 1, }, { 8, 8, 6, 4, 3, 2, 2, }, { 8, 7, 2, 1, 1, 1, 1, }, },
+ { 4169235, { 2, 1, 2, 2, 4, 2, 1, 1, }, { 2, 1, 2, 1, 1, 1, 4, 3, }, { 8, 7, 7, 6, 5, 2, 1, }, { 8, 7, 7, 6, 6, 6, 6, }, },
+ { 4288356, { 2, 2, 2, 1, 1, 3, 3, 1, }, { 2, 1, 1, 4, 2, 1, 1, 3, }, { 8, 7, 6, 5, 5, 5, 3, }, { 8, 7, 7, 7, 4, 3, 3, }, },
+ { 4407477, { 2, 3, 3, 1, 2, 1, 1, 2, }, { 2, 1, 3, 2, 4, 1, 1, 1, }, { 8, 7, 5, 3, 3, 2, 2, }, { 8, 7, 7, 5, 4, 1, 1, }, },
+ { 4526598, { 2, 1, 4, 1, 4, 1, 1, 1, }, { 2, 2, 2, 1, 2, 3, 1, 2, }, { 8, 7, 7, 4, 4, 1, 1, }, { 8, 7, 6, 5, 5, 4, 2, }, },
+ { 4645719, { 2, 4, 2, 1, 1, 2, 1, 2, }, { 2, 2, 1, 1, 3, 2, 3, 1, }, { 8, 7, 4, 3, 3, 3, 2, }, { 8, 7, 6, 6, 6, 4, 3, }, },
+ { 4764840, { 2, 1, 1, 1, 2, 4, 1, 3, }, { 2, 4, 1, 2, 1, 3, 1, 1, }, { 8, 7, 7, 7, 7, 6, 3, }, { 8, 7, 4, 4, 3, 3, 1, }, },
+ { 4883961, { 3, 1, 1, 3, 2, 2, 1, 2, }, { 2, 1, 2, 2, 2, 1, 2, 3, }, { 8, 6, 6, 6, 4, 3, 2, }, { 8, 7, 7, 6, 5, 4, 4, }, },
+ { 5003082, { 3, 3, 3, 1, 1, 1, 2, 1, }, { 2, 1, 2, 1, 1, 3, 1, 4, }, { 8, 6, 4, 2, 2, 2, 2, }, { 8, 7, 7, 6, 6, 6, 4, }, },
+ { 5122203, { 3, 1, 1, 2, 1, 2, 1, 4, }, { 2, 3, 1, 1, 1, 2, 4, 1, }, { 8, 6, 6, 6, 5, 5, 4, }, { 8, 7, 5, 5, 5, 5, 4, }, },
+ { 5241324, { 4, 1, 1, 3, 1, 2, 2, 1, }, { 2, 1, 3, 1, 1, 3, 3, 1, }, { 8, 5, 5, 5, 3, 3, 2, }, { 8, 7, 7, 5, 5, 5, 3, }, },
+ { 5360445, { 4, 3, 1, 1, 2, 1, 1, 2, }, { 2, 4, 1, 3, 2, 1, 1, 1, }, { 8, 5, 3, 3, 3, 2, 2, }, { 8, 7, 4, 4, 2, 1, 1, }, },
+ { 5479566, { 1, 1, 3, 1, 3, 2, 1, 3, }, { 3, 1, 1, 2, 1, 2, 1, 4, }, { 8, 8, 8, 6, 6, 4, 3, }, { 8, 6, 6, 6, 5, 5, 4, }, },
+ { 5598687, { 1, 2, 1, 1, 5, 1, 3, 1, }, { 3, 1, 1, 1, 1, 3, 1, 4, }, { 8, 8, 7, 7, 7, 3, 3, }, { 8, 6, 6, 6, 6, 6, 4, }, },
+ { 5717808, { 1, 3, 1, 2, 1, 3, 1, 3, }, { 3, 1, 1, 2, 4, 1, 1, 2, }, { 8, 8, 6, 6, 5, 5, 3, }, { 8, 6, 6, 6, 5, 2, 2, }, },
+ { 5836929, { 1, 1, 2, 3, 1, 2, 3, 2, }, { 3, 2, 1, 1, 1, 1, 2, 4, }, { 8, 8, 8, 7, 5, 5, 4, }, { 8, 6, 5, 5, 5, 5, 5, }, },
+ { 5956050, { 1, 2, 3, 3, 2, 2, 1, 1, }, { 3, 2, 3, 1, 1, 1, 1, 3, }, { 8, 8, 7, 5, 3, 2, 1, }, { 8, 6, 5, 3, 3, 3, 3, }, },
+ { 6075171, { 1, 3, 1, 1, 3, 3, 2, 1, }, { 3, 3, 1, 1, 3, 1, 2, 1, }, { 8, 8, 6, 6, 6, 4, 2, }, { 8, 6, 4, 4, 4, 2, 2, }, },
+ { 6194292, { 2, 1, 1, 3, 4, 1, 2, 1, }, { 3, 1, 2, 1, 3, 1, 3, 1, }, { 8, 7, 7, 7, 5, 2, 2, }, { 8, 6, 6, 5, 5, 3, 3, }, },
+ { 6313413, { 2, 3, 2, 2, 1, 2, 2, 1, }, { 3, 1, 1, 2, 1, 3, 2, 2, }, { 8, 7, 5, 4, 3, 3, 2, }, { 8, 6, 6, 6, 5, 5, 3, }, },
+ { 6432534, { 2, 3, 1, 1, 2, 2, 3, 1, }, { 3, 2, 1, 2, 3, 1, 2, 1, }, { 8, 7, 5, 5, 5, 4, 3, }, { 8, 6, 5, 5, 4, 2, 2, }, },
+ { 6551655, { 3, 1, 1, 2, 1, 4, 1, 2, }, { 3, 1, 2, 3, 1, 1, 3, 1, }, { 8, 6, 6, 6, 5, 5, 2, }, { 8, 6, 6, 5, 3, 3, 3, }, },
+ { 6670776, { 3, 1, 1, 1, 1, 3, 4, 1, }, { 3, 3, 1, 2, 1, 1, 3, 1, }, { 8, 6, 6, 6, 6, 6, 4, }, { 8, 6, 4, 4, 3, 3, 3, }, },
+ { 6789897, { 5, 2, 1, 1, 2, 1, 2, 1, }, { 3, 1, 1, 1, 2, 2, 3, 2, }, { 8, 4, 3, 3, 3, 2, 2, }, { 8, 6, 6, 6, 6, 5, 4, }, },
+ { 6909018, { 1, 2, 2, 2, 2, 1, 4, 1, }, { 4, 1, 1, 2, 1, 2, 1, 3, }, { 8, 8, 7, 6, 5, 4, 4, }, { 8, 5, 5, 5, 4, 4, 3, }, },
+ { 7028139, { 1, 1, 3, 2, 2, 2, 1, 3, }, { 4, 2, 2, 1, 2, 2, 1, 1, }, { 8, 8, 8, 6, 5, 4, 3, }, { 8, 5, 4, 3, 3, 2, 1, }, },
+ { 7147260, { 2, 1, 4, 3, 2, 1, 1, 1, }, { 4, 1, 1, 1, 4, 1, 1, 2, }, { 8, 7, 7, 4, 2, 1, 1, }, { 8, 5, 5, 5, 5, 2, 2, }, },
+ { 7266381, { 2, 4, 1, 3, 2, 1, 1, 1, }, { 4, 2, 1, 1, 1, 2, 1, 3, }, { 8, 7, 4, 4, 2, 1, 1, }, { 8, 5, 4, 4, 4, 4, 3, }, },
+ { 7385502, { 4, 2, 1, 3, 1, 2, 1, 1, }, { 4, 1, 1, 4, 2, 1, 1, 1, }, { 8, 5, 4, 4, 2, 2, 1, }, { 8, 5, 5, 5, 2, 1, 1, }, },
+ { 7504623, { 1, 1, 3, 4, 3, 1, 1, 1, }, { 5, 2, 1, 1, 1, 1, 1, 3, }, { 8, 8, 8, 6, 3, 1, 1, }, { 8, 4, 3, 3, 3, 3, 3, }, },
+ { 7623744, { 3, 1, 1, 2, 2, 1, 2, 3, }, { 5, 2, 1, 1, 1, 2, 1, 2, }, { 8, 6, 6, 6, 5, 4, 4, }, { 8, 4, 3, 3, 3, 3, 2, }, },
+};
diff --git a/backend/codablock.c b/backend/codablock.c
new file mode 100644
index 0000000..2eef2a7
--- /dev/null
+++ b/backend/codablock.c
@@ -0,0 +1,988 @@
+/* codablock.c - Handles Codablock-F and Codablock-E */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2016 - 2020 Harald Oehlmann
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include <assert.h>
+#include "common.h"
+
+INTERNAL int code_128(struct zint_symbol *symbol, const unsigned char source[], const size_t length);
+
+#define uchar unsigned char
+
+/* FTab C128 flags - may be added */
+#define CodeA 1
+#define CodeB 2
+#define CodeC 4
+#define CEnd 8
+#define CShift 16
+#define CFill 32
+#define CodeFNC1 64
+#define CodeFNC4 128
+#define ZTNum (CodeA+CodeB+CodeC)
+#define ZTFNC1 (CodeA+CodeB+CodeC+CodeFNC1)
+
+/* ASCII-Extension for Codablock-F */
+#define aFNC1 (uchar)(128)
+#define aFNC2 (uchar)(129)
+#define aFNC3 (uchar)(130)
+#define aFNC4 (uchar)(131)
+#define aCodeA (uchar)(132)
+#define aCodeB (uchar)(133)
+#define aCodeC (uchar)(134)
+#define aShift (uchar)(135)
+
+static const char *C128Table[107] = {
+ /* Code 128 character encodation - Table 1 */
+ "212222", "222122", "222221", "121223", "121322", "131222", "122213",
+ "122312", "132212", "221213", "221312", "231212", "112232", "122132", "122231", "113222",
+ "123122", "123221", "223211", "221132", "221231", "213212", "223112", "312131", "311222",
+ "321122", "321221", "312212", "322112", "322211", "212123", "212321", "232121", "111323",
+ "131123", "131321", "112313", "132113", "132311", "211313", "231113", "231311", "112133",
+ "112331", "132131", "113123", "113321", "133121", "313121", "211331", "231131", "213113",
+ "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111", "314111",
+ "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214",
+ "112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112",
+ "134111", "111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112",
+ "421211", "212141", "214121", "412121", "111143", "111341", "131141", "114113", "114311",
+ "411113", "411311", "113141", "114131", "311141", "411131", "211412", "211214", "211232",
+ "2331112"
+};
+
+/* Code F Analysing-Chart */
+typedef struct sCharacterSetTable
+{
+ int CharacterSet; /* Still possible character sets for actual*/
+ int AFollowing; /* Still following Characters in Charset A */
+ int BFollowing; /* Still following Characters in Charset B */
+ int CFollowing; /* Still following Characters in Charset C */
+} CharacterSetTable;
+
+/* Find the possible Code-128 Character sets for a character
+ * The result is an or of CodeA, CodeB, CodeC, CodeFNC1, CodeFNC4 depending on the
+ * possible Code 128 character sets.
+ */
+static int GetPossibleCharacterSet(unsigned char C)
+{
+ if (C<='\x1f') /* Control chars */
+ return CodeA;
+ if (C>='0' && C<='9')
+ return ZTNum; /* ZTNum=CodeA+CodeB+CodeC */
+ if (C==aFNC1)
+ return ZTFNC1; /* ZTFNC1=CodeA+CodeB+CodeC+CodeFNC1 */
+ if (C==aFNC4)
+ return (CodeA | CodeB | CodeFNC4);
+ if (C>='\x60' && C<='\x7f') /* 60 to 127 */
+ return CodeB;
+ return CodeA+CodeB;
+}
+
+/* Create a Table with the following information for each Data character:
+ * int CharacterSet is an or of CodeA, CodeB, CodeC, CodeFNC1, CodeFNC4,
+ * depending on which character set is applicable.
+ * (Result of GetPossibleCharacterSet)
+ * int AFollowing,BFollowing The number of source characters you still may encode
+ * in this character set.
+ * int CFollowing The number of characters encodable in CodeC if we
+ * start here.
+ */
+static void CreateCharacterSetTable(CharacterSetTable T[], unsigned char *data, const int dataLength)
+{
+ int charCur;
+ int runChar;
+
+ /* Treat the Data backwards */
+ charCur=dataLength-1;
+ T[charCur].CharacterSet=GetPossibleCharacterSet(data[charCur]);
+ T[charCur].AFollowing=((T[charCur].CharacterSet & CodeA)==0)?0:1;
+ T[charCur].BFollowing=((T[charCur].CharacterSet & CodeB)==0)?0:1;
+ T[charCur].CFollowing=0;
+
+ for (charCur--;charCur>=0;charCur--)
+ {
+ T[charCur].CharacterSet=GetPossibleCharacterSet(data[charCur]);
+ T[charCur].AFollowing=
+ ((T[charCur].CharacterSet & CodeA)==0)?0:T[charCur+1].AFollowing+1;
+ T[charCur].BFollowing=
+ ((T[charCur].CharacterSet & CodeB)==0)?0:T[charCur+1].BFollowing+1;
+ T[charCur].CFollowing=0;
+
+ }
+ /* Find the CodeC-chains */
+ for (charCur=0;charCur<dataLength;charCur++)
+ {
+ T[charCur].CFollowing=0;
+ if ((T[charCur].CharacterSet & CodeC)!=0)
+ {
+ /* CodeC possible */
+ runChar=charCur;
+ do{
+ /* Whether this is FNC1, whether next is */
+ /* numeric */
+ if (T[runChar].CharacterSet==ZTFNC1)
+ /* FNC1 */
+ ++(T[charCur].CFollowing);
+ else
+ {
+ ++runChar;
+ if (runChar>=dataLength)
+ break;
+ /* Only a Number may follow */
+ if (T[runChar].CharacterSet==ZTNum)
+ T[charCur].CFollowing+=2;
+ else
+ break;
+ }
+ ++runChar;
+ } while (runChar<dataLength);
+ }
+ }
+}
+
+/* Find the amount of numerical characters in pairs which will fit in
+ * one bundle into the line (up to here). This is calculated online because
+ * it depends on the space in the line.
+ */
+static int RemainingDigits(CharacterSetTable *T, int charCur,int emptyColumns)
+{
+ int digitCount; /* Numerical digits fitting in the line */
+ int runChar;
+ runChar=charCur;
+ digitCount=0;
+ while(emptyColumns>0 && runChar<charCur+T[charCur].CFollowing)
+ {
+ if (T[runChar].CharacterSet!=ZTFNC1)
+ {
+ /* NOT FNC1 */
+ digitCount+=2;
+ runChar++;
+ }
+ runChar++;
+ emptyColumns--;
+ }
+ return digitCount;
+}
+
+/* Find the Character distribution at a given column count.
+ * If too many rows (>44) are requested the columns are extended.
+ * Parameters :
+ * T Pointer on the Characters which fit in the row
+ * If a different count is calculated it is corrected
+ * in the callers workspace.
+ * pFillings Output of filling characters
+ * pSet Output of the character sets used, allocated by me.
+ * Return value Resulting row count
+ */
+
+static int Columns2Rows(struct zint_symbol *symbol, CharacterSetTable *T, const int dataLength,
+ int * pRows, int * pUseColumns, int * pSet, int * pFillings)
+{
+ int useColumns; /* Usable Characters per line */
+ int fillings; /* Number of filling characters */
+ int rowsCur;
+ int runChar;
+ int emptyColumns; /* Number of codes still empty in line. */
+ int emptyColumns2; /* Alternative emptyColumns to compare */
+ int CPaires; /* Number of digit pairs which may fit in the line */
+ int characterSetCur; /* Current Character Set */
+ int isFNC4; /* Set if current character FNC4 */
+
+ useColumns=*pUseColumns;
+
+ /* >>> Loop until rowsCur <= 44 */
+ do {
+ int charCur=0;
+ memset(pSet,0,dataLength*sizeof(int));
+ rowsCur=0;
+
+ /* >>> Line Loop */
+ do{
+ /* >> Start Character */
+ emptyColumns=useColumns; /* Remained place in Line */
+
+ /* >>Choose in Set A or B */
+ /* (C is changed as an option later on) */
+
+ pSet[charCur]=characterSetCur=
+ (T[charCur].AFollowing > T[charCur].BFollowing)
+ ? CodeA : CodeB;
+
+ /* >> Test on Numeric Mode C */
+ CPaires=RemainingDigits(T,charCur, emptyColumns);
+ if (CPaires>=4)
+ {
+ /* 4 Digits in Numeric compression ->OK */
+ /* > May an odd start find more ? */
+ /* Skip leading <FNC1>'s */
+ /* Typical structure : <FNC1><FNC1>12... */
+ /* Test if numeric after one isn't better.*/
+ runChar=charCur;
+ emptyColumns2=emptyColumns;
+ while (T[runChar].CharacterSet==ZTFNC1)
+ {
+ ++runChar;
+ --emptyColumns2;
+ }
+ if (CPaires>=RemainingDigits(T,runChar+1,emptyColumns2-1))
+ {
+ /* Start odd is not better */
+ /* We start in C */
+ pSet[charCur]=characterSetCur=CodeC;
+ /* Increment charCur */
+ if (T[charCur].CharacterSet!=ZTFNC1)
+ ++charCur; /* 2 Num.Digits */
+ }
+ }
+ ++charCur;
+ --emptyColumns;
+
+ /* >> Following characters */
+ while(emptyColumns>0 && charCur<dataLength)
+ {
+ isFNC4 = (T[charCur].CharacterSet & CodeFNC4);
+ switch(characterSetCur){
+ case CodeA:
+ case CodeB:
+ /* >> Check switching to CodeC */
+ /* Switch if :
+ * - Character not FNC1
+ * - 4 real Digits will fit in line
+ * - an odd Start will not be better
+ */
+ if (T[charCur].CharacterSet==ZTNum
+ && (CPaires=RemainingDigits(T,charCur, emptyColumns-1))>=4
+ && CPaires > RemainingDigits(T,charCur+1,emptyColumns-2))
+ {
+ /* > Change to C */
+ pSet[charCur]=characterSetCur=CodeC;
+ charCur+=2; /* 2 Digit */
+ emptyColumns-=2; /* <SwitchC>12 */
+ } else if (characterSetCur==CodeA)
+ {
+ if (T[charCur].AFollowing == 0 || (isFNC4 && T[charCur].AFollowing == 1))
+ {
+ /* Must change to B */
+ if (emptyColumns == 1 || (isFNC4 && emptyColumns == 2))
+ {
+ /* Can't switch: */
+ pSet[charCur-1]|=CEnd+CFill;
+ emptyColumns=0;
+ }else{
+ /* <Shift> or <switchB>? */
+ if (T[charCur].BFollowing == 1 || (isFNC4 && T[charCur].BFollowing == 2))
+ {
+ /* Note using order "FNC4 shift char" (same as CODE128) not "shift FNC4 char" as given in Table B.1 and Table B.2 */
+ if (isFNC4) { /* So skip FNC4 and shift value instead */
+ --emptyColumns;
+ ++charCur;
+ }
+ pSet[charCur]|=CShift;
+ } else {
+ pSet[charCur]|=CodeB;
+ characterSetCur = CodeB;
+ }
+ emptyColumns-=2;
+ ++charCur;
+ }
+ } else if (isFNC4 && emptyColumns == 1) {
+ /* Can't fit extended ASCII on same line */
+ pSet[charCur-1]|=CEnd+CFill;
+ emptyColumns=0;
+ }else{
+ --emptyColumns;
+ ++charCur;
+ }
+ } else { /* Last possibility : CodeB */
+ if (T[charCur].BFollowing == 0 || (isFNC4 && T[charCur].BFollowing == 1))
+ {
+ /* Must change to A */
+ if (emptyColumns == 1 || (isFNC4 && emptyColumns == 2))
+ {
+ /* Can't switch: */
+ pSet[charCur-1]|=CEnd+CFill;
+ emptyColumns=0;
+ } else {
+ /* <Shift> or <switchA>? */
+ if (T[charCur].AFollowing == 1 || (isFNC4 && T[charCur].AFollowing == 2))
+ {
+ /* Note using order "FNC4 shift char" (same as CODE128) not "shift FNC4 char" as given in Table B.1 and Table B.2 */
+ if (isFNC4) { /* So skip FNC4 and shift value instead */
+ --emptyColumns;
+ ++charCur;
+ }
+ pSet[charCur]|=CShift;
+ } else {
+ pSet[charCur]|=CodeA;
+ characterSetCur = CodeA;
+ }
+ emptyColumns-=2;
+ ++charCur;
+ }
+ } else if (isFNC4 && emptyColumns == 1) {
+ /* Can't fit extended ASCII on same line */
+ pSet[charCur-1]|=CEnd+CFill;
+ emptyColumns=0;
+ }else{
+ --emptyColumns;
+ ++charCur;
+ }
+ }
+ break;
+ case CodeC:
+ if(T[charCur].CFollowing>0)
+ {
+ charCur+=(T[charCur].CharacterSet==ZTFNC1)?1:2;
+ emptyColumns--;
+ }else{
+ /* Must change to A or B */
+ if (emptyColumns==1)
+ {
+ /* Can't switch: */
+ pSet[charCur-1]|=CEnd+CFill;
+ emptyColumns=0;
+ }else{
+ /*<SwitchA> or <switchA>?*/
+ characterSetCur=pSet[charCur]=
+ (T[charCur].AFollowing > T[charCur].BFollowing)
+ ?CodeA:CodeB;
+ emptyColumns-=2;
+ ++charCur;
+ }
+ }
+ break;
+ } /* switch */
+ } /* while */
+
+ /* > End of Codeline */
+ pSet[charCur-1]|=CEnd;
+ ++rowsCur;
+ } while (charCur<dataLength); /* <= Data.Len-1 */
+
+ /* Allow for check characters K1, K2 */
+ switch (emptyColumns) {
+ case 1:
+ pSet[charCur-1]|=CFill;
+ /* fall through */
+ case 0:
+ ++rowsCur;
+ fillings=useColumns-2+emptyColumns;
+ break;
+ case 2:
+ fillings=0;
+ break;
+ default:
+ pSet[charCur-1]|=CFill;
+ fillings=emptyColumns-2;
+ }
+
+ if (rowsCur>44) {
+ ++useColumns;
+ if (useColumns > 62) {
+ return ZINT_ERROR_TOO_LONG;
+ }
+ } else if (rowsCur == 1) {
+ rowsCur = 2;
+ fillings += useColumns;
+ }
+ } while(rowsCur>44);
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf(" -> out: rowsCur <%i>, useColumns <%i>, fillings <%i>\n",rowsCur,useColumns,fillings);
+ }
+ *pUseColumns=useColumns;
+ *pRows=rowsCur;
+ *pFillings=fillings;
+ return 0;
+}
+
+/* Find columns if row count is given.
+ */
+static int Rows2Columns(struct zint_symbol *symbol, CharacterSetTable *T, const int dataLength,
+ int * pRows, int * pUseColumns, int * pSet, int * pFillings)
+{
+ int rowsCur;
+ int rowsRequested; /* Number of requested rows */
+ int columnsRequested; /* Number of requested columns (if any) */
+ int backupRows = 0;
+ int fillings;
+ int backupFillings = 0;
+ int useColumns;
+ int testColumns; /* To enter into Width2Rows */
+ int backupColumns = 0;
+ int fBackupOk = 0; /* The memorised set is o.k. */
+ int testListSize = 0;
+ int pTestList[62];
+#ifndef _MSC_VER
+ int *pBackupSet[dataLength];
+#else
+ int *pBackupSet = (int *)_alloca(dataLength*sizeof(int));
+#endif
+
+ rowsRequested=*pRows;
+ columnsRequested = *pUseColumns >= 4 ? *pUseColumns : 0;
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Optimizer : Searching <%i> rows\n", rowsRequested);
+ }
+
+ if (columnsRequested) {
+ testColumns = columnsRequested;
+ } else {
+ /* First guess */
+ testColumns=dataLength/rowsRequested;
+ if (testColumns > 62)
+ testColumns = 62;
+ else if (testColumns < 4)
+ testColumns = 4;
+ }
+
+ for (;;) {
+ int errorCur;
+ pTestList[testListSize] = testColumns;
+ testListSize++;
+ useColumns=testColumns; /* Make a copy because it may be modified */
+ errorCur = Columns2Rows(symbol, T, dataLength, &rowsCur, &useColumns, pSet, &fillings);
+ if (errorCur != 0)
+ return errorCur;
+ if (rowsCur<=rowsRequested) {
+ /* Less or exactly line number found */
+ /* check if column count below already tested or at smallest/requested */
+ int fInTestList = (rowsCur == 2 || testColumns == 4 || testColumns == columnsRequested);
+ int posCur;
+ for (posCur = 0; posCur < testListSize && ! fInTestList; posCur++) {
+ if ( pTestList[posCur] == testColumns-1 )
+ fInTestList = 1;
+ }
+ if (fInTestList) {
+ /* >> Smaller Width already tested
+ */
+ if (rowsCur < rowsRequested) {
+ fillings += useColumns * (rowsRequested - rowsCur);
+ rowsCur = rowsRequested;
+ }
+ /* Exit with actual */
+ *pFillings=fillings;
+ *pRows=rowsCur;
+ *pUseColumns = useColumns;
+ return 0;
+ }
+ /* > Test more rows (shorter CDB) */
+ fBackupOk=(rowsCur==rowsRequested);
+ memcpy(pBackupSet,pSet,dataLength*sizeof(int));
+ backupFillings=fillings;
+ backupColumns=useColumns;
+ backupRows=rowsCur;
+ --testColumns;
+ } else {
+ /* > Too many rows */
+ int fInTestList = fBackupOk;
+ int posCur;
+ for (posCur = 0; posCur < testListSize && ! fInTestList; posCur++) {
+ if ( pTestList[posCur] == testColumns+1 )
+ fInTestList = 1;
+ }
+ if (fInTestList) {
+ /* The next less-rows (larger) code was
+ * already tested. So give the larger
+ * back.
+ */
+ memcpy(pSet,pBackupSet,dataLength*sizeof(int));
+ *pFillings=backupFillings;
+ *pRows=backupRows;
+ *pUseColumns=backupColumns;
+ return 0;
+ }
+ /* > Test less rows (longer code) */
+ backupRows=rowsCur;
+ memcpy(pBackupSet,pSet,dataLength*sizeof(int));
+ backupFillings=fillings;
+ backupColumns=useColumns;
+ fBackupOk=0;
+ ++testColumns;
+ }
+ }
+}
+
+/* Print a character in character set A
+ */
+static void A2C128_A(uchar **ppOutPos,uchar c)
+{
+ uchar * pOutPos = *ppOutPos;
+ switch(c){
+ case aCodeB: *pOutPos=100; break;
+ case aFNC4: *pOutPos=101; break;
+ case aFNC1: *pOutPos=102; break;
+ case aFNC2: *pOutPos=97; break;
+ case aFNC3: *pOutPos=96; break;
+ case aCodeC: *pOutPos=99; break;
+ case aShift: *pOutPos=98; break;
+ default:
+ /* +++ HaO 13.11.98 c>' ' && c < '\x1F' corrected */
+ if(c>=' ' && c<='_')
+ *pOutPos=(uchar)(c-' ');
+ else
+ *pOutPos=(uchar)(c+64);
+ break;
+ }
+ (*ppOutPos)++;
+}
+
+/* Output c in Set B
+ */
+static void A2C128_B(uchar **ppOutPos,uchar c)
+{
+ uchar * pOutPos = *ppOutPos;
+ switch(c){
+ case aFNC1: *pOutPos=102; break;
+ case aFNC2: *pOutPos=97; break;
+ case aFNC3: *pOutPos=96; break;
+ case aFNC4: *pOutPos=100; break;
+ case aCodeA: *pOutPos=101; break;
+ case aCodeC: *pOutPos=99; break;
+ case aShift: *pOutPos=98; break;
+ default: *pOutPos=(uchar)(c-' '); break;
+ }
+ ++(*ppOutPos);
+}
+
+/* Output c1, c2 in Set C
+ */
+static void A2C128_C(uchar **ppOutPos,uchar c1,uchar c2)
+{
+ uchar * pOutPos = *ppOutPos;
+ switch(c1){
+ case aFNC1: *pOutPos=102; break;
+ case aCodeB: *pOutPos=100; break;
+ case aCodeA: *pOutPos=101; break;
+ default: *pOutPos=(char)(10 * (c1- '0') + (c2 - '0'));break;
+ }
+ (*ppOutPos)++;
+}
+
+/* Output a character in Characterset
+ */
+static void ASCIIZ128(uchar **ppOutPos, int CharacterSet,uchar c1, uchar c2)
+{
+ if (CharacterSet==CodeA)
+ A2C128_A(ppOutPos,c1);
+ else if(CharacterSet==CodeB)
+ A2C128_B(ppOutPos,c1);
+ else
+ A2C128_C(ppOutPos,c1,c2);
+}
+
+/* XLate Tables D.2, D.3 and F.1 of Codablock-F Specification and call output
+ */
+static void SumASCII(uchar **ppOutPos, int Sum, int CharacterSet)
+{
+ switch (CharacterSet){
+ case CodeA: /* Row # Indicators and Data Check Characters K1/K2 for CodeA and CodeB are the same */
+ case CodeB:
+ if (Sum<=31)
+ A2C128_B(ppOutPos, (uchar)(Sum+96));
+ else if(Sum<=47)
+ A2C128_B(ppOutPos, (uchar)Sum);
+ else
+ A2C128_B(ppOutPos, (uchar)(Sum+10));
+ break;
+ case CodeC:
+ A2C128_C(ppOutPos
+ ,(char)(Sum/10+'0') ,(uchar)(Sum%10+'0'));
+ break;
+ }
+}
+
+/* Main function called by zint framework
+ */
+INTERNAL int codablock(struct zint_symbol *symbol,const unsigned char source[], const size_t length) {
+ int charCur, dataLength;
+ int Error;
+ int rows, columns, useColumns;
+ int fillings;
+ int Sum1,Sum2;
+ uchar * pOutPos;
+ int rowCur;
+ int characterSetCur;
+ int emptyColumns;
+ char dest[1000];
+ int r, c;
+#ifdef _MSC_VER
+ CharacterSetTable *T;
+ unsigned char *data;
+ int *pSet;
+ uchar * pOutput;
+#endif
+ /* Suppresses clang-analyzer-core.VLASize warning */
+ assert(length > 0);
+
+ /* Parameter check */
+ /* option1: rows <= 0: automatic, 1..44 */
+ rows = symbol->option_1;
+ if (rows == 1) {
+ Error = code_128(symbol, source, length);
+ if (Error < 5) {
+ symbol->output_options |= BARCODE_BIND;
+ if (symbol->border_width == 0) { /* Allow override if non-zero */
+ symbol->border_width = 1; /* AIM ISS-X-24 Section 4.6.1 b) (note change from previous default 2) */
+ }
+ }
+ return Error;
+ }
+ if (rows > 44) {
+ strcpy(symbol->errtxt, "410: Rows parameter not in 0..44");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+ /* option_2: (usable data) columns: <= 0: automatic, 9..67 (min 9 == 4 data, max 67 == 62 data) */
+ columns = symbol->option_2;
+ if ( ! (columns <= 0 || (columns >= 9 && columns <= 67)) ) {
+ strcpy(symbol->errtxt, "411: Columns parameter not in 0, 9..67");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+
+#ifndef _MSC_VER
+ unsigned char data[length*2+1];
+#else
+ data = (unsigned char *) _alloca(length * 2+1);
+#endif
+
+ dataLength = 0;
+ if (symbol->output_options & READER_INIT) {
+ data[dataLength] = aFNC3;
+ dataLength++;
+ }
+ /* Replace all Codes>127 with <fnc4>Code-128 */
+ for (charCur = 0; charCur < (int) length; charCur++) {
+ if (source[charCur]>127)
+ {
+ data[dataLength] = aFNC4;
+ dataLength++;
+ data[dataLength] = (unsigned char)(source[charCur]&127);
+ } else
+ data[dataLength] = source[charCur];
+ dataLength++;
+ }
+
+ /* Build character set table */
+#ifndef _MSC_VER
+ CharacterSetTable T[dataLength];
+ int pSet[dataLength];
+#else
+ T=(CharacterSetTable *)_alloca(dataLength*sizeof(CharacterSetTable));
+ pSet = (int *)_alloca(dataLength*sizeof(int));
+#endif
+ CreateCharacterSetTable(T,data,dataLength);
+
+ /* Find final row and column count */
+ /* nor row nor column count given */
+ if (rows <= 0 && columns <= 0) {
+ /* use 1/1 aspect/ratio Codablock */
+ columns = floor(sqrt(dataLength)) + 5;
+ if (columns > 67) {
+ columns = 67;
+ } else if (columns < 9) {
+ columns = 9;
+ }
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Auto column count for %d characters:%d\n", dataLength, columns);
+ }
+ }
+ /* There are 5 Codewords for Organisation Start(2),row(1),CheckSum,Stop */
+ useColumns = columns - 5;
+ if ( rows > 0 ) {
+ /* row count given */
+ Error = Rows2Columns(symbol, T, dataLength, &rows, &useColumns, pSet, &fillings);
+ } else {
+ /* column count given */
+ Error = Columns2Rows(symbol, T, dataLength, &rows, &useColumns, pSet, &fillings);
+ }
+ if (Error != 0) {
+ strcpy(symbol->errtxt, "413: Data string too long");
+ return Error;
+ }
+ /* Suppresses clang-analyzer-core.VLASize warning */
+ assert(rows >= 2 && useColumns >= 4);
+
+ /* Data Check Characters K1 and K2, Annex F */
+ Sum1 = Sum2 = 0;
+ for (charCur = 0; charCur < (int) length; charCur++) {
+ Sum1 = (Sum1 + (charCur + 1) * source[charCur]) % 86; /* Mod as we go along to avoid overflow */
+ Sum2 = (Sum2 + charCur * source[charCur]) % 86;
+ }
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) { /* start a new level of local variables */
+ int DPos;
+ printf("\nData:");
+ for (DPos=0 ; DPos< dataLength ; DPos++)
+ fputc(data[DPos],stdout);
+ printf("\n Set:");
+ for (DPos=0 ; DPos< dataLength ; DPos++) {
+ switch (pSet[DPos]&(CodeA+CodeB+CodeC)) {
+ case CodeA: fputc('A',stdout); break;
+ case CodeB: fputc('B',stdout); break;
+ case CodeC: fputc('C',stdout); break;
+ default: fputc('.',stdout); break;
+ }
+ }
+ printf("\nFNC1:");
+ for (DPos=0 ; DPos< dataLength ; DPos++)
+ fputc((pSet[DPos]&CodeFNC1)==0?'.':'X',stdout);
+ printf("\n END:");
+ for (DPos=0 ; DPos< dataLength ; DPos++)
+ fputc((pSet[DPos]&CEnd)==0?'.':'X',stdout);
+ printf("\nShif:");
+ for (DPos=0 ; DPos< dataLength ; DPos++)
+ fputc((pSet[DPos]&CShift)==0?'.':'X',stdout);
+ printf("\nFILL:");
+ for (DPos=0 ; DPos< dataLength ; DPos++)
+ fputc((pSet[DPos]&CFill)==0?'.':'X',stdout);
+ fputc('\n',stdout);
+ printf("K1 %d, K2 %d\n", Sum1, Sum2);
+ }
+
+ columns = useColumns + 5;
+
+ /* >>> Build C128 code numbers */
+ /* The C128 column count contains Start (2CW), Row ID, Checksum, Stop */
+#ifndef _MSC_VER
+ uchar pOutput[columns * rows];
+#else
+ pOutput = (unsigned char *)_alloca(columns * rows * sizeof(char));
+#endif
+ pOutPos = pOutput;
+ charCur=0;
+ /* >> Loop over rows */
+ for (rowCur=0 ; rowCur<rows ; rowCur++) {
+ if (charCur>=dataLength)
+ {
+ /* >> Empty line with StartA, aCodeB, row #, and then filler aCodeC aCodeB etc */
+ *pOutPos='\x67';
+ pOutPos++;
+ *pOutPos = 100; /* aCodeB */
+ pOutPos++;
+ characterSetCur = CodeB;
+ SumASCII(&pOutPos, rowCur + 42, characterSetCur); /* Row # */
+ emptyColumns = useColumns;
+ if (rowCur == rows - 1) {
+ emptyColumns -= 2;
+ }
+ while (emptyColumns>0)
+ {
+ if(characterSetCur==CodeC)
+ {
+ A2C128_C(&pOutPos,aCodeB,'\0');
+ characterSetCur=CodeB;
+ }else{
+ A2C128_B(&pOutPos,aCodeC);
+ characterSetCur=CodeC;
+ }
+ --emptyColumns;
+ }
+ }else{
+ /* >> Normal Line */
+ /* > Startcode */
+ switch (pSet[charCur] & (CodeA+CodeB+CodeC)){
+ case CodeA:
+ *pOutPos = '\x67';
+ pOutPos++;
+ *pOutPos = '\x62';
+ pOutPos++;
+ characterSetCur=CodeA;
+ break;
+ case CodeB:
+ *pOutPos = '\x67';
+ pOutPos++;
+ *pOutPos = '\x64';
+ pOutPos++;
+ characterSetCur=CodeB;
+ break;
+ case CodeC:
+ default:
+ *pOutPos = '\x67';
+ pOutPos++;
+ *pOutPos = '\x63';
+ pOutPos++;
+ characterSetCur=CodeC;
+ break;
+ }
+ /* > Set F1 */
+ /* In first line : # of rows */
+ SumASCII(&pOutPos, rowCur == 0 ? rows - 2 : rowCur + 42, characterSetCur);
+ /* >>> Data */
+ emptyColumns=useColumns;
+ /* >> Character loop */
+ while (emptyColumns > 0 && charCur < dataLength)
+ {
+ /* ? Change character set */
+ if (emptyColumns < useColumns)
+ {
+ if ((pSet[charCur]&CodeA)!=0)
+ {
+ /* Change to A */
+ ASCIIZ128(&pOutPos,characterSetCur,aCodeA,'\0');
+ --emptyColumns;
+ characterSetCur=CodeA;
+ } else if ((pSet[charCur]&CodeB)!=0)
+ {
+ /* Change to B */
+ ASCIIZ128(&pOutPos,characterSetCur,aCodeB,'\0');
+ --emptyColumns;
+ characterSetCur=CodeB;
+ } else if ((pSet[charCur]&CodeC)!=0)
+ {
+ /* Change to C */
+ ASCIIZ128(&pOutPos,characterSetCur,aCodeC,'\0');
+ --emptyColumns;
+ characterSetCur=CodeC;
+ }
+ }
+ if ((pSet[charCur]&CShift)!=0)
+ {
+ /* >> Shift it and put out the shifted character */
+ ASCIIZ128(&pOutPos,characterSetCur,aShift,'\0');
+ emptyColumns-=2;
+ characterSetCur=(characterSetCur==CodeB)?CodeA:CodeB;
+ ASCIIZ128(&pOutPos,characterSetCur,data[charCur],'\0');
+ characterSetCur=(characterSetCur==CodeB)?CodeA:CodeB;
+ }else{
+ /* Normal Character */
+ if (characterSetCur==CodeC)
+ {
+ if (data[charCur]==aFNC1)
+ A2C128_C(&pOutPos,aFNC1,'\0');
+ else
+ {
+ A2C128_C(&pOutPos, data[charCur], charCur + 1 < dataLength ? data[charCur + 1] : 0);
+ ++charCur;
+ /* We need this here to get the good index */
+ /* for the termination flags in Set. */
+ }
+ }else
+ ASCIIZ128(&pOutPos,characterSetCur,data[charCur],'\0');
+ --emptyColumns;
+ }
+ /* >> End Criteria */
+ if ((pSet[charCur] & CFill) || (pSet[charCur] & CEnd))
+ {
+ /* Fill Line but leave space for checks in last line */
+ if (rowCur == rows - 1) {
+ emptyColumns -= 2;
+ }
+ while(emptyColumns>0)
+ {
+ switch(characterSetCur){
+ case CodeC:
+ A2C128_C(&pOutPos,aCodeB,'\0');
+ characterSetCur=CodeB;
+ break;
+ case CodeB:
+ A2C128_B(&pOutPos,aCodeC);
+ characterSetCur=CodeC;
+ break;
+ case CodeA:
+ A2C128_A(&pOutPos,aCodeC);
+ characterSetCur=CodeC;
+ break;
+ }
+ --emptyColumns;
+ }
+ }
+ ++charCur;
+ } /* Loop over characters */
+ } /* if filling-Line / normal */
+
+ /* Add checksum in last line */
+ if (rowCur == rows - 1)
+ {
+ SumASCII(&pOutPos,Sum1,characterSetCur);
+ SumASCII(&pOutPos,Sum2,characterSetCur);
+ }
+ /* Add Code 128 checksum */
+ {
+ int Sum = pOutput[columns * rowCur] % 103;
+ int Pos = 1;
+ for ( ; Pos < useColumns+3 ; Pos++)
+ {
+ Sum = (Sum + pOutput[columns * rowCur + Pos] * Pos) % 103;
+ }
+ *pOutPos=(uchar)Sum;
+ pOutPos++;
+ }
+ /* Add end character */
+ *pOutPos=106;
+ pOutPos++;
+ } /* End Lineloop */
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ /* Dump the output to the screen
+ */
+ printf("\nCode 128 Code Numbers:\n");
+ { /* start a new level of local variables */
+ int DPos, DPos2;
+ for (DPos=0 ; DPos< rows ; DPos++)
+ {
+ for (DPos2=0 ; DPos2 < columns ; DPos2++)
+ {
+ printf("%3d ",(int)(pOutput[DPos*columns+DPos2]));
+ }
+ printf("\n");
+ }
+ }
+ printf("rows=%i columns=%i fillings=%i\n", rows, columns, fillings);
+ }
+#ifdef ZINT_TEST
+ if (symbol->debug & ZINT_DEBUG_TEST) {
+ debug_test_codeword_dump(symbol, pOutput, rows * columns);
+ }
+#endif
+
+ /* Paint the C128 patterns */
+ for (r = 0; r < rows; r++) {
+ strcpy(dest, "");
+ for(c = 0; c < columns; c++) {
+ strcat(dest, C128Table[pOutput[r * columns + c]]);
+ }
+ expand(symbol, dest);
+ symbol->row_height[r] = 10;
+ }
+
+ symbol->output_options |= BARCODE_BIND;
+
+ if (symbol->border_width == 0) { /* Allow override if non-zero */
+ symbol->border_width = 1; /* AIM ISS-X-24 Section 4.6.1 b) (note change from previous default 2) */
+ }
+
+ return 0;
+}
diff --git a/backend/code.c b/backend/code.c
index 9d30e5a..455491c 100644
--- a/backend/code.c
+++ b/backend/code.c
@@ -1,8 +1,11 @@
-/* code.c - Handles Code 11, 39, 39+ and 93 */
+/* code.c - Handles Code 11, 39, 39+, 93, PZN, Channel and VIN */
+/* LOGMARS MIL-STD-1189 Rev. B https://apps.dtic.mil/dtic/tr/fulltext/u2/a473534.pdf */
+/* PZN https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/IFA_Info_Code_39_EN.pdf */
+/* PZN https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/IFA-Info_Check_Digit_Calculations_PZN_PPN_UDI_EN.pdf */
/*
libzint - the open source barcode library
- Copyright (C) 2008 Robin Stuart <robin@zint.org.uk>
+ Copyright (C) 2008 - 2020 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -28,161 +31,769 @@
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
-*/
+ */
+/* vim: set ts=4 sw=4 et : */
/* In version 0.5 this file was 1,553 lines long! */
-#include <string.h>
#include <stdio.h>
-#include <stdlib.h>
+#include <assert.h>
#include "common.h"
-#define SODIUM "0123456789-"
-#define SILVER "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd"
-
-static const char *C11Table[11] = {"111121", "211121", "121121", "221111", "112121", "212111", "122111",
- "111221", "211211", "211111", "112111"};
+#define SODIUM "0123456789-"
+#define SILVER "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd"
+#define ARSENIC "0123456789ABCDEFGHJKLMNPRSTUVWXYZ"
+static const char *C11Table[11] = {
+ "111121", "211121", "121121", "221111", "112121", "212111", "122111",
+ "111221", "211211", "211111", "112111"
+};
/* Code 39 tables checked against ISO/IEC 16388:2007 */
-
+
/* Incorporates Table A1 */
-static const char *C39Table[43] = { "1112212111", "2112111121", "1122111121", "2122111111", "1112211121",
- "2112211111", "1122211111", "1112112121", "2112112111", "1122112111", "2111121121",
- "1121121121", "2121121111", "1111221121", "2111221111", "1121221111", "1111122121",
- "2111122111", "1121122111", "1111222111", "2111111221", "1121111221", "2121111211",
- "1111211221", "2111211211", "1121211211", "1111112221", "2111112211", "1121112211",
- "1111212211", "2211111121", "1221111121", "2221111111", "1211211121", "2211211111",
- "1221211111", "1211112121", "2211112111", "1221112111", "1212121111", "1212111211",
- "1211121211", "1112121211"};
-/* Code 39 character assignments (Table 1) */
-
-static const char *EC39Ctrl[128] = {"%U", "$A", "$B", "$C", "$D", "$E", "$F", "$G", "$H", "$I", "$J", "$K",
- "$L", "$M", "$N", "$O", "$P", "$Q", "$R", "$S", "$T", "$U", "$V", "$W", "$X", "$Y", "$Z",
- "%A", "%B", "%C", "%D", "%E", " ", "/A", "/B", "/C", "/D", "/E", "/F", "/G", "/H", "/I", "/J",
- "/K", "/L", "-", ".", "/O", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "/Z", "%F",
- "%G", "%H", "%I", "%J", "%V", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
- "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "%K", "%L", "%M", "%N", "%O",
- "%W", "+A", "+B", "+C", "+D", "+E", "+F", "+G", "+H", "+I", "+J", "+K", "+L", "+M", "+N", "+O",
- "+P", "+Q", "+R", "+S", "+T", "+U", "+V", "+W", "+X", "+Y", "+Z", "%P", "%Q", "%R", "%S", "%T"};
-/* Encoding the full ASCII character set in Code 39 (Table A2) */
-
-static const char *C93Ctrl[128] = {"bU", "aA", "aB", "aC", "aD", "aE", "aF", "aG", "aH", "aI", "aJ", "aK",
- "aL", "aM", "aN", "aO", "aP", "aQ", "aR", "aS", "aT", "aU", "aV", "aW", "aX", "aY", "aZ",
- "bA", "bB", "bC", "bD", "bE", " ", "cA", "cB", "cC", "cD", "cE", "cF", "cG", "cH", "cI", "cJ",
- "cK", "cL", "cM", "cN", "cO", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "cZ", "bF",
- "bG", "bH", "bI", "bJ", "bV", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
- "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bK", "bL", "bM", "bN", "bO",
- "bW", "dA", "dB", "dC", "dD", "dE", "dF", "dG", "dH", "dI", "dJ", "dK", "dL", "dM", "dN", "dO",
- "dP", "dQ", "dR", "dS", "dT", "dU", "dV", "dW", "dX", "dY", "dZ", "bP", "bQ", "bR", "bS", "bT"};
-
-static const char *C93Table[47] = {"131112", "111213", "111312", "111411", "121113", "121212", "121311",
- "111114", "131211", "141111", "211113", "211212", "211311", "221112", "221211", "231111",
- "112113", "112212", "112311", "122112", "132111", "111123", "111222", "111321", "121122",
- "131121", "212112", "212211", "211122", "211221", "221121", "222111", "112122", "112221",
- "122121", "123111", "121131", "311112", "311211", "321111", "112131", "113121", "211131",
- "121221", "312111", "311121", "122211"};
-
-/* Global Variables for Channel Code */
-int S[11], B[11];
-long value;
-long target_value;
-char pattern[30];
-
-int c39(struct zint_symbol *symbol, unsigned char source[], int length)
-{ /* Code 39 */
- unsigned int i;
- unsigned int counter;
- char check_digit;
- int error_number;
- char dest[775];
- char localstr[2] = { 0 };
-
- error_number = 0;
- counter = 0;
-
- if((symbol->option_2 < 0) || (symbol->option_2 > 1)) {
- symbol->option_2 = 0;
- }
-
- if((symbol->symbology == BARCODE_LOGMARS) && (length > 59)) {
- strcpy(symbol->errtxt, "Input too long");
- return ERROR_TOO_LONG;
- } else if(length > 74) {
- strcpy(symbol->errtxt, "Input too long");
- return ERROR_TOO_LONG;
- }
- to_upper(source);
- error_number = is_sane(SILVER , source, length);
- if(error_number == ERROR_INVALID_DATA) {
- strcpy(symbol->errtxt, "Invalid characters in data");
- return error_number;
- }
-
- /* Start character */
- strcpy(dest, "1211212111");
-
- for(i = 0; i < length; i++) {
- lookup(SILVER, C39Table, source[i], dest);
- counter += posn(SILVER, source[i]);
- }
-
- if((symbol->symbology == BARCODE_LOGMARS) || (symbol->option_2 == 1)) {
-
- counter = counter % 43;
- if(counter < 10) {
- check_digit = itoc(counter);
- } else {
- if(counter < 36) {
- check_digit = (counter - 10) + 'A';
- } else {
- switch(counter) {
- case 36: check_digit = '-'; break;
- case 37: check_digit = '.'; break;
- case 38: check_digit = ' '; break;
- case 39: check_digit = '$'; break;
- case 40: check_digit = '/'; break;
- case 41: check_digit = '+'; break;
- case 42: check_digit = 37; break;
- default: check_digit = ' '; break; /* Keep compiler happy */
- }
- }
- }
- lookup(SILVER, C39Table, check_digit, dest);
-
- /* Display a space check digit as _, otherwise it looks like an error */
- if(check_digit == ' ') {
- check_digit = '_';
- }
-
- localstr[0] = check_digit;
- localstr[1] = '\0';
- }
-
- /* Stop character */
- concat (dest, "121121211");
-
- if((symbol->symbology == BARCODE_LOGMARS) || (symbol->symbology == BARCODE_HIBC_39)) {
- /* LOGMARS uses wider 'wide' bars than normal Code 39 */
- counter = strlen(dest);
- for(i = 0; i < counter; i++) {
- if(dest[i] == '2') {
- dest[i] = '3';
- }
- }
- }
-
- expand(symbol, dest);
-
- if(symbol->symbology == BARCODE_CODE39) {
- ustrcpy(symbol->text, (unsigned char*)"*");
- uconcat(symbol->text, source);
- uconcat(symbol->text, (unsigned char*)localstr);
- uconcat(symbol->text, (unsigned char*)"*");
- } else {
- ustrcpy(symbol->text, source);
- uconcat(symbol->text, (unsigned char*)localstr);
- }
- return error_number;
+static const char *C39Table[43] = {
+ /* Code 39 character assignments (Table 1) */
+ "1112212111", "2112111121", "1122111121", "2122111111", "1112211121",
+ "2112211111", "1122211111", "1112112121", "2112112111", "1122112111", "2111121121",
+ "1121121121", "2121121111", "1111221121", "2111221111", "1121221111", "1111122121",
+ "2111122111", "1121122111", "1111222111", "2111111221", "1121111221", "2121111211",
+ "1111211221", "2111211211", "1121211211", "1111112221", "2111112211", "1121112211",
+ "1111212211", "2211111121", "1221111121", "2221111111", "1211211121", "2211211111",
+ "1221211111", "1211112121", "2211112111", "1221112111", "1212121111", "1212111211",
+ "1211121211", "1112121211"
+};
+
+static const char *EC39Ctrl[128] = {
+ /* Encoding the full ASCII character set in Code 39 (Table A2) */
+ "%U", "$A", "$B", "$C", "$D", "$E", "$F", "$G", "$H", "$I", "$J", "$K",
+ "$L", "$M", "$N", "$O", "$P", "$Q", "$R", "$S", "$T", "$U", "$V", "$W", "$X", "$Y", "$Z",
+ "%A", "%B", "%C", "%D", "%E", " ", "/A", "/B", "/C", "/D", "/E", "/F", "/G", "/H", "/I", "/J",
+ "/K", "/L", "-", ".", "/O", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "/Z", "%F",
+ "%G", "%H", "%I", "%J", "%V", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "%K", "%L", "%M", "%N", "%O",
+ "%W", "+A", "+B", "+C", "+D", "+E", "+F", "+G", "+H", "+I", "+J", "+K", "+L", "+M", "+N", "+O",
+ "+P", "+Q", "+R", "+S", "+T", "+U", "+V", "+W", "+X", "+Y", "+Z", "%P", "%Q", "%R", "%S", "%T"
+};
+
+static const char *C93Ctrl[128] = {
+ "bU", "aA", "aB", "aC", "aD", "aE", "aF", "aG", "aH", "aI", "aJ", "aK",
+ "aL", "aM", "aN", "aO", "aP", "aQ", "aR", "aS", "aT", "aU", "aV", "aW", "aX", "aY", "aZ",
+ "bA", "bB", "bC", "bD", "bE", " ", "cA", "cB", "cC", "$", "%", "cF", "cG", "cH", "cI", "cJ",
+ "+", "cL", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "cZ", "bF",
+ "bG", "bH", "bI", "bJ", "bV", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bK", "bL", "bM", "bN", "bO",
+ "bW", "dA", "dB", "dC", "dD", "dE", "dF", "dG", "dH", "dI", "dJ", "dK", "dL", "dM", "dN", "dO",
+ "dP", "dQ", "dR", "dS", "dT", "dU", "dV", "dW", "dX", "dY", "dZ", "bP", "bQ", "bR", "bS", "bT"
+};
+
+static const char *C93Table[47] = {
+ "131112", "111213", "111312", "111411", "121113", "121212", "121311",
+ "111114", "131211", "141111", "211113", "211212", "211311", "221112", "221211", "231111",
+ "112113", "112212", "112311", "122112", "132111", "111123", "111222", "111321", "121122",
+ "131121", "212112", "212211", "211122", "211221", "221121", "222111", "112122", "112221",
+ "122121", "123111", "121131", "311112", "311211", "321111", "112131", "113121", "211131",
+ "121221", "312111", "311121", "122211"
+};
+
+/* *********************** CODE 11 ******************** */
+INTERNAL int code_11(struct zint_symbol *symbol, unsigned char source[], int length) { /* Code 11 */
+
+ int i;
+ int h, c_digit, c_weight, c_count, k_digit, k_weight, k_count;
+ int weight[122], error_number;
+ char dest[750]; /* 6 + 121 * 6 + 2 * 6 + 5 + 1 == 750 */
+ char checkstr[3];
+ int num_check_digits;
+
+ /* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warning */
+ assert(length > 0);
+
+ if (length > 121) {
+ strcpy(symbol->errtxt, "320: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ error_number = is_sane(SODIUM, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "321: Invalid characters in data");
+ return error_number;
+ }
+
+ if (symbol->option_2 < 0 || symbol->option_2 > 2) {
+ strcpy(symbol->errtxt, "339: Invalid check digit version");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+ if (symbol->option_2 == 2) {
+ num_check_digits = 0;
+ } else if (symbol->option_2 == 1) {
+ num_check_digits = 1;
+ } else {
+ num_check_digits = 2;
+ }
+
+ c_weight = 1;
+ c_count = 0;
+ k_weight = 1;
+ k_count = 0;
+
+ /* start character */
+ strcpy(dest, "112211");
+
+ /* Draw main body of barcode */
+ for (i = 0; i < length; i++) {
+ lookup(SODIUM, C11Table, source[i], dest);
+ if (source[i] == '-')
+ weight[i] = 10;
+ else
+ weight[i] = ctoi(source[i]);
+ }
+
+ if (num_check_digits) {
+ /* Calculate C checksum */
+ for (h = length - 1; h >= 0; h--) {
+ c_count += (c_weight * weight[h]);
+ c_weight++;
+
+ if (c_weight > 10) {
+ c_weight = 1;
+ }
+ }
+ c_digit = c_count % 11;
+
+ if (num_check_digits == 1) {
+ checkstr[0] = itoc(c_digit);
+ if (checkstr[0] == 'A') {
+ checkstr[0] = '-';
+ }
+ checkstr[1] = '\0';
+ lookup(SODIUM, C11Table, checkstr[0], dest);
+ } else {
+ weight[length] = c_digit;
+
+ /* Calculate K checksum */
+ for (h = length; h >= 0; h--) {
+ k_count += (k_weight * weight[h]);
+ k_weight++;
+
+ if (k_weight > 9) {
+ k_weight = 1;
+ }
+ }
+ k_digit = k_count % 11;
+
+ checkstr[0] = itoc(c_digit);
+ checkstr[1] = itoc(k_digit);
+ if (checkstr[0] == 'A') {
+ checkstr[0] = '-';
+ }
+ if (checkstr[1] == 'A') {
+ checkstr[1] = '-';
+ }
+ checkstr[2] = '\0';
+ lookup(SODIUM, C11Table, checkstr[0], dest);
+ lookup(SODIUM, C11Table, checkstr[1], dest);
+ }
+ }
+
+ /* Stop character */
+ strcat(dest, "11221");
+
+ expand(symbol, dest);
+
+ ustrcpy(symbol->text, source);
+ if (num_check_digits) {
+ ustrcat(symbol->text, checkstr);
+ }
+ return error_number;
+}
+
+/* Code 39 */
+INTERNAL int c39(struct zint_symbol *symbol, unsigned char source[], const size_t length) {
+ int i;
+ int counter;
+ int error_number;
+ char dest[880]; /* 10 (Start) + 85 * 10 + 10 (Check) + 9 (Stop) + 1 = 880 */
+ char localstr[2] = {0};
+
+ counter = 0;
+
+ if ((symbol->option_2 < 0) || (symbol->option_2 > 1)) {
+ symbol->option_2 = 0;
+ }
+
+ if ((symbol->symbology == BARCODE_LOGMARS) && (length > 30)) { /* MIL-STD-1189 Rev. B Section 5.2.6.2 */
+ strcpy(symbol->errtxt, "322: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ } else if ((symbol->symbology == BARCODE_HIBC_39) && (length > 68)) { /* Prevent encoded_data out-of-bounds >= 143 due to wider 'wide' bars */
+ strcpy(symbol->errtxt, "319: Input too long"); /* Note use 319 (2of5 range) as 340 taken by CODE128 */
+ return ZINT_ERROR_TOO_LONG;
+ } else if (length > 85) {
+ strcpy(symbol->errtxt, "323: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ to_upper(source);
+ error_number = is_sane(SILVER, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "324: Invalid characters in data");
+ return error_number;
+ }
+
+ /* Start character */
+ strcpy(dest, "1211212111");
+
+ for (i = 0; i < (int) length; i++) {
+ lookup(SILVER, C39Table, source[i], dest);
+ counter += posn(SILVER, source[i]);
+ }
+
+ if (symbol->option_2 == 1) {
+
+ char check_digit;
+ counter = counter % 43;
+ if (counter < 10) {
+ check_digit = itoc(counter);
+ } else {
+ if (counter < 36) {
+ check_digit = (counter - 10) + 'A';
+ } else {
+ switch (counter) {
+ case 36: check_digit = '-';
+ break;
+ case 37: check_digit = '.';
+ break;
+ case 38: check_digit = ' ';
+ break;
+ case 39: check_digit = '$';
+ break;
+ case 40: check_digit = '/';
+ break;
+ case 41: check_digit = '+';
+ break;
+ case 42: check_digit = 37;
+ break;
+ default: check_digit = ' ';
+ break; /* Keep compiler happy */
+ }
+ }
+ }
+ lookup(SILVER, C39Table, check_digit, dest);
+
+ /* Display a space check digit as _, otherwise it looks like an error */
+ if (check_digit == ' ') {
+ check_digit = '_';
+ }
+
+ localstr[0] = check_digit;
+ localstr[1] = '\0';
+ }
+
+ /* Stop character */
+ strcat(dest, "121121211");
+
+ if ((symbol->symbology == BARCODE_LOGMARS) || (symbol->symbology == BARCODE_HIBC_39)) {
+ /* LOGMARS uses wider 'wide' bars than normal Code 39 */
+ counter = strlen(dest);
+ for (i = 0; i < counter; i++) {
+ if (dest[i] == '2') {
+ dest[i] = '3';
+ }
+ }
+ }
+
+ expand(symbol, dest);
+
+ if (symbol->symbology == BARCODE_CODE39) {
+ ustrcpy(symbol->text, "*");
+ ustrcat(symbol->text, source);
+ ustrcat(symbol->text, localstr);
+ ustrcat(symbol->text, "*");
+ } else {
+ ustrcpy(symbol->text, source);
+ ustrcat(symbol->text, localstr);
+ }
+ return error_number;
+}
+
+/* Pharmazentral Nummer (PZN) */
+INTERNAL int pharmazentral(struct zint_symbol *symbol, unsigned char source[], int length) {
+
+ int i, error_number, zeroes;
+ unsigned int count, check_digit;
+ char localstr[11];
+
+ if (length > 7) {
+ strcpy(symbol->errtxt, "325: Input wrong length");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "326: Invalid characters in data");
+ return error_number;
+ }
+
+ localstr[0] = '-';
+ zeroes = 7 - length + 1;
+ for (i = 1; i < zeroes; i++)
+ localstr[i] = '0';
+ ustrcpy(localstr + zeroes, source);
+
+ count = 0;
+ for (i = 1; i < 8; i++) {
+ count += i * ctoi(localstr[i]);
+ }
+
+ check_digit = count % 11;
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("PZN: %s, check digit %d\n", localstr, check_digit);
+ }
+
+ if (check_digit == 10) {
+ strcpy(symbol->errtxt, "327: Invalid PZN Data");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ localstr[8] = itoc(check_digit);
+ localstr[9] = '\0';
+ error_number = c39(symbol, (unsigned char *) localstr, strlen(localstr));
+ ustrcpy(symbol->text, "PZN ");
+ ustrcat(symbol->text, localstr);
+ return error_number;
+}
+
+/* Extended Code 39 - ISO/IEC 16388:2007 Annex A */
+INTERNAL int ec39(struct zint_symbol *symbol, unsigned char source[], int length) {
+
+ unsigned char buffer[85 * 2 + 1] = {0};
+ int i;
+ int error_number;
+
+ if (length > 85) {
+ strcpy(symbol->errtxt, "328: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* Creates a buffer string and places control characters into it */
+ for (i = 0; i < length; i++) {
+ if (source[i] > 127) {
+ /* Cannot encode extended ASCII */
+ strcpy(symbol->errtxt, "329: Invalid characters in input data");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ ustrcat(buffer, EC39Ctrl[source[i]]);
+ }
+
+ /* Then sends the buffer to the C39 function */
+ error_number = c39(symbol, buffer, ustrlen(buffer));
+
+ for (i = 0; i < length; i++)
+ symbol->text[i] = source[i] ? source[i] : ' ';
+ symbol->text[length] = '\0';
+
+ return error_number;
+}
+
+/* Code 93 is an advancement on Code 39 and the definition is a lot tighter */
+INTERNAL int c93(struct zint_symbol *symbol, unsigned char source[], int length) {
+
+ /* SILVER includes the extra characters a, b, c and d to represent Code 93 specific
+ shift characters 1, 2, 3 and 4 respectively. These characters are never used by
+ c39() and ec39() */
+
+ int i;
+ int h, weight, c, k, values[128], error_number;
+ char buffer[220];
+ char dest[670];
+ char set_copy[] = SILVER;
+
+ error_number = 0;
+ strcpy(buffer, "");
+
+ if (length > 107) {
+ strcpy(symbol->errtxt, "330: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* Message Content */
+ for (i = 0; i < length; i++) {
+ if (source[i] > 127) {
+ /* Cannot encode extended ASCII */
+ strcpy(symbol->errtxt, "331: Invalid characters in input data");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ strcat(buffer, C93Ctrl[source[i]]);
+ symbol->text[i] = source[i] ? source[i] : ' ';
+ }
+
+ /* Now we can check the true length of the barcode */
+ h = (int) strlen(buffer);
+ if (h > 107) {
+ strcpy(symbol->errtxt, "332: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ for (i = 0; i < h; i++) {
+ values[i] = posn(SILVER, buffer[i]);
+ }
+
+ /* Putting the data into dest[] is not done until after check digits are calculated */
+
+ /* Check digit C */
+ c = 0;
+ weight = 1;
+ for (i = h - 1; i >= 0; i--) {
+ c += values[i] * weight;
+ weight++;
+ if (weight == 21)
+ weight = 1;
+ }
+ c = c % 47;
+ values[h] = c;
+ buffer[h] = set_copy[c];
+
+ /* Check digit K */
+ k = 0;
+ weight = 1;
+ for (i = h; i >= 0; i--) {
+ k += values[i] * weight;
+ weight++;
+ if (weight == 16)
+ weight = 1;
+ }
+ k = k % 47;
+ buffer[++h] = set_copy[k];
+ buffer[++h] = '\0';
+
+ /* Start character */
+ strcpy(dest, "111141");
+
+ for (i = 0; i < h; i++) {
+ lookup(SILVER, C93Table, buffer[i], dest);
+ }
+
+ /* Stop character */
+ strcat(dest, "1111411");
+ expand(symbol, dest);
+
+ symbol->text[length] = set_copy[c];
+ symbol->text[length + 1] = set_copy[k];
+ symbol->text[length + 2] = '\0';
+
+ return error_number;
+}
+
+typedef const struct s_channel_precalc {
+ long value; unsigned char B[8]; unsigned char S[8]; unsigned char bmax[7]; unsigned char smax[7];
+} channel_precalc;
+
+//#define CHANNEL_GENERATE_PRECALCS
+
+#ifdef CHANNEL_GENERATE_PRECALCS
+/* To generate precalc tables uncomment define and run "./test_channel -f generate -g" and place result in "channel_precalcs.h" */
+static void channel_generate_precalc(int channels, long value, int mod, int last, int B[8], int S[8], int bmax[7], int smax[7]) {
+ int i;
+ if (value == mod) printf("static channel_precalc channel_precalcs%d[] = {\n", channels);
+ printf(" { %7ld, {", value); for (i = 0; i < 8; i++) printf(" %d,", B[i]); printf(" },");
+ printf(" {"); for (i = 0; i < 8; i++) printf(" %d,", S[i]); printf(" },");
+ printf(" {"); for (i = 0; i < 7; i++) printf(" %d,", bmax[i]); printf(" },");
+ printf(" {"); for (i = 0; i < 7; i++) printf(" %d,", smax[i]); printf(" }, },\n");
+ if (value == last) printf("};\n");
+}
+#else
+#include "channel_precalcs.h"
+#endif
+
+static long channel_copy_precalc(channel_precalc precalc, int B[8], int S[8], int bmax[7], int smax[7]) {
+ int i;
+
+ for (i = 0; i < 7; i++) {
+ B[i] = precalc.B[i];
+ S[i] = precalc.S[i];
+ bmax[i] = precalc.bmax[i];
+ smax[i] = precalc.smax[i];
+ }
+ B[7] = precalc.B[7];
+ S[7] = precalc.S[7];
+
+ return precalc.value;
+}
+
+/* CHNCHR is adapted from ANSI/AIM BC12-1998 Annex D Figure D5 and is Copyright (c) AIM 1997 */
+
+/* It is used here on the understanding that it forms part of the specification
+ for Channel Code and therefore its use is permitted under the following terms
+ set out in that document:
+
+ "It is the intent and understanding of AIM [t]hat the symbology presented in this
+ specification is entirely in the public domain and free of all use restrictions,
+ licenses and fees. AIM USA, its member companies, or individual officers
+ assume no liability for the use of this document." */
+
+static void CHNCHR(int channels, long target_value, int B[8], int S[8]) {
+ /* Use of initial pre-calculations taken from Barcode Writer in Pure PostScript (bwipp)
+ * Copyright (c) 2004-2020 Terry Burton (MIT/X-Consortium license) */
+ static channel_precalc initial_precalcs[6] = {
+ { 0, { 1, 1, 1, 1, 1, 2, 1, 2, }, { 1, 1, 1, 1, 1, 1, 1, 3, }, { 1, 1, 1, 1, 1, 3, 2, }, { 1, 1, 1, 1, 1, 3, 3, }, },
+ { 0, { 1, 1, 1, 1, 2, 1, 1, 3, }, { 1, 1, 1, 1, 1, 1, 1, 4, }, { 1, 1, 1, 1, 4, 3, 3, }, { 1, 1, 1, 1, 4, 4, 4, }, },
+ { 0, { 1, 1, 1, 2, 1, 1, 2, 3, }, { 1, 1, 1, 1, 1, 1, 1, 5, }, { 1, 1, 1, 5, 4, 4, 4, }, { 1, 1, 1, 5, 5, 5, 5, }, },
+ { 0, { 1, 1, 2, 1, 1, 2, 1, 4, }, { 1, 1, 1, 1, 1, 1, 1, 6, }, { 1, 1, 6, 5, 5, 5, 4, }, { 1, 1, 6, 6, 6, 6, 6, }, },
+ { 0, { 1, 2, 1, 1, 2, 1, 1, 5, }, { 1, 1, 1, 1, 1, 1, 1, 7, }, { 1, 7, 6, 6, 6, 5, 5, }, { 1, 7, 7, 7, 7, 7, 7, }, },
+ { 0, { 2, 1, 1, 2, 1, 1, 2, 5, }, { 1, 1, 1, 1, 1, 1, 1, 8, }, { 8, 7, 7, 7, 6, 6, 6, }, { 8, 8, 8, 8, 8, 8, 8, }, },
+ };
+ int bmax[7], smax[7];
+ long value = 0;
+
+ channel_copy_precalc(initial_precalcs[channels - 3], B, S, bmax, smax);
+
+#ifndef CHANNEL_GENERATE_PRECALCS
+ if (channels == 7 && target_value >= channel_precalcs7[0].value) {
+ value = channel_copy_precalc(channel_precalcs7[(target_value / channel_precalcs7[0].value) - 1], B, S, bmax, smax);
+ } else if (channels == 8 && target_value >= channel_precalcs8[0].value) {
+ value = channel_copy_precalc(channel_precalcs8[(target_value / channel_precalcs8[0].value) - 1], B, S, bmax, smax);
+ }
+#endif
+
+ goto chkchr;
+
+ls0:smax[1] = smax[0] + 1 - S[0]; B[0] = 1;
+ if (S[0] == 1) goto nb0;
+lb0: bmax[1] = bmax[0] + 1 - B[0]; S[1] = 1;
+ls1: smax[2] = smax[1] + 1 - S[1]; B[1] = 1;
+ if (S[0] + B[0] + S[1] == 3) goto nb1;
+lb1: bmax[2] = bmax[1] + 1 - B[1]; S[2] = 1;
+ls2: smax[3] = smax[2] + 1 - S[2]; B[2] = 1;
+ if (B[0] + S[1] + B[1] + S[2] == 4) goto nb2;
+lb2: bmax[3] = bmax[2] + 1 - B[2]; S[3] = 1;
+ls3: smax[4] = smax[3] + 1 - S[3]; B[3] = 1;
+ if (B[1] + S[2] + B[2] + S[3] == 4) goto nb3;
+lb3: bmax[4] = bmax[3] + 1 - B[3]; S[4] = 1;
+ls4: smax[5] = smax[4] + 1 - S[4]; B[4] = 1;
+ if (B[2] + S[3] + B[3] + S[4] == 4) goto nb4;
+lb4: bmax[5] = bmax[4] + 1 - B[4]; S[5] = 1;
+ls5: smax[6] = smax[5] + 1 - S[5]; B[5] = 1;
+ if (B[3] + S[4] + B[4] + S[5] == 4) goto nb5;
+lb5: bmax[6] = bmax[5] + 1 - B[5]; S[6] = 1;
+ls6: S[7] = smax[6] + 1 - S[6]; B[6] = 1;
+ if (B[4] + S[5] + B[5] + S[6] == 4) goto nb6;
+lb6: B[7] = bmax[6] + 1 - B[6];
+ if (B[5] + S[6] + B[6] + S[7] + B[7] == 5) goto nb6;
+chkchr:
+#ifdef CHANNEL_GENERATE_PRECALCS
+ if (channels == 7 && value && value % 115338 == 0) { /* 115338 == (576688 + 2) / 5 */
+ channel_generate_precalc(channels, value, 115338, 115338 * (5 - 1), B, S, bmax, smax);
+ } else if (channels == 8 && value && value % 119121 == 0) { /* 119121 == (7742862 + 3) / 65 */
+ channel_generate_precalc(channels, value, 119121, 119121 * (65 - 1), B, S, bmax, smax);
+ }
+#endif
+ if (value == target_value) return;
+ value++;
+nb6: if (++B[6] <= bmax[6]) goto lb6;
+ if (++S[6] <= smax[6]) goto ls6;
+nb5: if (++B[5] <= bmax[5]) goto lb5;
+ if (++S[5] <= smax[5]) goto ls5;
+nb4: if (++B[4] <= bmax[4]) goto lb4;
+ if (++S[4] <= smax[4]) goto ls4;
+nb3: if (++B[3] <= bmax[3]) goto lb3;
+ if (++S[3] <= smax[3]) goto ls3;
+nb2: if (++B[2] <= bmax[2]) goto lb2;
+ if (++S[2] <= smax[2]) goto ls2;
+nb1: if (++B[1] <= bmax[1]) goto lb1;
+ if (++S[1] <= smax[1]) goto ls1;
+nb0: if (++B[0] <= bmax[0]) goto lb0;
+ if (++S[0] <= smax[0]) goto ls0;
+}
+
+/* Channel Code - According to ANSI/AIM BC12-1998 */
+INTERNAL int channel_code(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int S[8] = {0}, B[8] = {0};
+ long target_value = 0;
+ char pattern[30];
+ int channels, i;
+ int error_number, range = 0, zeroes;
+ char hrt[9];
+
+ if (length > 7) {
+ strcpy(symbol->errtxt, "333: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "334: Invalid characters in data");
+ return error_number;
+ }
+
+ if ((symbol->option_2 < 3) || (symbol->option_2 > 8)) {
+ channels = 0;
+ } else {
+ channels = symbol->option_2;
+ }
+
+ for (i = 0; i < length; i++) {
+ target_value *= 10;
+ target_value += ctoi((char) source[i]);
+ }
+
+ if (channels == 0) {
+ channels = length + 1;
+ if (target_value > 576688 && channels < 8) {
+ channels = 8;
+ } else if (target_value > 44072 && channels < 7) {
+ channels = 7;
+ } else if (target_value > 3493 && channels < 6) {
+ channels = 6;
+ } else if (target_value > 292 && channels < 5) {
+ channels = 5;
+ } else if (target_value > 26 && channels < 4) {
+ channels = 4;
+ }
+ }
+ if (channels == 2) {
+ channels = 3;
+ }
+
+ switch (channels) {
+ case 3: if (target_value > 26) {
+ range = 1;
+ }
+ break;
+ case 4: if (target_value > 292) {
+ range = 1;
+ }
+ break;
+ case 5: if (target_value > 3493) {
+ range = 1;
+ }
+ break;
+ case 6: if (target_value > 44072) {
+ range = 1;
+ }
+ break;
+ case 7: if (target_value > 576688) {
+ range = 1;
+ }
+ break;
+ case 8: if (target_value > 7742862) {
+ range = 1;
+ }
+ break;
+ }
+ if (range) {
+ strcpy(symbol->errtxt, "335: Value out of range");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ CHNCHR(channels, target_value, B, S);
+
+ strcpy(pattern, "111111111"); /* Finder pattern */
+ for (i = 8 - channels; i < 8; i++) {
+ char part[3];
+ part[0] = itoc(S[i]);
+ part[1] = itoc(B[i]);
+ part[2] = '\0';
+ strcat(pattern, part);
+ }
+
+ zeroes = channels - 1 - length;
+ if (zeroes < 0) {
+ zeroes = 0;
+ }
+ memset(hrt, '0', zeroes);
+ ustrcpy(hrt + zeroes, source);
+ ustrcpy(symbol->text, hrt);
+
+ expand(symbol, pattern);
+
+ return error_number;
+}
+
+/* Vehicle Identification Number (VIN) */
+INTERNAL int vin(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) {
+
+ /* This code verifies the check digit present in North American VIN codes */
+
+ char local_source[18];
+ char dest[200];
+ char input_check;
+ char output_check;
+ int value[17];
+ int weight[17] = {8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2};
+ int sum;
+ int i;
+ int length = (int) in_length;
+
+ // Check length
+ if (length != 17) {
+ strcpy(symbol->errtxt, "336: Input wrong length, 17 characters required");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ // Check input characters, I, O and Q are not allowed
+ if (is_sane(ARSENIC, source, length) == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "337: Invalid characters in input data");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ ustrcpy(local_source, source);
+
+ to_upper((unsigned char *) local_source);
+
+
+ // Check digit only valid for North America
+ if (local_source[0] >= '1' && local_source[0] <= '5') {
+ input_check = local_source[8];
+
+ for (i = 0; i < 17; i++) {
+ if ((local_source[i] >= '0') && (local_source[i] <= '9')) {
+ value[i] = local_source[i] - '0';
+ } else if ((local_source[i] >= 'A') && (local_source[i] <= 'I')) {
+ value[i] = (local_source[i] - 'A') + 1;
+ } else if ((local_source[i] >= 'J') && (local_source[i] <= 'R')) {
+ value[i] = (local_source[i] - 'J') + 1;
+ } else if ((local_source[i] >= 'S') && (local_source[i] <= 'Z')) {
+ value[i] = (local_source[i] - 'S') + 2;
+ }
+ }
+
+ sum = 0;
+ for (i = 0; i < 17; i++) {
+ sum += value[i] * weight[i];
+ }
+
+ output_check = '0' + (sum % 11);
+
+ if (output_check == ':') {
+ // Check digit was 10
+ output_check = 'X';
+ }
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Producing VIN code: %s\n", local_source);
+ printf("Input check was %c, calculated check is %c\n", input_check, output_check);
+ }
+
+ if (input_check != output_check) {
+ strcpy(symbol->errtxt, "338: Invalid check digit in input data");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ }
+
+ /* Start character */
+ strcpy(dest, "1211212111");
+
+ /* Import character 'I' prefix? */
+ if (symbol->option_2 & 1) {
+ strcat(dest, "1121122111");
+ }
+
+ // Copy glyphs to symbol
+ for (i = 0; i < 17; i++) {
+ lookup(SILVER, C39Table, local_source[i], dest);
+ }
+
+ strcat(dest, "121121211");
+
+ ustrcpy(symbol->text, local_source);
+ expand(symbol, dest);
+
+ return 0;
}
diff --git a/backend/code1.c b/backend/code1.c
new file mode 100644
index 0000000..8ba456b
--- /dev/null
+++ b/backend/code1.c
@@ -0,0 +1,1770 @@
+/* code1.c - USS Code One */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2009-2020 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+#include "common.h"
+#include "code1.h"
+#include "reedsol.h"
+#include "large.h"
+#include <stdio.h>
+#include <math.h>
+
+static void horiz(struct zint_symbol *symbol, int row_no, int full) {
+ int i;
+
+ if (full) {
+ for (i = 0; i < symbol->width; i++) {
+ set_module(symbol, row_no, i);
+ }
+ } else {
+ for (i = 1; i < symbol->width - 1; i++) {
+ set_module(symbol, row_no, i);
+ }
+ }
+}
+
+static void central_finder(struct zint_symbol *symbol, int start_row, int row_count, int full_rows) {
+ int i;
+
+ for (i = 0; i < row_count; i++) {
+ if (i < full_rows) {
+ horiz(symbol, start_row + (i * 2), 1);
+ } else {
+ horiz(symbol, start_row + (i * 2), 0);
+ if (i != row_count - 1) {
+ set_module(symbol, start_row + (i * 2) + 1, 1);
+ set_module(symbol, start_row + (i * 2) + 1, symbol->width - 2);
+ }
+ }
+ }
+}
+
+static void vert(struct zint_symbol *symbol, int column, int height, int top) {
+ int i;
+
+ if (top) {
+ for (i = 0; i < height; i++) {
+ set_module(symbol, i, column);
+ }
+ } else {
+ for (i = 0; i < height; i++) {
+ set_module(symbol, symbol->rows - i - 1, column);
+ }
+ }
+}
+
+static void spigot(struct zint_symbol *symbol, int row_no) {
+ int i;
+
+ for (i = symbol->width - 1; i > 0; i--) {
+ if (module_is_set(symbol, row_no, i - 1)) {
+ set_module(symbol, row_no, i);
+ }
+ }
+}
+
+static int isedi(unsigned char input) {
+ int result = 0;
+
+ if (input == 13) {
+ result = 1;
+ }
+ if (input == '*') {
+ result = 1;
+ }
+ if (input == '>') {
+ result = 1;
+ }
+ if (input == ' ') {
+ result = 1;
+ }
+ if ((input >= '0') && (input <= '9')) {
+ result = 1;
+ }
+ if ((input >= 'A') && (input <= 'Z')) {
+ result = 1;
+ }
+
+ return result;
+}
+
+static int dq4bi(unsigned char source[], int sourcelen, int position) {
+ int i;
+
+ for (i = 0; ((position + i) < sourcelen) && isedi(source[position + i]); i++);
+
+ if ((position + i) == sourcelen) {
+ /* Reached end of input */
+ return 0;
+ }
+ if (i == 0) {
+ /* Not EDI */
+ return 0;
+ }
+
+ if (source[position + i - 1] == 13) {
+ return 1;
+ }
+ if (source[position + i - 1] == '*') {
+ return 1;
+ }
+ if (source[position + i - 1] == '>') {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int c1_look_ahead_test(unsigned char source[], int sourcelen, int position, int current_mode, int gs1) {
+ float ascii_count, c40_count, text_count, edi_count, byte_count;
+ char reduced_char;
+ int done, best_scheme, sp;
+
+ /* Step J */
+ if (current_mode == C1_ASCII) {
+ ascii_count = 0.0;
+ c40_count = 1.0;
+ text_count = 1.0;
+ edi_count = 1.0;
+ byte_count = 2.0;
+ } else {
+ ascii_count = 1.0;
+ c40_count = 2.0;
+ text_count = 2.0;
+ edi_count = 2.0;
+ byte_count = 3.0;
+ }
+
+ switch (current_mode) {
+ case C1_C40: c40_count = 0.0;
+ break;
+ case C1_TEXT: text_count = 0.0;
+ break;
+ case C1_BYTE: byte_count = 0.0;
+ break;
+ case C1_EDI: edi_count = 0.0;
+ break;
+ }
+
+ for (sp = position; (sp < sourcelen) && (sp <= (position + 8)); sp++) {
+
+ if (source[sp] <= 127) {
+ reduced_char = source[sp];
+ } else {
+ reduced_char = source[sp] - 127;
+ }
+
+ /* Step L */
+ if ((source[sp] >= '0') && (source[sp] <= '9')) {
+ ascii_count += 0.5;
+ } else {
+ ascii_count = ceil(ascii_count);
+ if (source[sp] > 127) {
+ ascii_count += 2.0;
+ } else {
+ ascii_count += 1.0;
+ }
+ }
+
+ /* Step M */
+ done = 0;
+ if (reduced_char == ' ') {
+ c40_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if ((reduced_char >= '0') && (reduced_char <= '9')) {
+ c40_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if ((reduced_char >= 'A') && (reduced_char <= 'Z')) {
+ c40_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if (source[sp] > 127) {
+ c40_count += (4.0 / 3.0);
+ }
+ if (done == 0) {
+ c40_count += (4.0 / 3.0);
+ }
+
+ /* Step N */
+ done = 0;
+ if (reduced_char == ' ') {
+ text_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if ((reduced_char >= '0') && (reduced_char <= '9')) {
+ text_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if ((reduced_char >= 'a') && (reduced_char <= 'z')) {
+ text_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if (source[sp] > 127) {
+ text_count += (4.0 / 3.0);
+ }
+ if (done == 0) {
+ text_count += (4.0 / 3.0);
+ }
+
+ /* Step O */
+ done = 0;
+ if (source[sp] == 13) {
+ edi_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if (source[sp] == '*') {
+ edi_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if (source[sp] == '>') {
+ edi_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if (source[sp] == ' ') {
+ edi_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if ((source[sp] >= '0') && (source[sp] <= '9')) {
+ edi_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if ((source[sp] >= 'A') && (source[sp] <= 'Z')) {
+ edi_count += (2.0 / 3.0);
+ done = 1;
+ }
+ if (source[sp] > 127) {
+ edi_count += (13.0 / 3.0);
+ } else {
+ if (done == 0) {
+ edi_count += (10.0 / 3.0);
+ }
+ }
+
+ /* Step P */
+ if (gs1 && (source[sp] == '[')) {
+ byte_count += 3.0;
+ } else {
+ byte_count += 1.0;
+ }
+
+ }
+
+ ascii_count = ceil(ascii_count);
+ c40_count = ceil(c40_count);
+ text_count = ceil(text_count);
+ edi_count = ceil(edi_count);
+ byte_count = ceil(byte_count);
+ best_scheme = C1_ASCII;
+
+ if (sp == sourcelen) {
+ /* Step K */
+ int best_count = (int) edi_count;
+
+ if (text_count <= best_count) {
+ best_count = (int) text_count;
+ best_scheme = C1_TEXT;
+ }
+
+ if (c40_count <= best_count) {
+ best_count = (int) c40_count;
+ best_scheme = C1_C40;
+ }
+
+ if (ascii_count <= best_count) {
+ best_count = (int) ascii_count;
+ best_scheme = C1_ASCII;
+ }
+
+ if (byte_count <= best_count) {
+ // best_count = (int) byte_count;
+ best_scheme = C1_BYTE;
+ }
+ } else {
+ /* Step Q */
+
+ if (((edi_count + 1.0 <= ascii_count) && (edi_count + 1.0 <= c40_count)) &&
+ ((edi_count + 1.0 <= byte_count) && (edi_count + 1.0 <= text_count))) {
+ best_scheme = C1_EDI;
+ }
+
+ if ((c40_count + 1.0 <= ascii_count) && (c40_count + 1.0 <= text_count)) {
+
+ if (c40_count < edi_count) {
+ best_scheme = C1_C40;
+ } else {
+ if (c40_count == edi_count) {
+ if (dq4bi(source, sourcelen, position)) {
+ best_scheme = C1_EDI;
+ } else {
+ best_scheme = C1_C40;
+ }
+ }
+ }
+ }
+
+ if (((text_count + 1.0 <= ascii_count) && (text_count + 1.0 <= c40_count)) &&
+ ((text_count + 1.0 <= byte_count) && (text_count + 1.0 <= edi_count))) {
+ best_scheme = C1_TEXT;
+ }
+
+ if (((ascii_count + 1.0 <= byte_count) && (ascii_count + 1.0 <= c40_count)) &&
+ ((ascii_count + 1.0 <= text_count) && (ascii_count + 1.0 <= edi_count))) {
+ best_scheme = C1_ASCII;
+ }
+
+ if (((byte_count + 1.0 <= ascii_count) && (byte_count + 1.0 <= c40_count)) &&
+ ((byte_count + 1.0 <= text_count) && (byte_count + 1.0 <= edi_count))) {
+ best_scheme = C1_BYTE;
+ }
+ }
+
+ return best_scheme;
+}
+
+static int c1_encode(struct zint_symbol *symbol, unsigned char source[], unsigned int target[], int length) {
+ int current_mode, next_mode;
+ int sp, tp, gs1, i, j, p, latch;
+ int c40_buffer[6], c40_p;
+ int text_buffer[6], text_p;
+ int edi_buffer[6], edi_p;
+ char decimal_binary[40];
+ int byte_start = 0;
+
+ sp = 0;
+ tp = 0;
+ memset(c40_buffer, 0, sizeof(*c40_buffer));
+ c40_p = 0;
+ memset(text_buffer, 0, sizeof(*text_buffer));
+ text_p = 0;
+ memset(edi_buffer, 0, sizeof(*edi_buffer));
+ edi_p = 0;
+ strcpy(decimal_binary, "");
+
+ if ((symbol->input_mode & 0x07) == GS1_MODE) {
+ gs1 = 1;
+ } else {
+ gs1 = 0;
+ }
+ if (gs1) {
+ /* FNC1 */
+ target[tp] = 232;
+ tp++;
+ }
+
+ /* Step A */
+ current_mode = C1_ASCII;
+ next_mode = C1_ASCII;
+
+ do {
+ if (current_mode != next_mode) {
+ /* Change mode */
+ switch (next_mode) {
+ case C1_C40: target[tp] = 230;
+ tp++;
+ break;
+ case C1_TEXT: target[tp] = 239;
+ tp++;
+ break;
+ case C1_EDI: target[tp] = 238;
+ tp++;
+ break;
+ case C1_BYTE: target[tp] = 231;
+ tp++;
+ break;
+ }
+ }
+
+ if ((current_mode != C1_BYTE) && (next_mode == C1_BYTE)) {
+ byte_start = tp;
+ }
+ current_mode = next_mode;
+
+ if (current_mode == C1_ASCII) {
+ /* Step B - ASCII encodation */
+ next_mode = C1_ASCII;
+
+ if ((length - sp) >= 21) {
+ /* Step B1 */
+ j = 0;
+
+ for (i = 0; i < 21; i++) {
+ if ((source[sp + i] >= '0') && (source[sp + i] <= '9')) {
+ j++;
+ }
+ }
+
+ if (j == 21) {
+ next_mode = C1_DECIMAL;
+ bin_append(15, 4, decimal_binary);
+ }
+ }
+
+ if ((next_mode == C1_ASCII) && ((length - sp) >= 13)) {
+ /* Step B2 */
+ j = 0;
+
+ for (i = 0; i < 13; i++) {
+ if ((source[sp + i] >= '0') && (source[sp + i] <= '9')) {
+ j++;
+ }
+ }
+
+ if (j == 13) {
+ latch = 0;
+ for (i = sp + 13; i < length; i++) {
+ if (!((source[i] >= '0') && (source[i] <= '9'))) {
+ latch = 1;
+ }
+ }
+
+ if (!(latch)) {
+ next_mode = C1_DECIMAL;
+ bin_append(15, 4, decimal_binary);
+ }
+ }
+ }
+
+ if (next_mode == C1_ASCII) { /* Step B3 */
+ if (istwodigits(source, length, sp)) {
+ target[tp] = (10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130;
+ tp++;
+ sp += 2;
+ } else {
+ if ((gs1) && (source[sp] == '[')) {
+ if ((length - sp) >= 15) {
+ /* Step B4 */
+ j = 0;
+
+ for (i = 0; i < 15; i++) {
+ if ((source[sp + i] >= '0') && (source[sp + i] <= '9')) {
+ j++;
+ }
+ }
+
+ if (j == 15) {
+ target[tp] = 236; /* FNC1 and change to Decimal */
+ tp++;
+ sp++;
+ next_mode = C1_DECIMAL;
+ }
+ }
+
+ if ((length - sp) >= 7) { /* Step B5 */
+ j = 0;
+
+ for (i = 0; i < 7; i++) {
+ if ((source[sp + i] >= '0') && (source[sp + i] <= '9')) {
+ j++;
+ }
+ }
+
+ if (j == 7) {
+ latch = 0;
+ for (i = sp + 7; i < length; i++) {
+ if (!((source[i] >= '0') && (source[i] <= '9'))) {
+ latch = 1;
+ }
+ }
+
+ if (!(latch)) {
+ target[tp] = 236; /* FNC1 and change to Decimal */
+ tp++;
+ sp++;
+ next_mode = C1_DECIMAL;
+ }
+ }
+ }
+ }
+
+ if (next_mode == C1_ASCII) {
+
+ /* Step B6 */
+ next_mode = c1_look_ahead_test(source, length, sp, current_mode, gs1);
+
+ if (next_mode == C1_ASCII) {
+ if (source[sp] > 127) {
+ /* Step B7 */
+ target[tp] = 235; /* FNC4 */
+ tp++;
+ target[tp] = (source[sp] - 128) + 1;
+ tp++;
+ sp++;
+ } else {
+ /* Step B8 */
+ if ((gs1) && (source[sp] == '[')) {
+ target[tp] = 232; /* FNC1 */
+ tp++;
+ sp++;
+ } else {
+ target[tp] = source[sp] + 1;
+ tp++;
+ sp++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (current_mode == C1_C40) {
+ /* Step C - C40 encodation */
+
+ next_mode = C1_C40;
+ if (c40_p == 0) {
+ int done = 0;
+ if ((length - sp) >= 12) {
+ j = 0;
+
+ for (i = 0; i < 12; i++) {
+ if ((source[sp + i] >= '0') && (source[sp + i] <= '9')) {
+ j++;
+ }
+ }
+
+ if (j == 12) {
+ next_mode = C1_ASCII;
+ done = 1;
+ }
+ }
+
+ if ((length - sp) >= 8) {
+ int latch = 0;
+ j = 0;
+
+ for (i = 0; i < 8; i++) {
+ if ((source[sp + i] >= '0') && (source[sp + i] <= '9')) {
+ j++;
+ }
+ }
+
+ if ((length - sp) == 8) {
+ latch = 1;
+ } else {
+ latch = 1;
+ for (j = sp + 8; j < length; j++) {
+ if ((source[j] <= '0') || (source[j] >= '9')) {
+ latch = 0;
+ }
+ }
+ }
+
+ if ((j == 8) && latch) {
+ next_mode = C1_ASCII;
+ done = 1;
+ }
+ }
+
+ if (!(done)) {
+ next_mode = c1_look_ahead_test(source, length, sp, current_mode, gs1);
+ }
+ }
+
+ if (next_mode != C1_C40) {
+ target[tp] = 255; /* Unlatch */
+ tp++;
+ } else {
+ int shift_set, value;
+ if (source[sp] > 127) {
+ c40_buffer[c40_p] = 1;
+ c40_p++;
+ c40_buffer[c40_p] = 30; /* Upper Shift */
+ c40_p++;
+ shift_set = c40_shift[source[sp] - 128];
+ value = c40_value[source[sp] - 128];
+ } else {
+ shift_set = c40_shift[source[sp]];
+ value = c40_value[source[sp]];
+ }
+
+ if (gs1 && (source[sp] == '[')) {
+ shift_set = 2;
+ value = 27; /* FNC1 */
+ }
+
+ if (shift_set != 0) {
+ c40_buffer[c40_p] = shift_set - 1;
+ c40_p++;
+ }
+ c40_buffer[c40_p] = value;
+ c40_p++;
+
+ if (c40_p >= 3) {
+ int iv;
+
+ iv = (1600 * c40_buffer[0]) + (40 * c40_buffer[1]) + (c40_buffer[2]) + 1;
+ target[tp] = iv / 256;
+ tp++;
+ target[tp] = iv % 256;
+ tp++;
+
+ c40_buffer[0] = c40_buffer[3];
+ c40_buffer[1] = c40_buffer[4];
+ c40_buffer[2] = c40_buffer[5];
+ c40_buffer[3] = 0;
+ c40_buffer[4] = 0;
+ c40_buffer[5] = 0;
+ c40_p -= 3;
+ }
+ sp++;
+ }
+ }
+
+ if (current_mode == C1_TEXT) {
+ /* Step D - Text encodation */
+
+ next_mode = C1_TEXT;
+ if (text_p == 0) {
+ int done = 0;
+ if ((length - sp) >= 12) {
+ j = 0;
+
+ for (i = 0; i < 12; i++) {
+ if ((source[sp + i] >= '0') && (source[sp + i] <= '9')) {
+ j++;
+ }
+ }
+
+ if (j == 12) {
+ next_mode = C1_ASCII;
+ done = 1;
+ }
+ }
+
+ if ((length - sp) >= 8) {
+ int latch = 0;
+ j = 0;
+
+ for (i = 0; i < 8; i++) {
+ if ((source[sp + i] >= '0') && (source[sp + i] <= '9')) {
+ j++;
+ }
+ }
+
+ if ((length - sp) == 8) {
+ latch = 1;
+ } else {
+ latch = 1;
+ for (j = sp + 8; j < length; j++) {
+ if ((source[j] <= '0') || (source[j] >= '9')) {
+ latch = 0;
+ }
+ }
+ }
+
+ if ((j == 8) && latch) {
+ next_mode = C1_ASCII;
+ done = 1;
+ }
+ }
+
+ if (!(done)) {
+ next_mode = c1_look_ahead_test(source, length, sp, current_mode, gs1);
+ }
+ }
+
+ if (next_mode != C1_TEXT) {
+ target[tp] = 255;
+ tp++; /* Unlatch */
+ } else {
+ int shift_set, value;
+ if (source[sp] > 127) {
+ text_buffer[text_p] = 1;
+ text_p++;
+ text_buffer[text_p] = 30;
+ text_p++; /* Upper Shift */
+ shift_set = text_shift[source[sp] - 128];
+ value = text_value[source[sp] - 128];
+ } else {
+ shift_set = text_shift[source[sp]];
+ value = text_value[source[sp]];
+ }
+
+ if (gs1 && (source[sp] == '[')) {
+ shift_set = 2;
+ value = 27; /* FNC1 */
+ }
+
+ if (shift_set != 0) {
+ text_buffer[text_p] = shift_set - 1;
+ text_p++;
+ }
+ text_buffer[text_p] = value;
+ text_p++;
+
+ if (text_p >= 3) {
+ int iv;
+
+ iv = (1600 * text_buffer[0]) + (40 * text_buffer[1]) + (text_buffer[2]) + 1;
+ target[tp] = iv / 256;
+ tp++;
+ target[tp] = iv % 256;
+ tp++;
+
+ text_buffer[0] = text_buffer[3];
+ text_buffer[1] = text_buffer[4];
+ text_buffer[2] = text_buffer[5];
+ text_buffer[3] = 0;
+ text_buffer[4] = 0;
+ text_buffer[5] = 0;
+ text_p -= 3;
+ }
+ sp++;
+ }
+ }
+
+ if (current_mode == C1_EDI) {
+ /* Step E - EDI Encodation */
+
+ next_mode = C1_EDI;
+ if (edi_p == 0) {
+ if ((length - sp) >= 12) {
+ j = 0;
+
+ for (i = 0; i < 12; i++) {
+ if ((source[sp + i] >= '0') && (source[sp + i] <= '9')) {
+ j++;
+ }
+ }
+
+ if (j == 12) {
+ next_mode = C1_ASCII;
+ }
+ }
+
+ if ((length - sp) >= 8) {
+ int latch = 0;
+ j = 0;
+
+ for (i = 0; i < 8; i++) {
+ if ((source[sp + i] >= '0') && (source[sp + i] <= '9')) {
+ j++;
+ }
+ }
+
+ if ((length - sp) == 8) {
+ latch = 1;
+ } else {
+ latch = 1;
+ for (j = sp + 8; j < length; j++) {
+ if ((source[j] <= '0') || (source[j] >= '9')) {
+ latch = 0;
+ }
+ }
+ }
+
+ if ((j == 8) && latch) {
+ next_mode = C1_ASCII;
+ }
+ }
+
+ if (!((isedi(source[sp]) && isedi(source[sp + 1])) && isedi(source[sp + 2]))) {
+ next_mode = C1_ASCII;
+ }
+ }
+
+ if (next_mode != C1_EDI) {
+ target[tp] = 255; /* Unlatch */
+ tp++;
+ } else {
+ int value = 0;
+ if (source[sp] == 13) {
+ value = 0;
+ }
+ if (source[sp] == '*') {
+ value = 1;
+ }
+ if (source[sp] == '>') {
+ value = 2;
+ }
+ if (source[sp] == ' ') {
+ value = 3;
+ }
+ if ((source[sp] >= '0') && (source[sp] <= '9')) {
+ value = source[sp] - '0' + 4;
+ }
+ if ((source[sp] >= 'A') && (source[sp] <= 'Z')) {
+ value = source[sp] - 'A' + 14;
+ }
+
+ edi_buffer[edi_p] = value;
+ edi_p++;
+
+ if (edi_p >= 3) {
+ int iv;
+
+ iv = (1600 * edi_buffer[0]) + (40 * edi_buffer[1]) + (edi_buffer[2]) + 1;
+ target[tp] = iv / 256;
+ tp++;
+ target[tp] = iv % 256;
+ tp++;
+
+ edi_buffer[0] = edi_buffer[3];
+ edi_buffer[1] = edi_buffer[4];
+ edi_buffer[2] = edi_buffer[5];
+ edi_buffer[3] = 0;
+ edi_buffer[4] = 0;
+ edi_buffer[5] = 0;
+ edi_p -= 3;
+ }
+ sp++;
+ }
+ }
+
+ if (current_mode == C1_DECIMAL) {
+ /* Step F - Decimal encodation */
+ int decimal_count, data_left;
+
+ next_mode = C1_DECIMAL;
+
+ data_left = length - sp;
+ decimal_count = 0;
+
+ if (data_left >= 1) {
+ if ((source[sp] >= '0') && (source[sp] <= '9')) {
+ decimal_count = 1;
+ }
+ }
+ if (data_left >= 2) {
+ if ((decimal_count == 1) && ((source[sp + 1] >= '0') && (source[sp + 1] <= '9'))) {
+ decimal_count = 2;
+ }
+ }
+ if (data_left >= 3) {
+ if ((decimal_count == 2) && ((source[sp + 2] >= '0') && (source[sp + 2] <= '9'))) {
+ decimal_count = 3;
+ }
+ }
+
+ if (decimal_count != 3) {
+ size_t bits_left_in_byte, target_count;
+ int sub_target;
+ /* Finish Decimal mode and go back to ASCII */
+
+ bin_append(63, 6, decimal_binary); /* Unlatch */
+
+ target_count = 3;
+ if (strlen(decimal_binary) <= 16) {
+ target_count = 2;
+ }
+ if (strlen(decimal_binary) <= 8) {
+ target_count = 1;
+ }
+ bits_left_in_byte = (8 * target_count) - strlen(decimal_binary);
+ if (bits_left_in_byte == 8) {
+ bits_left_in_byte = 0;
+ }
+
+ if (bits_left_in_byte == 2) {
+ bin_append(1, 2, decimal_binary);
+ }
+
+ if ((bits_left_in_byte == 4) || (bits_left_in_byte == 6)) {
+ if (decimal_count >= 1) {
+ bin_append(ctoi(source[sp]) + 1, 4, decimal_binary);
+ sp++;
+ } else {
+ bin_append(15, 4, decimal_binary);
+ }
+ }
+
+ if (bits_left_in_byte == 6) {
+ bin_append(1, 2, decimal_binary);
+ }
+
+ /* Binary buffer is full - transfer to target */
+ if (target_count >= 1) {
+ sub_target = 0;
+
+ for (i = 0; i < 8; i++) {
+ if (decimal_binary[i] == '1') {
+ sub_target += 128 >> i;
+ }
+ }
+ target[tp] = sub_target;
+ tp++;
+ }
+ if (target_count >= 2) {
+ sub_target = 0;
+
+ for (i = 0; i < 8; i++) {
+ if (decimal_binary[i + 8] == '1') {
+ sub_target += 128 >> i;
+ }
+ }
+ target[tp] = sub_target;
+ tp++;
+ }
+ if (target_count == 3) {
+ sub_target = 0;
+
+ for (i = 0; i < 8; i++) {
+ if (decimal_binary[i + 16] == '1') {
+ sub_target += 128 >> i;
+ }
+ }
+ target[tp] = sub_target;
+ tp++;
+ }
+
+ next_mode = C1_ASCII;
+ } else {
+ /* There are three digits - convert the value to binary */
+ bin_append((100 * ctoi(source[sp])) + (10 * ctoi(source[sp + 1])) + ctoi(source[sp + 2]) + 1, 10, decimal_binary);
+ sp += 3;
+ }
+
+ if (strlen(decimal_binary) >= 24) {
+ int target1 = 0, target2 = 0, target3 = 0;
+ char temp_binary[40];
+
+ /* Binary buffer is full - transfer to target */
+
+ for (p = 0; p < 8; p++) {
+ if (decimal_binary[p] == '1') {
+ target1 += (0x80 >> p);
+ }
+ if (decimal_binary[p + 8] == '1') {
+ target2 += (0x80 >> p);
+ }
+ if (decimal_binary[p + 16] == '1') {
+ target3 += (0x80 >> p);
+ }
+ }
+ target[tp] = target1;
+ tp++;
+ target[tp] = target2;
+ tp++;
+ target[tp] = target3;
+ tp++;
+
+ strcpy(temp_binary, "");
+ if (strlen(decimal_binary) > 24) {
+ for (i = 0; i <= (int) (strlen(decimal_binary) - 24); i++) {
+ temp_binary[i] = decimal_binary[i + 24];
+ }
+ strcpy(decimal_binary, temp_binary);
+ }
+ }
+ }
+
+ if (current_mode == C1_BYTE) {
+ next_mode = C1_BYTE;
+
+ if (gs1 && (source[sp] == '[')) {
+ next_mode = C1_ASCII;
+ } else {
+ if (source[sp] <= 127) {
+ next_mode = c1_look_ahead_test(source, length, sp, current_mode, gs1);
+ }
+ }
+
+ if (next_mode != C1_BYTE) {
+ /* Insert byte field length */
+ if ((tp - byte_start) <= 249) {
+ for (i = tp; i >= byte_start; i--) {
+ target[i + 1] = target[i];
+ }
+ target[byte_start] = (tp - byte_start);
+ tp++;
+ } else {
+ for (i = tp; i >= byte_start; i--) {
+ target[i + 2] = target[i];
+ }
+ target[byte_start] = 249 + ((tp - byte_start) / 250);
+ target[byte_start + 1] = ((tp - byte_start) % 250);
+ tp += 2;
+ }
+ } else {
+ target[tp] = source[sp];
+ tp++;
+ sp++;
+ }
+ }
+
+ if (tp > 1480) {
+ /* Data is too large for symbol */
+ strcpy(symbol->errtxt, "511: Input data too long");
+ return 0;
+ }
+ } while (sp < length);
+
+ /* Empty buffers */
+ if (c40_p == 2) {
+ int iv;
+
+ c40_buffer[2] = 1;
+ iv = (1600 * c40_buffer[0]) + (40 * c40_buffer[1]) + (c40_buffer[2]) + 1;
+ target[tp] = iv / 256;
+ tp++;
+ target[tp] = iv % 256;
+ tp++;
+ target[tp] = 255;
+ tp++; /* Unlatch */
+ }
+ if (c40_p == 1) {
+ int iv;
+
+ c40_buffer[1] = 1;
+ c40_buffer[2] = 31; /* Pad */
+ iv = (1600 * c40_buffer[0]) + (40 * c40_buffer[1]) + (c40_buffer[2]) + 1;
+ target[tp] = iv / 256;
+ tp++;
+ target[tp] = iv % 256;
+ tp++;
+ target[tp] = 255;
+ tp++; /* Unlatch */
+ }
+ if (text_p == 2) {
+ int iv;
+
+ text_buffer[2] = 1;
+ iv = (1600 * text_buffer[0]) + (40 * text_buffer[1]) + (text_buffer[2]) + 1;
+ target[tp] = iv / 256;
+ tp++;
+ target[tp] = iv % 256;
+ tp++;
+ target[tp] = 255;
+ tp++; /* Unlatch */
+ }
+ if (text_p == 1) {
+ int iv;
+
+ text_buffer[1] = 1;
+ text_buffer[2] = 31; /* Pad */
+ iv = (1600 * text_buffer[0]) + (40 * text_buffer[1]) + (text_buffer[2]) + 1;
+ target[tp] = iv / 256;
+ tp++;
+ target[tp] = iv % 256;
+ tp++;
+ target[tp] = 255;
+ tp++; /* Unlatch */
+ }
+
+ if (current_mode == C1_DECIMAL) {
+ size_t bits_left_in_byte, target_count;
+ int sub_target;
+ /* Finish Decimal mode and go back to ASCII */
+
+ bin_append(63, 6, decimal_binary); /* Unlatch */
+
+ target_count = 3;
+ if (strlen(decimal_binary) <= 16) {
+ target_count = 2;
+ }
+ if (strlen(decimal_binary) <= 8) {
+ target_count = 1;
+ }
+ bits_left_in_byte = (8 * target_count) - strlen(decimal_binary);
+ if (bits_left_in_byte == 8) {
+ bits_left_in_byte = 0;
+ }
+
+ if (bits_left_in_byte == 2) {
+ bin_append(1, 2, decimal_binary);
+ }
+
+ if ((bits_left_in_byte == 4) || (bits_left_in_byte == 6)) {
+ bin_append(15, 4, decimal_binary);
+ }
+
+ if (bits_left_in_byte == 6) {
+ bin_append(1, 2, decimal_binary);
+ }
+
+ /* Binary buffer is full - transfer to target */
+ if (target_count >= 1) {
+ sub_target = 0;
+
+ for (i = 0; i < 8; i++) {
+ if (decimal_binary[i] == '1') {
+ sub_target += 128 >> i;
+ }
+ }
+ target[tp] = sub_target;
+ tp++;
+ }
+ if (target_count >= 2) {
+ sub_target = 0;
+
+ for (i = 0; i < 8; i++) {
+ if (decimal_binary[i + 8] == '1') {
+ sub_target += 128 >> i;
+ }
+ }
+ target[tp] = sub_target;
+ tp++;
+ }
+ if (target_count == 3) {
+ sub_target = 0;
+
+ for (i = 0; i < 8; i++) {
+ if (decimal_binary[i + 16] == '1') {
+ sub_target += 128 >> i;
+ }
+ }
+ target[tp] = sub_target;
+ tp++;
+ }
+ }
+
+ if (current_mode == C1_BYTE) {
+ /* Insert byte field length */
+ if ((tp - byte_start) <= 249) {
+ for (i = tp; i >= byte_start; i--) {
+ target[i + 1] = target[i];
+ }
+ target[byte_start] = (tp - byte_start);
+ tp++;
+ } else {
+ for (i = tp; i >= byte_start; i--) {
+ target[i + 2] = target[i];
+ }
+ target[byte_start] = 249 + ((tp - byte_start) / 250);
+ target[byte_start + 1] = ((tp - byte_start) % 250);
+ tp += 2;
+ }
+ }
+
+ /* Re-check length of data */
+ if (tp > 1480) {
+ /* Data is too large for symbol */
+ strcpy(symbol->errtxt, "512: Input data too long");
+ return 0;
+ }
+ /*
+ printf("targets:\n");
+ for(i = 0; i < tp; i++) {
+ printf("[%d]", target[i]);
+ }
+ printf("\n");
+ */
+ return tp;
+}
+
+static void block_copy(struct zint_symbol *symbol, char grid[][120], int start_row, int start_col, int height, int width, int row_offset, int col_offset) {
+ int i, j;
+
+ for (i = start_row; i < (start_row + height); i++) {
+ for (j = start_col; j < (start_col + width); j++) {
+ if (grid[i][j] == '1') {
+ set_module(symbol, i + row_offset, j + col_offset);
+ }
+ }
+ }
+}
+
+INTERNAL int code_one(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int size = 1, i, j;
+
+ char datagrid[136][120];
+ int row, col;
+ int sub_version = 0;
+
+ if ((symbol->option_2 < 0) || (symbol->option_2 > 10)) {
+ strcpy(symbol->errtxt, "513: Invalid symbol size");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+
+ if (symbol->option_2 == 9) {
+ /* Version S */
+ int codewords;
+ large_int elreg;
+ unsigned int data[15], ecc[15];
+ int stream[30];
+ int block_width;
+
+ if (length > 18) {
+ strcpy(symbol->errtxt, "514: Input data too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ if (is_sane(NEON, source, length) == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "515: Invalid input data (Version S encodes numeric input only)");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ sub_version = 3;
+ codewords = 12;
+ block_width = 6; /* Version S-30 */
+ if (length <= 12) {
+ /* Version S-20 */
+ sub_version = 2;
+ codewords = 8;
+ block_width = 4;
+ }
+ if (length <= 6) {
+ /* Version S-10 */
+ sub_version = 1;
+ codewords = 4;
+ block_width = 2;
+ }
+
+ large_load_str_u64(&elreg, source, length);
+
+ for (i = 0; i < 15; i++) {
+ data[i] = 0;
+ ecc[i] = 0;
+ }
+
+ large_uint_array(&elreg, data, codewords, 5 /*bits*/);
+
+ rs_init_gf(0x25);
+ rs_init_code(codewords, 1);
+ rs_encode_long(codewords, data, ecc);
+ rs_free();
+
+ for (i = 0; i < codewords; i++) {
+ stream[i] = data[i];
+ stream[i + codewords] = ecc[codewords - i - 1];
+ }
+
+ for (i = 0; i < 136; i++) {
+ for (j = 0; j < 120; j++) {
+ datagrid[i][j] = '0';
+ }
+ }
+
+ i = 0;
+ for (row = 0; row < 2; row++) {
+ for (col = 0; col < block_width; col++) {
+ if (stream[i] & 0x10) {
+ datagrid[row * 2][col * 5] = '1';
+ }
+ if (stream[i] & 0x08) {
+ datagrid[row * 2][(col * 5) + 1] = '1';
+ }
+ if (stream[i] & 0x04) {
+ datagrid[row * 2][(col * 5) + 2] = '1';
+ }
+ if (stream[i] & 0x02) {
+ datagrid[(row * 2) + 1][col * 5] = '1';
+ }
+ if (stream[i] & 0x01) {
+ datagrid[(row * 2) + 1][(col * 5) + 1] = '1';
+ }
+ if (stream[i + 1] & 0x10) {
+ datagrid[row * 2][(col * 5) + 3] = '1';
+ }
+ if (stream[i + 1] & 0x08) {
+ datagrid[row * 2][(col * 5) + 4] = '1';
+ }
+ if (stream[i + 1] & 0x04) {
+ datagrid[(row * 2) + 1][(col * 5) + 2] = '1';
+ }
+ if (stream[i + 1] & 0x02) {
+ datagrid[(row * 2) + 1][(col * 5) + 3] = '1';
+ }
+ if (stream[i + 1] & 0x01) {
+ datagrid[(row * 2) + 1][(col * 5) + 4] = '1';
+ }
+ i += 2;
+ }
+ }
+
+ size = 9;
+ symbol->rows = 8;
+ symbol->width = 10 * sub_version + 1;
+ }
+
+ if (symbol->option_2 == 10) {
+ /* Version T */
+ unsigned int data[80] = {0}; /* Allow for doubled digits */
+ unsigned int ecc[22];
+ unsigned int stream[60];
+ int data_length;
+ int data_cw, ecc_cw, block_width;
+
+ if (length > 80) {
+ strcpy(symbol->errtxt, "519: Input data too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ data_length = c1_encode(symbol, source, data, length);
+
+ if (data_length == 0) {
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ if (data_length > 38) {
+ strcpy(symbol->errtxt, "516: Input data too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ size = 10;
+ sub_version = 3;
+ data_cw = 38;
+ ecc_cw = 22;
+ block_width = 12;
+ if (data_length <= 24) {
+ sub_version = 2;
+ data_cw = 24;
+ ecc_cw = 16;
+ block_width = 8;
+ }
+ if (data_length <= 10) {
+ sub_version = 1;
+ data_cw = 10;
+ ecc_cw = 10;
+ block_width = 4;
+ }
+
+ for (i = data_length; i < data_cw; i++) {
+ data[i] = 129; /* Pad */
+ }
+
+ /* Calculate error correction data */
+ rs_init_gf(0x12d);
+ rs_init_code(ecc_cw, 1);
+ rs_encode_long(data_cw, data, ecc);
+ rs_free();
+
+ /* "Stream" combines data and error correction data */
+ for (i = 0; i < data_cw; i++) {
+ stream[i] = data[i];
+ }
+ for (i = 0; i < ecc_cw; i++) {
+ stream[data_cw + i] = ecc[ecc_cw - i - 1];
+ }
+
+ for (i = 0; i < 136; i++) {
+ for (j = 0; j < 120; j++) {
+ datagrid[i][j] = '0';
+ }
+ }
+
+ i = 0;
+ for (row = 0; row < 5; row++) {
+ for (col = 0; col < block_width; col++) {
+ if (stream[i] & 0x80) {
+ datagrid[row * 2][col * 4] = '1';
+ }
+ if (stream[i] & 0x40) {
+ datagrid[row * 2][(col * 4) + 1] = '1';
+ }
+ if (stream[i] & 0x20) {
+ datagrid[row * 2][(col * 4) + 2] = '1';
+ }
+ if (stream[i] & 0x10) {
+ datagrid[row * 2][(col * 4) + 3] = '1';
+ }
+ if (stream[i] & 0x08) {
+ datagrid[(row * 2) + 1][col * 4] = '1';
+ }
+ if (stream[i] & 0x04) {
+ datagrid[(row * 2) + 1][(col * 4) + 1] = '1';
+ }
+ if (stream[i] & 0x02) {
+ datagrid[(row * 2) + 1][(col * 4) + 2] = '1';
+ }
+ if (stream[i] & 0x01) {
+ datagrid[(row * 2) + 1][(col * 4) + 3] = '1';
+ }
+ i++;
+ }
+ }
+
+ symbol->rows = 16;
+ symbol->width = (sub_version * 16) + 1;
+ }
+
+ if ((symbol->option_2 != 9) && (symbol->option_2 != 10)) {
+ /* Version A to H */
+ unsigned int data[1500], ecc[600];
+ unsigned int sub_data[190], sub_ecc[75];
+ unsigned int stream[2100];
+ int data_length;
+ int data_blocks;
+
+ for (i = 0; i < 1500; i++) {
+ data[i] = 0;
+ }
+ data_length = c1_encode(symbol, source, data, length);
+
+ if (data_length == 0) {
+ strcpy(symbol->errtxt, "517: Input data is too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ for (i = 7; i >= 0; i--) {
+ if (c1_data_length[i] >= data_length) {
+ size = i + 1;
+ }
+ }
+
+ if (symbol->option_2 > size) {
+ size = symbol->option_2;
+ }
+
+ if ((symbol-> option_2 != 0) && (symbol->option_2 < size)) {
+ strcpy(symbol->errtxt, "518: Input too long for selected symbol size");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ for (i = data_length; i < c1_data_length[size - 1]; i++) {
+ data[i] = 129; /* Pad */
+ }
+
+ /* Calculate error correction data */
+ data_length = c1_data_length[size - 1];
+ for (i = 0; i < 190; i++) {
+ sub_data[i] = 0;
+ }
+ for (i = 0; i < 75; i++) {
+ sub_ecc[i] = 0;
+ }
+
+ data_blocks = c1_blocks[size - 1];
+
+ rs_init_gf(0x12d);
+ rs_init_code(c1_ecc_blocks[size - 1], 0);
+ for (i = 0; i < data_blocks; i++) {
+ for (j = 0; j < c1_data_blocks[size - 1]; j++) {
+
+ sub_data[j] = data[j * data_blocks + i];
+ }
+ rs_encode_long(c1_data_blocks[size - 1], sub_data, sub_ecc);
+ for (j = 0; j < c1_ecc_blocks[size - 1]; j++) {
+ ecc[c1_ecc_length[size - 1] - (j * data_blocks + i) - 1] = sub_ecc[j];
+ }
+ }
+ rs_free();
+
+ /* "Stream" combines data and error correction data */
+ for (i = 0; i < data_length; i++) {
+ stream[i] = data[i];
+ }
+ for (i = 0; i < c1_ecc_length[size - 1]; i++) {
+ stream[data_length + i] = ecc[i];
+ }
+
+ for (i = 0; i < 136; i++) {
+ for (j = 0; j < 120; j++) {
+ datagrid[i][j] = '0';
+ }
+ }
+
+ i = 0;
+ for (row = 0; row < c1_grid_height[size - 1]; row++) {
+ for (col = 0; col < c1_grid_width[size - 1]; col++) {
+ if (stream[i] & 0x80) {
+ datagrid[row * 2][col * 4] = '1';
+ }
+ if (stream[i] & 0x40) {
+ datagrid[row * 2][(col * 4) + 1] = '1';
+ }
+ if (stream[i] & 0x20) {
+ datagrid[row * 2][(col * 4) + 2] = '1';
+ }
+ if (stream[i] & 0x10) {
+ datagrid[row * 2][(col * 4) + 3] = '1';
+ }
+ if (stream[i] & 0x08) {
+ datagrid[(row * 2) + 1][col * 4] = '1';
+ }
+ if (stream[i] & 0x04) {
+ datagrid[(row * 2) + 1][(col * 4) + 1] = '1';
+ }
+ if (stream[i] & 0x02) {
+ datagrid[(row * 2) + 1][(col * 4) + 2] = '1';
+ }
+ if (stream[i] & 0x01) {
+ datagrid[(row * 2) + 1][(col * 4) + 3] = '1';
+ }
+ i++;
+ }
+ }
+
+ symbol->rows = c1_height[size - 1];
+ symbol->width = c1_width[size - 1];
+ }
+
+ switch (size) {
+ case 1: /* Version A */
+ central_finder(symbol, 6, 3, 1);
+ vert(symbol, 4, 6, 1);
+ vert(symbol, 12, 5, 0);
+ set_module(symbol, 5, 12);
+ spigot(symbol, 0);
+ spigot(symbol, 15);
+ block_copy(symbol, datagrid, 0, 0, 5, 4, 0, 0);
+ block_copy(symbol, datagrid, 0, 4, 5, 12, 0, 2);
+ block_copy(symbol, datagrid, 5, 0, 5, 12, 6, 0);
+ block_copy(symbol, datagrid, 5, 12, 5, 4, 6, 2);
+ break;
+ case 2: /* Version B */
+ central_finder(symbol, 8, 4, 1);
+ vert(symbol, 4, 8, 1);
+ vert(symbol, 16, 7, 0);
+ set_module(symbol, 7, 16);
+ spigot(symbol, 0);
+ spigot(symbol, 21);
+ block_copy(symbol, datagrid, 0, 0, 7, 4, 0, 0);
+ block_copy(symbol, datagrid, 0, 4, 7, 16, 0, 2);
+ block_copy(symbol, datagrid, 7, 0, 7, 16, 8, 0);
+ block_copy(symbol, datagrid, 7, 16, 7, 4, 8, 2);
+ break;
+ case 3: /* Version C */
+ central_finder(symbol, 11, 4, 2);
+ vert(symbol, 4, 11, 1);
+ vert(symbol, 26, 13, 1);
+ vert(symbol, 4, 10, 0);
+ vert(symbol, 26, 10, 0);
+ spigot(symbol, 0);
+ spigot(symbol, 27);
+ block_copy(symbol, datagrid, 0, 0, 10, 4, 0, 0);
+ block_copy(symbol, datagrid, 0, 4, 10, 20, 0, 2);
+ block_copy(symbol, datagrid, 0, 24, 10, 4, 0, 4);
+ block_copy(symbol, datagrid, 10, 0, 10, 4, 8, 0);
+ block_copy(symbol, datagrid, 10, 4, 10, 20, 8, 2);
+ block_copy(symbol, datagrid, 10, 24, 10, 4, 8, 4);
+ break;
+ case 4: /* Version D */
+ central_finder(symbol, 16, 5, 1);
+ vert(symbol, 4, 16, 1);
+ vert(symbol, 20, 16, 1);
+ vert(symbol, 36, 16, 1);
+ vert(symbol, 4, 15, 0);
+ vert(symbol, 20, 15, 0);
+ vert(symbol, 36, 15, 0);
+ spigot(symbol, 0);
+ spigot(symbol, 12);
+ spigot(symbol, 27);
+ spigot(symbol, 39);
+ block_copy(symbol, datagrid, 0, 0, 15, 4, 0, 0);
+ block_copy(symbol, datagrid, 0, 4, 15, 14, 0, 2);
+ block_copy(symbol, datagrid, 0, 18, 15, 14, 0, 4);
+ block_copy(symbol, datagrid, 0, 32, 15, 4, 0, 6);
+ block_copy(symbol, datagrid, 15, 0, 15, 4, 10, 0);
+ block_copy(symbol, datagrid, 15, 4, 15, 14, 10, 2);
+ block_copy(symbol, datagrid, 15, 18, 15, 14, 10, 4);
+ block_copy(symbol, datagrid, 15, 32, 15, 4, 10, 6);
+ break;
+ case 5: /* Version E */
+ central_finder(symbol, 22, 5, 2);
+ vert(symbol, 4, 22, 1);
+ vert(symbol, 26, 24, 1);
+ vert(symbol, 48, 22, 1);
+ vert(symbol, 4, 21, 0);
+ vert(symbol, 26, 21, 0);
+ vert(symbol, 48, 21, 0);
+ spigot(symbol, 0);
+ spigot(symbol, 12);
+ spigot(symbol, 39);
+ spigot(symbol, 51);
+ block_copy(symbol, datagrid, 0, 0, 21, 4, 0, 0);
+ block_copy(symbol, datagrid, 0, 4, 21, 20, 0, 2);
+ block_copy(symbol, datagrid, 0, 24, 21, 20, 0, 4);
+ block_copy(symbol, datagrid, 0, 44, 21, 4, 0, 6);
+ block_copy(symbol, datagrid, 21, 0, 21, 4, 10, 0);
+ block_copy(symbol, datagrid, 21, 4, 21, 20, 10, 2);
+ block_copy(symbol, datagrid, 21, 24, 21, 20, 10, 4);
+ block_copy(symbol, datagrid, 21, 44, 21, 4, 10, 6);
+ break;
+ case 6: /* Version F */
+ central_finder(symbol, 31, 5, 3);
+ vert(symbol, 4, 31, 1);
+ vert(symbol, 26, 35, 1);
+ vert(symbol, 48, 31, 1);
+ vert(symbol, 70, 35, 1);
+ vert(symbol, 4, 30, 0);
+ vert(symbol, 26, 30, 0);
+ vert(symbol, 48, 30, 0);
+ vert(symbol, 70, 30, 0);
+ spigot(symbol, 0);
+ spigot(symbol, 12);
+ spigot(symbol, 24);
+ spigot(symbol, 45);
+ spigot(symbol, 57);
+ spigot(symbol, 69);
+ block_copy(symbol, datagrid, 0, 0, 30, 4, 0, 0);
+ block_copy(symbol, datagrid, 0, 4, 30, 20, 0, 2);
+ block_copy(symbol, datagrid, 0, 24, 30, 20, 0, 4);
+ block_copy(symbol, datagrid, 0, 44, 30, 20, 0, 6);
+ block_copy(symbol, datagrid, 0, 64, 30, 4, 0, 8);
+ block_copy(symbol, datagrid, 30, 0, 30, 4, 10, 0);
+ block_copy(symbol, datagrid, 30, 4, 30, 20, 10, 2);
+ block_copy(symbol, datagrid, 30, 24, 30, 20, 10, 4);
+ block_copy(symbol, datagrid, 30, 44, 30, 20, 10, 6);
+ block_copy(symbol, datagrid, 30, 64, 30, 4, 10, 8);
+ break;
+ case 7: /* Version G */
+ central_finder(symbol, 47, 6, 2);
+ vert(symbol, 6, 47, 1);
+ vert(symbol, 27, 49, 1);
+ vert(symbol, 48, 47, 1);
+ vert(symbol, 69, 49, 1);
+ vert(symbol, 90, 47, 1);
+ vert(symbol, 6, 46, 0);
+ vert(symbol, 27, 46, 0);
+ vert(symbol, 48, 46, 0);
+ vert(symbol, 69, 46, 0);
+ vert(symbol, 90, 46, 0);
+ spigot(symbol, 0);
+ spigot(symbol, 12);
+ spigot(symbol, 24);
+ spigot(symbol, 36);
+ spigot(symbol, 67);
+ spigot(symbol, 79);
+ spigot(symbol, 91);
+ spigot(symbol, 103);
+ block_copy(symbol, datagrid, 0, 0, 46, 6, 0, 0);
+ block_copy(symbol, datagrid, 0, 6, 46, 19, 0, 2);
+ block_copy(symbol, datagrid, 0, 25, 46, 19, 0, 4);
+ block_copy(symbol, datagrid, 0, 44, 46, 19, 0, 6);
+ block_copy(symbol, datagrid, 0, 63, 46, 19, 0, 8);
+ block_copy(symbol, datagrid, 0, 82, 46, 6, 0, 10);
+ block_copy(symbol, datagrid, 46, 0, 46, 6, 12, 0);
+ block_copy(symbol, datagrid, 46, 6, 46, 19, 12, 2);
+ block_copy(symbol, datagrid, 46, 25, 46, 19, 12, 4);
+ block_copy(symbol, datagrid, 46, 44, 46, 19, 12, 6);
+ block_copy(symbol, datagrid, 46, 63, 46, 19, 12, 8);
+ block_copy(symbol, datagrid, 46, 82, 46, 6, 12, 10);
+ break;
+ case 8: /* Version H */
+ central_finder(symbol, 69, 6, 3);
+ vert(symbol, 6, 69, 1);
+ vert(symbol, 26, 73, 1);
+ vert(symbol, 46, 69, 1);
+ vert(symbol, 66, 73, 1);
+ vert(symbol, 86, 69, 1);
+ vert(symbol, 106, 73, 1);
+ vert(symbol, 126, 69, 1);
+ vert(symbol, 6, 68, 0);
+ vert(symbol, 26, 68, 0);
+ vert(symbol, 46, 68, 0);
+ vert(symbol, 66, 68, 0);
+ vert(symbol, 86, 68, 0);
+ vert(symbol, 106, 68, 0);
+ vert(symbol, 126, 68, 0);
+ spigot(symbol, 0);
+ spigot(symbol, 12);
+ spigot(symbol, 24);
+ spigot(symbol, 36);
+ spigot(symbol, 48);
+ spigot(symbol, 60);
+ spigot(symbol, 87);
+ spigot(symbol, 99);
+ spigot(symbol, 111);
+ spigot(symbol, 123);
+ spigot(symbol, 135);
+ spigot(symbol, 147);
+ block_copy(symbol, datagrid, 0, 0, 68, 6, 0, 0);
+ block_copy(symbol, datagrid, 0, 6, 68, 18, 0, 2);
+ block_copy(symbol, datagrid, 0, 24, 68, 18, 0, 4);
+ block_copy(symbol, datagrid, 0, 42, 68, 18, 0, 6);
+ block_copy(symbol, datagrid, 0, 60, 68, 18, 0, 8);
+ block_copy(symbol, datagrid, 0, 78, 68, 18, 0, 10);
+ block_copy(symbol, datagrid, 0, 96, 68, 18, 0, 12);
+ block_copy(symbol, datagrid, 0, 114, 68, 6, 0, 14);
+ block_copy(symbol, datagrid, 68, 0, 68, 6, 12, 0);
+ block_copy(symbol, datagrid, 68, 6, 68, 18, 12, 2);
+ block_copy(symbol, datagrid, 68, 24, 68, 18, 12, 4);
+ block_copy(symbol, datagrid, 68, 42, 68, 18, 12, 6);
+ block_copy(symbol, datagrid, 68, 60, 68, 18, 12, 8);
+ block_copy(symbol, datagrid, 68, 78, 68, 18, 12, 10);
+ block_copy(symbol, datagrid, 68, 96, 68, 18, 12, 12);
+ block_copy(symbol, datagrid, 68, 114, 68, 6, 12, 14);
+ break;
+ case 9: /* Version S */
+ horiz(symbol, 5, 1);
+ horiz(symbol, 7, 1);
+ set_module(symbol, 6, 0);
+ set_module(symbol, 6, symbol->width - 1);
+ unset_module(symbol, 7, 1);
+ unset_module(symbol, 7, symbol->width - 2);
+ switch (sub_version) {
+ case 1: /* Version S-10 */
+ set_module(symbol, 0, 5);
+ block_copy(symbol, datagrid, 0, 0, 4, 5, 0, 0);
+ block_copy(symbol, datagrid, 0, 5, 4, 5, 0, 1);
+ break;
+ case 2: /* Version S-20 */
+ set_module(symbol, 0, 10);
+ set_module(symbol, 4, 10);
+ block_copy(symbol, datagrid, 0, 0, 4, 10, 0, 0);
+ block_copy(symbol, datagrid, 0, 10, 4, 10, 0, 1);
+ break;
+ case 3: /* Version S-30 */
+ set_module(symbol, 0, 15);
+ set_module(symbol, 4, 15);
+ set_module(symbol, 6, 15);
+ block_copy(symbol, datagrid, 0, 0, 4, 15, 0, 0);
+ block_copy(symbol, datagrid, 0, 15, 4, 15, 0, 1);
+ break;
+ }
+ break;
+ case 10: /* Version T */
+ horiz(symbol, 11, 1);
+ horiz(symbol, 13, 1);
+ horiz(symbol, 15, 1);
+ set_module(symbol, 12, 0);
+ set_module(symbol, 12, symbol->width - 1);
+ set_module(symbol, 14, 0);
+ set_module(symbol, 14, symbol->width - 1);
+ unset_module(symbol, 13, 1);
+ unset_module(symbol, 13, symbol->width - 2);
+ unset_module(symbol, 15, 1);
+ unset_module(symbol, 15, symbol->width - 2);
+ switch (sub_version) {
+ case 1: /* Version T-16 */
+ set_module(symbol, 0, 8);
+ set_module(symbol, 10, 8);
+ block_copy(symbol, datagrid, 0, 0, 10, 8, 0, 0);
+ block_copy(symbol, datagrid, 0, 8, 10, 8, 0, 1);
+ break;
+ case 2: /* Version T-32 */
+ set_module(symbol, 0, 16);
+ set_module(symbol, 10, 16);
+ set_module(symbol, 12, 16);
+ block_copy(symbol, datagrid, 0, 0, 10, 16, 0, 0);
+ block_copy(symbol, datagrid, 0, 16, 10, 16, 0, 1);
+ break;
+ case 3: /* Verion T-48 */
+ set_module(symbol, 0, 24);
+ set_module(symbol, 10, 24);
+ set_module(symbol, 12, 24);
+ set_module(symbol, 14, 24);
+ block_copy(symbol, datagrid, 0, 0, 10, 24, 0, 0);
+ block_copy(symbol, datagrid, 0, 24, 10, 24, 0, 1);
+ break;
+ }
+ break;
+ }
+
+ for (i = 0; i < symbol->rows; i++) {
+ symbol->row_height[i] = 1;
+ }
+
+ return 0;
+}
diff --git a/backend/code1.h b/backend/code1.h
new file mode 100644
index 0000000..aaf4898
--- /dev/null
+++ b/backend/code1.h
@@ -0,0 +1,102 @@
+/* code1.h - Lookup info for USS Code One */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2009-2017 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+
+static const char c40_shift[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 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,
+ 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+};
+
+static const char c40_value[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 15, 16, 17, 18, 19, 20, 21, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 22, 23, 24, 25, 26, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+};
+
+static const char text_shift[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 3, 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, 3, 3, 3, 3, 3
+};
+
+static const char text_value[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 15, 16, 17, 18, 19, 20, 21, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 22, 23, 24, 25, 26, 0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 27, 28, 29, 30, 31
+};
+
+static const unsigned short int c1_height[] = {
+ 16, 22, 28, 40, 52, 70, 104, 148
+};
+
+static const unsigned short int c1_width[] = {
+ 18, 22, 32, 42, 54, 76, 98, 134
+};
+
+static const unsigned short int c1_data_length[] = {
+ 10, 19, 44, 91, 182, 370, 732, 1480
+};
+
+static const unsigned short int c1_ecc_length[] = {
+ 10, 16, 26, 44, 70, 140, 280, 560
+};
+
+static const unsigned short int c1_blocks[] = {
+ 1, 1, 1, 1, 1, 2, 4, 8
+};
+
+static const unsigned short int c1_data_blocks[] = {
+ 10, 19, 44, 91, 182, 185, 183, 185
+};
+
+static const unsigned short int c1_ecc_blocks[] = {
+ 10, 16, 26, 44, 70, 70, 70, 70
+};
+
+static const unsigned short int c1_grid_width[] = {
+ 4, 5, 7, 9, 12, 17, 22, 30
+};
+
+static const unsigned short int c1_grid_height[] = {
+ 5, 7, 10, 15, 21, 30, 46, 68
+};
+
+#define C1_ASCII 1
+#define C1_C40 2
+#define C1_DECIMAL 3
+#define C1_TEXT 4
+#define C1_EDI 5
+#define C1_BYTE 6
diff --git a/backend/code128.c b/backend/code128.c
index f0f985d..b69613a 100644
--- a/backend/code128.c
+++ b/backend/code128.c
@@ -2,7 +2,7 @@
/*
libzint - the open source barcode library
- Copyright (C) 2008 Robin Stuart <robin@zint.org.uk>
+ Copyright (C) 2008-2020 Robin Stuart <rstuart114@gmail.com>
Bugfixes thanks to Christian Sakowski and BogDan Vatra
Redistribution and use in source and binary forms, with or without
@@ -29,162 +29,208 @@
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
-*/
+ */
+/* vim: set ts=4 sw=4 et : */
#include <stdio.h>
#include <string.h>
-#include <stdlib.h>
#ifdef _MSC_VER
-#include <malloc.h>
+#include <malloc.h>
#endif
+#include <assert.h>
#include "common.h"
+#include "code128.h"
#include "gs1.h"
-#define TRUE 1
-#define FALSE 0
-#define SHIFTA 90
-#define LATCHA 91
-#define SHIFTB 92
-#define LATCHB 93
-#define SHIFTC 94
-#define LATCHC 95
-#define AORB 96
-#define ABORC 97
+/* Code 128 tables checked against ISO/IEC 15417:2007 */
-#define DPDSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*"
+static const char *C128Table[107] = {
+ /* Code 128 character encodation - Table 1 */
+ "212222", "222122", "222221", "121223", "121322", "131222", "122213",
+ "122312", "132212", "221213", "221312", "231212", "112232", "122132", "122231", "113222",
+ "123122", "123221", "223211", "221132", "221231", "213212", "223112", "312131", "311222",
+ "321122", "321221", "312212", "322112", "322211", "212123", "212321", "232121", "111323",
+ "131123", "131321", "112313", "132113", "132311", "211313", "231113", "231311", "112133",
+ "112331", "132131", "113123", "113321", "133121", "313121", "211331", "231131", "213113",
+ "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111", "314111",
+ "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214",
+ "112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112",
+ "134111", "111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112",
+ "421211", "212141", "214121", "412121", "111143", "111341", "131141", "114113", "114311",
+ "411113", "411311", "113141", "114131", "311141", "411131", "211412", "211214", "211232",
+ "2331112"
+};
-static int list[2][170];
+/* Determine appropriate mode for a given character */
+INTERNAL int parunmodd(const unsigned char llyth) {
+ int modd;
-/* Code 128 tables checked against ISO/IEC 15417:2007 */
+ if (llyth <= 31) {
+ modd = SHIFTA;
+ } else if ((llyth >= 48) && (llyth <= 57)) {
+ modd = ABORC;
+ } else if (llyth <= 95) {
+ modd = AORB;
+ } else if (llyth <= 127) {
+ modd = SHIFTB;
+ } else if (llyth <= 159) {
+ modd = SHIFTA;
+ } else if (llyth <= 223) {
+ modd = AORB;
+ } else {
+ modd = SHIFTB;
+ }
-static const char *C128Table[107] = {"212222", "222122", "222221", "121223", "121322", "131222", "122213",
- "122312", "132212", "221213", "221312", "231212", "112232", "122132", "122231", "113222",
- "123122", "123221", "223211", "221132", "221231", "213212", "223112", "312131", "311222",
- "321122", "321221", "312212", "322112", "322211", "212123", "212321", "232121", "111323",
- "131123", "131321", "112313", "132113", "132311", "211313", "231113", "231311", "112133",
- "112331", "132131", "113123", "113321", "133121", "313121", "211331", "231131", "213113",
- "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111", "314111",
- "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214",
- "112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112",
- "134111", "111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112",
- "421211", "212141", "214121", "412121", "111143", "111341", "131141", "114113", "114311",
- "411113", "411311", "113141", "114131", "311141", "411131", "211412", "211214", "211232",
- "2331112"};
-/* Code 128 character encodation - Table 1 */
-
-int parunmodd(unsigned char llyth)
-{
- int modd;
- modd = 0;
-
- if(llyth <= 31) { modd = SHIFTA; }
- else if((llyth >= 48) && (llyth <= 57)) { modd = ABORC; }
- else if(llyth <= 95) { modd = AORB; }
- else if(llyth <= 127) { modd = SHIFTB; }
- else if(llyth <= 159) { modd = SHIFTA; }
- else if(llyth <= 223) { modd = AORB; }
- else { modd = SHIFTB; }
-
- return modd;
+ return modd;
}
/**
* bring together same type blocks
*/
-void grwp(int *indexliste)
-{
- int i, j;
-
- /* bring together same type blocks */
- if(*(indexliste) > 1) {
- i = 1;
- while(i < *(indexliste)) {
- if(list[1][i - 1] == list[1][i]) {
- /* bring together */
- list[0][i - 1] = list[0][i - 1] + list[0][i];
- j = i + 1;
-
- /* decreace the list */
- while(j < *(indexliste)) {
- list[0][j - 1] = list[0][j];
- list[1][j - 1] = list[1][j];
- j++;
- }
- *(indexliste) = *(indexliste) - 1;
- i--;
- }
- i++;
- }
- }
+static void grwp(int list[2][C128_MAX], int *indexliste) {
+
+ /* bring together same type blocks */
+ if (*(indexliste) > 1) {
+ int i = 1;
+ while (i < *(indexliste)) {
+ if (list[1][i - 1] == list[1][i]) {
+ int j;
+ /* bring together */
+ list[0][i - 1] = list[0][i - 1] + list[0][i];
+ j = i + 1;
+
+ /* decrease the list */
+ while (j < *(indexliste)) {
+ list[0][j - 1] = list[0][j];
+ list[1][j - 1] = list[1][j];
+ j++;
+ }
+ *(indexliste) = *(indexliste) - 1;
+ i--;
+ }
+ i++;
+ }
+ }
}
/**
* Implements rules from ISO 15417 Annex E
*/
-void dxsmooth(int *indexliste)
-{ /* Implements rules from ISO 15417 Annex E */
- int i, current, last, next, length;
-
- for(i = 0; i < *(indexliste); i++) {
- current = list[1][i];
- length = list[0][i];
- if(i != 0) { last = list[1][i - 1]; } else { last = FALSE; }
- if(i != *(indexliste) - 1) { next = list[1][i + 1]; } else { next = FALSE; }
-
- if(i == 0) { /* first block */
- if((*(indexliste) == 1) && ((length == 2) && (current == ABORC))) { /* Rule 1a */ list[1][i] = LATCHC; }
- if(current == ABORC) {
- if(length >= 4) {/* Rule 1b */ list[1][i] = LATCHC; } else { list[1][i] = AORB; current = AORB; }
- }
- if(current == SHIFTA) { /* Rule 1c */ list[1][i] = LATCHA; }
- if((current == AORB) && (next == SHIFTA)) { /* Rule 1c */ list[1][i] = LATCHA; current = LATCHA; }
- if(current == AORB) { /* Rule 1d */ list[1][i] = LATCHB; }
- } else {
- if((current == ABORC) && (length >= 4)) { /* Rule 3 */ list[1][i] = LATCHC; current = LATCHC; }
- if(current == ABORC) { list[1][i] = AORB; current = AORB; }
- if((current == AORB) && (last == LATCHA)) { list[1][i] = LATCHA; current = LATCHA; }
- if((current == AORB) && (last == LATCHB)) { list[1][i] = LATCHB; current = LATCHB; }
- if((current == AORB) && (next == SHIFTA)) { list[1][i] = LATCHA; current = LATCHA; }
- if((current == AORB) && (next == SHIFTB)) { list[1][i] = LATCHB; current = LATCHB; }
- if(current == AORB) { list[1][i] = LATCHB; current = LATCHB; }
- if((current == SHIFTA) && (length > 1)) { /* Rule 4 */ list[1][i] = LATCHA; current = LATCHA; }
- if((current == SHIFTB) && (length > 1)) { /* Rule 5 */ list[1][i] = LATCHB; current = LATCHB; }
- if((current == SHIFTA) && (last == LATCHA)) { list[1][i] = LATCHA; current = LATCHA; }
- if((current == SHIFTB) && (last == LATCHB)) { list[1][i] = LATCHB; current = LATCHB; }
- if((current == SHIFTA) && (last == LATCHC)) { list[1][i] = LATCHA; current = LATCHA; }
- if((current == SHIFTB) && (last == LATCHC)) { list[1][i] = LATCHB; current = LATCHB; }
- } /* Rule 2 is implimented elsewhere, Rule 6 is implied */
- }
- grwp(indexliste);
+INTERNAL void dxsmooth(int list[2][C128_MAX], int *indexliste) {
+ int i, last, next;
+
+ for (i = 0; i < *(indexliste); i++) {
+ int current = list[1][i]; /* Either ABORC, AORB, SHIFTA or SHIFTB */
+ int length = list[0][i];
+ if (i != 0) {
+ last = list[1][i - 1];
+ } else {
+ last = FALSE;
+ }
+ if (i != *(indexliste) - 1) {
+ next = list[1][i + 1];
+ } else {
+ next = FALSE;
+ }
+ if (i == 0) { /* first block */
+ if (current == ABORC) {
+ if ((*(indexliste) == 1) && (length == 2)) {
+ /* Rule 1a */
+ list[1][i] = LATCHC;
+ current = LATCHC;
+ } else if (length >= 4) {
+ /* Rule 1b */
+ list[1][i] = LATCHC;
+ current = LATCHC;
+ } else {
+ current = AORB; /* Determine below */
+ }
+ }
+ if (current == AORB) {
+ if (next == SHIFTA) {
+ /* Rule 1c */
+ list[1][i] = LATCHA;
+ } else {
+ /* Rule 1d */
+ list[1][i] = LATCHB;
+ }
+ } else if (current == SHIFTA) {
+ /* Rule 1c */
+ list[1][i] = LATCHA;
+ } else if (current == SHIFTB) { /* Unless LATCHC set above, can only be SHIFTB */
+ /* Rule 1d */
+ list[1][i] = LATCHB;
+ }
+ } else {
+ if (current == ABORC) {
+ if (length >= 4) {
+ /* Rule 3 */
+ list[1][i] = LATCHC;
+ current = LATCHC;
+ } else {
+ current = AORB; /* Determine below */
+ }
+ }
+ if (current == AORB) {
+ if (last == LATCHA || last == SHIFTB) { /* Maintain state */
+ list[1][i] = LATCHA;
+ } else if (last == LATCHB || last == SHIFTA) { /* Maintain state */
+ list[1][i] = LATCHB;
+ } else if (next == SHIFTA) {
+ list[1][i] = LATCHA;
+ } else {
+ list[1][i] = LATCHB;
+ }
+ } else if (current == SHIFTA) {
+ if (length > 1) {
+ /* Rule 4 */
+ list[1][i] = LATCHA;
+ } else if (last == LATCHA || last == SHIFTB) { /* Maintain state */
+ list[1][i] = LATCHA;
+ } else if (last == LATCHC) {
+ list[1][i] = LATCHA;
+ }
+ } else if (current == SHIFTB) { /* Unless LATCHC set above, can only be SHIFTB */
+ if (length > 1) {
+ /* Rule 5 */
+ list[1][i] = LATCHB;
+ } else if (last == LATCHB || last == SHIFTA) { /* Maintain state */
+ list[1][i] = LATCHB;
+ } else if (last == LATCHC) {
+ list[1][i] = LATCHB;
+ }
+ }
+ } /* Rule 2 is implemented elsewhere, Rule 6 is implied */
+ }
+
+ grwp(list, indexliste);
}
/**
* Translate Code 128 Set A characters into barcodes.
- * This set handles all control characters NULL to US.
+ * This set handles all control characters NUL to US.
*/
-void c128_set_a(unsigned char source, char dest[], int values[], int *bar_chars)
-{ /* Translate Code 128 Set A characters into barcodes */
- /* This set handles all control characters NULL to US */
-
- if(source > 127) {
- if(source < 160) {
- concat(dest, C128Table[(source - 128) + 64]);
- values[(*bar_chars)] = (source - 128) + 64;
- } else {
- concat(dest, C128Table[(source - 128) - 32]);
- values[(*bar_chars)] = (source - 128) - 32;
- }
- } else {
- if(source < 32) {
- concat(dest, C128Table[source + 64]);
- values[(*bar_chars)] = source + 64;
- } else {
- concat(dest, C128Table[source - 32]);
- values[(*bar_chars)] = source - 32;
- }
- }
- (*bar_chars)++;
+static void c128_set_a(unsigned char source, char dest[], int values[], int *bar_chars) {
+
+ if (source > 127) {
+ if (source < 160) {
+ strcat(dest, C128Table[(source - 128) + 64]);
+ values[(*bar_chars)] = (source - 128) + 64;
+ } else {
+ strcat(dest, C128Table[(source - 128) - 32]);
+ values[(*bar_chars)] = (source - 128) - 32;
+ }
+ } else {
+ if (source < 32) {
+ strcat(dest, C128Table[source + 64]);
+ values[(*bar_chars)] = source + 64;
+ } else {
+ strcat(dest, C128Table[source - 32]);
+ values[(*bar_chars)] = source - 32;
+ }
+ }
+ (*bar_chars)++;
}
/**
@@ -192,822 +238,834 @@ void c128_set_a(unsigned char source, char dest[], int values[], int *bar_chars)
* This set handles all characters which are not part of long numbers and not
* control characters.
*/
-void c128_set_b(unsigned char source, char dest[], int values[], int *bar_chars)
-{
- if(source > 127) {
- concat(dest, C128Table[source - 32 - 128]);
- values[(*bar_chars)] = source - 32 - 128;
- } else {
- concat(dest, C128Table[source - 32]);
- values[(*bar_chars)] = source - 32;
- }
- (*bar_chars)++;
+static void c128_set_b(unsigned char source, char dest[], int values[], int *bar_chars) {
+ if (source > 127) {
+ strcat(dest, C128Table[source - 32 - 128]);
+ values[(*bar_chars)] = source - 32 - 128;
+ } else {
+ strcat(dest, C128Table[source - 32]);
+ values[(*bar_chars)] = source - 32;
+ }
+ (*bar_chars)++;
}
-void c128_set_c(unsigned char source_a, unsigned char source_b, char dest[], int values[], int *bar_chars)
-{ /* Translate Code 128 Set C characters into barcodes */
- /* This set handles numbers in a compressed form */
- int weight;
-
- weight = (10 * ctoi(source_a)) + ctoi(source_b);
- concat(dest, C128Table[weight]);
- values[(*bar_chars)] = weight;
- (*bar_chars)++;
+/* Translate Code 128 Set C characters into barcodes
+ * This set handles numbers in a compressed form
+ */
+static void c128_set_c(unsigned char source_a, unsigned char source_b, char dest[], int values[], int *bar_chars) {
+ int weight;
+
+ weight = (10 * ctoi(source_a)) + ctoi(source_b);
+ strcat(dest, C128Table[weight]);
+ values[(*bar_chars)] = weight;
+ (*bar_chars)++;
}
-int code_128(struct zint_symbol *symbol, unsigned char source[], int length)
-{ /* Handle Code 128 and NVE-18 */
- int i, j, k,values[170] = { 0 }, bar_characters, read, total_sum;
- int error_number, indexchaine, indexliste, sourcelen, f_state;
- char set[170] = { ' ' }, fset[170] = { ' ' }, mode, last_set, current_set = ' ';
- float glyph_count;
- char dest[1000];
-
- error_number = 0;
- strcpy(dest, "");
-
- sourcelen = length;
-
- j = 0;
- bar_characters = 0;
- f_state = 0;
-
- if(sourcelen > 160) {
- /* This only blocks rediculously long input - the actual length of the
- resulting barcode depends on the type of data, so this is trapped later */
- strcpy(symbol->errtxt, "Input too long");
- return ERROR_TOO_LONG;
- }
-
- /* Detect extended ASCII characters */
- for(i = 0; i < sourcelen; i++) {
- if(source[i] >= 128)
- fset[i] = 'f';
- }
- fset[i] = '\0';
-
- /* Decide when to latch to extended mode - Annex E note 3 */
- j = 0;
- for(i = 0; i < sourcelen; i++) {
- if(fset[i] == 'f') {
- j++;
- } else {
- j = 0;
- }
-
- if(j >= 5) {
- for(k = i; k > (i - 5); k--) {
- fset[k] = 'F';
- }
- }
-
- if((j >= 3) && (i == (sourcelen - 1))) {
- for(k = i; k > (i - 3); k--) {
- fset[k] = 'F';
- }
- }
- }
-
- /* Decide if it is worth reverting to 646 encodation for a few characters as described in 4.3.4.2 (d) */
- for(i = 1; i < sourcelen; i++) {
- if((fset[i - 1] == 'F') && (fset[i] == ' ')) {
- /* Detected a change from 8859-1 to 646 - count how long for */
- for(j = 0; (fset[i + j] == ' ') && ((i + j) < sourcelen); j++);
- if((j < 5) || ((j < 3) && ((i + j) == (sourcelen - 1)))) {
- /* Uses the same figures recommended by Annex E note 3 */
- /* Change to shifting back rather than latching back */
- for(k = 0; k < j; k++) {
- fset[i + k] = 'n';
- }
- }
- }
- }
-
- /* Decide on mode using same system as PDF417 and rules of ISO 15417 Annex E */
- indexliste = 0;
- indexchaine = 0;
-
- mode = parunmodd(source[indexchaine]);
- if((symbol->symbology == BARCODE_CODE128B) && (mode == ABORC)) {
- mode = AORB;
- }
-
- for(i = 0; i < 170; i++) {
- list[0][i] = 0;
- }
-
- do {
- list[1][indexliste] = mode;
- while ((list[1][indexliste] == mode) && (indexchaine < sourcelen)) {
- list[0][indexliste]++;
- indexchaine++;
- mode = parunmodd(source[indexchaine]);
- if((symbol->symbology == BARCODE_CODE128B) && (mode == ABORC)) {
- mode = AORB;
- }
- }
- indexliste++;
- } while (indexchaine < sourcelen);
-
- dxsmooth(&indexliste);
-
- /* Resolve odd length LATCHC blocks */
- if((list[1][0] == LATCHC) && (list[0][0] & 1)) {
- /* Rule 2 */
- list[0][1]++;
- list[0][0]--;
- if(indexliste == 1) {
- list[0][1] = 1;
- list[1][1] = LATCHB;
- indexliste = 2;
- }
- }
- if(indexliste > 1) {
- for(i = 1; i < indexliste; i++) {
- if((list[1][i] == LATCHC) && (list[0][i] & 1)) {
- /* Rule 3b */
- list[0][i - 1]++;
- list[0][i]--;
- }
- }
- }
-
- /* Put set data into set[] */
-
- read = 0;
- for(i = 0; i < indexliste; i++) {
- for(j = 0; j < list[0][i]; j++) {
- switch(list[1][i]) {
- case SHIFTA: set[read] = 'a'; break;
- case LATCHA: set[read] = 'A'; break;
- case SHIFTB: set[read] = 'b'; break;
- case LATCHB: set[read] = 'B'; break;
- case LATCHC: set[read] = 'C'; break;
- }
- read++;
- }
- }
-
- /* Adjust for strings which start with shift characters - make them latch instead */
- if(set[0] == 'a') {
- i = 0;
- do {
- set[i] = 'A';
- i++;
- } while (set[i] == 'a');
- }
-
- if(set[0] == 'b') {
- i = 0;
- do {
- set[i] = 'B';
- i++;
- } while (set[i] == 'b');
- }
-
- /* Now we can calculate how long the barcode is going to be - and stop it from
- being too long */
- last_set = ' ';
- glyph_count = 0.0;
- for(i = 0; i < sourcelen; i++) {
- if((set[i] == 'a') || (set[i] == 'b')) {
- glyph_count = glyph_count + 1.0;
- }
- if((fset[i] == 'f') || (fset[i] == 'n')) {
- glyph_count = glyph_count + 1.0;
- }
- if(((set[i] == 'A') || (set[i] == 'B')) || (set[i] == 'C')) {
- if(set[i] != last_set) {
- last_set = set[i];
- glyph_count = glyph_count + 1.0;
- }
- }
- if(i == 0) {
- if(fset[i] == 'F') {
- glyph_count = glyph_count + 2.0;
- }
- } else {
- if((fset[i] == 'F') && (fset[i - 1] != 'F')) {
- glyph_count = glyph_count + 2.0;
- }
- if((fset[i] != 'F') && (fset[i - 1] == 'F')) {
- glyph_count = glyph_count + 2.0;
- }
- }
-
- if(set[i] == 'C') {
- glyph_count = glyph_count + 0.5;
- } else {
- glyph_count = glyph_count + 1.0;
- }
- }
- if(glyph_count > 80.0) {
- strcpy(symbol->errtxt, "Input too long");
- return ERROR_TOO_LONG;
- }
-
- /* So now we know what start character to use - we can get on with it! */
- if(symbol->output_options & READER_INIT) {
- /* Reader Initialisation mode */
- switch(set[0]) {
- case 'A': /* Start A */
- concat(dest, C128Table[103]);
- values[0] = 103;
- current_set = 'A';
- concat(dest, C128Table[96]); /* FNC3 */
- values[1] = 96;
- bar_characters++;
- break;
- case 'B': /* Start B */
- concat(dest, C128Table[104]);
- values[0] = 104;
- current_set = 'B';
- concat(dest, C128Table[96]); /* FNC3 */
- values[1] = 96;
- bar_characters++;
- break;
- case 'C': /* Start C */
- concat(dest, C128Table[104]); /* Start B */
- values[0] = 105;
- concat(dest, C128Table[96]); /* FNC3 */
- values[1] = 96;
- concat(dest, C128Table[99]); /* Code C */
- values[2] = 99;
- bar_characters += 2;
- current_set = 'C';
- break;
- }
- } else {
- /* Normal mode */
- switch(set[0]) {
- case 'A': /* Start A */
- concat(dest, C128Table[103]);
- values[0] = 103;
- current_set = 'A';
- break;
- case 'B': /* Start B */
- concat(dest, C128Table[104]);
- values[0] = 104;
- current_set = 'B';
- break;
- case 'C': /* Start C */
- concat(dest, C128Table[105]);
- values[0] = 105;
- current_set = 'C';
- break;
- }
- }
- bar_characters++;
- last_set = set[0];
-
- if(fset[0] == 'F') {
- switch(current_set) {
- case 'A':
- concat(dest, C128Table[101]);
- concat(dest, C128Table[101]);
- values[bar_characters] = 101;
- values[bar_characters + 1] = 101;
- break;
- case 'B':
- concat(dest, C128Table[100]);
- concat(dest, C128Table[100]);
- values[bar_characters] = 100;
- values[bar_characters + 1] = 100;
- break;
- }
- bar_characters += 2;
- f_state = 1;
- }
-
- /* Encode the data */
- read = 0;
- do {
-
- if((read != 0) && (set[read] != current_set))
- { /* Latch different code set */
- switch(set[read])
- {
- case 'A': concat(dest, C128Table[101]);
- values[bar_characters] = 101;
- bar_characters++;
- current_set = 'A';
- break;
- case 'B': concat(dest, C128Table[100]);
- values[bar_characters] = 100;
- bar_characters++;
- current_set = 'B';
- break;
- case 'C': concat(dest, C128Table[99]);
- values[bar_characters] = 99;
- bar_characters++;
- current_set = 'C';
- break;
- }
- }
-
- if(read != 0) {
- if((fset[read] == 'F') && (f_state == 0)) {
- /* Latch beginning of extended mode */
- switch(current_set) {
- case 'A':
- concat(dest, C128Table[101]);
- concat(dest, C128Table[101]);
- values[bar_characters] = 101;
- values[bar_characters + 1] = 101;
- break;
- case 'B':
- concat(dest, C128Table[100]);
- concat(dest, C128Table[100]);
- values[bar_characters] = 100;
- values[bar_characters + 1] = 100;
- break;
- }
- bar_characters += 2;
- f_state = 1;
- }
- if((fset[read] == ' ') && (f_state == 1)) {
- /* Latch end of extended mode */
- switch(current_set) {
- case 'A':
- concat(dest, C128Table[101]);
- concat(dest, C128Table[101]);
- values[bar_characters] = 101;
- values[bar_characters + 1] = 101;
- break;
- case 'B':
- concat(dest, C128Table[100]);
- concat(dest, C128Table[100]);
- values[bar_characters] = 100;
- values[bar_characters + 1] = 100;
- break;
- }
- bar_characters += 2;
- f_state = 0;
- }
- }
-
- if((fset[read] == 'f') || (fset[read] == 'n')) {
- /* Shift to or from extended mode */
- switch(current_set) {
- case 'A':
- concat(dest, C128Table[101]); /* FNC 4 */
- values[bar_characters] = 101;
- break;
- case 'B':
- concat(dest, C128Table[100]); /* FNC 4 */
- values[bar_characters] = 100;
- break;
- }
- bar_characters++;
- }
-
- if((set[read] == 'a') || (set[read] == 'b')) {
- /* Insert shift character */
- concat(dest, C128Table[98]);
- values[bar_characters] = 98;
- bar_characters++;
- }
-
- switch(set[read])
- { /* Encode data characters */
- case 'a':
- case 'A': c128_set_a(source[read], dest, values, &bar_characters);
- read++;
- break;
- case 'b':
- case 'B': c128_set_b(source[read], dest, values, &bar_characters);
- read++;
- break;
- case 'C': c128_set_c(source[read], source[read + 1], dest, values, &bar_characters);
- read += 2;
- break;
- }
-
- } while (read < sourcelen);
-
- /* check digit calculation */
- total_sum = 0;
- /*for(i = 0; i < bar_characters; i++) {
- printf("%d\n", values[i]);
- }*/
-
- for(i = 0; i < bar_characters; i++)
- {
- if(i > 0)
- {
- values[i] *= i;
- }
- total_sum += values[i];
- }
- concat(dest, C128Table[total_sum%103]);
-
- /* Stop character */
- concat(dest, C128Table[106]);
- expand(symbol, dest);
- return error_number;
+/* Handle Code 128, 128B and HIBC 128 */
+INTERNAL int code_128(struct zint_symbol *symbol, const unsigned char source[], const size_t length) {
+ int i, j, k, values[C128_MAX] = {0}, bar_characters, read, total_sum;
+ int error_number, indexchaine, indexliste, f_state;
+ int sourcelen;
+ int list[2][C128_MAX] = {{0}};
+ char set[C128_MAX] = {0}, fset[C128_MAX], mode, last_set, current_set = ' ';
+ float glyph_count;
+ char dest[1000];
+
+ /* Suppresses clang-analyzer-core.UndefinedBinaryOperatorResult warning on fset which is fully set */
+ assert(length > 0);
+
+ error_number = 0;
+ strcpy(dest, "");
+
+ sourcelen = length;
+
+ bar_characters = 0;
+ f_state = 0;
+
+ if (sourcelen > C128_MAX) {
+ /* This only blocks ridiculously long input - the actual length of the
+ resulting barcode depends on the type of data, so this is trapped later */
+ strcpy(symbol->errtxt, "340: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* Detect extended ASCII characters */
+ for (i = 0; i < sourcelen; i++) {
+ fset[i] = source[i] >= 128 ? 'f' : ' ';
+ }
+
+ /* Decide when to latch to extended mode - Annex E note 3 */
+ j = 0;
+ for (i = 0; i < sourcelen; i++) {
+ if (fset[i] == 'f') {
+ j++;
+ } else {
+ j = 0;
+ }
+
+ if (j >= 5) {
+ for (k = i; k > (i - 5); k--) {
+ fset[k] = 'F';
+ }
+ }
+
+ if ((j >= 3) && (i == (sourcelen - 1))) {
+ for (k = i; k > (i - 3); k--) {
+ fset[k] = 'F';
+ }
+ }
+ }
+
+ /* Decide if it is worth reverting to 646 encodation for a few characters as described in 4.3.4.2 (d) */
+ for (i = 1; i < sourcelen; i++) {
+ if ((fset[i - 1] == 'F') && (fset[i] == ' ')) {
+ /* Detected a change from 8859-1 to 646 - count how long for */
+ for (j = 0; ((i + j) < sourcelen) && (fset[i + j] == ' '); j++);
+ /* Count how many 8859-1 beyond */
+ k = 0;
+ if (i + j < sourcelen) {
+ for (k = 1; ((i + j + k) < sourcelen) && (fset[i + j + k] != ' '); k++);
+ }
+ if (j < 3 || (j < 5 && k > 2)) {
+ /* Change to shifting back rather than latching back */
+ /* Inverts the same figures recommended by Annex E note 3 */
+ for (k = 0; k < j; k++) {
+ fset[i + k] = 'n';
+ }
+ }
+ }
+ }
+
+ /* Decide on mode using same system as PDF417 and rules of ISO 15417 Annex E */
+ indexliste = 0;
+ indexchaine = 0;
+
+ mode = parunmodd(source[indexchaine]);
+ if ((symbol->symbology == BARCODE_CODE128B) && (mode == ABORC)) {
+ mode = AORB;
+ }
+
+ do {
+ list[1][indexliste] = mode;
+ while ((list[1][indexliste] == mode) && (indexchaine < sourcelen)) {
+ list[0][indexliste]++;
+ indexchaine++;
+ if (indexchaine == sourcelen) {
+ break;
+ }
+ mode = parunmodd(source[indexchaine]);
+ if ((symbol->symbology == BARCODE_CODE128B) && (mode == ABORC)) {
+ mode = AORB;
+ }
+ }
+ indexliste++;
+ } while (indexchaine < sourcelen);
+
+ dxsmooth(list, &indexliste);
+
+ /* Resolve odd length LATCHC blocks */
+ if ((list[1][0] == LATCHC) && (list[0][0] & 1)) {
+ /* Rule 2 */
+ list[0][1]++;
+ list[0][0]--;
+ if (indexliste == 1) {
+ list[0][1] = 1;
+ list[1][1] = LATCHB;
+ indexliste = 2;
+ }
+ }
+ if (indexliste > 1) {
+ for (i = 1; i < indexliste; i++) {
+ if ((list[1][i] == LATCHC) && (list[0][i] & 1)) {
+ /* Rule 3b */
+ list[0][i - 1]++;
+ list[0][i]--;
+ }
+ }
+ }
+
+ /* Put set data into set[] */
+
+ read = 0;
+ for (i = 0; i < indexliste; i++) {
+ for (j = 0; j < list[0][i]; j++) {
+ switch (list[1][i]) {
+ case SHIFTA: set[read] = 'a';
+ break;
+ case LATCHA: set[read] = 'A';
+ break;
+ case SHIFTB: set[read] = 'b';
+ break;
+ case LATCHB: set[read] = 'B';
+ break;
+ case LATCHC: set[read] = 'C';
+ break;
+ }
+ read++;
+ }
+ }
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Data: %.*s (%d)\n", sourcelen, source, sourcelen);
+ printf(" Set: %.*s\n", sourcelen, set);
+ printf("FSet: %.*s\n", sourcelen, fset);
+ }
+
+ /* Now we can calculate how long the barcode is going to be - and stop it from
+ being too long */
+ last_set = set[0];
+ glyph_count = 0.0;
+ for (i = 0; i < sourcelen; i++) {
+ if ((set[i] == 'a') || (set[i] == 'b')) {
+ glyph_count = glyph_count + 1.0;
+ }
+ if ((fset[i] == 'f') || (fset[i] == 'n')) {
+ glyph_count = glyph_count + 1.0;
+ }
+ if (((set[i] == 'A') || (set[i] == 'B')) || (set[i] == 'C')) {
+ if (set[i] != last_set) {
+ last_set = set[i];
+ glyph_count = glyph_count + 1.0;
+ }
+ }
+ if (i == 0) {
+ if (fset[i] == 'F') {
+ glyph_count = glyph_count + 2.0;
+ }
+ } else {
+ if ((fset[i] == 'F') && (fset[i - 1] != 'F')) {
+ glyph_count = glyph_count + 2.0;
+ }
+ if ((fset[i] != 'F') && (fset[i - 1] == 'F')) {
+ glyph_count = glyph_count + 2.0;
+ }
+ }
+
+ if (set[i] == 'C') {
+ glyph_count = glyph_count + 0.5;
+ } else {
+ glyph_count = glyph_count + 1.0;
+ }
+ }
+ if (glyph_count > 60.0) {
+ strcpy(symbol->errtxt, "341: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* So now we know what start character to use - we can get on with it! */
+ if (symbol->output_options & READER_INIT) {
+ /* Reader Initialisation mode */
+ switch (set[0]) {
+ case 'A': /* Start A */
+ strcat(dest, C128Table[103]);
+ values[0] = 103;
+ current_set = 'A';
+ strcat(dest, C128Table[96]); /* FNC3 */
+ values[1] = 96;
+ bar_characters++;
+ break;
+ case 'B': /* Start B */
+ strcat(dest, C128Table[104]);
+ values[0] = 104;
+ current_set = 'B';
+ strcat(dest, C128Table[96]); /* FNC3 */
+ values[1] = 96;
+ bar_characters++;
+ break;
+ case 'C': /* Start C */
+ strcat(dest, C128Table[104]); /* Start B */
+ values[0] = 104;
+ strcat(dest, C128Table[96]); /* FNC3 */
+ values[1] = 96;
+ strcat(dest, C128Table[99]); /* Code C */
+ values[2] = 99;
+ bar_characters += 2;
+ current_set = 'C';
+ break;
+ }
+ } else {
+ /* Normal mode */
+ switch (set[0]) {
+ case 'A': /* Start A */
+ strcat(dest, C128Table[103]);
+ values[0] = 103;
+ current_set = 'A';
+ break;
+ case 'B': /* Start B */
+ strcat(dest, C128Table[104]);
+ values[0] = 104;
+ current_set = 'B';
+ break;
+ case 'C': /* Start C */
+ strcat(dest, C128Table[105]);
+ values[0] = 105;
+ current_set = 'C';
+ break;
+ }
+ }
+ bar_characters++;
+
+ if (fset[0] == 'F') {
+ switch (current_set) {
+ case 'A':
+ strcat(dest, C128Table[101]);
+ strcat(dest, C128Table[101]);
+ values[bar_characters] = 101;
+ values[bar_characters + 1] = 101;
+ break;
+ case 'B':
+ strcat(dest, C128Table[100]);
+ strcat(dest, C128Table[100]);
+ values[bar_characters] = 100;
+ values[bar_characters + 1] = 100;
+ break;
+ }
+ bar_characters += 2;
+ f_state = 1;
+ }
+
+ /* Encode the data */
+ read = 0;
+ do {
+
+ if ((read != 0) && (set[read] != current_set)) {
+ /* Latch different code set */
+ switch (set[read]) {
+ case 'A': strcat(dest, C128Table[101]);
+ values[bar_characters] = 101;
+ bar_characters++;
+ current_set = 'A';
+ break;
+ case 'B': strcat(dest, C128Table[100]);
+ values[bar_characters] = 100;
+ bar_characters++;
+ current_set = 'B';
+ break;
+ case 'C': strcat(dest, C128Table[99]);
+ values[bar_characters] = 99;
+ bar_characters++;
+ current_set = 'C';
+ break;
+ }
+ }
+
+ if (read != 0) {
+ if ((fset[read] == 'F') && (f_state == 0)) {
+ /* Latch beginning of extended mode */
+ switch (current_set) {
+ case 'A':
+ strcat(dest, C128Table[101]);
+ strcat(dest, C128Table[101]);
+ values[bar_characters] = 101;
+ values[bar_characters + 1] = 101;
+ break;
+ case 'B':
+ strcat(dest, C128Table[100]);
+ strcat(dest, C128Table[100]);
+ values[bar_characters] = 100;
+ values[bar_characters + 1] = 100;
+ break;
+ }
+ bar_characters += 2;
+ f_state = 1;
+ }
+ if ((fset[read] == ' ') && (f_state == 1)) {
+ /* Latch end of extended mode */
+ switch (current_set) {
+ case 'A':
+ strcat(dest, C128Table[101]);
+ strcat(dest, C128Table[101]);
+ values[bar_characters] = 101;
+ values[bar_characters + 1] = 101;
+ break;
+ case 'B':
+ strcat(dest, C128Table[100]);
+ strcat(dest, C128Table[100]);
+ values[bar_characters] = 100;
+ values[bar_characters + 1] = 100;
+ break;
+ }
+ bar_characters += 2;
+ f_state = 0;
+ }
+ }
+
+ if ((fset[read] == 'f') || (fset[read] == 'n')) {
+ /* Shift to or from extended mode */
+ switch (current_set) {
+ case 'A':
+ strcat(dest, C128Table[101]); /* FNC 4 */
+ values[bar_characters] = 101;
+ break;
+ case 'B':
+ strcat(dest, C128Table[100]); /* FNC 4 */
+ values[bar_characters] = 100;
+ break;
+ }
+ bar_characters++;
+ }
+
+ if ((set[read] == 'a') || (set[read] == 'b')) {
+ /* Insert shift character */
+ strcat(dest, C128Table[98]);
+ values[bar_characters] = 98;
+ bar_characters++;
+ }
+
+ switch (set[read]) { /* Encode data characters */
+ case 'a':
+ case 'A': c128_set_a(source[read], dest, values, &bar_characters);
+ read++;
+ break;
+ case 'b':
+ case 'B': c128_set_b(source[read], dest, values, &bar_characters);
+ read++;
+ break;
+ case 'C': c128_set_c(source[read], source[read + 1], dest, values, &bar_characters);
+ read += 2;
+ break;
+ }
+
+ } while (read < sourcelen);
+
+ /* check digit calculation */
+ total_sum = values[0] % 103; /* Mod as we go along to avoid overflow */
+
+ for (i = 1; i < bar_characters; i++) {
+ total_sum = (total_sum + values[i] * i) % 103;
+ }
+ strcat(dest, C128Table[total_sum]);
+ values[bar_characters] = total_sum;
+ bar_characters++;
+
+ /* Stop character */
+ strcat(dest, C128Table[106]);
+ values[bar_characters] = 106;
+ bar_characters++;
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Codewords:");
+ for (i = 0; i < bar_characters; i++) {
+ printf(" %d", values[i]);
+ }
+ printf("\n");
+ }
+#ifdef ZINT_TEST
+ if (symbol->debug & ZINT_DEBUG_TEST) {
+ debug_test_codeword_dump_int(symbol, values, bar_characters);
+ }
+#endif
+
+ expand(symbol, dest);
+ return error_number;
}
-int ean_128(struct zint_symbol *symbol, unsigned char source[], int length)
-{ /* Handle EAN-128 (Now known as GS1-128) */
- int i, j,values[170], bar_characters, read, total_sum;
- int error_number, indexchaine, indexliste;
- char set[170], mode, last_set;
- float glyph_count;
- char dest[1000];
- int separator_row, linkage_flag, c_count;
+/* Handle EAN-128 (Now known as GS1-128) */
+INTERNAL int ean_128(struct zint_symbol *symbol, unsigned char source[], const size_t length) {
+ int i, j, values[C128_MAX] = {0}, bar_characters, read, total_sum;
+ int error_number, indexchaine, indexliste;
+ int list[2][C128_MAX] = {{0}};
+ char set[C128_MAX] = {0}, mode, last_set;
+ float glyph_count;
+ char dest[1000];
+ int separator_row, linkage_flag, c_count;
+ int reduced_length;
#ifndef _MSC_VER
- char reduced[length + 1];
+ char reduced[length + 1];
#else
- char* reduced = (char*)_alloca(length + 1);
+ char* reduced = (char*) _alloca(length + 1);
+#endif
+
+ strcpy(dest, "");
+ linkage_flag = 0;
+
+ bar_characters = 0;
+ separator_row = 0;
+
+ if (length > C128_MAX) {
+ /* This only blocks ridiculously long input - the actual length of the
+ resulting barcode depends on the type of data, so this is trapped later */
+ strcpy(symbol->errtxt, "342: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* if part of a composite symbol make room for the separator pattern */
+ if (symbol->symbology == BARCODE_EAN128_CC) {
+ separator_row = symbol->rows;
+ symbol->row_height[symbol->rows] = 1;
+ symbol->rows += 1;
+ }
+
+ error_number = gs1_verify(symbol, source, length, reduced);
+ if (error_number != 0) {
+ return error_number;
+ }
+ reduced_length = strlen(reduced);
+
+ /* Decide on mode using same system as PDF417 and rules of ISO 15417 Annex E */
+ indexliste = 0;
+ indexchaine = 0;
+
+ mode = parunmodd(reduced[indexchaine]);
+ if (reduced[indexchaine] == '[') {
+ mode = ABORC;
+ }
+
+ do {
+ list[1][indexliste] = mode;
+ while ((list[1][indexliste] == mode) && (indexchaine < reduced_length)) {
+ list[0][indexliste]++;
+ indexchaine++;
+ if (indexchaine == reduced_length) {
+ break;
+ }
+ mode = parunmodd(reduced[indexchaine]);
+ if (reduced[indexchaine] == '[') {
+ mode = ABORC;
+ }
+ }
+ indexliste++;
+ } while (indexchaine < reduced_length);
+
+ dxsmooth(list, &indexliste);
+
+ /* Put set data into set[] */
+ read = 0;
+ for (i = 0; i < indexliste; i++) {
+ for (j = 0; j < list[0][i]; j++) {
+ switch (list[1][i]) {
+ case SHIFTA: set[read] = 'a';
+ break;
+ case LATCHA: set[read] = 'A';
+ break;
+ case SHIFTB: set[read] = 'b';
+ break;
+ case LATCHB: set[read] = 'B';
+ break;
+ case LATCHC: set[read] = 'C';
+ break;
+ }
+ read++;
+ }
+ }
+
+ /* Watch out for odd-length Mode C blocks */
+ c_count = 0;
+ for (i = 0; i < read; i++) {
+ if (set[i] == 'C') {
+ if (reduced[i] == '[') {
+ if (c_count & 1) {
+ if ((i - c_count) != 0) {
+ set[i - c_count] = 'B';
+ } else {
+ set[i - 1] = 'B';
+ }
+ }
+ c_count = 0;
+ } else {
+ c_count++;
+ }
+ } else {
+ if (c_count & 1) {
+ if ((i - c_count) != 0) {
+ set[i - c_count] = 'B';
+ } else {
+ set[i - 1] = 'B';
+ }
+ }
+ c_count = 0;
+ }
+ }
+ if (c_count & 1) {
+ if ((i - c_count) != 0) {
+ set[i - c_count] = 'B';
+ } else {
+ set[i - 1] = 'B';
+ }
+ }
+ for (i = 1; i < read - 1; i++) {
+ if ((set[i] == 'C') && ((set[i - 1] == 'B') && (set[i + 1] == 'B'))) {
+ set[i] = 'B';
+ }
+ }
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Data: %s (%d)\n", reduced, reduced_length);
+ printf(" Set: %.*s\n", reduced_length, set);
+ }
+
+ /* Now we can calculate how long the barcode is going to be - and stop it from
+ being too long */
+ last_set = set[0];
+ glyph_count = 0.0;
+ for (i = 0; i < reduced_length; i++) {
+ if ((set[i] == 'a') || (set[i] == 'b')) {
+ glyph_count = glyph_count + 1.0;
+ }
+ if (((set[i] == 'A') || (set[i] == 'B')) || (set[i] == 'C')) {
+ if (set[i] != last_set) {
+ last_set = set[i];
+ glyph_count = glyph_count + 1.0;
+ }
+ }
+
+ if ((set[i] == 'C') && (reduced[i] != '[')) {
+ glyph_count = glyph_count + 0.5;
+ } else {
+ glyph_count = glyph_count + 1.0;
+ }
+ }
+ if (glyph_count > 60.0) {
+ strcpy(symbol->errtxt, "344: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* So now we know what start character to use - we can get on with it! */
+ switch (set[0]) {
+ case 'A': /* Start A */
+ strcat(dest, C128Table[103]);
+ values[0] = 103;
+ break;
+ case 'B': /* Start B */
+ strcat(dest, C128Table[104]);
+ values[0] = 104;
+ break;
+ case 'C': /* Start C */
+ strcat(dest, C128Table[105]);
+ values[0] = 105;
+ break;
+ }
+ bar_characters++;
+
+ strcat(dest, C128Table[102]);
+ values[1] = 102;
+ bar_characters++;
+
+ /* Encode the data */
+ read = 0;
+ do {
+
+ if ((read != 0) && (set[read] != set[read - 1])) { /* Latch different code set */
+ switch (set[read]) {
+ case 'A': strcat(dest, C128Table[101]);
+ values[bar_characters] = 101;
+ bar_characters++;
+ break;
+ case 'B': strcat(dest, C128Table[100]);
+ values[bar_characters] = 100;
+ bar_characters++;
+ break;
+ case 'C': strcat(dest, C128Table[99]);
+ values[bar_characters] = 99;
+ bar_characters++;
+ break;
+ }
+ }
+
+ if ((set[read] == 'a') || (set[read] == 'b')) {
+ /* Insert shift character */
+ strcat(dest, C128Table[98]);
+ values[bar_characters] = 98;
+ bar_characters++;
+ }
+
+ if (reduced[read] != '[') {
+ switch (set[read]) { /* Encode data characters */
+ case 'A':
+ case 'a':
+ c128_set_a(reduced[read], dest, values, &bar_characters);
+ read++;
+ break;
+ case 'B':
+ case 'b':
+ c128_set_b(reduced[read], dest, values, &bar_characters);
+ read++;
+ break;
+ case 'C':
+ c128_set_c(reduced[read], reduced[read + 1], dest, values, &bar_characters);
+ read += 2;
+ break;
+ }
+ } else {
+ strcat(dest, C128Table[102]);
+ values[bar_characters] = 102;
+ bar_characters++;
+ read++;
+ }
+ } while (read < reduced_length);
+
+ /* "...note that the linkage flag is an extra code set character between
+ the last data character and the Symbol Check Character" (GS1 Specification) */
+
+ /* Linkage flags in GS1-128 are determined by ISO/IEC 24723 section 7.4 */
+
+ switch (symbol->option_1) {
+ case 1:
+ case 2:
+ /* CC-A or CC-B 2D component */
+ switch (set[reduced_length - 1]) {
+ case 'A': linkage_flag = 100;
+ break;
+ case 'B': linkage_flag = 99;
+ break;
+ case 'C': linkage_flag = 101;
+ break;
+ }
+ break;
+ case 3:
+ /* CC-C 2D component */
+ switch (set[reduced_length - 1]) {
+ case 'A': linkage_flag = 99;
+ break;
+ case 'B': linkage_flag = 101;
+ break;
+ case 'C': linkage_flag = 100;
+ break;
+ }
+ break;
+ }
+
+ if (linkage_flag != 0) {
+ strcat(dest, C128Table[linkage_flag]);
+ values[bar_characters] = linkage_flag;
+ bar_characters++;
+ }
+
+ /* check digit calculation */
+ total_sum = values[0] % 103; /* Mod as we go along to avoid overflow */
+
+ for (i = 1; i < bar_characters; i++) {
+ total_sum = (total_sum + values[i] * i) % 103;
+ }
+ strcat(dest, C128Table[total_sum]);
+ values[bar_characters] = total_sum;
+ bar_characters++;
+
+ /* Stop character */
+ strcat(dest, C128Table[106]);
+ values[bar_characters] = 106;
+ bar_characters++;
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Codewords:");
+ for (i = 0; i < bar_characters; i++) {
+ printf(" %d", values[i]);
+ }
+ printf("\n");
+ }
+#ifdef ZINT_TEST
+ if (symbol->debug & ZINT_DEBUG_TEST) {
+ debug_test_codeword_dump_int(symbol, values, bar_characters);
+ }
#endif
- error_number = 0;
- strcpy(dest, "");
- linkage_flag = 0;
-
- j = 0;
- bar_characters = 0;
- separator_row = 0;
-
- memset(values, 0, sizeof(values));
- memset(set, ' ', sizeof(set));
-
- if(length > 160) {
- /* This only blocks rediculously long input - the actual length of the
- resulting barcode depends on the type of data, so this is trapped later */
- strcpy(symbol->errtxt, "Input too long");
- return ERROR_TOO_LONG;
- }
- for(i = 0; i < length; i++) {
- if(source[i] == '\0') {
- /* Null characters not allowed! */
- strcpy(symbol->errtxt, "NULL character in input data");
- return ERROR_INVALID_DATA;
- }
- }
-
- /* if part of a composite symbol make room for the separator pattern */
- if(symbol->symbology == BARCODE_EAN128_CC) {
- separator_row = symbol->rows;
- symbol->row_height[symbol->rows] = 1;
- symbol->rows += 1;
- }
-
- if(symbol->input_mode != GS1_MODE) {
- /* GS1 data has not been checked yet */
- error_number = gs1_verify(symbol, source, length, reduced);
- if(error_number != 0) { return error_number; }
- }
-
- /* Decide on mode using same system as PDF417 and rules of ISO 15417 Annex E */
- indexliste = 0;
- indexchaine = 0;
-
- mode = parunmodd(reduced[indexchaine]);
- if(reduced[indexchaine] == '[') {
- mode = ABORC;
- }
-
- for(i = 0; i < 170; i++) {
- list[0][i] = 0;
- }
-
- do {
- list[1][indexliste] = mode;
- while ((list[1][indexliste] == mode) && (indexchaine < strlen(reduced))) {
- list[0][indexliste]++;
- indexchaine++;
- mode = parunmodd(reduced[indexchaine]);
- if(reduced[indexchaine] == '[') { mode = ABORC; }
- }
- indexliste++;
- } while (indexchaine < strlen(reduced));
-
- dxsmooth(&indexliste);
-
- /* Put set data into set[] */
- read = 0;
- for(i = 0; i < indexliste; i++) {
- for(j = 0; j < list[0][i]; j++) {
- switch(list[1][i]) {
- case SHIFTA: set[read] = 'a'; break;
- case LATCHA: set[read] = 'A'; break;
- case SHIFTB: set[read] = 'b'; break;
- case LATCHB: set[read] = 'B'; break;
- case LATCHC: set[read] = 'C'; break;
- }
- read++;
- }
- }
-
- /* Watch out for odd-length Mode C blocks */
- c_count = 0;
- for(i = 0; i < read; i++) {
- if(set[i] == 'C') {
- if(reduced[i] == '[') {
- if(c_count & 1) {
- if((i - c_count) != 0) {
- set[i - c_count] = 'B';
- } else {
- set[i - 1] = 'B';
- }
- }
- c_count = 0;
- } else {
- c_count++;
- }
- } else {
- if(c_count & 1) {
- if((i - c_count) != 0) {
- set[i - c_count] = 'B';
- } else {
- set[i - 1] = 'B';
- }
- }
- c_count = 0;
- }
- }
- if(c_count & 1) {
- if((i - c_count) != 0) {
- set[i - c_count] = 'B';
- } else {
- set[i - 1] = 'B';
- }
- }
- for(i = 1; i < read - 1; i++) {
- if((set[i] == 'C') && ((set[i - 1] == 'B') && (set[i + 1] == 'B'))) {
- set[i] = 'B';
- }
- }
-
- /* for(i = 0; i < read; i++) {
- printf("char %c mode %c\n", reduced[i], set[i]);
- } */
-
- /* Now we can calculate how long the barcode is going to be - and stop it from
- being too long */
- last_set = ' ';
- glyph_count = 0.0;
- for(i = 0; i < strlen(reduced); i++) {
- if((set[i] == 'a') || (set[i] == 'b')) {
- glyph_count = glyph_count + 1.0;
- }
- if(((set[i] == 'A') || (set[i] == 'B')) || (set[i] == 'C')) {
- if(set[i] != last_set) {
- last_set = set[i];
- glyph_count = glyph_count + 1.0;
- }
- }
-
- if((set[i] == 'C') && (reduced[i] != '[')) {
- glyph_count = glyph_count + 0.5;
- } else {
- glyph_count = glyph_count + 1.0;
- }
- }
- if(glyph_count > 80.0) {
- strcpy(symbol->errtxt, "Input too long");
- return ERROR_TOO_LONG;
- }
-
- /* So now we know what start character to use - we can get on with it! */
- switch(set[0])
- {
- case 'A': /* Start A */
- concat(dest, C128Table[103]);
- values[0] = 103;
- break;
- case 'B': /* Start B */
- concat(dest, C128Table[104]);
- values[0] = 104;
- break;
- case 'C': /* Start C */
- concat(dest, C128Table[105]);
- values[0] = 105;
- break;
- }
- bar_characters++;
-
- concat(dest, C128Table[102]);
- values[1] = 102;
- bar_characters++;
-
- /* Encode the data */
- read = 0;
- do {
-
- if((read != 0) && (set[read] != set[read - 1]))
- { /* Latch different code set */
- switch(set[read])
- {
- case 'A': concat(dest, C128Table[101]);
- values[bar_characters] = 101;
- bar_characters++;
- break;
- case 'B': concat(dest, C128Table[100]);
- values[bar_characters] = 100;
- bar_characters++;
- break;
- case 'C': concat(dest, C128Table[99]);
- values[bar_characters] = 99;
- bar_characters++;
- break;
- }
- }
-
- if((set[read] == 'a') || (set[read] == 'b')) {
- /* Insert shift character */
- concat(dest, C128Table[98]);
- values[bar_characters] = 98;
- bar_characters++;
- }
-
- if(reduced[read] != '[') {
- switch(set[read])
- { /* Encode data characters */
- case 'A':
- case 'a':
- c128_set_a(reduced[read], dest, values, &bar_characters);
- read++;
- break;
- case 'B':
- case 'b':
- c128_set_b(reduced[read], dest, values, &bar_characters);
- read++;
- break;
- case 'C':
- c128_set_c(reduced[read], reduced[read + 1], dest, values, &bar_characters);
- read += 2;
- break;
- }
- } else {
- concat(dest, C128Table[102]);
- values[bar_characters] = 102;
- bar_characters++;
- read++;
- }
- } while (read < strlen(reduced));
-
- /* "...note that the linkage flag is an extra code set character between
- the last data character and the Symbol Check Character" (GS1 Specification) */
-
- /* Linkage flags in GS1-128 are determined by ISO/IEC 24723 section 7.4 */
-
- switch(symbol->option_1) {
- case 1:
- case 2:
- /* CC-A or CC-B 2D component */
- switch(set[strlen(reduced) - 1]) {
- case 'A': linkage_flag = 100; break;
- case 'B': linkage_flag = 99; break;
- case 'C': linkage_flag = 101; break;
- }
- break;
- case 3:
- /* CC-C 2D component */
- switch(set[strlen(reduced) - 1]) {
- case 'A': linkage_flag = 99; break;
- case 'B': linkage_flag = 101; break;
- case 'C': linkage_flag = 100; break;
- }
- break;
- }
-
- if(linkage_flag != 0) {
- concat(dest, C128Table[linkage_flag]);
- values[bar_characters] = linkage_flag;
- bar_characters++;
- }
-
- /*for(i = 0; i < bar_characters; i++) {
- printf("[%d] ", values[i]);
- }
- printf("\n");*/
-
- /* check digit calculation */
- total_sum = 0;
- for(i = 0; i < bar_characters; i++)
- {
- if(i > 0)
- {
- values[i] *= i;
-
- }
- total_sum += values[i];
- }
- concat(dest, C128Table[total_sum%103]);
- values[bar_characters] = total_sum % 103;
- bar_characters++;
-
- /* Stop character */
- concat(dest, C128Table[106]);
- values[bar_characters] = 106;
- bar_characters++;
- expand(symbol, dest);
-
- /* Add the separator pattern for composite symbols */
- if(symbol->symbology == BARCODE_EAN128_CC) {
- for(i = 0; i < symbol->width; i++) {
- if(!(module_is_set(symbol, separator_row + 1, i))) {
- set_module(symbol, separator_row, i);
- }
- }
- }
-
- for(i = 0; i < length; i++) {
- if((source[i] != '[') && (source[i] != ']')) {
- symbol->text[i] = source[i];
- }
- if(source[i] == '[') {
- symbol->text[i] = '(';
- }
- if(source[i] == ']') {
- symbol->text[i] = ')';
- }
- }
-
- return error_number;
+
+ expand(symbol, dest);
+
+ /* Add the separator pattern for composite symbols */
+ if (symbol->symbology == BARCODE_EAN128_CC) {
+ for (i = 0; i < symbol->width; i++) {
+ if (!(module_is_set(symbol, separator_row + 1, i))) {
+ set_module(symbol, separator_row, i);
+ }
+ }
+ }
+
+ for (i = 0; i < (int) length; i++) {
+ if ((source[i] != '[') && (source[i] != ']')) {
+ symbol->text[i] = source[i];
+ }
+ if (source[i] == '[') {
+ symbol->text[i] = '(';
+ }
+ if (source[i] == ']') {
+ symbol->text[i] = ')';
+ }
+ }
+
+ return error_number;
}
-int nve_18(struct zint_symbol *symbol, unsigned char source[], int length)
-{
- /* Add check digit if encoding an NVE18 symbol */
- int error_number, zeroes, i, nve_check, total_sum, sourcelen;
- unsigned char ean128_equiv[25];
-
- memset(ean128_equiv, 0, 25);
- sourcelen = length;
-
- if(sourcelen > 17) {
- strcpy(symbol->errtxt, "Input too long");
- return ERROR_TOO_LONG;
- }
-
- error_number = is_sane(NEON, source, length);
- if(error_number == ERROR_INVALID_DATA) {
- strcpy(symbol->errtxt, "Invalid characters in data");
- return error_number;
- }
- zeroes = 17 - sourcelen;
- strcpy((char *)ean128_equiv, "[00]");
- memset(ean128_equiv + 4, '0', zeroes);
- strcpy((char*)ean128_equiv + 4 + zeroes, (char*)source);
-
- total_sum = 0;
- for(i = sourcelen - 1; i >= 0; i--)
- {
- total_sum += ctoi(source[i]);
-
- if(!(i & 1)) {
- total_sum += 2 * ctoi(source[i]);
- }
- }
- nve_check = 10 - total_sum % 10;
- if(nve_check == 10) { nve_check = 0; }
- ean128_equiv[21] = itoc(nve_check);
- ean128_equiv[22] = '\0';
-
- error_number = ean_128(symbol, ean128_equiv, ustrlen(ean128_equiv));
-
- return error_number;
+/* Add check digit if encoding an NVE18 symbol */
+INTERNAL int nve_18(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int error_number, zeroes, i, nve_check, total_sum, sourcelen;
+ unsigned char ean128_equiv[25];
+
+ memset(ean128_equiv, 0, 25);
+ sourcelen = length;
+
+ if (sourcelen > 17) {
+ strcpy(symbol->errtxt, "345: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "346: Invalid characters in data");
+ return error_number;
+ }
+ zeroes = 17 - sourcelen;
+ strcpy((char *) ean128_equiv, "[00]");
+ memset(ean128_equiv + 4, '0', zeroes);
+ strcpy((char*) ean128_equiv + 4 + zeroes, (char*) source);
+
+ total_sum = 0;
+ for (i = sourcelen - 1; i >= 0; i--) {
+ total_sum += ctoi(source[i]);
+
+ if (!(i & 1)) {
+ total_sum += 2 * ctoi(source[i]);
+ }
+ }
+ nve_check = 10 - total_sum % 10;
+ if (nve_check == 10) {
+ nve_check = 0;
+ }
+ ean128_equiv[21] = itoc(nve_check);
+ ean128_equiv[22] = '\0';
+
+ error_number = ean_128(symbol, ean128_equiv, ustrlen(ean128_equiv));
+
+ return error_number;
}
-int ean_14(struct zint_symbol *symbol, unsigned char source[], int length)
-{
- /* EAN-14 - A version of EAN-128 */
- int i, count, check_digit;
- int error_number, zeroes;
- unsigned char ean128_equiv[20];
-
- if(length > 13) {
- strcpy(symbol->errtxt, "Input wrong length");
- return ERROR_TOO_LONG;
- }
-
- error_number = is_sane(NEON, source, length);
- if(error_number == ERROR_INVALID_DATA) {
- strcpy(symbol->errtxt, "Invalid character in data");
- return error_number;
- }
-
- zeroes = 13 - length;
- strcpy((char*)ean128_equiv, "[01]");
- memset(ean128_equiv + 4, '0', zeroes);
- ustrcpy(ean128_equiv + 4 + zeroes, source);
-
- count = 0;
- for (i = length - 1; i >= 0; i--) {
- count += ctoi(source[i]);
-
- if (!(i & 1)) {
- count += 2 * ctoi(source[i]);
- }
- }
- check_digit = 10 - (count % 10);
- if (check_digit == 10) { check_digit = 0; }
- ean128_equiv[17] = itoc(check_digit);
- ean128_equiv[18] = '\0';
-
- error_number = ean_128(symbol, ean128_equiv, ustrlen(ean128_equiv));
-
- return error_number;
+/* EAN-14 - A version of EAN-128 */
+INTERNAL int ean_14(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int i, count, check_digit;
+ int error_number, zeroes;
+ unsigned char ean128_equiv[20];
+
+ if (length > 13) {
+ strcpy(symbol->errtxt, "347: Input wrong length");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ error_number = is_sane(NEON, source, length);
+ if (error_number == ZINT_ERROR_INVALID_DATA) {
+ strcpy(symbol->errtxt, "348: Invalid character in data");
+ return error_number;
+ }
+
+ zeroes = 13 - length;
+ strcpy((char*) ean128_equiv, "[01]");
+ memset(ean128_equiv + 4, '0', zeroes);
+ ustrcpy(ean128_equiv + 4 + zeroes, source);
+
+ count = 0;
+ for (i = length - 1; i >= 0; i--) {
+ count += ctoi(source[i]);
+
+ if (!(i & 1)) {
+ count += 2 * ctoi(source[i]);
+ }
+ }
+ check_digit = 10 - (count % 10);
+ if (check_digit == 10) {
+ check_digit = 0;
+ }
+ ean128_equiv[17] = itoc(check_digit);
+ ean128_equiv[18] = '\0';
+
+ error_number = ean_128(symbol, ean128_equiv, ustrlen(ean128_equiv));
+
+ return error_number;
}
diff --git a/backend/code128.h b/backend/code128.h
new file mode 100644
index 0000000..0b1f042
--- /dev/null
+++ b/backend/code128.h
@@ -0,0 +1,57 @@
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2020 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+#ifndef CODE128_H
+#define CODE128_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define C128_MAX 160
+
+#define SHIFTA 90
+#define LATCHA 91
+#define SHIFTB 92
+#define LATCHB 93
+#define SHIFTC 94
+#define LATCHC 95
+#define AORB 96
+#define ABORC 97
+
+INTERNAL int parunmodd(const unsigned char llyth);
+INTERNAL void dxsmooth(int list[2][C128_MAX], int *indexliste);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CODE128_H */
diff --git a/backend/code16k.c b/backend/code16k.c
new file mode 100644
index 0000000..c7394c5
--- /dev/null
+++ b/backend/code16k.c
@@ -0,0 +1,504 @@
+/* code16k.c - Handles Code 16k stacked symbology */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2008 - 2020 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+/* Updated to comply with BS EN 12323:2005 */
+
+/* Code 16k can hold up to 77 characters or 154 numbers */
+
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include "common.h"
+#include "code128.h"
+
+static const char *C16KTable[107] = {
+ /* EN 12323 Table 1 - "Code 16K" character encodations */
+ "212222", "222122", "222221", "121223", "121322", "131222", "122213",
+ "122312", "132212", "221213", "221312", "231212", "112232", "122132", "122231", "113222",
+ "123122", "123221", "223211", "221132", "221231", "213212", "223112", "312131", "311222",
+ "321122", "321221", "312212", "322112", "322211", "212123", "212321", "232121", "111323",
+ "131123", "131321", "112313", "132113", "132311", "211313", "231113", "231311", "112133",
+ "112331", "132131", "113123", "113321", "133121", "313121", "211331", "231131", "213113",
+ "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111", "314111",
+ "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214",
+ "112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112",
+ "134111", "111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112",
+ "421211", "212141", "214121", "412121", "111143", "111341", "131141", "114113", "114311",
+ "411113", "411311", "113141", "114131", "311141", "411131", "211412", "211214", "211232",
+ "211133"
+};
+
+
+static const char *C16KStartStop[8] = {
+ /* EN 12323 Table 3 and Table 4 - Start patterns and stop patterns */
+ "3211", "2221", "2122", "1411", "1132", "1231", "1114", "3112"
+};
+
+/* EN 12323 Table 5 - Start and stop values defining row numbers */
+static const int C16KStartValues[16] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7
+};
+
+static const int C16KStopValues[16] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 0, 1, 2, 3
+};
+
+static void c16k_set_a(const unsigned char source, int values[], int *bar_chars) {
+ if (source > 127) {
+ if (source < 160) {
+ values[(*bar_chars)] = source + 64 - 128;
+ } else {
+ values[(*bar_chars)] = source - 32 - 128;
+ }
+ } else {
+ if (source < 32) {
+ values[(*bar_chars)] = source + 64;
+ } else {
+ values[(*bar_chars)] = source - 32;
+ }
+ }
+ (*bar_chars)++;
+}
+
+static void c16k_set_b(const unsigned char source, int values[], int *bar_chars) {
+ if (source > 127) {
+ values[(*bar_chars)] = source - 32 - 128;
+ } else {
+ values[(*bar_chars)] = source - 32;
+ }
+ (*bar_chars)++;
+}
+
+static void c16k_set_c(const unsigned char source_a, unsigned char source_b, int values[], int *bar_chars) {
+ int weight;
+
+ weight = (10 * ctoi(source_a)) + ctoi(source_b);
+ values[(*bar_chars)] = weight;
+ (*bar_chars)++;
+}
+
+INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], const size_t length) {
+ char width_pattern[100];
+ int current_row, rows_needed, looper, first_check, second_check;
+ int indexchaine;
+ int list[2][C128_MAX] = {{0}};
+ char set[C128_MAX] = {0}, fset[C128_MAX], mode, last_set, current_set;
+ int pads_needed, indexliste, i, j, m, read, mx_reader;
+ int values[C128_MAX] = {0};
+ int bar_characters;
+ float glyph_count;
+ int errornum, first_sum, second_sum;
+ int input_length;
+ int gs1, c_count;
+
+ /* Suppresses clang-analyzer-core.UndefinedBinaryOperatorResult warning on fset which is fully set */
+ assert(length > 0);
+
+ errornum = 0;
+ strcpy(width_pattern, "");
+ input_length = length;
+
+ if ((symbol->input_mode & 0x07) == GS1_MODE) {
+ gs1 = 1;
+ } else {
+ gs1 = 0;
+ }
+
+ if (input_length > C128_MAX) {
+ strcpy(symbol->errtxt, "420: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ bar_characters = 0;
+
+ /* Detect extended ASCII characters */
+ for (i = 0; i < input_length; i++) {
+ fset[i] = source[i] >= 128 ? 'f' : ' ';
+ }
+ /* Note to be safe not using extended ASCII latch as not mentioned in BS EN 12323:2005 */
+
+ /* Detect mode A, B and C characters */
+ indexliste = 0;
+ indexchaine = 0;
+
+ mode = parunmodd(source[indexchaine]);
+ if ((gs1) && (source[indexchaine] == '[')) {
+ mode = ABORC;
+ } /* FNC1 */
+
+ do {
+ list[1][indexliste] = mode;
+ while ((list[1][indexliste] == mode) && (indexchaine < input_length)) {
+ list[0][indexliste]++;
+ indexchaine++;
+ if (indexchaine == input_length) {
+ break;
+ }
+ mode = parunmodd(source[indexchaine]);
+ if ((gs1) && (source[indexchaine] == '[')) {
+ mode = ABORC;
+ } /* FNC1 */
+ }
+ indexliste++;
+ } while (indexchaine < input_length);
+
+ dxsmooth(list, &indexliste);
+
+ /* Put set data into set[] */
+ read = 0;
+ for (i = 0; i < indexliste; i++) {
+ for (j = 0; j < list[0][i]; j++) {
+ switch (list[1][i]) {
+ case SHIFTA: set[read] = 'a';
+ break;
+ case LATCHA: set[read] = 'A';
+ break;
+ case SHIFTB: set[read] = 'b';
+ break;
+ case LATCHB: set[read] = 'B';
+ break;
+ case LATCHC: set[read] = 'C';
+ break;
+ }
+ read++;
+ }
+ }
+
+ /* Watch out for odd-length Mode C blocks */
+ c_count = 0;
+ for (i = 0; i < read; i++) {
+ if (set[i] == 'C') {
+ if (source[i] == '[') {
+ if (c_count & 1) {
+ if ((i - c_count) != 0) {
+ set[i - c_count] = 'B';
+ } else {
+ set[i - 1] = 'B';
+ }
+ }
+ c_count = 0;
+ } else {
+ c_count++;
+ }
+ } else {
+ if (c_count & 1) {
+ if ((i - c_count) != 0) {
+ set[i - c_count] = 'B';
+ } else {
+ set[i - 1] = 'B';
+ }
+ }
+ c_count = 0;
+ }
+ }
+ if (c_count & 1) {
+ if ((i - c_count) != 0) {
+ set[i - c_count] = 'B';
+ } else {
+ set[i - 1] = 'B';
+ }
+ }
+ for (i = 1; i < read - 1; i++) {
+ if ((set[i] == 'C') && ((set[i - 1] == 'B') && (set[i + 1] == 'B'))) {
+ set[i] = 'B';
+ }
+ }
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Data: %.*s\n", input_length, source);
+ printf(" Set: %.*s\n", input_length, set);
+ printf("FSet: %.*s\n", input_length, fset);
+ }
+
+ /* Make sure the data will fit in the symbol */
+ last_set = set[0];
+ glyph_count = 0.0;
+ for (i = 0; i < input_length; i++) {
+ if ((set[i] == 'a') || (set[i] == 'b')) {
+ glyph_count = glyph_count + 1.0;
+ }
+ if (fset[i] == 'f') {
+ glyph_count = glyph_count + 1.0;
+ }
+ if (((set[i] == 'A') || (set[i] == 'B')) || (set[i] == 'C')) {
+ if (set[i] != last_set) {
+ last_set = set[i];
+ glyph_count = glyph_count + 1.0;
+ }
+ }
+ if (i == 0) {
+ if ((set[i] == 'B') && (set[1] == 'C')) {
+ glyph_count = glyph_count - 1.0;
+ }
+ if ((set[i] == 'B') && (set[1] == 'B')) {
+ if (set[2] == 'C') {
+ glyph_count = glyph_count - 1.0;
+ }
+ }
+ }
+
+ if ((set[i] == 'C') && (!((gs1) && (source[i] == '[')))) {
+ glyph_count = glyph_count + 0.5;
+ } else {
+ glyph_count = glyph_count + 1.0;
+ }
+ }
+
+ if ((gs1) && (set[0] != 'A')) {
+ /* FNC1 can be integrated with mode character */
+ glyph_count--;
+ }
+
+ if (glyph_count > 77.0) {
+ strcpy(symbol->errtxt, "421: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* Calculate how tall the symbol will be */
+ glyph_count = glyph_count + 2.0;
+ i = (int)glyph_count;
+ rows_needed = (i / 5);
+ if (i % 5 > 0) {
+ rows_needed++;
+ }
+
+ if (rows_needed == 1) {
+ rows_needed = 2;
+ }
+
+ /* start with the mode character - Table 2 */
+ m = 0;
+ switch (set[0]) {
+ case 'A': m = 0;
+ break;
+ case 'B': m = 1;
+ break;
+ case 'C': m = 2;
+ break;
+ }
+
+ if (symbol->output_options & READER_INIT) {
+ if (m == 2) {
+ m = 5;
+ }
+ if (gs1) {
+ strcpy(symbol->errtxt, "422: Cannot use both GS1 mode and Reader Initialisation");
+ return ZINT_ERROR_INVALID_OPTION;
+ } else {
+ if ((set[0] == 'B') && (set[1] == 'C')) {
+ m = 6;
+ }
+ }
+ values[bar_characters] = (7 * (rows_needed - 2)) + m; /* see 4.3.4.2 */
+ values[bar_characters + 1] = 96; /* FNC3 */
+ bar_characters += 2;
+ } else {
+ if (gs1) {
+ /* Integrate FNC1 */
+ switch (set[0]) {
+ case 'B': m = 3;
+ break;
+ case 'C': m = 4;
+ break;
+ }
+ } else {
+ if ((set[0] == 'B') && (set[1] == 'C')) {
+ m = 5;
+ }
+ if (((set[0] == 'B') && (set[1] == 'B')) && (set[2] == 'C')) {
+ m = 6;
+ }
+ }
+ values[bar_characters] = (7 * (rows_needed - 2)) + m; /* see 4.3.4.2 */
+ bar_characters++;
+ }
+
+ current_set = set[0];
+ read = 0;
+
+ /* Encode the data */
+ do {
+
+ if ((read != 0) && (set[read] != set[read - 1])) {
+ /* Latch different code set */
+ switch (set[read]) {
+ case 'A':
+ values[bar_characters] = 101;
+ bar_characters++;
+ current_set = 'A';
+ break;
+ case 'B':
+ values[bar_characters] = 100;
+ bar_characters++;
+ current_set = 'B';
+ break;
+ case 'C':
+ if (!((read == 1) && (set[0] == 'B'))) {
+ /* Not Mode C/Shift B */
+ if (!((read == 2) && ((set[0] == 'B') && (set[1] == 'B')))) {
+ /* Not Mode C/Double Shift B */
+ values[bar_characters] = 99;
+ bar_characters++;
+ }
+ }
+ current_set = 'C';
+ break;
+ }
+ }
+
+ if (fset[read] == 'f') {
+ /* Shift extended mode */
+ switch (current_set) {
+ case 'A':
+ values[bar_characters] = 101; /* FNC 4 */
+ break;
+ case 'B':
+ values[bar_characters] = 100; /* FNC 4 */
+ break;
+ }
+ bar_characters++;
+ }
+
+ if ((set[read] == 'a') || (set[read] == 'b')) {
+ /* Insert shift character */
+ values[bar_characters] = 98;
+ bar_characters++;
+ }
+
+ if (!((gs1) && (source[read] == '['))) {
+ switch (set[read]) { /* Encode data characters */
+ case 'A':
+ case 'a':
+ c16k_set_a(source[read], values, &bar_characters);
+ read++;
+ break;
+ case 'B':
+ case 'b':
+ c16k_set_b(source[read], values, &bar_characters);
+ read++;
+ break;
+ case 'C': c16k_set_c(source[read], source[read + 1], values, &bar_characters);
+ read += 2;
+ break;
+ }
+ } else {
+ values[bar_characters] = 102;
+ bar_characters++;
+ read++;
+ }
+ } while (read < input_length);
+
+ pads_needed = 5 - ((bar_characters + 2) % 5);
+ if (pads_needed == 5) {
+ pads_needed = 0;
+ }
+ if ((bar_characters + pads_needed) < 8) {
+ pads_needed += 8 - (bar_characters + pads_needed);
+ }
+ for (i = 0; i < pads_needed; i++) {
+ values[bar_characters] = 103;
+ bar_characters++;
+ }
+
+ /* Calculate check digits */
+ first_sum = 0;
+ second_sum = 0;
+ for (i = 0; i < bar_characters; i++) {
+ first_sum += (i + 2) * values[i];
+ second_sum += (i + 1) * values[i];
+ }
+ first_check = first_sum % 107;
+ second_sum += first_check * (bar_characters + 1);
+ second_check = second_sum % 107;
+ values[bar_characters] = first_check;
+ values[bar_characters + 1] = second_check;
+ bar_characters += 2;
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Codewords:");
+ for (i = 0; i < bar_characters; i++) {
+ printf(" %d", values[i]);
+ }
+ printf("\n");
+ }
+#ifdef ZINT_TEST
+ if (symbol->debug & ZINT_DEBUG_TEST) {
+ debug_test_codeword_dump_int(symbol, values, bar_characters); /* Missing row start/stop */
+ }
+#endif
+
+ for (current_row = 0; current_row < rows_needed; current_row++) {
+ int writer;
+ int flip_flop;
+ int len;
+
+ strcpy(width_pattern, "");
+ strcat(width_pattern, C16KStartStop[C16KStartValues[current_row]]);
+ strcat(width_pattern, "1");
+ for (i = 0; i < 5; i++) {
+ strcat(width_pattern, C16KTable[values[(current_row * 5) + i]]);
+ }
+ strcat(width_pattern, C16KStartStop[C16KStopValues[current_row]]);
+
+ /* Write the information into the symbol */
+ writer = 0;
+ flip_flop = 1;
+ for (mx_reader = 0, len = strlen(width_pattern); mx_reader < len; mx_reader++) {
+ for (looper = 0; looper < ctoi(width_pattern[mx_reader]); looper++) {
+ if (flip_flop == 1) {
+ set_module(symbol, current_row, writer);
+ writer++;
+ } else {
+ writer++;
+ }
+ }
+ if (flip_flop == 0) {
+ flip_flop = 1;
+ } else {
+ flip_flop = 0;
+ }
+ }
+ symbol->row_height[current_row] = 10;
+ }
+
+ symbol->rows = rows_needed;
+ symbol->width = 70;
+
+ symbol->output_options |= BARCODE_BIND;
+
+ if (symbol->border_width == 0) { /* Allow override if non-zero */
+ symbol->border_width = 1; /* BS EN 12323:2005 Section 4.3.7 minimum (note change from previous default 2) */
+ }
+
+ return errornum;
+}
diff --git a/backend/code49.c b/backend/code49.c
new file mode 100644
index 0000000..3d7aebf
--- /dev/null
+++ b/backend/code49.c
@@ -0,0 +1,361 @@
+/* code49.c - Handles Code 49 */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2009 - 2020 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+#include <string.h>
+#include <stdio.h>
+#include "common.h"
+#include "code49.h"
+
+#define INSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%!&*"
+
+/* "!" represents Shift 1 and "&" represents Shift 2, "*" represents FNC1 */
+
+INTERNAL int code_49(struct zint_symbol *symbol, unsigned char source[], const int length) {
+ int i, j, rows, M, x_count, y_count, z_count, posn_val, local_value;
+ char intermediate[170] = "";
+ int codewords[170], codeword_count;
+ int c_grid[8][8]; /* Refers to table 3 */
+ int w_grid[8][4]; /* Refets to table 2 */
+ int pad_count = 0;
+ char pattern[80];
+ int gs1;
+ int h, len;
+
+ if (length > 81) {
+ strcpy(symbol->errtxt, "430: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ if ((symbol->input_mode & 0x07) == GS1_MODE) {
+ gs1 = 1;
+ strcpy(intermediate, "*"); /* FNC1 */
+ } else {
+ gs1 = 0;
+ }
+
+ for (i = 0; i < length; i++) {
+ if (source[i] > 127) {
+ strcpy(symbol->errtxt, "431: Invalid characters in input data");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ if (gs1 && (source[i] == '['))
+ strcat(intermediate, "*"); /* FNC1 */
+ else
+ strcat(intermediate, c49_table7[source[i]]);
+ }
+
+ codeword_count = 0;
+ i = 0;
+ h = strlen(intermediate);
+ do {
+ if ((intermediate[i] >= '0') && (intermediate[i] <= '9')) {
+ /* Numeric data */
+ for (j = 0; (intermediate[i + j] >= '0') && (intermediate[i + j] <= '9'); j++);
+ if (j >= 5) {
+ /* Use Numeric Encodation Method */
+ int block_count, c;
+ int block_remain;
+ int block_value;
+
+ codewords[codeword_count] = 48; /* Numeric Shift */
+ codeword_count++;
+
+ block_count = j / 5;
+ block_remain = j % 5;
+
+ for (c = 0; c < block_count; c++) {
+ if ((c == block_count - 1) && (block_remain == 2)) {
+ /* Rule (d) */
+ block_value = 100000;
+ block_value += ctoi(intermediate[i]) * 1000;
+ block_value += ctoi(intermediate[i + 1]) * 100;
+ block_value += ctoi(intermediate[i + 2]) * 10;
+ block_value += ctoi(intermediate[i + 3]);
+
+ codewords[codeword_count] = block_value / (48 * 48);
+ block_value = block_value - (48 * 48) * codewords[codeword_count];
+ codeword_count++;
+ codewords[codeword_count] = block_value / 48;
+ block_value = block_value - 48 * codewords[codeword_count];
+ codeword_count++;
+ codewords[codeword_count] = block_value;
+ codeword_count++;
+ i += 4;
+ block_value = ctoi(intermediate[i]) * 100;
+ block_value += ctoi(intermediate[i + 1]) * 10;
+ block_value += ctoi(intermediate[i + 2]);
+
+ codewords[codeword_count] = block_value / 48;
+ block_value = block_value - 48 * codewords[codeword_count];
+ codeword_count++;
+ codewords[codeword_count] = block_value;
+ codeword_count++;
+ i += 3;
+ } else {
+ block_value = ctoi(intermediate[i]) * 10000;
+ block_value += ctoi(intermediate[i + 1]) * 1000;
+ block_value += ctoi(intermediate[i + 2]) * 100;
+ block_value += ctoi(intermediate[i + 3]) * 10;
+ block_value += ctoi(intermediate[i + 4]);
+
+ codewords[codeword_count] = block_value / (48 * 48);
+ block_value = block_value - (48 * 48) * codewords[codeword_count];
+ codeword_count++;
+ codewords[codeword_count] = block_value / 48;
+ block_value = block_value - 48 * codewords[codeword_count];
+ codeword_count++;
+ codewords[codeword_count] = block_value;
+ codeword_count++;
+ i += 5;
+ }
+ }
+
+ switch (block_remain) {
+ case 1:
+ /* Rule (a) */
+ codewords[codeword_count] = posn(INSET, intermediate[i]);
+ codeword_count++;
+ i++;
+ break;
+ case 3:
+ /* Rule (b) */
+ block_value = ctoi(intermediate[i]) * 100;
+ block_value += ctoi(intermediate[i + 1]) * 10;
+ block_value += ctoi(intermediate[i + 2]);
+
+ codewords[codeword_count] = block_value / 48;
+ block_value = block_value - 48 * codewords[codeword_count];
+ codeword_count++;
+ codewords[codeword_count] = block_value;
+ codeword_count++;
+ i += 3;
+ break;
+ case 4:
+ /* Rule (c) */
+ block_value = 100000;
+ block_value += ctoi(intermediate[i]) * 1000;
+ block_value += ctoi(intermediate[i + 1]) * 100;
+ block_value += ctoi(intermediate[i + 2]) * 10;
+ block_value += ctoi(intermediate[i + 3]);
+
+ codewords[codeword_count] = block_value / (48 * 48);
+ block_value = block_value - (48 * 48) * codewords[codeword_count];
+ codeword_count++;
+ codewords[codeword_count] = block_value / 48;
+ block_value = block_value - 48 * codewords[codeword_count];
+ codeword_count++;
+ codewords[codeword_count] = block_value;
+ codeword_count++;
+ i += 4;
+ break;
+ }
+ if (i < h) {
+ /* There is more to add */
+ codewords[codeword_count] = 48; /* Numeric Shift */
+ codeword_count++;
+ }
+ } else {
+ codewords[codeword_count] = posn(INSET, intermediate[i]);
+ codeword_count++;
+ i++;
+ }
+ } else {
+ codewords[codeword_count] = posn(INSET, intermediate[i]);
+ codeword_count++;
+ i++;
+ }
+ } while (i < h);
+
+ switch (codewords[0]) {
+ /* Set starting mode value */
+ case 48: M = 2;
+ break;
+ case 43: M = 4;
+ break;
+ case 44: M = 5;
+ break;
+ default: M = 0;
+ break;
+ }
+
+ if (M != 0) {
+ codeword_count--;
+ for (i = 0; i < codeword_count; i++) {
+ codewords[i] = codewords[i + 1];
+ }
+ }
+
+ if (codeword_count > 49) {
+ strcpy(symbol->errtxt, "432: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* Place codewords in code character array (c grid) */
+ rows = 0;
+ do {
+ for (i = 0; i < 7; i++) {
+ if (((rows * 7) + i) < codeword_count) {
+ c_grid[rows][i] = codewords[(rows * 7) + i];
+ } else {
+ c_grid[rows][i] = 48; /* Pad */
+ pad_count++;
+ }
+ }
+ rows++;
+ } while ((rows * 7) < codeword_count);
+
+ if ((((rows <= 6) && (pad_count < 5))) || (rows > 6) || (rows == 1)) {
+ /* Add a row */
+ for (i = 0; i < 7; i++) {
+ c_grid[rows][i] = 48; /* Pad */
+ }
+ rows++;
+ }
+
+ /* Add row count and mode character */
+ c_grid[rows - 1][6] = (7 * (rows - 2)) + M;
+
+ /* Add row check character */
+ for (i = 0; i < rows - 1; i++) {
+ int row_sum = 0;
+
+ for (j = 0; j < 7; j++) {
+ row_sum += c_grid[i][j];
+ }
+ c_grid[i][7] = row_sum % 49;
+ }
+
+ /* Calculate Symbol Check Characters */
+ posn_val = 0;
+ x_count = c_grid[rows - 1][6] * 20;
+ y_count = c_grid[rows - 1][6] * 16;
+ z_count = c_grid[rows - 1][6] * 38;
+ for (i = 0; i < rows - 1; i++) {
+ for (j = 0; j < 4; j++) {
+ local_value = (c_grid[i][2 * j] * 49) + c_grid[i][(2 * j) + 1];
+ x_count += c49_x_weight[posn_val] * local_value;
+ y_count += c49_y_weight[posn_val] * local_value;
+ z_count += c49_z_weight[posn_val] * local_value;
+ posn_val++;
+ }
+ }
+
+ if (rows > 6) {
+ /* Add Z Symbol Check */
+ c_grid[rows - 1][0] = (z_count % 2401) / 49;
+ c_grid[rows - 1][1] = (z_count % 2401) % 49;
+ }
+
+ local_value = (c_grid[rows - 1][0] * 49) + c_grid[rows - 1][1];
+ x_count += c49_x_weight[posn_val] * local_value;
+ y_count += c49_y_weight[posn_val] * local_value;
+ posn_val++;
+
+ /* Add Y Symbol Check */
+ c_grid[rows - 1][2] = (y_count % 2401) / 49;
+ c_grid[rows - 1][3] = (y_count % 2401) % 49;
+
+ local_value = (c_grid[rows - 1][2] * 49) + c_grid[rows - 1][3];
+ x_count += c49_x_weight[posn_val] * local_value;
+
+ /* Add X Symbol Check */
+ c_grid[rows - 1][4] = (x_count % 2401) / 49;
+ c_grid[rows - 1][5] = (x_count % 2401) % 49;
+
+ /* Add last row check character */
+ j = 0;
+ for (i = 0; i < 7; i++) {
+ j += c_grid[rows - 1][i];
+ }
+ c_grid[rows - 1][7] = j % 49;
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Codewords:\n");
+ for (i = 0; i < rows; i++) {
+ for (j = 0; j < 8; j++) {
+ printf(" %2d", c_grid[i][j]);
+ }
+ printf("\n");
+ }
+ }
+#ifdef ZINT_TEST
+ if (symbol->debug & ZINT_DEBUG_TEST) {
+ debug_test_codeword_dump_int(symbol, (int *)c_grid, rows * 8);
+ }
+#endif
+
+ /* Transfer data to symbol character array (w grid) */
+ for (i = 0; i < rows; i++) {
+ for (j = 0; j < 4; j++) {
+ w_grid[i][j] = (c_grid[i][2 * j] * 49) + c_grid[i][(2 * j) + 1];
+ }
+ }
+
+ for (i = 0; i < rows; i++) {
+ strcpy(pattern, "10"); /* Start character */
+ for (j = 0; j < 4; j++) {
+ if (i != (rows - 1)) {
+ if (c49_table4[i][j] == 'E') {
+ /* Even Parity */
+ bin_append(c49_even_bitpattern[w_grid[i][j]], 16, pattern);
+ } else {
+ /* Odd Parity */
+ bin_append(c49_odd_bitpattern[w_grid[i][j]], 16, pattern);
+ }
+ } else {
+ /* Last row uses all even parity */
+ bin_append(c49_even_bitpattern[w_grid[i][j]], 16, pattern);
+ }
+ }
+ strcat(pattern, "1111"); /* Stop character */
+
+ /* Expand into symbol */
+ symbol->row_height[i] = 10;
+
+ for (j = 0, len = strlen(pattern); j < len; j++) {
+ if (pattern[j] == '1') {
+ set_module(symbol, i, j);
+ }
+ }
+ }
+
+ symbol->rows = rows;
+ symbol->width = strlen(pattern);
+
+ symbol->output_options |= BARCODE_BIND;
+
+ if (symbol->border_width == 0) { /* Allow override if non-zero */
+ symbol->border_width = 1; /* ANSI/AIM BC6-2000 Section 2.1 (note change from previous default 2) */
+ }
+
+ return 0;
+}
diff --git a/backend/code49.h b/backend/code49.h
new file mode 100644
index 0000000..01dec46
--- /dev/null
+++ b/backend/code49.h
@@ -0,0 +1,558 @@
+/* code49.h - Code 49 Tables */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2009-2017 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+
+/* This data set taken from ANSI/AIM-BC6-2000, 4th April 2000 */
+
+static const char *c49_table7[128] = {
+ /* Table 7: Code 49 ASCII Chart */
+ "! ", "!A", "!B", "!C", "!D", "!E", "!F", "!G", "!H", "!I", "!J", "!K", "!L",
+ "!M", "!N", "!O", "!P", "!Q", "!R", "!S", "!T", "!U", "!V", "!W", "!X", "!Y",
+ "!Z", "!1", "!2", "!3", "!4", "!5", " ", "!6", "!7", "!8", "$", "%", "!9", "!0",
+ "!-", "!.", "!$", "+", "!/", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6",
+ "7", "8", "9", "!+", "&1", "&2", "&3", "&4", "&5", "&6", "A", "B", "C", "D", "E",
+ "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
+ "V", "W", "X", "Y", "Z", "&7", "&8", "&9", "&0", "&-", "&.", "&A", "&B", "&C",
+ "&D", "&E", "&F", "&G", "&H", "&I", "&J", "&K", "&L", "&M", "&N", "&O", "&P",
+ "&Q", "&R", "&S", "&T", "&U", "&V", "&W", "&X", "&Y", "&Z", "&$", "&/", "&+",
+ "&%", "& "
+};
+
+/* Table 5: Check Character Weighting Values */
+static const char c49_x_weight[] = {
+ 1, 9, 31, 26, 2, 12, 17, 23, 37, 18, 22, 6, 27, 44, 15, 43,
+ 39, 11, 13, 5, 41, 33, 36, 8, 4, 32, 3, 19, 40, 25, 29, 10
+};
+
+static const char c49_y_weight[] = {
+ 9, 31, 26, 2, 12, 17, 23, 37, 18, 22, 6, 27, 44, 15, 43, 39,
+ 11, 13, 5, 41, 33, 36, 8, 4, 32, 3, 19, 40, 25, 29, 10, 24
+};
+
+static const char c49_z_weight[] = {
+ 31, 26, 2, 12, 17, 23, 37, 18, 22, 6, 27, 44, 15, 43, 39, 11,
+ 13, 5, 41, 33, 36, 8, 4, 32, 3, 19, 40, 25, 29, 10, 24, 30
+};
+
+static const char *c49_table4[8] = {
+ /* Table 4: Row Parity Pattern for Code 49 Symbols */
+ "OEEO", "EOEO", "OOEE", "EEOO", "OEOE", "EOOE", "OOOO", "EEEE"
+};
+
+static const unsigned short int c49_even_bitpattern[] = {
+ /* Appendix E - Code 49 Encodation Patterns (Even Symbol Character Parity) */
+ 0xBE5C, 0xC16E, 0x86DC, 0xC126, 0x864C, 0x9EDC, 0xC726, 0x9E4C, 0xDF26, 0x82CC,
+ 0x8244, 0x8ECC, 0xC322, 0x8E44, 0xBECC, 0xCF22, 0xBE44, 0xC162, 0x86C4, 0xC762,
+ 0x9EC4, 0xDF62, 0x812E, 0x872E, 0x9F2E, 0x836E, 0x8326, 0x8F6E, 0x8F26, 0xBF6E,
+ 0x8166, 0x8122, 0x8766, 0x8722, 0x9F66, 0x9F22, 0x8362, 0x8F62, 0xBF62, 0xA2E0,
+ 0xE8B8, 0xFA2E, 0xD370, 0xF4DC, 0xD130, 0xF44C, 0xAEE0, 0xEBB8, 0xFAEE, 0xA660,
+ 0xE998, 0xFA66, 0xA220, 0xE888, 0xFA22, 0xD730, 0xF5CC, 0xD310, 0xF4C4, 0xAE20,
+ 0xEB88, 0xFAE2, 0x9170, 0xE45C, 0xD8B8, 0xF62E, 0xC9B8, 0xF26E, 0xB370, 0xC898,
+ 0xF226, 0xB130, 0xEC4C, 0x9770, 0xE5DC, 0x9330, 0xE4CC, 0x9110, 0xE444, 0xD888,
+ 0xF622, 0xCB98, 0xF2E6, 0xB730, 0xC988, 0xF262, 0xB310, 0xECC4, 0x9710, 0xE5C4,
+ 0xDB88, 0xF6E2, 0x88B8, 0xE22E, 0xCC5C, 0xB8B8, 0xEE2E, 0xC4DC, 0x99B8, 0xC44C,
+ 0x9898, 0xE626, 0xDC4C, 0x8BB8, 0xE2EE, 0x8998, 0xE266, 0xBBB8, 0x8888, 0xE222,
+ 0xB998, 0xCC44, 0xB888, 0xEE22, 0xC5CC, 0x9B98, 0xC4C4, 0x9988, 0xE662, 0xDCC4,
+ 0x8B88, 0xE2E2, 0xCDC4, 0xBB88, 0xEEE2, 0x845C, 0xC62E, 0x9C5C, 0xDE2E, 0xC26E,
+ 0x8CDC, 0xC226, 0x8C4C, 0xBCDC, 0xCE26, 0xBC4C, 0x85DC, 0x84CC, 0x9DDC, 0x8444,
+ 0x9CCC, 0xC622, 0x9C44, 0xDE22, 0xC2E6, 0x8DCC, 0xC262, 0x8CC4, 0xBDCC, 0xCE62,
+ 0xBCC4, 0x85C4, 0xC6E2, 0x9DC4, 0xDEE2, 0x822E, 0x8E2E, 0x866E, 0x8626, 0x9E6E,
+ 0x9E26, 0x82EE, 0x8266, 0x8EEE, 0x8222, 0x8E66, 0xBEEE, 0x8E22, 0xBE66, 0x86E6,
+ 0x8662, 0x9EE6, 0x9E62, 0x82E2, 0x8EE2, 0xBEE2, 0xA170, 0xE85C, 0xD1B8, 0xF46E,
+ 0xD098, 0xF426, 0xA770, 0xE9DC, 0xA330, 0xE8CC, 0xA110, 0xE844, 0xD7B8, 0xF5EE,
+ 0xD398, 0xF4E6, 0xD188, 0xF462, 0xAF30, 0xEBCC, 0xA710, 0xE9C4, 0xD788, 0xF5E2,
+ 0x90B8, 0xE42E, 0xD85C, 0xC8DC, 0xB1B8, 0xC84C, 0xB098, 0xEC26, 0x93B8, 0xE4EE,
+ 0x9198, 0xE466, 0x9088, 0xE422, 0xD844, 0xCBDC, 0xB7B8, 0xC9CC, 0xB398, 0xC8C4,
+ 0xB188, 0xEC62, 0x9798, 0xE5E6, 0x9388, 0xE4E2, 0xD9C4, 0xCBC4, 0xB788, 0xEDE2,
+ 0x885C, 0xCC2E, 0xB85C, 0xC46E, 0x98DC, 0xC426, 0x984C, 0xDC26, 0x89DC, 0x88CC,
+ 0xB9DC, 0x8844, 0xB8CC, 0xCC22, 0xB844, 0xC5EE, 0x9BDC, 0xC4E6, 0x99CC, 0xC462,
+ 0x98C4, 0xDC62, 0x8BCC, 0x89C4, 0xBBCC, 0xCCE2, 0xB9C4, 0xC5E2, 0x9BC4, 0xDDE2,
+ 0x842E, 0x9C2E, 0x8C6E, 0x8C26, 0xBC6E, 0x84EE, 0x8466, 0x9CEE, 0x8422, 0x9C66,
+ 0x9C22, 0x8DEE, 0x8CE6, 0xBDEE, 0x8C62, 0xBCE6, 0xBC62, 0x85E6, 0x84E2, 0x9DE6,
+ 0x9CE2, 0x8DE2, 0xBDE2, 0xA0B8, 0xE82E, 0xD0DC, 0xD04C, 0xA3B8, 0xE8EE, 0xA198,
+ 0xE866, 0xA088, 0xE822, 0xD3DC, 0xD1CC, 0xD0C4, 0xAFB8, 0xEBEE, 0xA798, 0xE9E6,
+ 0xA388, 0xE8E2, 0xD7CC, 0xD3C4, 0x905C, 0xD82E, 0xC86E, 0xB0DC, 0xC826, 0xB04C,
+ 0x91DC, 0x90CC, 0x9044, 0xD822, 0xC9EE, 0xB3DC, 0xC8E6, 0xB1CC, 0xC862, 0xB0C4,
+ 0x97DC, 0x93CC, 0x91C4, 0xD8E2, 0xCBE6, 0xB7CC, 0xC9E2, 0xB3C4, 0x882E, 0x986E,
+ 0x9826, 0x88EE, 0x8866, 0xB8EE, 0x8822, 0xB866, 0x99EE, 0x98E6, 0x9862, 0x8BEE,
+ 0x89E6, 0xBBEE, 0x88E2, 0xB9E6, 0xB8E2, 0x9BE6, 0x99E2, 0xA05C, 0xD06E, 0xD026,
+ 0xA1DC, 0xA0CC, 0xA044, 0xD1EE, 0xD0E6, 0xD062, 0xA7DC, 0xA3CC, 0xA1C4, 0xD7EE,
+ 0xD3E6, 0xD1E2, 0x902E, 0xB06E, 0x90EE, 0x9066, 0x9022, 0xB1EE, 0xB0E6, 0xB062,
+ 0x93EE, 0x91E6, 0x90E2, 0xB7EE, 0xB3E6, 0xB1E2, 0xA9C0, 0xEA70, 0xFA9C, 0xD460,
+ 0xF518, 0xFD46, 0xA840, 0xEA10, 0xFA84, 0xED78, 0xFB5E, 0x94E0, 0xE538, 0xF94E,
+ 0xDA70, 0xF69C, 0xCA30, 0xF28C, 0xB460, 0xED18, 0xFB46, 0x9420, 0xE508, 0xF942,
+ 0xDA10, 0xF684, 0x9AF0, 0xE6BC, 0xDD78, 0xF75E, 0x8A70, 0xE29C, 0xCD38, 0xF34E,
+ 0xBA70, 0xEE9C, 0xC518, 0xF146, 0x9A30, 0xE68C, 0xDD18, 0xF746, 0x8A10, 0xE284,
+ 0xCD08, 0xF342, 0xBA10, 0xEE84, 0x8D78, 0xE35E, 0xCEBC, 0xBD78, 0xEF5E, 0x8538,
+ 0xE14E, 0xC69C, 0x9D38, 0xE74E, 0xDE9C, 0xC28C, 0x8D18, 0xE346, 0xCE8C, 0xBD18,
+ 0xEF46, 0x8508, 0xE142, 0xC684, 0x9D08, 0xE742, 0xDE84, 0x86BC, 0xC75E, 0x9EBC,
+ 0xDF5E, 0x829C, 0xC34E, 0x8E9C, 0xCF4E, 0xBE9C, 0xC146, 0x868C, 0xC746, 0x9E8C,
+ 0xDF46, 0x8284, 0xC342, 0x8E84, 0xCF42, 0xBE84, 0x835E, 0x8F5E, 0xBF5E, 0x814E,
+ 0x874E, 0x9F4E, 0x8346, 0x8F46, 0xBF46, 0x8142, 0x8742, 0x9F42, 0xD2F0, 0xF4BC,
+ 0xADE0, 0xEB78, 0xFADE, 0xA4E0, 0xE938, 0xFA4E, 0xD670, 0xF59C, 0xD230, 0xF48C,
+ 0xAC60, 0xEB18, 0xFAC6, 0xA420, 0xE908, 0xFA42, 0xD610, 0xF584, 0xC978, 0xF25E,
+ 0xB2F0, 0xECBC, 0x96F0, 0xE5BC, 0x9270, 0xE49C, 0xD938, 0xF64E, 0xCB38, 0xF2CE,
+ 0xB670, 0xC918, 0xF246, 0xB230, 0xEC8C, 0x9630, 0xE58C, 0x9210, 0xE484, 0xD908,
+ 0xF642, 0xCB08, 0xF2C2, 0xB610, 0xED84, 0xC4BC, 0x9978, 0xE65E, 0xDCBC, 0x8B78,
+ 0xE2DE, 0x8938, 0xE24E, 0xBB78, 0xCC9C, 0xB938, 0xEE4E, 0xC59C, 0x9B38, 0xC48C,
+ 0x9918, 0xE646, 0xDC8C, 0x8B18, 0xE2C6, 0x8908, 0xE242, 0xBB18, 0xCC84, 0xB908,
+ 0xEE42, 0xC584, 0x9B08, 0xE6C2, 0xDD84, 0xC25E, 0x8CBC, 0xCE5E, 0xBCBC, 0x85BC,
+ 0x849C, 0x9DBC, 0xC64E, 0x9C9C, 0xDE4E, 0xC2CE, 0x8D9C, 0xC246, 0x8C8C, 0xBD9C,
+ 0xCE46, 0xBC8C, 0x858C, 0x8484, 0x9D8C, 0xC642, 0x9C84, 0xDE42, 0xC2C2, 0x8D84,
+ 0xCEC2, 0xBD84, 0x865E, 0x9E5E, 0x82DE, 0x824E, 0x8EDE, 0x8E4E, 0xBEDE, 0xBE4E,
+ 0x86CE, 0x8646, 0x9ECE, 0x9E46, 0x82C6, 0x8242, 0x8EC6, 0x8E42, 0xBEC6, 0xBE42,
+ 0x86C2, 0x9EC2, 0xD178, 0xF45E, 0xA6F0, 0xE9BC, 0xA270, 0xE89C, 0xD778, 0xF5DE,
+ 0xD338, 0xF4CE, 0xD118, 0xF446, 0xAE70, 0xEB9C, 0xA630, 0xE98C, 0xA210, 0xE884,
+ 0xD718, 0xF5C6, 0xD308, 0xF4C2, 0xAE10, 0xEB84, 0xC8BC, 0xB178, 0xEC5E, 0x9378,
+ 0xE4DE, 0x9138, 0xE44E, 0xD89C, 0xCBBC, 0xB778, 0xC99C, 0xB338, 0xC88C, 0xB118,
+ 0xEC46, 0x9738, 0xE5CE, 0x9318, 0xE4C6, 0x9108, 0xE442, 0xD884, 0xCB8C, 0xB718,
+ 0xC984, 0xB308, 0xECC2, 0x9708, 0xE5C2, 0xDB84, 0xC45E, 0x98BC, 0xDC5E, 0x89BC,
+ 0x889C, 0xB9BC, 0xCC4E, 0xB89C, 0xC5DE, 0x9BBC, 0xC4CE, 0x999C, 0xC446, 0x988C,
+ 0xDC46, 0x8B9C, 0x898C, 0xBB9C, 0x8884, 0xB98C, 0xCC42, 0xB884, 0xC5C6, 0x9B8C,
+ 0xC4C2, 0x9984, 0xDCC2, 0x8B84, 0xCDC2, 0xBB84, 0x8C5E, 0xBC5E, 0x84DE, 0x844E,
+ 0x9CDE, 0x9C4E, 0x8DDE, 0x8CCE, 0xBDDE, 0x8C46, 0xBCCE, 0xBC46, 0x85CE, 0x84C6,
+ 0x9DCE, 0x8442, 0x9CC6, 0x9C42, 0x8DC6, 0x8CC2, 0xBDC6, 0xBCC2, 0x85C2, 0x9DC2,
+ 0xD0BC, 0xA378, 0xE8DE, 0xA138, 0xE84E, 0xD3BC, 0xD19C, 0xD08C, 0xAF78, 0xEBDE,
+ 0xA738, 0xE9CE, 0xA318, 0xE8C6, 0xA108, 0xE842, 0xD79C, 0xD38C, 0xD184, 0xAF18,
+ 0xEBC6, 0xA708, 0xE9C2, 0xC85E, 0xB0BC, 0x91BC, 0x909C, 0xD84E, 0xC9DE, 0xB3BC,
+ 0xC8CE, 0xB19C, 0xC846, 0xB08C, 0x97BC, 0x939C, 0x918C, 0x9084, 0xD842, 0xCBCE,
+ 0xB79C, 0xC9C6, 0xB38C, 0xC8C2, 0xB184, 0x978C, 0x9384, 0xD9C2, 0x985E, 0x88DE,
+ 0x884E, 0xB8DE, 0xB84E, 0x99DE, 0x98CE, 0x9846, 0x8BDE, 0x89CE, 0xBBDE, 0x88C6,
+ 0xB9CE, 0x8842, 0xB8C6, 0xB842, 0x9BCE, 0x99C6, 0x98C2, 0x8BC6, 0x89C2, 0xBBC6,
+ 0xB9C2, 0xD05E, 0xA1BC, 0xA09C, 0xD1DE, 0xD0CE, 0xD046, 0xA7BC, 0xA39C, 0xA18C,
+ 0xA084, 0xD7DE, 0xD3CE, 0xD1C6, 0xD0C2, 0xAF9C, 0xA78C, 0xA384, 0xB05E, 0x90DE,
+ 0x904E, 0xB1DE, 0xB0CE, 0xB046, 0x93DE, 0x91CE, 0x90C6, 0x9042, 0xB7DE, 0xB3CE,
+ 0xB1C6, 0xB0C2, 0x97CE, 0x93C6, 0x91C2, 0xA0DE, 0xA04E, 0xA3DE, 0xA1CE, 0xA0C6,
+ 0xA042, 0xAFDE, 0xA7CE, 0xA3C6, 0xA1C2, 0xD4F0, 0xF53C, 0xA8E0, 0xEA38, 0xFA8E,
+ 0xD430, 0xF50C, 0xA820, 0xEA08, 0xFA82, 0xDAF8, 0xF6BE, 0xCA78, 0xF29E, 0xB4F0,
+ 0xED3C, 0x9470, 0xE51C, 0xDA38, 0xF68E, 0xCA18, 0xF286, 0xB430, 0xED0C, 0x9410,
+ 0xE504, 0xDA08, 0xF682, 0xCD7C, 0xBAF8, 0xEEBE, 0xC53C, 0x9A78, 0xE69E, 0xDD3C,
+ 0x8A38, 0xE28E, 0xCD1C, 0xBA38, 0xEE8E, 0xC50C, 0x9A18, 0xE686, 0xDD0C, 0x8A08,
+ 0xE282, 0xCD04, 0xBA08, 0xEE82, 0xC6BE, 0x9D7C, 0xDEBE, 0xC29E, 0x8D3C, 0xCE9E,
+ 0xBD3C, 0x851C, 0xC68E, 0x9D1C, 0xDE8E, 0xC286, 0x8D0C, 0xCE86, 0xBD0C, 0x8504,
+ 0xC682, 0x9D04, 0xDE82, 0x8EBE, 0xBEBE, 0x869E, 0x9E9E, 0x828E, 0x8E8E, 0xBE8E,
+ 0x8686, 0x9E86, 0x8282, 0x8E82, 0xBE82, 0xE97C, 0xD6F8, 0xF5BE, 0xD278, 0xF49E,
+ 0xACF0, 0xEB3C, 0xA470, 0xE91C, 0xD638, 0xF58E, 0xD218, 0xF486, 0xAC30, 0xEB0C,
+ 0xA410, 0xE904, 0xD608, 0xF582, 0x92F8, 0xE4BE, 0xD97C, 0xCB7C, 0xB6F8, 0xC93C,
+ 0xB278, 0xEC9E, 0x9678, 0xE59E, 0x9238, 0xE48E, 0xD91C, 0xCB1C, 0xB638, 0xC90C,
+ 0xB218, 0xEC86, 0x9618, 0xE586, 0x9208, 0xE482, 0xD904, 0xCB04, 0xB608, 0xED82,
+ 0x897C, 0xCCBE, 0xB97C, 0xC5BE, 0x9B7C, 0xC49E, 0x993C, 0xDC9E, 0x8B3C, 0x891C,
+ 0xBB3C, 0xCC8E, 0xB91C, 0xC58E, 0x9B1C, 0xC486, 0x990C, 0xDC86, 0x8B0C, 0x8904,
+ 0xBB0C, 0xCC82, 0xB904, 0xC582, 0x9B04, 0xDD82, 0x84BE, 0x9CBE, 0x8DBE, 0x8C9E,
+ 0xBDBE, 0xBC9E, 0x859E, 0x848E, 0x9D9E, 0x9C8E, 0x8D8E, 0x8C86, 0xBD8E, 0xBC86,
+ 0x8586, 0x8482, 0x9D86, 0x9C82, 0x8D82, 0xBD82, 0xA2F8, 0xE8BE, 0xD37C, 0xD13C,
+ 0xAEF8, 0xEBBE, 0xA678, 0xE99E, 0xA238, 0xE88E, 0xD73C, 0xD31C, 0xD10C, 0xAE38,
+ 0xEB8E, 0xA618, 0xE986, 0xA208, 0xE882, 0xD70C, 0xD304, 0x917C, 0xD8BE, 0xC9BE,
+ 0xB37C, 0xC89E, 0xB13C, 0x977C, 0x933C, 0x911C, 0xD88E, 0xCB9E, 0xB73C, 0xC98E,
+ 0xB31C, 0xC886, 0xB10C, 0x971C, 0x930C, 0x9104, 0xD882, 0xCB86, 0xB70C, 0xC982,
+ 0xB304, 0x88BE, 0xB8BE, 0x99BE, 0x989E, 0x8BBE, 0x899E, 0xBBBE, 0x888E, 0xB99E,
+ 0xB88E, 0x9B9E, 0x998E, 0x9886, 0x8B8E, 0x8986, 0xBB8E, 0x8882, 0xB986, 0xB882,
+ 0x9B86, 0x9982, 0xA17C, 0xD1BE, 0xD09E, 0xA77C, 0xA33C, 0xA11C, 0xD7BE, 0xD39E,
+ 0xD18E, 0xD086, 0xAF3C, 0xA71C, 0xA30C, 0xA104, 0xD78E, 0xD386, 0xD182, 0x90BE,
+ 0xB1BE, 0xB09E, 0x93BE, 0x919E, 0x908E, 0xB7BE, 0xB39E, 0xB18E, 0xB086, 0x979E,
+ 0x938E, 0x9186, 0x9082, 0xB78E, 0xB386, 0xB182, 0xA0BE, 0xA3BE, 0xA19E, 0xA08E,
+ 0xAFBE, 0xA79E, 0xA38E, 0xA186, 0xA082, 0xA9F0, 0xEA7C, 0xD478, 0xF51E, 0xA870,
+ 0xEA1C, 0xD418, 0xF506, 0xA810, 0xEA04, 0xED7E, 0x94F8, 0xE53E, 0xDA7C, 0xCA3C,
+ 0xB478, 0xED1E, 0x9438, 0xE50E, 0xDA1C, 0xCA0C, 0xB418, 0xED06, 0x9408, 0xE502,
+ 0xDA04, 0x9AFC, 0xDD7E, 0x8A7C, 0xCD3E, 0xBA7C, 0xC51E, 0x9A3C, 0xDD1E, 0x8A1C,
+ 0xCD0E, 0xBA1C, 0xC506, 0x9A0C, 0xDD06, 0x8A04, 0xCD02, 0xBA04, 0x8D7E, 0xBD7E,
+ 0x853E, 0x9D3E, 0x8D1E, 0xBD1E, 0x850E, 0x9D0E, 0x8D06, 0xBD06, 0x8502, 0x9D02,
+ 0xD2FC, 0xADF8, 0xEB7E, 0xA4F8, 0xE93E, 0xD67C, 0xD23C, 0xAC78, 0xEB1E, 0xA438,
+ 0xE90E, 0xD61C, 0xD20C, 0xAC18, 0xEB06, 0xA408, 0xE902, 0xC97E, 0xB2FC, 0x96FC,
+ 0x927C, 0xD93E, 0xCB3E, 0xB67C, 0xC91E, 0xB23C, 0x963C, 0x921C, 0xD90E, 0xCB0E,
+ 0xB61C, 0xC906, 0xB20C, 0x960C, 0x9204, 0xD902, 0x997E, 0x8B7E, 0x893E, 0xBB7E,
+ 0xB93E, 0xE4A0, 0xF928, 0xD940, 0xF650, 0xFD94, 0xCB40, 0xF2D0, 0xEDA0, 0xFB68,
+ 0x8940, 0xE250, 0xCCA0, 0xF328, 0xB940, 0xEE50, 0xFB94, 0xC5A0, 0xF168, 0x9B40,
+ 0xE6D0, 0xF9B4, 0xDDA0, 0xF768, 0xFDDA, 0x84A0, 0xE128, 0xC650, 0xF194, 0x9CA0,
+ 0xE728, 0xF9CA, 0xDE50, 0xF794, 0xC2D0, 0x8DA0, 0xE368, 0xCED0, 0xF3B4, 0xBDA0,
+ 0xEF68, 0xFBDA, 0x8250, 0xC328, 0x8E50, 0xE394, 0xCF28, 0xF3CA, 0xBE50, 0xEF94,
+ 0xC168, 0x86D0, 0xE1B4, 0xC768, 0xF1DA, 0x9ED0, 0xE7B4, 0xDF68, 0xF7DA, 0x8128,
+ 0xC194, 0x8728, 0xE1CA, 0xC794, 0x9F28, 0xE7CA, 0x8368, 0xC3B4, 0x8F68, 0xE3DA,
+ 0xCFB4, 0xBF68, 0xEFDA, 0xE8A0, 0xFA28, 0xD340, 0xF4D0, 0xFD34, 0xEBA0, 0xFAE8,
+ 0x9140, 0xE450, 0xF914, 0xD8A0, 0xF628, 0xFD8A, 0xC9A0, 0xF268, 0xB340, 0xECD0,
+ 0xFB34, 0x9740, 0xE5D0, 0xF974, 0xDBA0, 0xF6E8, 0xFDBA, 0x88A0, 0xE228, 0xCC50,
+ 0xF314, 0xB8A0, 0xEE28, 0xFB8A, 0xC4D0, 0xF134, 0x99A0, 0xE668, 0xF99A, 0xDCD0,
+ 0xF734, 0x8BA0, 0xE2E8, 0xCDD0, 0xF374, 0xBBA0, 0xEEE8, 0xFBBA, 0x8450, 0xE114,
+ 0xC628, 0xF18A, 0x9C50, 0xE714, 0xDE28, 0xF78A, 0xC268, 0x8CD0, 0xE334, 0xCE68,
+ 0xF39A, 0xBCD0, 0xEF34, 0x85D0, 0xE174, 0xC6E8, 0xF1BA, 0x9DD0, 0xE774, 0xDEE8,
+ 0xF7BA, 0x8228, 0xC314, 0x8E28, 0xE38A, 0xCF14, 0xC134, 0x8668, 0xE19A, 0xC734,
+ 0x9E68, 0xE79A, 0xDF34, 0x82E8, 0xC374, 0x8EE8, 0xE3BA, 0xCF74, 0xBEE8, 0xEFBA,
+ 0x8114, 0xC18A, 0x8714, 0xC78A, 0x8334, 0xC39A, 0x8F34, 0xCF9A, 0x8174, 0xC1BA,
+ 0x8774, 0xC7BA, 0x9F74, 0xDFBA, 0xA140, 0xE850, 0xFA14, 0xD1A0, 0xF468, 0xFD1A,
+ 0xA740, 0xE9D0, 0xFA74, 0xD7A0, 0xF5E8, 0xFD7A, 0x90A0, 0xE428, 0xF90A, 0xD850,
+ 0xF614, 0xC8D0, 0xF234, 0xB1A0, 0xEC68, 0xFB1A, 0x93A0, 0xE4E8, 0xF93A, 0xD9D0,
+ 0xF674, 0xCBD0, 0xF2F4, 0xB7A0, 0xEDE8, 0xFB7A, 0x8850, 0xE214, 0xCC28, 0xF30A,
+ 0xB850, 0xEE14, 0xC468, 0xF11A, 0x98D0, 0xE634, 0xDC68, 0xF71A, 0x89D0, 0xE274,
+ 0xCCE8, 0xF33A, 0xB9D0, 0xEE74, 0xC5E8, 0xF17A, 0x9BD0, 0xE6F4, 0xDDE8, 0xF77A,
+ 0x8428, 0xE10A, 0xC614, 0x9C28, 0xE70A, 0xC234, 0x8C68, 0xE31A, 0xCE34, 0xBC68,
+ 0xEF1A, 0x84E8, 0xE13A, 0xC674, 0x9CE8, 0xE73A, 0xDE74, 0xC2F4, 0x8DE8, 0xE37A,
+ 0xCEF4, 0xBDE8, 0xEF7A, 0x8214, 0xC30A, 0x8E14, 0xC11A, 0x8634, 0xC71A, 0x9E34,
+ 0x8274, 0xC33A, 0x8E74, 0xCF3A, 0xBE74, 0xC17A, 0x86F4, 0xC77A, 0x9EF4, 0xDF7A,
+ 0x810A, 0x870A, 0x831A, 0x8F1A, 0x813A, 0x873A, 0x9F3A, 0x837A, 0x8F7A, 0xBF7A,
+ 0xA0A0, 0xE828, 0xFA0A, 0xD0D0, 0xF434, 0xA3A0, 0xE8E8, 0xFA3A, 0xD3D0, 0xF4F4,
+ 0xAFA0, 0xEBE8, 0xFAFA, 0x9050, 0xE414, 0xD828, 0xF60A, 0xC868, 0xF21A, 0xB0D0,
+ 0xEC34, 0x91D0, 0xE474, 0xD8E8, 0xF63A, 0xC9E8, 0xF27A, 0xB3D0, 0xECF4, 0x97D0,
+ 0xE5F4, 0xDBE8, 0xF6FA, 0x8828, 0xE20A, 0xCC14, 0xC434, 0x9868, 0xE61A, 0xDC34,
+ 0x88E8, 0xE23A, 0xCC74, 0xB8E8, 0xEE3A, 0xC4F4, 0x99E8, 0xE67A, 0xDCF4, 0x8BE8,
+ 0xE2FA, 0xCDF4, 0xBBE8, 0xEEFA, 0x8414, 0xC60A, 0xC21A, 0x8C34, 0xCE1A, 0x8474,
+ 0xC63A, 0x9C74, 0xDE3A, 0xC27A, 0x8CF4, 0xCE7A, 0xBCF4, 0x85F4, 0xC6FA, 0x9DF4,
+ 0xDEFA, 0x820A, 0x861A, 0x823A, 0x8E3A, 0x867A, 0x9E7A, 0x82FA, 0x8EFA, 0xBEFA,
+ 0xA050, 0xE814, 0xD068, 0xF41A, 0xA1D0, 0xE874, 0xD1E8, 0xF47A, 0xA7D0, 0xE9F4,
+ 0xD7E8, 0xF5FA, 0x9028, 0xE40A, 0xC834, 0xB068, 0xEC1A, 0x90E8, 0xE43A, 0xD874,
+ 0xC8F4, 0xB1E8, 0xEC7A, 0x93E8, 0xE4FA, 0xD9F4, 0xCBF4, 0xB7E8, 0xEDFA, 0x8814,
+ 0xC41A, 0x9834, 0x8874, 0xCC3A, 0xB874, 0xC47A, 0x98F4, 0xDC7A, 0x89F4, 0xCCFA,
+ 0xB9F4, 0xC5FA, 0x9BF4, 0xDDFA, 0x840A, 0x8C1A, 0x843A, 0x9C3A, 0x8C7A, 0xBC7A,
+ 0x84FA, 0x9CFA, 0x8DFA, 0xBDFA, 0xEA40, 0xFA90, 0xED60, 0xFB58, 0xE520, 0xF948,
+ 0xDA40, 0xF690, 0xFDA4, 0x9AC0, 0xE6B0, 0xF9AC, 0xDD60, 0xF758, 0xFDD6, 0x8A40,
+ 0xE290, 0xCD20, 0xF348, 0xBA40, 0xEE90, 0xFBA4, 0x8D60, 0xE358, 0xCEB0, 0xF3AC,
+ 0xBD60, 0xEF58, 0xFBD6, 0x8520, 0xE148, 0xC690, 0xF1A4, 0x9D20, 0xE748, 0xF9D2,
+ 0xDE90, 0xF7A4, 0x86B0, 0xE1AC, 0xC758, 0xF1D6, 0x9EB0, 0xE7AC, 0xDF58, 0xF7D6,
+ 0x8290, 0xC348, 0x8E90, 0xE3A4, 0xCF48, 0xF3D2, 0xBE90, 0xEFA4, 0x8358, 0xC3AC,
+ 0x8F58, 0xE3D6, 0xCFAC, 0xBF58, 0xEFD6, 0x8148, 0xC1A4, 0x8748, 0xE1D2, 0xC7A4,
+ 0x9F48, 0xE7D2, 0xDFA4, 0xD2C0, 0xF4B0, 0xFD2C, 0xEB60, 0xFAD8, 0xE920, 0xFA48,
+ 0xD640, 0xF590, 0xFD64, 0xC960, 0xF258, 0xB2C0, 0xECB0, 0xFB2C, 0x96C0, 0xE5B0,
+ 0xF96C, 0x9240, 0xE490, 0xF924, 0xD920, 0xF648, 0xFD92, 0xCB20, 0xF2C8, 0xB640,
+ 0xED90, 0xFB64, 0xC4B0, 0xF12C, 0x9960, 0xE658, 0xF996, 0xDCB0, 0xF72C, 0x8B60,
+ 0xE2D8, 0x8920, 0xE248, 0xBB60, 0xCC90, 0xF324, 0xB920, 0xEE48, 0xFB92, 0xC590,
+ 0xF164, 0x9B20, 0xE6C8, 0xF9B2, 0xDD90, 0xF764, 0xC258, 0x8CB0, 0xE32C, 0xCE58,
+ 0xF396, 0xBCB0, 0xEF2C, 0x85B0, 0xE16C, 0x8490, 0xE124, 0x9DB0, 0xC648, 0xF192,
+ 0x9C90, 0xE724, 0xDE48, 0xF792, 0xC2C8, 0x8D90, 0xE364, 0xCEC8, 0xF3B2, 0xBD90,
+ 0xEF64, 0xC12C, 0x8658, 0xE196, 0xC72C, 0x9E58, 0xE796, 0xDF2C, 0x82D8, 0x8248,
+ 0x8ED8, 0xC324, 0x8E48, 0xE392, 0xBED8, 0xCF24, 0xBE48, 0xEF92, 0xC164, 0x86C8,
+ 0xE1B2, 0xC764, 0x9EC8, 0xE7B2, 0xDF64, 0x832C, 0xC396, 0x8F2C, 0xCF96, 0x816C,
+ 0x8124, 0x876C, 0xC192, 0x8724, 0x9F6C, 0xC792, 0x9F24, 0x8364, 0xC3B2, 0x8F64,
+ 0xCFB2, 0xBF64, 0xD160, 0xF458, 0xFD16, 0xA6C0, 0xE9B0, 0xFA6C, 0xA240, 0xE890,
+ 0xFA24, 0xD760, 0xF5D8, 0xFD76, 0xD320, 0xF4C8, 0xFD32, 0xAE40, 0xEB90, 0xFAE4,
+ 0xC8B0, 0xF22C, 0xB160, 0xEC58, 0xFB16, 0x9360, 0xE4D8, 0xF936, 0x9120, 0xE448,
+ 0xF912, 0xD890, 0xF624, 0xCBB0, 0xF2EC, 0xB760, 0xC990, 0xF264, 0xB320, 0xECC8,
+ 0xFB32, 0x9720, 0xE5C8, 0xF972, 0xDB90, 0xF6E4, 0xC458, 0xF116, 0x98B0, 0xE62C,
+ 0xDC58, 0xF716, 0x89B0, 0xE26C, 0x8890, 0xE224, 0xB9B0, 0xCC48, 0xF312, 0xB890,
+ 0xEE24, 0xC5D8, 0xF176, 0x9BB0, 0xC4C8, 0xF132, 0x9990, 0xE664, 0xDCC8, 0xF732,
+ 0x8B90, 0xE2E4, 0xCDC8, 0xF372, 0xBB90, 0xEEE4, 0xC22C, 0x8C58, 0xE316, 0xCE2C,
+ 0xBC58, 0xEF16, 0x84D8, 0xE136, 0x8448, 0xE112, 0x9CD8, 0xC624, 0x9C48, 0xE712,
+ 0xDE24, 0xC2EC, 0x8DD8, 0xC264, 0x8CC8, 0xE332, 0xBDD8, 0xCE64, 0xBCC8, 0xEF32,
+ 0x85C8, 0xE172, 0xC6E4, 0x9DC8, 0xE772, 0xDEE4, 0xC116, 0x862C, 0xC716, 0x9E2C,
+ 0x826C, 0x8224, 0x8E6C, 0xC312, 0x8E24, 0xBE6C, 0xCF12, 0xC176, 0x86EC, 0xC132,
+ 0x8664, 0x9EEC, 0xC732, 0x9E64, 0xDF32, 0x82E4, 0xC372, 0x8EE4, 0xCF72, 0xBEE4,
+ 0x8316, 0x8F16, 0x8136, 0x8112, 0x8736, 0x8712, 0x9F36, 0x8376, 0x8332, 0x8F76,
+ 0x8F32, 0xBF76, 0x8172, 0x8772, 0x9F72, 0xD0B0, 0xF42C, 0xA360, 0xE8D8, 0xFA36,
+ 0xA120, 0xE848, 0xFA12, 0xD3B0, 0xF4EC, 0xD190, 0xF464, 0xAF60, 0xEBD8, 0xFAF6,
+ 0xA720, 0xE9C8, 0xFA72, 0xD790, 0xF5E4, 0xC858, 0xF216, 0xB0B0, 0xEC2C, 0x91B0,
+ 0xE46C, 0x9090, 0xE424, 0xD848, 0xF612, 0xC9D8, 0xF276, 0xB3B0, 0xC8C8, 0xF232,
+ 0xB190, 0xEC64, 0x97B0, 0xE5EC, 0x9390, 0xE4E4, 0xD9C8, 0xF672, 0xCBC8, 0xF2F2,
+ 0xB790, 0xEDE4, 0xC42C, 0x9858, 0xE616, 0xDC2C, 0x88D8, 0xE236, 0x8848, 0xE212,
+ 0xB8D8, 0xCC24, 0xB848, 0xEE12, 0xC4EC, 0x99D8, 0xC464, 0x98C8, 0xE632, 0xDC64,
+ 0x8BD8, 0xE2F6, 0x89C8, 0xE272, 0xBBD8, 0xCCE4, 0xB9C8, 0xEE72, 0xC5E4, 0x9BC8,
+ 0xE6F2, 0xDDE4, 0xC216, 0x8C2C, 0xCE16, 0x846C, 0x8424, 0x9C6C, 0xC612, 0x9C24,
+ 0xC276, 0x8CEC, 0xC232, 0x8C64, 0xBCEC, 0xCE32, 0xBC64, 0x85EC, 0x84E4, 0x9DEC,
+ 0xC672, 0x9CE4, 0xDE72, 0xC2F2, 0x8DE4, 0xCEF2, 0xBDE4, 0x8616, 0x8236, 0x8212,
+ 0x8E36, 0x8E12, 0x8676, 0x8632, 0x9E76, 0x9E32, 0x82F6, 0x8272, 0x8EF6, 0x8E72,
+ 0xBEF6, 0xBE72, 0x86F2, 0x9EF2, 0xD058, 0xF416, 0xA1B0, 0xE86C, 0xA090, 0xE824,
+ 0xD1D8, 0xF476, 0xD0C8, 0xF432, 0xA7B0, 0xE9EC, 0xA390, 0xE8E4, 0xD7D8, 0xF5F6,
+ 0xD3C8, 0xF4F2, 0xAF90, 0xEBE4, 0xC82C, 0xB058, 0xEC16, 0x90D8, 0xE436, 0x9048,
+ 0xE412, 0xD824, 0xC8EC, 0xB1D8, 0xC864, 0xB0C8, 0xEC32, 0x93D8, 0xE4F6, 0x91C8,
+ 0xE472, 0xD8E4, 0xCBEC, 0xB7D8, 0xC9E4, 0xB3C8, 0xECF2, 0x97C8, 0xE5F2, 0xDBE4,
+ 0xC416, 0x982C, 0x886C, 0x8824, 0xB86C, 0xCC12, 0xC476, 0x98EC, 0xC432, 0x9864,
+ 0xDC32, 0x89EC, 0x88E4, 0xB9EC, 0xCC72, 0xB8E4, 0xC5F6, 0x9BEC, 0xC4F2, 0x99E4,
+ 0xDCF2, 0x8BE4, 0xCDF2, 0xBBE4, 0x8C16, 0x8436, 0x8412, 0x9C36, 0x8C76, 0x8C32,
+ 0xBC76, 0x84F6, 0x8472, 0x9CF6, 0x9C72, 0x8DF6, 0x8CF2, 0xBDF6, 0xBCF2, 0x85F2,
+ 0x9DF2, 0xD02C, 0xA0D8, 0xE836, 0xA048, 0xE812, 0xD0EC, 0xD064, 0xA3D8, 0xE8F6,
+ 0xA1C8, 0xE872, 0xD3EC, 0xD1E4, 0xAFD8, 0xEBF6, 0xA7C8, 0xE9F2, 0xC816, 0x906C,
+ 0x9024, 0xC876, 0xB0EC, 0xC832, 0xB064, 0x91EC, 0x90E4, 0xD872, 0xC9F6, 0xB3EC,
+ 0xC8F2, 0xB1E4, 0x97EC, 0x93E4, 0xD9F2, 0x8836, 0x8812, 0x9876, 0x9832, 0x88F6,
+ 0x8872, 0xB8F6, 0xB872, 0x99F6, 0x98F2, 0x8BF6, 0x89F2, 0xBBF6, 0xB9F2, 0xD4C0,
+ 0xF530, 0xFD4C, 0xEA20, 0xFA88, 0xDAE0, 0xF6B8, 0xFDAE, 0xCA60, 0xF298, 0xB4C0,
+ 0xED30, 0xFB4C, 0x9440, 0xE510, 0xF944, 0xDA20, 0xF688, 0xFDA2, 0xCD70, 0xF35C,
+ 0xBAE0, 0xEEB8, 0xFBAE, 0xC530, 0xF14C, 0x9A60, 0xE698, 0xF9A6, 0xDD30, 0xF74C,
+ 0x8A20, 0xE288, 0xCD10, 0xF344, 0xBA20, 0xEE88, 0xFBA2, 0xC6B8, 0xF1AE, 0x9D70,
+ 0xE75C, 0xDEB8, 0xF7AE, 0xC298, 0x8D30, 0xE34C, 0xCE98, 0xF3A6, 0xBD30, 0xEF4C,
+ 0x8510, 0xE144, 0xC688, 0xF1A2, 0x9D10, 0xE744, 0xDE88, 0xF7A2, 0xC35C, 0x8EB8,
+ 0xE3AE, 0xCF5C, 0xBEB8, 0xEFAE, 0xC14C, 0x8698, 0xE1A6, 0xC74C, 0x9E98, 0xE7A6,
+ 0xDF4C, 0x8288, 0xC344, 0x8E88, 0xE3A2, 0xCF44, 0xBE88, 0xEFA2, 0xC1AE, 0x875C,
+ 0xC7AE, 0x9F5C, 0xDFAE, 0x834C, 0xC3A6, 0x8F4C, 0xCFA6, 0xBF4C, 0x8144, 0xC1A2,
+ 0x8744, 0xC7A2, 0x9F44, 0xDFA2, 0xE970, 0xFA5C, 0xD6E0, 0xF5B8, 0xFD6E, 0xD260,
+ 0xF498, 0xFD26, 0xACC0, 0xEB30, 0xFACC, 0xA440, 0xE910, 0xFA44, 0xD620, 0xF588,
+ 0xFD62, 0x92E0, 0xE4B8, 0xF92E, 0xD970, 0xF65C, 0xCB70, 0xF2DC, 0xB6E0, 0xC930,
+ 0xF24C, 0xB260, 0xEC98, 0xFB26, 0x9660, 0xE598, 0xF966, 0x9220, 0xE488, 0xF922,
+ 0xD910, 0xF644, 0xCB10, 0xF2C4, 0xB620, 0xED88, 0xFB62, 0x8970, 0xE25C, 0xCCB8,
+ 0xF32E, 0xB970, 0xEE5C, 0xC5B8, 0xF16E, 0x9B70, 0xC498, 0xF126, 0x9930, 0xE64C,
+ 0xDC98, 0xF726, 0x8B30, 0xE2CC, 0x8910, 0xE244, 0xBB30, 0xCC88, 0xF322, 0xB910,
+ 0xEE44, 0xC588, 0xF162, 0x9B10, 0xE6C4, 0xDD88, 0xF762, 0x84B8, 0xE12E, 0xC65C,
+ 0x9CB8, 0xE72E, 0xDE5C, 0xC2DC, 0x8DB8, 0xC24C, 0x8C98, 0xE326, 0xBDB8, 0xCE4C,
+ 0xBC98, 0xEF26, 0x8598, 0xE166, 0x8488, 0xE122, 0x9D98, 0xC644, 0x9C88, 0xE722,
+ 0xDE44, 0xC2C4, 0x8D88, 0xE362, 0xCEC4, 0xBD88, 0xEF62, 0x825C, 0xC32E, 0x8E5C,
+ 0xCF2E
+};
+
+static const unsigned short int c49_odd_bitpattern[] = {
+ /* Appendix E - Code 49 Encodation Patterns (Odd Symbol Character Parity) */
+ 0xC940, 0xF250, 0xECA0, 0xFB28, 0xE5A0, 0xF968, 0xDB40, 0xF6D0, 0xFDB4, 0xC4A0,
+ 0xF128, 0x9940, 0xE650, 0xF994, 0xDCA0, 0xF728, 0xFDCA, 0x8B40, 0xE2D0, 0xCDA0,
+ 0xF368, 0xBB40, 0xEED0, 0xFBB4, 0xC250, 0x8CA0, 0xE328, 0xCE50, 0xF394, 0xBCA0,
+ 0xEF28, 0xFBCA, 0x85A0, 0xE168, 0xC6D0, 0xF1B4, 0x9DA0, 0xE768, 0xF9DA, 0xDED0,
+ 0xF7B4, 0xC128, 0x8650, 0xE194, 0xC728, 0xF1CA, 0x9E50, 0xE794, 0xDF28, 0xF7CA,
+ 0x82D0, 0xC368, 0x8ED0, 0xE3B4, 0xCF68, 0xF3DA, 0xBED0, 0xEFB4, 0x8328, 0xC394,
+ 0x8F28, 0xE3CA, 0xCF94, 0x8168, 0xC1B4, 0x8768, 0xE1DA, 0xC7B4, 0x9F68, 0xE7DA,
+ 0xDFB4, 0xD140, 0xF450, 0xFD14, 0xE9A0, 0xFA68, 0xD740, 0xF5D0, 0xFD74, 0xC8A0,
+ 0xF228, 0xB140, 0xEC50, 0xFB14, 0x9340, 0xE4D0, 0xF934, 0xD9A0, 0xF668, 0xFD9A,
+ 0xCBA0, 0xF2E8, 0xB740, 0xEDD0, 0xFB74, 0xC450, 0xF114, 0x98A0, 0xE628, 0xF98A,
+ 0xDC50, 0xF714, 0x89A0, 0xE268, 0xCCD0, 0xF334, 0xB9A0, 0xEE68, 0xFB9A, 0xC5D0,
+ 0xF174, 0x9BA0, 0xE6E8, 0xF9BA, 0xDDD0, 0xF774, 0xC228, 0x8C50, 0xE314, 0xCE28,
+ 0xF38A, 0xBC50, 0xEF14, 0x84D0, 0xE134, 0xC668, 0xF19A, 0x9CD0, 0xE734, 0xDE68,
+ 0xF79A, 0xC2E8, 0x8DD0, 0xE374, 0xCEE8, 0xF3BA, 0xBDD0, 0xEF74, 0xC114, 0x8628,
+ 0xE18A, 0xC714, 0x9E28, 0xE78A, 0x8268, 0xC334, 0x8E68, 0xE39A, 0xCF34, 0xBE68,
+ 0xEF9A, 0xC174, 0x86E8, 0xE1BA, 0xC774, 0x9EE8, 0xE7BA, 0xDF74, 0x8314, 0xC38A,
+ 0x8F14, 0x8134, 0xC19A, 0x8734, 0xC79A, 0x9F34, 0x8374, 0xC3BA, 0x8F74, 0xCFBA,
+ 0xBF74, 0xD0A0, 0xF428, 0xFD0A, 0xA340, 0xE8D0, 0xFA34, 0xD3A0, 0xF4E8, 0xFD3A,
+ 0xAF40, 0xEBD0, 0xFAF4, 0xC850, 0xF214, 0xB0A0, 0xEC28, 0xFB0A, 0x91A0, 0xE468,
+ 0xF91A, 0xD8D0, 0xF634, 0xC9D0, 0xF274, 0xB3A0, 0xECE8, 0xFB3A, 0x97A0, 0xE5E8,
+ 0xF97A, 0xDBD0, 0xF6F4, 0xC428, 0xF10A, 0x9850, 0xE614, 0xDC28, 0xF70A, 0x88D0,
+ 0xE234, 0xCC68, 0xF31A, 0xB8D0, 0xEE34, 0xC4E8, 0xF13A, 0x99D0, 0xE674, 0xDCE8,
+ 0xF73A, 0x8BD0, 0xE2F4, 0xCDE8, 0xF37A, 0xBBD0, 0xEEF4, 0xC214, 0x8C28, 0xE30A,
+ 0xCE14, 0x8468, 0xE11A, 0xC634, 0x9C68, 0xE71A, 0xDE34, 0xC274, 0x8CE8, 0xE33A,
+ 0xCE74, 0xBCE8, 0xEF3A, 0x85E8, 0xE17A, 0xC6F4, 0x9DE8, 0xE77A, 0xDEF4, 0xC10A,
+ 0x8614, 0xC70A, 0x8234, 0xC31A, 0x8E34, 0xCF1A, 0xC13A, 0x8674, 0xC73A, 0x9E74,
+ 0xDF3A, 0x82F4, 0xC37A, 0x8EF4, 0xCF7A, 0xBEF4, 0x830A, 0x811A, 0x871A, 0x833A,
+ 0x8F3A, 0x817A, 0x877A, 0x9F7A, 0xD050, 0xF414, 0xA1A0, 0xE868, 0xFA1A, 0xD1D0,
+ 0xF474, 0xA7A0, 0xE9E8, 0xFA7A, 0xD7D0, 0xF5F4, 0xC828, 0xF20A, 0xB050, 0xEC14,
+ 0x90D0, 0xE434, 0xD868, 0xF61A, 0xC8E8, 0xF23A, 0xB1D0, 0xEC74, 0x93D0, 0xE4F4,
+ 0xD9E8, 0xF67A, 0xCBE8, 0xF2FA, 0xB7D0, 0xEDF4, 0xC414, 0x9828, 0xE60A, 0x8868,
+ 0xE21A, 0xCC34, 0xB868, 0xEE1A, 0xC474, 0x98E8, 0xE63A, 0xDC74, 0x89E8, 0xE27A,
+ 0xCCF4, 0xB9E8, 0xEE7A, 0xC5F4, 0x9BE8, 0xE6FA, 0xDDF4, 0xC20A, 0x8C14, 0x8434,
+ 0xC61A, 0x9C34, 0xC23A, 0x8C74, 0xCE3A, 0xBC74, 0x84F4, 0xC67A, 0x9CF4, 0xDE7A,
+ 0xC2FA, 0x8DF4, 0xCEFA, 0xBDF4, 0x860A, 0x821A, 0x8E1A, 0x863A, 0x9E3A, 0x827A,
+ 0x8E7A, 0xBE7A, 0x86FA, 0x9EFA, 0xD028, 0xF40A, 0xA0D0, 0xE834, 0xD0E8, 0xF43A,
+ 0xA3D0, 0xE8F4, 0xD3E8, 0xF4FA, 0xAFD0, 0xEBF4, 0xC814, 0x9068, 0xE41A, 0xD834,
+ 0xC874, 0xB0E8, 0xEC3A, 0x91E8, 0xE47A, 0xD8F4, 0xC9F4, 0xB3E8, 0xECFA, 0x97E8,
+ 0xE5FA, 0xDBF4, 0xC40A, 0x8834, 0xCC1A, 0xC43A, 0x9874, 0xDC3A, 0x88F4, 0xCC7A,
+ 0xB8F4, 0xC4FA, 0x99F4, 0xDCFA, 0x8BF4, 0xCDFA, 0xBBF4, 0x841A, 0x8C3A, 0x847A,
+ 0x9C7A, 0x8CFA, 0xBCFA, 0x85FA, 0x9DFA, 0xF520, 0xFD48, 0xDAC0, 0xF6B0, 0xFDAC,
+ 0xCA40, 0xF290, 0xED20, 0xFB48, 0xCD60, 0xF358, 0xBAC0, 0xEEB0, 0xFBAC, 0xC520,
+ 0xF148, 0x9A40, 0xE690, 0xF9A4, 0xDD20, 0xF748, 0xFDD2, 0xC6B0, 0xF1AC, 0x9D60,
+ 0xE758, 0xF9D6, 0xDEB0, 0xF7AC, 0xC290, 0x8D20, 0xE348, 0xCE90, 0xF3A4, 0xBD20,
+ 0xEF48, 0xFBD2, 0xC358, 0x8EB0, 0xE3AC, 0xCF58, 0xF3D6, 0xBEB0, 0xEFAC, 0xC148,
+ 0x8690, 0xE1A4, 0xC748, 0xF1D2, 0x9E90, 0xE7A4, 0xDF48, 0xF7D2, 0xC1AC, 0x8758,
+ 0xE1D6, 0xC7AC, 0x9F58, 0xE7D6, 0xDFAC, 0x8348, 0xC3A4, 0x8F48, 0xE3D2, 0xCFA4,
+ 0xBF48, 0xEFD2, 0xE960, 0xFA58, 0xD6C0, 0xF5B0, 0xFD6C, 0xD240, 0xF490, 0xFD24,
+ 0xEB20, 0xFAC8, 0x92C0, 0xE4B0, 0xF92C, 0xD960, 0xF658, 0xFD96, 0xCB60, 0xF2D8,
+ 0xB6C0, 0xC920, 0xF248, 0xB240, 0xEC90, 0xFB24, 0x9640, 0xE590, 0xF964, 0xDB20,
+ 0xF6C8, 0xFDB2, 0x8960, 0xE258, 0xCCB0, 0xF32C, 0xB960, 0xEE58, 0xFB96, 0xC5B0,
+ 0xF16C, 0x9B60, 0xC490, 0xF124, 0x9920, 0xE648, 0xF992, 0xDC90, 0xF724, 0x8B20,
+ 0xE2C8, 0xCD90, 0xF364, 0xBB20, 0xEEC8, 0xFBB2, 0x84B0, 0xE12C, 0xC658, 0xF196,
+ 0x9CB0, 0xE72C, 0xDE58, 0xF796, 0xC2D8, 0x8DB0, 0xC248, 0x8C90, 0xE324, 0xBDB0,
+ 0xCE48, 0xF392, 0xBC90, 0xEF24, 0x8590, 0xE164, 0xC6C8, 0xF1B2, 0x9D90, 0xE764,
+ 0xDEC8, 0xF7B2, 0x8258, 0xC32C, 0x8E58, 0xE396, 0xCF2C, 0xBE58, 0xEF96, 0xC16C,
+ 0x86D8, 0xC124, 0x8648, 0xE192, 0x9ED8, 0xC724, 0x9E48, 0xE792, 0xDF24, 0x82C8,
+ 0xC364, 0x8EC8, 0xE3B2, 0xCF64, 0xBEC8, 0xEFB2, 0x812C, 0xC196, 0x872C, 0xC796,
+ 0x9F2C, 0x836C, 0x8324, 0x8F6C, 0xC392, 0x8F24, 0xBF6C, 0xCF92, 0x8164, 0xC1B2,
+ 0x8764, 0xC7B2, 0x9F64, 0xDFB2, 0xA2C0, 0xE8B0, 0xFA2C, 0xD360, 0xF4D8, 0xFD36,
+ 0xD120, 0xF448, 0xFD12, 0xAEC0, 0xEBB0, 0xFAEC, 0xA640, 0xE990, 0xFA64, 0xD720,
+ 0xF5C8, 0xFD72, 0x9160, 0xE458, 0xF916, 0xD8B0, 0xF62C, 0xC9B0, 0xF26C, 0xB360,
+ 0xC890, 0xF224, 0xB120, 0xEC48, 0xFB12, 0x9760, 0xE5D8, 0xF976, 0x9320, 0xE4C8,
+ 0xF932, 0xD990, 0xF664, 0xCB90, 0xF2E4, 0xB720, 0xEDC8, 0xFB72, 0x88B0, 0xE22C,
+ 0xCC58, 0xF316, 0xB8B0, 0xEE2C, 0xC4D8, 0xF136, 0x99B0, 0xC448, 0xF112, 0x9890,
+ 0xE624, 0xDC48, 0xF712, 0x8BB0, 0xE2EC, 0x8990, 0xE264, 0xBBB0, 0xCCC8, 0xF332,
+ 0xB990, 0xEE64, 0xC5C8, 0xF172, 0x9B90, 0xE6E4, 0xDDC8, 0xF772, 0x8458, 0xE116,
+ 0xC62C, 0x9C58, 0xE716, 0xDE2C, 0xC26C, 0x8CD8, 0xC224, 0x8C48, 0xE312, 0xBCD8,
+ 0xCE24, 0xBC48, 0xEF12, 0x85D8, 0xE176, 0x84C8, 0xE132, 0x9DD8, 0xC664, 0x9CC8,
+ 0xE732, 0xDE64, 0xC2E4, 0x8DC8, 0xE372, 0xCEE4, 0xBDC8, 0xEF72, 0x822C, 0xC316,
+ 0x8E2C, 0xCF16, 0xC136, 0x866C, 0xC112, 0x8624, 0x9E6C, 0xC712, 0x9E24, 0x82EC,
+ 0x8264, 0x8EEC, 0xC332, 0x8E64, 0xBEEC, 0xCF32, 0xBE64, 0xC172, 0x86E4, 0xC772,
+ 0x9EE4, 0xDF72, 0x8116, 0x8716, 0x8336, 0x8312, 0x8F36, 0x8F12, 0x8176, 0x8132,
+ 0x8776, 0x8732, 0x9F76, 0x9F32, 0x8372, 0x8F72, 0xBF72, 0xA160, 0xE858, 0xFA16,
+ 0xD1B0, 0xF46C, 0xD090, 0xF424, 0xA760, 0xE9D8, 0xFA76, 0xA320, 0xE8C8, 0xFA32,
+ 0xD7B0, 0xF5EC, 0xD390, 0xF4E4, 0xAF20, 0xEBC8, 0xFAF2, 0x90B0, 0xE42C, 0xD858,
+ 0xF616, 0xC8D8, 0xF236, 0xB1B0, 0xC848, 0xF212, 0xB090, 0xEC24, 0x93B0, 0xE4EC,
+ 0x9190, 0xE464, 0xD8C8, 0xF632, 0xCBD8, 0xF2F6, 0xB7B0, 0xC9C8, 0xF272, 0xB390,
+ 0xECE4, 0x9790, 0xE5E4, 0xDBC8, 0xF6F2, 0x8858, 0xE216, 0xCC2C, 0xB858, 0xEE16,
+ 0xC46C, 0x98D8, 0xC424, 0x9848, 0xE612, 0xDC24, 0x89D8, 0xE276, 0x88C8, 0xE232,
+ 0xB9D8, 0xCC64, 0xB8C8, 0xEE32, 0xC5EC, 0x9BD8, 0xC4E4, 0x99C8, 0xE672, 0xDCE4,
+ 0x8BC8, 0xE2F2, 0xCDE4, 0xBBC8, 0xEEF2, 0x842C, 0xC616, 0x9C2C, 0xC236, 0x8C6C,
+ 0xC212, 0x8C24, 0xBC6C, 0xCE12, 0x84EC, 0x8464, 0x9CEC, 0xC632, 0x9C64, 0xDE32,
+ 0xC2F6, 0x8DEC, 0xC272, 0x8CE4, 0xBDEC, 0xCE72, 0xBCE4, 0x85E4, 0xC6F2, 0x9DE4,
+ 0xDEF2, 0x8216, 0x8E16, 0x8636, 0x8612, 0x9E36, 0x8276, 0x8232, 0x8E76, 0x8E32,
+ 0xBE76, 0x86F6, 0x8672, 0x9EF6, 0x9E72, 0x82F2, 0x8EF2, 0xBEF2, 0xA0B0, 0xE82C,
+ 0xD0D8, 0xF436, 0xD048, 0xF412, 0xA3B0, 0xE8EC, 0xA190, 0xE864, 0xD3D8, 0xF4F6,
+ 0xD1C8, 0xF472, 0xAFB0, 0xEBEC, 0xA790, 0xE9E4, 0xD7C8, 0xF5F2, 0x9058, 0xE416,
+ 0xD82C, 0xC86C, 0xB0D8, 0xC824, 0xB048, 0xEC12, 0x91D8, 0xE476, 0x90C8, 0xE432,
+ 0xD864, 0xC9EC, 0xB3D8, 0xC8E4, 0xB1C8, 0xEC72, 0x97D8, 0xE5F6, 0x93C8, 0xE4F2,
+ 0xD9E4, 0xCBE4, 0xB7C8, 0xEDF2, 0x882C, 0xCC16, 0xC436, 0x986C, 0xC412, 0x9824,
+ 0x88EC, 0x8864, 0xB8EC, 0xCC32, 0xB864, 0xC4F6, 0x99EC, 0xC472, 0x98E4, 0xDC72,
+ 0x8BEC, 0x89E4, 0xBBEC, 0xCCF2, 0xB9E4, 0xC5F2, 0x9BE4, 0xDDF2, 0x8416, 0x8C36,
+ 0x8C12, 0x8476, 0x8432, 0x9C76, 0x9C32, 0x8CF6, 0x8C72, 0xBCF6, 0xBC72, 0x85F6,
+ 0x84F2, 0x9DF6, 0x9CF2, 0x8DF2, 0xBDF2, 0xA058, 0xE816, 0xD06C, 0xD024, 0xA1D8,
+ 0xE876, 0xA0C8, 0xE832, 0xD1EC, 0xD0E4, 0xA7D8, 0xE9F6, 0xA3C8, 0xE8F2, 0xD7EC,
+ 0xD3E4, 0x902C, 0xC836, 0xB06C, 0xC812, 0x90EC, 0x9064, 0xD832, 0xC8F6, 0xB1EC,
+ 0xC872, 0xB0E4, 0x93EC, 0x91E4, 0xD8F2, 0xCBF6, 0xB7EC, 0xC9F2, 0xB3E4, 0x8816,
+ 0x9836, 0x8876, 0x8832, 0xB876, 0x98F6, 0x9872, 0x89F6, 0x88F2, 0xB9F6, 0xB8F2,
+ 0x9BF6, 0x99F2, 0xEA60, 0xFA98, 0xD440, 0xF510, 0xFD44, 0xED70, 0xFB5C, 0x94C0,
+ 0xE530, 0xF94C, 0xDA60, 0xF698, 0xFDA6, 0xCA20, 0xF288, 0xB440, 0xED10, 0xFB44,
+ 0x9AE0, 0xE6B8, 0xF9AE, 0xDD70, 0xF75C, 0x8A60, 0xE298, 0xCD30, 0xF34C, 0xBA60,
+ 0xEE98, 0xFBA6, 0xC510, 0xF144, 0x9A20, 0xE688, 0xF9A2, 0xDD10, 0xF744, 0x8D70,
+ 0xE35C, 0xCEB8, 0xF3AE, 0xBD70, 0xEF5C, 0x8530, 0xE14C, 0xC698, 0xF1A6, 0x9D30,
+ 0xE74C, 0xDE98, 0xF7A6, 0xC288, 0x8D10, 0xE344, 0xCE88, 0xF3A2, 0xBD10, 0xEF44,
+ 0x86B8, 0xE1AE, 0xC75C, 0x9EB8, 0xE7AE, 0xDF5C, 0x8298, 0xC34C, 0x8E98, 0xE3A6,
+ 0xCF4C, 0xBE98, 0xEFA6, 0xC144, 0x8688, 0xE1A2, 0xC744, 0x9E88, 0xE7A2, 0xDF44,
+ 0x835C, 0xC3AE, 0x8F5C, 0xCFAE, 0xBF5C, 0x814C, 0xC1A6, 0x874C, 0xC7A6, 0x9F4C,
+ 0xDFA6, 0x8344, 0xC3A2, 0x8F44, 0xCFA2, 0xBF44, 0xD2E0, 0xF4B8, 0xFD2E, 0xADC0,
+ 0xEB70, 0xFADC, 0xA4C0, 0xE930, 0xFA4C, 0xD660, 0xF598, 0xFD66, 0xD220, 0xF488,
+ 0xFD22, 0xAC40, 0xEB10, 0xFAC4, 0xC970, 0xF25C, 0xB2E0, 0xECB8, 0xFB2E, 0x96E0,
+ 0xE5B8, 0xF96E, 0x9260, 0xE498, 0xF926, 0xD930, 0xF64C, 0xCB30, 0xF2CC, 0xB660,
+ 0xC910, 0xF244, 0xB220, 0xEC88, 0xFB22, 0x9620, 0xE588, 0xF962, 0xDB10, 0xF6C4,
+ 0xC4B8, 0xF12E, 0x9970, 0xE65C, 0xDCB8, 0xF72E, 0x8B70, 0xE2DC, 0x8930, 0xE24C,
+ 0xBB70, 0xCC98, 0xF326, 0xB930, 0xEE4C, 0xC598, 0xF166, 0x9B30, 0xC488, 0xF122,
+ 0x9910, 0xE644, 0xDC88, 0xF722, 0x8B10, 0xE2C4, 0xCD88, 0xF362, 0xBB10, 0xEEC4,
+ 0xC25C, 0x8CB8, 0xE32E, 0xCE5C, 0xBCB8, 0xEF2E, 0x85B8, 0xE16E, 0x8498, 0xE126,
+ 0x9DB8, 0xC64C, 0x9C98, 0xE726, 0xDE4C, 0xC2CC, 0x8D98, 0xC244, 0x8C88, 0xE322,
+ 0xBD98, 0xCE44, 0xBC88, 0xEF22, 0x8588, 0xE162, 0xC6C4, 0x9D88, 0xE762, 0xDEC4,
+ 0xC12E, 0x865C, 0xC72E, 0x9E5C, 0xDF2E, 0x82DC, 0x824C, 0x8EDC, 0xC326, 0x8E4C,
+ 0xBEDC, 0xCF26, 0xBE4C, 0xC166, 0x86CC, 0xC122, 0x8644, 0x9ECC, 0xC722, 0x9E44,
+ 0xDF22, 0x82C4, 0xC362, 0x8EC4, 0xCF62, 0xBEC4, 0x832E, 0x8F2E, 0x816E, 0x8126,
+ 0x876E, 0x8726, 0x9F6E, 0x9F26, 0x8366, 0x8322, 0x8F66, 0x8F22, 0xBF66, 0x8162,
+ 0x8762, 0x9F62, 0xD170, 0xF45C, 0xA6E0, 0xE9B8, 0xFA6E, 0xA260, 0xE898, 0xFA26,
+ 0xD770, 0xF5DC, 0xD330, 0xF4CC, 0xD110, 0xF444, 0xAE60, 0xEB98, 0xFAE6, 0xA620,
+ 0xE988, 0xFA62, 0xD710, 0xF5C4, 0xC8B8, 0xF22E, 0xB170, 0xEC5C, 0x9370, 0xE4DC,
+ 0x9130, 0xE44C, 0xD898, 0xF626, 0xCBB8, 0xF2EE, 0xB770, 0xC998, 0xF266, 0xB330,
+ 0xC888, 0xF222, 0xB110, 0xEC44, 0x9730, 0xE5CC, 0x9310, 0xE4C4, 0xD988, 0xF662,
+ 0xCB88, 0xF2E2, 0xB710, 0xEDC4, 0xC45C, 0x98B8, 0xE62E, 0xDC5C, 0x89B8, 0xE26E,
+ 0x8898, 0xE226, 0xB9B8, 0xCC4C, 0xB898, 0xEE26, 0xC5DC, 0x9BB8, 0xC4CC, 0x9998,
+ 0xC444, 0x9888, 0xE622, 0xDC44, 0x8B98, 0xE2E6, 0x8988, 0xE262, 0xBB98, 0xCCC4,
+ 0xB988, 0xEE62, 0xC5C4, 0x9B88, 0xE6E2, 0xDDC4, 0xC22E, 0x8C5C, 0xCE2E, 0xBC5C,
+ 0x84DC, 0x844C, 0x9CDC, 0xC626, 0x9C4C, 0xDE26, 0xC2EE, 0x8DDC, 0xC266, 0x8CCC,
+ 0xC222, 0xBDDC, 0x8C44, 0xBCCC, 0xCE22, 0xBC44, 0x85CC, 0x84C4, 0x9DCC, 0xC662,
+ 0x9CC4, 0xDE62, 0xC2E2, 0x8DC4, 0xCEE2, 0xBDC4, 0x862E, 0x9E2E, 0x826E, 0x8226,
+ 0x8E6E, 0x8E26, 0xBE6E, 0x86EE, 0x8666, 0x9EEE, 0x8622, 0x9E66, 0x9E22, 0x82E6,
+ 0x8262, 0x8EE6, 0x8E62, 0xBEE6, 0xBE62, 0x86E2, 0x9EE2, 0xD0B8, 0xF42E, 0xA370,
+ 0xE8DC, 0xA130, 0xE84C, 0xD3B8, 0xF4EE, 0xD198, 0xF466, 0xD088, 0xF422, 0xAF70,
+ 0xEBDC, 0xA730, 0xE9CC, 0xA310, 0xE8C4, 0xD798, 0xF5E6, 0xD388, 0xF4E2, 0xAF10,
+ 0xEBC4, 0xC85C, 0xB0B8, 0xEC2E, 0x91B8, 0xE46E, 0x9098, 0xE426, 0xD84C, 0xC9DC,
+ 0xB3B8, 0xC8CC, 0xB198, 0xC844, 0xB088, 0xEC22, 0x97B8, 0xE5EE, 0x9398, 0xE4E6,
+ 0x9188, 0xE462, 0xD8C4, 0xCBCC, 0xB798, 0xC9C4, 0xB388, 0xECE2, 0x9788, 0xE5E2,
+ 0xDBC4, 0xC42E, 0x985C, 0xDC2E, 0x88DC, 0x884C, 0xB8DC, 0xCC26, 0xB84C, 0xC4EE,
+ 0x99DC, 0xC466, 0x98CC, 0xC422, 0x9844, 0xDC22, 0x8BDC, 0x89CC, 0xBBDC, 0x88C4,
+ 0xB9CC, 0xCC62, 0xB8C4, 0xC5E6, 0x9BCC, 0xC4E2, 0x99C4, 0xDCE2, 0x8BC4, 0xCDE2,
+ 0xBBC4, 0x8C2E, 0x846E, 0x8426, 0x9C6E, 0x9C26, 0x8CEE, 0x8C66, 0xBCEE, 0x8C22,
+ 0xBC66, 0x85EE, 0x84E6, 0x9DEE, 0x8462, 0x9CE6, 0x9C62, 0x8DE6, 0x8CE2, 0xBDE6,
+ 0xBCE2, 0x85E2, 0x9DE2, 0xD05C, 0xA1B8, 0xE86E, 0xA098, 0xE826, 0xD1DC, 0xD0CC,
+ 0xD044, 0xA7B8, 0xE9EE, 0xA398, 0xE8E6, 0xA188, 0xE862, 0xD7DC, 0xD3CC, 0xD1C4,
+ 0xAF98, 0xEBE6, 0xA788, 0xE9E2, 0xC82E, 0xB05C, 0x90DC, 0x904C, 0xD826, 0xC8EE,
+ 0xB1DC, 0xC866, 0xB0CC, 0xC822, 0xB044, 0x93DC, 0x91CC, 0x90C4, 0xD862, 0xCBEE,
+ 0xB7DC, 0xC9E6, 0xB3CC, 0xC8E2, 0xB1C4, 0x97CC, 0x93C4, 0xD9E2, 0x982E, 0x886E,
+ 0x8826, 0xB86E, 0x98EE, 0x9866, 0x9822, 0x89EE, 0x88E6, 0xB9EE, 0x8862, 0xB8E6,
+ 0xB862, 0x9BEE, 0x99E6, 0x98E2, 0x8BE6, 0x89E2, 0xBBE6, 0xB9E2, 0xD02E, 0xA0DC,
+ 0xA04C, 0xD0EE, 0xD066, 0xD022, 0xA3DC, 0xA1CC, 0xA0C4, 0xD3EE, 0xD1E6, 0xD0E2,
+ 0xAFDC, 0xA7CC, 0xA3C4, 0x906E, 0x9026, 0xB0EE, 0xB066, 0x91EE, 0x90E6, 0x9062,
+ 0xB3EE, 0xB1E6, 0xB0E2, 0x97EE, 0x93E6, 0x91E2, 0xD4E0, 0xF538, 0xFD4E, 0xA8C0,
+ 0xEA30, 0xFA8C, 0xD420, 0xF508, 0xFD42, 0xDAF0, 0xF6BC, 0xCA70, 0xF29C, 0xB4E0,
+ 0xED38, 0xFB4E, 0x9460, 0xE518, 0xF946, 0xDA30, 0xF68C, 0xCA10, 0xF284, 0xB420,
+ 0xED08, 0xFB42, 0xCD78, 0xF35E, 0xBAF0, 0xEEBC, 0xC538, 0xF14E, 0x9A70, 0xE69C,
+ 0xDD38, 0xF74E, 0x8A30, 0xE28C, 0xCD18, 0xF346, 0xBA30, 0xEE8C, 0xC508, 0xF142,
+ 0x9A10, 0xE684, 0xDD08, 0xF742, 0xC6BC, 0x9D78, 0xE75E, 0xDEBC, 0xC29C, 0x8D38,
+ 0xE34E, 0xCE9C, 0xBD38, 0xEF4E, 0x8518, 0xE146, 0xC68C, 0x9D18, 0xE746, 0xDE8C,
+ 0xC284, 0x8D08, 0xE342, 0xCE84, 0xBD08, 0xEF42, 0xC35E, 0x8EBC, 0xCF5E, 0xBEBC,
+ 0xC14E, 0x869C, 0xC74E, 0x9E9C, 0xDF4E, 0x828C, 0xC346, 0x8E8C, 0xCF46, 0xBE8C,
+ 0xC142, 0x8684, 0xC742, 0x9E84, 0xDF42, 0x875E, 0x9F5E, 0x834E, 0x8F4E, 0xBF4E,
+ 0x8146, 0x8746, 0x9F46, 0x8342, 0x8F42, 0xBF42, 0xE978, 0xFA5E, 0xD6F0, 0xF5BC,
+ 0xD270, 0xF49C, 0xACE0, 0xEB38, 0xFACE, 0xA460, 0xE918, 0xFA46, 0xD630, 0xF58C,
+ 0xD210, 0xF484, 0xAC20, 0xEB08, 0xFAC2, 0x92F0, 0xE4BC, 0xD978, 0xF65E, 0xCB78,
+ 0xF2DE, 0xB6F0, 0xC938, 0xF24E, 0xB270, 0xEC9C, 0x9670, 0xE59C, 0x9230, 0xE48C,
+ 0xD918, 0xF646, 0xCB18, 0xF2C6, 0xB630, 0xC908, 0xF242, 0xB210, 0xEC84, 0x9610,
+ 0xE584, 0xDB08, 0xF6C2, 0x8978, 0xE25E, 0xCCBC, 0xB978, 0xEE5E, 0xC5BC, 0x9B78,
+ 0xC49C, 0x9938, 0xE64E, 0xDC9C, 0x8B38, 0xE2CE, 0x8918, 0xE246, 0xBB38, 0xCC8C,
+ 0xB918, 0xEE46, 0xC58C, 0x9B18, 0xC484, 0x9908, 0xE642, 0xDC84, 0x8B08, 0xE2C2,
+ 0xCD84, 0xBB08, 0xEEC2, 0x84BC, 0xC65E, 0x9CBC, 0xDE5E, 0xC2DE, 0x8DBC, 0xC24E,
+ 0x8C9C, 0xBDBC, 0xCE4E, 0xBC9C, 0x859C, 0x848C, 0x9D9C, 0xC646, 0x9C8C, 0xDE46,
+ 0xC2C6, 0x8D8C, 0xC242, 0x8C84, 0xBD8C, 0xCE42, 0xBC84, 0x8584, 0xC6C2, 0x9D84,
+ 0xDEC2, 0x825E, 0x8E5E, 0xBE5E, 0x86DE, 0x864E, 0x9EDE, 0x9E4E, 0x82CE, 0x8246,
+ 0x8ECE, 0x8E46, 0xBECE, 0xBE46, 0x86C6, 0x8642, 0x9EC6, 0x9E42, 0x82C2, 0x8EC2,
+ 0xBEC2, 0xA2F0, 0xE8BC, 0xD378, 0xF4DE, 0xD138, 0xF44E, 0xAEF0, 0xEBBC, 0xA670,
+ 0xE99C, 0xA230, 0xE88C, 0xD738, 0xF5CE, 0xD318, 0xF4C6, 0xD108, 0xF442, 0xAE30,
+ 0xEB8C, 0xA610, 0xE984, 0xD708, 0xF5C2, 0x9178, 0xE45E, 0xD8BC, 0xC9BC, 0xB378,
+ 0xC89C, 0xB138, 0xEC4E, 0x9778, 0xE5DE, 0x9338, 0xE4CE, 0x9118, 0xE446, 0xD88C,
+ 0xCB9C, 0xB738, 0xC98C, 0xB318, 0xC884, 0xB108, 0xEC42, 0x9718, 0xE5C6, 0x9308,
+ 0xE4C2, 0xD984, 0xCB84, 0xB708, 0xEDC2, 0x88BC, 0xCC5E, 0xB8BC, 0xC4DE, 0x99BC,
+ 0xC44E, 0x989C, 0xDC4E, 0x8BBC, 0x899C, 0xBBBC, 0x888C, 0xB99C, 0xCC46, 0xB88C,
+ 0xC5CE, 0x9B9C, 0xC4C6, 0x998C, 0xC442, 0x9884, 0xDC42, 0x8B8C, 0x8984, 0xBB8C,
+ 0xCCC2, 0xB984, 0xC5C2, 0x9B84, 0xDDC2, 0x845E, 0x9C5E, 0x8CDE, 0x8C4E, 0xBCDE,
+ 0xBC4E, 0x85DE, 0x84CE, 0x9DDE, 0x8446, 0x9CCE, 0x9C46, 0x8DCE, 0x8CC6, 0xBDCE,
+ 0x8C42, 0xBCC6, 0xBC42, 0x85C6, 0x84C2, 0x9DC6, 0x9CC2, 0x8DC2, 0xBDC2, 0xA178,
+ 0xE85E, 0xD1BC, 0xD09C, 0xA778, 0xE9DE, 0xA338, 0xE8CE, 0xA118, 0xE846, 0xD7BC,
+ 0xD39C, 0xD18C, 0xD084, 0xAF38, 0xEBCE, 0xA718, 0xE9C6, 0xA308, 0xE8C2, 0xD78C,
+ 0xD384, 0x90BC, 0xD85E, 0xC8DE, 0xB1BC, 0xC84E, 0xB09C, 0x93BC, 0x919C, 0x908C,
+ 0xD846, 0xCBDE, 0xB7BC, 0xC9CE, 0xB39C, 0xC8C6, 0xB18C, 0xC842, 0xB084, 0x979C,
+ 0x938C, 0x9184, 0xD8C2, 0xCBC6, 0xB78C, 0xC9C2, 0xB384, 0x885E, 0xB85E, 0x98DE,
+ 0x984E, 0x89DE, 0x88CE, 0xB9DE, 0x8846, 0xB8CE, 0xB846, 0x9BDE, 0x99CE, 0x98C6,
+ 0x9842, 0x8BCE, 0x89C6, 0xBBCE, 0x88C2, 0xB9C6, 0xB8C2, 0x9BC6, 0x99C2, 0xA0BC,
+ 0xD0DE, 0xD04E, 0xA3BC, 0xA19C, 0xA08C, 0xD3DE, 0xD1CE, 0xD0C6, 0xD042, 0xAFBC,
+ 0xA79C, 0xA38C, 0xA184, 0xD7CE, 0xD3C6, 0xD1C2, 0x905E, 0xB0DE, 0xB04E, 0x91DE,
+ 0x90CE, 0x9046, 0xB3DE, 0xB1CE, 0xB0C6, 0xB042, 0x97DE, 0x93CE, 0x91C6, 0x90C2,
+ 0xB7CE, 0xB3C6, 0xB1C2, 0xA05E, 0xA1DE, 0xA0CE, 0xA046, 0xA7DE, 0xA3CE, 0xA1C6,
+ 0xA0C2, 0xA9E0, 0xEA78, 0xFA9E, 0xD470, 0xF51C, 0xA860, 0xEA18, 0xFA86, 0xD410,
+ 0xF504, 0xED7C, 0x94F0, 0xE53C, 0xDA78, 0xF69E, 0xCA38, 0xF28E, 0xB470, 0xED1C,
+ 0x9430, 0xE50C, 0xDA18, 0xF686, 0xCA08, 0xF282, 0xB410, 0xED04, 0x9AF8, 0xE6BE,
+ 0xDD7C, 0x8A78, 0xE29E, 0xCD3C, 0xBA78, 0xEE9E, 0xC51C, 0x9A38, 0xE68E, 0xDD1C,
+ 0x8A18, 0xE286, 0xCD0C, 0xBA18, 0xEE86, 0xC504, 0x9A08, 0xE682, 0xDD04, 0x8D7C,
+ 0xCEBE, 0xBD7C, 0x853C, 0xC69E, 0x9D3C, 0xDE9E, 0xC28E, 0x8D1C, 0xCE8E, 0xBD1C,
+ 0x850C, 0xC686, 0x9D0C, 0xDE86, 0xC282, 0x8D04, 0xCE82, 0xBD04, 0x86BE, 0x9EBE,
+ 0x829E, 0x8E9E, 0xBE9E, 0x868E, 0x9E8E, 0x8286, 0x8E86, 0xBE86, 0x8682, 0x9E82,
+ 0xD2F8, 0xF4BE, 0xADF0, 0xEB7C, 0xA4F0, 0xE93C, 0xD678, 0xF59E, 0xD238, 0xF48E,
+ 0xAC70, 0xEB1C, 0xA430, 0xE90C, 0xD618, 0xF586, 0xD208, 0xF482, 0xAC10, 0xEB04,
+ 0xC97C, 0xB2F8, 0xECBE, 0x96F8, 0xE5BE, 0x9278, 0xE49E, 0xD93C, 0xCB3C, 0xB678,
+ 0xC91C, 0xB238, 0xEC8E, 0x9638, 0xE58E, 0x9218, 0xE486, 0xD90C, 0xCB0C, 0xB618,
+ 0xC904, 0xB208, 0xEC82, 0x9608, 0xE582, 0xDB04, 0xC4BE, 0x997C, 0xDCBE, 0x8B7C,
+ 0x893C, 0xBB7C, 0xCC9E, 0xB93C, 0xC59E, 0x9B3C, 0xC48E, 0x991C, 0xDC8E, 0x8B1C,
+ 0x890C, 0xBB1C, 0xCC86, 0xB90C, 0xC586, 0x9B0C, 0xC482, 0x9904, 0xDC82, 0x8B04,
+ 0xCD82, 0xBB04, 0x8CBE, 0xBCBE, 0x85BE, 0x849E, 0x9DBE, 0x9C9E, 0x8D9E, 0x8C8E,
+ 0xBD9E, 0xBC8E, 0x858E, 0x8486, 0x9D8E, 0x9C86, 0x8D86, 0x8C82, 0xBD86, 0xBC82,
+ 0x8582, 0x9D82, 0xD17C, 0xA6F8, 0xE9BE, 0xA278, 0xE89E, 0xD77C, 0xD33C, 0xD11C,
+ 0xAE78, 0xEB9E, 0xA638, 0xE98E, 0xA218, 0xE886, 0xD71C, 0xD30C, 0xD104, 0xAE18,
+ 0xEB86, 0xA608, 0xE982, 0xC8BE, 0xB17C, 0x937C, 0x913C, 0xD89E, 0xCBBE, 0xB77C,
+ 0xC99E, 0xB33C, 0xC88E, 0xB11C, 0x973C, 0x931C, 0x910C, 0xD886, 0xCB8E, 0xB71C,
+ 0xC986, 0xB30C, 0xC882, 0xB104, 0x970C, 0x9304, 0xD982, 0x98BE, 0x89BE, 0x889E,
+ 0xB9BE, 0xB89E, 0x9BBE, 0x999E, 0x988E, 0x8B9E, 0x898E, 0xBB9E, 0x8886, 0xB98E,
+ 0xB886, 0x9B8E, 0x9986, 0x9882, 0x8B86, 0x8982, 0xBB86, 0xB982, 0xD0BE, 0xA37C,
+ 0xA13C, 0xD3BE, 0xD19E, 0xD08E, 0xAF7C, 0xA73C, 0xA31C, 0xA10C, 0xD79E, 0xD38E,
+ 0xD186, 0xD082, 0xAF1C, 0xA70C, 0xA304, 0xB0BE, 0x91BE, 0x909E, 0xB3BE, 0xB19E,
+ 0xB08E, 0x97BE, 0x939E, 0x918E, 0x9086, 0xB79E, 0xB38E, 0xB186, 0xB082, 0x978E,
+ 0x9386, 0x9182, 0xA1BE, 0xA09E, 0xA7BE, 0xA39E, 0xA18E, 0xA086, 0xAF9E, 0xA78E,
+ 0xA386, 0xA182, 0xD4F8, 0xF53E, 0xA8F0, 0xEA3C, 0xD438, 0xF50E, 0xA830, 0xEA0C,
+ 0xD408, 0xF502, 0xDAFC, 0xCA7C, 0xB4F8, 0xED3E, 0x9478, 0xE51E, 0xDA3C, 0xCA1C,
+ 0xB438, 0xED0E, 0x9418, 0xE506, 0xDA0C, 0xCA04, 0xB408, 0xED02, 0xCD7E, 0xBAFC,
+ 0xC53E, 0x9A7C, 0xDD3E, 0x8A3C, 0xCD1E, 0xBA3C, 0xC50E, 0x9A1C, 0xDD0E, 0x8A0C,
+ 0xCD06, 0xBA0C, 0xC502, 0x9A04, 0xDD02, 0x9D7E, 0x8D3E, 0xBD3E, 0x851E, 0x9D1E,
+ 0x8D0E, 0xBD0E, 0x8506, 0x9D06, 0x8D02, 0xBD02, 0xE97E, 0xD6FC, 0xD27C, 0xACF8,
+ 0xEB3E, 0xA478, 0xE91E, 0xD63C, 0xD21C, 0xAC38, 0xEB0E, 0xA418, 0xE906, 0xD60C,
+ 0xD204, 0x92FC, 0xD97E, 0xCB7E, 0xB6FC, 0xC93E, 0xB27C, 0x967C, 0x923C, 0xD91E,
+ 0xCB1E, 0xB63C, 0xC90E, 0xB21C, 0x961C, 0x920C, 0xD906, 0xCB06, 0xB60C, 0xC902,
+ 0xB204, 0x897E, 0xB97E, 0x9B7E, 0x993E, 0x8B3E, 0x891E, 0xBB3E, 0xB91E, 0x9B1E,
+ 0x990E, 0x8B0E, 0x8906, 0xBB0E, 0xB906, 0x9B06, 0x9902, 0xA2FC, 0xD37E, 0xD13E,
+ 0xAEFC
+};
diff --git a/backend/common.c b/backend/common.c
index 72cc3ca..f295099 100644
--- a/backend/common.c
+++ b/backend/common.c
@@ -2,7 +2,7 @@
/*
libzint - the open source barcode library
- Copyright (C) 2008 Robin Stuart <robin@zint.org.uk>
+ Copyright (C) 2008 - 2020 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -28,359 +28,473 @@
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
-*/
-#include <string.h>
+ */
+/* vim: set ts=4 sw=4 et : */
#include <stdio.h>
-#include <stdlib.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
#include "common.h"
-int ustrlen(const unsigned char data[]) {
- /* Local replacement for strlen() with unsigned char strings */
- int i;
- for (i=0;data[i];i++);
-
- return i;
+/* Converts a character 0-9 to its equivalent integer value */
+INTERNAL int ctoi(const char source) {
+ if ((source >= '0') && (source <= '9'))
+ return (source - '0');
+ if ((source >= 'A') && (source <= 'F'))
+ return (source - 'A' + 10);
+ if ((source >= 'a') && (source <= 'f'))
+ return (source - 'a' + 10);
+ return -1;
}
-void ustrcpy(unsigned char target[],const unsigned char source[]) {
- /* Local replacement for strcpy() with unsigned char strings */
- int i, len;
+/* Convert an integer value to a string representing its binary equivalent */
+INTERNAL void bin_append(const int arg, const int length, char *binary) {
+ size_t posn = strlen(binary);
- len = ustrlen(source);
- for(i = 0; i < len; i++) {
- target[i] = source[i];
- }
- target[i] = '\0';
+ bin_append_posn(arg, length, binary, posn);
+
+ binary[posn + length] = '\0';
}
-void concat(char dest[],const char source[])
-{ /* Concatinates dest[] with the contents of source[], copying /0 as well */
- unsigned int i, j, n;
+/* Convert an integer value to a string representing its binary equivalent at a set position */
+INTERNAL void bin_append_posn(const int arg, const int length, char *binary, size_t posn) {
+ int i;
+ int start;
- j = strlen(dest);
- n = strlen(source);
- for(i = 0; i <= n; i++) {
- dest[i + j] = source[i]; }
-}
+ start = 0x01 << (length - 1);
-void uconcat(unsigned char dest[], const unsigned char source[])
-{ /* Concatinates dest[] with the contents of source[], copying /0 as well */
- unsigned int i, j;
+ for (i = 0; i < length; i++) {
+ binary[posn + i] = '0';
+ if (arg & (start >> i)) {
+ binary[posn + i] = '1';
+ }
+ }
+}
- j = ustrlen(dest);
- for(i = 0; i <= ustrlen(source); i++) {
- dest[i + j] = source[i]; }
+/* Converts an integer value to its hexadecimal character */
+INTERNAL char itoc(const int source) {
+ if ((source >= 0) && (source <= 9)) {
+ return ('0' + source);
+ } else {
+ return ('A' + (source - 10));
+ }
}
+/* Converts lower case characters to upper case in a string source[] */
+INTERNAL void to_upper(unsigned char source[]) {
+ size_t i, src_len = ustrlen(source);
-int ctoi(char source)
-{ /* Converts a character 0-9 to its equivalent integer value */
- if((source >= '0') && (source <= '9'))
- return (source - '0');
- return(source - 'A' + 10);
+ for (i = 0; i < src_len; i++) {
+ if ((source[i] >= 'a') && (source[i] <= 'z')) {
+ source [i] = (source[i] - 'a') + 'A';
+ }
+ }
}
-char itoc(int source)
-{ /* Converts an integer value to its hexadecimal character */
- if ((source >= 0) && (source <= 9)) {
- return ('0' + source); }
- else {
- return ('A' + (source - 10)); }
+/* Verifies that a string only uses valid characters */
+INTERNAL int is_sane(const char test_string[], const unsigned char source[], const size_t length) {
+ unsigned int j;
+ size_t i, lt = strlen(test_string);
+
+ for (i = 0; i < length; i++) {
+ unsigned int latch = FALSE;
+ for (j = 0; j < lt; j++) {
+ if (source[i] == test_string[j]) {
+ latch = TRUE;
+ break;
+ }
+ }
+ if (!(latch)) {
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ }
+
+ return 0;
}
-void to_upper(unsigned char source[])
-{ /* Converts lower case characters to upper case in a string source[] */
- unsigned int i, src_len = ustrlen(source);
+/* Replaces huge switch statements for looking up in tables */
+INTERNAL void lookup(const char set_string[], const char *table[], const char data, char dest[]) {
+ size_t i, n = strlen(set_string);
- for (i = 0; i < src_len; i++) {
- if ((source[i] >= 'a') && (source[i] <= 'z')) {
- source [i] = (source[i] - 'a') + 'A'; }
- }
+ for (i = 0; i < n; i++) {
+ if (data == set_string[i]) {
+ strcat(dest, table[i]);
+ }
+ }
}
-int is_sane(char test_string[], unsigned char source[], int length)
-{ /* Verifies that a string only uses valid characters */
- unsigned int i, j, latch;
- unsigned int lt = strlen(test_string);
-
- for(i = 0; i < length; i++) {
- latch = FALSE;
- for(j = 0; j < lt; j++) {
- if (source[i] == test_string[j]) {
- latch = TRUE;
- break;
- }
- }
- if (!(latch)) {
- return ERROR_INVALID_DATA;
- }
- }
-
- return 0;
+/* Returns the position of data in set_string */
+INTERNAL int posn(const char set_string[], const char data) {
+ int i, n = (int)strlen(set_string);
+
+ for (i = 0; i < n; i++) {
+ if (data == set_string[i]) {
+ return i;
+ }
+ }
+ return -1;
}
-int posn(char set_string[], char data)
-{ /* Returns the position of data in set_string */
- unsigned int i, n = strlen(set_string);
+/* Returns the number of times a character occurs in a string */
+INTERNAL int ustrchr_cnt(const unsigned char string[], const size_t length, const unsigned char c) {
+ int count = 0;
+ unsigned int i;
+ for (i = 0; i < length; i++) {
+ if (string[i] == c) {
+ count++;
+ }
+ }
+ return count;
+}
- for(i = 0; i < n; i++) {
- if (data == set_string[i]) { return i; } }
- return 0;
+/* Return true (1) if a module is dark/black/colour, otherwise false (0) */
+INTERNAL int module_is_set(const struct zint_symbol *symbol, const int y_coord, const int x_coord) {
+ if (symbol->symbology == BARCODE_ULTRA) {
+ return symbol->encoded_data[y_coord][x_coord];
+ } else {
+ return (symbol->encoded_data[y_coord][x_coord / 8] >> (x_coord % 8)) & 1;
+ }
}
-void lookup(char set_string[],const char *table[], char data, char dest[])
-{ /* Replaces huge switch statements for looking up in tables */
- unsigned int i, n = strlen(set_string);
+/* Set a module to dark/black */
+INTERNAL void set_module(struct zint_symbol *symbol, const int y_coord, const int x_coord) {
+ symbol->encoded_data[y_coord][x_coord / 8] |= 1 << (x_coord % 8);
+}
- for(i = 0; i < n; i++) {
- if (data == set_string[i]) { concat(dest, table[i]); } }
+/* Set a module to a colour */
+INTERNAL void set_module_colour(struct zint_symbol *symbol, const int y_coord, const int x_coord, const int colour) {
+ symbol->encoded_data[y_coord][x_coord] = colour;
}
-int module_is_set(struct zint_symbol *symbol, int y_coord, int x_coord)
-{
- return (symbol->encoded_data[y_coord][x_coord / 7] >> (x_coord % 7)) & 1;
-#if 0
- switch(x_sub) {
- case 0: if((symbol->encoded_data[y_coord][x_char] & 0x01) != 0) { result = 1; } break;
- case 1: if((symbol->encoded_data[y_coord][x_char] & 0x02) != 0) { result = 1; } break;
- case 2: if((symbol->encoded_data[y_coord][x_char] & 0x04) != 0) { result = 1; } break;
- case 3: if((symbol->encoded_data[y_coord][x_char] & 0x08) != 0) { result = 1; } break;
- case 4: if((symbol->encoded_data[y_coord][x_char] & 0x10) != 0) { result = 1; } break;
- case 5: if((symbol->encoded_data[y_coord][x_char] & 0x20) != 0) { result = 1; } break;
- case 6: if((symbol->encoded_data[y_coord][x_char] & 0x40) != 0) { result = 1; } break;
- }
-
- return result;
-#endif
+/* Set (or unset) a module to white */
+INTERNAL void unset_module(struct zint_symbol *symbol, const int y_coord, const int x_coord) {
+ symbol->encoded_data[y_coord][x_coord / 8] &= ~(1 << (x_coord % 8));
}
-void set_module(struct zint_symbol *symbol, int y_coord, int x_coord)
-{
- symbol->encoded_data[y_coord][x_coord / 7] |= 1 << (x_coord % 7);
-#if 0
- int x_char, x_sub;
-
-
- x_char = x_coord / 7;
- x_sub = x_coord % 7;
-
- switch(x_sub) {
- case 0: symbol->encoded_data[y_coord][x_char] += 0x01; break;
- case 1: symbol->encoded_data[y_coord][x_char] += 0x02; break;
- case 2: symbol->encoded_data[y_coord][x_char] += 0x04; break;
- case 3: symbol->encoded_data[y_coord][x_char] += 0x08; break;
- case 4: symbol->encoded_data[y_coord][x_char] += 0x10; break;
- case 5: symbol->encoded_data[y_coord][x_char] += 0x20; break;
- case 6: symbol->encoded_data[y_coord][x_char] += 0x40; break;
- } /* The last binary digit is reserved for colour barcodes */
-#endif
+/* Expands from a width pattern to a bit pattern */
+INTERNAL void expand(struct zint_symbol *symbol, const char data[]) {
+
+ size_t reader, n = strlen(data);
+ int writer, i;
+ char latch;
+
+ writer = 0;
+ latch = '1';
+
+ for (reader = 0; reader < n; reader++) {
+ for (i = 0; i < ctoi(data[reader]); i++) {
+ if (latch == '1') {
+ set_module(symbol, symbol->rows, writer);
+ }
+ writer++;
+ }
+
+ latch = (latch == '1' ? '0' : '1');
+ }
+
+ if (symbol->symbology != BARCODE_PHARMA) {
+ if (writer > symbol->width) {
+ symbol->width = writer;
+ }
+ } else {
+ /* Pharmacode One ends with a space - adjust for this */
+ if (writer > symbol->width + 2) {
+ symbol->width = writer - 2;
+ }
+ }
+ symbol->rows = symbol->rows + 1;
}
-void unset_module(struct zint_symbol *symbol, int y_coord, int x_coord)
-{
- symbol->encoded_data[y_coord][x_coord / 7] &= ~(1 << (x_coord % 7));
-#if 0
- int x_char, x_sub;
-
- x_char = x_coord / 7;
- x_sub = x_coord % 7;
-
- switch(x_sub) {
- case 0: symbol->encoded_data[y_coord][x_char] -= 0x01; break;
- case 1: symbol->encoded_data[y_coord][x_char] -= 0x02; break;
- case 2: symbol->encoded_data[y_coord][x_char] -= 0x04; break;
- case 3: symbol->encoded_data[y_coord][x_char] -= 0x08; break;
- case 4: symbol->encoded_data[y_coord][x_char] -= 0x10; break;
- case 5: symbol->encoded_data[y_coord][x_char] -= 0x20; break;
- case 6: symbol->encoded_data[y_coord][x_char] -= 0x40; break;
- } /* The last binary digit is reserved for colour barcodes */
-#endif
+/* Indicates which symbologies can have row binding
+ * Note: if change this must also change version in frontend/main.c */
+INTERNAL int is_stackable(const int symbology) {
+ if (symbology < BARCODE_PDF417) {
+ return 1;
+ }
+
+ switch (symbology) {
+ case BARCODE_CODE128B:
+ case BARCODE_ISBNX:
+ case BARCODE_EAN14:
+ case BARCODE_NVE18:
+ case BARCODE_KOREAPOST:
+ case BARCODE_PLESSEY:
+ case BARCODE_TELEPEN_NUM:
+ case BARCODE_ITF14:
+ case BARCODE_CODE32:
+ case BARCODE_CODABLOCKF:
+ case BARCODE_HIBC_BLOCKF:
+ return 1;
+ }
+
+ return 0;
}
-void expand(struct zint_symbol *symbol, char data[])
-{ /* Expands from a width pattern to a bit pattern */
-
- unsigned int reader, n = strlen(data);
- int writer, i;
- char latch;
-
- writer = 0;
- latch = '1';
-
- for(reader = 0; reader < n; reader++) {
- for(i = 0; i < ctoi(data[reader]); i++) {
- if(latch == '1') { set_module(symbol, symbol->rows, writer); }
- writer++;
- }
-
- latch = (latch == '1' ? '0' : '1');
- }
-
- if(symbol->symbology != BARCODE_PHARMA) {
- if(writer > symbol->width) {
- symbol->width = writer;
- }
- } else {
- /* Pharmacode One ends with a space - adjust for this */
- if(writer > symbol->width + 2) {
- symbol->width = writer - 2;
- }
- }
- symbol->rows = symbol->rows + 1;
+/* Indicates which symbols can have addon (EAN-2 and EAN-5) */
+INTERNAL int is_extendable(const int symbology) {
+ if (symbology == BARCODE_EANX || symbology == BARCODE_EANX_CHK) {
+ return 1;
+ }
+ if (symbology == BARCODE_UPCA || symbology == BARCODE_UPCA_CHK) {
+ return 1;
+ }
+ if (symbology == BARCODE_UPCE || symbology == BARCODE_UPCE_CHK) {
+ return 1;
+ }
+ if (symbology == BARCODE_ISBNX) {
+ return 1;
+ }
+ if (symbology == BARCODE_UPCA_CC) {
+ return 1;
+ }
+ if (symbology == BARCODE_UPCE_CC) {
+ return 1;
+ }
+ if (symbology == BARCODE_EANX_CC) {
+ return 1;
+ }
+
+ return 0;
}
-int is_stackable(int symbology) {
- /* Indicates which symbologies can have row binding */
- if(symbology < BARCODE_PDF417) { return 1; }
- if(symbology == BARCODE_CODE128B) { return 1; }
- if(symbology == BARCODE_ISBNX) { return 1; }
- if(symbology == BARCODE_EAN14) { return 1; }
- if(symbology == BARCODE_NVE18) { return 1; }
- if(symbology == BARCODE_KOREAPOST) { return 1; }
- if(symbology == BARCODE_PLESSEY) { return 1; }
- if(symbology == BARCODE_TELEPEN_NUM) { return 1; }
- if(symbology == BARCODE_ITF14) { return 1; }
- if(symbology == BARCODE_CODE32) { return 1; }
-
- return 0;
+/* Indicates which symbols can have composite 2D component data */
+INTERNAL int is_composite(int symbology) {
+ return symbology >= BARCODE_EANX_CC && symbology <= BARCODE_RSS_EXPSTACK_CC;
}
-int is_extendable(int symbology) {
- /* Indicates which symbols can have addon */
- if(symbology == BARCODE_EANX) { return 1; }
- if(symbology == BARCODE_UPCA) { return 1; }
- if(symbology == BARCODE_UPCE) { return 1; }
- if(symbology == BARCODE_ISBNX) { return 1; }
- if(symbology == BARCODE_UPCA_CC) { return 1; }
- if(symbology == BARCODE_UPCE_CC) { return 1; }
- if(symbology == BARCODE_EANX_CC) { return 1; }
-
- return 0;
+INTERNAL int istwodigits(const unsigned char source[], const int length, const int position) {
+ if ((position + 1 < length) && (source[position] >= '0') && (source[position] <= '9')
+ && (source[position + 1] >= '0') && (source[position + 1] <= '9')) {
+ return 1;
+ }
+
+ return 0;
}
-int roundup(float input)
-{
- float remainder;
- int integer_part;
-
- integer_part = (int)input;
- remainder = input - integer_part;
-
- if(remainder > 0.1) {
- integer_part++;
- }
-
- return integer_part;
+/* State machine to decode UTF-8 to Unicode codepoints (state 0 means done, state 12 means error) */
+INTERNAL unsigned int decode_utf8(unsigned int* state, unsigned int* codep, const unsigned char byte) {
+ /*
+ Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+ modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+ See https://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
+ */
+
+ static const unsigned char utf8d[] = {
+ /* The first part of the table maps bytes to character classes that
+ * reduce the size of the transition table and create bitmasks. */
+ 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,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,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,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,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+
+ /* The second part is a transition table that maps a combination
+ * of a state of the automaton and a character class to a state. */
+ 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
+ 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
+ 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
+ 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
+ 12,36,12,12,12,12,12,12,12,12,12,12,
+ };
+
+ unsigned int type = utf8d[byte];
+
+ *codep = *state != 0 ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & byte;
+
+ *state = utf8d[256 + *state + type];
+
+ return *state;
}
-int istwodigits(unsigned char source[], int position)
-{
- if((source[position] >= '0') && (source[position] <= '9')) {
- if((source[position + 1] >= '0') && (source[position + 1] <= '9')) {
- return 1;
- }
- }
-
- return 0;
+/* Convert UTF-8 to Unicode. If `disallow_4byte` unset, allow all values (UTF-32).
+ * If `disallow_4byte` set, only allow codepoints <= U+FFFF (ie four-byte sequences not allowed) (UTF-16, no surrogates) */
+INTERNAL int utf8_to_unicode(struct zint_symbol *symbol, const unsigned char source[], unsigned int vals[], size_t *length, int disallow_4byte) {
+ size_t bpos;
+ int jpos;
+ unsigned int codepoint, state = 0;
+
+ bpos = 0;
+ jpos = 0;
+
+ while (bpos < *length) {
+ do {
+ decode_utf8(&state, &codepoint, source[bpos++]);
+ } while (bpos < *length && state != 0 && state != 12);
+
+ if (state != 0) {
+ strcpy(symbol->errtxt, "240: Corrupt Unicode data");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ if (disallow_4byte && codepoint > 0xffff) {
+ strcpy(symbol->errtxt, "242: Unicode sequences of more than 3 bytes not supported");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ vals[jpos] = codepoint;
+ jpos++;
+ }
+
+ *length = jpos;
+
+ return 0;
}
-float froundup(float input)
-{
- float fraction, output = 0.0;
-
- fraction = input - (int)input;
- if(fraction > 0.01) { output = (input - fraction) + 1.0; } else { output = input; }
-
- return output;
+/* Enforce minimum permissable height of rows */
+INTERNAL void set_minimum_height(struct zint_symbol *symbol, const int min_height) {
+ int fixed_height = 0;
+ int zero_count = 0;
+ int i;
+
+ for (i = 0; i < symbol->rows; i++) {
+ fixed_height += symbol->row_height[i];
+
+ if (symbol->row_height[i] == 0) {
+ zero_count++;
+ }
+ }
+
+ if (zero_count > 0) {
+ if (((symbol->height - fixed_height) / zero_count) < min_height) {
+ for (i = 0; i < symbol->rows; i++) {
+ if (symbol->row_height[i] == 0) {
+ symbol->row_height[i] = min_height;
+ }
+ }
+ }
+ }
}
-int latin1_process(unsigned char source[], unsigned char preprocessed[], int *length)
-{
- int j, i, next;
-
- /* Convert Unicode to Latin-1 for those symbologies which only support Latin-1 */
- j = 0;
- i = 0;
- if (length && *length) {
- do {
- next = -1;
- if(source[i] < 128) {
- preprocessed[j] = source[i];
- j++;
- next = i + 1;
- } else {
- if(source[i] == 0xC2) {
- preprocessed[j] = source[i + 1];
- j++;
- next = i + 2;
- }
- if(source[i] == 0xC3) {
- preprocessed[j] = source[i + 1] + 64;
- j++;
- next = i + 2;
- }
- }
- if(next == -1) {
- return ERROR_INVALID_DATA;
- }
- i = next;
- } while(i < *length);
- preprocessed[j] = '\0';
- *length = j;
- }
-
- return 0;
+/* Calculate optimized encoding modes. Adapted from Project Nayuki */
+INTERNAL void pn_define_mode(char* mode, const unsigned int data[], const size_t length, const int debug,
+ unsigned int state[], const char mode_types[], const int num_modes, pn_head_costs head_costs, pn_switch_cost switch_cost, pn_eod_cost eod_cost, pn_cur_cost cur_cost) {
+ /*
+ * Copyright (c) Project Nayuki. (MIT License)
+ * https://www.nayuki.io/page/qr-code-generator-library
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * - The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+ int i, j, k, cm_i;
+ unsigned int min_cost;
+ char cur_mode;
+#ifndef _MSC_VER
+ unsigned int prev_costs[num_modes];
+ char char_modes[length * num_modes];
+ unsigned int cur_costs[num_modes];
+#else
+ unsigned int* prev_costs;
+ char* char_modes;
+ unsigned int* cur_costs;
+ prev_costs = (unsigned int*) _alloca(num_modes * sizeof(unsigned int));
+ char_modes = (char*) _alloca(length * num_modes);
+ cur_costs = (unsigned int*) _alloca(num_modes * sizeof(unsigned int));
+#endif
+
+ /* char_modes[i * num_modes + j] represents the mode to encode the code point at index i such that the final
+ * segment ends in mode_types[j] and the total number of bits is minimized over all possible choices */
+ memset(char_modes, 0, length * num_modes);
+
+ /* At the beginning of each iteration of the loop below, prev_costs[j] is the minimum number of 1/6 (1/XX_MULT)
+ * bits needed to encode the entire string prefix of length i, and end in mode_types[j] */
+ memcpy(prev_costs, (*head_costs)(state), num_modes * sizeof(unsigned int));
+
+ /* Calculate costs using dynamic programming */
+ for (i = 0, cm_i = 0; i < (int) length; i++, cm_i += num_modes) {
+ memset(cur_costs, 0, num_modes * sizeof(unsigned int));
+
+ (*cur_cost)(state, data, length, i, char_modes, prev_costs, cur_costs);
+
+ if (eod_cost && i == (int) length - 1) { /* Add end of data costs if last character */
+ for (j = 0; j < num_modes; j++) {
+ if (char_modes[cm_i + j]) {
+ cur_costs[j] += (*eod_cost)(state, j);
+ }
+ }
+ }
+
+ /* Start new segment at the end to switch modes */
+ for (j = 0; j < num_modes; j++) { /* To mode */
+ for (k = 0; k < num_modes; k++) { /* From mode */
+ if (j != k && char_modes[cm_i + k]) {
+ unsigned int new_cost = cur_costs[k] + (*switch_cost)(state, k, j);
+ if (!char_modes[cm_i + j] || new_cost < cur_costs[j]) {
+ cur_costs[j] = new_cost;
+ char_modes[cm_i + j] = mode_types[k];
+ }
+ }
+ }
+ }
+
+ memcpy(prev_costs, cur_costs, num_modes * sizeof(unsigned int));
+ }
+
+ /* Find optimal ending mode */
+ min_cost = prev_costs[0];
+ cur_mode = mode_types[0];
+ for (i = 1; i < num_modes; i++) {
+ if (prev_costs[i] < min_cost) {
+ min_cost = prev_costs[i];
+ cur_mode = mode_types[i];
+ }
+ }
+
+ /* Get optimal mode for each code point by tracing backwards */
+ for (i = length - 1, cm_i = i * num_modes; i >= 0; i--, cm_i -= num_modes) {
+ j = strchr(mode_types, cur_mode) - mode_types;
+ cur_mode = char_modes[cm_i + j];
+ mode[i] = cur_mode;
+ }
+
+ if (debug & ZINT_DEBUG_PRINT) {
+ printf(" Mode: %.*s\n", (int)length, mode);
+ }
}
-int utf8toutf16(struct zint_symbol *symbol, unsigned char source[], int vals[], int *length)
-{
- int bpos, jpos, error_number;
- int next;
-
- bpos = 0;
- jpos = 0;
- error_number = 0;
- next = 0;
-
- do {
- if(source[bpos] <= 0x7f) {
- /* 1 byte mode (7-bit ASCII) */
- vals[jpos] = source[bpos];
- next = bpos + 1;
- jpos++;
- } else {
- if((source[bpos] >= 0x80) && (source[bpos] <= 0xbf)) {
- strcpy(symbol->errtxt, "Corrupt Unicode data");
- return ERROR_INVALID_DATA;
- }
- if((source[bpos] >= 0xc0) && (source[bpos] <= 0xc1)) {
- strcpy(symbol->errtxt, "Overlong encoding not supported");
- return ERROR_INVALID_DATA;
- }
-
- if((source[bpos] >= 0xc2) && (source[bpos] <= 0xdf)) {
- /* 2 byte mode */
- vals[jpos] = ((source[bpos] & 0x1f) << 6) + (source[bpos + 1] & 0x3f);
- next = bpos + 2;
- jpos++;
- } else
- if((source[bpos] >= 0xe0) && (source[bpos] <= 0xef)) {
- /* 3 byte mode */
- vals[jpos] = ((source[bpos] & 0x0f) << 12) + ((source[bpos + 1] & 0x3f) << 6) + (source[bpos + 2] & 0x3f);
- next = bpos + 3;
- jpos ++;
- } else
- if(source[bpos] >= 0xf0) {
- strcpy(symbol->errtxt, "Unicode sequences of more than 3 bytes not supported");
- return ERROR_INVALID_DATA;
- }
- }
-
- bpos = next;
-
- } while(bpos < *length);
- *length = jpos;
-
- return error_number;
+#ifdef ZINT_TEST
+/* Dumps hex-formatted codewords in symbol->errtxt (for use in testing) */
+void debug_test_codeword_dump(struct zint_symbol *symbol, unsigned char* codewords, int length) {
+ int i, max = length, cnt_len = 0;
+ if (length > 30) { /* 30*3 < errtxt 92 (100 - "Warning ") chars */
+ sprintf(symbol->errtxt, "(%d) ", length); /* Place the number of codewords at the front */
+ cnt_len = strlen(symbol->errtxt);
+ max = 30 - (cnt_len + 2) / 3;
+ }
+ for (i = 0; i < max; i++) {
+ sprintf(symbol->errtxt + cnt_len + i * 3, "%02X ", codewords[i]);
+ }
+ symbol->errtxt[strlen(symbol->errtxt) - 1] = '\0'; /* Zap last space */
}
+void debug_test_codeword_dump_int(struct zint_symbol *symbol, int* codewords, int length) {
+ int i, max = 0, cnt_len, errtxt_len;
+ char temp[20];
+ errtxt_len = sprintf(symbol->errtxt, "(%d) ", length); /* Place the number of codewords at the front */
+ for (i = 0, cnt_len = errtxt_len; i < length; i++) {
+ cnt_len += sprintf(temp, "%d ", codewords[i]);
+ if (cnt_len > 92) {
+ break;
+ }
+ max++;
+ }
+ for (i = 0; i < max; i++) {
+ errtxt_len += sprintf(symbol->errtxt + errtxt_len, "%d ", codewords[i]);
+ }
+ symbol->errtxt[strlen(symbol->errtxt) - 1] = '\0'; /* Zap last space */
+}
+#endif
diff --git a/backend/common.h b/backend/common.h
index d7fead9..649eaeb 100644
--- a/backend/common.h
+++ b/backend/common.h
@@ -2,7 +2,7 @@
/*
libzint - the open source barcode library
- Copyright (C) 2009 Robin Stuart <robin@zint.org.uk>
+ Copyright (C) 2009 - 2020 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -28,52 +28,83 @@
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
-*/
+ */
+/* vim: set ts=4 sw=4 et : */
/* Used in some logic */
#ifndef __COMMON_H
#define __COMMON_H
#ifndef FALSE
-#define FALSE 0
+#define FALSE 0
#endif
#ifndef TRUE
-#define TRUE 1
+#define TRUE 1
#endif
/* The most commonly used set */
-#define NEON "0123456789"
+#define NEON "0123456789"
#include "zint.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* Helpers to cast away char pointer signedness */
+#define ustrlen(source) strlen((const char *) (source))
+#define ustrcpy(target, source) strcpy((char *) (target), (const char *) (source))
+#define ustrcat(target, source) strcat((char *) (target), (const char *) (source))
+
+#if defined(__GNUC__) && !defined(_WIN32) && !defined(ZINT_TEST)
+#define INTERNAL __attribute__ ((visibility ("hidden")))
+#else
+#define INTERNAL
+#endif
+
+#if defined(ZINT_TEST)
+#define STATIC_UNLESS_ZINT_TEST
+#else
+#define STATIC_UNLESS_ZINT_TEST static
+#endif
#ifdef __cplusplus
-extern "C"
-{
+extern "C" {
#endif /* __cplusplus */
-extern int ustrlen(const unsigned char source[]);
-extern void ustrcpy(unsigned char target[], const unsigned char source[]);
-extern void concat(char dest[], const char source[]);
-extern void uconcat(unsigned char dest[], const unsigned char source[]);
-extern int ctoi(char source);
-extern char itoc(int source);
-extern void to_upper(unsigned char source[]);
-extern int is_sane(char test_string[], unsigned char source[], int length);
-extern void lookup(char set_string[],const char *table[], char data, char dest[]);
-extern int posn(char set_string[], char data);
-extern void expand(struct zint_symbol *symbol, char data[]);
-extern int is_stackable(int symbology);
-extern int is_extendable(int symbology);
-extern int roundup(float input);
-extern int module_is_set(struct zint_symbol *symbol, int y_coord, int x_coord);
-extern void set_module(struct zint_symbol *symbol, int y_coord, int x_coord);
-extern void unset_module(struct zint_symbol *symbol, int y_coord, int x_coord);
-extern int istwodigits(unsigned char source[], int position);
-extern float froundup(float input);
-extern int parunmodd(unsigned char llyth);
-extern int latin1_process(unsigned char source[], unsigned char preprocessed[], int *length);
-extern int utf8toutf16(struct zint_symbol *symbol, unsigned char source[], int vals[], int *length);
+ INTERNAL int ctoi(const char source);
+ INTERNAL char itoc(const int source);
+ INTERNAL void to_upper(unsigned char source[]);
+ INTERNAL int is_sane(const char test_string[], const unsigned char source[], const size_t length);
+ INTERNAL void lookup(const char set_string[], const char *table[], const char data, char dest[]);
+ INTERNAL void bin_append(const int arg, const int length, char *binary);
+ INTERNAL void bin_append_posn(const int arg, const int length, char *binary, size_t posn);
+ INTERNAL int posn(const char set_string[], const char data);
+ INTERNAL int ustrchr_cnt(const unsigned char string[], const size_t length, const unsigned char c);
+ INTERNAL int module_is_set(const struct zint_symbol *symbol, const int y_coord, const int x_coord);
+ INTERNAL void set_module(struct zint_symbol *symbol, const int y_coord, const int x_coord);
+ INTERNAL void set_module_colour(struct zint_symbol *symbol, const int y_coord, const int x_coord, const int colour);
+ INTERNAL void unset_module(struct zint_symbol *symbol, const int y_coord, const int x_coord);
+ INTERNAL void expand(struct zint_symbol *symbol, const char data[]);
+ INTERNAL int is_stackable(const int symbology);
+ INTERNAL int is_extendable(const int symbology);
+ INTERNAL int is_composite(const int symbology);
+ INTERNAL int istwodigits(const unsigned char source[], int length, const int position);
+ INTERNAL unsigned int decode_utf8(unsigned int* state, unsigned int* codep, const unsigned char byte);
+ INTERNAL int utf8_to_unicode(struct zint_symbol *symbol, const unsigned char source[], unsigned int vals[], size_t *length, int disallow_4byte);
+ INTERNAL void set_minimum_height(struct zint_symbol *symbol, const int min_height);
+
+ typedef unsigned int* (*pn_head_costs)(unsigned int state[]);
+ typedef unsigned int (*pn_switch_cost)(unsigned int state[], const int k, const int j);
+ typedef unsigned int (*pn_eod_cost)(unsigned int state[], const int k);
+ typedef void (*pn_cur_cost)(unsigned int state[], const unsigned int data[], const size_t length, const int i, char* char_modes, unsigned int prev_costs[], unsigned int cur_costs[]);
+ INTERNAL void pn_define_mode(char* mode, const unsigned int data[], const size_t length, const int debug,
+ unsigned int state[], const char mode_types[], const int num_modes, pn_head_costs head_costs, pn_switch_cost switch_cost, pn_eod_cost eod_cost, pn_cur_cost cur_cost);
+
+ #ifdef ZINT_TEST
+ void debug_test_codeword_dump(struct zint_symbol *symbol, unsigned char* codewords, int length);
+ void debug_test_codeword_dump_int(struct zint_symbol *symbol, int* codewords, int length);
+ #endif
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/backend/composite.c b/backend/composite.c
new file mode 100644
index 0000000..1184965
--- /dev/null
+++ b/backend/composite.c
@@ -0,0 +1,1668 @@
+/* composite.c - Handles GS1 Composite Symbols */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2008-2019 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+/* The functions "getBit", "init928" and "encode928" are copyright BSI and are
+ released with permission under the following terms:
+
+ "Copyright subsists in all BSI publications. BSI also holds the copyright, in the
+ UK, of the international standardisation bodies. Except as
+ permitted under the Copyright, Designs and Patents Act 1988 no extract may be
+ reproduced, stored in a retrieval system or transmitted in any form or by any
+ means - electronic, photocopying, recording or otherwise - without prior written
+ permission from BSI.
+
+ "This does not preclude the free use, in the course of implementing the standard,
+ of necessary details such as symbols, and size, type or grade designations. If these
+ details are to be used for any other purpose than implementation then the prior
+ written permission of BSI must be obtained."
+
+ The date of publication for these functions is 31 May 2006
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "composite.h"
+#include "pdf417.h"
+#include "gs1.h"
+#include "general_field.h"
+
+#define UINT unsigned short
+
+INTERNAL int eanx(struct zint_symbol *symbol, unsigned char source[], int length);
+INTERNAL int ean_128(struct zint_symbol *symbol, unsigned char source[], const size_t length);
+INTERNAL void ean_leading_zeroes(struct zint_symbol *symbol, unsigned char source[], unsigned char local_source[]);
+INTERNAL int rss14(struct zint_symbol *symbol, unsigned char source[], int length);
+INTERNAL int rsslimited(struct zint_symbol *symbol, unsigned char source[], int length);
+INTERNAL int rssexpanded(struct zint_symbol *symbol, unsigned char source[], int length);
+
+static UINT pwr928[69][7];
+
+static int _min(int first, int second) {
+
+ if (first <= second)
+ return first;
+ else
+ return second;
+}
+
+/* gets bit in bitString at bitPos */
+static int getBit(UINT *bitStr, int bitPos) {
+ return !!(bitStr[bitPos >> 4] & (0x8000 >> (bitPos & 15)));
+}
+
+/* initialize pwr928 encoding table */
+static void init928(void) {
+ int i, j, v;
+ int cw[7];
+ cw[6] = 1L;
+ for (i = 5; i >= 0; i--)
+ cw[i] = 0;
+
+ for (i = 0; i < 7; i++)
+ pwr928[0][i] = cw[i];
+ for (j = 1; j < 69; j++) {
+ for (v = 0, i = 6; i >= 1; i--) {
+ v = (2 * cw[i]) + (v / 928);
+ pwr928[j][i] = cw[i] = v % 928;
+ }
+ pwr928[j][0] = cw[0] = (2 * cw[0]) + (v / 928);
+ }
+ return;
+}
+
+/* converts bit string to base 928 values, codeWords[0] is highest order */
+static int encode928(UINT bitString[], UINT codeWords[], int bitLng) {
+ int i, j, b, cwNdx, cwLng;
+ for (cwNdx = cwLng = b = 0; b < bitLng; b += 69, cwNdx += 7) {
+ int bitCnt = _min(bitLng - b, 69);
+ int cwCnt;
+ cwLng += cwCnt = bitCnt / 10 + 1;
+ for (i = 0; i < cwCnt; i++)
+ codeWords[cwNdx + i] = 0; /* init 0 */
+ for (i = 0; i < bitCnt; i++) {
+ if (getBit(bitString, b + bitCnt - i - 1)) {
+ for (j = 0; j < cwCnt; j++)
+ codeWords[cwNdx + j] += pwr928[i][j + 7 - cwCnt];
+ }
+ }
+ for (i = cwCnt - 1; i > 0; i--) {
+ /* add "carries" */
+ codeWords[cwNdx + i - 1] += codeWords[cwNdx + i] / 928L;
+ codeWords[cwNdx + i] %= 928L;
+ }
+ }
+ return (cwLng);
+}
+
+/* CC-A 2D component */
+static int cc_a(struct zint_symbol *symbol, char source[], int cc_width) {
+ int i, segment, bitlen, cwCnt, variant, rows;
+ int k, offset, j, total, rsCodeWords[8];
+ int LeftRAPStart, RightRAPStart, CentreRAPStart, StartCluster;
+ int LeftRAP, RightRAP, CentreRAP, Cluster, dummy[5];
+ int loop;
+ UINT codeWords[28];
+ UINT bitStr[13];
+ char pattern[580];
+ char local_source[210]; /* A copy of source but with padding zeroes to make 208 bits */
+
+ variant = 0;
+
+ for (i = 0; i < 13; i++) {
+ bitStr[i] = 0;
+ }
+ for (i = 0; i < 28; i++) {
+ codeWords[i] = 0;
+ }
+
+ bitlen = (int)strlen(source);
+
+ for (i = 0; i < 208; i++) {
+ local_source[i] = '0';
+ }
+ for (i = 0; i < bitlen; i++) {
+ local_source[i] = source[i];
+ }
+ local_source[208] = '\0';
+
+ for (segment = 0; segment < 13; segment++) {
+ int strpos = segment * 16;
+ for (i = 0; i < 16; i++) {
+ if (local_source[strpos + i] == '1') {
+ bitStr[segment] += (0x8000 >> i);
+ }
+ }
+ }
+
+ init928();
+ /* encode codeWords from bitStr */
+ cwCnt = encode928(bitStr, codeWords, bitlen);
+
+ switch (cc_width) {
+ case 2:
+ switch (cwCnt) {
+ case 6: variant = 0;
+ break;
+ case 8: variant = 1;
+ break;
+ case 9: variant = 2;
+ break;
+ case 11: variant = 3;
+ break;
+ case 12: variant = 4;
+ break;
+ case 14: variant = 5;
+ break;
+ case 17: variant = 6;
+ break;
+ }
+ break;
+ case 3:
+ switch (cwCnt) {
+ case 8: variant = 7;
+ break;
+ case 10: variant = 8;
+ break;
+ case 12: variant = 9;
+ break;
+ case 14: variant = 10;
+ break;
+ case 17: variant = 11;
+ break;
+ }
+ break;
+ case 4:
+ switch (cwCnt) {
+ case 8: variant = 12;
+ break;
+ case 11: variant = 13;
+ break;
+ case 14: variant = 14;
+ break;
+ case 17: variant = 15;
+ break;
+ case 20: variant = 16;
+ break;
+ }
+ break;
+ }
+
+ rows = ccaVariants[variant];
+ k = ccaVariants[17 + variant];
+ offset = ccaVariants[34 + variant];
+
+ /* Reed-Solomon error correction */
+
+ for (i = 0; i < 8; i++) {
+ rsCodeWords[i] = 0;
+ }
+ for (i = 0; i < cwCnt; i++) {
+ total = (codeWords[i] + rsCodeWords[k - 1]) % 929;
+ for (j = k - 1; j >= 0; j--) {
+ if (j == 0) {
+ rsCodeWords[j] = (929 - (total * ccaCoeffs[offset + j]) % 929) % 929;
+ } else {
+ rsCodeWords[j] = (rsCodeWords[j - 1] + 929 - (total * ccaCoeffs[offset + j]) % 929) % 929;
+ }
+ }
+ }
+
+ for (j = 0; j < k; j++) {
+ if (rsCodeWords[j] != 0) {
+ rsCodeWords[j] = 929 - rsCodeWords[j];
+ }
+ }
+
+ for (i = k - 1; i >= 0; i--) {
+ codeWords[cwCnt] = rsCodeWords[i];
+ cwCnt++;
+ }
+
+ /* Place data into table */
+ LeftRAPStart = aRAPTable[variant];
+ CentreRAPStart = aRAPTable[variant + 17];
+ RightRAPStart = aRAPTable[variant + 34];
+ StartCluster = aRAPTable[variant + 51] / 3;
+
+ LeftRAP = LeftRAPStart;
+ CentreRAP = CentreRAPStart;
+ RightRAP = RightRAPStart;
+ Cluster = StartCluster; /* Cluster can be 0, 1 or 2 for Cluster(0), Cluster(3) and Cluster(6) */
+
+ for (i = 0; i < rows; i++) {
+ strcpy(pattern, "");
+ offset = 929 * Cluster;
+ for (j = 0; j < 5; j++) {
+ dummy[j] = 0;
+ }
+ for (j = 0; j < cc_width; j++) {
+ dummy[j + 1] = codeWords[i * cc_width + j];
+ }
+ /* Copy the data into codebarre */
+ if (cc_width != 3) {
+ bin_append(rap_side[LeftRAP - 1], 10, pattern);
+ }
+ bin_append(pdf_bitpattern[offset + dummy[1]], 16, pattern);
+ strcat(pattern, "0");
+ if (cc_width == 3) {
+ bin_append(rap_centre[CentreRAP - 1], 10, pattern);
+ }
+ if (cc_width >= 2) {
+ bin_append(pdf_bitpattern[offset + dummy[2]], 16, pattern);
+ strcat(pattern, "0");
+ }
+ if (cc_width == 4) {
+ bin_append(rap_centre[CentreRAP - 1], 10, pattern);
+ }
+ if (cc_width >= 3) {
+ bin_append(pdf_bitpattern[offset + dummy[3]], 16, pattern);
+ strcat(pattern, "0");
+ }
+ if (cc_width == 4) {
+ bin_append(pdf_bitpattern[offset + dummy[4]], 16, pattern);
+ strcat(pattern, "0");
+ }
+ bin_append(rap_side[RightRAP - 1], 10, pattern);
+ strcat(pattern, "1"); /* stop */
+
+ /* so now pattern[] holds the string of '1's and '0's. - copy this to the symbol */
+ for (loop = 0; loop < (int) strlen(pattern); loop++) {
+ if (pattern[loop] == '1') {
+ set_module(symbol, i, loop);
+ }
+ }
+ symbol->row_height[i] = 2;
+ symbol->rows++;
+ symbol->width = strlen(pattern);
+
+ /* Set up RAPs and Cluster for next row */
+ LeftRAP++;
+ CentreRAP++;
+ RightRAP++;
+ Cluster++;
+
+ if (LeftRAP == 53) {
+ LeftRAP = 1;
+ }
+ if (CentreRAP == 53) {
+ CentreRAP = 1;
+ }
+ if (RightRAP == 53) {
+ RightRAP = 1;
+ }
+ if (Cluster == 3) {
+ Cluster = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* CC-B 2D component */
+static int cc_b(struct zint_symbol *symbol, char source[], int cc_width) {
+ int length, i;
+#ifndef _MSC_VER
+ unsigned char data_string[(strlen(source) / 8) + 3];
+#else
+ unsigned char* data_string = (unsigned char*) _alloca((strlen(source) / 8) + 3);
+#endif
+ int chainemc[180], mclength;
+ int k, j, p, longueur, mccorrection[50], offset;
+ int total, dummy[5];
+ char pattern[580];
+ int variant, LeftRAPStart, CentreRAPStart, RightRAPStart, StartCluster;
+ int LeftRAP, CentreRAP, RightRAP, Cluster, loop;
+
+ length = strlen(source) / 8;
+
+ for (i = 0; i < length; i++) {
+ int binloc = i * 8;
+
+ data_string[i] = 0;
+ for (p = 0; p < 8; p++) {
+ if (source[binloc + p] == '1') {
+ data_string[i] += (0x80 >> p);
+ }
+ }
+ }
+
+
+ mclength = 0;
+
+ /* "the CC-B component shall have codeword 920 in the first symbol character position" (section 9a) */
+ chainemc[mclength] = 920;
+ mclength++;
+
+ byteprocess(chainemc, &mclength, data_string, 0, length);
+
+ /* Now figure out which variant of the symbol to use and load values accordingly */
+
+ variant = 0;
+
+ if (cc_width == 2) {
+ variant = 13;
+ if (mclength <= 33) {
+ variant = 12;
+ }
+ if (mclength <= 29) {
+ variant = 11;
+ }
+ if (mclength <= 24) {
+ variant = 10;
+ }
+ if (mclength <= 19) {
+ variant = 9;
+ }
+ if (mclength <= 13) {
+ variant = 8;
+ }
+ if (mclength <= 8) {
+ variant = 7;
+ }
+ }
+
+ if (cc_width == 3) {
+ variant = 23;
+ if (mclength <= 70) {
+ variant = 22;
+ }
+ if (mclength <= 58) {
+ variant = 21;
+ }
+ if (mclength <= 46) {
+ variant = 20;
+ }
+ if (mclength <= 34) {
+ variant = 19;
+ }
+ if (mclength <= 24) {
+ variant = 18;
+ }
+ if (mclength <= 18) {
+ variant = 17;
+ }
+ if (mclength <= 14) {
+ variant = 16;
+ }
+ if (mclength <= 10) {
+ variant = 15;
+ }
+ if (mclength <= 6) {
+ variant = 14;
+ }
+ }
+
+ if (cc_width == 4) {
+ variant = 34;
+ if (mclength <= 108) {
+ variant = 33;
+ }
+ if (mclength <= 90) {
+ variant = 32;
+ }
+ if (mclength <= 72) {
+ variant = 31;
+ }
+ if (mclength <= 54) {
+ variant = 30;
+ }
+ if (mclength <= 39) {
+ variant = 29;
+ }
+ if (mclength <= 30) {
+ variant = 28;
+ }
+ if (mclength <= 24) {
+ variant = 27;
+ }
+ if (mclength <= 18) {
+ variant = 26;
+ }
+ if (mclength <= 12) {
+ variant = 25;
+ }
+ if (mclength <= 8) {
+ variant = 24;
+ }
+ }
+
+ /* Now we have the variant we can load the data - from here on the same as MicroPDF417 code */
+ variant--;
+ assert(variant >= 0);
+ symbol->option_2 = MicroVariants[variant]; /* columns */
+ symbol->rows = MicroVariants[variant + 34]; /* rows */
+ k = MicroVariants[variant + 68]; /* number of EC CWs */
+ longueur = (symbol->option_2 * symbol->rows) - k; /* number of non-EC CWs */
+ i = longueur - mclength; /* amount of padding required */
+ offset = MicroVariants[variant + 102]; /* coefficient offset */
+
+ /* We add the padding */
+ while (i > 0) {
+ chainemc[mclength] = 900;
+ mclength++;
+ i--;
+ }
+
+ /* Reed-Solomon error correction */
+ longueur = mclength;
+ for (loop = 0; loop < 50; loop++) {
+ mccorrection[loop] = 0;
+ }
+ for (i = 0; i < longueur; i++) {
+ total = (chainemc[i] + mccorrection[k - 1]) % 929;
+ for (j = k - 1; j >= 0; j--) {
+ if (j == 0) {
+ mccorrection[j] = (929 - (total * Microcoeffs[offset + j]) % 929) % 929;
+ } else {
+ mccorrection[j] = (mccorrection[j - 1] + 929 - (total * Microcoeffs[offset + j]) % 929) % 929;
+ }
+ }
+ }
+
+ for (j = 0; j < k; j++) {
+ if (mccorrection[j] != 0) {
+ mccorrection[j] = 929 - mccorrection[j];
+ }
+ }
+ /* we add these codes to the string */
+ for (i = k - 1; i >= 0; i--) {
+ chainemc[mclength] = mccorrection[i];
+ mclength++;
+ }
+
+ /* Now get the RAP (Row Address Pattern) start values */
+ LeftRAPStart = RAPTable[variant];
+ CentreRAPStart = RAPTable[variant + 34];
+ RightRAPStart = RAPTable[variant + 68];
+ StartCluster = RAPTable[variant + 102] / 3;
+
+ /* That's all values loaded, get on with the encoding */
+
+ LeftRAP = LeftRAPStart;
+ CentreRAP = CentreRAPStart;
+ RightRAP = RightRAPStart;
+ Cluster = StartCluster;
+ /* Cluster can be 0, 1 or 2 for Cluster(0), Cluster(3) and Cluster(6) */
+
+ for (i = 0; i < symbol->rows; i++) {
+ strcpy(pattern, "");
+ offset = 929 * Cluster;
+ for (j = 0; j < 5; j++) {
+ dummy[j] = 0;
+ }
+ for (j = 0; j < symbol->option_2; j++) {
+ dummy[j + 1] = chainemc[i * symbol->option_2 + j];
+ }
+ /* Copy the data into codebarre */
+ bin_append(rap_side[LeftRAP - 1], 10, pattern);
+ bin_append(pdf_bitpattern[offset + dummy[1]], 16, pattern);
+ strcat(pattern, "0");
+ if (cc_width == 3) {
+ bin_append(rap_centre[CentreRAP - 1], 10, pattern);
+ }
+ if (cc_width >= 2) {
+ bin_append(pdf_bitpattern[offset + dummy[2]], 16, pattern);
+ strcat(pattern, "0");
+ }
+ if (cc_width == 4) {
+ bin_append(rap_centre[CentreRAP - 1], 10, pattern);
+ }
+ if (cc_width >= 3) {
+ bin_append(pdf_bitpattern[offset + dummy[3]], 16, pattern);
+ strcat(pattern, "0");
+ }
+ if (cc_width == 4) {
+ bin_append(pdf_bitpattern[offset + dummy[4]], 16, pattern);
+ strcat(pattern, "0");
+ }
+ bin_append(rap_side[RightRAP - 1], 10, pattern);
+ strcat(pattern, "1"); /* stop */
+
+ /* so now pattern[] holds the string of '1's and '0's. - copy this to the symbol */
+ for (loop = 0; loop < (int) strlen(pattern); loop++) {
+ if (pattern[loop] == '1') {
+ set_module(symbol, i, loop);
+ }
+ }
+ symbol->row_height[i] = 2;
+ symbol->width = strlen(pattern);
+
+ /* Set up RAPs and Cluster for next row */
+ LeftRAP++;
+ CentreRAP++;
+ RightRAP++;
+ Cluster++;
+
+ if (LeftRAP == 53) {
+ LeftRAP = 1;
+ }
+ if (CentreRAP == 53) {
+ CentreRAP = 1;
+ }
+ if (RightRAP == 53) {
+ RightRAP = 1;
+ }
+ if (Cluster == 3) {
+ Cluster = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* CC-C 2D component - byte compressed PDF417 */
+static int cc_c(struct zint_symbol *symbol, char source[], int cc_width, int ecc_level) {
+ int length, i, p;
+#ifndef _MSC_VER
+ unsigned char data_string[(strlen(source) / 8) + 4];
+#else
+ unsigned char* data_string = (unsigned char*) _alloca((strlen(source) / 8) + 4);
+#endif
+ int chainemc[1000], mclength, k;
+ int offset, longueur, loop, total, j, mccorrection[520];
+ int c1, c2, c3, dummy[35];
+ char pattern[580];
+
+ length = strlen(source) / 8;
+
+ for (i = 0; i < length; i++) {
+ int binloc = i * 8;
+
+ data_string[i] = 0;
+ for (p = 0; p < 8; p++) {
+ if (source[binloc + p] == '1') {
+ data_string[i] += (0x80 >> p);
+ }
+ }
+ }
+
+ mclength = 0;
+
+ chainemc[mclength] = 0; /* space for length descriptor */
+ mclength++;
+ chainemc[mclength] = 920; /* CC-C identifier */
+ mclength++;
+
+ byteprocess(chainemc, &mclength, data_string, 0, length);
+
+ chainemc[0] = mclength;
+
+ k = 1;
+ for (i = 1; i <= (ecc_level + 1); i++) {
+ k *= 2;
+ }
+
+ /* 796 - we now take care of the Reed Solomon codes */
+ switch (ecc_level) {
+ case 1: offset = 2;
+ break;
+ case 2: offset = 6;
+ break;
+ case 3: offset = 14;
+ break;
+ case 4: offset = 30;
+ break;
+ case 5: offset = 62;
+ break;
+ case 6: offset = 126;
+ break;
+ case 7: offset = 254;
+ break;
+ case 8: offset = 510;
+ break;
+ default: offset = 0;
+ break;
+ }
+
+ longueur = mclength;
+ for (loop = 0; loop < 520; loop++) {
+ mccorrection[loop] = 0;
+ }
+ for (i = 0; i < longueur; i++) {
+ total = (chainemc[i] + mccorrection[k - 1]) % 929;
+ for (j = k - 1; j >= 0; j--) {
+ if (j == 0) {
+ mccorrection[j] = (929 - (total * coefrs[offset + j]) % 929) % 929;
+ } else {
+ mccorrection[j] = (mccorrection[j - 1] + 929 - (total * coefrs[offset + j]) % 929) % 929;
+ }
+ }
+ }
+
+ for (j = 0; j < k; j++) {
+ if (mccorrection[j] != 0) {
+ mccorrection[j] = 929 - mccorrection[j];
+ }
+ }
+ /* we add these codes to the string */
+ for (i = k - 1; i >= 0; i--) {
+ chainemc[mclength] = mccorrection[i];
+ mclength++;
+ }
+
+ /* 818 - The CW string is finished */
+ c1 = (mclength / cc_width - 1) / 3;
+ c2 = ecc_level * 3 + (mclength / cc_width - 1) % 3;
+ c3 = cc_width - 1;
+
+ /* we now encode each row */
+ for (i = 0; i <= (mclength / cc_width) - 1; i++) {
+ for (j = 0; j < cc_width; j++) {
+ dummy[j + 1] = chainemc[i * cc_width + j];
+ }
+ k = (i / 3) * 30;
+ switch (i % 3) {
+ case 0:
+ dummy[0] = k + c1;
+ dummy[cc_width + 1] = k + c3;
+ offset = 0; /* cluster(0) */
+ break;
+ case 1:
+ dummy[0] = k + c2;
+ dummy[cc_width + 1] = k + c1;
+ offset = 929; /* cluster(3) */
+ break;
+ case 2:
+ dummy[0] = k + c3;
+ dummy[cc_width + 1] = k + c2;
+ offset = 1858; /* cluster(6) */
+ break;
+ }
+ strcpy(pattern, "");
+ bin_append(0x1FEA8, 17, pattern); /* Row start */
+
+ for (j = 0; j <= cc_width + 1; j++) {
+ bin_append(pdf_bitpattern[offset + dummy[j]], 16, pattern);
+ strcat(pattern, "0");
+ }
+ bin_append(0x3FA29, 18, pattern); /* Row Stop */
+
+ for (loop = 0; loop < (int) strlen(pattern); loop++) {
+ if (pattern[loop] == '1') {
+ set_module(symbol, i, loop);
+ }
+ }
+ symbol->row_height[i] = 3;
+ }
+ symbol->rows = (mclength / cc_width);
+ symbol->width = (int)strlen(pattern);
+
+ return 0;
+}
+
+static int calc_padding_cca(int binary_length, int cc_width) {
+ int target_bitsize = 0;
+
+ switch (cc_width) {
+ case 2:
+ if (binary_length <= 167) {
+ target_bitsize = 167;
+ }
+ if (binary_length <= 138) {
+ target_bitsize = 138;
+ }
+ if (binary_length <= 118) {
+ target_bitsize = 118;
+ }
+ if (binary_length <= 108) {
+ target_bitsize = 108;
+ }
+ if (binary_length <= 88) {
+ target_bitsize = 88;
+ }
+ if (binary_length <= 78) {
+ target_bitsize = 78;
+ }
+ if (binary_length <= 59) {
+ target_bitsize = 59;
+ }
+ break;
+ case 3:
+ if (binary_length <= 167) {
+ target_bitsize = 167;
+ }
+ if (binary_length <= 138) {
+ target_bitsize = 138;
+ }
+ if (binary_length <= 118) {
+ target_bitsize = 118;
+ }
+ if (binary_length <= 98) {
+ target_bitsize = 98;
+ }
+ if (binary_length <= 78) {
+ target_bitsize = 78;
+ }
+ break;
+ case 4:
+ if (binary_length <= 197) {
+ target_bitsize = 197;
+ }
+ if (binary_length <= 167) {
+ target_bitsize = 167;
+ }
+ if (binary_length <= 138) {
+ target_bitsize = 138;
+ }
+ if (binary_length <= 108) {
+ target_bitsize = 108;
+ }
+ if (binary_length <= 78) {
+ target_bitsize = 78;
+ }
+ break;
+ }
+
+ return target_bitsize;
+}
+
+static int calc_padding_ccb(int binary_length, int cc_width) {
+ int target_bitsize = 0;
+
+ switch (cc_width) {
+ case 2:
+ if (binary_length <= 336) {
+ target_bitsize = 336;
+ }
+ if (binary_length <= 296) {
+ target_bitsize = 296;
+ }
+ if (binary_length <= 256) {
+ target_bitsize = 256;
+ }
+ if (binary_length <= 208) {
+ target_bitsize = 208;
+ }
+ if (binary_length <= 160) {
+ target_bitsize = 160;
+ }
+ if (binary_length <= 104) {
+ target_bitsize = 104;
+ }
+ if (binary_length <= 56) {
+ target_bitsize = 56;
+ }
+ break;
+ case 3:
+ if (binary_length <= 768) {
+ target_bitsize = 768;
+ }
+ if (binary_length <= 648) {
+ target_bitsize = 648;
+ }
+ if (binary_length <= 536) {
+ target_bitsize = 536;
+ }
+ if (binary_length <= 416) {
+ target_bitsize = 416;
+ }
+ if (binary_length <= 304) {
+ target_bitsize = 304;
+ }
+ if (binary_length <= 208) {
+ target_bitsize = 208;
+ }
+ if (binary_length <= 152) {
+ target_bitsize = 152;
+ }
+ if (binary_length <= 112) {
+ target_bitsize = 112;
+ }
+ if (binary_length <= 72) {
+ target_bitsize = 72;
+ }
+ if (binary_length <= 32) {
+ target_bitsize = 32;
+ }
+ break;
+ case 4:
+ if (binary_length <= 1184) {
+ target_bitsize = 1184;
+ }
+ if (binary_length <= 1016) {
+ target_bitsize = 1016;
+ }
+ if (binary_length <= 840) {
+ target_bitsize = 840;
+ }
+ if (binary_length <= 672) {
+ target_bitsize = 672;
+ }
+ if (binary_length <= 496) {
+ target_bitsize = 496;
+ }
+ if (binary_length <= 352) {
+ target_bitsize = 352;
+ }
+ if (binary_length <= 264) {
+ target_bitsize = 264;
+ }
+ if (binary_length <= 208) {
+ target_bitsize = 208;
+ }
+ if (binary_length <= 152) {
+ target_bitsize = 152;
+ }
+ if (binary_length <= 96) {
+ target_bitsize = 96;
+ }
+ if (binary_length <= 56) {
+ target_bitsize = 56;
+ }
+ break;
+ }
+
+ return target_bitsize;
+}
+
+static int calc_padding_ccc(int binary_length, int *cc_width, int lin_width, int *ecc) {
+ int target_bitsize = 0;
+ int byte_length, codewords_used, ecc_level, ecc_codewords, rows;
+ int codewords_total, target_codewords, target_bytesize;
+
+ byte_length = binary_length / 8;
+ if (binary_length % 8 != 0) {
+ byte_length++;
+ }
+
+ codewords_used = (byte_length / 6) * 5;
+ codewords_used += byte_length % 6;
+
+ /* Recommended minimum ecc levels ISO/IEC 1543:2015 (PDF417) Annex E Table E.1,
+ restricted by CC-C codeword max 900 (30 cols * 30 rows), GS1 General Specifications 19.1 5.9.2.3 */
+ if (codewords_used <= 40) {
+ ecc_level = 2;
+ } else if (codewords_used <= 160) {
+ ecc_level = 3;
+ } else if (codewords_used <= 320) {
+ ecc_level = 4;
+ } else if (codewords_used <= 833) { /* 900 - 3 - 64 */
+ ecc_level = 5;
+ } else if (codewords_used <= 865) { /* 900 - 3 - 32 */
+ ecc_level = 4; /* Not recommended but allow to meet advertised "up to 2361 digits" (allows max 2372) */
+ } else {
+ return 0;
+ }
+ *(ecc) = ecc_level;
+ ecc_codewords = 1 << (ecc_level + 1);
+
+ codewords_used += ecc_codewords;
+ codewords_used += 3;
+
+ *(cc_width) = (lin_width - 53) / 17; // -53 = (6 left quiet zone + 10 right quiet zone - (17 * 3 + 18))
+ if (*(cc_width) > 30) {
+ *(cc_width) = 30;
+ }
+ rows = ceil((double) codewords_used / *(cc_width));
+ /* stop the symbol from becoming too high */
+ while (rows > 30 && *(cc_width) < 30) {
+ *(cc_width) = *(cc_width) + 1;
+ rows = ceil((double) codewords_used / *(cc_width));
+ }
+
+ if (rows > 30) {
+ return 0;
+ }
+ if (rows < 3) {
+ rows = 3;
+ }
+
+ codewords_total = *(cc_width) * rows;
+
+ target_codewords = codewords_total - ecc_codewords;
+ target_codewords -= 3;
+
+ target_bytesize = 6 * (target_codewords / 5);
+ target_bytesize += target_codewords % 5;
+
+ target_bitsize = 8 * target_bytesize;
+
+ return target_bitsize;
+}
+
+static int cc_binary_string(struct zint_symbol *symbol, const char source[], char binary_string[], int cc_mode, int *cc_width, int *ecc, int lin_width) { /* Handles all data encodation from section 5 of ISO/IEC 24723 */
+ int encoding_method, read_posn, alpha_pad;
+ int i, j, ai_crop, ai_crop_posn, fnc1_latch;
+ int ai90_mode, last_digit, remainder, binary_length;
+ int mode;
+ int source_len = strlen(source);
+#ifndef _MSC_VER
+ char general_field[source_len + 1];
+#else
+ char* general_field = (char*) _alloca(source_len + 1);
+#endif
+ int target_bitsize;
+
+ encoding_method = 1;
+ read_posn = 0;
+ ai_crop = 0;
+ ai_crop_posn = -1;
+ fnc1_latch = 0;
+ alpha_pad = 0;
+ ai90_mode = 0;
+ *ecc = 0;
+ target_bitsize = 0;
+ mode = NUMERIC;
+
+ if ((source[0] == '1') && ((source[1] == '0') || (source[1] == '1') || (source[1] == '7'))) {
+ /* Source starts (10), (11) or (17) */
+ encoding_method = 2;
+ }
+
+ if ((source[0] == '9') && (source[1] == '0')) {
+ /* Source starts (90) */
+ encoding_method = 3;
+ }
+
+ if (encoding_method == 1) {
+ strcat(binary_string, "0");
+ }
+
+ if (encoding_method == 2) {
+ /* Encoding Method field "10" - date and lot number */
+
+ strcat(binary_string, "10");
+
+ if (source[1] == '0') {
+ /* No date data */
+ strcat(binary_string, "11");
+ read_posn = 2;
+ } else {
+ long int group_val;
+ /* Production Date (11) or Expiration Date (17) */
+ char date_str[4];
+ date_str[0] = source[2];
+ date_str[1] = source[3];
+ date_str[2] = '\0';
+ group_val = atoi(date_str) * 384;
+
+ date_str[0] = source[4];
+ date_str[1] = source[5];
+ group_val += (atoi(date_str) - 1) * 32;
+
+ date_str[0] = source[6];
+ date_str[1] = source[7];
+ group_val += atoi(date_str);
+
+ bin_append(group_val, 16, binary_string);
+
+ if (source[1] == '1') {
+ /* Production Date AI 11 */
+ strcat(binary_string, "0");
+ } else {
+ /* Expiration Date AI 17 */
+ strcat(binary_string, "1");
+ }
+ read_posn = 8;
+
+ if ((source[read_posn] == '1') && (source[read_posn + 1] == '0')) {
+ /* Followed by AI 10 - strip this from general field */
+ read_posn += 2;
+ } else if (source[read_posn]) {
+ /* ISO/IEC 24723:2010 5.3.1 "If a lot number does not directly follow the date element string, a FNC1 is encoded following the date element string ..." */
+ fnc1_latch = 1;
+ } else {
+ /* "... even if no more data follows the date element string" */
+ /* So still need FNC1 character but can't do single FNC1 in numeric mode, so insert alphanumeric latch "0000" and alphanumeric FNC1 "01111"
+ (this implementation detail taken from BWIPP https://github.com/bwipp/postscriptbarcode Copyright (c) 2004-2019 Terry Burton) */
+ strcat(binary_string, "000001111");
+ /* Note an alphanumeric FNC1 is also a numeric latch, so now in numeric mode */
+ }
+ }
+ }
+
+ if (encoding_method == 3) {
+ /* Encodation Method field of "11" - AI 90 */
+#ifndef _MSC_VER
+ char ninety[source_len + 1];
+#else
+ char* ninety = (char*) _alloca(source_len + 1);
+#endif
+ int ninety_len, alpha, alphanum, numeric, test1, test2, test3;
+
+ /* "This encodation method may be used if an element string with an AI
+ 90 occurs at the start of the data message, and if the data field
+ following the two-digit AI 90 starts with an alphanumeric string which
+ complies with a specific format." (para 5.3.2) */
+
+ memset(ninety, 0, source_len + 1);
+ i = 0;
+ do {
+ ninety[i] = source[i + 2];
+ i++;
+ } while ((source_len > i + 2) && ('[' != source[i + 2]));
+ ninety[i] = '\0';
+ ninety_len = strlen(ninety);
+
+ /* Find out if the AI 90 data is alphabetic or numeric or both */
+
+ alpha = 0;
+ alphanum = 0;
+ numeric = 0;
+
+ for (i = 0; i < ninety_len; i++) {
+
+ if ((ninety[i] >= 'A') && (ninety[i] <= 'Z')) {
+ /* Character is alphabetic */
+ alpha += 1;
+ } else if ((ninety[i] >= '0') && (ninety[i] <= '9')) {
+ /* Character is numeric */
+ numeric += 1;
+ } else {
+ alphanum += 1;
+ }
+ }
+
+ /* must start with 0, 1, 2 or 3 digits followed by an uppercase character */
+ test1 = -1;
+ for (i = 3; i >= 0; i--) {
+ if ((ninety[i] >= 'A') && (ninety[i] <= 'Z')) {
+ test1 = i;
+ }
+ }
+
+ test2 = 0;
+ for (i = 0; i < test1; i++) {
+ if (!((ninety[i] >= '0') && (ninety[i] <= '9'))) {
+ test2 = 1;
+ }
+ }
+
+ /* leading zeros are not permitted */
+ test3 = 0;
+ if ((test1 >= 1) && (ninety[0] == '0')) {
+ test3 = 1;
+ }
+
+ if ((test1 != -1) && (test2 != 1) && (test3 == 0)) {
+ int next_ai_posn;
+ char numeric_part[4];
+ int numeric_value;
+ int table3_letter;
+ /* Encodation method "11" can be used */
+ strcat(binary_string, "11");
+
+ numeric -= test1;
+ alpha--;
+
+ /* Decide on numeric, alpha or alphanumeric mode */
+ /* Alpha mode is a special mode for AI 90 */
+
+ if (alphanum == 0 && alpha > numeric) {
+ /* Alphabetic mode */
+ strcat(binary_string, "11");
+ ai90_mode = 2;
+ } else if (alphanum == 0 && alpha == 0) {
+ /* Numeric mode */
+ strcat(binary_string, "10");
+ ai90_mode = 3;
+ } else {
+ /* Alphanumeric mode */
+ strcat(binary_string, "0");
+ ai90_mode = 1;
+ mode = ALPHA;
+ }
+
+ next_ai_posn = 2 + ninety_len;
+
+ if (source[next_ai_posn] == '[') {
+ /* There are more AIs afterwards */
+ if ((source[next_ai_posn + 1] == '2') && (source[next_ai_posn + 2] == '1')) {
+ /* AI 21 follows */
+ ai_crop = 1;
+ }
+
+ if ((source[next_ai_posn + 1] == '8') && (source[next_ai_posn + 2] == '0') && (source[next_ai_posn + 3] == '0') && (source[next_ai_posn + 4] == '4')) {
+ /* AI 8004 follows */
+ ai_crop = 3;
+ }
+ }
+
+ switch (ai_crop) {
+ case 0: strcat(binary_string, "0");
+ break;
+ case 1: strcat(binary_string, "10");
+ ai_crop_posn = next_ai_posn + 1;
+ break;
+ case 3: strcat(binary_string, "11");
+ ai_crop_posn = next_ai_posn + 1;
+ break;
+ }
+
+ if (test1 == 0) {
+ strcpy(numeric_part, "0");
+ } else {
+ for (i = 0; i < test1; i++) {
+ numeric_part[i] = ninety[i];
+ }
+ numeric_part[i] = '\0';
+ }
+
+ numeric_value = atoi(numeric_part);
+
+ table3_letter = -1;
+ if (numeric_value < 31) {
+ table3_letter = posn("BDHIJKLNPQRSTVWZ", ninety[test1]);
+ }
+
+ if (table3_letter != -1) {
+ /* Encoding can be done according to 5.3.2 c) 2) */
+ /* five bit binary string representing value before letter */
+ bin_append(numeric_value, 5, binary_string);
+
+ /* followed by four bit representation of letter from Table 3 */
+ bin_append(table3_letter, 4, binary_string);
+ } else {
+ /* Encoding is done according to 5.3.2 c) 3) */
+ bin_append(31, 5, binary_string);
+ /* ten bit representation of number */
+ bin_append(numeric_value, 10, binary_string);
+
+ /* five bit representation of ASCII character */
+ bin_append(ninety[test1] - 65, 5, binary_string);
+ }
+
+ read_posn = test1 + 3;
+
+ /* Do Alpha mode encoding of the rest of the AI 90 data field here */
+ if (ai90_mode == 2) {
+ /* Alpha encodation (section 5.3.3) */
+ do {
+ if ((source[read_posn] >= 'A') && (source[read_posn] <= 'Z')) {
+ bin_append(source[read_posn] - 65, 5, binary_string);
+
+ } else if ((source[read_posn] >= '0') && (source[read_posn] <= '9')) {
+ bin_append(source[read_posn] + 4, 6, binary_string);
+
+ } else if (source[read_posn] == '[') {
+ bin_append(31, 5, binary_string);
+ }
+
+ read_posn++;
+ } while ((source[read_posn - 1] != '[') && (source[read_posn - 1] != '\0'));
+ alpha_pad = 1; /* This is overwritten if a general field is encoded */
+ }
+
+ } else {
+ /* Use general field encodation instead */
+ strcat(binary_string, "0");
+ read_posn = 0;
+ }
+ }
+
+ /* The compressed data field has been processed if appropriate - the
+ rest of the data (if any) goes into a general-purpose data compaction field */
+
+ j = 0;
+ if (fnc1_latch == 1) {
+ /* Encodation method "10" has been used but it is not followed by
+ AI 10, so a FNC1 character needs to be added */
+ general_field[j] = '[';
+ j++;
+ }
+
+ for (i = read_posn; i < source_len; i++) {
+ /* Skip "[21" or "[8004" AIs if encodation method "11" used */
+ if (i == ai_crop_posn) {
+ i += ai_crop;
+ } else {
+ general_field[j] = source[i];
+ j++;
+ }
+ }
+ general_field[j] = '\0';
+
+ if (strlen(general_field) != 0) {
+ alpha_pad = 0;
+ }
+
+ if (!general_field_encode(general_field, &mode, &last_digit, binary_string)) {
+ /* Invalid characters in input data */
+ strcpy(symbol->errtxt, "441: Invalid characters in input data");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ binary_length = (int)strlen(binary_string);
+ switch (cc_mode) {
+ case 1:
+ target_bitsize = calc_padding_cca(binary_length, *(cc_width));
+ break;
+ case 2:
+ target_bitsize = calc_padding_ccb(binary_length, *(cc_width));
+ break;
+ case 3:
+ target_bitsize = calc_padding_ccc(binary_length, cc_width, lin_width, ecc);
+ break;
+ }
+
+ if (target_bitsize == 0) {
+ strcpy(symbol->errtxt, "442: Input too long for selected 2d component");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ remainder = target_bitsize - binary_length;
+
+ if (last_digit) {
+ /* There is still one more numeric digit to encode */
+
+ if ((remainder >= 4) && (remainder <= 6)) {
+ /* ISO/IEC 24723:2010 5.4.1 c) 2) "If four to six bits remain, add 1 to the digit value and encode the result in the next four bits. ..." */
+ bin_append(ctoi(last_digit) + 1, 4, binary_string);
+ if (remainder > 4) {
+ /* "... The fifth and sixth bits, if present, shall be “0”s." (Covered by adding truncated alphanumeric latch below but do explicitly anyway) */
+ bin_append(0, remainder - 4, binary_string);
+ }
+ } else {
+ bin_append((11 * ctoi(last_digit)) + 18, 7, binary_string);
+ /* This may push the symbol up to the next size */
+ }
+ }
+
+ if (strlen(binary_string) > 11805) { /* (2361 * 5) */
+ strcpy(symbol->errtxt, "443: Input too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ binary_length = (int)strlen(binary_string);
+ switch (cc_mode) {
+ case 1:
+ target_bitsize = calc_padding_cca(binary_length, *(cc_width));
+ break;
+ case 2:
+ target_bitsize = calc_padding_ccb(binary_length, *(cc_width));
+ break;
+ case 3:
+ target_bitsize = calc_padding_ccc(binary_length, cc_width, lin_width, ecc);
+ break;
+ }
+
+ if (target_bitsize == 0) {
+ strcpy(symbol->errtxt, "444: Input too long for selected 2d component");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ if (binary_length < target_bitsize) {
+ /* Now add padding to binary string */
+ if (alpha_pad == 1) {
+ strcat(binary_string, "11111");
+ alpha_pad = 0;
+ /* Extra FNC1 character required after Alpha encodation (section 5.3.3) */
+ }
+
+ if (mode == NUMERIC) {
+ strcat(binary_string, "0000");
+ }
+
+ while (strlen(binary_string) < (unsigned int) target_bitsize) {
+ strcat(binary_string, "00100");
+ }
+
+ if (strlen(binary_string) > (unsigned int) target_bitsize) {
+ binary_string[target_bitsize] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+static int linear_dummy_run(unsigned char *source, int length) {
+ struct zint_symbol *dummy;
+ int error_number;
+ int linear_width;
+
+ dummy = ZBarcode_Create();
+ dummy->symbology = BARCODE_EAN128_CC;
+ dummy->option_1 = 3;
+ error_number = ean_128(dummy, source, length);
+ linear_width = dummy->width;
+ ZBarcode_Delete(dummy);
+
+ if (error_number == 0) {
+ return linear_width;
+ } else {
+ return 0;
+ }
+}
+
+INTERNAL int composite(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int error_number, cc_mode, cc_width, ecc_level;
+ int j, i, k;
+ unsigned int bs = 13 * length + 500 + 1; /* Allow for 8 bits + 5-bit latch per char + 500 bits overhead/padding */
+#ifndef _MSC_VER
+ char binary_string[bs];
+#else
+ char* binary_string = (char*) _alloca(bs);
+#endif
+ unsigned int pri_len;
+ struct zint_symbol *linear;
+ int top_shift, bottom_shift;
+ int linear_width = 0;
+
+ /* Perform sanity checks on input options first */
+ error_number = 0;
+ pri_len = (int)strlen(symbol->primary);
+ if (pri_len == 0) {
+ strcpy(symbol->errtxt, "445: No primary (linear) message in 2D composite");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+
+ if (length > 2990) {
+ strcpy(symbol->errtxt, "446: 2D component input data too long");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ cc_mode = symbol->option_1;
+ if ((cc_mode == 3) && (symbol->symbology != BARCODE_EAN128_CC)) {
+ /* CC-C can only be used with a GS1-128 linear part */
+ strcpy(symbol->errtxt, "447: Invalid mode (CC-C only valid with GS1-128 linear component)");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+
+ if (symbol->symbology == BARCODE_EAN128_CC) {
+ /* Do a test run of encoding the linear component to establish its width */
+ linear_width = linear_dummy_run((unsigned char *) symbol->primary, pri_len);
+ if (linear_width == 0) {
+ strcpy(symbol->errtxt, "448: Invalid data");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ }
+
+ switch (symbol->symbology) {
+ /* Determine width of 2D component according to ISO/IEC 24723 Table 1 */
+ case BARCODE_EANX_CC:
+ cc_width = 0;
+ if (pri_len < 20) {
+ int padded_pri_len;
+ char padded_pri[20];
+ padded_pri[0] = '\0';
+ ean_leading_zeroes(symbol, (unsigned char*) symbol->primary, (unsigned char*) padded_pri);
+ padded_pri_len = strlen(padded_pri);
+ if (padded_pri_len <= 7) { /* EAN-8 */
+ cc_width = 3;
+ } else {
+ switch (padded_pri_len) {
+ case 10: /* EAN-8 + 2 */
+ case 13: /* EAN-8 + 5 */
+ cc_width = 3;
+ break;
+ case 12: /* EAN-13 */
+ case 15: /* EAN-13 + 2 */
+ case 18: /* EAN-13 + 5 */
+ cc_width = 4;
+ break;
+ }
+ }
+ }
+ if (cc_width == 0) {
+ strcpy(symbol->errtxt, "449: Invalid length EAN input in linear component");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ break;
+ case BARCODE_EAN128_CC: cc_width = 4;
+ break;
+ case BARCODE_RSS14_CC: cc_width = 4;
+ break;
+ case BARCODE_RSS_LTD_CC: cc_width = 3;
+ break;
+ case BARCODE_RSS_EXP_CC: cc_width = 4;
+ break;
+ case BARCODE_UPCA_CC: cc_width = 4;
+ break;
+ case BARCODE_UPCE_CC: cc_width = 2;
+ break;
+ case BARCODE_RSS14STACK_CC: cc_width = 2;
+ break;
+ case BARCODE_RSS14_OMNI_CC: cc_width = 2;
+ break;
+ case BARCODE_RSS_EXPSTACK_CC: cc_width = 4;
+ break;
+ }
+
+ memset(binary_string, 0, bs);
+
+ if (cc_mode < 1 || cc_mode > 3) {
+ cc_mode = 1;
+ }
+
+ if (cc_mode == 1) {
+ i = cc_binary_string(symbol, (char *) source, binary_string, cc_mode, &cc_width, &ecc_level, linear_width);
+ if (i == ZINT_ERROR_TOO_LONG) {
+ cc_mode = 2;
+ memset(binary_string, 0, bs);
+ } else if (i != 0) {
+ return i;
+ }
+ }
+
+ if (cc_mode == 2) {
+ /* If the data didn't fit into CC-A it is recalculated for CC-B */
+ i = cc_binary_string(symbol, (char *) source, binary_string, cc_mode, &cc_width, &ecc_level, linear_width);
+ if (i == ZINT_ERROR_TOO_LONG) {
+ if (symbol->symbology != BARCODE_EAN128_CC) {
+ return ZINT_ERROR_TOO_LONG;
+ }
+ cc_mode = 3;
+ memset(binary_string, 0, bs);
+ } else if (i != 0) {
+ return i;
+ }
+ }
+
+ if (cc_mode == 3) {
+ /* If the data didn't fit in CC-B (and linear part is GS1-128) it is recalculated for CC-C */
+ i = cc_binary_string(symbol, (char *) source, binary_string, cc_mode, &cc_width, &ecc_level, linear_width);
+ if (i != 0) {
+ return i;
+ }
+ }
+
+ switch (cc_mode) {
+ /* Note that ecc_level is only relevant to CC-C */
+ case 1: error_number = cc_a(symbol, binary_string, cc_width);
+ break;
+ case 2: error_number = cc_b(symbol, binary_string, cc_width);
+ break;
+ case 3: error_number = cc_c(symbol, binary_string, cc_width, ecc_level);
+ break;
+ }
+
+ if (error_number != 0) {
+ return ZINT_ERROR_ENCODING_PROBLEM;
+ }
+
+ /* 2D component done, now calculate linear component */
+ linear = ZBarcode_Create(); /* Symbol contains the 2D component and Linear contains the rest */
+
+ linear->symbology = symbol->symbology;
+
+ if (linear->symbology != BARCODE_EAN128_CC) {
+ /* Set the "component linkage" flag in the linear component */
+ linear->option_1 = 2;
+ } else {
+ /* GS1-128 needs to know which type of 2D component is used */
+ linear->option_1 = cc_mode;
+ }
+
+ switch (symbol->symbology) {
+ case BARCODE_EANX_CC: error_number = eanx(linear, (unsigned char *) symbol->primary, pri_len);
+ break;
+ case BARCODE_EAN128_CC: error_number = ean_128(linear, (unsigned char *) symbol->primary, pri_len);
+ break;
+ case BARCODE_RSS14_CC: error_number = rss14(linear, (unsigned char *) symbol->primary, pri_len);
+ break;
+ case BARCODE_RSS_LTD_CC: error_number = rsslimited(linear, (unsigned char *) symbol->primary, pri_len);
+ break;
+ case BARCODE_RSS_EXP_CC: error_number = rssexpanded(linear, (unsigned char *) symbol->primary, pri_len);
+ break;
+ case BARCODE_UPCA_CC: error_number = eanx(linear, (unsigned char *) symbol->primary, pri_len);
+ break;
+ case BARCODE_UPCE_CC: error_number = eanx(linear, (unsigned char *) symbol->primary, pri_len);
+ break;
+ case BARCODE_RSS14STACK_CC: error_number = rss14(linear, (unsigned char *) symbol->primary, pri_len);
+ break;
+ case BARCODE_RSS14_OMNI_CC: error_number = rss14(linear, (unsigned char *) symbol->primary, pri_len);
+ break;
+ case BARCODE_RSS_EXPSTACK_CC: error_number = rssexpanded(linear, (unsigned char *) symbol->primary, pri_len);
+ break;
+ }
+
+ if (error_number != 0) {
+ strcpy(symbol->errtxt, linear->errtxt);
+ strcat(symbol->errtxt, " in linear component ");
+ ZBarcode_Delete(linear);
+ return error_number;
+ }
+
+ /* Merge the linear component with the 2D component */
+
+ top_shift = 0;
+ bottom_shift = 0;
+
+ switch (symbol->symbology) {
+ /* Determine horizontal alignment (according to section 12.3) */
+ case BARCODE_EANX_CC:
+ switch (ustrlen(linear->text)) { /* Use zero-padded length */
+ case 8: /* EAN-8 */
+ case 11: /* EAN-8 + 2 */
+ case 14: /* EAN-8 + 5 */
+ if (cc_mode == 1) {
+ bottom_shift = 3;
+ } else {
+ bottom_shift = 13;
+ }
+ break;
+ case 13: /* EAN-13 */
+ case 16: /* EAN-13 + 2 */
+ case 19: /* EAN-13 + 5 */
+ bottom_shift = 2;
+ break;
+ }
+ break;
+ case BARCODE_EAN128_CC: if (cc_mode == 3) {
+ bottom_shift = 7;
+ } else {
+ /* ISO/IEC 24723:2010 12.3 g) "GS1-128 components linked to the right quiet zone of the CC-A or CC-B: the CC-A or CC-B component is
+ aligned with the last space module of one of the rightmost symbol characters of the linear component. To
+ calculate the target Code 128 symbol character position for alignment, number the positions from right to
+ left (0 is the Stop character, 1 is the Check character, etc.), and then Position = (total number of Code 128 symbol characters – 9) div 2"
+ */
+ int num_symbols = (linear_width - 2) / 11;
+ int position = (num_symbols - 9) / 2;
+ int calc_shift = linear->width - position * 11 - 1 - symbol->width; /* Less 1 to align with last space module */
+ if (position) {
+ calc_shift -= 2; /* Less additional stop modules */
+ }
+ if (calc_shift > 0) {
+ top_shift = calc_shift;
+ } else if (calc_shift < 0) {
+ bottom_shift = -calc_shift;
+ }
+ }
+ break;
+ case BARCODE_RSS14_CC: bottom_shift = 4;
+ break;
+ case BARCODE_RSS_LTD_CC:
+ if (cc_mode == 1) {
+ top_shift = 1;
+ } else {
+ bottom_shift = 9;
+ }
+ break;
+ case BARCODE_RSS_EXP_CC: k = 1;
+ while ((!(module_is_set(linear, 1, k - 1))) && module_is_set(linear, 1, k)) {
+ k++;
+ }
+ top_shift = k;
+ break;
+ case BARCODE_UPCA_CC: bottom_shift = 2;
+ break;
+ case BARCODE_UPCE_CC: bottom_shift = 2;
+ break;
+ case BARCODE_RSS14STACK_CC: top_shift = 1;
+ break;
+ case BARCODE_RSS14_OMNI_CC: top_shift = 1;
+ break;
+ case BARCODE_RSS_EXPSTACK_CC: k = 1;
+ while ((!(module_is_set(linear, 1, k - 1))) && module_is_set(linear, 1, k)) {
+ k++;
+ }
+ top_shift = k;
+ break;
+ }
+
+ if (top_shift != 0) {
+ /* Move the 2d component of the symbol horizontally */
+ for (i = 0; i <= symbol->rows; i++) {
+ for (j = (symbol->width + top_shift); j >= top_shift; j--) {
+ if (module_is_set(symbol, i, j - top_shift)) {
+ set_module(symbol, i, j);
+ } else {
+ unset_module(symbol, i, j);
+ }
+ }
+ for (j = 0; j < top_shift; j++) {
+ unset_module(symbol, i, j);
+ }
+ }
+ }
+
+ /* Merge linear and 2D components into one structure */
+ for (i = 0; i <= linear->rows; i++) {
+ symbol->row_height[symbol->rows + i] = linear->row_height[i];
+ for (j = 0; j <= linear->width; j++) {
+ if (module_is_set(linear, i, j)) {
+ set_module(symbol, i + symbol->rows, j + bottom_shift);
+ } else {
+ unset_module(symbol, i + symbol->rows, j + bottom_shift);
+ }
+ }
+ }
+ if ((linear->width + bottom_shift) > symbol->width + top_shift) {
+ symbol->width = linear->width + bottom_shift;
+ } else if ((symbol->width + top_shift) > linear->width + bottom_shift) {
+ symbol->width += top_shift;
+ }
+ symbol->rows += linear->rows;
+ ustrcpy(symbol->text, (unsigned char *) linear->text);
+
+ ZBarcode_Delete(linear);
+
+ return error_number;
+}
diff --git a/backend/composite.h b/backend/composite.h
new file mode 100644
index 0000000..6195d29
--- /dev/null
+++ b/backend/composite.h
@@ -0,0 +1,67 @@
+/* composite.c - Tables for UCC.EAN Composite Symbols */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2008-2017 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+/* CC-A component coefficients from ISO/IEC 24728:2006 Annex F */
+static const unsigned short int ccaCoeffs[30] = {
+ /* k = 4 */
+ 522, 568, 723, 809,
+
+ /* k = 5 */
+ 427, 919, 460, 155, 566,
+
+ /* k = 6 */
+ 861, 285, 19, 803, 17, 766,
+
+ /* k = 7 */
+ 76, 925, 537, 597, 784, 691, 437,
+
+ /* k = 8 */
+ 237, 308, 436, 284, 646, 653, 428, 379
+};
+
+/* rows, error codewords, k-offset of valid CC-A sizes from ISO/IEC 24723:2006 Table 9 */
+static const char ccaVariants[51] = {
+ 5, 6, 7, 8, 9, 10, 12, 4, 5, 6, 7, 8, 3, 4, 5, 6, 7,
+ 4, 4, 5, 5, 6, 6, 7, 4, 5, 6, 7, 7, 4, 5, 6, 7, 8,
+ 0, 0, 4, 4, 9, 9, 15, 0, 4, 9, 15, 15, 0, 4, 9, 15, 22
+};
+
+/* following is Left RAP, Centre RAP, Right RAP and Start Cluster from ISO/IEC 24723:2006 tables 10 and 11 */
+static const char aRAPTable[68] = {
+ 39, 1, 32, 8, 14, 43, 20, 11, 1, 5, 15, 21, 40, 43, 46, 34, 29,
+ 0, 0, 0, 0, 0, 0, 0, 43, 33, 37, 47, 1, 20, 23, 26, 14, 9,
+ 19, 33, 12, 40, 46, 23, 52, 23, 13, 17, 27, 33, 52, 3, 6, 46, 41,
+ 6, 0, 3, 3, 3, 0, 3, 3, 0, 3, 6, 6, 0, 0, 0, 0, 3
+};
+
+/* Row Address Patterns are as defined in pdf417.h */
diff --git a/backend/dllversion.c b/backend/dllversion.c
index 50f1653..71f5a75 100644
--- a/backend/dllversion.c
+++ b/backend/dllversion.c
@@ -18,14 +18,14 @@ HRESULT DllGetVersion (DLLVERSIONINFO2* pdvi)
{
if (!pdvi || (sizeof(*pdvi) != pdvi->info1.cbSize))
return (E_INVALIDARG);
-
+
pdvi->info1.dwMajorVersion = 2;
- pdvi->info1.dwMinorVersion = 4;
- pdvi->info1.dwBuildNumber = 2;
+ pdvi->info1.dwMinorVersion = 8;
+ pdvi->info1.dwBuildNumber = 1;
pdvi->info1.dwPlatformID = DLLVER_PLATFORM_WINDOWS;
if (sizeof(DLLVERSIONINFO2) == pdvi->info1.cbSize)
- pdvi->ullVersion = MAKEDLLVERULL(2, 4, 2, 0);
-
+ pdvi->ullVersion = MAKEDLLVERULL(2, 8, 1, 0);
+
return S_OK;
}
#endif /* _WIN32 */
diff --git a/backend/dmatrix.c b/backend/dmatrix.c
new file mode 100644
index 0000000..212eb6d
--- /dev/null
+++ b/backend/dmatrix.c
@@ -0,0 +1,1342 @@
+/* dmatrix.c Handles Data Matrix ECC 200 symbols */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2009-2017 Robin Stuart <rstuart114@gmail.com>
+
+ developed from and including some functions from:
+ IEC16022 bar code generation
+ Adrian Kennard, Andrews & Arnold Ltd
+ with help from Cliff Hones on the RS coding
+
+ (c) 2004 Adrian Kennard, Andrews & Arnold Ltd
+ (c) 2006 Stefan Schmidt <stefan@datenfreihafen.org>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+/* ceilf (C99) not before MSVC++2013 (C++ 12.0) */
+#if _MSC_VER < 1800
+#define ceilf ceil
+#endif
+#endif
+#include "common.h"
+#include "reedsol.h"
+#include "dmatrix.h"
+
+/* Annex M placement alorithm low level */
+static void ecc200placementbit(int *array, const int NR, const int NC, int r, int c, const int p, const char b) {
+ if (r < 0) {
+ r += NR;
+ c += 4 - ((NR + 4) % 8);
+ }
+ if (c < 0) {
+ c += NC;
+ r += 4 - ((NC + 4) % 8);
+ }
+ // Necessary for 26x32,26x40,26x48,36x120,36x144,72x120,72x144
+ if (r >= NR) {
+#ifdef DEBUG
+ fprintf(stderr, "r >= NR:%i,%i at r=%i->", p, b, r);
+#endif
+ r -= NR;
+#ifdef DEBUG
+ fprintf(stderr, "%i,c=%i\n", r, c);
+#endif
+ }
+#ifdef DEBUG
+ if (0 != array[r * NC + c]) {
+ int a = array[r * NC + c];
+ fprintf(stderr, "Double:%i,%i->%i,%i at r=%i,c=%i\n", a >> 3, a & 7, p, b, r, c);
+ return;
+ }
+#endif
+ // Check index limits
+ assert(r < NR);
+ assert(c < NC);
+ // Check double-assignment
+ assert(0 == array[r * NC + c]);
+ array[r * NC + c] = (p << 3) + b;
+}
+
+static void ecc200placementblock(int *array, const int NR, const int NC, const int r,
+ const int c, const int p) {
+ ecc200placementbit(array, NR, NC, r - 2, c - 2, p, 7);
+ ecc200placementbit(array, NR, NC, r - 2, c - 1, p, 6);
+ ecc200placementbit(array, NR, NC, r - 1, c - 2, p, 5);
+ ecc200placementbit(array, NR, NC, r - 1, c - 1, p, 4);
+ ecc200placementbit(array, NR, NC, r - 1, c - 0, p, 3);
+ ecc200placementbit(array, NR, NC, r - 0, c - 2, p, 2);
+ ecc200placementbit(array, NR, NC, r - 0, c - 1, p, 1);
+ ecc200placementbit(array, NR, NC, r - 0, c - 0, p, 0);
+}
+
+static void ecc200placementcornerA(int *array, const int NR, const int NC, const int p) {
+ ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7);
+ ecc200placementbit(array, NR, NC, NR - 1, 1, p, 6);
+ ecc200placementbit(array, NR, NC, NR - 1, 2, p, 5);
+ ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
+ ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
+ ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2);
+ ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1);
+ ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0);
+}
+
+static void ecc200placementcornerB(int *array, const int NR, const int NC, const int p) {
+ ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7);
+ ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6);
+ ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5);
+ ecc200placementbit(array, NR, NC, 0, NC - 4, p, 4);
+ ecc200placementbit(array, NR, NC, 0, NC - 3, p, 3);
+ ecc200placementbit(array, NR, NC, 0, NC - 2, p, 2);
+ ecc200placementbit(array, NR, NC, 0, NC - 1, p, 1);
+ ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0);
+}
+
+static void ecc200placementcornerC(int *array, const int NR, const int NC, const int p) {
+ ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7);
+ ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6);
+ ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5);
+ ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
+ ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
+ ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2);
+ ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1);
+ ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0);
+}
+
+static void ecc200placementcornerD(int *array, const int NR, const int NC, const int p) {
+ ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7);
+ ecc200placementbit(array, NR, NC, NR - 1, NC - 1, p, 6);
+ ecc200placementbit(array, NR, NC, 0, NC - 3, p, 5);
+ ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
+ ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
+ ecc200placementbit(array, NR, NC, 1, NC - 3, p, 2);
+ ecc200placementbit(array, NR, NC, 1, NC - 2, p, 1);
+ ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0);
+}
+
+/* Annex M placement alorithm main function */
+static void ecc200placement(int *array, const int NR, const int NC) {
+ int r, c, p;
+ // invalidate
+ for (r = 0; r < NR; r++)
+ for (c = 0; c < NC; c++)
+ array[r * NC + c] = 0;
+ // start
+ p = 1;
+ r = 4;
+ c = 0;
+ do {
+ // check corner
+ if (r == NR && !c)
+ ecc200placementcornerA(array, NR, NC, p++);
+ if (r == NR - 2 && !c && NC % 4)
+ ecc200placementcornerB(array, NR, NC, p++);
+ if (r == NR - 2 && !c && (NC % 8) == 4)
+ ecc200placementcornerC(array, NR, NC, p++);
+ if (r == NR + 4 && c == 2 && !(NC % 8))
+ ecc200placementcornerD(array, NR, NC, p++);
+ // up/right
+ do {
+ if (r < NR && c >= 0 && !array[r * NC + c])
+ ecc200placementblock(array, NR, NC, r, c, p++);
+ r -= 2;
+ c += 2;
+ } while (r >= 0 && c < NC);
+ r++;
+ c += 3;
+ // down/left
+ do {
+ if (r >= 0 && c < NC && !array[r * NC + c])
+ ecc200placementblock(array, NR, NC, r, c, p++);
+ r += 2;
+ c -= 2;
+ } while (r < NR && c >= 0);
+ r += 3;
+ c++;
+ } while (r < NR || c < NC);
+ // unfilled corner
+ if (!array[NR * NC - 1])
+ array[NR * NC - 1] = array[NR * NC - NC - 2] = 1;
+}
+
+/* calculate and append ecc code, and if necessary interleave */
+static void ecc200(unsigned char *binary, const int bytes, const int datablock, const int rsblock, const int skew) {
+ int blocks = (bytes + 2) / datablock, b;
+ int n;
+ rs_init_gf(0x12d);
+ rs_init_code(rsblock, 1);
+ for (b = 0; b < blocks; b++) {
+ unsigned char buf[256], ecc[256];
+ int p = 0;
+ for (n = b; n < bytes; n += blocks)
+ buf[p++] = binary[n];
+ rs_encode(p, buf, ecc);
+ p = rsblock - 1; // comes back reversed
+ for (n = b; n < rsblock * blocks; n += blocks) {
+ if (skew) {
+ /* Rotate ecc data to make 144x144 size symbols acceptable */
+ /* See http://groups.google.com/group/postscriptbarcode/msg/5ae8fda7757477da */
+ if (b < 8) {
+ binary[bytes + n + 2] = ecc[p--];
+ } else {
+ binary[bytes + n - 8] = ecc[p--];
+ }
+ } else {
+ binary[bytes + n] = ecc[p--];
+ }
+ }
+ }
+ rs_free();
+}
+
+/* Return true (1) if a character is valid in X12 set */
+static int isX12(const int source) {
+
+ switch(source) {
+ case 13: // CR
+ case 42: // *
+ case 62: // >
+ case 32: // space
+ return 1;
+ }
+
+ if ((source >= '0') && (source <= '9')) {
+ return 1;
+ }
+ if ((source >= 'A') && (source <= 'Z')) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Insert a character into the middle of a string at position posn */
+static void dminsert(char binary_string[], const int posn, const char newbit) {
+ int i, end;
+
+ end = (int) strlen(binary_string);
+ for (i = end + 1; i > posn; i--) {
+ binary_string[i] = binary_string[i - 1];
+ }
+ binary_string[posn] = newbit;
+}
+
+static void insert_value(unsigned char binary_stream[], const int posn, const int streamlen, const int newbit) {
+ int i;
+
+ for(i = (int)streamlen; i > posn; i--) {
+ binary_stream[i] = binary_stream[i - 1];
+ }
+ binary_stream[posn] = (unsigned char) newbit;
+}
+
+static int p_r_6_2_1(const unsigned char inputData[], const size_t position, const size_t sourcelen) {
+ /* Annex P section (r)(6)(ii)(I)
+ "If one of the three X12 terminator/separator characters first
+ occurs in the yet to be processed data before a non-X12 character..."
+ */
+
+ size_t i;
+ size_t nonX12Position = 0;
+ size_t specialX12Position = 0;
+ int retval = 0;
+
+ for (i = position; i < sourcelen; i++) {
+ if (nonX12Position == 0) {
+ if (isX12(inputData[i]) != 1) {
+ nonX12Position = i;
+ }
+ }
+
+ if (specialX12Position == 0) {
+ if ((inputData[i] == (char) 13) ||
+ (inputData[i] == '*') ||
+ (inputData[i] == '>')) {
+ specialX12Position = i;
+ }
+ }
+ }
+
+ if ((nonX12Position != 0) && (specialX12Position != 0)) {
+ if (specialX12Position < nonX12Position) {
+ retval = 1;
+ }
+ }
+
+ return retval;
+}
+
+/* 'look ahead test' from Annex P */
+static int look_ahead_test(const unsigned char inputData[], const size_t sourcelen, const size_t position, const int current_mode, const int gs1) {
+ float ascii_count, c40_count, text_count, x12_count, edf_count, b256_count, best_count;
+ const float stiction = (1.0F / 24.0F); // smallest change to act on, to get around floating point inaccuracies
+ int best_scheme;
+ size_t sp;
+
+ best_scheme = DM_NULL;
+
+ /* step (j) */
+ if (current_mode == DM_ASCII) {
+ ascii_count = 0.0F;
+ c40_count = 1.0F;
+ text_count = 1.0F;
+ x12_count = 1.0F;
+ edf_count = 1.0F;
+ b256_count = 1.25F;
+ } else {
+ ascii_count = 1.0F;
+ c40_count = 2.0F;
+ text_count = 2.0F;
+ x12_count = 2.0F;
+ edf_count = 2.0F;
+ b256_count = 2.25F;
+ }
+
+ switch (current_mode) {
+ case DM_C40: c40_count = 0.0F;
+ break;
+ case DM_TEXT: text_count = 0.0F;
+ break;
+ case DM_X12: x12_count = 0.0F;
+ break;
+ case DM_EDIFACT: edf_count = 0.0F;
+ break;
+ case DM_BASE256: b256_count = 0.0F;
+ break;
+ }
+
+ sp = position;
+
+ do {
+ if (sp == sourcelen) {
+ /* At the end of data ... step (k) */
+ ascii_count = ceilf(ascii_count);
+ b256_count = ceilf(b256_count);
+ edf_count = ceilf(edf_count);
+ text_count = ceilf(text_count);
+ x12_count = ceilf(x12_count);
+ c40_count = ceilf(c40_count);
+
+ best_count = c40_count;
+ best_scheme = DM_C40; // (k)(7)
+
+ if (x12_count < (best_count - stiction)) {
+ best_count = x12_count;
+ best_scheme = DM_X12; // (k)(6)
+ }
+
+ if (text_count < (best_count - stiction)) {
+ best_count = text_count;
+ best_scheme = DM_TEXT; // (k)(5)
+ }
+
+ if (edf_count < (best_count - stiction)) {
+ best_count = edf_count;
+ best_scheme = DM_EDIFACT; // (k)(4)
+ }
+
+ if (b256_count < (best_count - stiction)) {
+ best_count = b256_count;
+ best_scheme = DM_BASE256; // (k)(3)
+ }
+
+ if (ascii_count <= (best_count + stiction)) {
+ best_scheme = DM_ASCII; // (k)(2)
+ }
+ } else {
+
+ /* ascii ... step (l) */
+ if ((inputData[sp] >= '0') && (inputData[sp] <= '9')) {
+ ascii_count += 0.5F; // (l)(1)
+ } else {
+ if (inputData[sp] > 127) {
+ ascii_count = ceilf(ascii_count) + 2.0F; // (l)(2)
+ } else {
+ ascii_count = ceilf(ascii_count) + 1.0F; // (l)(3)
+ }
+ }
+
+ /* c40 ... step (m) */
+ if ((inputData[sp] == ' ') ||
+ (((inputData[sp] >= '0') && (inputData[sp] <= '9')) ||
+ ((inputData[sp] >= 'A') && (inputData[sp] <= 'Z')))) {
+ c40_count += (2.0F / 3.0F); // (m)(1)
+ } else {
+ if (inputData[sp] > 127) {
+ c40_count += (8.0F / 3.0F); // (m)(2)
+ } else {
+ c40_count += (4.0F / 3.0F); // (m)(3)
+ }
+ }
+
+ /* text ... step (n) */
+ if ((inputData[sp] == ' ') ||
+ (((inputData[sp] >= '0') && (inputData[sp] <= '9')) ||
+ ((inputData[sp] >= 'a') && (inputData[sp] <= 'z')))) {
+ text_count += (2.0F / 3.0F); // (n)(1)
+ } else {
+ if (inputData[sp] > 127) {
+ text_count += (8.0F / 3.0F); // (n)(2)
+ } else {
+ text_count += (4.0F / 3.0F); // (n)(3)
+ }
+ }
+
+ /* x12 ... step (o) */
+ if (isX12(inputData[sp])) {
+ x12_count += (2.0F / 3.0F); // (o)(1)
+ } else {
+ if (inputData[sp] > 127) {
+ x12_count += (13.0F / 3.0F); // (o)(2)
+ } else {
+ x12_count += (10.0F / 3.0F); // (o)(3)
+ }
+ }
+
+ /* edifact ... step (p) */
+ if ((inputData[sp] >= ' ') && (inputData[sp] <= '^')) {
+ edf_count += (3.0F / 4.0F); // (p)(1)
+ } else {
+ if (inputData[sp] > 127) {
+ edf_count += 17.0F; // (p)(2) > Value changed from ISO
+ } else {
+ edf_count += 13.0F; // (p)(3) > Value changed from ISO
+ }
+ }
+ if (gs1 && (inputData[sp] == '[')) {
+ /* fnc1 and gs have the same weight of 13.0f */
+ edf_count += 13.0F; // > Value changed from ISO
+ }
+
+ /* base 256 ... step (q) */
+ if ((gs1 == 1) && (inputData[sp] == '[')) {
+ /* FNC1 separator */
+ b256_count += 4.0F; // (q)(1)
+ } else {
+ b256_count += 1.0F; // (q)(2)
+ }
+ }
+
+
+ if (sp > (position + 3)) {
+ /* 4 data characters processed ... step (r) */
+
+ /* step (r)(6) */
+ if (((c40_count + 1.0F) < (ascii_count - stiction)) &&
+ ((c40_count + 1.0F) < (b256_count - stiction)) &&
+ ((c40_count + 1.0F) < (edf_count - stiction)) &&
+ ((c40_count + 1.0F) < (text_count - stiction))) {
+
+ if (c40_count < (x12_count - stiction)) {
+ best_scheme = DM_C40;
+ }
+
+ if ((c40_count >= (x12_count - stiction))
+ && (c40_count <= (x12_count + stiction))) {
+ if (p_r_6_2_1(inputData, sp, sourcelen) == 1) {
+ // Test (r)(6)(ii)(i)
+ best_scheme = DM_X12;
+ } else {
+ best_scheme = DM_C40;
+ }
+ }
+ }
+
+ /* step (r)(5) */
+ if (((x12_count + 1.0F) < (ascii_count - stiction)) &&
+ ((x12_count + 1.0F) < (b256_count - stiction)) &&
+ ((x12_count + 1.0F) < (edf_count - stiction)) &&
+ ((x12_count + 1.0F) < (text_count - stiction)) &&
+ ((x12_count + 1.0F) < (c40_count - stiction))) {
+ best_scheme = DM_X12;
+ }
+
+ /* step (r)(4) */
+ if (((text_count + 1.0F) < (ascii_count - stiction)) &&
+ ((text_count + 1.0F) < (b256_count - stiction)) &&
+ ((text_count + 1.0F) < (edf_count - stiction)) &&
+ ((text_count + 1.0F) < (x12_count - stiction)) &&
+ ((text_count + 1.0F) < (c40_count - stiction))) {
+ best_scheme = DM_TEXT;
+ }
+
+ /* step (r)(3) */
+ if (((edf_count + 1.0F) < (ascii_count - stiction)) &&
+ ((edf_count + 1.0F) < (b256_count - stiction)) &&
+ ((edf_count + 1.0F) < (text_count - stiction)) &&
+ ((edf_count + 1.0F) < (x12_count - stiction)) &&
+ ((edf_count + 1.0F) < (c40_count - stiction))) {
+ best_scheme = DM_EDIFACT;
+ }
+
+ /* step (r)(2) */
+ if (((b256_count + 1.0F) <= (ascii_count + stiction)) ||
+ (((b256_count + 1.0F) < (edf_count - stiction)) &&
+ ((b256_count + 1.0F) < (text_count - stiction)) &&
+ ((b256_count + 1.0F) < (x12_count - stiction)) &&
+ ((b256_count + 1.0F) < (c40_count - stiction)))) {
+ best_scheme = DM_BASE256;
+ }
+
+ /* step (r)(1) */
+ if (((ascii_count + 1.0F) <= (b256_count + stiction)) &&
+ ((ascii_count + 1.0F) <= (edf_count + stiction)) &&
+ ((ascii_count + 1.0F) <= (text_count + stiction)) &&
+ ((ascii_count + 1.0F) <= (x12_count + stiction)) &&
+ ((ascii_count + 1.0F) <= (c40_count + stiction))) {
+ best_scheme = DM_ASCII;
+ }
+ }
+
+ sp++;
+ } while (best_scheme == DM_NULL); // step (s)
+
+ return best_scheme;
+}
+
+/* Encodes data using ASCII, C40, Text, X12, EDIFACT or Base 256 modes as appropriate
+ Supports encoding FNC1 in supporting systems */
+static int dm200encode(struct zint_symbol *symbol, const unsigned char source[], unsigned char target[], int *last_mode, size_t *length_p, int process_buffer[], int *process_p, int *binlen_p) {
+
+ size_t sp;
+ int tp, i, gs1;
+ int current_mode, next_mode;
+ size_t inputlen = *length_p;
+ int debug = symbol->debug;
+#ifndef _MSC_VER
+ char binary[2 * inputlen + 1 + 4 + 1]; /* Allow for GS1/READER_INIT, ECI and nul chars overhead */
+#else
+ char* binary = (char*) _alloca(2 * inputlen + 1 + 4 + 1);
+#endif
+
+ sp = 0;
+ tp = 0;
+ memset(process_buffer, 0, 8);
+ *process_p = 0;
+ strcpy(binary, "");
+
+ /* step (a) */
+ current_mode = DM_ASCII;
+ next_mode = DM_ASCII;
+
+ /* gs1 flag values: 0: no gs1, 1: gs1 with FNC1 serparator, 2: GS separator */
+ if ((symbol->input_mode & 0x07) == GS1_MODE) {
+ if (symbol->output_options & GS1_GS_SEPARATOR) {
+ gs1 = 2;
+ } else {
+ gs1 = 1;
+ }
+ } else {
+ gs1 = 0;
+ }
+
+ if (gs1) {
+ target[tp] = 232;
+ tp++;
+ strcat(binary, " ");
+ if (debug) printf("FN1 ");
+ } /* FNC1 */
+
+ if (symbol->output_options & READER_INIT) {
+ if (gs1) {
+ strcpy(symbol->errtxt, "521: Cannot encode in GS1 mode and Reader Initialisation at the same time");
+ return ZINT_ERROR_INVALID_OPTION;
+ } else {
+ target[tp] = 234;
+ tp++; /* Reader Programming */
+ strcat(binary, " ");
+ if (debug) printf("RP ");
+ }
+ }
+
+ if (symbol->eci > 0) {
+ /* Encode ECI numbers according to Table 6 */
+ target[tp] = 241; /* ECI Character */
+ tp++;
+ if (symbol->eci <= 126) {
+ target[tp] = (unsigned char) symbol->eci + 1;
+ tp++;
+ strcat(binary, " ");
+ }
+ if ((symbol->eci >= 127) && (symbol->eci <= 16382)) {
+ target[tp] = (unsigned char) ((symbol->eci - 127) / 254) + 128;
+ tp++;
+ target[tp] = (unsigned char) ((symbol->eci - 127) % 254) + 1;
+ tp++;
+ strcat(binary, " ");
+ }
+ if (symbol->eci >= 16383) {
+ target[tp] = (unsigned char) ((symbol->eci - 16383) / 64516) + 192;
+ tp++;
+ target[tp] = (unsigned char) (((symbol->eci - 16383) / 254) % 254) + 1;
+ tp++;
+ target[tp] = (unsigned char) ((symbol->eci - 16383) % 254) + 1;
+ tp++;
+ strcat(binary, " ");
+ }
+ if (debug) printf("ECI %d ", symbol->eci + 1);
+ }
+
+ /* Check for Macro05/Macro06 */
+ /* "[)>[RS]05[GS]...[RS][EOT]" -> CW 236 */
+ /* "[)>[RS]06[GS]...[RS][EOT]" -> CW 237 */
+ if (tp == 0 && sp == 0 && inputlen >= 9
+ && source[0] == '[' && source[1] == ')' && source[2] == '>'
+ && source[3] == '\x1e' && source[4] == '0'
+ && (source[5] == '5' || source[5] == '6')
+ && source[6] == '\x1d'
+ && source[inputlen - 2] == '\x1e' && source[inputlen - 1] == '\x04') {
+ /* Output macro Codeword */
+ if (source[5] == '5') {
+ target[tp] = 236;
+ if (debug) printf("Macro05 ");
+ } else {
+ target[tp] = 237;
+ if (debug) printf("Macro06 ");
+ }
+ tp++;
+ strcat(binary, " ");
+ /* Remove macro characters from input string */
+ sp = 7;
+ inputlen -= 2;
+ *length_p -= 2;
+ }
+
+
+ while (sp < inputlen) {
+
+ current_mode = next_mode;
+
+ /* step (b) - ASCII encodation */
+ if (current_mode == DM_ASCII) {
+ next_mode = DM_ASCII;
+
+ if (istwodigits(source, inputlen, sp)) {
+ target[tp] = (unsigned char) ((10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130);
+ if (debug) printf("N%d ", target[tp] - 130);
+ tp++;
+ strcat(binary, " ");
+ sp += 2;
+ } else {
+ next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
+
+ if (next_mode != DM_ASCII) {
+ switch (next_mode) {
+ case DM_C40: target[tp] = 230;
+ tp++;
+ strcat(binary, " ");
+ if (debug) printf("C40 ");
+ break;
+ case DM_TEXT: target[tp] = 239;
+ tp++;
+ strcat(binary, " ");
+ if (debug) printf("TEX ");
+ break;
+ case DM_X12: target[tp] = 238;
+ tp++;
+ strcat(binary, " ");
+ if (debug) printf("X12 ");
+ break;
+ case DM_EDIFACT: target[tp] = 240;
+ tp++;
+ strcat(binary, " ");
+ if (debug) printf("EDI ");
+ break;
+ case DM_BASE256: target[tp] = 231;
+ tp++;
+ strcat(binary, " ");
+ if (debug) printf("BAS ");
+ break;
+ }
+ } else {
+ if (source[sp] > 127) {
+ target[tp] = 235; /* FNC4 */
+ if (debug) printf("FN4 ");
+ tp++;
+ target[tp] = (source[sp] - 128) + 1;
+ if (debug) printf("A%02X ", target[tp] - 1);
+ tp++;
+ strcat(binary, " ");
+ } else {
+ if (gs1 && (source[sp] == '[')) {
+ if (gs1==2) {
+ target[tp] = 29+1; /* GS */
+ if (debug) printf("GS ");
+ } else {
+ target[tp] = 232; /* FNC1 */
+ if (debug) printf("FN1 ");
+ }
+ } else {
+ target[tp] = source[sp] + 1;
+ if (debug) printf("A%02X ", target[tp] - 1);
+ }
+ tp++;
+ strcat(binary, " ");
+ }
+ sp++;
+ }
+ }
+
+ }
+
+ /* step (c) C40 encodation */
+ if (current_mode == DM_C40) {
+
+ next_mode = DM_C40;
+ if (*process_p == 0) {
+ next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
+ }
+
+ if (next_mode != DM_C40) {
+ target[tp] = 254;
+ tp++;
+ strcat(binary, " "); /* Unlatch */
+ next_mode = DM_ASCII;
+ if (debug) printf("ASC ");
+ } else {
+ int shift_set, value;
+ if (source[sp] > 127) {
+ process_buffer[*process_p] = 1;
+ (*process_p)++;
+ process_buffer[*process_p] = 30;
+ (*process_p)++; /* Upper Shift */
+ shift_set = c40_shift[source[sp] - 128];
+ value = c40_value[source[sp] - 128];
+ } else {
+ shift_set = c40_shift[source[sp]];
+ value = c40_value[source[sp]];
+ }
+
+ if (gs1 && (source[sp] == '[')) {
+ if (gs1 == 2) {
+ shift_set = c40_shift[29];
+ value = c40_value[29]; /* GS */
+ } else {
+ shift_set = 2;
+ value = 27; /* FNC1 */
+ }
+ }
+
+ if (shift_set != 0) {
+ process_buffer[*process_p] = shift_set - 1;
+ (*process_p)++;
+ }
+ process_buffer[*process_p] = value;
+ (*process_p)++;
+
+ while (*process_p >= 3) {
+ int iv;
+
+ iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1;
+ target[tp] = (unsigned char) (iv / 256);
+ tp++;
+ target[tp] = iv % 256;
+ tp++;
+ strcat(binary, " ");
+ if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]);
+
+ process_buffer[0] = process_buffer[3];
+ process_buffer[1] = process_buffer[4];
+ process_buffer[2] = process_buffer[5];
+ process_buffer[3] = 0;
+ process_buffer[4] = 0;
+ process_buffer[5] = 0;
+ *process_p -= 3;
+ }
+ sp++;
+ }
+ }
+
+ /* step (d) Text encodation */
+ if (current_mode == DM_TEXT) {
+
+ next_mode = DM_TEXT;
+ if (*process_p == 0) {
+ next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
+ }
+
+ if (next_mode != DM_TEXT) {
+ target[tp] = 254;
+ tp++;
+ strcat(binary, " "); /* Unlatch */
+ next_mode = DM_ASCII;
+ if (debug) printf("ASC ");
+ } else {
+ int shift_set, value;
+ if (source[sp] > 127) {
+ process_buffer[*process_p] = 1;
+ (*process_p)++;
+ process_buffer[*process_p] = 30;
+ (*process_p)++; /* Upper Shift */
+ shift_set = text_shift[source[sp] - 128];
+ value = text_value[source[sp] - 128];
+ } else {
+ shift_set = text_shift[source[sp]];
+ value = text_value[source[sp]];
+ }
+
+ if (gs1 && (source[sp] == '[')) {
+ if (gs1 == 2) {
+ shift_set = text_shift[29];
+ value = text_value[29]; /* GS */
+ } else {
+ shift_set = 2;
+ value = 27; /* FNC1 */
+ }
+ }
+
+ if (shift_set != 0) {
+ process_buffer[*process_p] = shift_set - 1;
+ (*process_p)++;
+ }
+ process_buffer[*process_p] = value;
+ (*process_p)++;
+
+ while (*process_p >= 3) {
+ int iv;
+
+ iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1;
+ target[tp] = (unsigned char) (iv / 256);
+ tp++;
+ target[tp] = iv % 256;
+ tp++;
+ strcat(binary, " ");
+ if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]);
+
+ process_buffer[0] = process_buffer[3];
+ process_buffer[1] = process_buffer[4];
+ process_buffer[2] = process_buffer[5];
+ process_buffer[3] = 0;
+ process_buffer[4] = 0;
+ process_buffer[5] = 0;
+ *process_p -= 3;
+ }
+ sp++;
+ }
+ }
+
+ /* step (e) X12 encodation */
+ if (current_mode == DM_X12) {
+
+ next_mode = DM_X12;
+ if (*process_p == 0) {
+ next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
+ }
+
+ if (next_mode != DM_X12) {
+ target[tp] = 254;
+ tp++;
+ strcat(binary, " "); /* Unlatch */
+ next_mode = DM_ASCII;
+ if (debug) printf("ASC ");
+ } else {
+ int value = 0;
+ if (source[sp] == 13) {
+ value = 0;
+ }
+ if (source[sp] == '*') {
+ value = 1;
+ }
+ if (source[sp] == '>') {
+ value = 2;
+ }
+ if (source[sp] == ' ') {
+ value = 3;
+ }
+ if ((source[sp] >= '0') && (source[sp] <= '9')) {
+ value = (source[sp] - '0') + 4;
+ }
+ if ((source[sp] >= 'A') && (source[sp] <= 'Z')) {
+ value = (source[sp] - 'A') + 14;
+ }
+
+ process_buffer[*process_p] = value;
+ (*process_p)++;
+
+ while (*process_p >= 3) {
+ int iv;
+
+ iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1;
+ target[tp] = (unsigned char) (iv / 256);
+ tp++;
+ target[tp] = iv % 256;
+ tp++;
+ strcat(binary, " ");
+ if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]);
+
+ process_buffer[0] = process_buffer[3];
+ process_buffer[1] = process_buffer[4];
+ process_buffer[2] = process_buffer[5];
+ process_buffer[3] = 0;
+ process_buffer[4] = 0;
+ process_buffer[5] = 0;
+ *process_p -= 3;
+ }
+ sp++;
+ }
+ }
+
+ /* step (f) EDIFACT encodation */
+ if (current_mode == DM_EDIFACT) {
+
+ next_mode = DM_EDIFACT;
+ if (*process_p == 3) {
+ next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
+ }
+
+ if (next_mode != DM_EDIFACT) {
+ process_buffer[*process_p] = 31;
+ (*process_p)++;
+ next_mode = DM_ASCII;
+ } else {
+ int value = source[sp];
+
+ if (source[sp] >= 64) { // '@'
+ value -= 64;
+ }
+
+ process_buffer[*process_p] = value;
+ (*process_p)++;
+ sp++;
+ }
+
+ while (*process_p >= 4) {
+ target[tp] = (unsigned char) ((process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4));
+ tp++;
+ target[tp] = ((process_buffer[1] & 0x0f) << 4) + ((process_buffer[2] & 0x3c) >> 2);
+ tp++;
+ target[tp] = (unsigned char) (((process_buffer[2] & 0x03) << 6) + process_buffer[3]);
+ tp++;
+ strcat(binary, " ");
+ if (debug) printf("[%d %d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2], process_buffer[3]);
+
+ process_buffer[0] = process_buffer[4];
+ process_buffer[1] = process_buffer[5];
+ process_buffer[2] = process_buffer[6];
+ process_buffer[3] = process_buffer[7];
+ process_buffer[4] = 0;
+ process_buffer[5] = 0;
+ process_buffer[6] = 0;
+ process_buffer[7] = 0;
+ *process_p -= 4;
+ }
+ }
+
+ /* step (g) Base 256 encodation */
+ if (current_mode == DM_BASE256) {
+ next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
+
+ if (next_mode == DM_BASE256) {
+ target[tp] = source[sp];
+ if (debug) printf("B%02X ", target[tp]);
+ tp++;
+ sp++;
+ strcat(binary, "b");
+ } else {
+ next_mode = DM_ASCII;
+ if (debug) printf("ASC ");
+ }
+ }
+
+ if (tp > 1558) {
+ strcpy(symbol->errtxt, "520: Data too long to fit in symbol");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ } /* while */
+
+ /* Add length and randomising algorithm to b256 */
+ i = 0;
+ while (i < tp) {
+ if (binary[i] == 'b') {
+ if ((i == 0) || (binary[i - 1] != 'b')) {
+ /* start of binary data */
+ int binary_count; /* length of b256 data */
+
+ for (binary_count = 0; binary_count + i < tp && binary[binary_count + i] == 'b'; binary_count++);
+
+ if (binary_count <= 249) {
+ dminsert(binary, i, 'b');
+ insert_value(target, i, tp, binary_count);
+ tp++;
+ } else {
+ dminsert(binary, i, 'b');
+ dminsert(binary, i + 1, 'b');
+ insert_value(target, i, tp, (binary_count / 250) + 249);
+ tp++;
+ insert_value(target, i + 1, tp, binary_count % 250);
+ tp++;
+ }
+ }
+ }
+ i++;
+ }
+
+ for (i = 0; i < tp; i++) {
+ if (binary[i] == 'b') {
+ int prn, temp;
+
+ prn = ((149 * (i + 1)) % 255) + 1;
+ temp = target[i] + prn;
+ if (temp <= 255) {
+ target[i] = (unsigned char) (temp);
+ } else {
+ target[i] = (unsigned char) (temp - 256);
+ }
+ }
+ }
+
+ *(last_mode) = current_mode;
+ *binlen_p = tp;
+ return 0;
+}
+
+static int dm200encode_remainder(unsigned char target[], int target_length, const unsigned char source[], const size_t inputlen, const int last_mode, const int process_buffer[], const int process_p, const int symbols_left) {
+ int debug = 0;
+
+ switch (last_mode) {
+ case DM_C40:
+ case DM_TEXT:
+ if (process_p == 1) // 1 data character left to encode.
+ {
+ if (symbols_left > 1) {
+ target[target_length] = 254;
+ target_length++; // Unlatch and encode remaining data in ascii.
+ }
+ target[target_length] = source[inputlen - 1] + 1;
+ target_length++;
+ } else if (process_p == 2) // 2 data characters left to encode.
+ {
+ // Pad with shift 1 value (0) and encode as double.
+ int intValue = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + 1; // ie (0 + 1).
+ target[target_length] = (unsigned char) (intValue / 256);
+ target_length++;
+ target[target_length] = (unsigned char) (intValue % 256);
+ target_length++;
+ if (symbols_left > 2) {
+ target[target_length] = 254; // Unlatch
+ target_length++;
+ }
+ } else {
+ if (symbols_left > 0) {
+ target[target_length] = 254; // Unlatch
+ target_length++;
+ }
+ }
+ break;
+
+ case DM_X12:
+ if ((symbols_left == process_p) && (process_p == 1)) {
+ // Unlatch not required!
+ target[target_length] = source[inputlen - 1] + 1;
+ target_length++;
+ } else {
+ target[target_length] = (254);
+ target_length++; // Unlatch.
+
+ if (process_p == 1) {
+ target[target_length] = source[inputlen - 1] + 1;
+ target_length++;
+ }
+
+ if (process_p == 2) {
+ target[target_length] = source[inputlen - 2] + 1;
+ target_length++;
+ target[target_length] = source[inputlen - 1] + 1;
+ target_length++;
+ }
+ }
+ break;
+
+ case DM_EDIFACT:
+ if (symbols_left <= 2) // Unlatch not required!
+ {
+ if (process_p == 1) {
+ target[target_length] = source[inputlen - 1] + 1;
+ target_length++;
+ }
+
+ if (process_p == 2) {
+ target[target_length] = source[inputlen - 2] + 1;
+ target_length++;
+ target[target_length] = source[inputlen - 1] + 1;
+ target_length++;
+ }
+ } else {
+ // Append edifact unlatch value (31) and empty buffer
+ if (process_p == 0) {
+ target[target_length] = (unsigned char) (31 << 2);
+ target_length++;
+ }
+
+ if (process_p == 1) {
+ target[target_length] = (unsigned char) ((process_buffer[0] << 2) + ((31 & 0x30) >> 4));
+ target_length++;
+ target[target_length] = (unsigned char) ((31 & 0x0f) << 4);
+ target_length++;
+ }
+
+ if (process_p == 2) {
+ target[target_length] = (unsigned char) ((process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4));
+ target_length++;
+ target[target_length] = (unsigned char) (((process_buffer[1] & 0x0f) << 4) + ((31 & 0x3c) >> 2));
+ target_length++;
+ target[target_length] = (unsigned char) (((31 & 0x03) << 6));
+ target_length++;
+ }
+
+ if (process_p == 3) {
+ target[target_length] = (unsigned char) ((process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4));
+ target_length++;
+ target[target_length] = (unsigned char) (((process_buffer[1] & 0x0f) << 4) + ((process_buffer[2] & 0x3c) >> 2));
+ target_length++;
+ target[target_length] = (unsigned char) (((process_buffer[2] & 0x03) << 6) + 31);
+ target_length++;
+ }
+ }
+ break;
+ }
+
+ if (debug) {
+ int i;
+ printf("\n\n");
+ for (i = 0; i < target_length; i++)
+ printf("%03d ", target[i]);
+
+ printf("\n");
+ }
+
+ return target_length;
+}
+
+/* add pad bits */
+static void add_tail(unsigned char target[], int tp, const int tail_length) {
+ int i, prn, temp;
+
+ for (i = tail_length; i > 0; i--) {
+ if (i == tail_length) {
+ target[tp] = 129;
+ tp++; /* Pad */
+ } else {
+ prn = ((149 * (tp + 1)) % 253) + 1;
+ temp = 129 + prn;
+ if (temp <= 254) {
+ target[tp] = (unsigned char) (temp);
+ tp++;
+ } else {
+ target[tp] = (unsigned char) (temp - 254);
+ tp++;
+ }
+ }
+ }
+}
+
+static int data_matrix_200(struct zint_symbol *symbol,const unsigned char source[], const size_t in_length) {
+ int i, skew = 0;
+ size_t inputlen = in_length;
+ unsigned char binary[2200];
+ int binlen;
+ int process_buffer[8]; /* holds remaining data to finalised */
+ int process_p; /* number of characters left to finalise */
+ int symbolsize, optionsize, calcsize;
+ int taillength, error_number = 0;
+ int H, W, FH, FW, datablock, bytes, rsblock;
+ int last_mode = DM_ASCII;
+ int symbols_left;
+
+ /* inputlen may be decremented by 2 if macro character is used */
+ error_number = dm200encode(symbol, source, binary, &last_mode, &inputlen, process_buffer, &process_p, &binlen);
+ if (error_number != 0) {
+ return error_number;
+ }
+
+ if ((symbol->option_2 >= 1) && (symbol->option_2 <= DMSIZESCOUNT)) {
+ optionsize = intsymbol[symbol->option_2 - 1];
+ } else {
+ optionsize = -1;
+ }
+
+ calcsize = DMSIZESCOUNT - 1;
+ for (i = DMSIZESCOUNT - 1; i > -1; i--) {
+ if (matrixbytes[i] >= (binlen + process_p)) {
+ // Allow for the remaining data characters
+ calcsize = i;
+ }
+ }
+
+ if (optionsize == -1) {
+ // We are in automatic size mode as the exact symbol size was not given
+ // Now check the detailed search options square only or no dmre
+ if (symbol->option_3 == DM_SQUARE) {
+ /* Skip rectangular symbols in square only mode */
+ while (matrixH[calcsize] != matrixW[calcsize]) {
+ calcsize++;
+ }
+ } else if (symbol->option_3 != DM_DMRE) {
+ /* Skip DMRE symbols in no dmre mode */
+ while (isDMRE[calcsize]) {
+ calcsize++;
+ }
+ }
+ symbolsize = calcsize;
+ } else {
+ // The symbol size was given by --ver (option_2)
+ // Thus check if the data fits into this symbol size and use this size
+ if (calcsize > optionsize) {
+ strcpy(symbol->errtxt, "522: Input too long for selected symbol size");
+ return ZINT_ERROR_TOO_LONG;
+ }
+ symbolsize = optionsize;
+ }
+
+ // Now we know the symbol size we can handle the remaining data in the process buffer.
+ symbols_left = matrixbytes[symbolsize] - binlen;
+ binlen = dm200encode_remainder(binary, binlen, source, inputlen, last_mode, process_buffer, process_p, symbols_left);
+
+ if (binlen > matrixbytes[symbolsize]) {
+ strcpy(symbol->errtxt, "523: Data too long to fit in symbol");
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ H = matrixH[symbolsize];
+ W = matrixW[symbolsize];
+ FH = matrixFH[symbolsize];
+ FW = matrixFW[symbolsize];
+ bytes = matrixbytes[symbolsize];
+ datablock = matrixdatablock[symbolsize];
+ rsblock = matrixrsblock[symbolsize];
+
+ taillength = bytes - binlen;
+
+ if (taillength != 0) {
+ add_tail(binary, binlen, taillength);
+ }
+
+ // ecc code
+ if (symbolsize == INTSYMBOL144) {
+ skew = 1;
+ }
+ ecc200(binary, bytes, datablock, rsblock, skew);
+ // Print Codewords
+#ifdef DEBUG
+ {
+ int CWCount;
+ int posCur;
+ if (skew)
+ CWCount = 1558 + 620;
+ else
+ CWCount = bytes + rsblock * (bytes / datablock);
+ printf("Codewords (%i):", CWCount);
+ for (posCur = 0; posCur < CWCount; posCur++)
+ printf(" %3i", binary[posCur]);
+ puts("\n");
+ }
+#endif
+ { // placement
+ int x, y, NC, NR, *places;
+ unsigned char *grid;
+ NC = W - 2 * (W / FW);
+ NR = H - 2 * (H / FH);
+ places = (int*) malloc(NC * NR * sizeof (int));
+ ecc200placement(places, NR, NC);
+ grid = (unsigned char*) malloc(W * H);
+ memset(grid, 0, W * H);
+ for (y = 0; y < H; y += FH) {
+ for (x = 0; x < W; x++)
+ grid[y * W + x] = 1;
+ for (x = 0; x < W; x += 2)
+ grid[(y + FH - 1) * W + x] = 1;
+ }
+ for (x = 0; x < W; x += FW) {
+ for (y = 0; y < H; y++)
+ grid[y * W + x] = 1;
+ for (y = 0; y < H; y += 2)
+ grid[y * W + x + FW - 1] = 1;
+ }
+#ifdef DEBUG
+ // Print position matrix as in standard
+ for (y = NR - 1; y >= 0; y--) {
+ for (x = 0; x < NC; x++) {
+ int v;
+ if (x != 0)
+ fprintf(stderr, "|");
+ v = places[(NR - y - 1) * NC + x];
+ fprintf(stderr, "%3d.%2d", (v >> 3), 8 - (v & 7));
+ }
+ fprintf(stderr, "\n");
+ }
+#endif
+ for (y = 0; y < NR; y++) {
+ for (x = 0; x < NC; x++) {
+ int v = places[(NR - y - 1) * NC + x];
+ //fprintf (stderr, "%4d", v);
+ if (v == 1 || (v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7)))))
+ grid[(1 + y + 2 * (y / (FH - 2))) * W + 1 + x + 2 * (x / (FW - 2))] = 1;
+ }
+ //fprintf (stderr, "\n");
+ }
+ for (y = H - 1; y >= 0; y--) {
+ int x;
+ for (x = 0; x < W; x++) {
+ if (grid[W * y + x]) {
+ set_module(symbol, (H - y) - 1, x);
+ }
+ }
+ symbol->row_height[(H - y) - 1] = 1;
+ }
+ free(grid);
+ free(places);
+ }
+
+ symbol->rows = H;
+ symbol->width = W;
+
+ return error_number;
+}
+
+INTERNAL int dmatrix(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) {
+ int error_number;
+
+ if (symbol->option_1 <= 1) {
+ /* ECC 200 */
+ error_number = data_matrix_200(symbol, source, in_length);
+ } else {
+ /* ECC 000 - 140 */
+ strcpy(symbol->errtxt, "524: Older Data Matrix standards are no longer supported");
+ error_number = ZINT_ERROR_INVALID_OPTION;
+ }
+
+ return error_number;
+}
diff --git a/backend/dmatrix.h b/backend/dmatrix.h
new file mode 100644
index 0000000..ef39825
--- /dev/null
+++ b/backend/dmatrix.h
@@ -0,0 +1,248 @@
+/* dmatrix.h - Handles Data Matrix ECC 200 */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2009-2017 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+/*
+ Containes Extended Rectangular Data Matrix (DMRE)
+ See http://www.dmre.info for information
+ Contact: harald.oehlmann@eurodatacouncil.org
+ */
+
+#ifndef __DMATRIX_H
+#define __DMATRIX_H
+
+#define MAXBARCODE 3116
+
+#define DM_NULL 0
+#define DM_ASCII 1
+#define DM_C40 2
+#define DM_TEXT 3
+#define DM_X12 4
+#define DM_EDIFACT 5
+#define DM_BASE256 6
+
+static const char c40_shift[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 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,
+ 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+};
+
+static const char c40_value[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 15, 16, 17, 18, 19, 20, 21, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 22, 23, 24, 25, 26, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+};
+
+static const char text_shift[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 3, 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, 3, 3, 3, 3, 3
+};
+
+static const char text_value[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 15, 16, 17, 18, 19, 20, 21, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 22, 23, 24, 25, 26, 0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 27, 28, 29, 30, 31
+};
+
+// Position in option array [symbol option value - 1]
+// The position in the option array is by increasing total data codewords with square first
+// The last comment value is the total data codewords value.
+// The index of this array is the --vers parameter value -1 and is given as first comment value
+
+static const unsigned short int intsymbol[] = {
+/* Standard DM */
+ 0, /* 1: 10x10 , 3*/ 1, /* 2: 12x12 , 5*/ 3, /* 3: 14x14 , 8*/ 5, /* 4: 16x16 , 12*/
+ 7, /* 5: 18x18 , 18*/ 9, /* 6: 20x20 , 22*/ 12, /* 7: 22x22 , 30*/ 15, /* 8: 24x24 , 36*/
+ 18, /* 9: 26x26 , 44*/ 23, /* 10: 32x32 , 62*/ 31, /* 11: 36x36 , 86*/ 34, /* 12: 40x40 ,114*/
+ 36, /* 13: 44x44 ,144*/ 37, /* 14: 48x48 ,174*/ 38, /* 15: 52x52 ,204*/ 39, /* 16: 64x64 ,280*/
+ 40, /* 17: 72x72 ,368*/ 41, /* 18: 80x80 ,456*/ 42, /* 19: 88x88 ,576*/ 43, /* 20: 96x96 ,696*/
+ 44, /* 21:104x104,816*/ 45, /* 22:120x120,1050*/46, /* 23:132x132,1304*/47, /* 24:144x144,1558*/
+ 2, /* 25: 8x18 , 5*/ 4, /* 26: 8x32 , 10*/ 6, /* 27: 12x26 , 16*/ 10, /* 28: 12x36 , 22*/
+ 13, /* 29: 16x36 , 32*/ 20, /* 30: 16x48 , 49*/
+/* DMRE */
+ 8, /* 31: 8x48 , 18*/ 11, /* 32: 8x64 , 24*/ 14, /* 33: 8x80 , 32*/ 16, /* 34: 8x96 , 38*/
+ 21, /* 35: 8x120, 49*/ 25, /* 36: 8x144, 63*/ 17, /* 37: 12x64 , 43*/ 26, /* 38: 12x88 , 64*/
+ 24, /* 39: 16x64 , 62*/ 19, /* 40: 20x36 , 44*/ 22, /* 41: 20x44 , 56*/ 30, /* 42: 20x64 , 84*/
+ 28, /* 43: 22x48 , 72*/ 29, /* 44: 24x48 , 80*/ 33, /* 45: 24x64 ,108*/ 27, /* 46: 26x40 , 70*/
+ 32, /* 47: 26x48 , 90*/ 35, /* 48: 26x64 ,118*/
+ 0
+};
+
+// Number of DM Sizes
+#define DMSIZESCOUNT 48
+// Number of 144x144 for special interlace
+#define INTSYMBOL144 47
+
+// Is the current code a DMRE code ?
+// This is the case, if intsymbol index >= 30
+
+static const char isDMRE[] = {
+ /* 0*/ 0, /* 10x10, 3*/ 0, /* 12x12 , 5*/ 0, /* 8x18 , 5*/ 0, /* 14x14 , 8*/
+ /* 4*/ 0, /* 8x32 , 10*/ 0, /* 16x16 , 12*/ 0, /* 12x26 , 16*/ 0, /* 18x18 , 18*/
+ /* 8*/ 1, /* 8x48 , 18*/ 0, /* 20x20 , 22*/ 0, /* 12x36 , 22*/ 1, /* 8x64 , 24*/
+ /*12*/ 0, /* 22x22 , 30*/ 0, /* 16x36 , 32*/ 1, /* 8x80 , 32*/ 0, /* 24x24 , 36*/
+ /*16*/ 1, /* 8x96 , 38*/ 1, /* 12x64 , 43*/ 0, /* 26x26 , 44*/ 1, /* 20x36 , 44*/
+ /*20*/ 0, /* 16x48 , 49*/ 1, /* 8x120, 49*/ 1, /* 20x44 , 56*/ 0, /* 32x32 , 62*/
+ /*24*/ 1, /* 16x64 , 62*/ 1, /* 8x144, 63*/ 1, /* 12x88 , 64*/ 1, /* 26x40 , 70*/
+ /*28*/ 1, /* 22x48 , 72*/ 1, /* 24x48 , 80*/ 1, /* 20x64 , 84*/ 0, /* 36x36 , 86*/
+ /*32*/ 1, /* 26x48 , 90*/ 1, /* 24x64 ,108*/ 0, /* 40x40 ,114*/ 1, /* 26x64 ,118*/
+ /*36*/ 0, /* 44x44 ,144*/ 0, /* 48x48 ,174*/ 0, /* 52x52 ,204*/ 0, /* 64x64 ,280*/
+ /*40*/ 0, /* 72x72 ,368*/ 0, /* 80x80 ,456*/ 0, /* 88x88 ,576*/ 0, /* 96x96 ,696*/
+ /*44*/ 0, /*104x104,816*/ 0, /*120x120,1050*/0, /*132x132,1304*/0 /*144x144,1558*/
+};
+
+// Horizontal matrix size
+
+static const unsigned short int matrixH[] = {
+ /* 0*/ 10, /* 10x10 , 3*/ 12, /* 12x12 , 5 */ 8, /* 8x18 , 5*/ 14, /* 14x14 , 8*/
+ /* 4*/ 8, /* 8x32 , 10*/ 16, /* 16x16 , 12*/ 12, /* 12x26 , 16*/ 18, /* 18x18 , 18*/
+ /* 8*/ 8, /* 8x48 , 18*/ 20, /* 20x20 , 22*/ 12, /* 12x36 , 22*/ 8, /* 8x64 , 24*/
+ /*12*/ 22, /* 22x22 , 30*/ 16, /* 16x36 , 32*/ 8, /* 8x80 , 32*/ 24, /* 24x24 , 36*/
+ /*16*/ 8, /* 8x96 , 38*/ 12, /* 12x64 , 43*/ 26, /* 26x26 , 44*/ 20, /* 20x36 , 44*/
+ /*20*/ 16, /* 16x48 , 49*/ 8, /* 8x120, 49*/ 20, /* 20x44 , 56*/ 32, /* 32x32 , 62*/
+ /*24*/ 16, /* 16x64 , 62*/ 8, /* 8x144, 63*/ 12, /* 12x88 , 64*/ 26, /* 26x40 , 70*/
+ /*28*/ 22, /* 22x48 , 72*/ 24, /* 24x48 , 80*/ 20, /* 20x64 , 84*/ 36, /* 36x36 , 86*/
+ /*32*/ 26, /* 26x48 , 90*/ 24, /* 24x64 ,108*/ 40, /* 40x40 ,114*/ 26, /* 26x64 ,118*/
+ /*36*/ 44, /* 44x44 ,144*/ 48, /* 48x48 ,174*/ 52, /* 52x52 ,204*/ 64, /* 64x64 ,280*/
+ /*40*/ 72, /* 72x72 ,368*/ 80, /* 80x80 ,456*/ 88, /* 88x88 ,576*/ 96, /* 96x96 ,696*/
+ /*44*/104, /*104x104,816*/ 120,/*120x120,1050*/132,/*132x132,1304*/144 /*144x144,1558*/
+};
+
+// Vertical matrix sizes
+
+static const unsigned short int matrixW[] = {
+ /* 0*/ 10, /* 10x10 */ 12, /* 12x12 */ 18, /* 8x18 */ 14, /* 14x14 */
+ /* 4*/ 32, /* 8x32 */ 16, /* 16x16 */ 26, /* 12x26 */ 18, /* 18x18 */
+ /* 8*/ 48, /* 8x48 */ 20, /* 20x20 */ 36, /* 12x36 */ 64, /* 8x64 */
+ /*12*/ 22, /* 22x22 */ 36, /* 16x36 */ 80, /* 8x80 */ 24, /* 24x24 */
+ /*16*/ 96, /* 8x96 */ 64, /* 12x64 */ 26, /* 26x26 */ 36, /* 20x36 */
+ /*20*/ 48, /* 16x48 */120, /* 8x120*/ 44, /* 20x44 */ 32, /* 32x32 */
+ /*24*/ 64, /* 16x64 */144, /* 8x144*/ 88, /* 12x88 */ 40, /* 26x40 */
+ /*28*/ 48, /* 22x48 */ 48, /* 24x48 */ 64, /* 20x64 */ 36, /* 36x36 */
+ /*32*/ 48, /* 26x48 */ 64, /* 24x64 */ 40, /* 40x40 */ 64, /* 26x64 */
+ /*36*/ 44, /* 44x44 */ 48, /* 48x48 */ 52, /* 52x52 */ 64, /* 64x64 */
+ /*40*/ 72, /* 72x72 */ 80, /* 80x80 */ 88, /* 88x88 */ 96, /* 96x96 */
+ /*44*/104, /*104x104*/120, /*120x120*/ 132, /*132x132*/144 /*144x144*/
+
+};
+
+// Horizontal submodule size (including subfinder)
+
+static const unsigned short int matrixFH[] = {
+ /* 0*/ 10, /* 10x10 */ 12, /* 12x12 */ 8, /* 8x18 */ 14, /* 14x14 */
+ /* 4*/ 8, /* 8x32 */ 16, /* 16x16 */ 12, /* 12x26 */ 18, /* 18x18 */
+ /* 8*/ 8, /* 8x48 */ 20, /* 20x20 */ 12, /* 12x36 */ 8, /* 8x64 */
+ /*12*/ 22, /* 22x22 */ 16, /* 16x36 */ 8, /* 8x80 */ 24, /* 24x24 */
+ /*16*/ 8, /* 8x96 */ 12, /* 12x64 */ 26, /* 26x26 */ 20, /* 20x36 */
+ /*20*/ 16, /* 16x48 */ 8, /* 8x120*/ 20, /* 20x44 */ 16, /* 32x32 */
+ /*24*/ 16, /* 16x64 */ 8, /* 8x144*/ 12, /* 12x88 */ 26, /* 26x40 */
+ /*28*/ 22, /* 22x48 */ 24, /* 24x48 */ 20, /* 20x64 */ 18, /* 36x36 */
+ /*32*/ 26, /* 26x48 */ 24, /* 24x64 */ 20, /* 40x40 */ 26, /* 26x64 */
+ /*36*/ 22, /* 44x44 */ 24, /* 48x48 */ 26, /* 52x52 */ 16, /* 64x64 */
+ /*40*/ 18, /* 72x72 */ 20, /* 80x80 */ 22, /* 88x88 */ 24, /* 96x96 */
+ /*44*/ 26, /*104x104*/ 20, /*120x120*/ 22, /*132x132*/ 24 /*144x144*/
+};
+
+// Vertical submodule size (including subfinder)
+
+static const unsigned short int matrixFW[] = {
+ /* 0*/ 10, /* 10x10 */ 12, /* 12x12 */ 18, /* 8x18 */ 14, /* 14x14 */
+ /* 4*/ 16, /* 8x32 */ 16, /* 16x16 */ 26, /* 12x26 */ 18, /* 18x18 */
+ /* 8*/ 24, /* 8x48 */ 20, /* 20x20 */ 18, /* 12x36 */ 16, /* 8x64 */
+ /*12*/ 22, /* 22x22 */ 18, /* 16x36 */ 20, /* 8x80 */ 24, /* 24x24 */
+ /*16*/ 24, /* 8x96 */ 16, /* 12x64 */ 26, /* 26x26 */ 18, /* 20x36 */
+ /*20*/ 24, /* 16x48 */ 20, /* 8x120*/ 22, /* 20x44 */ 16, /* 32x32 */
+ /*24*/ 16, /* 16x64 */ 24, /* 8x144*/ 22, /* 12x88 */ 20, /* 26x40 */
+ /*28*/ 24, /* 22x48 */ 24, /* 24x48 */ 16, /* 20x64 */ 18, /* 36x36 */
+ /*32*/ 24, /* 26x48 */ 16, /* 24x64 */ 20, /* 40x40 */ 16, /* 26x64 */
+ /*36*/ 22, /* 44x44 */ 24, /* 48x48 */ 26, /* 52x52 */ 16, /* 64x64 */
+ /*40*/ 18, /* 72x72 */ 20, /* 80x80 */ 22, /* 88x88 */ 24, /* 96x96 */
+ /*44*/ 26, /*104x104*/ 20, /*120x120*/ 22, /*132x132*/ 24 /*144x144*/
+};
+
+// Total Data Codewords
+
+static const unsigned short int matrixbytes[] = {
+ /* 0*/ 3, /* 10x10 */ 5, /* 12x12 */ 5, /* 8x18 */ 8, /* 14x14 */
+ /* 4*/ 10, /* 8x32 */ 12, /* 16x16 */ 16, /* 12x26 */ 18, /* 18x18 */
+ /* 8*/ 18, /* 8x48 */ 22, /* 20x20 */ 22, /* 12x36 */ 24, /* 8x64 */
+ /*12*/ 30, /* 22x22 */ 32, /* 16x36 */ 32, /* 8x80 */ 36, /* 24x24 */
+ /*16*/ 38, /* 8x96 */ 43, /* 12x64 */ 44, /* 26x26 */ 44, /* 20x36 */
+ /*20*/ 49, /* 16x48 */ 49, /* 8x120*/ 56, /* 20x44 */ 62, /* 32x32 */
+ /*24*/ 62, /* 16x64 */ 63, /* 8x144*/ 64, /* 12x88 */ 70, /* 26x40 */
+ /*28*/ 72, /* 22x48 */ 80, /* 24x48 */ 84, /* 20x64 */ 86, /* 36x36 */
+ /*32*/ 90, /* 26x48 */ 108, /* 24x64 */ 114, /* 40x40 */ 118, /* 26x64 */
+ /*36*/ 144, /* 44x44 */ 174, /* 48x48 */ 204, /* 52x52 */ 280, /* 64x64 */
+ /*40*/ 368, /* 72x72 */ 456, /* 80x80 */ 576, /* 88x88 */ 696, /* 96x96 */
+ /*44*/ 816, /*104x104*/1050, /*120x120*/1304, /*132x132*/1558 /*144x144*/
+};
+
+// Data Codewords per RS-Block
+
+static const unsigned short int matrixdatablock[] = {
+ /* 0*/ 3, /* 10x10 */ 5, /* 12x12 */ 5, /* 8x18 */ 8, /* 14x14 */
+ /* 4*/ 10, /* 8x32 */ 12, /* 16x16 */ 16, /* 12x26 */ 18, /* 18x18 */
+ /* 8*/ 18, /* 8x48 */ 22, /* 20x20 */ 22, /* 12x36 */ 24, /* 8x64 */
+ /*12*/ 30, /* 22x22 */ 32, /* 16x36 */ 32, /* 8x80 */ 36, /* 24x24 */
+ /*16*/ 38, /* 8x96 */ 43, /* 12x64 */ 44, /* 26x26 */ 44, /* 20x36 */
+ /*20*/ 49, /* 16x48 */ 49, /* 8x120*/ 56, /* 20x44 */ 62, /* 32x32 */
+ /*24*/ 62, /* 16x64 */ 63, /* 8x144*/ 64, /* 12x88 */ 70, /* 26x40 */
+ /*28*/ 72, /* 22x48 */ 80, /* 24x48 */ 84, /* 20x64 */ 86, /* 36x36 */
+ /*32*/ 90, /* 26x48 */ 108, /* 24x64 */ 114, /* 40x40 */ 118, /* 26x64 */
+ /*36*/ 144, /* 44x44 */ 174, /* 48x48 */ 102, /* 52x52 */ 140, /* 64x64 */
+ /*40*/ 92, /* 72x72 */ 114, /* 80x80 */ 144, /* 88x88 */ 174, /* 96x96 */
+ /*44*/ 136, /*104x104*/ 175, /*120x120*/ 163, /*132x132*/ 156 /* 144x144*/
+};
+
+// ECC Codewords per RS-Block
+
+static const unsigned short int matrixrsblock[] = {
+ /* 0*/ 5, /* 10x10 */ 7, /* 12x12 */ 7, /* 8x18 */ 10, /* 14x14 */
+ /* 4*/ 11, /* 8x32 */ 12, /* 16x16 */ 14, /* 12x26 */ 14, /* 18x18 */
+ /* 8*/ 15, /* 8x48 */ 18, /* 20x20 */ 18, /* 12x36 */ 18, /* 8x64 */
+ /*12*/ 20, /* 22x22 */ 24, /* 16x36 */ 22, /* 8x80 */ 24, /* 24x24 */
+ /*16*/ 28, /* 8x96 */ 27, /* 12x64 */ 28, /* 26x26 */ 28, /* 20x36 */
+ /*20*/ 28, /* 16x48 */ 32, /* 8x120*/ 34, /* 20x44 */ 36, /* 32x32 */
+ /*24*/ 36, /* 16x64 */ 36, /* 8x144*/ 36, /* 12x88 */ 38, /* 26x40 */
+ /*28*/ 38, /* 22x48 */ 41, /* 24x48 */ 42, /* 20x64 */ 42, /* 36x36 */
+ /*32*/ 42, /* 26x48 */ 46, /* 24x64 */ 48, /* 40x40 */ 50, /* 26x64 */
+ /*36*/ 56, /* 44x44 */ 68, /* 48x48 */ 42, /* 52x52 */ 56, /* 64x64 */
+ /*40*/ 36, /* 72x72 */ 48, /* 80x80 */ 56, /* 88x88 */ 68, /* 96x96 */
+ /*44*/ 56, /*104x104*/ 68, /*120x120*/ 62, /*132x132*/ 62 /*144x144*/
+};
+
+#endif /* __DMATRIX_H */
diff --git a/backend/dotcode.c b/backend/dotcode.c
new file mode 100644
index 0000000..78f3914
--- /dev/null
+++ b/backend/dotcode.c
@@ -0,0 +1,1569 @@
+/* dotcode.c - Handles DotCode */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2017-2020 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+/*
+ * Attempts to encode DotCode according to (AIMD013) ISS DotCode Rev. 4.0, DRAFT 0.15, TSC Pre-PR #5, dated May 28, 2019
+ * Incorporating suggestions from Terry Burton at BWIPP
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#ifndef _MSC_VER
+#include <stdint.h>
+#else
+#include "ms_stdint.h"
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "gs1.h"
+
+#define GF 113
+#define PM 3
+#define SCORE_UNLIT_EDGE -99999
+
+/* DotCode symbol character dot patterns, from Annex C */
+static const unsigned short int dot_patterns[113] = {
+ 0x155, 0x0ab, 0x0ad, 0x0b5, 0x0d5, 0x156, 0x15a, 0x16a, 0x1aa, 0x0ae,
+ 0x0b6, 0x0ba, 0x0d6, 0x0da, 0x0ea, 0x12b, 0x12d, 0x135, 0x14b, 0x14d,
+ 0x153, 0x159, 0x165, 0x169, 0x195, 0x1a5, 0x1a9, 0x057, 0x05b, 0x05d,
+ 0x06b, 0x06d, 0x075, 0x097, 0x09b, 0x09d, 0x0a7, 0x0b3, 0x0b9, 0x0cb,
+ 0x0cd, 0x0d3, 0x0d9, 0x0e5, 0x0e9, 0x12e, 0x136, 0x13a, 0x14e, 0x15c,
+ 0x166, 0x16c, 0x172, 0x174, 0x196, 0x19a, 0x1a6, 0x1ac, 0x1b2, 0x1b4,
+ 0x1ca, 0x1d2, 0x1d4, 0x05e, 0x06e, 0x076, 0x07a, 0x09e, 0x0bc, 0x0ce,
+ 0x0dc, 0x0e6, 0x0ec, 0x0f2, 0x0f4, 0x117, 0x11b, 0x11d, 0x127, 0x133,
+ 0x139, 0x147, 0x163, 0x171, 0x18b, 0x18d, 0x193, 0x199, 0x1a3, 0x1b1,
+ 0x1c5, 0x1c9, 0x1d1, 0x02f, 0x037, 0x03b, 0x03d, 0x04f, 0x067, 0x073,
+ 0x079, 0x08f, 0x0c7, 0x0e3, 0x0f1, 0x11e, 0x13c, 0x178, 0x18e, 0x19c,
+ 0x1b8, 0x1c6, 0x1cc
+};
+
+// Printed() routine from Annex A adapted to char array of ASCII 1's and 0's
+static int get_dot(char Dots[], const int Hgt, const int Wid, const int x, const int y) {
+ int retval = 0;
+
+ if ((x >= 0) && (x < Wid) && (y >= 0) && (y < Hgt)) {
+ if (Dots[(y * Wid) + x] == '1') {
+ retval = 1;
+ }
+ }
+
+ return retval;
+}
+
+static int clr_col(char *Dots, const int Hgt, const int Wid, const int x) {
+ int y;
+ for (y = x & 1; y < Hgt; y += 2) {
+ if (get_dot(Dots, Hgt, Wid, x, y)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int clr_row(char *Dots, const int Hgt, const int Wid, const int y) {
+ int x;
+ for (x = y & 1; x < Wid; x += 2) {
+ if (get_dot(Dots, Hgt, Wid, x, y)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+// calc penalty for empty interior columns
+static int col_penalty(char *Dots, int Hgt, int Wid) {
+ int x, penalty = 0, penalty_local = 0;
+
+ for (x = 1; x < Wid - 1; x++) {
+ if (clr_col(Dots, Hgt, Wid, x)) {
+ if (penalty_local == 0) {
+ penalty_local = Hgt;
+ } else {
+ penalty_local *= Hgt;
+ }
+ } else {
+ if (penalty_local) {
+ penalty += penalty_local;
+ penalty_local = 0;
+ }
+ }
+ }
+
+ return penalty + penalty_local;
+}
+
+// calc penalty for empty interior rows
+static int row_penalty(char *Dots, int Hgt, int Wid) {
+ int y, penalty = 0, penalty_local = 0;
+
+ for (y = 1; y < Hgt - 1; y++) {
+ if (clr_row(Dots, Hgt, Wid, y)) {
+ if (penalty_local == 0) {
+ penalty_local = Wid;
+ } else {
+ penalty_local *= Wid;
+ }
+ } else {
+ if (penalty_local) {
+ penalty += penalty_local;
+ penalty_local = 0;
+ }
+ }
+ }
+
+ return penalty + penalty_local;
+}
+
+/* Dot pattern scoring routine from Annex A */
+static int score_array(char Dots[], int Hgt, int Wid) {
+ int x, y, worstedge, first, last, sum;
+ int penalty = 0;
+
+ // first, guard against "pathelogical" gaps in the array
+ // subtract a penalty score for empty rows/columns from total code score for each mask,
+ // where the penalty is Sum(N ^ n), where N is the number of positions in a column/row,
+ // and n is the number of consecutive empty rows/columns
+ penalty = row_penalty(Dots, Hgt, Wid) + col_penalty(Dots, Hgt, Wid);
+
+ sum = 0;
+ first = -1;
+ last = -1;
+
+ // across the top edge, count printed dots and measure their extent
+ for (x = 0; x < Wid; x += 2) {
+ if (get_dot(Dots, Hgt, Wid, x, 0)) {
+ if (first < 0) {
+ first = x;
+ }
+ last = x;
+ sum++;
+ }
+ }
+ if (sum == 0) {
+ return SCORE_UNLIT_EDGE; // guard against empty top edge
+ }
+
+ worstedge = sum + last - first;
+ worstedge *= Hgt;
+
+ sum = 0;
+ first = -1;
+ last = -1;
+
+ // across the bottom edge, ditto
+ for (x = Wid & 1; x < Wid; x += 2) {
+ if (get_dot(Dots, Hgt, Wid, x, Hgt - 1)) {
+ if (first < 0) {
+ first = x;
+ }
+ last = x;
+ sum++;
+ }
+ }
+ if (sum == 0) {
+ return SCORE_UNLIT_EDGE; // guard against empty bottom edge
+ }
+
+ sum += last - first;
+ sum *= Hgt;
+ if (sum < worstedge) {
+ worstedge = sum;
+ }
+
+ sum = 0;
+ first = -1;
+ last = -1;
+
+ // down the left edge, ditto
+ for (y = 0; y < Hgt; y += 2) {
+ if (get_dot(Dots, Hgt, Wid, 0, y)) {
+ if (first < 0) {
+ first = y;
+ }
+ last = y;
+ sum++;
+ }
+ }
+ if (sum == 0) {
+ return SCORE_UNLIT_EDGE; // guard against empty left edge
+ }
+
+ sum += last - first;
+ sum *= Wid;
+ if (sum < worstedge) {
+ worstedge = sum;
+ }
+
+ sum = 0;
+ first = -1;
+ last = -1;
+
+ // down the right edge, ditto
+ for (y = Hgt & 1; y < Hgt; y += 2) {
+ if (get_dot(Dots, Hgt, Wid, Wid - 1, y)) {
+ if (first < 0) {
+ first = y;
+ }
+ last = y;
+ sum++;
+ }
+ }
+ if (sum == 0) {
+ return SCORE_UNLIT_EDGE; // guard against empty right edge
+ }
+
+ sum += last - first;
+ sum *= Wid;
+ if (sum < worstedge) {
+ worstedge = sum;
+ }
+
+ // throughout the array, count the # of unprinted 5-somes (cross patterns)
+ // plus the # of printed dots surrounded by 8 unprinted neighbors
+ sum = 0;
+ for (y = 0; y < Hgt; y++) {
+ for (x = y & 1; x < Wid; x += 2) {
+ if ((!get_dot(Dots, Hgt, Wid, x - 1, y - 1))
+ && (!get_dot(Dots, Hgt, Wid, x + 1, y - 1))
+ && (!get_dot(Dots, Hgt, Wid, x - 1, y + 1))
+ && (!get_dot(Dots, Hgt, Wid, x + 1, y + 1))
+ && ((!get_dot(Dots, Hgt, Wid, x, y))
+ || ((!get_dot(Dots, Hgt, Wid, x - 2, y))
+ && (!get_dot(Dots, Hgt, Wid, x, y - 2))
+ && (!get_dot(Dots, Hgt, Wid, x + 2, y))
+ && (!get_dot(Dots, Hgt, Wid, x, y + 2))))) {
+ sum++;
+ }
+ }
+ }
+
+ return (worstedge - sum * sum - penalty);
+}
+
+//-------------------------------------------------------------------------
+// "rsencode(nd,nc)" adds "nc" R-S check words to "nd" data words in wd[]
+// employing Galois Field GF, where GF is prime, with a prime modulus of PM
+//-------------------------------------------------------------------------
+
+static void rsencode(int nd, int nc, unsigned char *wd) {
+ // roots (antilogs): root[0] = 1; for (i = 1; i < GF - 1; i++) root[i] = (PM * root[i - 1]) % GF;
+ static int root[GF - 1] = {
+ 1, 3, 9, 27, 81, 17, 51, 40, 7, 21,
+ 63, 76, 2, 6, 18, 54, 49, 34, 102, 80,
+ 14, 42, 13, 39, 4, 12, 36, 108, 98, 68,
+ 91, 47, 28, 84, 26, 78, 8, 24, 72, 103,
+ 83, 23, 69, 94, 56, 55, 52, 43, 16, 48,
+ 31, 93, 53, 46, 25, 75, 112, 110, 104, 86,
+ 32, 96, 62, 73, 106, 92, 50, 37, 111, 107,
+ 95, 59, 64, 79, 11, 33, 99, 71, 100, 74,
+ 109, 101, 77, 5, 15, 45, 22, 66, 85, 29,
+ 87, 35, 105, 89, 41, 10, 30, 90, 44, 19,
+ 57, 58, 61, 70, 97, 65, 82, 20, 60, 67,
+ 88, 38
+ };
+ int i, j, k, nw, start, step, c[GF];
+
+ // Here we compute how many interleaved R-S blocks will be needed
+ nw = nd + nc;
+ step = (nw + GF - 2) / (GF - 1);
+
+ // ...& then for each such block:
+ for (start = 0; start < step; start++) {
+ int ND = (nd - start + step - 1) / step;
+ int NW = (nw - start + step - 1) / step;
+ int NC = NW - ND;
+
+ // first compute the generator polynomial "c" of order "NC":
+ memset(c, 0, GF * sizeof(int)); // Keep clang-tidy happy (as far as UndefinedBinaryOperatorResult warning below at least)
+
+ c[0] = 1;
+ for (i = 1; i <= NC; i++) {
+ for (j = NC; j >= 1; j--) {
+ c[j] = (GF + c[j] - (root[i] * c[j - 1]) % GF) % GF;
+ }
+ }
+
+ // & then compute the corresponding checkword values into wd[]
+ // ... (a) starting at wd[start] & (b) stepping by step
+ for (i = ND; i < NW; i++) {
+ wd[start + i * step] = 0;
+ }
+ for (i = 0; i < ND; i++) {
+ k = (wd[start + i * step] + wd[start + ND * step]) % GF; // NOLINT wd set 0..(nd - 1) and start + i * step <= nd - 1
+ for (j = 0; j < NC - 1; j++) {
+ wd[start + (ND + j) * step] = (GF - ((c[j + 1] * k) % GF) + wd[start + (ND + j + 1) * step]) % GF;
+ }
+ wd[start + (ND + NC - 1) * step] = (GF - ((c[NC] * k) % GF)) % GF;
+ }
+ for (i = ND; i < NW; i++) {
+ wd[start + i * step] = (GF - wd[start + i * step]) % GF;
+ }
+ }
+}
+
+/* Check if the next character is directly encodable in code set A (Annex F.II.D) */
+static int datum_a(const unsigned char source[], int position, int length) {
+ int retval = 0;
+
+ if (position < length) {
+ if (source[position] <= 95) {
+ retval = 1;
+ }
+ }
+
+ return retval;
+}
+
+/* Check if the next character is directly encodable in code set B (Annex F.II.D). Note changed to return 2 if CR/LF */
+static int datum_b(const unsigned char source[], int position, int length) {
+ int retval = 0;
+
+ if (position < length) {
+ if ((source[position] >= 32) && (source[position] <= 127)) {
+ retval = 1;
+ }
+
+ switch (source[position]) {
+ case 9: // HT
+ case 28: // FS
+ case 29: // GS
+ case 30: // RS
+ retval = 1;
+ }
+
+ if (position + 1 < length) {
+ if ((source[position] == 13) && (source[position + 1] == 10)) { // CRLF
+ retval = 2;
+ }
+ }
+ }
+
+ return retval;
+}
+
+/* Check if the next characters are directly encodable in code set C (Annex F.II.D) */
+static int datum_c(const unsigned char source[], int position, int length) {
+ int retval = 0;
+
+ if (position <= length - 2) {
+ if (((source[position] >= '0') && (source[position] <= '9'))
+ && ((source[position + 1] >= '0') && (source[position + 1] <= '9')))
+ retval = 1;
+ }
+
+ return retval;
+}
+
+/* Returns how many consecutive digits lie immediately ahead (Annex F.II.A) */
+static int n_digits(const unsigned char source[], int position, int length) {
+ int i;
+
+ for (i = position; ((source[i] >= '0') && (source[i] <= '9')) && (i < length); i++);
+
+ return i - position;
+}
+
+/* checks ahead for 10 or more digits starting "17xxxxxx10..." (Annex F.II.B) */
+static int seventeen_ten(const unsigned char source[], int position, int length) {
+ int found = 0;
+
+ if (n_digits(source, position, length) >= 10) {
+ if (((source[position] == '1') && (source[position + 1] == '7'))
+ && ((source[position + 8] == '1') && (source[position + 9] == '0'))) {
+ found = 1;
+ }
+ }
+
+ return found;
+}
+
+/* checks how many characters ahead can be reached while datum_c is true,
+ * returning the resulting number of codewords (Annex F.II.E)
+ */
+static int ahead_c(const unsigned char source[], int position, int length) {
+ int count = 0;
+ int i;
+
+ for (i = position; (i < length) && datum_c(source, i, length); i += 2) {
+ count++;
+ }
+
+ return count;
+}
+
+/* Annex F.II.F */
+static int try_c(const unsigned char source[], int position, int length) {
+ int retval = 0;
+
+ if (n_digits(source, position, length) > 0) {
+ if (ahead_c(source, position, length) > ahead_c(source, position + 1, length)) {
+ retval = ahead_c(source, position, length);
+ }
+ }
+
+ return retval;
+}
+
+/* Annex F.II.G */
+static int ahead_a(const unsigned char source[], int position, int length) {
+ int count = 0;
+ int i;
+
+ for (i = position; ((i < length) && datum_a(source, i, length))
+ && (try_c(source, i, length) < 2); i++) {
+ count++;
+ }
+
+ return count;
+}
+
+/* Annex F.II.H Note: changed to return number of chars encodable. Number of codewords returned in *p_nx. */
+static int ahead_b(const unsigned char source[], int position, int length, int *p_nx) {
+ int count = 0;
+ int i, incr;
+
+ for (i = position; (i < length) && (incr = datum_b(source, i, length))
+ && (try_c(source, i, length) < 2); i += incr) {
+ count++;
+ }
+
+ if (p_nx != NULL) {
+ *p_nx = count;
+ }
+
+ return i - position;
+}
+
+/* checks if the next character is in the range 128 to 255 (Annex F.II.I) */
+static int binary(const unsigned char source[], int length, int position) {
+ int retval = 0;
+
+ if (position < length && source[position] >= 128) {
+ retval = 1;
+ }
+
+ return retval;
+}
+
+/* Analyse input data stream and encode using algorithm from Annex F */
+static int dotcode_encode_message(struct zint_symbol *symbol, const unsigned char source[], int length, unsigned char *codeword_array, int *binary_finish) {
+ static char lead_specials[] = "\x09\x1C\x1D\x1E"; // HT, FS, GS, RS
+
+ int input_position, array_length, i;
+ char encoding_mode;
+ int inside_macro;
+ int debug = (symbol->debug & ZINT_DEBUG_PRINT);
+ int binary_buffer_size = 0;
+ int lawrencium[6]; // Reversed radix 103 values
+ int nx;
+
+#if defined(_MSC_VER) && _MSC_VER == 1200
+ uint64_t binary_buffer = 0;
+#else
+ uint64_t binary_buffer = 0ULL;
+#endif
+
+ input_position = 0;
+ array_length = 0;
+ encoding_mode = 'C';
+ inside_macro = 0;
+
+ if (symbol->output_options & READER_INIT) {
+ codeword_array[array_length] = 109; // FNC3
+ array_length++;
+ }
+
+ if ((symbol->input_mode & 0x07) != GS1_MODE) {
+ if (length > 2) {
+ if (((source[input_position] >= '0') && (source[input_position] <= '9')) &&
+ ((source[input_position + 1] >= '0') && (source[input_position + 1] <= '9'))) {
+ codeword_array[array_length] = 107; // FNC1
+ array_length++;
+ }
+ }
+ }
+
+ if (symbol->eci > 0) {
+ codeword_array[array_length] = 108; // FNC2
+ array_length++;
+ if (symbol->eci <= 39) {
+ codeword_array[array_length] = symbol->eci;
+ array_length++;
+ } else {
+ // the next three codewords valued A, B & C encode the ECI value of
+ // (A - 40) * 12769 + B * 113 + C + 40 (Section 5.2.1)
+ int a, b, c;
+ a = (symbol->eci - 40) / 12769;
+ b = ((symbol->eci - 40) - (12769 * a)) / 113;
+ c = (symbol->eci - 40) - (12769 * a) - (113 * b);
+
+ codeword_array[array_length] = a + 40;
+ array_length++;
+ codeword_array[array_length] = b;
+ array_length++;
+ codeword_array[array_length] = c;
+ array_length++;
+ }
+ }
+
+ // Prevent encodation as a macro if a special character is in first position
+ if (strchr(lead_specials, source[input_position]) != NULL) {
+ codeword_array[array_length] = 101; // Latch A
+ array_length++;
+ codeword_array[array_length] = source[input_position] + 64;
+ array_length++;
+ encoding_mode = 'A';
+ input_position++;
+ }
+
+ while (input_position < length) {
+ int done = 0;
+ /* Step A */
+ if ((input_position == length - 2) && (inside_macro != 0) && (inside_macro != 100)) {
+ // inside_macro only gets set to 97, 98 or 99 if the last two characters are RS/EOT
+ input_position += 2;
+ done = 1;
+ if (debug) {
+ printf("A ");
+ }
+ }
+
+ /* Step B */
+ if ((input_position == length - 1) && (inside_macro == 100)) {
+ // inside_macro only gets set to 100 if the last character is EOT
+ input_position++;
+ done = 1;
+ if (debug) {
+ printf("B ");
+ }
+ }
+
+ /* Step C1 */
+ if ((!done) && (encoding_mode == 'C')) {
+ if ((array_length == 0) && (length > 6)) {
+ if ((source[input_position] == '[')
+ && (source[input_position + 1] == ')')
+ && (source[input_position + 2] == '>')
+ && (source[input_position + 3] == 30) // RS
+ && (source[length - 1] == 4)) { // EOT
+
+
+ if ((source[input_position + 6] == 29) && (source[length - 2] == 30)) { // GS/RS
+ if ((source[input_position + 4] == '0') && (source[input_position + 5] == '5')) {
+ codeword_array[array_length] = 106; // Latch B
+ array_length++;
+ encoding_mode = 'B';
+ codeword_array[array_length] = 97; // Macro
+ array_length++;
+ input_position += 7;
+ inside_macro = 97;
+ done = 1;
+ if (debug) {
+ printf("C1/1 ");
+ }
+ }
+
+ if ((!done) && (source[input_position + 4] == '0') && (source[input_position + 5] == '6')) {
+ codeword_array[array_length] = 106; // Latch B
+ array_length++;
+ encoding_mode = 'B';
+ codeword_array[array_length] = 98; // Macro
+ array_length++;
+ input_position += 7;
+ inside_macro = 98;
+ done = 1;
+ if (debug) {
+ printf("C1/2 ");
+ }
+ }
+
+ if ((!done) && (source[input_position + 4] == '1') && (source[input_position + 5] == '2')) {
+ codeword_array[array_length] = 106; // Latch B
+ array_length++;
+ encoding_mode = 'B';
+ codeword_array[array_length] = 99; // Macro
+ array_length++;
+ input_position += 7;
+ inside_macro = 99;
+ done = 1;
+ if (debug) {
+ printf("C1/3 ");
+ }
+ }
+ }
+
+ if ((!done) && (source[input_position + 4] >= '0') && (source[input_position + 4] <= '9') &&
+ (source[input_position + 5] >= '0') && (source[input_position + 5] <= '9')) {
+ codeword_array[array_length] = 106; // Latch B
+ array_length++;
+ encoding_mode = 'B';
+ codeword_array[array_length] = 100; // Macro
+ array_length++;
+ input_position += 4;
+ inside_macro = 100;
+ done = 1;
+ if (debug) {
+ printf("C1/4 ");
+ }
+ }
+ }
+ }
+ }
+
+ /* Step C2 */
+ if ((!done) && (encoding_mode == 'C')) {
+ if (seventeen_ten(source, input_position, length)) {
+ codeword_array[array_length] = 100; // (17)...(10)
+ array_length++;
+ codeword_array[array_length] = ((source[input_position + 2] - '0') * 10) + (source[input_position + 3] - '0');
+ array_length++;
+ codeword_array[array_length] = ((source[input_position + 4] - '0') * 10) + (source[input_position + 5] - '0');
+ array_length++;
+ codeword_array[array_length] = ((source[input_position + 6] - '0') * 10) + (source[input_position + 7] - '0');
+ array_length++;
+ input_position += 10;
+ done = 1;
+ if (debug) {
+ printf("C2/1 ");
+ }
+ }
+ }
+
+ if ((!done) && (encoding_mode == 'C')) {
+ if (datum_c(source, input_position, length) || ((source[input_position] == '[') && ((symbol->input_mode & 0x07) == GS1_MODE))) {
+ if (source[input_position] == '[') {
+ codeword_array[array_length] = 107; // FNC1
+ input_position++;
+ } else {
+ codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0');
+ input_position += 2;
+ }
+ array_length++;
+ done = 1;
+ if (debug) {
+ printf("C2/2 ");
+ }
+ }
+ }
+
+ /* Step C3 */
+ if ((!done) && (encoding_mode == 'C')) {
+ if (binary(source, length, input_position)) {
+ if (n_digits(source, input_position + 1, length) > 0) {
+ if ((source[input_position] - 128) < 32) {
+ codeword_array[array_length] = 110; // Upper Shift A
+ array_length++;
+ codeword_array[array_length] = source[input_position] - 128 + 64;
+ array_length++;
+ } else {
+ codeword_array[array_length] = 111; // Upper Shift B
+ array_length++;
+ codeword_array[array_length] = source[input_position] - 128 - 32;
+ array_length++;
+ }
+ input_position++;
+ } else {
+ codeword_array[array_length] = 112; // Bin Latch
+ array_length++;
+ encoding_mode = 'X';
+ }
+ done = 1;
+ if (debug) {
+ printf("C3 ");
+ }
+ }
+ }
+
+ /* Step C4 */
+ if ((!done) && (encoding_mode == 'C')) {
+ int m = ahead_a(source, input_position, length);
+ int n = ahead_b(source, input_position, length, &nx);
+ if (m > n) {
+ codeword_array[array_length] = 101; // Latch A
+ array_length++;
+ encoding_mode = 'A';
+ } else {
+ if (nx >= 1 && nx <= 4) {
+ codeword_array[array_length] = 101 + nx; // nx Shift B
+ array_length++;
+
+ for (i = 0; i < nx; i++) {
+ if (source[input_position] >= 32) {
+ codeword_array[array_length] = source[input_position] - 32;
+ } else if (source[input_position] == 13) { // CR/LF
+ codeword_array[array_length] = 96;
+ input_position++;
+ } else {
+ switch(source[input_position]) {
+ case 9: codeword_array[array_length] = 97; break; // HT
+ case 28: codeword_array[array_length] = 98; break; // FS
+ case 29: codeword_array[array_length] = 99; break; // GS
+ case 30: codeword_array[array_length] = 100; break; // RS
+ }
+ }
+ array_length++;
+ input_position++;
+ }
+ } else {
+ codeword_array[array_length] = 106; // Latch B
+ array_length++;
+ encoding_mode = 'B';
+ }
+ }
+ done = 1;
+ if (debug) {
+ printf("C4 ");
+ }
+ }
+
+ /* Step D1 */
+ if ((!done) && (encoding_mode == 'B')) {
+ int n = try_c(source, input_position, length);
+
+ if (n >= 2) {
+ if (n <= 4) {
+ codeword_array[array_length] = 103 + (n - 2); // nx Shift C
+ array_length++;
+ for (i = 0; i < n; i++) {
+ codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0');
+ array_length++;
+ input_position += 2;
+ }
+ } else {
+ codeword_array[array_length] = 106; // Latch C
+ array_length++;
+ encoding_mode = 'C';
+ }
+ done = 1;
+ if (debug) {
+ printf("D1 ");
+ }
+ }
+ }
+
+ /* Step D2 */
+ if ((!done) && (encoding_mode == 'B')) {
+ if ((source[input_position] == '[') && ((symbol->input_mode & 0x07) == GS1_MODE)) {
+ codeword_array[array_length] = 107; // FNC1
+ array_length++;
+ input_position++;
+ done = 1;
+ if (debug) {
+ printf("D2/1 ");
+ }
+ } else {
+ if (datum_b(source, input_position, length)) {
+
+ if ((source[input_position] >= 32) && (source[input_position] <= 127)) {
+ codeword_array[array_length] = source[input_position] - 32;
+ done = 1;
+
+ } else if (source[input_position] == 13) {
+ /* CR/LF */
+ codeword_array[array_length] = 96;
+ input_position++;
+ done = 1;
+
+ } else if (input_position != 0) {
+ /* HT, FS, GS and RS in the first data position would be interpreted as a macro (see table 2) */
+ switch(source[input_position]) {
+ case 9: // HT
+ codeword_array[array_length] = 97;
+ break;
+ case 28: // FS
+ codeword_array[array_length] = 98;
+ break;
+ case 29: // GS
+ codeword_array[array_length] = 99;
+ break;
+ case 30: // RS
+ codeword_array[array_length] = 100;
+ break;
+ }
+ done = 1;
+ }
+
+ if (done == 1) {
+ array_length++;
+ input_position++;
+ if (debug) {
+ printf("D2/2 ");
+ }
+ }
+ }
+ }
+ }
+
+ /* Step D3 */
+ if ((!done) && (encoding_mode == 'B')) {
+ if (binary(source, length, input_position)) {
+ if (datum_b(source, input_position + 1, length)) {
+ if ((source[input_position] - 128) < 32) {
+ codeword_array[array_length] = 110; // Bin Shift A
+ array_length++;
+ codeword_array[array_length] = source[input_position] - 128 + 64;
+ array_length++;
+ } else {
+ codeword_array[array_length] = 111; // Bin Shift B
+ array_length++;
+ codeword_array[array_length] = source[input_position] - 128 - 32;
+ array_length++;
+ }
+ input_position++;
+ } else {
+ codeword_array[array_length] = 112; // Bin Latch
+ array_length++;
+ encoding_mode = 'X';
+ }
+ done = 1;
+ if (debug) {
+ printf("D3 ");
+ }
+ }
+ }
+
+ /* Step D4 */
+ if ((!done) && (encoding_mode == 'B')) {
+ if (ahead_a(source, input_position, length) == 1) {
+ codeword_array[array_length] = 101; // Shift A
+ array_length++;
+ if (source[input_position] < 32) {
+ codeword_array[array_length] = source[input_position] + 64;
+ } else {
+ codeword_array[array_length] = source[input_position] - 32;
+ }
+ array_length++;
+ input_position++;
+ } else {
+ codeword_array[array_length] = 102; // Latch A
+ array_length++;
+ encoding_mode = 'A';
+ }
+ done = 1;
+ if (debug) {
+ printf("D4 ");
+ }
+ }
+
+ /* Step E1 */
+ if ((!done) && (encoding_mode == 'A')) {
+ int n = try_c(source, input_position, length);
+ if (n >= 2) {
+ if (n <= 4) {
+ codeword_array[array_length] = 103 + (n - 2); // nx Shift C
+ array_length++;
+ for (i = 0; i < n; i++) {
+ codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0');
+ array_length++;
+ input_position += 2;
+ }
+ } else {
+ codeword_array[array_length] = 106; // Latch C
+ array_length++;
+ encoding_mode = 'C';
+ }
+ done = 1;
+ if (debug) {
+ printf("E1 ");
+ }
+ }
+ }
+
+ /* Step E2 */
+ if ((!done) && (encoding_mode == 'A')) {
+ if ((source[input_position] == '[') && ((symbol->input_mode & 0x07) == GS1_MODE)) {
+ // Note: this branch probably never reached as no reason to be in Code Set A for GS1 data
+ codeword_array[array_length] = 107; // FNC1
+ array_length++;
+ input_position++;
+ done = 1;
+ if (debug) {
+ printf("E2/1 ");
+ }
+ } else {
+ if (datum_a(source, input_position, length)) {
+ if (source[input_position] < 32) {
+ codeword_array[array_length] = source[input_position] + 64;
+ } else {
+ codeword_array[array_length] = source[input_position] - 32;
+ }
+ array_length++;
+ input_position++;
+ done = 1;
+ if (debug) {
+ printf("E2/2 ");
+ }
+ }
+ }
+ }
+
+ /* Step E3 */
+ if ((!done) && (encoding_mode == 'A')) {
+ if (binary(source, length, input_position)) {
+ if (datum_a(source, input_position + 1, length)) {
+ if ((source[input_position] - 128) < 32) {
+ codeword_array[array_length] = 110; // Bin Shift A
+ array_length++;
+ codeword_array[array_length] = source[input_position] - 128 + 64;
+ array_length++;
+ } else {
+ codeword_array[array_length] = 111; // Bin Shift B
+ array_length++;
+ codeword_array[array_length] = source[input_position] - 128 - 32;
+ array_length++;
+ }
+ input_position++;
+ } else {
+ codeword_array[array_length] = 112; // Bin Latch
+ array_length++;
+ encoding_mode = 'X';
+ }
+ done = 1;
+ if (debug) {
+ printf("E3 ");
+ }
+ }
+ }
+
+ /* Step E4 */
+ if ((!done) && (encoding_mode == 'A')) {
+ ahead_b(source, input_position, length, &nx);
+
+ if (nx >= 1 && nx <= 6) {
+ codeword_array[array_length] = 95 + nx; // nx Shift B
+ array_length++;
+ for (i = 0; i < nx; i++) {
+ if (source[input_position] >= 32) {
+ codeword_array[array_length] = source[input_position] - 32;
+ } else if (source[input_position] == 13) { // CR/LF
+ codeword_array[array_length] = 96;
+ input_position++;
+ } else {
+ switch(source[input_position]) {
+ case 9: codeword_array[array_length] = 97; break; // HT
+ case 28: codeword_array[array_length] = 98; break; // FS
+ case 29: codeword_array[array_length] = 99; break; // GS
+ case 30: codeword_array[array_length] = 100; break; // RS
+ }
+ }
+ array_length++;
+ input_position++;
+ }
+ } else {
+ codeword_array[array_length] = 102; // Latch B
+ array_length++;
+ encoding_mode = 'B';
+ }
+ done = 1;
+ if (debug) {
+ printf("E4 ");
+ }
+ }
+
+ /* Step F1 */
+ if ((!done) && (encoding_mode == 'X')) {
+ int n = try_c(source, input_position, length);
+
+ if (n >= 2) {
+ /* Empty binary buffer */
+ for (i = 0; i < (binary_buffer_size + 1); i++) {
+ lawrencium[i] = binary_buffer % 103;
+ binary_buffer /= 103;
+ }
+
+ for (i = 0; i < (binary_buffer_size + 1); i++) {
+ codeword_array[array_length] = lawrencium[binary_buffer_size - i];
+ array_length++;
+ }
+ binary_buffer = 0;
+ binary_buffer_size = 0;
+
+ if (n <= 7) {
+ codeword_array[array_length] = 101 + n; // Interrupt for nx Shift C
+ array_length++;
+ for (i = 0; i < n; i++) {
+ codeword_array[array_length] = ((source[input_position] - '0') * 10) + (source[input_position + 1] - '0');
+ array_length++;
+ input_position += 2;
+ }
+ } else {
+ codeword_array[array_length] = 111; // Terminate with Latch to C
+ array_length++;
+ encoding_mode = 'C';
+ }
+ done = 1;
+ if (debug) {
+ printf("F1 ");
+ }
+ }
+ }
+
+ /* Step F2 */
+ /* Section 5.2.1.1 para D.2.i states:
+ * "Groups of six codewords, each valued between 0 and 102, are radix converted from
+ * base 103 into five base 259 values..."
+ */
+ if ((!done) && (encoding_mode == 'X')) {
+ if (binary(source, length, input_position)
+ || binary(source, length, input_position + 1)
+ || binary(source, length, input_position + 2)
+ || binary(source, length, input_position + 3)) {
+ binary_buffer *= 259;
+ binary_buffer += source[input_position];
+ binary_buffer_size++;
+
+ if (binary_buffer_size == 5) {
+ for (i = 0; i < 6; i++) {
+ lawrencium[i] = binary_buffer % 103;
+ binary_buffer /= 103;
+ }
+
+ for (i = 0; i < 6; i++) {
+ codeword_array[array_length] = lawrencium[5 - i];
+ array_length++;
+ }
+ binary_buffer = 0;
+ binary_buffer_size = 0;
+ }
+ input_position++;
+ done = 1;
+ if (debug) {
+ printf("F2 ");
+ }
+ }
+ }
+
+ /* Step F3 */
+ if ((!done) && (encoding_mode == 'X')) {
+ /* Empty binary buffer */
+ for (i = 0; i < (binary_buffer_size + 1); i++) {
+ lawrencium[i] = binary_buffer % 103;
+ binary_buffer /= 103;
+ }
+
+ for (i = 0; i < (binary_buffer_size + 1); i++) {
+ codeword_array[array_length] = lawrencium[binary_buffer_size - i];
+ array_length++;
+ }
+ binary_buffer = 0;
+ binary_buffer_size = 0;
+
+ if (ahead_a(source, input_position, length) > ahead_b(source, input_position, length, NULL)) {
+ codeword_array[array_length] = 109; // Terminate with Latch to A
+ encoding_mode = 'A';
+ } else {
+ codeword_array[array_length] = 110; // Terminate with Latch to B
+ encoding_mode = 'B';
+ }
+ array_length++;
+ // done = 1 // As long as last branch not needed
+ if (debug) {
+ printf("F3 ");
+ }
+ }
+ }
+
+ if (encoding_mode == 'X') {
+ if (binary_buffer_size != 0) {
+ /* Empty binary buffer */
+ for (i = 0; i < (binary_buffer_size + 1); i++) {
+ lawrencium[i] = binary_buffer % 103;
+ binary_buffer /= 103;
+ }
+
+ for (i = 0; i < (binary_buffer_size + 1); i++) {
+ codeword_array[array_length] = lawrencium[binary_buffer_size - i];
+ array_length++;
+ }
+ }
+ *(binary_finish) = 1;
+ }
+
+ if (debug) {
+ printf("\n");
+ }
+
+ return array_length;
+}
+
+/* Convert codewords to binary data stream */
+static size_t make_dotstream(unsigned char masked_array[], int array_length, char dot_stream[]) {
+ int i;
+
+ dot_stream[0] = '\0';
+
+ /* Mask value is encoded as two dots */
+ bin_append(masked_array[0], 2, dot_stream);
+
+ /* The rest of the data uses 9-bit dot patterns from Annex C */
+ for (i = 1; i < array_length; i++) {
+ bin_append(dot_patterns[masked_array[i]], 9, dot_stream); // NOLINT masked_array values modulo 113 and fully set
+ }
+
+ return strlen(dot_stream);
+}
+
+/* Determines if a given dot is a reserved corner dot
+ * to be used by one of the last six bits
+ */
+static int is_corner(int column, int row, int width, int height) {
+ int corner = 0;
+
+ /* Top Left */
+ if ((column == 0) && (row == 0)) {
+ corner = 1;
+ }
+
+ /* Top Right */
+ if (height % 2) {
+ if (((column == width - 2) && (row == 0))
+ || ((column == width - 1) && (row == 1))) {
+ corner = 1;
+ }
+ } else {
+ if ((column == width - 1) && (row == 0)) {
+ corner = 1;
+ }
+ }
+
+ /* Bottom Left */
+ if (height % 2) {
+ if ((column == 0) && (row == height - 1)) {
+ corner = 1;
+ }
+ } else {
+ if (((column == 0) && (row == height - 2))
+ || ((column == 1) && (row == height - 1))) {
+ corner = 1;
+ }
+ }
+
+ /* Bottom Right */
+ if (((column == width - 2) && (row == height - 1))
+ || ((column == width - 1) && (row == height - 2))) {
+ corner = 1;
+ }
+
+ return corner;
+}
+
+/* Place the dots in the symbol*/
+static void fold_dotstream(char dot_stream[], int width, int height, char dot_array[]) {
+ int column, row;
+ int input_position = 0;
+
+ if (height % 2) {
+ /* Horizontal folding */
+ for (row = 0; row < height; row++) {
+ for (column = 0; column < width; column++) {
+ if (!((column + row) % 2)) {
+ if (is_corner(column, row, width, height)) {
+ dot_array[(row * width) + column] = 'C';
+ } else {
+ dot_array[((height - row - 1) * width) + column] = dot_stream[input_position];
+ input_position++;
+ }
+ } else {
+ dot_array[((height - row - 1) * width) + column] = ' '; // Non-data position
+ }
+ }
+ }
+
+ /* Corners */
+ dot_array[width - 2] = dot_stream[input_position];
+ input_position++;
+ dot_array[(height * width) - 2] = dot_stream[input_position];
+ input_position++;
+ dot_array[(width * 2) - 1] = dot_stream[input_position];
+ input_position++;
+ dot_array[((height - 1) * width) - 1] = dot_stream[input_position];
+ input_position++;
+ dot_array[0] = dot_stream[input_position];
+ input_position++;
+ dot_array[(height - 1) * width] = dot_stream[input_position];
+ } else {
+ /* Vertical folding */
+ for (column = 0; column < width; column++) {
+ for (row = 0; row < height; row++) {
+ if (!((column + row) % 2)) {
+ if (is_corner(column, row, width, height)) {
+ dot_array[(row * width) + column] = 'C';
+ } else {
+ dot_array[(row * width) + column] = dot_stream[input_position];
+ input_position++;
+ }
+ } else {
+ dot_array[(row * width) + column] = ' '; // Non-data position
+ }
+ }
+ }
+
+ /* Corners */
+ dot_array[((height - 1) * width) - 1] = dot_stream[input_position];
+ input_position++;
+ dot_array[(height - 2) * width] = dot_stream[input_position];
+ input_position++;
+ dot_array[(height * width) - 2] = dot_stream[input_position];
+ input_position++;
+ dot_array[((height - 1) * width) + 1] = dot_stream[input_position];
+ input_position++;
+ dot_array[width - 1] = dot_stream[input_position];
+ input_position++;
+ dot_array[0] = dot_stream[input_position];
+ }
+}
+
+static void apply_mask(int mask, int data_length, unsigned char *masked_codeword_array, unsigned char *codeword_array, int ecc_length) {
+ int weight = 0;
+ int j;
+
+ switch (mask) {
+ case 0:
+ masked_codeword_array[0] = 0;
+ for (j = 0; j < data_length; j++) {
+ masked_codeword_array[j + 1] = codeword_array[j];
+ }
+ break;
+ case 1:
+ masked_codeword_array[0] = 1;
+ for (j = 0; j < data_length; j++) {
+ masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113;
+ weight += 3;
+ }
+ break;
+ case 2:
+ masked_codeword_array[0] = 2;
+ for (j = 0; j < data_length; j++) {
+ masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113;
+ weight += 7;
+ }
+ break;
+ case 3:
+ masked_codeword_array[0] = 3;
+ for (j = 0; j < data_length; j++) {
+ masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113;
+ weight += 17;
+ }
+ break;
+ }
+
+ rsencode(data_length + 1, ecc_length, masked_codeword_array);
+}
+
+static void force_corners(int width, int height, char *dot_array) {
+ if (width % 2) {
+ // "Vertical" symbol
+ dot_array[0] = '1';
+ dot_array[width - 1] = '1';
+ dot_array[(height - 2) * width] = '1';
+ dot_array[((height - 1) * width) - 1] = '1';
+ dot_array[((height - 1) * width) + 1] = '1';
+ dot_array[(height * width) - 2] = '1';
+ } else {
+ // "Horizontal" symbol
+ dot_array[0] = '1';
+ dot_array[width - 2] = '1';
+ dot_array[(2 * width) - 1] = '1';
+ dot_array[((height - 1) * width) - 1] = '1';
+ dot_array[(height - 1) * width] = '1';
+ dot_array[(height * width) - 2] = '1';
+ }
+}
+
+INTERNAL int dotcode(struct zint_symbol *symbol, const unsigned char source[], int length) {
+ int i, j, k;
+ size_t jc, n_dots;
+ int data_length, ecc_length;
+ int min_dots, min_area;
+ int height, width;
+ int mask_score[8];
+ size_t dot_stream_length;
+ int high_score, best_mask;
+ int binary_finish = 0;
+ int debug = symbol->debug;
+ int padding_dots, is_first;
+ int codeword_array_len = length * 4 + 8; /* Allow up to 4 codewords per input + 2 (FNC) + 4 (ECI) + 2 (special char 1st position) */
+#ifdef _MSC_VER
+ unsigned char* masked_codeword_array;
+#endif
+
+#ifndef _MSC_VER
+ unsigned char codeword_array[codeword_array_len];
+#else
+ char* dot_stream;
+ char* dot_array;
+ unsigned char* codeword_array = (unsigned char *) _alloca(codeword_array_len);
+#endif /* _MSC_VER */
+
+ if (symbol->eci > 811799) {
+ strcpy(symbol->errtxt, "525: Invalid ECI");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+
+ data_length = dotcode_encode_message(symbol, source, length, codeword_array, &binary_finish);
+
+ ecc_length = 3 + (data_length / 2);
+
+ if (debug & ZINT_DEBUG_PRINT) {
+ printf("Codeword length = %d, ECC length = %d\n", data_length, ecc_length);
+ printf("Codewords: ");
+ for (i = 0; i < data_length; i++) {
+ printf("[%d] ",codeword_array[i]);
+ }
+ printf("\n");
+ }
+#ifdef ZINT_TEST
+ if (debug & ZINT_DEBUG_TEST) {
+ debug_test_codeword_dump(symbol, codeword_array, data_length);
+ }
+#endif
+
+ min_dots = 9 * (data_length + 3 + (data_length / 2)) + 2;
+ min_area = min_dots * 2;
+
+ if (symbol->option_2 == 0) {
+ /* Automatic sizing */
+ /* Following Rule 3 (Section 5.2.2) and applying a recommended width to height ratio 3:2 */
+ /* Eliminates under sized symbols */
+
+ float h = (float) (sqrt(min_area * 0.666));
+ float w = (float) (sqrt(min_area * 1.5));
+
+ height = (int) h;
+ width = (int) w;
+
+ if ((width + height) % 2 == 1) {
+ if ((width * height) < min_area) {
+ width++;
+ height++;
+ }
+ } else {
+ if ((h * width) < (w * height)) {
+ width++;
+ if ((width * height) < min_area) {
+ width--;
+ height++;
+ if ((width * height) < min_area) {
+ width += 2;
+ }
+ }
+ } else {
+ height++;
+ if ((width * height) < min_area) {
+ width++;
+ height--;
+ if ((width * height) < min_area) {
+ height += 2;
+ }
+ }
+ }
+ }
+
+ } else {
+ /* User defined width */
+ /* Eliminates under sized symbols */
+
+ width = symbol->option_2;
+ height = (min_area + (width - 1)) / width;
+
+ if (!((width + height) % 2)) {
+ height++;
+ }
+ }
+
+ if (debug & ZINT_DEBUG_PRINT) {
+ printf("Width = %d, Height = %d\n", width, height);
+ }
+
+ if ((height > 200) || (width > 200)) {
+ strcpy(symbol->errtxt, "526: Specified symbol size is too large");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+
+ if ((height < 5) || (width < 5)) {
+ strcpy(symbol->errtxt, "527: Specified symbol size has a dimension which is too small");
+ return ZINT_ERROR_INVALID_OPTION;
+ }
+
+ n_dots = (height * width) / 2;
+
+#ifndef _MSC_VER
+ char dot_stream[height * width * 3];
+ char dot_array[width * height * sizeof (char) ];
+#else
+ dot_stream = (char *) _alloca(height * width * 3);
+ if (!dot_stream) return ZINT_ERROR_MEMORY;
+
+ dot_array = (char *) _alloca(width * height * sizeof (char));
+ if (!dot_array) return ZINT_ERROR_MEMORY;
+#endif
+
+ /* Add pad characters */
+ padding_dots = n_dots - min_dots; /* get the number of free dots available for padding */
+ is_first = 1; /* first padding character flag */
+
+ while (padding_dots >= 9) {
+ if (padding_dots < 18 && ((data_length % 2) == 0))
+ padding_dots -= 9;
+
+ else if (padding_dots >= 18) {
+ if ((data_length % 2) == 0)
+ padding_dots -= 9;
+ else
+ padding_dots -= 18;
+ } else
+ break; /* not enough padding dots left for padding */
+
+ if ((is_first == 1) && (binary_finish == 1))
+ codeword_array[data_length] = 109;
+ else
+ codeword_array[data_length] = 106;
+
+ data_length++;
+ is_first = 0;
+ }
+
+ ecc_length = 3 + (data_length / 2);
+
+
+#ifndef _MSC_VER
+ unsigned char masked_codeword_array[data_length + 1 + ecc_length];
+#else
+ masked_codeword_array = (unsigned char *) _alloca((data_length + 1 + ecc_length) * sizeof (unsigned char));
+#endif /* _MSC_VER */
+
+ /* Evaluate data mask options */
+ for (i = 0; i < 4; i++) {
+
+ apply_mask(i, data_length, masked_codeword_array, codeword_array, ecc_length);
+
+ dot_stream_length = make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream);
+
+ /* Add pad bits */
+ for (jc = dot_stream_length; jc < n_dots; jc++) {
+ strcat(dot_stream, "1");
+ }
+
+ fold_dotstream(dot_stream, width, height, dot_array);
+
+ mask_score[i] = score_array(dot_array, height, width);
+
+ if (debug & ZINT_DEBUG_PRINT) {
+ printf("Mask %d score is %d\n", i, mask_score[i]);
+ }
+ }
+
+ high_score = mask_score[0];
+ best_mask = 0;
+
+ for (i = 1; i < 4; i++) {
+ if (mask_score[i] >= high_score) {
+ high_score = mask_score[i];
+ best_mask = i;
+ }
+ }
+
+ /* Re-evaluate using forced corners if needed */
+ if (best_mask <= (height * width) / 2) {
+ for (i = 0; i < 4; i++) {
+
+ apply_mask(i, data_length, masked_codeword_array, codeword_array, ecc_length);
+
+ dot_stream_length = make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream);
+
+ /* Add pad bits */
+ for (jc = dot_stream_length; jc < n_dots; jc++) {
+ strcat(dot_stream, "1");
+ }
+
+ fold_dotstream(dot_stream, width, height, dot_array);
+
+ force_corners(width, height, dot_array);
+
+ mask_score[i + 4] = score_array(dot_array, height, width);
+
+ if (debug & ZINT_DEBUG_PRINT) {
+ printf("Mask %d score is %d\n", i + 4, mask_score[i + 4]);
+ }
+ }
+
+ for (i = 4; i < 8; i++) {
+ if (mask_score[i] >= high_score) {
+ high_score = mask_score[i];
+ best_mask = i;
+ }
+ }
+ }
+
+ if (debug & ZINT_DEBUG_PRINT) {
+ printf("Applying mask %d, high_score %d\n", best_mask, high_score);
+ }
+
+ /* Apply best mask */
+ apply_mask(best_mask % 4, data_length, masked_codeword_array, codeword_array, ecc_length);
+
+ dot_stream_length = make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream);
+
+ /* Add pad bits */
+ for (jc = dot_stream_length; jc < n_dots; jc++) {
+ strcat(dot_stream, "1");
+ }
+
+ fold_dotstream(dot_stream, width, height, dot_array);
+
+ if (best_mask >= 4) {
+ force_corners(width, height, dot_array);
+ }
+
+ /* Copy values to symbol */
+ symbol->width = width;
+ symbol->rows = height;
+
+ for (k = 0; k < height; k++) {
+ for (j = 0; j < width; j++) {
+ if (dot_array[(k * width) + j] == '1') {
+ set_module(symbol, k, j);
+ }
+ }
+ symbol->row_height[k] = 1;
+ }
+
+ if (!(symbol->output_options & BARCODE_DOTTY_MODE)) {
+ symbol->output_options += BARCODE_DOTTY_MODE;
+ }
+
+ return 0;
+}
diff --git a/backend/eci.c b/backend/eci.c
new file mode 100644
index 0000000..4227790
--- /dev/null
+++ b/backend/eci.c
@@ -0,0 +1,273 @@
+/* eci.c - Extended Channel Interpretations
+
+ libzint - the open source barcode library
+ Copyright (C) 2009 - 2020 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+/* vim: set ts=4 sw=4 et : */
+
+#include <string.h>
+#include <stdio.h>
+#include "eci.h"
+#include "common.h"
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+
+/* Convert Unicode to other character encodings */
+INTERNAL int utf_to_eci(const int eci, const unsigned char source[], unsigned char dest[], size_t *length) {
+ int in_posn;
+ int out_posn;
+ int ext;
+ int done;
+
+ if (eci == 26) {
+ /* Unicode mode, do not process - just copy data across */
+ memcpy(dest, source, *length);
+ dest[*length] = '\0';
+ return 0;
+ }
+
+ in_posn = 0;
+ out_posn = 0;
+ do {
+ /* Single byte (ASCII) character */
+ int bytelen = 1;
+ int glyph = (int) source[in_posn];
+
+ if ((source[in_posn] >= 0x80) && (source[in_posn] < 0xc0)) {
+ /* Something has gone wrong, abort */
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ if ((source[in_posn] >= 0xc0) && (source[in_posn] < 0xe0)) {
+ /* Two-byte character */
+ bytelen = 2;
+ glyph = (source[in_posn] & 0x1f) << 6;
+
+ if ((int) *length < (in_posn + 2)) {
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ if (source[in_posn + 1] > 0xc0) {
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ glyph += (source[in_posn + 1] & 0x3f);
+ }
+
+ if ((source[in_posn] >= 0xe0) && (source[in_posn] < 0xf0)) {
+ /* Three-byte character */
+ bytelen = 3;
+ glyph = (source[in_posn] & 0x0f) << 12;
+
+ if ((int) *length < (in_posn + 2)) {
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ if ((int) *length < (in_posn + 3)) {
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ if (source[in_posn + 1] > 0xc0) {
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ if (source[in_posn + 2] > 0xc0) {
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ glyph += (source[in_posn + 1] & 0x3f) << 6;
+ glyph += (source[in_posn + 2] & 0x3f);
+ }
+
+ if (source[in_posn] >= 0xf0 || glyph > 0x2122) {
+ /* Not in any ISO 8859 or Windows page */
+ return ZINT_ERROR_INVALID_DATA;
+ }
+
+ if (glyph < 128) {
+ dest[out_posn] = glyph;
+ } else {
+ done = 0;
+ for (ext = 0; ext < 128; ext++) {
+ switch (eci) {
+ case 3: // Latin-1
+ if (glyph == iso_8859_1[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 4: // Latin-2
+ if (glyph == iso_8859_2[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 5: // Latin-3
+ if (glyph == iso_8859_3[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 6: // Latin-4
+ if (glyph == iso_8859_4[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 7: // Latin/Cyrillic
+ if (glyph == iso_8859_5[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 8: // Latin/Arabic
+ if (glyph == iso_8859_6[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 9: // Latin/Greek
+ if (glyph == iso_8859_7[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 10: // Latin/Hebrew
+ if (glyph == iso_8859_8[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 11: // Latin-5
+ if (glyph == iso_8859_9[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 12: // Latin-6
+ if (glyph == iso_8859_10[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 13: // Latin/Thai
+ if (glyph == iso_8859_11[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 15: // Latin-7
+ if (glyph == iso_8859_13[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 16: // Latin-8
+ if (glyph == iso_8859_14[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 17: // Latin-9
+ if (glyph == iso_8859_15[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 18: // Latin-10
+ if (glyph == iso_8859_16[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 21: // Windows-1250
+ if (glyph == windows_1250[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 22: // Windows-1251
+ if (glyph == windows_1251[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 23: // Windows-1252
+ if (glyph == windows_1252[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ case 24: // Windows-1256
+ if (glyph == windows_1256[ext]) {
+ dest[out_posn] = ext + 128;
+ done = 1;
+ }
+ break;
+ default:
+ break;
+ }
+ if (done) {
+ break;
+ }
+ }
+
+ if (!(done)) {
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ }
+
+ in_posn += bytelen;
+ out_posn++;
+ } while (in_posn < (int) *length);
+ dest[out_posn] = '\0';
+ *length = out_posn;
+
+ return 0;
+}
+
+/* Find the lowest ECI mode which will encode a given set of Unicode text */
+INTERNAL int get_best_eci(unsigned char source[], size_t length) {
+ int eci = 3;
+
+#ifndef _MSC_VER
+ unsigned char local_source[length + 1];
+#else
+ unsigned char *local_source = (unsigned char*) _alloca(length + 1);
+#endif
+
+ do {
+ if (utf_to_eci(eci, source, local_source, &length) == 0) {
+ return eci;
+ }
+ eci++;
+ } while (eci < 25);
+
+ return 26; // If all of these fail, use Unicode!
+}
diff --git a/backend/eci.h b/backend/eci.h
new file mode 100644
index 0000000..d4f2534
--- /dev/null
+++ b/backend/eci.h
@@ -0,0 +1,254 @@
+/* eci.c - Extended Channel Interpretations to Unicode tables
+
+ libzint - the open source barcode library
+ Copyright (C) 2009-2017 Robin Stuart <rstuart114@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+ */
+
+#ifndef ECI_H
+#define ECI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
<