Bump to version 2.7.1 59/236759/2 accepted/tizen/unified/20200708.125323 submit/tizen/20200701.041707 submit/tizen/20200702.015201 submit/tizen/20200706.003724 submit/tizen/20200708.035054
authorTae-Young Chung <ty83.chung@samsung.com>
Mon, 22 Jun 2020 02:16:33 +0000 (11:16 +0900)
committerTae-Young Chung <ty83.chung@samsung.com>
Mon, 22 Jun 2020 04:32:26 +0000 (13:32 +0900)
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>
88 files changed:
backend/2of5.c
backend/CMakeLists.txt
backend/DEVELOPER
backend/Makefile [deleted file]
backend/Makefile.mingw
backend/auspost.c [new file with mode: 0644]
backend/aztec.c [new file with mode: 0644]
backend/aztec.h [new file with mode: 0644]
backend/bmp.c [new file with mode: 0644]
backend/bmp.h [new file with mode: 0644]
backend/channel_precalcs.h [new file with mode: 0644]
backend/codablock.c [new file with mode: 0644]
backend/code.c
backend/code1.c [new file with mode: 0644]
backend/code1.h [new file with mode: 0644]
backend/code128.c
backend/code128.h [new file with mode: 0644]
backend/code16k.c [new file with mode: 0644]
backend/code49.c [new file with mode: 0644]
backend/code49.h [new file with mode: 0644]
backend/common.c
backend/common.h
backend/composite.c [new file with mode: 0644]
backend/composite.h [new file with mode: 0644]
backend/dllversion.c
backend/dmatrix.c [new file with mode: 0644]
backend/dmatrix.h [new file with mode: 0644]
backend/dotcode.c [new file with mode: 0644]
backend/eci.c [new file with mode: 0644]
backend/eci.h [new file with mode: 0644]
backend/emf.c [new file with mode: 0644]
backend/emf.h [new file with mode: 0644]
backend/font.h
backend/gb18030.c [new file with mode: 0644]
backend/gb18030.h [new file with mode: 0644]
backend/gb2312.c [new file with mode: 0644]
backend/gb2312.h
backend/general_field.c [new file with mode: 0644]
backend/general_field.h [new file with mode: 0644]
backend/gif.c [new file with mode: 0644]
backend/gridmtx.c [new file with mode: 0644]
backend/gridmtx.h [new file with mode: 0644]
backend/gs1.c
backend/gs1.h
backend/hanxin.c [new file with mode: 0644]
backend/hanxin.h [new file with mode: 0644]
backend/imail.c [new file with mode: 0644]
backend/large.c
backend/large.h
backend/library.c
backend/libzint.rc
backend/mailmark.c [new file with mode: 0644]
backend/maxicode.c [new file with mode: 0644]
backend/maxicode.h [new file with mode: 0644]
backend/maxipng.h [deleted file]
backend/medical.c [new file with mode: 0644]
backend/ms_stdint.h [new file with mode: 0644]
backend/output.c [new file with mode: 0644]
backend/output.h [new file with mode: 0644]
backend/pcx.c [new file with mode: 0644]
backend/pcx.h [new file with mode: 0644]
backend/pdf417.c [new file with mode: 0644]
backend/pdf417.h [new file with mode: 0644]
backend/plessey.c [new file with mode: 0644]
backend/png.c
backend/postal.c [new file with mode: 0644]
backend/ps.c
backend/qr.c
backend/qr.h
backend/raster.c [new file with mode: 0644]
backend/reedsol.c
backend/reedsol.h
backend/render.c [deleted file]
backend/rss.c [new file with mode: 0644]
backend/rss.h [new file with mode: 0644]
backend/sjis.c [new file with mode: 0644]
backend/sjis.h
backend/stdint_msvc.h [new file with mode: 0644]
backend/svg.c [new file with mode: 0644]
backend/telepen.c [new file with mode: 0644]
backend/tif.c [new file with mode: 0644]
backend/tif.h [new file with mode: 0644]
backend/ultra.c [new file with mode: 0644]
backend/upcean.c
backend/vector.c [new file with mode: 0644]
backend/zint.def [deleted file]
backend/zint.h
packaging/zint.spec

index df07f46..c3c795d 100644 (file)
@@ -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
     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;
 }
index 64d88f1..e7baa0b 100644 (file)
@@ -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})
 
index 7db3a77..8f50755 100644 (file)
@@ -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 (file)
index 2f339dd..0000000
+++ /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 *~
-
-
index 87fc946..e79a912 100644 (file)
@@ -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 (file)
index 0000000..39d3414
--- /dev/null
@@ -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 (file)
index 0000000..f5e88bd
--- /dev/null
@@ -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 (file)
index 0000000..69b55fc
--- /dev/null
@@ -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 (file)
index 0000000..240c697
--- /dev/null
@@ -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 (file)
index 0000000..3a6ab34
--- /dev/null
@@ -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 (file)
index 0000000..f979e1a
--- /dev/null
@@ -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 (file)
index 0000000..2eef2a7
--- /dev/null
@@ -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;
+}
index 9d30e5a..455491c 100644 (file)
@@ -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
     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 (file)
index 0000000..8ba456b
--- /dev/null
@@ -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 (file)
index 0000000..aaf4898
--- /dev/null
@@ -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
index f0f985d..b69613a 100644 (file)
@@ -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
     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 (file)
index 0000000..0b1f042
--- /dev/null
@@ -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 (file)
index 0000000..c7394c5
--- /dev/null
@@ -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 (file)
index 0000000..3d7aebf
--- /dev/null
@@ -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 (file)
index 0000000..01dec46
--- /dev/null
@@ -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
+};
index 72cc3ca..f295099 100644 (file)
@@ -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
     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
index d7fead9..649eaeb 100644 (file)
@@ -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
     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 (file)
index 0000000..1184965
--- /dev/null
@@ -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 (file)
index 0000000..6195d29
--- /dev/null
@@ -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 */
index 50f1653..71f5a75 100644 (file)
@@ -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 (file)
index 0000000..212eb6d
--- /dev/null
@@ -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 (file)
index 0000000..ef39825
--- /dev/null
@@ -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 (file)
index 0000000..78f3914
--- /dev/null
@@ -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 (file)
index 0000000..4227790
--- /dev/null
@@ -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 (file)
index 0000000..d4f2534
--- /dev/null
@@ -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
+
+static const unsigned short int iso_8859_1[] = {// Latin alphabet No. 1
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+};
+
+static const unsigned short int iso_8859_2[] = {// Latin alphabet No. 2
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x0104, 0x02d8, 0x0141, 0x00a4, 0x013d, 0x015a, 0x00a7, 0x00a8, 0x0160, 0x015e, 0x0164, 0x0179, 0x00ad, 0x017d, 0x017b,
+    0x00b0, 0x0105, 0x02db, 0x0142, 0x00b4, 0x013e, 0x015b, 0x02c7, 0x00b8, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c,
+    0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
+    0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
+    0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
+    0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9
+};
+
+static const unsigned short int iso_8859_3[] = {// Latin alphabet No. 3
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x0126, 0x02d8, 0x00a3, 0x00a4, 0x0000, 0x0124, 0x00a7, 0x00a8, 0x0130, 0x015e, 0x011e, 0x0134, 0x00ad, 0x0000, 0x017b,
+    0x00b0, 0x0127, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x0125, 0x00b7, 0x00b8, 0x0131, 0x015f, 0x011f, 0x0135, 0x00bd, 0x0000, 0x017c,
+    0x00c0, 0x00c1, 0x00c2, 0x0000, 0x00c4, 0x010a, 0x0108, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x0000, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x0120, 0x00d6, 0x00d7, 0x011c, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x016c, 0x015c, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x0000, 0x00e4, 0x010b, 0x0109, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x0000, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x0121, 0x00f6, 0x00f7, 0x011d, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x016d, 0x015d, 0x02d9
+};
+
+static const unsigned short int iso_8859_4[] = {// Latin alphabet No. 4
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x0104, 0x0138, 0x0156, 0x00a4, 0x012b, 0x013b, 0x00a7, 0x00a8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00ad, 0x017d, 0x00af,
+    0x00b0, 0x0105, 0x02db, 0x0157, 0x00b4, 0x0129, 0x013c, 0x02c7, 0x00b8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014a, 0x017e, 0x014b,
+    0x0100, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x012e, 0x010c, 0x00c9, 0x0118, 0x00cb, 0x0116, 0x00cd, 0x00ce, 0x012a,
+    0x0110, 0x0145, 0x014c, 0x0136, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x0172, 0x00da, 0x00db, 0x00dc, 0x0168, 0x016a, 0x00df,
+    0x0101, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x012f, 0x010d, 0x00e9, 0x0119, 0x00eb, 0x0117, 0x00ed, 0x00ee, 0x012b,
+    0x0111, 0x0146, 0x014d, 0x0137, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x0173, 0x00fa, 0x00fb, 0x00fc, 0x0169, 0x016b, 0x02d9
+};
+
+static const unsigned short int iso_8859_5[] = {// Latin/Cyrillic alphabet
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x00ad, 0x040e, 0x040f,
+    0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+    0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
+    0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+    0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+    0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x00a7, 0x045e, 0x045f
+};
+
+static const unsigned short int iso_8859_6[] = {// Latin/Arabic alphabet
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x0000, 0x0000, 0x0000, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x060c, 0x00ad, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x061b, 0x0000, 0x0000, 0x0000, 0x061f,
+    0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f,
+    0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f,
+    0x0650, 0x0651, 0x0652, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static const unsigned short int iso_8859_7[] = {// Latin/Greek alphabet
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x2018, 0x2019, 0x00a3, 0x20ac, 0x20af, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x037a, 0x00ab, 0x00ac, 0x00ad, 0x0000, 0x2015,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x0384, 0x0385, 0x0386, 0x00b7, 0x0388, 0x0389, 0x038a, 0x00bb, 0x038c, 0x00bd, 0x038e, 0x038f,
+    0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
+    0x03a0, 0x03a1, 0x0000, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,
+    0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+    0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x0000
+};
+
+static const unsigned short int iso_8859_8[] = {// Latin/Hebrew alphabet
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x0000, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2017,
+    0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
+    0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x0000, 0x0000, 0x200e, 0x200f, 0x0000
+};
+
+static const unsigned short int iso_8859_9[] = {// Latin alphabet No. 5
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x011e, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x0130, 0x015e, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x011f, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x0131, 0x015f, 0x00ff
+};
+
+static const unsigned short int iso_8859_10[] = {// Latin alphabet No. 6
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x0104, 0x0112, 0x0122, 0x012a, 0x012b, 0x0136, 0x00a7, 0x013b, 0x0110, 0x0160, 0x0166, 0x017d, 0x00ad, 0x016a, 0x014a,
+    0x00b0, 0x0105, 0x0113, 0x0123, 0x012b, 0x0129, 0x0137, 0x00b7, 0x013c, 0x0111, 0x0161, 0x0167, 0x017e, 0x2015, 0x016b, 0x014b,
+    0x0100, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x012e, 0x010c, 0x00c9, 0x0118, 0x00cb, 0x0116, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x0145, 0x014c, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x0168, 0x00d8, 0x0172, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x0101, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x012f, 0x010d, 0x00e9, 0x0119, 0x00eb, 0x0117, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x0146, 0x014d, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x0169, 0x00f8, 0x0173, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x0138
+};
+
+static const unsigned short int iso_8859_11[] = {// Latin/Thai alphabet
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f,
+    0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f,
+    0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f,
+    0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e36, 0x0e36, 0x0e37, 0x0e38, 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e3f,
+    0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0e4e, 0x0e4f,
+    0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, 0x0e58, 0x0e59, 0x0e5a, 0x0e5b, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static const unsigned short int iso_8859_13[] = {// Latin alphabet No. 7
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x201d, 0x00a2, 0x00a3, 0x00a4, 0x201e, 0x00a6, 0x00a7, 0x00d8, 0x00a9, 0x0156, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00c6,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x201c, 0x00b5, 0x00b6, 0x00b7, 0x00f8, 0x00b9, 0x0157, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00e6,
+    0x0104, 0x012e, 0x0100, 0x0106, 0x00c4, 0x00c5, 0x0118, 0x0112, 0x010c, 0x00c9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012a, 0x013b,
+    0x0160, 0x0143, 0x0145, 0x00d3, 0x014c, 0x00d5, 0x00d6, 0x00d7, 0x0172, 0x0141, 0x015a, 0x016a, 0x00dc, 0x017b, 0x017d, 0x00df,
+    0x0105, 0x012f, 0x0101, 0x0107, 0x00e4, 0x00e5, 0x0119, 0x0113, 0x010d, 0x00e9, 0x017a, 0x0117, 0x0123, 0x0137, 0x012b, 0x013c,
+    0x0161, 0x0144, 0x0146, 0x00f3, 0x014d, 0x00f5, 0x00f6, 0x00f7, 0x0173, 0x0142, 0x015b, 0x016b, 0x00fc, 0x017c, 0x017e, 0x2019
+};
+
+static const unsigned short int iso_8859_14[] = {// Latin alphabet No. 8 (Celtic)
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x1e02, 0x1e03, 0x00a3, 0x010a, 0x010b, 0x1e0a, 0x00a7, 0x1e80, 0x00a9, 0x1e82, 0x1e0b, 0x1ef2, 0x00ad, 0x00ae, 0x0178,
+    0x1e1e, 0x1e1f, 0x0120, 0x0121, 0x1e40, 0x1e41, 0x00b6, 0x1e56, 0x1e81, 0x1e57, 0x1e83, 0x1e60, 0x1ef3, 0x1e84, 0x1e85, 0x1e61,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x0174, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x1e6a, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x0176, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x0175, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x1e6b, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x0177, 0x00ff
+};
+
+static const unsigned short int iso_8859_15[] = {// Latin alphabet No. 9
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20ac, 0x00a5, 0x0160, 0x00a7, 0x0161, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x017d, 0x00b5, 0x00b6, 0x00b7, 0x017e, 0x00b9, 0x00ba, 0x00bb, 0x0152, 0x0153, 0x0178, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+};
+
+static const unsigned short int iso_8859_16[] = {// Latin alphabet No. 10
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00a0, 0x0104, 0x0105, 0x0141, 0x20ac, 0x201e, 0x0160, 0x00a7, 0x0161, 0x00a9, 0x0218, 0x00ab, 0x0179, 0x00ad, 0x017a, 0x017b,
+    0x00b0, 0x00b1, 0x010c, 0x0142, 0x017d, 0x201d, 0x00b6, 0x00b7, 0x017e, 0x010d, 0x0219, 0x00bb, 0x0152, 0x0153, 0x0178, 0x017c,
+    0x00c0, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0106, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x0110, 0x0143, 0x00d2, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x015a, 0x0170, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x0118, 0x021a, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x0107, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x0111, 0x0144, 0x00f2, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x015b, 0x0171, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x0119, 0x021b, 0x00ff
+};
+
+static const unsigned short int windows_1250[] = {
+    0x20ac, 0x0000, 0x201a, 0x0000, 0x201e, 0x2026, 0x2020, 0x2021, 0x0000, 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
+    0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
+    0x00a0, 0x02c7, 0x02db, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
+    0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
+    0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
+    0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
+    0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
+    0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9
+};
+
+static const unsigned short int windows_1251[] = {
+    0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, 0x2021, 0x20ac, 0x2030, 0x0409, 0x2039, 0x040a, 0x040c, 0x040b, 0x040f,
+    0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0459, 0x203a, 0x045a, 0x045c, 0x045b, 0x045f,
+    0x00a0, 0x040e, 0x045e, 0x0408, 0x00a4, 0x0490, 0x00a6, 0x00a7, 0x0401, 0x00a9, 0x0404, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0407,
+    0x00b0, 0x00b1, 0x0406, 0x0456, 0x0491, 0x00b5, 0x00b6, 0x00b7, 0x0451, 0x2116, 0x0454, 0x00bb, 0x0458, 0x0405, 0x0455, 0x0457,
+    0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+    0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
+    0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+    0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f
+};
+
+static const unsigned short int windows_1252[] = {
+    0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017d, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x0000, 0x017e, 0x0178,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+};
+
+static const unsigned short int windows_1256[] = {
+    0x20ac, 0x067e, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
+    0x06af, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x06a9, 0x2122, 0x0691, 0x203a, 0x0153, 0x200c, 0x200d, 0x06ba,
+    0x00a0, 0x060c, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x06be, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x061b, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x061f,
+    0x06c1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f,
+    0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00d7, 0x0637, 0x0638, 0x0639, 0x063a, 0x0640, 0x0641, 0x0642, 0x0643,
+    0x00e0, 0x0644, 0x00e2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x0649, 0x064a, 0x00ee, 0x00ef,
+    0x064b, 0x064c, 0x064d, 0x064e, 0x00f4, 0x064f, 0x0650, 0x00f7, 0x0651, 0x00f9, 0x0652, 0x00fb, 0x00fc, 0x200e, 0x200f, 0x06d2
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ECI_H */
+
+
diff --git a/backend/emf.c b/backend/emf.c
new file mode 100644 (file)
index 0000000..bd6f6a2
--- /dev/null
@@ -0,0 +1,655 @@
+/*  emf.c - Support for Microsoft Enhanced Metafile Format
+
+    libzint - the open source barcode library
+    Copyright (C) 2016 - 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 : */
+
+/* Developed according to [MS-EMF] - v20160714, Released July 14, 2016
+ * and [MS-WMF] - v20160714, Released July 14, 2016 */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "emf.h"
+
+int colour_to_red(int colour) {
+    int return_val = 0;
+
+    switch(colour) {
+        case 0: // White
+        case 3: // Magenta
+        case 4: // Red
+        case 5: // Yellow
+            return_val = 255;
+            break;
+    }
+
+    return return_val;
+}
+
+int colour_to_green(int colour) {
+    int return_val = 0;
+
+    switch(colour) {
+        case 0: // White
+        case 1: // Cyan
+        case 5: // Yellow
+        case 6: // Green
+            return_val = 255;
+            break;
+    }
+
+    return return_val;
+}
+
+int colour_to_blue(int colour) {
+    int return_val = 0;
+
+    switch(colour) {
+        case 0: // White
+        case 1: // Cyan
+        case 2: // Blue
+        case 3: // Magenta
+            return_val = 255;
+            break;
+    }
+
+    return return_val;
+}
+
+static int count_rectangles(struct zint_symbol *symbol) {
+    int rectangles = 0;
+    struct zint_vector_rect *rect;
+
+    rect = symbol->vector->rectangles;
+    while (rect) {
+        rectangles++;
+        rect = rect->next;
+    }
+
+    return rectangles;
+}
+
+static int count_circles(struct zint_symbol *symbol) {
+    int circles = 0;
+    struct zint_vector_circle *circ;
+
+    circ = symbol->vector->circles;
+    while (circ) {
+        circles++;
+        circ = circ->next;
+    }
+
+    return circles;
+}
+
+static int count_hexagons(struct zint_symbol *symbol) {
+    int hexagons = 0;
+    struct zint_vector_hexagon *hex;
+
+    hex = symbol->vector->hexagons;
+    while (hex) {
+        hexagons++;
+        hex = hex->next;
+    }
+
+    return hexagons;
+}
+
+static int count_strings(struct zint_symbol *symbol) {
+    int strings = 0;
+    struct zint_vector_string *str;
+
+    str = symbol->vector->strings;
+    while (str) {
+        strings++;
+        str = str->next;
+    }
+
+    return strings;
+}
+
+static void utfle_copy(unsigned char *output, unsigned char *input, int length) {
+    int i;
+    int o;
+
+    /* Convert UTF-8 to UTF-16LE - only needs to handle characters <= U+00FF */
+    i = 0;
+    o = 0;
+    do {
+        if (input[i] <= 0x7f) {
+            /* 1 byte mode (7-bit ASCII) */
+            output[o] = input[i];
+            output[o + 1] = 0x00;
+            o += 2;
+            i++;
+        } else {
+            /* 2 byte mode */
+            output[o] = ((input[i] & 0x1f) << 6) + (input[i + 1] & 0x3f);
+            output[o + 1] = 0x00;
+            o += 2;
+            i += 2;
+        }
+    } while (i < length);
+}
+
+static int bump_up(int input) {
+    /* Strings length must be a multiple of 4 bytes */
+    if ((input % 2) == 1) {
+        input++;
+    }
+    return input;
+}
+
+INTERNAL int emf_plot(struct zint_symbol *symbol) {
+    int i,j;
+    FILE *emf_file;
+    int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
+    int error_number = 0;
+    int rectangle_count, this_rectangle;
+    int circle_count, this_circle;
+    int hexagon_count, this_hexagon;
+    int string_count, this_text;
+    int bytecount, recordcount;
+    float radius;
+    int colours_used = 0;
+    int rectangle_count_bycolour[8];
+    unsigned char *this_string[6];
+    uint32_t spacing;
+
+    float ax, ay, bx, by, cx, cy, dx, dy, ex, ey, fx, fy;
+
+    struct zint_vector_rect *rect;
+    struct zint_vector_circle *circ;
+    struct zint_vector_hexagon *hex;
+    struct zint_vector_string *str;
+
+    emr_header_t emr_header;
+    emr_eof_t emr_eof;
+    emr_createbrushindirect_t emr_createbrushindirect_fg;
+    emr_createbrushindirect_t emr_createbrushindirect_bg;
+    emr_createbrushindirect_t emr_createbrushindirect_colour[8]; // Used for colour symbols only
+    emr_selectobject_t emr_selectobject_fgbrush;
+    emr_selectobject_t emr_selectobject_bgbrush;
+    emr_selectobject_t emr_selectobject_colour[8]; // Used for colour symbols only
+    emr_createpen_t emr_createpen;
+    emr_selectobject_t emr_selectobject_pen;
+    emr_rectangle_t background;
+    emr_extcreatefontindirectw_t emr_extcreatefontindirectw;
+    emr_selectobject_t emr_selectobject_font;
+    //emr_extcreatefontindirectw_t emr_extcreatefontindirectw_big;
+    //emr_selectobject_t emr_selectobject_font_big;
+
+#ifdef _MSC_VER
+    emr_rectangle_t *rectangle;
+    emr_ellipse_t *circle;
+    emr_polygon_t *hexagon;
+    emr_exttextoutw_t *text;
+#endif
+
+    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]);
+
+    rectangle_count = count_rectangles(symbol);
+    circle_count = count_circles(symbol);
+    hexagon_count = count_hexagons(symbol);
+    string_count = count_strings(symbol);
+
+#ifndef _MSC_VER
+    emr_rectangle_t rectangle[rectangle_count ? rectangle_count : 1]; // Avoid sanitize runtime error by making always non-zero
+    emr_ellipse_t circle[circle_count ? circle_count : 1];
+    emr_polygon_t hexagon[hexagon_count ? hexagon_count : 1];
+    emr_exttextoutw_t text[string_count ? string_count: 1];
+#else
+    rectangle = (emr_rectangle_t*) _alloca(rectangle_count * sizeof (emr_rectangle_t));
+    circle = (emr_ellipse_t*) _alloca(circle_count * sizeof (emr_ellipse_t));
+    hexagon = (emr_polygon_t*) _alloca(hexagon_count * sizeof (emr_polygon_t));
+    text = (emr_exttextoutw_t*) _alloca(string_count * sizeof (emr_exttextoutw_t));
+#endif
+
+    //Calculate how many coloured rectangles
+    if (symbol->symbology == BARCODE_ULTRA) {
+        for (i = 0; i < 8; i++) {
+            rectangle_count_bycolour[i] = 0;
+        }
+
+        rect = symbol->vector->rectangles;
+        while (rect) {
+            if (rectangle_count_bycolour[rect->colour] == 0) {
+                colours_used++;
+            }
+            rectangle_count_bycolour[rect->colour]++;
+            rect = rect->next;
+        }
+    }
+
+    /* Header */
+    emr_header.type = 0x00000001; // EMR_HEADER
+    emr_header.size = 108; // Including extensions
+    emr_header.emf_header.bounds.left = 0;
+    emr_header.emf_header.bounds.right = ceil(symbol->vector->width);
+    emr_header.emf_header.bounds.bottom = ceil(symbol->vector->height);
+    emr_header.emf_header.bounds.top = 0;
+    emr_header.emf_header.frame.left = 0;
+    emr_header.emf_header.frame.right = emr_header.emf_header.bounds.right * 30;
+    emr_header.emf_header.frame.top = 0;
+    emr_header.emf_header.frame.bottom = emr_header.emf_header.bounds.bottom * 30;
+    emr_header.emf_header.record_signature = 0x464d4520; // ENHMETA_SIGNATURE
+    emr_header.emf_header.version = 0x00010000;
+    emr_header.emf_header.handles = 4; // Number of graphics objects
+    emr_header.emf_header.reserved = 0x0000;
+    emr_header.emf_header.n_description = 0;
+    emr_header.emf_header.off_description = 0;
+    emr_header.emf_header.n_pal_entries = 0;
+    emr_header.emf_header.device.cx = 1000;
+    emr_header.emf_header.device.cy = 1000;
+    emr_header.emf_header.millimeters.cx = 300;
+    emr_header.emf_header.millimeters.cy = 300;
+    /* HeaderExtension1 */
+    emr_header.emf_header.cb_pixel_format = 0x0000; // None set
+    emr_header.emf_header.off_pixel_format = 0x0000; // None set
+    emr_header.emf_header.b_open_gl = 0x0000; // OpenGL not present
+    /* HeaderExtension2 */
+    emr_header.emf_header.micrometers.cx = 0;
+    emr_header.emf_header.micrometers.cy = 0;
+    bytecount = 108;
+    recordcount = 1;
+
+    /* Create Brushes */
+    emr_createbrushindirect_bg.type = 0x00000027; // EMR_CREATEBRUSHINDIRECT
+    emr_createbrushindirect_bg.size = 24;
+    emr_createbrushindirect_bg.ih_brush = 1;
+    emr_createbrushindirect_bg.log_brush.brush_style = 0x0000; // BS_SOLID
+    emr_createbrushindirect_bg.log_brush.color.red = bgred;
+    emr_createbrushindirect_bg.log_brush.color.green = bggrn;
+    emr_createbrushindirect_bg.log_brush.color.blue = bgblu;
+    emr_createbrushindirect_bg.log_brush.color.reserved = 0;
+    emr_createbrushindirect_bg.log_brush.brush_hatch = 0x0006; // HS_SOLIDCLR
+    bytecount += 24;
+    recordcount++;
+
+    if (symbol->symbology == BARCODE_ULTRA) {
+        for (i = 0; i < 8; i++) {
+            emr_createbrushindirect_colour[i].type = 0x00000027; // EMR_CREATEBRUSHINDIRECT
+            emr_createbrushindirect_colour[i].size = 24;
+            emr_createbrushindirect_colour[i].ih_brush = 2 + i;
+            emr_createbrushindirect_colour[i].log_brush.brush_style = 0x0000; // BS_SOLID
+            emr_createbrushindirect_colour[i].log_brush.color.red = colour_to_red(i);
+            emr_createbrushindirect_colour[i].log_brush.color.green = colour_to_green(i);
+            emr_createbrushindirect_colour[i].log_brush.color.blue = colour_to_blue(i);
+            emr_createbrushindirect_colour[i].log_brush.color.reserved = 0;
+            emr_createbrushindirect_colour[i].log_brush.brush_hatch = 0x0006; // HS_SOLIDCLR
+        }
+        bytecount += colours_used * 24;
+        recordcount += colours_used;
+    } else {
+        emr_createbrushindirect_fg.type = 0x00000027; // EMR_CREATEBRUSHINDIRECT
+        emr_createbrushindirect_fg.size = 24;
+        emr_createbrushindirect_fg.ih_brush = 2;
+        emr_createbrushindirect_fg.log_brush.brush_style = 0x0000; // BS_SOLID
+        emr_createbrushindirect_fg.log_brush.color.red = fgred;
+        emr_createbrushindirect_fg.log_brush.color.green = fggrn;
+        emr_createbrushindirect_fg.log_brush.color.blue = fgblu;
+        emr_createbrushindirect_fg.log_brush.color.reserved = 0;
+        emr_createbrushindirect_fg.log_brush.brush_hatch = 0x0006; // HS_SOLIDCLR
+        bytecount += 24;
+        recordcount++;
+    }
+
+    emr_selectobject_bgbrush.type = 0x00000025; // EMR_SELECTOBJECT
+    emr_selectobject_bgbrush.size = 12;
+    emr_selectobject_bgbrush.ih_object = 1;
+    bytecount += 12;
+    recordcount++;
+
+    if (symbol->symbology == BARCODE_ULTRA) {
+        for (i = 0; i < 8; i++) {
+            emr_selectobject_colour[i].type = 0x00000025; // EMR_SELECTOBJECT
+            emr_selectobject_colour[i].size = 12;
+            emr_selectobject_colour[i].ih_object = 2 + i;
+        }
+        bytecount += colours_used * 12;
+        recordcount += colours_used;
+    } else {
+        emr_selectobject_fgbrush.type = 0x00000025; // EMR_SELECTOBJECT
+        emr_selectobject_fgbrush.size = 12;
+        emr_selectobject_fgbrush.ih_object = 2;
+        bytecount += 12;
+        recordcount++;
+    }
+
+    /* Create Pens */
+    emr_createpen.type = 0x00000026; // EMR_CREATEPEN
+    emr_createpen.size = 28;
+    emr_createpen.ih_pen = 10;
+    emr_createpen.log_pen.pen_style = 0x00000005; // PS_NULL
+    emr_createpen.log_pen.width.x = 1;
+    emr_createpen.log_pen.width.y = 0; // ignored
+    emr_createpen.log_pen.color_ref.red = 0;
+    emr_createpen.log_pen.color_ref.green = 0;
+    emr_createpen.log_pen.color_ref.blue = 0;
+    emr_createpen.log_pen.color_ref.reserved = 0;
+    bytecount += 28;
+    recordcount++;
+
+    emr_selectobject_pen.type = 0x00000025; // EMR_SELECTOBJECT
+    emr_selectobject_pen.size = 12;
+    emr_selectobject_pen.ih_object = 10;
+    bytecount += 12;
+    recordcount++;
+
+    /* Make background from a rectangle */
+    background.type = 0x0000002b; // EMR_RECTANGLE;
+    background.size = 24;
+    background.box.top = 0;
+    background.box.left = 0;
+    background.box.right = emr_header.emf_header.bounds.right;
+    background.box.bottom = emr_header.emf_header.bounds.bottom;
+    bytecount += 24;
+    recordcount++;
+
+    //Rectangles
+    rect = symbol->vector->rectangles;
+    this_rectangle = 0;
+    while (rect) {
+        rectangle[this_rectangle].type = 0x0000002b; // EMR_RECTANGLE;
+        rectangle[this_rectangle].size = 24;
+        rectangle[this_rectangle].box.top = rect->y;
+        rectangle[this_rectangle].box.bottom = rect->y + rect->height;
+        rectangle[this_rectangle].box.left = rect->x;
+        rectangle[this_rectangle].box.right = rect->x + rect->width;
+        this_rectangle++;
+        bytecount += 24;
+        recordcount++;
+        rect = rect->next;
+    }
+
+    //Circles
+    circ = symbol->vector->circles;
+    this_circle = 0;
+    while (circ) {
+        radius = circ->diameter / 2.0;
+        circle[this_circle].type = 0x0000002a; // EMR_ELLIPSE
+        circle[this_circle].size = 24;
+        circle[this_circle].box.top = circ->y - radius;
+        circle[this_circle].box.bottom = circ->y + radius;
+        circle[this_circle].box.left = circ->x - radius;
+        circle[this_circle].box.right = circ->x + radius;
+        this_circle++;
+        bytecount += 24;
+        recordcount++;
+        circ = circ->next;
+    }
+
+    //Hexagons
+    hex = symbol->vector->hexagons;
+    this_hexagon = 0;
+    while (hex) {
+        hexagon[this_hexagon].type = 0x00000003; // EMR_POLYGON
+        hexagon[this_hexagon].size = 76;
+        hexagon[this_hexagon].count = 6;
+
+        radius = hex->diameter / 2.0;
+        ay = hex->y + (1.0 * radius);
+        by = hex->y + (0.5 * radius);
+        cy = hex->y - (0.5 * radius);
+        dy = hex->y - (1.0 * radius);
+        ey = hex->y - (0.5 * radius);
+        fy = hex->y + (0.5 * radius);
+        ax = hex->x;
+        bx = hex->x + (0.86 * radius);
+        cx = hex->x + (0.86 * radius);
+        dx = hex->x;
+        ex = hex->x - (0.86 * radius);
+        fx = hex->x - (0.86 * radius);
+
+        hexagon[this_hexagon].a_points_a.x = ax;
+        hexagon[this_hexagon].a_points_a.y = ay;
+        hexagon[this_hexagon].a_points_b.x = bx;
+        hexagon[this_hexagon].a_points_b.y = by;
+        hexagon[this_hexagon].a_points_c.x = cx;
+        hexagon[this_hexagon].a_points_c.y = cy;
+        hexagon[this_hexagon].a_points_d.x = dx;
+        hexagon[this_hexagon].a_points_d.y = dy;
+        hexagon[this_hexagon].a_points_e.x = ex;
+        hexagon[this_hexagon].a_points_e.y = ey;
+        hexagon[this_hexagon].a_points_f.x = fx;
+        hexagon[this_hexagon].a_points_f.y = fy;
+
+        hexagon[this_hexagon].bounds.top = hexagon[this_hexagon].a_points_d.y;
+        hexagon[this_hexagon].bounds.bottom = hexagon[this_hexagon].a_points_a.y;
+        hexagon[this_hexagon].bounds.left = hexagon[this_hexagon].a_points_e.x;
+        hexagon[this_hexagon].bounds.right = hexagon[this_hexagon].a_points_c.x;
+        this_hexagon++;
+        bytecount += 76;
+        recordcount++;
+        hex = hex->next;
+    }
+
+    /* Create font records */
+    if (symbol->vector->strings) {
+        emr_extcreatefontindirectw.type = 0x00000052; // EMR_EXTCREATEFONTINDIRECTW
+        emr_extcreatefontindirectw.size = 104;
+        emr_extcreatefontindirectw.ih_fonts = 4;
+        emr_extcreatefontindirectw.elw.height = 16 * symbol->scale;
+        emr_extcreatefontindirectw.elw.width = 0; // automatic
+        emr_extcreatefontindirectw.elw.escapement = 0;
+        emr_extcreatefontindirectw.elw.orientation = 0;
+        emr_extcreatefontindirectw.elw.weight = 400;
+        emr_extcreatefontindirectw.elw.italic = 0x00;
+        emr_extcreatefontindirectw.elw.underline = 0x00;
+        emr_extcreatefontindirectw.elw.strike_out = 0x00;
+        emr_extcreatefontindirectw.elw.char_set = 0x01;
+        emr_extcreatefontindirectw.elw.out_precision = 0x00; // OUT_DEFAULT_PRECIS
+        emr_extcreatefontindirectw.elw.clip_precision = 0x00; // CLIP_DEFAULT_PRECIS
+        emr_extcreatefontindirectw.elw.quality = 0x00;
+        emr_extcreatefontindirectw.elw.pitch_and_family = 0x00;
+        for (i = 0; i < 64; i++) {
+            emr_extcreatefontindirectw.elw.facename[i] = '\0';
+        }
+        utfle_copy(emr_extcreatefontindirectw.elw.facename, (unsigned char*) "sans-serif", 10);
+        bytecount += 104;
+        recordcount++;
+
+        emr_selectobject_font.type = 0x00000025; // EMR_SELECTOBJECT
+        emr_selectobject_font.size = 12;
+        emr_selectobject_font.ih_object = 4;
+        bytecount += 12;
+        recordcount++;
+    }
+
+    //Text
+    str = symbol->vector->strings;
+    this_text = 0;
+    while (str) {
+        this_string[this_text] = (unsigned char *) malloc(bump_up(str->length + 1) * 2);
+        text[this_text].type = 0x00000054; // EMR_EXTTEXTOUTW
+        text[this_text].size = 76 + (6 * bump_up(str->length + 1));
+        text[this_text].bounds.top = 0; // ignored
+        text[this_text].bounds.left = 0; // ignored
+        text[this_text].bounds.right = 0xffffffff; // ignored
+        text[this_text].bounds.bottom = 0xffffffff; // ignored
+        text[this_text].i_graphics_mode = 0x00000001; // GM_COMPATIBLE
+        text[this_text].ex_scale = 1.0;
+        text[this_text].ey_scale = 1.0;
+        text[this_text].w_emr_text.reference.x = str->x - (4 * str->length * symbol->scale); // text left
+        text[this_text].w_emr_text.reference.y = str->y - (16 * symbol->scale); // text top
+        text[this_text].w_emr_text.chars = str->length;
+        text[this_text].w_emr_text.off_string = 76;
+        text[this_text].w_emr_text.options = 0;
+        text[this_text].w_emr_text.rectangle.top = 0;
+        text[this_text].w_emr_text.rectangle.left = 0;
+        text[this_text].w_emr_text.rectangle.right = 0xffffffff;
+        text[this_text].w_emr_text.rectangle.bottom = 0xffffffff;
+        text[this_text].w_emr_text.off_dx = 76 + (2 * bump_up(str->length + 1));
+        for (i = 0; i < bump_up(str->length + 1) * 2; i++) {
+            this_string[this_text][i] = '\0';
+        }
+        utfle_copy(this_string[this_text], str->text, str->length);
+        bytecount += 76 + (6 * bump_up(str->length + 1));
+        recordcount++;
+
+        this_text++;
+        str = str->next;
+    }
+
+    /* Create EOF record */
+    emr_eof.type = 0x0000000e; // EMR_EOF
+    emr_eof.size = 20; // Assuming no palette entries
+    emr_eof.n_pal_entries = 0;
+    emr_eof.off_pal_entries = 0;
+    emr_eof.size_last = emr_eof.size;
+    bytecount += 20;
+    recordcount++;
+
+    if (symbol->symbology == BARCODE_MAXICODE) {
+        bytecount += 5 * sizeof (emr_selectobject_t);
+        recordcount += 5;
+    }
+
+    /* Put final counts in header */
+    emr_header.emf_header.bytes = bytecount;
+    emr_header.emf_header.records = recordcount;
+
+    /* Send EMF data to file */
+    if (symbol->output_options & BARCODE_STDOUT) {
+        emf_file = stdout;
+    } else {
+        emf_file = fopen(symbol->outfile, "wb");
+    }
+    if (emf_file == NULL) {
+        strcpy(symbol->errtxt, "640: Could not open output file");
+        return ZINT_ERROR_FILE_ACCESS;
+    }
+
+    fwrite(&emr_header, sizeof (emr_header_t), 1, emf_file);
+
+    fwrite(&emr_createbrushindirect_bg, sizeof (emr_createbrushindirect_t), 1, emf_file);
+
+    if (symbol->symbology == BARCODE_ULTRA) {
+        for (i = 0; i < 8; i++) {
+            if (rectangle_count_bycolour[i]) {
+                fwrite(&emr_createbrushindirect_colour[i], sizeof (emr_createbrushindirect_t), 1, emf_file);
+            }
+        }
+    } else {
+        fwrite(&emr_createbrushindirect_fg, sizeof (emr_createbrushindirect_t), 1, emf_file);
+    }
+
+    fwrite(&emr_createpen, sizeof (emr_createpen_t), 1, emf_file);
+
+    if (symbol->vector->strings) {
+        fwrite(&emr_extcreatefontindirectw, sizeof (emr_extcreatefontindirectw_t), 1, emf_file);
+    }
+
+    fwrite(&emr_selectobject_bgbrush, sizeof (emr_selectobject_t), 1, emf_file);
+    fwrite(&emr_selectobject_pen, sizeof (emr_selectobject_t), 1, emf_file);
+    fwrite(&background, sizeof (emr_rectangle_t), 1, emf_file);
+
+    if (symbol->symbology == BARCODE_ULTRA) {
+        for(i = 0; i < 8; i++) {
+            if (rectangle_count_bycolour[i]) {
+                fwrite(&emr_selectobject_colour[i], sizeof (emr_selectobject_t), 1, emf_file);
+
+                rect = symbol->vector->rectangles;
+                this_rectangle = 0;
+                while (rect) {
+                    if (rect->colour == i) {
+                        fwrite(&rectangle[this_rectangle], sizeof (emr_rectangle_t), 1, emf_file);
+                    }
+                    this_rectangle++;
+                    rect = rect->next;
+                }
+            }
+        }
+    } else {
+        fwrite(&emr_selectobject_fgbrush, sizeof (emr_selectobject_t), 1, emf_file);
+
+        // Rectangles
+        for (i = 0; i < rectangle_count; i++) {
+            fwrite(&rectangle[i], sizeof (emr_rectangle_t), 1, emf_file);
+        }
+    }
+
+    // Hexagons
+    for (i = 0; i < hexagon_count; i++) {
+        fwrite(&hexagon[i], sizeof (emr_polygon_t), 1, emf_file);
+    }
+
+    // Circles
+    if (symbol->symbology == BARCODE_MAXICODE) {
+        // Bullseye needed
+        for (i = 0; i < circle_count; i++) {
+            fwrite(&circle[i], sizeof (emr_ellipse_t), 1, emf_file);
+            if (i < circle_count - 1) {
+                if (i % 2) {
+                    fwrite(&emr_selectobject_fgbrush, sizeof (emr_selectobject_t), 1, emf_file);
+                } else {
+                    fwrite(&emr_selectobject_bgbrush, sizeof (emr_selectobject_t), 1, emf_file);
+                }
+            }
+        }
+    } else {
+        for (i = 0; i < circle_count; i++) {
+            fwrite(&circle[i], sizeof (emr_ellipse_t), 1, emf_file);
+        }
+    }
+
+    // Text
+    if (string_count > 0) {
+        fwrite(&emr_selectobject_font, sizeof (emr_selectobject_t), 1, emf_file);
+    }
+
+    for (i = 0; i < string_count; i++) {
+        spacing = 8 * symbol->scale;
+        fwrite(&text[i], sizeof (emr_exttextoutw_t), 1, emf_file);
+        fwrite(this_string[i], bump_up(text[i].w_emr_text.chars + 1) * 2, 1, emf_file); // NOLINT text set 0..(string_count - 1)
+        free(this_string[i]);
+        for (j = 0; j < bump_up(text[i].w_emr_text.chars + 1); j++) {
+            fwrite(&spacing, 4, 1, emf_file);
+        }
+    }
+
+    fwrite(&emr_eof, sizeof (emr_eof_t), 1, emf_file);
+
+    if (symbol->output_options & BARCODE_STDOUT) {
+        fflush(emf_file);
+    } else {
+        fclose(emf_file);
+    }
+    return error_number;
+}
diff --git a/backend/emf.h b/backend/emf.h
new file mode 100644 (file)
index 0000000..5ecb23d
--- /dev/null
@@ -0,0 +1,223 @@
+/*  emf.h - header structure for Microsoft EMF
+
+    libzint - the open source barcode library
+    Copyright (C) 2016-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 EMF_H
+#define        EMF_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 rect_l {
+        int32_t left;
+        int32_t top;
+        int32_t right;
+        int32_t bottom;
+    } rect_l_t;
+
+    typedef struct size_l {
+        uint32_t cx;
+        uint32_t cy;
+    } size_l_t;
+
+    typedef struct point_l {
+        int32_t x;
+        int32_t y;
+    } point_l_t;
+
+    typedef struct color_ref {
+        uint8_t red;
+        uint8_t green;
+        uint8_t blue;
+        uint8_t reserved;
+    } color_ref_t;
+
+    typedef struct log_brush_ex {
+        uint32_t brush_style;
+        color_ref_t color;
+        uint32_t brush_hatch;
+    } log_brush_ex_t;
+
+    typedef struct log_pen {
+        uint32_t pen_style;
+        point_l_t width;
+        color_ref_t color_ref;
+    } log_pen_t;
+
+    typedef struct log_font {
+        int32_t height;
+        int32_t width;
+        int32_t escapement;
+        int32_t orientation;
+        int32_t weight;
+        uint8_t italic;
+        uint8_t underline;
+        uint8_t strike_out;
+        uint8_t char_set;
+        uint8_t out_precision;
+        uint8_t clip_precision;
+        uint8_t quality;
+        uint8_t pitch_and_family;
+        unsigned char facename[64];
+    } log_font_t;
+
+    typedef struct emr_text {
+        point_l_t reference;
+        uint32_t chars;
+        uint32_t off_string;
+        uint32_t options;
+        rect_l_t rectangle;
+        uint32_t off_dx;
+    } emr_text_t;
+
+    typedef struct emf_header {
+        rect_l_t bounds;
+        rect_l_t frame;
+        uint32_t record_signature;
+        uint32_t version;
+        uint32_t bytes;
+        uint32_t records;
+        uint16_t handles;
+        uint16_t reserved;
+        uint32_t n_description;
+        uint32_t off_description;
+        uint32_t n_pal_entries;
+        size_l_t device;
+        size_l_t millimeters;
+        // HeaderExtension1 Object
+        uint32_t cb_pixel_format;
+        uint32_t off_pixel_format;
+        uint32_t b_open_gl;
+        // HeaderExtension2 Object
+        size_l_t micrometers;
+    } emf_header_t;
+
+    typedef struct emr_header {
+        uint32_t type;
+        uint32_t size;
+        emf_header_t emf_header;
+    } emr_header_t;
+
+    typedef struct emr_createbrushindirect {
+        uint32_t type;
+        uint32_t size;
+        uint32_t ih_brush;
+        log_brush_ex_t log_brush;
+    } emr_createbrushindirect_t;
+
+    typedef struct emr_createpen {
+        uint32_t type;
+        uint32_t size;
+        uint32_t ih_pen;
+        log_pen_t log_pen;
+    } emr_createpen_t;
+
+    typedef struct emr_selectobject {
+        uint32_t type;
+        uint32_t size;
+        uint32_t ih_object;
+    } emr_selectobject_t;
+
+    typedef struct emr_rectangle {
+        uint32_t type;
+        uint32_t size;
+        rect_l_t box;
+    } emr_rectangle_t;
+
+    typedef struct emr_ellipse {
+        uint32_t type;
+        uint32_t size;
+        rect_l_t box;
+    } emr_ellipse_t;
+
+    typedef struct emr_polygon {
+        uint32_t type;
+        uint32_t size;
+        rect_l_t bounds;
+        uint32_t count;
+        point_l_t a_points_a;
+        point_l_t a_points_b;
+        point_l_t a_points_c;
+        point_l_t a_points_d;
+        point_l_t a_points_e;
+        point_l_t a_points_f;
+    } emr_polygon_t;
+
+    typedef struct emr_extcreatefontindirectw {
+        uint32_t type;
+        uint32_t size;
+        uint32_t ih_fonts;
+        log_font_t elw;
+    } emr_extcreatefontindirectw_t;
+
+    typedef struct emr_exttextoutw {
+        uint32_t type;
+        uint32_t size;
+        rect_l_t bounds;
+        uint32_t i_graphics_mode;
+        float ex_scale;
+        float ey_scale;
+        emr_text_t w_emr_text;
+    } emr_exttextoutw_t;
+
+    typedef struct emr_eof {
+        uint32_t type;
+        uint32_t size;
+        uint32_t n_pal_entries;
+        uint32_t off_pal_entries;
+        uint32_t size_last;
+    } emr_eof_t;
+
+    typedef struct box {
+        emr_rectangle_t top;
+        emr_rectangle_t bottom;
+        emr_rectangle_t left;
+        emr_rectangle_t right;
+    } box_t;
+
+#pragma pack()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EMF_H */
+
+
index 4ce6364..021efac 100644 (file)
@@ -2,7 +2,7 @@
 
 /*
     libzint - the open source barcode library
-    Copyright (C) 2008 Robin Stuart <robin@zint.org.uk>
+    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
     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 file contains the pixel-by-pixel representation of the "Misc Fixed" font
-   at 10 point size processed by the Gimp */
-
-static const int ascii_font[9310] = {
-       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,
-       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,
-       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,
-       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,
-       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,
-       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,0,1,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,0,0,0,
-       0,0,0,0,0,1,0,0,1,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,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,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,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,0,1,0,0,0,
-       0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,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,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,0,0,0,0,1,
-       0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,1,
-       0,1,0,0,0,0,0,1,0,0,0,0,1,1,0,0,
-       1,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,
-       0,0,0,0,1,0,0,0,0,1,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,0,0,0,1,1,0,0,0,0,
-       0,0,1,0,0,0,0,1,1,1,1,0,0,1,1,1,
-       1,1,1,0,0,0,0,0,1,0,0,1,1,1,1,1,
-       1,0,0,0,1,1,1,0,0,1,1,1,1,1,1,0,
-       0,1,1,1,1,0,0,0,1,1,1,1,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,0,0,0,0,1,1,1,0,0,0,
-       0,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,
-       1,1,0,0,1,1,1,1,0,0,0,1,1,1,1,1,
-       1,0,1,1,1,1,1,1,0,0,1,1,1,1,0,0,
-       1,0,0,0,0,1,0,0,1,1,1,1,1,0,0,0,
-       0,1,1,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,1,
-       0,0,1,1,1,1,0,0,1,1,1,1,1,0,0,0,
-       1,1,1,1,0,0,1,1,1,1,1,0,0,0,1,1,
-       1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,
-       1,0,0,0,0,1,0,0,1,0,0,0,1,0,1,1,
-       1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,
-       0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,
-       0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,
-       0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,
-       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,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,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,1,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,1,
-       0,1,0,0,0,1,1,1,1,0,0,1,0,0,1,0,
-       1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,
-       0,0,0,1,0,0,0,0,0,0,1,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,0,0,0,1,0,0,1,0,0,0,
-       0,1,1,0,0,0,1,0,0,0,0,1,0,0,0,0,
-       0,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,
-       0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,
-       1,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
-       0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,
-       1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,
-       0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,
-       0,0,0,1,1,0,0,1,1,0,1,0,0,0,0,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,
-       1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,
-       0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,
-       0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,
-       0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,
-       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,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,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,1,
-       0,1,0,0,1,0,0,1,0,1,0,1,0,0,1,1,
-       0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,
-       0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,
-       0,1,0,0,0,0,0,0,1,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,0,0,1,0,0,0,0,1,0,0,
-       1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,
-       0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,
-       1,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,
-       0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
-       0,1,0,0,0,0,1,0,1,0,0,1,1,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,
-       0,0,0,1,1,0,0,1,1,0,1,1,0,0,0,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,
-       0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0,
-       0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,
-       0,0,0,0,0,0,0,1,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,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,
-       0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
-       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,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,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,
-       1,1,1,0,1,0,0,1,0,1,0,0,1,1,1,0,
-       0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,
-       0,1,0,1,0,0,0,0,1,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,0,0,0,1,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,
-       1,0,0,0,0,0,1,0,1,0,0,1,1,1,1,1,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,
-       0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,0,
-       1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,
-       0,0,0,1,1,1,1,1,1,0,0,0,0,1,0,0,
-       0,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,
-       0,0,0,1,0,1,1,0,1,0,1,1,0,0,0,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,
-       0,1,0,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,1,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,0,0,1,0,1,1,1,0,0,0,1,1,
-       1,1,0,0,0,1,1,1,0,1,0,0,1,1,1,1,
-       0,0,0,0,1,0,0,0,0,0,1,1,1,0,1,0,
-       1,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,
-       0,0,1,1,0,1,0,0,0,1,0,0,0,0,0,1,
-       0,0,0,0,1,1,0,1,0,0,1,0,1,1,1,0,
-       0,0,1,1,1,1,0,0,1,0,1,1,1,0,0,0,
-       1,1,1,0,1,0,1,0,1,1,1,0,0,0,1,1,
-       1,1,0,0,1,1,1,1,1,0,0,1,0,0,0,0,
-       1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,
-       1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,1,
-       1,1,1,1,0,0,0,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,
-       1,1,1,0,0,0,0,0,1,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,0,0,0,1,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,
-       1,1,0,0,0,1,0,0,1,0,0,1,0,0,0,0,
-       1,0,1,0,1,1,1,0,0,0,0,0,1,0,0,0,
-       0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0,
-       0,1,0,0,0,0,0,1,1,0,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
-       0,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,
-       0,0,0,0,1,0,1,1,1,1,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,1,1,1,1,0,
-       0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,
-       1,1,1,1,1,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,1,1,0,0,0,0,0,1,0,0,0,
-       0,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,0,1,1,
-       0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       1,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,
-       0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0,
-       0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,1,0,1,1,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,
-       1,0,1,1,1,1,1,0,0,1,0,0,0,1,0,0,
-       1,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,1,0,1,0,1,0,1,1,0,0,0,1,
-       0,1,0,0,0,0,1,0,1,1,0,0,0,1,0,1,
-       0,0,0,1,1,0,1,1,0,0,0,1,0,1,0,0,
-       0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,
-       1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,
-       1,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,
-       0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,1,0,0,0,0,1,1,1,0,0,0,0,1,0,0,
-       0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,
-       0,1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,
-       0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,
-       0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,
-       1,0,1,1,0,0,0,1,0,0,0,0,1,0,0,0,
-       0,1,0,0,1,0,0,0,1,1,1,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,
-       1,1,1,1,1,0,1,0,0,0,1,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,1,1,1,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,
-       0,0,0,1,0,0,0,0,1,0,1,0,0,1,0,1,
-       0,1,0,0,0,0,1,0,1,1,1,1,1,0,0,1,
-       0,0,0,0,1,0,1,1,1,1,1,0,0,0,0,0,
-       1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       1,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,
-       0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,
-       1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,1,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,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,
-       0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,0,1,0,
-       0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,
-       1,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,
-       0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,0,
-       0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,
-       1,1,1,0,0,0,0,1,0,1,0,0,0,1,1,1,
-       0,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,
-       1,1,1,0,0,0,0,0,1,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,0,0,0,0,1,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,
-       0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
-       0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,0,
-       0,0,0,0,1,0,0,0,1,0,1,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,
-       0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,1,
-       1,1,0,0,1,0,1,0,0,1,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       1,0,0,1,0,0,1,0,0,0,1,0,1,0,1,0,
-       0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,
-       0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,0,1,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,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,1,1,1,1,1,
-       1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,1,0,1,1,1,0,0,0,0,0,0,0,1,
-       0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,
-       1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,
-       1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,
-       0,0,1,1,0,0,0,1,0,0,0,0,1,0,0,0,
-       1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,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,
-       0,1,0,0,1,0,0,1,0,1,0,0,1,1,0,0,
-       1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,
-       0,1,0,1,0,0,0,0,1,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,0,0,0,0,1,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,
-       0,0,1,0,1,1,1,1,1,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       1,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,
-       0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,
-       0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,
-       0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,1,
-       0,0,1,0,1,0,1,0,0,0,1,0,0,1,0,0,
-       0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       1,0,0,0,1,1,0,0,0,0,1,0,1,0,1,0,
-       0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,
-       0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,
-       0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,
-       1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,
-       0,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,
-       1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,1,0,0,1,0,0,1,0,1,0,1,0,1,0,0,
-       1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,
-       0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,
-       0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,
-       1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,
-       1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,
-       0,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,
-       0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,0,1,1,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,
-       0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,1,
-       0,0,0,1,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       1,0,0,0,1,1,0,0,0,0,1,0,1,0,1,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,
-       0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,1,0,1,1,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,
-       1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,
-       0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,1,
-       0,1,0,0,0,0,1,0,1,1,0,0,0,1,0,1,
-       0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,
-       1,0,0,0,0,1,0,0,0,0,1,0,1,0,1,0,
-       1,0,0,0,0,1,0,0,1,1,1,0,1,0,0,1,
-       0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,1,0,0,0,1,1,1,1,0,0,1,0,0,1,1,
-       0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,
-       0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,
-       1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,
-       1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,1,
-       0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,
-       0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,
-       0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
-       0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
-       0,0,0,0,1,0,0,0,0,0,1,1,1,1,0,1,
-       0,0,0,0,1,0,1,1,1,1,0,0,0,0,1,1,
-       1,1,0,0,1,1,1,1,0,0,0,1,1,1,1,1,
-       1,0,1,0,0,0,0,0,0,0,1,1,1,0,1,0,
-       1,0,0,0,0,1,0,0,1,1,1,1,1,0,0,1,
-       1,1,0,0,0,1,0,0,0,0,1,0,1,1,1,1,
-       1,1,0,1,0,0,0,0,1,0,1,0,0,0,0,1,
-       0,0,1,1,1,1,0,0,1,0,0,0,0,0,0,0,
-       1,1,1,1,0,0,1,0,0,0,0,1,0,0,1,1,
-       1,1,0,0,0,0,0,1,0,0,0,0,1,1,1,1,
-       0,0,0,0,1,1,0,0,0,0,0,1,0,1,0,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,1,
-       1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,1,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,0,1,0,1,1,1,0,0,0,1,1,
-       1,1,0,0,0,1,1,1,0,1,0,0,1,1,1,1,
-       0,0,0,0,1,0,0,0,0,1,0,1,1,1,0,0,
-       1,0,0,0,0,1,0,0,1,1,1,1,1,0,0,1,
-       0,0,0,1,0,1,0,0,0,0,1,0,0,1,1,1,
-       1,1,0,0,1,0,0,0,1,0,1,0,0,0,0,1,
-       0,0,1,1,1,1,0,0,1,0,1,1,1,0,0,0,
-       1,1,1,0,1,0,1,0,0,0,0,0,0,0,1,1,
-       1,1,0,0,0,0,0,1,1,0,0,0,1,1,1,0,
-       1,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,
-       1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,1,
-       1,1,1,1,0,0,0,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,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,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,0,0,0,0,1,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
-       0,1,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,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,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,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,0,0,0,0,0,0,0,0,
-       0,1,0,0,0,0,0,1,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,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,1,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,0,0,0,0,0,0,0,
-       0,0,0,0,1,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,0,0,0,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,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,0,0,1,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,1,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,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,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,0,0,0,0,0,
-       0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
-       0,1,1,1,1,1,1,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,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       1,1,1,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,0,0,0,0,0,0,0,
-       0,0,0,0,1,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,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,
-       0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0
-};
-
-static const int ascii_ext_font[9310] = {
-       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,
-       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,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,1,1,0,0,0,0,1,1,
-       0,0,1,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,0,0,0,0,0,0,0,1,0,0,0,0,0,
-       1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,
-       1,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,
-       1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,
-       0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,1,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,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,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,0,0,
-       0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,0,
-       1,1,1,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,0,
-       0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
-       0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,
-       1,0,0,0,0,0,0,0,1,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,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,0,0,0,0,
-       0,1,0,0,0,0,0,1,0,0,1,0,0,1,0,0,
-       1,1,0,0,0,1,0,0,1,0,0,0,0,1,1,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,
-       0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,
-       0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,1,
-       0,0,0,0,0,1,0,0,1,0,0,1,0,0,1,1,
-       0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,
-       1,0,0,0,0,0,1,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,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,0,1,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,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,0,0,0,
-       1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,
-       0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,
-       0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,
-       0,0,1,1,1,1,1,0,0,1,0,0,1,0,0,0,
-       0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,
-       0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
-       1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,1,
-       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,0,0,1,
-       0,0,0,0,1,1,1,1,0,0,1,1,1,1,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,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,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,0,0,0,0,0,
-       0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,1,0,0,0,0,1,1,0,0,0,0,1,1,
-       0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,
-       1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
-       1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,
-       1,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,
-       1,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,0,0,0,0,0,0,
-       0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,
-       0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,0,
-       1,1,1,1,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,0,1,
-       0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,
-       0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,
-       0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,
-       0,1,0,1,1,0,0,0,1,0,0,0,1,0,0,1,
-       0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,
-       0,1,1,0,0,0,0,0,1,1,0,0,0,0,0,1,
-       1,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,
-       0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,
-       1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,
-       1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,
-       1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,
-       0,0,1,1,1,1,1,0,0,1,0,0,0,1,0,1,
-       1,0,0,0,1,0,0,1,1,1,1,0,0,0,1,1,
-       1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,
-       0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,
-       1,0,0,0,1,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0,
-       0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,
-       0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,0,
-       1,1,0,0,0,1,0,0,1,0,0,0,0,1,1,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,
-       0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,
-       0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,1,
-       0,0,0,0,0,1,0,0,1,0,0,1,0,0,1,1,
-       0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,
-       1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,
-       0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,1,
-       0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,
-       0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,
-       0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,
-       0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,
-       1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,
-       1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,
-       0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,
-       1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,
-       0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,
-       0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,
-       1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,
-       1,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,
-       1,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,1,0,0,0,1,0,1,1,1,1,1,0,
-       0,0,1,0,0,1,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,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,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,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,1,
-       0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,
-       0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,1,
-       0,0,1,1,0,0,0,0,1,0,1,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,
-       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,0,0,0,0,0,0,0,
-       0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,
-       1,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,
-       1,0,0,0,1,0,0,1,0,0,0,0,1,1,0,0,
-       0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,
-       0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,1,0,0,0,0,0,1,
-       1,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,0,1,0,1,0,0,1,0,0,0,0,1,
-       0,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,
-       1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,
-       1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,
-       0,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,
-       0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,
-       1,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,
-       0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,
-       0,0,0,1,1,0,0,0,0,0,1,1,1,1,0,1,
-       0,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,
-       1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,
-       0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,
-       0,1,1,1,1,0,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,1,0,0,0,0,1,0,1,0,1,1,1,0,
-       0,1,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,
-       0,0,0,0,0,1,0,0,1,0,0,0,1,1,1,1,
-       1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,
-       1,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
-       1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,1,1,0,1,0,0,
-       0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,1,1,1,1,0,0,1,1,
-       0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,
-       1,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,0,1,0,1,0,0,1,0,0,0,0,1,
-       0,0,1,1,1,0,0,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,1,0,0,1,1,0,0,0,0,1,0,
-       1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,
-       1,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,
-       1,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,1,0,0,0,0,1,0,1,1,0,0,0,1,
-       0,1,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,1,
-       1,1,0,0,0,1,0,0,1,0,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,
-       0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,
-       0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,
-       0,0,0,0,1,1,1,1,0,0,1,1,0,0,1,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,1,
-       1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
-       1,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,
-       1,1,1,0,0,0,0,1,0,1,0,0,0,0,1,0,
-       0,1,0,0,0,1,0,1,0,0,0,0,1,0,0,1,
-       0,0,0,1,0,0,0,0,1,1,1,1,1,1,0,1,
-       1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,
-       1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,
-       1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,
-       1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,
-       1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,
-       0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,
-       0,0,1,0,0,1,0,0,0,0,0,1,1,1,0,0,
-       0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,
-       1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,
-       1,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,
-       1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,
-       1,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,1,
-       0,0,1,0,0,0,1,0,0,
-       0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,
-       1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,
-       0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,
-       1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,
-       1,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
-       1,0,0,0,0,1,0,1,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,0,1,0,0,0,1,0,
-       1,1,0,0,0,1,1,0,1,0,0,1,0,0,1,1,
-       0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,
-       0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,
-       1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,
-       0,0,1,0,0,0,1,0,0,1,1,0,0,1,0,0,
-       1,1,0,0,1,0,0,1,1,0,0,1,0,0,1,1,
-       0,0,1,0,0,1,1,0,0,1,0,0,1,1,0,0,
-       1,0,0,1,0,1,1,1,1,1,0,0,0,0,0,0,
-       1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,
-       1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,
-       1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,1,
-       0,0,1,0,0,1,0,0,0,
-       0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,0,
-       0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,
-       0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,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,0,0,0,
-       1,0,0,0,0,1,0,1,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,0,1,0,0,0,1,0,1,
-       0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,1,
-       0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,
-       1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,
-       0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,0,0,1,0,0,0,1,1,1,1,1,0,
-       0,0,1,0,0,0,1,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,
-       1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,1,1,1,1,1,1,0,
-       1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,0,1,0,1,0,0,1,0,0,0,0,1,
-       0,0,0,1,0,1,0,0,0,
-       0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,1,
-       1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,
-       0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,
-       0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,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,0,1,
-       1,0,0,0,0,1,0,1,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,0,1,0,0,0,1,0,0,1,
-       1,1,0,1,0,0,0,1,0,0,1,0,0,1,1,1,
-       0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,
-       1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,
-       0,0,0,1,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,
-       1,1,0,0,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
-       0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,0,1,0,1,0,0,0,1,1,0,1,
-       0,0,0,1,1,0,1,0,0,0,1,1,0,1,0,0,
-       0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,1,
-       1,0,1,0,0,1,0,0,1,1,0,0,0,0,1,0,
-       1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,
-       0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,
-       0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,
-       1,1,0,0,0,1,0,1,0,0,0,1,1,0,1,0,
-       0,0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,
-       1,1,0,0,0,1,1,1,0,0,1,1,0,0,0,1,
-       0,0,0,1,1,1,0,0,0,
-       0,0,1,0,0,0,0,1,1,1,1,0,0,0,0,1,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,
-       0,0,0,0,0,1,0,0,0,0,1,1,1,1,0,0,
-       0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,
-       0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,
-       0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,
-       1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,
-       0,1,0,1,0,0,1,1,1,0,0,0,0,0,0,1,
-       0,1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,
-       0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,0,
-       1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,0,
-       1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,
-       1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,
-       1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,
-       0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,
-       0,0,0,1,1,0,0,1,1,1,1,0,0,0,1,1,
-       1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,
-       0,0,0,1,1,1,1,0,0,1,0,0,0,0,0,1,
-       0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,
-       1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,
-       1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,
-       0,1,1,1,1,1,0,0,0,1,1,1,0,1,0,0,
-       1,1,1,0,1,0,0,1,1,1,0,1,0,0,1,1,
-       1,0,1,0,0,1,1,1,0,1,0,0,1,1,1,0,
-       1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,
-       0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,1,
-       1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,
-       1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,
-       0,0,1,1,1,1,1,0,0,0,1,1,1,0,0,1,
-       0,0,0,0,1,0,0,1,1,1,1,0,0,0,1,1,
-       1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,
-       0,0,0,1,1,1,1,0,0,0,0,1,1,0,0,0,
-       0,1,1,1,1,0,0,0,1,1,1,0,1,0,0,1,
-       1,1,0,1,0,0,1,1,1,0,1,0,0,1,1,1,
-       0,1,0,0,0,0,1,0,0,0,1,0,1,1,1,0,
-       0,0,0,0,1,0,0,0,0,
-       0,0,0,0,0,0,0,0,1,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,0,0,0,1,0,0,0,
-       0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,
-       0,0,0,1,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,0,0,0,0,1,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,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,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,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,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,0,0,1,0,0,0,1,0,0,0,0,0,
-       0,1,0,0,1,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,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
-       0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,
-       0,0,1,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,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,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,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,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,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,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,1,0,0,0,0,0
-};
-
-static const int small_font[] = {
-       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,
-       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,
-       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,
-       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,0,0,0,1,0,1,0,0,0,0,0,0,0,
-       0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
-       1,0,0,0,0,1,0,0,0,1,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,0,0,
-       0,0,1,0,0,0,1,1,0,0,1,1,1,1,0,0,
-       0,1,0,0,1,1,1,1,0,0,1,1,0,0,1,1,
-       1,1,0,0,1,1,0,0,0,1,1,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,0,0,0,1,1,0,0,
-       0,1,1,0,0,1,1,1,0,0,0,1,1,0,0,1,
-       1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,1,
-       1,0,0,1,0,0,1,0,0,1,1,1,0,0,0,0,
-       1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,1,
-       0,1,0,0,1,0,0,1,1,0,0,1,1,1,0,0,
-       0,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,
-       1,1,1,0,1,0,0,1,0,1,0,0,1,0,1,0,
-       0,1,0,1,0,0,1,0,0,1,0,1,0,1,1,1,
-       1,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,
-       0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,
-       0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,
-       1,0,1,0,0,0,0,0,1,1,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,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,0,0,0,1,0,0,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,0,0,
-       0,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,
-       1,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,
-       1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,
-       1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,1,0,0,1,0,1,0,
-       0,1,1,0,0,1,0,0,1,0,0,0,0,1,0,0,
-       1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,
-       0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,1,
-       0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,0,0,1,0,1,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,
-       0,1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,
-       1,0,1,0,1,0,0,1,0,0,0,0,1,1,1,1,
-       0,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,
-       0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,0,
-       0,1,0,1,0,0,1,0,0,1,0,1,0,0,0,0,
-       1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,
-       0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,
-       0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,1,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,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,0,0,0,0,1,0,0,0,0,1,0,
-       0,1,0,1,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,1,0,1,0,1,1,1,1,1,1,
-       0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,0,
-       1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,
-       0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,
-       0,0,1,0,0,0,0,0,1,0,0,1,1,0,0,1,
-       0,1,0,0,1,1,1,0,0,1,1,1,0,0,0,0,
-       1,0,0,0,1,1,0,0,1,0,0,1,0,0,1,1,
-       0,0,0,1,1,0,0,0,0,1,0,0,1,1,1,1,
-       0,0,0,1,0,0,0,0,0,1,0,1,0,1,1,0,
-       1,0,0,1,0,1,1,1,0,0,1,0,0,0,0,1,
-       0,0,1,0,1,1,1,0,0,1,1,1,0,0,1,0,
-       0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,
-       1,0,1,1,0,0,0,1,0,0,0,0,1,1,1,1,
-       0,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,
-       0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,0,
-       0,1,0,0,1,1,0,0,0,1,0,1,0,0,0,1,
-       0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,1,1,1,0,1,1,1,0,0,0,1,1,0,0,0,
-       1,1,1,0,0,1,1,0,0,0,1,0,0,0,0,1,
-       1,1,0,1,1,1,0,0,0,1,1,0,0,0,0,0,
-       1,0,1,0,1,0,0,0,0,1,0,0,1,0,1,0,
-       0,1,1,1,0,0,0,1,1,0,0,1,1,1,0,0,
-       0,1,1,1,0,1,1,1,0,0,0,1,1,1,0,1,
-       1,1,0,0,1,0,0,1,0,0,1,0,1,0,1,0,
-       0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,
-       1,0,0,1,1,0,0,0,0,1,0,0,0,0,1,1,
-       0,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,
-       1,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,
-       0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,1,
-       1,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1,
-       0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,
-       0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,1,
-       1,1,1,0,0,0,0,1,0,1,0,0,1,0,0,0,
-       1,0,0,1,0,0,1,0,0,1,1,1,0,0,0,0,
-       0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
-       0,0,0,0,1,0,0,0,1,0,0,1,0,1,1,0,
-       1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1,
-       0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,
-       1,1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,
-       1,0,1,1,0,0,0,1,0,0,0,0,1,0,0,1,
-       0,1,0,1,1,0,1,0,0,1,0,1,1,1,0,0,
-       1,0,0,1,0,1,1,1,0,0,0,0,1,0,0,0,
-       0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,1,
-       1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,
-       0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,
-       0,0,1,0,1,0,1,1,0,1,1,1,0,0,1,0,
-       0,1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,
-       1,0,1,1,0,0,0,0,0,1,0,0,1,1,1,1,
-       0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,1,0,0,0,0,
-       1,0,0,0,1,0,0,1,0,0,1,0,1,0,1,0,
-       0,1,0,0,1,1,0,0,1,0,0,1,0,0,0,1,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,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,0,
-       0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,
-       0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,
-       0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,
-       0,0,1,1,0,0,1,0,0,0,0,0,1,0,1,0,
-       0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,
-       0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,
-       0,0,0,1,0,0,1,0,0,0,0,1,0,0,1,1,
-       0,0,0,1,1,0,0,0,0,1,0,0,1,1,1,1,
-       0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,
-       0,1,0,1,0,0,1,0,0,0,1,0,0,1,0,0,
-       1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,1,
-       0,1,0,1,1,0,1,0,0,1,0,1,0,0,0,0,
-       1,1,0,1,0,1,0,1,0,0,1,0,0,1,0,0,
-       0,1,0,0,1,0,0,1,0,0,1,1,0,0,1,1,
-       1,1,0,1,0,0,1,0,0,0,1,0,0,1,0,0,
-       0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       1,0,1,1,0,1,0,0,1,0,1,0,0,0,0,1,
-       0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,1,
-       1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,
-       1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,1,
-       0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,0,0,0,0,1,1,0,0,
-       1,0,0,0,1,0,0,1,0,0,1,0,1,0,1,1,
-       1,1,0,0,1,1,0,0,0,1,0,1,0,0,1,0,
-       0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,
-       0,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,
-       1,1,1,0,0,0,0,1,0,0,1,0,1,0,0,0,
-       0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,
-       1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,
-       0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,
-       0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,0,
-       0,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,
-       0,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,
-       0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,1,0,0,0,1,1,0,0,
-       1,0,0,1,0,1,1,1,0,0,0,1,1,0,0,1,
-       1,1,0,0,1,1,1,1,0,1,0,0,0,0,0,1,
-       1,1,0,1,0,0,1,0,0,1,1,1,0,0,1,1,
-       0,0,1,0,0,1,0,1,1,1,1,0,1,0,0,1,
-       0,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,
-       0,1,1,0,0,1,0,0,1,0,0,1,1,0,0,0,
-       0,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,
-       0,1,0,1,0,0,1,0,0,0,1,0,0,1,1,1,
-       1,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,
-       0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,
-       0,1,0,1,0,1,1,1,0,0,0,1,1,0,0,0,
-       1,1,1,0,0,1,1,0,0,0,1,0,0,0,1,0,
-       0,0,0,1,0,0,1,0,0,1,1,1,0,0,1,0,
-       1,0,1,0,0,1,0,0,1,1,1,0,1,0,0,1,
-       0,1,0,0,1,0,0,1,1,0,0,1,1,1,0,0,
-       0,1,1,1,0,1,0,0,0,0,1,1,1,0,0,0,
-       0,1,1,0,0,1,1,1,0,0,0,1,0,0,1,1,
-       1,1,0,1,0,0,1,0,0,0,1,0,0,1,1,1,
-       1,0,0,0,0,1,0,0,0,1,0,0,0,1,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,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,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
-       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,0,0,0,0,
-       0,0,0,1,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,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
+static const char ascii_font[] = {
+    /* Each character is 7 x 14 pixels */
+    0, 0, 8, 8, 8, 8, 8, 8, 8, 0, 8, 8, 0, 0, /* ! */
+    0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* " */
+    0, 0, 20, 20, 20, 62, 20, 20, 62, 20, 20, 20, 0, 0, /* # */
+    0, 0, 8, 60, 74, 74, 40, 28, 10, 74, 74, 60, 8, 0, /* $ */
+    0, 0, 50, 74, 76, 56, 8, 16, 28, 50, 82, 76, 0, 0, /* % */
+    0, 0, 24, 36, 36, 36, 24, 50, 74, 68, 76, 50, 0, 0, /* & */
+    0, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ' */
+    0, 2, 4, 8, 8, 16, 16, 16, 16, 16, 8, 8, 4, 2, /* ( */
+    0, 32, 16, 8, 8, 4, 4, 4, 4, 4, 8, 8, 16, 32, /* ) */
+    0, 0, 0, 0, 8, 42, 28, 8, 28, 42, 8, 0, 0, 0, /* * */
+    0, 0, 0, 0, 8, 8, 8, 62, 8, 8, 8, 0, 0, 0, /* + */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 8, 8, 16, /* , */
+    0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, /* - */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 28, 8, 0, /* . */
+    0, 2, 2, 4, 4, 8, 8, 8, 16, 16, 32, 32, 64, 64, /* / */
+    0, 0, 24, 36, 66, 66, 66, 66, 66, 66, 36, 24, 0, 0, /* 0 */
+    0, 0, 8, 24, 40, 8, 8, 8, 8, 8, 8, 62, 0, 0, /* 1 */
+    0, 0, 60, 66, 66, 2, 4, 4, 8, 16, 32, 126, 0, 0, /* 2 */
+    0, 0, 126, 2, 4, 8, 28, 2, 2, 66, 66, 60, 0, 0, /* 3 */
+    0, 0, 4, 12, 20, 20, 36, 36, 68, 126, 4, 4, 0, 0, /* 4 */
+    0, 0, 126, 64, 64, 124, 66, 2, 2, 66, 66, 60, 0, 0, /* 5 */
+    0, 0, 28, 32, 64, 64, 92, 98, 66, 66, 66, 60, 0, 0, /* 6 */
+    0, 0, 126, 2, 4, 4, 8, 8, 16, 16, 32, 32, 0, 0, /* 7 */
+    0, 0, 60, 66, 66, 36, 24, 36, 66, 66, 66, 60, 0, 0, /* 8 */
+    0, 0, 60, 66, 66, 66, 70, 58, 2, 66, 68, 56, 0, 0, /* 9 */
+    0, 0, 0, 0, 8, 28, 8, 0, 0, 8, 28, 8, 0, 0, /* : */
+    0, 0, 0, 0, 0, 24, 24, 0, 0, 24, 8, 8, 16, 0, /* ; */
+    0, 0, 0, 2, 4, 8, 16, 32, 16, 8, 4, 2, 0, 0, /* < */
+    0, 0, 0, 0, 0, 126, 0, 0, 126, 0, 0, 0, 0, 0, /* = */
+    0, 0, 0, 32, 16, 8, 4, 2, 4, 8, 16, 32, 0, 0, /* > */
+    0, 0, 60, 66, 66, 4, 8, 8, 8, 0, 8, 8, 0, 0, /* ? */
+    0, 0, 28, 34, 78, 82, 82, 82, 82, 78, 32, 30, 0, 0, /* @ */
+    0, 0, 24, 36, 66, 66, 66, 126, 66, 66, 66, 66, 0, 0, /* A */
+    0, 0, 120, 68, 66, 68, 120, 68, 66, 66, 68, 120, 0, 0, /* B */
+    0, 0, 60, 66, 66, 64, 64, 64, 64, 66, 66, 60, 0, 0, /* C */
+    0, 0, 120, 68, 66, 66, 66, 66, 66, 66, 68, 120, 0, 0, /* D */
+    0, 0, 126, 64, 64, 64, 120, 64, 64, 64, 64, 126, 0, 0, /* E */
+    0, 0, 126, 64, 64, 64, 120, 64, 64, 64, 64, 64, 0, 0, /* F */
+    0, 0, 60, 66, 66, 64, 64, 78, 66, 66, 70, 58, 0, 0, /* G */
+    0, 0, 66, 66, 66, 66, 126, 66, 66, 66, 66, 66, 0, 0, /* H */
+    0, 0, 62, 8, 8, 8, 8, 8, 8, 8, 8, 62, 0, 0, /* I */
+    0, 0, 14, 4, 4, 4, 4, 4, 4, 68, 68, 56, 0, 0, /* J */
+    0, 0, 66, 68, 72, 80, 96, 80, 72, 68, 66, 66, 0, 0, /* K */
+    0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 126, 0, 0, /* L */
+    0, 0, 66, 102, 102, 90, 90, 66, 66, 66, 66, 66, 0, 0, /* M */
+    0, 0, 66, 66, 98, 98, 82, 74, 70, 70, 66, 66, 0, 0, /* N */
+    0, 0, 60, 66, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* O */
+    0, 0, 124, 66, 66, 66, 66, 124, 64, 64, 64, 64, 0, 0, /* P */
+    0, 0, 60, 66, 66, 66, 66, 66, 114, 74, 70, 60, 4, 2, /* Q */
+    0, 0, 124, 66, 66, 66, 66, 124, 72, 68, 66, 66, 0, 0, /* R */
+    0, 0, 60, 66, 66, 64, 48, 12, 2, 66, 66, 60, 0, 0, /* S */
+    0, 0, 127, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, /* T */
+    0, 0, 66, 66, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* U */
+    0, 0, 66, 66, 66, 66, 36, 36, 36, 24, 24, 24, 0, 0, /* V */
+    0, 0, 34, 34, 34, 34, 34, 34, 42, 42, 42, 20, 0, 0, /* W */
+    0, 0, 66, 66, 36, 36, 24, 24, 36, 36, 66, 66, 0, 0, /* X */
+    0, 0, 34, 34, 34, 20, 20, 8, 8, 8, 8, 8, 0, 0, /* Y */
+    0, 0, 126, 2, 4, 8, 8, 16, 32, 32, 64, 126, 0, 0, /* Z */
+    0, 30, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 30, /* [ */
+    0, 64, 64, 32, 32, 16, 16, 16, 8, 8, 4, 4, 2, 2, /* \ */
+    0, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 60, /* ] */
+    0, 24, 36, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ^ */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, /* _ */
+    0, 16, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` */
+    0, 0, 0, 0, 0, 60, 66, 2, 62, 66, 66, 62, 0, 0, /* a */
+    0, 0, 64, 64, 64, 92, 98, 66, 66, 66, 98, 92, 0, 0, /* b */
+    0, 0, 0, 0, 0, 60, 66, 64, 64, 64, 66, 60, 0, 0, /* c */
+    0, 0, 2, 2, 2, 58, 70, 66, 66, 66, 70, 58, 0, 0, /* d */
+    0, 0, 0, 0, 0, 60, 66, 66, 126, 64, 66, 60, 0, 0, /* e */
+    0, 0, 12, 18, 16, 16, 124, 16, 16, 16, 16, 16, 0, 0, /* f */
+    0, 0, 0, 0, 0, 58, 68, 68, 68, 56, 32, 92, 66, 60, /* g */
+    0, 0, 64, 64, 64, 92, 98, 66, 66, 66, 66, 66, 0, 0, /* h */
+    0, 0, 8, 8, 0, 24, 8, 8, 8, 8, 8, 62, 0, 0, /* i */
+    0, 0, 2, 2, 0, 6, 2, 2, 2, 2, 2, 34, 34, 28, /* j */
+    0, 0, 64, 64, 64, 68, 72, 80, 112, 72, 68, 66, 0, 0, /* k */
+    0, 0, 24, 8, 8, 8, 8, 8, 8, 8, 8, 62, 0, 0, /* l */
+    0, 0, 0, 0, 0, 52, 42, 42, 42, 42, 42, 34, 0, 0, /* m */
+    0, 0, 0, 0, 0, 92, 98, 66, 66, 66, 66, 66, 0, 0, /* n */
+    0, 0, 0, 0, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0, /* o */
+    0, 0, 0, 0, 0, 92, 98, 66, 66, 66, 98, 92, 64, 64, /* p */
+    0, 0, 0, 0, 0, 58, 70, 66, 66, 66, 70, 58, 2, 2, /* q */
+    0, 0, 0, 0, 0, 92, 98, 66, 64, 64, 64, 64, 0, 0, /* r */
+    0, 0, 0, 0, 0, 60, 66, 32, 24, 4, 66, 60, 0, 0, /* s */
+    0, 0, 16, 16, 16, 124, 16, 16, 16, 16, 18, 12, 0, 0, /* t */
+    0, 0, 0, 0, 0, 66, 66, 66, 66, 66, 70, 58, 0, 0, /* u */
+    0, 0, 0, 0, 0, 34, 34, 34, 20, 20, 8, 8, 0, 0, /* v */
+    0, 0, 0, 0, 0, 34, 34, 42, 42, 42, 42, 20, 0, 0, /* w */
+    0, 0, 0, 0, 0, 66, 66, 36, 24, 36, 66, 66, 0, 0, /* x */
+    0, 0, 0, 0, 0, 66, 66, 66, 66, 70, 58, 2, 66, 60, /* y */
+    0, 0, 0, 0, 0, 126, 4, 8, 16, 16, 32, 126, 0, 0, /* z */
+    0, 6, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 6, /* { */
+    0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* | */
+    0, 48, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 48, /* } */
+    0, 32, 82, 74, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ~ */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* \7f */
+    0, 0, 8, 8, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0, /* ¡ */
+    0, 0, 0, 0, 16, 60, 82, 80, 80, 80, 82, 60, 16, 0, /* ¢ */
+    0, 0, 0, 12, 18, 16, 16, 60, 16, 16, 60, 18, 0, 0, /* £ */
+    0, 0, 0, 0, 66, 60, 36, 36, 60, 66, 0, 0, 0, 0, /* ¤ */
+    0, 0, 34, 20, 20, 8, 62, 8, 62, 8, 8, 8, 0, 0, /* ¥ */
+    0, 0, 8, 8, 8, 8, 0, 0, 8, 8, 8, 8, 0, 0, /* ¦ */
+    0, 60, 66, 32, 24, 36, 66, 36, 24, 4, 66, 60, 0, 0, /* § */
+    0, 36, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ¨ */
+    0, 60, 66, 90, 102, 98, 98, 98, 102, 90, 66, 60, 0, 0, /* © */
+    0, 28, 34, 30, 34, 38, 26, 0, 62, 0, 0, 0, 0, 0, /* ª */
+    0, 0, 0, 0, 0, 10, 20, 40, 80, 40, 20, 10, 0, 0, /* « */
+    0, 0, 0, 0, 0, 0, 0, 0, 62, 2, 2, 2, 0, 0, /* ¬ */
+    0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, /* ­ */
+    0, 60, 66, 122, 102, 102, 122, 102, 102, 102, 66, 60, 0, 0, /* ® */
+    0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ¯ */
+    0, 24, 36, 36, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ° */
+    0, 0, 0, 0, 0, 0, 8, 8, 62, 8, 8, 62, 0, 0, /* ± */
+    0, 24, 36, 4, 8, 16, 32, 60, 0, 0, 0, 0, 0, 0, /* ² */
+    0, 24, 36, 4, 24, 4, 36, 24, 0, 0, 0, 0, 0, 0, /* ³ */
+    0, 4, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ´ */
+    0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 54, 42, 32, 32, /* µ */
+    0, 0, 30, 42, 42, 42, 42, 26, 10, 10, 10, 10, 10, 14, /* ¶ */
+    0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, /* · */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 16, /* ¸ */
+    0, 8, 24, 8, 8, 8, 8, 28, 0, 0, 0, 0, 0, 0, /* ¹ */
+    0, 0, 24, 36, 36, 24, 0, 60, 0, 0, 0, 0, 0, 0, /* º */
+    0, 0, 0, 0, 0, 80, 40, 20, 10, 20, 40, 80, 0, 0, /* » */
+    0, 0, 32, 98, 36, 36, 40, 18, 22, 42, 78, 66, 0, 0, /* ¼ */
+    0, 0, 32, 98, 36, 36, 40, 20, 26, 34, 68, 78, 0, 0, /* ½ */
+    0, 0, 98, 18, 36, 24, 104, 18, 38, 42, 78, 2, 0, 0, /* ¾ */
+    0, 0, 0, 16, 16, 0, 16, 16, 16, 16, 32, 66, 66, 60, /* ¿ */
+    16, 8, 0, 24, 36, 66, 66, 126, 66, 66, 66, 66, 0, 0, /* À */
+    8, 16, 0, 24, 36, 66, 66, 126, 66, 66, 66, 66, 0, 0, /* Á */
+    24, 36, 0, 24, 36, 66, 66, 126, 66, 66, 66, 66, 0, 0, /* Â */
+    50, 76, 0, 24, 36, 66, 66, 126, 66, 66, 66, 66, 0, 0, /* Ã */
+    0, 36, 0, 24, 36, 66, 66, 126, 66, 66, 66, 66, 0, 0, /* Ä */
+    0, 24, 36, 24, 36, 66, 66, 126, 66, 66, 66, 66, 0, 0, /* Å */
+    0, 0, 30, 40, 72, 72, 126, 72, 72, 72, 72, 78, 0, 0, /* Æ */
+    0, 0, 60, 66, 66, 64, 64, 64, 64, 66, 66, 60, 8, 16, /* Ç */
+    16, 8, 0, 126, 64, 64, 64, 124, 64, 64, 64, 126, 0, 0, /* È */
+    8, 16, 0, 126, 64, 64, 64, 124, 64, 64, 64, 126, 0, 0, /* É */
+    24, 36, 0, 126, 64, 64, 64, 124, 64, 64, 64, 126, 0, 0, /* Ê */
+    0, 36, 0, 126, 64, 64, 64, 124, 64, 64, 64, 126, 0, 0, /* Ë */
+    16, 8, 0, 62, 8, 8, 8, 8, 8, 8, 8, 62, 0, 0, /* Ì */
+    4, 8, 0, 62, 8, 8, 8, 8, 8, 8, 8, 62, 0, 0, /* Í */
+    8, 20, 0, 62, 8, 8, 8, 8, 8, 8, 8, 62, 0, 0, /* Î */
+    0, 20, 0, 62, 8, 8, 8, 8, 8, 8, 8, 62, 0, 0, /* Ï */
+    0, 0, 60, 34, 33, 33, 121, 33, 33, 33, 34, 60, 0, 0, /* Ð */
+    50, 76, 0, 98, 98, 82, 82, 74, 74, 74, 70, 70, 0, 0, /* Ñ */
+    16, 8, 0, 60, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* Ò */
+    8, 16, 0, 60, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* Ó */
+    24, 36, 0, 60, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* Ô */
+    50, 76, 0, 60, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* Õ */
+    0, 36, 0, 60, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* Ö */
+    0, 0, 0, 0, 0, 65, 34, 20, 8, 20, 34, 65, 0, 0, /* × */
+    2, 2, 60, 70, 74, 74, 74, 82, 82, 82, 98, 60, 64, 64, /* Ø */
+    16, 8, 0, 66, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* Ù */
+    8, 16, 0, 66, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* Ú */
+    24, 36, 0, 66, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* Û */
+    0, 36, 0, 66, 66, 66, 66, 66, 66, 66, 66, 60, 0, 0, /* Ü */
+    4, 8, 0, 34, 34, 20, 20, 8, 8, 8, 8, 8, 0, 0, /* Ý */
+    0, 0, 64, 64, 124, 66, 66, 66, 66, 124, 64, 64, 0, 0, /* Þ */
+    0, 0, 24, 36, 36, 36, 56, 36, 34, 34, 34, 124, 0, 0, /* ß */
+    0, 0, 16, 8, 0, 60, 66, 14, 50, 66, 70, 58, 0, 0, /* à */
+    0, 0, 4, 8, 0, 60, 66, 14, 50, 66, 70, 58, 0, 0, /* á */
+    0, 0, 24, 36, 0, 60, 66, 14, 50, 66, 70, 58, 0, 0, /* â */
+    0, 0, 50, 76, 0, 60, 66, 14, 50, 66, 70, 58, 0, 0, /* ã */
+    0, 0, 0, 36, 0, 60, 66, 14, 50, 66, 70, 58, 0, 0, /* ä */
+    0, 24, 36, 24, 0, 60, 66, 14, 50, 66, 70, 58, 0, 0, /* å */
+    0, 0, 0, 0, 0, 62, 73, 25, 47, 72, 73, 62, 0, 0, /* æ */
+    0, 0, 0, 0, 0, 60, 66, 64, 64, 64, 66, 60, 8, 16, /* ç */
+    0, 0, 16, 8, 0, 60, 66, 66, 126, 64, 66, 60, 0, 0, /* è */
+    0, 0, 8, 16, 0, 60, 66, 66, 126, 64, 66, 60, 0, 0, /* é */
+    0, 0, 24, 36, 0, 60, 66, 66, 126, 64, 66, 60, 0, 0, /* ê */
+    0, 0, 0, 36, 0, 60, 66, 66, 126, 64, 66, 60, 0, 0, /* ë */
+    0, 0, 16, 8, 0, 24, 8, 8, 8, 8, 8, 62, 0, 0, /* ì */
+    0, 0, 4, 8, 0, 24, 8, 8, 8, 8, 8, 62, 0, 0, /* í */
+    0, 0, 24, 36, 0, 24, 8, 8, 8, 8, 8, 62, 0, 0, /* î */
+    0, 0, 0, 20, 0, 24, 8, 8, 8, 8, 8, 62, 0, 0, /* ï */
+    0, 20, 8, 20, 2, 30, 34, 34, 34, 34, 34, 28, 0, 0, /* ð */
+    0, 0, 50, 76, 0, 92, 98, 66, 66, 66, 66, 66, 0, 0, /* ñ */
+    0, 0, 16, 8, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0, /* ò */
+    0, 0, 8, 16, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0, /* ó */
+    0, 0, 24, 36, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0, /* ô */
+    0, 0, 50, 76, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0, /* õ */
+    0, 0, 0, 36, 0, 60, 66, 66, 66, 66, 66, 60, 0, 0, /* ö */
+    0, 0, 0, 0, 0, 0, 0, 24, 0, 126, 0, 24, 0, 0, /* ÷ */
+    0, 0, 0, 2, 4, 60, 74, 74, 82, 82, 98, 60, 64, 64, /* ø */
+    0, 0, 16, 8, 0, 66, 66, 66, 66, 66, 70, 58, 0, 0, /* ù */
+    0, 0, 8, 16, 0, 66, 66, 66, 66, 66, 70, 58, 0, 0, /* ú */
+    0, 0, 24, 36, 0, 66, 66, 66, 66, 66, 70, 58, 0, 0, /* û */
+    0, 0, 0, 36, 0, 66, 66, 66, 66, 66, 70, 58, 0, 0, /* ü */
+    0, 0, 8, 16, 0, 66, 66, 34, 36, 20, 28, 8, 72, 48, /* ý */
+    0, 0, 64, 64, 64, 92, 98, 66, 66, 66, 98, 92, 64, 64, /* þ */
+    0, 0, 0, 36, 0, 66, 66, 34, 36, 20, 28, 8, 72, 48, /* ÿ */
 };
 
-static const int small_font_extended[] = {
-       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,
-       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,
-       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,
-       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,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,
-       1,1,0,0,1,0,1,0,0,1,1,1,0,0,1,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,1,1,0,1,1,1,1,0,0,0,1,0,0,
-       0,0,1,0,0,0,1,1,0,0,0,1,1,0,0,0,
-       0,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,
-       0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,
-       0,1,1,0,0,0,0,0,1,0,0,0,1,1,0,0,
-       0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,
-       0,0,1,0,0,1,1,0,0,0,1,1,1,0,0,1,
-       1,0,0,1,1,1,1,0,1,1,1,1,0,1,1,1,
-       1,0,1,1,1,1,0,0,1,1,1,0,0,1,1,1,
-       0,0,1,1,1,0,0,1,1,1,0,1,1,1,0,0,
-       1,0,1,1,0,0,1,1,0,0,0,1,1,0,0,0,
-       1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,
-       0,0,0,0,1,1,1,0,1,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,
-       0,1,0,0,0,0,0,1,1,0,0,0,1,0,0,0,
-       0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,
-       0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,
-       0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,
-       0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,0,
-       1,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,
-       0,0,0,1,1,0,0,0,1,0,1,0,0,0,1,0,
-       0,0,0,0,0,0,0,1,0,1,0,
-       0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,1,
-       0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,
-       0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,1,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,0,
-       0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,
-       1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,1,
-       0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,
-       0,1,1,0,0,0,0,0,0,0,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,
-       1,1,0,0,0,1,1,0,0,1,0,1,0,0,1,0,
-       0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,
-       0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,1,0,0,1,1,0,0,0,0,
-       0,0,0,1,0,1,1,0,1,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,0,0,0,0,0,0,1,0,1,
-       0,1,1,1,0,0,1,0,0,1,0,0,0,1,0,0,
-       0,1,0,0,0,0,1,0,1,0,1,0,1,0,0,0,
-       0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,
-       0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,
-       0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,
-       1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,
-       0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,
-       1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
-       0,1,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,1,1,1,0,0,1,0,0,0,0,
-       1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,
-       1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,1,
-       0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,
-       0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,0,
-       1,1,1,1,1,0,1,0,0,0,0,0,1,0,0,0,
-       0,0,0,0,1,0,0,1,0,1,1,0,1,0,0,1,
-       1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,
-       0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,
-       0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,1,0,1,0,1,1,0,1,0,
-       0,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,
-       0,0,1,1,1,0,0,0,0,1,0,0,0,0,1,0,
-       0,0,0,1,0,0,0,0,1,0,0,1,1,0,1,0,
-       1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,
-       0,1,0,1,0,1,1,0,1,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,
-       0,1,0,0,1,0,1,0,1,0,0,0,1,1,1,0,
-       0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,
-       1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,0,
-       1,1,0,0,1,1,0,0,0,1,1,0,0,0,1,1,
-       0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,
-       0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,
-       1,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,
-       1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,0,
-       0,0,0,0,1,1,1,0,1,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,
-       0,1,1,1,0,0,1,0,0,1,0,
-       0,0,1,0,0,1,0,1,0,0,1,1,1,0,0,0,
-       1,0,1,0,0,1,1,1,0,0,0,0,0,0,0,1,
-       0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,
-       0,0,1,0,0,1,0,1,1,1,1,0,0,0,0,0,
-       0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,1,1,0,0,0,1,1,0,0,0,
-       0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,1,
-       1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,
-       0,0,0,1,0,0,1,1,0,0,1,0,1,0,1,1,
-       0,1,1,0,1,0,0,1,0,0,0,1,1,1,1,0,
-       1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,
-       1,1,1,0,1,1,1,1,0,1,1,1,0,0,1,0,
-       0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,
-       0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,
-       1,0,1,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,
-       1,0,0,1,1,0,1,0,1,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,
-       0,1,1,1,0,0,1,0,0,1,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,1,0,1,0,1,1,0,0,1,
-       0,0,0,1,0,1,1,0,1,0,1,1,0,1,0,1,
-       1,0,1,0,1,1,0,0,0,1,0,0,0,0,1,0,
-       0,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,1,
-       1,1,0,1,0,1,1,0,1,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,
-       0,1,0,0,1,0,1,0,0,1,0,
-       0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,
-       1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,0,
-       1,1,0,0,0,0,0,0,1,0,1,0,1,0,0,0,
-       0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,
-       0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,1,
-       0,0,0,1,1,0,0,1,0,1,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,
-       0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,
-       0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,
-       0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,
-       1,0,1,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,
-       1,0,0,1,1,0,1,0,1,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,1,0,0,1,0,0,0,1,0,
-       0,1,0,0,0,0,1,0,0,1,0,1,0,1,1,0,
-       1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,
-       0,1,1,0,1,0,1,1,0,1,0,1,0,0,0,1,
-       0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,
-       0,0,1,1,0,0,0,0,0,1,0,0,0,0,1,0,
-       0,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,
-       0,0,0,1,1,0,1,0,1,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,
-       0,1,0,0,1,0,0,1,0,1,0,
-       0,0,1,0,0,0,1,1,1,0,1,0,1,1,0,1,
-       0,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,
-       0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-       0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
-       1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,1,1,1,0,0,0,1,0,1,0,0,0,
-       0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,
-       0,0,1,1,1,0,0,0,1,0,0,1,0,0,1,0,
-       1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,
-       0,0,1,0,1,0,0,1,0,1,0,1,1,0,0,1,
-       1,0,0,1,1,1,1,0,1,1,1,1,0,1,1,1,
-       1,0,1,1,1,1,0,0,1,1,1,0,0,1,1,1,
-       0,0,1,1,1,0,0,1,1,1,0,1,1,1,0,0,
-       1,0,0,1,0,0,1,1,0,0,0,1,1,0,0,0,
-       1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,
-       0,1,0,1,1,1,0,0,0,1,1,0,0,0,1,1,
-       0,0,0,1,1,0,0,0,1,1,0,0,0,0,1,0,
-       0,1,0,0,0,0,1,0,1,0,0,0,1,0,1,0,
-       0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,
-       1,0,1,0,0,1,0,1,0,0,1,1,1,0,0,0,
-       1,1,0,0,1,1,0,0,0,1,1,0,0,0,1,1,
-       0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,1,
-       0,0,1,1,1,0,0,1,1,1,0,0,1,1,0,0,
-       1,0,0,1,0,0,1,1,0,0,0,1,1,0,0,0,
-       1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,
-       1,0,0,1,1,1,0,0,0,1,1,1,0,0,1,1,
-       1,0,0,1,1,1,0,0,1,1,1,0,0,0,1,0,
-       0,1,1,1,0,0,0,0,1,0,0,
-       0,0,0,0,0,0,0,1,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,0,0,0,0,0,0,0,0,1,1,1,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,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,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
-       0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,
-       0,0,0,0,1,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,
-       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,
-       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,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,0,0,
-       0,1,0,0,0,0,0,1,0,0,0
+static const char small_font[] = {
+    /* Each character is 5 x 9 pixels */
+    0, 2, 2, 2, 2, 0, 2, 0, 0, /* ! */
+    0, 5, 5, 5, 0, 0, 0, 0, 0, /* " */
+    0, 0, 5, 15, 5, 15, 5, 0, 0, /* # */
+    0, 0, 7, 26, 7, 18, 7, 0, 0, /* $ */
+    0, 8, 9, 2, 4, 25, 1, 0, 0, /* % */
+    0, 0, 4, 10, 4, 10, 5, 0, 0, /* & */
+    0, 2, 2, 2, 0, 0, 0, 0, 0, /* ' */
+    0, 2, 4, 4, 4, 4, 2, 0, 0, /* ( */
+    0, 4, 2, 2, 2, 2, 4, 0, 0, /* ) */
+    0, 0, 5, 2, 7, 2, 5, 0, 0, /* * */
+    0, 0, 2, 2, 15, 2, 2, 0, 0, /* + */
+    0, 0, 0, 0, 16, 3, 2, 4, 0, /* , */
+    0, 0, 0, 0, 15, 0, 0, 0, 0, /* - */
+    0, 0, 0, 0, 0, 6, 6, 0, 0, /* . */
+    0, 0, 1, 2, 4, 8, 0, 0, 0, /* / */
+    0, 2, 5, 5, 5, 5, 2, 0, 0, /* 0 */
+    0, 2, 6, 2, 2, 2, 7, 0, 0, /* 1 */
+    0, 6, 9, 1, 2, 4, 15, 0, 0, /* 2 */
+    0, 15, 1, 6, 1, 9, 6, 0, 0, /* 3 */
+    0, 2, 6, 10, 15, 2, 2, 0, 0, /* 4 */
+    0, 15, 8, 14, 1, 9, 6, 0, 0, /* 5 */
+    0, 6, 8, 14, 9, 9, 6, 0, 0, /* 6 */
+    0, 15, 1, 2, 2, 4, 4, 0, 0, /* 7 */
+    0, 6, 9, 6, 9, 9, 6, 0, 0, /* 8 */
+    0, 6, 9, 9, 7, 1, 6, 0, 0, /* 9 */
+    0, 0, 6, 6, 0, 6, 6, 0, 0, /* : */
+    0, 0, 6, 6, 0, 6, 4, 8, 0, /* ; */
+    0, 0, 1, 2, 4, 2, 1, 0, 0, /* < */
+    0, 0, 0, 15, 0, 15, 0, 0, 0, /* = */
+    0, 0, 4, 2, 1, 2, 4, 0, 0, /* > */
+    0, 2, 5, 1, 2, 0, 2, 0, 0, /* ? */
+    0, 6, 9, 11, 11, 8, 6, 0, 0, /* @ */
+    0, 6, 9, 9, 15, 9, 9, 0, 0, /* A */
+    0, 14, 9, 14, 9, 9, 14, 0, 0, /* B */
+    0, 6, 9, 8, 8, 9, 6, 0, 0, /* C */
+    0, 14, 9, 9, 9, 9, 14, 0, 0, /* D */
+    0, 15, 8, 14, 8, 8, 15, 0, 0, /* E */
+    0, 15, 8, 14, 8, 8, 8, 0, 0, /* F */
+    0, 6, 9, 8, 11, 9, 7, 0, 0, /* G */
+    0, 9, 9, 15, 9, 9, 9, 0, 0, /* H */
+    0, 7, 2, 2, 2, 2, 7, 0, 0, /* I */
+    0, 1, 1, 1, 1, 9, 6, 0, 0, /* J */
+    0, 9, 10, 12, 12, 10, 9, 0, 0, /* K */
+    0, 8, 8, 8, 8, 8, 15, 0, 0, /* L */
+    0, 9, 15, 15, 9, 9, 9, 0, 0, /* M */
+    0, 9, 13, 13, 11, 11, 9, 0, 0, /* N */
+    0, 6, 9, 9, 9, 9, 6, 0, 0, /* O */
+    0, 14, 9, 9, 14, 8, 8, 0, 0, /* P */
+    0, 6, 9, 9, 9, 13, 6, 1, 0, /* Q */
+    0, 14, 9, 9, 14, 10, 9, 0, 0, /* R */
+    0, 6, 9, 4, 2, 9, 6, 0, 0, /* S */
+    0, 7, 2, 2, 2, 2, 2, 0, 0, /* T */
+    0, 9, 9, 9, 9, 9, 6, 0, 0, /* U */
+    0, 9, 9, 9, 9, 6, 6, 0, 0, /* V */
+    0, 9, 9, 9, 15, 15, 9, 0, 0, /* W */
+    0, 9, 9, 6, 6, 9, 9, 0, 0, /* X */
+    0, 5, 5, 5, 2, 2, 2, 0, 0, /* Y */
+    0, 15, 1, 2, 4, 8, 15, 0, 0, /* Z */
+    0, 7, 4, 4, 4, 4, 7, 0, 0, /* [ */
+    0, 0, 8, 4, 2, 1, 0, 0, 0, /* \ */
+    0, 7, 1, 1, 1, 1, 7, 0, 0, /* ] */
+    0, 2, 5, 0, 0, 0, 0, 0, 0, /* ^ */
+    0, 0, 0, 0, 0, 0, 15, 0, 0, /* _ */
+    0, 4, 2, 0, 0, 0, 0, 0, 0, /* ` */
+    0, 0, 0, 7, 9, 11, 5, 0, 0, /* a */
+    0, 8, 8, 14, 9, 9, 14, 0, 0, /* b */
+    0, 0, 0, 6, 8, 8, 6, 0, 0, /* c */
+    0, 1, 1, 7, 9, 9, 7, 0, 0, /* d */
+    0, 0, 0, 6, 11, 12, 6, 0, 0, /* e */
+    0, 2, 5, 4, 14, 4, 4, 0, 0, /* f */
+    0, 0, 0, 7, 9, 6, 8, 7, 0, /* g */
+    0, 8, 8, 14, 9, 9, 9, 0, 0, /* h */
+    0, 2, 0, 6, 2, 2, 7, 0, 0, /* i */
+    0, 1, 0, 1, 1, 1, 5, 2, 0, /* j */
+    0, 8, 8, 10, 12, 10, 9, 0, 0, /* k */
+    0, 6, 2, 2, 2, 2, 7, 0, 0, /* l */
+    0, 0, 0, 10, 15, 9, 9, 0, 0, /* m */
+    0, 0, 0, 14, 9, 9, 9, 0, 0, /* n */
+    0, 0, 0, 6, 9, 9, 6, 0, 0, /* o */
+    0, 0, 0, 14, 9, 9, 14, 8, 0, /* p */
+    0, 0, 0, 7, 9, 9, 7, 1, 0, /* q */
+    0, 0, 0, 14, 9, 8, 8, 0, 0, /* r */
+    0, 0, 0, 7, 12, 3, 14, 0, 0, /* s */
+    0, 4, 4, 14, 4, 4, 3, 0, 0, /* t */
+    0, 0, 0, 9, 9, 9, 7, 0, 0, /* u */
+    0, 0, 0, 5, 5, 5, 2, 0, 0, /* v */
+    0, 0, 0, 9, 9, 15, 15, 0, 0, /* w */
+    0, 0, 0, 9, 6, 6, 9, 0, 0, /* x */
+    0, 0, 0, 9, 9, 5, 2, 4, 0, /* y */
+    0, 0, 0, 15, 2, 4, 15, 0, 0, /* z */
+    0, 1, 2, 6, 2, 2, 1, 0, 0, /* { */
+    0, 2, 2, 2, 2, 2, 2, 0, 0, /* | */
+    0, 4, 2, 3, 2, 2, 4, 0, 0, /* } */
+    0, 5, 10, 0, 0, 0, 0, 0, 0, /* ~ */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, /* \7f */
+    0, 2, 0, 2, 2, 2, 2, 0, 0, /* ¡ */
+    0, 0, 2, 7, 10, 10, 7, 2, 0, /* ¢ */
+    0, 0, 3, 4, 14, 4, 11, 0, 0, /* £ */
+    0, 0, 8, 7, 5, 7, 8, 0, 0, /* ¤ */
+    0, 5, 21, 2, 7, 2, 18, 0, 0, /* ¥ */
+    0, 0, 2, 2, 0, 2, 2, 0, 0, /* ¦ */
+    0, 3, 4, 6, 5, 3, 1, 6, 0, /* § */
+    0, 5, 0, 0, 0, 0, 0, 0, 0, /* ¨ */
+    0, 7, 8, 10, 12, 10, 8, 7, 0, /* © */
+    0, 6, 26, 22, 16, 16, 16, 0, 0, /* ª */
+    0, 0, 0, 4, 9, 4, 0, 0, 0, /* « */
+    0, 0, 0, 16, 15, 17, 0, 0, 0, /* ¬ */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, /* ­ */
+    0, 7, 8, 14, 12, 12, 8, 7, 0, /* ® */
+    0, 15, 16, 16, 16, 16, 16, 0, 0, /* ¯ */
+    0, 2, 5, 2, 0, 0, 0, 0, 0, /* ° */
+    0, 2, 2, 15, 2, 2, 15, 0, 0, /* ± */
+    0, 6, 2, 20, 6, 0, 16, 0, 0, /* ² */
+    0, 6, 6, 2, 6, 0, 0, 0, 0, /* ³ */
+    0, 2, 4, 0, 0, 0, 0, 0, 0, /* ´ */
+    0, 0, 0, 9, 9, 9, 14, 8, 0, /* µ */
+    0, 7, 13, 13, 5, 5, 5, 0, 0, /* ¶ */
+    0, 0, 0, 6, 6, 0, 0, 0, 0, /* · */
+    0, 0, 0, 0, 0, 0, 2, 4, 0, /* ¸ */
+    0, 2, 6, 2, 7, 0, 0, 0, 0, /* ¹ */
+    0, 4, 10, 4, 0, 0, 0, 0, 0, /* º */
+    0, 0, 0, 9, 4, 9, 0, 0, 0, /* » */
+    0, 8, 8, 8, 25, 3, 7, 1, 0, /* ¼ */
+    0, 8, 8, 8, 11, 1, 2, 3, 0, /* ½ */
+    0, 12, 12, 4, 13, 3, 7, 1, 0, /* ¾ */
+    0, 2, 0, 2, 4, 5, 2, 0, 0, /* ¿ */
+    0, 6, 9, 9, 15, 9, 9, 0, 0, /* À */
+    0, 6, 9, 9, 15, 9, 9, 0, 0, /* Á */
+    0, 6, 9, 9, 15, 9, 9, 0, 0, /* Â */
+    0, 6, 9, 9, 15, 9, 9, 0, 0, /* Ã */
+    0, 9, 6, 9, 15, 9, 9, 0, 0, /* Ä */
+    0, 6, 6, 9, 15, 9, 9, 0, 0, /* Å */
+    0, 7, 10, 11, 14, 10, 11, 0, 0, /* Æ */
+    0, 6, 9, 8, 8, 9, 6, 4, 0, /* Ç */
+    0, 15, 8, 14, 8, 8, 15, 0, 0, /* È */
+    0, 15, 8, 14, 8, 8, 15, 0, 0, /* É */
+    0, 15, 8, 14, 8, 8, 15, 0, 0, /* Ê */
+    0, 15, 8, 14, 8, 8, 15, 0, 0, /* Ë */
+    0, 7, 2, 2, 2, 2, 7, 0, 0, /* Ì */
+    0, 7, 2, 2, 2, 2, 7, 0, 0, /* Í */
+    0, 7, 2, 2, 2, 2, 7, 0, 0, /* Î */
+    0, 7, 2, 2, 2, 2, 7, 0, 0, /* Ï */
+    0, 14, 5, 13, 5, 5, 14, 0, 0, /* Ð */
+    0, 11, 9, 13, 11, 11, 9, 0, 0, /* Ñ */
+    0, 6, 9, 9, 9, 9, 6, 0, 0, /* Ò */
+    0, 6, 9, 9, 9, 9, 6, 0, 0, /* Ó */
+    0, 6, 9, 9, 9, 9, 6, 0, 0, /* Ô */
+    0, 6, 9, 9, 9, 9, 6, 0, 0, /* Õ */
+    0, 9, 6, 9, 9, 9, 6, 0, 0, /* Ö */
+    0, 0, 0, 9, 6, 6, 9, 0, 0, /* × */
+    0, 7, 11, 11, 13, 13, 14, 0, 0, /* Ø */
+    0, 9, 9, 9, 9, 9, 6, 0, 0, /* Ù */
+    0, 9, 9, 9, 9, 9, 6, 0, 0, /* Ú */
+    0, 9, 9, 9, 9, 9, 6, 0, 0, /* Û */
+    0, 9, 0, 9, 9, 9, 6, 0, 0, /* Ü */
+    0, 5, 5, 5, 2, 2, 2, 0, 0, /* Ý */
+    0, 8, 14, 9, 14, 8, 8, 0, 0, /* Þ */
+    0, 6, 9, 10, 9, 9, 10, 0, 0, /* ß */
+    0, 4, 2, 7, 9, 11, 5, 0, 0, /* à */
+    0, 2, 4, 7, 9, 11, 5, 0, 0, /* á */
+    0, 2, 5, 7, 9, 11, 5, 0, 0, /* â */
+    0, 5, 10, 7, 9, 11, 5, 0, 0, /* ã */
+    0, 5, 0, 7, 9, 11, 5, 0, 0, /* ä */
+    0, 6, 6, 7, 9, 11, 5, 0, 0, /* å */
+    0, 0, 0, 7, 11, 10, 7, 0, 0, /* æ */
+    0, 0, 0, 3, 4, 4, 3, 2, 0, /* ç */
+    0, 4, 2, 6, 11, 12, 6, 0, 0, /* è */
+    0, 2, 4, 6, 11, 12, 6, 0, 0, /* é */
+    0, 4, 10, 6, 11, 12, 6, 0, 0, /* ê */
+    0, 10, 0, 6, 11, 12, 6, 0, 0, /* ë */
+    0, 4, 2, 6, 2, 2, 7, 0, 0, /* ì */
+    0, 2, 4, 6, 2, 2, 7, 0, 0, /* í */
+    0, 2, 5, 6, 2, 2, 7, 0, 0, /* î */
+    0, 5, 0, 6, 2, 2, 7, 0, 0, /* ï */
+    0, 4, 3, 6, 9, 9, 6, 0, 0, /* ð */
+    0, 5, 10, 14, 9, 9, 9, 0, 0, /* ñ */
+    0, 4, 2, 6, 9, 9, 6, 0, 0, /* ò */
+    0, 2, 4, 6, 9, 9, 6, 0, 0, /* ó */
+    0, 6, 0, 6, 9, 9, 6, 0, 0, /* ô */
+    0, 5, 10, 6, 9, 9, 6, 0, 0, /* õ */
+    0, 5, 0, 6, 9, 9, 6, 0, 0, /* ö */
+    0, 0, 6, 0, 15, 0, 6, 0, 0, /* ÷ */
+    0, 0, 0, 7, 11, 13, 14, 0, 0, /* ø */
+    0, 4, 2, 9, 9, 9, 7, 0, 0, /* ù */
+    0, 2, 4, 9, 9, 9, 7, 0, 0, /* ú */
+    0, 6, 0, 9, 9, 9, 7, 0, 0, /* û */
+    0, 5, 0, 9, 9, 9, 7, 0, 0, /* ü */
+    0, 2, 4, 9, 9, 5, 2, 4, 0, /* ý */
+    0, 0, 8, 14, 9, 9, 14, 8, 0, /* þ */
+    0, 5, 0, 9, 9, 5, 2, 4, 0, /* ÿ */
 };
diff --git a/backend/gb18030.c b/backend/gb18030.c
new file mode 100644 (file)
index 0000000..ae67fd7
--- /dev/null
@@ -0,0 +1,2968 @@
+/*
+    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 : */
+/*
+ * Adapted from GNU LIBICONV library and patched to allow 2 duplicate mappings
+ * for compatibility with GB 2312 (GB2312.TXT):
+ * 1) U+30FB to 0xA1A4 (duplicate of U+00B7)
+ * 2) U+2015 to 0xA1AA (duplicate of U+2014)
+ */
+/*
+ * Copyright (C) 1999-2001, 2005, 2012, 2016 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <string.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "gb2312.h"
+#include "gb18030.h"
+
+INTERNAL int utf_to_eci(const int eci, const unsigned char source[], unsigned char dest[], size_t *length); /* Convert Unicode to other encodings */
+
+/*
+ * CP936 extensions (libiconv-1.16/lib/cp936ext.h)
+ */
+
+static const unsigned short cp936ext_page01[16] = {
+  0x0000, 0x0000, 0x0000, 0x0000, 0xa8bd, 0x0000, 0x0000, 0x0000, /*0x40-0x47*/
+  0xa8be, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x48-0x4f*/
+};
+static const unsigned short cp936ext_page02[24] = {
+  0x0000, 0xa8bb, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x50-0x57*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x58-0x5f*/
+  0x0000, 0xa8c0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x60-0x67*/
+};
+static const unsigned short cp936ext_pagefe[24] = {
+  0x0000, 0xa6f2, 0x0000, 0xa6f4, 0xa6f5, 0xa6e0, 0xa6e1, 0xa6f0, /*0x30-0x37*/
+  0xa6f1, 0xa6e2, 0xa6e3, 0xa6ee, 0xa6ef, 0xa6e6, 0xa6e7, 0xa6e4, /*0x38-0x3f*/
+  0xa6e5, 0xa6e8, 0xa6e9, 0xa6ea, 0xa6eb, 0x0000, 0x0000, 0x0000, /*0x40-0x47*/
+};
+
+static int cp936ext_wctomb(unsigned int* r, unsigned int wc) {
+    unsigned short c = 0;
+    if (wc >= 0x0140 && wc < 0x0150) {
+        c = cp936ext_page01[wc-0x0140];
+    } else if (wc >= 0x0250 && wc < 0x0268) {
+        c = cp936ext_page02[wc-0x0250];
+    } else if (wc >= 0xfe30 && wc < 0xfe48) {
+        c = cp936ext_pagefe[wc-0xfe30];
+    }
+    if (c != 0) {
+        *r = c;
+        return 2;
+    }
+    return 0;
+}
+
+/*
+ * GBK extensions (libiconv-1.16/lib/gbkext_inv.h)
+ */
+
+static const unsigned short gbkext_inv_2charset[14313] = {
+  0xa840, 0xa841, 0xa842, 0xa95c, 0xa843, 0xa844, 0xa845, 0xa846,
+  0xa847, 0xa848, 0xa959, 0xa849, 0xa84a, 0xa84b, 0xa84c, 0xa84d,
+  0xa84e, 0xa84f, 0xa850, 0xa851, 0xa852, 0xa892, 0xa853, 0xa854,
+  0xa855, 0xa856, 0xa857, 0xa858, 0xa859, 0xa85a, 0xa85b, 0xa85c,
+  0xa85d, 0xa85e, 0xa85f, 0xa860, 0xa861, 0xa862, 0xa863, 0xa864,
+  0xa865, 0xa866, 0xa867, 0xa868, 0xa869, 0xa86a, 0xa86b, 0xa86c,
+  0xa86d, 0xa86e, 0xa86f, 0xa870, 0xa871, 0xa872, 0xa873, 0xa874,
+  0xa875, 0xa876, 0xa877, 0xa878, 0xa879, 0xa87a, 0xa87b, 0xa87c,
+  0xa87d, 0xa87e, 0xa880, 0xa881, 0xa882, 0xa883, 0xa884, 0xa885,
+  0xa886, 0xa887, 0xa888, 0xa889, 0xa88a, 0xa88b, 0xa88c, 0xa88d,
+  0xa88e, 0xa88f, 0xa890, 0xa891, 0xa965, 0xa996, 0xa893, 0xa894,
+  0xa895, 0xa940, 0xa941, 0xa942, 0xa943, 0xa944, 0xa945, 0xa946,
+  0xa947, 0xa948, 0xa961, 0xa962, 0xa966, 0xa967, 0xa960, 0xa963,
+  0xa964, 0xa95a, 0xa949, 0xa94a, 0xa94b, 0xa94c, 0xa94d, 0xa94e,
+  0xa94f, 0xa950, 0xa951, 0xa952, 0xa953, 0xa954, 0x8140, 0x8141,
+  0x8142, 0x8143, 0x8144, 0x8145, 0x8146, 0x8147, 0x8148, 0x8149,
+  0x814a, 0x814b, 0x814c, 0x814d, 0x814e, 0x814f, 0x8150, 0x8151,
+  0x8152, 0x8153, 0x8154, 0x8155, 0x8156, 0x8157, 0x8158, 0x8159,
+  0x815a, 0x815b, 0x815c, 0x815d, 0x815e, 0x815f, 0x8160, 0x8161,
+  0x8162, 0x8163, 0x8164, 0x8165, 0x8166, 0x8167, 0x8168, 0x8169,
+  0x816a, 0x816b, 0x816c, 0x816d, 0x816e, 0x816f, 0x8170, 0x8171,
+  0x8172, 0x8173, 0x8174, 0x8175, 0x8176, 0x8177, 0x8178, 0x8179,
+  0x817a, 0x817b, 0x817c, 0x817d, 0x817e, 0x8180, 0x8181, 0x8182,
+  0x8183, 0x8184, 0x8185, 0x8186, 0x8187, 0x8188, 0x8189, 0x818a,
+  0x818b, 0x818c, 0x818d, 0x818e, 0x818f, 0x8190, 0x8191, 0x8192,
+  0x8193, 0x8194, 0x8195, 0x8196, 0x8197, 0x8198, 0x8199, 0x819a,
+  0x819b, 0x819c, 0x819d, 0x819e, 0x819f, 0x81a0, 0x81a1, 0x81a2,
+  0x81a3, 0x81a4, 0x81a5, 0x81a6, 0x81a7, 0x81a8, 0x81a9, 0x81aa,
+  0x81ab, 0x81ac, 0x81ad, 0x81ae, 0x81af, 0x81b0, 0x81b1, 0x81b2,
+  0x81b3, 0x81b4, 0x81b5, 0x81b6, 0x81b7, 0x81b8, 0x81b9, 0x81ba,
+  0x81bb, 0x81bc, 0x81bd, 0x81be, 0x81bf, 0x81c0, 0x81c1, 0x81c2,
+  0x81c3, 0x81c4, 0x81c5, 0x81c6, 0x81c7, 0x81c8, 0x81c9, 0x81ca,
+  0x81cb, 0x81cc, 0x81cd, 0x81ce, 0x81cf, 0x81d0, 0x81d1, 0x81d2,
+  0x81d3, 0x81d4, 0x81d5, 0x81d6, 0x81d7, 0x81d8, 0x81d9, 0x81da,
+  0x81db, 0x81dc, 0x81dd, 0x81de, 0x81df, 0x81e0, 0x81e1, 0x81e2,
+  0x81e3, 0x81e4, 0x81e5, 0x81e6, 0x81e7, 0x81e8, 0x81e9, 0x81ea,
+  0x81eb, 0x81ec, 0x81ed, 0x81ee, 0x81ef, 0x81f0, 0x81f1, 0x81f2,
+  0x81f3, 0x81f4, 0x81f5, 0x81f6, 0x81f7, 0x81f8, 0x81f9, 0x81fa,
+  0x81fb, 0x81fc, 0x81fd, 0x81fe, 0x8240, 0x8241, 0x8242, 0x8243,
+  0x8244, 0x8245, 0x8246, 0x8247, 0x8248, 0x8249, 0x824a, 0x824b,
+  0x824c, 0x824d, 0x824e, 0x824f, 0x8250, 0x8251, 0x8252, 0x8253,
+  0x8254, 0x8255, 0x8256, 0x8257, 0x8258, 0x8259, 0x825a, 0x825b,
+  0x825c, 0x825d, 0x825e, 0x825f, 0x8260, 0x8261, 0x8262, 0x8263,
+  0x8264, 0x8265, 0x8266, 0x8267, 0x8268, 0x8269, 0x826a, 0x826b,
+  0x826c, 0x826d, 0x826e, 0x826f, 0x8270, 0x8271, 0x8272, 0x8273,
+  0x8274, 0x8275, 0x8276, 0x8277, 0x8278, 0x8279, 0x827a, 0x827b,
+  0x827c, 0x827d, 0x827e, 0x8280, 0x8281, 0x8282, 0x8283, 0x8284,
+  0x8285, 0x8286, 0x8287, 0x8288, 0x8289, 0x828a, 0x828b, 0x828c,
+  0x828d, 0x828e, 0x828f, 0x8290, 0x8291, 0x8292, 0x8293, 0x8294,
+  0x8295, 0x8296, 0x8297, 0x8298, 0x8299, 0x829a, 0x829b, 0x829c,
+  0x829d, 0x829e, 0x829f, 0x82a0, 0x82a1, 0x82a2, 0x82a3, 0x82a4,
+  0x82a5, 0x82a6, 0x82a7, 0x82a8, 0x82a9, 0x82aa, 0x82ab, 0x82ac,
+  0x82ad, 0x82ae, 0x82af, 0x82b0, 0x82b1, 0x82b2, 0x82b3, 0x82b4,
+  0x82b5, 0x82b6, 0x82b7, 0x82b8, 0x82b9, 0x82ba, 0x82bb, 0x82bc,
+  0x82bd, 0x82be, 0x82bf, 0x82c0, 0x82c1, 0x82c2, 0x82c3, 0x82c4,
+  0x82c5, 0x82c6, 0x82c7, 0x82c8, 0x82c9, 0x82ca, 0x82cb, 0x82cc,
+  0x82cd, 0x82ce, 0x82cf, 0x82d0, 0x82d1, 0x82d2, 0x82d3, 0x82d4,
+  0x82d5, 0x82d6, 0x82d7, 0x82d8, 0x82d9, 0x82da, 0x82db, 0x82dc,
+  0x82dd, 0x82de, 0x82df, 0x82e0, 0x82e1, 0x82e2, 0x82e3, 0x82e4,
+  0x82e5, 0x82e6, 0x82e7, 0x82e8, 0x82e9, 0x82ea, 0x82eb, 0x82ec,
+  0x82ed, 0x82ee, 0x82ef, 0x82f0, 0x82f1, 0x82f2, 0x82f3, 0x82f4,
+  0x82f5, 0x82f6, 0x82f7, 0x82f8, 0x82f9, 0x82fa, 0x82fb, 0x82fc,
+  0x82fd, 0x82fe, 0x8340, 0x8341, 0x8342, 0x8343, 0x8344, 0x8345,
+  0x8346, 0x8347, 0x8348, 0x8349, 0x834a, 0x834b, 0x834c, 0x834d,
+  0x834e, 0x834f, 0x8350, 0x8351, 0x8352, 0x8353, 0x8354, 0x8355,
+  0x8356, 0x8357, 0x8358, 0x8359, 0x835a, 0x835b, 0x835c, 0x835d,
+  0x835e, 0x835f, 0x8360, 0x8361, 0x8362, 0x8363, 0x8364, 0x8365,
+  0x8366, 0x8367, 0x8368, 0x8369, 0x836a, 0x836b, 0x836c, 0x836d,
+  0x836e, 0x836f, 0x8370, 0x8371, 0x8372, 0x8373, 0x8374, 0x8375,
+  0x8376, 0x8377, 0x8378, 0x8379, 0x837a, 0x837b, 0x837c, 0x837d,
+  0x837e, 0x8380, 0x8381, 0x8382, 0x8383, 0x8384, 0x8385, 0x8386,
+  0x8387, 0x8388, 0x8389, 0x838a, 0x838b, 0x838c, 0x838d, 0x838e,
+  0x838f, 0x8390, 0x8391, 0x8392, 0x8393, 0x8394, 0x8395, 0x8396,
+  0x8397, 0x8398, 0x8399, 0x839a, 0x839b, 0x839c, 0x839d, 0x839e,
+  0x839f, 0x83a0, 0x83a1, 0x83a2, 0x83a3, 0x83a4, 0x83a5, 0x83a6,
+  0x83a7, 0x83a8, 0x83a9, 0x83aa, 0x83ab, 0x83ac, 0x83ad, 0x83ae,
+  0x83af, 0x83b0, 0x83b1, 0x83b2, 0x83b3, 0x83b4, 0x83b5, 0x83b6,
+  0x83b7, 0x83b8, 0x83b9, 0x83ba, 0x83bb, 0x83bc, 0x83bd, 0x83be,
+  0x83bf, 0x83c0, 0x83c1, 0x83c2, 0x83c3, 0x83c4, 0x83c5, 0x83c6,
+  0x83c7, 0x83c8, 0x83c9, 0x83ca, 0x83cb, 0x83cc, 0x83cd, 0x83ce,
+  0x83cf, 0x83d0, 0x83d1, 0x83d2, 0x83d3, 0x83d4, 0x83d5, 0x83d6,
+  0x83d7, 0x83d8, 0x83d9, 0x83da, 0x83db, 0x83dc, 0x83dd, 0x83de,
+  0x83df, 0x83e0, 0x83e1, 0x83e2, 0x83e3, 0x83e4, 0x83e5, 0x83e6,
+  0x83e7, 0x83e8, 0x83e9, 0x83ea, 0x83eb, 0x83ec, 0x83ed, 0x83ee,
+  0x83ef, 0x83f0, 0x83f1, 0x83f2, 0x83f3, 0x83f4, 0x83f5, 0x83f6,
+  0x83f7, 0x83f8, 0x83f9, 0x83fa, 0x83fb, 0x83fc, 0x83fd, 0x83fe,
+  0x8440, 0x8441, 0x8442, 0x8443, 0x8444, 0x8445, 0x8446, 0x8447,
+  0x8448, 0x8449, 0x844a, 0x844b, 0x844c, 0x844d, 0x844e, 0x844f,
+  0x8450, 0x8451, 0x8452, 0x8453, 0x8454, 0x8455, 0x8456, 0x8457,
+  0x8458, 0x8459, 0x845a, 0x845b, 0x845c, 0x845d, 0x845e, 0x845f,
+  0x8460, 0x8461, 0x8462, 0x8463, 0x8464, 0x8465, 0x8466, 0x8467,
+  0x8468, 0x8469, 0x846a, 0x846b, 0x846c, 0x846d, 0x846e, 0x846f,
+  0x8470, 0x8471, 0x8472, 0x8473, 0x8474, 0x8475, 0x8476, 0x8477,
+  0x8478, 0x8479, 0x847a, 0x847b, 0x847c, 0x847d, 0x847e, 0x8480,
+  0x8481, 0x8482, 0x8483, 0x8484, 0x8485, 0x8486, 0x8487, 0x8488,
+  0x8489, 0x848a, 0x848b, 0x848c, 0x848d, 0x848e, 0x848f, 0x8490,
+  0x8491, 0x8492, 0x8493, 0x8494, 0x8495, 0x8496, 0x8497, 0x8498,
+  0x8499, 0x849a, 0x849b, 0x849c, 0x849d, 0x849e, 0x849f, 0x84a0,
+  0x84a1, 0x84a2, 0x84a3, 0x84a4, 0x84a5, 0x84a6, 0x84a7, 0x84a8,
+  0x84a9, 0x84aa, 0x84ab, 0x84ac, 0x84ad, 0x84ae, 0x84af, 0x84b0,
+  0x84b1, 0x84b2, 0x84b3, 0x84b4, 0x84b5, 0x84b6, 0x84b7, 0x84b8,
+  0x84b9, 0x84ba, 0x84bb, 0x84bc, 0x84bd, 0x84be, 0x84bf, 0x84c0,
+  0x84c1, 0x84c2, 0x84c3, 0x84c4, 0x84c5, 0x84c6, 0x84c7, 0x84c8,
+  0x84c9, 0x84ca, 0x84cb, 0x84cc, 0x84cd, 0x84ce, 0x84cf, 0x84d0,
+  0x84d1, 0x84d2, 0x84d3, 0x84d4, 0x84d5, 0x84d6, 0x84d7, 0x84d8,
+  0x84d9, 0x84da, 0x84db, 0x84dc, 0x84dd, 0x84de, 0x84df, 0x84e0,
+  0x84e1, 0x84e2, 0x84e3, 0x84e4, 0x84e5, 0x84e6, 0x84e7, 0x84e8,
+  0x84e9, 0x84ea, 0x84eb, 0x84ec, 0x84ed, 0x84ee, 0x84ef, 0x84f0,
+  0x84f1, 0x84f2, 0x84f3, 0x84f4, 0x84f5, 0x84f6, 0x84f7, 0x84f8,
+  0x84f9, 0x84fa, 0x84fb, 0x84fc, 0x84fd, 0x84fe, 0x8540, 0x8541,
+  0x8542, 0x8543, 0x8544, 0x8545, 0x8546, 0x8547, 0x8548, 0x8549,
+  0x854a, 0x854b, 0x854c, 0x854d, 0x854e, 0x854f, 0x8550, 0x8551,
+  0x8552, 0x8553, 0x8554, 0x8555, 0x8556, 0x8557, 0x8558, 0x8559,
+  0x855a, 0x855b, 0x855c, 0x855d, 0x855e, 0x855f, 0x8560, 0x8561,
+  0x8562, 0x8563, 0x8564, 0x8565, 0x8566, 0x8567, 0x8568, 0x8569,
+  0x856a, 0x856b, 0x856c, 0x856d, 0x856e, 0x856f, 0x8570, 0x8571,
+  0x8572, 0x8573, 0x8574, 0x8575, 0x8576, 0x8577, 0x8578, 0x8579,
+  0x857a, 0x857b, 0x857c, 0x857d, 0x857e, 0x8580, 0x8581, 0x8582,
+  0x8583, 0x8584, 0x8585, 0x8586, 0x8587, 0x8588, 0x8589, 0x858a,
+  0x858b, 0x858c, 0x858d, 0x858e, 0x858f, 0x8590, 0x8591, 0x8592,
+  0x8593, 0x8594, 0x8595, 0x8596, 0x8597, 0x8598, 0x8599, 0x859a,
+  0x859b, 0x859c, 0x859d, 0x859e, 0x859f, 0x85a0, 0x85a1, 0x85a2,
+  0x85a3, 0x85a4, 0x85a5, 0x85a6, 0x85a7, 0x85a8, 0x85a9, 0x85aa,
+  0x85ab, 0x85ac, 0x85ad, 0x85ae, 0x85af, 0x85b0, 0x85b1, 0x85b2,
+  0x85b3, 0x85b4, 0x85b5, 0x85b6, 0x85b7, 0x85b8, 0x85b9, 0x85ba,
+  0x85bb, 0x85bc, 0x85bd, 0x85be, 0x85bf, 0x85c0, 0x85c1, 0x85c2,
+  0x85c3, 0x85c4, 0x85c5, 0x85c6, 0x85c7, 0x85c8, 0x85c9, 0x85ca,
+  0x85cb, 0x85cc, 0x85cd, 0x85ce, 0x85cf, 0x85d0, 0x85d1, 0x85d2,
+  0x85d3, 0x85d4, 0x85d5, 0x85d6, 0x85d7, 0x85d8, 0x85d9, 0x85da,
+  0x85db, 0x85dc, 0x85dd, 0x85de, 0x85df, 0x85e0, 0x85e1, 0x85e2,
+  0x85e3, 0x85e4, 0x85e5, 0x85e6, 0x85e7, 0x85e8, 0x85e9, 0x85ea,
+  0x85eb, 0x85ec, 0x85ed, 0x85ee, 0x85ef, 0x85f0, 0x85f1, 0x85f2,
+  0x85f3, 0x85f4, 0x85f5, 0x85f6, 0x85f7, 0x85f8, 0x85f9, 0x85fa,
+  0x85fb, 0x85fc, 0x85fd, 0x85fe, 0x8640, 0x8641, 0x8642, 0x8643,
+  0x8644, 0x8645, 0x8646, 0x8647, 0x8648, 0x8649, 0x864a, 0x864b,
+  0x864c, 0x864d, 0x864e, 0x864f, 0x8650, 0x8651, 0x8652, 0x8653,
+  0x8654, 0x8655, 0x8656, 0x8657, 0x8658, 0x8659, 0x865a, 0x865b,
+  0x865c, 0x865d, 0x865e, 0x865f, 0x8660, 0x8661, 0x8662, 0x8663,
+  0x8664, 0x8665, 0x8666, 0x8667, 0x8668, 0x8669, 0x866a, 0x866b,
+  0x866c, 0x866d, 0x866e, 0x866f, 0x8670, 0x8671, 0x8672, 0x8673,
+  0x8674, 0x8675, 0x8676, 0x8677, 0x8678, 0x8679, 0x867a, 0x867b,
+  0x867c, 0x867d, 0x867e, 0x8680, 0x8681, 0x8682, 0x8683, 0x8684,
+  0x8685, 0x8686, 0x8687, 0x8688, 0x8689, 0x868a, 0x868b, 0x868c,
+  0x868d, 0x868e, 0x868f, 0x8690, 0x8691, 0x8692, 0x8693, 0x8694,
+  0x8695, 0x8696, 0x8697, 0x8698, 0x8699, 0x869a, 0x869b, 0x869c,
+  0x869d, 0x869e, 0x869f, 0x86a0, 0x86a1, 0x86a2, 0x86a3, 0x86a4,
+  0x86a5, 0x86a6, 0x86a7, 0x86a8, 0x86a9, 0x86aa, 0x86ab, 0x86ac,
+  0x86ad, 0x86ae, 0x86af, 0x86b0, 0x86b1, 0x86b2, 0x86b3, 0x86b4,
+  0x86b5, 0x86b6, 0x86b7, 0x86b8, 0x86b9, 0x86ba, 0x86bb, 0x86bc,
+  0x86bd, 0x86be, 0x86bf, 0x86c0, 0x86c1, 0x86c2, 0x86c3, 0x86c4,
+  0x86c5, 0x86c6, 0x86c7, 0x86c8, 0x86c9, 0x86ca, 0x86cb, 0x86cc,
+  0x86cd, 0x86ce, 0x86cf, 0x86d0, 0x86d1, 0x86d2, 0x86d3, 0x86d4,
+  0x86d5, 0x86d6, 0x86d7, 0x86d8, 0x86d9, 0x86da, 0x86db, 0x86dc,
+  0x86dd, 0x86de, 0x86df, 0x86e0, 0x86e1, 0x86e2, 0x86e3, 0x86e4,
+  0x86e5, 0x86e6, 0x86e7, 0x86e8, 0x86e9, 0x86ea, 0x86eb, 0x86ec,
+  0x86ed, 0x86ee, 0x86ef, 0x86f0, 0x86f1, 0x86f2, 0x86f3, 0x86f4,
+  0x86f5, 0x86f6, 0x86f7, 0x86f8, 0x86f9, 0x86fa, 0x86fb, 0x86fc,
+  0x86fd, 0x86fe, 0x8740, 0x8741, 0x8742, 0x8743, 0x8744, 0x8745,
+  0x8746, 0x8747, 0x8748, 0x8749, 0x874a, 0x874b, 0x874c, 0x874d,
+  0x874e, 0x874f, 0x8750, 0x8751, 0x8752, 0x8753, 0x8754, 0x8755,
+  0x8756, 0x8757, 0x8758, 0x8759, 0x875a, 0x875b, 0x875c, 0x875d,
+  0x875e, 0x875f, 0x8760, 0x8761, 0x8762, 0x8763, 0x8764, 0x8765,
+  0x8766, 0x8767, 0x8768, 0x8769, 0x876a, 0x876b, 0x876c, 0x876d,
+  0x876e, 0x876f, 0x8770, 0x8771, 0x8772, 0x8773, 0x8774, 0x8775,
+  0x8776, 0x8777, 0x8778, 0x8779, 0x877a, 0x877b, 0x877c, 0x877d,
+  0x877e, 0x8780, 0x8781, 0x8782, 0x8783, 0x8784, 0x8785, 0x8786,
+  0x8787, 0x8788, 0x8789, 0x878a, 0x878b, 0x878c, 0x878d, 0x878e,
+  0x878f, 0x8790, 0x8791, 0x8792, 0x8793, 0x8794, 0x8795, 0x8796,
+  0x8797, 0x8798, 0x8799, 0x879a, 0x879b, 0x879c, 0x879d, 0x879e,
+  0x879f, 0x87a0, 0x87a1, 0x87a2, 0x87a3, 0x87a4, 0x87a5, 0x87a6,
+  0x87a7, 0x87a8, 0x87a9, 0x87aa, 0x87ab, 0x87ac, 0x87ad, 0x87ae,
+  0x87af, 0x87b0, 0x87b1, 0x87b2, 0x87b3, 0x87b4, 0x87b5, 0x87b6,
+  0x87b7, 0x87b8, 0x87b9, 0x87ba, 0x87bb, 0x87bc, 0x87bd, 0x87be,
+  0x87bf, 0x87c0, 0x87c1, 0x87c2, 0x87c3, 0x87c4, 0x87c5, 0x87c6,
+  0x87c7, 0x87c8, 0x87c9, 0x87ca, 0x87cb, 0x87cc, 0x87cd, 0x87ce,
+  0x87cf, 0x87d0, 0x87d1, 0x87d2, 0x87d3, 0x87d4, 0x87d5, 0x87d6,
+  0x87d7, 0x87d8, 0x87d9, 0x87da, 0x87db, 0x87dc, 0x87dd, 0x87de,
+  0x87df, 0x87e0, 0x87e1, 0x87e2, 0x87e3, 0x87e4, 0x87e5, 0x87e6,
+  0x87e7, 0x87e8, 0x87e9, 0x87ea, 0x87eb, 0x87ec, 0x87ed, 0x87ee,
+  0x87ef, 0x87f0, 0x87f1, 0x87f2, 0x87f3, 0x87f4, 0x87f5, 0x87f6,
+  0x87f7, 0x87f8, 0x87f9, 0x87fa, 0x87fb, 0x87fc, 0x87fd, 0x87fe,
+  0x8840, 0x8841, 0x8842, 0x8843, 0x8844, 0x8845, 0x8846, 0x8847,
+  0x8848, 0x8849, 0x884a, 0x884b, 0x884c, 0x884d, 0x884e, 0x884f,
+  0x8850, 0x8851, 0x8852, 0x8853, 0x8854, 0x8855, 0x8856, 0x8857,
+  0x8858, 0x8859, 0x885a, 0x885b, 0x885c, 0x885d, 0x885e, 0x885f,
+  0x8860, 0x8861, 0x8862, 0x8863, 0x8864, 0x8865, 0x8866, 0x8867,
+  0x8868, 0x8869, 0x886a, 0x886b, 0x886c, 0x886d, 0x886e, 0x886f,
+  0x8870, 0x8871, 0x8872, 0x8873, 0x8874, 0x8875, 0x8876, 0x8877,
+  0x8878, 0x8879, 0x887a, 0x887b, 0x887c, 0x887d, 0x887e, 0x8880,
+  0x8881, 0x8882, 0x8883, 0x8884, 0x8885, 0x8886, 0x8887, 0x8888,
+  0x8889, 0x888a, 0x888b, 0x888c, 0x888d, 0x888e, 0x888f, 0x8890,
+  0x8891, 0x8892, 0x8893, 0x8894, 0x8895, 0x8896, 0x8897, 0x8898,
+  0x8899, 0x889a, 0x889b, 0x889c, 0x889d, 0x889e, 0x889f, 0x88a0,
+  0x88a1, 0x88a2, 0x88a3, 0x88a4, 0x88a5, 0x88a6, 0x88a7, 0x88a8,
+  0x88a9, 0x88aa, 0x88ab, 0x88ac, 0x88ad, 0x88ae, 0x88af, 0x88b0,
+  0x88b1, 0x88b2, 0x88b3, 0x88b4, 0x88b5, 0x88b6, 0x88b7, 0x88b8,
+  0x88b9, 0x88ba, 0x88bb, 0x88bc, 0x88bd, 0x88be, 0x88bf, 0x88c0,
+  0x88c1, 0x88c2, 0x88c3, 0x88c4, 0x88c5, 0x88c6, 0x88c7, 0x88c8,
+  0x88c9, 0x88ca, 0x88cb, 0x88cc, 0x88cd, 0x88ce, 0x88cf, 0x88d0,
+  0x88d1, 0x88d2, 0x88d3, 0x88d4, 0x88d5, 0x88d6, 0x88d7, 0x88d8,
+  0x88d9, 0x88da, 0x88db, 0x88dc, 0x88dd, 0x88de, 0x88df, 0x88e0,
+  0x88e1, 0x88e2, 0x88e3, 0x88e4, 0x88e5, 0x88e6, 0x88e7, 0x88e8,
+  0x88e9, 0x88ea, 0x88eb, 0x88ec, 0x88ed, 0x88ee, 0x88ef, 0x88f0,
+  0x88f1, 0x88f2, 0x88f3, 0x88f4, 0x88f5, 0x88f6, 0x88f7, 0x88f8,
+  0x88f9, 0x88fa, 0x88fb, 0x88fc, 0x88fd, 0x88fe, 0x8940, 0x8941,
+  0x8942, 0x8943, 0x8944, 0x8945, 0x8946, 0x8947, 0x8948, 0x8949,
+  0x894a, 0x894b, 0x894c, 0x894d, 0x894e, 0x894f, 0x8950, 0x8951,
+  0x8952, 0x8953, 0x8954, 0x8955, 0x8956, 0x8957, 0x8958, 0x8959,
+  0x895a, 0x895b, 0x895c, 0x895d, 0x895e, 0x895f, 0x8960, 0x8961,
+  0x8962, 0x8963, 0x8964, 0x8965, 0x8966, 0x8967, 0x8968, 0x8969,
+  0x896a, 0x896b, 0x896c, 0x896d, 0x896e, 0x896f, 0x8970, 0x8971,
+  0x8972, 0x8973, 0x8974, 0x8975, 0x8976, 0x8977, 0x8978, 0x8979,
+  0x897a, 0x897b, 0x897c, 0x897d, 0x897e, 0x8980, 0x8981, 0x8982,
+  0x8983, 0x8984, 0x8985, 0x8986, 0x8987, 0x8988, 0x8989, 0x898a,
+  0x898b, 0x898c, 0x898d, 0x898e, 0x898f, 0x8990, 0x8991, 0x8992,
+  0x8993, 0x8994, 0x8995, 0x8996, 0x8997, 0x8998, 0x8999, 0x899a,
+  0x899b, 0x899c, 0x899d, 0x899e, 0x899f, 0x89a0, 0x89a1, 0x89a2,
+  0x89a3, 0x89a4, 0x89a5, 0x89a6, 0x89a7, 0x89a8, 0x89a9, 0x89aa,
+  0x89ab, 0x89ac, 0x89ad, 0x89ae, 0x89af, 0x89b0, 0x89b1, 0x89b2,
+  0x89b3, 0x89b4, 0x89b5, 0x89b6, 0x89b7, 0x89b8, 0x89b9, 0x89ba,
+  0x89bb, 0x89bc, 0x89bd, 0x89be, 0x89bf, 0x89c0, 0x89c1, 0x89c2,
+  0x89c3, 0x89c4, 0x89c5, 0x89c6, 0x89c7, 0x89c8, 0x89c9, 0x89ca,
+  0x89cb, 0x89cc, 0x89cd, 0x89ce, 0x89cf, 0x89d0, 0x89d1, 0x89d2,
+  0x89d3, 0x89d4, 0x89d5, 0x89d6, 0x89d7, 0x89d8, 0x89d9, 0x89da,
+  0x89db, 0x89dc, 0x89dd, 0x89de, 0x89df, 0x89e0, 0x89e1, 0x89e2,
+  0x89e3, 0x89e4, 0x89e5, 0x89e6, 0x89e7, 0x89e8, 0x89e9, 0x89ea,
+  0x89eb, 0x89ec, 0x89ed, 0x89ee, 0x89ef, 0x89f0, 0x89f1, 0x89f2,
+  0x89f3, 0x89f4, 0x89f5, 0x89f6, 0x89f7, 0x89f8, 0x89f9, 0x89fa,
+  0x89fb, 0x89fc, 0x89fd, 0x89fe, 0x8a40, 0x8a41, 0x8a42, 0x8a43,
+  0x8a44, 0x8a45, 0x8a46, 0x8a47, 0x8a48, 0x8a49, 0x8a4a, 0x8a4b,
+  0x8a4c, 0x8a4d, 0x8a4e, 0x8a4f, 0x8a50, 0x8a51, 0x8a52, 0x8a53,
+  0x8a54, 0x8a55, 0x8a56, 0x8a57, 0x8a58, 0x8a59, 0x8a5a, 0x8a5b,
+  0x8a5c, 0x8a5d, 0x8a5e, 0x8a5f, 0x8a60, 0x8a61, 0x8a62, 0x8a63,
+  0x8a64, 0x8a65, 0x8a66, 0x8a67, 0x8a68, 0x8a69, 0x8a6a, 0x8a6b,
+  0x8a6c, 0x8a6d, 0x8a6e, 0x8a6f, 0x8a70, 0x8a71, 0x8a72, 0x8a73,
+  0x8a74, 0x8a75, 0x8a76, 0x8a77, 0x8a78, 0x8a79, 0x8a7a, 0x8a7b,
+  0x8a7c, 0x8a7d, 0x8a7e, 0x8a80, 0x8a81, 0x8a82, 0x8a83, 0x8a84,
+  0x8a85, 0x8a86, 0x8a87, 0x8a88, 0x8a89, 0x8a8a, 0x8a8b, 0x8a8c,
+  0x8a8d, 0x8a8e, 0x8a8f, 0x8a90, 0x8a91, 0x8a92, 0x8a93, 0x8a94,
+  0x8a95, 0x8a96, 0x8a97, 0x8a98, 0x8a99, 0x8a9a, 0x8a9b, 0x8a9c,
+  0x8a9d, 0x8a9e, 0x8a9f, 0x8aa0, 0x8aa1, 0x8aa2, 0x8aa3, 0x8aa4,
+  0x8aa5, 0x8aa6, 0x8aa7, 0x8aa8, 0x8aa9, 0x8aaa, 0x8aab, 0x8aac,
+  0x8aad, 0x8aae, 0x8aaf, 0x8ab0, 0x8ab1, 0x8ab2, 0x8ab3, 0x8ab4,
+  0x8ab5, 0x8ab6, 0x8ab7, 0x8ab8, 0x8ab9, 0x8aba, 0x8abb, 0x8abc,
+  0x8abd, 0x8abe, 0x8abf, 0x8ac0, 0x8ac1, 0x8ac2, 0x8ac3, 0x8ac4,
+  0x8ac5, 0x8ac6, 0x8ac7, 0x8ac8, 0x8ac9, 0x8aca, 0x8acb, 0x8acc,
+  0x8acd, 0x8ace, 0x8acf, 0x8ad0, 0x8ad1, 0x8ad2, 0x8ad3, 0x8ad4,
+  0x8ad5, 0x8ad6, 0x8ad7, 0x8ad8, 0x8ad9, 0x8ada, 0x8adb, 0x8adc,
+  0x8add, 0x8ade, 0x8adf, 0x8ae0, 0x8ae1, 0x8ae2, 0x8ae3, 0x8ae4,
+  0x8ae5, 0x8ae6, 0x8ae7, 0x8ae8, 0x8ae9, 0x8aea, 0x8aeb, 0x8aec,
+  0x8aed, 0x8aee, 0x8aef, 0x8af0, 0x8af1, 0x8af2, 0x8af3, 0x8af4,
+  0x8af5, 0x8af6, 0x8af7, 0x8af8, 0x8af9, 0x8afa, 0x8afb, 0x8afc,
+  0x8afd, 0x8afe, 0x8b40, 0x8b41, 0x8b42, 0x8b43, 0x8b44, 0x8b45,
+  0x8b46, 0x8b47, 0x8b48, 0x8b49, 0x8b4a, 0x8b4b, 0x8b4c, 0x8b4d,
+  0x8b4e, 0x8b4f, 0x8b50, 0x8b51, 0x8b52, 0x8b53, 0x8b54, 0x8b55,
+  0x8b56, 0x8b57, 0x8b58, 0x8b59, 0x8b5a, 0x8b5b, 0x8b5c, 0x8b5d,
+  0x8b5e, 0x8b5f, 0x8b60, 0x8b61, 0x8b62, 0x8b63, 0x8b64, 0x8b65,
+  0x8b66, 0x8b67, 0x8b68, 0x8b69, 0x8b6a, 0x8b6b, 0x8b6c, 0x8b6d,
+  0x8b6e, 0x8b6f, 0x8b70, 0x8b71, 0x8b72, 0x8b73, 0x8b74, 0x8b75,
+  0x8b76, 0x8b77, 0x8b78, 0x8b79, 0x8b7a, 0x8b7b, 0x8b7c, 0x8b7d,
+  0x8b7e, 0x8b80, 0x8b81, 0x8b82, 0x8b83, 0x8b84, 0x8b85, 0x8b86,
+  0x8b87, 0x8b88, 0x8b89, 0x8b8a, 0x8b8b, 0x8b8c, 0x8b8d, 0x8b8e,
+  0x8b8f, 0x8b90, 0x8b91, 0x8b92, 0x8b93, 0x8b94, 0x8b95, 0x8b96,
+  0x8b97, 0x8b98, 0x8b99, 0x8b9a, 0x8b9b, 0x8b9c, 0x8b9d, 0x8b9e,
+  0x8b9f, 0x8ba0, 0x8ba1, 0x8ba2, 0x8ba3, 0x8ba4, 0x8ba5, 0x8ba6,
+  0x8ba7, 0x8ba8, 0x8ba9, 0x8baa, 0x8bab, 0x8bac, 0x8bad, 0x8bae,
+  0x8baf, 0x8bb0, 0x8bb1, 0x8bb2, 0x8bb3, 0x8bb4, 0x8bb5, 0x8bb6,
+  0x8bb7, 0x8bb8, 0x8bb9, 0x8bba, 0x8bbb, 0x8bbc, 0x8bbd, 0x8bbe,
+  0x8bbf, 0x8bc0, 0x8bc1, 0x8bc2, 0x8bc3, 0x8bc4, 0x8bc5, 0x8bc6,
+  0x8bc7, 0x8bc8, 0x8bc9, 0x8bca, 0x8bcb, 0x8bcc, 0x8bcd, 0x8bce,
+  0x8bcf, 0x8bd0, 0x8bd1, 0x8bd2, 0x8bd3, 0x8bd4, 0x8bd5, 0x8bd6,
+  0x8bd7, 0x8bd8, 0x8bd9, 0x8bda, 0x8bdb, 0x8bdc, 0x8bdd, 0x8bde,
+  0x8bdf, 0x8be0, 0x8be1, 0x8be2, 0x8be3, 0x8be4, 0x8be5, 0x8be6,
+  0x8be7, 0x8be8, 0x8be9, 0x8bea, 0x8beb, 0x8bec, 0x8bed, 0x8bee,
+  0x8bef, 0x8bf0, 0x8bf1, 0x8bf2, 0x8bf3, 0x8bf4, 0x8bf5, 0x8bf6,
+  0x8bf7, 0x8bf8, 0x8bf9, 0x8bfa, 0x8bfb, 0x8bfc, 0x8bfd, 0x8bfe,
+  0x8c40, 0x8c41, 0x8c42, 0x8c43, 0x8c44, 0x8c45, 0x8c46, 0x8c47,
+  0x8c48, 0x8c49, 0x8c4a, 0x8c4b, 0x8c4c, 0x8c4d, 0x8c4e, 0x8c4f,
+  0x8c50, 0x8c51, 0x8c52, 0x8c53, 0x8c54, 0x8c55, 0x8c56, 0x8c57,
+  0x8c58, 0x8c59, 0x8c5a, 0x8c5b, 0x8c5c, 0x8c5d, 0x8c5e, 0x8c5f,
+  0x8c60, 0x8c61, 0x8c62, 0x8c63, 0x8c64, 0x8c65, 0x8c66, 0x8c67,
+  0x8c68, 0x8c69, 0x8c6a, 0x8c6b, 0x8c6c, 0x8c6d, 0x8c6e, 0x8c6f,
+  0x8c70, 0x8c71, 0x8c72, 0x8c73, 0x8c74, 0x8c75, 0x8c76, 0x8c77,
+  0x8c78, 0x8c79, 0x8c7a, 0x8c7b, 0x8c7c, 0x8c7d, 0x8c7e, 0x8c80,
+  0x8c81, 0x8c82, 0x8c83, 0x8c84, 0x8c85, 0x8c86, 0x8c87, 0x8c88,
+  0x8c89, 0x8c8a, 0x8c8b, 0x8c8c, 0x8c8d, 0x8c8e, 0x8c8f, 0x8c90,
+  0x8c91, 0x8c92, 0x8c93, 0x8c94, 0x8c95, 0x8c96, 0x8c97, 0x8c98,
+  0x8c99, 0x8c9a, 0x8c9b, 0x8c9c, 0x8c9d, 0x8c9e, 0x8c9f, 0x8ca0,
+  0x8ca1, 0x8ca2, 0x8ca3, 0x8ca4, 0x8ca5, 0x8ca6, 0x8ca7, 0x8ca8,
+  0x8ca9, 0x8caa, 0x8cab, 0x8cac, 0x8cad, 0x8cae, 0x8caf, 0x8cb0,
+  0x8cb1, 0x8cb2, 0x8cb3, 0x8cb4, 0x8cb5, 0x8cb6, 0x8cb7, 0x8cb8,
+  0x8cb9, 0x8cba, 0x8cbb, 0x8cbc, 0x8cbd, 0x8cbe, 0x8cbf, 0x8cc0,
+  0x8cc1, 0x8cc2, 0x8cc3, 0x8cc4, 0x8cc5, 0x8cc6, 0x8cc7, 0x8cc8,
+  0x8cc9, 0x8cca, 0x8ccb, 0x8ccc, 0x8ccd, 0x8cce, 0x8ccf, 0x8cd0,
+  0x8cd1, 0x8cd2, 0x8cd3, 0x8cd4, 0x8cd5, 0x8cd6, 0x8cd7, 0x8cd8,
+  0x8cd9, 0x8cda, 0x8cdb, 0x8cdc, 0x8cdd, 0x8cde, 0x8cdf, 0x8ce0,
+  0x8ce1, 0x8ce2, 0x8ce3, 0x8ce4, 0x8ce5, 0x8ce6, 0x8ce7, 0x8ce8,
+  0x8ce9, 0x8cea, 0x8ceb, 0x8cec, 0x8ced, 0x8cee, 0x8cef, 0x8cf0,
+  0x8cf1, 0x8cf2, 0x8cf3, 0x8cf4, 0x8cf5, 0x8cf6, 0x8cf7, 0x8cf8,
+  0x8cf9, 0x8cfa, 0x8cfb, 0x8cfc, 0x8cfd, 0x8cfe, 0x8d40, 0x8d41,
+  0x8d42, 0x8d43, 0x8d44, 0x8d45, 0x8d46, 0x8d47, 0x8d48, 0x8d49,
+  0x8d4a, 0x8d4b, 0x8d4c, 0x8d4d, 0x8d4e, 0x8d4f, 0x8d50, 0x8d51,
+  0x8d52, 0x8d53, 0x8d54, 0x8d55, 0x8d56, 0x8d57, 0x8d58, 0x8d59,
+  0x8d5a, 0x8d5b, 0x8d5c, 0x8d5d, 0x8d5e, 0x8d5f, 0x8d60, 0x8d61,
+  0x8d62, 0x8d63, 0x8d64, 0x8d65, 0x8d66, 0x8d67, 0x8d68, 0x8d69,
+  0x8d6a, 0x8d6b, 0x8d6c, 0x8d6d, 0x8d6e, 0x8d6f, 0x8d70, 0x8d71,
+  0x8d72, 0x8d73, 0x8d74, 0x8d75, 0x8d76, 0x8d77, 0x8d78, 0x8d79,
+  0x8d7a, 0x8d7b, 0x8d7c, 0x8d7d, 0x8d7e, 0x8d80, 0x8d81, 0x8d82,
+  0x8d83, 0x8d84, 0x8d85, 0x8d86, 0x8d87, 0x8d88, 0x8d89, 0x8d8a,
+  0x8d8b, 0x8d8c, 0x8d8d, 0x8d8e, 0x8d8f, 0x8d90, 0x8d91, 0x8d92,
+  0x8d93, 0x8d94, 0x8d95, 0x8d96, 0x8d97, 0x8d98, 0x8d99, 0x8d9a,
+  0x8d9b, 0x8d9c, 0x8d9d, 0x8d9e, 0x8d9f, 0x8da0, 0x8da1, 0x8da2,
+  0x8da3, 0x8da4, 0x8da5, 0x8da6, 0x8da7, 0x8da8, 0x8da9, 0x8daa,
+  0x8dab, 0x8dac, 0x8dad, 0x8dae, 0x8daf, 0x8db0, 0x8db1, 0x8db2,
+  0x8db3, 0x8db4, 0x8db5, 0x8db6, 0x8db7, 0x8db8, 0x8db9, 0x8dba,
+  0x8dbb, 0x8dbc, 0x8dbd, 0x8dbe, 0x8dbf, 0x8dc0, 0x8dc1, 0x8dc2,
+  0x8dc3, 0x8dc4, 0x8dc5, 0x8dc6, 0x8dc7, 0x8dc8, 0x8dc9, 0x8dca,
+  0x8dcb, 0x8dcc, 0x8dcd, 0x8dce, 0x8dcf, 0x8dd0, 0x8dd1, 0x8dd2,
+  0x8dd3, 0x8dd4, 0x8dd5, 0x8dd6, 0x8dd7, 0x8dd8, 0x8dd9, 0x8dda,
+  0x8ddb, 0x8ddc, 0x8ddd, 0x8dde, 0x8ddf, 0x8de0, 0x8de1, 0x8de2,
+  0x8de3, 0x8de4, 0x8de5, 0x8de6, 0x8de7, 0x8de8, 0x8de9, 0x8dea,
+  0x8deb, 0x8dec, 0x8ded, 0x8dee, 0x8def, 0x8df0, 0x8df1, 0x8df2,
+  0x8df3, 0x8df4, 0x8df5, 0x8df6, 0x8df7, 0x8df8, 0x8df9, 0x8dfa,
+  0x8dfb, 0x8dfc, 0x8dfd, 0x8dfe, 0x8e40, 0x8e41, 0x8e42, 0x8e43,
+  0x8e44, 0x8e45, 0x8e46, 0x8e47, 0x8e48, 0x8e49, 0x8e4a, 0x8e4b,
+  0x8e4c, 0x8e4d, 0x8e4e, 0x8e4f, 0x8e50, 0x8e51, 0x8e52, 0x8e53,
+  0x8e54, 0x8e55, 0x8e56, 0x8e57, 0x8e58, 0x8e59, 0x8e5a, 0x8e5b,
+  0x8e5c, 0x8e5d, 0x8e5e, 0x8e5f, 0x8e60, 0x8e61, 0x8e62, 0x8e63,
+  0x8e64, 0x8e65, 0x8e66, 0x8e67, 0x8e68, 0x8e69, 0x8e6a, 0x8e6b,
+  0x8e6c, 0x8e6d, 0x8e6e, 0x8e6f, 0x8e70, 0x8e71, 0x8e72, 0x8e73,
+  0x8e74, 0x8e75, 0x8e76, 0x8e77, 0x8e78, 0x8e79, 0x8e7a, 0x8e7b,
+  0x8e7c, 0x8e7d, 0x8e7e, 0x8e80, 0x8e81, 0x8e82, 0x8e83, 0x8e84,
+  0x8e85, 0x8e86, 0x8e87, 0x8e88, 0x8e89, 0x8e8a, 0x8e8b, 0x8e8c,
+  0x8e8d, 0x8e8e, 0x8e8f, 0x8e90, 0x8e91, 0x8e92, 0x8e93, 0x8e94,
+  0x8e95, 0x8e96, 0x8e97, 0x8e98, 0x8e99, 0x8e9a, 0x8e9b, 0x8e9c,
+  0x8e9d, 0x8e9e, 0x8e9f, 0x8ea0, 0x8ea1, 0x8ea2, 0x8ea3, 0x8ea4,
+  0x8ea5, 0x8ea6, 0x8ea7, 0x8ea8, 0x8ea9, 0x8eaa, 0x8eab, 0x8eac,
+  0x8ead, 0x8eae, 0x8eaf, 0x8eb0, 0x8eb1, 0x8eb2, 0x8eb3, 0x8eb4,
+  0x8eb5, 0x8eb6, 0x8eb7, 0x8eb8, 0x8eb9, 0x8eba, 0x8ebb, 0x8ebc,
+  0x8ebd, 0x8ebe, 0x8ebf, 0x8ec0, 0x8ec1, 0x8ec2, 0x8ec3, 0x8ec4,
+  0x8ec5, 0x8ec6, 0x8ec7, 0x8ec8, 0x8ec9, 0x8eca, 0x8ecb, 0x8ecc,
+  0x8ecd, 0x8ece, 0x8ecf, 0x8ed0, 0x8ed1, 0x8ed2, 0x8ed3, 0x8ed4,
+  0x8ed5, 0x8ed6, 0x8ed7, 0x8ed8, 0x8ed9, 0x8eda, 0x8edb, 0x8edc,
+  0x8edd, 0x8ede, 0x8edf, 0x8ee0, 0x8ee1, 0x8ee2, 0x8ee3, 0x8ee4,
+  0x8ee5, 0x8ee6, 0x8ee7, 0x8ee8, 0x8ee9, 0x8eea, 0x8eeb, 0x8eec,
+  0x8eed, 0x8eee, 0x8eef, 0x8ef0, 0x8ef1, 0x8ef2, 0x8ef3, 0x8ef4,
+  0x8ef5, 0x8ef6, 0x8ef7, 0x8ef8, 0x8ef9, 0x8efa, 0x8efb, 0x8efc,
+  0x8efd, 0x8efe, 0x8f40, 0x8f41, 0x8f42, 0x8f43, 0x8f44, 0x8f45,
+  0x8f46, 0x8f47, 0x8f48, 0x8f49, 0x8f4a, 0x8f4b, 0x8f4c, 0x8f4d,
+  0x8f4e, 0x8f4f, 0x8f50, 0x8f51, 0x8f52, 0x8f53, 0x8f54, 0x8f55,
+  0x8f56, 0x8f57, 0x8f58, 0x8f59, 0x8f5a, 0x8f5b, 0x8f5c, 0x8f5d,
+  0x8f5e, 0x8f5f, 0x8f60, 0x8f61, 0x8f62, 0x8f63, 0x8f64, 0x8f65,
+  0x8f66, 0x8f67, 0x8f68, 0x8f69, 0x8f6a, 0x8f6b, 0x8f6c, 0x8f6d,
+  0x8f6e, 0x8f6f, 0x8f70, 0x8f71, 0x8f72, 0x8f73, 0x8f74, 0x8f75,
+  0x8f76, 0x8f77, 0x8f78, 0x8f79, 0x8f7a, 0x8f7b, 0x8f7c, 0x8f7d,
+  0x8f7e, 0x8f80, 0x8f81, 0x8f82, 0x8f83, 0x8f84, 0x8f85, 0x8f86,
+  0x8f87, 0x8f88, 0x8f89, 0x8f8a, 0x8f8b, 0x8f8c, 0x8f8d, 0x8f8e,
+  0x8f8f, 0x8f90, 0x8f91, 0x8f92, 0x8f93, 0x8f94, 0x8f95, 0x8f96,
+  0x8f97, 0x8f98, 0x8f99, 0x8f9a, 0x8f9b, 0x8f9c, 0x8f9d, 0x8f9e,
+  0x8f9f, 0x8fa0, 0x8fa1, 0x8fa2, 0x8fa3, 0x8fa4, 0x8fa5, 0x8fa6,
+  0x8fa7, 0x8fa8, 0x8fa9, 0x8faa, 0x8fab, 0x8fac, 0x8fad, 0x8fae,
+  0x8faf, 0x8fb0, 0x8fb1, 0x8fb2, 0x8fb3, 0x8fb4, 0x8fb5, 0x8fb6,
+  0x8fb7, 0x8fb8, 0x8fb9, 0x8fba, 0x8fbb, 0x8fbc, 0x8fbd, 0x8fbe,
+  0x8fbf, 0x8fc0, 0x8fc1, 0x8fc2, 0x8fc3, 0x8fc4, 0x8fc5, 0x8fc6,
+  0x8fc7, 0x8fc8, 0x8fc9, 0x8fca, 0x8fcb, 0x8fcc, 0x8fcd, 0x8fce,
+  0x8fcf, 0x8fd0, 0x8fd1, 0x8fd2, 0x8fd3, 0x8fd4, 0x8fd5, 0x8fd6,
+  0x8fd7, 0x8fd8, 0x8fd9, 0x8fda, 0x8fdb, 0x8fdc, 0x8fdd, 0x8fde,
+  0x8fdf, 0x8fe0, 0x8fe1, 0x8fe2, 0x8fe3, 0x8fe4, 0x8fe5, 0x8fe6,
+  0x8fe7, 0x8fe8, 0x8fe9, 0x8fea, 0x8feb, 0x8fec, 0x8fed, 0x8fee,
+  0x8fef, 0x8ff0, 0x8ff1, 0x8ff2, 0x8ff3, 0x8ff4, 0x8ff5, 0x8ff6,
+  0x8ff7, 0x8ff8, 0x8ff9, 0x8ffa, 0x8ffb, 0x8ffc, 0x8ffd, 0x8ffe,
+  0x9040, 0x9041, 0x9042, 0x9043, 0x9044, 0x9045, 0x9046, 0x9047,
+  0x9048, 0x9049, 0x904a, 0x904b, 0x904c, 0x904d, 0x904e, 0x904f,
+  0x9050, 0x9051, 0x9052, 0x9053, 0x9054, 0x9055, 0x9056, 0x9057,
+  0x9058, 0x9059, 0x905a, 0x905b, 0x905c, 0x905d, 0x905e, 0x905f,
+  0x9060, 0x9061, 0x9062, 0x9063, 0x9064, 0x9065, 0x9066, 0x9067,
+  0x9068, 0x9069, 0x906a, 0x906b, 0x906c, 0x906d, 0x906e, 0x906f,
+  0x9070, 0x9071, 0x9072, 0x9073, 0x9074, 0x9075, 0x9076, 0x9077,
+  0x9078, 0x9079, 0x907a, 0x907b, 0x907c, 0x907d, 0x907e, 0x9080,
+  0x9081, 0x9082, 0x9083, 0x9084, 0x9085, 0x9086, 0x9087, 0x9088,
+  0x9089, 0x908a, 0x908b, 0x908c, 0x908d, 0x908e, 0x908f, 0x9090,
+  0x9091, 0x9092, 0x9093, 0x9094, 0x9095, 0x9096, 0x9097, 0x9098,
+  0x9099, 0x909a, 0x909b, 0x909c, 0x909d, 0x909e, 0x909f, 0x90a0,
+  0x90a1, 0x90a2, 0x90a3, 0x90a4, 0x90a5, 0x90a6, 0x90a7, 0x90a8,
+  0x90a9, 0x90aa, 0x90ab, 0x90ac, 0x90ad, 0x90ae, 0x90af, 0x90b0,
+  0x90b1, 0x90b2, 0x90b3, 0x90b4, 0x90b5, 0x90b6, 0x90b7, 0x90b8,
+  0x90b9, 0x90ba, 0x90bb, 0x90bc, 0x90bd, 0x90be, 0x90bf, 0x90c0,
+  0x90c1, 0x90c2, 0x90c3, 0x90c4, 0x90c5, 0x90c6, 0x90c7, 0x90c8,
+  0x90c9, 0x90ca, 0x90cb, 0x90cc, 0x90cd, 0x90ce, 0x90cf, 0x90d0,
+  0x90d1, 0x90d2, 0x90d3, 0x90d4, 0x90d5, 0x90d6, 0x90d7, 0x90d8,
+  0x90d9, 0x90da, 0x90db, 0x90dc, 0x90dd, 0x90de, 0x90df, 0x90e0,
+  0x90e1, 0x90e2, 0x90e3, 0x90e4, 0x90e5, 0x90e6, 0x90e7, 0x90e8,
+  0x90e9, 0x90ea, 0x90eb, 0x90ec, 0x90ed, 0x90ee, 0x90ef, 0x90f0,
+  0x90f1, 0x90f2, 0x90f3, 0x90f4, 0x90f5, 0x90f6, 0x90f7, 0x90f8,
+  0x90f9, 0x90fa, 0x90fb, 0x90fc, 0x90fd, 0x90fe, 0x9140, 0x9141,
+  0x9142, 0x9143, 0x9144, 0x9145, 0x9146, 0x9147, 0x9148, 0x9149,
+  0x914a, 0x914b, 0x914c, 0x914d, 0x914e, 0x914f, 0x9150, 0x9151,
+  0x9152, 0x9153, 0x9154, 0x9155, 0x9156, 0x9157, 0x9158, 0x9159,
+  0x915a, 0x915b, 0x915c, 0x915d, 0x915e, 0x915f, 0x9160, 0x9161,
+  0x9162, 0x9163, 0x9164, 0x9165, 0x9166, 0x9167, 0x9168, 0x9169,
+  0x916a, 0x916b, 0x916c, 0x916d, 0x916e, 0x916f, 0x9170, 0x9171,
+  0x9172, 0x9173, 0x9174, 0x9175, 0x9176, 0x9177, 0x9178, 0x9179,
+  0x917a, 0x917b, 0x917c, 0x917d, 0x917e, 0x9180, 0x9181, 0x9182,
+  0x9183, 0x9184, 0x9185, 0x9186, 0x9187, 0x9188, 0x9189, 0x918a,
+  0x918b, 0x918c, 0x918d, 0x918e, 0x918f, 0x9190, 0x9191, 0x9192,
+  0x9193, 0x9194, 0x9195, 0x9196, 0x9197, 0x9198, 0x9199, 0x919a,
+  0x919b, 0x919c, 0x919d, 0x919e, 0x919f, 0x91a0, 0x91a1, 0x91a2,
+  0x91a3, 0x91a4, 0x91a5, 0x91a6, 0x91a7, 0x91a8, 0x91a9, 0x91aa,
+  0x91ab, 0x91ac, 0x91ad, 0x91ae, 0x91af, 0x91b0, 0x91b1, 0x91b2,
+  0x91b3, 0x91b4, 0x91b5, 0x91b6, 0x91b7, 0x91b8, 0x91b9, 0x91ba,
+  0x91bb, 0x91bc, 0x91bd, 0x91be, 0x91bf, 0x91c0, 0x91c1, 0x91c2,
+  0x91c3, 0x91c4, 0x91c5, 0x91c6, 0x91c7, 0x91c8, 0x91c9, 0x91ca,
+  0x91cb, 0x91cc, 0x91cd, 0x91ce, 0x91cf, 0x91d0, 0x91d1, 0x91d2,
+  0x91d3, 0x91d4, 0x91d5, 0x91d6, 0x91d7, 0x91d8, 0x91d9, 0x91da,
+  0x91db, 0x91dc, 0x91dd, 0x91de, 0x91df, 0x91e0, 0x91e1, 0x91e2,
+  0x91e3, 0x91e4, 0x91e5, 0x91e6, 0x91e7, 0x91e8, 0x91e9, 0x91ea,
+  0x91eb, 0x91ec, 0x91ed, 0x91ee, 0x91ef, 0x91f0, 0x91f1, 0x91f2,
+  0x91f3, 0x91f4, 0x91f5, 0x91f6, 0x91f7, 0x91f8, 0x91f9, 0x91fa,
+  0x91fb, 0x91fc, 0x91fd, 0x91fe, 0x9240, 0x9241, 0x9242, 0x9243,
+  0x9244, 0x9245, 0x9246, 0x9247, 0x9248, 0x9249, 0x924a, 0x924b,
+  0x924c, 0x924d, 0x924e, 0x924f, 0x9250, 0x9251, 0x9252, 0x9253,
+  0x9254, 0x9255, 0x9256, 0x9257, 0x9258, 0x9259, 0x925a, 0x925b,
+  0x925c, 0x925d, 0x925e, 0x925f, 0x9260, 0x9261, 0x9262, 0x9263,
+  0x9264, 0x9265, 0x9266, 0x9267, 0x9268, 0x9269, 0x926a, 0x926b,
+  0x926c, 0x926d, 0x926e, 0x926f, 0x9270, 0x9271, 0x9272, 0x9273,
+  0x9274, 0x9275, 0x9276, 0x9277, 0x9278, 0x9279, 0x927a, 0x927b,
+  0x927c, 0x927d, 0x927e, 0x9280, 0x9281, 0x9282, 0x9283, 0x9284,
+  0x9285, 0x9286, 0x9287, 0x9288, 0x9289, 0x928a, 0x928b, 0x928c,
+  0x928d, 0x928e, 0x928f, 0x9290, 0x9291, 0x9292, 0x9293, 0x9294,
+  0x9295, 0x9296, 0x9297, 0x9298, 0x9299, 0x929a, 0x929b, 0x929c,
+  0x929d, 0x929e, 0x929f, 0x92a0, 0x92a1, 0x92a2, 0x92a3, 0x92a4,
+  0x92a5, 0x92a6, 0x92a7, 0x92a8, 0x92a9, 0x92aa, 0x92ab, 0x92ac,
+  0x92ad, 0x92ae, 0x92af, 0x92b0, 0x92b1, 0x92b2, 0x92b3, 0x92b4,
+  0x92b5, 0x92b6, 0x92b7, 0x92b8, 0x92b9, 0x92ba, 0x92bb, 0x92bc,
+  0x92bd, 0x92be, 0x92bf, 0x92c0, 0x92c1, 0x92c2, 0x92c3, 0x92c4,
+  0x92c5, 0x92c6, 0x92c7, 0x92c8, 0x92c9, 0x92ca, 0x92cb, 0x92cc,
+  0x92cd, 0x92ce, 0x92cf, 0x92d0, 0x92d1, 0x92d2, 0x92d3, 0x92d4,
+  0x92d5, 0x92d6, 0x92d7, 0x92d8, 0x92d9, 0x92da, 0x92db, 0x92dc,
+  0x92dd, 0x92de, 0x92df, 0x92e0, 0x92e1, 0x92e2, 0x92e3, 0x92e4,
+  0x92e5, 0x92e6, 0x92e7, 0x92e8, 0x92e9, 0x92ea, 0x92eb, 0x92ec,
+  0x92ed, 0x92ee, 0x92ef, 0x92f0, 0x92f1, 0x92f2, 0x92f3, 0x92f4,
+  0x92f5, 0x92f6, 0x92f7, 0x92f8, 0x92f9, 0x92fa, 0x92fb, 0x92fc,
+  0x92fd, 0x92fe, 0x9340, 0x9341, 0x9342, 0x9343, 0x9344, 0x9345,
+  0x9346, 0x9347, 0x9348, 0x9349, 0x934a, 0x934b, 0x934c, 0x934d,
+  0x934e, 0x934f, 0x9350, 0x9351, 0x9352, 0x9353, 0x9354, 0x9355,
+  0x9356, 0x9357, 0x9358, 0x9359, 0x935a, 0x935b, 0x935c, 0x935d,
+  0x935e, 0x935f, 0x9360, 0x9361, 0x9362, 0x9363, 0x9364, 0x9365,
+  0x9366, 0x9367, 0x9368, 0x9369, 0x936a, 0x936b, 0x936c, 0x936d,
+  0x936e, 0x936f, 0x9370, 0x9371, 0x9372, 0x9373, 0x9374, 0x9375,
+  0x9376, 0x9377, 0x9378, 0x9379, 0x937a, 0x937b, 0x937c, 0x937d,
+  0x937e, 0x9380, 0x9381, 0x9382, 0x9383, 0x9384, 0x9385, 0x9386,
+  0x9387, 0x9388, 0x9389, 0x938a, 0x938b, 0x938c, 0x938d, 0x938e,
+  0x938f, 0x9390, 0x9391, 0x9392, 0x9393, 0x9394, 0x9395, 0x9396,
+  0x9397, 0x9398, 0x9399, 0x939a, 0x939b, 0x939c, 0x939d, 0x939e,
+  0x939f, 0x93a0, 0x93a1, 0x93a2, 0x93a3, 0x93a4, 0x93a5, 0x93a6,
+  0x93a7, 0x93a8, 0x93a9, 0x93aa, 0x93ab, 0x93ac, 0x93ad, 0x93ae,
+  0x93af, 0x93b0, 0x93b1, 0x93b2, 0x93b3, 0x93b4, 0x93b5, 0x93b6,
+  0x93b7, 0x93b8, 0x93b9, 0x93ba, 0x93bb, 0x93bc, 0x93bd, 0x93be,
+  0x93bf, 0x93c0, 0x93c1, 0x93c2, 0x93c3, 0x93c4, 0x93c5, 0x93c6,
+  0x93c7, 0x93c8, 0x93c9, 0x93ca, 0x93cb, 0x93cc, 0x93cd, 0x93ce,
+  0x93cf, 0x93d0, 0x93d1, 0x93d2, 0x93d3, 0x93d4, 0x93d5, 0x93d6,
+  0x93d7, 0x93d8, 0x93d9, 0x93da, 0x93db, 0x93dc, 0x93dd, 0x93de,
+  0x93df, 0x93e0, 0x93e1, 0x93e2, 0x93e3, 0x93e4, 0x93e5, 0x93e6,
+  0x93e7, 0x93e8, 0x93e9, 0x93ea, 0x93eb, 0x93ec, 0x93ed, 0x93ee,
+  0x93ef, 0x93f0, 0x93f1, 0x93f2, 0x93f3, 0x93f4, 0x93f5, 0x93f6,
+  0x93f7, 0x93f8, 0x93f9, 0x93fa, 0x93fb, 0x93fc, 0x93fd, 0x93fe,
+  0x9440, 0x9441, 0x9442, 0x9443, 0x9444, 0x9445, 0x9446, 0x9447,
+  0x9448, 0x9449, 0x944a, 0x944b, 0x944c, 0x944d, 0x944e, 0x944f,
+  0x9450, 0x9451, 0x9452, 0x9453, 0x9454, 0x9455, 0x9456, 0x9457,
+  0x9458, 0x9459, 0x945a, 0x945b, 0x945c, 0x945d, 0x945e, 0x945f,
+  0x9460, 0x9461, 0x9462, 0x9463, 0x9464, 0x9465, 0x9466, 0x9467,
+  0x9468, 0x9469, 0x946a, 0x946b, 0x946c, 0x946d, 0x946e, 0x946f,
+  0x9470, 0x9471, 0x9472, 0x9473, 0x9474, 0x9475, 0x9476, 0x9477,
+  0x9478, 0x9479, 0x947a, 0x947b, 0x947c, 0x947d, 0x947e, 0x9480,
+  0x9481, 0x9482, 0x9483, 0x9484, 0x9485, 0x9486, 0x9487, 0x9488,
+  0x9489, 0x948a, 0x948b, 0x948c, 0x948d, 0x948e, 0x948f, 0x9490,
+  0x9491, 0x9492, 0x9493, 0x9494, 0x9495, 0x9496, 0x9497, 0x9498,
+  0x9499, 0x949a, 0x949b, 0x949c, 0x949d, 0x949e, 0x949f, 0x94a0,
+  0x94a1, 0x94a2, 0x94a3, 0x94a4, 0x94a5, 0x94a6, 0x94a7, 0x94a8,
+  0x94a9, 0x94aa, 0x94ab, 0x94ac, 0x94ad, 0x94ae, 0x94af, 0x94b0,
+  0x94b1, 0x94b2, 0x94b3, 0x94b4, 0x94b5, 0x94b6, 0x94b7, 0x94b8,
+  0x94b9, 0x94ba, 0x94bb, 0x94bc, 0x94bd, 0x94be, 0x94bf, 0x94c0,
+  0x94c1, 0x94c2, 0x94c3, 0x94c4, 0x94c5, 0x94c6, 0x94c7, 0x94c8,
+  0x94c9, 0x94ca, 0x94cb, 0x94cc, 0x94cd, 0x94ce, 0x94cf, 0x94d0,
+  0x94d1, 0x94d2, 0x94d3, 0x94d4, 0x94d5, 0x94d6, 0x94d7, 0x94d8,
+  0x94d9, 0x94da, 0x94db, 0x94dc, 0x94dd, 0x94de, 0x94df, 0x94e0,
+  0x94e1, 0x94e2, 0x94e3, 0x94e4, 0x94e5, 0x94e6, 0x94e7, 0x94e8,
+  0x94e9, 0x94ea, 0x94eb, 0x94ec, 0x94ed, 0x94ee, 0x94ef, 0x94f0,
+  0x94f1, 0x94f2, 0x94f3, 0x94f4, 0x94f5, 0x94f6, 0x94f7, 0x94f8,
+  0x94f9, 0x94fa, 0x94fb, 0x94fc, 0x94fd, 0x94fe, 0x9540, 0x9541,
+  0x9542, 0x9543, 0x9544, 0x9545, 0x9546, 0x9547, 0x9548, 0x9549,
+  0x954a, 0x954b, 0x954c, 0x954d, 0x954e, 0x954f, 0x9550, 0x9551,
+  0x9552, 0x9553, 0x9554, 0x9555, 0x9556, 0x9557, 0x9558, 0x9559,
+  0x955a, 0x955b, 0x955c, 0x955d, 0x955e, 0x955f, 0x9560, 0x9561,
+  0x9562, 0x9563, 0x9564, 0x9565, 0x9566, 0x9567, 0x9568, 0x9569,
+  0x956a, 0x956b, 0x956c, 0x956d, 0x956e, 0x956f, 0x9570, 0x9571,
+  0x9572, 0x9573, 0x9574, 0x9575, 0x9576, 0x9577, 0x9578, 0x9579,
+  0x957a, 0x957b, 0x957c, 0x957d, 0x957e, 0x9580, 0x9581, 0x9582,
+  0x9583, 0x9584, 0x9585, 0x9586, 0x9587, 0x9588, 0x9589, 0x958a,
+  0x958b, 0x958c, 0x958d, 0x958e, 0x958f, 0x9590, 0x9591, 0x9592,
+  0x9593, 0x9594, 0x9595, 0x9596, 0x9597, 0x9598, 0x9599, 0x959a,
+  0x959b, 0x959c, 0x959d, 0x959e, 0x959f, 0x95a0, 0x95a1, 0x95a2,
+  0x95a3, 0x95a4, 0x95a5, 0x95a6, 0x95a7, 0x95a8, 0x95a9, 0x95aa,
+  0x95ab, 0x95ac, 0x95ad, 0x95ae, 0x95af, 0x95b0, 0x95b1, 0x95b2,
+  0x95b3, 0x95b4, 0x95b5, 0x95b6, 0x95b7, 0x95b8, 0x95b9, 0x95ba,
+  0x95bb, 0x95bc, 0x95bd, 0x95be, 0x95bf, 0x95c0, 0x95c1, 0x95c2,
+  0x95c3, 0x95c4, 0x95c5, 0x95c6, 0x95c7, 0x95c8, 0x95c9, 0x95ca,
+  0x95cb, 0x95cc, 0x95cd, 0x95ce, 0x95cf, 0x95d0, 0x95d1, 0x95d2,
+  0x95d3, 0x95d4, 0x95d5, 0x95d6, 0x95d7, 0x95d8, 0x95d9, 0x95da,
+  0x95db, 0x95dc, 0x95dd, 0x95de, 0x95df, 0x95e0, 0x95e1, 0x95e2,
+  0x95e3, 0x95e4, 0x95e5, 0x95e6, 0x95e7, 0x95e8, 0x95e9, 0x95ea,
+  0x95eb, 0x95ec, 0x95ed, 0x95ee, 0x95ef, 0x95f0, 0x95f1, 0x95f2,
+  0x95f3, 0x95f4, 0x95f5, 0x95f6, 0x95f7, 0x95f8, 0x95f9, 0x95fa,
+  0x95fb, 0x95fc, 0x95fd, 0x95fe, 0x9640, 0x9641, 0x9642, 0x9643,
+  0x9644, 0x9645, 0x9646, 0x9647, 0x9648, 0x9649, 0x964a, 0x964b,
+  0x964c, 0x964d, 0x964e, 0x964f, 0x9650, 0x9651, 0x9652, 0x9653,
+  0x9654, 0x9655, 0x9656, 0x9657, 0x9658, 0x9659, 0x965a, 0x965b,
+  0x965c, 0x965d, 0x965e, 0x965f, 0x9660, 0x9661, 0x9662, 0x9663,
+  0x9664, 0x9665, 0x9666, 0x9667, 0x9668, 0x9669, 0x966a, 0x966b,
+  0x966c, 0x966d, 0x966e, 0x966f, 0x9670, 0x9671, 0x9672, 0x9673,
+  0x9674, 0x9675, 0x9676, 0x9677, 0x9678, 0x9679, 0x967a, 0x967b,
+  0x967c, 0x967d, 0x967e, 0x9680, 0x9681, 0x9682, 0x9683, 0x9684,
+  0x9685, 0x9686, 0x9687, 0x9688, 0x9689, 0x968a, 0x968b, 0x968c,
+  0x968d, 0x968e, 0x968f, 0x9690, 0x9691, 0x9692, 0x9693, 0x9694,
+  0x9695, 0x9696, 0x9697, 0x9698, 0x9699, 0x969a, 0x969b, 0x969c,
+  0x969d, 0x969e, 0x969f, 0x96a0, 0x96a1, 0x96a2, 0x96a3, 0x96a4,
+  0x96a5, 0x96a6, 0x96a7, 0x96a8, 0x96a9, 0x96aa, 0x96ab, 0x96ac,
+  0x96ad, 0x96ae, 0x96af, 0x96b0, 0x96b1, 0x96b2, 0x96b3, 0x96b4,
+  0x96b5, 0x96b6, 0x96b7, 0x96b8, 0x96b9, 0x96ba, 0x96bb, 0x96bc,
+  0x96bd, 0x96be, 0x96bf, 0x96c0, 0x96c1, 0x96c2, 0x96c3, 0x96c4,
+  0x96c5, 0x96c6, 0x96c7, 0x96c8, 0x96c9, 0x96ca, 0x96cb, 0x96cc,
+  0x96cd, 0x96ce, 0x96cf, 0x96d0, 0x96d1, 0x96d2, 0x96d3, 0x96d4,
+  0x96d5, 0x96d6, 0x96d7, 0x96d8, 0x96d9, 0x96da, 0x96db, 0x96dc,
+  0x96dd, 0x96de, 0x96df, 0x96e0, 0x96e1, 0x96e2, 0x96e3, 0x96e4,
+  0x96e5, 0x96e6, 0x96e7, 0x96e8, 0x96e9, 0x96ea, 0x96eb, 0x96ec,
+  0x96ed, 0x96ee, 0x96ef, 0x96f0, 0x96f1, 0x96f2, 0x96f3, 0x96f4,
+  0x96f5, 0x96f6, 0x96f7, 0x96f8, 0x96f9, 0x96fa, 0x96fb, 0x96fc,
+  0x96fd, 0x96fe, 0x9740, 0x9741, 0x9742, 0x9743, 0x9744, 0x9745,
+  0x9746, 0x9747, 0x9748, 0x9749, 0x974a, 0x974b, 0x974c, 0x974d,
+  0x974e, 0x974f, 0x9750, 0x9751, 0x9752, 0x9753, 0x9754, 0x9755,
+  0x9756, 0x9757, 0x9758, 0x9759, 0x975a, 0x975b, 0x975c, 0x975d,
+  0x975e, 0x975f, 0x9760, 0x9761, 0x9762, 0x9763, 0x9764, 0x9765,
+  0x9766, 0x9767, 0x9768, 0x9769, 0x976a, 0x976b, 0x976c, 0x976d,
+  0x976e, 0x976f, 0x9770, 0x9771, 0x9772, 0x9773, 0x9774, 0x9775,
+  0x9776, 0x9777, 0x9778, 0x9779, 0x977a, 0x977b, 0x977c, 0x977d,
+  0x977e, 0x9780, 0x9781, 0x9782, 0x9783, 0x9784, 0x9785, 0x9786,
+  0x9787, 0x9788, 0x9789, 0x978a, 0x978b, 0x978c, 0x978d, 0x978e,
+  0x978f, 0x9790, 0x9791, 0x9792, 0x9793, 0x9794, 0x9795, 0x9796,
+  0x9797, 0x9798, 0x9799, 0x979a, 0x979b, 0x979c, 0x979d, 0x979e,
+  0x979f, 0x97a0, 0x97a1, 0x97a2, 0x97a3, 0x97a4, 0x97a5, 0x97a6,
+  0x97a7, 0x97a8, 0x97a9, 0x97aa, 0x97ab, 0x97ac, 0x97ad, 0x97ae,
+  0x97af, 0x97b0, 0x97b1, 0x97b2, 0x97b3, 0x97b4, 0x97b5, 0x97b6,
+  0x97b7, 0x97b8, 0x97b9, 0x97ba, 0x97bb, 0x97bc, 0x97bd, 0x97be,
+  0x97bf, 0x97c0, 0x97c1, 0x97c2, 0x97c3, 0x97c4, 0x97c5, 0x97c6,
+  0x97c7, 0x97c8, 0x97c9, 0x97ca, 0x97cb, 0x97cc, 0x97cd, 0x97ce,
+  0x97cf, 0x97d0, 0x97d1, 0x97d2, 0x97d3, 0x97d4, 0x97d5, 0x97d6,
+  0x97d7, 0x97d8, 0x97d9, 0x97da, 0x97db, 0x97dc, 0x97dd, 0x97de,
+  0x97df, 0x97e0, 0x97e1, 0x97e2, 0x97e3, 0x97e4, 0x97e5, 0x97e6,
+  0x97e7, 0x97e8, 0x97e9, 0x97ea, 0x97eb, 0x97ec, 0x97ed, 0x97ee,
+  0x97ef, 0x97f0, 0x97f1, 0x97f2, 0x97f3, 0x97f4, 0x97f5, 0x97f6,
+  0x97f7, 0x97f8, 0x97f9, 0x97fa, 0x97fb, 0x97fc, 0x97fd, 0x97fe,
+  0x9840, 0x9841, 0x9842, 0x9843, 0x9844, 0x9845, 0x9846, 0x9847,
+  0x9848, 0x9849, 0x984a, 0x984b, 0x984c, 0x984d, 0x984e, 0x984f,
+  0x9850, 0x9851, 0x9852, 0x9853, 0x9854, 0x9855, 0x9856, 0x9857,
+  0x9858, 0x9859, 0x985a, 0x985b, 0x985c, 0x985d, 0x985e, 0x985f,
+  0x9860, 0x9861, 0x9862, 0x9863, 0x9864, 0x9865, 0x9866, 0x9867,
+  0x9868, 0x9869, 0x986a, 0x986b, 0x986c, 0x986d, 0x986e, 0x986f,
+  0x9870, 0x9871, 0x9872, 0x9873, 0x9874, 0x9875, 0x9876, 0x9877,
+  0x9878, 0x9879, 0x987a, 0x987b, 0x987c, 0x987d, 0x987e, 0x9880,
+  0x9881, 0x9882, 0x9883, 0x9884, 0x9885, 0x9886, 0x9887, 0x9888,
+  0x9889, 0x988a, 0x988b, 0x988c, 0x988d, 0x988e, 0x988f, 0x9890,
+  0x9891, 0x9892, 0x9893, 0x9894, 0x9895, 0x9896, 0x9897, 0x9898,
+  0x9899, 0x989a, 0x989b, 0x989c, 0x989d, 0x989e, 0x989f, 0x98a0,
+  0x98a1, 0x98a2, 0x98a3, 0x98a4, 0x98a5, 0x98a6, 0x98a7, 0x98a8,
+  0x98a9, 0x98aa, 0x98ab, 0x98ac, 0x98ad, 0x98ae, 0x98af, 0x98b0,
+  0x98b1, 0x98b2, 0x98b3, 0x98b4, 0x98b5, 0x98b6, 0x98b7, 0x98b8,
+  0x98b9, 0x98ba, 0x98bb, 0x98bc, 0x98bd, 0x98be, 0x98bf, 0x98c0,
+  0x98c1, 0x98c2, 0x98c3, 0x98c4, 0x98c5, 0x98c6, 0x98c7, 0x98c8,
+  0x98c9, 0x98ca, 0x98cb, 0x98cc, 0x98cd, 0x98ce, 0x98cf, 0x98d0,
+  0x98d1, 0x98d2, 0x98d3, 0x98d4, 0x98d5, 0x98d6, 0x98d7, 0x98d8,
+  0x98d9, 0x98da, 0x98db, 0x98dc, 0x98dd, 0x98de, 0x98df, 0x98e0,
+  0x98e1, 0x98e2, 0x98e3, 0x98e4, 0x98e5, 0x98e6, 0x98e7, 0x98e8,
+  0x98e9, 0x98ea, 0x98eb, 0x98ec, 0x98ed, 0x98ee, 0x98ef, 0x98f0,
+  0x98f1, 0x98f2, 0x98f3, 0x98f4, 0x98f5, 0x98f6, 0x98f7, 0x98f8,
+  0x98f9, 0x98fa, 0x98fb, 0x98fc, 0x98fd, 0x98fe, 0x9940, 0x9941,
+  0x9942, 0x9943, 0x9944, 0x9945, 0x9946, 0x9947, 0x9948, 0x9949,
+  0x994a, 0x994b, 0x994c, 0x994d, 0x994e, 0x994f, 0x9950, 0x9951,
+  0x9952, 0x9953, 0x9954, 0x9955, 0x9956, 0x9957, 0x9958, 0x9959,
+  0x995a, 0x995b, 0x995c, 0x995d, 0x995e, 0x995f, 0x9960, 0x9961,
+  0x9962, 0x9963, 0x9964, 0x9965, 0x9966, 0x9967, 0x9968, 0x9969,
+  0x996a, 0x996b, 0x996c, 0x996d, 0x996e, 0x996f, 0x9970, 0x9971,
+  0x9972, 0x9973, 0x9974, 0x9975, 0x9976, 0x9977, 0x9978, 0x9979,
+  0x997a, 0x997b, 0x997c, 0x997d, 0x997e, 0x9980, 0x9981, 0x9982,
+  0x9983, 0x9984, 0x9985, 0x9986, 0x9987, 0x9988, 0x9989, 0x998a,
+  0x998b, 0x998c, 0x998d, 0x998e, 0x998f, 0x9990, 0x9991, 0x9992,
+  0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998, 0x9999, 0x999a,
+  0x999b, 0x999c, 0x999d, 0x999e, 0x999f, 0x99a0, 0x99a1, 0x99a2,
+  0x99a3, 0x99a4, 0x99a5, 0x99a6, 0x99a7, 0x99a8, 0x99a9, 0x99aa,
+  0x99ab, 0x99ac, 0x99ad, 0x99ae, 0x99af, 0x99b0, 0x99b1, 0x99b2,
+  0x99b3, 0x99b4, 0x99b5, 0x99b6, 0x99b7, 0x99b8, 0x99b9, 0x99ba,
+  0x99bb, 0x99bc, 0x99bd, 0x99be, 0x99bf, 0x99c0, 0x99c1, 0x99c2,
+  0x99c3, 0x99c4, 0x99c5, 0x99c6, 0x99c7, 0x99c8, 0x99c9, 0x99ca,
+  0x99cb, 0x99cc, 0x99cd, 0x99ce, 0x99cf, 0x99d0, 0x99d1, 0x99d2,
+  0x99d3, 0x99d4, 0x99d5, 0x99d6, 0x99d7, 0x99d8, 0x99d9, 0x99da,
+  0x99db, 0x99dc, 0x99dd, 0x99de, 0x99df, 0x99e0, 0x99e1, 0x99e2,
+  0x99e3, 0x99e4, 0x99e5, 0x99e6, 0x99e7, 0x99e8, 0x99e9, 0x99ea,
+  0x99eb, 0x99ec, 0x99ed, 0x99ee, 0x99ef, 0x99f0, 0x99f1, 0x99f2,
+  0x99f3, 0x99f4, 0x99f5, 0x99f6, 0x99f7, 0x99f8, 0x99f9, 0x99fa,
+  0x99fb, 0x99fc, 0x99fd, 0x99fe, 0x9a40, 0x9a41, 0x9a42, 0x9a43,
+  0x9a44, 0x9a45, 0x9a46, 0x9a47, 0x9a48, 0x9a49, 0x9a4a, 0x9a4b,
+  0x9a4c, 0x9a4d, 0x9a4e, 0x9a4f, 0x9a50, 0x9a51, 0x9a52, 0x9a53,
+  0x9a54, 0x9a55, 0x9a56, 0x9a57, 0x9a58, 0x9a59, 0x9a5a, 0x9a5b,
+  0x9a5c, 0x9a5d, 0x9a5e, 0x9a5f, 0x9a60, 0x9a61, 0x9a62, 0x9a63,
+  0x9a64, 0x9a65, 0x9a66, 0x9a67, 0x9a68, 0x9a69, 0x9a6a, 0x9a6b,
+  0x9a6c, 0x9a6d, 0x9a6e, 0x9a6f, 0x9a70, 0x9a71, 0x9a72, 0x9a73,
+  0x9a74, 0x9a75, 0x9a76, 0x9a77, 0x9a78, 0x9a79, 0x9a7a, 0x9a7b,
+  0x9a7c, 0x9a7d, 0x9a7e, 0x9a80, 0x9a81, 0x9a82, 0x9a83, 0x9a84,
+  0x9a85, 0x9a86, 0x9a87, 0x9a88, 0x9a89, 0x9a8a, 0x9a8b, 0x9a8c,
+  0x9a8d, 0x9a8e, 0x9a8f, 0x9a90, 0x9a91, 0x9a92, 0x9a93, 0x9a94,
+  0x9a95, 0x9a96, 0x9a97, 0x9a98, 0x9a99, 0x9a9a, 0x9a9b, 0x9a9c,
+  0x9a9d, 0x9a9e, 0x9a9f, 0x9aa0, 0x9aa1, 0x9aa2, 0x9aa3, 0x9aa4,
+  0x9aa5, 0x9aa6, 0x9aa7, 0x9aa8, 0x9aa9, 0x9aaa, 0x9aab, 0x9aac,
+  0x9aad, 0x9aae, 0x9aaf, 0x9ab0, 0x9ab1, 0x9ab2, 0x9ab3, 0x9ab4,
+  0x9ab5, 0x9ab6, 0x9ab7, 0x9ab8, 0x9ab9, 0x9aba, 0x9abb, 0x9abc,
+  0x9abd, 0x9abe, 0x9abf, 0x9ac0, 0x9ac1, 0x9ac2, 0x9ac3, 0x9ac4,
+  0x9ac5, 0x9ac6, 0x9ac7, 0x9ac8, 0x9ac9, 0x9aca, 0x9acb, 0x9acc,
+  0x9acd, 0x9ace, 0x9acf, 0x9ad0, 0x9ad1, 0x9ad2, 0x9ad3, 0x9ad4,
+  0x9ad5, 0x9ad6, 0x9ad7, 0x9ad8, 0x9ad9, 0x9ada, 0x9adb, 0x9adc,
+  0x9add, 0x9ade, 0x9adf, 0x9ae0, 0x9ae1, 0x9ae2, 0x9ae3, 0x9ae4,
+  0x9ae5, 0x9ae6, 0x9ae7, 0x9ae8, 0x9ae9, 0x9aea, 0x9aeb, 0x9aec,
+  0x9aed, 0x9aee, 0x9aef, 0x9af0, 0x9af1, 0x9af2, 0x9af3, 0x9af4,
+  0x9af5, 0x9af6, 0x9af7, 0x9af8, 0x9af9, 0x9afa, 0x9afb, 0x9afc,
+  0x9afd, 0x9afe, 0x9b40, 0x9b41, 0x9b42, 0x9b43, 0x9b44, 0x9b45,
+  0x9b46, 0x9b47, 0x9b48, 0x9b49, 0x9b4a, 0x9b4b, 0x9b4c, 0x9b4d,
+  0x9b4e, 0x9b4f, 0x9b50, 0x9b51, 0x9b52, 0x9b53, 0x9b54, 0x9b55,
+  0x9b56, 0x9b57, 0x9b58, 0x9b59, 0x9b5a, 0x9b5b, 0x9b5c, 0x9b5d,
+  0x9b5e, 0x9b5f, 0x9b60, 0x9b61, 0x9b62, 0x9b63, 0x9b64, 0x9b65,
+  0x9b66, 0x9b67, 0x9b68, 0x9b69, 0x9b6a, 0x9b6b, 0x9b6c, 0x9b6d,
+  0x9b6e, 0x9b6f, 0x9b70, 0x9b71, 0x9b72, 0x9b73, 0x9b74, 0x9b75,
+  0x9b76, 0x9b77, 0x9b78, 0x9b79, 0x9b7a, 0x9b7b, 0x9b7c, 0x9b7d,
+  0x9b7e, 0x9b80, 0x9b81, 0x9b82, 0x9b83, 0x9b84, 0x9b85, 0x9b86,
+  0x9b87, 0x9b88, 0x9b89, 0x9b8a, 0x9b8b, 0x9b8c, 0x9b8d, 0x9b8e,
+  0x9b8f, 0x9b90, 0x9b91, 0x9b92, 0x9b93, 0x9b94, 0x9b95, 0x9b96,
+  0x9b97, 0x9b98, 0x9b99, 0x9b9a, 0x9b9b, 0x9b9c, 0x9b9d, 0x9b9e,
+  0x9b9f, 0x9ba0, 0x9ba1, 0x9ba2, 0x9ba3, 0x9ba4, 0x9ba5, 0x9ba6,
+  0x9ba7, 0x9ba8, 0x9ba9, 0x9baa, 0x9bab, 0x9bac, 0x9bad, 0x9bae,
+  0x9baf, 0x9bb0, 0x9bb1, 0x9bb2, 0x9bb3, 0x9bb4, 0x9bb5, 0x9bb6,
+  0x9bb7, 0x9bb8, 0x9bb9, 0x9bba, 0x9bbb, 0x9bbc, 0x9bbd, 0x9bbe,
+  0x9bbf, 0x9bc0, 0x9bc1, 0x9bc2, 0x9bc3, 0x9bc4, 0x9bc5, 0x9bc6,
+  0x9bc7, 0x9bc8, 0x9bc9, 0x9bca, 0x9bcb, 0x9bcc, 0x9bcd, 0x9bce,
+  0x9bcf, 0x9bd0, 0x9bd1, 0x9bd2, 0x9bd3, 0x9bd4, 0x9bd5, 0x9bd6,
+  0x9bd7, 0x9bd8, 0x9bd9, 0x9bda, 0x9bdb, 0x9bdc, 0x9bdd, 0x9bde,
+  0x9bdf, 0x9be0, 0x9be1, 0x9be2, 0x9be3, 0x9be4, 0x9be5, 0x9be6,
+  0x9be7, 0x9be8, 0x9be9, 0x9bea, 0x9beb, 0x9bec, 0x9bed, 0x9bee,
+  0x9bef, 0x9bf0, 0x9bf1, 0x9bf2, 0x9bf3, 0x9bf4, 0x9bf5, 0x9bf6,
+  0x9bf7, 0x9bf8, 0x9bf9, 0x9bfa, 0x9bfb, 0x9bfc, 0x9bfd, 0x9bfe,
+  0x9c40, 0x9c41, 0x9c42, 0x9c43, 0x9c44, 0x9c45, 0x9c46, 0x9c47,
+  0x9c48, 0x9c49, 0x9c4a, 0x9c4b, 0x9c4c, 0x9c4d, 0x9c4e, 0x9c4f,
+  0x9c50, 0x9c51, 0x9c52, 0x9c53, 0x9c54, 0x9c55, 0x9c56, 0x9c57,
+  0x9c58, 0x9c59, 0x9c5a, 0x9c5b, 0x9c5c, 0x9c5d, 0x9c5e, 0x9c5f,
+  0x9c60, 0x9c61, 0x9c62, 0x9c63, 0x9c64, 0x9c65, 0x9c66, 0x9c67,
+  0x9c68, 0x9c69, 0x9c6a, 0x9c6b, 0x9c6c, 0x9c6d, 0x9c6e, 0x9c6f,
+  0x9c70, 0x9c71, 0x9c72, 0x9c73, 0x9c74, 0x9c75, 0x9c76, 0x9c77,
+  0x9c78, 0x9c79, 0x9c7a, 0x9c7b, 0x9c7c, 0x9c7d, 0x9c7e, 0x9c80,
+  0x9c81, 0x9c82, 0x9c83, 0x9c84, 0x9c85, 0x9c86, 0x9c87, 0x9c88,
+  0x9c89, 0x9c8a, 0x9c8b, 0x9c8c, 0x9c8d, 0x9c8e, 0x9c8f, 0x9c90,
+  0x9c91, 0x9c92, 0x9c93, 0x9c94, 0x9c95, 0x9c96, 0x9c97, 0x9c98,
+  0x9c99, 0x9c9a, 0x9c9b, 0x9c9c, 0x9c9d, 0x9c9e, 0x9c9f, 0x9ca0,
+  0x9ca1, 0x9ca2, 0x9ca3, 0x9ca4, 0x9ca5, 0x9ca6, 0x9ca7, 0x9ca8,
+  0x9ca9, 0x9caa, 0x9cab, 0x9cac, 0x9cad, 0x9cae, 0x9caf, 0x9cb0,
+  0x9cb1, 0x9cb2, 0x9cb3, 0x9cb4, 0x9cb5, 0x9cb6, 0x9cb7, 0x9cb8,
+  0x9cb9, 0x9cba, 0x9cbb, 0x9cbc, 0x9cbd, 0x9cbe, 0x9cbf, 0x9cc0,
+  0x9cc1, 0x9cc2, 0x9cc3, 0x9cc4, 0x9cc5, 0x9cc6, 0x9cc7, 0x9cc8,
+  0x9cc9, 0x9cca, 0x9ccb, 0x9ccc, 0x9ccd, 0x9cce, 0x9ccf, 0x9cd0,
+  0x9cd1, 0x9cd2, 0x9cd3, 0x9cd4, 0x9cd5, 0x9cd6, 0x9cd7, 0x9cd8,
+  0x9cd9, 0x9cda, 0x9cdb, 0x9cdc, 0x9cdd, 0x9cde, 0x9cdf, 0x9ce0,
+  0x9ce1, 0x9ce2, 0x9ce3, 0x9ce4, 0x9ce5, 0x9ce6, 0x9ce7, 0x9ce8,
+  0x9ce9, 0x9cea, 0x9ceb, 0x9cec, 0x9ced, 0x9cee, 0x9cef, 0x9cf0,
+  0x9cf1, 0x9cf2, 0x9cf3, 0x9cf4, 0x9cf5, 0x9cf6, 0x9cf7, 0x9cf8,
+  0x9cf9, 0x9cfa, 0x9cfb, 0x9cfc, 0x9cfd, 0x9cfe, 0x9d40, 0x9d41,
+  0x9d42, 0x9d43, 0x9d44, 0x9d45, 0x9d46, 0x9d47, 0x9d48, 0x9d49,
+  0x9d4a, 0x9d4b, 0x9d4c, 0x9d4d, 0x9d4e, 0x9d4f, 0x9d50, 0x9d51,
+  0x9d52, 0x9d53, 0x9d54, 0x9d55, 0x9d56, 0x9d57, 0x9d58, 0x9d59,
+  0x9d5a, 0x9d5b, 0x9d5c, 0x9d5d, 0x9d5e, 0x9d5f, 0x9d60, 0x9d61,
+  0x9d62, 0x9d63, 0x9d64, 0x9d65, 0x9d66, 0x9d67, 0x9d68, 0x9d69,
+  0x9d6a, 0x9d6b, 0x9d6c, 0x9d6d, 0x9d6e, 0x9d6f, 0x9d70, 0x9d71,
+  0x9d72, 0x9d73, 0x9d74, 0x9d75, 0x9d76, 0x9d77, 0x9d78, 0x9d79,
+  0x9d7a, 0x9d7b, 0x9d7c, 0x9d7d, 0x9d7e, 0x9d80, 0x9d81, 0x9d82,
+  0x9d83, 0x9d84, 0x9d85, 0x9d86, 0x9d87, 0x9d88, 0x9d89, 0x9d8a,
+  0x9d8b, 0x9d8c, 0x9d8d, 0x9d8e, 0x9d8f, 0x9d90, 0x9d91, 0x9d92,
+  0x9d93, 0x9d94, 0x9d95, 0x9d96, 0x9d97, 0x9d98, 0x9d99, 0x9d9a,
+  0x9d9b, 0x9d9c, 0x9d9d, 0x9d9e, 0x9d9f, 0x9da0, 0x9da1, 0x9da2,
+  0x9da3, 0x9da4, 0x9da5, 0x9da6, 0x9da7, 0x9da8, 0x9da9, 0x9daa,
+  0x9dab, 0x9dac, 0x9dad, 0x9dae, 0x9daf, 0x9db0, 0x9db1, 0x9db2,
+  0x9db3, 0x9db4, 0x9db5, 0x9db6, 0x9db7, 0x9db8, 0x9db9, 0x9dba,
+  0x9dbb, 0x9dbc, 0x9dbd, 0x9dbe, 0x9dbf, 0x9dc0, 0x9dc1, 0x9dc2,
+  0x9dc3, 0x9dc4, 0x9dc5, 0x9dc6, 0x9dc7, 0x9dc8, 0x9dc9, 0x9dca,
+  0x9dcb, 0x9dcc, 0x9dcd, 0x9dce, 0x9dcf, 0x9dd0, 0x9dd1, 0x9dd2,
+  0x9dd3, 0x9dd4, 0x9dd5, 0x9dd6, 0x9dd7, 0x9dd8, 0x9dd9, 0x9dda,
+  0x9ddb, 0x9ddc, 0x9ddd, 0x9dde, 0x9ddf, 0x9de0, 0x9de1, 0x9de2,
+  0x9de3, 0x9de4, 0x9de5, 0x9de6, 0x9de7, 0x9de8, 0x9de9, 0x9dea,
+  0x9deb, 0x9dec, 0x9ded, 0x9dee, 0x9def, 0x9df0, 0x9df1, 0x9df2,
+  0x9df3, 0x9df4, 0x9df5, 0x9df6, 0x9df7, 0x9df8, 0x9df9, 0x9dfa,
+  0x9dfb, 0x9dfc, 0x9dfd, 0x9dfe, 0x9e40, 0x9e41, 0x9e42, 0x9e43,
+  0x9e44, 0x9e45, 0x9e46, 0x9e47, 0x9e48, 0x9e49, 0x9e4a, 0x9e4b,
+  0x9e4c, 0x9e4d, 0x9e4e, 0x9e4f, 0x9e50, 0x9e51, 0x9e52, 0x9e53,
+  0x9e54, 0x9e55, 0x9e56, 0x9e57, 0x9e58, 0x9e59, 0x9e5a, 0x9e5b,
+  0x9e5c, 0x9e5d, 0x9e5e, 0x9e5f, 0x9e60, 0x9e61, 0x9e62, 0x9e63,
+  0x9e64, 0x9e65, 0x9e66, 0x9e67, 0x9e68, 0x9e69, 0x9e6a, 0x9e6b,
+  0x9e6c, 0x9e6d, 0x9e6e, 0x9e6f, 0x9e70, 0x9e71, 0x9e72, 0x9e73,
+  0x9e74, 0x9e75, 0x9e76, 0x9e77, 0x9e78, 0x9e79, 0x9e7a, 0x9e7b,
+  0x9e7c, 0x9e7d, 0x9e7e, 0x9e80, 0x9e81, 0x9e82, 0x9e83, 0x9e84,
+  0x9e85, 0x9e86, 0x9e87, 0x9e88, 0x9e89, 0x9e8a, 0x9e8b, 0x9e8c,
+  0x9e8d, 0x9e8e, 0x9e8f, 0x9e90, 0x9e91, 0x9e92, 0x9e93, 0x9e94,
+  0x9e95, 0x9e96, 0x9e97, 0x9e98, 0x9e99, 0x9e9a, 0x9e9b, 0x9e9c,
+  0x9e9d, 0x9e9e, 0x9e9f, 0x9ea0, 0x9ea1, 0x9ea2, 0x9ea3, 0x9ea4,
+  0x9ea5, 0x9ea6, 0x9ea7, 0x9ea8, 0x9ea9, 0x9eaa, 0x9eab, 0x9eac,
+  0x9ead, 0x9eae, 0x9eaf, 0x9eb0, 0x9eb1, 0x9eb2, 0x9eb3, 0x9eb4,
+  0x9eb5, 0x9eb6, 0x9eb7, 0x9eb8, 0x9eb9, 0x9eba, 0x9ebb, 0x9ebc,
+  0x9ebd, 0x9ebe, 0x9ebf, 0x9ec0, 0x9ec1, 0x9ec2, 0x9ec3, 0x9ec4,
+  0x9ec5, 0x9ec6, 0x9ec7, 0x9ec8, 0x9ec9, 0x9eca, 0x9ecb, 0x9ecc,
+  0x9ecd, 0x9ece, 0x9ecf, 0x9ed0, 0x9ed1, 0x9ed2, 0x9ed3, 0x9ed4,
+  0x9ed5, 0x9ed6, 0x9ed7, 0x9ed8, 0x9ed9, 0x9eda, 0x9edb, 0x9edc,
+  0x9edd, 0x9ede, 0x9edf, 0x9ee0, 0x9ee1, 0x9ee2, 0x9ee3, 0x9ee4,
+  0x9ee5, 0x9ee6, 0x9ee7, 0x9ee8, 0x9ee9, 0x9eea, 0x9eeb, 0x9eec,
+  0x9eed, 0x9eee, 0x9eef, 0x9ef0, 0x9ef1, 0x9ef2, 0x9ef3, 0x9ef4,
+  0x9ef5, 0x9ef6, 0x9ef7, 0x9ef8, 0x9ef9, 0x9efa, 0x9efb, 0x9efc,
+  0x9efd, 0x9efe, 0x9f40, 0x9f41, 0x9f42, 0x9f43, 0x9f44, 0x9f45,
+  0x9f46, 0x9f47, 0x9f48, 0x9f49, 0x9f4a, 0x9f4b, 0x9f4c, 0x9f4d,
+  0x9f4e, 0x9f4f, 0x9f50, 0x9f51, 0x9f52, 0x9f53, 0x9f54, 0x9f55,
+  0x9f56, 0x9f57, 0x9f58, 0x9f59, 0x9f5a, 0x9f5b, 0x9f5c, 0x9f5d,
+  0x9f5e, 0x9f5f, 0x9f60, 0x9f61, 0x9f62, 0x9f63, 0x9f64, 0x9f65,
+  0x9f66, 0x9f67, 0x9f68, 0x9f69, 0x9f6a, 0x9f6b, 0x9f6c, 0x9f6d,
+  0x9f6e, 0x9f6f, 0x9f70, 0x9f71, 0x9f72, 0x9f73, 0x9f74, 0x9f75,
+  0x9f76, 0x9f77, 0x9f78, 0x9f79, 0x9f7a, 0x9f7b, 0x9f7c, 0x9f7d,
+  0x9f7e, 0x9f80, 0x9f81, 0x9f82, 0x9f83, 0x9f84, 0x9f85, 0x9f86,
+  0x9f87, 0x9f88, 0x9f89, 0x9f8a, 0x9f8b, 0x9f8c, 0x9f8d, 0x9f8e,
+  0x9f8f, 0x9f90, 0x9f91, 0x9f92, 0x9f93, 0x9f94, 0x9f95, 0x9f96,
+  0x9f97, 0x9f98, 0x9f99, 0x9f9a, 0x9f9b, 0x9f9c, 0x9f9d, 0x9f9e,
+  0x9f9f, 0x9fa0, 0x9fa1, 0x9fa2, 0x9fa3, 0x9fa4, 0x9fa5, 0x9fa6,
+  0x9fa7, 0x9fa8, 0x9fa9, 0x9faa, 0x9fab, 0x9fac, 0x9fad, 0x9fae,
+  0x9faf, 0x9fb0, 0x9fb1, 0x9fb2, 0x9fb3, 0x9fb4, 0x9fb5, 0x9fb6,
+  0x9fb7, 0x9fb8, 0x9fb9, 0x9fba, 0x9fbb, 0x9fbc, 0x9fbd, 0x9fbe,
+  0x9fbf, 0x9fc0, 0x9fc1, 0x9fc2, 0x9fc3, 0x9fc4, 0x9fc5, 0x9fc6,
+  0x9fc7, 0x9fc8, 0x9fc9, 0x9fca, 0x9fcb, 0x9fcc, 0x9fcd, 0x9fce,
+  0x9fcf, 0x9fd0, 0x9fd1, 0x9fd2, 0x9fd3, 0x9fd4, 0x9fd5, 0x9fd6,
+  0x9fd7, 0x9fd8, 0x9fd9, 0x9fda, 0x9fdb, 0x9fdc, 0x9fdd, 0x9fde,
+  0x9fdf, 0x9fe0, 0x9fe1, 0x9fe2, 0x9fe3, 0x9fe4, 0x9fe5, 0x9fe6,
+  0x9fe7, 0x9fe8, 0x9fe9, 0x9fea, 0x9feb, 0x9fec, 0x9fed, 0x9fee,
+  0x9fef, 0x9ff0, 0x9ff1, 0x9ff2, 0x9ff3, 0x9ff4, 0x9ff5, 0x9ff6,
+  0x9ff7, 0x9ff8, 0x9ff9, 0x9ffa, 0x9ffb, 0x9ffc, 0x9ffd, 0x9ffe,
+  0xa040, 0xa041, 0xa042, 0xa043, 0xa044, 0xa045, 0xa046, 0xa047,
+  0xa048, 0xa049, 0xa04a, 0xa04b, 0xa04c, 0xa04d, 0xa04e, 0xa04f,
+  0xa050, 0xa051, 0xa052, 0xa053, 0xa054, 0xa055, 0xa056, 0xa057,
+  0xa058, 0xa059, 0xa05a, 0xa05b, 0xa05c, 0xa05d, 0xa05e, 0xa05f,
+  0xa060, 0xa061, 0xa062, 0xa063, 0xa064, 0xa065, 0xa066, 0xa067,
+  0xa068, 0xa069, 0xa06a, 0xa06b, 0xa06c, 0xa06d, 0xa06e, 0xa06f,
+  0xa070, 0xa071, 0xa072, 0xa073, 0xa074, 0xa075, 0xa076, 0xa077,
+  0xa078, 0xa079, 0xa07a, 0xa07b, 0xa07c, 0xa07d, 0xa07e, 0xa080,
+  0xa081, 0xa082, 0xa083, 0xa084, 0xa085, 0xa086, 0xa087, 0xa088,
+  0xa089, 0xa08a, 0xa08b, 0xa08c, 0xa08d, 0xa08e, 0xa08f, 0xa090,
+  0xa091, 0xa092, 0xa093, 0xa094, 0xa095, 0xa096, 0xa097, 0xa098,
+  0xa099, 0xa09a, 0xa09b, 0xa09c, 0xa09d, 0xa09e, 0xa09f, 0xa0a0,
+  0xa0a1, 0xa0a2, 0xa0a3, 0xa0a4, 0xa0a5, 0xa0a6, 0xa0a7, 0xa0a8,
+  0xa0a9, 0xa0aa, 0xa0ab, 0xa0ac, 0xa0ad, 0xa0ae, 0xa0af, 0xa0b0,
+  0xa0b1, 0xa0b2, 0xa0b3, 0xa0b4, 0xa0b5, 0xa0b6, 0xa0b7, 0xa0b8,
+  0xa0b9, 0xa0ba, 0xa0bb, 0xa0bc, 0xa0bd, 0xa0be, 0xa0bf, 0xa0c0,
+  0xa0c1, 0xa0c2, 0xa0c3, 0xa0c4, 0xa0c5, 0xa0c6, 0xa0c7, 0xa0c8,
+  0xa0c9, 0xa0ca, 0xa0cb, 0xa0cc, 0xa0cd, 0xa0ce, 0xa0cf, 0xa0d0,
+  0xa0d1, 0xa0d2, 0xa0d3, 0xa0d4, 0xa0d5, 0xa0d6, 0xa0d7, 0xa0d8,
+  0xa0d9, 0xa0da, 0xa0db, 0xa0dc, 0xa0dd, 0xa0de, 0xa0df, 0xa0e0,
+  0xa0e1, 0xa0e2, 0xa0e3, 0xa0e4, 0xa0e5, 0xa0e6, 0xa0e7, 0xa0e8,
+  0xa0e9, 0xa0ea, 0xa0eb, 0xa0ec, 0xa0ed, 0xa0ee, 0xa0ef, 0xa0f0,
+  0xa0f1, 0xa0f2, 0xa0f3, 0xa0f4, 0xa0f5, 0xa0f6, 0xa0f7, 0xa0f8,
+  0xa0f9, 0xa0fa, 0xa0fb, 0xa0fc, 0xa0fd, 0xa0fe, 0xaa40, 0xaa41,
+  0xaa42, 0xaa43, 0xaa44, 0xaa45, 0xaa46, 0xaa47, 0xaa48, 0xaa49,
+  0xaa4a, 0xaa4b, 0xaa4c, 0xaa4d, 0xaa4e, 0xaa4f, 0xaa50, 0xaa51,
+  0xaa52, 0xaa53, 0xaa54, 0xaa55, 0xaa56, 0xaa57, 0xaa58, 0xaa59,
+  0xaa5a, 0xaa5b, 0xaa5c, 0xaa5d, 0xaa5e, 0xaa5f, 0xaa60, 0xaa61,
+  0xaa62, 0xaa63, 0xaa64, 0xaa65, 0xaa66, 0xaa67, 0xaa68, 0xaa69,
+  0xaa6a, 0xaa6b, 0xaa6c, 0xaa6d, 0xaa6e, 0xaa6f, 0xaa70, 0xaa71,
+  0xaa72, 0xaa73, 0xaa74, 0xaa75, 0xaa76, 0xaa77, 0xaa78, 0xaa79,
+  0xaa7a, 0xaa7b, 0xaa7c, 0xaa7d, 0xaa7e, 0xaa80, 0xaa81, 0xaa82,
+  0xaa83, 0xaa84, 0xaa85, 0xaa86, 0xaa87, 0xaa88, 0xaa89, 0xaa8a,
+  0xaa8b, 0xaa8c, 0xaa8d, 0xaa8e, 0xaa8f, 0xaa90, 0xaa91, 0xaa92,
+  0xaa93, 0xaa94, 0xaa95, 0xaa96, 0xaa97, 0xaa98, 0xaa99, 0xaa9a,
+  0xaa9b, 0xaa9c, 0xaa9d, 0xaa9e, 0xaa9f, 0xaaa0, 0xab40, 0xab41,
+  0xab42, 0xab43, 0xab44, 0xab45, 0xab46, 0xab47, 0xab48, 0xab49,
+  0xab4a, 0xab4b, 0xab4c, 0xab4d, 0xab4e, 0xab4f, 0xab50, 0xab51,
+  0xab52, 0xab53, 0xab54, 0xab55, 0xab56, 0xab57, 0xab58, 0xab59,
+  0xab5a, 0xab5b, 0xab5c, 0xab5d, 0xab5e, 0xab5f, 0xab60, 0xab61,
+  0xab62, 0xab63, 0xab64, 0xab65, 0xab66, 0xab67, 0xab68, 0xab69,
+  0xab6a, 0xab6b, 0xab6c, 0xab6d, 0xab6e, 0xab6f, 0xab70, 0xab71,
+  0xab72, 0xab73, 0xab74, 0xab75, 0xab76, 0xab77, 0xab78, 0xab79,
+  0xab7a, 0xab7b, 0xab7c, 0xab7d, 0xab7e, 0xab80, 0xab81, 0xab82,
+  0xab83, 0xab84, 0xab85, 0xab86, 0xab87, 0xab88, 0xab89, 0xab8a,
+  0xab8b, 0xab8c, 0xab8d, 0xab8e, 0xab8f, 0xab90, 0xab91, 0xab92,
+  0xab93, 0xab94, 0xab95, 0xab96, 0xab97, 0xab98, 0xab99, 0xab9a,
+  0xab9b, 0xab9c, 0xab9d, 0xab9e, 0xab9f, 0xaba0, 0xac40, 0xac41,
+  0xac42, 0xac43, 0xac44, 0xac45, 0xac46, 0xac47, 0xac48, 0xac49,
+  0xac4a, 0xac4b, 0xac4c, 0xac4d, 0xac4e, 0xac4f, 0xac50, 0xac51,
+  0xac52, 0xac53, 0xac54, 0xac55, 0xac56, 0xac57, 0xac58, 0xac59,
+  0xac5a, 0xac5b, 0xac5c, 0xac5d, 0xac5e, 0xac5f, 0xac60, 0xac61,
+  0xac62, 0xac63, 0xac64, 0xac65, 0xac66, 0xac67, 0xac68, 0xac69,
+  0xac6a, 0xac6b, 0xac6c, 0xac6d, 0xac6e, 0xac6f, 0xac70, 0xac71,
+  0xac72, 0xac73, 0xac74, 0xac75, 0xac76, 0xac77, 0xac78, 0xac79,
+  0xac7a, 0xac7b, 0xac7c, 0xac7d, 0xac7e, 0xac80, 0xac81, 0xac82,
+  0xac83, 0xac84, 0xac85, 0xac86, 0xac87, 0xac88, 0xac89, 0xac8a,
+  0xac8b, 0xac8c, 0xac8d, 0xac8e, 0xac8f, 0xac90, 0xac91, 0xac92,
+  0xac93, 0xac94, 0xac95, 0xac96, 0xac97, 0xac98, 0xac99, 0xac9a,
+  0xac9b, 0xac9c, 0xac9d, 0xac9e, 0xac9f, 0xaca0, 0xad40, 0xad41,
+  0xad42, 0xad43, 0xad44, 0xad45, 0xad46, 0xad47, 0xad48, 0xad49,
+  0xad4a, 0xad4b, 0xad4c, 0xad4d, 0xad4e, 0xad4f, 0xad50, 0xad51,
+  0xad52, 0xad53, 0xad54, 0xad55, 0xad56, 0xad57, 0xad58, 0xad59,
+  0xad5a, 0xad5b, 0xad5c, 0xad5d, 0xad5e, 0xad5f, 0xad60, 0xad61,
+  0xad62, 0xad63, 0xad64, 0xad65, 0xad66, 0xad67, 0xad68, 0xad69,
+  0xad6a, 0xad6b, 0xad6c, 0xad6d, 0xad6e, 0xad6f, 0xad70, 0xad71,
+  0xad72, 0xad73, 0xad74, 0xad75, 0xad76, 0xad77, 0xad78, 0xad79,
+  0xad7a, 0xad7b, 0xad7c, 0xad7d, 0xad7e, 0xad80, 0xad81, 0xad82,
+  0xad83, 0xad84, 0xad85, 0xad86, 0xad87, 0xad88, 0xad89, 0xad8a,
+  0xad8b, 0xad8c, 0xad8d, 0xad8e, 0xad8f, 0xad90, 0xad91, 0xad92,
+  0xad93, 0xad94, 0xad95, 0xad96, 0xad97, 0xad98, 0xad99, 0xad9a,
+  0xad9b, 0xad9c, 0xad9d, 0xad9e, 0xad9f, 0xada0, 0xae40, 0xae41,
+  0xae42, 0xae43, 0xae44, 0xae45, 0xae46, 0xae47, 0xae48, 0xae49,
+  0xae4a, 0xae4b, 0xae4c, 0xae4d, 0xae4e, 0xae4f, 0xae50, 0xae51,
+  0xae52, 0xae53, 0xae54, 0xae55, 0xae56, 0xae57, 0xae58, 0xae59,
+  0xae5a, 0xae5b, 0xae5c, 0xae5d, 0xae5e, 0xae5f, 0xae60, 0xae61,
+  0xae62, 0xae63, 0xae64, 0xae65, 0xae66, 0xae67, 0xae68, 0xae69,
+  0xae6a, 0xae6b, 0xae6c, 0xae6d, 0xae6e, 0xae6f, 0xae70, 0xae71,
+  0xae72, 0xae73, 0xae74, 0xae75, 0xae76, 0xae77, 0xae78, 0xae79,
+  0xae7a, 0xae7b, 0xae7c, 0xae7d, 0xae7e, 0xae80, 0xae81, 0xae82,
+  0xae83, 0xae84, 0xae85, 0xae86, 0xae87, 0xae88, 0xae89, 0xae8a,
+  0xae8b, 0xae8c, 0xae8d, 0xae8e, 0xae8f, 0xae90, 0xae91, 0xae92,
+  0xae93, 0xae94, 0xae95, 0xae96, 0xae97, 0xae98, 0xae99, 0xae9a,
+  0xae9b, 0xae9c, 0xae9d, 0xae9e, 0xae9f, 0xaea0, 0xaf40, 0xaf41,
+  0xaf42, 0xaf43, 0xaf44, 0xaf45, 0xaf46, 0xaf47, 0xaf48, 0xaf49,
+  0xaf4a, 0xaf4b, 0xaf4c, 0xaf4d, 0xaf4e, 0xaf4f, 0xaf50, 0xaf51,
+  0xaf52, 0xaf53, 0xaf54, 0xaf55, 0xaf56, 0xaf57, 0xaf58, 0xaf59,
+  0xaf5a, 0xaf5b, 0xaf5c, 0xaf5d, 0xaf5e, 0xaf5f, 0xaf60, 0xaf61,
+  0xaf62, 0xaf63, 0xaf64, 0xaf65, 0xaf66, 0xaf67, 0xaf68, 0xaf69,
+  0xaf6a, 0xaf6b, 0xaf6c, 0xaf6d, 0xaf6e, 0xaf6f, 0xaf70, 0xaf71,
+  0xaf72, 0xaf73, 0xaf74, 0xaf75, 0xaf76, 0xaf77, 0xaf78, 0xaf79,
+  0xaf7a, 0xaf7b, 0xaf7c, 0xaf7d, 0xaf7e, 0xaf80, 0xaf81, 0xaf82,
+  0xaf83, 0xaf84, 0xaf85, 0xaf86, 0xaf87, 0xaf88, 0xaf89, 0xaf8a,
+  0xaf8b, 0xaf8c, 0xaf8d, 0xaf8e, 0xaf8f, 0xaf90, 0xaf91, 0xaf92,
+  0xaf93, 0xaf94, 0xaf95, 0xaf96, 0xaf97, 0xaf98, 0xaf99, 0xaf9a,
+  0xaf9b, 0xaf9c, 0xaf9d, 0xaf9e, 0xaf9f, 0xafa0, 0xb040, 0xb041,
+  0xb042, 0xb043, 0xb044, 0xb045, 0xb046, 0xb047, 0xb048, 0xb049,
+  0xb04a, 0xb04b, 0xb04c, 0xb04d, 0xb04e, 0xb04f, 0xb050, 0xb051,
+  0xb052, 0xb053, 0xb054, 0xb055, 0xb056, 0xb057, 0xb058, 0xb059,
+  0xb05a, 0xb05b, 0xb05c, 0xb05d, 0xb05e, 0xb05f, 0xb060, 0xb061,
+  0xb062, 0xb063, 0xb064, 0xb065, 0xb066, 0xb067, 0xb068, 0xb069,
+  0xb06a, 0xb06b, 0xb06c, 0xb06d, 0xb06e, 0xb06f, 0xb070, 0xb071,
+  0xb072, 0xb073, 0xb074, 0xb075, 0xb076, 0xb077, 0xb078, 0xb079,
+  0xb07a, 0xb07b, 0xb07c, 0xb07d, 0xb07e, 0xb080, 0xb081, 0xb082,
+  0xb083, 0xb084, 0xb085, 0xb086, 0xb087, 0xb088, 0xb089, 0xb08a,
+  0xb08b, 0xb08c, 0xb08d, 0xb08e, 0xb08f, 0xb090, 0xb091, 0xb092,
+  0xb093, 0xb094, 0xb095, 0xb096, 0xb097, 0xb098, 0xb099, 0xb09a,
+  0xb09b, 0xb09c, 0xb09d, 0xb09e, 0xb09f, 0xb0a0, 0xb140, 0xb141,
+  0xb142, 0xb143, 0xb144, 0xb145, 0xb146, 0xb147, 0xb148, 0xb149,
+  0xb14a, 0xb14b, 0xb14c, 0xb14d, 0xb14e, 0xb14f, 0xb150, 0xb151,
+  0xb152, 0xb153, 0xb154, 0xb155, 0xb156, 0xb157, 0xb158, 0xb159,
+  0xb15a, 0xb15b, 0xb15c, 0xb15d, 0xb15e, 0xb15f, 0xb160, 0xb161,
+  0xb162, 0xb163, 0xb164, 0xb165, 0xb166, 0xb167, 0xb168, 0xb169,
+  0xb16a, 0xb16b, 0xb16c, 0xb16d, 0xb16e, 0xb16f, 0xb170, 0xb171,
+  0xb172, 0xb173, 0xb174, 0xb175, 0xb176, 0xb177, 0xb178, 0xb179,
+  0xb17a, 0xb17b, 0xb17c, 0xb17d, 0xb17e, 0xb180, 0xb181, 0xb182,
+  0xb183, 0xb184, 0xb185, 0xb186, 0xb187, 0xb188, 0xb189, 0xb18a,
+  0xb18b, 0xb18c, 0xb18d, 0xb18e, 0xb18f, 0xb190, 0xb191, 0xb192,
+  0xb193, 0xb194, 0xb195, 0xb196, 0xb197, 0xb198, 0xb199, 0xb19a,
+  0xb19b, 0xb19c, 0xb19d, 0xb19e, 0xb19f, 0xb1a0, 0xb240, 0xb241,
+  0xb242, 0xb243, 0xb244, 0xb245, 0xb246, 0xb247, 0xb248, 0xb249,
+  0xb24a, 0xb24b, 0xb24c, 0xb24d, 0xb24e, 0xb24f, 0xb250, 0xb251,
+  0xb252, 0xb253, 0xb254, 0xb255, 0xb256, 0xb257, 0xb258, 0xb259,
+  0xb25a, 0xb25b, 0xb25c, 0xb25d, 0xb25e, 0xb25f, 0xb260, 0xb261,
+  0xb262, 0xb263, 0xb264, 0xb265, 0xb266, 0xb267, 0xb268, 0xb269,
+  0xb26a, 0xb26b, 0xb26c, 0xb26d, 0xb26e, 0xb26f, 0xb270, 0xb271,
+  0xb272, 0xb273, 0xb274, 0xb275, 0xb276, 0xb277, 0xb278, 0xb279,
+  0xb27a, 0xb27b, 0xb27c, 0xb27d, 0xb27e, 0xb280, 0xb281, 0xb282,
+  0xb283, 0xb284, 0xb285, 0xb286, 0xb287, 0xb288, 0xb289, 0xb28a,
+  0xb28b, 0xb28c, 0xb28d, 0xb28e, 0xb28f, 0xb290, 0xb291, 0xb292,
+  0xb293, 0xb294, 0xb295, 0xb296, 0xb297, 0xb298, 0xb299, 0xb29a,
+  0xb29b, 0xb29c, 0xb29d, 0xb29e, 0xb29f, 0xb2a0, 0xb340, 0xb341,
+  0xb342, 0xb343, 0xb344, 0xb345, 0xb346, 0xb347, 0xb348, 0xb349,
+  0xb34a, 0xb34b, 0xb34c, 0xb34d, 0xb34e, 0xb34f, 0xb350, 0xb351,
+  0xb352, 0xb353, 0xb354, 0xb355, 0xb356, 0xb357, 0xb358, 0xb359,
+  0xb35a, 0xb35b, 0xb35c, 0xb35d, 0xb35e, 0xb35f, 0xb360, 0xb361,
+  0xb362, 0xb363, 0xb364, 0xb365, 0xb366, 0xb367, 0xb368, 0xb369,
+  0xb36a, 0xb36b, 0xb36c, 0xb36d, 0xb36e, 0xb36f, 0xb370, 0xb371,
+  0xb372, 0xb373, 0xb374, 0xb375, 0xb376, 0xb377, 0xb378, 0xb379,
+  0xb37a, 0xb37b, 0xb37c, 0xb37d, 0xb37e, 0xb380, 0xb381, 0xb382,
+  0xb383, 0xb384, 0xb385, 0xb386, 0xb387, 0xb388, 0xb389, 0xb38a,
+  0xb38b, 0xb38c, 0xb38d, 0xb38e, 0xb38f, 0xb390, 0xb391, 0xb392,
+  0xb393, 0xb394, 0xb395, 0xb396, 0xb397, 0xb398, 0xb399, 0xb39a,
+  0xb39b, 0xb39c, 0xb39d, 0xb39e, 0xb39f, 0xb3a0, 0xb440, 0xb441,
+  0xb442, 0xb443, 0xb444, 0xb445, 0xb446, 0xb447, 0xb448, 0xb449,
+  0xb44a, 0xb44b, 0xb44c, 0xb44d, 0xb44e, 0xb44f, 0xb450, 0xb451,
+  0xb452, 0xb453, 0xb454, 0xb455, 0xb456, 0xb457, 0xb458, 0xb459,
+  0xb45a, 0xb45b, 0xb45c, 0xb45d, 0xb45e, 0xb45f, 0xb460, 0xb461,
+  0xb462, 0xb463, 0xb464, 0xb465, 0xb466, 0xb467, 0xb468, 0xb469,
+  0xb46a, 0xb46b, 0xb46c, 0xb46d, 0xb46e, 0xb46f, 0xb470, 0xb471,
+  0xb472, 0xb473, 0xb474, 0xb475, 0xb476, 0xb477, 0xb478, 0xb479,
+  0xb47a, 0xb47b, 0xb47c, 0xb47d, 0xb47e, 0xb480, 0xb481, 0xb482,
+  0xb483, 0xb484, 0xb485, 0xb486, 0xb487, 0xb488, 0xb489, 0xb48a,
+  0xb48b, 0xb48c, 0xb48d, 0xb48e, 0xb48f, 0xb490, 0xb491, 0xb492,
+  0xb493, 0xb494, 0xb495, 0xb496, 0xb497, 0xb498, 0xb499, 0xb49a,
+  0xb49b, 0xb49c, 0xb49d, 0xb49e, 0xb49f, 0xb4a0, 0xb540, 0xb541,
+  0xb542, 0xb543, 0xb544, 0xb545, 0xb546, 0xb547, 0xb548, 0xb549,
+  0xb54a, 0xb54b, 0xb54c, 0xb54d, 0xb54e, 0xb54f, 0xb550, 0xb551,
+  0xb552, 0xb553, 0xb554, 0xb555, 0xb556, 0xb557, 0xb558, 0xb559,
+  0xb55a, 0xb55b, 0xb55c, 0xb55d, 0xb55e, 0xb55f, 0xb560, 0xb561,
+  0xb562, 0xb563, 0xb564, 0xb565, 0xb566, 0xb567, 0xb568, 0xb569,
+  0xb56a, 0xb56b, 0xb56c, 0xb56d, 0xb56e, 0xb56f, 0xb570, 0xb571,
+  0xb572, 0xb573, 0xb574, 0xb575, 0xb576, 0xb577, 0xb578, 0xb579,
+  0xb57a, 0xb57b, 0xb57c, 0xb57d, 0xb57e, 0xb580, 0xb581, 0xb582,
+  0xb583, 0xb584, 0xb585, 0xb586, 0xb587, 0xb588, 0xb589, 0xb58a,
+  0xb58b, 0xb58c, 0xb58d, 0xb58e, 0xb58f, 0xb590, 0xb591, 0xb592,
+  0xb593, 0xb594, 0xb595, 0xb596, 0xb597, 0xb598, 0xb599, 0xb59a,
+  0xb59b, 0xb59c, 0xb59d, 0xb59e, 0xb59f, 0xb5a0, 0xb640, 0xb641,
+  0xb642, 0xb643, 0xb644, 0xb645, 0xb646, 0xb647, 0xb648, 0xb649,
+  0xb64a, 0xb64b, 0xb64c, 0xb64d, 0xb64e, 0xb64f, 0xb650, 0xb651,
+  0xb652, 0xb653, 0xb654, 0xb655, 0xb656, 0xb657, 0xb658, 0xb659,
+  0xb65a, 0xb65b, 0xb65c, 0xb65d, 0xb65e, 0xb65f, 0xb660, 0xb661,
+  0xb662, 0xb663, 0xb664, 0xb665, 0xb666, 0xb667, 0xb668, 0xb669,
+  0xb66a, 0xb66b, 0xb66c, 0xb66d, 0xb66e, 0xb66f, 0xb670, 0xb671,
+  0xb672, 0xb673, 0xb674, 0xb675, 0xb676, 0xb677, 0xb678, 0xb679,
+  0xb67a, 0xb67b, 0xb67c, 0xb67d, 0xb67e, 0xb680, 0xb681, 0xb682,
+  0xb683, 0xb684, 0xb685, 0xb686, 0xb687, 0xb688, 0xb689, 0xb68a,
+  0xb68b, 0xb68c, 0xb68d, 0xb68e, 0xb68f, 0xb690, 0xb691, 0xb692,
+  0xb693, 0xb694, 0xb695, 0xb696, 0xb697, 0xb698, 0xb699, 0xb69a,
+  0xb69b, 0xb69c, 0xb69d, 0xb69e, 0xb69f, 0xb6a0, 0xb740, 0xb741,
+  0xb742, 0xb743, 0xb744, 0xb745, 0xb746, 0xb747, 0xb748, 0xb749,
+  0xb74a, 0xb74b, 0xb74c, 0xb74d, 0xb74e, 0xb74f, 0xb750, 0xb751,
+  0xb752, 0xb753, 0xb754, 0xb755, 0xb756, 0xb757, 0xb758, 0xb759,
+  0xb75a, 0xb75b, 0xb75c, 0xb75d, 0xb75e, 0xb75f, 0xb760, 0xb761,
+  0xb762, 0xb763, 0xb764, 0xb765, 0xb766, 0xb767, 0xb768, 0xb769,
+  0xb76a, 0xb76b, 0xb76c, 0xb76d, 0xb76e, 0xb76f, 0xb770, 0xb771,
+  0xb772, 0xb773, 0xb774, 0xb775, 0xb776, 0xb777, 0xb778, 0xb779,
+  0xb77a, 0xb77b, 0xb77c, 0xb77d, 0xb77e, 0xb780, 0xb781, 0xb782,
+  0xb783, 0xb784, 0xb785, 0xb786, 0xb787, 0xb788, 0xb789, 0xb78a,
+  0xb78b, 0xb78c, 0xb78d, 0xb78e, 0xb78f, 0xb790, 0xb791, 0xb792,
+  0xb793, 0xb794, 0xb795, 0xb796, 0xb797, 0xb798, 0xb799, 0xb79a,
+  0xb79b, 0xb79c, 0xb79d, 0xb79e, 0xb79f, 0xb7a0, 0xb840, 0xb841,
+  0xb842, 0xb843, 0xb844, 0xb845, 0xb846, 0xb847, 0xb848, 0xb849,
+  0xb84a, 0xb84b, 0xb84c, 0xb84d, 0xb84e, 0xb84f, 0xb850, 0xb851,
+  0xb852, 0xb853, 0xb854, 0xb855, 0xb856, 0xb857, 0xb858, 0xb859,
+  0xb85a, 0xb85b, 0xb85c, 0xb85d, 0xb85e, 0xb85f, 0xb860, 0xb861,
+  0xb862, 0xb863, 0xb864, 0xb865, 0xb866, 0xb867, 0xb868, 0xb869,
+  0xb86a, 0xb86b, 0xb86c, 0xb86d, 0xb86e, 0xb86f, 0xb870, 0xb871,
+  0xb872, 0xb873, 0xb874, 0xb875, 0xb876, 0xb877, 0xb878, 0xb879,
+  0xb87a, 0xb87b, 0xb87c, 0xb87d, 0xb87e, 0xb880, 0xb881, 0xb882,
+  0xb883, 0xb884, 0xb885, 0xb886, 0xb887, 0xb888, 0xb889, 0xb88a,
+  0xb88b, 0xb88c, 0xb88d, 0xb88e, 0xb88f, 0xb890, 0xb891, 0xb892,
+  0xb893, 0xb894, 0xb895, 0xb896, 0xb897, 0xb898, 0xb899, 0xb89a,
+  0xb89b, 0xb89c, 0xb89d, 0xb89e, 0xb89f, 0xb8a0, 0xb940, 0xb941,
+  0xb942, 0xb943, 0xb944, 0xb945, 0xb946, 0xb947, 0xb948, 0xb949,
+  0xb94a, 0xb94b, 0xb94c, 0xb94d, 0xb94e, 0xb94f, 0xb950, 0xb951,
+  0xb952, 0xb953, 0xb954, 0xb955, 0xb956, 0xb957, 0xb958, 0xb959,
+  0xb95a, 0xb95b, 0xb95c, 0xb95d, 0xb95e, 0xb95f, 0xb960, 0xb961,
+  0xb962, 0xb963, 0xb964, 0xb965, 0xb966, 0xb967, 0xb968, 0xb969,
+  0xb96a, 0xb96b, 0xb96c, 0xb96d, 0xb96e, 0xb96f, 0xb970, 0xb971,
+  0xb972, 0xb973, 0xb974, 0xb975, 0xb976, 0xb977, 0xb978, 0xb979,
+  0xb97a, 0xb97b, 0xb97c, 0xb97d, 0xb97e, 0xb980, 0xb981, 0xb982,
+  0xb983, 0xb984, 0xb985, 0xb986, 0xb987, 0xb988, 0xb989, 0xb98a,
+  0xb98b, 0xb98c, 0xb98d, 0xb98e, 0xb98f, 0xb990, 0xb991, 0xb992,
+  0xb993, 0xb994, 0xb995, 0xb996, 0xb997, 0xb998, 0xb999, 0xb99a,
+  0xb99b, 0xb99c, 0xb99d, 0xb99e, 0xb99f, 0xb9a0, 0xba40, 0xba41,
+  0xba42, 0xba43, 0xba44, 0xba45, 0xba46, 0xba47, 0xba48, 0xba49,
+  0xba4a, 0xba4b, 0xba4c, 0xba4d, 0xba4e, 0xba4f, 0xba50, 0xba51,
+  0xba52, 0xba53, 0xba54, 0xba55, 0xba56, 0xba57, 0xba58, 0xba59,
+  0xba5a, 0xba5b, 0xba5c, 0xba5d, 0xba5e, 0xba5f, 0xba60, 0xba61,
+  0xba62, 0xba63, 0xba64, 0xba65, 0xba66, 0xba67, 0xba68, 0xba69,
+  0xba6a, 0xba6b, 0xba6c, 0xba6d, 0xba6e, 0xba6f, 0xba70, 0xba71,
+  0xba72, 0xba73, 0xba74, 0xba75, 0xba76, 0xba77, 0xba78, 0xba79,
+  0xba7a, 0xba7b, 0xba7c, 0xba7d, 0xba7e, 0xba80, 0xba81, 0xba82,
+  0xba83, 0xba84, 0xba85, 0xba86, 0xba87, 0xba88, 0xba89, 0xba8a,
+  0xba8b, 0xba8c, 0xba8d, 0xba8e, 0xba8f, 0xba90, 0xba91, 0xba92,
+  0xba93, 0xba94, 0xba95, 0xba96, 0xba97, 0xba98, 0xba99, 0xba9a,
+  0xba9b, 0xba9c, 0xba9d, 0xba9e, 0xba9f, 0xbaa0, 0xbb40, 0xbb41,
+  0xbb42, 0xbb43, 0xbb44, 0xbb45, 0xbb46, 0xbb47, 0xbb48, 0xbb49,
+  0xbb4a, 0xbb4b, 0xbb4c, 0xbb4d, 0xbb4e, 0xbb4f, 0xbb50, 0xbb51,
+  0xbb52, 0xbb53, 0xbb54, 0xbb55, 0xbb56, 0xbb57, 0xbb58, 0xbb59,
+  0xbb5a, 0xbb5b, 0xbb5c, 0xbb5d, 0xbb5e, 0xbb5f, 0xbb60, 0xbb61,
+  0xbb62, 0xbb63, 0xbb64, 0xbb65, 0xbb66, 0xbb67, 0xbb68, 0xbb69,
+  0xbb6a, 0xbb6b, 0xbb6c, 0xbb6d, 0xbb6e, 0xbb6f, 0xbb70, 0xbb71,
+  0xbb72, 0xbb73, 0xbb74, 0xbb75, 0xbb76, 0xbb77, 0xbb78, 0xbb79,
+  0xbb7a, 0xbb7b, 0xbb7c, 0xbb7d, 0xbb7e, 0xbb80, 0xbb81, 0xbb82,
+  0xbb83, 0xbb84, 0xbb85, 0xbb86, 0xbb87, 0xbb88, 0xbb89, 0xbb8a,
+  0xbb8b, 0xbb8c, 0xbb8d, 0xbb8e, 0xbb8f, 0xbb90, 0xbb91, 0xbb92,
+  0xbb93, 0xbb94, 0xbb95, 0xbb96, 0xbb97, 0xbb98, 0xbb99, 0xbb9a,
+  0xbb9b, 0xbb9c, 0xbb9d, 0xbb9e, 0xbb9f, 0xbba0, 0xbc40, 0xbc41,
+  0xbc42, 0xbc43, 0xbc44, 0xbc45, 0xbc46, 0xbc47, 0xbc48, 0xbc49,
+  0xbc4a, 0xbc4b, 0xbc4c, 0xbc4d, 0xbc4e, 0xbc4f, 0xbc50, 0xbc51,
+  0xbc52, 0xbc53, 0xbc54, 0xbc55, 0xbc56, 0xbc57, 0xbc58, 0xbc59,
+  0xbc5a, 0xbc5b, 0xbc5c, 0xbc5d, 0xbc5e, 0xbc5f, 0xbc60, 0xbc61,
+  0xbc62, 0xbc63, 0xbc64, 0xbc65, 0xbc66, 0xbc67, 0xbc68, 0xbc69,
+  0xbc6a, 0xbc6b, 0xbc6c, 0xbc6d, 0xbc6e, 0xbc6f, 0xbc70, 0xbc71,
+  0xbc72, 0xbc73, 0xbc74, 0xbc75, 0xbc76, 0xbc77, 0xbc78, 0xbc79,
+  0xbc7a, 0xbc7b, 0xbc7c, 0xbc7d, 0xbc7e, 0xbc80, 0xbc81, 0xbc82,
+  0xbc83, 0xbc84, 0xbc85, 0xbc86, 0xbc87, 0xbc88, 0xbc89, 0xbc8a,
+  0xbc8b, 0xbc8c, 0xbc8d, 0xbc8e, 0xbc8f, 0xbc90, 0xbc91, 0xbc92,
+  0xbc93, 0xbc94, 0xbc95, 0xbc96, 0xbc97, 0xbc98, 0xbc99, 0xbc9a,
+  0xbc9b, 0xbc9c, 0xbc9d, 0xbc9e, 0xbc9f, 0xbca0, 0xbd40, 0xbd41,
+  0xbd42, 0xbd43, 0xbd44, 0xbd45, 0xbd46, 0xbd47, 0xbd48, 0xbd49,
+  0xbd4a, 0xbd4b, 0xbd4c, 0xbd4d, 0xbd4e, 0xbd4f, 0xbd50, 0xbd51,
+  0xbd52, 0xbd53, 0xbd54, 0xbd55, 0xbd56, 0xbd57, 0xbd58, 0xbd59,
+  0xbd5a, 0xbd5b, 0xbd5c, 0xbd5d, 0xbd5e, 0xbd5f, 0xbd60, 0xbd61,
+  0xbd62, 0xbd63, 0xbd64, 0xbd65, 0xbd66, 0xbd67, 0xbd68, 0xbd69,
+  0xbd6a, 0xbd6b, 0xbd6c, 0xbd6d, 0xbd6e, 0xbd6f, 0xbd70, 0xbd71,
+  0xbd72, 0xbd73, 0xbd74, 0xbd75, 0xbd76, 0xbd77, 0xbd78, 0xbd79,
+  0xbd7a, 0xbd7b, 0xbd7c, 0xbd7d, 0xbd7e, 0xbd80, 0xbd81, 0xbd82,
+  0xbd83, 0xbd84, 0xbd85, 0xbd86, 0xbd87, 0xbd88, 0xbd89, 0xbd8a,
+  0xbd8b, 0xbd8c, 0xbd8d, 0xbd8e, 0xbd8f, 0xbd90, 0xbd91, 0xbd92,
+  0xbd93, 0xbd94, 0xbd95, 0xbd96, 0xbd97, 0xbd98, 0xbd99, 0xbd9a,
+  0xbd9b, 0xbd9c, 0xbd9d, 0xbd9e, 0xbd9f, 0xbda0, 0xbe40, 0xbe41,
+  0xbe42, 0xbe43, 0xbe44, 0xbe45, 0xbe46, 0xbe47, 0xbe48, 0xbe49,
+  0xbe4a, 0xbe4b, 0xbe4c, 0xbe4d, 0xbe4e, 0xbe4f, 0xbe50, 0xbe51,
+  0xbe52, 0xbe53, 0xbe54, 0xbe55, 0xbe56, 0xbe57, 0xbe58, 0xbe59,
+  0xbe5a, 0xbe5b, 0xbe5c, 0xbe5d, 0xbe5e, 0xbe5f, 0xbe60, 0xbe61,
+  0xbe62, 0xbe63, 0xbe64, 0xbe65, 0xbe66, 0xbe67, 0xbe68, 0xbe69,
+  0xbe6a, 0xbe6b, 0xbe6c, 0xbe6d, 0xbe6e, 0xbe6f, 0xbe70, 0xbe71,
+  0xbe72, 0xbe73, 0xbe74, 0xbe75, 0xbe76, 0xbe77, 0xbe78, 0xbe79,
+  0xbe7a, 0xbe7b, 0xbe7c, 0xbe7d, 0xbe7e, 0xbe80, 0xbe81, 0xbe82,
+  0xbe83, 0xbe84, 0xbe85, 0xbe86, 0xbe87, 0xbe88, 0xbe89, 0xbe8a,
+  0xbe8b, 0xbe8c, 0xbe8d, 0xbe8e, 0xbe8f, 0xbe90, 0xbe91, 0xbe92,
+  0xbe93, 0xbe94, 0xbe95, 0xbe96, 0xbe97, 0xbe98, 0xbe99, 0xbe9a,
+  0xbe9b, 0xbe9c, 0xbe9d, 0xbe9e, 0xbe9f, 0xbea0, 0xbf40, 0xbf41,
+  0xbf42, 0xbf43, 0xbf44, 0xbf45, 0xbf46, 0xbf47, 0xbf48, 0xbf49,
+  0xbf4a, 0xbf4b, 0xbf4c, 0xbf4d, 0xbf4e, 0xbf4f, 0xbf50, 0xbf51,
+  0xbf52, 0xbf53, 0xbf54, 0xbf55, 0xbf56, 0xbf57, 0xbf58, 0xbf59,
+  0xbf5a, 0xbf5b, 0xbf5c, 0xbf5d, 0xbf5e, 0xbf5f, 0xbf60, 0xbf61,
+  0xbf62, 0xbf63, 0xbf64, 0xbf65, 0xbf66, 0xbf67, 0xbf68, 0xbf69,
+  0xbf6a, 0xbf6b, 0xbf6c, 0xbf6d, 0xbf6e, 0xbf6f, 0xbf70, 0xbf71,
+  0xbf72, 0xbf73, 0xbf74, 0xbf75, 0xbf76, 0xbf77, 0xbf78, 0xbf79,
+  0xbf7a, 0xbf7b, 0xbf7c, 0xbf7d, 0xbf7e, 0xbf80, 0xbf81, 0xbf82,
+  0xbf83, 0xbf84, 0xbf85, 0xbf86, 0xbf87, 0xbf88, 0xbf89, 0xbf8a,
+  0xbf8b, 0xbf8c, 0xbf8d, 0xbf8e, 0xbf8f, 0xbf90, 0xbf91, 0xbf92,
+  0xbf93, 0xbf94, 0xbf95, 0xbf96, 0xbf97, 0xbf98, 0xbf99, 0xbf9a,
+  0xbf9b, 0xbf9c, 0xbf9d, 0xbf9e, 0xbf9f, 0xbfa0, 0xc040, 0xc041,
+  0xc042, 0xc043, 0xc044, 0xc045, 0xc046, 0xc047, 0xc048, 0xc049,
+  0xc04a, 0xc04b, 0xc04c, 0xc04d, 0xc04e, 0xc04f, 0xc050, 0xc051,
+  0xc052, 0xc053, 0xc054, 0xc055, 0xc056, 0xc057, 0xc058, 0xc059,
+  0xc05a, 0xc05b, 0xc05c, 0xc05d, 0xc05e, 0xc05f, 0xc060, 0xc061,
+  0xc062, 0xc063, 0xc064, 0xc065, 0xc066, 0xc067, 0xc068, 0xc069,
+  0xc06a, 0xc06b, 0xc06c, 0xc06d, 0xc06e, 0xc06f, 0xc070, 0xc071,
+  0xc072, 0xc073, 0xc074, 0xc075, 0xc076, 0xc077, 0xc078, 0xc079,
+  0xc07a, 0xc07b, 0xc07c, 0xc07d, 0xc07e, 0xc080, 0xc081, 0xc082,
+  0xc083, 0xc084, 0xc085, 0xc086, 0xc087, 0xc088, 0xc089, 0xc08a,
+  0xc08b, 0xc08c, 0xc08d, 0xc08e, 0xc08f, 0xc090, 0xc091, 0xc092,
+  0xc093, 0xc094, 0xc095, 0xc096, 0xc097, 0xc098, 0xc099, 0xc09a,
+  0xc09b, 0xc09c, 0xc09d, 0xc09e, 0xc09f, 0xc0a0, 0xc140, 0xc141,
+  0xc142, 0xc143, 0xc144, 0xc145, 0xc146, 0xc147, 0xc148, 0xc149,
+  0xc14a, 0xc14b, 0xc14c, 0xc14d, 0xc14e, 0xc14f, 0xc150, 0xc151,
+  0xc152, 0xc153, 0xc154, 0xc155, 0xc156, 0xc157, 0xc158, 0xc159,
+  0xc15a, 0xc15b, 0xc15c, 0xc15d, 0xc15e, 0xc15f, 0xc160, 0xc161,
+  0xc162, 0xc163, 0xc164, 0xc165, 0xc166, 0xc167, 0xc168, 0xc169,
+  0xc16a, 0xc16b, 0xc16c, 0xc16d, 0xc16e, 0xc16f, 0xc170, 0xc171,
+  0xc172, 0xc173, 0xc174, 0xc175, 0xc176, 0xc177, 0xc178, 0xc179,
+  0xc17a, 0xc17b, 0xc17c, 0xc17d, 0xc17e, 0xc180, 0xc181, 0xc182,
+  0xc183, 0xc184, 0xc185, 0xc186, 0xc187, 0xc188, 0xc189, 0xc18a,
+  0xc18b, 0xc18c, 0xc18d, 0xc18e, 0xc18f, 0xc190, 0xc191, 0xc192,
+  0xc193, 0xc194, 0xc195, 0xc196, 0xc197, 0xc198, 0xc199, 0xc19a,
+  0xc19b, 0xc19c, 0xc19d, 0xc19e, 0xc19f, 0xc1a0, 0xc240, 0xc241,
+  0xc242, 0xc243, 0xc244, 0xc245, 0xc246, 0xc247, 0xc248, 0xc249,
+  0xc24a, 0xc24b, 0xc24c, 0xc24d, 0xc24e, 0xc24f, 0xc250, 0xc251,
+  0xc252, 0xc253, 0xc254, 0xc255, 0xc256, 0xc257, 0xc258, 0xc259,
+  0xc25a, 0xc25b, 0xc25c, 0xc25d, 0xc25e, 0xc25f, 0xc260, 0xc261,
+  0xc262, 0xc263, 0xc264, 0xc265, 0xc266, 0xc267, 0xc268, 0xc269,
+  0xc26a, 0xc26b, 0xc26c, 0xc26d, 0xc26e, 0xc26f, 0xc270, 0xc271,
+  0xc272, 0xc273, 0xc274, 0xc275, 0xc276, 0xc277, 0xc278, 0xc279,
+  0xc27a, 0xc27b, 0xc27c, 0xc27d, 0xc27e, 0xc280, 0xc281, 0xc282,
+  0xc283, 0xc284, 0xc285, 0xc286, 0xc287, 0xc288, 0xc289, 0xc28a,
+  0xc28b, 0xc28c, 0xc28d, 0xc28e, 0xc28f, 0xc290, 0xc291, 0xc292,
+  0xc293, 0xc294, 0xc295, 0xc296, 0xc297, 0xc298, 0xc299, 0xc29a,
+  0xc29b, 0xc29c, 0xc29d, 0xc29e, 0xc29f, 0xc2a0, 0xc340, 0xc341,
+  0xc342, 0xc343, 0xc344, 0xc345, 0xc346, 0xc347, 0xc348, 0xc349,
+  0xc34a, 0xc34b, 0xc34c, 0xc34d, 0xc34e, 0xc34f, 0xc350, 0xc351,
+  0xc352, 0xc353, 0xc354, 0xc355, 0xc356, 0xc357, 0xc358, 0xc359,
+  0xc35a, 0xc35b, 0xc35c, 0xc35d, 0xc35e, 0xc35f, 0xc360, 0xc361,
+  0xc362, 0xc363, 0xc364, 0xc365, 0xc366, 0xc367, 0xc368, 0xc369,
+  0xc36a, 0xc36b, 0xc36c, 0xc36d, 0xc36e, 0xc36f, 0xc370, 0xc371,
+  0xc372, 0xc373, 0xc374, 0xc375, 0xc376, 0xc377, 0xc378, 0xc379,
+  0xc37a, 0xc37b, 0xc37c, 0xc37d, 0xc37e, 0xc380, 0xc381, 0xc382,
+  0xc383, 0xc384, 0xc385, 0xc386, 0xc387, 0xc388, 0xc389, 0xc38a,
+  0xc38b, 0xc38c, 0xc38d, 0xc38e, 0xc38f, 0xc390, 0xc391, 0xc392,
+  0xc393, 0xc394, 0xc395, 0xc396, 0xc397, 0xc398, 0xc399, 0xc39a,
+  0xc39b, 0xc39c, 0xc39d, 0xc39e, 0xc39f, 0xc3a0, 0xc440, 0xc441,
+  0xc442, 0xc443, 0xc444, 0xc445, 0xc446, 0xc447, 0xc448, 0xc449,
+  0xc44a, 0xc44b, 0xc44c, 0xc44d, 0xc44e, 0xc44f, 0xc450, 0xc451,
+  0xc452, 0xc453, 0xc454, 0xc455, 0xc456, 0xc457, 0xc458, 0xc459,
+  0xc45a, 0xc45b, 0xc45c, 0xc45d, 0xc45e, 0xc45f, 0xc460, 0xc461,
+  0xc462, 0xc463, 0xc464, 0xc465, 0xc466, 0xc467, 0xc468, 0xc469,
+  0xc46a, 0xc46b, 0xc46c, 0xc46d, 0xc46e, 0xc46f, 0xc470, 0xc471,
+  0xc472, 0xc473, 0xc474, 0xc475, 0xc476, 0xc477, 0xc478, 0xc479,
+  0xc47a, 0xc47b, 0xc47c, 0xc47d, 0xc47e, 0xc480, 0xc481, 0xc482,
+  0xc483, 0xc484, 0xc485, 0xc486, 0xc487, 0xc488, 0xc489, 0xc48a,
+  0xc48b, 0xc48c, 0xc48d, 0xc48e, 0xc48f, 0xc490, 0xc491, 0xc492,
+  0xc493, 0xc494, 0xc495, 0xc496, 0xc497, 0xc498, 0xc499, 0xc49a,
+  0xc49b, 0xc49c, 0xc49d, 0xc49e, 0xc49f, 0xc4a0, 0xc540, 0xc541,
+  0xc542, 0xc543, 0xc544, 0xc545, 0xc546, 0xc547, 0xc548, 0xc549,
+  0xc54a, 0xc54b, 0xc54c, 0xc54d, 0xc54e, 0xc54f, 0xc550, 0xc551,
+  0xc552, 0xc553, 0xc554, 0xc555, 0xc556, 0xc557, 0xc558, 0xc559,
+  0xc55a, 0xc55b, 0xc55c, 0xc55d, 0xc55e, 0xc55f, 0xc560, 0xc561,
+  0xc562, 0xc563, 0xc564, 0xc565, 0xc566, 0xc567, 0xc568, 0xc569,
+  0xc56a, 0xc56b, 0xc56c, 0xc56d, 0xc56e, 0xc56f, 0xc570, 0xc571,
+  0xc572, 0xc573, 0xc574, 0xc575, 0xc576, 0xc577, 0xc578, 0xc579,
+  0xc57a, 0xc57b, 0xc57c, 0xc57d, 0xc57e, 0xc580, 0xc581, 0xc582,
+  0xc583, 0xc584, 0xc585, 0xc586, 0xc587, 0xc588, 0xc589, 0xc58a,
+  0xc58b, 0xc58c, 0xc58d, 0xc58e, 0xc58f, 0xc590, 0xc591, 0xc592,
+  0xc593, 0xc594, 0xc595, 0xc596, 0xc597, 0xc598, 0xc599, 0xc59a,
+  0xc59b, 0xc59c, 0xc59d, 0xc59e, 0xc59f, 0xc5a0, 0xc640, 0xc641,
+  0xc642, 0xc643, 0xc644, 0xc645, 0xc646, 0xc647, 0xc648, 0xc649,
+  0xc64a, 0xc64b, 0xc64c, 0xc64d, 0xc64e, 0xc64f, 0xc650, 0xc651,
+  0xc652, 0xc653, 0xc654, 0xc655, 0xc656, 0xc657, 0xc658, 0xc659,
+  0xc65a, 0xc65b, 0xc65c, 0xc65d, 0xc65e, 0xc65f, 0xc660, 0xc661,
+  0xc662, 0xc663, 0xc664, 0xc665, 0xc666, 0xc667, 0xc668, 0xc669,
+  0xc66a, 0xc66b, 0xc66c, 0xc66d, 0xc66e, 0xc66f, 0xc670, 0xc671,
+  0xc672, 0xc673, 0xc674, 0xc675, 0xc676, 0xc677, 0xc678, 0xc679,
+  0xc67a, 0xc67b, 0xc67c, 0xc67d, 0xc67e, 0xc680, 0xc681, 0xc682,
+  0xc683, 0xc684, 0xc685, 0xc686, 0xc687, 0xc688, 0xc689, 0xc68a,
+  0xc68b, 0xc68c, 0xc68d, 0xc68e, 0xc68f, 0xc690, 0xc691, 0xc692,
+  0xc693, 0xc694, 0xc695, 0xc696, 0xc697, 0xc698, 0xc699, 0xc69a,
+  0xc69b, 0xc69c, 0xc69d, 0xc69e, 0xc69f, 0xc6a0, 0xc740, 0xc741,
+  0xc742, 0xc743, 0xc744, 0xc745, 0xc746, 0xc747, 0xc748, 0xc749,
+  0xc74a, 0xc74b, 0xc74c, 0xc74d, 0xc74e, 0xc74f, 0xc750, 0xc751,
+  0xc752, 0xc753, 0xc754, 0xc755, 0xc756, 0xc757, 0xc758, 0xc759,
+  0xc75a, 0xc75b, 0xc75c, 0xc75d, 0xc75e, 0xc75f, 0xc760, 0xc761,
+  0xc762, 0xc763, 0xc764, 0xc765, 0xc766, 0xc767, 0xc768, 0xc769,
+  0xc76a, 0xc76b, 0xc76c, 0xc76d, 0xc76e, 0xc76f, 0xc770, 0xc771,
+  0xc772, 0xc773, 0xc774, 0xc775, 0xc776, 0xc777, 0xc778, 0xc779,
+  0xc77a, 0xc77b, 0xc77c, 0xc77d, 0xc77e, 0xc780, 0xc781, 0xc782,
+  0xc783, 0xc784, 0xc785, 0xc786, 0xc787, 0xc788, 0xc789, 0xc78a,
+  0xc78b, 0xc78c, 0xc78d, 0xc78e, 0xc78f, 0xc790, 0xc791, 0xc792,
+  0xc793, 0xc794, 0xc795, 0xc796, 0xc797, 0xc798, 0xc799, 0xc79a,
+  0xc79b, 0xc79c, 0xc79d, 0xc79e, 0xc79f, 0xc7a0, 0xc840, 0xc841,
+  0xc842, 0xc843, 0xc844, 0xc845, 0xc846, 0xc847, 0xc848, 0xc849,
+  0xc84a, 0xc84b, 0xc84c, 0xc84d, 0xc84e, 0xc84f, 0xc850, 0xc851,
+  0xc852, 0xc853, 0xc854, 0xc855, 0xc856, 0xc857, 0xc858, 0xc859,
+  0xc85a, 0xc85b, 0xc85c, 0xc85d, 0xc85e, 0xc85f, 0xc860, 0xc861,
+  0xc862, 0xc863, 0xc864, 0xc865, 0xc866, 0xc867, 0xc868, 0xc869,
+  0xc86a, 0xc86b, 0xc86c, 0xc86d, 0xc86e, 0xc86f, 0xc870, 0xc871,
+  0xc872, 0xc873, 0xc874, 0xc875, 0xc876, 0xc877, 0xc878, 0xc879,
+  0xc87a, 0xc87b, 0xc87c, 0xc87d, 0xc87e, 0xc880, 0xc881, 0xc882,
+  0xc883, 0xc884, 0xc885, 0xc886, 0xc887, 0xc888, 0xc889, 0xc88a,
+  0xc88b, 0xc88c, 0xc88d, 0xc88e, 0xc88f, 0xc890, 0xc891, 0xc892,
+  0xc893, 0xc894, 0xc895, 0xc896, 0xc897, 0xc898, 0xc899, 0xc89a,
+  0xc89b, 0xc89c, 0xc89d, 0xc89e, 0xc89f, 0xc8a0, 0xc940, 0xc941,
+  0xc942, 0xc943, 0xc944, 0xc945, 0xc946, 0xc947, 0xc948, 0xc949,
+  0xc94a, 0xc94b, 0xc94c, 0xc94d, 0xc94e, 0xc94f, 0xc950, 0xc951,
+  0xc952, 0xc953, 0xc954, 0xc955, 0xc956, 0xc957, 0xc958, 0xc959,
+  0xc95a, 0xc95b, 0xc95c, 0xc95d, 0xc95e, 0xc95f, 0xc960, 0xc961,
+  0xc962, 0xc963, 0xc964, 0xc965, 0xc966, 0xc967, 0xc968, 0xc969,
+  0xc96a, 0xc96b, 0xc96c, 0xc96d, 0xc96e, 0xc96f, 0xc970, 0xc971,
+  0xc972, 0xc973, 0xc974, 0xc975, 0xc976, 0xc977, 0xc978, 0xc979,
+  0xc97a, 0xc97b, 0xc97c, 0xc97d, 0xc97e, 0xc980, 0xc981, 0xc982,
+  0xc983, 0xc984, 0xc985, 0xc986, 0xc987, 0xc988, 0xc989, 0xc98a,
+  0xc98b, 0xc98c, 0xc98d, 0xc98e, 0xc98f, 0xc990, 0xc991, 0xc992,
+  0xc993, 0xc994, 0xc995, 0xc996, 0xc997, 0xc998, 0xc999, 0xc99a,
+  0xc99b, 0xc99c, 0xc99d, 0xc99e, 0xc99f, 0xc9a0, 0xca40, 0xca41,
+  0xca42, 0xca43, 0xca44, 0xca45, 0xca46, 0xca47, 0xca48, 0xca49,
+  0xca4a, 0xca4b, 0xca4c, 0xca4d, 0xca4e, 0xca4f, 0xca50, 0xca51,
+  0xca52, 0xca53, 0xca54, 0xca55, 0xca56, 0xca57, 0xca58, 0xca59,
+  0xca5a, 0xca5b, 0xca5c, 0xca5d, 0xca5e, 0xca5f, 0xca60, 0xca61,
+  0xca62, 0xca63, 0xca64, 0xca65, 0xca66, 0xca67, 0xca68, 0xca69,
+  0xca6a, 0xca6b, 0xca6c, 0xca6d, 0xca6e, 0xca6f, 0xca70, 0xca71,
+  0xca72, 0xca73, 0xca74, 0xca75, 0xca76, 0xca77, 0xca78, 0xca79,
+  0xca7a, 0xca7b, 0xca7c, 0xca7d, 0xca7e, 0xca80, 0xca81, 0xca82,
+  0xca83, 0xca84, 0xca85, 0xca86, 0xca87, 0xca88, 0xca89, 0xca8a,
+  0xca8b, 0xca8c, 0xca8d, 0xca8e, 0xca8f, 0xca90, 0xca91, 0xca92,
+  0xca93, 0xca94, 0xca95, 0xca96, 0xca97, 0xca98, 0xca99, 0xca9a,
+  0xca9b, 0xca9c, 0xca9d, 0xca9e, 0xca9f, 0xcaa0, 0xcb40, 0xcb41,
+  0xcb42, 0xcb43, 0xcb44, 0xcb45, 0xcb46, 0xcb47, 0xcb48, 0xcb49,
+  0xcb4a, 0xcb4b, 0xcb4c, 0xcb4d, 0xcb4e, 0xcb4f, 0xcb50, 0xcb51,
+  0xcb52, 0xcb53, 0xcb54, 0xcb55, 0xcb56, 0xcb57, 0xcb58, 0xcb59,
+  0xcb5a, 0xcb5b, 0xcb5c, 0xcb5d, 0xcb5e, 0xcb5f, 0xcb60, 0xcb61,
+  0xcb62, 0xcb63, 0xcb64, 0xcb65, 0xcb66, 0xcb67, 0xcb68, 0xcb69,
+  0xcb6a, 0xcb6b, 0xcb6c, 0xcb6d, 0xcb6e, 0xcb6f, 0xcb70, 0xcb71,
+  0xcb72, 0xcb73, 0xcb74, 0xcb75, 0xcb76, 0xcb77, 0xcb78, 0xcb79,
+  0xcb7a, 0xcb7b, 0xcb7c, 0xcb7d, 0xcb7e, 0xcb80, 0xcb81, 0xcb82,
+  0xcb83, 0xcb84, 0xcb85, 0xcb86, 0xcb87, 0xcb88, 0xcb89, 0xcb8a,
+  0xcb8b, 0xcb8c, 0xcb8d, 0xcb8e, 0xcb8f, 0xcb90, 0xcb91, 0xcb92,
+  0xcb93, 0xcb94, 0xcb95, 0xcb96, 0xcb97, 0xcb98, 0xcb99, 0xcb9a,
+  0xcb9b, 0xcb9c, 0xcb9d, 0xcb9e, 0xcb9f, 0xcba0, 0xcc40, 0xcc41,
+  0xcc42, 0xcc43, 0xcc44, 0xcc45, 0xcc46, 0xcc47, 0xcc48, 0xcc49,
+  0xcc4a, 0xcc4b, 0xcc4c, 0xcc4d, 0xcc4e, 0xcc4f, 0xcc50, 0xcc51,
+  0xcc52, 0xcc53, 0xcc54, 0xcc55, 0xcc56, 0xcc57, 0xcc58, 0xcc59,
+  0xcc5a, 0xcc5b, 0xcc5c, 0xcc5d, 0xcc5e, 0xcc5f, 0xcc60, 0xcc61,
+  0xcc62, 0xcc63, 0xcc64, 0xcc65, 0xcc66, 0xcc67, 0xcc68, 0xcc69,
+  0xcc6a, 0xcc6b, 0xcc6c, 0xcc6d, 0xcc6e, 0xcc6f, 0xcc70, 0xcc71,
+  0xcc72, 0xcc73, 0xcc74, 0xcc75, 0xcc76, 0xcc77, 0xcc78, 0xcc79,
+  0xcc7a, 0xcc7b, 0xcc7c, 0xcc7d, 0xcc7e, 0xcc80, 0xcc81, 0xcc82,
+  0xcc83, 0xcc84, 0xcc85, 0xcc86, 0xcc87, 0xcc88, 0xcc89, 0xcc8a,
+  0xcc8b, 0xcc8c, 0xcc8d, 0xcc8e, 0xcc8f, 0xcc90, 0xcc91, 0xcc92,
+  0xcc93, 0xcc94, 0xcc95, 0xcc96, 0xcc97, 0xcc98, 0xcc99, 0xcc9a,
+  0xcc9b, 0xcc9c, 0xcc9d, 0xcc9e, 0xcc9f, 0xcca0, 0xcd40, 0xcd41,
+  0xcd42, 0xcd43, 0xcd44, 0xcd45, 0xcd46, 0xcd47, 0xcd48, 0xcd49,
+  0xcd4a, 0xcd4b, 0xcd4c, 0xcd4d, 0xcd4e, 0xcd4f, 0xcd50, 0xcd51,
+  0xcd52, 0xcd53, 0xcd54, 0xcd55, 0xcd56, 0xcd57, 0xcd58, 0xcd59,
+  0xcd5a, 0xcd5b, 0xcd5c, 0xcd5d, 0xcd5e, 0xcd5f, 0xcd60, 0xcd61,
+  0xcd62, 0xcd63, 0xcd64, 0xcd65, 0xcd66, 0xcd67, 0xcd68, 0xcd69,
+  0xcd6a, 0xcd6b, 0xcd6c, 0xcd6d, 0xcd6e, 0xcd6f, 0xcd70, 0xcd71,
+  0xcd72, 0xcd73, 0xcd74, 0xcd75, 0xcd76, 0xcd77, 0xcd78, 0xcd79,
+  0xcd7a, 0xcd7b, 0xcd7c, 0xcd7d, 0xcd7e, 0xcd80, 0xcd81, 0xcd82,
+  0xcd83, 0xcd84, 0xcd85, 0xcd86, 0xcd87, 0xcd88, 0xcd89, 0xcd8a,
+  0xcd8b, 0xcd8c, 0xcd8d, 0xcd8e, 0xcd8f, 0xcd90, 0xcd91, 0xcd92,
+  0xcd93, 0xcd94, 0xcd95, 0xcd96, 0xcd97, 0xcd98, 0xcd99, 0xcd9a,
+  0xcd9b, 0xcd9c, 0xcd9d, 0xcd9e, 0xcd9f, 0xcda0, 0xce40, 0xce41,
+  0xce42, 0xce43, 0xce44, 0xce45, 0xce46, 0xce47, 0xce48, 0xce49,
+  0xce4a, 0xce4b, 0xce4c, 0xce4d, 0xce4e, 0xce4f, 0xce50, 0xce51,
+  0xce52, 0xce53, 0xce54, 0xce55, 0xce56, 0xce57, 0xce58, 0xce59,
+  0xce5a, 0xce5b, 0xce5c, 0xce5d, 0xce5e, 0xce5f, 0xce60, 0xce61,
+  0xce62, 0xce63, 0xce64, 0xce65, 0xce66, 0xce67, 0xce68, 0xce69,
+  0xce6a, 0xce6b, 0xce6c, 0xce6d, 0xce6e, 0xce6f, 0xce70, 0xce71,
+  0xce72, 0xce73, 0xce74, 0xce75, 0xce76, 0xce77, 0xce78, 0xce79,
+  0xce7a, 0xce7b, 0xce7c, 0xce7d, 0xce7e, 0xce80, 0xce81, 0xce82,
+  0xce83, 0xce84, 0xce85, 0xce86, 0xce87, 0xce88, 0xce89, 0xce8a,
+  0xce8b, 0xce8c, 0xce8d, 0xce8e, 0xce8f, 0xce90, 0xce91, 0xce92,
+  0xce93, 0xce94, 0xce95, 0xce96, 0xce97, 0xce98, 0xce99, 0xce9a,
+  0xce9b, 0xce9c, 0xce9d, 0xce9e, 0xce9f, 0xcea0, 0xcf40, 0xcf41,
+  0xcf42, 0xcf43, 0xcf44, 0xcf45, 0xcf46, 0xcf47, 0xcf48, 0xcf49,
+  0xcf4a, 0xcf4b, 0xcf4c, 0xcf4d, 0xcf4e, 0xcf4f, 0xcf50, 0xcf51,
+  0xcf52, 0xcf53, 0xcf54, 0xcf55, 0xcf56, 0xcf57, 0xcf58, 0xcf59,
+  0xcf5a, 0xcf5b, 0xcf5c, 0xcf5d, 0xcf5e, 0xcf5f, 0xcf60, 0xcf61,
+  0xcf62, 0xcf63, 0xcf64, 0xcf65, 0xcf66, 0xcf67, 0xcf68, 0xcf69,
+  0xcf6a, 0xcf6b, 0xcf6c, 0xcf6d, 0xcf6e, 0xcf6f, 0xcf70, 0xcf71,
+  0xcf72, 0xcf73, 0xcf74, 0xcf75, 0xcf76, 0xcf77, 0xcf78, 0xcf79,
+  0xcf7a, 0xcf7b, 0xcf7c, 0xcf7d, 0xcf7e, 0xcf80, 0xcf81, 0xcf82,
+  0xcf83, 0xcf84, 0xcf85, 0xcf86, 0xcf87, 0xcf88, 0xcf89, 0xcf8a,
+  0xcf8b, 0xcf8c, 0xcf8d, 0xcf8e, 0xcf8f, 0xcf90, 0xcf91, 0xcf92,
+  0xcf93, 0xcf94, 0xcf95, 0xcf96, 0xcf97, 0xcf98, 0xcf99, 0xcf9a,
+  0xcf9b, 0xcf9c, 0xcf9d, 0xcf9e, 0xcf9f, 0xcfa0, 0xd040, 0xd041,
+  0xd042, 0xd043, 0xd044, 0xd045, 0xd046, 0xd047, 0xd048, 0xd049,
+  0xd04a, 0xd04b, 0xd04c, 0xd04d, 0xd04e, 0xd04f, 0xd050, 0xd051,
+  0xd052, 0xd053, 0xd054, 0xd055, 0xd056, 0xd057, 0xd058, 0xd059,
+  0xd05a, 0xd05b, 0xd05c, 0xd05d, 0xd05e, 0xd05f, 0xd060, 0xd061,
+  0xd062, 0xd063, 0xd064, 0xd065, 0xd066, 0xd067, 0xd068, 0xd069,
+  0xd06a, 0xd06b, 0xd06c, 0xd06d, 0xd06e, 0xd06f, 0xd070, 0xd071,
+  0xd072, 0xd073, 0xd074, 0xd075, 0xd076, 0xd077, 0xd078, 0xd079,
+  0xd07a, 0xd07b, 0xd07c, 0xd07d, 0xd07e, 0xd080, 0xd081, 0xd082,
+  0xd083, 0xd084, 0xd085, 0xd086, 0xd087, 0xd088, 0xd089, 0xd08a,
+  0xd08b, 0xd08c, 0xd08d, 0xd08e, 0xd08f, 0xd090, 0xd091, 0xd092,
+  0xd093, 0xd094, 0xd095, 0xd096, 0xd097, 0xd098, 0xd099, 0xd09a,
+  0xd09b, 0xd09c, 0xd09d, 0xd09e, 0xd09f, 0xd0a0, 0xd140, 0xd141,
+  0xd142, 0xd143, 0xd144, 0xd145, 0xd146, 0xd147, 0xd148, 0xd149,
+  0xd14a, 0xd14b, 0xd14c, 0xd14d, 0xd14e, 0xd14f, 0xd150, 0xd151,
+  0xd152, 0xd153, 0xd154, 0xd155, 0xd156, 0xd157, 0xd158, 0xd159,
+  0xd15a, 0xd15b, 0xd15c, 0xd15d, 0xd15e, 0xd15f, 0xd160, 0xd161,
+  0xd162, 0xd163, 0xd164, 0xd165, 0xd166, 0xd167, 0xd168, 0xd169,
+  0xd16a, 0xd16b, 0xd16c, 0xd16d, 0xd16e, 0xd16f, 0xd170, 0xd171,
+  0xd172, 0xd173, 0xd174, 0xd175, 0xd176, 0xd177, 0xd178, 0xd179,
+  0xd17a, 0xd17b, 0xd17c, 0xd17d, 0xd17e, 0xd180, 0xd181, 0xd182,
+  0xd183, 0xd184, 0xd185, 0xd186, 0xd187, 0xd188, 0xd189, 0xd18a,
+  0xd18b, 0xd18c, 0xd18d, 0xd18e, 0xd18f, 0xd190, 0xd191, 0xd192,
+  0xd193, 0xd194, 0xd195, 0xd196, 0xd197, 0xd198, 0xd199, 0xd19a,
+  0xd19b, 0xd19c, 0xd19d, 0xd19e, 0xd19f, 0xd1a0, 0xd240, 0xd241,
+  0xd242, 0xd243, 0xd244, 0xd245, 0xd246, 0xd247, 0xd248, 0xd249,
+  0xd24a, 0xd24b, 0xd24c, 0xd24d, 0xd24e, 0xd24f, 0xd250, 0xd251,
+  0xd252, 0xd253, 0xd254, 0xd255, 0xd256, 0xd257, 0xd258, 0xd259,
+  0xd25a, 0xd25b, 0xd25c, 0xd25d, 0xd25e, 0xd25f, 0xd260, 0xd261,
+  0xd262, 0xd263, 0xd264, 0xd265, 0xd266, 0xd267, 0xd268, 0xd269,
+  0xd26a, 0xd26b, 0xd26c, 0xd26d, 0xd26e, 0xd26f, 0xd270, 0xd271,
+  0xd272, 0xd273, 0xd274, 0xd275, 0xd276, 0xd277, 0xd278, 0xd279,
+  0xd27a, 0xd27b, 0xd27c, 0xd27d, 0xd27e, 0xd280, 0xd281, 0xd282,
+  0xd283, 0xd284, 0xd285, 0xd286, 0xd287, 0xd288, 0xd289, 0xd28a,
+  0xd28b, 0xd28c, 0xd28d, 0xd28e, 0xd28f, 0xd290, 0xd291, 0xd292,
+  0xd293, 0xd294, 0xd295, 0xd296, 0xd297, 0xd298, 0xd299, 0xd29a,
+  0xd29b, 0xd29c, 0xd29d, 0xd29e, 0xd29f, 0xd2a0, 0xd340, 0xd341,
+  0xd342, 0xd343, 0xd344, 0xd345, 0xd346, 0xd347, 0xd348, 0xd349,
+  0xd34a, 0xd34b, 0xd34c, 0xd34d, 0xd34e, 0xd34f, 0xd350, 0xd351,
+  0xd352, 0xd353, 0xd354, 0xd355, 0xd356, 0xd357, 0xd358, 0xd359,
+  0xd35a, 0xd35b, 0xd35c, 0xd35d, 0xd35e, 0xd35f, 0xd360, 0xd361,
+  0xd362, 0xd363, 0xd364, 0xd365, 0xd366, 0xd367, 0xd368, 0xd369,
+  0xd36a, 0xd36b, 0xd36c, 0xd36d, 0xd36e, 0xd36f, 0xd370, 0xd371,
+  0xd372, 0xd373, 0xd374, 0xd375, 0xd376, 0xd377, 0xd378, 0xd379,
+  0xd37a, 0xd37b, 0xd37c, 0xd37d, 0xd37e, 0xd380, 0xd381, 0xd382,
+  0xd383, 0xd384, 0xd385, 0xd386, 0xd387, 0xd388, 0xd389, 0xd38a,
+  0xd38b, 0xd38c, 0xd38d, 0xd38e, 0xd38f, 0xd390, 0xd391, 0xd392,
+  0xd393, 0xd394, 0xd395, 0xd396, 0xd397, 0xd398, 0xd399, 0xd39a,
+  0xd39b, 0xd39c, 0xd39d, 0xd39e, 0xd39f, 0xd3a0, 0xd440, 0xd441,
+  0xd442, 0xd443, 0xd444, 0xd445, 0xd446, 0xd447, 0xd448, 0xd449,
+  0xd44a, 0xd44b, 0xd44c, 0xd44d, 0xd44e, 0xd44f, 0xd450, 0xd451,
+  0xd452, 0xd453, 0xd454, 0xd455, 0xd456, 0xd457, 0xd458, 0xd459,
+  0xd45a, 0xd45b, 0xd45c, 0xd45d, 0xd45e, 0xd45f, 0xd460, 0xd461,
+  0xd462, 0xd463, 0xd464, 0xd465, 0xd466, 0xd467, 0xd468, 0xd469,
+  0xd46a, 0xd46b, 0xd46c, 0xd46d, 0xd46e, 0xd46f, 0xd470, 0xd471,
+  0xd472, 0xd473, 0xd474, 0xd475, 0xd476, 0xd477, 0xd478, 0xd479,
+  0xd47a, 0xd47b, 0xd47c, 0xd47d, 0xd47e, 0xd480, 0xd481, 0xd482,
+  0xd483, 0xd484, 0xd485, 0xd486, 0xd487, 0xd488, 0xd489, 0xd48a,
+  0xd48b, 0xd48c, 0xd48d, 0xd48e, 0xd48f, 0xd490, 0xd491, 0xd492,
+  0xd493, 0xd494, 0xd495, 0xd496, 0xd497, 0xd498, 0xd499, 0xd49a,
+  0xd49b, 0xd49c, 0xd49d, 0xd49e, 0xd49f, 0xd4a0, 0xd540, 0xd541,
+  0xd542, 0xd543, 0xd544, 0xd545, 0xd546, 0xd547, 0xd548, 0xd549,
+  0xd54a, 0xd54b, 0xd54c, 0xd54d, 0xd54e, 0xd54f, 0xd550, 0xd551,
+  0xd552, 0xd553, 0xd554, 0xd555, 0xd556, 0xd557, 0xd558, 0xd559,
+  0xd55a, 0xd55b, 0xd55c, 0xd55d, 0xd55e, 0xd55f, 0xd560, 0xd561,
+  0xd562, 0xd563, 0xd564, 0xd565, 0xd566, 0xd567, 0xd568, 0xd569,
+  0xd56a, 0xd56b, 0xd56c, 0xd56d, 0xd56e, 0xd56f, 0xd570, 0xd571,
+  0xd572, 0xd573, 0xd574, 0xd575, 0xd576, 0xd577, 0xd578, 0xd579,
+  0xd57a, 0xd57b, 0xd57c, 0xd57d, 0xd57e, 0xd580, 0xd581, 0xd582,
+  0xd583, 0xd584, 0xd585, 0xd586, 0xd587, 0xd588, 0xd589, 0xd58a,
+  0xd58b, 0xd58c, 0xd58d, 0xd58e, 0xd58f, 0xd590, 0xd591, 0xd592,
+  0xd593, 0xd594, 0xd595, 0xd596, 0xd597, 0xd598, 0xd599, 0xd59a,
+  0xd59b, 0xd59c, 0xd59d, 0xd59e, 0xd59f, 0xd5a0, 0xd640, 0xd641,
+  0xd642, 0xd643, 0xd644, 0xd645, 0xd646, 0xd647, 0xd648, 0xd649,
+  0xd64a, 0xd64b, 0xd64c, 0xd64d, 0xd64e, 0xd64f, 0xd650, 0xd651,
+  0xd652, 0xd653, 0xd654, 0xd655, 0xd656, 0xd657, 0xd658, 0xd659,
+  0xd65a, 0xd65b, 0xd65c, 0xd65d, 0xd65e, 0xd65f, 0xd660, 0xd661,
+  0xd662, 0xd663, 0xd664, 0xd665, 0xd666, 0xd667, 0xd668, 0xd669,
+  0xd66a, 0xd66b, 0xd66c, 0xd66d, 0xd66e, 0xd66f, 0xd670, 0xd671,
+  0xd672, 0xd673, 0xd674, 0xd675, 0xd676, 0xd677, 0xd678, 0xd679,
+  0xd67a, 0xd67b, 0xd67c, 0xd67d, 0xd67e, 0xd680, 0xd681, 0xd682,
+  0xd683, 0xd684, 0xd685, 0xd686, 0xd687, 0xd688, 0xd689, 0xd68a,
+  0xd68b, 0xd68c, 0xd68d, 0xd68e, 0xd68f, 0xd690, 0xd691, 0xd692,
+  0xd693, 0xd694, 0xd695, 0xd696, 0xd697, 0xd698, 0xd699, 0xd69a,
+  0xd69b, 0xd69c, 0xd69d, 0xd69e, 0xd69f, 0xd6a0, 0xd740, 0xd741,
+  0xd742, 0xd743, 0xd744, 0xd745, 0xd746, 0xd747, 0xd748, 0xd749,
+  0xd74a, 0xd74b, 0xd74c, 0xd74d, 0xd74e, 0xd74f, 0xd750, 0xd751,
+  0xd752, 0xd753, 0xd754, 0xd755, 0xd756, 0xd757, 0xd758, 0xd759,
+  0xd75a, 0xd75b, 0xd75c, 0xd75d, 0xd75e, 0xd75f, 0xd760, 0xd761,
+  0xd762, 0xd763, 0xd764, 0xd765, 0xd766, 0xd767, 0xd768, 0xd769,
+  0xd76a, 0xd76b, 0xd76c, 0xd76d, 0xd76e, 0xd76f, 0xd770, 0xd771,
+  0xd772, 0xd773, 0xd774, 0xd775, 0xd776, 0xd777, 0xd778, 0xd779,
+  0xd77a, 0xd77b, 0xd77c, 0xd77d, 0xd77e, 0xd780, 0xd781, 0xd782,
+  0xd783, 0xd784, 0xd785, 0xd786, 0xd787, 0xd788, 0xd789, 0xd78a,
+  0xd78b, 0xd78c, 0xd78d, 0xd78e, 0xd78f, 0xd790, 0xd791, 0xd792,
+  0xd793, 0xd794, 0xd795, 0xd796, 0xd797, 0xd798, 0xd799, 0xd79a,
+  0xd79b, 0xd79c, 0xd79d, 0xd79e, 0xd79f, 0xd7a0, 0xd840, 0xd841,
+  0xd842, 0xd843, 0xd844, 0xd845, 0xd846, 0xd847, 0xd848, 0xd849,
+  0xd84a, 0xd84b, 0xd84c, 0xd84d, 0xd84e, 0xd84f, 0xd850, 0xd851,
+  0xd852, 0xd853, 0xd854, 0xd855, 0xd856, 0xd857, 0xd858, 0xd859,
+  0xd85a, 0xd85b, 0xd85c, 0xd85d, 0xd85e, 0xd85f, 0xd860, 0xd861,
+  0xd862, 0xd863, 0xd864, 0xd865, 0xd866, 0xd867, 0xd868, 0xd869,
+  0xd86a, 0xd86b, 0xd86c, 0xd86d, 0xd86e, 0xd86f, 0xd870, 0xd871,
+  0xd872, 0xd873, 0xd874, 0xd875, 0xd876, 0xd877, 0xd878, 0xd879,
+  0xd87a, 0xd87b, 0xd87c, 0xd87d, 0xd87e, 0xd880, 0xd881, 0xd882,
+  0xd883, 0xd884, 0xd885, 0xd886, 0xd887, 0xd888, 0xd889, 0xd88a,
+  0xd88b, 0xd88c, 0xd88d, 0xd88e, 0xd88f, 0xd890, 0xd891, 0xd892,
+  0xd893, 0xd894, 0xd895, 0xd896, 0xd897, 0xd898, 0xd899, 0xd89a,
+  0xd89b, 0xd89c, 0xd89d, 0xd89e, 0xd89f, 0xd8a0, 0xd940, 0xd941,
+  0xd942, 0xd943, 0xd944, 0xd945, 0xd946, 0xd947, 0xd948, 0xd949,
+  0xd94a, 0xd94b, 0xd94c, 0xd94d, 0xd94e, 0xd94f, 0xd950, 0xd951,
+  0xd952, 0xd953, 0xd954, 0xd955, 0xd956, 0xd957, 0xd958, 0xd959,
+  0xd95a, 0xd95b, 0xd95c, 0xd95d, 0xd95e, 0xd95f, 0xd960, 0xd961,
+  0xd962, 0xd963, 0xd964, 0xd965, 0xd966, 0xd967, 0xd968, 0xd969,
+  0xd96a, 0xd96b, 0xd96c, 0xd96d, 0xd96e, 0xd96f, 0xd970, 0xd971,
+  0xd972, 0xd973, 0xd974, 0xd975, 0xd976, 0xd977, 0xd978, 0xd979,
+  0xd97a, 0xd97b, 0xd97c, 0xd97d, 0xd97e, 0xd980, 0xd981, 0xd982,
+  0xd983, 0xd984, 0xd985, 0xd986, 0xd987, 0xd988, 0xd989, 0xd98a,
+  0xd98b, 0xd98c, 0xd98d, 0xd98e, 0xd98f, 0xd990, 0xd991, 0xd992,
+  0xd993, 0xd994, 0xd995, 0xd996, 0xd997, 0xd998, 0xd999, 0xd99a,
+  0xd99b, 0xd99c, 0xd99d, 0xd99e, 0xd99f, 0xd9a0, 0xda40, 0xda41,
+  0xda42, 0xda43, 0xda44, 0xda45, 0xda46, 0xda47, 0xda48, 0xda49,
+  0xda4a, 0xda4b, 0xda4c, 0xda4d, 0xda4e, 0xda4f, 0xda50, 0xda51,
+  0xda52, 0xda53, 0xda54, 0xda55, 0xda56, 0xda57, 0xda58, 0xda59,
+  0xda5a, 0xda5b, 0xda5c, 0xda5d, 0xda5e, 0xda5f, 0xda60, 0xda61,
+  0xda62, 0xda63, 0xda64, 0xda65, 0xda66, 0xda67, 0xda68, 0xda69,
+  0xda6a, 0xda6b, 0xda6c, 0xda6d, 0xda6e, 0xda6f, 0xda70, 0xda71,
+  0xda72, 0xda73, 0xda74, 0xda75, 0xda76, 0xda77, 0xda78, 0xda79,
+  0xda7a, 0xda7b, 0xda7c, 0xda7d, 0xda7e, 0xda80, 0xda81, 0xda82,
+  0xda83, 0xda84, 0xda85, 0xda86, 0xda87, 0xda88, 0xda89, 0xda8a,
+  0xda8b, 0xda8c, 0xda8d, 0xda8e, 0xda8f, 0xda90, 0xda91, 0xda92,
+  0xda93, 0xda94, 0xda95, 0xda96, 0xda97, 0xda98, 0xda99, 0xda9a,
+  0xda9b, 0xda9c, 0xda9d, 0xda9e, 0xda9f, 0xdaa0, 0xdb40, 0xdb41,
+  0xdb42, 0xdb43, 0xdb44, 0xdb45, 0xdb46, 0xdb47, 0xdb48, 0xdb49,
+  0xdb4a, 0xdb4b, 0xdb4c, 0xdb4d, 0xdb4e, 0xdb4f, 0xdb50, 0xdb51,
+  0xdb52, 0xdb53, 0xdb54, 0xdb55, 0xdb56, 0xdb57, 0xdb58, 0xdb59,
+  0xdb5a, 0xdb5b, 0xdb5c, 0xdb5d, 0xdb5e, 0xdb5f, 0xdb60, 0xdb61,
+  0xdb62, 0xdb63, 0xdb64, 0xdb65, 0xdb66, 0xdb67, 0xdb68, 0xdb69,
+  0xdb6a, 0xdb6b, 0xdb6c, 0xdb6d, 0xdb6e, 0xdb6f, 0xdb70, 0xdb71,
+  0xdb72, 0xdb73, 0xdb74, 0xdb75, 0xdb76, 0xdb77, 0xdb78, 0xdb79,
+  0xdb7a, 0xdb7b, 0xdb7c, 0xdb7d, 0xdb7e, 0xdb80, 0xdb81, 0xdb82,
+  0xdb83, 0xdb84, 0xdb85, 0xdb86, 0xdb87, 0xdb88, 0xdb89, 0xdb8a,
+  0xdb8b, 0xdb8c, 0xdb8d, 0xdb8e, 0xdb8f, 0xdb90, 0xdb91, 0xdb92,
+  0xdb93, 0xdb94, 0xdb95, 0xdb96, 0xdb97, 0xdb98, 0xdb99, 0xdb9a,
+  0xdb9b, 0xdb9c, 0xdb9d, 0xdb9e, 0xdb9f, 0xdba0, 0xdc40, 0xdc41,
+  0xdc42, 0xdc43, 0xdc44, 0xdc45, 0xdc46, 0xdc47, 0xdc48, 0xdc49,
+  0xdc4a, 0xdc4b, 0xdc4c, 0xdc4d, 0xdc4e, 0xdc4f, 0xdc50, 0xdc51,
+  0xdc52, 0xdc53, 0xdc54, 0xdc55, 0xdc56, 0xdc57, 0xdc58, 0xdc59,
+  0xdc5a, 0xdc5b, 0xdc5c, 0xdc5d, 0xdc5e, 0xdc5f, 0xdc60, 0xdc61,
+  0xdc62, 0xdc63, 0xdc64, 0xdc65, 0xdc66, 0xdc67, 0xdc68, 0xdc69,
+  0xdc6a, 0xdc6b, 0xdc6c, 0xdc6d, 0xdc6e, 0xdc6f, 0xdc70, 0xdc71,
+  0xdc72, 0xdc73, 0xdc74, 0xdc75, 0xdc76, 0xdc77, 0xdc78, 0xdc79,
+  0xdc7a, 0xdc7b, 0xdc7c, 0xdc7d, 0xdc7e, 0xdc80, 0xdc81, 0xdc82,
+  0xdc83, 0xdc84, 0xdc85, 0xdc86, 0xdc87, 0xdc88, 0xdc89, 0xdc8a,
+  0xdc8b, 0xdc8c, 0xdc8d, 0xdc8e, 0xdc8f, 0xdc90, 0xdc91, 0xdc92,
+  0xdc93, 0xdc94, 0xdc95, 0xdc96, 0xdc97, 0xdc98, 0xdc99, 0xdc9a,
+  0xdc9b, 0xdc9c, 0xdc9d, 0xdc9e, 0xdc9f, 0xdca0, 0xdd40, 0xdd41,
+  0xdd42, 0xdd43, 0xdd44, 0xdd45, 0xdd46, 0xdd47, 0xdd48, 0xdd49,
+  0xdd4a, 0xdd4b, 0xdd4c, 0xdd4d, 0xdd4e, 0xdd4f, 0xdd50, 0xdd51,
+  0xdd52, 0xdd53, 0xdd54, 0xdd55, 0xdd56, 0xdd57, 0xdd58, 0xdd59,
+  0xdd5a, 0xdd5b, 0xdd5c, 0xdd5d, 0xdd5e, 0xdd5f, 0xdd60, 0xdd61,
+  0xdd62, 0xdd63, 0xdd64, 0xdd65, 0xdd66, 0xdd67, 0xdd68, 0xdd69,
+  0xdd6a, 0xdd6b, 0xdd6c, 0xdd6d, 0xdd6e, 0xdd6f, 0xdd70, 0xdd71,
+  0xdd72, 0xdd73, 0xdd74, 0xdd75, 0xdd76, 0xdd77, 0xdd78, 0xdd79,
+  0xdd7a, 0xdd7b, 0xdd7c, 0xdd7d, 0xdd7e, 0xdd80, 0xdd81, 0xdd82,
+  0xdd83, 0xdd84, 0xdd85, 0xdd86, 0xdd87, 0xdd88, 0xdd89, 0xdd8a,
+  0xdd8b, 0xdd8c, 0xdd8d, 0xdd8e, 0xdd8f, 0xdd90, 0xdd91, 0xdd92,
+  0xdd93, 0xdd94, 0xdd95, 0xdd96, 0xdd97, 0xdd98, 0xdd99, 0xdd9a,
+  0xdd9b, 0xdd9c, 0xdd9d, 0xdd9e, 0xdd9f, 0xdda0, 0xde40, 0xde41,
+  0xde42, 0xde43, 0xde44, 0xde45, 0xde46, 0xde47, 0xde48, 0xde49,
+  0xde4a, 0xde4b, 0xde4c, 0xde4d, 0xde4e, 0xde4f, 0xde50, 0xde51,
+  0xde52, 0xde53, 0xde54, 0xde55, 0xde56, 0xde57, 0xde58, 0xde59,
+  0xde5a, 0xde5b, 0xde5c, 0xde5d, 0xde5e, 0xde5f, 0xde60, 0xde61,
+  0xde62, 0xde63, 0xde64, 0xde65, 0xde66, 0xde67, 0xde68, 0xde69,
+  0xde6a, 0xde6b, 0xde6c, 0xde6d, 0xde6e, 0xde6f, 0xde70, 0xde71,
+  0xde72, 0xde73, 0xde74, 0xde75, 0xde76, 0xde77, 0xde78, 0xde79,
+  0xde7a, 0xde7b, 0xde7c, 0xde7d, 0xde7e, 0xde80, 0xde81, 0xde82,
+  0xde83, 0xde84, 0xde85, 0xde86, 0xde87, 0xde88, 0xde89, 0xde8a,
+  0xde8b, 0xde8c, 0xde8d, 0xde8e, 0xde8f, 0xde90, 0xde91, 0xde92,
+  0xde93, 0xde94, 0xde95, 0xde96, 0xde97, 0xde98, 0xde99, 0xde9a,
+  0xde9b, 0xde9c, 0xde9d, 0xde9e, 0xde9f, 0xdea0, 0xdf40, 0xdf41,
+  0xdf42, 0xdf43, 0xdf44, 0xdf45, 0xdf46, 0xdf47, 0xdf48, 0xdf49,
+  0xdf4a, 0xdf4b, 0xdf4c, 0xdf4d, 0xdf4e, 0xdf4f, 0xdf50, 0xdf51,
+  0xdf52, 0xdf53, 0xdf54, 0xdf55, 0xdf56, 0xdf57, 0xdf58, 0xdf59,
+  0xdf5a, 0xdf5b, 0xdf5c, 0xdf5d, 0xdf5e, 0xdf5f, 0xdf60, 0xdf61,
+  0xdf62, 0xdf63, 0xdf64, 0xdf65, 0xdf66, 0xdf67, 0xdf68, 0xdf69,
+  0xdf6a, 0xdf6b, 0xdf6c, 0xdf6d, 0xdf6e, 0xdf6f, 0xdf70, 0xdf71,
+  0xdf72, 0xdf73, 0xdf74, 0xdf75, 0xdf76, 0xdf77, 0xdf78, 0xdf79,
+  0xdf7a, 0xdf7b, 0xdf7c, 0xdf7d, 0xdf7e, 0xdf80, 0xdf81, 0xdf82,
+  0xdf83, 0xdf84, 0xdf85, 0xdf86, 0xdf87, 0xdf88, 0xdf89, 0xdf8a,
+  0xdf8b, 0xdf8c, 0xdf8d, 0xdf8e, 0xdf8f, 0xdf90, 0xdf91, 0xdf92,
+  0xdf93, 0xdf94, 0xdf95, 0xdf96, 0xdf97, 0xdf98, 0xdf99, 0xdf9a,
+  0xdf9b, 0xdf9c, 0xdf9d, 0xdf9e, 0xdf9f, 0xdfa0, 0xe040, 0xe041,
+  0xe042, 0xe043, 0xe044, 0xe045, 0xe046, 0xe047, 0xe048, 0xe049,
+  0xe04a, 0xe04b, 0xe04c, 0xe04d, 0xe04e, 0xe04f, 0xe050, 0xe051,
+  0xe052, 0xe053, 0xe054, 0xe055, 0xe056, 0xe057, 0xe058, 0xe059,
+  0xe05a, 0xe05b, 0xe05c, 0xe05d, 0xe05e, 0xe05f, 0xe060, 0xe061,
+  0xe062, 0xe063, 0xe064, 0xe065, 0xe066, 0xe067, 0xe068, 0xe069,
+  0xe06a, 0xe06b, 0xe06c, 0xe06d, 0xe06e, 0xe06f, 0xe070, 0xe071,
+  0xe072, 0xe073, 0xe074, 0xe075, 0xe076, 0xe077, 0xe078, 0xe079,
+  0xe07a, 0xe07b, 0xe07c, 0xe07d, 0xe07e, 0xe080, 0xe081, 0xe082,
+  0xe083, 0xe084, 0xe085, 0xe086, 0xe087, 0xe088, 0xe089, 0xe08a,
+  0xe08b, 0xe08c, 0xe08d, 0xe08e, 0xe08f, 0xe090, 0xe091, 0xe092,
+  0xe093, 0xe094, 0xe095, 0xe096, 0xe097, 0xe098, 0xe099, 0xe09a,
+  0xe09b, 0xe09c, 0xe09d, 0xe09e, 0xe09f, 0xe0a0, 0xe140, 0xe141,
+  0xe142, 0xe143, 0xe144, 0xe145, 0xe146, 0xe147, 0xe148, 0xe149,
+  0xe14a, 0xe14b, 0xe14c, 0xe14d, 0xe14e, 0xe14f, 0xe150, 0xe151,
+  0xe152, 0xe153, 0xe154, 0xe155, 0xe156, 0xe157, 0xe158, 0xe159,
+  0xe15a, 0xe15b, 0xe15c, 0xe15d, 0xe15e, 0xe15f, 0xe160, 0xe161,
+  0xe162, 0xe163, 0xe164, 0xe165, 0xe166, 0xe167, 0xe168, 0xe169,
+  0xe16a, 0xe16b, 0xe16c, 0xe16d, 0xe16e, 0xe16f, 0xe170, 0xe171,
+  0xe172, 0xe173, 0xe174, 0xe175, 0xe176, 0xe177, 0xe178, 0xe179,
+  0xe17a, 0xe17b, 0xe17c, 0xe17d, 0xe17e, 0xe180, 0xe181, 0xe182,
+  0xe183, 0xe184, 0xe185, 0xe186, 0xe187, 0xe188, 0xe189, 0xe18a,
+  0xe18b, 0xe18c, 0xe18d, 0xe18e, 0xe18f, 0xe190, 0xe191, 0xe192,
+  0xe193, 0xe194, 0xe195, 0xe196, 0xe197, 0xe198, 0xe199, 0xe19a,
+  0xe19b, 0xe19c, 0xe19d, 0xe19e, 0xe19f, 0xe1a0, 0xe240, 0xe241,
+  0xe242, 0xe243, 0xe244, 0xe245, 0xe246, 0xe247, 0xe248, 0xe249,
+  0xe24a, 0xe24b, 0xe24c, 0xe24d, 0xe24e, 0xe24f, 0xe250, 0xe251,
+  0xe252, 0xe253, 0xe254, 0xe255, 0xe256, 0xe257, 0xe258, 0xe259,
+  0xe25a, 0xe25b, 0xe25c, 0xe25d, 0xe25e, 0xe25f, 0xe260, 0xe261,
+  0xe262, 0xe263, 0xe264, 0xe265, 0xe266, 0xe267, 0xe268, 0xe269,
+  0xe26a, 0xe26b, 0xe26c, 0xe26d, 0xe26e, 0xe26f, 0xe270, 0xe271,
+  0xe272, 0xe273, 0xe274, 0xe275, 0xe276, 0xe277, 0xe278, 0xe279,
+  0xe27a, 0xe27b, 0xe27c, 0xe27d, 0xe27e, 0xe280, 0xe281, 0xe282,
+  0xe283, 0xe284, 0xe285, 0xe286, 0xe287, 0xe288, 0xe289, 0xe28a,
+  0xe28b, 0xe28c, 0xe28d, 0xe28e, 0xe28f, 0xe290, 0xe291, 0xe292,
+  0xe293, 0xe294, 0xe295, 0xe296, 0xe297, 0xe298, 0xe299, 0xe29a,
+  0xe29b, 0xe29c, 0xe29d, 0xe29e, 0xe29f, 0xe2a0, 0xe340, 0xe341,
+  0xe342, 0xe343, 0xe344, 0xe345, 0xe346, 0xe347, 0xe348, 0xe349,
+  0xe34a, 0xe34b, 0xe34c, 0xe34d, 0xe34e, 0xe34f, 0xe350, 0xe351,
+  0xe352, 0xe353, 0xe354, 0xe355, 0xe356, 0xe357, 0xe358, 0xe359,
+  0xe35a, 0xe35b, 0xe35c, 0xe35d, 0xe35e, 0xe35f, 0xe360, 0xe361,
+  0xe362, 0xe363, 0xe364, 0xe365, 0xe366, 0xe367, 0xe368, 0xe369,
+  0xe36a, 0xe36b, 0xe36c, 0xe36d, 0xe36e, 0xe36f, 0xe370, 0xe371,
+  0xe372, 0xe373, 0xe374, 0xe375, 0xe376, 0xe377, 0xe378, 0xe379,
+  0xe37a, 0xe37b, 0xe37c, 0xe37d, 0xe37e, 0xe380, 0xe381, 0xe382,
+  0xe383, 0xe384, 0xe385, 0xe386, 0xe387, 0xe388, 0xe389, 0xe38a,
+  0xe38b, 0xe38c, 0xe38d, 0xe38e, 0xe38f, 0xe390, 0xe391, 0xe392,
+  0xe393, 0xe394, 0xe395, 0xe396, 0xe397, 0xe398, 0xe399, 0xe39a,
+  0xe39b, 0xe39c, 0xe39d, 0xe39e, 0xe39f, 0xe3a0, 0xe440, 0xe441,
+  0xe442, 0xe443, 0xe444, 0xe445, 0xe446, 0xe447, 0xe448, 0xe449,
+  0xe44a, 0xe44b, 0xe44c, 0xe44d, 0xe44e, 0xe44f, 0xe450, 0xe451,
+  0xe452, 0xe453, 0xe454, 0xe455, 0xe456, 0xe457, 0xe458, 0xe459,
+  0xe45a, 0xe45b, 0xe45c, 0xe45d, 0xe45e, 0xe45f, 0xe460, 0xe461,
+  0xe462, 0xe463, 0xe464, 0xe465, 0xe466, 0xe467, 0xe468, 0xe469,
+  0xe46a, 0xe46b, 0xe46c, 0xe46d, 0xe46e, 0xe46f, 0xe470, 0xe471,
+  0xe472, 0xe473, 0xe474, 0xe475, 0xe476, 0xe477, 0xe478, 0xe479,
+  0xe47a, 0xe47b, 0xe47c, 0xe47d, 0xe47e, 0xe480, 0xe481, 0xe482,
+  0xe483, 0xe484, 0xe485, 0xe486, 0xe487, 0xe488, 0xe489, 0xe48a,
+  0xe48b, 0xe48c, 0xe48d, 0xe48e, 0xe48f, 0xe490, 0xe491, 0xe492,
+  0xe493, 0xe494, 0xe495, 0xe496, 0xe497, 0xe498, 0xe499, 0xe49a,
+  0xe49b, 0xe49c, 0xe49d, 0xe49e, 0xe49f, 0xe4a0, 0xe540, 0xe541,
+  0xe542, 0xe543, 0xe544, 0xe545, 0xe546, 0xe547, 0xe548, 0xe549,
+  0xe54a, 0xe54b, 0xe54c, 0xe54d, 0xe54e, 0xe54f, 0xe550, 0xe551,
+  0xe552, 0xe553, 0xe554, 0xe555, 0xe556, 0xe557, 0xe558, 0xe559,
+  0xe55a, 0xe55b, 0xe55c, 0xe55d, 0xe55e, 0xe55f, 0xe560, 0xe561,
+  0xe562, 0xe563, 0xe564, 0xe565, 0xe566, 0xe567, 0xe568, 0xe569,
+  0xe56a, 0xe56b, 0xe56c, 0xe56d, 0xe56e, 0xe56f, 0xe570, 0xe571,
+  0xe572, 0xe573, 0xe574, 0xe575, 0xe576, 0xe577, 0xe578, 0xe579,
+  0xe57a, 0xe57b, 0xe57c, 0xe57d, 0xe57e, 0xe580, 0xe581, 0xe582,
+  0xe583, 0xe584, 0xe585, 0xe586, 0xe587, 0xe588, 0xe589, 0xe58a,
+  0xe58b, 0xe58c, 0xe58d, 0xe58e, 0xe58f, 0xe590, 0xe591, 0xe592,
+  0xe593, 0xe594, 0xe595, 0xe596, 0xe597, 0xe598, 0xe599, 0xe59a,
+  0xe59b, 0xe59c, 0xe59d, 0xe59e, 0xe59f, 0xe5a0, 0xe640, 0xe641,
+  0xe642, 0xe643, 0xe644, 0xe645, 0xe646, 0xe647, 0xe648, 0xe649,
+  0xe64a, 0xe64b, 0xe64c, 0xe64d, 0xe64e, 0xe64f, 0xe650, 0xe651,
+  0xe652, 0xe653, 0xe654, 0xe655, 0xe656, 0xe657, 0xe658, 0xe659,
+  0xe65a, 0xe65b, 0xe65c, 0xe65d, 0xe65e, 0xe65f, 0xe660, 0xe661,
+  0xe662, 0xe663, 0xe664, 0xe665, 0xe666, 0xe667, 0xe668, 0xe669,
+  0xe66a, 0xe66b, 0xe66c, 0xe66d, 0xe66e, 0xe66f, 0xe670, 0xe671,
+  0xe672, 0xe673, 0xe674, 0xe675, 0xe676, 0xe677, 0xe678, 0xe679,
+  0xe67a, 0xe67b, 0xe67c, 0xe67d, 0xe67e, 0xe680, 0xe681, 0xe682,
+  0xe683, 0xe684, 0xe685, 0xe686, 0xe687, 0xe688, 0xe689, 0xe68a,
+  0xe68b, 0xe68c, 0xe68d, 0xe68e, 0xe68f, 0xe690, 0xe691, 0xe692,
+  0xe693, 0xe694, 0xe695, 0xe696, 0xe697, 0xe698, 0xe699, 0xe69a,
+  0xe69b, 0xe69c, 0xe69d, 0xe69e, 0xe69f, 0xe6a0, 0xe740, 0xe741,
+  0xe742, 0xe743, 0xe744, 0xe745, 0xe746, 0xe747, 0xe748, 0xe749,
+  0xe74a, 0xe74b, 0xe74c, 0xe74d, 0xe74e, 0xe74f, 0xe750, 0xe751,
+  0xe752, 0xe753, 0xe754, 0xe755, 0xe756, 0xe757, 0xe758, 0xe759,
+  0xe75a, 0xe75b, 0xe75c, 0xe75d, 0xe75e, 0xe75f, 0xe760, 0xe761,
+  0xe762, 0xe763, 0xe764, 0xe765, 0xe766, 0xe767, 0xe768, 0xe769,
+  0xe76a, 0xe76b, 0xe76c, 0xe76d, 0xe76e, 0xe76f, 0xe770, 0xe771,
+  0xe772, 0xe773, 0xe774, 0xe775, 0xe776, 0xe777, 0xe778, 0xe779,
+  0xe77a, 0xe77b, 0xe77c, 0xe77d, 0xe77e, 0xe780, 0xe781, 0xe782,
+  0xe783, 0xe784, 0xe785, 0xe786, 0xe787, 0xe788, 0xe789, 0xe78a,
+  0xe78b, 0xe78c, 0xe78d, 0xe78e, 0xe78f, 0xe790, 0xe791, 0xe792,
+  0xe793, 0xe794, 0xe795, 0xe796, 0xe797, 0xe798, 0xe799, 0xe79a,
+  0xe79b, 0xe79c, 0xe79d, 0xe79e, 0xe79f, 0xe7a0, 0xe840, 0xe841,
+  0xe842, 0xe843, 0xe844, 0xe845, 0xe846, 0xe847, 0xe848, 0xe849,
+  0xe84a, 0xe84b, 0xe84c, 0xe84d, 0xe84e, 0xe84f, 0xe850, 0xe851,
+  0xe852, 0xe853, 0xe854, 0xe855, 0xe856, 0xe857, 0xe858, 0xe859,
+  0xe85a, 0xe85b, 0xe85c, 0xe85d, 0xe85e, 0xe85f, 0xe860, 0xe861,
+  0xe862, 0xe863, 0xe864, 0xe865, 0xe866, 0xe867, 0xe868, 0xe869,
+  0xe86a, 0xe86b, 0xe86c, 0xe86d, 0xe86e, 0xe86f, 0xe870, 0xe871,
+  0xe872, 0xe873, 0xe874, 0xe875, 0xe876, 0xe877, 0xe878, 0xe879,
+  0xe87a, 0xe87b, 0xe87c, 0xe87d, 0xe87e, 0xe880, 0xe881, 0xe882,
+  0xe883, 0xe884, 0xe885, 0xe886, 0xe887, 0xe888, 0xe889, 0xe88a,
+  0xe88b, 0xe88c, 0xe88d, 0xe88e, 0xe88f, 0xe890, 0xe891, 0xe892,
+  0xe893, 0xe894, 0xe895, 0xe896, 0xe897, 0xe898, 0xe899, 0xe89a,
+  0xe89b, 0xe89c, 0xe89d, 0xe89e, 0xe89f, 0xe8a0, 0xe940, 0xe941,
+  0xe942, 0xe943, 0xe944, 0xe945, 0xe946, 0xe947, 0xe948, 0xe949,
+  0xe94a, 0xe94b, 0xe94c, 0xe94d, 0xe94e, 0xe94f, 0xe950, 0xe951,
+  0xe952, 0xe953, 0xe954, 0xe955, 0xe956, 0xe957, 0xe958, 0xe959,
+  0xe95a, 0xe95b, 0xe95c, 0xe95d, 0xe95e, 0xe95f, 0xe960, 0xe961,
+  0xe962, 0xe963, 0xe964, 0xe965, 0xe966, 0xe967, 0xe968, 0xe969,
+  0xe96a, 0xe96b, 0xe96c, 0xe96d, 0xe96e, 0xe96f, 0xe970, 0xe971,
+  0xe972, 0xe973, 0xe974, 0xe975, 0xe976, 0xe977, 0xe978, 0xe979,
+  0xe97a, 0xe97b, 0xe97c, 0xe97d, 0xe97e, 0xe980, 0xe981, 0xe982,
+  0xe983, 0xe984, 0xe985, 0xe986, 0xe987, 0xe988, 0xe989, 0xe98a,
+  0xe98b, 0xe98c, 0xe98d, 0xe98e, 0xe98f, 0xe990, 0xe991, 0xe992,
+  0xe993, 0xe994, 0xe995, 0xe996, 0xe997, 0xe998, 0xe999, 0xe99a,
+  0xe99b, 0xe99c, 0xe99d, 0xe99e, 0xe99f, 0xe9a0, 0xea40, 0xea41,
+  0xea42, 0xea43, 0xea44, 0xea45, 0xea46, 0xea47, 0xea48, 0xea49,
+  0xea4a, 0xea4b, 0xea4c, 0xea4d, 0xea4e, 0xea4f, 0xea50, 0xea51,
+  0xea52, 0xea53, 0xea54, 0xea55, 0xea56, 0xea57, 0xea58, 0xea59,
+  0xea5a, 0xea5b, 0xea5c, 0xea5d, 0xea5e, 0xea5f, 0xea60, 0xea61,
+  0xea62, 0xea63, 0xea64, 0xea65, 0xea66, 0xea67, 0xea68, 0xea69,
+  0xea6a, 0xea6b, 0xea6c, 0xea6d, 0xea6e, 0xea6f, 0xea70, 0xea71,
+  0xea72, 0xea73, 0xea74, 0xea75, 0xea76, 0xea77, 0xea78, 0xea79,
+  0xea7a, 0xea7b, 0xea7c, 0xea7d, 0xea7e, 0xea80, 0xea81, 0xea82,
+  0xea83, 0xea84, 0xea85, 0xea86, 0xea87, 0xea88, 0xea89, 0xea8a,
+  0xea8b, 0xea8c, 0xea8d, 0xea8e, 0xea8f, 0xea90, 0xea91, 0xea92,
+  0xea93, 0xea94, 0xea95, 0xea96, 0xea97, 0xea98, 0xea99, 0xea9a,
+  0xea9b, 0xea9c, 0xea9d, 0xea9e, 0xea9f, 0xeaa0, 0xeb40, 0xeb41,
+  0xeb42, 0xeb43, 0xeb44, 0xeb45, 0xeb46, 0xeb47, 0xeb48, 0xeb49,
+  0xeb4a, 0xeb4b, 0xeb4c, 0xeb4d, 0xeb4e, 0xeb4f, 0xeb50, 0xeb51,
+  0xeb52, 0xeb53, 0xeb54, 0xeb55, 0xeb56, 0xeb57, 0xeb58, 0xeb59,
+  0xeb5a, 0xeb5b, 0xeb5c, 0xeb5d, 0xeb5e, 0xeb5f, 0xeb60, 0xeb61,
+  0xeb62, 0xeb63, 0xeb64, 0xeb65, 0xeb66, 0xeb67, 0xeb68, 0xeb69,
+  0xeb6a, 0xeb6b, 0xeb6c, 0xeb6d, 0xeb6e, 0xeb6f, 0xeb70, 0xeb71,
+  0xeb72, 0xeb73, 0xeb74, 0xeb75, 0xeb76, 0xeb77, 0xeb78, 0xeb79,
+  0xeb7a, 0xeb7b, 0xeb7c, 0xeb7d, 0xeb7e, 0xeb80, 0xeb81, 0xeb82,
+  0xeb83, 0xeb84, 0xeb85, 0xeb86, 0xeb87, 0xeb88, 0xeb89, 0xeb8a,
+  0xeb8b, 0xeb8c, 0xeb8d, 0xeb8e, 0xeb8f, 0xeb90, 0xeb91, 0xeb92,
+  0xeb93, 0xeb94, 0xeb95, 0xeb96, 0xeb97, 0xeb98, 0xeb99, 0xeb9a,
+  0xeb9b, 0xeb9c, 0xeb9d, 0xeb9e, 0xeb9f, 0xeba0, 0xec40, 0xec41,
+  0xec42, 0xec43, 0xec44, 0xec45, 0xec46, 0xec47, 0xec48, 0xec49,
+  0xec4a, 0xec4b, 0xec4c, 0xec4d, 0xec4e, 0xec4f, 0xec50, 0xec51,
+  0xec52, 0xec53, 0xec54, 0xec55, 0xec56, 0xec57, 0xec58, 0xec59,
+  0xec5a, 0xec5b, 0xec5c, 0xec5d, 0xec5e, 0xec5f, 0xec60, 0xec61,
+  0xec62, 0xec63, 0xec64, 0xec65, 0xec66, 0xec67, 0xec68, 0xec69,
+  0xec6a, 0xec6b, 0xec6c, 0xec6d, 0xec6e, 0xec6f, 0xec70, 0xec71,
+  0xec72, 0xec73, 0xec74, 0xec75, 0xec76, 0xec77, 0xec78, 0xec79,
+  0xec7a, 0xec7b, 0xec7c, 0xec7d, 0xec7e, 0xec80, 0xec81, 0xec82,
+  0xec83, 0xec84, 0xec85, 0xec86, 0xec87, 0xec88, 0xec89, 0xec8a,
+  0xec8b, 0xec8c, 0xec8d, 0xec8e, 0xec8f, 0xec90, 0xec91, 0xec92,
+  0xec93, 0xec94, 0xec95, 0xec96, 0xec97, 0xec98, 0xec99, 0xec9a,
+  0xec9b, 0xec9c, 0xec9d, 0xec9e, 0xec9f, 0xeca0, 0xed40, 0xed41,
+  0xed42, 0xed43, 0xed44, 0xed45, 0xed46, 0xed47, 0xed48, 0xed49,
+  0xed4a, 0xed4b, 0xed4c, 0xed4d, 0xed4e, 0xed4f, 0xed50, 0xed51,
+  0xed52, 0xed53, 0xed54, 0xed55, 0xed56, 0xed57, 0xed58, 0xed59,
+  0xed5a, 0xed5b, 0xed5c, 0xed5d, 0xed5e, 0xed5f, 0xed60, 0xed61,
+  0xed62, 0xed63, 0xed64, 0xed65, 0xed66, 0xed67, 0xed68, 0xed69,
+  0xed6a, 0xed6b, 0xed6c, 0xed6d, 0xed6e, 0xed6f, 0xed70, 0xed71,
+  0xed72, 0xed73, 0xed74, 0xed75, 0xed76, 0xed77, 0xed78, 0xed79,
+  0xed7a, 0xed7b, 0xed7c, 0xed7d, 0xed7e, 0xed80, 0xed81, 0xed82,
+  0xed83, 0xed84, 0xed85, 0xed86, 0xed87, 0xed88, 0xed89, 0xed8a,
+  0xed8b, 0xed8c, 0xed8d, 0xed8e, 0xed8f, 0xed90, 0xed91, 0xed92,
+  0xed93, 0xed94, 0xed95, 0xed96, 0xed97, 0xed98, 0xed99, 0xed9a,
+  0xed9b, 0xed9c, 0xed9d, 0xed9e, 0xed9f, 0xeda0, 0xee40, 0xee41,
+  0xee42, 0xee43, 0xee44, 0xee45, 0xee46, 0xee47, 0xee48, 0xee49,
+  0xee4a, 0xee4b, 0xee4c, 0xee4d, 0xee4e, 0xee4f, 0xee50, 0xee51,
+  0xee52, 0xee53, 0xee54, 0xee55, 0xee56, 0xee57, 0xee58, 0xee59,
+  0xee5a, 0xee5b, 0xee5c, 0xee5d, 0xee5e, 0xee5f, 0xee60, 0xee61,
+  0xee62, 0xee63, 0xee64, 0xee65, 0xee66, 0xee67, 0xee68, 0xee69,
+  0xee6a, 0xee6b, 0xee6c, 0xee6d, 0xee6e, 0xee6f, 0xee70, 0xee71,
+  0xee72, 0xee73, 0xee74, 0xee75, 0xee76, 0xee77, 0xee78, 0xee79,
+  0xee7a, 0xee7b, 0xee7c, 0xee7d, 0xee7e, 0xee80, 0xee81, 0xee82,
+  0xee83, 0xee84, 0xee85, 0xee86, 0xee87, 0xee88, 0xee89, 0xee8a,
+  0xee8b, 0xee8c, 0xee8d, 0xee8e, 0xee8f, 0xee90, 0xee91, 0xee92,
+  0xee93, 0xee94, 0xee95, 0xee96, 0xee97, 0xee98, 0xee99, 0xee9a,
+  0xee9b, 0xee9c, 0xee9d, 0xee9e, 0xee9f, 0xeea0, 0xef40, 0xef41,
+  0xef42, 0xef43, 0xef44, 0xef45, 0xef46, 0xef47, 0xef48, 0xef49,
+  0xef4a, 0xef4b, 0xef4c, 0xef4d, 0xef4e, 0xef4f, 0xef50, 0xef51,
+  0xef52, 0xef53, 0xef54, 0xef55, 0xef56, 0xef57, 0xef58, 0xef59,
+  0xef5a, 0xef5b, 0xef5c, 0xef5d, 0xef5e, 0xef5f, 0xef60, 0xef61,
+  0xef62, 0xef63, 0xef64, 0xef65, 0xef66, 0xef67, 0xef68, 0xef69,
+  0xef6a, 0xef6b, 0xef6c, 0xef6d, 0xef6e, 0xef6f, 0xef70, 0xef71,
+  0xef72, 0xef73, 0xef74, 0xef75, 0xef76, 0xef77, 0xef78, 0xef79,
+  0xef7a, 0xef7b, 0xef7c, 0xef7d, 0xef7e, 0xef80, 0xef81, 0xef82,
+  0xef83, 0xef84, 0xef85, 0xef86, 0xef87, 0xef88, 0xef89, 0xef8a,
+  0xef8b, 0xef8c, 0xef8d, 0xef8e, 0xef8f, 0xef90, 0xef91, 0xef92,
+  0xef93, 0xef94, 0xef95, 0xef96, 0xef97, 0xef98, 0xef99, 0xef9a,
+  0xef9b, 0xef9c, 0xef9d, 0xef9e, 0xef9f, 0xefa0, 0xf040, 0xf041,
+  0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047, 0xf048, 0xf049,
+  0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f, 0xf050, 0xf051,
+  0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057, 0xf058, 0xf059,
+  0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f, 0xf060, 0xf061,
+  0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067, 0xf068, 0xf069,
+  0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f, 0xf070, 0xf071,
+  0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077, 0xf078, 0xf079,
+  0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf080, 0xf081, 0xf082,
+  0xf083, 0xf084, 0xf085, 0xf086, 0xf087, 0xf088, 0xf089, 0xf08a,
+  0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f, 0xf090, 0xf091, 0xf092,
+  0xf093, 0xf094, 0xf095, 0xf096, 0xf097, 0xf098, 0xf099, 0xf09a,
+  0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f, 0xf0a0, 0xf140, 0xf141,
+  0xf142, 0xf143, 0xf144, 0xf145, 0xf146, 0xf147, 0xf148, 0xf149,
+  0xf14a, 0xf14b, 0xf14c, 0xf14d, 0xf14e, 0xf14f, 0xf150, 0xf151,
+  0xf152, 0xf153, 0xf154, 0xf155, 0xf156, 0xf157, 0xf158, 0xf159,
+  0xf15a, 0xf15b, 0xf15c, 0xf15d, 0xf15e, 0xf15f, 0xf160, 0xf161,
+  0xf162, 0xf163, 0xf164, 0xf165, 0xf166, 0xf167, 0xf168, 0xf169,
+  0xf16a, 0xf16b, 0xf16c, 0xf16d, 0xf16e, 0xf16f, 0xf170, 0xf171,
+  0xf172, 0xf173, 0xf174, 0xf175, 0xf176, 0xf177, 0xf178, 0xf179,
+  0xf17a, 0xf17b, 0xf17c, 0xf17d, 0xf17e, 0xf180, 0xf181, 0xf182,
+  0xf183, 0xf184, 0xf185, 0xf186, 0xf187, 0xf188, 0xf189, 0xf18a,
+  0xf18b, 0xf18c, 0xf18d, 0xf18e, 0xf18f, 0xf190, 0xf191, 0xf192,
+  0xf193, 0xf194, 0xf195, 0xf196, 0xf197, 0xf198, 0xf199, 0xf19a,
+  0xf19b, 0xf19c, 0xf19d, 0xf19e, 0xf19f, 0xf1a0, 0xf240, 0xf241,
+  0xf242, 0xf243, 0xf244, 0xf245, 0xf246, 0xf247, 0xf248, 0xf249,
+  0xf24a, 0xf24b, 0xf24c, 0xf24d, 0xf24e, 0xf24f, 0xf250, 0xf251,
+  0xf252, 0xf253, 0xf254, 0xf255, 0xf256, 0xf257, 0xf258, 0xf259,
+  0xf25a, 0xf25b, 0xf25c, 0xf25d, 0xf25e, 0xf25f, 0xf260, 0xf261,
+  0xf262, 0xf263, 0xf264, 0xf265, 0xf266, 0xf267, 0xf268, 0xf269,
+  0xf26a, 0xf26b, 0xf26c, 0xf26d, 0xf26e, 0xf26f, 0xf270, 0xf271,
+  0xf272, 0xf273, 0xf274, 0xf275, 0xf276, 0xf277, 0xf278, 0xf279,
+  0xf27a, 0xf27b, 0xf27c, 0xf27d, 0xf27e, 0xf280, 0xf281, 0xf282,
+  0xf283, 0xf284, 0xf285, 0xf286, 0xf287, 0xf288, 0xf289, 0xf28a,
+  0xf28b, 0xf28c, 0xf28d, 0xf28e, 0xf28f, 0xf290, 0xf291, 0xf292,
+  0xf293, 0xf294, 0xf295, 0xf296, 0xf297, 0xf298, 0xf299, 0xf29a,
+  0xf29b, 0xf29c, 0xf29d, 0xf29e, 0xf29f, 0xf2a0, 0xf340, 0xf341,
+  0xf342, 0xf343, 0xf344, 0xf345, 0xf346, 0xf347, 0xf348, 0xf349,
+  0xf34a, 0xf34b, 0xf34c, 0xf34d, 0xf34e, 0xf34f, 0xf350, 0xf351,
+  0xf352, 0xf353, 0xf354, 0xf355, 0xf356, 0xf357, 0xf358, 0xf359,
+  0xf35a, 0xf35b, 0xf35c, 0xf35d, 0xf35e, 0xf35f, 0xf360, 0xf361,
+  0xf362, 0xf363, 0xf364, 0xf365, 0xf366, 0xf367, 0xf368, 0xf369,
+  0xf36a, 0xf36b, 0xf36c, 0xf36d, 0xf36e, 0xf36f, 0xf370, 0xf371,
+  0xf372, 0xf373, 0xf374, 0xf375, 0xf376, 0xf377, 0xf378, 0xf379,
+  0xf37a, 0xf37b, 0xf37c, 0xf37d, 0xf37e, 0xf380, 0xf381, 0xf382,
+  0xf383, 0xf384, 0xf385, 0xf386, 0xf387, 0xf388, 0xf389, 0xf38a,
+  0xf38b, 0xf38c, 0xf38d, 0xf38e, 0xf38f, 0xf390, 0xf391, 0xf392,
+  0xf393, 0xf394, 0xf395, 0xf396, 0xf397, 0xf398, 0xf399, 0xf39a,
+  0xf39b, 0xf39c, 0xf39d, 0xf39e, 0xf39f, 0xf3a0, 0xf440, 0xf441,
+  0xf442, 0xf443, 0xf444, 0xf445, 0xf446, 0xf447, 0xf448, 0xf449,
+  0xf44a, 0xf44b, 0xf44c, 0xf44d, 0xf44e, 0xf44f, 0xf450, 0xf451,
+  0xf452, 0xf453, 0xf454, 0xf455, 0xf456, 0xf457, 0xf458, 0xf459,
+  0xf45a, 0xf45b, 0xf45c, 0xf45d, 0xf45e, 0xf45f, 0xf460, 0xf461,
+  0xf462, 0xf463, 0xf464, 0xf465, 0xf466, 0xf467, 0xf468, 0xf469,
+  0xf46a, 0xf46b, 0xf46c, 0xf46d, 0xf46e, 0xf46f, 0xf470, 0xf471,
+  0xf472, 0xf473, 0xf474, 0xf475, 0xf476, 0xf477, 0xf478, 0xf479,
+  0xf47a, 0xf47b, 0xf47c, 0xf47d, 0xf47e, 0xf480, 0xf481, 0xf482,
+  0xf483, 0xf484, 0xf485, 0xf486, 0xf487, 0xf488, 0xf489, 0xf48a,
+  0xf48b, 0xf48c, 0xf48d, 0xf48e, 0xf48f, 0xf490, 0xf491, 0xf492,
+  0xf493, 0xf494, 0xf495, 0xf496, 0xf497, 0xf498, 0xf499, 0xf49a,
+  0xf49b, 0xf49c, 0xf49d, 0xf49e, 0xf49f, 0xf4a0, 0xf540, 0xf541,
+  0xf542, 0xf543, 0xf544, 0xf545, 0xf546, 0xf547, 0xf548, 0xf549,
+  0xf54a, 0xf54b, 0xf54c, 0xf54d, 0xf54e, 0xf54f, 0xf550, 0xf551,
+  0xf552, 0xf553, 0xf554, 0xf555, 0xf556, 0xf557, 0xf558, 0xf559,
+  0xf55a, 0xf55b, 0xf55c, 0xf55d, 0xf55e, 0xf55f, 0xf560, 0xf561,
+  0xf562, 0xf563, 0xf564, 0xf565, 0xf566, 0xf567, 0xf568, 0xf569,
+  0xf56a, 0xf56b, 0xf56c, 0xf56d, 0xf56e, 0xf56f, 0xf570, 0xf571,
+  0xf572, 0xf573, 0xf574, 0xf575, 0xf576, 0xf577, 0xf578, 0xf579,
+  0xf57a, 0xf57b, 0xf57c, 0xf57d, 0xf57e, 0xf580, 0xf581, 0xf582,
+  0xf583, 0xf584, 0xf585, 0xf586, 0xf587, 0xf588, 0xf589, 0xf58a,
+  0xf58b, 0xf58c, 0xf58d, 0xf58e, 0xf58f, 0xf590, 0xf591, 0xf592,
+  0xf593, 0xf594, 0xf595, 0xf596, 0xf597, 0xf598, 0xf599, 0xf59a,
+  0xf59b, 0xf59c, 0xf59d, 0xf59e, 0xf59f, 0xf5a0, 0xf640, 0xf641,
+  0xf642, 0xf643, 0xf644, 0xf645, 0xf646, 0xf647, 0xf648, 0xf649,
+  0xf64a, 0xf64b, 0xf64c, 0xf64d, 0xf64e, 0xf64f, 0xf650, 0xf651,
+  0xf652, 0xf653, 0xf654, 0xf655, 0xf656, 0xf657, 0xf658, 0xf659,
+  0xf65a, 0xf65b, 0xf65c, 0xf65d, 0xf65e, 0xf65f, 0xf660, 0xf661,
+  0xf662, 0xf663, 0xf664, 0xf665, 0xf666, 0xf667, 0xf668, 0xf669,
+  0xf66a, 0xf66b, 0xf66c, 0xf66d, 0xf66e, 0xf66f, 0xf670, 0xf671,
+  0xf672, 0xf673, 0xf674, 0xf675, 0xf676, 0xf677, 0xf678, 0xf679,
+  0xf67a, 0xf67b, 0xf67c, 0xf67d, 0xf67e, 0xf680, 0xf681, 0xf682,
+  0xf683, 0xf684, 0xf685, 0xf686, 0xf687, 0xf688, 0xf689, 0xf68a,
+  0xf68b, 0xf68c, 0xf68d, 0xf68e, 0xf68f, 0xf690, 0xf691, 0xf692,
+  0xf693, 0xf694, 0xf695, 0xf696, 0xf697, 0xf698, 0xf699, 0xf69a,
+  0xf69b, 0xf69c, 0xf69d, 0xf69e, 0xf69f, 0xf6a0, 0xf740, 0xf741,
+  0xf742, 0xf743, 0xf744, 0xf745, 0xf746, 0xf747, 0xf748, 0xf749,
+  0xf74a, 0xf74b, 0xf74c, 0xf74d, 0xf74e, 0xf74f, 0xf750, 0xf751,
+  0xf752, 0xf753, 0xf754, 0xf755, 0xf756, 0xf757, 0xf758, 0xf759,
+  0xf75a, 0xf75b, 0xf75c, 0xf75d, 0xf75e, 0xf75f, 0xf760, 0xf761,
+  0xf762, 0xf763, 0xf764, 0xf765, 0xf766, 0xf767, 0xf768, 0xf769,
+  0xf76a, 0xf76b, 0xf76c, 0xf76d, 0xf76e, 0xf76f, 0xf770, 0xf771,
+  0xf772, 0xf773, 0xf774, 0xf775, 0xf776, 0xf777, 0xf778, 0xf779,
+  0xf77a, 0xf77b, 0xf77c, 0xf77d, 0xf77e, 0xf780, 0xf781, 0xf782,
+  0xf783, 0xf784, 0xf785, 0xf786, 0xf787, 0xf788, 0xf789, 0xf78a,
+  0xf78b, 0xf78c, 0xf78d, 0xf78e, 0xf78f, 0xf790, 0xf791, 0xf792,
+  0xf793, 0xf794, 0xf795, 0xf796, 0xf797, 0xf798, 0xf799, 0xf79a,
+  0xf79b, 0xf79c, 0xf79d, 0xf79e, 0xf79f, 0xf7a0, 0xf840, 0xf841,
+  0xf842, 0xf843, 0xf844, 0xf845, 0xf846, 0xf847, 0xf848, 0xf849,
+  0xf84a, 0xf84b, 0xf84c, 0xf84d, 0xf84e, 0xf84f, 0xf850, 0xf851,
+  0xf852, 0xf853, 0xf854, 0xf855, 0xf856, 0xf857, 0xf858, 0xf859,
+  0xf85a, 0xf85b, 0xf85c, 0xf85d, 0xf85e, 0xf85f, 0xf860, 0xf861,
+  0xf862, 0xf863, 0xf864, 0xf865, 0xf866, 0xf867, 0xf868, 0xf869,
+  0xf86a, 0xf86b, 0xf86c, 0xf86d, 0xf86e, 0xf86f, 0xf870, 0xf871,
+  0xf872, 0xf873, 0xf874, 0xf875, 0xf876, 0xf877, 0xf878, 0xf879,
+  0xf87a, 0xf87b, 0xf87c, 0xf87d, 0xf87e, 0xf880, 0xf881, 0xf882,
+  0xf883, 0xf884, 0xf885, 0xf886, 0xf887, 0xf888, 0xf889, 0xf88a,
+  0xf88b, 0xf88c, 0xf88d, 0xf88e, 0xf88f, 0xf890, 0xf891, 0xf892,
+  0xf893, 0xf894, 0xf895, 0xf896, 0xf897, 0xf898, 0xf899, 0xf89a,
+  0xf89b, 0xf89c, 0xf89d, 0xf89e, 0xf89f, 0xf8a0, 0xf940, 0xf941,
+  0xf942, 0xf943, 0xf944, 0xf945, 0xf946, 0xf947, 0xf948, 0xf949,
+  0xf94a, 0xf94b, 0xf94c, 0xf94d, 0xf94e, 0xf94f, 0xf950, 0xf951,
+  0xf952, 0xf953, 0xf954, 0xf955, 0xf956, 0xf957, 0xf958, 0xf959,
+  0xf95a, 0xf95b, 0xf95c, 0xf95d, 0xf95e, 0xf95f, 0xf960, 0xf961,
+  0xf962, 0xf963, 0xf964, 0xf965, 0xf966, 0xf967, 0xf968, 0xf969,
+  0xf96a, 0xf96b, 0xf96c, 0xf96d, 0xf96e, 0xf96f, 0xf970, 0xf971,
+  0xf972, 0xf973, 0xf974, 0xf975, 0xf976, 0xf977, 0xf978, 0xf979,
+  0xf97a, 0xf97b, 0xf97c, 0xf97d, 0xf97e, 0xf980, 0xf981, 0xf982,
+  0xf983, 0xf984, 0xf985, 0xf986, 0xf987, 0xf988, 0xf989, 0xf98a,
+  0xf98b, 0xf98c, 0xf98d, 0xf98e, 0xf98f, 0xf990, 0xf991, 0xf992,
+  0xf993, 0xf994, 0xf995, 0xf996, 0xf997, 0xf998, 0xf999, 0xf99a,
+  0xf99b, 0xf99c, 0xf99d, 0xf99e, 0xf99f, 0xf9a0, 0xfa40, 0xfa41,
+  0xfa42, 0xfa43, 0xfa44, 0xfa45, 0xfa46, 0xfa47, 0xfa48, 0xfa49,
+  0xfa4a, 0xfa4b, 0xfa4c, 0xfa4d, 0xfa4e, 0xfa4f, 0xfa50, 0xfa51,
+  0xfa52, 0xfa53, 0xfa54, 0xfa55, 0xfa56, 0xfa57, 0xfa58, 0xfa59,
+  0xfa5a, 0xfa5b, 0xfa5c, 0xfa5d, 0xfa5e, 0xfa5f, 0xfa60, 0xfa61,
+  0xfa62, 0xfa63, 0xfa64, 0xfa65, 0xfa66, 0xfa67, 0xfa68, 0xfa69,
+  0xfa6a, 0xfa6b, 0xfa6c, 0xfa6d, 0xfa6e, 0xfa6f, 0xfa70, 0xfa71,
+  0xfa72, 0xfa73, 0xfa74, 0xfa75, 0xfa76, 0xfa77, 0xfa78, 0xfa79,
+  0xfa7a, 0xfa7b, 0xfa7c, 0xfa7d, 0xfa7e, 0xfa80, 0xfa81, 0xfa82,
+  0xfa83, 0xfa84, 0xfa85, 0xfa86, 0xfa87, 0xfa88, 0xfa89, 0xfa8a,
+  0xfa8b, 0xfa8c, 0xfa8d, 0xfa8e, 0xfa8f, 0xfa90, 0xfa91, 0xfa92,
+  0xfa93, 0xfa94, 0xfa95, 0xfa96, 0xfa97, 0xfa98, 0xfa99, 0xfa9a,
+  0xfa9b, 0xfa9c, 0xfa9d, 0xfa9e, 0xfa9f, 0xfaa0, 0xfb40, 0xfb41,
+  0xfb42, 0xfb43, 0xfb44, 0xfb45, 0xfb46, 0xfb47, 0xfb48, 0xfb49,
+  0xfb4a, 0xfb4b, 0xfb4c, 0xfb4d, 0xfb4e, 0xfb4f, 0xfb50, 0xfb51,
+  0xfb52, 0xfb53, 0xfb54, 0xfb55, 0xfb56, 0xfb57, 0xfb58, 0xfb59,
+  0xfb5a, 0xfb5b, 0xfb5c, 0xfb5d, 0xfb5e, 0xfb5f, 0xfb60, 0xfb61,
+  0xfb62, 0xfb63, 0xfb64, 0xfb65, 0xfb66, 0xfb67, 0xfb68, 0xfb69,
+  0xfb6a, 0xfb6b, 0xfb6c, 0xfb6d, 0xfb6e, 0xfb6f, 0xfb70, 0xfb71,
+  0xfb72, 0xfb73, 0xfb74, 0xfb75, 0xfb76, 0xfb77, 0xfb78, 0xfb79,
+  0xfb7a, 0xfb7b, 0xfb7c, 0xfb7d, 0xfb7e, 0xfb80, 0xfb81, 0xfb82,
+  0xfb83, 0xfb84, 0xfb85, 0xfb86, 0xfb87, 0xfb88, 0xfb89, 0xfb8a,
+  0xfb8b, 0xfb8c, 0xfb8d, 0xfb8e, 0xfb8f, 0xfb90, 0xfb91, 0xfb92,
+  0xfb93, 0xfb94, 0xfb95, 0xfb96, 0xfb97, 0xfb98, 0xfb99, 0xfb9a,
+  0xfb9b, 0xfb9c, 0xfb9d, 0xfb9e, 0xfb9f, 0xfba0, 0xfc40, 0xfc41,
+  0xfc42, 0xfc43, 0xfc44, 0xfc45, 0xfc46, 0xfc47, 0xfc48, 0xfc49,
+  0xfc4a, 0xfc4b, 0xfc4c, 0xfc4d, 0xfc4e, 0xfc4f, 0xfc50, 0xfc51,
+  0xfc52, 0xfc53, 0xfc54, 0xfc55, 0xfc56, 0xfc57, 0xfc58, 0xfc59,
+  0xfc5a, 0xfc5b, 0xfc5c, 0xfc5d, 0xfc5e, 0xfc5f, 0xfc60, 0xfc61,
+  0xfc62, 0xfc63, 0xfc64, 0xfc65, 0xfc66, 0xfc67, 0xfc68, 0xfc69,
+  0xfc6a, 0xfc6b, 0xfc6c, 0xfc6d, 0xfc6e, 0xfc6f, 0xfc70, 0xfc71,
+  0xfc72, 0xfc73, 0xfc74, 0xfc75, 0xfc76, 0xfc77, 0xfc78, 0xfc79,
+  0xfc7a, 0xfc7b, 0xfc7c, 0xfc7d, 0xfc7e, 0xfc80, 0xfc81, 0xfc82,
+  0xfc83, 0xfc84, 0xfc85, 0xfc86, 0xfc87, 0xfc88, 0xfc89, 0xfc8a,
+  0xfc8b, 0xfc8c, 0xfc8d, 0xfc8e, 0xfc8f, 0xfc90, 0xfc91, 0xfc92,
+  0xfc93, 0xfc94, 0xfc95, 0xfc96, 0xfc97, 0xfc98, 0xfc99, 0xfc9a,
+  0xfc9b, 0xfc9c, 0xfc9d, 0xfc9e, 0xfc9f, 0xfca0, 0xfd40, 0xfd41,
+  0xfd42, 0xfd43, 0xfd44, 0xfd45, 0xfd46, 0xfd47, 0xfd48, 0xfd49,
+  0xfd4a, 0xfd4b, 0xfd4c, 0xfd4d, 0xfd4e, 0xfd4f, 0xfd50, 0xfd51,
+  0xfd52, 0xfd53, 0xfd54, 0xfd55, 0xfd56, 0xfd57, 0xfd58, 0xfd59,
+  0xfd5a, 0xfd5b, 0xfd5c, 0xfd5d, 0xfd5e, 0xfd5f, 0xfd60, 0xfd61,
+  0xfd62, 0xfd63, 0xfd64, 0xfd65, 0xfd66, 0xfd67, 0xfd68, 0xfd69,
+  0xfd6a, 0xfd6b, 0xfd6c, 0xfd6d, 0xfd6e, 0xfd6f, 0xfd70, 0xfd71,
+  0xfd72, 0xfd73, 0xfd74, 0xfd75, 0xfd76, 0xfd77, 0xfd78, 0xfd79,
+  0xfd7a, 0xfd7b, 0xfd7c, 0xfd7d, 0xfd7e, 0xfd80, 0xfd81, 0xfd82,
+  0xfd83, 0xfd84, 0xfd85, 0xfd86, 0xfd87, 0xfd88, 0xfd89, 0xfd8a,
+  0xfd8b, 0xfd8c, 0xfd8d, 0xfd8e, 0xfd8f, 0xfd90, 0xfd91, 0xfd92,
+  0xfd93, 0xfd94, 0xfd95, 0xfd96, 0xfd97, 0xfd98, 0xfd99, 0xfd9a,
+  0xfd9b, 0xfd9c, 0xfd9d, 0xfd9e, 0xfd9f, 0xfda0, 0xfe40, 0xfe41,
+  0xfe42, 0xfe43, 0xfe44, 0xfe45, 0xfe46, 0xfe47, 0xfe48, 0xfe49,
+  0xfe4a, 0xfe4b, 0xfe4c, 0xfe4d, 0xfe4e, 0xfe4f, 0xa955, 0xa968,
+  0xa969, 0xa96a, 0xa96b, 0xa96c, 0xa96d, 0xa96e, 0xa96f, 0xa970,
+  0xa971, 0xa972, 0xa973, 0xa974, 0xa975, 0xa976, 0xa977, 0xa978,
+  0xa979, 0xa97a, 0xa97b, 0xa97c, 0xa97d, 0xa97e, 0xa980, 0xa981,
+  0xa982, 0xa983, 0xa984, 0xa985, 0xa986, 0xa987, 0xa988, 0xa956,
+  0xa957,
+};
+
+typedef struct {
+  unsigned short indx; /* index into big table */
+  unsigned short used; /* bitmask of used entries */
+} Summary16;
+
+static const Summary16 gbkext_inv_uni2indx_page02[14] = {
+  /* 0x0200 */
+  {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 },
+  {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 },
+  {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 },
+  {    0, 0x0c00 }, {    2, 0x0200 },
+};
+static const Summary16 gbkext_inv_uni2indx_page20[44] = {
+  /* 0x2000 */
+  {    3, 0x0000 }, {    3, 0x0029 }, {    6, 0x0020 }, {    7, 0x0020 },
+  {    8, 0x0000 }, {    8, 0x0000 }, {    8, 0x0000 }, {    8, 0x0000 },
+  {    8, 0x0000 }, {    8, 0x0000 }, {    8, 0x0000 }, {    8, 0x0000 },
+  {    8, 0x0000 }, {    8, 0x0000 }, {    8, 0x0000 }, {    8, 0x0000 },
+  /* 0x2100 */
+  {    8, 0x0220 }, {   10, 0x0000 }, {   10, 0x0002 }, {   11, 0x0000 },
+  {   11, 0x0000 }, {   11, 0x0000 }, {   11, 0x0000 }, {   11, 0x0000 },
+  {   11, 0x0000 }, {   11, 0x03c0 }, {   15, 0x0000 }, {   15, 0x0000 },
+  {   15, 0x0000 }, {   15, 0x0000 }, {   15, 0x0000 }, {   15, 0x0000 },
+  /* 0x2200 */
+  {   15, 0x0000 }, {   15, 0x8020 }, {   17, 0x0008 }, {   18, 0x0000 },
+  {   18, 0x0000 }, {   18, 0x0004 }, {   19, 0x00c0 }, {   21, 0x0000 },
+  {   21, 0x0000 }, {   21, 0x0020 }, {   22, 0x0000 }, {   22, 0x8000 },
+};
+static const Summary16 gbkext_inv_uni2indx_page25[17] = {
+  /* 0x2500 */
+  {   23, 0x0000 }, {   23, 0x0000 }, {   23, 0x0000 }, {   23, 0x0000 },
+  {   23, 0x0000 }, {   23, 0xffff }, {   39, 0xffff }, {   55, 0x000f },
+  {   59, 0xfffe }, {   74, 0x0038 }, {   77, 0x0000 }, {   77, 0x3000 },
+  {   79, 0x0000 }, {   79, 0x0000 }, {   79, 0x003c }, {   83, 0x0000 },
+  /* 0x2600 */
+  {   83, 0x0200 },
+};
+static const Summary16 gbkext_inv_uni2indx_page30[16] = {
+  /* 0x3000 */
+  {   84, 0x00c0 }, {   86, 0x6004 }, {   89, 0x03fe }, {   98, 0x0000 },
+  {   98, 0x0000 }, {   98, 0x0000 }, {   98, 0x0000 }, {   98, 0x0000 },
+  {   98, 0x0000 }, {   98, 0x7800 }, {  102, 0x0000 }, {  102, 0x0000 },
+  {  102, 0x0000 }, {  102, 0x0000 }, {  102, 0x0000 }, {  102, 0x7000 },
+};
+static const Summary16 gbkext_inv_uni2indx_page32[30] = {
+  /* 0x3200 */
+  {  105, 0x0000 }, {  105, 0x0000 }, {  105, 0x0000 }, {  105, 0x0002 },
+  {  106, 0x0000 }, {  106, 0x0000 }, {  106, 0x0000 }, {  106, 0x0000 },
+  {  106, 0x0000 }, {  106, 0x0000 }, {  106, 0x0008 }, {  107, 0x0000 },
+  {  107, 0x0000 }, {  107, 0x0000 }, {  107, 0x0000 }, {  107, 0x0000 },
+  /* 0x3300 */
+  {  107, 0x0000 }, {  107, 0x0000 }, {  107, 0x0000 }, {  107, 0x0000 },
+  {  107, 0x0000 }, {  107, 0x0000 }, {  107, 0x0000 }, {  107, 0x0000 },
+  {  107, 0xc000 }, {  109, 0x7000 }, {  112, 0x0002 }, {  113, 0x0000 },
+  {  113, 0x4010 }, {  115, 0x0026 },
+};
+static const Summary16 gbkext_inv_uni2indx_page4e[1307] = {
+  /* 0x4e00 */
+  {  118, 0x8074 }, {  123, 0x8084 }, {  126, 0xc24b }, {  133, 0x10aa },
+  {  138, 0x0457 }, {  144, 0x0ca2 }, {  149, 0xfdbc }, {  161, 0xbff4 },
+  {  173, 0x04bf }, {  181, 0x72c1 }, {  188, 0x8408 }, {  191, 0x73d3 },
+  {  201, 0x9100 }, {  204, 0x1c05 }, {  209, 0xe2c5 }, {  217, 0x5712 },
+  /* 0x4f00 */
+  {  224, 0x19fd }, {  234, 0x307c }, {  241, 0x730a }, {  248, 0xcaaa },
+  {  256, 0x1fb7 }, {  267, 0x0054 }, {  270, 0x6d46 }, {  278, 0x27a6 },
+  {  286, 0x54e7 }, {  295, 0xd76d }, {  306, 0x2816 }, {  311, 0x7fdf },
+  {  325, 0x3bc7 }, {  335, 0x0a7c }, {  342, 0x18b5 }, {  349, 0xbaf5 },
+  /* 0x5000 */
+  {  360, 0x4fff }, {  373, 0x68eb }, {  382, 0x889d }, {  389, 0xabff },
+  {  402, 0x2e77 }, {  412, 0xebdf }, {  425, 0xefdf }, {  439, 0x373f },
+  {  450, 0xdede }, {  462, 0xffff }, {  478, 0xec57 }, {  488, 0xf3fb },
+  {  501, 0x7fff }, {  516, 0xfbbf }, {  530, 0x8f3f }, {  541, 0xf7d7 },
+  /* 0x5100 */
+  {  554, 0xf73f }, {  567, 0xfffb }, {  582, 0xfffd }, {  597, 0x7fff },
+  {  612, 0xd484 }, {  618, 0xeb8d }, {  628, 0x86db }, {  637, 0xc404 },
+  {  641, 0xccd8 }, {  649, 0xe51b }, {  658, 0x67ca }, {  667, 0xc710 },
+  {  673, 0x652e }, {  681, 0xd7fd }, {  694, 0x57ec }, {  704, 0x4096 },
+  /* 0x5200 */
+  {  709, 0x9a30 }, {  715, 0xd039 }, {  722, 0x94ee }, {  731, 0x5036 },
+  {  737, 0xcbf0 }, {  746, 0xafac }, {  756, 0x795d }, {  766, 0x5ffb },
+  {  779, 0xfef9 }, {  792, 0x17f6 }, {  802, 0xc0f0 }, {  808, 0x3ff1 },
+  {  819, 0xf577 }, {  831, 0x7eba }, {  842, 0xffef }, {  857, 0x39fe },
+  /* 0x5300 */
+  {  868, 0x5e9e }, {  878, 0xd91e }, {  887, 0xbbb4 }, {  897, 0x31ff },
+  {  908, 0x3855 }, {  915, 0x2b11 }, {  921, 0x3520 }, {  926, 0x7a44 },
+  {  933, 0xc58b }, {  941, 0x5adf }, {  952, 0xbc93 }, {  961, 0x77bf },
+  {  974, 0xc0f9 }, {  982, 0x742d }, {  990, 0x0086 }, {  993, 0xc410 },
+  /* 0x5400 */
+  {  997, 0x08a5 }, { 1002, 0x1710 }, { 1007, 0x0434 }, { 1011, 0xa4c9 },
+  { 1018, 0xf2b6 }, { 1028, 0xe402 }, { 1033, 0xfeab }, { 1045, 0xc611 },
+  { 1051, 0x27aa }, { 1059, 0xd18a }, { 1066, 0x4027 }, { 1071, 0x56e5 },
+  { 1080, 0x0c28 }, { 1084, 0x0940 }, { 1087, 0x981f }, { 1095, 0x4bf3 },
+  /* 0x5500 */
+  { 1105, 0x7d3d }, { 1116, 0xf7ec }, { 1128, 0x2b62 }, { 1135, 0x2f74 },
+  { 1144, 0xf9a5 }, { 1154, 0xef9e }, { 1166, 0x8b0d }, { 1173, 0xa61f },
+  { 1182, 0x7060 }, { 1187, 0x4ced }, { 1196, 0xff7f }, { 1211, 0x9555 },
+  { 1219, 0xcdcf }, { 1230, 0x4fa1 }, { 1238, 0x6285 }, { 1244, 0x9f53 },
+  /* 0x5600 */
+  { 1254, 0x2cfc }, { 1263, 0x36ff }, { 1275, 0xcf67 }, { 1286, 0x75a9 },
+  { 1295, 0x8fff }, { 1308, 0xec6f }, { 1319, 0xe0eb }, { 1328, 0xe7bd },
+  { 1340, 0x3f9f }, { 1352, 0xfff7 }, { 1367, 0x7ff7 }, { 1381, 0xef7f },
+  { 1395, 0xfbff }, { 1410, 0x136f }, { 1419, 0xd7e8 }, { 1429, 0x19cc },
+  /* 0x5700 */
+  { 1436, 0xf8a7 }, { 1446, 0x6fff }, { 1460, 0x08f7 }, { 1468, 0xb1f6 },
+  { 1478, 0x0b7a }, { 1486, 0x037c }, { 1493, 0x50ac }, { 1499, 0xe737 },
+  { 1510, 0xe783 }, { 1519, 0xf7f3 }, { 1532, 0x9520 }, { 1537, 0xfeeb },
+  { 1550, 0x37f3 }, { 1561, 0x58cb }, { 1569, 0x5fee }, { 1581, 0xd8ef },
+  /* 0x5800 */
+  { 1592, 0xd73a }, { 1602, 0xbddd }, { 1614, 0xfbec }, { 1626, 0xffde },
+  { 1640, 0xcfef }, { 1653, 0xbeed }, { 1665, 0xe7df }, { 1678, 0xbfff },
+  { 1693, 0xfdd4 }, { 1704, 0x39f3 }, { 1714, 0xfcff }, { 1728, 0xefff },
+  { 1743, 0xffdd }, { 1757, 0xffdd }, { 1771, 0xa7ef }, { 1783, 0xfdb6 },
+  /* 0x5900 */
+  { 1795, 0x5f6b }, { 1806, 0x698f }, { 1815, 0x114f }, { 1822, 0xe86d },
+  { 1831, 0x3469 }, { 1838, 0xfa0d }, { 1847, 0xffda }, { 1860, 0xdca7 },
+  { 1870, 0xda21 }, { 1877, 0xbd33 }, { 1887, 0x30c7 }, { 1894, 0xb5fb },
+  { 1906, 0xf3bf }, { 1919, 0xca60 }, { 1925, 0xeed7 }, { 1937, 0x75ff },
+  /* 0x5a00 */
+  { 1950, 0xec05 }, { 1957, 0x6ef5 }, { 1968, 0xfdd6 }, { 1980, 0xefa9 },
+  { 1991, 0xf9be }, { 2003, 0xfbdf }, { 2017, 0xfb7b }, { 2030, 0x7b0f },
+  { 2040, 0xffff }, { 2056, 0xf3fb }, { 2069, 0xfbff }, { 2084, 0xbed3 },
+  { 2095, 0xedf9 }, { 2107, 0xeeab }, { 2118, 0xf5b4 }, { 2128, 0xfffd },
+  /* 0x5b00 */
+  { 2143, 0xfdff }, { 2158, 0xff3f }, { 2172, 0xffff }, { 2188, 0xff6b },
+  { 2201, 0xfffe }, { 2216, 0x4044 }, { 2219, 0xe983 }, { 2227, 0xdbd4 },
+  { 2237, 0x6444 }, { 2242, 0x8057 }, { 2248, 0xf380 }, { 2255, 0x1c86 },
+  { 2261, 0xef0b }, { 2271, 0x1ff2 }, { 2281, 0xbecd }, { 2292, 0x60fe },
+  /* 0x5c00 */
+  { 2301, 0x79ad }, { 2311, 0xca8d }, { 2319, 0xef4b }, { 2330, 0x00ed },
+  { 2336, 0x30d8 }, { 2342, 0xbddc }, { 2353, 0x3f94 }, { 2362, 0x79fd },
+  { 2374, 0xcef9 }, { 2385, 0xe02c }, { 2391, 0xc5f3 }, { 2401, 0x5e55 },
+  { 2410, 0xf7ed }, { 2423, 0xfdfb }, { 2437, 0xda8d }, { 2446, 0xf7fe },
+  /* 0x5d00 */
+  { 2460, 0xbf33 }, { 2471, 0xb7af }, { 2483, 0x9d2f }, { 2493, 0x9fef },
+  { 2506, 0xe37f }, { 2518, 0xd6ff }, { 2531, 0x65ff }, { 2543, 0xffef },
+  { 2558, 0xfffb }, { 2573, 0xddff }, { 2587, 0xffff }, { 2603, 0xff7f },
+  { 2618, 0xdfdf }, { 2632, 0x97ff }, { 2645, 0x3419 }, { 2651, 0x9f61 },
+  /* 0x5e00 */
+  { 2660, 0x6e91 }, { 2668, 0xc08c }, { 2673, 0x9f3f }, { 2685, 0xc67d },
+  { 2695, 0xefcb }, { 2707, 0xb7cf }, { 2719, 0xfff9 }, { 2733, 0x42a3 },
+  { 2739, 0x732e }, { 2748, 0x2904 }, { 2752, 0xdf1e }, { 2763, 0xbc17 },
+  { 2772, 0xf9ff }, { 2786, 0xf7b1 }, { 2797, 0xfaff }, { 2811, 0x3b2f },
+  /* 0x5f00 */
+  { 2821, 0x72e0 }, { 2828, 0x7655 }, { 2837, 0x591e }, { 2845, 0xe9fd },
+  { 2857, 0xfffe }, { 2872, 0xde12 }, { 2880, 0xc9a9 }, { 2888, 0xe574 },
+  { 2897, 0xe048 }, { 2902, 0xec5a }, { 2911, 0x9afd }, { 2922, 0xcf5f },
+  { 2934, 0x4d87 }, { 2942, 0xdc38 }, { 2950, 0x936c }, { 2958, 0x16dd },
+  /* 0x6000 */
+  { 2967, 0x1b80 }, { 2972, 0xc58b }, { 2980, 0x701c }, { 2986, 0x67df },
+  { 2998, 0xd7f1 }, { 3009, 0xd9da }, { 3019, 0x4063 }, { 3024, 0x40b6 },
+  { 3030, 0xcde7 }, { 3041, 0x53ab }, { 3050, 0x46b6 }, { 3058, 0xe6e9 },
+  { 3068, 0xf39f }, { 3080, 0x4add }, { 3089, 0x043e }, { 3095, 0xf9a6 },
+  /* 0x6100 */
+  { 3105, 0x1cbc }, { 3113, 0x7bdf }, { 3126, 0xf726 }, { 3136, 0x7fff },
+  { 3151, 0xaaff }, { 3163, 0xdfdd }, { 3176, 0xfe7b }, { 3189, 0xff5e },
+  { 3202, 0xb7ff }, { 3216, 0xdfef }, { 3230, 0xec7f }, { 3242, 0xbf7f },
+  { 3256, 0xf2fb }, { 3268, 0xffe9 }, { 3281, 0xffbf }, { 3296, 0x7fdf },
+  /* 0x6200 */
+  { 3310, 0x02bf }, { 3318, 0x7218 }, { 3324, 0xabc9 }, { 3333, 0x1f67 },
+  { 3343, 0x8474 }, { 3349, 0xf6e1 }, { 3359, 0x0137 }, { 3365, 0x2db6 },
+  { 3374, 0xf9ee }, { 3386, 0x7211 }, { 3392, 0xe6c8 }, { 3400, 0x45dd },
+  { 3409, 0x880b }, { 3414, 0x6022 }, { 3418, 0x0c13 }, { 3423, 0x0f25 },
+  /* 0x6300 */
+  { 3430, 0xbc79 }, { 3440, 0x13bd }, { 3449, 0x72c0 }, { 3455, 0xd9fb },
+  { 3467, 0x0593 }, { 3473, 0x3fde }, { 3485, 0x9d71 }, { 3494, 0xf33d },
+  { 3505, 0x287a }, { 3512, 0xfeba }, { 3524, 0x8852 }, { 3529, 0xaa66 },
+  { 3537, 0x1daf }, { 3547, 0xbfba }, { 3559, 0xd9f4 }, { 3569, 0x5eab },
+  /* 0x6400 */
+  { 3579, 0x67d8 }, { 3588, 0xa7e6 }, { 3598, 0xcbbc }, { 3608, 0x5bef },
+  { 3620, 0xfa0d }, { 3629, 0xbeeb }, { 3641, 0xdd7f }, { 3654, 0xf8ff },
+  { 3667, 0xff4b }, { 3679, 0xbd99 }, { 3689, 0x8def }, { 3700, 0xea5e },
+  { 3710, 0x9fda }, { 3721, 0xbe7a }, { 3732, 0xffab }, { 3745, 0xffff },
+  /* 0x6500 */
+  { 3761, 0xfdfe }, { 3775, 0xfefb }, { 3789, 0x37df }, { 3801, 0x348f },
+  { 3809, 0x6cdf }, { 3820, 0x959d }, { 3829, 0xe7b3 }, { 3840, 0xff6a },
+  { 3852, 0xe77f }, { 3865, 0x6574 }, { 3873, 0x554d }, { 3881, 0xcdfe },
+  { 3893, 0x2785 }, { 3900, 0xff3b }, { 3913, 0x0c1a }, { 3918, 0xfb3c },
+  /* 0x6600 */
+  { 3929, 0x2bb2 }, { 3937, 0x5dc7 }, { 3947, 0x5e5e }, { 3957, 0xaf8d },
+  { 3967, 0x67f5 }, { 3978, 0x7b03 }, { 3986, 0x3ead }, { 3996, 0xbb2e },
+  { 4006, 0xef6b }, { 4018, 0xdf3d }, { 4030, 0xbe7f }, { 4043, 0xbdef },
+  { 4056, 0xffff }, { 4072, 0xc5ff }, { 4084, 0xfdbf }, { 4098, 0x2d62 },
+  /* 0x6700 */
+  { 4105, 0xd0fe }, { 4115, 0x574e }, { 4124, 0x42bf }, { 4133, 0xdbcd },
+  { 4144, 0x2cb2 }, { 4151, 0x2fb4 }, { 4160, 0x58dc }, { 4168, 0x2f52 },
+  { 4176, 0xf56d }, { 4187, 0x8a5e }, { 4195, 0x5253 }, { 4202, 0xfe16 },
+  { 4212, 0x7fe5 }, { 4224, 0x88e0 }, { 4229, 0x6dda }, { 4239, 0x5fe4 },
+  /* 0x6800 */
+  { 4249, 0x205e }, { 4255, 0xdf35 }, { 4266, 0xf9fd }, { 4279, 0x8c73 },
+  { 4287, 0xa880 }, { 4291, 0xffc4 }, { 4302, 0xf400 }, { 4307, 0xff2f },
+  { 4320, 0x7f95 }, { 4331, 0xff77 }, { 4345, 0x5e3b }, { 4355, 0xffd6 },
+  { 4368, 0xd5fa }, { 4379, 0xfadb }, { 4391, 0xbff6 }, { 4404, 0xe9dc },
+  /* 0x6900 */
+  { 4414, 0x97dd }, { 4425, 0x7ffa }, { 4438, 0xdfee }, { 4451, 0x5dee },
+  { 4462, 0xfffb }, { 4477, 0x9b6f }, { 4488, 0xb7b6 }, { 4499, 0xec7d },
+  { 4510, 0xdc2a }, { 4518, 0xe6cf }, { 4529, 0xd67f }, { 4541, 0xf76d },
+  { 4553, 0xabfd }, { 4565, 0x77ee }, { 4577, 0xdffe }, { 4591, 0x5ffb },
+  /* 0x6a00 */
+  { 4604, 0xfbff }, { 4619, 0x7e7f }, { 4632, 0x7afd }, { 4644, 0x9fdd },
+  { 4656, 0xff6f }, { 4670, 0xf4fe }, { 4682, 0xffdd }, { 4696, 0xedfd },
+  { 4709, 0xbfee }, { 4722, 0xff7c }, { 4735, 0xe5fe }, { 4747, 0xffff },
+  { 4763, 0xffff }, { 4779, 0xffff }, { 4795, 0xffff }, { 4811, 0xffff },
+  /* 0x6b00 */
+  { 4827, 0xffff }, { 4843, 0xffff }, { 4859, 0xff60 }, { 4869, 0xb97b },
+  { 4880, 0xed37 }, { 4891, 0xfdff }, { 4906, 0xfb03 }, { 4915, 0xe5ff },
+  { 4928, 0xd121 }, { 4934, 0xf3b3 }, { 4945, 0xfbfd }, { 4959, 0x7f47 },
+  { 4970, 0x57d9 }, { 4980, 0xf503 }, { 4988, 0x73fd }, { 5000, 0xddd7 },
+  /* 0x6c00 */
+  { 5012, 0x5f1f }, { 5023, 0x7084 }, { 5028, 0x3829 }, { 5034, 0xdeca },
+  { 5044, 0xf938 }, { 5053, 0x074e }, { 5060, 0xf8ec }, { 5070, 0x9daa },
+  { 5079, 0x6c91 }, { 5086, 0x75e6 }, { 5096, 0x9105 }, { 5101, 0x04f1 },
+  { 5107, 0xe9cf }, { 5118, 0xb706 }, { 5126, 0x32d0 }, { 5132, 0x8214 },
+  /* 0x6d00 */
+  { 5136, 0xa76d }, { 5146, 0xb17b }, { 5156, 0xb35f }, { 5167, 0x85d1 },
+  { 5174, 0x1215 }, { 5179, 0xa9e1 }, { 5187, 0x39b6 }, { 5196, 0xee6f },
+  { 5208, 0xacdb }, { 5218, 0x17c5 }, { 5226, 0x3024 }, { 5230, 0x7edb },
+  { 5242, 0xe70e }, { 5251, 0x9cbd }, { 5261, 0xa7ac }, { 5270, 0xe575 },
+  /* 0x6e00 */
+  { 5280, 0x8bdf }, { 5291, 0xdb2c }, { 5300, 0x55c4 }, { 5307, 0xfaeb },
+  { 5319, 0x9fe7 }, { 5331, 0x76a7 }, { 5341, 0xb7ff }, { 5355, 0x3fff },
+  { 5369, 0x7d97 }, { 5380, 0x6efe }, { 5392, 0x7b5b }, { 5403, 0xd329 },
+  { 5411, 0x7779 }, { 5422, 0x3b45 }, { 5430, 0xfc88 }, { 5438, 0xfdef },
+  /* 0x6f00 */
+  { 5452, 0x7dbb }, { 5464, 0xffc7 }, { 5477, 0x51ee }, { 5486, 0xbfb5 },
+  { 5498, 0xd73f }, { 5510, 0xaeff }, { 5523, 0x9fbb }, { 5535, 0xeaeb },
+  { 5546, 0x8cef }, { 5556, 0xefff }, { 5571, 0xff7d }, { 5585, 0xfdb7 },
+  { 5598, 0xfdfa }, { 5611, 0xbff9 }, { 5624, 0x3ffc }, { 5636, 0xffff },
+  /* 0x7000 */
+  { 5652, 0xffff }, { 5668, 0xf3fd }, { 5681, 0xfff7 }, { 5696, 0xfddf },
+  { 5710, 0x6fff }, { 5724, 0xbfff }, { 5739, 0x47ff }, { 5751, 0x2e9e },
+  { 5760, 0xb9de }, { 5771, 0xcd8b }, { 5780, 0x07ff }, { 5791, 0xc475 },
+  { 5799, 0xfaf0 }, { 5809, 0x74ff }, { 5821, 0x442f }, { 5828, 0xdd7f },
+  /* 0x7100 */
+  { 5841, 0xf9ff }, { 5855, 0xf896 }, { 5864, 0x7fbf }, { 5878, 0xffbc },
+  { 5891, 0xabdf }, { 5903, 0xafff }, { 5917, 0xbe2f }, { 5928, 0xdaf3 },
+  { 5939, 0x7bef }, { 5952, 0x7cef }, { 5964, 0xeefe }, { 5977, 0xfdd7 },
+  { 5990, 0xbff7 }, { 6004, 0xffcf }, { 6018, 0xbf5e }, { 6030, 0xfdff },
+  /* 0x7200 */
+  { 6045, 0xffbf }, { 6060, 0xdfff }, { 6075, 0xeaff }, { 6088, 0x541c },
+  { 6094, 0xce7f }, { 6106, 0x55bb }, { 6116, 0x3d39 }, { 6125, 0x39db },
+  { 6135, 0x53ec }, { 6144, 0x7ffb }, { 6158, 0x4fff }, { 6171, 0xfc2e },
+  { 6181, 0x9ee1 }, { 6190, 0xbd7a }, { 6201, 0x0cfc }, { 6209, 0xe260 },
+  /* 0x7300 */
+  { 6215, 0xbbf5 }, { 6227, 0x8717 }, { 6235, 0xa1d9 }, { 6243, 0x3c6d },
+  { 6252, 0xdfff }, { 6267, 0xff7a }, { 6280, 0x4ffe }, { 6292, 0xbfff },
+  { 6307, 0xb56f }, { 6318, 0x77bd }, { 6330, 0x35fb }, { 6341, 0xf372 },
+  { 6351, 0x58fa }, { 6360, 0xbdfc }, { 6372, 0xdd5e }, { 6383, 0xfffb },
+  /* 0x7400 */
+  { 6398, 0x7997 }, { 6408, 0xf3fe }, { 6421, 0xaa9b }, { 6430, 0xef86 },
+  { 6440, 0xfffd }, { 6455, 0x215f }, { 6463, 0xdfff }, { 6478, 0xbf3e },
+  { 6490, 0xb774 }, { 6500, 0xaffe }, { 6513, 0xfc7f }, { 6526, 0xfbff },
+  { 6541, 0xffff }, { 6557, 0xaffb }, { 6570, 0x3fa2 }, { 6579, 0x7f2f },
+  /* 0x7500 */
+  { 6591, 0x5fef }, { 6604, 0x68f5 }, { 6613, 0x44df }, { 6622, 0xb250 },
+  { 6628, 0x26de }, { 6637, 0xe1ef }, { 6648, 0xfb9f }, { 6661, 0x7ceb },
+  { 6672, 0x77b7 }, { 6684, 0x5929 }, { 6691, 0x27c4 }, { 6698, 0x8cc0 },
+  { 6703, 0xd843 }, { 6710, 0xb68b }, { 6719, 0xf223 }, { 6727, 0x6dec },
+  /* 0x7600 */
+  { 6737, 0xebd4 }, { 6747, 0x745e }, { 6756, 0xd18a }, { 6763, 0x2ec6 },
+  { 6771, 0xcff6 }, { 6783, 0xafaf }, { 6795, 0x77f7 }, { 6808, 0x96ff },
+  { 6820, 0xb62b }, { 6829, 0xfdb5 }, { 6841, 0xbfef }, { 6855, 0x7fe9 },
+  { 6867, 0x1a9b }, { 6875, 0x7628 }, { 6882, 0x3fdf }, { 6895, 0xace9 },
+  /* 0x7700 */
+  { 6904, 0xd46d }, { 6913, 0x79ff }, { 6926, 0x5cba }, { 6935, 0xea1f },
+  { 6945, 0xff74 }, { 6957, 0xf3fc }, { 6969, 0xe691 }, { 6977, 0x1dff },
+  { 6989, 0x8fce }, { 6999, 0x7ff9 }, { 7012, 0xe95a }, { 7021, 0x57d6 },
+  { 7031, 0xdfff }, { 7046, 0xe77f }, { 7059, 0x8553 }, { 7066, 0x1eb7 },
+  /* 0x7800 */
+  { 7076, 0xcdf8 }, { 7086, 0x4a29 }, { 7092, 0xcd17 }, { 7101, 0xa06e },
+  { 7108, 0xaf5e }, { 7119, 0xdf1a }, { 7129, 0x83ff }, { 7140, 0xef7f },
+  { 7154, 0x8d7f }, { 7165, 0x6275 }, { 7173, 0xff55 }, { 7185, 0xbde0 },
+  { 7194, 0xf1dd }, { 7205, 0xfdce }, { 7217, 0xeeff }, { 7231, 0xfb6b },
+  /* 0x7900 */
+  { 7243, 0xffdd }, { 7257, 0xbff7 }, { 7271, 0xffef }, { 7286, 0xa3ef },
+  { 7297, 0xfcbc }, { 7308, 0x0337 }, { 7315, 0x5e5a }, { 7324, 0xfa7f },
+  { 7337, 0x7bcc }, { 7347, 0xfbff }, { 7362, 0xff7f }, { 7377, 0x91f7 },
+  { 7387, 0xd5b4 }, { 7396, 0x7ed9 }, { 7407, 0x5527 }, { 7415, 0xd6fe },
+  /* 0x7a00 */
+  { 7427, 0x97b2 }, { 7436, 0xbb6f }, { 7448, 0xfff6 }, { 7462, 0x4577 },
+  { 7471, 0xffbf }, { 7486, 0xff7d }, { 7500, 0xffff }, { 7516, 0x782e },
+  { 7524, 0xdea4 }, { 7533, 0x4e19 }, { 7540, 0xce9e }, { 7550, 0x7ff7 },
+  { 7564, 0xf7ff }, { 7579, 0x3dbf }, { 7591, 0x5f96 }, { 7601, 0x59ff },
+  /* 0x7b00 */
+  { 7613, 0x72a7 }, { 7622, 0xb5cd }, { 7632, 0xa28e }, { 7639, 0xaaf5 },
+  { 7649, 0x655f }, { 7659, 0xd2a8 }, { 7666, 0xbffa }, { 7679, 0xb559 },
+  { 7688, 0xdfde }, { 7701, 0xcf4e }, { 7711, 0xc039 }, { 7717, 0xfeed },
+  { 7730, 0xef3d }, { 7742, 0xd9f5 }, { 7753, 0xbb9d }, { 7764, 0xaf7d },
+  /* 0x7c00 */
+  { 7776, 0x677f }, { 7788, 0x7fbf }, { 7802, 0xfb3f }, { 7815, 0x7eff },
+  { 7829, 0xdffc }, { 7842, 0xffff }, { 7858, 0xffff }, { 7874, 0xc7e7 },
+  { 7885, 0xfdff }, { 7900, 0x0e59 }, { 7907, 0xbbcb }, { 7918, 0x8df1 },
+  { 7927, 0xca5d }, { 7936, 0x6d1f }, { 7946, 0x7efe }, { 7959, 0xf6ff },
+  /* 0x7d00 */
+  { 7973, 0xfbff }, { 7988, 0xffff }, { 8004, 0x777a }, { 8015, 0xffff },
+  { 8031, 0xffff }, { 8047, 0xffff }, { 8063, 0xbfff }, { 8078, 0xff7f },
+  { 8093, 0xffff }, { 8109, 0xffff }, { 8125, 0xbfbf }, { 8139, 0xffff },
+  { 8155, 0xffff }, { 8171, 0xffff }, { 8187, 0xffff }, { 8203, 0xffff },
+  /* 0x7e00 */
+  { 8219, 0xffff }, { 8235, 0xffff }, { 8251, 0xffff }, { 8267, 0xf7ff },
+  { 8282, 0xff7d }, { 8296, 0xffff }, { 8312, 0xffff }, { 8328, 0xffff },
+  { 8344, 0xfffb }, { 8359, 0x77ff }, { 8373, 0x4000 }, { 8374, 0x1810 },
+  { 8377, 0x0000 }, { 8377, 0x0040 }, { 8378, 0x1010 }, { 8380, 0x0200 },
+  /* 0x7f00 */
+  { 8381, 0x0400 }, { 8382, 0x4001 }, { 8384, 0x0000 }, { 8384, 0xfa80 },
+  { 8391, 0xffcb }, { 8404, 0x7a4c }, { 8412, 0xb8f9 }, { 8422, 0xbde9 },
+  { 8433, 0xabfd }, { 8445, 0x1bef }, { 8456, 0x7f6d }, { 8468, 0x4cfa },
+  { 8477, 0xabdd }, { 8488, 0x7ecf }, { 8500, 0xbd9c }, { 8510, 0xe7f4 },
+  /* 0x8000 */
+  { 8521, 0xc784 }, { 8528, 0xec0a }, { 8535, 0xf81a }, { 8543, 0x5615 },
+  { 8550, 0xc3b3 }, { 8559, 0xfaeb }, { 8571, 0xf9ff }, { 8585, 0x7ffd },
+  { 8599, 0xe526 }, { 8607, 0x42b7 }, { 8615, 0x11c8 }, { 8620, 0x0b69 },
+  { 8627, 0x8fa0 }, { 8634, 0x813f }, { 8642, 0x404d }, { 8647, 0xcaa0 },
+  /* 0x8100 */
+  { 8653, 0x19bb }, { 8662, 0xbaa0 }, { 8669, 0x6fff }, { 8683, 0xbeb9 },
+  { 8694, 0xe2bf }, { 8705, 0xf9c4 }, { 8714, 0x9d5e }, { 8724, 0x01ec },
+  { 8730, 0x7afa }, { 8741, 0xc6fd }, { 8752, 0xfab7 }, { 8764, 0xf3f7 },
+  { 8777, 0xebb0 }, { 8786, 0xffff }, { 8802, 0xcb77 }, { 8813, 0xa7e7 },
+  /* 0x8200 */
+  { 8824, 0xcf88 }, { 8832, 0x27ea }, { 8841, 0x42f1 }, { 8848, 0xb404 },
+  { 8853, 0x756f }, { 8864, 0x7aff }, { 8877, 0x3eff }, { 8890, 0x19e2 },
+  { 8897, 0x12eb }, { 8905, 0x4c79 }, { 8913, 0x008d }, { 8917, 0x9c64 },
+  { 8924, 0x026d }, { 8930, 0x2641 }, { 8935, 0x7784 }, { 8943, 0xf56d },
+  /* 0x8300 */
+  { 8954, 0x2c01 }, { 8958, 0xe34d }, { 8967, 0x467f }, { 8977, 0xe885 },
+  { 8984, 0x7d36 }, { 8994, 0x23e8 }, { 9001, 0x0004 }, { 9002, 0xc67f },
+  { 9013, 0xbd9f }, { 9025, 0xa6f3 }, { 9035, 0xf0fe }, { 9046, 0xc820 },
+  { 9050, 0x6b5c }, { 9059, 0x4eaf }, { 9069, 0xf9dc }, { 9080, 0xdcf8 },
+  /* 0x8400 */
+  { 9090, 0x07a5 }, { 9097, 0xcefd }, { 9109, 0xfe0f }, { 9120, 0xcefd },
+  { 9132, 0xffbf }, { 9147, 0xe17d }, { 9157, 0xc5f5 }, { 9167, 0xfa95 },
+  { 9177, 0xa47b }, { 9186, 0xed7f }, { 9199, 0x7ffd }, { 9213, 0x58eb },
+  { 9222, 0xd9ed }, { 9233, 0x5fb4 }, { 9243, 0xef96 }, { 9254, 0x6ffe },
+  /* 0x8500 */
+  { 9267, 0xefff }, { 9282, 0x7b75 }, { 9293, 0xe7fd }, { 9306, 0xc07f },
+  { 9315, 0xf8f7 }, { 9327, 0xbdbf }, { 9340, 0xfeef }, { 9354, 0xb1eb },
+  { 9364, 0x7f4f }, { 9376, 0xe7ff }, { 9390, 0x3aef }, { 9401, 0xfd7e },
+  { 9414, 0x7dfd }, { 9427, 0xefd6 }, { 9439, 0xfdef }, { 9453, 0x77ff },
+  /* 0x8600 */
+  { 9467, 0xffdf }, { 9482, 0xffbd }, { 9496, 0xfd7f }, { 9510, 0xeeff },
+  { 9524, 0x1fff }, { 9537, 0xbbec }, { 9548, 0xa7fb }, { 9560, 0x01fd },
+  { 9568, 0xc3f8 }, { 9577, 0xcfd7 }, { 9589, 0x6867 }, { 9597, 0xfb8c },
+  { 9607, 0x312e }, { 9614, 0x34ec }, { 9622, 0x9def }, { 9634, 0xbce0 },
+  /* 0x8700 */
+  { 9642, 0xd872 }, { 9650, 0xaa53 }, { 9658, 0xbdd1 }, { 9668, 0x376d },
+  { 9678, 0xac7f }, { 9689, 0xfd77 }, { 9702, 0xbfc6 }, { 9713, 0x87ae },
+  { 9722, 0xd6d3 }, { 9732, 0x7f77 }, { 9745, 0x46ff }, { 9756, 0xdbd7 },
+  { 9768, 0xf3be }, { 9780, 0xf7f1 }, { 9792, 0xbbde }, { 9804, 0xbdff },
+  /* 0x8800 */
+  { 9818, 0xfbf7 }, { 9832, 0xf797 }, { 9844, 0xfff9 }, { 9858, 0xedfb },
+  { 9871, 0xcfce }, { 9882, 0xfd6f }, { 9895, 0xa4c1 }, { 9901, 0x1f7a },
+  { 9911, 0xd6c9 }, { 9920, 0xefbb }, { 9933, 0xd7eb }, { 9945, 0xef7d },
+  { 9958, 0xbd99 }, { 9968, 0x7ccb }, { 9978, 0xfec3 }, { 9989, 0xace4 },
+  /* 0x8900 */
+  { 9997, 0xfbfb }, { 10011, 0xf1f2 }, { 10021, 0xf3dd }, { 10033, 0xffae },
+  { 10046, 0xffed }, { 10060, 0x3fff }, { 10074, 0xffbf }, { 10089, 0x77ff },
+  { 10103, 0xffb5 }, { 10116, 0xffff }, { 10132, 0xffff }, { 10148, 0xffff },
+  { 10164, 0x2009 }, { 10167, 0xabb8 }, { 10176, 0x7797 }, { 10187, 0xfff7 },
+  /* 0x8a00 */
+  { 10202, 0xff7e }, { 10216, 0xffff }, { 10232, 0xffff }, { 10248, 0xbfff },
+  { 10263, 0xfeff }, { 10278, 0xffff }, { 10294, 0xffff }, { 10310, 0xfdff },
+  { 10325, 0xf9ff }, { 10339, 0xfff7 }, { 10354, 0xffff }, { 10370, 0xffff },
+  { 10386, 0xffff }, { 10402, 0xffff }, { 10418, 0xffff }, { 10434, 0xffff },
+  /* 0x8b00 */
+  { 10450, 0xff7f }, { 10465, 0xffff }, { 10481, 0xffbf }, { 10496, 0xffff },
+  { 10512, 0xffff }, { 10528, 0xffff }, { 10544, 0xefbf }, { 10558, 0xffff },
+  { 10574, 0xffff }, { 10590, 0xffff }, { 10606, 0x1000 }, { 10607, 0x0802 },
+  { 10609, 0x0080 }, { 10610, 0x0001 }, { 10611, 0x0400 }, { 10612, 0x0000 },
+  /* 0x8c00 */
+  { 10612, 0x0200 }, { 10613, 0x4000 }, { 10614, 0x0000 }, { 10614, 0xff00 },
+  { 10622, 0xed3d }, { 10633, 0xfbdf }, { 10647, 0xf3f9 }, { 10659, 0xf8f7 },
+  { 10671, 0xe9db }, { 10682, 0xfeef }, { 10696, 0xffff }, { 10712, 0xffff },
+  { 10728, 0xffff }, { 10744, 0xffff }, { 10760, 0xffff }, { 10776, 0xffff },
+  /* 0x8d00 */
+  { 10792, 0xffff }, { 10808, 0x1fff }, { 10821, 0x0001 }, { 10822, 0x0000 },
+  { 10822, 0x0000 }, { 10822, 0x8086 }, { 10826, 0xd720 }, { 10833, 0xff06 },
+  { 10843, 0xf3cd }, { 10854, 0x7fed }, { 10867, 0xfff7 }, { 10882, 0x2ac5 },
+  { 10889, 0x27a7 }, { 10898, 0x133d }, { 10906, 0x62e7 }, { 10915, 0xd057 },
+  /* 0x8e00 */
+  { 10923, 0x69df }, { 10934, 0x1fef }, { 10946, 0x29f3 }, { 10955, 0xd9dd },
+  { 10966, 0xf068 }, { 10973, 0xfdf9 }, { 10986, 0x4dbf }, { 10997, 0x6faa },
+  { 11007, 0x7f5d }, { 11019, 0xafee }, { 11031, 0x67ff }, { 11044, 0xfbfb },
+  { 11058, 0xbfff }, { 11073, 0xffff }, { 11089, 0xffff }, { 11105, 0xffff },
+  /* 0x8f00 */
+  { 11121, 0xffff }, { 11137, 0xffff }, { 11153, 0xffff }, { 11169, 0xffff },
+  { 11185, 0xffff }, { 11201, 0xffff }, { 11217, 0x043f }, { 11224, 0x0000 },
+  { 11224, 0x1001 }, { 11226, 0x2004 }, { 11228, 0xf4f7 }, { 11240, 0x9dbc },
+  { 11250, 0xbe49 }, { 11259, 0x04c4 }, { 11263, 0x908b }, { 11269, 0xdc76 },
+  /* 0x9000 */
+  { 11279, 0x5180 }, { 11283, 0x1328 }, { 11288, 0x1fb8 }, { 11297, 0xa69f },
+  { 11307, 0x5f69 }, { 11317, 0xf670 }, { 11326, 0x9ed3 }, { 11336, 0x5fcf },
+  { 11348, 0xf6f2 }, { 11359, 0xd555 }, { 11368, 0x2bb1 }, { 11376, 0xb084 },
+  { 11381, 0x3b4d }, { 11390, 0xc774 }, { 11399, 0x5639 }, { 11407, 0x9eef },
+  /* 0x9100 */
+  { 11419, 0xffeb }, { 11433, 0xbdff }, { 11447, 0x7ff3 }, { 11460, 0xfdfd },
+  { 11474, 0x01b7 }, { 11481, 0x9b7a }, { 11491, 0x29c1 }, { 11497, 0x1c08 },
+  { 11501, 0xc55f }, { 11511, 0xf3f8 }, { 11522, 0x1bf3 }, { 11532, 0xfbcf },
+  { 11545, 0x097f }, { 11554, 0xeffd }, { 11568, 0xffff }, { 11584, 0xffff },
+  /* 0x9200 */
+  { 11600, 0xffff }, { 11616, 0xffff }, { 11632, 0xffff }, { 11648, 0xffff },
+  { 11664, 0xffff }, { 11680, 0xffff }, { 11696, 0xffff }, { 11712, 0xffef },
+  { 11727, 0xbfff }, { 11742, 0xffff }, { 11758, 0xbfff }, { 11773, 0xffff },
+  { 11789, 0xfeff }, { 11804, 0xffff }, { 11820, 0xffff }, { 11836, 0xffff },
+  /* 0x9300 */
+  { 11852, 0xffff }, { 11868, 0xffff }, { 11884, 0xffff }, { 11900, 0xbfff },
+  { 11915, 0xffff }, { 11931, 0xffff }, { 11947, 0xfbff }, { 11962, 0xffff },
+  { 11978, 0x7fff }, { 11993, 0xffff }, { 12009, 0xffff }, { 12025, 0xffff },
+  { 12041, 0xfbff }, { 12056, 0xffbf }, { 12071, 0xffff }, { 12087, 0xffff },
+  /* 0x9400 */
+  { 12103, 0xffff }, { 12119, 0xffff }, { 12135, 0xffff }, { 12151, 0xbfff },
+  { 12166, 0xffff }, { 12182, 0xffff }, { 12198, 0xf7ff }, { 12213, 0xffff },
+  { 12229, 0x001f }, { 12234, 0x0142 }, { 12237, 0x0000 }, { 12237, 0x0000 },
+  { 12237, 0x8080 }, { 12239, 0x0418 }, { 12242, 0x0040 }, { 12243, 0x0800 },
+  /* 0x9500 */
+  { 12244, 0x0000 }, { 12244, 0x1000 }, { 12245, 0x0081 }, { 12247, 0x2008 },
+  { 12249, 0x0908 }, { 12252, 0x0420 }, { 12254, 0x4001 }, { 12256, 0x7fb0 },
+  { 12266, 0xffff }, { 12282, 0xffff }, { 12298, 0xffff }, { 12314, 0xffff },
+  { 12330, 0xffff }, { 12346, 0xffff }, { 12362, 0x10ff }, { 12371, 0x8000 },
+  /* 0x9600 */
+  { 12372, 0x0080 }, { 12373, 0x4908 }, { 12377, 0xbbf9 }, { 12389, 0x4781 },
+  { 12395, 0xc40a }, { 12400, 0x77ce }, { 12411, 0xe869 }, { 12419, 0xff0b },
+  { 12430, 0x569f }, { 12440, 0xec6e }, { 12450, 0xff7f }, { 12465, 0x8db6 },
+  { 12474, 0x0d0c }, { 12479, 0xffdb }, { 12493, 0x78fe }, { 12504, 0xbd37 },
+  /* 0x9700 */
+  { 12515, 0x1c2c }, { 12521, 0xafb7 }, { 12533, 0xdbff }, { 12547, 0xbcfa },
+  { 12558, 0xffff }, { 12574, 0xb5b3 }, { 12584, 0xfdd8 }, { 12595, 0xefa7 },
+  { 12607, 0xd7df }, { 12620, 0xfee9 }, { 12632, 0x57f6 }, { 12643, 0xffeb },
+  { 12657, 0xffff }, { 12673, 0xffff }, { 12689, 0xc13f }, { 12698, 0xff97 },
+  /* 0x9800 */
+  { 12711, 0xffff }, { 12727, 0xffff }, { 12743, 0xffff }, { 12759, 0xffff },
+  { 12775, 0xffff }, { 12791, 0xffff }, { 12807, 0xffff }, { 12823, 0x001f },
+  { 12828, 0x4800 }, { 12830, 0x0224 }, { 12833, 0xff08 }, { 12842, 0xffff },
+  { 12858, 0xbfff }, { 12873, 0x38d1 }, { 12880, 0xfe7f }, { 12894, 0xffff },
+  /* 0x9900 */
+  { 12910, 0xdfff }, { 12925, 0xfffe }, { 12940, 0xbfff }, { 12955, 0xffff },
+  { 12971, 0xffff }, { 12987, 0xffcf }, { 13001, 0x0057 }, { 13006, 0x4b08 },
+  { 13011, 0x520c }, { 13016, 0xfc00 }, { 13022, 0xfedf }, { 13036, 0xffff },
+  { 13052, 0xffff }, { 13068, 0xffff }, { 13084, 0xffff }, { 13100, 0xffff },
+  /* 0x9a00 */
+  { 13116, 0xffff }, { 13132, 0xffff }, { 13148, 0xffff }, { 13164, 0xffff },
+  { 13180, 0xffff }, { 13196, 0xffff }, { 13212, 0x0fff }, { 13224, 0x0004 },
+  { 13225, 0x6208 }, { 13229, 0x0230 }, { 13232, 0xfe40 }, { 13240, 0xea3c },
+  { 13249, 0xe7d8 }, { 13259, 0x7ef5 }, { 13271, 0x57bd }, { 13282, 0xf5ff },
+  /* 0x9b00 */
+  { 13296, 0x7ef7 }, { 13309, 0x7ff7 }, { 13323, 0x7ff7 }, { 13337, 0xe7fb },
+  { 13350, 0x5c41 }, { 13356, 0xffed }, { 13370, 0xffff }, { 13386, 0xffff },
+  { 13402, 0xffff }, { 13418, 0xffff }, { 13434, 0xffff }, { 13450, 0xffff },
+  { 13466, 0xffff }, { 13482, 0xffff }, { 13498, 0xffff }, { 13514, 0xffff },
+  /* 0x9c00 */
+  { 13530, 0xffff }, { 13546, 0xffff }, { 13562, 0xffff }, { 13578, 0xffff },
+  { 13594, 0xffff }, { 13610, 0xffff }, { 13626, 0xffff }, { 13642, 0x6fff },
+  { 13656, 0x9619 }, { 13663, 0x23c8 }, { 13669, 0x9400 }, { 13672, 0xc200 },
+  { 13675, 0x0307 }, { 13680, 0x0c06 }, { 13684, 0xfffb }, { 13699, 0xffff },
+  /* 0x9d00 */
+  { 13715, 0xffff }, { 13731, 0xffff }, { 13747, 0xffff }, { 13763, 0xffff },
+  { 13779, 0xffff }, { 13795, 0xffff }, { 13811, 0xffff }, { 13827, 0xffff },
+  { 13843, 0xffff }, { 13859, 0xffff }, { 13875, 0xffff }, { 13891, 0xffff },
+  { 13907, 0xffff }, { 13923, 0xffff }, { 13939, 0xffff }, { 13955, 0xffff },
+  /* 0x9e00 */
+  { 13971, 0xffff }, { 13987, 0x7fff }, { 14002, 0x4090 }, { 14005, 0x1811 },
+  { 14009, 0x2001 }, { 14011, 0xa25d }, { 14019, 0xc027 }, { 14025, 0x3ff4 },
+  { 14036, 0xf67b }, { 14048, 0x5ff3 }, { 14060, 0xffbf }, { 14075, 0x96ef },
+  { 14086, 0x1def }, { 14097, 0x46ed }, { 14106, 0x795a }, { 14115, 0xa5ff },
+  /* 0x9f00 */
+  { 14127, 0x97ff }, { 14140, 0xfd76 }, { 14152, 0x6ffa }, { 14164, 0x957f },
+  { 14175, 0xffef }, { 14190, 0xfffc }, { 14204, 0xffff }, { 14220, 0x7fff },
+  { 14235, 0xe006 }, { 14240, 0x71ff }, { 14252, 0x003e },
+};
+static const Summary16 gbkext_inv_uni2indx_pagef9[19] = {
+  /* 0xf900 */
+  { 14257, 0x0000 }, { 14257, 0x0000 }, { 14257, 0x1000 }, { 14258, 0x0000 },
+  { 14258, 0x0000 }, { 14258, 0x0000 }, { 14258, 0x0000 }, { 14258, 0x0200 },
+  { 14259, 0x0000 }, { 14259, 0x0020 }, { 14260, 0x0000 }, { 14260, 0x0000 },
+  { 14260, 0x0000 }, { 14260, 0x0000 }, { 14260, 0x0080 }, { 14261, 0x0002 },
+  /* 0xfa00 */
+  { 14262, 0xf000 }, { 14266, 0x811a }, { 14271, 0x039b },
+};
+static const Summary16 gbkext_inv_uni2indx_pagefe[31] = {
+  /* 0xfe00 */
+  { 14278, 0x0000 }, { 14278, 0x0000 }, { 14278, 0x0000 }, { 14278, 0x0001 },
+  { 14279, 0xfe00 }, { 14286, 0xfef7 }, { 14300, 0x0f7f }, { 14311, 0x0000 },
+  { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0000 },
+  { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0000 },
+  /* 0xff00 */
+  { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0000 },
+  { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0000 },
+  { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0000 },
+  { 14311, 0x0000 }, { 14311, 0x0000 }, { 14311, 0x0014 },
+};
+
+static int gbkext_inv_wctomb(unsigned int* r, unsigned int wc) {
+    const Summary16 *summary = NULL;
+    if (wc >= 0x0200 && wc < 0x02e0) {
+        summary = &gbkext_inv_uni2indx_page02[(wc>>4)-0x020];
+    } else if (wc >= 0x2000 && wc < 0x22c0) {
+        summary = &gbkext_inv_uni2indx_page20[(wc>>4)-0x200];
+    } else if (wc >= 0x2500 && wc < 0x2610) {
+        summary = &gbkext_inv_uni2indx_page25[(wc>>4)-0x250];
+    } else if (wc >= 0x3000 && wc < 0x3100) {
+        summary = &gbkext_inv_uni2indx_page30[(wc>>4)-0x300];
+    } else if (wc >= 0x3200 && wc < 0x33e0) {
+        summary = &gbkext_inv_uni2indx_page32[(wc>>4)-0x320];
+    } else if (wc >= 0x4e00 && wc < 0x9fb0) {
+        summary = &gbkext_inv_uni2indx_page4e[(wc>>4)-0x4e0];
+    } else if (wc >= 0xf900 && wc < 0xfa30) {
+        summary = &gbkext_inv_uni2indx_pagef9[(wc>>4)-0xf90];
+    } else if (wc >= 0xfe00 && wc < 0xfff0) {
+        summary = &gbkext_inv_uni2indx_pagefe[(wc>>4)-0xfe0];
+    }
+    if (summary) {
+        unsigned short used = summary->used;
+        unsigned int i = wc & 0x0f;
+        if (used & ((unsigned short) 1 << i)) {
+            /* Keep in 'used' only the bits 0..i-1. */
+            used &= ((unsigned short) 1 << i) - 1;
+            /* Add 'summary->indx' and the number of bits set in 'used'. */
+            used = (used & 0x5555) + ((used & 0xaaaa) >> 1);
+            used = (used & 0x3333) + ((used & 0xcccc) >> 2);
+            used = (used & 0x0f0f) + ((used & 0xf0f0) >> 4);
+            used = (used & 0x00ff) + (used >> 8);
+            *r = gbkext_inv_2charset[summary->indx + used];
+            return 2;
+        }
+    }
+    return 0;
+}
+
+/*
+ * GBK (libiconv-1.16/lib/gbk.h)
+ */
+
+static int gbk_wctomb(unsigned int* r, unsigned int wc) {
+    int ret;
+
+    /* ZINT: Note these mappings U+30FB and U+2015 different from GB 2312 */
+    if (wc != 0x30fb && wc != 0x2015) {
+        ret = gb2312_wctomb_zint(r, wc); /* In gb2312.c */
+        if (ret) {
+            return ret;
+        }
+    }
+    ret = gbkext_inv_wctomb(r, wc);
+    if (ret) {
+        return ret;
+    }
+    if (wc >= 0x2170 && wc <= 0x2179) {
+        *r = 0xa2a1 + (wc-0x2170);
+        return 2;
+    }
+    ret = cp936ext_wctomb(r, wc);
+    if (ret) {
+        return ret;
+    }
+    /* ZINT: gb2312_wctomb_zint() is patched to map U+00B7 to 0xA1A4 and U+2014 to 0xA1AA */
+
+    return 0;
+}
+
+/*
+ * GB18030 two-byte extension (libiconv-1.16/lib/gb18030ext.h)
+ */
+
+static const unsigned short gb18030ext_page2e[80] = {
+  0x0000, 0xfe50, 0x0000, 0x0000, 0xfe54, 0x0000, 0x0000, 0x0000, /*0x80-0x87*/
+  0xfe57, 0x0000, 0x0000, 0xfe58, 0xfe5d, 0x0000, 0x0000, 0x0000, /*0x88-0x8f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe5e, /*0x90-0x97*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x98-0x9f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe6b, /*0xa0-0xa7*/
+  0x0000, 0x0000, 0xfe6e, 0x0000, 0x0000, 0x0000, 0xfe71, 0x0000, /*0xa8-0xaf*/
+  0x0000, 0x0000, 0x0000, 0xfe73, 0x0000, 0x0000, 0xfe74, 0xfe75, /*0xb0-0xb7*/
+  0x0000, 0x0000, 0x0000, 0xfe79, 0x0000, 0x0000, 0x0000, 0x0000, /*0xb8-0xbf*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0xc0-0xc7*/
+  0x0000, 0x0000, 0xfe84, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0xc8-0xcf*/
+};
+static const unsigned short gb18030ext_page2f[16] = {
+  0xa98a, 0xa98b, 0xa98c, 0xa98d, 0xa98e, 0xa98f, 0xa990, 0xa991, /*0xf0-0xf7*/
+  0xa992, 0xa993, 0xa994, 0xa995, 0x0000, 0x0000, 0x0000, 0x0000, /*0xf8-0xff*/
+};
+static const unsigned short gb18030ext_page34[56] = {
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe56, /*0x40-0x47*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x48-0x4f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x50-0x57*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x58-0x5f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x60-0x67*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x68-0x6f*/
+  0x0000, 0x0000, 0x0000, 0xfe55, 0x0000, 0x0000, 0x0000, 0x0000, /*0x70-0x77*/
+};
+static const unsigned short gb18030ext_page36[24] = {
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe5c, 0x0000, /*0x08-0x0f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x10-0x17*/
+  0x0000, 0x0000, 0xfe5b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x18-0x1f*/
+};
+static const unsigned short gb18030ext_page39[24] = {
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe62, /*0xc8-0xcf*/
+  0xfe65, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0xd0-0xd7*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe63, /*0xd8-0xdf*/
+};
+static const unsigned short gb18030ext_page43[56] = {
+  0x0000, 0x0000, 0x0000, 0x0000, 0xfe78, 0x0000, 0x0000, 0x0000, /*0xa8-0xaf*/
+  0x0000, 0xfe77, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0xb0-0xb7*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0xb8-0xbf*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0xc0-0xc7*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0xc8-0xcf*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0xd0-0xd7*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe7a, 0x0000, 0x0000, /*0xd8-0xdf*/
+};
+static const unsigned short gb18030ext_page46[32] = {
+  0x0000, 0x0000, 0x0000, 0x0000, 0xfe7d, 0x0000, 0x0000, 0x0000, /*0x48-0x4f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x50-0x57*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x58-0x5f*/
+  0x0000, 0xfe7c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x60-0x67*/
+};
+static const unsigned short gb18030ext_page47_1[16] = {
+  0x0000, 0x0000, 0x0000, 0xfe80, 0x0000, 0x0000, 0x0000, 0x0000, /*0x20-0x27*/
+  0x0000, 0xfe81, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x28-0x2f*/
+};
+static const unsigned short gb18030ext_page47_2[24] = {
+  0x0000, 0x0000, 0x0000, 0x0000, 0xfe82, 0x0000, 0x0000, 0x0000, /*0x78-0x7f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x80-0x87*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe83, 0x0000, 0x0000, /*0x88-0x8f*/
+};
+static const unsigned short gb18030ext_page49[120] = {
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe85, /*0x40-0x47*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x48-0x4f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x50-0x57*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x58-0x5f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x60-0x67*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x68-0x6f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x70-0x77*/
+  0x0000, 0x0000, 0xfe86, 0x0000, 0x0000, 0xfe87, 0x0000, 0x0000, /*0x78-0x7f*/
+  0x0000, 0x0000, 0xfe88, 0xfe89, 0x0000, 0xfe8a, 0xfe8b, 0x0000, /*0x80-0x87*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x88-0x8f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x90-0x97*/
+  0x0000, 0x0000, 0x0000, 0xfe8d, 0x0000, 0x0000, 0x0000, 0xfe8c, /*0x98-0x9f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0xa0-0xa7*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0xa8-0xaf*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe8f, 0xfe8e, /*0xb0-0xb7*/
+};
+static const unsigned short gb18030ext_page4c[56] = {
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe96, /*0x70-0x77*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x78-0x7f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x80-0x87*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x88-0x8f*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x90-0x97*/
+  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe93, /*0x98-0x9f*/
+  0xfe94, 0xfe95, 0xfe97, 0xfe92, 0x0000, 0x0000, 0x0000, 0x0000, /*0xa0-0xa7*/
+};
+static const unsigned short gb18030ext_page4d[16] = {
+  0x0000, 0x0000, 0x0000, 0xfe98, 0xfe99, 0xfe9a, 0xfe9b, 0xfe9c, /*0x10-0x17*/
+  0xfe9d, 0xfe9e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x18-0x1f*/
+};
+static const unsigned short gb18030ext_page9f[16] = {
+  0x0000, 0x0000, 0x0000, 0x0000, 0xfe59, 0xfe61, 0xfe66, 0xfe67, /*0xb0-0xb7*/
+  0xfe6d, 0xfe7e, 0xfe90, 0xfea0, 0x0000, 0x0000, 0x0000, 0x0000, /*0xb8-0xbf*/
+};
+static const unsigned short gb18030ext_pagefe[16] = {
+  0xa6d9, 0xa6db, 0xa6da, 0xa6dc, 0xa6dd, 0xa6de, 0xa6df, 0xa6ec, /*0x10-0x17*/
+  0xa6ed, 0xa6f3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*0x18-0x1f*/
+};
+
+static int gb18030ext_wctomb(unsigned int* r, unsigned int wc) {
+    unsigned short c = 0;
+    if (wc == 0x01f9) {
+        c = 0xa8bf;
+    } else if (wc == 0x1e3f) {
+        c = 0xa8bc;
+    } else if (wc == 0x20ac) {
+        c = 0xa2e3;
+    } else if (wc >= 0x2e80 && wc < 0x2ed0) {
+        c = gb18030ext_page2e[wc-0x2e80];
+    } else if (wc >= 0x2ff0 && wc < 0x3000) {
+        c = gb18030ext_page2f[wc-0x2ff0];
+    } else if (wc == 0x303e) {
+        c = 0xa989;
+    } else if (wc >= 0x3440 && wc < 0x3478) {
+        c = gb18030ext_page34[wc-0x3440];
+    } else if (wc == 0x359e) {
+        c = 0xfe5a;
+    } else if (wc >= 0x3608 && wc < 0x3620) {
+        c = gb18030ext_page36[wc-0x3608];
+    } else if (wc == 0x3918) {
+        c = 0xfe60;
+    } else if (wc == 0x396e) {
+        c = 0xfe5f;
+    } else if (wc >= 0x39c8 && wc < 0x39e0) {
+        c = gb18030ext_page39[wc-0x39c8];
+    } else if (wc == 0x3a73) {
+        c = 0xfe64;
+    } else if (wc == 0x3b4e) {
+        c = 0xfe68;
+    } else if (wc == 0x3c6e) {
+        c = 0xfe69;
+    } else if (wc == 0x3ce0) {
+        c = 0xfe6a;
+    } else if (wc == 0x4056) {
+        c = 0xfe6f;
+    } else if (wc == 0x415f) {
+        c = 0xfe70;
+    } else if (wc == 0x4337) {
+        c = 0xfe72;
+    } else if (wc >= 0x43a8 && wc < 0x43e0) {
+        c = gb18030ext_page43[wc-0x43a8];
+    } else if (wc == 0x44d6) {
+        c = 0xfe7b;
+    } else if (wc >= 0x4648 && wc < 0x4668) {
+        c = gb18030ext_page46[wc-0x4648];
+    } else if (wc >= 0x4720 && wc < 0x4730) {
+        c = gb18030ext_page47_1[wc-0x4720];
+    } else if (wc >= 0x4778 && wc < 0x4790) {
+        c = gb18030ext_page47_2[wc-0x4778];
+    } else if (wc >= 0x4940 && wc < 0x49b8) {
+        c = gb18030ext_page49[wc-0x4940];
+    } else if (wc >= 0x4c70 && wc < 0x4ca8) {
+        c = gb18030ext_page4c[wc-0x4c70];
+    } else if (wc >= 0x4d10 && wc < 0x4d20) {
+        c = gb18030ext_page4d[wc-0x4d10];
+    } else if (wc == 0x4dae) {
+        c = 0xfe9f;
+    } else if (wc >= 0x9fb4 && wc < 0x9fbc) {
+        c = gb18030ext_page9f[wc-0x9fb0];
+    } else if (wc >= 0xfe10 && wc < 0xfe1a) {
+        c = gb18030ext_pagefe[wc-0xfe10];
+    } else if (wc == 0x20087) {
+        c = 0xfe51;
+    } else if (wc == 0x20089) {
+        c = 0xfe52;
+    } else if (wc == 0x200cc) {
+        c = 0xfe53;
+    } else if (wc == 0x215d7) {
+        c = 0xfe6c;
+    } else if (wc == 0x2298f) {
+        c = 0xfe76;
+    } else if (wc == 0x241fe) {
+        c = 0xfe91;
+    }
+    if (c != 0) {
+        *r = c;
+        return 2;
+    }
+    return 0;
+}
+
+/*
+ * GB18030 four-byte extension (libiconv-1.16/lib/gb18030uni.h)
+ */
+
+static const unsigned short gb18030uni_uni2charset_ranges[412] = {
+  0x0080, 0x00a3,  0x00a5, 0x00a6,  0x00a9, 0x00af,  0x00b2, 0x00b6,
+  0x00b8, 0x00d6,  0x00d8, 0x00df,  0x00e2, 0x00e7,  0x00eb, 0x00eb,
+  0x00ee, 0x00f1,  0x00f4, 0x00f6,  0x00f8, 0x00f8,  0x00fb, 0x00fb,
+  0x00fd, 0x0100,  0x0102, 0x0112,  0x0114, 0x011a,  0x011c, 0x012a,
+  0x012c, 0x0143,  0x0145, 0x0147,  0x0149, 0x014c,  0x014e, 0x016a,
+  0x016c, 0x01cd,  0x01cf, 0x01cf,  0x01d1, 0x01d1,  0x01d3, 0x01d3,
+  0x01d5, 0x01d5,  0x01d7, 0x01d7,  0x01d9, 0x01d9,  0x01db, 0x01db,
+  0x01dd, 0x01f8,  0x01fa, 0x0250,  0x0252, 0x0260,  0x0262, 0x02c6,
+  0x02c8, 0x02c8,  0x02cc, 0x02d8,  0x02da, 0x0390,  0x03a2, 0x03a2,
+  0x03aa, 0x03b0,  0x03c2, 0x03c2,  0x03ca, 0x0400,  0x0402, 0x040f,
+  0x0450, 0x0450,  0x0452, 0x200f,  0x2011, 0x2012,  0x2017, 0x2017,
+  0x201a, 0x201b,  0x201e, 0x2024,  0x2027, 0x202f,  0x2031, 0x2031,
+  0x2034, 0x2034,  0x2036, 0x203a,  0x203c, 0x20ab,  0x20ad, 0x2102,
+  0x2104, 0x2104,  0x2106, 0x2108,  0x210a, 0x2115,  0x2117, 0x2120,
+  0x2122, 0x215f,  0x216c, 0x216f,  0x217a, 0x218f,  0x2194, 0x2195,
+  0x219a, 0x2207,  0x2209, 0x220e,  0x2210, 0x2210,  0x2212, 0x2214,
+  0x2216, 0x2219,  0x221b, 0x221c,  0x2221, 0x2222,  0x2224, 0x2224,
+  0x2226, 0x2226,  0x222c, 0x222d,  0x222f, 0x2233,  0x2238, 0x223c,
+  0x223e, 0x2247,  0x2249, 0x224b,  0x224d, 0x2251,  0x2253, 0x225f,
+  0x2262, 0x2263,  0x2268, 0x226d,  0x2270, 0x2294,  0x2296, 0x2298,
+  0x229a, 0x22a4,  0x22a6, 0x22be,  0x22c0, 0x2311,  0x2313, 0x245f,
+  0x246a, 0x2473,  0x249c, 0x24ff,  0x254c, 0x254f,  0x2574, 0x2580,
+  0x2590, 0x2592,  0x2596, 0x259f,  0x25a2, 0x25b1,  0x25b4, 0x25bb,
+  0x25be, 0x25c5,  0x25c8, 0x25ca,  0x25cc, 0x25cd,  0x25d0, 0x25e1,
+  0x25e6, 0x2604,  0x2607, 0x2608,  0x260a, 0x263f,  0x2641, 0x2641,
+  0x2643, 0x2e80,  0x2e82, 0x2e83,  0x2e85, 0x2e87,  0x2e89, 0x2e8a,
+  0x2e8d, 0x2e96,  0x2e98, 0x2ea6,  0x2ea8, 0x2ea9,  0x2eab, 0x2ead,
+  0x2eaf, 0x2eb2,  0x2eb4, 0x2eb5,  0x2eb8, 0x2eba,  0x2ebc, 0x2ec9,
+  0x2ecb, 0x2fef,  0x2ffc, 0x2fff,  0x3004, 0x3004,  0x3018, 0x301c,
+  0x301f, 0x3020,  0x302a, 0x303d,  0x303f, 0x3040,  0x3094, 0x309a,
+  0x309f, 0x30a0,  0x30f7, 0x30fb,  0x30ff, 0x3104,  0x312a, 0x321f,
+  0x322a, 0x3230,  0x3232, 0x32a2,  0x32a4, 0x338d,  0x3390, 0x339b,
+  0x339f, 0x33a0,  0x33a2, 0x33c3,  0x33c5, 0x33cd,  0x33cf, 0x33d0,
+  0x33d3, 0x33d4,  0x33d6, 0x3446,  0x3448, 0x3472,  0x3474, 0x359d,
+  0x359f, 0x360d,  0x360f, 0x3619,  0x361b, 0x3917,  0x3919, 0x396d,
+  0x396f, 0x39ce,  0x39d1, 0x39de,  0x39e0, 0x3a72,  0x3a74, 0x3b4d,
+  0x3b4f, 0x3c6d,  0x3c6f, 0x3cdf,  0x3ce1, 0x4055,  0x4057, 0x415e,
+  0x4160, 0x4336,  0x4338, 0x43ab,  0x43ad, 0x43b0,  0x43b2, 0x43dc,
+  0x43de, 0x44d5,  0x44d7, 0x464b,  0x464d, 0x4660,  0x4662, 0x4722,
+  0x4724, 0x4728,  0x472a, 0x477b,  0x477d, 0x478c,  0x478e, 0x4946,
+  0x4948, 0x4979,  0x497b, 0x497c,  0x497e, 0x4981,  0x4984, 0x4984,
+  0x4987, 0x499a,  0x499c, 0x499e,  0x49a0, 0x49b5,  0x49b8, 0x4c76,
+  0x4c78, 0x4c9e,  0x4ca4, 0x4d12,  0x4d1a, 0x4dad,  0x4daf, 0x4dff,
+  0x9fa6, 0xd7ff,
+                   0xe76c, 0xe76c,  0xe7c8, 0xe7c8,  0xe7e7, 0xe7f3,
+  0xe815, 0xe815,  0xe819, 0xe81d,  0xe81f, 0xe825,  0xe827, 0xe82a,
+  0xe82d, 0xe830,  0xe833, 0xe83a,  0xe83c, 0xe842,  0xe844, 0xe853,
+  0xe856, 0xe863,
+                   0xe865, 0xf92b,  0xf92d, 0xf978,  0xf97a, 0xf994,
+  0xf996, 0xf9e6,  0xf9e8, 0xf9f0,  0xf9f2, 0xfa0b,  0xfa10, 0xfa10,
+  0xfa12, 0xfa12,  0xfa15, 0xfa17,  0xfa19, 0xfa1e,  0xfa22, 0xfa22,
+  0xfa25, 0xfa26,  0xfa2a, 0xfe2f,  0xfe32, 0xfe32,  0xfe45, 0xfe48,
+  0xfe53, 0xfe53,  0xfe58, 0xfe58,  0xfe67, 0xfe67,  0xfe6c, 0xff00,
+  0xff5f, 0xffdf,  0xffe6, 0xffff
+};
+
+static const unsigned short gb18030uni_ranges[206] = {
+    128,   129,   131,   133,   134,   135,   137,   140,
+    142,   144,   145,   147,   148,   149,   150,   151,
+    152,   153,   154,   155,   156,   157,   158,   159,
+    160,   161,   162,   163,   164,   165,   166,   167,
+    168,   171,   172,   189,   196,   213,   220,   221,
+    285,   286,   287,   291,   293,   295,   297,   298,
+    300,   301,   302,   303,   304,   305,   306,   307,
+    308,   320,   330,   334,   338,   339,   340,   341,
+    342,   343,   347,   348,   349,   354,   355,   359,
+    360,   361,   362,   363,   365,   369,   371,   372,
+    373,   374,   375,   376,   386,   426,   502,   538,
+    553,   556,   558,   560,   562,   564,   565,   567,
+    571,   573,   574,   575,   576,   577,   578,   579,
+    581,   582,   583,   584,   585,   586,   588,   589,
+    590,   602,   606,   625,   627,   636,   637,   720,
+    724,   810,   813,   850,   860,   861,   862,   864,
+    867,   868,   869,   870,   872,   873,   874,   875,
+    876,   877,   878,   879,   880,   882,   883,   884,
+    885,   886,   887,   888,   889,   890,   891,   892,
+    893,   894,   895,   896,   897,   898,   899,   900,
+    901,   902,   903,   905,   907,   908,   909,   911,
+    912,   917,   924,   925, 21827,
+                                     25775, 25866, 25896,
+  25929, 25932, 25933, 25934, 25936, 25938, 25939, 25940,
+  25942,
+         25943, 25944, 25945, 25946, 25947, 25948, 25952,
+  25953, 25955, 25956, 25959, 25961, 25964, 25966, 25984,
+  25994, 25998, 26012, 26016, 26110, 26116
+};
+
+static int gb18030uni_wctomb(unsigned int* r1, unsigned int* r2, unsigned int wc) {
+    unsigned int i = wc;
+    if (i >= 0x0080 && i <= 0xffff) {
+        if (i == 0xe7c7) {
+            i = 7457;
+        } else {
+            unsigned int k1 = 0;
+            unsigned int k2 = 205;
+            while (k1 < k2) {
+                unsigned int k = (k1 + k2) / 2;
+                if (i <= gb18030uni_uni2charset_ranges[2*k+1]) {
+                    k2 = k;
+                } else if (i >= gb18030uni_uni2charset_ranges[2*k+2]) {
+                    k1 = k + 1;
+                } else {
+                    return 0;
+                }
+            }
+            {
+                unsigned int diff = gb18030uni_ranges[k1];
+                i -= diff;
+            }
+        }
+        *r2 = (i % 10) + 0x30; i = i / 10;
+        *r2 |= ((i % 126) + 0x81) << 8; i = i / 126;
+        *r1 = (i % 10) + 0x30; i = i / 10;
+        *r1 |= (i + 0x81) << 8;
+        return 4;
+    }
+    return 0;
+}
+
+/*
+ * GB18030 (libiconv-1.16/lib/gb18030.h)
+ */
+
+static const unsigned short gb18030_pua2charset[31*3] = {
+/* Unicode range   GB18030 range */
+  0xe766, 0xe76b,  0xa2ab, /*.. 0xa2b0, */
+  0xe76d, 0xe76d,  0xa2e4,
+  0xe76e, 0xe76f,  0xa2ef, /*.. 0xa2f0, */
+  0xe770, 0xe771,  0xa2fd, /*.. 0xa2fe, */
+  0xe772, 0xe77c,  0xa4f4, /*.. 0xa4fe, */
+  0xe77d, 0xe784,  0xa5f7, /*.. 0xa5fe, */
+  0xe785, 0xe78c,  0xa6b9, /*.. 0xa6c0, */
+  0xe78d, 0xe793,  0xa6d9, /*.. 0xa6df, */
+  0xe794, 0xe795,  0xa6ec, /*.. 0xa6ed, */
+  0xe796, 0xe796,  0xa6f3,
+  0xe797, 0xe79f,  0xa6f6, /*.. 0xa6fe, */
+  0xe7a0, 0xe7ae,  0xa7c2, /*.. 0xa7d0, */
+  0xe7af, 0xe7bb,  0xa7f2, /*.. 0xa7fe, */
+  0xe7bc, 0xe7c6,  0xa896, /*.. 0xa8a0, */
+  0xe7c9, 0xe7cc,  0xa8c1, /*.. 0xa8c4, */
+  0xe7cd, 0xe7e1,  0xa8ea, /*.. 0xa8fe, */
+  0xe7e2, 0xe7e2,  0xa958,
+  0xe7e3, 0xe7e3,  0xa95b,
+  0xe7e4, 0xe7e6,  0xa95d, /*.. 0xa95f, */
+  0xe7f4, 0xe800,  0xa997, /*.. 0xa9a3, */
+  0xe801, 0xe80f,  0xa9f0, /*.. 0xa9fe, */
+  0xe810, 0xe814,  0xd7fa, /*.. 0xd7fe, */
+  0xe816, 0xe818,  0xfe51, /*.. 0xfe53, */
+  0xe81e, 0xe81e,  0xfe59,
+  0xe826, 0xe826,  0xfe61,
+  0xe82b, 0xe82c,  0xfe66, /*.. 0xfe67, */
+  0xe831, 0xe832,  0xfe6c, /*.. 0xfe6d, */
+  0xe83b, 0xe83b,  0xfe76,
+  0xe843, 0xe843,  0xfe7e,
+  0xe854, 0xe855,  0xfe90, /*.. 0xfe91, */
+  0xe864, 0xe864,  0xfea0,
+};
+
+INTERNAL int gb18030_wctomb_zint(unsigned int* r1, unsigned int* r2, unsigned int wc) {
+    int ret;
+
+    /* Code set 0 (ASCII) */
+    if (wc < 0x0080) {
+        *r1 = wc;
+        return 1;
+    }
+
+    /* Code set 1 (GBK extended) */
+    ret = gbk_wctomb(r1, wc);
+    if (ret) {
+        return ret;
+    }
+
+    ret = gb18030ext_wctomb(r1, wc);
+    if (ret) {
+        return ret;
+    }
+
+    /* Code set 2 (remainder of Unicode U+0000..U+FFFF) */
+    if (wc >= 0xe000 && wc <= 0xe864) {
+        if (wc < 0xe766) {
+            /* User-defined characters range U+E000..U+E765 */
+            if (wc < 0xe4c6) {
+                unsigned int i = wc - 0xe000;
+                *r1 = (i % 94) + 0xa1; i = i / 94;
+                *r1 |= (i < 6 ? i + 0xaa : i + 0xf2) << 8;
+                return 2;
+            } else {
+                unsigned int i = wc - 0xe4c6;
+                *r1 = ((i / 96) + 0xa1) << 8; i = i % 96;
+                *r1 |= i + (i >= 0x3f ? 0x41 : 0x40);
+                return 2;
+            }
+        } else {
+            /* User-defined characters, two-byte part of range U+E766..U+E864 */
+            unsigned int k1 = 0;
+            unsigned int k2 = 31;
+            /* Invariant: We know that if wc occurs in Unicode interval in
+            gb18030_pua2charset, it does so at a k with  k1 <= k < k2. */
+            while (k1 < k2) {
+                unsigned int k = (k1 + k2) / 2;
+                if (wc < gb18030_pua2charset[k*3+0]) {
+                    k2 = k;
+                } else if (wc > gb18030_pua2charset[k*3+1]) {
+                    k1 = k + 1;
+                } else {
+                    *r1 = gb18030_pua2charset[k*3+2] + (wc - gb18030_pua2charset[k*3+0]);
+                    return 2;
+                }
+            }
+        }
+    }
+    ret = gb18030uni_wctomb(r1, r2, wc);
+    if (ret) {
+        return ret;
+    }
+
+    /* Code set 3 (Unicode U+10000..U+10FFFF) */
+    if (wc >= 0x10000 && wc < 0x110000) {
+        unsigned int i = wc - 0x10000;
+        *r2 = (i % 10) + 0x30; i = i / 10;
+        *r2 |= ((i % 126) + 0x81) << 8; i = i / 126;
+        *r1 = (i % 10) + 0x30; i = i / 10;
+        *r1 |= (i + 0x90) << 8;
+        return 4;
+    }
+    return 0;
+}
+
+/* Convert UTF-8 string to GB 18030 and place in array of ints */
+INTERNAL int gb18030_utf8tomb(struct zint_symbol *symbol, const unsigned char source[], size_t* p_length, unsigned int* gbdata) {
+    int error_number, ret;
+    unsigned int i, j, length;
+#ifndef _MSC_VER
+    unsigned int utfdata[*p_length + 1];
+#else
+    unsigned int* utfdata = (unsigned int*) _alloca((*p_length + 1) * sizeof(unsigned int));
+#endif
+
+    error_number = utf8_to_unicode(symbol, source, utfdata, p_length, 0 /*disallow_4byte*/);
+    if (error_number != 0) {
+        return error_number;
+    }
+
+    for (i = 0, j = 0, length = *p_length; i < length; i++, j++) {
+        if (utfdata[i] < 0x80) {
+            gbdata[j] = utfdata[i];
+        } else {
+            ret = gb18030_wctomb_zint(gbdata + j, gbdata + j + 1, utfdata[i]);
+            if (ret == 0) {
+                strcpy(symbol->errtxt, "820: Invalid character in input data");
+                return ZINT_ERROR_INVALID_DATA;
+            }
+            if (ret == 4) {
+                j++;
+            }
+        }
+    }
+
+    *p_length = j;
+
+    return 0;
+}
+
+/* Convert UTF-8 string to single byte ECI and place in array of ints */
+INTERNAL int gb18030_utf8tosb(int eci, const unsigned char source[], size_t* p_length, unsigned int* gbdata, int full_multibyte) {
+    int error_number;
+#ifndef _MSC_VER
+    unsigned char single_byte[*p_length + 1];
+#else
+    unsigned char* single_byte = (unsigned char*) _alloca(*p_length + 1);
+#endif
+
+    error_number = utf_to_eci(eci, source, single_byte, p_length);
+    if (error_number != 0) {
+        /* Note not setting `symbol->errtxt`, up to caller */
+        return error_number;
+    }
+
+    gb18030_cpy(single_byte, p_length, gbdata, full_multibyte);
+
+    return 0;
+}
+
+/* If `full_multibyte` set, copy byte input stream to array of ints, putting double-bytes that match HANXIN Chinese mode in single entry,
+ * and quad-bytes in 2 entries. If `full_multibyte` not set, do a straight copy */
+INTERNAL void gb18030_cpy(const unsigned char source[], size_t* p_length, unsigned int* gbdata, int full_multibyte) {
+    unsigned int i, j, length;
+    int done;
+    unsigned char c1, c2, c3, c4;
+
+    if (full_multibyte) {
+        for (i = 0, j = 0, length = *p_length; i < length; i++, j++) {
+            done = 0;
+            c1 = source[i];
+            if (length - i >= 2) {
+                if (c1 >= 0x81 && c1 <= 0xFE) {
+                    c2 = source[i + 1];
+                    if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
+                        gbdata[j] = (c1 << 8) | c2;
+                        i++;
+                        done = 1;
+                    } else if (length - i >= 4 && (c2 >= 0x30 && c2 <= 0x39)) {
+                        c3 = source[i + 2];
+                        c4 = source[i + 3];
+                        if ((c3 >= 0x81 && c3 <= 0xFE) && (c4 >= 0x30 && c4 <= 0x39)) {
+                            gbdata[j++] = (c1 << 8) | c2;
+                            gbdata[j] = (c3 << 8) | c4;
+                            i += 3;
+                            done = 1;
+                        }
+                    }
+                }
+            }
+            if (!done) {
+                gbdata[j] = c1;
+            }
+        }
+        *p_length = j;
+    } else {
+        /* Straight copy */
+        for (i = 0, length = *p_length; i < length; i++) {
+            gbdata[i] = source[i];
+        }
+    }
+}
diff --git a/backend/gb18030.h b/backend/gb18030.h
new file mode 100644 (file)
index 0000000..704e4bd
--- /dev/null
@@ -0,0 +1,49 @@
+/*  gb18030.h - Unicode to GB 18030
+
+    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 : */
+
+#ifndef GB18030_H
+#define GB18030_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+INTERNAL int gb18030_wctomb_zint(unsigned int* r1, unsigned int* r2, unsigned int wc);
+INTERNAL int gb18030_utf8tomb(struct zint_symbol *symbol, const unsigned char source[], size_t* p_length, unsigned int* gbdata);
+INTERNAL int gb18030_utf8tosb(int eci, const unsigned char source[], size_t* p_length, unsigned int* gbdata, int full_multibyte);
+INTERNAL void gb18030_cpy(const unsigned char source[], size_t* p_length, unsigned int* gbdata, int full_multibyte);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* GB18030_H */
diff --git a/backend/gb2312.c b/backend/gb2312.c
new file mode 100644 (file)
index 0000000..1259f68
--- /dev/null
@@ -0,0 +1,1624 @@
+/*
+    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 : */
+/*
+ * Adapted from GNU LIBICONV library and patched to add 2 duplicate mappings
+ * for compatibility with GB 18030 subset:
+ * 1) U+00B7 to 0xA1A4 (duplicate of U+30FB)
+ * 2) U+2014 to 0xA1AA (duplicate of U+2015)
+ */
+/*
+ * Copyright (C) 1999-2001, 2012, 2016 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <string.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "gb2312.h"
+
+INTERNAL int utf_to_eci(const int eci, const unsigned char source[], unsigned char dest[], size_t *length); /* Convert Unicode to other encodings */
+
+/*
+ * GB2312.1980-0 (libiconv-1.16/lib/gb2312.h)
+ */
+
+/* ZINT: Table converted from GB 2312 to EUC-CN values using tools/cnv_gb2312.php:
+ *
+while ($line = fgets(STDIN)) {
+    echo preg_replace_callback('/0x([0-9a-f]{4})/', function ($matches) {
+        return '0x' . dechex(hexdec($matches[1]) + 0x8080);
+    }, $line);
+}
+ */
+static const unsigned short gb2312_2charset[7445] = {
+  0xa1e8, 0xa1ec, 0xa1a7, 0xa1e3, 0xa1c0, 0xa1c1, 0xa8a4, 0xa8a2,
+  0xa8a8, 0xa8a6, 0xa8ba, 0xa8ac, 0xa8aa, 0xa8b0, 0xa8ae, 0xa1c2,
+  0xa8b4, 0xa8b2, 0xa8b9, 0xa8a1, 0xa8a5, 0xa8a7, 0xa8a9, 0xa8ad,
+  0xa8b1, 0xa8a3, 0xa8ab, 0xa8af, 0xa8b3, 0xa8b5, 0xa8b6, 0xa8b7,
+  0xa8b8, 0xa1a6, 0xa1a5, 0xa6a1, 0xa6a2, 0xa6a3, 0xa6a4, 0xa6a5,
+  0xa6a6, 0xa6a7, 0xa6a8, 0xa6a9, 0xa6aa, 0xa6ab, 0xa6ac, 0xa6ad,
+  0xa6ae, 0xa6af, 0xa6b0, 0xa6b1, 0xa6b2, 0xa6b3, 0xa6b4, 0xa6b5,
+  0xa6b6, 0xa6b7, 0xa6b8, 0xa6c1, 0xa6c2, 0xa6c3, 0xa6c4, 0xa6c5,
+  0xa6c6, 0xa6c7, 0xa6c8, 0xa6c9, 0xa6ca, 0xa6cb, 0xa6cc, 0xa6cd,
+  0xa6ce, 0xa6cf, 0xa6d0, 0xa6d1, 0xa6d2, 0xa6d3, 0xa6d4, 0xa6d5,
+  0xa6d6, 0xa6d7, 0xa6d8, 0xa7a7, 0xa7a1, 0xa7a2, 0xa7a3, 0xa7a4,
+  0xa7a5, 0xa7a6, 0xa7a8, 0xa7a9, 0xa7aa, 0xa7ab, 0xa7ac, 0xa7ad,
+  0xa7ae, 0xa7af, 0xa7b0, 0xa7b1, 0xa7b2, 0xa7b3, 0xa7b4, 0xa7b5,
+  0xa7b6, 0xa7b7, 0xa7b8, 0xa7b9, 0xa7ba, 0xa7bb, 0xa7bc, 0xa7bd,
+  0xa7be, 0xa7bf, 0xa7c0, 0xa7c1, 0xa7d1, 0xa7d2, 0xa7d3, 0xa7d4,
+  0xa7d5, 0xa7d6, 0xa7d8, 0xa7d9, 0xa7da, 0xa7db, 0xa7dc, 0xa7dd,
+  0xa7de, 0xa7df, 0xa7e0, 0xa7e1, 0xa7e2, 0xa7e3, 0xa7e4, 0xa7e5,
+  0xa7e6, 0xa7e7, 0xa7e8, 0xa7e9, 0xa7ea, 0xa7eb, 0xa7ec, 0xa7ed,
+  0xa7ee, 0xa7ef, 0xa7f0, 0xa7f1, 0xa7d7, 0xa1aa, 0xa1ac, 0xa1ae,
+  0xa1af, 0xa1b0, 0xa1b1, 0xa1ad, 0xa1eb, 0xa1e4, 0xa1e5, 0xa1f9,
+  0xa1e6, 0xa1ed, 0xa2f1, 0xa2f2, 0xa2f3, 0xa2f4, 0xa2f5, 0xa2f6,
+  0xa2f7, 0xa2f8, 0xa2f9, 0xa2fa, 0xa2fb, 0xa2fc, 0xa1fb, 0xa1fc,
+  0xa1fa, 0xa1fd, 0xa1ca, 0xa1c7, 0xa1c6, 0xa1cc, 0xa1d8, 0xa1de,
+  0xa1cf, 0xa1ce, 0xa1c4, 0xa1c5, 0xa1c9, 0xa1c8, 0xa1d2, 0xa1d3,
+  0xa1e0, 0xa1df, 0xa1c3, 0xa1cb, 0xa1d7, 0xa1d6, 0xa1d5, 0xa1d9,
+  0xa1d4, 0xa1dc, 0xa1dd, 0xa1da, 0xa1db, 0xa1d1, 0xa1cd, 0xa1d0,
+  0xa2d9, 0xa2da, 0xa2db, 0xa2dc, 0xa2dd, 0xa2de, 0xa2df, 0xa2e0,
+  0xa2e1, 0xa2e2, 0xa2c5, 0xa2c6, 0xa2c7, 0xa2c8, 0xa2c9, 0xa2ca,
+  0xa2cb, 0xa2cc, 0xa2cd, 0xa2ce, 0xa2cf, 0xa2d0, 0xa2d1, 0xa2d2,
+  0xa2d3, 0xa2d4, 0xa2d5, 0xa2d6, 0xa2d7, 0xa2d8, 0xa2b1, 0xa2b2,
+  0xa2b3, 0xa2b4, 0xa2b5, 0xa2b6, 0xa2b7, 0xa2b8, 0xa2b9, 0xa2ba,
+  0xa2bb, 0xa2bc, 0xa2bd, 0xa2be, 0xa2bf, 0xa2c0, 0xa2c1, 0xa2c2,
+  0xa2c3, 0xa2c4, 0xa9a4, 0xa9a5, 0xa9a6, 0xa9a7, 0xa9a8, 0xa9a9,
+  0xa9aa, 0xa9ab, 0xa9ac, 0xa9ad, 0xa9ae, 0xa9af, 0xa9b0, 0xa9b1,
+  0xa9b2, 0xa9b3, 0xa9b4, 0xa9b5, 0xa9b6, 0xa9b7, 0xa9b8, 0xa9b9,
+  0xa9ba, 0xa9bb, 0xa9bc, 0xa9bd, 0xa9be, 0xa9bf, 0xa9c0, 0xa9c1,
+  0xa9c2, 0xa9c3, 0xa9c4, 0xa9c5, 0xa9c6, 0xa9c7, 0xa9c8, 0xa9c9,
+  0xa9ca, 0xa9cb, 0xa9cc, 0xa9cd, 0xa9ce, 0xa9cf, 0xa9d0, 0xa9d1,
+  0xa9d2, 0xa9d3, 0xa9d4, 0xa9d5, 0xa9d6, 0xa9d7, 0xa9d8, 0xa9d9,
+  0xa9da, 0xa9db, 0xa9dc, 0xa9dd, 0xa9de, 0xa9df, 0xa9e0, 0xa9e1,
+  0xa9e2, 0xa9e3, 0xa9e4, 0xa9e5, 0xa9e6, 0xa9e7, 0xa9e8, 0xa9e9,
+  0xa9ea, 0xa9eb, 0xa9ec, 0xa9ed, 0xa9ee, 0xa9ef, 0xa1f6, 0xa1f5,
+  0xa1f8, 0xa1f7, 0xa1f4, 0xa1f3, 0xa1f0, 0xa1f2, 0xa1f1, 0xa1ef,
+  0xa1ee, 0xa1e2, 0xa1e1, 0xa1a1, 0xa1a2, 0xa1a3, 0xa1a8, 0xa1a9,
+  0xa1b4, 0xa1b5, 0xa1b6, 0xa1b7, 0xa1b8, 0xa1b9, 0xa1ba, 0xa1bb,
+  0xa1be, 0xa1bf, 0xa1fe, 0xa1b2, 0xa1b3, 0xa1bc, 0xa1bd, 0xa4a1,
+  0xa4a2, 0xa4a3, 0xa4a4, 0xa4a5, 0xa4a6, 0xa4a7, 0xa4a8, 0xa4a9,
+  0xa4aa, 0xa4ab, 0xa4ac, 0xa4ad, 0xa4ae, 0xa4af, 0xa4b0, 0xa4b1,
+  0xa4b2, 0xa4b3, 0xa4b4, 0xa4b5, 0xa4b6, 0xa4b7, 0xa4b8, 0xa4b9,
+  0xa4ba, 0xa4bb, 0xa4bc, 0xa4bd, 0xa4be, 0xa4bf, 0xa4c0, 0xa4c1,
+  0xa4c2, 0xa4c3, 0xa4c4, 0xa4c5, 0xa4c6, 0xa4c7, 0xa4c8, 0xa4c9,
+  0xa4ca, 0xa4cb, 0xa4cc, 0xa4cd, 0xa4ce, 0xa4cf, 0xa4d0, 0xa4d1,
+  0xa4d2, 0xa4d3, 0xa4d4, 0xa4d5, 0xa4d6, 0xa4d7, 0xa4d8, 0xa4d9,
+  0xa4da, 0xa4db, 0xa4dc, 0xa4dd, 0xa4de, 0xa4df, 0xa4e0, 0xa4e1,
+  0xa4e2, 0xa4e3, 0xa4e4, 0xa4e5, 0xa4e6, 0xa4e7, 0xa4e8, 0xa4e9,
+  0xa4ea, 0xa4eb, 0xa4ec, 0xa4ed, 0xa4ee, 0xa4ef, 0xa4f0, 0xa4f1,
+  0xa4f2, 0xa4f3, 0xa5a1, 0xa5a2, 0xa5a3, 0xa5a4, 0xa5a5, 0xa5a6,
+  0xa5a7, 0xa5a8, 0xa5a9, 0xa5aa, 0xa5ab, 0xa5ac, 0xa5ad, 0xa5ae,
+  0xa5af, 0xa5b0, 0xa5b1, 0xa5b2, 0xa5b3, 0xa5b4, 0xa5b5, 0xa5b6,
+  0xa5b7, 0xa5b8, 0xa5b9, 0xa5ba, 0xa5bb, 0xa5bc, 0xa5bd, 0xa5be,
+  0xa5bf, 0xa5c0, 0xa5c1, 0xa5c2, 0xa5c3, 0xa5c4, 0xa5c5, 0xa5c6,
+  0xa5c7, 0xa5c8, 0xa5c9, 0xa5ca, 0xa5cb, 0xa5cc, 0xa5cd, 0xa5ce,
+  0xa5cf, 0xa5d0, 0xa5d1, 0xa5d2, 0xa5d3, 0xa5d4, 0xa5d5, 0xa5d6,
+  0xa5d7, 0xa5d8, 0xa5d9, 0xa5da, 0xa5db, 0xa5dc, 0xa5dd, 0xa5de,
+  0xa5df, 0xa5e0, 0xa5e1, 0xa5e2, 0xa5e3, 0xa5e4, 0xa5e5, 0xa5e6,
+  0xa5e7, 0xa5e8, 0xa5e9, 0xa5ea, 0xa5eb, 0xa5ec, 0xa5ed, 0xa5ee,
+  0xa5ef, 0xa5f0, 0xa5f1, 0xa5f2, 0xa5f3, 0xa5f4, 0xa5f5, 0xa5f6,
+  0xa1a4, 0xa8c5, 0xa8c6, 0xa8c7, 0xa8c8, 0xa8c9, 0xa8ca, 0xa8cb,
+  0xa8cc, 0xa8cd, 0xa8ce, 0xa8cf, 0xa8d0, 0xa8d1, 0xa8d2, 0xa8d3,
+  0xa8d4, 0xa8d5, 0xa8d6, 0xa8d7, 0xa8d8, 0xa8d9, 0xa8da, 0xa8db,
+  0xa8dc, 0xa8dd, 0xa8de, 0xa8df, 0xa8e0, 0xa8e1, 0xa8e2, 0xa8e3,
+  0xa8e4, 0xa8e5, 0xa8e6, 0xa8e7, 0xa8e8, 0xa8e9, 0xa2e5, 0xa2e6,
+  0xa2e7, 0xa2e8, 0xa2e9, 0xa2ea, 0xa2eb, 0xa2ec, 0xa2ed, 0xa2ee,
+  0xd2bb, 0xb6a1, 0xc6df, 0xcdf2, 0xd5c9, 0xc8fd, 0xc9cf, 0xcfc2,
+  0xd8a2, 0xb2bb, 0xd3eb, 0xd8a4, 0xb3f3, 0xd7a8, 0xc7d2, 0xd8a7,
+  0xcac0, 0xc7f0, 0xb1fb, 0xd2b5, 0xb4d4, 0xb6ab, 0xcbbf, 0xd8a9,
+  0xb6aa, 0xc1bd, 0xd1cf, 0xc9a5, 0xd8ad, 0xb8f6, 0xd1be, 0xe3dc,
+  0xd6d0, 0xb7e1, 0xb4ae, 0xc1d9, 0xd8bc, 0xcde8, 0xb5a4, 0xceaa,
+  0xd6f7, 0xc0f6, 0xbed9, 0xd8af, 0xc4cb, 0xbec3, 0xd8b1, 0xc3b4,
+  0xd2e5, 0xd6ae, 0xceda, 0xd5a7, 0xbaf5, 0xb7a6, 0xc0d6, 0xc6b9,
+  0xc5d2, 0xc7c7, 0xb9d4, 0xb3cb, 0xd2d2, 0xd8bf, 0xbec5, 0xc6f2,
+  0xd2b2, 0xcfb0, 0xcfe7, 0xcae9, 0xd8c0, 0xc2f2, 0xc2d2, 0xc8e9,
+  0xc7ac, 0xc1cb, 0xd3e8, 0xd5f9, 0xcac2, 0xb6fe, 0xd8a1, 0xd3da,
+  0xbff7, 0xd4c6, 0xbba5, 0xd8c1, 0xcee5, 0xbeae, 0xd8a8, 0xd1c7,
+  0xd0a9, 0xd8bd, 0xd9ef, 0xcdf6, 0xbfba, 0xbdbb, 0xbaa5, 0xd2e0,
+  0xb2fa, 0xbae0, 0xc4b6, 0xcfed, 0xbea9, 0xcda4, 0xc1c1, 0xc7d7,
+  0xd9f1, 0xd9f4, 0xc8cb, 0xd8e9, 0xd2da, 0xcab2, 0xc8ca, 0xd8ec,
+  0xd8ea, 0xd8c6, 0xbdf6, 0xc6cd, 0xb3f0, 0xd8eb, 0xbdf1, 0xbde9,
+  0xc8d4, 0xb4d3, 0xc2d8, 0xb2d6, 0xd7d0, 0xcacb, 0xcbfb, 0xd5cc,
+  0xb8b6, 0xcfc9, 0xd9da, 0xd8f0, 0xc7aa, 0xd8ee, 0xb4fa, 0xc1ee,
+  0xd2d4, 0xd8ed, 0xd2c7, 0xd8ef, 0xc3c7, 0xd1f6, 0xd6d9, 0xd8f2,
+  0xd8f5, 0xbcfe, 0xbcdb, 0xc8ce, 0xb7dd, 0xb7c2, 0xc6f3, 0xd8f8,
+  0xd2c1, 0xcee9, 0xbcbf, 0xb7fc, 0xb7a5, 0xd0dd, 0xd6da, 0xd3c5,
+  0xbbef, 0xbbe1, 0xd8f1, 0xc9a1, 0xceb0, 0xb4ab, 0xd8f3, 0xc9cb,
+  0xd8f6, 0xc2d7, 0xd8f7, 0xceb1, 0xd8f9, 0xb2ae, 0xb9c0, 0xd9a3,
+  0xb0e9, 0xc1e6, 0xc9ec, 0xcbc5, 0xcbc6, 0xd9a4, 0xb5e8, 0xb5ab,
+  0xcebb, 0xb5cd, 0xd7a1, 0xd7f4, 0xd3d3, 0xcce5, 0xbace, 0xd9a2,
+  0xd9dc, 0xd3e0, 0xd8fd, 0xb7f0, 0xd7f7, 0xd8fe, 0xd8fa, 0xd9a1,
+  0xc4e3, 0xd3b6, 0xd8f4, 0xd9dd, 0xd8fb, 0xc5e5, 0xc0d0, 0xd1f0,
+  0xb0db, 0xbcd1, 0xd9a6, 0xd9a5, 0xd9ac, 0xd9ae, 0xd9ab, 0xcab9,
+  0xd9a9, 0xd6b6, 0xb3de, 0xd9a8, 0xc0fd, 0xcacc, 0xd9aa, 0xd9a7,
+  0xd9b0, 0xb6b1, 0xb9a9, 0xd2c0, 0xcfc0, 0xc2c2, 0xbdc4, 0xd5ec,
+  0xb2e0, 0xc7c8, 0xbfeb, 0xd9ad, 0xd9af, 0xceea, 0xbaee, 0xc7d6,
+  0xb1e3, 0xb4d9, 0xb6ed, 0xd9b4, 0xbfa1, 0xd9de, 0xc7ce, 0xc0fe,
+  0xd9b8, 0xcbd7, 0xb7fd, 0xd9b5, 0xd9b7, 0xb1a3, 0xd3e1, 0xd9b9,
+  0xd0c5, 0xd9b6, 0xd9b1, 0xd9b2, 0xc1a9, 0xd9b3, 0xbcf3, 0xd0de,
+  0xb8a9, 0xbee3, 0xd9bd, 0xd9ba, 0xb0b3, 0xd9c2, 0xd9c4, 0xb1b6,
+  0xd9bf, 0xb5b9, 0xbef3, 0xccc8, 0xbaf2, 0xd2d0, 0xd9c3, 0xbde8,
+  0xb3ab, 0xd9c5, 0xbeeb, 0xd9c6, 0xd9bb, 0xc4df, 0xd9be, 0xd9c1,
+  0xd9c0, 0xd5ae, 0xd6b5, 0xc7e3, 0xd9c8, 0xbcd9, 0xd9ca, 0xd9bc,
+  0xd9cb, 0xc6ab, 0xd9c9, 0xd7f6, 0xcda3, 0xbda1, 0xd9cc, 0xc5bc,
+  0xcdb5, 0xd9cd, 0xd9c7, 0xb3a5, 0xbffe, 0xb8b5, 0xc0fc, 0xb0f8,
+  0xb4f6, 0xd9ce, 0xd9cf, 0xb4a2, 0xd9d0, 0xb4df, 0xb0c1, 0xd9d1,
+  0xc9b5, 0xcff1, 0xd9d2, 0xc1c5, 0xd9d6, 0xc9ae, 0xd9d5, 0xd9d4,
+  0xd9d7, 0xcbdb, 0xbda9, 0xc6a7, 0xd9d3, 0xd9d8, 0xd9d9, 0xc8e5,
+  0xc0dc, 0xb6f9, 0xd8a3, 0xd4ca, 0xd4aa, 0xd0d6, 0xb3e4, 0xd5d7,
+  0xcfc8, 0xb9e2, 0xbfcb, 0xc3e2, 0xb6d2, 0xcdc3, 0xd9ee, 0xd9f0,
+  0xb5b3, 0xb6b5, 0xbea4, 0xc8eb, 0xc8ab, 0xb0cb, 0xb9ab, 0xc1f9,
+  0xd9e2, 0xc0bc, 0xb9b2, 0xb9d8, 0xd0cb, 0xb1f8, 0xc6e4, 0xbedf,
+  0xb5e4, 0xd7c8, 0xd1f8, 0xbce6, 0xcade, 0xbcbd, 0xd9e6, 0xd8e7,
+  0xc4da, 0xb8d4, 0xc8bd, 0xb2e1, 0xd4d9, 0xc3b0, 0xc3e1, 0xdaa2,
+  0xc8df, 0xd0b4, 0xbefc, 0xc5a9, 0xb9da, 0xdaa3, 0xd4a9, 0xdaa4,
+  0xd9fb, 0xb6ac, 0xb7eb, 0xb1f9, 0xd9fc, 0xb3e5, 0xbef6, 0xbff6,
+  0xd2b1, 0xc0e4, 0xb6b3, 0xd9fe, 0xd9fd, 0xbebb, 0xc6e0, 0xd7bc,
+  0xdaa1, 0xc1b9, 0xb5f2, 0xc1e8, 0xbcf5, 0xb4d5, 0xc1dd, 0xc4fd,
+  0xbcb8, 0xb7b2, 0xb7ef, 0xd9ec, 0xc6be, 0xbfad, 0xbbcb, 0xb5ca,
+  0xdbc9, 0xd0d7, 0xcdb9, 0xb0bc, 0xb3f6, 0xbbf7, 0xdbca, 0xbaaf,
+  0xd4e4, 0xb5b6, 0xb5f3, 0xd8d6, 0xc8d0, 0xb7d6, 0xc7d0, 0xd8d7,
+  0xbfaf, 0xdbbb, 0xd8d8, 0xd0cc, 0xbbae, 0xebbe, 0xc1d0, 0xc1f5,
+  0xd4f2, 0xb8d5, 0xb4b4, 0xb3f5, 0xc9be, 0xc5d0, 0xc5d9, 0xc0fb,
+  0xb1f0, 0xd8d9, 0xb9ce, 0xb5bd, 0xd8da, 0xd6c6, 0xcba2, 0xc8af,
+  0xc9b2, 0xb4cc, 0xbfcc, 0xb9f4, 0xd8db, 0xd8dc, 0xb6e7, 0xbcc1,
+  0xccea, 0xcff7, 0xd8dd, 0xc7b0, 0xb9d0, 0xbda3, 0xccde, 0xc6ca,
+  0xd8e0, 0xd8de, 0xd8df, 0xb0fe, 0xbee7, 0xcaa3, 0xbcf4, 0xb8b1,
+  0xb8ee, 0xd8e2, 0xbdcb, 0xd8e4, 0xd8e3, 0xc5fc, 0xd8e5, 0xd8e6,
+  0xc1a6, 0xc8b0, 0xb0ec, 0xb9a6, 0xbcd3, 0xcef1, 0xdbbd, 0xc1d3,
+  0xb6af, 0xd6fa, 0xc5ac, 0xbdd9, 0xdbbe, 0xdbbf, 0xc0f8, 0xbea2,
+  0xc0cd, 0xdbc0, 0xcac6, 0xb2aa, 0xd3c2, 0xc3e3, 0xd1ab, 0xdbc2,
+  0xc0d5, 0xdbc3, 0xbfb1, 0xc4bc, 0xc7da, 0xdbc4, 0xd9e8, 0xc9d7,
+  0xb9b4, 0xcef0, 0xd4c8, 0xb0fc, 0xb4d2, 0xd0d9, 0xd9e9, 0xdecb,
+  0xd9eb, 0xd8b0, 0xbbaf, 0xb1b1, 0xb3d7, 0xd8ce, 0xd4d1, 0xbdb3,
+  0xbfef, 0xcfbb, 0xd8d0, 0xb7cb, 0xd8d1, 0xc6a5, 0xc7f8, 0xd2bd,
+  0xd8d2, 0xc4e4, 0xcaae, 0xc7a7, 0xd8a6, 0xc9fd, 0xcee7, 0xbbdc,
+  0xb0eb, 0xbbaa, 0xd0ad, 0xb1b0, 0xd7e4, 0xd7bf, 0xb5a5, 0xc2f4,
+  0xc4cf, 0xb2a9, 0xb2b7, 0xb1e5, 0xdfb2, 0xd5bc, 0xbfa8, 0xc2ac,
+  0xd8d5, 0xc2b1, 0xd8d4, 0xced4, 0xdae0, 0xcec0, 0xd8b4, 0xc3ae,
+  0xd3a1, 0xcea3, 0xbcb4, 0xc8b4, 0xc2d1, 0xbeed, 0xd0b6, 0xdae1,
+  0xc7e4, 0xb3a7, 0xb6f2, 0xccfc, 0xc0fa, 0xc0f7, 0xd1b9, 0xd1e1,
+  0xd8c7, 0xb2de, 0xc0e5, 0xbaf1, 0xd8c8, 0xd4ad, 0xcfe1, 0xd8c9,
+  0xd8ca, 0xcfc3, 0xb3f8, 0xbec7, 0xd8cb, 0xdbcc, 0xc8a5, 0xcfd8,
+  0xc8fe, 0xb2ce, 0xd3d6, 0xb2e6, 0xbcb0, 0xd3d1, 0xcbab, 0xb7b4,
+  0xb7a2, 0xcae5, 0xc8a1, 0xcadc, 0xb1e4, 0xd0f0, 0xc5d1, 0xdbc5,
+  0xb5fe, 0xbfda, 0xb9c5, 0xbee4, 0xc1ed, 0xdfb6, 0xdfb5, 0xd6bb,
+  0xbdd0, 0xd5d9, 0xb0c8, 0xb6a3, 0xbfc9, 0xcca8, 0xdfb3, 0xcab7,
+  0xd3d2, 0xd8cf, 0xd2b6, 0xbac5, 0xcbbe, 0xccbe, 0xdfb7, 0xb5f0,
+  0xdfb4, 0xd3f5, 0xb3d4, 0xb8f7, 0xdfba, 0xbacf, 0xbcaa, 0xb5f5,
+  0xcdac, 0xc3fb, 0xbaf3, 0xc0f4, 0xcdc2, 0xcff2, 0xdfb8, 0xcfc5,
+  0xc2c0, 0xdfb9, 0xc2f0, 0xbefd, 0xc1df, 0xcdcc, 0xd2f7, 0xb7cd,
+  0xdfc1, 0xdfc4, 0xb7f1, 0xb0c9, 0xb6d6, 0xb7d4, 0xbaac, 0xccfd,
+  0xbfd4, 0xcbb1, 0xc6f4, 0xd6a8, 0xdfc5, 0xcee2, 0xb3b3, 0xcefc,
+  0xb4b5, 0xcec7, 0xbaf0, 0xcee1, 0xd1bd, 0xdfc0, 0xb4f4, 0xb3ca,
+  0xb8e6, 0xdfbb, 0xc4c5, 0xdfbc, 0xdfbd, 0xdfbe, 0xc5bb, 0xdfbf,
+  0xdfc2, 0xd4b1, 0xdfc3, 0xc7ba, 0xced8, 0xc4d8, 0xdfca, 0xdfcf,
+  0xd6dc, 0xdfc9, 0xdfda, 0xceb6, 0xbac7, 0xdfce, 0xdfc8, 0xc5de,
+  0xc9eb, 0xbaf4, 0xc3fc, 0xbed7, 0xdfc6, 0xdfcd, 0xc5d8, 0xd5a6,
+  0xbacd, 0xbecc, 0xd3bd, 0xb8c0, 0xd6e4, 0xdfc7, 0xb9be, 0xbfa7,
+  0xc1fc, 0xdfcb, 0xdfcc, 0xdfd0, 0xdfdb, 0xdfe5, 0xdfd7, 0xdfd6,
+  0xd7c9, 0xdfe3, 0xdfe4, 0xe5eb, 0xd2a7, 0xdfd2, 0xbfa9, 0xd4db,
+  0xbfc8, 0xdfd4, 0xcfcc, 0xdfdd, 0xd1ca, 0xdfde, 0xb0a7, 0xc6b7,
+  0xdfd3, 0xbae5, 0xb6df, 0xcddb, 0xb9fe, 0xd4d5, 0xdfdf, 0xcfec,
+  0xb0a5, 0xdfe7, 0xdfd1, 0xd1c6, 0xdfd5, 0xdfd8, 0xdfd9, 0xdfdc,
+  0xbba9, 0xdfe0, 0xdfe1, 0xdfe2, 0xdfe6, 0xdfe8, 0xd3b4, 0xb8e7,
+  0xc5b6, 0xdfea, 0xc9da, 0xc1a8, 0xc4c4, 0xbfde, 0xcff8, 0xd5dc,
+  0xdfee, 0xb2b8, 0xbadf, 0xdfec, 0xdbc1, 0xd1e4, 0xcbf4, 0xb4bd,
+  0xb0a6, 0xdff1, 0xccc6, 0xdff2, 0xdfed, 0xdfe9, 0xdfeb, 0xdfef,
+  0xdff0, 0xbbbd, 0xdff3, 0xdff4, 0xbba3, 0xcadb, 0xcea8, 0xe0a7,
+  0xb3aa, 0xe0a6, 0xe0a1, 0xdffe, 0xcdd9, 0xdffc, 0xdffa, 0xbfd0,
+  0xd7c4, 0xc9cc, 0xdff8, 0xb0a1, 0xdffd, 0xdffb, 0xe0a2, 0xe0a8,
+  0xb7c8, 0xc6a1, 0xc9b6, 0xc0b2, 0xdff5, 0xc5be, 0xd8c4, 0xdff9,
+  0xc4f6, 0xe0a3, 0xe0a4, 0xe0a5, 0xd0a5, 0xe0b4, 0xcce4, 0xe0b1,
+  0xbfa6, 0xe0af, 0xceb9, 0xe0ab, 0xc9c6, 0xc0ae, 0xe0ae, 0xbaed,
+  0xbab0, 0xe0a9, 0xdff6, 0xe0b3, 0xe0b8, 0xb4ad, 0xe0b9, 0xcfb2,
+  0xbac8, 0xe0b0, 0xd0fa, 0xe0ac, 0xd4fb, 0xdff7, 0xc5e7, 0xe0ad,
+  0xd3f7, 0xe0b6, 0xe0b7, 0xe0c4, 0xd0e1, 0xe0bc, 0xe0c9, 0xe0ca,
+  0xe0be, 0xe0aa, 0xc9a4, 0xe0c1, 0xe0b2, 0xcac8, 0xe0c3, 0xe0b5,
+  0xcecb, 0xcbc3, 0xe0cd, 0xe0c6, 0xe0c2, 0xe0cb, 0xe0ba, 0xe0bf,
+  0xe0c0, 0xe0c5, 0xe0c7, 0xe0c8, 0xe0cc, 0xe0bb, 0xcbd4, 0xe0d5,
+  0xe0d6, 0xe0d2, 0xe0d0, 0xbcce, 0xe0d1, 0xb8c2, 0xd8c5, 0xd0ea,
+  0xc2ef, 0xe0cf, 0xe0bd, 0xe0d4, 0xe0d3, 0xe0d7, 0xe0dc, 0xe0d8,
+  0xd6f6, 0xb3b0, 0xd7ec, 0xcbbb, 0xe0da, 0xcefb, 0xbad9, 0xe0e1,
+  0xe0dd, 0xd2ad, 0xe0e2, 0xe0db, 0xe0d9, 0xe0df, 0xe0e0, 0xe0de,
+  0xe0e4, 0xc6f7, 0xd8ac, 0xd4eb, 0xe0e6, 0xcac9, 0xe0e5, 0xb8c1,
+  0xe0e7, 0xe0e8, 0xe0e9, 0xe0e3, 0xbabf, 0xcce7, 0xe0ea, 0xcff9,
+  0xe0eb, 0xc8c2, 0xbdc0, 0xc4d2, 0xe0ec, 0xe0ed, 0xc7f4, 0xcbc4,
+  0xe0ee, 0xbbd8, 0xd8b6, 0xd2f2, 0xe0ef, 0xcdc5, 0xb6da, 0xe0f1,
+  0xd4b0, 0xc0a7, 0xb4d1, 0xcea7, 0xe0f0, 0xe0f2, 0xb9cc, 0xb9fa,
+  0xcdbc, 0xe0f3, 0xc6d4, 0xe0f4, 0xd4b2, 0xc8a6, 0xe0f6, 0xe0f5,
+  0xe0f7, 0xcdc1, 0xcaa5, 0xd4da, 0xdbd7, 0xdbd9, 0xdbd8, 0xb9e7,
+  0xdbdc, 0xdbdd, 0xb5d8, 0xdbda, 0xdbdb, 0xb3a1, 0xdbdf, 0xbbf8,
+  0xd6b7, 0xdbe0, 0xbef9, 0xb7bb, 0xdbd0, 0xccae, 0xbfb2, 0xbbb5,
+  0xd7f8, 0xbfd3, 0xbfe9, 0xbce1, 0xccb3, 0xdbde, 0xb0d3, 0xceeb,
+  0xb7d8, 0xd7b9, 0xc6c2, 0xc0a4, 0xccb9, 0xdbe7, 0xdbe1, 0xc6ba,
+  0xdbe3, 0xdbe8, 0xc5f7, 0xdbea, 0xdbe9, 0xbfc0, 0xdbe6, 0xdbe5,
+  0xb4b9, 0xc0ac, 0xc2a2, 0xdbe2, 0xdbe4, 0xd0cd, 0xdbed, 0xc0dd,
+  0xdbf2, 0xb6e2, 0xdbf3, 0xdbd2, 0xb9b8, 0xd4ab, 0xdbec, 0xbfd1,
+  0xdbf0, 0xdbd1, 0xb5e6, 0xdbeb, 0xbfe5, 0xdbee, 0xdbf1, 0xdbf9,
+  0xb9a1, 0xb0a3, 0xc2f1, 0xb3c7, 0xdbef, 0xdbf8, 0xc6d2, 0xdbf4,
+  0xdbf5, 0xdbf7, 0xdbf6, 0xdbfe, 0xd3f2, 0xb2ba, 0xdbfd, 0xdca4,
+  0xdbfb, 0xdbfa, 0xdbfc, 0xc5e0, 0xbbf9, 0xdca3, 0xdca5, 0xccc3,
+  0xb6d1, 0xddc0, 0xdca1, 0xdca2, 0xc7b5, 0xb6e9, 0xdca7, 0xdca6,
+  0xdca9, 0xb1a4, 0xb5cc, 0xbfb0, 0xd1df, 0xb6c2, 0xdca8, 0xcbfa,
+  0xebf3, 0xcbdc, 0xcbfe, 0xccc1, 0xc8fb, 0xdcaa, 0xccee, 0xdcab,
+  0xdbd3, 0xdcaf, 0xdcac, 0xbeb3, 0xcafb, 0xdcad, 0xc9ca, 0xc4b9,
+  0xc7bd, 0xdcae, 0xd4f6, 0xd0e6, 0xc4ab, 0xb6d5, 0xdbd4, 0xb1da,
+  0xdbd5, 0xdbd6, 0xbabe, 0xc8c0, 0xcabf, 0xc8c9, 0xd7b3, 0xc9f9,
+  0xbfc7, 0xbaf8, 0xd2bc, 0xe2ba, 0xb4a6, 0xb1b8, 0xb8b4, 0xcfc4,
+  0xd9e7, 0xcfa6, 0xcde2, 0xd9ed, 0xb6e0, 0xd2b9, 0xb9bb, 0xe2b9,
+  0xe2b7, 0xb4f3, 0xccec, 0xccab, 0xb7f2, 0xd8b2, 0xd1eb, 0xbabb,
+  0xcaa7, 0xcdb7, 0xd2c4, 0xbfe4, 0xbcd0, 0xb6e1, 0xdec5, 0xdec6,
+  0xdbbc, 0xd1d9, 0xc6e6, 0xc4ce, 0xb7ee, 0xb7dc, 0xbffc, 0xd7e0,
+  0xc6f5, 0xb1bc, 0xdec8, 0xbdb1, 0xccd7, 0xdeca, 0xdec9, 0xb5ec,
+  0xc9dd, 0xb0c2, 0xc5ae, 0xc5ab, 0xc4cc, 0xbce9, 0xcbfd, 0xbac3,
+  0xe5f9, 0xc8e7, 0xe5fa, 0xcdfd, 0xd7b1, 0xb8be, 0xc2e8, 0xc8d1,
+  0xe5fb, 0xb6ca, 0xbccb, 0xd1fd, 0xe6a1, 0xc3ee, 0xe6a4, 0xe5fe,
+  0xe6a5, 0xcdd7, 0xb7c1, 0xe5fc, 0xe5fd, 0xe6a3, 0xc4dd, 0xe6a8,
+  0xe6a7, 0xc3c3, 0xc6de, 0xe6aa, 0xc4b7, 0xe6a2, 0xcabc, 0xbde3,
+  0xb9c3, 0xe6a6, 0xd0d5, 0xceaf, 0xe6a9, 0xe6b0, 0xd2a6, 0xbdaa,
+  0xe6ad, 0xe6af, 0xc0d1, 0xd2cc, 0xbca7, 0xe6b1, 0xd2f6, 0xd7cb,
+  0xcdfe, 0xcdde, 0xc2a6, 0xe6ab, 0xe6ac, 0xbdbf, 0xe6ae, 0xe6b3,
+  0xe6b2, 0xe6b6, 0xe6b8, 0xc4ef, 0xc4c8, 0xbeea, 0xc9ef, 0xe6b7,
+  0xb6f0, 0xc3e4, 0xd3e9, 0xe6b4, 0xe6b5, 0xc8a2, 0xe6bd, 0xe6b9,
+  0xc6c5, 0xcdf1, 0xe6bb, 0xe6bc, 0xbbe9, 0xe6be, 0xe6ba, 0xc0b7,
+  0xd3a4, 0xe6bf, 0xc9f4, 0xe6c3, 0xe6c4, 0xd0f6, 0xc3bd, 0xc3c4,
+  0xe6c2, 0xe6c1, 0xe6c7, 0xcfb1, 0xebf4, 0xe6ca, 0xe6c5, 0xbcde,
+  0xc9a9, 0xbcb5, 0xcfd3, 0xe6c8, 0xe6c9, 0xe6ce, 0xe6d0, 0xe6d1,
+  0xe6cb, 0xb5d5, 0xe6cc, 0xe6cf, 0xc4db, 0xe6c6, 0xe6cd, 0xe6d2,
+  0xe6d4, 0xe6d3, 0xe6d5, 0xd9f8, 0xe6d6, 0xe6d7, 0xd7d3, 0xe6dd,
+  0xe6de, 0xbfd7, 0xd4d0, 0xd7d6, 0xb4e6, 0xcbef, 0xe6da, 0xd8c3,
+  0xd7ce, 0xd0a2, 0xc3cf, 0xe6df, 0xbcbe, 0xb9c2, 0xe6db, 0xd1a7,
+  0xbaa2, 0xc2cf, 0xd8ab, 0xcaeb, 0xe5ee, 0xe6dc, 0xb7f5, 0xc8e6,
+  0xc4f5, 0xe5b2, 0xc4fe, 0xcbfc, 0xe5b3, 0xd5ac, 0xd3ee, 0xcad8,
+  0xb0b2, 0xcbce, 0xcdea, 0xbaea, 0xe5b5, 0xe5b4, 0xd7da, 0xb9d9,
+  0xd6e6, 0xb6a8, 0xcdf0, 0xd2cb, 0xb1a6, 0xcab5, 0xb3e8, 0xc9f3,
+  0xbfcd, 0xd0fb, 0xcad2, 0xe5b6, 0xbbc2, 0xcfdc, 0xb9ac, 0xd4d7,
+  0xbaa6, 0xd1e7, 0xcffc, 0xbcd2, 0xe5b7, 0xc8dd, 0xbfed, 0xb1f6,
+  0xcbde, 0xbcc5, 0xbcc4, 0xd2fa, 0xc3dc, 0xbfdc, 0xb8bb, 0xc3c2,
+  0xbaae, 0xd4a2, 0xc7de, 0xc4af, 0xb2ec, 0xb9d1, 0xe5bb, 0xc1c8,
+  0xd5af, 0xe5bc, 0xe5be, 0xb4e7, 0xb6d4, 0xcbc2, 0xd1b0, 0xb5bc,
+  0xcad9, 0xb7e2, 0xc9e4, 0xbdab, 0xcebe, 0xd7f0, 0xd0a1, 0xc9d9,
+  0xb6fb, 0xe6d8, 0xbce2, 0xb3be, 0xc9d0, 0xe6d9, 0xb3a2, 0xdecc,
+  0xd3c8, 0xdecd, 0xd2a2, 0xdece, 0xbecd, 0xdecf, 0xcaac, 0xd2fc,
+  0xb3df, 0xe5ea, 0xc4e1, 0xbea1, 0xceb2, 0xc4f2, 0xbed6, 0xc6a8,
+  0xb2e3, 0xbed3, 0xc7fc, 0xcceb, 0xbdec, 0xcedd, 0xcaba, 0xc6c1,
+  0xe5ec, 0xd0bc, 0xd5b9, 0xe5ed, 0xcaf4, 0xcdc0, 0xc2c5, 0xe5ef,
+  0xc2c4, 0xe5f0, 0xe5f8, 0xcdcd, 0xc9bd, 0xd2d9, 0xe1a8, 0xd3ec,
+  0xcbea, 0xc6f1, 0xe1ac, 0xe1a7, 0xe1a9, 0xe1aa, 0xe1af, 0xb2ed,
+  0xe1ab, 0xb8da, 0xe1ad, 0xe1ae, 0xe1b0, 0xb5ba, 0xe1b1, 0xe1b3,
+  0xe1b8, 0xd1d2, 0xe1b6, 0xe1b5, 0xc1eb, 0xe1b7, 0xd4c0, 0xe1b2,
+  0xe1ba, 0xb0b6, 0xe1b4, 0xbff9, 0xe1b9, 0xe1bb, 0xe1be, 0xe1bc,
+  0xd6c5, 0xcfbf, 0xe1bd, 0xe1bf, 0xc2cd, 0xb6eb, 0xd3f8, 0xc7cd,
+  0xb7e5, 0xbefe, 0xe1c0, 0xe1c1, 0xe1c7, 0xb3e7, 0xc6e9, 0xb4de,
+  0xd1c2, 0xe1c8, 0xe1c6, 0xe1c5, 0xe1c3, 0xe1c2, 0xb1c0, 0xd5b8,
+  0xe1c4, 0xe1cb, 0xe1cc, 0xe1ca, 0xeffa, 0xe1d3, 0xe1d2, 0xc7b6,
+  0xe1c9, 0xe1ce, 0xe1d0, 0xe1d4, 0xe1d1, 0xe1cd, 0xe1cf, 0xe1d5,
+  0xe1d6, 0xe1d7, 0xe1d8, 0xe1da, 0xe1db, 0xcea1, 0xe7dd, 0xb4a8,
+  0xd6dd, 0xd1b2, 0xb3b2, 0xb9a4, 0xd7f3, 0xc7c9, 0xbede, 0xb9ae,
+  0xced7, 0xb2ee, 0xdbcf, 0xbcba, 0xd2d1, 0xcbc8, 0xb0cd, 0xcfef,
+  0xd9e3, 0xbded, 0xb1d2, 0xcad0, 0xb2bc, 0xcba7, 0xb7ab, 0xcaa6,
+  0xcfa3, 0xe0f8, 0xd5ca, 0xe0fb, 0xe0fa, 0xc5c1, 0xccfb, 0xc1b1,
+  0xe0f9, 0xd6e3, 0xb2af, 0xd6c4, 0xb5db, 0xb4f8, 0xd6a1, 0xcfaf,
+  0xb0ef, 0xe0fc, 0xe1a1, 0xb3a3, 0xe0fd, 0xe0fe, 0xc3b1, 0xc3dd,
+  0xe1a2, 0xb7f9, 0xbbcf, 0xe1a3, 0xc4bb, 0xe1a4, 0xe1a5, 0xe1a6,
+  0xb4b1, 0xb8c9, 0xc6bd, 0xc4ea, 0xb2a2, 0xd0d2, 0xe7db, 0xbbc3,
+  0xd3d7, 0xd3c4, 0xb9e3, 0xe2cf, 0xd7af, 0xc7ec, 0xb1d3, 0xb4b2,
+  0xe2d1, 0xd0f2, 0xc2ae, 0xe2d0, 0xbfe2, 0xd3a6, 0xb5d7, 0xe2d2,
+  0xb5ea, 0xc3ed, 0xb8fd, 0xb8ae, 0xc5d3, 0xb7cf, 0xe2d4, 0xe2d3,
+  0xb6c8, 0xd7f9, 0xcda5, 0xe2d8, 0xe2d6, 0xcafc, 0xbfb5, 0xd3b9,
+  0xe2d5, 0xe2d7, 0xc1ae, 0xc0c8, 0xe2db, 0xe2da, 0xc0aa, 0xc1ce,
+  0xe2dc, 0xe2dd, 0xe2de, 0xdbc8, 0xd1d3, 0xcda2, 0xbda8, 0xdec3,
+  0xd8a5, 0xbfaa, 0xdbcd, 0xd2ec, 0xc6fa, 0xc5aa, 0xdec4, 0xb1d7,
+  0xdfae, 0xcabd, 0xdfb1, 0xb9ad, 0xd2fd, 0xb8a5, 0xbaeb, 0xb3da,
+  0xb5dc, 0xd5c5, 0xc3d6, 0xcfd2, 0xbba1, 0xe5f3, 0xe5f2, 0xe5f4,
+  0xcde4, 0xc8f5, 0xb5af, 0xc7bf, 0xe5f6, 0xecb0, 0xe5e6, 0xb9e9,
+  0xb5b1, 0xc2bc, 0xe5e8, 0xe5e7, 0xe5e9, 0xd2cd, 0xe1ea, 0xd0ce,
+  0xcdae, 0xd1e5, 0xb2ca, 0xb1eb, 0xb1f2, 0xc5ed, 0xd5c3, 0xd3b0,
+  0xe1dc, 0xe1dd, 0xd2db, 0xb3b9, 0xb1cb, 0xcdf9, 0xd5f7, 0xe1de,
+  0xbeb6, 0xb4fd, 0xe1df, 0xbadc, 0xe1e0, 0xbbb2, 0xc2c9, 0xe1e1,
+  0xd0ec, 0xcdbd, 0xe1e2, 0xb5c3, 0xc5c7, 0xe1e3, 0xe1e4, 0xd3f9,
+  0xe1e5, 0xd1ad, 0xe1e6, 0xcea2, 0xe1e7, 0xb5c2, 0xe1e8, 0xbbd5,
+  0xd0c4, 0xe2e0, 0xb1d8, 0xd2e4, 0xe2e1, 0xbcc9, 0xc8cc, 0xe2e3,
+  0xecfe, 0xecfd, 0xdfaf, 0xe2e2, 0xd6be, 0xcdfc, 0xc3a6, 0xe3c3,
+  0xd6d2, 0xe2e7, 0xe2e8, 0xd3c7, 0xe2ec, 0xbfec, 0xe2ed, 0xe2e5,
+  0xb3c0, 0xc4ee, 0xe2ee, 0xd0c3, 0xbaf6, 0xe2e9, 0xb7de, 0xbbb3,
+  0xccac, 0xcbcb, 0xe2e4, 0xe2e6, 0xe2ea, 0xe2eb, 0xe2f7, 0xe2f4,
+  0xd4f5, 0xe2f3, 0xc5ad, 0xd5fa, 0xc5c2, 0xb2c0, 0xe2ef, 0xe2f2,
+  0xc1af, 0xcbbc, 0xb5a1, 0xe2f9, 0xbcb1, 0xe2f1, 0xd0d4, 0xd4b9,
+  0xe2f5, 0xb9d6, 0xe2f6, 0xc7d3, 0xe2f0, 0xd7dc, 0xeda1, 0xe2f8,
+  0xeda5, 0xe2fe, 0xcad1, 0xc1b5, 0xbbd0, 0xbfd6, 0xbae3, 0xcba1,
+  0xeda6, 0xeda3, 0xeda2, 0xbbd6, 0xeda7, 0xd0f4, 0xeda4, 0xbade,
+  0xb6f7, 0xe3a1, 0xb6b2, 0xccf1, 0xb9a7, 0xcfa2, 0xc7a1, 0xbfd2,
+  0xb6f1, 0xe2fa, 0xe2fb, 0xe2fd, 0xe2fc, 0xc4d5, 0xe3a2, 0xd3c1,
+  0xe3a7, 0xc7c4, 0xcfa4, 0xe3a9, 0xbab7, 0xe3a8, 0xbbda, 0xe3a3,
+  0xe3a4, 0xe3aa, 0xe3a6, 0xcef2, 0xd3c6, 0xbbbc, 0xd4c3, 0xc4fa,
+  0xeda8, 0xd0fc, 0xe3a5, 0xc3f5, 0xe3ad, 0xb1af, 0xe3b2, 0xbcc2,
+  0xe3ac, 0xb5bf, 0xc7e9, 0xe3b0, 0xbeaa, 0xcdef, 0xbbf3, 0xcce8,
+  0xe3af, 0xe3b1, 0xcfa7, 0xe3ae, 0xcea9, 0xbbdd, 0xb5eb, 0xbee5,
+  0xb2d2, 0xb3cd, 0xb1b9, 0xe3ab, 0xb2d1, 0xb5ac, 0xb9df, 0xb6e8,
+  0xcfeb, 0xe3b7, 0xbbcc, 0xc8c7, 0xd0ca, 0xe3b8, 0xb3ee, 0xeda9,
+  0xd3fa, 0xd3e4, 0xedaa, 0xe3b9, 0xd2e2, 0xe3b5, 0xd3de, 0xb8d0,
+  0xe3b3, 0xe3b6, 0xb7df, 0xe3b4, 0xc0a2, 0xe3ba, 0xd4b8, 0xb4c8,
+  0xe3bb, 0xbbc5, 0xc9f7, 0xc9e5, 0xc4bd, 0xedab, 0xc2fd, 0xbbdb,
+  0xbfae, 0xcebf, 0xe3bc, 0xbfb6, 0xb1ef, 0xd4f7, 0xe3be, 0xedad,
+  0xe3bf, 0xbaa9, 0xedac, 0xe3bd, 0xe3c0, 0xbab6, 0xb6ae, 0xd0b8,
+  0xb0c3, 0xedae, 0xedaf, 0xc0c1, 0xe3c1, 0xc5b3, 0xe3c2, 0xdcb2,
+  0xedb0, 0xb8ea, 0xceec, 0xeaa7, 0xd0e7, 0xcaf9, 0xc8d6, 0xcfb7,
+  0xb3c9, 0xced2, 0xbde4, 0xe3de, 0xbbf2, 0xeaa8, 0xd5bd, 0xc6dd,
+  0xeaa9, 0xeaaa, 0xeaac, 0xeaab, 0xeaae, 0xeaad, 0xbdd8, 0xeaaf,
+  0xc2be, 0xb4c1, 0xb4f7, 0xbba7, 0xece6, 0xece5, 0xb7bf, 0xcbf9,
+  0xb1e2, 0xece7, 0xc9c8, 0xece8, 0xece9, 0xcad6, 0xded0, 0xb2c5,
+  0xd4fa, 0xc6cb, 0xb0c7, 0xb4f2, 0xc8d3, 0xcdd0, 0xbfb8, 0xbfdb,
+  0xc7a4, 0xd6b4, 0xc0a9, 0xded1, 0xc9a8, 0xd1ef, 0xc5a4, 0xb0e7,
+  0xb3b6, 0xc8c5, 0xb0e2, 0xb7f6, 0xc5fa, 0xb6f3, 0xd5d2, 0xb3d0,
+  0xbcbc, 0xb3ad, 0xbef1, 0xb0d1, 0xd2d6, 0xcae3, 0xd7a5, 0xcdb6,
+  0xb6b6, 0xbfb9, 0xd5db, 0xb8a7, 0xc5d7, 0xded2, 0xbfd9, 0xc2d5,
+  0xc7c0, 0xbba4, 0xb1a8, 0xc5ea, 0xc5fb, 0xcca7, 0xb1a7, 0xb5d6,
+  0xc4a8, 0xded3, 0xd1ba, 0xb3e9, 0xc3f2, 0xb7f7, 0xd6f4, 0xb5a3,
+  0xb2f0, 0xc4b4, 0xc4e9, 0xc0ad, 0xded4, 0xb0e8, 0xc5c4, 0xc1e0,
+  0xb9d5, 0xbedc, 0xcdd8, 0xb0ce, 0xcdcf, 0xded6, 0xbed0, 0xd7be,
+  0xded5, 0xd5d0, 0xb0dd, 0xc4e2, 0xc2a3, 0xbcf0, 0xd3b5, 0xc0b9,
+  0xc5a1, 0xb2a6, 0xd4f1, 0xc0a8, 0xcac3, 0xded7, 0xd5fc, 0xb9b0,
+  0xc8ad, 0xcba9, 0xded9, 0xbfbd, 0xc6b4, 0xd7a7, 0xcab0, 0xc4c3,
+  0xb3d6, 0xb9d2, 0xd6b8, 0xeafc, 0xb0b4, 0xbfe6, 0xccf4, 0xcdda,
+  0xd6bf, 0xc2ce, 0xcece, 0xcca2, 0xd0ae, 0xc4d3, 0xb5b2, 0xded8,
+  0xd5f5, 0xbcb7, 0xbbd3, 0xb0a4, 0xc5b2, 0xb4ec, 0xd5f1, 0xeafd,
+  0xdeda, 0xcda6, 0xcdec, 0xcee6, 0xdedc, 0xcdb1, 0xc0a6, 0xd7bd,
+  0xdedb, 0xb0c6, 0xbab4, 0xc9d3, 0xc4f3, 0xbee8, 0xb2b6, 0xc0cc,
+  0xcbf0, 0xbcf1, 0xbbbb, 0xb5b7, 0xc5f5, 0xdee6, 0xdee3, 0xbedd,
+  0xdedf, 0xb4b7, 0xbddd, 0xdee0, 0xc4ed, 0xcfc6, 0xb5e0, 0xb6de,
+  0xcada, 0xb5f4, 0xdee5, 0xd5c6, 0xdee1, 0xcccd, 0xc6fe, 0xc5c5,
+  0xd2b4, 0xbef2, 0xc2d3, 0xccbd, 0xb3b8, 0xbdd3, 0xbfd8, 0xcdc6,
+  0xd1da, 0xb4eb, 0xdee4, 0xdedd, 0xdee7, 0xeafe, 0xc2b0, 0xdee2,
+  0xd6c0, 0xb5a7, 0xb2f4, 0xdee8, 0xdef2, 0xdeed, 0xdef1, 0xc8e0,
+  0xd7e1, 0xdeef, 0xc3e8, 0xcce1, 0xb2e5, 0xd2be, 0xdeee, 0xdeeb,
+  0xced5, 0xb4a7, 0xbfab, 0xbebe, 0xbdd2, 0xdee9, 0xd4ae, 0xdede,
+  0xdeea, 0xc0bf, 0xdeec, 0xb2f3, 0xb8e9, 0xc2a7, 0xbdc1, 0xdef5,
+  0xdef8, 0xb2ab, 0xb4a4, 0xb4ea, 0xc9a6, 0xdef6, 0xcbd1, 0xb8e3,
+  0xdef7, 0xdefa, 0xdef9, 0xccc2, 0xb0e1, 0xb4ee, 0xe5ba, 0xd0af,
+  0xb2eb, 0xeba1, 0xdef4, 0xc9e3, 0xdef3, 0xb0da, 0xd2a1, 0xb1f7,
+  0xccaf, 0xdef0, 0xcba4, 0xd5aa, 0xdefb, 0xb4dd, 0xc4a6, 0xdefd,
+  0xc3fe, 0xc4a1, 0xdfa1, 0xc1cc, 0xdefc, 0xbeef, 0xc6b2, 0xb3c5,
+  0xc8f6, 0xcbba, 0xdefe, 0xdfa4, 0xd7b2, 0xb3b7, 0xc1c3, 0xc7cb,
+  0xb2a5, 0xb4e9, 0xd7ab, 0xc4ec, 0xdfa2, 0xdfa3, 0xdfa5, 0xbab3,
+  0xdfa6, 0xc0de, 0xc9c3, 0xb2d9, 0xc7e6, 0xdfa7, 0xc7dc, 0xdfa8,
+  0xeba2, 0xcbd3, 0xdfaa, 0xdfa9, 0xb2c1, 0xc5ca, 0xdfab, 0xd4dc,
+  0xc8c1, 0xdfac, 0xbef0, 0xdfad, 0xd6a7, 0xeab7, 0xebb6, 0xcad5,
+  0xd8fc, 0xb8c4, 0xb9a5, 0xb7c5, 0xd5fe, 0xb9ca, 0xd0a7, 0xf4cd,
+  0xb5d0, 0xc3f4, 0xbec8, 0xebb7, 0xb0bd, 0xbdcc, 0xc1b2, 0xb1d6,
+  0xb3a8, 0xb8d2, 0xc9a2, 0xb6d8, 0xebb8, 0xbeb4, 0xcafd, 0xc7c3,
+  0xd5fb, 0xb7f3, 0xcec4, 0xd5ab, 0xb1f3, 0xecb3, 0xb0df, 0xecb5,
+  0xb6b7, 0xc1cf, 0xf5fa, 0xd0b1, 0xd5e5, 0xced3, 0xbdef, 0xb3e2,
+  0xb8ab, 0xd5b6, 0xedbd, 0xb6cf, 0xcbb9, 0xd0c2, 0xb7bd, 0xecb6,
+  0xcaa9, 0xc5d4, 0xecb9, 0xecb8, 0xc2c3, 0xecb7, 0xd0fd, 0xecba,
+  0xecbb, 0xd7e5, 0xecbc, 0xecbd, 0xc6ec, 0xcede, 0xbcc8, 0xc8d5,
+  0xb5a9, 0xbec9, 0xd6bc, 0xd4e7, 0xd1ae, 0xd0f1, 0xeab8, 0xeab9,
+  0xeaba, 0xbab5, 0xcab1, 0xbff5, 0xcdfa, 0xeac0, 0xb0ba, 0xeabe,
+  0xc0a5, 0xeabb, 0xb2fd, 0xc3f7, 0xbbe8, 0xd2d7, 0xcef4, 0xeabf,
+  0xeabc, 0xeac3, 0xd0c7, 0xd3b3, 0xb4ba, 0xc3c1, 0xd7f2, 0xd5d1,
+  0xcac7, 0xeac5, 0xeac4, 0xeac7, 0xeac6, 0xd6e7, 0xcfd4, 0xeacb,
+  0xbbce, 0xbdfa, 0xc9ce, 0xeacc, 0xc9b9, 0xcffe, 0xeaca, 0xd4ce,
+  0xeacd, 0xeacf, 0xcded, 0xeac9, 0xeace, 0xceee, 0xbbde, 0xb3bf,
+  0xc6d5, 0xbeb0, 0xcefa, 0xc7e7, 0xbea7, 0xead0, 0xd6c7, 0xc1c0,
+  0xd4dd, 0xead1, 0xcfbe, 0xead2, 0xcaee, 0xc5af, 0xb0b5, 0xead4,
+  0xead3, 0xf4df, 0xc4ba, 0xb1a9, 0xe5df, 0xead5, 0xcaef, 0xead6,
+  0xead7, 0xc6d8, 0xead8, 0xead9, 0xd4bb, 0xc7fa, 0xd2b7, 0xb8fc,
+  0xeac2, 0xb2dc, 0xc2fc, 0xd4f8, 0xcce6, 0xd7ee, 0xd4c2, 0xd3d0,
+  0xebc3, 0xc5f3, 0xb7fe, 0xebd4, 0xcbb7, 0xebde, 0xc0ca, 0xcdfb,
+  0xb3af, 0xc6da, 0xebfc, 0xc4be, 0xceb4, 0xc4a9, 0xb1be, 0xd4fd,
+  0xcaf5, 0xd6ec, 0xc6d3, 0xb6e4, 0xbbfa, 0xd0e0, 0xc9b1, 0xd4d3,
+  0xc8a8, 0xb8cb, 0xe8be, 0xc9bc, 0xe8bb, 0xc0ee, 0xd0d3, 0xb2c4,
+  0xb4e5, 0xe8bc, 0xd5c8, 0xb6c5, 0xe8bd, 0xcaf8, 0xb8dc, 0xccf5,
+  0xc0b4, 0xd1ee, 0xe8bf, 0xe8c2, 0xbabc, 0xb1ad, 0xbddc, 0xeabd,
+  0xe8c3, 0xe8c6, 0xe8cb, 0xe8cc, 0xcbc9, 0xb0e5, 0xbcab, 0xb9b9,
+  0xe8c1, 0xcdf7, 0xe8ca, 0xcef6, 0xd5ed, 0xc1d6, 0xe8c4, 0xc3b6,
+  0xb9fb, 0xd6a6, 0xe8c8, 0xcae0, 0xd4e6, 0xe8c0, 0xe8c5, 0xe8c7,
+  0xc7b9, 0xb7e3, 0xe8c9, 0xbfdd, 0xe8d2, 0xe8d7, 0xe8d5, 0xbcdc,
+  0xbccf, 0xe8db, 0xe8de, 0xe8da, 0xb1fa, 0xb0d8, 0xc4b3, 0xb8cc,
+  0xc6e2, 0xc8be, 0xc8e1, 0xe8cf, 0xe8d4, 0xe8d6, 0xb9f1, 0xe8d8,
+  0xd7f5, 0xc4fb, 0xe8dc, 0xb2e9, 0xe8d1, 0xbced, 0xbfc2, 0xe8cd,
+  0xd6f9, 0xc1f8, 0xb2f1, 0xe8df, 0xcac1, 0xe8d9, 0xd5a4, 0xb1ea,
+  0xd5bb, 0xe8ce, 0xe8d0, 0xb6b0, 0xe8d3, 0xe8dd, 0xc0b8, 0xcaf7,
+  0xcba8, 0xc6dc, 0xc0f5, 0xe8e9, 0xd0a3, 0xe8f2, 0xd6ea, 0xe8e0,
+  0xe8e1, 0xd1f9, 0xbacb, 0xb8f9, 0xb8f1, 0xd4d4, 0xe8ef, 0xe8ee,
+  0xe8ec, 0xb9f0, 0xccd2, 0xe8e6, 0xcea6, 0xbff2, 0xb0b8, 0xe8f1,
+  0xe8f0, 0xd7c0, 0xe8e4, 0xcda9, 0xc9a3, 0xbbb8, 0xbddb, 0xe8ea,
+  0xe8e2, 0xe8e3, 0xe8e5, 0xb5b5, 0xe8e7, 0xc7c5, 0xe8eb, 0xe8ed,
+  0xbdb0, 0xd7ae, 0xe8f8, 0xe8f5, 0xcdb0, 0xe8f6, 0xc1ba, 0xe8e8,
+  0xc3b7, 0xb0f0, 0xe8f4, 0xe8f7, 0xb9a3, 0xc9d2, 0xc3ce, 0xcee0,
+  0xc0e6, 0xcbf3, 0xccdd, 0xd0b5, 0xcae1, 0xe8f3, 0xbcec, 0xe8f9,
+  0xc3de, 0xc6e5, 0xb9f7, 0xb0f4, 0xd7d8, 0xbcac, 0xc5ef, 0xccc4,
+  0xe9a6, 0xc9ad, 0xe9a2, 0xc0e2, 0xbfc3, 0xe8fe, 0xb9d7, 0xe8fb,
+  0xe9a4, 0xd2ce, 0xe9a3, 0xd6b2, 0xd7b5, 0xe9a7, 0xbdb7, 0xe8fc,
+  0xe8fd, 0xe9a1, 0xcdd6, 0xd2ac, 0xe9b2, 0xe9a9, 0xb4aa, 0xb4bb,
+  0xe9ab, 0xd0a8, 0xe9a5, 0xb3fe, 0xe9ac, 0xc0e3, 0xe9aa, 0xe9b9,
+  0xe9b8, 0xe9ae, 0xe8fa, 0xe9a8, 0xbfac, 0xe9b1, 0xe9ba, 0xc2a5,
+  0xe9af, 0xb8c5, 0xe9ad, 0xd3dc, 0xe9b4, 0xe9b5, 0xe9b7, 0xe9c7,
+  0xc0c6, 0xe9c5, 0xe9b0, 0xe9bb, 0xb0f1, 0xe9bc, 0xd5a5, 0xe9be,
+  0xe9bf, 0xe9c1, 0xc1f1, 0xc8b6, 0xe9bd, 0xe9c2, 0xe9c3, 0xe9b3,
+  0xe9b6, 0xbbb1, 0xe9c0, 0xbcf7, 0xe9c4, 0xe9c6, 0xe9ca, 0xe9ce,
+  0xb2db, 0xe9c8, 0xb7ae, 0xe9cb, 0xe9cc, 0xd5c1, 0xc4a3, 0xe9d8,
+  0xbae1, 0xe9c9, 0xd3a3, 0xe9d4, 0xe9d7, 0xe9d0, 0xe9cf, 0xc7c1,
+  0xe9d2, 0xe9d9, 0xb3c8, 0xe9d3, 0xcff0, 0xe9cd, 0xb3f7, 0xe9d6,
+  0xe9da, 0xccb4, 0xcfad, 0xe9d5, 0xe9dc, 0xe9db, 0xe9de, 0xe9d1,
+  0xe9dd, 0xe9df, 0xc3ca, 0xc7b7, 0xb4ce, 0xbbb6, 0xd0c0, 0xeca3,
+  0xc5b7, 0xd3fb, 0xeca4, 0xeca5, 0xc6db, 0xbfee, 0xeca6, 0xeca7,
+  0xd0aa, 0xc7b8, 0xb8e8, 0xeca8, 0xd6b9, 0xd5fd, 0xb4cb, 0xb2bd,
+  0xcee4, 0xc6e7, 0xcde1, 0xb4f5, 0xcbc0, 0xbcdf, 0xe9e2, 0xe9e3,
+  0xd1ea, 0xe9e5, 0xb4f9, 0xe9e4, 0xd1b3, 0xcae2, 0xb2d0, 0xe9e8,
+  0xe9e6, 0xe9e7, 0xd6b3, 0xe9e9, 0xe9ea, 0xe9eb, 0xe9ec, 0xecaf,
+  0xc5b9, 0xb6ce, 0xd2f3, 0xb5ee, 0xbbd9, 0xecb1, 0xd2e3, 0xcee3,
+  0xc4b8, 0xc3bf, 0xb6be, 0xd8b9, 0xb1c8, 0xb1cf, 0xb1d1, 0xc5fe,
+  0xb1d0, 0xc3ab, 0xd5b1, 0xeba4, 0xbac1, 0xccba, 0xeba5, 0xeba7,
+  0xeba8, 0xeba6, 0xeba9, 0xebab, 0xebaa, 0xebac, 0xcacf, 0xd8b5,
+  0xc3f1, 0xc3a5, 0xc6f8, 0xebad, 0xc4ca, 0xebae, 0xebaf, 0xebb0,
+  0xb7d5, 0xb7fa, 0xebb1, 0xc7e2, 0xebb3, 0xbaa4, 0xd1f5, 0xb0b1,
+  0xebb2, 0xebb4, 0xb5aa, 0xc2c8, 0xc7e8, 0xebb5, 0xcbae, 0xe3df,
+  0xd3c0, 0xd9db, 0xcda1, 0xd6ad, 0xc7f3, 0xd9e0, 0xbbe3, 0xbaba,
+  0xe3e2, 0xcfab, 0xe3e0, 0xc9c7, 0xbab9, 0xd1b4, 0xe3e1, 0xc8ea,
+  0xb9af, 0xbdad, 0xb3d8, 0xcedb, 0xccc0, 0xe3e8, 0xe3e9, 0xcdf4,
+  0xccad, 0xbcb3, 0xe3ea, 0xe3eb, 0xd0da, 0xc6fb, 0xb7da, 0xc7df,
+  0xd2ca, 0xced6, 0xe3e4, 0xe3ec, 0xc9f2, 0xb3c1, 0xe3e7, 0xc6e3,
+  0xe3e5, 0xedb3, 0xe3e6, 0xc9b3, 0xc5e6, 0xb9b5, 0xc3bb, 0xe3e3,
+  0xc5bd, 0xc1a4, 0xc2d9, 0xb2d7, 0xe3ed, 0xbba6, 0xc4ad, 0xe3f0,
+  0xbeda, 0xe3fb, 0xe3f5, 0xbad3, 0xb7d0, 0xd3cd, 0xd6ce, 0xd5d3,
+  0xb9c1, 0xd5b4, 0xd1d8, 0xd0b9, 0xc7f6, 0xc8aa, 0xb2b4, 0xc3da,
+  0xe3ee, 0xe3fc, 0xe3ef, 0xb7a8, 0xe3f7, 0xe3f4, 0xb7ba, 0xc5a2,
+  0xe3f6, 0xc5dd, 0xb2a8, 0xc6fc, 0xc4e0, 0xd7a2, 0xc0e1, 0xe3f9,
+  0xe3fa, 0xe3fd, 0xcca9, 0xe3f3, 0xd3be, 0xb1c3, 0xedb4, 0xe3f1,
+  0xe3f2, 0xe3f8, 0xd0ba, 0xc6c3, 0xd4f3, 0xe3fe, 0xbde0, 0xe4a7,
+  0xe4a6, 0xd1f3, 0xe4a3, 0xe4a9, 0xc8f7, 0xcfb4, 0xe4a8, 0xe4ae,
+  0xc2e5, 0xb6b4, 0xbdf2, 0xe4a2, 0xbae9, 0xe4aa, 0xe4ac, 0xb6fd,
+  0xd6de, 0xe4b2, 0xe4ad, 0xe4a1, 0xbbee, 0xcddd, 0xc7a2, 0xc5c9,
+  0xc1f7, 0xe4a4, 0xc7b3, 0xbdac, 0xbdbd, 0xe4a5, 0xd7c7, 0xb2e2,
+  0xe4ab, 0xbcc3, 0xe4af, 0xbbeb, 0xe4b0, 0xc5a8, 0xe4b1, 0xd5e3,
+  0xbfa3, 0xe4ba, 0xe4b7, 0xe4bb, 0xe4bd, 0xc6d6, 0xbac6, 0xc0cb,
+  0xb8a1, 0xe4b4, 0xd4a1, 0xbaa3, 0xbdfe, 0xe4bc, 0xcdbf, 0xc4f9,
+  0xcffb, 0xc9e6, 0xd3bf, 0xcfd1, 0xe4b3, 0xe4b8, 0xe4b9, 0xcce9,
+  0xccce, 0xc0d4, 0xe4b5, 0xc1b0, 0xe4b6, 0xced0, 0xbbc1, 0xb5d3,
+  0xc8f3, 0xbda7, 0xd5c7, 0xc9ac, 0xb8a2, 0xe4ca, 0xe4cc, 0xd1c4,
+  0xd2ba, 0xbaad, 0xbad4, 0xe4c3, 0xb5ed, 0xd7cd, 0xe4c0, 0xcffd,
+  0xe4bf, 0xc1dc, 0xccca, 0xcae7, 0xc4d7, 0xccd4, 0xe4c8, 0xe4c7,
+  0xe4c1, 0xe4c4, 0xb5ad, 0xd3d9, 0xe4c6, 0xd2f9, 0xb4e3, 0xbbb4,
+  0xc9ee, 0xb4be, 0xbbec, 0xd1cd, 0xcced, 0xedb5, 0xc7e5, 0xd4a8,
+  0xe4cb, 0xd7d5, 0xe4c2, 0xbda5, 0xe4c5, 0xd3e6, 0xe4c9, 0xc9f8,
+  0xe4be, 0xd3e5, 0xc7fe, 0xb6c9, 0xd4fc, 0xb2b3, 0xe4d7, 0xcec2,
+  0xe4cd, 0xcebc, 0xb8db, 0xe4d6, 0xbfca, 0xd3ce, 0xc3ec, 0xc5c8,
+  0xe4d8, 0xcdc4, 0xe4cf, 0xe4d4, 0xe4d5, 0xbafe, 0xcfe6, 0xd5bf,
+  0xe4d2, 0xe4d0, 0xe4ce, 0xcde5, 0xcaaa, 0xc0a3, 0xbda6, 0xe4d3,
+  0xb8c8, 0xe4e7, 0xd4b4, 0xe4db, 0xc1ef, 0xe4e9, 0xd2e7, 0xe4df,
+  0xe4e0, 0xcfaa, 0xcbdd, 0xe4da, 0xe4d1, 0xe4e5, 0xc8dc, 0xe4e3,
+  0xc4e7, 0xe4e2, 0xe4e1, 0xb3fc, 0xe4e8, 0xb5e1, 0xd7cc, 0xe4e6,
+  0xbbac, 0xd7d2, 0xcccf, 0xebf8, 0xe4e4, 0xb9f6, 0xd6cd, 0xe4d9,
+  0xe4dc, 0xc2fa, 0xe4de, 0xc2cb, 0xc0c4, 0xc2d0, 0xb1f5, 0xccb2,
+  0xb5ce, 0xe4ef, 0xc6af, 0xc6e1, 0xe4f5, 0xc2a9, 0xc0ec, 0xd1dd,
+  0xe4ee, 0xc4ae, 0xe4ed, 0xe4f6, 0xe4f4, 0xc2fe, 0xe4dd, 0xe4f0,
+  0xcafe, 0xd5c4, 0xe4f1, 0xd1fa, 0xe4eb, 0xe4ec, 0xe4f2, 0xceab,
+  0xc5cb, 0xc7b1, 0xc2ba, 0xe4ea, 0xc1ca, 0xccb6, 0xb3b1, 0xe4fb,
+  0xe4f3, 0xe4fa, 0xe4fd, 0xe4fc, 0xb3ce, 0xb3ba, 0xe4f7, 0xe4f9,
+  0xe4f8, 0xc5ec, 0xc0bd, 0xd4e8, 0xe5a2, 0xb0c4, 0xe5a4, 0xe5a3,
+  0xbca4, 0xe5a5, 0xe5a1, 0xe4fe, 0xb1f4, 0xe5a8, 0xe5a9, 0xe5a6,
+  0xe5a7, 0xe5aa, 0xc6d9, 0xe5ab, 0xe5ad, 0xe5ac, 0xe5af, 0xe5ae,
+  0xb9e0, 0xe5b0, 0xe5b1, 0xbbf0, 0xece1, 0xc3f0, 0xb5c6, 0xbbd2,
+  0xc1e9, 0xd4ee, 0xbec4, 0xd7c6, 0xd4d6, 0xb2d3, 0xecbe, 0xeac1,
+  0xc2af, 0xb4b6, 0xd1d7, 0xb3b4, 0xc8b2, 0xbfbb, 0xecc0, 0xd6cb,
+  0xecbf, 0xecc1, 0xecc5, 0xbee6, 0xccbf, 0xc5da, 0xbebc, 0xecc6,
+  0xb1fe, 0xecc4, 0xd5a8, 0xb5e3, 0xecc2, 0xc1b6, 0xb3e3, 0xecc3,
+  0xcbb8, 0xc0c3, 0xccfe, 0xc1d2, 0xecc8, 0xbae6, 0xc0d3, 0xd6f2,
+  0xd1cc, 0xbfbe, 0xb7b3, 0xc9d5, 0xecc7, 0xbbe2, 0xcccc, 0xbdfd,
+  0xc8c8, 0xcfa9, 0xcde9, 0xc5eb, 0xb7e9, 0xd1c9, 0xbab8, 0xecc9,
+  0xecca, 0xbbc0, 0xeccb, 0xece2, 0xb1ba, 0xb7d9, 0xbdb9, 0xeccc,
+  0xd1e6, 0xeccd, 0xc8bb, 0xecd1, 0xecd3, 0xbbcd, 0xbce5, 0xeccf,
+  0xc9b7, 0xc3ba, 0xece3, 0xd5d5, 0xecd0, 0xd6f3, 0xecd2, 0xecce,
+  0xecd4, 0xecd5, 0xc9bf, 0xcfa8, 0xd0dc, 0xd1ac, 0xc8db, 0xecd6,
+  0xcef5, 0xcaec, 0xecda, 0xecd9, 0xb0be, 0xecd7, 0xecd8, 0xece4,
+  0xc8bc, 0xc1c7, 0xecdc, 0xd1e0, 0xecdb, 0xd4ef, 0xecdd, 0xdbc6,
+  0xecde, 0xb1ac, 0xecdf, 0xece0, 0xd7a6, 0xc5c0, 0xebbc, 0xb0ae,
+  0xbef4, 0xb8b8, 0xd2af, 0xb0d6, 0xb5f9, 0xd8b3, 0xcbac, 0xe3dd,
+  0xc6ac, 0xb0e6, 0xc5c6, 0xebb9, 0xebba, 0xebbb, 0xd1c0, 0xc5a3,
+  0xeaf2, 0xc4b2, 0xc4b5, 0xc0ce, 0xeaf3, 0xc4c1, 0xceef, 0xeaf0,
+  0xeaf4, 0xc9fc, 0xc7a3, 0xccd8, 0xcefe, 0xeaf5, 0xeaf6, 0xcfac,
+  0xc0e7, 0xeaf7, 0xb6bf, 0xeaf8, 0xeaf9, 0xeafa, 0xeafb, 0xeaf1,
+  0xc8ae, 0xe1eb, 0xb7b8, 0xe1ec, 0xe1ed, 0xd7b4, 0xe1ee, 0xe1ef,
+  0xd3cc, 0xe1f1, 0xbff1, 0xe1f0, 0xb5d2, 0xb1b7, 0xe1f3, 0xe1f2,
+  0xbafc, 0xe1f4, 0xb9b7, 0xbed1, 0xc4fc, 0xbadd, 0xbdc6, 0xe1f5,
+  0xe1f7, 0xb6c0, 0xcfc1, 0xcaa8, 0xe1f6, 0xd5f8, 0xd3fc, 0xe1f8,
+  0xe1fc, 0xe1f9, 0xe1fa, 0xc0ea, 0xe1fe, 0xe2a1, 0xc0c7, 0xe1fb,
+  0xe1fd, 0xe2a5, 0xc1d4, 0xe2a3, 0xe2a8, 0xb2fe, 0xe2a2, 0xc3cd,
+  0xb2c2, 0xe2a7, 0xe2a6, 0xe2a4, 0xe2a9, 0xe2ab, 0xd0c9, 0xd6ed,
+  0xc3a8, 0xe2ac, 0xcfd7, 0xe2ae, 0xbaef, 0xe9e0, 0xe2ad, 0xe2aa,
+  0xbbab, 0xd4b3, 0xe2b0, 0xe2af, 0xe9e1, 0xe2b1, 0xe2b2, 0xe2b3,
+  0xcca1, 0xe2b4, 0xe2b5, 0xd0fe, 0xc2ca, 0xd3f1, 0xcdf5, 0xe7e0,
+  0xe7e1, 0xbec1, 0xc2ea, 0xe7e4, 0xe7e3, 0xcde6, 0xc3b5, 0xe7e2,
+  0xbbb7, 0xcfd6, 0xc1e1, 0xe7e9, 0xe7e8, 0xe7f4, 0xb2a3, 0xe7ea,
+  0xe7e6, 0xe7ec, 0xe7eb, 0xc9ba, 0xd5e4, 0xe7e5, 0xb7a9, 0xe7e7,
+  0xe7ee, 0xe7f3, 0xd6e9, 0xe7ed, 0xe7f2, 0xe7f1, 0xb0e0, 0xe7f5,
+  0xc7f2, 0xc0c5, 0xc0ed, 0xc1f0, 0xe7f0, 0xe7f6, 0xcbf6, 0xe8a2,
+  0xe8a1, 0xd7c1, 0xe7fa, 0xe7f9, 0xe7fb, 0xe7f7, 0xe7fe, 0xe7fd,
+  0xe7fc, 0xc1d5, 0xc7d9, 0xc5fd, 0xc5c3, 0xc7ed, 0xe8a3, 0xe8a6,
+  0xe8a5, 0xe8a7, 0xbaf7, 0xe7f8, 0xe8a4, 0xc8f0, 0xc9aa, 0xe8a9,
+  0xb9e5, 0xd1fe, 0xe8a8, 0xe8aa, 0xe8ad, 0xe8ae, 0xc1a7, 0xe8af,
+  0xe8b0, 0xe8ac, 0xe8b4, 0xe8ab, 0xe8b1, 0xe8b5, 0xe8b2, 0xe8b3,
+  0xe8b7, 0xe8b6, 0xb9cf, 0xf0ac, 0xf0ad, 0xc6b0, 0xb0ea, 0xc8bf,
+  0xcddf, 0xcecd, 0xeab1, 0xeab2, 0xc6bf, 0xb4c9, 0xeab3, 0xd5e7,
+  0xddf9, 0xeab4, 0xeab5, 0xeab6, 0xb8ca, 0xdfb0, 0xc9f5, 0xccf0,
+  0xc9fa, 0xc9fb, 0xd3c3, 0xcba6, 0xb8a6, 0xf0ae, 0xb1c2, 0xe5b8,
+  0xccef, 0xd3c9, 0xbcd7, 0xc9ea, 0xb5e7, 0xc4d0, 0xb5e9, 0xeeae,
+  0xbbad, 0xe7de, 0xeeaf, 0xb3a9, 0xeeb2, 0xeeb1, 0xbde7, 0xeeb0,
+  0xceb7, 0xc5cf, 0xc1f4, 0xdbce, 0xeeb3, 0xd0f3, 0xc2d4, 0xc6e8,
+  0xb7ac, 0xeeb4, 0xb3eb, 0xbbfb, 0xeeb5, 0xe7dc, 0xeeb6, 0xbdae,
+  0xf1e2, 0xcae8, 0xd2c9, 0xf0da, 0xf0db, 0xf0dc, 0xc1c6, 0xb8ed,
+  0xbece, 0xf0de, 0xc5b1, 0xf0dd, 0xd1f1, 0xf0e0, 0xb0cc, 0xbdea,
+  0xd2df, 0xf0df, 0xb4af, 0xb7e8, 0xf0e6, 0xf0e5, 0xc6a3, 0xf0e1,
+  0xf0e2, 0xb4c3, 0xf0e3, 0xd5ee, 0xccdb, 0xbed2, 0xbcb2, 0xf0e8,
+  0xf0e7, 0xf0e4, 0xb2a1, 0xd6a2, 0xd3b8, 0xbeb7, 0xc8ac, 0xf0ea,
+  0xd1f7, 0xd6cc, 0xbadb, 0xf0e9, 0xb6bb, 0xcdb4, 0xc6a6, 0xc1a1,
+  0xf0eb, 0xf0ee, 0xf0ed, 0xf0f0, 0xf0ec, 0xbbbe, 0xf0ef, 0xccb5,
+  0xf0f2, 0xb3d5, 0xb1d4, 0xf0f3, 0xf0f4, 0xf0f6, 0xb4e1, 0xf0f1,
+  0xf0f7, 0xf0fa, 0xf0f8, 0xf0f5, 0xf0fd, 0xf0f9, 0xf0fc, 0xf0fe,
+  0xf1a1, 0xcec1, 0xf1a4, 0xf1a3, 0xc1f6, 0xf0fb, 0xcadd, 0xb4f1,
+  0xb1f1, 0xccb1, 0xf1a6, 0xf1a7, 0xf1ac, 0xd5ce, 0xf1a9, 0xc8b3,
+  0xf1a2, 0xf1ab, 0xf1a8, 0xf1a5, 0xf1aa, 0xb0a9, 0xf1ad, 0xf1af,
+  0xf1b1, 0xf1b0, 0xf1ae, 0xd1a2, 0xf1b2, 0xf1b3, 0xb9ef, 0xb5c7,
+  0xb0d7, 0xb0d9, 0xd4ed, 0xb5c4, 0xbdd4, 0xbbca, 0xf0a7, 0xb8de,
+  0xf0a8, 0xb0a8, 0xf0a9, 0xcdee, 0xf0aa, 0xf0ab, 0xc6a4, 0xd6e5,
+  0xf1e4, 0xf1e5, 0xc3f3, 0xd3db, 0xd6d1, 0xc5e8, 0xd3af, 0xd2e6,
+  0xeec1, 0xb0bb, 0xd5b5, 0xd1ce, 0xbce0, 0xbad0, 0xbff8, 0xb8c7,
+  0xb5c1, 0xc5cc, 0xcaa2, 0xc3cb, 0xeec2, 0xc4bf, 0xb6a2, 0xedec,
+  0xc3a4, 0xd6b1, 0xcfe0, 0xedef, 0xc5ce, 0xb6dc, 0xcaa1, 0xeded,
+  0xedf0, 0xedf1, 0xc3bc, 0xbfb4, 0xedee, 0xedf4, 0xedf2, 0xd5e6,
+  0xc3df, 0xedf3, 0xedf6, 0xd5a3, 0xd1a3, 0xedf5, 0xc3d0, 0xedf7,
+  0xbff4, 0xbeec, 0xedf8, 0xccf7, 0xd1db, 0xd7c5, 0xd5f6, 0xedfc,
+  0xedfb, 0xedf9, 0xedfa, 0xedfd, 0xbea6, 0xcbaf, 0xeea1, 0xb6bd,
+  0xeea2, 0xc4c0, 0xedfe, 0xbdde, 0xb2c7, 0xb6c3, 0xeea5, 0xd8ba,
+  0xeea3, 0xeea6, 0xc3e9, 0xb3f2, 0xeea7, 0xeea4, 0xcfb9, 0xeea8,
+  0xc2f7, 0xeea9, 0xeeaa, 0xdeab, 0xc6b3, 0xc7c6, 0xd6f5, 0xb5c9,
+  0xcbb2, 0xeeab, 0xcdab, 0xeeac, 0xd5b0, 0xeead, 0xf6c4, 0xdbc7,
+  0xb4a3, 0xc3ac, 0xf1e6, 0xcab8, 0xd2d3, 0xd6aa, 0xeff2, 0xbed8,
+  0xbdc3, 0xeff3, 0xb6cc, 0xb0ab, 0xcaaf, 0xedb6, 0xedb7, 0xcef9,
+  0xb7af, 0xbff3, 0xedb8, 0xc2eb, 0xc9b0, 0xedb9, 0xc6f6, 0xbfb3,
+  0xedbc, 0xc5f8, 0xd1d0, 0xd7a9, 0xedba, 0xedbb, 0xd1e2, 0xedbf,
+  0xedc0, 0xedc4, 0xedc8, 0xedc6, 0xedce, 0xd5e8, 0xedc9, 0xedc7,
+  0xedbe, 0xc5e9, 0xc6c6, 0xc9e9, 0xd4d2, 0xedc1, 0xedc2, 0xedc3,
+  0xedc5, 0xc0f9, 0xb4a1, 0xb9e8, 0xedd0, 0xedd1, 0xedca, 0xedcf,
+  0xcef8, 0xcbb6, 0xedcc, 0xedcd, 0xcff5, 0xedd2, 0xc1f2, 0xd3b2,
+  0xedcb, 0xc8b7, 0xbcef, 0xc5f0, 0xedd6, 0xb5ef, 0xc2b5, 0xb0ad,
+  0xcbe9, 0xb1ae, 0xedd4, 0xcdeb, 0xb5e2, 0xedd5, 0xedd3, 0xedd7,
+  0xb5fa, 0xedd8, 0xedd9, 0xeddc, 0xb1cc, 0xc5f6, 0xbcee, 0xedda,
+  0xccbc, 0xb2ea, 0xeddb, 0xc4eb, 0xb4c5, 0xb0f5, 0xeddf, 0xc0da,
+  0xb4e8, 0xc5cd, 0xeddd, 0xbfc4, 0xedde, 0xc4a5, 0xede0, 0xede1,
+  0xede3, 0xc1d7, 0xbbc7, 0xbdb8, 0xede2, 0xede4, 0xede6, 0xede5,
+  0xede7, 0xcabe, 0xecea, 0xc0f1, 0xc9e7, 0xeceb, 0xc6ee, 0xecec,
+  0xc6ed, 0xeced, 0xecf0, 0xd7e6, 0xecf3, 0xecf1, 0xecee, 0xecef,
+  0xd7a3, 0xc9f1, 0xcbee, 0xecf4, 0xecf2, 0xcfe9, 0xecf6, 0xc6b1,
+  0xbcc0, 0xecf5, 0xb5bb, 0xbbf6, 0xecf7, 0xd9f7, 0xbdfb, 0xc2bb,
+  0xecf8, 0xecf9, 0xb8a3, 0xecfa, 0xecfb, 0xecfc, 0xd3ed, 0xd8ae,
+  0xc0eb, 0xc7dd, 0xbacc, 0xd0e3, 0xcbbd, 0xcdba, 0xb8d1, 0xb1fc,
+  0xc7ef, 0xd6d6, 0xbfc6, 0xc3eb, 0xeff5, 0xc3d8, 0xd7e2, 0xeff7,
+  0xb3d3, 0xc7d8, 0xd1ed, 0xd6c8, 0xeff8, 0xeff6, 0xbbfd, 0xb3c6,
+  0xbdd5, 0xd2c6, 0xbbe0, 0xcfa1, 0xeffc, 0xeffb, 0xeff9, 0xb3cc,
+  0xc9d4, 0xcbb0, 0xeffe, 0xb0de, 0xd6c9, 0xeffd, 0xb3ed, 0xf6d5,
+  0xcec8, 0xf0a2, 0xf0a1, 0xb5be, 0xbcda, 0xbbfc, 0xb8e5, 0xc4c2,
+  0xf0a3, 0xcbeb, 0xf0a6, 0xd1a8, 0xbebf, 0xc7ee, 0xf1b6, 0xf1b7,
+  0xbfd5, 0xb4a9, 0xf1b8, 0xcdbb, 0xc7d4, 0xd5ad, 0xf1b9, 0xf1ba,
+  0xc7cf, 0xd2a4, 0xd6cf, 0xf1bb, 0xbdd1, 0xb4b0, 0xbebd, 0xb4dc,
+  0xced1, 0xbfdf, 0xf1bd, 0xbffa, 0xf1bc, 0xf1bf, 0xf1be, 0xf1c0,
+  0xf1c1, 0xc1fe, 0xc1a2, 0xcafa, 0xd5be, 0xbeba, 0xbeb9, 0xd5c2,
+  0xbfa2, 0xcdaf, 0xf1b5, 0xbddf, 0xb6cb, 0xd6f1, 0xf3c3, 0xf3c4,
+  0xb8cd, 0xf3c6, 0xf3c7, 0xb0ca, 0xf3c5, 0xf3c9, 0xcbf1, 0xf3cb,
+  0xd0a6, 0xb1ca, 0xf3c8, 0xf3cf, 0xb5d1, 0xf3d7, 0xf3d2, 0xf3d4,
+  0xf3d3, 0xb7fb, 0xb1bf, 0xf3ce, 0xf3ca, 0xb5da, 0xf3d0, 0xf3d1,
+  0xf3d5, 0xf3cd, 0xbce3, 0xc1fd, 0xf3d6, 0xf3da, 0xf3cc, 0xb5c8,
+  0xbdee, 0xf3dc, 0xb7a4, 0xbff0, 0xd6fe, 0xcdb2, 0xb4f0, 0xb2df,
+  0xf3d8, 0xf3d9, 0xc9b8, 0xf3dd, 0xf3de, 0xf3e1, 0xf3df, 0xf3e3,
+  0xf3e2, 0xf3db, 0xbfea, 0xb3ef, 0xf3e0, 0xc7a9, 0xbcf2, 0xf3eb,
+  0xb9bf, 0xf3e4, 0xb2ad, 0xbbfe, 0xcbe3, 0xf3ed, 0xf3e9, 0xb9dc,
+  0xf3ee, 0xf3e5, 0xf3e6, 0xf3ea, 0xc2e1, 0xf3ec, 0xf3ef, 0xf3e8,
+  0xbcfd, 0xcfe4, 0xf3f0, 0xf3e7, 0xf3f2, 0xd7ad, 0xc6aa, 0xf3f3,
+  0xf3f1, 0xc2a8, 0xb8dd, 0xf3f5, 0xf3f4, 0xb4db, 0xf3f6, 0xf3f7,
+  0xf3f8, 0xc0ba, 0xc0e9, 0xc5f1, 0xf3fb, 0xf3fa, 0xb4d8, 0xf3fe,
+  0xf3f9, 0xf3fc, 0xf3fd, 0xf4a1, 0xf4a3, 0xbbc9, 0xf4a2, 0xf4a4,
+  0xb2be, 0xf4a6, 0xf4a5, 0xbcae, 0xc3d7, 0xd9e1, 0xc0e0, 0xf4cc,
+  0xd7d1, 0xb7db, 0xf4ce, 0xc1a3, 0xc6c9, 0xb4d6, 0xd5b3, 0xf4d0,
+  0xf4cf, 0xf4d1, 0xcbda, 0xf4d2, 0xd4c1, 0xd6e0, 0xb7e0, 0xc1b8,
+  0xc1bb, 0xf4d3, 0xbeac, 0xb4e2, 0xf4d4, 0xf4d5, 0xbeab, 0xf4d6,
+  0xf4db, 0xf4d7, 0xf4da, 0xbafd, 0xf4d8, 0xf4d9, 0xb8e2, 0xccc7,
+  0xf4dc, 0xb2da, 0xc3d3, 0xd4e3, 0xbfb7, 0xf4dd, 0xc5b4, 0xf4e9,
+  0xcfb5, 0xcec9, 0xcbd8, 0xcbf7, 0xbdf4, 0xd7cf, 0xc0db, 0xd0f5,
+  0xf4ea, 0xf4eb, 0xf4ec, 0xf7e3, 0xb7b1, 0xf4ed, 0xd7eb, 0xf4ee,
+  0xe6f9, 0xbec0, 0xe6fa, 0xbaec, 0xe6fb, 0xcfcb, 0xe6fc, 0xd4bc,
+  0xbcb6, 0xe6fd, 0xe6fe, 0xbccd, 0xc8d2, 0xceb3, 0xe7a1, 0xb4bf,
+  0xe7a2, 0xc9b4, 0xb8d9, 0xc4c9, 0xd7dd, 0xc2da, 0xb7d7, 0xd6bd,
+  0xcec6, 0xb7c4, 0xc5a6, 0xe7a3, 0xcfdf, 0xe7a4, 0xe7a5, 0xe7a6,
+  0xc1b7, 0xd7e9, 0xc9f0, 0xcfb8, 0xd6af, 0xd6d5, 0xe7a7, 0xb0ed,
+  0xe7a8, 0xe7a9, 0xc9dc, 0xd2ef, 0xbead, 0xe7aa, 0xb0f3, 0xc8de,
+  0xbde1, 0xe7ab, 0xc8c6, 0xe7ac, 0xbbe6, 0xb8f8, 0xd1a4, 0xe7ad,
+  0xc2e7, 0xbef8, 0xbdca, 0xcdb3, 0xe7ae, 0xe7af, 0xbeee, 0xd0e5,
+  0xcbe7, 0xccd0, 0xbccc, 0xe7b0, 0xbca8, 0xd0f7, 0xe7b1, 0xd0f8,
+  0xe7b2, 0xe7b3, 0xb4c2, 0xe7b4, 0xe7b5, 0xc9fe, 0xceac, 0xc3e0,
+  0xe7b7, 0xb1c1, 0xb3f1, 0xe7b8, 0xe7b9, 0xd7db, 0xd5c0, 0xe7ba,
+  0xc2cc, 0xd7ba, 0xe7bb, 0xe7bc, 0xe7bd, 0xbcea, 0xc3e5, 0xc0c2,
+  0xe7be, 0xe7bf, 0xbca9, 0xe7c0, 0xe7c1, 0xe7b6, 0xb6d0, 0xe7c2,
+  0xe7c3, 0xe7c4, 0xbbba, 0xb5de, 0xc2c6, 0xb1e0, 0xe7c5, 0xd4b5,
+  0xe7c6, 0xb8bf, 0xe7c8, 0xe7c7, 0xb7ec, 0xe7c9, 0xb2f8, 0xe7ca,
+  0xe7cb, 0xe7cc, 0xe7cd, 0xe7ce, 0xe7cf, 0xe7d0, 0xd3a7, 0xcbf5,
+  0xe7d1, 0xe7d2, 0xe7d3, 0xe7d4, 0xc9c9, 0xe7d5, 0xe7d6, 0xe7d7,
+  0xe7d8, 0xe7d9, 0xbdc9, 0xe7da, 0xf3be, 0xb8d7, 0xc8b1, 0xf3bf,
+  0xf3c0, 0xf3c1, 0xb9de, 0xcdf8, 0xd8e8, 0xbab1, 0xc2de, 0xeeb7,
+  0xb7a3, 0xeeb9, 0xeeb8, 0xb0d5, 0xeebb, 0xd5d6, 0xd7ef, 0xd6c3,
+  0xeebd, 0xcaf0, 0xeebc, 0xeebe, 0xeec0, 0xeebf, 0xd1f2, 0xc7bc,
+  0xc3c0, 0xb8e1, 0xc1e7, 0xf4c6, 0xd0df, 0xf4c7, 0xcfdb, 0xc8ba,
+  0xf4c8, 0xf4c9, 0xf4ca, 0xf4cb, 0xd9fa, 0xb8fe, 0xe5f1, 0xd3f0,
+  0xf4e0, 0xcecc, 0xb3e1, 0xf1b4, 0xd2ee, 0xf4e1, 0xcfe8, 0xf4e2,
+  0xc7cc, 0xb5d4, 0xb4e4, 0xf4e4, 0xf4e3, 0xf4e5, 0xf4e6, 0xf4e7,
+  0xbab2, 0xb0bf, 0xf4e8, 0xb7ad, 0xd2ed, 0xd2ab, 0xc0cf, 0xbfbc,
+  0xeba3, 0xd5df, 0xeac8, 0xf1f3, 0xb6f8, 0xcba3, 0xc4cd, 0xf1e7,
+  0xf1e8, 0xb8fb, 0xf1e9, 0xbac4, 0xd4c5, 0xb0d2, 0xf1ea, 0xf1eb,
+  0xf1ec, 0xf1ed, 0xf1ee, 0xf1ef, 0xf1f1, 0xf1f0, 0xc5d5, 0xf1f2,
+  0xb6fa, 0xf1f4, 0xd2ae, 0xdec7, 0xcbca, 0xb3dc, 0xb5a2, 0xb9a2,
+  0xc4f4, 0xf1f5, 0xf1f6, 0xc1c4, 0xc1fb, 0xd6b0, 0xf1f7, 0xf1f8,
+  0xc1aa, 0xc6b8, 0xbedb, 0xf1f9, 0xb4cf, 0xf1fa, 0xedb2, 0xedb1,
+  0xcbe0, 0xd2de, 0xcbc1, 0xd5d8, 0xc8e2, 0xc0df, 0xbca1, 0xebc1,
+  0xd0a4, 0xd6e2, 0xb6c7, 0xb8d8, 0xebc0, 0xb8ce, 0xebbf, 0xb3a6,
+  0xb9c9, 0xd6ab, 0xb7f4, 0xb7ca, 0xbce7, 0xb7be, 0xebc6, 0xebc7,
+  0xb0b9, 0xbfcf, 0xebc5, 0xd3fd, 0xebc8, 0xebc9, 0xb7ce, 0xebc2,
+  0xebc4, 0xc9f6, 0xd6d7, 0xd5cd, 0xd0b2, 0xebcf, 0xceb8, 0xebd0,
+  0xb5a8, 0xb1b3, 0xebd2, 0xcca5, 0xc5d6, 0xebd3, 0xebd1, 0xc5df,
+  0xebce, 0xcaa4, 0xebd5, 0xb0fb, 0xbafa, 0xd8b7, 0xf1e3, 0xebca,
+  0xebcb, 0xebcc, 0xebcd, 0xebd6, 0xe6c0, 0xebd9, 0xbfe8, 0xd2c8,
+  0xebd7, 0xebdc, 0xb8ec, 0xebd8, 0xbdba, 0xd0d8, 0xb0b7, 0xebdd,
+  0xc4dc, 0xd6ac, 0xb4e0, 0xc2f6, 0xbcb9, 0xebda, 0xebdb, 0xd4e0,
+  0xc6ea, 0xc4d4, 0xebdf, 0xc5a7, 0xd9f5, 0xb2b1, 0xebe4, 0xbdc5,
+  0xebe2, 0xebe3, 0xb8ac, 0xcdd1, 0xebe5, 0xebe1, 0xc1b3, 0xc6a2,
+  0xccf3, 0xebe6, 0xc0b0, 0xd2b8, 0xebe7, 0xb8af, 0xb8ad, 0xebe8,
+  0xc7bb, 0xcdf3, 0xebea, 0xebeb, 0xebed, 0xd0c8, 0xebf2, 0xebee,
+  0xebf1, 0xc8f9, 0xd1fc, 0xebec, 0xebe9, 0xb8b9, 0xcfd9, 0xc4e5,
+  0xebef, 0xebf0, 0xccda, 0xcdc8, 0xb0f2, 0xebf6, 0xebf5, 0xb2b2,
+  0xb8e0, 0xebf7, 0xb1ec, 0xccc5, 0xc4a4, 0xcfa5, 0xebf9, 0xeca2,
+  0xc5f2, 0xebfa, 0xc9c5, 0xe2df, 0xebfe, 0xcdce, 0xeca1, 0xb1db,
+  0xd3b7, 0xd2dc, 0xebfd, 0xebfb, 0xb3bc, 0xeab0, 0xd7d4, 0xf4ab,
+  0xb3f4, 0xd6c1, 0xd6c2, 0xd5e9, 0xbeca, 0xf4a7, 0xd2a8, 0xf4a8,
+  0xf4a9, 0xf4aa, 0xbecb, 0xd3df, 0xc9e0, 0xc9e1, 0xf3c2, 0xcae6,
+  0xccf2, 0xe2b6, 0xcbb4, 0xcee8, 0xd6db, 0xf4ad, 0xf4ae, 0xf4af,
+  0xf4b2, 0xbabd, 0xf4b3, 0xb0e3, 0xf4b0, 0xf4b1, 0xbda2, 0xb2d5,
+  0xf4b6, 0xf4b7, 0xb6e6, 0xb2b0, 0xcfcf, 0xf4b4, 0xb4ac, 0xf4b5,
+  0xf4b8, 0xf4b9, 0xcda7, 0xf4ba, 0xf4bb, 0xf4bc, 0xcbd2, 0xf4bd,
+  0xf4be, 0xf4bf, 0xf4de, 0xc1bc, 0xbce8, 0xc9ab, 0xd1de, 0xe5f5,
+  0xdcb3, 0xd2d5, 0xdcb4, 0xb0ac, 0xdcb5, 0xbdda, 0xdcb9, 0xd8c2,
+  0xdcb7, 0xd3f3, 0xc9d6, 0xdcba, 0xdcb6, 0xdcbb, 0xc3a2, 0xdcbc,
+  0xdcc5, 0xdcbd, 0xcedf, 0xd6a5, 0xdccf, 0xdccd, 0xdcd2, 0xbde6,
+  0xc2ab, 0xdcb8, 0xdccb, 0xdcce, 0xdcbe, 0xb7d2, 0xb0c5, 0xdcc7,
+  0xd0be, 0xdcc1, 0xbba8, 0xb7bc, 0xdccc, 0xdcc6, 0xdcbf, 0xc7db,
+  0xd1bf, 0xdcc0, 0xdcca, 0xdcd0, 0xcead, 0xdcc2, 0xdcc3, 0xdcc8,
+  0xdcc9, 0xb2d4, 0xdcd1, 0xcbd5, 0xd4b7, 0xdcdb, 0xdcdf, 0xcca6,
+  0xdce6, 0xc3e7, 0xdcdc, 0xbfc1, 0xdcd9, 0xb0fa, 0xb9b6, 0xdce5,
+  0xdcd3, 0xdcc4, 0xdcd6, 0xc8f4, 0xbfe0, 0xc9bb, 0xb1bd, 0xd3a2,
+  0xdcda, 0xdcd5, 0xc6bb, 0xdcde, 0xd7c2, 0xc3af, 0xb7b6, 0xc7d1,
+  0xc3a9, 0xdce2, 0xdcd8, 0xdceb, 0xdcd4, 0xdcdd, 0xbea5, 0xdcd7,
+  0xdce0, 0xdce3, 0xdce4, 0xdcf8, 0xdce1, 0xdda2, 0xdce7, 0xbceb,
+  0xb4c4, 0xc3a3, 0xb2e7, 0xdcfa, 0xdcf2, 0xdcef, 0xdcfc, 0xdcee,
+  0xd2f0, 0xb2e8, 0xc8d7, 0xc8e3, 0xdcfb, 0xdced, 0xdcf7, 0xdcf5,
+  0xbea3, 0xdcf4, 0xb2dd, 0xdcf3, 0xbcf6, 0xdce8, 0xbbc4, 0xc0f3,
+  0xbcd4, 0xdce9, 0xdcea, 0xdcf1, 0xdcf6, 0xdcf9, 0xb5b4, 0xc8d9,
+  0xbbe7, 0xdcfe, 0xdcfd, 0xd3ab, 0xdda1, 0xdda3, 0xdda5, 0xd2f1,
+  0xdda4, 0xdda6, 0xdda7, 0xd2a9, 0xbac9, 0xdda9, 0xddb6, 0xddb1,
+  0xddb4, 0xddb0, 0xc6ce, 0xc0f2, 0xc9af, 0xdcec, 0xddae, 0xddb7,
+  0xdcf0, 0xddaf, 0xddb8, 0xddac, 0xddb9, 0xddb3, 0xddad, 0xc4aa,
+  0xdda8, 0xc0b3, 0xc1ab, 0xddaa, 0xddab, 0xddb2, 0xbbf1, 0xddb5,
+  0xd3a8, 0xddba, 0xddbb, 0xc3a7, 0xddd2, 0xddbc, 0xddd1, 0xb9bd,
+  0xbed5, 0xbefa, 0xbaca, 0xddca, 0xddc5, 0xddbf, 0xb2cb, 0xddc3,
+  0xddcb, 0xb2a4, 0xddd5, 0xddbe, 0xc6d0, 0xddd0, 0xddd4, 0xc1e2,
+  0xb7c6, 0xddce, 0xddcf, 0xddc4, 0xddbd, 0xddcd, 0xccd1, 0xddc9,
+  0xddc2, 0xc3c8, 0xc6bc, 0xceae, 0xddcc, 0xddc8, 0xddc1, 0xddc6,
+  0xc2dc, 0xd3a9, 0xd3aa, 0xddd3, 0xcff4, 0xc8f8, 0xdde6, 0xddc7,
+  0xdde0, 0xc2e4, 0xdde1, 0xddd7, 0xd6f8, 0xddd9, 0xddd8, 0xb8f0,
+  0xddd6, 0xc6cf, 0xb6ad, 0xdde2, 0xbaf9, 0xd4e1, 0xdde7, 0xb4d0,
+  0xddda, 0xbffb, 0xdde3, 0xdddf, 0xdddd, 0xb5d9, 0xdddb, 0xdddc,
+  0xddde, 0xbdaf, 0xdde4, 0xdde5, 0xddf5, 0xc3c9, 0xcbe2, 0xddf2,
+  0xd8e1, 0xc6d1, 0xddf4, 0xd5f4, 0xddf3, 0xddf0, 0xddec, 0xddef,
+  0xdde8, 0xd0ee, 0xc8d8, 0xddee, 0xdde9, 0xddea, 0xcbf2, 0xdded,
+  0xb1cd, 0xc0b6, 0xbcbb, 0xddf1, 0xddf7, 0xddf6, 0xddeb, 0xc5ee,
+  0xddfb, 0xdea4, 0xdea3, 0xddf8, 0xc3ef, 0xc2fb, 0xd5e1, 0xceb5,
+  0xddfd, 0xb2cc, 0xc4e8, 0xcadf, 0xc7be, 0xddfa, 0xddfc, 0xddfe,
+  0xdea2, 0xb0aa, 0xb1ce, 0xdeac, 0xdea6, 0xbdb6, 0xc8ef, 0xdea1,
+  0xdea5, 0xdea9, 0xdea8, 0xdea7, 0xdead, 0xd4cc, 0xdeb3, 0xdeaa,
+  0xdeae, 0xc0d9, 0xb1a1, 0xdeb6, 0xdeb1, 0xdeb2, 0xd1a6, 0xdeb5,
+  0xdeaf, 0xdeb0, 0xd0bd, 0xdeb4, 0xcaed, 0xdeb9, 0xdeb8, 0xdeb7,
+  0xdebb, 0xbde5, 0xb2d8, 0xc3ea, 0xdeba, 0xc5ba, 0xdebc, 0xccd9,
+  0xb7aa, 0xd4e5, 0xdebd, 0xdebf, 0xc4a2, 0xdec1, 0xdebe, 0xdec0,
+  0xd5ba, 0xdec2, 0xf2ae, 0xbba2, 0xc2b2, 0xc5b0, 0xc2c7, 0xf2af,
+  0xd0e9, 0xd3dd, 0xebbd, 0xb3e6, 0xf2b0, 0xf2b1, 0xcaad, 0xbae7,
+  0xf2b3, 0xf2b5, 0xf2b4, 0xcbe4, 0xcfba, 0xf2b2, 0xcab4, 0xd2cf,
+  0xc2ec, 0xcec3, 0xf2b8, 0xb0f6, 0xf2b7, 0xf2be, 0xb2cf, 0xd1c1,
+  0xf2ba, 0xf2bc, 0xd4e9, 0xf2bb, 0xf2b6, 0xf2bf, 0xf2bd, 0xf2b9,
+  0xf2c7, 0xf2c4, 0xf2c6, 0xf2ca, 0xf2c2, 0xf2c0, 0xf2c5, 0xd6fb,
+  0xf2c1, 0xc7f9, 0xc9df, 0xf2c8, 0xb9c6, 0xb5b0, 0xf2c3, 0xf2c9,
+  0xf2d0, 0xf2d6, 0xbbd7, 0xf2d5, 0xcddc, 0xd6eb, 0xf2d2, 0xf2d4,
+  0xb8f2, 0xf2cb, 0xf2ce, 0xc2f9, 0xd5dd, 0xf2cc, 0xf2cd, 0xf2cf,
+  0xf2d3, 0xf2d9, 0xd3bc, 0xb6ea, 0xcaf1, 0xb7e4, 0xf2d7, 0xf2d8,
+  0xf2da, 0xf2dd, 0xf2db, 0xf2dc, 0xd1d1, 0xf2d1, 0xcdc9, 0xcecf,
+  0xd6a9, 0xf2e3, 0xc3db, 0xf2e0, 0xc0af, 0xf2ec, 0xf2de, 0xf2e1,
+  0xf2e8, 0xf2e2, 0xf2e7, 0xf2e6, 0xf2e9, 0xf2df, 0xf2e4, 0xf2ea,
+  0xd3ac, 0xf2e5, 0xb2f5, 0xf2f2, 0xd0ab, 0xf2f5, 0xbbc8, 0xf2f9,
+  0xf2f0, 0xf2f6, 0xf2f8, 0xf2fa, 0xf2f3, 0xf2f1, 0xbafb, 0xb5fb,
+  0xf2ef, 0xf2f7, 0xf2ed, 0xf2ee, 0xf2eb, 0xf3a6, 0xf3a3, 0xf3a2,
+  0xf2f4, 0xc8da, 0xf2fb, 0xf3a5, 0xc3f8, 0xf2fd, 0xf3a7, 0xf3a9,
+  0xf3a4, 0xf2fc, 0xf3ab, 0xf3aa, 0xc2dd, 0xf3ae, 0xf3b0, 0xf3a1,
+  0xf3b1, 0xf3ac, 0xf3af, 0xf2fe, 0xf3ad, 0xf3b2, 0xf3b4, 0xf3a8,
+  0xf3b3, 0xf3b5, 0xd0b7, 0xf3b8, 0xd9f9, 0xf3b9, 0xf3b7, 0xc8e4,
+  0xf3b6, 0xf3ba, 0xf3bb, 0xb4c0, 0xeec3, 0xf3bc, 0xf3bd, 0xd1aa,
+  0xf4ac, 0xd0c6, 0xd0d0, 0xd1dc, 0xcfce, 0xbdd6, 0xd1c3, 0xbae2,
+  0xe1e9, 0xd2c2, 0xf1c2, 0xb2b9, 0xb1ed, 0xf1c3, 0xc9c0, 0xb3c4,
+  0xd9f2, 0xcba5, 0xf1c4, 0xd6d4, 0xf1c5, 0xf4c0, 0xf1c6, 0xd4ac,
+  0xf1c7, 0xb0c0, 0xf4c1, 0xf4c2, 0xb4fc, 0xc5db, 0xccbb, 0xd0e4,
+  0xcde0, 0xf1c8, 0xd9f3, 0xb1bb, 0xcfae, 0xb8a4, 0xf1ca, 0xf1cb,
+  0xb2c3, 0xc1d1, 0xd7b0, 0xf1c9, 0xf1cc, 0xf1ce, 0xd9f6, 0xd2e1,
+  0xd4a3, 0xf4c3, 0xc8b9, 0xf4c4, 0xf1cd, 0xf1cf, 0xbfe3, 0xf1d0,
+  0xf1d4, 0xf1d6, 0xf1d1, 0xc9d1, 0xc5e1, 0xc2e3, 0xb9fc, 0xf1d3,
+  0xf1d5, 0xb9d3, 0xf1db, 0xbad6, 0xb0fd, 0xf1d9, 0xf1d8, 0xf1d2,
+  0xf1da, 0xf1d7, 0xc8ec, 0xcdca, 0xf1dd, 0xe5bd, 0xf1dc, 0xf1de,
+  0xf1df, 0xcfe5, 0xf4c5, 0xbdf3, 0xf1e0, 0xf1e1, 0xcef7, 0xd2aa,
+  0xf1fb, 0xb8b2, 0xbcfb, 0xb9db, 0xb9e6, 0xc3d9, 0xcad3, 0xeae8,
+  0xc0c0, 0xbef5, 0xeae9, 0xeaea, 0xeaeb, 0xeaec, 0xeaed, 0xeaee,
+  0xeaef, 0xbdc7, 0xf5fb, 0xf5fd, 0xf5fe, 0xf5fc, 0xbde2, 0xf6a1,
+  0xb4a5, 0xf6a2, 0xf6a3, 0xecb2, 0xd1d4, 0xd9ea, 0xf6a4, 0xeeba,
+  0xd5b2, 0xd3fe, 0xccdc, 0xcac4, 0xe5c0, 0xf6a5, 0xbeaf, 0xc6a9,
+  0xdaa5, 0xbcc6, 0xb6a9, 0xb8bc, 0xc8cf, 0xbca5, 0xdaa6, 0xdaa7,
+  0xccd6, 0xc8c3, 0xdaa8, 0xc6fd, 0xd1b5, 0xd2e9, 0xd1b6, 0xbcc7,
+  0xbdb2, 0xbbe4, 0xdaa9, 0xdaaa, 0xd1c8, 0xdaab, 0xd0ed, 0xb6ef,
+  0xc2db, 0xcbcf, 0xb7ed, 0xc9e8, 0xb7c3, 0xbef7, 0xd6a4, 0xdaac,
+  0xdaad, 0xc6c0, 0xd7e7, 0xcab6, 0xd5a9, 0xcbdf, 0xd5ef, 0xdaae,
+  0xd6df, 0xb4ca, 0xdab0, 0xdaaf, 0xd2eb, 0xdab1, 0xdab2, 0xdab3,
+  0xcad4, 0xdab4, 0xcaab, 0xdab5, 0xdab6, 0xb3cf, 0xd6ef, 0xdab7,
+  0xbbb0, 0xb5ae, 0xdab8, 0xdab9, 0xb9ee, 0xd1af, 0xd2e8, 0xdaba,
+  0xb8c3, 0xcfea, 0xb2ef, 0xdabb, 0xdabc, 0xbdeb, 0xcedc, 0xd3ef,
+  0xdabd, 0xcef3, 0xdabe, 0xd3d5, 0xbbe5, 0xdabf, 0xcbb5, 0xcbd0,
+  0xdac0, 0xc7eb, 0xd6ee, 0xdac1, 0xc5b5, 0xb6c1, 0xdac2, 0xb7cc,
+  0xbfce, 0xdac3, 0xdac4, 0xcbad, 0xdac5, 0xb5f7, 0xdac6, 0xc1c2,
+  0xd7bb, 0xdac7, 0xccb8, 0xd2ea, 0xc4b1, 0xdac8, 0xb5fd, 0xbbd1,
+  0xdac9, 0xd0b3, 0xdaca, 0xdacb, 0xcebd, 0xdacc, 0xdacd, 0xdace,
+  0xb2f7, 0xdad1, 0xdacf, 0xd1e8, 0xdad0, 0xc3d5, 0xdad2, 0xdad3,
+  0xdad4, 0xdad5, 0xd0bb, 0xd2a5, 0xb0f9, 0xdad6, 0xc7ab, 0xdad7,
+  0xbdf7, 0xc3a1, 0xdad8, 0xdad9, 0xc3fd, 0xccb7, 0xdada, 0xdadb,
+  0xc0be, 0xc6d7, 0xdadc, 0xdadd, 0xc7b4, 0xdade, 0xdadf, 0xb9c8,
+  0xbbed, 0xb6b9, 0xf4f8, 0xf4f9, 0xcde3, 0xf5b9, 0xebe0, 0xcff3,
+  0xbbbf, 0xbac0, 0xd4a5, 0xe1d9, 0xf5f4, 0xb1aa, 0xb2f2, 0xf5f5,
+  0xf5f7, 0xbad1, 0xf5f6, 0xc3b2, 0xf5f9, 0xf5f8, 0xb1b4, 0xd5ea,
+  0xb8ba, 0xb9b1, 0xb2c6, 0xd4f0, 0xcfcd, 0xb0dc, 0xd5cb, 0xbbf5,
+  0xd6ca, 0xb7b7, 0xccb0, 0xc6b6, 0xb1e1, 0xb9ba, 0xd6fc, 0xb9e1,
+  0xb7a1, 0xbcfa, 0xeada, 0xeadb, 0xccf9, 0xb9f3, 0xeadc, 0xb4fb,
+  0xc3b3, 0xb7d1, 0xbad8, 0xeadd, 0xd4f4, 0xeade, 0xbcd6, 0xbbdf,
+  0xeadf, 0xc1de, 0xc2b8, 0xd4df, 0xd7ca, 0xeae0, 0xeae1, 0xeae4,
+  0xeae2, 0xeae3, 0xc9de, 0xb8b3, 0xb6c4, 0xeae5, 0xcaea, 0xc9cd,
+  0xb4cd, 0xe2d9, 0xc5e2, 0xeae6, 0xc0b5, 0xd7b8, 0xeae7, 0xd7ac,
+  0xc8fc, 0xd8d3, 0xd8cd, 0xd4de, 0xd4f9, 0xc9c4, 0xd3ae, 0xb8d3,
+  0xb3e0, 0xc9e2, 0xf4f6, 0xbad5, 0xf4f7, 0xd7df, 0xf4f1, 0xb8b0,
+  0xd5d4, 0xb8cf, 0xc6f0, 0xb3c3, 0xf4f2, 0xb3ac, 0xd4bd, 0xc7f7,
+  0xf4f4, 0xf4f3, 0xcccb, 0xc8a4, 0xf4f5, 0xd7e3, 0xc5bf, 0xf5c0,
+  0xf5bb, 0xf5c3, 0xf5c2, 0xd6ba, 0xf5c1, 0xd4be, 0xf5c4, 0xf5cc,
+  0xb0cf, 0xb5f8, 0xf5c9, 0xf5ca, 0xc5dc, 0xf5c5, 0xf5c6, 0xf5c7,
+  0xf5cb, 0xbee0, 0xf5c8, 0xb8fa, 0xf5d0, 0xf5d3, 0xbfe7, 0xb9f2,
+  0xf5bc, 0xf5cd, 0xc2b7, 0xccf8, 0xbcf9, 0xf5ce, 0xf5cf, 0xf5d1,
+  0xb6e5, 0xf5d2, 0xf5d5, 0xf5bd, 0xf5d4, 0xd3bb, 0xb3ec, 0xcca4,
+  0xf5d6, 0xf5d7, 0xbee1, 0xf5d8, 0xccdf, 0xf5db, 0xb2c8, 0xd7d9,
+  0xf5d9, 0xf5da, 0xf5dc, 0xf5e2, 0xf5e0, 0xf5df, 0xf5dd, 0xf5e1,
+  0xf5de, 0xf5e4, 0xf5e5, 0xcce3, 0xe5bf, 0xb5b8, 0xf5e3, 0xf5e8,
+  0xcca3, 0xf5e6, 0xf5e7, 0xf5be, 0xb1c4, 0xf5bf, 0xb5c5, 0xb2e4,
+  0xf5ec, 0xf5e9, 0xb6d7, 0xf5ed, 0xf5ea, 0xf5eb, 0xb4da, 0xd4ea,
+  0xf5ee, 0xb3f9, 0xf5ef, 0xf5f1, 0xf5f0, 0xf5f2, 0xf5f3, 0xc9ed,
+  0xb9aa, 0xc7fb, 0xb6e3, 0xccc9, 0xeaa6, 0xb3b5, 0xd4fe, 0xb9ec,
+  0xd0f9, 0xe9ed, 0xd7aa, 0xe9ee, 0xc2d6, 0xc8ed, 0xbae4, 0xe9ef,
+  0xe9f0, 0xe9f1, 0xd6e1, 0xe9f2, 0xe9f3, 0xe9f5, 0xe9f4, 0xe9f6,
+  0xe9f7, 0xc7e1, 0xe9f8, 0xd4d8, 0xe9f9, 0xbdce, 0xe9fa, 0xe9fb,
+  0xbdcf, 0xe9fc, 0xb8a8, 0xc1be, 0xe9fd, 0xb1b2, 0xbbd4, 0xb9f5,
+  0xe9fe, 0xeaa1, 0xeaa2, 0xeaa3, 0xb7f8, 0xbcad, 0xcae4, 0xe0ce,
+  0xd4af, 0xcfbd, 0xd5b7, 0xeaa4, 0xd5de, 0xeaa5, 0xd0c1, 0xb9bc,
+  0xb4c7, 0xb1d9, 0xc0b1, 0xb1e6, 0xb1e7, 0xb1e8, 0xb3bd, 0xc8e8,
+  0xe5c1, 0xb1df, 0xc1c9, 0xb4ef, 0xc7a8, 0xd3d8, 0xc6f9, 0xd1b8,
+  0xb9fd, 0xc2f5, 0xd3ad, 0xd4cb, 0xbdfc, 0xe5c2, 0xb7b5, 0xe5c3,
+  0xbbb9, 0xd5e2, 0xbdf8, 0xd4b6, 0xcea5, 0xc1ac, 0xb3d9, 0xccf6,
+  0xe5c6, 0xe5c4, 0xe5c8, 0xe5ca, 0xe5c7, 0xb5cf, 0xc6c8, 0xb5fc,
+  0xe5c5, 0xcaf6, 0xe5c9, 0xc3d4, 0xb1c5, 0xbca3, 0xd7b7, 0xcdcb,
+  0xcbcd, 0xcaca, 0xccd3, 0xe5cc, 0xe5cb, 0xc4e6, 0xd1a1, 0xd1b7,
+  0xe5cd, 0xe5d0, 0xcdb8, 0xd6f0, 0xe5cf, 0xb5dd, 0xcdbe, 0xe5d1,
+  0xb6ba, 0xcda8, 0xb9e4, 0xcac5, 0xb3d1, 0xcbd9, 0xd4ec, 0xe5d2,
+  0xb7ea, 0xe5ce, 0xe5d5, 0xb4fe, 0xe5d6, 0xe5d3, 0xe5d4, 0xd2dd,
+  0xc2df, 0xb1c6, 0xd3e2, 0xb6dd, 0xcbec, 0xe5d7, 0xd3f6, 0xb1e9,
+  0xb6f4, 0xe5da, 0xe5d8, 0xe5d9, 0xb5c0, 0xd2c5, 0xe5dc, 0xe5de,
+  0xe5dd, 0xc7b2, 0xd2a3, 0xe5db, 0xd4e2, 0xd5da, 0xe5e0, 0xd7f1,
+  0xe5e1, 0xb1dc, 0xd1fb, 0xe5e2, 0xe5e4, 0xe5e3, 0xe5e5, 0xd2d8,
+  0xb5cb, 0xe7df, 0xdaf5, 0xdaf8, 0xdaf6, 0xdaf7, 0xdafa, 0xd0cf,
+  0xc4c7, 0xb0ee, 0xd0b0, 0xdaf9, 0xd3ca, 0xbaaa, 0xdba2, 0xc7f1,
+  0xdafc, 0xdafb, 0xc9db, 0xdafd, 0xdba1, 0xd7de, 0xdafe, 0xc1da,
+  0xdba5, 0xd3f4, 0xdba7, 0xdba4, 0xdba8, 0xbdbc, 0xc0c9, 0xdba3,
+  0xdba6, 0xd6a3, 0xdba9, 0xdbad, 0xdbae, 0xdbac, 0xbac2, 0xbfa4,
+  0xdbab, 0xdbaa, 0xd4c7, 0xb2bf, 0xdbaf, 0xb9f9, 0xdbb0, 0xb3bb,
+  0xb5a6, 0xb6bc, 0xdbb1, 0xb6f5, 0xdbb2, 0xb1c9, 0xdbb4, 0xdbb3,
+  0xdbb5, 0xdbb7, 0xdbb6, 0xdbb8, 0xdbb9, 0xdbba, 0xd3cf, 0xf4fa,
+  0xc7f5, 0xd7c3, 0xc5e4, 0xf4fc, 0xf4fd, 0xf4fb, 0xbec6, 0xd0ef,
+  0xb7d3, 0xd4cd, 0xccaa, 0xf5a2, 0xf5a1, 0xbaa8, 0xf4fe, 0xcbd6,
+  0xf5a4, 0xc0d2, 0xb3ea, 0xcdaa, 0xf5a5, 0xf5a3, 0xbdb4, 0xf5a8,
+  0xf5a9, 0xbdcd, 0xc3b8, 0xbfe1, 0xcbe1, 0xf5aa, 0xf5a6, 0xf5a7,
+  0xc4f0, 0xf5ac, 0xb4bc, 0xd7ed, 0xb4d7, 0xf5ab, 0xf5ae, 0xf5ad,
+  0xf5af, 0xd0d1, 0xc3d1, 0xc8a9, 0xf5b0, 0xf5b1, 0xf5b2, 0xf5b3,
+  0xf5b4, 0xf5b5, 0xf5b7, 0xf5b6, 0xf5b8, 0xb2c9, 0xd3d4, 0xcacd,
+  0xc0ef, 0xd6d8, 0xd2b0, 0xc1bf, 0xbdf0, 0xb8aa, 0xbcf8, 0xf6c6,
+  0xf6c7, 0xf6c8, 0xf6c9, 0xf6ca, 0xf6cc, 0xf6cb, 0xf7e9, 0xf6cd,
+  0xf6ce, 0xeec4, 0xeec5, 0xeec6, 0xd5eb, 0xb6a4, 0xeec8, 0xeec7,
+  0xeec9, 0xeeca, 0xc7a5, 0xeecb, 0xeecc, 0xb7b0, 0xb5f6, 0xeecd,
+  0xeecf, 0xeece, 0xb8c6, 0xeed0, 0xeed1, 0xeed2, 0xb6db, 0xb3ae,
+  0xd6d3, 0xc4c6, 0xb1b5, 0xb8d6, 0xeed3, 0xeed4, 0xd4bf, 0xc7d5,
+  0xbefb, 0xced9, 0xb9b3, 0xeed6, 0xeed5, 0xeed8, 0xeed7, 0xc5a5,
+  0xeed9, 0xeeda, 0xc7ae, 0xeedb, 0xc7af, 0xeedc, 0xb2a7, 0xeedd,
+  0xeede, 0xeedf, 0xeee0, 0xeee1, 0xd7ea, 0xeee2, 0xeee3, 0xbcd8,
+  0xeee4, 0xd3cb, 0xccfa, 0xb2ac, 0xc1e5, 0xeee5, 0xc7a6, 0xc3ad,
+  0xeee6, 0xeee7, 0xeee8, 0xeee9, 0xeeea, 0xeeeb, 0xeeec, 0xeeed,
+  0xeeee, 0xeeef, 0xeef0, 0xeef1, 0xeef2, 0xeef4, 0xeef3, 0xeef5,
+  0xcdad, 0xc2c1, 0xeef6, 0xeef7, 0xeef8, 0xd5a1, 0xeef9, 0xcfb3,
+  0xeefa, 0xeefb, 0xeefc, 0xeefd, 0xefa1, 0xeefe, 0xefa2, 0xb8f5,
+  0xc3fa, 0xefa3, 0xefa4, 0xbdc2, 0xd2bf, 0xb2f9, 0xefa5, 0xefa6,
+  0xefa7, 0xd2f8, 0xefa8, 0xd6fd, 0xefa9, 0xc6cc, 0xefaa, 0xefab,
+  0xc1b4, 0xefac, 0xcffa, 0xcbf8, 0xefae, 0xefad, 0xb3fa, 0xb9f8,
+  0xefaf, 0xefb0, 0xd0e2, 0xefb1, 0xefb2, 0xb7e6, 0xd0bf, 0xefb3,
+  0xefb4, 0xefb5, 0xc8f1, 0xcce0, 0xefb6, 0xefb7, 0xefb8, 0xefb9,
+  0xefba, 0xd5e0, 0xefbb, 0xb4ed, 0xc3aa, 0xefbc, 0xefbd, 0xefbe,
+  0xefbf, 0xcefd, 0xefc0, 0xc2e0, 0xb4b8, 0xd7b6, 0xbdf5, 0xcfc7,
+  0xefc3, 0xefc1, 0xefc2, 0xefc4, 0xb6a7, 0xbcfc, 0xbee2, 0xc3cc,
+  0xefc5, 0xefc6, 0xefc7, 0xefcf, 0xefc8, 0xefc9, 0xefca, 0xc7c2,
+  0xeff1, 0xb6cd, 0xefcb, 0xefcc, 0xefcd, 0xb6c6, 0xc3be, 0xefce,
+  0xefd0, 0xefd1, 0xefd2, 0xd5f2, 0xefd3, 0xc4f7, 0xefd4, 0xc4f8,
+  0xefd5, 0xefd6, 0xb8e4, 0xb0f7, 0xefd7, 0xefd8, 0xefd9, 0xefda,
+  0xefdb, 0xefdc, 0xefdd, 0xefde, 0xbeb5, 0xefe1, 0xefdf, 0xefe0,
+  0xefe2, 0xefe3, 0xc1cd, 0xefe4, 0xefe5, 0xefe6, 0xefe7, 0xefe8,
+  0xefe9, 0xefea, 0xefeb, 0xefec, 0xc0d8, 0xefed, 0xc1ad, 0xefee,
+  0xefef, 0xeff0, 0xcfe2, 0xb3a4, 0xc3c5, 0xe3c5, 0xc9c1, 0xe3c6,
+  0xb1d5, 0xceca, 0xb4b3, 0xc8f2, 0xe3c7, 0xcfd0, 0xe3c8, 0xbce4,
+  0xe3c9, 0xe3ca, 0xc3c6, 0xd5a2, 0xc4d6, 0xb9eb, 0xcec5, 0xe3cb,
+  0xc3f6, 0xe3cc, 0xb7a7, 0xb8f3, 0xbad2, 0xe3cd, 0xe3ce, 0xd4c4,
+  0xe3cf, 0xe3d0, 0xd1cb, 0xe3d1, 0xe3d2, 0xe3d3, 0xe3d4, 0xd1d6,
+  0xe3d5, 0xb2fb, 0xc0bb, 0xe3d6, 0xc0ab, 0xe3d7, 0xe3d8, 0xe3d9,
+  0xe3da, 0xe3db, 0xb8b7, 0xdae2, 0xb6d3, 0xdae4, 0xdae3, 0xdae6,
+  0xc8ee, 0xdae5, 0xb7c0, 0xd1f4, 0xd2f5, 0xd5f3, 0xbdd7, 0xd7e8,
+  0xdae8, 0xdae7, 0xb0a2, 0xcdd3, 0xdae9, 0xb8bd, 0xbcca, 0xc2bd,
+  0xc2a4, 0xb3c2, 0xdaea, 0xc2aa, 0xc4b0, 0xbdb5, 0xcfde, 0xdaeb,
+  0xc9c2, 0xb1dd, 0xdaec, 0xb6b8, 0xd4ba, 0xb3fd, 0xdaed, 0xd4c9,
+  0xcfd5, 0xc5e3, 0xdaee, 0xdaef, 0xdaf0, 0xc1ea, 0xccd5, 0xcfdd,
+  0xd3e7, 0xc2a1, 0xdaf1, 0xcbe5, 0xdaf2, 0xcbe6, 0xd2fe, 0xb8f4,
+  0xdaf3, 0xb0af, 0xcfb6, 0xd5cf, 0xcbed, 0xdaf4, 0xe3c4, 0xc1a5,
+  0xf6bf, 0xf6c0, 0xf6c1, 0xc4d1, 0xc8b8, 0xd1e3, 0xd0db, 0xd1c5,
+  0xbcaf, 0xb9cd, 0xeff4, 0xb4c6, 0xd3ba, 0xf6c2, 0xb3fb, 0xf6c3,
+  0xb5f1, 0xf6c5, 0xd3ea, 0xf6a7, 0xd1a9, 0xf6a9, 0xf6a8, 0xc1e3,
+  0xc0d7, 0xb1a2, 0xceed, 0xd0e8, 0xf6ab, 0xcff6, 0xf6aa, 0xd5f0,
+  0xf6ac, 0xc3b9, 0xbbf4, 0xf6ae, 0xf6ad, 0xc4de, 0xc1d8, 0xcbaa,
+  0xcfbc, 0xf6af, 0xf6b0, 0xf6b1, 0xc2b6, 0xb0d4, 0xc5f9, 0xf6b2,
+  0xc7e0, 0xf6a6, 0xbeb8, 0xbeb2, 0xb5e5, 0xb7c7, 0xbfbf, 0xc3d2,
+  0xc3e6, 0xd8cc, 0xb8ef, 0xbdf9, 0xd1a5, 0xb0d0, 0xf7b0, 0xf7b1,
+  0xd0ac, 0xb0b0, 0xf7b2, 0xf7b3, 0xf7b4, 0xc7ca, 0xbecf, 0xf7b7,
+  0xf7b6, 0xb1de, 0xf7b5, 0xf7b8, 0xf7b9, 0xcea4, 0xc8cd, 0xbaab,
+  0xe8b8, 0xe8b9, 0xe8ba, 0xbec2, 0xd2f4, 0xd4cf, 0xc9d8, 0xd2b3,
+  0xb6a5, 0xc7ea, 0xf1fc, 0xcfee, 0xcbb3, 0xd0eb, 0xe7ef, 0xcde7,
+  0xb9cb, 0xb6d9, 0xf1fd, 0xb0e4, 0xcbcc, 0xf1fe, 0xd4a4, 0xc2ad,
+  0xc1ec, 0xc6c4, 0xbeb1, 0xf2a1, 0xbcd5, 0xf2a2, 0xf2a3, 0xf2a4,
+  0xd2c3, 0xc6b5, 0xcdc7, 0xf2a5, 0xd3b1, 0xbfc5, 0xcce2, 0xf2a6,
+  0xf2a7, 0xd1d5, 0xb6ee, 0xf2a8, 0xf2a9, 0xb5df, 0xf2aa, 0xf2ab,
+  0xb2fc, 0xf2ac, 0xf2ad, 0xc8a7, 0xb7e7, 0xeca9, 0xecaa, 0xecab,
+  0xecac, 0xc6ae, 0xecad, 0xecae, 0xb7c9, 0xcab3, 0xe2b8, 0xf7cf,
+  0xf7d0, 0xb2cd, 0xf7d1, 0xf7d3, 0xf7d2, 0xe2bb, 0xbca2, 0xe2bc,
+  0xe2bd, 0xe2be, 0xe2bf, 0xe2c0, 0xe2c1, 0xb7b9, 0xd2fb, 0xbda4,
+  0xcace, 0xb1a5, 0xcbc7, 0xe2c2, 0xb6fc, 0xc8c4, 0xe2c3, 0xbdc8,
+  0xb1fd, 0xe2c4, 0xb6f6, 0xe2c5, 0xc4d9, 0xe2c6, 0xcfda, 0xb9dd,
+  0xe2c7, 0xc0a1, 0xe2c8, 0xb2f6, 0xe2c9, 0xc1f3, 0xe2ca, 0xe2cb,
+  0xc2f8, 0xe2cc, 0xe2cd, 0xe2ce, 0xcad7, 0xd8b8, 0xd9e5, 0xcfe3,
+  0xf0a5, 0xdcb0, 0xc2ed, 0xd4a6, 0xcdd4, 0xd1b1, 0xb3db, 0xc7fd,
+  0xb2b5, 0xc2bf, 0xe6e0, 0xcabb, 0xe6e1, 0xe6e2, 0xbed4, 0xe6e3,
+  0xd7a4, 0xcdd5, 0xe6e5, 0xbcdd, 0xe6e4, 0xe6e6, 0xe6e7, 0xc2ee,
+  0xbdbe, 0xe6e8, 0xc2e6, 0xbaa7, 0xe6e9, 0xe6ea, 0xb3d2, 0xd1e9,
+  0xbfa5, 0xe6eb, 0xc6ef, 0xe6ec, 0xe6ed, 0xe6ee, 0xc6ad, 0xe6ef,
+  0xc9a7, 0xe6f0, 0xe6f1, 0xe6f2, 0xe5b9, 0xe6f3, 0xe6f4, 0xc2e2,
+  0xe6f5, 0xe6f6, 0xd6e8, 0xe6f7, 0xe6f8, 0xb9c7, 0xf7bb, 0xf7ba,
+  0xf7be, 0xf7bc, 0xbaa1, 0xf7bf, 0xf7c0, 0xf7c2, 0xf7c1, 0xf7c4,
+  0xf7c3, 0xf7c5, 0xf7c6, 0xf7c7, 0xcbe8, 0xb8df, 0xf7d4, 0xf7d5,
+  0xf7d6, 0xf7d8, 0xf7da, 0xf7d7, 0xf7db, 0xf7d9, 0xd7d7, 0xf7dc,
+  0xf7dd, 0xf7de, 0xf7df, 0xf7e0, 0xdbcb, 0xd8aa, 0xe5f7, 0xb9ed,
+  0xbffd, 0xbbea, 0xf7c9, 0xc6c7, 0xf7c8, 0xf7ca, 0xf7cc, 0xf7cb,
+  0xf7cd, 0xceba, 0xf7ce, 0xc4a7, 0xd3e3, 0xf6cf, 0xc2b3, 0xf6d0,
+  0xf6d1, 0xf6d2, 0xf6d3, 0xf6d4, 0xf6d6, 0xb1ab, 0xf6d7, 0xf6d8,
+  0xf6d9, 0xf6da, 0xf6db, 0xf6dc, 0xf6dd, 0xf6de, 0xcfca, 0xf6df,
+  0xf6e0, 0xf6e1, 0xf6e2, 0xf6e3, 0xf6e4, 0xc0f0, 0xf6e5, 0xf6e6,
+  0xf6e7, 0xf6e8, 0xf6e9, 0xf6ea, 0xf6eb, 0xf6ec, 0xf6ed, 0xf6ee,
+  0xf6ef, 0xf6f0, 0xf6f1, 0xf6f2, 0xf6f3, 0xf6f4, 0xbea8, 0xf6f5,
+  0xf6f6, 0xf6f7, 0xf6f8, 0xc8fa, 0xf6f9, 0xf6fa, 0xf6fb, 0xf6fc,
+  0xf6fd, 0xf6fe, 0xf7a1, 0xf7a2, 0xf7a3, 0xf7a4, 0xf7a5, 0xf7a6,
+  0xf7a7, 0xf7a8, 0xb1ee, 0xf7a9, 0xf7aa, 0xf7ab, 0xf7ac, 0xf7ad,
+  0xc1db, 0xf7ae, 0xf7af, 0xc4f1, 0xf0af, 0xbca6, 0xf0b0, 0xc3f9,
+  0xc5b8, 0xd1bb, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xd1bc,
+  0xd1ec, 0xf0b7, 0xf0b6, 0xd4a7, 0xcdd2, 0xf0b8, 0xf0ba, 0xf0b9,
+  0xf0bb, 0xf0bc, 0xb8eb, 0xf0bd, 0xbae8, 0xf0be, 0xf0bf, 0xbee9,
+  0xf0c0, 0xb6ec, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xc8b5, 0xf0c5,
+  0xf0c6, 0xf0c7, 0xc5f4, 0xf0c8, 0xf0c9, 0xf0ca, 0xf7bd, 0xf0cb,
+  0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf, 0xbad7, 0xf0d0, 0xf0d1, 0xf0d2,
+  0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d8, 0xd3a5, 0xf0d7, 0xf0d9,
+  0xf5ba, 0xc2b9, 0xf7e4, 0xf7e5, 0xf7e6, 0xf7e7, 0xf7e8, 0xc2b4,
+  0xf7ea, 0xf7eb, 0xc2f3, 0xf4f0, 0xf4ef, 0xc2e9, 0xf7e1, 0xf7e2,
+  0xbbc6, 0xd9e4, 0xcaf2, 0xc0e8, 0xf0a4, 0xbada, 0xc7ad, 0xc4ac,
+  0xf7ec, 0xf7ed, 0xf7ee, 0xf7f0, 0xf7ef, 0xf7f1, 0xf7f4, 0xf7f3,
+  0xf7f2, 0xf7f5, 0xf7f6, 0xede9, 0xedea, 0xedeb, 0xf6bc, 0xf6bd,
+  0xf6be, 0xb6a6, 0xd8be, 0xb9c4, 0xd8bb, 0xdcb1, 0xcaf3, 0xf7f7,
+  0xf7f8, 0xf7f9, 0xf7fb, 0xf7fa, 0xb1c7, 0xf7fc, 0xf7fd, 0xf7fe,
+  0xc6eb, 0xecb4, 0xb3dd, 0xf6b3, 0xf6b4, 0xc1e4, 0xf6b5, 0xf6b6,
+  0xf6b7, 0xf6b8, 0xf6b9, 0xf6ba, 0xc8a3, 0xf6bb, 0xc1fa, 0xb9a8,
+  0xede8, 0xb9ea, 0xd9df, 0xa3a1, 0xa3a2, 0xa3a3, 0xa1e7, 0xa3a5,
+  0xa3a6, 0xa3a7, 0xa3a8, 0xa3a9, 0xa3aa, 0xa3ab, 0xa3ac, 0xa3ad,
+  0xa3ae, 0xa3af, 0xa3b0, 0xa3b1, 0xa3b2, 0xa3b3, 0xa3b4, 0xa3b5,
+  0xa3b6, 0xa3b7, 0xa3b8, 0xa3b9, 0xa3ba, 0xa3bb, 0xa3bc, 0xa3bd,
+  0xa3be, 0xa3bf, 0xa3c0, 0xa3c1, 0xa3c2, 0xa3c3, 0xa3c4, 0xa3c5,
+  0xa3c6, 0xa3c7, 0xa3c8, 0xa3c9, 0xa3ca, 0xa3cb, 0xa3cc, 0xa3cd,
+  0xa3ce, 0xa3cf, 0xa3d0, 0xa3d1, 0xa3d2, 0xa3d3, 0xa3d4, 0xa3d5,
+  0xa3d6, 0xa3d7, 0xa3d8, 0xa3d9, 0xa3da, 0xa3db, 0xa3dc, 0xa3dd,
+  0xa3de, 0xa3df, 0xa3e0, 0xa3e1, 0xa3e2, 0xa3e3, 0xa3e4, 0xa3e5,
+  0xa3e6, 0xa3e7, 0xa3e8, 0xa3e9, 0xa3ea, 0xa3eb, 0xa3ec, 0xa3ed,
+  0xa3ee, 0xa3ef, 0xa3f0, 0xa3f1, 0xa3f2, 0xa3f3, 0xa3f4, 0xa3f5,
+  0xa3f6, 0xa3f7, 0xa3f8, 0xa3f9, 0xa3fa, 0xa3fb, 0xa3fc, 0xa3fd,
+  0xa1ab, 0xa1e9, 0xa1ea, 0xa3fe, 0xa3a4,
+};
+
+typedef struct {
+  unsigned short indx; /* index into big table */
+  unsigned short used; /* bitmask of used entries */
+} Summary16;
+
+static const Summary16 gb2312_uni2indx_page00[70] = {
+  /* 0x0000 */
+  {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 },
+  {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 },
+  {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0190 }, {    3, 0x0003 },
+  {    5, 0x0000 }, {    5, 0x0080 }, {    6, 0x3703 }, {   13, 0x168c },
+  /* 0x0100 */
+  {   19, 0x0002 }, {   20, 0x0808 }, {   22, 0x0800 }, {   23, 0x0000 },
+  {   23, 0x2000 }, {   24, 0x0000 }, {   24, 0x0800 }, {   25, 0x0000 },
+  {   25, 0x0000 }, {   25, 0x0000 }, {   25, 0x0000 }, {   25, 0x0000 },
+  {   25, 0x4000 }, {   26, 0x1555 }, {   33, 0x0000 }, {   33, 0x0000 },
+  /* 0x0200 */
+  {   33, 0x0000 }, {   33, 0x0000 }, {   33, 0x0000 }, {   33, 0x0000 },
+  {   33, 0x0000 }, {   33, 0x0000 }, {   33, 0x0000 }, {   33, 0x0000 },
+  {   33, 0x0000 }, {   33, 0x0000 }, {   33, 0x0000 }, {   33, 0x0000 },
+  {   33, 0x0280 }, {   35, 0x0000 }, {   35, 0x0000 }, {   35, 0x0000 },
+  /* 0x0300 */
+  {   35, 0x0000 }, {   35, 0x0000 }, {   35, 0x0000 }, {   35, 0x0000 },
+  {   35, 0x0000 }, {   35, 0x0000 }, {   35, 0x0000 }, {   35, 0x0000 },
+  {   35, 0x0000 }, {   35, 0xfffe }, {   50, 0x03fb }, {   59, 0xfffe },
+  {   74, 0x03fb }, {   83, 0x0000 }, {   83, 0x0000 }, {   83, 0x0000 },
+  /* 0x0400 */
+  {   83, 0x0002 }, {   84, 0xffff }, {  100, 0xffff }, {  116, 0xffff },
+  {  132, 0xffff }, {  148, 0x0002 },
+};
+static const Summary16 gb2312_uni2indx_page20[101] = {
+  /* 0x2000 */
+  {  149, 0x0000 }, {  149, 0x3360 }, {  155, 0x0040 }, {  156, 0x080d },
+  {  160, 0x0000 }, {  160, 0x0000 }, {  160, 0x0000 }, {  160, 0x0000 },
+  {  160, 0x0000 }, {  160, 0x0000 }, {  160, 0x0000 }, {  160, 0x0000 },
+  {  160, 0x0000 }, {  160, 0x0000 }, {  160, 0x0000 }, {  160, 0x0000 },
+  /* 0x2100 */
+  {  160, 0x0008 }, {  161, 0x0040 }, {  162, 0x0000 }, {  162, 0x0000 },
+  {  162, 0x0000 }, {  162, 0x0000 }, {  162, 0x0fff }, {  174, 0x0000 },
+  {  174, 0x0000 }, {  174, 0x000f }, {  178, 0x0000 }, {  178, 0x0000 },
+  {  178, 0x0000 }, {  178, 0x0000 }, {  178, 0x0000 }, {  178, 0x0000 },
+  /* 0x2200 */
+  {  178, 0x8100 }, {  180, 0x6402 }, {  184, 0x4fa1 }, {  192, 0x20f0 },
+  {  197, 0x1100 }, {  199, 0x0000 }, {  199, 0xc033 }, {  205, 0x0000 },
+  {  205, 0x0000 }, {  205, 0x0200 }, {  206, 0x0020 }, {  207, 0x0000 },
+  {  207, 0x0000 }, {  207, 0x0000 }, {  207, 0x0000 }, {  207, 0x0000 },
+  /* 0x2300 */
+  {  207, 0x0000 }, {  207, 0x0004 }, {  208, 0x0000 }, {  208, 0x0000 },
+  {  208, 0x0000 }, {  208, 0x0000 }, {  208, 0x0000 }, {  208, 0x0000 },
+  {  208, 0x0000 }, {  208, 0x0000 }, {  208, 0x0000 }, {  208, 0x0000 },
+  {  208, 0x0000 }, {  208, 0x0000 }, {  208, 0x0000 }, {  208, 0x0000 },
+  /* 0x2400 */
+  {  208, 0x0000 }, {  208, 0x0000 }, {  208, 0x0000 }, {  208, 0x0000 },
+  {  208, 0x0000 }, {  208, 0x0000 }, {  208, 0x03ff }, {  218, 0xfff0 },
+  {  230, 0xffff }, {  246, 0x0fff }, {  258, 0x0000 }, {  258, 0x0000 },
+  {  258, 0x0000 }, {  258, 0x0000 }, {  258, 0x0000 }, {  258, 0x0000 },
+  /* 0x2500 */
+  {  258, 0xffff }, {  274, 0xffff }, {  290, 0xffff }, {  306, 0xffff },
+  {  322, 0x0fff }, {  334, 0x0000 }, {  334, 0x0000 }, {  334, 0x0000 },
+  {  334, 0x0000 }, {  334, 0x0000 }, {  334, 0x0003 }, {  336, 0x000c },
+  {  338, 0xc8c0 }, {  343, 0x0000 }, {  343, 0x0000 }, {  343, 0x0000 },
+  /* 0x2600 */
+  {  343, 0x0060 }, {  345, 0x0000 }, {  345, 0x0000 }, {  345, 0x0000 },
+  {  345, 0x0005 },
+};
+static const Summary16 gb2312_uni2indx_page30[35] = {
+  /* 0x3000 */
+  {  347, 0xff2f }, {  360, 0x00fb }, {  367, 0x0000 }, {  367, 0x0000 },
+  {  367, 0xfffe }, {  382, 0xffff }, {  398, 0xffff }, {  414, 0xffff },
+  {  430, 0xffff }, {  446, 0x000f }, {  450, 0xfffe }, {  465, 0xffff },
+  {  481, 0xffff }, {  497, 0xffff }, {  513, 0xffff }, {  529, 0x087f },
+  /* 0x3100 */
+  {  537, 0xffe0 }, {  548, 0xffff }, {  564, 0x03ff }, {  574, 0x0000 },
+  {  574, 0x0000 }, {  574, 0x0000 }, {  574, 0x0000 }, {  574, 0x0000 },
+  {  574, 0x0000 }, {  574, 0x0000 }, {  574, 0x0000 }, {  574, 0x0000 },
+  {  574, 0x0000 }, {  574, 0x0000 }, {  574, 0x0000 }, {  574, 0x0000 },
+  /* 0x3200 */
+  {  574, 0x0000 }, {  574, 0x0000 }, {  574, 0x03ff },
+};
+static const Summary16 gb2312_uni2indx_page4e[1263] = {
+  /* 0x4e00 */
+  {  584, 0x7f8b }, {  595, 0x7f7b }, {  608, 0x3db4 }, {  617, 0xef55 },
+  {  628, 0xfba8 }, {  638, 0xf35d }, {  649, 0x0243 }, {  653, 0x400b },
+  {  657, 0xfb40 }, {  665, 0x8d3e }, {  674, 0x7bf7 }, {  687, 0x8c2c },
+  {  693, 0x6eff }, {  706, 0xe3fa }, {  717, 0x1d3a }, {  725, 0xa8ed },
+  /* 0x4f00 */
+  {  734, 0xe602 }, {  740, 0xcf83 }, {  749, 0x8cf5 }, {  758, 0x3555 },
+  {  766, 0xe048 }, {  771, 0xffab }, {  784, 0x92b9 }, {  792, 0xd859 },
+  {  800, 0xab18 }, {  807, 0x2892 }, {  812, 0xd7e9 }, {  823, 0x8020 },
+  {  825, 0xc438 }, {  831, 0xf583 }, {  840, 0xe74a }, {  849, 0x450a },
+  /* 0x5000 */
+  {  854, 0xb000 }, {  857, 0x9714 }, {  864, 0x7762 }, {  873, 0x5400 },
+  {  876, 0xd188 }, {  882, 0x1420 }, {  885, 0x1020 }, {  887, 0xc8c0 },
+  {  892, 0x2121 }, {  896, 0x0000 }, {  896, 0x13a8 }, {  902, 0x0c04 },
+  {  905, 0x8000 }, {  906, 0x0440 }, {  908, 0x70c0 }, {  913, 0x0828 },
+  /* 0x5100 */
+  {  916, 0x08c0 }, {  919, 0x0004 }, {  920, 0x0002 }, {  921, 0x8000 },
+  {  922, 0x2b7b }, {  932, 0x1472 }, {  938, 0x7924 }, {  945, 0x3bfb },
+  {  957, 0x3327 }, {  965, 0x1ae4 }, {  972, 0x9835 }, {  979, 0x38ef },
+  {  989, 0x9ad1 }, {  997, 0x2802 }, { 1000, 0xa813 }, { 1006, 0xbf69 },
+  /* 0x5200 */
+  { 1017, 0x65cf }, { 1027, 0x2fc6 }, { 1036, 0x6b11 }, { 1043, 0xafc9 },
+  { 1053, 0x340f }, { 1060, 0x5053 }, { 1066, 0x86a2 }, { 1072, 0xa004 },
+  { 1075, 0x0106 }, { 1078, 0xe809 }, { 1084, 0x3f0f }, { 1094, 0xc00e },
+  { 1099, 0x0a88 }, { 1103, 0x8145 }, { 1108, 0x0010 }, { 1109, 0xc601 },
+  /* 0x5300 */
+  { 1114, 0xa161 }, { 1120, 0x26e1 }, { 1127, 0x444b }, { 1133, 0xce00 },
+  { 1138, 0xc7aa }, { 1147, 0xd4ee }, { 1157, 0xcadf }, { 1168, 0x85bb },
+  { 1177, 0x3a74 }, { 1185, 0xa520 }, { 1190, 0x436c }, { 1197, 0x8840 },
+  { 1200, 0x3f06 }, { 1208, 0x8bd2 }, { 1216, 0xff79 }, { 1229, 0x3bef },
+  /* 0x5400 */
+  { 1241, 0xf75a }, { 1252, 0xe8ef }, { 1263, 0xfbcb }, { 1275, 0x5b36 },
+  { 1284, 0x0d49 }, { 1290, 0x1bfd }, { 1301, 0x0154 }, { 1305, 0x39ee },
+  { 1315, 0xd855 }, { 1323, 0x2e75 }, { 1332, 0xbfd8 }, { 1343, 0xa91a },
+  { 1350, 0xf3d7 }, { 1362, 0xf6bf }, { 1375, 0x67e0 }, { 1383, 0xb40c },
+  /* 0x5500 */
+  { 1389, 0x82c2 }, { 1394, 0x0813 }, { 1398, 0xd49d }, { 1407, 0xd08b },
+  { 1414, 0x065a }, { 1420, 0x1061 }, { 1424, 0x74f2 }, { 1433, 0x59e0 },
+  { 1440, 0x8f9f }, { 1451, 0xb312 }, { 1458, 0x0080 }, { 1459, 0x6aaa },
+  { 1467, 0x3230 }, { 1472, 0xb05e }, { 1480, 0x9d7a }, { 1490, 0x60ac },
+  /* 0x5600 */
+  { 1496, 0xd303 }, { 1503, 0xc900 }, { 1507, 0x3098 }, { 1512, 0x8a56 },
+  { 1519, 0x7000 }, { 1522, 0x1390 }, { 1527, 0x1f14 }, { 1534, 0x1842 },
+  { 1538, 0xc060 }, { 1542, 0x0008 }, { 1543, 0x8008 }, { 1545, 0x1080 },
+  { 1547, 0x0400 }, { 1548, 0xec90 }, { 1555, 0x2817 }, { 1561, 0xe633 },
+  /* 0x5700 */
+  { 1570, 0x0758 }, { 1576, 0x9000 }, { 1578, 0xf708 }, { 1586, 0x4e09 },
+  { 1592, 0xf485 }, { 1600, 0xfc83 }, { 1609, 0xaf53 }, { 1619, 0x18c8 },
+  { 1624, 0x187c }, { 1631, 0x080c }, { 1634, 0x6adf }, { 1645, 0x0114 },
+  { 1648, 0xc80c }, { 1653, 0xa734 }, { 1661, 0xa011 }, { 1665, 0x2710 },
+  /* 0x5800 */
+  { 1670, 0x28c5 }, { 1676, 0x4222 }, { 1680, 0x0413 }, { 1684, 0x0021 },
+  { 1686, 0x3010 }, { 1689, 0x4112 }, { 1693, 0x1820 }, { 1696, 0x4000 },
+  { 1697, 0x022b }, { 1702, 0xc60c }, { 1708, 0x0300 }, { 1710, 0x1000 },
+  { 1711, 0x0022 }, { 1713, 0x0022 }, { 1715, 0x5810 }, { 1719, 0x0249 },
+  /* 0x5900 */
+  { 1723, 0xa094 }, { 1728, 0x9670 }, { 1735, 0xeeb0 }, { 1744, 0x1792 },
+  { 1751, 0xcb96 }, { 1760, 0x05f2 }, { 1767, 0x0025 }, { 1770, 0x2358 },
+  { 1776, 0x25de }, { 1785, 0x42cc }, { 1791, 0xcf38 }, { 1800, 0x4a04 },
+  { 1804, 0x0c40 }, { 1807, 0x359f }, { 1817, 0x1128 }, { 1821, 0x8a00 },
+  /* 0x5a00 */
+  { 1824, 0x13fa }, { 1833, 0x910a }, { 1838, 0x0229 }, { 1842, 0x1056 },
+  { 1847, 0x0641 }, { 1851, 0x0420 }, { 1853, 0x0484 }, { 1856, 0x84f0 },
+  { 1862, 0x0000 }, { 1862, 0x0c04 }, { 1865, 0x0400 }, { 1866, 0x412c },
+  { 1871, 0x1206 }, { 1875, 0x1154 }, { 1880, 0x0a4b }, { 1886, 0x0002 },
+  /* 0x5b00 */
+  { 1887, 0x0200 }, { 1888, 0x00c0 }, { 1890, 0x0000 }, { 1890, 0x0094 },
+  { 1893, 0x0001 }, { 1894, 0xbfbb }, { 1907, 0x167c }, { 1915, 0x242b },
+  { 1921, 0x9bbb }, { 1932, 0x7fa8 }, { 1942, 0x0c7f }, { 1951, 0xe379 },
+  { 1961, 0x10f4 }, { 1967, 0xe00d }, { 1973, 0x4132 }, { 1978, 0x9f01 },
+  /* 0x5c00 */
+  { 1985, 0x8652 }, { 1991, 0x3572 }, { 1999, 0x10b4 }, { 2004, 0xff12 },
+  { 2014, 0xcf27 }, { 2024, 0x4223 }, { 2029, 0xc06b }, { 2036, 0x8602 },
+  { 2040, 0x3106 }, { 2045, 0x1fd3 }, { 2055, 0x3a0c }, { 2061, 0xa1aa },
+  { 2068, 0x0812 }, { 2071, 0x0204 }, { 2073, 0x2572 }, { 2080, 0x0801 },
+  /* 0x5d00 */
+  { 2082, 0x40cc }, { 2087, 0x4850 }, { 2091, 0x62d0 }, { 2097, 0x6010 },
+  { 2100, 0x1c80 }, { 2104, 0x2900 }, { 2107, 0x9a00 }, { 2111, 0x0010 },
+  { 2112, 0x0004 }, { 2113, 0x2200 }, { 2115, 0x0000 }, { 2115, 0x0080 },
+  { 2116, 0x2020 }, { 2118, 0x6800 }, { 2121, 0xcbe6 }, { 2131, 0x609e },
+  /* 0x5e00 */
+  { 2138, 0x916e }, { 2146, 0x3f73 }, { 2157, 0x60c0 }, { 2161, 0x3982 },
+  { 2167, 0x1034 }, { 2171, 0x4830 }, { 2175, 0x0006 }, { 2177, 0xbd5c },
+  { 2187, 0x8cd1 }, { 2194, 0xd6fb }, { 2206, 0x20e1 }, { 2211, 0x43e8 },
+  { 2218, 0x0600 }, { 2220, 0x084e }, { 2225, 0x0500 }, { 2227, 0xc4d0 },
+  /* 0x5f00 */
+  { 2233, 0x8d1f }, { 2242, 0x89aa }, { 2249, 0xa6e1 }, { 2257, 0x1602 },
+  { 2261, 0x0001 }, { 2262, 0x21ed }, { 2270, 0x3656 }, { 2278, 0x1a8b },
+  { 2285, 0x1fb7 }, { 2296, 0x13a5 }, { 2303, 0x6502 }, { 2308, 0x30a0 },
+  { 2312, 0xb278 }, { 2320, 0x23c7 }, { 2328, 0x6c93 }, { 2336, 0xe922 },
+  /* 0x6000 */
+  { 2343, 0xe47f }, { 2354, 0x3a74 }, { 2362, 0x8fe3 }, { 2372, 0x9820 },
+  { 2376, 0x280e }, { 2381, 0x2625 }, { 2387, 0xbf9c }, { 2398, 0xbf49 },
+  { 2408, 0x3218 }, { 2413, 0xac54 }, { 2420, 0xb949 }, { 2428, 0x1916 },
+  { 2434, 0x0c60 }, { 2438, 0xb522 }, { 2445, 0xfbc1 }, { 2455, 0x0659 },
+  /* 0x6100 */
+  { 2461, 0xe343 }, { 2469, 0x8420 }, { 2472, 0x08d9 }, { 2478, 0x8000 },
+  { 2479, 0x5500 }, { 2483, 0x2022 }, { 2486, 0x0184 }, { 2489, 0x00a1 },
+  { 2492, 0x4800 }, { 2494, 0x2010 }, { 2496, 0x1380 }, { 2500, 0x4080 },
+  { 2502, 0x0d04 }, { 2506, 0x0016 }, { 2509, 0x0040 }, { 2510, 0x8020 },
+  /* 0x6200 */
+  { 2512, 0xfd40 }, { 2520, 0x8de7 }, { 2530, 0x5436 }, { 2537, 0xe098 },
+  { 2543, 0x7b8b }, { 2553, 0x091e }, { 2559, 0xfec8 }, { 2569, 0xd249 },
+  { 2576, 0x0611 }, { 2580, 0x8dee }, { 2590, 0x1937 }, { 2598, 0xba22 },
+  { 2605, 0x77f4 }, { 2616, 0x9fdd }, { 2628, 0xf3ec }, { 2639, 0xf0da },
+  /* 0x6300 */
+  { 2648, 0x4386 }, { 2654, 0xec42 }, { 2661, 0x8d3f }, { 2671, 0x2604 },
+  { 2675, 0xfa6c }, { 2685, 0xc021 }, { 2689, 0x628e }, { 2696, 0x0cc2 },
+  { 2701, 0xd785 }, { 2710, 0x0145 }, { 2714, 0x77ad }, { 2725, 0x5599 },
+  { 2733, 0xe250 }, { 2739, 0x4045 }, { 2743, 0x260b }, { 2749, 0xa154 },
+  /* 0x6400 */
+  { 2755, 0x9827 }, { 2762, 0x5819 }, { 2768, 0x3443 }, { 2774, 0xa410 },
+  { 2778, 0x05f2 }, { 2785, 0x4114 }, { 2789, 0x2280 }, { 2792, 0x0700 },
+  { 2795, 0x00b4 }, { 2799, 0x4266 }, { 2805, 0x7210 }, { 2810, 0x15a1 },
+  { 2816, 0x6025 }, { 2821, 0x4185 }, { 2826, 0x0054 }, { 2829, 0x0000 },
+  /* 0x6500 */
+  { 2829, 0x0201 }, { 2831, 0x0104 }, { 2833, 0xc820 }, { 2837, 0xcb70 },
+  { 2845, 0x9320 }, { 2850, 0x6a62 }, { 2857, 0x184c }, { 2862, 0x0095 },
+  { 2866, 0x1880 }, { 2869, 0x9a8b }, { 2877, 0xaab2 }, { 2885, 0x3201 },
+  { 2889, 0xd87a }, { 2898, 0x00c4 }, { 2901, 0xf3e5 }, { 2912, 0x04c3 },
+  /* 0x6600 */
+  { 2917, 0xd44d }, { 2925, 0xa238 }, { 2931, 0xa1a1 }, { 2937, 0x5072 },
+  { 2943, 0x980a }, { 2948, 0x84fc }, { 2956, 0xc152 }, { 2962, 0x44d1 },
+  { 2968, 0x1094 }, { 2972, 0x20c2 }, { 2976, 0x4180 }, { 2979, 0x4210 },
+  { 2982, 0x0000 }, { 2982, 0x3a00 }, { 2986, 0x0240 }, { 2988, 0xd29d },
+  /* 0x6700 */
+  { 2997, 0x2f01 }, { 3003, 0xa8b1 }, { 3010, 0xbd40 }, { 3017, 0x2432 },
+  { 3022, 0xd34d }, { 3031, 0xd04b }, { 3038, 0xa723 }, { 3046, 0xd0ad },
+  { 3054, 0x0a92 }, { 3059, 0x75a1 }, { 3067, 0xadac }, { 3076, 0x01e9 },
+  { 3082, 0x801a }, { 3086, 0x771f }, { 3097, 0x9225 }, { 3103, 0xa01b },
+  /* 0x6800 */
+  { 3109, 0xdfa1 }, { 3119, 0x20ca }, { 3124, 0x0602 }, { 3127, 0x738c },
+  { 3135, 0x577f }, { 3147, 0x003b }, { 3152, 0x0bff }, { 3163, 0x00d0 },
+  { 3166, 0x806a }, { 3171, 0x0088 }, { 3173, 0xa1c4 }, { 3179, 0x0029 },
+  { 3182, 0x2a05 }, { 3187, 0x0524 }, { 3191, 0x4009 }, { 3194, 0x1623 },
+  /* 0x6900 */
+  { 3200, 0x6822 }, { 3205, 0x8005 }, { 3208, 0x2011 }, { 3211, 0xa211 },
+  { 3216, 0x0004 }, { 3217, 0x6490 }, { 3222, 0x4849 }, { 3227, 0x1382 },
+  { 3232, 0x23d5 }, { 3240, 0x1930 }, { 3245, 0x2980 }, { 3249, 0x0892 },
+  { 3253, 0x5402 }, { 3257, 0x8811 }, { 3261, 0x2001 }, { 3263, 0xa004 },
+  /* 0x6a00 */
+  { 3266, 0x0400 }, { 3267, 0x8180 }, { 3270, 0x8502 }, { 3274, 0x6022 },
+  { 3278, 0x0090 }, { 3280, 0x0b01 }, { 3284, 0x0022 }, { 3286, 0x1202 },
+  { 3289, 0x4011 }, { 3292, 0x0083 }, { 3295, 0x1a01 }, { 3299, 0x0000 },
+  { 3299, 0x0000 }, { 3299, 0x0000 }, { 3299, 0x0000 }, { 3299, 0x0000 },
+  /* 0x6b00 */
+  { 3299, 0x0000 }, { 3299, 0x0000 }, { 3299, 0x009f }, { 3305, 0x4684 },
+  { 3310, 0x12c8 }, { 3315, 0x0200 }, { 3316, 0x04fc }, { 3323, 0x1a00 },
+  { 3326, 0x2ede }, { 3336, 0x0c4c }, { 3341, 0x0402 }, { 3343, 0x80b8 },
+  { 3348, 0xa826 }, { 3354, 0x0afc }, { 3362, 0x8c02 }, { 3366, 0x2228 },
+  /* 0x6c00 */
+  { 3370, 0xa0e0 }, { 3375, 0x8f7b }, { 3386, 0xc7d6 }, { 3396, 0x2135 },
+  { 3402, 0x06c7 }, { 3409, 0xf8b1 }, { 3418, 0x0713 }, { 3424, 0x6255 },
+  { 3431, 0x936e }, { 3440, 0x8a19 }, { 3446, 0x6efa }, { 3457, 0xfb0e },
+  { 3467, 0x1630 }, { 3472, 0x48f9 }, { 3480, 0xcd2f }, { 3490, 0x7deb },
+  /* 0x6d00 */
+  { 3502, 0x5892 }, { 3508, 0x4e84 }, { 3514, 0x4ca0 }, { 3519, 0x7a2e },
+  { 3528, 0xedea }, { 3539, 0x561e }, { 3547, 0xc649 }, { 3554, 0x1190 },
+  { 3558, 0x5324 }, { 3564, 0xe83a }, { 3572, 0xcfdb }, { 3584, 0x8124 },
+  { 3588, 0x18f1 }, { 3595, 0x6342 }, { 3601, 0x5853 }, { 3608, 0x1a8a },
+  /* 0x6e00 */
+  { 3614, 0x7420 }, { 3619, 0x24d3 }, { 3626, 0xaa3b }, { 3635, 0x0514 },
+  { 3639, 0x6018 }, { 3643, 0x8958 }, { 3649, 0x4800 }, { 3651, 0xc000 },
+  { 3653, 0x8268 }, { 3658, 0x9101 }, { 3662, 0x84a4 }, { 3667, 0x2cd6 },
+  { 3675, 0x8886 }, { 3680, 0xc4ba }, { 3688, 0x0377 }, { 3696, 0x0210 },
+  /* 0x6f00 */
+  { 3698, 0x8244 }, { 3702, 0x0038 }, { 3705, 0xae11 }, { 3712, 0x404a },
+  { 3716, 0x28c0 }, { 3720, 0x5100 }, { 3723, 0x6044 }, { 3727, 0x1514 },
+  { 3732, 0x7310 }, { 3738, 0x1000 }, { 3739, 0x0082 }, { 3741, 0x0248 },
+  { 3744, 0x0205 }, { 3747, 0x4006 }, { 3750, 0xc003 }, { 3754, 0x0000 },
+  /* 0x7000 */
+  { 3754, 0x0000 }, { 3754, 0x0c02 }, { 3757, 0x0008 }, { 3758, 0x0220 },
+  { 3760, 0x9000 }, { 3762, 0x4000 }, { 3763, 0xb800 }, { 3767, 0xd161 },
+  { 3774, 0x4621 }, { 3779, 0x3274 }, { 3786, 0xf800 }, { 3791, 0x3b8a },
+  { 3799, 0x050f }, { 3805, 0x8b00 }, { 3809, 0xbbd0 }, { 3818, 0x2280 },
+  /* 0x7100 */
+  { 3821, 0x0600 }, { 3823, 0x0769 }, { 3830, 0x8040 }, { 3832, 0x0043 },
+  { 3835, 0x5420 }, { 3839, 0x5000 }, { 3841, 0x41d0 }, { 3846, 0x250c },
+  { 3851, 0x8410 }, { 3854, 0x8310 }, { 3858, 0x1101 }, { 3861, 0x0228 },
+  { 3864, 0x4008 }, { 3866, 0x0030 }, { 3868, 0x40a1 }, { 3872, 0x0200 },
+  /* 0x7200 */
+  { 3873, 0x0040 }, { 3874, 0x2000 }, { 3875, 0x1500 }, { 3878, 0xabe3 },
+  { 3888, 0x3180 }, { 3892, 0xaa44 }, { 3898, 0xc2c6 }, { 3905, 0xc624 },
+  { 3911, 0xac13 }, { 3918, 0x8004 }, { 3920, 0xb000 }, { 3923, 0x03d1 },
+  { 3929, 0x611e }, { 3936, 0x4285 }, { 3941, 0xf303 }, { 3949, 0x1d9f },
+  /* 0x7300 */
+  { 3959, 0x440a }, { 3963, 0x78e8 }, { 3971, 0x5e26 }, { 3979, 0xc392 },
+  { 3986, 0x2000 }, { 3987, 0x0085 }, { 3990, 0xb001 }, { 3994, 0x4000 },
+  { 3995, 0x4a90 }, { 4000, 0x8842 }, { 4004, 0xca04 }, { 4009, 0x0c8d },
+  { 4015, 0xa705 }, { 4022, 0x4203 }, { 4026, 0x22a1 }, { 4031, 0x0004 },
+  /* 0x7400 */
+  { 4032, 0x8668 }, { 4038, 0x0c01 }, { 4041, 0x5564 }, { 4048, 0x1079 },
+  { 4054, 0x0002 }, { 4055, 0xdea0 }, { 4063, 0x2000 }, { 4064, 0x40c1 },
+  { 4068, 0x488b }, { 4074, 0x5001 }, { 4077, 0x0380 }, { 4080, 0x0400 },
+  { 4081, 0x0000 }, { 4081, 0x5004 }, { 4084, 0xc05d }, { 4091, 0x80d0 },
+  /* 0x7500 */
+  { 4095, 0xa010 }, { 4098, 0x970a }, { 4105, 0xbb20 }, { 4112, 0x4daf },
+  { 4122, 0xd921 }, { 4129, 0x1e10 }, { 4134, 0x0460 }, { 4137, 0x8314 },
+  { 4142, 0x8848 }, { 4146, 0xa6d6 }, { 4155, 0xd83b }, { 4164, 0x733f },
+  { 4175, 0x27bc }, { 4184, 0x4974 }, { 4191, 0x0ddc }, { 4199, 0x9213 },
+  /* 0x7600 */
+  { 4205, 0x142b }, { 4211, 0x8ba1 }, { 4218, 0x2e75 }, { 4227, 0xd139 },
+  { 4235, 0x3009 }, { 4239, 0x5050 }, { 4243, 0x8808 }, { 4246, 0x6900 },
+  { 4250, 0x49d4 }, { 4257, 0x024a }, { 4261, 0x4010 }, { 4263, 0x8016 },
+  { 4267, 0xe564 }, { 4275, 0x89d7 }, { 4284, 0xc020 }, { 4287, 0x5316 },
+  /* 0x7700 */
+  { 4294, 0x2b92 }, { 4301, 0x8600 }, { 4304, 0xa345 }, { 4311, 0x15e0 },
+  { 4317, 0x008b }, { 4321, 0x0c03 }, { 4325, 0x196e }, { 4333, 0xe200 },
+  { 4337, 0x7031 }, { 4343, 0x8006 }, { 4346, 0x16a5 }, { 4353, 0xa829 },
+  { 4359, 0x2000 }, { 4360, 0x1880 }, { 4363, 0x7aac }, { 4372, 0xe148 },
+  /* 0x7800 */
+  { 4378, 0x3207 }, { 4384, 0xb5d6 }, { 4394, 0x32e8 }, { 4401, 0x5f91 },
+  { 4410, 0x50a1 }, { 4415, 0x20e5 }, { 4421, 0x7c00 }, { 4426, 0x1080 },
+  { 4428, 0x7280 }, { 4433, 0x9d8a }, { 4441, 0x00aa }, { 4445, 0x421f },
+  { 4452, 0x0e22 }, { 4457, 0x0231 }, { 4461, 0x1100 }, { 4463, 0x0494 },
+  /* 0x7900 */
+  { 4467, 0x0022 }, { 4469, 0x4008 }, { 4471, 0x0010 }, { 4472, 0x5c10 },
+  { 4477, 0x0343 }, { 4482, 0xfcc8 }, { 4491, 0xa1a5 }, { 4498, 0x0580 },
+  { 4501, 0x8433 }, { 4507, 0x0400 }, { 4508, 0x0080 }, { 4509, 0x6e08 },
+  { 4515, 0x2a4b }, { 4522, 0x8126 }, { 4527, 0xaad8 }, { 4535, 0x2901 },
+  /* 0x7a00 */
+  { 4539, 0x684d }, { 4546, 0x4490 }, { 4550, 0x0009 }, { 4552, 0xba88 },
+  { 4559, 0x0040 }, { 4560, 0x0082 }, { 4562, 0x0000 }, { 4562, 0x87d1 },
+  { 4570, 0x215b }, { 4577, 0xb1e6 }, { 4586, 0x3161 }, { 4592, 0x8008 },
+  { 4594, 0x0800 }, { 4595, 0xc240 }, { 4599, 0xa069 }, { 4605, 0xa600 },
+  /* 0x7b00 */
+  { 4609, 0x8d58 }, { 4616, 0x4a32 }, { 4622, 0x5d71 }, { 4631, 0x550a },
+  { 4637, 0x9aa0 }, { 4643, 0x2d57 }, { 4652, 0x4005 }, { 4655, 0x4aa6 },
+  { 4662, 0x2021 }, { 4665, 0x30b1 }, { 4671, 0x3fc6 }, { 4681, 0x0112 },
+  { 4684, 0x10c2 }, { 4688, 0x260a }, { 4693, 0x4462 }, { 4698, 0x5082 },
+  /* 0x7c00 */
+  { 4702, 0x9880 }, { 4706, 0x8040 }, { 4708, 0x04c0 }, { 4711, 0x8100 },
+  { 4713, 0x2003 }, { 4716, 0x0000 }, { 4716, 0x0000 }, { 4716, 0x3818 },
+  { 4721, 0x0200 }, { 4722, 0xf1a6 }, { 4731, 0x4434 }, { 4736, 0x720e },
+  { 4743, 0x35a2 }, { 4750, 0x92e0 }, { 4756, 0x8101 }, { 4759, 0x0900 },
+  /* 0x7d00 */
+  { 4761, 0x0400 }, { 4762, 0x0000 }, { 4762, 0x8885 }, { 4767, 0x0000 },
+  { 4767, 0x0000 }, { 4767, 0x0000 }, { 4767, 0x4000 }, { 4768, 0x0080 },
+  { 4769, 0x0000 }, { 4769, 0x0000 }, { 4769, 0x4040 }, { 4771, 0x0000 },
+  { 4771, 0x0000 }, { 4771, 0x0000 }, { 4771, 0x0000 }, { 4771, 0x0000 },
+  /* 0x7e00 */
+  { 4771, 0x0000 }, { 4771, 0x0000 }, { 4771, 0x0000 }, { 4771, 0x0800 },
+  { 4772, 0x0082 }, { 4774, 0x0000 }, { 4774, 0x0000 }, { 4774, 0x0000 },
+  { 4774, 0x0004 }, { 4775, 0x8800 }, { 4777, 0xbfff }, { 4792, 0xe7ef },
+  { 4805, 0xffff }, { 4821, 0xffbf }, { 4836, 0xefef }, { 4850, 0xfdff },
+  /* 0x7f00 */
+  { 4865, 0xfbff }, { 4880, 0xbffe }, { 4894, 0xffff }, { 4910, 0x057f },
+  { 4919, 0x0034 }, { 4922, 0x85b3 }, { 4930, 0x4706 }, { 4936, 0x4216 },
+  { 4941, 0x5402 }, { 4945, 0xe410 }, { 4950, 0x8092 }, { 4954, 0xb305 },
+  { 4961, 0x5422 }, { 4966, 0x8130 }, { 4970, 0x4263 }, { 4976, 0x180b },
+  /* 0x8000 */
+  { 4981, 0x387b }, { 4990, 0x13f5 }, { 4999, 0x07e5 }, { 5007, 0xa9ea },
+  { 5016, 0x3c4c }, { 5023, 0x0514 }, { 5027, 0x0600 }, { 5029, 0x8002 },
+  { 5031, 0x1ad9 }, { 5039, 0xbd48 }, { 5047, 0xee37 }, { 5058, 0xf496 },
+  { 5067, 0x705f }, { 5076, 0x7ec0 }, { 5084, 0xbfb2 }, { 5095, 0x355f },
+  /* 0x8100 */
+  { 5105, 0xe644 }, { 5112, 0x455f }, { 5121, 0x9000 }, { 5123, 0x4146 },
+  { 5128, 0x1d40 }, { 5133, 0x063b }, { 5140, 0x62a1 }, { 5146, 0xfe13 },
+  { 5156, 0x8505 }, { 5161, 0x3902 }, { 5166, 0x0548 }, { 5170, 0x0c08 },
+  { 5173, 0x144f }, { 5180, 0x0000 }, { 5180, 0x3488 }, { 5185, 0x5818 },
+  /* 0x8200 */
+  { 5190, 0x3077 }, { 5198, 0xd815 }, { 5205, 0xbd0e }, { 5214, 0x4bfb },
+  { 5225, 0x8a90 }, { 5230, 0x8500 }, { 5233, 0xc100 }, { 5236, 0xe61d },
+  { 5245, 0xed14 }, { 5253, 0xb386 }, { 5261, 0xff72 }, { 5273, 0x639b },
+  { 5282, 0xfd92 }, { 5292, 0xd9be }, { 5303, 0x887b }, { 5311, 0x0a92 },
+  /* 0x8300 */
+  { 5316, 0xd3fe }, { 5328, 0x1cb2 }, { 5335, 0xb980 }, { 5341, 0x177a },
+  { 5350, 0x82c9 }, { 5356, 0xdc17 }, { 5365, 0xfffb }, { 5380, 0x3980 },
+  { 5385, 0x4260 }, { 5389, 0x590c }, { 5395, 0x0f01 }, { 5400, 0x37df },
+  { 5412, 0x94a3 }, { 5419, 0xb150 }, { 5425, 0x0623 }, { 5430, 0x2307 },
+  /* 0x8400 */
+  { 5436, 0xf85a }, { 5445, 0x3102 }, { 5449, 0x01f0 }, { 5454, 0x3102 },
+  { 5458, 0x0040 }, { 5459, 0x1e82 }, { 5465, 0x3a0a }, { 5471, 0x056a },
+  { 5477, 0x5b84 }, { 5484, 0x1280 }, { 5487, 0x8002 }, { 5489, 0xa714 },
+  { 5496, 0x2612 }, { 5501, 0xa04b }, { 5507, 0x1069 }, { 5512, 0x9001 },
+  /* 0x8500 */
+  { 5515, 0x1000 }, { 5516, 0x848a }, { 5521, 0x1802 }, { 5524, 0x3f80 },
+  { 5531, 0x0708 }, { 5535, 0x4240 }, { 5538, 0x0110 }, { 5540, 0x4e14 },
+  { 5546, 0x80b0 }, { 5550, 0x1800 }, { 5552, 0xc510 }, { 5557, 0x0281 },
+  { 5560, 0x8202 }, { 5563, 0x1029 }, { 5567, 0x0210 }, { 5569, 0x8800 },
+  /* 0x8600 */
+  { 5571, 0x0020 }, { 5572, 0x0042 }, { 5574, 0x0280 }, { 5576, 0x1100 },
+  { 5578, 0xe000 }, { 5581, 0x4413 }, { 5586, 0x5804 }, { 5590, 0xfe02 },
+  { 5598, 0x3c07 }, { 5605, 0x3028 }, { 5609, 0x9798 }, { 5617, 0x0473 },
+  { 5623, 0xced1 }, { 5632, 0xcb13 }, { 5640, 0x6210 }, { 5644, 0x431f },
+  /* 0x8700 */
+  { 5652, 0x278d }, { 5660, 0x55ac }, { 5668, 0x422e }, { 5674, 0xc892 },
+  { 5680, 0x5380 }, { 5685, 0x0288 }, { 5688, 0x4039 }, { 5693, 0x7851 },
+  { 5700, 0x292c }, { 5706, 0x8088 }, { 5709, 0xb900 }, { 5714, 0x2428 },
+  { 5718, 0x0c41 }, { 5722, 0x080e }, { 5726, 0x4421 }, { 5730, 0x4200 },
+  /* 0x8800 */
+  { 5732, 0x0408 }, { 5734, 0x0868 }, { 5738, 0x0006 }, { 5740, 0x1204 },
+  { 5743, 0x3031 }, { 5748, 0x0290 }, { 5751, 0x5b3e }, { 5761, 0xe085 },
+  { 5767, 0x2936 }, { 5774, 0x1044 }, { 5777, 0x2814 }, { 5781, 0x1082 },
+  { 5784, 0x4266 }, { 5790, 0x8334 }, { 5796, 0x013c }, { 5801, 0x531b },
+  /* 0x8900 */
+  { 5809, 0x0404 }, { 5811, 0x0e0d }, { 5817, 0x0c22 }, { 5821, 0x0051 },
+  { 5824, 0x0012 }, { 5826, 0xc000 }, { 5828, 0x0040 }, { 5829, 0x8800 },
+  { 5831, 0x004a }, { 5834, 0x0000 }, { 5834, 0x0000 }, { 5834, 0x0000 },
+  { 5834, 0xdff6 }, { 5847, 0x5447 }, { 5854, 0x8868 }, { 5859, 0x0008 },
+  /* 0x8a00 */
+  { 5860, 0x0081 }, { 5862, 0x0000 }, { 5862, 0x0000 }, { 5862, 0x4000 },
+  { 5863, 0x0100 }, { 5864, 0x0000 }, { 5864, 0x0000 }, { 5864, 0x0200 },
+  { 5865, 0x0600 }, { 5867, 0x0008 }, { 5868, 0x0000 }, { 5868, 0x0000 },
+  { 5868, 0x0000 }, { 5868, 0x0000 }, { 5868, 0x0000 }, { 5868, 0x0000 },
+  /* 0x8b00 */
+  { 5868, 0x0080 }, { 5869, 0x0000 }, { 5869, 0x0040 }, { 5870, 0x0000 },
+  { 5870, 0x0000 }, { 5870, 0x0000 }, { 5870, 0x1040 }, { 5872, 0x0000 },
+  { 5872, 0x0000 }, { 5872, 0x0000 }, { 5872, 0xefff }, { 5887, 0xf7fd },
+  { 5901, 0xff7f }, { 5916, 0xfffe }, { 5931, 0xfbff }, { 5946, 0xffff },
+  /* 0x8c00 */
+  { 5962, 0xfdff }, { 5977, 0xbfff }, { 5992, 0xffff }, { 6008, 0x00ff },
+  { 6016, 0x12c2 }, { 6021, 0x0420 }, { 6023, 0x0c06 }, { 6027, 0x0708 },
+  { 6031, 0x1624 }, { 6036, 0x0110 }, { 6038, 0x0000 }, { 6038, 0x0000 },
+  { 6038, 0x0000 }, { 6038, 0x0000 }, { 6038, 0x0000 }, { 6038, 0x0000 },
+  /* 0x8d00 */
+  { 6038, 0x0000 }, { 6038, 0xe000 }, { 6041, 0xfffe }, { 6056, 0xffff },
+  { 6072, 0xffff }, { 6088, 0x7f79 }, { 6100, 0x28df }, { 6109, 0x00f9 },
+  { 6115, 0x0c32 }, { 6120, 0x8012 }, { 6123, 0x0008 }, { 6124, 0xd53a },
+  { 6133, 0xd858 }, { 6140, 0xecc2 }, { 6148, 0x9d18 }, { 6155, 0x2fa8 },
+  /* 0x8e00 */
+  { 6163, 0x9620 }, { 6168, 0xe010 }, { 6172, 0xd60c }, { 6179, 0x2622 },
+  { 6184, 0x0f97 }, { 6193, 0x0206 }, { 6196, 0xb240 }, { 6201, 0x9055 },
+  { 6207, 0x80a2 }, { 6211, 0x5011 }, { 6215, 0x9800 }, { 6218, 0x0404 },
+  { 6220, 0x4000 }, { 6221, 0x0000 }, { 6221, 0x0000 }, { 6221, 0x0000 },
+  /* 0x8f00 */
+  { 6221, 0x0000 }, { 6221, 0x0000 }, { 6221, 0x0000 }, { 6221, 0x0000 },
+  { 6221, 0x0000 }, { 6221, 0x0000 }, { 6221, 0xfbc0 }, { 6230, 0xffff },
+  { 6246, 0xeffe }, { 6260, 0xdffb }, { 6274, 0x0b08 }, { 6278, 0x6243 },
+  { 6284, 0x41b6 }, { 6291, 0xfb3b }, { 6303, 0x6f74 }, { 6313, 0x2389 },
+  /* 0x9000 */
+  { 6319, 0xae7f }, { 6331, 0xecd7 }, { 6342, 0xe047 }, { 6349, 0x5960 },
+  { 6355, 0xa096 }, { 6361, 0x098f }, { 6368, 0x612c }, { 6374, 0xa030 },
+  { 6378, 0x090d }, { 6383, 0x2aaa }, { 6390, 0xd44e }, { 6398, 0x4f7b },
+  { 6409, 0xc4b2 }, { 6416, 0x388b }, { 6423, 0xa9c6 }, { 6431, 0x6110 },
+  /* 0x9100 */
+  { 6435, 0x0014 }, { 6437, 0x4200 }, { 6439, 0x800c }, { 6442, 0x0202 },
+  { 6444, 0xfe48 }, { 6453, 0x6485 }, { 6459, 0xd63e }, { 6469, 0xe3f7 },
+  { 6481, 0x3aa0 }, { 6487, 0x0c07 }, { 6492, 0xe40c }, { 6498, 0x0430 },
+  { 6501, 0xf680 }, { 6508, 0x1002 }, { 6510, 0x0000 }, { 6510, 0x0000 },
+  /* 0x9200 */
+  { 6510, 0x0000 }, { 6510, 0x0000 }, { 6510, 0x0000 }, { 6510, 0x0000 },
+  { 6510, 0x0000 }, { 6510, 0x0000 }, { 6510, 0x0000 }, { 6510, 0x0010 },
+  { 6511, 0x4000 }, { 6512, 0x0000 }, { 6512, 0x4000 }, { 6513, 0x0000 },
+  { 6513, 0x0100 }, { 6514, 0x0000 }, { 6514, 0x0000 }, { 6514, 0x0000 },
+  /* 0x9300 */
+  { 6514, 0x0000 }, { 6514, 0x0000 }, { 6514, 0x0000 }, { 6514, 0x4000 },
+  { 6515, 0x0000 }, { 6515, 0x0000 }, { 6515, 0x0400 }, { 6516, 0x0000 },
+  { 6516, 0x8000 }, { 6517, 0x0000 }, { 6517, 0x0000 }, { 6517, 0x0000 },
+  { 6517, 0x0400 }, { 6518, 0x0040 }, { 6519, 0x0000 }, { 6519, 0x0000 },
+  /* 0x9400 */
+  { 6519, 0x0000 }, { 6519, 0x0000 }, { 6519, 0x0000 }, { 6519, 0x4000 },
+  { 6520, 0x0000 }, { 6520, 0x0000 }, { 6520, 0x0800 }, { 6521, 0x0000 },
+  { 6521, 0xffe0 }, { 6532, 0xfebd }, { 6545, 0xffff }, { 6561, 0xffff },
+  { 6577, 0x7f7f }, { 6591, 0xfbe7 }, { 6604, 0xffbf }, { 6619, 0xf7ff },
+  /* 0x9500 */
+  { 6634, 0xffff }, { 6650, 0xefff }, { 6665, 0xff7e }, { 6679, 0xdff7 },
+  { 6693, 0xf6f7 }, { 6706, 0xfbdf }, { 6720, 0xbffe }, { 6734, 0x804f },
+  { 6740, 0x0000 }, { 6740, 0x0000 }, { 6740, 0x0000 }, { 6740, 0x0000 },
+  { 6740, 0x0000 }, { 6740, 0x0000 }, { 6740, 0xef00 }, { 6747, 0x7fff },
+  /* 0x9600 */
+  { 6762, 0xff7f }, { 6777, 0xb6f7 }, { 6789, 0x4406 }, { 6793, 0xb87e },
+  { 6803, 0x3bf5 }, { 6814, 0x8831 }, { 6819, 0x1796 }, { 6827, 0x00f4 },
+  { 6832, 0xa960 }, { 6838, 0x1391 }, { 6844, 0x0080 }, { 6845, 0x7249 },
+  { 6852, 0xf2f3 }, { 6863, 0x0024 }, { 6865, 0x8701 }, { 6870, 0x42c8 },
+  /* 0x9700 */
+  { 6875, 0xe3d3 }, { 6885, 0x5048 }, { 6889, 0x2400 }, { 6891, 0x4305 },
+  { 6896, 0x0000 }, { 6896, 0x4a4c }, { 6902, 0x0227 }, { 6907, 0x1058 },
+  { 6911, 0x2820 }, { 6914, 0x0116 }, { 6918, 0xa809 }, { 6923, 0x0014 },
+  { 6925, 0x0000 }, { 6925, 0x0000 }, { 6925, 0x3ec0 }, { 6932, 0x0068 },
+  /* 0x9800 */
+  { 6935, 0x0000 }, { 6935, 0x0000 }, { 6935, 0x0000 }, { 6935, 0x0000 },
+  { 6935, 0x0000 }, { 6935, 0x0000 }, { 6935, 0x0000 }, { 6935, 0xffe0 },
+  { 6946, 0xb7ff }, { 6960, 0xfddb }, { 6973, 0x00f7 }, { 6980, 0x0000 },
+  { 6980, 0x4000 }, { 6981, 0xc72e }, { 6990, 0x0180 }, { 6992, 0x0000 },
+  /* 0x9900 */
+  { 6992, 0x2000 }, { 6993, 0x0001 }, { 6994, 0x4000 }, { 6995, 0x0000 },
+  { 6995, 0x0000 }, { 6995, 0x0030 }, { 6997, 0xffa8 }, { 7008, 0xb4f7 },
+  { 7019, 0xadf3 }, { 7030, 0x03ff }, { 7040, 0x0120 }, { 7042, 0x0000 },
+  { 7042, 0x0000 }, { 7042, 0x0000 }, { 7042, 0x0000 }, { 7042, 0x0000 },
+  /* 0x9a00 */
+  { 7042, 0x0000 }, { 7042, 0x0000 }, { 7042, 0x0000 }, { 7042, 0x0000 },
+  { 7042, 0x0000 }, { 7042, 0x0000 }, { 7042, 0xf000 }, { 7046, 0xfffb },
+  { 7061, 0x9df7 }, { 7073, 0xfdcf }, { 7086, 0x01bf }, { 7094, 0x15c3 },
+  { 7101, 0x1827 }, { 7107, 0x810a }, { 7111, 0xa842 }, { 7116, 0x0a00 },
+  /* 0x9b00 */
+  { 7118, 0x8108 }, { 7121, 0x8008 }, { 7123, 0x8008 }, { 7125, 0x1804 },
+  { 7128, 0xa3be }, { 7138, 0x0012 }, { 7140, 0x0000 }, { 7140, 0x0000 },
+  { 7140, 0x0000 }, { 7140, 0x0000 }, { 7140, 0x0000 }, { 7140, 0x0000 },
+  { 7140, 0x0000 }, { 7140, 0x0000 }, { 7140, 0x0000 }, { 7140, 0x0000 },
+  /* 0x9c00 */
+  { 7140, 0x0000 }, { 7140, 0x0000 }, { 7140, 0x0000 }, { 7140, 0x0000 },
+  { 7140, 0x0000 }, { 7140, 0x0000 }, { 7140, 0x0000 }, { 7140, 0x9000 },
+  { 7142, 0x69e6 }, { 7151, 0xdc37 }, { 7161, 0x6bff }, { 7174, 0x3dff },
+  { 7187, 0xfcf8 }, { 7198, 0xf3f9 }, { 7210, 0x0004 },
+};
+static const Summary16 gb2312_uni2indx_page9e[27] = {
+  /* 0x9e00 */
+  { 7211, 0x0000 }, { 7211, 0x8000 }, { 7212, 0xbf6f }, { 7225, 0xe7ee },
+  { 7237, 0xdffe }, { 7251, 0x5da2 }, { 7259, 0x3fd8 }, { 7269, 0xc00b },
+  { 7274, 0x0984 }, { 7278, 0xa00c }, { 7282, 0x0040 }, { 7283, 0x6910 },
+  { 7288, 0xe210 }, { 7293, 0xb912 }, { 7300, 0x86a5 }, { 7307, 0x5a00 },
+  /* 0x9f00 */
+  { 7311, 0x6800 }, { 7314, 0x0289 }, { 7318, 0x9005 }, { 7322, 0x6a80 },
+  { 7327, 0x0010 }, { 7328, 0x0003 }, { 7330, 0x0000 }, { 7330, 0x8000 },
+  { 7331, 0x1ff9 }, { 7342, 0x8e00 }, { 7346, 0x0001 },
+};
+static const Summary16 gb2312_uni2indx_pageff[15] = {
+  /* 0xff00 */
+  { 7347, 0xfffe }, { 7362, 0xffff }, { 7378, 0xffff }, { 7394, 0xffff },
+  { 7410, 0xffff }, { 7426, 0x7fff }, { 7441, 0x0000 }, { 7441, 0x0000 },
+  { 7441, 0x0000 }, { 7441, 0x0000 }, { 7441, 0x0000 }, { 7441, 0x0000 },
+  { 7441, 0x0000 }, { 7441, 0x0000 }, { 7441, 0x002b },
+};
+
+INTERNAL int gb2312_wctomb_zint(unsigned int* r, unsigned int wc) {
+    const Summary16 *summary = NULL;
+    if (wc < 0x0460) {
+        if (wc == 0x00b7) { /* ZINT: Patched to duplicate map to 0xA1A4 */
+            *r = 0xA1A4;
+            return 2;
+        }
+        summary = &gb2312_uni2indx_page00[(wc>>4)];
+    } else if (wc >= 0x2000 && wc < 0x2650) {
+        if (wc == 0x2014) { /* ZINT: Patched to duplicate map to 0xA1AA */
+            *r = 0xA1AA;
+            return 2;
+        }
+        summary = &gb2312_uni2indx_page20[(wc>>4)-0x200];
+    } else if (wc >= 0x3000 && wc < 0x3230) {
+        summary = &gb2312_uni2indx_page30[(wc>>4)-0x300];
+    } else if (wc >= 0x4e00 && wc < 0x9cf0) {
+        summary = &gb2312_uni2indx_page4e[(wc>>4)-0x4e0];
+    } else if (wc >= 0x9e00 && wc < 0x9fb0) {
+        summary = &gb2312_uni2indx_page9e[(wc>>4)-0x9e0];
+    } else if (wc >= 0xff00 && wc < 0xfff0) {
+        summary = &gb2312_uni2indx_pageff[(wc>>4)-0xff0];
+    }
+    if (summary) {
+        unsigned short used = summary->used;
+        unsigned int i = wc & 0x0f;
+        if (used & ((unsigned short) 1 << i)) {
+            /* Keep in 'used' only the bits 0..i-1. */
+            used &= ((unsigned short) 1 << i) - 1;
+            /* Add 'summary->indx' and the number of bits set in 'used'. */
+            used = (used & 0x5555) + ((used & 0xaaaa) >> 1);
+            used = (used & 0x3333) + ((used & 0xcccc) >> 2);
+            used = (used & 0x0f0f) + ((used & 0xf0f0) >> 4);
+            used = (used & 0x00ff) + (used >> 8);
+            *r = gb2312_2charset[summary->indx + used];
+            return 2;
+        }
+    }
+    return 0;
+}
+
+/* Convert UTF-8 string to GB 2312 (EUC-CN) and place in array of ints */
+INTERNAL int gb2312_utf8tomb(struct zint_symbol *symbol, const unsigned char source[], size_t* p_length, unsigned int* gbdata) {
+    int error_number;
+    unsigned int i, length;
+#ifndef _MSC_VER
+    unsigned int utfdata[*p_length + 1];
+#else
+    unsigned int* utfdata = (unsigned int*) _alloca((*p_length + 1) * sizeof(unsigned int));
+#endif
+
+    error_number = utf8_to_unicode(symbol, source, utfdata, p_length, 1 /*disallow_4byte*/);
+    if (error_number != 0) {
+        return error_number;
+    }
+
+    for (i = 0, length = *p_length; i < length; i++) {
+        if (utfdata[i] < 0x80) {
+            gbdata[i] = utfdata[i];
+        } else {
+            if (!gb2312_wctomb_zint(gbdata + i, utfdata[i])) {
+                strcpy(symbol->errtxt, "810: Invalid character in input data");
+                return ZINT_ERROR_INVALID_DATA;
+            }
+        }
+    }
+
+    return 0;
+}
+
+/* Convert UTF-8 string to single byte ECI and place in array of ints */
+INTERNAL int gb2312_utf8tosb(int eci, const unsigned char source[], size_t* p_length, unsigned int* gbdata, int full_multibyte) {
+    int error_number;
+#ifndef _MSC_VER
+    unsigned char single_byte[*p_length + 1];
+#else
+    unsigned char* single_byte = (unsigned char*) _alloca(*p_length + 1);
+#endif
+
+    error_number = utf_to_eci(eci, source, single_byte, p_length);
+    if (error_number != 0) {
+        /* Note not setting `symbol->errtxt`, up to caller */
+        return error_number;
+    }
+
+    gb2312_cpy(single_byte, p_length, gbdata, full_multibyte);
+
+    return 0;
+}
+
+/* If `full_multibyte` set, copy byte input stream to array of ints, putting double-bytes that match GRIDMATRIX Chinese mode in a single entry.
+ * If `full_multibyte` not set, do a straight copy */
+INTERNAL void gb2312_cpy(const unsigned char source[], size_t* p_length, unsigned int* gbdata, int full_multibyte) {
+    unsigned int i, j, length;
+    unsigned char c1, c2;
+
+    if (full_multibyte) {
+        for (i = 0, j = 0, length = *p_length; i < length; i++, j++) {
+            if (length - i >= 2) {
+                c1 = source[i];
+                c2 = source[i + 1];
+                if (((c1 >= 0xA1 && c1 <= 0xA9) || (c1 >= 0xB0 && c1 <= 0xF7)) && c2 >= 0xA1 && c2 <= 0xFE) {
+                    /* This may or may not be valid GB 2312 (EUC-CN), but don't care as long as it can be encoded in GRIDMATRIX Chinese mode */
+                    gbdata[j] = (c1 << 8) | c2;
+                    i++;
+                } else {
+                    gbdata[j] = c1;
+                }
+            } else {
+                gbdata[j] = source[i];
+            }
+        }
+        *p_length = j;
+    } else {
+        /* Straight copy */
+        for (i = 0, length = *p_length; i < length; i++) {
+            gbdata[i] = source[i];
+        }
+    }
+}
index 572ff3b..b3ca91b 100644 (file)
@@ -1,7 +1,7 @@
-/*  gb2312.h - Unicode to GB 2312-1980 lookup table
+/*  gb2312.h - Unicode to GB 2312-1980 (EUC-CN)
 
     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
     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 : */
 
-static const unsigned long int gb2312_lookup[] = {
-       0x00A4, 0xA1E8,
-       0x00A7, 0xA1EC,
-       0x00A8, 0xA1A7,
-       0x00B0, 0xA1E3,
-       0x00B1, 0xA1C0,
-       0x00B7, 0xA1A4,
-       0x00D7, 0xA1C1,
-       0x00E0, 0xA8A4,
-       0x00E1, 0xA8A2,
-       0x00E8, 0xA8A8,
-       0x00E9, 0xA8A6,
-       0x00EA, 0xA8BA,
-       0x00EC, 0xA8AC,
-       0x00ED, 0xA8AA,
-       0x00F2, 0xA8B0,
-       0x00F3, 0xA8AE,
-       0x00F7, 0xA1C2,
-       0x00F9, 0xA8B4,
-       0x00FA, 0xA8B2,
-       0x00FC, 0xA8B9,
-       0x0101, 0xA8A1,
-       0x0113, 0xA8A5,
-       0x011B, 0xA8A7,
-       0x012B, 0xA8A9,
-       0x014D, 0xA8AD,
-       0x016B, 0xA8B1,
-       0x01CE, 0xA8A3,
-       0x01D0, 0xA8AB,
-       0x01D2, 0xA8AF,
-       0x01D4, 0xA8B3,
-       0x01D6, 0xA8B5,
-       0x01D8, 0xA8B6,
-       0x01DA, 0xA8B7,
-       0x01DC, 0xA8B8,
-       0x02C7, 0xA1A6,
-       0x02C9, 0xA1A5,
-       0x0391, 0xA6A1,
-       0x0392, 0xA6A2,
-       0x0393, 0xA6A3,
-       0x0394, 0xA6A4,
-       0x0395, 0xA6A5,
-       0x0396, 0xA6A6,
-       0x0397, 0xA6A7,
-       0x0398, 0xA6A8,
-       0x0399, 0xA6A9,
-       0x039A, 0xA6AA,
-       0x039B, 0xA6AB,
-       0x039C, 0xA6AC,
-       0x039D, 0xA6AD,
-       0x039E, 0xA6AE,
-       0x039F, 0xA6AF,
-       0x03A0, 0xA6B0,
-       0x03A1, 0xA6B1,
-       0x03A3, 0xA6B2,
-       0x03A4, 0xA6B3,
-       0x03A5, 0xA6B4,
-       0x03A6, 0xA6B5,
-       0x03A7, 0xA6B6,
-       0x03A8, 0xA6B7,
-       0x03A9, 0xA6B8,
-       0x03B1, 0xA6C1,
-       0x03B2, 0xA6C2,
-       0x03B3, 0xA6C3,
-       0x03B4, 0xA6C4,
-       0x03B5, 0xA6C5,
-       0x03B6, 0xA6C6,
-       0x03B7, 0xA6C7,
-       0x03B8, 0xA6C8,
-       0x03B9, 0xA6C9,
-       0x03BA, 0xA6CA,
-       0x03BB, 0xA6CB,
-       0x03BC, 0xA6CC,
-       0x03BD, 0xA6CD,
-       0x03BE, 0xA6CE,
-       0x03BF, 0xA6CF,
-       0x03C0, 0xA6D0,
-       0x03C1, 0xA6D1,
-       0x03C3, 0xA6D2,
-       0x03C4, 0xA6D3,
-       0x03C5, 0xA6D4,
-       0x03C6, 0xA6D5,
-       0x03C7, 0xA6D6,
-       0x03C8, 0xA6D7,
-       0x03C9, 0xA6D8,
-       0x0401, 0xA7A7,
-       0x0410, 0xA7A1,
-       0x0411, 0xA7A2,
-       0x0412, 0xA7A3,
-       0x0413, 0xA7A4,
-       0x0414, 0xA7A5,
-       0x0415, 0xA7A6,
-       0x0416, 0xA7A8,
-       0x0417, 0xA7A9,
-       0x0418, 0xA7AA,
-       0x0419, 0xA7AB,
-       0x041A, 0xA7AC,
-       0x041B, 0xA7AD,
-       0x041C, 0xA7AE,
-       0x041D, 0xA7AF,
-       0x041E, 0xA7B0,
-       0x041F, 0xA7B1,
-       0x0420, 0xA7B2,
-       0x0421, 0xA7B3,
-       0x0422, 0xA7B4,
-       0x0423, 0xA7B5,
-       0x0424, 0xA7B6,
-       0x0425, 0xA7B7,
-       0x0426, 0xA7B8,
-       0x0427, 0xA7B9,
-       0x0428, 0xA7BA,
-       0x0429, 0xA7BB,
-       0x042A, 0xA7BC,
-       0x042B, 0xA7BD,
-       0x042C, 0xA7BE,
-       0x042D, 0xA7BF,
-       0x042E, 0xA7C0,
-       0x042F, 0xA7C1,
-       0x0430, 0xA7D1,
-       0x0431, 0xA7D2,
-       0x0432, 0xA7D3,
-       0x0433, 0xA7D4,
-       0x0434, 0xA7D5,
-       0x0435, 0xA7D6,
-       0x0436, 0xA7D8,
-       0x0437, 0xA7D9,
-       0x0438, 0xA7DA,
-       0x0439, 0xA7DB,
-       0x043A, 0xA7DC,
-       0x043B, 0xA7DD,
-       0x043C, 0xA7DE,
-       0x043D, 0xA7DF,
-       0x043E, 0xA7E0,
-       0x043F, 0xA7E1,
-       0x0440, 0xA7E2,
-       0x0441, 0xA7E3,
-       0x0442, 0xA7E4,
-       0x0443, 0xA7E5,
-       0x0444, 0xA7E6,
-       0x0445, 0xA7E7,
-       0x0446, 0xA7E8,
-       0x0447, 0xA7E9,
-       0x0448, 0xA7EA,
-       0x0449, 0xA7EB,
-       0x044A, 0xA7EC,
-       0x044B, 0xA7ED,
-       0x044C, 0xA7EE,
-       0x044D, 0xA7EF,
-       0x044E, 0xA7F0,
-       0x044F, 0xA7F1,
-       0x0451, 0xA7D7,
-       0x2014, 0xA1AA,
-       0x2016, 0xA1AC,
-       0x2018, 0xA1AE,
-       0x2019, 0xA1AF,
-       0x201C, 0xA1B0,
-       0x201D, 0xA1B1,
-       0x2026, 0xA1AD,
-       0x2030, 0xA1EB,
-       0x2032, 0xA1E4,
-       0x2033, 0xA1E5,
-       0x203B, 0xA1F9,
-       0x2103, 0xA1E6,
-       0x2116, 0xA1ED,
-       0x2160, 0xA2F1,
-       0x2161, 0xA2F2,
-       0x2162, 0xA2F3,
-       0x2163, 0xA2F4,
-       0x2164, 0xA2F5,
-       0x2165, 0xA2F6,
-       0x2166, 0xA2F7,
-       0x2167, 0xA2F8,
-       0x2168, 0xA2F9,
-       0x2169, 0xA2FA,
-       0x216A, 0xA2FB,
-       0x216B, 0xA2FC,
-       0x2190, 0xA1FB,
-       0x2191, 0xA1FC,
-       0x2192, 0xA1FA,
-       0x2193, 0xA1FD,
-       0x2208, 0xA1CA,
-       0x220F, 0xA1C7,
-       0x2211, 0xA1C6,
-       0x221A, 0xA1CC,
-       0x221D, 0xA1D8,
-       0x221E, 0xA1DE,
-       0x2220, 0xA1CF,
-       0x2225, 0xA1CE,
-       0x2227, 0xA1C4,
-       0x2228, 0xA1C5,
-       0x2229, 0xA1C9,
-       0x222A, 0xA1C8,
-       0x222B, 0xA1D2,
-       0x222E, 0xA1D3,
-       0x2234, 0xA1E0,
-       0x2235, 0xA1DF,
-       0x2236, 0xA1C3,
-       0x2237, 0xA1CB,
-       0x223D, 0xA1D7,
-       0x2248, 0xA1D6,
-       0x224C, 0xA1D5,
-       0x2260, 0xA1D9,
-       0x2261, 0xA1D4,
-       0x2264, 0xA1DC,
-       0x2265, 0xA1DD,
-       0x226E, 0xA1DA,
-       0x226F, 0xA1DB,
-       0x2299, 0xA1D1,
-       0x22A5, 0xA1CD,
-       0x2312, 0xA1D0,
-       0x2460, 0xA2D9,
-       0x2461, 0xA2DA,
-       0x2462, 0xA2DB,
-       0x2463, 0xA2DC,
-       0x2464, 0xA2DD,
-       0x2465, 0xA2DE,
-       0x2466, 0xA2DF,
-       0x2467, 0xA2E0,
-       0x2468, 0xA2E1,
-       0x2469, 0xA2E2,
-       0x2474, 0xA2C5,
-       0x2475, 0xA2C6,
-       0x2476, 0xA2C7,
-       0x2477, 0xA2C8,
-       0x2478, 0xA2C9,
-       0x2479, 0xA2CA,
-       0x247A, 0xA2CB,
-       0x247B, 0xA2CC,
-       0x247C, 0xA2CD,
-       0x247D, 0xA2CE,
-       0x247E, 0xA2CF,
-       0x247F, 0xA2D0,
-       0x2480, 0xA2D1,
-       0x2481, 0xA2D2,
-       0x2482, 0xA2D3,
-       0x2483, 0xA2D4,
-       0x2484, 0xA2D5,
-       0x2485, 0xA2D6,
-       0x2486, 0xA2D7,
-       0x2487, 0xA2D8,
-       0x2488, 0xA2B1,
-       0x2489, 0xA2B2,
-       0x248A, 0xA2B3,
-       0x248B, 0xA2B4,
-       0x248C, 0xA2B5,
-       0x248D, 0xA2B6,
-       0x248E, 0xA2B7,
-       0x248F, 0xA2B8,
-       0x2490, 0xA2B9,
-       0x2491, 0xA2BA,
-       0x2492, 0xA2BB,
-       0x2493, 0xA2BC,
-       0x2494, 0xA2BD,
-       0x2495, 0xA2BE,
-       0x2496, 0xA2BF,
-       0x2497, 0xA2C0,
-       0x2498, 0xA2C1,
-       0x2499, 0xA2C2,
-       0x249A, 0xA2C3,
-       0x249B, 0xA2C4,
-       0x2500, 0xA9A4,
-       0x2501, 0xA9A5,
-       0x2502, 0xA9A6,
-       0x2503, 0xA9A7,
-       0x2504, 0xA9A8,
-       0x2505, 0xA9A9,
-       0x2506, 0xA9AA,
-       0x2507, 0xA9AB,
-       0x2508, 0xA9AC,
-       0x2509, 0xA9AD,
-       0x250A, 0xA9AE,
-       0x250B, 0xA9AF,
-       0x250C, 0xA9B0,
-       0x250D, 0xA9B1,
-       0x250E, 0xA9B2,
-       0x250F, 0xA9B3,
-       0x2510, 0xA9B4,
-       0x2511, 0xA9B5,
-       0x2512, 0xA9B6,
-       0x2513, 0xA9B7,
-       0x2514, 0xA9B8,
-       0x2515, 0xA9B9,
-       0x2516, 0xA9BA,
-       0x2517, 0xA9BB,
-       0x2518, 0xA9BC,
-       0x2519, 0xA9BD,
-       0x251A, 0xA9BE,
-       0x251B, 0xA9BF,
-       0x251C, 0xA9C0,
-       0x251D, 0xA9C1,
-       0x251E, 0xA9C2,
-       0x251F, 0xA9C3,
-       0x2520, 0xA9C4,
-       0x2521, 0xA9C5,
-       0x2522, 0xA9C6,
-       0x2523, 0xA9C7,
-       0x2524, 0xA9C8,
-       0x2525, 0xA9C9,
-       0x2526, 0xA9CA,
-       0x2527, 0xA9CB,
-       0x2528, 0xA9CC,
-       0x2529, 0xA9CD,
-       0x252A, 0xA9CE,
-       0x252B, 0xA9CF,
-       0x252C, 0xA9D0,
-       0x252D, 0xA9D1,
-       0x252E, 0xA9D2,
-       0x252F, 0xA9D3,
-       0x2530, 0xA9D4,
-       0x2531, 0xA9D5,
-       0x2532, 0xA9D6,
-       0x2533, 0xA9D7,
-       0x2534, 0xA9D8,
-       0x2535, 0xA9D9,
-       0x2536, 0xA9DA,
-       0x2537, 0xA9DB,
-       0x2538, 0xA9DC,
-       0x2539, 0xA9DD,
-       0x253A, 0xA9DE,
-       0x253B, 0xA9DF,
-       0x253C, 0xA9E0,
-       0x253D, 0xA9E1,
-       0x253E, 0xA9E2,
-       0x253F, 0xA9E3,
-       0x2540, 0xA9E4,
-       0x2541, 0xA9E5,
-       0x2542, 0xA9E6,
-       0x2543, 0xA9E7,
-       0x2544, 0xA9E8,
-       0x2545, 0xA9E9,
-       0x2546, 0xA9EA,
-       0x2547, 0xA9EB,
-       0x2548, 0xA9EC,
-       0x2549, 0xA9ED,
-       0x254A, 0xA9EE,
-       0x254B, 0xA9EF,
-       0x25A0, 0xA1F6,
-       0x25A1, 0xA1F5,
-       0x25B2, 0xA1F8,
-       0x25B3, 0xA1F7,
-       0x25C6, 0xA1F4,
-       0x25C7, 0xA1F3,
-       0x25CB, 0xA1F0,
-       0x25CE, 0xA1F2,
-       0x25CF, 0xA1F1,
-       0x2605, 0xA1EF,
-       0x2606, 0xA1EE,
-       0x2640, 0xA1E2,
-       0x2642, 0xA1E1,
-       0x3000, 0xA1A1,
-       0x3001, 0xA1A2,
-       0x3002, 0xA1A3,
-       0x3003, 0xA1A8,
-       0x3005, 0xA1A9,
-       0x3008, 0xA1B4,
-       0x3009, 0xA1B5,
-       0x300A, 0xA1B6,
-       0x300B, 0xA1B7,
-       0x300C, 0xA1B8,
-       0x300D, 0xA1B9,
-       0x300E, 0xA1BA,
-       0x300F, 0xA1BB,
-       0x3010, 0xA1BE,
-       0x3011, 0xA1BF,
-       0x3013, 0xA1FE,
-       0x3014, 0xA1B2,
-       0x3015, 0xA1B3,
-       0x3016, 0xA1BC,
-       0x3017, 0xA1BD,
-       0x3041, 0xA4A1,
-       0x3042, 0xA4A2,
-       0x3043, 0xA4A3,
-       0x3044, 0xA4A4,
-       0x3045, 0xA4A5,
-       0x3046, 0xA4A6,
-       0x3047, 0xA4A7,
-       0x3048, 0xA4A8,
-       0x3049, 0xA4A9,
-       0x304A, 0xA4AA,
-       0x304B, 0xA4AB,
-       0x304C, 0xA4AC,
-       0x304D, 0xA4AD,
-       0x304E, 0xA4AE,
-       0x304F, 0xA4AF,
-       0x3050, 0xA4B0,
-       0x3051, 0xA4B1,
-       0x3052, 0xA4B2,
-       0x3053, 0xA4B3,
-       0x3054, 0xA4B4,
-       0x3055, 0xA4B5,
-       0x3056, 0xA4B6,
-       0x3057, 0xA4B7,
-       0x3058, 0xA4B8,
-       0x3059, 0xA4B9,
-       0x305A, 0xA4BA,
-       0x305B, 0xA4BB,
-       0x305C, 0xA4BC,
-       0x305D, 0xA4BD,
-       0x305E, 0xA4BE,
-       0x305F, 0xA4BF,
-       0x3060, 0xA4C0,
-       0x3061, 0xA4C1,
-       0x3062, 0xA4C2,
-       0x3063, 0xA4C3,
-       0x3064, 0xA4C4,
-       0x3065, 0xA4C5,
-       0x3066, 0xA4C6,
-       0x3067, 0xA4C7,
-       0x3068, 0xA4C8,
-       0x3069, 0xA4C9,
-       0x306A, 0xA4CA,
-       0x306B, 0xA4CB,
-       0x306C, 0xA4CC,
-       0x306D, 0xA4CD,
-       0x306E, 0xA4CE,
-       0x306F, 0xA4CF,
-       0x3070, 0xA4D0,
-       0x3071, 0xA4D1,
-       0x3072, 0xA4D2,
-       0x3073, 0xA4D3,
-       0x3074, 0xA4D4,
-       0x3075, 0xA4D5,
-       0x3076, 0xA4D6,
-       0x3077, 0xA4D7,
-       0x3078, 0xA4D8,
-       0x3079, 0xA4D9,
-       0x307A, 0xA4DA,
-       0x307B, 0xA4DB,
-       0x307C, 0xA4DC,
-       0x307D, 0xA4DD,
-       0x307E, 0xA4DE,
-       0x307F, 0xA4DF,
-       0x3080, 0xA4E0,
-       0x3081, 0xA4E1,
-       0x3082, 0xA4E2,
-       0x3083, 0xA4E3,
-       0x3084, 0xA4E4,
-       0x3085, 0xA4E5,
-       0x3086, 0xA4E6,
-       0x3087, 0xA4E7,
-       0x3088, 0xA4E8,
-       0x3089, 0xA4E9,
-       0x308A, 0xA4EA,
-       0x308B, 0xA4EB,
-       0x308C, 0xA4EC,
-       0x308D, 0xA4ED,
-       0x308E, 0xA4EE,
-       0x308F, 0xA4EF,
-       0x3090, 0xA4F0,
-       0x3091, 0xA4F1,
-       0x3092, 0xA4F2,
-       0x3093, 0xA4F3,
-       0x30A1, 0xA5A1,
-       0x30A2, 0xA5A2,
-       0x30A3, 0xA5A3,
-       0x30A4, 0xA5A4,
-       0x30A5, 0xA5A5,
-       0x30A6, 0xA5A6,
-       0x30A7, 0xA5A7,
-       0x30A8, 0xA5A8,
-       0x30A9, 0xA5A9,
-       0x30AA, 0xA5AA,
-       0x30AB, 0xA5AB,
-       0x30AC, 0xA5AC,
-       0x30AD, 0xA5AD,
-       0x30AE, 0xA5AE,
-       0x30AF, 0xA5AF,
-       0x30B0, 0xA5B0,
-       0x30B1, 0xA5B1,
-       0x30B2, 0xA5B2,
-       0x30B3, 0xA5B3,
-       0x30B4, 0xA5B4,
-       0x30B5, 0xA5B5,
-       0x30B6, 0xA5B6,
-       0x30B7, 0xA5B7,
-       0x30B8, 0xA5B8,
-       0x30B9, 0xA5B9,
-       0x30BA, 0xA5BA,
-       0x30BB, 0xA5BB,
-       0x30BC, 0xA5BC,
-       0x30BD, 0xA5BD,
-       0x30BE, 0xA5BE,
-       0x30BF, 0xA5BF,
-       0x30C0, 0xA5C0,
-       0x30C1, 0xA5C1,
-       0x30C2, 0xA5C2,
-       0x30C3, 0xA5C3,
-       0x30C4, 0xA5C4,
-       0x30C5, 0xA5C5,
-       0x30C6, 0xA5C6,
-       0x30C7, 0xA5C7,
-       0x30C8, 0xA5C8,
-       0x30C9, 0xA5C9,
-       0x30CA, 0xA5CA,
-       0x30CB, 0xA5CB,
-       0x30CC, 0xA5CC,
-       0x30CD, 0xA5CD,
-       0x30CE, 0xA5CE,
-       0x30CF, 0xA5CF,
-       0x30D0, 0xA5D0,
-       0x30D1, 0xA5D1,
-       0x30D2, 0xA5D2,
-       0x30D3, 0xA5D3,
-       0x30D4, 0xA5D4,
-       0x30D5, 0xA5D5,
-       0x30D6, 0xA5D6,
-       0x30D7, 0xA5D7,
-       0x30D8, 0xA5D8,
-       0x30D9, 0xA5D9,
-       0x30DA, 0xA5DA,
-       0x30DB, 0xA5DB,
-       0x30DC, 0xA5DC,
-       0x30DD, 0xA5DD,
-       0x30DE, 0xA5DE,
-       0x30DF, 0xA5DF,
-       0x30E0, 0xA5E0,
-       0x30E1, 0xA5E1,
-       0x30E2, 0xA5E2,
-       0x30E3, 0xA5E3,
-       0x30E4, 0xA5E4,
-       0x30E5, 0xA5E5,
-       0x30E6, 0xA5E6,
-       0x30E7, 0xA5E7,
-       0x30E8, 0xA5E8,
-       0x30E9, 0xA5E9,
-       0x30EA, 0xA5EA,
-       0x30EB, 0xA5EB,
-       0x30EC, 0xA5EC,
-       0x30ED, 0xA5ED,
-       0x30EE, 0xA5EE,
-       0x30EF, 0xA5EF,
-       0x30F0, 0xA5F0,
-       0x30F1, 0xA5F1,
-       0x30F2, 0xA5F2,
-       0x30F3, 0xA5F3,
-       0x30F4, 0xA5F4,
-       0x30F5, 0xA5F5,
-       0x30F6, 0xA5F6,
-       0x3105, 0xA8C5,
-       0x3106, 0xA8C6,
-       0x3107, 0xA8C7,
-       0x3108, 0xA8C8,
-       0x3109, 0xA8C9,
-       0x310A, 0xA8CA,
-       0x310B, 0xA8CB,
-       0x310C, 0xA8CC,
-       0x310D, 0xA8CD,
-       0x310E, 0xA8CE,
-       0x310F, 0xA8CF,
-       0x3110, 0xA8D0,
-       0x3111, 0xA8D1,
-       0x3112, 0xA8D2,
-       0x3113, 0xA8D3,
-       0x3114, 0xA8D4,
-       0x3115, 0xA8D5,
-       0x3116, 0xA8D6,
-       0x3117, 0xA8D7,
-       0x3118, 0xA8D8,
-       0x3119, 0xA8D9,
-       0x311A, 0xA8DA,
-       0x311B, 0xA8DB,
-       0x311C, 0xA8DC,
-       0x311D, 0xA8DD,
-       0x311E, 0xA8DE,
-       0x311F, 0xA8DF,
-       0x3120, 0xA8E0,
-       0x3121, 0xA8E1,
-       0x3122, 0xA8E2,
-       0x3123, 0xA8E3,
-       0x3124, 0xA8E4,
-       0x3125, 0xA8E5,
-       0x3126, 0xA8E6,
-       0x3127, 0xA8E7,
-       0x3128, 0xA8E8,
-       0x3129, 0xA8E9,
-       0x3220, 0xA2E5,
-       0x3221, 0xA2E6,
-       0x3222, 0xA2E7,
-       0x3223, 0xA2E8,
-       0x3224, 0xA2E9,
-       0x3225, 0xA2EA,
-       0x3226, 0xA2EB,
-       0x3227, 0xA2EC,
-       0x3228, 0xA2ED,
-       0x3229, 0xA2EE,
-       0x4E00, 0xD2BB,
-       0x4E01, 0xB6A1,
-       0x4E03, 0xC6DF,
-       0x4E07, 0xCDF2,
-       0x4E08, 0xD5C9,
-       0x4E09, 0xC8FD,
-       0x4E0A, 0xC9CF,
-       0x4E0B, 0xCFC2,
-       0x4E0C, 0xD8A2,
-       0x4E0D, 0xB2BB,
-       0x4E0E, 0xD3EB,
-       0x4E10, 0xD8A4,
-       0x4E11, 0xB3F3,
-       0x4E13, 0xD7A8,
-       0x4E14, 0xC7D2,
-       0x4E15, 0xD8A7,
-       0x4E16, 0xCAC0,
-       0x4E18, 0xC7F0,
-       0x4E19, 0xB1FB,
-       0x4E1A, 0xD2B5,
-       0x4E1B, 0xB4D4,
-       0x4E1C, 0xB6AB,
-       0x4E1D, 0xCBBF,
-       0x4E1E, 0xD8A9,
-       0x4E22, 0xB6AA,
-       0x4E24, 0xC1BD,
-       0x4E25, 0xD1CF,
-       0x4E27, 0xC9A5,
-       0x4E28, 0xD8AD,
-       0x4E2A, 0xB8F6,
-       0x4E2B, 0xD1BE,
-       0x4E2C, 0xE3DC,
-       0x4E2D, 0xD6D0,
-       0x4E30, 0xB7E1,
-       0x4E32, 0xB4AE,
-       0x4E34, 0xC1D9,
-       0x4E36, 0xD8BC,
-       0x4E38, 0xCDE8,
-       0x4E39, 0xB5A4,
-       0x4E3A, 0xCEAA,
-       0x4E3B, 0xD6F7,
-       0x4E3D, 0xC0F6,
-       0x4E3E, 0xBED9,
-       0x4E3F, 0xD8AF,
-       0x4E43, 0xC4CB,
-       0x4E45, 0xBEC3,
-       0x4E47, 0xD8B1,
-       0x4E48, 0xC3B4,
-       0x4E49, 0xD2E5,
-       0x4E4B, 0xD6AE,
-       0x4E4C, 0xCEDA,
-       0x4E4D, 0xD5A7,
-       0x4E4E, 0xBAF5,
-       0x4E4F, 0xB7A6,
-       0x4E50, 0xC0D6,
-       0x4E52, 0xC6B9,
-       0x4E53, 0xC5D2,
-       0x4E54, 0xC7C7,
-       0x4E56, 0xB9D4,
-       0x4E58, 0xB3CB,
-       0x4E59, 0xD2D2,
-       0x4E5C, 0xD8BF,
-       0x4E5D, 0xBEC5,
-       0x4E5E, 0xC6F2,
-       0x4E5F, 0xD2B2,
-       0x4E60, 0xCFB0,
-       0x4E61, 0xCFE7,
-       0x4E66, 0xCAE9,
-       0x4E69, 0xD8C0,
-       0x4E70, 0xC2F2,
-       0x4E71, 0xC2D2,
-       0x4E73, 0xC8E9,
-       0x4E7E, 0xC7AC,
-       0x4E86, 0xC1CB,
-       0x4E88, 0xD3E8,
-       0x4E89, 0xD5F9,
-       0x4E8B, 0xCAC2,
-       0x4E8C, 0xB6FE,
-       0x4E8D, 0xD8A1,
-       0x4E8E, 0xD3DA,
-       0x4E8F, 0xBFF7,
-       0x4E91, 0xD4C6,
-       0x4E92, 0xBBA5,
-       0x4E93, 0xD8C1,
-       0x4E94, 0xCEE5,
-       0x4E95, 0xBEAE,
-       0x4E98, 0xD8A8,
-       0x4E9A, 0xD1C7,
-       0x4E9B, 0xD0A9,
-       0x4E9F, 0xD8BD,
-       0x4EA0, 0xD9EF,
-       0x4EA1, 0xCDF6,
-       0x4EA2, 0xBFBA,
-       0x4EA4, 0xBDBB,
-       0x4EA5, 0xBAA5,
-       0x4EA6, 0xD2E0,
-       0x4EA7, 0xB2FA,
-       0x4EA8, 0xBAE0,
-       0x4EA9, 0xC4B6,
-       0x4EAB, 0xCFED,
-       0x4EAC, 0xBEA9,
-       0x4EAD, 0xCDA4,
-       0x4EAE, 0xC1C1,
-       0x4EB2, 0xC7D7,
-       0x4EB3, 0xD9F1,
-       0x4EB5, 0xD9F4,
-       0x4EBA, 0xC8CB,
-       0x4EBB, 0xD8E9,
-       0x4EBF, 0xD2DA,
-       0x4EC0, 0xCAB2,
-       0x4EC1, 0xC8CA,
-       0x4EC2, 0xD8EC,
-       0x4EC3, 0xD8EA,
-       0x4EC4, 0xD8C6,
-       0x4EC5, 0xBDF6,
-       0x4EC6, 0xC6CD,
-       0x4EC7, 0xB3F0,
-       0x4EC9, 0xD8EB,
-       0x4ECA, 0xBDF1,
-       0x4ECB, 0xBDE9,
-       0x4ECD, 0xC8D4,
-       0x4ECE, 0xB4D3,
-       0x4ED1, 0xC2D8,
-       0x4ED3, 0xB2D6,
-       0x4ED4, 0xD7D0,
-       0x4ED5, 0xCACB,
-       0x4ED6, 0xCBFB,
-       0x4ED7, 0xD5CC,
-       0x4ED8, 0xB8B6,
-       0x4ED9, 0xCFC9,
-       0x4EDD, 0xD9DA,
-       0x4EDE, 0xD8F0,
-       0x4EDF, 0xC7AA,
-       0x4EE1, 0xD8EE,
-       0x4EE3, 0xB4FA,
-       0x4EE4, 0xC1EE,
-       0x4EE5, 0xD2D4,
-       0x4EE8, 0xD8ED,
-       0x4EEA, 0xD2C7,
-       0x4EEB, 0xD8EF,
-       0x4EEC, 0xC3C7,
-       0x4EF0, 0xD1F6,
-       0x4EF2, 0xD6D9,
-       0x4EF3, 0xD8F2,
-       0x4EF5, 0xD8F5,
-       0x4EF6, 0xBCFE,
-       0x4EF7, 0xBCDB,
-       0x4EFB, 0xC8CE,
-       0x4EFD, 0xB7DD,
-       0x4EFF, 0xB7C2,
-       0x4F01, 0xC6F3,
-       0x4F09, 0xD8F8,
-       0x4F0A, 0xD2C1,
-       0x4F0D, 0xCEE9,
-       0x4F0E, 0xBCBF,
-       0x4F0F, 0xB7FC,
-       0x4F10, 0xB7A5,
-       0x4F11, 0xD0DD,
-       0x4F17, 0xD6DA,
-       0x4F18, 0xD3C5,
-       0x4F19, 0xBBEF,
-       0x4F1A, 0xBBE1,
-       0x4F1B, 0xD8F1,
-       0x4F1E, 0xC9A1,
-       0x4F1F, 0xCEB0,
-       0x4F20, 0xB4AB,
-       0x4F22, 0xD8F3,
-       0x4F24, 0xC9CB,
-       0x4F25, 0xD8F6,
-       0x4F26, 0xC2D7,
-       0x4F27, 0xD8F7,
-       0x4F2A, 0xCEB1,
-       0x4F2B, 0xD8F9,
-       0x4F2F, 0xB2AE,
-       0x4F30, 0xB9C0,
-       0x4F32, 0xD9A3,
-       0x4F34, 0xB0E9,
-       0x4F36, 0xC1E6,
-       0x4F38, 0xC9EC,
-       0x4F3A, 0xCBC5,
-       0x4F3C, 0xCBC6,
-       0x4F3D, 0xD9A4,
-       0x4F43, 0xB5E8,
-       0x4F46, 0xB5AB,
-       0x4F4D, 0xCEBB,
-       0x4F4E, 0xB5CD,
-       0x4F4F, 0xD7A1,
-       0x4F50, 0xD7F4,
-       0x4F51, 0xD3D3,
-       0x4F53, 0xCCE5,
-       0x4F55, 0xBACE,
-       0x4F57, 0xD9A2,
-       0x4F58, 0xD9DC,
-       0x4F59, 0xD3E0,
-       0x4F5A, 0xD8FD,
-       0x4F5B, 0xB7F0,
-       0x4F5C, 0xD7F7,
-       0x4F5D, 0xD8FE,
-       0x4F5E, 0xD8FA,
-       0x4F5F, 0xD9A1,
-       0x4F60, 0xC4E3,
-       0x4F63, 0xD3B6,
-       0x4F64, 0xD8F4,
-       0x4F65, 0xD9DD,
-       0x4F67, 0xD8FB,
-       0x4F69, 0xC5E5,
-       0x4F6C, 0xC0D0,
-       0x4F6F, 0xD1F0,
-       0x4F70, 0xB0DB,
-       0x4F73, 0xBCD1,
-       0x4F74, 0xD9A6,
-       0x4F76, 0xD9A5,
-       0x4F7B, 0xD9AC,
-       0x4F7C, 0xD9AE,
-       0x4F7E, 0xD9AB,
-       0x4F7F, 0xCAB9,
-       0x4F83, 0xD9A9,
-       0x4F84, 0xD6B6,
-       0x4F88, 0xB3DE,
-       0x4F89, 0xD9A8,
-       0x4F8B, 0xC0FD,
-       0x4F8D, 0xCACC,
-       0x4F8F, 0xD9AA,
-       0x4F91, 0xD9A7,
-       0x4F94, 0xD9B0,
-       0x4F97, 0xB6B1,
-       0x4F9B, 0xB9A9,
-       0x4F9D, 0xD2C0,
-       0x4FA0, 0xCFC0,
-       0x4FA3, 0xC2C2,
-       0x4FA5, 0xBDC4,
-       0x4FA6, 0xD5EC,
-       0x4FA7, 0xB2E0,
-       0x4FA8, 0xC7C8,
-       0x4FA9, 0xBFEB,
-       0x4FAA, 0xD9AD,
-       0x4FAC, 0xD9AF,
-       0x4FAE, 0xCEEA,
-       0x4FAF, 0xBAEE,
-       0x4FB5, 0xC7D6,
-       0x4FBF, 0xB1E3,
-       0x4FC3, 0xB4D9,
-       0x4FC4, 0xB6ED,
-       0x4FC5, 0xD9B4,
-       0x4FCA, 0xBFA1,
-       0x4FCE, 0xD9DE,
-       0x4FCF, 0xC7CE,
-       0x4FD0, 0xC0FE,
-       0x4FD1, 0xD9B8,
-       0x4FD7, 0xCBD7,
-       0x4FD8, 0xB7FD,
-       0x4FDA, 0xD9B5,
-       0x4FDC, 0xD9B7,
-       0x4FDD, 0xB1A3,
-       0x4FDE, 0xD3E1,
-       0x4FDF, 0xD9B9,
-       0x4FE1, 0xD0C5,
-       0x4FE3, 0xD9B6,
-       0x4FE6, 0xD9B1,
-       0x4FE8, 0xD9B2,
-       0x4FE9, 0xC1A9,
-       0x4FEA, 0xD9B3,
-       0x4FED, 0xBCF3,
-       0x4FEE, 0xD0DE,
-       0x4FEF, 0xB8A9,
-       0x4FF1, 0xBEE3,
-       0x4FF3, 0xD9BD,
-       0x4FF8, 0xD9BA,
-       0x4FFA, 0xB0B3,
-       0x4FFE, 0xD9C2,
-       0x500C, 0xD9C4,
-       0x500D, 0xB1B6,
-       0x500F, 0xD9BF,
-       0x5012, 0xB5B9,
-       0x5014, 0xBEF3,
-       0x5018, 0xCCC8,
-       0x5019, 0xBAF2,
-       0x501A, 0xD2D0,
-       0x501C, 0xD9C3,
-       0x501F, 0xBDE8,
-       0x5021, 0xB3AB,
-       0x5025, 0xD9C5,
-       0x5026, 0xBEEB,
-       0x5028, 0xD9C6,
-       0x5029, 0xD9BB,
-       0x502A, 0xC4DF,
-       0x502C, 0xD9BE,
-       0x502D, 0xD9C1,
-       0x502E, 0xD9C0,
-       0x503A, 0xD5AE,
-       0x503C, 0xD6B5,
-       0x503E, 0xC7E3,
-       0x5043, 0xD9C8,
-       0x5047, 0xBCD9,
-       0x5048, 0xD9CA,
-       0x504C, 0xD9BC,
-       0x504E, 0xD9CB,
-       0x504F, 0xC6AB,
-       0x5055, 0xD9C9,
-       0x505A, 0xD7F6,
-       0x505C, 0xCDA3,
-       0x5065, 0xBDA1,
-       0x506C, 0xD9CC,
-       0x5076, 0xC5BC,
-       0x5077, 0xCDB5,
-       0x507B, 0xD9CD,
-       0x507E, 0xD9C7,
-       0x507F, 0xB3A5,
-       0x5080, 0xBFFE,
-       0x5085, 0xB8B5,
-       0x5088, 0xC0FC,
-       0x508D, 0xB0F8,
-       0x50A3, 0xB4F6,
-       0x50A5, 0xD9CE,
-       0x50A7, 0xD9CF,
-       0x50A8, 0xB4A2,
-       0x50A9, 0xD9D0,
-       0x50AC, 0xB4DF,
-       0x50B2, 0xB0C1,
-       0x50BA, 0xD9D1,
-       0x50BB, 0xC9B5,
-       0x50CF, 0xCFF1,
-       0x50D6, 0xD9D2,
-       0x50DA, 0xC1C5,
-       0x50E6, 0xD9D6,
-       0x50E7, 0xC9AE,
-       0x50EC, 0xD9D5,
-       0x50ED, 0xD9D4,
-       0x50EE, 0xD9D7,
-       0x50F3, 0xCBDB,
-       0x50F5, 0xBDA9,
-       0x50FB, 0xC6A7,
-       0x5106, 0xD9D3,
-       0x5107, 0xD9D8,
-       0x510B, 0xD9D9,
-       0x5112, 0xC8E5,
-       0x5121, 0xC0DC,
-       0x513F, 0xB6F9,
-       0x5140, 0xD8A3,
-       0x5141, 0xD4CA,
-       0x5143, 0xD4AA,
-       0x5144, 0xD0D6,
-       0x5145, 0xB3E4,
-       0x5146, 0xD5D7,
-       0x5148, 0xCFC8,
-       0x5149, 0xB9E2,
-       0x514B, 0xBFCB,
-       0x514D, 0xC3E2,
-       0x5151, 0xB6D2,
-       0x5154, 0xCDC3,
-       0x5155, 0xD9EE,
-       0x5156, 0xD9F0,
-       0x515A, 0xB5B3,
-       0x515C, 0xB6B5,
-       0x5162, 0xBEA4,
-       0x5165, 0xC8EB,
-       0x5168, 0xC8AB,
-       0x516B, 0xB0CB,
-       0x516C, 0xB9AB,
-       0x516D, 0xC1F9,
-       0x516E, 0xD9E2,
-       0x5170, 0xC0BC,
-       0x5171, 0xB9B2,
-       0x5173, 0xB9D8,
-       0x5174, 0xD0CB,
-       0x5175, 0xB1F8,
-       0x5176, 0xC6E4,
-       0x5177, 0xBEDF,
-       0x5178, 0xB5E4,
-       0x5179, 0xD7C8,
-       0x517B, 0xD1F8,
-       0x517C, 0xBCE6,
-       0x517D, 0xCADE,
-       0x5180, 0xBCBD,
-       0x5181, 0xD9E6,
-       0x5182, 0xD8E7,
-       0x5185, 0xC4DA,
-       0x5188, 0xB8D4,
-       0x5189, 0xC8BD,
-       0x518C, 0xB2E1,
-       0x518D, 0xD4D9,
-       0x5192, 0xC3B0,
-       0x5195, 0xC3E1,
-       0x5196, 0xDAA2,
-       0x5197, 0xC8DF,
-       0x5199, 0xD0B4,
-       0x519B, 0xBEFC,
-       0x519C, 0xC5A9,
-       0x51A0, 0xB9DA,
-       0x51A2, 0xDAA3,
-       0x51A4, 0xD4A9,
-       0x51A5, 0xDAA4,
-       0x51AB, 0xD9FB,
-       0x51AC, 0xB6AC,
-       0x51AF, 0xB7EB,
-       0x51B0, 0xB1F9,
-       0x51B1, 0xD9FC,
-       0x51B2, 0xB3E5,
-       0x51B3, 0xBEF6,
-       0x51B5, 0xBFF6,
-       0x51B6, 0xD2B1,
-       0x51B7, 0xC0E4,
-       0x51BB, 0xB6B3,
-       0x51BC, 0xD9FE,
-       0x51BD, 0xD9FD,
-       0x51C0, 0xBEBB,
-       0x51C4, 0xC6E0,
-       0x51C6, 0xD7BC,
-       0x51C7, 0xDAA1,
-       0x51C9, 0xC1B9,
-       0x51CB, 0xB5F2,
-       0x51CC, 0xC1E8,
-       0x51CF, 0xBCF5,
-       0x51D1, 0xB4D5,
-       0x51DB, 0xC1DD,
-       0x51DD, 0xC4FD,
-       0x51E0, 0xBCB8,
-       0x51E1, 0xB7B2,
-       0x51E4, 0xB7EF,
-       0x51EB, 0xD9EC,
-       0x51ED, 0xC6BE,
-       0x51EF, 0xBFAD,
-       0x51F0, 0xBBCB,
-       0x51F3, 0xB5CA,
-       0x51F5, 0xDBC9,
-       0x51F6, 0xD0D7,
-       0x51F8, 0xCDB9,
-       0x51F9, 0xB0BC,
-       0x51FA, 0xB3F6,
-       0x51FB, 0xBBF7,
-       0x51FC, 0xDBCA,
-       0x51FD, 0xBAAF,
-       0x51FF, 0xD4E4,
-       0x5200, 0xB5B6,
-       0x5201, 0xB5F3,
-       0x5202, 0xD8D6,
-       0x5203, 0xC8D0,
-       0x5206, 0xB7D6,
-       0x5207, 0xC7D0,
-       0x5208, 0xD8D7,
-       0x520A, 0xBFAF,
-       0x520D, 0xDBBB,
-       0x520E, 0xD8D8,
-       0x5211, 0xD0CC,
-       0x5212, 0xBBAE,
-       0x5216, 0xEBBE,
-       0x5217, 0xC1D0,
-       0x5218, 0xC1F5,
-       0x5219, 0xD4F2,
-       0x521A, 0xB8D5,
-       0x521B, 0xB4B4,
-       0x521D, 0xB3F5,
-       0x5220, 0xC9BE,
-       0x5224, 0xC5D0,
-       0x5228, 0xC5D9,
-       0x5229, 0xC0FB,
-       0x522B, 0xB1F0,
-       0x522D, 0xD8D9,
-       0x522E, 0xB9CE,
-       0x5230, 0xB5BD,
-       0x5233, 0xD8DA,
-       0x5236, 0xD6C6,
-       0x5237, 0xCBA2,
-       0x5238, 0xC8AF,
-       0x5239, 0xC9B2,
-       0x523A, 0xB4CC,
-       0x523B, 0xBFCC,
-       0x523D, 0xB9F4,
-       0x523F, 0xD8DB,
-       0x5240, 0xD8DC,
-       0x5241, 0xB6E7,
-       0x5242, 0xBCC1,
-       0x5243, 0xCCEA,
-       0x524A, 0xCFF7,
-       0x524C, 0xD8DD,
-       0x524D, 0xC7B0,
-       0x5250, 0xB9D0,
-       0x5251, 0xBDA3,
-       0x5254, 0xCCDE,
-       0x5256, 0xC6CA,
-       0x525C, 0xD8E0,
-       0x525E, 0xD8DE,
-       0x5261, 0xD8DF,
-       0x5265, 0xB0FE,
-       0x5267, 0xBEE7,
-       0x5269, 0xCAA3,
-       0x526A, 0xBCF4,
-       0x526F, 0xB8B1,
-       0x5272, 0xB8EE,
-       0x527D, 0xD8E2,
-       0x527F, 0xBDCB,
-       0x5281, 0xD8E4,
-       0x5282, 0xD8E3,
-       0x5288, 0xC5FC,
-       0x5290, 0xD8E5,
-       0x5293, 0xD8E6,
-       0x529B, 0xC1A6,
-       0x529D, 0xC8B0,
-       0x529E, 0xB0EC,
-       0x529F, 0xB9A6,
-       0x52A0, 0xBCD3,
-       0x52A1, 0xCEF1,
-       0x52A2, 0xDBBD,
-       0x52A3, 0xC1D3,
-       0x52A8, 0xB6AF,
-       0x52A9, 0xD6FA,
-       0x52AA, 0xC5AC,
-       0x52AB, 0xBDD9,
-       0x52AC, 0xDBBE,
-       0x52AD, 0xDBBF,
-       0x52B1, 0xC0F8,
-       0x52B2, 0xBEA2,
-       0x52B3, 0xC0CD,
-       0x52BE, 0xDBC0,
-       0x52BF, 0xCAC6,
-       0x52C3, 0xB2AA,
-       0x52C7, 0xD3C2,
-       0x52C9, 0xC3E3,
-       0x52CB, 0xD1AB,
-       0x52D0, 0xDBC2,
-       0x52D2, 0xC0D5,
-       0x52D6, 0xDBC3,
-       0x52D8, 0xBFB1,
-       0x52DF, 0xC4BC,
-       0x52E4, 0xC7DA,
-       0x52F0, 0xDBC4,
-       0x52F9, 0xD9E8,
-       0x52FA, 0xC9D7,
-       0x52FE, 0xB9B4,
-       0x52FF, 0xCEF0,
-       0x5300, 0xD4C8,
-       0x5305, 0xB0FC,
-       0x5306, 0xB4D2,
-       0x5308, 0xD0D9,
-       0x530D, 0xD9E9,
-       0x530F, 0xDECB,
-       0x5310, 0xD9EB,
-       0x5315, 0xD8B0,
-       0x5316, 0xBBAF,
-       0x5317, 0xB1B1,
-       0x5319, 0xB3D7,
-       0x531A, 0xD8CE,
-       0x531D, 0xD4D1,
-       0x5320, 0xBDB3,
-       0x5321, 0xBFEF,
-       0x5323, 0xCFBB,
-       0x5326, 0xD8D0,
-       0x532A, 0xB7CB,
-       0x532E, 0xD8D1,
-       0x5339, 0xC6A5,
-       0x533A, 0xC7F8,
-       0x533B, 0xD2BD,
-       0x533E, 0xD8D2,
-       0x533F, 0xC4E4,
-       0x5341, 0xCAAE,
-       0x5343, 0xC7A7,
-       0x5345, 0xD8A6,
-       0x5347, 0xC9FD,
-       0x5348, 0xCEE7,
-       0x5349, 0xBBDC,
-       0x534A, 0xB0EB,
-       0x534E, 0xBBAA,
-       0x534F, 0xD0AD,
-       0x5351, 0xB1B0,
-       0x5352, 0xD7E4,
-       0x5353, 0xD7BF,
-       0x5355, 0xB5A5,
-       0x5356, 0xC2F4,
-       0x5357, 0xC4CF,
-       0x535A, 0xB2A9,
-       0x535C, 0xB2B7,
-       0x535E, 0xB1E5,
-       0x535F, 0xDFB2,
-       0x5360, 0xD5BC,
-       0x5361, 0xBFA8,
-       0x5362, 0xC2AC,
-       0x5363, 0xD8D5,
-       0x5364, 0xC2B1,
-       0x5366, 0xD8D4,
-       0x5367, 0xCED4,
-       0x5369, 0xDAE0,
-       0x536B, 0xCEC0,
-       0x536E, 0xD8B4,
-       0x536F, 0xC3AE,
-       0x5370, 0xD3A1,
-       0x5371, 0xCEA3,
-       0x5373, 0xBCB4,
-       0x5374, 0xC8B4,
-       0x5375, 0xC2D1,
-       0x5377, 0xBEED,
-       0x5378, 0xD0B6,
-       0x537A, 0xDAE1,
-       0x537F, 0xC7E4,
-       0x5382, 0xB3A7,
-       0x5384, 0xB6F2,
-       0x5385, 0xCCFC,
-       0x5386, 0xC0FA,
-       0x5389, 0xC0F7,
-       0x538B, 0xD1B9,
-       0x538C, 0xD1E1,
-       0x538D, 0xD8C7,
-       0x5395, 0xB2DE,
-       0x5398, 0xC0E5,
-       0x539A, 0xBAF1,
-       0x539D, 0xD8C8,
-       0x539F, 0xD4AD,
-       0x53A2, 0xCFE1,
-       0x53A3, 0xD8C9,
-       0x53A5, 0xD8CA,
-       0x53A6, 0xCFC3,
-       0x53A8, 0xB3F8,
-       0x53A9, 0xBEC7,
-       0x53AE, 0xD8CB,
-       0x53B6, 0xDBCC,
-       0x53BB, 0xC8A5,
-       0x53BF, 0xCFD8,
-       0x53C1, 0xC8FE,
-       0x53C2, 0xB2CE,
-       0x53C8, 0xD3D6,
-       0x53C9, 0xB2E6,
-       0x53CA, 0xBCB0,
-       0x53CB, 0xD3D1,
-       0x53CC, 0xCBAB,
-       0x53CD, 0xB7B4,
-       0x53D1, 0xB7A2,
-       0x53D4, 0xCAE5,
-       0x53D6, 0xC8A1,
-       0x53D7, 0xCADC,
-       0x53D8, 0xB1E4,
-       0x53D9, 0xD0F0,
-       0x53DB, 0xC5D1,
-       0x53DF, 0xDBC5,
-       0x53E0, 0xB5FE,
-       0x53E3, 0xBFDA,
-       0x53E4, 0xB9C5,
-       0x53E5, 0xBEE4,
-       0x53E6, 0xC1ED,
-       0x53E8, 0xDFB6,
-       0x53E9, 0xDFB5,
-       0x53EA, 0xD6BB,
-       0x53EB, 0xBDD0,
-       0x53EC, 0xD5D9,
-       0x53ED, 0xB0C8,
-       0x53EE, 0xB6A3,
-       0x53EF, 0xBFC9,
-       0x53F0, 0xCCA8,
-       0x53F1, 0xDFB3,
-       0x53F2, 0xCAB7,
-       0x53F3, 0xD3D2,
-       0x53F5, 0xD8CF,
-       0x53F6, 0xD2B6,
-       0x53F7, 0xBAC5,
-       0x53F8, 0xCBBE,
-       0x53F9, 0xCCBE,
-       0x53FB, 0xDFB7,
-       0x53FC, 0xB5F0,
-       0x53FD, 0xDFB4,
-       0x5401, 0xD3F5,
-       0x5403, 0xB3D4,
-       0x5404, 0xB8F7,
-       0x5406, 0xDFBA,
-       0x5408, 0xBACF,
-       0x5409, 0xBCAA,
-       0x540A, 0xB5F5,
-       0x540C, 0xCDAC,
-       0x540D, 0xC3FB,
-       0x540E, 0xBAF3,
-       0x540F, 0xC0F4,
-       0x5410, 0xCDC2,
-       0x5411, 0xCFF2,
-       0x5412, 0xDFB8,
-       0x5413, 0xCFC5,
-       0x5415, 0xC2C0,
-       0x5416, 0xDFB9,
-       0x5417, 0xC2F0,
-       0x541B, 0xBEFD,
-       0x541D, 0xC1DF,
-       0x541E, 0xCDCC,
-       0x541F, 0xD2F7,
-       0x5420, 0xB7CD,
-       0x5421, 0xDFC1,
-       0x5423, 0xDFC4,
-       0x5426, 0xB7F1,
-       0x5427, 0xB0C9,
-       0x5428, 0xB6D6,
-       0x5429, 0xB7D4,
-       0x542B, 0xBAAC,
-       0x542C, 0xCCFD,
-       0x542D, 0xBFD4,
-       0x542E, 0xCBB1,
-       0x542F, 0xC6F4,
-       0x5431, 0xD6A8,
-       0x5432, 0xDFC5,
-       0x5434, 0xCEE2,
-       0x5435, 0xB3B3,
-       0x5438, 0xCEFC,
-       0x5439, 0xB4B5,
-       0x543B, 0xCEC7,
-       0x543C, 0xBAF0,
-       0x543E, 0xCEE1,
-       0x5440, 0xD1BD,
-       0x5443, 0xDFC0,
-       0x5446, 0xB4F4,
-       0x5448, 0xB3CA,
-       0x544A, 0xB8E6,
-       0x544B, 0xDFBB,
-       0x5450, 0xC4C5,
-       0x5452, 0xDFBC,
-       0x5453, 0xDFBD,
-       0x5454, 0xDFBE,
-       0x5455, 0xC5BB,
-       0x5456, 0xDFBF,
-       0x5457, 0xDFC2,
-       0x5458, 0xD4B1,
-       0x5459, 0xDFC3,
-       0x545B, 0xC7BA,
-       0x545C, 0xCED8,
-       0x5462, 0xC4D8,
-       0x5464, 0xDFCA,
-       0x5466, 0xDFCF,
-       0x5468, 0xD6DC,
-       0x5471, 0xDFC9,
-       0x5472, 0xDFDA,
-       0x5473, 0xCEB6,
-       0x5475, 0xBAC7,
-       0x5476, 0xDFCE,
-       0x5477, 0xDFC8,
-       0x5478, 0xC5DE,
-       0x547B, 0xC9EB,
-       0x547C, 0xBAF4,
-       0x547D, 0xC3FC,
-       0x5480, 0xBED7,
-       0x5482, 0xDFC6,
-       0x5484, 0xDFCD,
-       0x5486, 0xC5D8,
-       0x548B, 0xD5A6,
-       0x548C, 0xBACD,
-       0x548E, 0xBECC,
-       0x548F, 0xD3BD,
-       0x5490, 0xB8C0,
-       0x5492, 0xD6E4,
-       0x5494, 0xDFC7,
-       0x5495, 0xB9BE,
-       0x5496, 0xBFA7,
-       0x5499, 0xC1FC,
-       0x549A, 0xDFCB,
-       0x549B, 0xDFCC,
-       0x549D, 0xDFD0,
-       0x54A3, 0xDFDB,
-       0x54A4, 0xDFE5,
-       0x54A6, 0xDFD7,
-       0x54A7, 0xDFD6,
-       0x54A8, 0xD7C9,
-       0x54A9, 0xDFE3,
-       0x54AA, 0xDFE4,
-       0x54AB, 0xE5EB,
-       0x54AC, 0xD2A7,
-       0x54AD, 0xDFD2,
-       0x54AF, 0xBFA9,
-       0x54B1, 0xD4DB,
-       0x54B3, 0xBFC8,
-       0x54B4, 0xDFD4,
-       0x54B8, 0xCFCC,
-       0x54BB, 0xDFDD,
-       0x54BD, 0xD1CA,
-       0x54BF, 0xDFDE,
-       0x54C0, 0xB0A7,
-       0x54C1, 0xC6B7,
-       0x54C2, 0xDFD3,
-       0x54C4, 0xBAE5,
-       0x54C6, 0xB6DF,
-       0x54C7, 0xCDDB,
-       0x54C8, 0xB9FE,
-       0x54C9, 0xD4D5,
-       0x54CC, 0xDFDF,
-       0x54CD, 0xCFEC,
-       0x54CE, 0xB0A5,
-       0x54CF, 0xDFE7,
-       0x54D0, 0xDFD1,
-       0x54D1, 0xD1C6,
-       0x54D2, 0xDFD5,
-       0x54D3, 0xDFD8,
-       0x54D4, 0xDFD9,
-       0x54D5, 0xDFDC,
-       0x54D7, 0xBBA9,
-       0x54D9, 0xDFE0,
-       0x54DA, 0xDFE1,
-       0x54DC, 0xDFE2,
-       0x54DD, 0xDFE6,
-       0x54DE, 0xDFE8,
-       0x54DF, 0xD3B4,
-       0x54E5, 0xB8E7,
-       0x54E6, 0xC5B6,
-       0x54E7, 0xDFEA,
-       0x54E8, 0xC9DA,
-       0x54E9, 0xC1A8,
-       0x54EA, 0xC4C4,
-       0x54ED, 0xBFDE,
-       0x54EE, 0xCFF8,
-       0x54F2, 0xD5DC,
-       0x54F3, 0xDFEE,
-       0x54FA, 0xB2B8,
-       0x54FC, 0xBADF,
-       0x54FD, 0xDFEC,
-       0x54FF, 0xDBC1,
-       0x5501, 0xD1E4,
-       0x5506, 0xCBF4,
-       0x5507, 0xB4BD,
-       0x5509, 0xB0A6,
-       0x550F, 0xDFF1,
-       0x5510, 0xCCC6,
-       0x5511, 0xDFF2,
-       0x5514, 0xDFED,
-       0x551B, 0xDFE9,
-       0x5520, 0xDFEB,
-       0x5522, 0xDFEF,
-       0x5523, 0xDFF0,
-       0x5524, 0xBBBD,
-       0x5527, 0xDFF3,
-       0x552A, 0xDFF4,
-       0x552C, 0xBBA3,
-       0x552E, 0xCADB,
-       0x552F, 0xCEA8,
-       0x5530, 0xE0A7,
-       0x5531, 0xB3AA,
-       0x5533, 0xE0A6,
-       0x5537, 0xE0A1,
-       0x553C, 0xDFFE,
-       0x553E, 0xCDD9,
-       0x553F, 0xDFFC,
-       0x5541, 0xDFFA,
-       0x5543, 0xBFD0,
-       0x5544, 0xD7C4,
-       0x5546, 0xC9CC,
-       0x5549, 0xDFF8,
-       0x554A, 0xB0A1,
-       0x5550, 0xDFFD,
-       0x5555, 0xDFFB,
-       0x5556, 0xE0A2,
-       0x555C, 0xE0A8,
-       0x5561, 0xB7C8,
-       0x5564, 0xC6A1,
-       0x5565, 0xC9B6,
-       0x5566, 0xC0B2,
-       0x5567, 0xDFF5,
-       0x556A, 0xC5BE,
-       0x556C, 0xD8C4,
-       0x556D, 0xDFF9,
-       0x556E, 0xC4F6,
-       0x5575, 0xE0A3,
-       0x5576, 0xE0A4,
-       0x5577, 0xE0A5,
-       0x5578, 0xD0A5,
-       0x557B, 0xE0B4,
-       0x557C, 0xCCE4,
-       0x557E, 0xE0B1,
-       0x5580, 0xBFA6,
-       0x5581, 0xE0AF,
-       0x5582, 0xCEB9,
-       0x5583, 0xE0AB,
-       0x5584, 0xC9C6,
-       0x5587, 0xC0AE,
-       0x5588, 0xE0AE,
-       0x5589, 0xBAED,
-       0x558A, 0xBAB0,
-       0x558B, 0xE0A9,
-       0x558F, 0xDFF6,
-       0x5591, 0xE0B3,
-       0x5594, 0xE0B8,
-       0x5598, 0xB4AD,
-       0x5599, 0xE0B9,
-       0x559C, 0xCFB2,
-       0x559D, 0xBAC8,
-       0x559F, 0xE0B0,
-       0x55A7, 0xD0FA,
-       0x55B1, 0xE0AC,
-       0x55B3, 0xD4FB,
-       0x55B5, 0xDFF7,
-       0x55B7, 0xC5E7,
-       0x55B9, 0xE0AD,
-       0x55BB, 0xD3F7,
-       0x55BD, 0xE0B6,
-       0x55BE, 0xE0B7,
-       0x55C4, 0xE0C4,
-       0x55C5, 0xD0E1,
-       0x55C9, 0xE0BC,
-       0x55CC, 0xE0C9,
-       0x55CD, 0xE0CA,
-       0x55D1, 0xE0BE,
-       0x55D2, 0xE0AA,
-       0x55D3, 0xC9A4,
-       0x55D4, 0xE0C1,
-       0x55D6, 0xE0B2,
-       0x55DC, 0xCAC8,
-       0x55DD, 0xE0C3,
-       0x55DF, 0xE0B5,
-       0x55E1, 0xCECB,
-       0x55E3, 0xCBC3,
-       0x55E4, 0xE0CD,
-       0x55E5, 0xE0C6,
-       0x55E6, 0xE0C2,
-       0x55E8, 0xE0CB,
-       0x55EA, 0xE0BA,
-       0x55EB, 0xE0BF,
-       0x55EC, 0xE0C0,
-       0x55EF, 0xE0C5,
-       0x55F2, 0xE0C7,
-       0x55F3, 0xE0C8,
-       0x55F5, 0xE0CC,
-       0x55F7, 0xE0BB,
-       0x55FD, 0xCBD4,
-       0x55FE, 0xE0D5,
-       0x5600, 0xE0D6,
-       0x5601, 0xE0D2,
-       0x5608, 0xE0D0,
-       0x5609, 0xBCCE,
-       0x560C, 0xE0D1,
-       0x560E, 0xB8C2,
-       0x560F, 0xD8C5,
-       0x5618, 0xD0EA,
-       0x561B, 0xC2EF,
-       0x561E, 0xE0CF,
-       0x561F, 0xE0BD,
-       0x5623, 0xE0D4,
-       0x5624, 0xE0D3,
-       0x5627, 0xE0D7,
-       0x562C, 0xE0DC,
-       0x562D, 0xE0D8,
-       0x5631, 0xD6F6,
-       0x5632, 0xB3B0,
-       0x5634, 0xD7EC,
-       0x5636, 0xCBBB,
-       0x5639, 0xE0DA,
-       0x563B, 0xCEFB,
-       0x563F, 0xBAD9,
-       0x564C, 0xE0E1,
-       0x564D, 0xE0DD,
-       0x564E, 0xD2AD,
-       0x5654, 0xE0E2,
-       0x5657, 0xE0DB,
-       0x5658, 0xE0D9,
-       0x5659, 0xE0DF,
-       0x565C, 0xE0E0,
-       0x5662, 0xE0DE,
-       0x5664, 0xE0E4,
-       0x5668, 0xC6F7,
-       0x5669, 0xD8AC,
-       0x566A, 0xD4EB,
-       0x566B, 0xE0E6,
-       0x566C, 0xCAC9,
-       0x5671, 0xE0E5,
-       0x5676, 0xB8C1,
-       0x567B, 0xE0E7,
-       0x567C, 0xE0E8,
-       0x5685, 0xE0E9,
-       0x5686, 0xE0E3,
-       0x568E, 0xBABF,
-       0x568F, 0xCCE7,
-       0x5693, 0xE0EA,
-       0x56A3, 0xCFF9,
-       0x56AF, 0xE0EB,
-       0x56B7, 0xC8C2,
-       0x56BC, 0xBDC0,
-       0x56CA, 0xC4D2,
-       0x56D4, 0xE0EC,
-       0x56D7, 0xE0ED,
-       0x56DA, 0xC7F4,
-       0x56DB, 0xCBC4,
-       0x56DD, 0xE0EE,
-       0x56DE, 0xBBD8,
-       0x56DF, 0xD8B6,
-       0x56E0, 0xD2F2,
-       0x56E1, 0xE0EF,
-       0x56E2, 0xCDC5,
-       0x56E4, 0xB6DA,
-       0x56EB, 0xE0F1,
-       0x56ED, 0xD4B0,
-       0x56F0, 0xC0A7,
-       0x56F1, 0xB4D1,
-       0x56F4, 0xCEA7,
-       0x56F5, 0xE0F0,
-       0x56F9, 0xE0F2,
-       0x56FA, 0xB9CC,
-       0x56FD, 0xB9FA,
-       0x56FE, 0xCDBC,
-       0x56FF, 0xE0F3,
-       0x5703, 0xC6D4,
-       0x5704, 0xE0F4,
-       0x5706, 0xD4B2,
-       0x5708, 0xC8A6,
-       0x5709, 0xE0F6,
-       0x570A, 0xE0F5,
-       0x571C, 0xE0F7,
-       0x571F, 0xCDC1,
-       0x5723, 0xCAA5,
-       0x5728, 0xD4DA,
-       0x5729, 0xDBD7,
-       0x572A, 0xDBD9,
-       0x572C, 0xDBD8,
-       0x572D, 0xB9E7,
-       0x572E, 0xDBDC,
-       0x572F, 0xDBDD,
-       0x5730, 0xB5D8,
-       0x5733, 0xDBDA,
-       0x5739, 0xDBDB,
-       0x573A, 0xB3A1,
-       0x573B, 0xDBDF,
-       0x573E, 0xBBF8,
-       0x5740, 0xD6B7,
-       0x5742, 0xDBE0,
-       0x5747, 0xBEF9,
-       0x574A, 0xB7BB,
-       0x574C, 0xDBD0,
-       0x574D, 0xCCAE,
-       0x574E, 0xBFB2,
-       0x574F, 0xBBB5,
-       0x5750, 0xD7F8,
-       0x5751, 0xBFD3,
-       0x5757, 0xBFE9,
-       0x575A, 0xBCE1,
-       0x575B, 0xCCB3,
-       0x575C, 0xDBDE,
-       0x575D, 0xB0D3,
-       0x575E, 0xCEEB,
-       0x575F, 0xB7D8,
-       0x5760, 0xD7B9,
-       0x5761, 0xC6C2,
-       0x5764, 0xC0A4,
-       0x5766, 0xCCB9,
-       0x5768, 0xDBE7,
-       0x5769, 0xDBE1,
-       0x576A, 0xC6BA,
-       0x576B, 0xDBE3,
-       0x576D, 0xDBE8,
-       0x576F, 0xC5F7,
-       0x5773, 0xDBEA,
-       0x5776, 0xDBE9,
-       0x5777, 0xBFC0,
-       0x577B, 0xDBE6,
-       0x577C, 0xDBE5,
-       0x5782, 0xB4B9,
-       0x5783, 0xC0AC,
-       0x5784, 0xC2A2,
-       0x5785, 0xDBE2,
-       0x5786, 0xDBE4,
-       0x578B, 0xD0CD,
-       0x578C, 0xDBED,
-       0x5792, 0xC0DD,
-       0x5793, 0xDBF2,
-       0x579B, 0xB6E2,
-       0x57A0, 0xDBF3,
-       0x57A1, 0xDBD2,
-       0x57A2, 0xB9B8,
-       0x57A3, 0xD4AB,
-       0x57A4, 0xDBEC,
-       0x57A6, 0xBFD1,
-       0x57A7, 0xDBF0,
-       0x57A9, 0xDBD1,
-       0x57AB, 0xB5E6,
-       0x57AD, 0xDBEB,
-       0x57AE, 0xBFE5,
-       0x57B2, 0xDBEE,
-       0x57B4, 0xDBF1,
-       0x57B8, 0xDBF9,
-       0x57C2, 0xB9A1,
-       0x57C3, 0xB0A3,
-       0x57CB, 0xC2F1,
-       0x57CE, 0xB3C7,
-       0x57CF, 0xDBEF,
-       0x57D2, 0xDBF8,
-       0x57D4, 0xC6D2,
-       0x57D5, 0xDBF4,
-       0x57D8, 0xDBF5,
-       0x57D9, 0xDBF7,
-       0x57DA, 0xDBF6,
-       0x57DD, 0xDBFE,
-       0x57DF, 0xD3F2,
-       0x57E0, 0xB2BA,
-       0x57E4, 0xDBFD,
-       0x57ED, 0xDCA4,
-       0x57EF, 0xDBFB,
-       0x57F4, 0xDBFA,
-       0x57F8, 0xDBFC,
-       0x57F9, 0xC5E0,
-       0x57FA, 0xBBF9,
-       0x57FD, 0xDCA3,
-       0x5800, 0xDCA5,
-       0x5802, 0xCCC3,
-       0x5806, 0xB6D1,
-       0x5807, 0xDDC0,
-       0x580B, 0xDCA1,
-       0x580D, 0xDCA2,
-       0x5811, 0xC7B5,
-       0x5815, 0xB6E9,
-       0x5819, 0xDCA7,
-       0x581E, 0xDCA6,
-       0x5820, 0xDCA9,
-       0x5821, 0xB1A4,
-       0x5824, 0xB5CC,
-       0x582A, 0xBFB0,
-       0x5830, 0xD1DF,
-       0x5835, 0xB6C2,
-       0x5844, 0xDCA8,
-       0x584C, 0xCBFA,
-       0x584D, 0xEBF3,
-       0x5851, 0xCBDC,
-       0x5854, 0xCBFE,
-       0x5858, 0xCCC1,
-       0x585E, 0xC8FB,
-       0x5865, 0xDCAA,
-       0x586B, 0xCCEE,
-       0x586C, 0xDCAB,
-       0x587E, 0xDBD3,
-       0x5880, 0xDCAF,
-       0x5881, 0xDCAC,
-       0x5883, 0xBEB3,
-       0x5885, 0xCAFB,
-       0x5889, 0xDCAD,
-       0x5892, 0xC9CA,
-       0x5893, 0xC4B9,
-       0x5899, 0xC7BD,
-       0x589A, 0xDCAE,
-       0x589E, 0xD4F6,
-       0x589F, 0xD0E6,
-       0x58A8, 0xC4AB,
-       0x58A9, 0xB6D5,
-       0x58BC, 0xDBD4,
-       0x58C1, 0xB1DA,
-       0x58C5, 0xDBD5,
-       0x58D1, 0xDBD6,
-       0x58D5, 0xBABE,
-       0x58E4, 0xC8C0,
-       0x58EB, 0xCABF,
-       0x58EC, 0xC8C9,
-       0x58EE, 0xD7B3,
-       0x58F0, 0xC9F9,
-       0x58F3, 0xBFC7,
-       0x58F6, 0xBAF8,
-       0x58F9, 0xD2BC,
-       0x5902, 0xE2BA,
-       0x5904, 0xB4A6,
-       0x5907, 0xB1B8,
-       0x590D, 0xB8B4,
-       0x590F, 0xCFC4,
-       0x5914, 0xD9E7,
-       0x5915, 0xCFA6,
-       0x5916, 0xCDE2,
-       0x5919, 0xD9ED,
-       0x591A, 0xB6E0,
-       0x591C, 0xD2B9,
-       0x591F, 0xB9BB,
-       0x5924, 0xE2B9,
-       0x5925, 0xE2B7,
-       0x5927, 0xB4F3,
-       0x5929, 0xCCEC,
-       0x592A, 0xCCAB,
-       0x592B, 0xB7F2,
-       0x592D, 0xD8B2,
-       0x592E, 0xD1EB,
-       0x592F, 0xBABB,
-       0x5931, 0xCAA7,
-       0x5934, 0xCDB7,
-       0x5937, 0xD2C4,
-       0x5938, 0xBFE4,
-       0x5939, 0xBCD0,
-       0x593A, 0xB6E1,
-       0x593C, 0xDEC5,
-       0x5941, 0xDEC6,
-       0x5942, 0xDBBC,
-       0x5944, 0xD1D9,
-       0x5947, 0xC6E6,
-       0x5948, 0xC4CE,
-       0x5949, 0xB7EE,
-       0x594B, 0xB7DC,
-       0x594E, 0xBFFC,
-       0x594F, 0xD7E0,
-       0x5951, 0xC6F5,
-       0x5954, 0xB1BC,
-       0x5955, 0xDEC8,
-       0x5956, 0xBDB1,
-       0x5957, 0xCCD7,
-       0x5958, 0xDECA,
-       0x595A, 0xDEC9,
-       0x5960, 0xB5EC,
-       0x5962, 0xC9DD,
-       0x5965, 0xB0C2,
-       0x5973, 0xC5AE,
-       0x5974, 0xC5AB,
-       0x5976, 0xC4CC,
-       0x5978, 0xBCE9,
-       0x5979, 0xCBFD,
-       0x597D, 0xBAC3,
-       0x5981, 0xE5F9,
-       0x5982, 0xC8E7,
-       0x5983, 0xE5FA,
-       0x5984, 0xCDFD,
-       0x5986, 0xD7B1,
-       0x5987, 0xB8BE,
-       0x5988, 0xC2E8,
-       0x598A, 0xC8D1,
-       0x598D, 0xE5FB,
-       0x5992, 0xB6CA,
-       0x5993, 0xBCCB,
-       0x5996, 0xD1FD,
-       0x5997, 0xE6A1,
-       0x5999, 0xC3EE,
-       0x599E, 0xE6A4,
-       0x59A3, 0xE5FE,
-       0x59A4, 0xE6A5,
-       0x59A5, 0xCDD7,
-       0x59A8, 0xB7C1,
-       0x59A9, 0xE5FC,
-       0x59AA, 0xE5FD,
-       0x59AB, 0xE6A3,
-       0x59AE, 0xC4DD,
-       0x59AF, 0xE6A8,
-       0x59B2, 0xE6A7,
-       0x59B9, 0xC3C3,
-       0x59BB, 0xC6DE,
-       0x59BE, 0xE6AA,
-       0x59C6, 0xC4B7,
-       0x59CA, 0xE6A2,
-       0x59CB, 0xCABC,
-       0x59D0, 0xBDE3,
-       0x59D1, 0xB9C3,
-       0x59D2, 0xE6A6,
-       0x59D3, 0xD0D5,
-       0x59D4, 0xCEAF,
-       0x59D7, 0xE6A9,
-       0x59D8, 0xE6B0,
-       0x59DA, 0xD2A6,
-       0x59DC, 0xBDAA,
-       0x59DD, 0xE6AD,
-       0x59E3, 0xE6AF,
-       0x59E5, 0xC0D1,
-       0x59E8, 0xD2CC,
-       0x59EC, 0xBCA7,
-       0x59F9, 0xE6B1,
-       0x59FB, 0xD2F6,
-       0x59FF, 0xD7CB,
-       0x5A01, 0xCDFE,
-       0x5A03, 0xCDDE,
-       0x5A04, 0xC2A6,
-       0x5A05, 0xE6AB,
-       0x5A06, 0xE6AC,
-       0x5A07, 0xBDBF,
-       0x5A08, 0xE6AE,
-       0x5A09, 0xE6B3,
-       0x5A0C, 0xE6B2,
-       0x5A11, 0xE6B6,
-       0x5A13, 0xE6B8,
-       0x5A18, 0xC4EF,
-       0x5A1C, 0xC4C8,
-       0x5A1F, 0xBEEA,
-       0x5A20, 0xC9EF,
-       0x5A23, 0xE6B7,
-       0x5A25, 0xB6F0,
-       0x5A29, 0xC3E4,
-       0x5A31, 0xD3E9,
-       0x5A32, 0xE6B4,
-       0x5A34, 0xE6B5,
-       0x5A36, 0xC8A2,
-       0x5A3C, 0xE6BD,
-       0x5A40, 0xE6B9,
-       0x5A46, 0xC6C5,
-       0x5A49, 0xCDF1,
-       0x5A4A, 0xE6BB,
-       0x5A55, 0xE6BC,
-       0x5A5A, 0xBBE9,
-       0x5A62, 0xE6BE,
-       0x5A67, 0xE6BA,
-       0x5A6A, 0xC0B7,
-       0x5A74, 0xD3A4,
-       0x5A75, 0xE6BF,
-       0x5A76, 0xC9F4,
-       0x5A77, 0xE6C3,
-       0x5A7A, 0xE6C4,
-       0x5A7F, 0xD0F6,
-       0x5A92, 0xC3BD,
-       0x5A9A, 0xC3C4,
-       0x5A9B, 0xE6C2,
-       0x5AAA, 0xE6C1,
-       0x5AB2, 0xE6C7,
-       0x5AB3, 0xCFB1,
-       0x5AB5, 0xEBF4,
-       0x5AB8, 0xE6CA,
-       0x5ABE, 0xE6C5,
-       0x5AC1, 0xBCDE,
-       0x5AC2, 0xC9A9,
-       0x5AC9, 0xBCB5,
-       0x5ACC, 0xCFD3,
-       0x5AD2, 0xE6C8,
-       0x5AD4, 0xE6C9,
-       0x5AD6, 0xE6CE,
-       0x5AD8, 0xE6D0,
-       0x5ADC, 0xE6D1,
-       0x5AE0, 0xE6CB,
-       0x5AE1, 0xB5D5,
-       0x5AE3, 0xE6CC,
-       0x5AE6, 0xE6CF,
-       0x5AE9, 0xC4DB,
-       0x5AEB, 0xE6C6,
-       0x5AF1, 0xE6CD,
-       0x5B09, 0xE6D2,
-       0x5B16, 0xE6D4,
-       0x5B17, 0xE6D3,
-       0x5B32, 0xE6D5,
-       0x5B34, 0xD9F8,
-       0x5B37, 0xE6D6,
-       0x5B40, 0xE6D7,
-       0x5B50, 0xD7D3,
-       0x5B51, 0xE6DD,
-       0x5B53, 0xE6DE,
-       0x5B54, 0xBFD7,
-       0x5B55, 0xD4D0,
-       0x5B57, 0xD7D6,
-       0x5B58, 0xB4E6,
-       0x5B59, 0xCBEF,
-       0x5B5A, 0xE6DA,
-       0x5B5B, 0xD8C3,
-       0x5B5C, 0xD7CE,
-       0x5B5D, 0xD0A2,
-       0x5B5F, 0xC3CF,
-       0x5B62, 0xE6DF,
-       0x5B63, 0xBCBE,
-       0x5B64, 0xB9C2,
-       0x5B65, 0xE6DB,
-       0x5B66, 0xD1A7,
-       0x5B69, 0xBAA2,
-       0x5B6A, 0xC2CF,
-       0x5B6C, 0xD8AB,
-       0x5B70, 0xCAEB,
-       0x5B71, 0xE5EE,
-       0x5B73, 0xE6DC,
-       0x5B75, 0xB7F5,
-       0x5B7A, 0xC8E6,
-       0x5B7D, 0xC4F5,
-       0x5B80, 0xE5B2,
-       0x5B81, 0xC4FE,
-       0x5B83, 0xCBFC,
-       0x5B84, 0xE5B3,
-       0x5B85, 0xD5AC,
-       0x5B87, 0xD3EE,
-       0x5B88, 0xCAD8,
-       0x5B89, 0xB0B2,
-       0x5B8B, 0xCBCE,
-       0x5B8C, 0xCDEA,
-       0x5B8F, 0xBAEA,
-       0x5B93, 0xE5B5,
-       0x5B95, 0xE5B4,
-       0x5B97, 0xD7DA,
-       0x5B98, 0xB9D9,
-       0x5B99, 0xD6E6,
-       0x5B9A, 0xB6A8,
-       0x5B9B, 0xCDF0,
-       0x5B9C, 0xD2CB,
-       0x5B9D, 0xB1A6,
-       0x5B9E, 0xCAB5,
-       0x5BA0, 0xB3E8,
-       0x5BA1, 0xC9F3,
-       0x5BA2, 0xBFCD,
-       0x5BA3, 0xD0FB,
-       0x5BA4, 0xCAD2,
-       0x5BA5, 0xE5B6,
-       0x5BA6, 0xBBC2,
-       0x5BAA, 0xCFDC,
-       0x5BAB, 0xB9AC,
-       0x5BB0, 0xD4D7,
-       0x5BB3, 0xBAA6,
-       0x5BB4, 0xD1E7,
-       0x5BB5, 0xCFFC,
-       0x5BB6, 0xBCD2,
-       0x5BB8, 0xE5B7,
-       0x5BB9, 0xC8DD,
-       0x5BBD, 0xBFED,
-       0x5BBE, 0xB1F6,
-       0x5BBF, 0xCBDE,
-       0x5BC2, 0xBCC5,
-       0x5BC4, 0xBCC4,
-       0x5BC5, 0xD2FA,
-       0x5BC6, 0xC3DC,
-       0x5BC7, 0xBFDC,
-       0x5BCC, 0xB8BB,
-       0x5BD0, 0xC3C2,
-       0x5BD2, 0xBAAE,
-       0x5BD3, 0xD4A2,
-       0x5BDD, 0xC7DE,
-       0x5BDE, 0xC4AF,
-       0x5BDF, 0xB2EC,
-       0x5BE1, 0xB9D1,
-       0x5BE4, 0xE5BB,
-       0x5BE5, 0xC1C8,
-       0x5BE8, 0xD5AF,
-       0x5BEE, 0xE5BC,
-       0x5BF0, 0xE5BE,
-       0x5BF8, 0xB4E7,
-       0x5BF9, 0xB6D4,
-       0x5BFA, 0xCBC2,
-       0x5BFB, 0xD1B0,
-       0x5BFC, 0xB5BC,
-       0x5BFF, 0xCAD9,
-       0x5C01, 0xB7E2,
-       0x5C04, 0xC9E4,
-       0x5C06, 0xBDAB,
-       0x5C09, 0xCEBE,
-       0x5C0A, 0xD7F0,
-       0x5C0F, 0xD0A1,
-       0x5C11, 0xC9D9,
-       0x5C14, 0xB6FB,
-       0x5C15, 0xE6D8,
-       0x5C16, 0xBCE2,
-       0x5C18, 0xB3BE,
-       0x5C1A, 0xC9D0,
-       0x5C1C, 0xE6D9,
-       0x5C1D, 0xB3A2,
-       0x5C22, 0xDECC,
-       0x5C24, 0xD3C8,
-       0x5C25, 0xDECD,
-       0x5C27, 0xD2A2,
-       0x5C2C, 0xDECE,
-       0x5C31, 0xBECD,
-       0x5C34, 0xDECF,
-       0x5C38, 0xCAAC,
-       0x5C39, 0xD2FC,
-       0x5C3A, 0xB3DF,
-       0x5C3B, 0xE5EA,
-       0x5C3C, 0xC4E1,
-       0x5C3D, 0xBEA1,
-       0x5C3E, 0xCEB2,
-       0x5C3F, 0xC4F2,
-       0x5C40, 0xBED6,
-       0x5C41, 0xC6A8,
-       0x5C42, 0xB2E3,
-       0x5C45, 0xBED3,
-       0x5C48, 0xC7FC,
-       0x5C49, 0xCCEB,
-       0x5C4A, 0xBDEC,
-       0x5C4B, 0xCEDD,
-       0x5C4E, 0xCABA,
-       0x5C4F, 0xC6C1,
-       0x5C50, 0xE5EC,
-       0x5C51, 0xD0BC,
-       0x5C55, 0xD5B9,
-       0x5C59, 0xE5ED,
-       0x5C5E, 0xCAF4,
-       0x5C60, 0xCDC0,
-       0x5C61, 0xC2C5,
-       0x5C63, 0xE5EF,
-       0x5C65, 0xC2C4,
-       0x5C66, 0xE5F0,
-       0x5C6E, 0xE5F8,
-       0x5C6F, 0xCDCD,
-       0x5C71, 0xC9BD,
-       0x5C79, 0xD2D9,
-       0x5C7A, 0xE1A8,
-       0x5C7F, 0xD3EC,
-       0x5C81, 0xCBEA,
-       0x5C82, 0xC6F1,
-       0x5C88, 0xE1AC,
-       0x5C8C, 0xE1A7,
-       0x5C8D, 0xE1A9,
-       0x5C90, 0xE1AA,
-       0x5C91, 0xE1AF,
-       0x5C94, 0xB2ED,
-       0x5C96, 0xE1AB,
-       0x5C97, 0xB8DA,
-       0x5C98, 0xE1AD,
-       0x5C99, 0xE1AE,
-       0x5C9A, 0xE1B0,
-       0x5C9B, 0xB5BA,
-       0x5C9C, 0xE1B1,
-       0x5CA2, 0xE1B3,
-       0x5CA3, 0xE1B8,
-       0x5CA9, 0xD1D2,
-       0x5CAB, 0xE1B6,
-       0x5CAC, 0xE1B5,
-       0x5CAD, 0xC1EB,
-       0x5CB1, 0xE1B7,
-       0x5CB3, 0xD4C0,
-       0x5CB5, 0xE1B2,
-       0x5CB7, 0xE1BA,
-       0x5CB8, 0xB0B6,
-       0x5CBD, 0xE1B4,
-       0x5CBF, 0xBFF9,
-       0x5CC1, 0xE1B9,
-       0x5CC4, 0xE1BB,
-       0x5CCB, 0xE1BE,
-       0x5CD2, 0xE1BC,
-       0x5CD9, 0xD6C5,
-       0x5CE1, 0xCFBF,
-       0x5CE4, 0xE1BD,
-       0x5CE5, 0xE1BF,
-       0x5CE6, 0xC2CD,
-       0x5CE8, 0xB6EB,
-       0x5CEA, 0xD3F8,
-       0x5CED, 0xC7CD,
-       0x5CF0, 0xB7E5,
-       0x5CFB, 0xBEFE,
-       0x5D02, 0xE1C0,
-       0x5D03, 0xE1C1,
-       0x5D06, 0xE1C7,
-       0x5D07, 0xB3E7,
-       0x5D0E, 0xC6E9,
-       0x5D14, 0xB4DE,
-       0x5D16, 0xD1C2,
-       0x5D1B, 0xE1C8,
-       0x5D1E, 0xE1C6,
-       0x5D24, 0xE1C5,
-       0x5D26, 0xE1C3,
-       0x5D27, 0xE1C2,
-       0x5D29, 0xB1C0,
-       0x5D2D, 0xD5B8,
-       0x5D2E, 0xE1C4,
-       0x5D34, 0xE1CB,
-       0x5D3D, 0xE1CC,
-       0x5D3E, 0xE1CA,
-       0x5D47, 0xEFFA,
-       0x5D4A, 0xE1D3,
-       0x5D4B, 0xE1D2,
-       0x5D4C, 0xC7B6,
-       0x5D58, 0xE1C9,
-       0x5D5B, 0xE1CE,
-       0x5D5D, 0xE1D0,
-       0x5D69, 0xE1D4,
-       0x5D6B, 0xE1D1,
-       0x5D6C, 0xE1CD,
-       0x5D6F, 0xE1CF,
-       0x5D74, 0xE1D5,
-       0x5D82, 0xE1D6,
-       0x5D99, 0xE1D7,
-       0x5D9D, 0xE1D8,
-       0x5DB7, 0xE1DA,
-       0x5DC5, 0xE1DB,
-       0x5DCD, 0xCEA1,
-       0x5DDB, 0xE7DD,
-       0x5DDD, 0xB4A8,
-       0x5DDE, 0xD6DD,
-       0x5DE1, 0xD1B2,
-       0x5DE2, 0xB3B2,
-       0x5DE5, 0xB9A4,
-       0x5DE6, 0xD7F3,
-       0x5DE7, 0xC7C9,
-       0x5DE8, 0xBEDE,
-       0x5DE9, 0xB9AE,
-       0x5DEB, 0xCED7,
-       0x5DEE, 0xB2EE,
-       0x5DEF, 0xDBCF,
-       0x5DF1, 0xBCBA,
-       0x5DF2, 0xD2D1,
-       0x5DF3, 0xCBC8,
-       0x5DF4, 0xB0CD,
-       0x5DF7, 0xCFEF,
-       0x5DFD, 0xD9E3,
-       0x5DFE, 0xBDED,
-       0x5E01, 0xB1D2,
-       0x5E02, 0xCAD0,
-       0x5E03, 0xB2BC,
-       0x5E05, 0xCBA7,
-       0x5E06, 0xB7AB,
-       0x5E08, 0xCAA6,
-       0x5E0C, 0xCFA3,
-       0x5E0F, 0xE0F8,
-       0x5E10, 0xD5CA,
-       0x5E11, 0xE0FB,
-       0x5E14, 0xE0FA,
-       0x5E15, 0xC5C1,
-       0x5E16, 0xCCFB,
-       0x5E18, 0xC1B1,
-       0x5E19, 0xE0F9,
-       0x5E1A, 0xD6E3,
-       0x5E1B, 0xB2AF,
-       0x5E1C, 0xD6C4,
-       0x5E1D, 0xB5DB,
-       0x5E26, 0xB4F8,
-       0x5E27, 0xD6A1,
-       0x5E2D, 0xCFAF,
-       0x5E2E, 0xB0EF,
-       0x5E31, 0xE0FC,
-       0x5E37, 0xE1A1,
-       0x5E38, 0xB3A3,
-       0x5E3B, 0xE0FD,
-       0x5E3C, 0xE0FE,
-       0x5E3D, 0xC3B1,
-       0x5E42, 0xC3DD,
-       0x5E44, 0xE1A2,
-       0x5E45, 0xB7F9,
-       0x5E4C, 0xBBCF,
-       0x5E54, 0xE1A3,
-       0x5E55, 0xC4BB,
-       0x5E5B, 0xE1A4,
-       0x5E5E, 0xE1A5,
-       0x5E61, 0xE1A6,
-       0x5E62, 0xB4B1,
-       0x5E72, 0xB8C9,
-       0x5E73, 0xC6BD,
-       0x5E74, 0xC4EA,
-       0x5E76, 0xB2A2,
-       0x5E78, 0xD0D2,
-       0x5E7A, 0xE7DB,
-       0x5E7B, 0xBBC3,
-       0x5E7C, 0xD3D7,
-       0x5E7D, 0xD3C4,
-       0x5E7F, 0xB9E3,
-       0x5E80, 0xE2CF,
-       0x5E84, 0xD7AF,
-       0x5E86, 0xC7EC,
-       0x5E87, 0xB1D3,
-       0x5E8A, 0xB4B2,
-       0x5E8B, 0xE2D1,
-       0x5E8F, 0xD0F2,
-       0x5E90, 0xC2AE,
-       0x5E91, 0xE2D0,
-       0x5E93, 0xBFE2,
-       0x5E94, 0xD3A6,
-       0x5E95, 0xB5D7,
-       0x5E96, 0xE2D2,
-       0x5E97, 0xB5EA,
-       0x5E99, 0xC3ED,
-       0x5E9A, 0xB8FD,
-       0x5E9C, 0xB8AE,
-       0x5E9E, 0xC5D3,
-       0x5E9F, 0xB7CF,
-       0x5EA0, 0xE2D4,
-       0x5EA5, 0xE2D3,
-       0x5EA6, 0xB6C8,
-       0x5EA7, 0xD7F9,
-       0x5EAD, 0xCDA5,
-       0x5EB3, 0xE2D8,
-       0x5EB5, 0xE2D6,
-       0x5EB6, 0xCAFC,
-       0x5EB7, 0xBFB5,
-       0x5EB8, 0xD3B9,
-       0x5EB9, 0xE2D5,
-       0x5EBE, 0xE2D7,
-       0x5EC9, 0xC1AE,
-       0x5ECA, 0xC0C8,
-       0x5ED1, 0xE2DB,
-       0x5ED2, 0xE2DA,
-       0x5ED3, 0xC0AA,
-       0x5ED6, 0xC1CE,
-       0x5EDB, 0xE2DC,
-       0x5EE8, 0xE2DD,
-       0x5EEA, 0xE2DE,
-       0x5EF4, 0xDBC8,
-       0x5EF6, 0xD1D3,
-       0x5EF7, 0xCDA2,
-       0x5EFA, 0xBDA8,
-       0x5EFE, 0xDEC3,
-       0x5EFF, 0xD8A5,
-       0x5F00, 0xBFAA,
-       0x5F01, 0xDBCD,
-       0x5F02, 0xD2EC,
-       0x5F03, 0xC6FA,
-       0x5F04, 0xC5AA,
-       0x5F08, 0xDEC4,
-       0x5F0A, 0xB1D7,
-       0x5F0B, 0xDFAE,
-       0x5F0F, 0xCABD,
-       0x5F11, 0xDFB1,
-       0x5F13, 0xB9AD,
-       0x5F15, 0xD2FD,
-       0x5F17, 0xB8A5,
-       0x5F18, 0xBAEB,
-       0x5F1B, 0xB3DA,
-       0x5F1F, 0xB5DC,
-       0x5F20, 0xD5C5,
-       0x5F25, 0xC3D6,
-       0x5F26, 0xCFD2,
-       0x5F27, 0xBBA1,
-       0x5F29, 0xE5F3,
-       0x5F2A, 0xE5F2,
-       0x5F2D, 0xE5F4,
-       0x5F2F, 0xCDE4,
-       0x5F31, 0xC8F5,
-       0x5F39, 0xB5AF,
-       0x5F3A, 0xC7BF,
-       0x5F3C, 0xE5F6,
-       0x5F40, 0xECB0,
-       0x5F50, 0xE5E6,
-       0x5F52, 0xB9E9,
-       0x5F53, 0xB5B1,
-       0x5F55, 0xC2BC,
-       0x5F56, 0xE5E8,
-       0x5F57, 0xE5E7,
-       0x5F58, 0xE5E9,
-       0x5F5D, 0xD2CD,
-       0x5F61, 0xE1EA,
-       0x5F62, 0xD0CE,
-       0x5F64, 0xCDAE,
-       0x5F66, 0xD1E5,
-       0x5F69, 0xB2CA,
-       0x5F6A, 0xB1EB,
-       0x5F6C, 0xB1F2,
-       0x5F6D, 0xC5ED,
-       0x5F70, 0xD5C3,
-       0x5F71, 0xD3B0,
-       0x5F73, 0xE1DC,
-       0x5F77, 0xE1DD,
-       0x5F79, 0xD2DB,
-       0x5F7B, 0xB3B9,
-       0x5F7C, 0xB1CB,
-       0x5F80, 0xCDF9,
-       0x5F81, 0xD5F7,
-       0x5F82, 0xE1DE,
-       0x5F84, 0xBEB6,
-       0x5F85, 0xB4FD,
-       0x5F87, 0xE1DF,
-       0x5F88, 0xBADC,
-       0x5F89, 0xE1E0,
-       0x5F8A, 0xBBB2,
-       0x5F8B, 0xC2C9,
-       0x5F8C, 0xE1E1,
-       0x5F90, 0xD0EC,
-       0x5F92, 0xCDBD,
-       0x5F95, 0xE1E2,
-       0x5F97, 0xB5C3,
-       0x5F98, 0xC5C7,
-       0x5F99, 0xE1E3,
-       0x5F9C, 0xE1E4,
-       0x5FA1, 0xD3F9,
-       0x5FA8, 0xE1E5,
-       0x5FAA, 0xD1AD,
-       0x5FAD, 0xE1E6,
-       0x5FAE, 0xCEA2,
-       0x5FB5, 0xE1E7,
-       0x5FB7, 0xB5C2,
-       0x5FBC, 0xE1E8,
-       0x5FBD, 0xBBD5,
-       0x5FC3, 0xD0C4,
-       0x5FC4, 0xE2E0,
-       0x5FC5, 0xB1D8,
-       0x5FC6, 0xD2E4,
-       0x5FC9, 0xE2E1,
-       0x5FCC, 0xBCC9,
-       0x5FCD, 0xC8CC,
-       0x5FCF, 0xE2E3,
-       0x5FD0, 0xECFE,
-       0x5FD1, 0xECFD,
-       0x5FD2, 0xDFAF,
-       0x5FD6, 0xE2E2,
-       0x5FD7, 0xD6BE,
-       0x5FD8, 0xCDFC,
-       0x5FD9, 0xC3A6,
-       0x5FDD, 0xE3C3,
-       0x5FE0, 0xD6D2,
-       0x5FE1, 0xE2E7,
-       0x5FE4, 0xE2E8,
-       0x5FE7, 0xD3C7,
-       0x5FEA, 0xE2EC,
-       0x5FEB, 0xBFEC,
-       0x5FED, 0xE2ED,
-       0x5FEE, 0xE2E5,
-       0x5FF1, 0xB3C0,
-       0x5FF5, 0xC4EE,
-       0x5FF8, 0xE2EE,
-       0x5FFB, 0xD0C3,
-       0x5FFD, 0xBAF6,
-       0x5FFE, 0xE2E9,
-       0x5FFF, 0xB7DE,
-       0x6000, 0xBBB3,
-       0x6001, 0xCCAC,
-       0x6002, 0xCBCB,
-       0x6003, 0xE2E4,
-       0x6004, 0xE2E6,
-       0x6005, 0xE2EA,
-       0x6006, 0xE2EB,
-       0x600A, 0xE2F7,
-       0x600D, 0xE2F4,
-       0x600E, 0xD4F5,
-       0x600F, 0xE2F3,
-       0x6012, 0xC5AD,
-       0x6014, 0xD5FA,
-       0x6015, 0xC5C2,
-       0x6016, 0xB2C0,
-       0x6019, 0xE2EF,
-       0x601B, 0xE2F2,
-       0x601C, 0xC1AF,
-       0x601D, 0xCBBC,
-       0x6020, 0xB5A1,
-       0x6021, 0xE2F9,
-       0x6025, 0xBCB1,
-       0x6026, 0xE2F1,
-       0x6027, 0xD0D4,
-       0x6028, 0xD4B9,
-       0x6029, 0xE2F5,
-       0x602A, 0xB9D6,
-       0x602B, 0xE2F6,
-       0x602F, 0xC7D3,
-       0x6035, 0xE2F0,
-       0x603B, 0xD7DC,
-       0x603C, 0xEDA1,
-       0x603F, 0xE2F8,
-       0x6041, 0xEDA5,
-       0x6042, 0xE2FE,
-       0x6043, 0xCAD1,
-       0x604B, 0xC1B5,
-       0x604D, 0xBBD0,
-       0x6050, 0xBFD6,
-       0x6052, 0xBAE3,
-       0x6055, 0xCBA1,
-       0x6059, 0xEDA6,
-       0x605A, 0xEDA3,
-       0x605D, 0xEDA2,
-       0x6062, 0xBBD6,
-       0x6063, 0xEDA7,
-       0x6064, 0xD0F4,
-       0x6067, 0xEDA4,
-       0x6068, 0xBADE,
-       0x6069, 0xB6F7,
-       0x606A, 0xE3A1,
-       0x606B, 0xB6B2,
-       0x606C, 0xCCF1,
-       0x606D, 0xB9A7,
-       0x606F, 0xCFA2,
-       0x6070, 0xC7A1,
-       0x6073, 0xBFD2,
-       0x6076, 0xB6F1,
-       0x6078, 0xE2FA,
-       0x6079, 0xE2FB,
-       0x607A, 0xE2FD,
-       0x607B, 0xE2FC,
-       0x607C, 0xC4D5,
-       0x607D, 0xE3A2,
-       0x607F, 0xD3C1,
-       0x6083, 0xE3A7,
-       0x6084, 0xC7C4,
-       0x6089, 0xCFA4,
-       0x608C, 0xE3A9,
-       0x608D, 0xBAB7,
-       0x6092, 0xE3A8,
-       0x6094, 0xBBDA,
-       0x6096, 0xE3A3,
-       0x609A, 0xE3A4,
-       0x609B, 0xE3AA,
-       0x609D, 0xE3A6,
-       0x609F, 0xCEF2,
-       0x60A0, 0xD3C6,
-       0x60A3, 0xBBBC,
-       0x60A6, 0xD4C3,
-       0x60A8, 0xC4FA,
-       0x60AB, 0xEDA8,
-       0x60AC, 0xD0FC,
-       0x60AD, 0xE3A5,
-       0x60AF, 0xC3F5,
-       0x60B1, 0xE3AD,
-       0x60B2, 0xB1AF,
-       0x60B4, 0xE3B2,
-       0x60B8, 0xBCC2,
-       0x60BB, 0xE3AC,
-       0x60BC, 0xB5BF,
-       0x60C5, 0xC7E9,
-       0x60C6, 0xE3B0,
-       0x60CA, 0xBEAA,
-       0x60CB, 0xCDEF,
-       0x60D1, 0xBBF3,
-       0x60D5, 0xCCE8,
-       0x60D8, 0xE3AF,
-       0x60DA, 0xE3B1,
-       0x60DC, 0xCFA7,
-       0x60DD, 0xE3AE,
-       0x60DF, 0xCEA9,
-       0x60E0, 0xBBDD,
-       0x60E6, 0xB5EB,
-       0x60E7, 0xBEE5,
-       0x60E8, 0xB2D2,
-       0x60E9, 0xB3CD,
-       0x60EB, 0xB1B9,
-       0x60EC, 0xE3AB,
-       0x60ED, 0xB2D1,
-       0x60EE, 0xB5AC,
-       0x60EF, 0xB9DF,
-       0x60F0, 0xB6E8,
-       0x60F3, 0xCFEB,
-       0x60F4, 0xE3B7,
-       0x60F6, 0xBBCC,
-       0x60F9, 0xC8C7,
-       0x60FA, 0xD0CA,
-       0x6100, 0xE3B8,
-       0x6101, 0xB3EE,
-       0x6106, 0xEDA9,
-       0x6108, 0xD3FA,
-       0x6109, 0xD3E4,
-       0x610D, 0xEDAA,
-       0x610E, 0xE3B9,
-       0x610F, 0xD2E2,
-       0x6115, 0xE3B5,
-       0x611A, 0xD3DE,
-       0x611F, 0xB8D0,
-       0x6120, 0xE3B3,
-       0x6123, 0xE3B6,
-       0x6124, 0xB7DF,
-       0x6126, 0xE3B4,
-       0x6127, 0xC0A2,
-       0x612B, 0xE3BA,
-       0x613F, 0xD4B8,
-       0x6148, 0xB4C8,
-       0x614A, 0xE3BB,
-       0x614C, 0xBBC5,
-       0x614E, 0xC9F7,
-       0x6151, 0xC9E5,
-       0x6155, 0xC4BD,
-       0x615D, 0xEDAB,
-       0x6162, 0xC2FD,
-       0x6167, 0xBBDB,
-       0x6168, 0xBFAE,
-       0x6170, 0xCEBF,
-       0x6175, 0xE3BC,
-       0x6177, 0xBFB6,
-       0x618B, 0xB1EF,
-       0x618E, 0xD4F7,
-       0x6194, 0xE3BE,
-       0x619D, 0xEDAD,
-       0x61A7, 0xE3BF,
-       0x61A8, 0xBAA9,
-       0x61A9, 0xEDAC,
-       0x61AC, 0xE3BD,
-       0x61B7, 0xE3C0,
-       0x61BE, 0xBAB6,
-       0x61C2, 0xB6AE,
-       0x61C8, 0xD0B8,
-       0x61CA, 0xB0C3,
-       0x61CB, 0xEDAE,
-       0x61D1, 0xEDAF,
-       0x61D2, 0xC0C1,
-       0x61D4, 0xE3C1,
-       0x61E6, 0xC5B3,
-       0x61F5, 0xE3C2,
-       0x61FF, 0xDCB2,
-       0x6206, 0xEDB0,
-       0x6208, 0xB8EA,
-       0x620A, 0xCEEC,
-       0x620B, 0xEAA7,
-       0x620C, 0xD0E7,
-       0x620D, 0xCAF9,
-       0x620E, 0xC8D6,
-       0x620F, 0xCFB7,
-       0x6210, 0xB3C9,
-       0x6211, 0xCED2,
-       0x6212, 0xBDE4,
-       0x6215, 0xE3DE,
-       0x6216, 0xBBF2,
-       0x6217, 0xEAA8,
-       0x6218, 0xD5BD,
-       0x621A, 0xC6DD,
-       0x621B, 0xEAA9,
-       0x621F, 0xEAAA,
-       0x6221, 0xEAAC,
-       0x6222, 0xEAAB,
-       0x6224, 0xEAAE,
-       0x6225, 0xEAAD,
-       0x622A, 0xBDD8,
-       0x622C, 0xEAAF,
-       0x622E, 0xC2BE,
-       0x6233, 0xB4C1,
-       0x6234, 0xB4F7,
-       0x6237, 0xBBA7,
-       0x623D, 0xECE6,
-       0x623E, 0xECE5,
-       0x623F, 0xB7BF,
-       0x6240, 0xCBF9,
-       0x6241, 0xB1E2,
-       0x6243, 0xECE7,
-       0x6247, 0xC9C8,
-       0x6248, 0xECE8,
-       0x6249, 0xECE9,
-       0x624B, 0xCAD6,
-       0x624C, 0xDED0,
-       0x624D, 0xB2C5,
-       0x624E, 0xD4FA,
-       0x6251, 0xC6CB,
-       0x6252, 0xB0C7,
-       0x6253, 0xB4F2,
-       0x6254, 0xC8D3,
-       0x6258, 0xCDD0,
-       0x625B, 0xBFB8,
-       0x6263, 0xBFDB,
-       0x6266, 0xC7A4,
-       0x6267, 0xD6B4,
-       0x6269, 0xC0A9,
-       0x626A, 0xDED1,
-       0x626B, 0xC9A8,
-       0x626C, 0xD1EF,
-       0x626D, 0xC5A4,
-       0x626E, 0xB0E7,
-       0x626F, 0xB3B6,
-       0x6270, 0xC8C5,
-       0x6273, 0xB0E2,
-       0x6276, 0xB7F6,
-       0x6279, 0xC5FA,
-       0x627C, 0xB6F3,
-       0x627E, 0xD5D2,
-       0x627F, 0xB3D0,
-       0x6280, 0xBCBC,
-       0x6284, 0xB3AD,
-       0x6289, 0xBEF1,
-       0x628A, 0xB0D1,
-       0x6291, 0xD2D6,
-       0x6292, 0xCAE3,
-       0x6293, 0xD7A5,
-       0x6295, 0xCDB6,
-       0x6296, 0xB6B6,
-       0x6297, 0xBFB9,
-       0x6298, 0xD5DB,
-       0x629A, 0xB8A7,
-       0x629B, 0xC5D7,
-       0x629F, 0xDED2,
-       0x62A0, 0xBFD9,
-       0x62A1, 0xC2D5,
-       0x62A2, 0xC7C0,
-       0x62A4, 0xBBA4,
-       0x62A5, 0xB1A8,
-       0x62A8, 0xC5EA,
-       0x62AB, 0xC5FB,
-       0x62AC, 0xCCA7,
-       0x62B1, 0xB1A7,
-       0x62B5, 0xB5D6,
-       0x62B9, 0xC4A8,
-       0x62BB, 0xDED3,
-       0x62BC, 0xD1BA,
-       0x62BD, 0xB3E9,
-       0x62BF, 0xC3F2,
-       0x62C2, 0xB7F7,
-       0x62C4, 0xD6F4,
-       0x62C5, 0xB5A3,
-       0x62C6, 0xB2F0,
-       0x62C7, 0xC4B4,
-       0x62C8, 0xC4E9,
-       0x62C9, 0xC0AD,
-       0x62CA, 0xDED4,
-       0x62CC, 0xB0E8,
-       0x62CD, 0xC5C4,
-       0x62CE, 0xC1E0,
-       0x62D0, 0xB9D5,
-       0x62D2, 0xBEDC,
-       0x62D3, 0xCDD8,
-       0x62D4, 0xB0CE,
-       0x62D6, 0xCDCF,
-       0x62D7, 0xDED6,
-       0x62D8, 0xBED0,
-       0x62D9, 0xD7BE,
-       0x62DA, 0xDED5,
-       0x62DB, 0xD5D0,
-       0x62DC, 0xB0DD,
-       0x62DF, 0xC4E2,
-       0x62E2, 0xC2A3,
-       0x62E3, 0xBCF0,
-       0x62E5, 0xD3B5,
-       0x62E6, 0xC0B9,
-       0x62E7, 0xC5A1,
-       0x62E8, 0xB2A6,
-       0x62E9, 0xD4F1,
-       0x62EC, 0xC0A8,
-       0x62ED, 0xCAC3,
-       0x62EE, 0xDED7,
-       0x62EF, 0xD5FC,
-       0x62F1, 0xB9B0,
-       0x62F3, 0xC8AD,
-       0x62F4, 0xCBA9,
-       0x62F6, 0xDED9,
-       0x62F7, 0xBFBD,
-       0x62FC, 0xC6B4,
-       0x62FD, 0xD7A7,
-       0x62FE, 0xCAB0,
-       0x62FF, 0xC4C3,
-       0x6301, 0xB3D6,
-       0x6302, 0xB9D2,
-       0x6307, 0xD6B8,
-       0x6308, 0xEAFC,
-       0x6309, 0xB0B4,
-       0x630E, 0xBFE6,
-       0x6311, 0xCCF4,
-       0x6316, 0xCDDA,
-       0x631A, 0xD6BF,
-       0x631B, 0xC2CE,
-       0x631D, 0xCECE,
-       0x631E, 0xCCA2,
-       0x631F, 0xD0AE,
-       0x6320, 0xC4D3,
-       0x6321, 0xB5B2,
-       0x6322, 0xDED8,
-       0x6323, 0xD5F5,
-       0x6324, 0xBCB7,
-       0x6325, 0xBBD3,
-       0x6328, 0xB0A4,
-       0x632A, 0xC5B2,
-       0x632B, 0xB4EC,
-       0x632F, 0xD5F1,
-       0x6332, 0xEAFD,
-       0x6339, 0xDEDA,
-       0x633A, 0xCDA6,
-       0x633D, 0xCDEC,
-       0x6342, 0xCEE6,
-       0x6343, 0xDEDC,
-       0x6345, 0xCDB1,
-       0x6346, 0xC0A6,
-       0x6349, 0xD7BD,
-       0x634B, 0xDEDB,
-       0x634C, 0xB0C6,
-       0x634D, 0xBAB4,
-       0x634E, 0xC9D3,
-       0x634F, 0xC4F3,
-       0x6350, 0xBEE8,
-       0x6355, 0xB2B6,
-       0x635E, 0xC0CC,
-       0x635F, 0xCBF0,
-       0x6361, 0xBCF1,
-       0x6362, 0xBBBB,
-       0x6363, 0xB5B7,
-       0x6367, 0xC5F5,
-       0x6369, 0xDEE6,
-       0x636D, 0xDEE3,
-       0x636E, 0xBEDD,
-       0x6371, 0xDEDF,
-       0x6376, 0xB4B7,
-       0x6377, 0xBDDD,
-       0x637A, 0xDEE0,
-       0x637B, 0xC4ED,
-       0x6380, 0xCFC6,
-       0x6382, 0xB5E0,
-       0x6387, 0xB6DE,
-       0x6388, 0xCADA,
-       0x6389, 0xB5F4,
-       0x638A, 0xDEE5,
-       0x638C, 0xD5C6,
-       0x638E, 0xDEE1,
-       0x638F, 0xCCCD,
-       0x6390, 0xC6FE,
-       0x6392, 0xC5C5,
-       0x6396, 0xD2B4,
-       0x6398, 0xBEF2,
-       0x63A0, 0xC2D3,
-       0x63A2, 0xCCBD,
-       0x63A3, 0xB3B8,
-       0x63A5, 0xBDD3,
-       0x63A7, 0xBFD8,
-       0x63A8, 0xCDC6,
-       0x63A9, 0xD1DA,
-       0x63AA, 0xB4EB,
-       0x63AC, 0xDEE4,
-       0x63AD, 0xDEDD,
-       0x63AE, 0xDEE7,
-       0x63B0, 0xEAFE,
-       0x63B3, 0xC2B0,
-       0x63B4, 0xDEE2,
-       0x63B7, 0xD6C0,
-       0x63B8, 0xB5A7,
-       0x63BA, 0xB2F4,
-       0x63BC, 0xDEE8,
-       0x63BE, 0xDEF2,
-       0x63C4, 0xDEED,
-       0x63C6, 0xDEF1,
-       0x63C9, 0xC8E0,
-       0x63CD, 0xD7E1,
-       0x63CE, 0xDEEF,
-       0x63CF, 0xC3E8,
-       0x63D0, 0xCCE1,
-       0x63D2, 0xB2E5,
-       0x63D6, 0xD2BE,
-       0x63DE, 0xDEEE,
-       0x63E0, 0xDEEB,
-       0x63E1, 0xCED5,
-       0x63E3, 0xB4A7,
-       0x63E9, 0xBFAB,
-       0x63EA, 0xBEBE,
-       0x63ED, 0xBDD2,
-       0x63F2, 0xDEE9,
-       0x63F4, 0xD4AE,
-       0x63F6, 0xDEDE,
-       0x63F8, 0xDEEA,
-       0x63FD, 0xC0BF,
-       0x63FF, 0xDEEC,
-       0x6400, 0xB2F3,
-       0x6401, 0xB8E9,
-       0x6402, 0xC2A7,
-       0x6405, 0xBDC1,
-       0x640B, 0xDEF5,
-       0x640C, 0xDEF8,
-       0x640F, 0xB2AB,
-       0x6410, 0xB4A4,
-       0x6413, 0xB4EA,
-       0x6414, 0xC9A6,
-       0x641B, 0xDEF6,
-       0x641C, 0xCBD1,
-       0x641E, 0xB8E3,
-       0x6420, 0xDEF7,
-       0x6421, 0xDEFA,
-       0x6426, 0xDEF9,
-       0x642A, 0xCCC2,
-       0x642C, 0xB0E1,
-       0x642D, 0xB4EE,
-       0x6434, 0xE5BA,
-       0x643A, 0xD0AF,
-       0x643D, 0xB2EB,
-       0x643F, 0xEBA1,
-       0x6441, 0xDEF4,
-       0x6444, 0xC9E3,
-       0x6445, 0xDEF3,
-       0x6446, 0xB0DA,
-       0x6447, 0xD2A1,
-       0x6448, 0xB1F7,
-       0x644A, 0xCCAF,
-       0x6452, 0xDEF0,
-       0x6454, 0xCBA4,
-       0x6458, 0xD5AA,
-       0x645E, 0xDEFB,
-       0x6467, 0xB4DD,
-       0x6469, 0xC4A6,
-       0x646D, 0xDEFD,
-       0x6478, 0xC3FE,
-       0x6479, 0xC4A1,
-       0x647A, 0xDFA1,
-       0x6482, 0xC1CC,
-       0x6484, 0xDEFC,
-       0x6485, 0xBEEF,
-       0x6487, 0xC6B2,
-       0x6491, 0xB3C5,
-       0x6492, 0xC8F6,
-       0x6495, 0xCBBA,
-       0x6496, 0xDEFE,
-       0x6499, 0xDFA4,
-       0x649E, 0xD7B2,
-       0x64A4, 0xB3B7,
-       0x64A9, 0xC1C3,
-       0x64AC, 0xC7CB,
-       0x64AD, 0xB2A5,
-       0x64AE, 0xB4E9,
-       0x64B0, 0xD7AB,
-       0x64B5, 0xC4EC,
-       0x64B7, 0xDFA2,
-       0x64B8, 0xDFA3,
-       0x64BA, 0xDFA5,
-       0x64BC, 0xBAB3,
-       0x64C0, 0xDFA6,
-       0x64C2, 0xC0DE,
-       0x64C5, 0xC9C3,
-       0x64CD, 0xB2D9,
-       0x64CE, 0xC7E6,
-       0x64D0, 0xDFA7,
-       0x64D2, 0xC7DC,
-       0x64D7, 0xDFA8,
-       0x64D8, 0xEBA2,
-       0x64DE, 0xCBD3,
-       0x64E2, 0xDFAA,
-       0x64E4, 0xDFA9,
-       0x64E6, 0xB2C1,
-       0x6500, 0xC5CA,
-       0x6509, 0xDFAB,
-       0x6512, 0xD4DC,
-       0x6518, 0xC8C1,
-       0x6525, 0xDFAC,
-       0x652B, 0xBEF0,
-       0x652E, 0xDFAD,
-       0x652F, 0xD6A7,
-       0x6534, 0xEAB7,
-       0x6535, 0xEBB6,
-       0x6536, 0xCAD5,
-       0x6538, 0xD8FC,
-       0x6539, 0xB8C4,
-       0x653B, 0xB9A5,
-       0x653E, 0xB7C5,
-       0x653F, 0xD5FE,
-       0x6545, 0xB9CA,
-       0x6548, 0xD0A7,
-       0x6549, 0xF4CD,
-       0x654C, 0xB5D0,
-       0x654F, 0xC3F4,
-       0x6551, 0xBEC8,
-       0x6555, 0xEBB7,
-       0x6556, 0xB0BD,
-       0x6559, 0xBDCC,
-       0x655B, 0xC1B2,
-       0x655D, 0xB1D6,
-       0x655E, 0xB3A8,
-       0x6562, 0xB8D2,
-       0x6563, 0xC9A2,
-       0x6566, 0xB6D8,
-       0x656B, 0xEBB8,
-       0x656C, 0xBEB4,
-       0x6570, 0xCAFD,
-       0x6572, 0xC7C3,
-       0x6574, 0xD5FB,
-       0x6577, 0xB7F3,
-       0x6587, 0xCEC4,
-       0x658B, 0xD5AB,
-       0x658C, 0xB1F3,
-       0x6590, 0xECB3,
-       0x6591, 0xB0DF,
-       0x6593, 0xECB5,
-       0x6597, 0xB6B7,
-       0x6599, 0xC1CF,
-       0x659B, 0xF5FA,
-       0x659C, 0xD0B1,
-       0x659F, 0xD5E5,
-       0x65A1, 0xCED3,
-       0x65A4, 0xBDEF,
-       0x65A5, 0xB3E2,
-       0x65A7, 0xB8AB,
-       0x65A9, 0xD5B6,
-       0x65AB, 0xEDBD,
-       0x65AD, 0xB6CF,
-       0x65AF, 0xCBB9,
-       0x65B0, 0xD0C2,
-       0x65B9, 0xB7BD,
-       0x65BC, 0xECB6,
-       0x65BD, 0xCAA9,
-       0x65C1, 0xC5D4,
-       0x65C3, 0xECB9,
-       0x65C4, 0xECB8,
-       0x65C5, 0xC2C3,
-       0x65C6, 0xECB7,
-       0x65CB, 0xD0FD,
-       0x65CC, 0xECBA,
-       0x65CE, 0xECBB,
-       0x65CF, 0xD7E5,
-       0x65D2, 0xECBC,
-       0x65D6, 0xECBD,
-       0x65D7, 0xC6EC,
-       0x65E0, 0xCEDE,
-       0x65E2, 0xBCC8,
-       0x65E5, 0xC8D5,
-       0x65E6, 0xB5A9,
-       0x65E7, 0xBEC9,
-       0x65E8, 0xD6BC,
-       0x65E9, 0xD4E7,
-       0x65EC, 0xD1AE,
-       0x65ED, 0xD0F1,
-       0x65EE, 0xEAB8,
-       0x65EF, 0xEAB9,
-       0x65F0, 0xEABA,
-       0x65F1, 0xBAB5,
-       0x65F6, 0xCAB1,
-       0x65F7, 0xBFF5,
-       0x65FA, 0xCDFA,
-       0x6600, 0xEAC0,
-       0x6602, 0xB0BA,
-       0x6603, 0xEABE,
-       0x6606, 0xC0A5,
-       0x660A, 0xEABB,
-       0x660C, 0xB2FD,
-       0x660E, 0xC3F7,
-       0x660F, 0xBBE8,
-       0x6613, 0xD2D7,
-       0x6614, 0xCEF4,
-       0x6615, 0xEABF,
-       0x6619, 0xEABC,
-       0x661D, 0xEAC3,
-       0x661F, 0xD0C7,
-       0x6620, 0xD3B3,
-       0x6625, 0xB4BA,
-       0x6627, 0xC3C1,
-       0x6628, 0xD7F2,
-       0x662D, 0xD5D1,
-       0x662F, 0xCAC7,
-       0x6631, 0xEAC5,
-       0x6634, 0xEAC4,
-       0x6635, 0xEAC7,
-       0x6636, 0xEAC6,
-       0x663C, 0xD6E7,
-       0x663E, 0xCFD4,
-       0x6641, 0xEACB,
-       0x6643, 0xBBCE,
-       0x664B, 0xBDFA,
-       0x664C, 0xC9CE,
-       0x664F, 0xEACC,
-       0x6652, 0xC9B9,
-       0x6653, 0xCFFE,
-       0x6654, 0xEACA,
-       0x6655, 0xD4CE,
-       0x6656, 0xEACD,
-       0x6657, 0xEACF,
-       0x665A, 0xCDED,
-       0x665F, 0xEAC9,
-       0x6661, 0xEACE,
-       0x6664, 0xCEEE,
-       0x6666, 0xBBDE,
-       0x6668, 0xB3BF,
-       0x666E, 0xC6D5,
-       0x666F, 0xBEB0,
-       0x6670, 0xCEFA,
-       0x6674, 0xC7E7,
-       0x6676, 0xBEA7,
-       0x6677, 0xEAD0,
-       0x667A, 0xD6C7,
-       0x667E, 0xC1C0,
-       0x6682, 0xD4DD,
-       0x6684, 0xEAD1,
-       0x6687, 0xCFBE,
-       0x668C, 0xEAD2,
-       0x6691, 0xCAEE,
-       0x6696, 0xC5AF,
-       0x6697, 0xB0B5,
-       0x669D, 0xEAD4,
-       0x66A7, 0xEAD3,
-       0x66A8, 0xF4DF,
-       0x66AE, 0xC4BA,
-       0x66B4, 0xB1A9,
-       0x66B9, 0xE5DF,
-       0x66BE, 0xEAD5,
-       0x66D9, 0xCAEF,
-       0x66DB, 0xEAD6,
-       0x66DC, 0xEAD7,
-       0x66DD, 0xC6D8,
-       0x66E6, 0xEAD8,
-       0x66E9, 0xEAD9,
-       0x66F0, 0xD4BB,
-       0x66F2, 0xC7FA,
-       0x66F3, 0xD2B7,
-       0x66F4, 0xB8FC,
-       0x66F7, 0xEAC2,
-       0x66F9, 0xB2DC,
-       0x66FC, 0xC2FC,
-       0x66FE, 0xD4F8,
-       0x66FF, 0xCCE6,
-       0x6700, 0xD7EE,
-       0x6708, 0xD4C2,
-       0x6709, 0xD3D0,
-       0x670A, 0xEBC3,
-       0x670B, 0xC5F3,
-       0x670D, 0xB7FE,
-       0x6710, 0xEBD4,
-       0x6714, 0xCBB7,
-       0x6715, 0xEBDE,
-       0x6717, 0xC0CA,
-       0x671B, 0xCDFB,
-       0x671D, 0xB3AF,
-       0x671F, 0xC6DA,
-       0x6726, 0xEBFC,
-       0x6728, 0xC4BE,
-       0x672A, 0xCEB4,
-       0x672B, 0xC4A9,
-       0x672C, 0xB1BE,
-       0x672D, 0xD4FD,
-       0x672F, 0xCAF5,
-       0x6731, 0xD6EC,
-       0x6734, 0xC6D3,
-       0x6735, 0xB6E4,
-       0x673A, 0xBBFA,
-       0x673D, 0xD0E0,
-       0x6740, 0xC9B1,
-       0x6742, 0xD4D3,
-       0x6743, 0xC8A8,
-       0x6746, 0xB8CB,
-       0x6748, 0xE8BE,
-       0x6749, 0xC9BC,
-       0x674C, 0xE8BB,
-       0x674E, 0xC0EE,
-       0x674F, 0xD0D3,
-       0x6750, 0xB2C4,
-       0x6751, 0xB4E5,
-       0x6753, 0xE8BC,
-       0x6756, 0xD5C8,
-       0x675C, 0xB6C5,
-       0x675E, 0xE8BD,
-       0x675F, 0xCAF8,
-       0x6760, 0xB8DC,
-       0x6761, 0xCCF5,
-       0x6765, 0xC0B4,
-       0x6768, 0xD1EE,
-       0x6769, 0xE8BF,
-       0x676A, 0xE8C2,
-       0x676D, 0xBABC,
-       0x676F, 0xB1AD,
-       0x6770, 0xBDDC,
-       0x6772, 0xEABD,
-       0x6773, 0xE8C3,
-       0x6775, 0xE8C6,
-       0x6777, 0xE8CB,
-       0x677C, 0xE8CC,
-       0x677E, 0xCBC9,
-       0x677F, 0xB0E5,
-       0x6781, 0xBCAB,
-       0x6784, 0xB9B9,
-       0x6787, 0xE8C1,
-       0x6789, 0xCDF7,
-       0x678B, 0xE8CA,
-       0x6790, 0xCEF6,
-       0x6795, 0xD5ED,
-       0x6797, 0xC1D6,
-       0x6798, 0xE8C4,
-       0x679A, 0xC3B6,
-       0x679C, 0xB9FB,
-       0x679D, 0xD6A6,
-       0x679E, 0xE8C8,
-       0x67A2, 0xCAE0,
-       0x67A3, 0xD4E6,
-       0x67A5, 0xE8C0,
-       0x67A7, 0xE8C5,
-       0x67A8, 0xE8C7,
-       0x67AA, 0xC7B9,
-       0x67AB, 0xB7E3,
-       0x67AD, 0xE8C9,
-       0x67AF, 0xBFDD,
-       0x67B0, 0xE8D2,
-       0x67B3, 0xE8D7,
-       0x67B5, 0xE8D5,
-       0x67B6, 0xBCDC,
-       0x67B7, 0xBCCF,
-       0x67B8, 0xE8DB,
-       0x67C1, 0xE8DE,
-       0x67C3, 0xE8DA,
-       0x67C4, 0xB1FA,
-       0x67CF, 0xB0D8,
-       0x67D0, 0xC4B3,
-       0x67D1, 0xB8CC,
-       0x67D2, 0xC6E2,
-       0x67D3, 0xC8BE,
-       0x67D4, 0xC8E1,
-       0x67D8, 0xE8CF,
-       0x67D9, 0xE8D4,
-       0x67DA, 0xE8D6,
-       0x67DC, 0xB9F1,
-       0x67DD, 0xE8D8,
-       0x67DE, 0xD7F5,
-       0x67E0, 0xC4FB,
-       0x67E2, 0xE8DC,
-       0x67E5, 0xB2E9,
-       0x67E9, 0xE8D1,
-       0x67EC, 0xBCED,
-       0x67EF, 0xBFC2,
-       0x67F0, 0xE8CD,
-       0x67F1, 0xD6F9,
-       0x67F3, 0xC1F8,
-       0x67F4, 0xB2F1,
-       0x67FD, 0xE8DF,
-       0x67FF, 0xCAC1,
-       0x6800, 0xE8D9,
-       0x6805, 0xD5A4,
-       0x6807, 0xB1EA,
-       0x6808, 0xD5BB,
-       0x6809, 0xE8CE,
-       0x680A, 0xE8D0,
-       0x680B, 0xB6B0,
-       0x680C, 0xE8D3,
-       0x680E, 0xE8DD,
-       0x680F, 0xC0B8,
-       0x6811, 0xCAF7,
-       0x6813, 0xCBA8,
-       0x6816, 0xC6DC,
-       0x6817, 0xC0F5,
-       0x681D, 0xE8E9,
-       0x6821, 0xD0A3,
-       0x6829, 0xE8F2,
-       0x682A, 0xD6EA,
-       0x6832, 0xE8E0,
-       0x6833, 0xE8E1,
-       0x6837, 0xD1F9,
-       0x6838, 0xBACB,
-       0x6839, 0xB8F9,
-       0x683C, 0xB8F1,
-       0x683D, 0xD4D4,
-       0x683E, 0xE8EF,
-       0x6840, 0xE8EE,
-       0x6841, 0xE8EC,
-       0x6842, 0xB9F0,
-       0x6843, 0xCCD2,
-       0x6844, 0xE8E6,
-       0x6845, 0xCEA6,
-       0x6846, 0xBFF2,
-       0x6848, 0xB0B8,
-       0x6849, 0xE8F1,
-       0x684A, 0xE8F0,
-       0x684C, 0xD7C0,
-       0x684E, 0xE8E4,
-       0x6850, 0xCDA9,
-       0x6851, 0xC9A3,
-       0x6853, 0xBBB8,
-       0x6854, 0xBDDB,
-       0x6855, 0xE8EA,
-       0x6860, 0xE8E2,
-       0x6861, 0xE8E3,
-       0x6862, 0xE8E5,
-       0x6863, 0xB5B5,
-       0x6864, 0xE8E7,
-       0x6865, 0xC7C5,
-       0x6866, 0xE8EB,
-       0x6867, 0xE8ED,
-       0x6868, 0xBDB0,
-       0x6869, 0xD7AE,
-       0x686B, 0xE8F8,
-       0x6874, 0xE8F5,
-       0x6876, 0xCDB0,
-       0x6877, 0xE8F6,
-       0x6881, 0xC1BA,
-       0x6883, 0xE8E8,
-       0x6885, 0xC3B7,
-       0x6886, 0xB0F0,
-       0x688F, 0xE8F4,
-       0x6893, 0xE8F7,
-       0x6897, 0xB9A3,
-       0x68A2, 0xC9D2,
-       0x68A6, 0xC3CE,
-       0x68A7, 0xCEE0,
-       0x68A8, 0xC0E6,
-       0x68AD, 0xCBF3,
-       0x68AF, 0xCCDD,
-       0x68B0, 0xD0B5,
-       0x68B3, 0xCAE1,
-       0x68B5, 0xE8F3,
-       0x68C0, 0xBCEC,
-       0x68C2, 0xE8F9,
-       0x68C9, 0xC3DE,
-       0x68CB, 0xC6E5,
-       0x68CD, 0xB9F7,
-       0x68D2, 0xB0F4,
-       0x68D5, 0xD7D8,
-       0x68D8, 0xBCAC,
-       0x68DA, 0xC5EF,
-       0x68E0, 0xCCC4,
-       0x68E3, 0xE9A6,
-       0x68EE, 0xC9AD,
-       0x68F0, 0xE9A2,
-       0x68F1, 0xC0E2,
-       0x68F5, 0xBFC3,
-       0x68F9, 0xE8FE,
-       0x68FA, 0xB9D7,
-       0x68FC, 0xE8FB,
-       0x6901, 0xE9A4,
-       0x6905, 0xD2CE,
-       0x690B, 0xE9A3,
-       0x690D, 0xD6B2,
-       0x690E, 0xD7B5,
-       0x6910, 0xE9A7,
-       0x6912, 0xBDB7,
-       0x691F, 0xE8FC,
-       0x6920, 0xE8FD,
-       0x6924, 0xE9A1,
-       0x692D, 0xCDD6,
-       0x6930, 0xD2AC,
-       0x6934, 0xE9B2,
-       0x6939, 0xE9A9,
-       0x693D, 0xB4AA,
-       0x693F, 0xB4BB,
-       0x6942, 0xE9AB,
-       0x6954, 0xD0A8,
-       0x6957, 0xE9A5,
-       0x695A, 0xB3FE,
-       0x695D, 0xE9AC,
-       0x695E, 0xC0E3,
-       0x6960, 0xE9AA,
-       0x6963, 0xE9B9,
-       0x6966, 0xE9B8,
-       0x696B, 0xE9AE,
-       0x696E, 0xE8FA,
-       0x6971, 0xE9A8,
-       0x6977, 0xBFAC,
-       0x6978, 0xE9B1,
-       0x6979, 0xE9BA,
-       0x697C, 0xC2A5,
-       0x6980, 0xE9AF,
-       0x6982, 0xB8C5,
-       0x6984, 0xE9AD,
-       0x6986, 0xD3DC,
-       0x6987, 0xE9B4,
-       0x6988, 0xE9B5,
-       0x6989, 0xE9B7,
-       0x698D, 0xE9C7,
-       0x6994, 0xC0C6,
-       0x6995, 0xE9C5,
-       0x6998, 0xE9B0,
-       0x699B, 0xE9BB,
-       0x699C, 0xB0F1,
-       0x69A7, 0xE9BC,
-       0x69A8, 0xD5A5,
-       0x69AB, 0xE9BE,
-       0x69AD, 0xE9BF,
-       0x69B1, 0xE9C1,
-       0x69B4, 0xC1F1,
-       0x69B7, 0xC8B6,
-       0x69BB, 0xE9BD,
-       0x69C1, 0xE9C2,
-       0x69CA, 0xE9C3,
-       0x69CC, 0xE9B3,
-       0x69CE, 0xE9B6,
-       0x69D0, 0xBBB1,
-       0x69D4, 0xE9C0,
-       0x69DB, 0xBCF7,
-       0x69DF, 0xE9C4,
-       0x69E0, 0xE9C6,
-       0x69ED, 0xE9CA,
-       0x69F2, 0xE9CE,
-       0x69FD, 0xB2DB,
-       0x69FF, 0xE9C8,
-       0x6A0A, 0xB7AE,
-       0x6A17, 0xE9CB,
-       0x6A18, 0xE9CC,
-       0x6A1F, 0xD5C1,
-       0x6A21, 0xC4A3,
-       0x6A28, 0xE9D8,
-       0x6A2A, 0xBAE1,
-       0x6A2F, 0xE9C9,
-       0x6A31, 0xD3A3,
-       0x6A35, 0xE9D4,
-       0x6A3D, 0xE9D7,
-       0x6A3E, 0xE9D0,
-       0x6A44, 0xE9CF,
-       0x6A47, 0xC7C1,
-       0x6A50, 0xE9D2,
-       0x6A58, 0xE9D9,
-       0x6A59, 0xB3C8,
-       0x6A5B, 0xE9D3,
-       0x6A61, 0xCFF0,
-       0x6A65, 0xE9CD,
-       0x6A71, 0xB3F7,
-       0x6A79, 0xE9D6,
-       0x6A7C, 0xE9DA,
-       0x6A80, 0xCCB4,
-       0x6A84, 0xCFAD,
-       0x6A8E, 0xE9D5,
-       0x6A90, 0xE9DC,
-       0x6A91, 0xE9DB,
-       0x6A97, 0xE9DE,
-       0x6AA0, 0xE9D1,
-       0x6AA9, 0xE9DD,
-       0x6AAB, 0xE9DF,
-       0x6AAC, 0xC3CA,
-       0x6B20, 0xC7B7,
-       0x6B21, 0xB4CE,
-       0x6B22, 0xBBB6,
-       0x6B23, 0xD0C0,
-       0x6B24, 0xECA3,
-       0x6B27, 0xC5B7,
-       0x6B32, 0xD3FB,
-       0x6B37, 0xECA4,
-       0x6B39, 0xECA5,
-       0x6B3A, 0xC6DB,
-       0x6B3E, 0xBFEE,
-       0x6B43, 0xECA6,
-       0x6B46, 0xECA7,
-       0x6B47, 0xD0AA,
-       0x6B49, 0xC7B8,
-       0x6B4C, 0xB8E8,
-       0x6B59, 0xECA8,
-       0x6B62, 0xD6B9,
-       0x6B63, 0xD5FD,
-       0x6B64, 0xB4CB,
-       0x6B65, 0xB2BD,
-       0x6B66, 0xCEE4,
-       0x6B67, 0xC6E7,
-       0x6B6A, 0xCDE1,
-       0x6B79, 0xB4F5,
-       0x6B7B, 0xCBC0,
-       0x6B7C, 0xBCDF,
-       0x6B81, 0xE9E2,
-       0x6B82, 0xE9E3,
-       0x6B83, 0xD1EA,
-       0x6B84, 0xE9E5,
-       0x6B86, 0xB4F9,
-       0x6B87, 0xE9E4,
-       0x6B89, 0xD1B3,
-       0x6B8A, 0xCAE2,
-       0x6B8B, 0xB2D0,
-       0x6B8D, 0xE9E8,
-       0x6B92, 0xE9E6,
-       0x6B93, 0xE9E7,
-       0x6B96, 0xD6B3,
-       0x6B9A, 0xE9E9,
-       0x6B9B, 0xE9EA,
-       0x6BA1, 0xE9EB,
-       0x6BAA, 0xE9EC,
-       0x6BB3, 0xECAF,
-       0x6BB4, 0xC5B9,
-       0x6BB5, 0xB6CE,
-       0x6BB7, 0xD2F3,
-       0x6BBF, 0xB5EE,
-       0x6BC1, 0xBBD9,
-       0x6BC2, 0xECB1,
-       0x6BC5, 0xD2E3,
-       0x6BCB, 0xCEE3,
-       0x6BCD, 0xC4B8,
-       0x6BCF, 0xC3BF,
-       0x6BD2, 0xB6BE,
-       0x6BD3, 0xD8B9,
-       0x6BD4, 0xB1C8,
-       0x6BD5, 0xB1CF,
-       0x6BD6, 0xB1D1,
-       0x6BD7, 0xC5FE,
-       0x6BD9, 0xB1D0,
-       0x6BDB, 0xC3AB,
-       0x6BE1, 0xD5B1,
-       0x6BEA, 0xEBA4,
-       0x6BEB, 0xBAC1,
-       0x6BEF, 0xCCBA,
-       0x6BF3, 0xEBA5,
-       0x6BF5, 0xEBA7,
-       0x6BF9, 0xEBA8,
-       0x6BFD, 0xEBA6,
-       0x6C05, 0xEBA9,
-       0x6C06, 0xEBAB,
-       0x6C07, 0xEBAA,
-       0x6C0D, 0xEBAC,
-       0x6C0F, 0xCACF,
-       0x6C10, 0xD8B5,
-       0x6C11, 0xC3F1,
-       0x6C13, 0xC3A5,
-       0x6C14, 0xC6F8,
-       0x6C15, 0xEBAD,
-       0x6C16, 0xC4CA,
-       0x6C18, 0xEBAE,
-       0x6C19, 0xEBAF,
-       0x6C1A, 0xEBB0,
-       0x6C1B, 0xB7D5,
-       0x6C1F, 0xB7FA,
-       0x6C21, 0xEBB1,
-       0x6C22, 0xC7E2,
-       0x6C24, 0xEBB3,
-       0x6C26, 0xBAA4,
-       0x6C27, 0xD1F5,
-       0x6C28, 0xB0B1,
-       0x6C29, 0xEBB2,
-       0x6C2A, 0xEBB4,
-       0x6C2E, 0xB5AA,
-       0x6C2F, 0xC2C8,
-       0x6C30, 0xC7E8,
-       0x6C32, 0xEBB5,
-       0x6C34, 0xCBAE,
-       0x6C35, 0xE3DF,
-       0x6C38, 0xD3C0,
-       0x6C3D, 0xD9DB,
-       0x6C40, 0xCDA1,
-       0x6C41, 0xD6AD,
-       0x6C42, 0xC7F3,
-       0x6C46, 0xD9E0,
-       0x6C47, 0xBBE3,
-       0x6C49, 0xBABA,
-       0x6C4A, 0xE3E2,
-       0x6C50, 0xCFAB,
-       0x6C54, 0xE3E0,
-       0x6C55, 0xC9C7,
-       0x6C57, 0xBAB9,
-       0x6C5B, 0xD1B4,
-       0x6C5C, 0xE3E1,
-       0x6C5D, 0xC8EA,
-       0x6C5E, 0xB9AF,
-       0x6C5F, 0xBDAD,
-       0x6C60, 0xB3D8,
-       0x6C61, 0xCEDB,
-       0x6C64, 0xCCC0,
-       0x6C68, 0xE3E8,
-       0x6C69, 0xE3E9,
-       0x6C6A, 0xCDF4,
-       0x6C70, 0xCCAD,
-       0x6C72, 0xBCB3,
-       0x6C74, 0xE3EA,
-       0x6C76, 0xE3EB,
-       0x6C79, 0xD0DA,
-       0x6C7D, 0xC6FB,
-       0x6C7E, 0xB7DA,
-       0x6C81, 0xC7DF,
-       0x6C82, 0xD2CA,
-       0x6C83, 0xCED6,
-       0x6C85, 0xE3E4,
-       0x6C86, 0xE3EC,
-       0x6C88, 0xC9F2,
-       0x6C89, 0xB3C1,
-       0x6C8C, 0xE3E7,
-       0x6C8F, 0xC6E3,
-       0x6C90, 0xE3E5,
-       0x6C93, 0xEDB3,
-       0x6C94, 0xE3E6,
-       0x6C99, 0xC9B3,
-       0x6C9B, 0xC5E6,
-       0x6C9F, 0xB9B5,
-       0x6CA1, 0xC3BB,
-       0x6CA3, 0xE3E3,
-       0x6CA4, 0xC5BD,
-       0x6CA5, 0xC1A4,
-       0x6CA6, 0xC2D9,
-       0x6CA7, 0xB2D7,
-       0x6CA9, 0xE3ED,
-       0x6CAA, 0xBBA6,
-       0x6CAB, 0xC4AD,
-       0x6CAD, 0xE3F0,
-       0x6CAE, 0xBEDA,
-       0x6CB1, 0xE3FB,
-       0x6CB2, 0xE3F5,
-       0x6CB3, 0xBAD3,
-       0x6CB8, 0xB7D0,
-       0x6CB9, 0xD3CD,
-       0x6CBB, 0xD6CE,
-       0x6CBC, 0xD5D3,
-       0x6CBD, 0xB9C1,
-       0x6CBE, 0xD5B4,
-       0x6CBF, 0xD1D8,
-       0x6CC4, 0xD0B9,
-       0x6CC5, 0xC7F6,
-       0x6CC9, 0xC8AA,
-       0x6CCA, 0xB2B4,
-       0x6CCC, 0xC3DA,
-       0x6CD0, 0xE3EE,
-       0x6CD3, 0xE3FC,
-       0x6CD4, 0xE3EF,
-       0x6CD5, 0xB7A8,
-       0x6CD6, 0xE3F7,
-       0x6CD7, 0xE3F4,
-       0x6CDB, 0xB7BA,
-       0x6CDE, 0xC5A2,
-       0x6CE0, 0xE3F6,
-       0x6CE1, 0xC5DD,
-       0x6CE2, 0xB2A8,
-       0x6CE3, 0xC6FC,
-       0x6CE5, 0xC4E0,
-       0x6CE8, 0xD7A2,
-       0x6CEA, 0xC0E1,
-       0x6CEB, 0xE3F9,
-       0x6CEE, 0xE3FA,
-       0x6CEF, 0xE3FD,
-       0x6CF0, 0xCCA9,
-       0x6CF1, 0xE3F3,
-       0x6CF3, 0xD3BE,
-       0x6CF5, 0xB1C3,
-       0x6CF6, 0xEDB4,
-       0x6CF7, 0xE3F1,
-       0x6CF8, 0xE3F2,
-       0x6CFA, 0xE3F8,
-       0x6CFB, 0xD0BA,
-       0x6CFC, 0xC6C3,
-       0x6CFD, 0xD4F3,
-       0x6CFE, 0xE3FE,
-       0x6D01, 0xBDE0,
-       0x6D04, 0xE4A7,
-       0x6D07, 0xE4A6,
-       0x6D0B, 0xD1F3,
-       0x6D0C, 0xE4A3,
-       0x6D0E, 0xE4A9,
-       0x6D12, 0xC8F7,
-       0x6D17, 0xCFB4,
-       0x6D19, 0xE4A8,
-       0x6D1A, 0xE4AE,
-       0x6D1B, 0xC2E5,
-       0x6D1E, 0xB6B4,
-       0x6D25, 0xBDF2,
-       0x6D27, 0xE4A2,
-       0x6D2A, 0xBAE9,
-       0x6D2B, 0xE4AA,
-       0x6D2E, 0xE4AC,
-       0x6D31, 0xB6FD,
-       0x6D32, 0xD6DE,
-       0x6D33, 0xE4B2,
-       0x6D35, 0xE4AD,
-       0x6D39, 0xE4A1,
-       0x6D3B, 0xBBEE,
-       0x6D3C, 0xCDDD,
-       0x6D3D, 0xC7A2,
-       0x6D3E, 0xC5C9,
-       0x6D41, 0xC1F7,
-       0x6D43, 0xE4A4,
-       0x6D45, 0xC7B3,
-       0x6D46, 0xBDAC,
-       0x6D47, 0xBDBD,
-       0x6D48, 0xE4A5,
-       0x6D4A, 0xD7C7,
-       0x6D4B, 0xB2E2,
-       0x6D4D, 0xE4AB,
-       0x6D4E, 0xBCC3,
-       0x6D4F, 0xE4AF,
-       0x6D51, 0xBBEB,
-       0x6D52, 0xE4B0,
-       0x6D53, 0xC5A8,
-       0x6D54, 0xE4B1,
-       0x6D59, 0xD5E3,
-       0x6D5A, 0xBFA3,
-       0x6D5C, 0xE4BA,
-       0x6D5E, 0xE4B7,
-       0x6D60, 0xE4BB,
-       0x6D63, 0xE4BD,
-       0x6D66, 0xC6D6,
-       0x6D69, 0xBAC6,
-       0x6D6A, 0xC0CB,
-       0x6D6E, 0xB8A1,
-       0x6D6F, 0xE4B4,
-       0x6D74, 0xD4A1,
-       0x6D77, 0xBAA3,
-       0x6D78, 0xBDFE,
-       0x6D7C, 0xE4BC,
-       0x6D82, 0xCDBF,
-       0x6D85, 0xC4F9,
-       0x6D88, 0xCFFB,
-       0x6D89, 0xC9E6,
-       0x6D8C, 0xD3BF,
-       0x6D8E, 0xCFD1,
-       0x6D91, 0xE4B3,
-       0x6D93, 0xE4B8,
-       0x6D94, 0xE4B9,
-       0x6D95, 0xCCE9,
-       0x6D9B, 0xCCCE,
-       0x6D9D, 0xC0D4,
-       0x6D9E, 0xE4B5,
-       0x6D9F, 0xC1B0,
-       0x6DA0, 0xE4B6,
-       0x6DA1, 0xCED0,
-       0x6DA3, 0xBBC1,
-       0x6DA4, 0xB5D3,
-       0x6DA6, 0xC8F3,
-       0x6DA7, 0xBDA7,
-       0x6DA8, 0xD5C7,
-       0x6DA9, 0xC9AC,
-       0x6DAA, 0xB8A2,
-       0x6DAB, 0xE4CA,
-       0x6DAE, 0xE4CC,
-       0x6DAF, 0xD1C4,
-       0x6DB2, 0xD2BA,
-       0x6DB5, 0xBAAD,
-       0x6DB8, 0xBAD4,
-       0x6DBF, 0xE4C3,
-       0x6DC0, 0xB5ED,
-       0x6DC4, 0xD7CD,
-       0x6DC5, 0xE4C0,
-       0x6DC6, 0xCFFD,
-       0x6DC7, 0xE4BF,
-       0x6DCB, 0xC1DC,
-       0x6DCC, 0xCCCA,
-       0x6DD1, 0xCAE7,
-       0x6DD6, 0xC4D7,
-       0x6DD8, 0xCCD4,
-       0x6DD9, 0xE4C8,
-       0x6DDD, 0xE4C7,
-       0x6DDE, 0xE4C1,
-       0x6DE0, 0xE4C4,
-       0x6DE1, 0xB5AD,
-       0x6DE4, 0xD3D9,
-       0x6DE6, 0xE4C6,
-       0x6DEB, 0xD2F9,
-       0x6DEC, 0xB4E3,
-       0x6DEE, 0xBBB4,
-       0x6DF1, 0xC9EE,
-       0x6DF3, 0xB4BE,
-       0x6DF7, 0xBBEC,
-       0x6DF9, 0xD1CD,
-       0x6DFB, 0xCCED,
-       0x6DFC, 0xEDB5,
-       0x6E05, 0xC7E5,
-       0x6E0A, 0xD4A8,
-       0x6E0C, 0xE4CB,
-       0x6E0D, 0xD7D5,
-       0x6E0E, 0xE4C2,
-       0x6E10, 0xBDA5,
-       0x6E11, 0xE4C5,
-       0x6E14, 0xD3E6,
-       0x6E16, 0xE4C9,
-       0x6E17, 0xC9F8,
-       0x6E1A, 0xE4BE,
-       0x6E1D, 0xD3E5,
-       0x6E20, 0xC7FE,
-       0x6E21, 0xB6C9,
-       0x6E23, 0xD4FC,
-       0x6E24, 0xB2B3,
-       0x6E25, 0xE4D7,
-       0x6E29, 0xCEC2,
-       0x6E2B, 0xE4CD,
-       0x6E2D, 0xCEBC,
-       0x6E2F, 0xB8DB,
-       0x6E32, 0xE4D6,
-       0x6E34, 0xBFCA,
-       0x6E38, 0xD3CE,
-       0x6E3A, 0xC3EC,
-       0x6E43, 0xC5C8,
-       0x6E44, 0xE4D8,
-       0x6E4D, 0xCDC4,
-       0x6E4E, 0xE4CF,
-       0x6E53, 0xE4D4,
-       0x6E54, 0xE4D5,
-       0x6E56, 0xBAFE,
-       0x6E58, 0xCFE6,
-       0x6E5B, 0xD5BF,
-       0x6E5F, 0xE4D2,
-       0x6E6B, 0xE4D0,
-       0x6E6E, 0xE4CE,
-       0x6E7E, 0xCDE5,
-       0x6E7F, 0xCAAA,
-       0x6E83, 0xC0A3,
-       0x6E85, 0xBDA6,
-       0x6E86, 0xE4D3,
-       0x6E89, 0xB8C8,
-       0x6E8F, 0xE4E7,
-       0x6E90, 0xD4B4,
-       0x6E98, 0xE4DB,
-       0x6E9C, 0xC1EF,
-       0x6E9F, 0xE4E9,
-       0x6EA2, 0xD2E7,
-       0x6EA5, 0xE4DF,
-       0x6EA7, 0xE4E0,
-       0x6EAA, 0xCFAA,
-       0x6EAF, 0xCBDD,
-       0x6EB1, 0xE4DA,
-       0x6EB2, 0xE4D1,
-       0x6EB4, 0xE4E5,
-       0x6EB6, 0xC8DC,
-       0x6EB7, 0xE4E3,
-       0x6EBA, 0xC4E7,
-       0x6EBB, 0xE4E2,
-       0x6EBD, 0xE4E1,
-       0x6EC1, 0xB3FC,
-       0x6EC2, 0xE4E8,
-       0x6EC7, 0xB5E1,
-       0x6ECB, 0xD7CC,
-       0x6ECF, 0xE4E6,
-       0x6ED1, 0xBBAC,
-       0x6ED3, 0xD7D2,
-       0x6ED4, 0xCCCF,
-       0x6ED5, 0xEBF8,
-       0x6ED7, 0xE4E4,
-       0x6EDA, 0xB9F6,
-       0x6EDE, 0xD6CD,
-       0x6EDF, 0xE4D9,
-       0x6EE0, 0xE4DC,
-       0x6EE1, 0xC2FA,
-       0x6EE2, 0xE4DE,
-       0x6EE4, 0xC2CB,
-       0x6EE5, 0xC0C4,
-       0x6EE6, 0xC2D0,
-       0x6EE8, 0xB1F5,
-       0x6EE9, 0xCCB2,
-       0x6EF4, 0xB5CE,
-       0x6EF9, 0xE4EF,
-       0x6F02, 0xC6AF,
-       0x6F06, 0xC6E1,
-       0x6F09, 0xE4F5,
-       0x6F0F, 0xC2A9,
-       0x6F13, 0xC0EC,
-       0x6F14, 0xD1DD,
-       0x6F15, 0xE4EE,
-       0x6F20, 0xC4AE,
-       0x6F24, 0xE4ED,
-       0x6F29, 0xE4F6,
-       0x6F2A, 0xE4F4,
-       0x6F2B, 0xC2FE,
-       0x6F2D, 0xE4DD,
-       0x6F2F, 0xE4F0,
-       0x6F31, 0xCAFE,
-       0x6F33, 0xD5C4,
-       0x6F36, 0xE4F1,
-       0x6F3E, 0xD1FA,
-       0x6F46, 0xE4EB,
-       0x6F47, 0xE4EC,
-       0x6F4B, 0xE4F2,
-       0x6F4D, 0xCEAB,
-       0x6F58, 0xC5CB,
-       0x6F5C, 0xC7B1,
-       0x6F5E, 0xC2BA,
-       0x6F62, 0xE4EA,
-       0x6F66, 0xC1CA,
-       0x6F6D, 0xCCB6,
-       0x6F6E, 0xB3B1,
-       0x6F72, 0xE4FB,
-       0x6F74, 0xE4F3,
-       0x6F78, 0xE4FA,
-       0x6F7A, 0xE4FD,
-       0x6F7C, 0xE4FC,
-       0x6F84, 0xB3CE,
-       0x6F88, 0xB3BA,
-       0x6F89, 0xE4F7,
-       0x6F8C, 0xE4F9,
-       0x6F8D, 0xE4F8,
-       0x6F8E, 0xC5EC,
-       0x6F9C, 0xC0BD,
-       0x6FA1, 0xD4E8,
-       0x6FA7, 0xE5A2,
-       0x6FB3, 0xB0C4,
-       0x6FB6, 0xE5A4,
-       0x6FB9, 0xE5A3,
-       0x6FC0, 0xBCA4,
-       0x6FC2, 0xE5A5,
-       0x6FC9, 0xE5A1,
-       0x6FD1, 0xE4FE,
-       0x6FD2, 0xB1F4,
-       0x6FDE, 0xE5A8,
-       0x6FE0, 0xE5A9,
-       0x6FE1, 0xE5A6,
-       0x6FEE, 0xE5A7,
-       0x6FEF, 0xE5AA,
-       0x7011, 0xC6D9,
-       0x701A, 0xE5AB,
-       0x701B, 0xE5AD,
-       0x7023, 0xE5AC,
-       0x7035, 0xE5AF,
-       0x7039, 0xE5AE,
-       0x704C, 0xB9E0,
-       0x704F, 0xE5B0,
-       0x705E, 0xE5B1,
-       0x706B, 0xBBF0,
-       0x706C, 0xECE1,
-       0x706D, 0xC3F0,
-       0x706F, 0xB5C6,
-       0x7070, 0xBBD2,
-       0x7075, 0xC1E9,
-       0x7076, 0xD4EE,
-       0x7078, 0xBEC4,
-       0x707C, 0xD7C6,
-       0x707E, 0xD4D6,
-       0x707F, 0xB2D3,
-       0x7080, 0xECBE,
-       0x7085, 0xEAC1,
-       0x7089, 0xC2AF,
-       0x708A, 0xB4B6,
-       0x708E, 0xD1D7,
-       0x7092, 0xB3B4,
-       0x7094, 0xC8B2,
-       0x7095, 0xBFBB,
-       0x7096, 0xECC0,
-       0x7099, 0xD6CB,
-       0x709C, 0xECBF,
-       0x709D, 0xECC1,
-       0x70AB, 0xECC5,
-       0x70AC, 0xBEE6,
-       0x70AD, 0xCCBF,
-       0x70AE, 0xC5DA,
-       0x70AF, 0xBEBC,
-       0x70B1, 0xECC6,
-       0x70B3, 0xB1FE,
-       0x70B7, 0xECC4,
-       0x70B8, 0xD5A8,
-       0x70B9, 0xB5E3,
-       0x70BB, 0xECC2,
-       0x70BC, 0xC1B6,
-       0x70BD, 0xB3E3,
-       0x70C0, 0xECC3,
-       0x70C1, 0xCBB8,
-       0x70C2, 0xC0C3,
-       0x70C3, 0xCCFE,
-       0x70C8, 0xC1D2,
-       0x70CA, 0xECC8,
-       0x70D8, 0xBAE6,
-       0x70D9, 0xC0D3,
-       0x70DB, 0xD6F2,
-       0x70DF, 0xD1CC,
-       0x70E4, 0xBFBE,
-       0x70E6, 0xB7B3,
-       0x70E7, 0xC9D5,
-       0x70E8, 0xECC7,
-       0x70E9, 0xBBE2,
-       0x70EB, 0xCCCC,
-       0x70EC, 0xBDFD,
-       0x70ED, 0xC8C8,
-       0x70EF, 0xCFA9,
-       0x70F7, 0xCDE9,
-       0x70F9, 0xC5EB,
-       0x70FD, 0xB7E9,
-       0x7109, 0xD1C9,
-       0x710A, 0xBAB8,
-       0x7110, 0xECC9,
-       0x7113, 0xECCA,
-       0x7115, 0xBBC0,
-       0x7116, 0xECCB,
-       0x7118, 0xECE2,
-       0x7119, 0xB1BA,
-       0x711A, 0xB7D9,
-       0x7126, 0xBDB9,
-       0x712F, 0xECCC,
-       0x7130, 0xD1E6,
-       0x7131, 0xECCD,
-       0x7136, 0xC8BB,
-       0x7145, 0xECD1,
-       0x714A, 0xECD3,
-       0x714C, 0xBBCD,
-       0x714E, 0xBCE5,
-       0x715C, 0xECCF,
-       0x715E, 0xC9B7,
-       0x7164, 0xC3BA,
-       0x7166, 0xECE3,
-       0x7167, 0xD5D5,
-       0x7168, 0xECD0,
-       0x716E, 0xD6F3,
-       0x7172, 0xECD2,
-       0x7173, 0xECCE,
-       0x7178, 0xECD4,
-       0x717A, 0xECD5,
-       0x717D, 0xC9BF,
-       0x7184, 0xCFA8,
-       0x718A, 0xD0DC,
-       0x718F, 0xD1AC,
-       0x7194, 0xC8DB,
-       0x7198, 0xECD6,
-       0x7199, 0xCEF5,
-       0x719F, 0xCAEC,
-       0x71A0, 0xECDA,
-       0x71A8, 0xECD9,
-       0x71AC, 0xB0BE,
-       0x71B3, 0xECD7,
-       0x71B5, 0xECD8,
-       0x71B9, 0xECE4,
-       0x71C3, 0xC8BC,
-       0x71CE, 0xC1C7,
-       0x71D4, 0xECDC,
-       0x71D5, 0xD1E0,
-       0x71E0, 0xECDB,
-       0x71E5, 0xD4EF,
-       0x71E7, 0xECDD,
-       0x71EE, 0xDBC6,
-       0x71F9, 0xECDE,
-       0x7206, 0xB1AC,
-       0x721D, 0xECDF,
-       0x7228, 0xECE0,
-       0x722A, 0xD7A6,
-       0x722C, 0xC5C0,
-       0x7230, 0xEBBC,
-       0x7231, 0xB0AE,
-       0x7235, 0xBEF4,
-       0x7236, 0xB8B8,
-       0x7237, 0xD2AF,
-       0x7238, 0xB0D6,
-       0x7239, 0xB5F9,
-       0x723B, 0xD8B3,
-       0x723D, 0xCBAC,
-       0x723F, 0xE3DD,
-       0x7247, 0xC6AC,
-       0x7248, 0xB0E6,
-       0x724C, 0xC5C6,
-       0x724D, 0xEBB9,
-       0x7252, 0xEBBA,
-       0x7256, 0xEBBB,
-       0x7259, 0xD1C0,
-       0x725B, 0xC5A3,
-       0x725D, 0xEAF2,
-       0x725F, 0xC4B2,
-       0x7261, 0xC4B5,
-       0x7262, 0xC0CE,
-       0x7266, 0xEAF3,
-       0x7267, 0xC4C1,
-       0x7269, 0xCEEF,
-       0x726E, 0xEAF0,
-       0x726F, 0xEAF4,
-       0x7272, 0xC9FC,
-       0x7275, 0xC7A3,
-       0x7279, 0xCCD8,
-       0x727A, 0xCEFE,
-       0x727E, 0xEAF5,
-       0x727F, 0xEAF6,
-       0x7280, 0xCFAC,
-       0x7281, 0xC0E7,
-       0x7284, 0xEAF7,
-       0x728A, 0xB6BF,
-       0x728B, 0xEAF8,
-       0x728D, 0xEAF9,
-       0x728F, 0xEAFA,
-       0x7292, 0xEAFB,
-       0x729F, 0xEAF1,
-       0x72AC, 0xC8AE,
-       0x72AD, 0xE1EB,
-       0x72AF, 0xB7B8,
-       0x72B0, 0xE1EC,
-       0x72B4, 0xE1ED,
-       0x72B6, 0xD7B4,
-       0x72B7, 0xE1EE,
-       0x72B8, 0xE1EF,
-       0x72B9, 0xD3CC,
-       0x72C1, 0xE1F1,
-       0x72C2, 0xBFF1,
-       0x72C3, 0xE1F0,
-       0x72C4, 0xB5D2,
-       0x72C8, 0xB1B7,
-       0x72CD, 0xE1F3,
-       0x72CE, 0xE1F2,
-       0x72D0, 0xBAFC,
-       0x72D2, 0xE1F4,
-       0x72D7, 0xB9B7,
-       0x72D9, 0xBED1,
-       0x72DE, 0xC4FC,
-       0x72E0, 0xBADD,
-       0x72E1, 0xBDC6,
-       0x72E8, 0xE1F5,
-       0x72E9, 0xE1F7,
-       0x72EC, 0xB6C0,
-       0x72ED, 0xCFC1,
-       0x72EE, 0xCAA8,
-       0x72EF, 0xE1F6,
-       0x72F0, 0xD5F8,
-       0x72F1, 0xD3FC,
-       0x72F2, 0xE1F8,
-       0x72F3, 0xE1FC,
-       0x72F4, 0xE1F9,
-       0x72F7, 0xE1FA,
-       0x72F8, 0xC0EA,
-       0x72FA, 0xE1FE,
-       0x72FB, 0xE2A1,
-       0x72FC, 0xC0C7,
-       0x7301, 0xE1FB,
-       0x7303, 0xE1FD,
-       0x730A, 0xE2A5,
-       0x730E, 0xC1D4,
-       0x7313, 0xE2A3,
-       0x7315, 0xE2A8,
-       0x7316, 0xB2FE,
-       0x7317, 0xE2A2,
-       0x731B, 0xC3CD,
-       0x731C, 0xB2C2,
-       0x731D, 0xE2A7,
-       0x731E, 0xE2A6,
-       0x7321, 0xE2A4,
-       0x7322, 0xE2A9,
-       0x7325, 0xE2AB,
-       0x7329, 0xD0C9,
-       0x732A, 0xD6ED,
-       0x732B, 0xC3A8,
-       0x732C, 0xE2AC,
-       0x732E, 0xCFD7,
-       0x7331, 0xE2AE,
-       0x7334, 0xBAEF,
-       0x7337, 0xE9E0,
-       0x7338, 0xE2AD,
-       0x7339, 0xE2AA,
-       0x733E, 0xBBAB,
-       0x733F, 0xD4B3,
-       0x734D, 0xE2B0,
-       0x7350, 0xE2AF,
-       0x7352, 0xE9E1,
-       0x7357, 0xE2B1,
-       0x7360, 0xE2B2,
-       0x736C, 0xE2B3,
-       0x736D, 0xCCA1,
-       0x736F, 0xE2B4,
-       0x737E, 0xE2B5,
-       0x7384, 0xD0FE,
-       0x7387, 0xC2CA,
-       0x7389, 0xD3F1,
-       0x738B, 0xCDF5,
-       0x738E, 0xE7E0,
-       0x7391, 0xE7E1,
-       0x7396, 0xBEC1,
-       0x739B, 0xC2EA,
-       0x739F, 0xE7E4,
-       0x73A2, 0xE7E3,
-       0x73A9, 0xCDE6,
-       0x73AB, 0xC3B5,
-       0x73AE, 0xE7E2,
-       0x73AF, 0xBBB7,
-       0x73B0, 0xCFD6,
-       0x73B2, 0xC1E1,
-       0x73B3, 0xE7E9,
-       0x73B7, 0xE7E8,
-       0x73BA, 0xE7F4,
-       0x73BB, 0xB2A3,
-       0x73C0, 0xE7EA,
-       0x73C2, 0xE7E6,
-       0x73C8, 0xE7EC,
-       0x73C9, 0xE7EB,
-       0x73CA, 0xC9BA,
-       0x73CD, 0xD5E4,
-       0x73CF, 0xE7E5,
-       0x73D0, 0xB7A9,
-       0x73D1, 0xE7E7,
-       0x73D9, 0xE7EE,
-       0x73DE, 0xE7F3,
-       0x73E0, 0xD6E9,
-       0x73E5, 0xE7ED,
-       0x73E7, 0xE7F2,
-       0x73E9, 0xE7F1,
-       0x73ED, 0xB0E0,
-       0x73F2, 0xE7F5,
-       0x7403, 0xC7F2,
-       0x7405, 0xC0C5,
-       0x7406, 0xC0ED,
-       0x7409, 0xC1F0,
-       0x740A, 0xE7F0,
-       0x740F, 0xE7F6,
-       0x7410, 0xCBF6,
-       0x741A, 0xE8A2,
-       0x741B, 0xE8A1,
-       0x7422, 0xD7C1,
-       0x7425, 0xE7FA,
-       0x7426, 0xE7F9,
-       0x7428, 0xE7FB,
-       0x742A, 0xE7F7,
-       0x742C, 0xE7FE,
-       0x742E, 0xE7FD,
-       0x7430, 0xE7FC,
-       0x7433, 0xC1D5,
-       0x7434, 0xC7D9,
-       0x7435, 0xC5FD,
-       0x7436, 0xC5C3,
-       0x743C, 0xC7ED,
-       0x7441, 0xE8A3,
-       0x7455, 0xE8A6,
-       0x7457, 0xE8A5,
-       0x7459, 0xE8A7,
-       0x745A, 0xBAF7,
-       0x745B, 0xE7F8,
-       0x745C, 0xE8A4,
-       0x745E, 0xC8F0,
-       0x745F, 0xC9AA,
-       0x746D, 0xE8A9,
-       0x7470, 0xB9E5,
-       0x7476, 0xD1FE,
-       0x7477, 0xE8A8,
-       0x747E, 0xE8AA,
-       0x7480, 0xE8AD,
-       0x7481, 0xE8AE,
-       0x7483, 0xC1A7,
-       0x7487, 0xE8AF,
-       0x748B, 0xE8B0,
-       0x748E, 0xE8AC,
-       0x7490, 0xE8B4,
-       0x749C, 0xE8AB,
-       0x749E, 0xE8B1,
-       0x74A7, 0xE8B5,
-       0x74A8, 0xE8B2,
-       0x74A9, 0xE8B3,
-       0x74BA, 0xE8B7,
-       0x74D2, 0xE8B6,
-       0x74DC, 0xB9CF,
-       0x74DE, 0xF0AC,
-       0x74E0, 0xF0AD,
-       0x74E2, 0xC6B0,
-       0x74E3, 0xB0EA,
-       0x74E4, 0xC8BF,
-       0x74E6, 0xCDDF,
-       0x74EE, 0xCECD,
-       0x74EF, 0xEAB1,
-       0x74F4, 0xEAB2,
-       0x74F6, 0xC6BF,
-       0x74F7, 0xB4C9,
-       0x74FF, 0xEAB3,
-       0x7504, 0xD5E7,
-       0x750D, 0xDDF9,
-       0x750F, 0xEAB4,
-       0x7511, 0xEAB5,
-       0x7513, 0xEAB6,
-       0x7518, 0xB8CA,
-       0x7519, 0xDFB0,
-       0x751A, 0xC9F5,
-       0x751C, 0xCCF0,
-       0x751F, 0xC9FA,
-       0x7525, 0xC9FB,
-       0x7528, 0xD3C3,
-       0x7529, 0xCBA6,
-       0x752B, 0xB8A6,
-       0x752C, 0xF0AE,
-       0x752D, 0xB1C2,
-       0x752F, 0xE5B8,
-       0x7530, 0xCCEF,
-       0x7531, 0xD3C9,
-       0x7532, 0xBCD7,
-       0x7533, 0xC9EA,
-       0x7535, 0xB5E7,
-       0x7537, 0xC4D0,
-       0x7538, 0xB5E9,
-       0x753A, 0xEEAE,
-       0x753B, 0xBBAD,
-       0x753E, 0xE7DE,
-       0x7540, 0xEEAF,
-       0x7545, 0xB3A9,
-       0x7548, 0xEEB2,
-       0x754B, 0xEEB1,
-       0x754C, 0xBDE7,
-       0x754E, 0xEEB0,
-       0x754F, 0xCEB7,
-       0x7554, 0xC5CF,
-       0x7559, 0xC1F4,
-       0x755A, 0xDBCE,
-       0x755B, 0xEEB3,
-       0x755C, 0xD0F3,
-       0x7565, 0xC2D4,
-       0x7566, 0xC6E8,
-       0x756A, 0xB7AC,
-       0x7572, 0xEEB4,
-       0x7574, 0xB3EB,
-       0x7578, 0xBBFB,
-       0x7579, 0xEEB5,
-       0x757F, 0xE7DC,
-       0x7583, 0xEEB6,
-       0x7586, 0xBDAE,
-       0x758B, 0xF1E2,
-       0x758F, 0xCAE8,
-       0x7591, 0xD2C9,
-       0x7592, 0xF0DA,
-       0x7594, 0xF0DB,
-       0x7596, 0xF0DC,
-       0x7597, 0xC1C6,
-       0x7599, 0xB8ED,
-       0x759A, 0xBECE,
-       0x759D, 0xF0DE,
-       0x759F, 0xC5B1,
-       0x75A0, 0xF0DD,
-       0x75A1, 0xD1F1,
-       0x75A3, 0xF0E0,
-       0x75A4, 0xB0CC,
-       0x75A5, 0xBDEA,
-       0x75AB, 0xD2DF,
-       0x75AC, 0xF0DF,
-       0x75AE, 0xB4AF,
-       0x75AF, 0xB7E8,
-       0x75B0, 0xF0E6,
-       0x75B1, 0xF0E5,
-       0x75B2, 0xC6A3,
-       0x75B3, 0xF0E1,
-       0x75B4, 0xF0E2,
-       0x75B5, 0xB4C3,
-       0x75B8, 0xF0E3,
-       0x75B9, 0xD5EE,
-       0x75BC, 0xCCDB,
-       0x75BD, 0xBED2,
-       0x75BE, 0xBCB2,
-       0x75C2, 0xF0E8,
-       0x75C3, 0xF0E7,
-       0x75C4, 0xF0E4,
-       0x75C5, 0xB2A1,
-       0x75C7, 0xD6A2,
-       0x75C8, 0xD3B8,
-       0x75C9, 0xBEB7,
-       0x75CA, 0xC8AC,
-       0x75CD, 0xF0EA,
-       0x75D2, 0xD1F7,
-       0x75D4, 0xD6CC,
-       0x75D5, 0xBADB,
-       0x75D6, 0xF0E9,
-       0x75D8, 0xB6BB,
-       0x75DB, 0xCDB4,
-       0x75DE, 0xC6A6,
-       0x75E2, 0xC1A1,
-       0x75E3, 0xF0EB,
-       0x75E4, 0xF0EE,
-       0x75E6, 0xF0ED,
-       0x75E7, 0xF0F0,
-       0x75E8, 0xF0EC,
-       0x75EA, 0xBBBE,
-       0x75EB, 0xF0EF,
-       0x75F0, 0xCCB5,
-       0x75F1, 0xF0F2,
-       0x75F4, 0xB3D5,
-       0x75F9, 0xB1D4,
-       0x75FC, 0xF0F3,
-       0x75FF, 0xF0F4,
-       0x7600, 0xF0F6,
-       0x7601, 0xB4E1,
-       0x7603, 0xF0F1,
-       0x7605, 0xF0F7,
-       0x760A, 0xF0FA,
-       0x760C, 0xF0F8,
-       0x7610, 0xF0F5,
-       0x7615, 0xF0FD,
-       0x7617, 0xF0F9,
-       0x7618, 0xF0FC,
-       0x7619, 0xF0FE,
-       0x761B, 0xF1A1,
-       0x761F, 0xCEC1,
-       0x7620, 0xF1A4,
-       0x7622, 0xF1A3,
-       0x7624, 0xC1F6,
-       0x7625, 0xF0FB,
-       0x7626, 0xCADD,
-       0x7629, 0xB4F1,
-       0x762A, 0xB1F1,
-       0x762B, 0xCCB1,
-       0x762D, 0xF1A6,
-       0x7630, 0xF1A7,
-       0x7633, 0xF1AC,
-       0x7634, 0xD5CE,
-       0x7635, 0xF1A9,
-       0x7638, 0xC8B3,
-       0x763C, 0xF1A2,
-       0x763E, 0xF1AB,
-       0x763F, 0xF1A8,
-       0x7640, 0xF1A5,
-       0x7643, 0xF1AA,
-       0x764C, 0xB0A9,
-       0x764D, 0xF1AD,
-       0x7654, 0xF1AF,
-       0x7656, 0xF1B1,
-       0x765C, 0xF1B0,
-       0x765E, 0xF1AE,
-       0x7663, 0xD1A2,
-       0x766B, 0xF1B2,
-       0x766F, 0xF1B3,
-       0x7678, 0xB9EF,
-       0x767B, 0xB5C7,
-       0x767D, 0xB0D7,
-       0x767E, 0xB0D9,
-       0x7682, 0xD4ED,
-       0x7684, 0xB5C4,
-       0x7686, 0xBDD4,
-       0x7687, 0xBBCA,
-       0x7688, 0xF0A7,
-       0x768B, 0xB8DE,
-       0x768E, 0xF0A8,
-       0x7691, 0xB0A8,
-       0x7693, 0xF0A9,
-       0x7696, 0xCDEE,
-       0x7699, 0xF0AA,
-       0x76A4, 0xF0AB,
-       0x76AE, 0xC6A4,
-       0x76B1, 0xD6E5,
-       0x76B2, 0xF1E4,
-       0x76B4, 0xF1E5,
-       0x76BF, 0xC3F3,
-       0x76C2, 0xD3DB,
-       0x76C5, 0xD6D1,
-       0x76C6, 0xC5E8,
-       0x76C8, 0xD3AF,
-       0x76CA, 0xD2E6,
-       0x76CD, 0xEEC1,
-       0x76CE, 0xB0BB,
-       0x76CF, 0xD5B5,
-       0x76D0, 0xD1CE,
-       0x76D1, 0xBCE0,
-       0x76D2, 0xBAD0,
-       0x76D4, 0xBFF8,
-       0x76D6, 0xB8C7,
-       0x76D7, 0xB5C1,
-       0x76D8, 0xC5CC,
-       0x76DB, 0xCAA2,
-       0x76DF, 0xC3CB,
-       0x76E5, 0xEEC2,
-       0x76EE, 0xC4BF,
-       0x76EF, 0xB6A2,
-       0x76F1, 0xEDEC,
-       0x76F2, 0xC3A4,
-       0x76F4, 0xD6B1,
-       0x76F8, 0xCFE0,
-       0x76F9, 0xEDEF,
-       0x76FC, 0xC5CE,
-       0x76FE, 0xB6DC,
-       0x7701, 0xCAA1,
-       0x7704, 0xEDED,
-       0x7707, 0xEDF0,
-       0x7708, 0xEDF1,
-       0x7709, 0xC3BC,
-       0x770B, 0xBFB4,
-       0x770D, 0xEDEE,
-       0x7719, 0xEDF4,
-       0x771A, 0xEDF2,
-       0x771F, 0xD5E6,
-       0x7720, 0xC3DF,
-       0x7722, 0xEDF3,
-       0x7726, 0xEDF6,
-       0x7728, 0xD5A3,
-       0x7729, 0xD1A3,
-       0x772D, 0xEDF5,
-       0x772F, 0xC3D0,
-       0x7735, 0xEDF7,
-       0x7736, 0xBFF4,
-       0x7737, 0xBEEC,
-       0x7738, 0xEDF8,
-       0x773A, 0xCCF7,
-       0x773C, 0xD1DB,
-       0x7740, 0xD7C5,
-       0x7741, 0xD5F6,
-       0x7743, 0xEDFC,
-       0x7747, 0xEDFB,
-       0x7750, 0xEDF9,
-       0x7751, 0xEDFA,
-       0x775A, 0xEDFD,
-       0x775B, 0xBEA6,
-       0x7761, 0xCBAF,
-       0x7762, 0xEEA1,
-       0x7763, 0xB6BD,
-       0x7765, 0xEEA2,
-       0x7766, 0xC4C0,
-       0x7768, 0xEDFE,
-       0x776B, 0xBDDE,
-       0x776C, 0xB2C7,
-       0x7779, 0xB6C3,
-       0x777D, 0xEEA5,
-       0x777E, 0xD8BA,
-       0x777F, 0xEEA3,
-       0x7780, 0xEEA6,
-       0x7784, 0xC3E9,
-       0x7785, 0xB3F2,
-       0x778C, 0xEEA7,
-       0x778D, 0xEEA4,
-       0x778E, 0xCFB9,
-       0x7791, 0xEEA8,
-       0x7792, 0xC2F7,
-       0x779F, 0xEEA9,
-       0x77A0, 0xEEAA,
-       0x77A2, 0xDEAB,
-       0x77A5, 0xC6B3,
-       0x77A7, 0xC7C6,
-       0x77A9, 0xD6F5,
-       0x77AA, 0xB5C9,
-       0x77AC, 0xCBB2,
-       0x77B0, 0xEEAB,
-       0x77B3, 0xCDAB,
-       0x77B5, 0xEEAC,
-       0x77BB, 0xD5B0,
-       0x77BD, 0xEEAD,
-       0x77BF, 0xF6C4,
-       0x77CD, 0xDBC7,
-       0x77D7, 0xB4A3,
-       0x77DB, 0xC3AC,
-       0x77DC, 0xF1E6,
-       0x77E2, 0xCAB8,
-       0x77E3, 0xD2D3,
-       0x77E5, 0xD6AA,
-       0x77E7, 0xEFF2,
-       0x77E9, 0xBED8,
-       0x77EB, 0xBDC3,
-       0x77EC, 0xEFF3,
-       0x77ED, 0xB6CC,
-       0x77EE, 0xB0AB,
-       0x77F3, 0xCAAF,
-       0x77F6, 0xEDB6,
-       0x77F8, 0xEDB7,
-       0x77FD, 0xCEF9,
-       0x77FE, 0xB7AF,
-       0x77FF, 0xBFF3,
-       0x7800, 0xEDB8,
-       0x7801, 0xC2EB,
-       0x7802, 0xC9B0,
-       0x7809, 0xEDB9,
-       0x780C, 0xC6F6,
-       0x780D, 0xBFB3,
-       0x7811, 0xEDBC,
-       0x7812, 0xC5F8,
-       0x7814, 0xD1D0,
-       0x7816, 0xD7A9,
-       0x7817, 0xEDBA,
-       0x7818, 0xEDBB,
-       0x781A, 0xD1E2,
-       0x781C, 0xEDBF,
-       0x781D, 0xEDC0,
-       0x781F, 0xEDC4,
-       0x7823, 0xEDC8,
-       0x7825, 0xEDC6,
-       0x7826, 0xEDCE,
-       0x7827, 0xD5E8,
-       0x7829, 0xEDC9,
-       0x782C, 0xEDC7,
-       0x782D, 0xEDBE,
-       0x7830, 0xC5E9,
-       0x7834, 0xC6C6,
-       0x7837, 0xC9E9,
-       0x7838, 0xD4D2,
-       0x7839, 0xEDC1,
-       0x783A, 0xEDC2,
-       0x783B, 0xEDC3,
-       0x783C, 0xEDC5,
-       0x783E, 0xC0F9,
-       0x7840, 0xB4A1,
-       0x7845, 0xB9E8,
-       0x7847, 0xEDD0,
-       0x784C, 0xEDD1,
-       0x784E, 0xEDCA,
-       0x7850, 0xEDCF,
-       0x7852, 0xCEF8,
-       0x7855, 0xCBB6,
-       0x7856, 0xEDCC,
-       0x7857, 0xEDCD,
-       0x785D, 0xCFF5,
-       0x786A, 0xEDD2,
-       0x786B, 0xC1F2,
-       0x786C, 0xD3B2,
-       0x786D, 0xEDCB,
-       0x786E, 0xC8B7,
-       0x7877, 0xBCEF,
-       0x787C, 0xC5F0,
-       0x7887, 0xEDD6,
-       0x7889, 0xB5EF,
-       0x788C, 0xC2B5,
-       0x788D, 0xB0AD,
-       0x788E, 0xCBE9,
-       0x7891, 0xB1AE,
-       0x7893, 0xEDD4,
-       0x7897, 0xCDEB,
-       0x7898, 0xB5E2,
-       0x789A, 0xEDD5,
-       0x789B, 0xEDD3,
-       0x789C, 0xEDD7,
-       0x789F, 0xB5FA,
-       0x78A1, 0xEDD8,
-       0x78A3, 0xEDD9,
-       0x78A5, 0xEDDC,
-       0x78A7, 0xB1CC,
-       0x78B0, 0xC5F6,
-       0x78B1, 0xBCEE,
-       0x78B2, 0xEDDA,
-       0x78B3, 0xCCBC,
-       0x78B4, 0xB2EA,
-       0x78B9, 0xEDDB,
-       0x78BE, 0xC4EB,
-       0x78C1, 0xB4C5,
-       0x78C5, 0xB0F5,
-       0x78C9, 0xEDDF,
-       0x78CA, 0xC0DA,
-       0x78CB, 0xB4E8,
-       0x78D0, 0xC5CD,
-       0x78D4, 0xEDDD,
-       0x78D5, 0xBFC4,
-       0x78D9, 0xEDDE,
-       0x78E8, 0xC4A5,
-       0x78EC, 0xEDE0,
-       0x78F2, 0xEDE1,
-       0x78F4, 0xEDE3,
-       0x78F7, 0xC1D7,
-       0x78FA, 0xBBC7,
-       0x7901, 0xBDB8,
-       0x7905, 0xEDE2,
-       0x7913, 0xEDE4,
-       0x791E, 0xEDE6,
-       0x7924, 0xEDE5,
-       0x7934, 0xEDE7,
-       0x793A, 0xCABE,
-       0x793B, 0xECEA,
-       0x793C, 0xC0F1,
-       0x793E, 0xC9E7,
-       0x7940, 0xECEB,
-       0x7941, 0xC6EE,
-       0x7946, 0xECEC,
-       0x7948, 0xC6ED,
-       0x7949, 0xECED,
-       0x7953, 0xECF0,
-       0x7956, 0xD7E6,
-       0x7957, 0xECF3,
-       0x795A, 0xECF1,
-       0x795B, 0xECEE,
-       0x795C, 0xECEF,
-       0x795D, 0xD7A3,
-       0x795E, 0xC9F1,
-       0x795F, 0xCBEE,
-       0x7960, 0xECF4,
-       0x7962, 0xECF2,
-       0x7965, 0xCFE9,
-       0x7967, 0xECF6,
-       0x7968, 0xC6B1,
-       0x796D, 0xBCC0,
-       0x796F, 0xECF5,
-       0x7977, 0xB5BB,
-       0x7978, 0xBBF6,
-       0x797A, 0xECF7,
-       0x7980, 0xD9F7,
-       0x7981, 0xBDFB,
-       0x7984, 0xC2BB,
-       0x7985, 0xECF8,
-       0x798A, 0xECF9,
-       0x798F, 0xB8A3,
-       0x799A, 0xECFA,
-       0x79A7, 0xECFB,
-       0x79B3, 0xECFC,
-       0x79B9, 0xD3ED,
-       0x79BA, 0xD8AE,
-       0x79BB, 0xC0EB,
-       0x79BD, 0xC7DD,
-       0x79BE, 0xBACC,
-       0x79C0, 0xD0E3,
-       0x79C1, 0xCBBD,
-       0x79C3, 0xCDBA,
-       0x79C6, 0xB8D1,
-       0x79C9, 0xB1FC,
-       0x79CB, 0xC7EF,
-       0x79CD, 0xD6D6,
-       0x79D1, 0xBFC6,
-       0x79D2, 0xC3EB,
-       0x79D5, 0xEFF5,
-       0x79D8, 0xC3D8,
-       0x79DF, 0xD7E2,
-       0x79E3, 0xEFF7,
-       0x79E4, 0xB3D3,
-       0x79E6, 0xC7D8,
-       0x79E7, 0xD1ED,
-       0x79E9, 0xD6C8,
-       0x79EB, 0xEFF8,
-       0x79ED, 0xEFF6,
-       0x79EF, 0xBBFD,
-       0x79F0, 0xB3C6,
-       0x79F8, 0xBDD5,
-       0x79FB, 0xD2C6,
-       0x79FD, 0xBBE0,
-       0x7A00, 0xCFA1,
-       0x7A02, 0xEFFC,
-       0x7A03, 0xEFFB,
-       0x7A06, 0xEFF9,
-       0x7A0B, 0xB3CC,
-       0x7A0D, 0xC9D4,
-       0x7A0E, 0xCBB0,
-       0x7A14, 0xEFFE,
-       0x7A17, 0xB0DE,
-       0x7A1A, 0xD6C9,
-       0x7A1E, 0xEFFD,
-       0x7A20, 0xB3ED,
-       0x7A23, 0xF6D5,
-       0x7A33, 0xCEC8,
-       0x7A37, 0xF0A2,
-       0x7A39, 0xF0A1,
-       0x7A3B, 0xB5BE,
-       0x7A3C, 0xBCDA,
-       0x7A3D, 0xBBFC,
-       0x7A3F, 0xB8E5,
-       0x7A46, 0xC4C2,
-       0x7A51, 0xF0A3,
-       0x7A57, 0xCBEB,
-       0x7A70, 0xF0A6,
-       0x7A74, 0xD1A8,
-       0x7A76, 0xBEBF,
-       0x7A77, 0xC7EE,
-       0x7A78, 0xF1B6,
-       0x7A79, 0xF1B7,
-       0x7A7A, 0xBFD5,
-       0x7A7F, 0xB4A9,
-       0x7A80, 0xF1B8,
-       0x7A81, 0xCDBB,
-       0x7A83, 0xC7D4,
-       0x7A84, 0xD5AD,
-       0x7A86, 0xF1B9,
-       0x7A88, 0xF1BA,
-       0x7A8D, 0xC7CF,
-       0x7A91, 0xD2A4,
-       0x7A92, 0xD6CF,
-       0x7A95, 0xF1BB,
-       0x7A96, 0xBDD1,
-       0x7A97, 0xB4B0,
-       0x7A98, 0xBEBD,
-       0x7A9C, 0xB4DC,
-       0x7A9D, 0xCED1,
-       0x7A9F, 0xBFDF,
-       0x7AA0, 0xF1BD,
-       0x7AA5, 0xBFFA,
-       0x7AA6, 0xF1BC,
-       0x7AA8, 0xF1BF,
-       0x7AAC, 0xF1BE,
-       0x7AAD, 0xF1C0,
-       0x7AB3, 0xF1C1,
-       0x7ABF, 0xC1FE,
-       0x7ACB, 0xC1A2,
-       0x7AD6, 0xCAFA,
-       0x7AD9, 0xD5BE,
-       0x7ADE, 0xBEBA,
-       0x7ADF, 0xBEB9,
-       0x7AE0, 0xD5C2,
-       0x7AE3, 0xBFA2,
-       0x7AE5, 0xCDAF,
-       0x7AE6, 0xF1B5,
-       0x7AED, 0xBDDF,
-       0x7AEF, 0xB6CB,
-       0x7AF9, 0xD6F1,
-       0x7AFA, 0xF3C3,
-       0x7AFD, 0xF3C4,
-       0x7AFF, 0xB8CD,
-       0x7B03, 0xF3C6,
-       0x7B04, 0xF3C7,
-       0x7B06, 0xB0CA,
-       0x7B08, 0xF3C5,
-       0x7B0A, 0xF3C9,
-       0x7B0B, 0xCBF1,
-       0x7B0F, 0xF3CB,
-       0x7B11, 0xD0A6,
-       0x7B14, 0xB1CA,
-       0x7B15, 0xF3C8,
-       0x7B19, 0xF3CF,
-       0x7B1B, 0xB5D1,
-       0x7B1E, 0xF3D7,
-       0x7B20, 0xF3D2,
-       0x7B24, 0xF3D4,
-       0x7B25, 0xF3D3,
-       0x7B26, 0xB7FB,
-       0x7B28, 0xB1BF,
-       0x7B2A, 0xF3CE,
-       0x7B2B, 0xF3CA,
-       0x7B2C, 0xB5DA,
-       0x7B2E, 0xF3D0,
-       0x7B31, 0xF3D1,
-       0x7B33, 0xF3D5,
-       0x7B38, 0xF3CD,
-       0x7B3A, 0xBCE3,
-       0x7B3C, 0xC1FD,
-       0x7B3E, 0xF3D6,
-       0x7B45, 0xF3DA,
-       0x7B47, 0xF3CC,
-       0x7B49, 0xB5C8,
-       0x7B4B, 0xBDEE,
-       0x7B4C, 0xF3DC,
-       0x7B4F, 0xB7A4,
-       0x7B50, 0xBFF0,
-       0x7B51, 0xD6FE,
-       0x7B52, 0xCDB2,
-       0x7B54, 0xB4F0,
-       0x7B56, 0xB2DF,
-       0x7B58, 0xF3D8,
-       0x7B5A, 0xF3D9,
-       0x7B5B, 0xC9B8,
-       0x7B5D, 0xF3DD,
-       0x7B60, 0xF3DE,
-       0x7B62, 0xF3E1,
-       0x7B6E, 0xF3DF,
-       0x7B71, 0xF3E3,
-       0x7B72, 0xF3E2,
-       0x7B75, 0xF3DB,
-       0x7B77, 0xBFEA,
-       0x7B79, 0xB3EF,
-       0x7B7B, 0xF3E0,
-       0x7B7E, 0xC7A9,
-       0x7B80, 0xBCF2,
-       0x7B85, 0xF3EB,
-       0x7B8D, 0xB9BF,
-       0x7B90, 0xF3E4,
-       0x7B94, 0xB2AD,
-       0x7B95, 0xBBFE,
-       0x7B97, 0xCBE3,
-       0x7B9C, 0xF3ED,
-       0x7B9D, 0xF3E9,
-       0x7BA1, 0xB9DC,
-       0x7BA2, 0xF3EE,
-       0x7BA6, 0xF3E5,
-       0x7BA7, 0xF3E6,
-       0x7BA8, 0xF3EA,
-       0x7BA9, 0xC2E1,
-       0x7BAA, 0xF3EC,
-       0x7BAB, 0xF3EF,
-       0x7BAC, 0xF3E8,
-       0x7BAD, 0xBCFD,
-       0x7BB1, 0xCFE4,
-       0x7BB4, 0xF3F0,
-       0x7BB8, 0xF3E7,
-       0x7BC1, 0xF3F2,
-       0x7BC6, 0xD7AD,
-       0x7BC7, 0xC6AA,
-       0x7BCC, 0xF3F3,
-       0x7BD1, 0xF3F1,
-       0x7BD3, 0xC2A8,
-       0x7BD9, 0xB8DD,
-       0x7BDA, 0xF3F5,
-       0x7BDD, 0xF3F4,
-       0x7BE1, 0xB4DB,
-       0x7BE5, 0xF3F6,
-       0x7BE6, 0xF3F7,
-       0x7BEA, 0xF3F8,
-       0x7BEE, 0xC0BA,
-       0x7BF1, 0xC0E9,
-       0x7BF7, 0xC5F1,
-       0x7BFC, 0xF3FB,
-       0x7BFE, 0xF3FA,
-       0x7C07, 0xB4D8,
-       0x7C0B, 0xF3FE,
-       0x7C0C, 0xF3F9,
-       0x7C0F, 0xF3FC,
-       0x7C16, 0xF3FD,
-       0x7C1F, 0xF4A1,
-       0x7C26, 0xF4A3,
-       0x7C27, 0xBBC9,
-       0x7C2A, 0xF4A2,
-       0x7C38, 0xF4A4,
-       0x7C3F, 0xB2BE,
-       0x7C40, 0xF4A6,
-       0x7C41, 0xF4A5,
-       0x7C4D, 0xBCAE,
-       0x7C73, 0xC3D7,
-       0x7C74, 0xD9E1,
-       0x7C7B, 0xC0E0,
-       0x7C7C, 0xF4CC,
-       0x7C7D, 0xD7D1,
-       0x7C89, 0xB7DB,
-       0x7C91, 0xF4CE,
-       0x7C92, 0xC1A3,
-       0x7C95, 0xC6C9,
-       0x7C97, 0xB4D6,
-       0x7C98, 0xD5B3,
-       0x7C9C, 0xF4D0,
-       0x7C9D, 0xF4CF,
-       0x7C9E, 0xF4D1,
-       0x7C9F, 0xCBDA,
-       0x7CA2, 0xF4D2,
-       0x7CA4, 0xD4C1,
-       0x7CA5, 0xD6E0,
-       0x7CAA, 0xB7E0,
-       0x7CAE, 0xC1B8,
-       0x7CB1, 0xC1BB,
-       0x7CB2, 0xF4D3,
-       0x7CB3, 0xBEAC,
-       0x7CB9, 0xB4E2,
-       0x7CBC, 0xF4D4,
-       0x7CBD, 0xF4D5,
-       0x7CBE, 0xBEAB,
-       0x7CC1, 0xF4D6,
-       0x7CC5, 0xF4DB,
-       0x7CC7, 0xF4D7,
-       0x7CC8, 0xF4DA,
-       0x7CCA, 0xBAFD,
-       0x7CCC, 0xF4D8,
-       0x7CCD, 0xF4D9,
-       0x7CD5, 0xB8E2,
-       0x7CD6, 0xCCC7,
-       0x7CD7, 0xF4DC,
-       0x7CD9, 0xB2DA,
-       0x7CDC, 0xC3D3,
-       0x7CDF, 0xD4E3,
-       0x7CE0, 0xBFB7,
-       0x7CE8, 0xF4DD,
-       0x7CEF, 0xC5B4,
-       0x7CF8, 0xF4E9,
-       0x7CFB, 0xCFB5,
-       0x7D0A, 0xCEC9,
-       0x7D20, 0xCBD8,
-       0x7D22, 0xCBF7,
-       0x7D27, 0xBDF4,
-       0x7D2B, 0xD7CF,
-       0x7D2F, 0xC0DB,
-       0x7D6E, 0xD0F5,
-       0x7D77, 0xF4EA,
-       0x7DA6, 0xF4EB,
-       0x7DAE, 0xF4EC,
-       0x7E3B, 0xF7E3,
-       0x7E41, 0xB7B1,
-       0x7E47, 0xF4ED,
-       0x7E82, 0xD7EB,
-       0x7E9B, 0xF4EE,
-       0x7E9F, 0xE6F9,
-       0x7EA0, 0xBEC0,
-       0x7EA1, 0xE6FA,
-       0x7EA2, 0xBAEC,
-       0x7EA3, 0xE6FB,
-       0x7EA4, 0xCFCB,
-       0x7EA5, 0xE6FC,
-       0x7EA6, 0xD4BC,
-       0x7EA7, 0xBCB6,
-       0x7EA8, 0xE6FD,
-       0x7EA9, 0xE6FE,
-       0x7EAA, 0xBCCD,
-       0x7EAB, 0xC8D2,
-       0x7EAC, 0xCEB3,
-       0x7EAD, 0xE7A1,
-       0x7EAF, 0xB4BF,
-       0x7EB0, 0xE7A2,
-       0x7EB1, 0xC9B4,
-       0x7EB2, 0xB8D9,
-       0x7EB3, 0xC4C9,
-       0x7EB5, 0xD7DD,
-       0x7EB6, 0xC2DA,
-       0x7EB7, 0xB7D7,
-       0x7EB8, 0xD6BD,
-       0x7EB9, 0xCEC6,
-       0x7EBA, 0xB7C4,
-       0x7EBD, 0xC5A6,
-       0x7EBE, 0xE7A3,
-       0x7EBF, 0xCFDF,
-       0x7EC0, 0xE7A4,
-       0x7EC1, 0xE7A5,
-       0x7EC2, 0xE7A6,
-       0x7EC3, 0xC1B7,
-       0x7EC4, 0xD7E9,
-       0x7EC5, 0xC9F0,
-       0x7EC6, 0xCFB8,
-       0x7EC7, 0xD6AF,
-       0x7EC8, 0xD6D5,
-       0x7EC9, 0xE7A7,
-       0x7ECA, 0xB0ED,
-       0x7ECB, 0xE7A8,
-       0x7ECC, 0xE7A9,
-       0x7ECD, 0xC9DC,
-       0x7ECE, 0xD2EF,
-       0x7ECF, 0xBEAD,
-       0x7ED0, 0xE7AA,
-       0x7ED1, 0xB0F3,
-       0x7ED2, 0xC8DE,
-       0x7ED3, 0xBDE1,
-       0x7ED4, 0xE7AB,
-       0x7ED5, 0xC8C6,
-       0x7ED7, 0xE7AC,
-       0x7ED8, 0xBBE6,
-       0x7ED9, 0xB8F8,
-       0x7EDA, 0xD1A4,
-       0x7EDB, 0xE7AD,
-       0x7EDC, 0xC2E7,
-       0x7EDD, 0xBEF8,
-       0x7EDE, 0xBDCA,
-       0x7EDF, 0xCDB3,
-       0x7EE0, 0xE7AE,
-       0x7EE1, 0xE7AF,
-       0x7EE2, 0xBEEE,
-       0x7EE3, 0xD0E5,
-       0x7EE5, 0xCBE7,
-       0x7EE6, 0xCCD0,
-       0x7EE7, 0xBCCC,
-       0x7EE8, 0xE7B0,
-       0x7EE9, 0xBCA8,
-       0x7EEA, 0xD0F7,
-       0x7EEB, 0xE7B1,
-       0x7EED, 0xD0F8,
-       0x7EEE, 0xE7B2,
-       0x7EEF, 0xE7B3,
-       0x7EF0, 0xB4C2,
-       0x7EF1, 0xE7B4,
-       0x7EF2, 0xE7B5,
-       0x7EF3, 0xC9FE,
-       0x7EF4, 0xCEAC,
-       0x7EF5, 0xC3E0,
-       0x7EF6, 0xE7B7,
-       0x7EF7, 0xB1C1,
-       0x7EF8, 0xB3F1,
-       0x7EFA, 0xE7B8,
-       0x7EFB, 0xE7B9,
-       0x7EFC, 0xD7DB,
-       0x7EFD, 0xD5C0,
-       0x7EFE, 0xE7BA,
-       0x7EFF, 0xC2CC,
-       0x7F00, 0xD7BA,
-       0x7F01, 0xE7BB,
-       0x7F02, 0xE7BC,
-       0x7F03, 0xE7BD,
-       0x7F04, 0xBCEA,
-       0x7F05, 0xC3E5,
-       0x7F06, 0xC0C2,
-       0x7F07, 0xE7BE,
-       0x7F08, 0xE7BF,
-       0x7F09, 0xBCA9,
-       0x7F0B, 0xE7C0,
-       0x7F0C, 0xE7C1,
-       0x7F0D, 0xE7B6,
-       0x7F0E, 0xB6D0,
-       0x7F0F, 0xE7C2,
-       0x7F11, 0xE7C3,
-       0x7F12, 0xE7C4,
-       0x7F13, 0xBBBA,
-       0x7F14, 0xB5DE,
-       0x7F15, 0xC2C6,
-       0x7F16, 0xB1E0,
-       0x7F17, 0xE7C5,
-       0x7F18, 0xD4B5,
-       0x7F19, 0xE7C6,
-       0x7F1A, 0xB8BF,
-       0x7F1B, 0xE7C8,
-       0x7F1C, 0xE7C7,
-       0x7F1D, 0xB7EC,
-       0x7F1F, 0xE7C9,
-       0x7F20, 0xB2F8,
-       0x7F21, 0xE7CA,
-       0x7F22, 0xE7CB,
-       0x7F23, 0xE7CC,
-       0x7F24, 0xE7CD,
-       0x7F25, 0xE7CE,
-       0x7F26, 0xE7CF,
-       0x7F27, 0xE7D0,
-       0x7F28, 0xD3A7,
-       0x7F29, 0xCBF5,
-       0x7F2A, 0xE7D1,
-       0x7F2B, 0xE7D2,
-       0x7F2C, 0xE7D3,
-       0x7F2D, 0xE7D4,
-       0x7F2E, 0xC9C9,
-       0x7F2F, 0xE7D5,
-       0x7F30, 0xE7D6,
-       0x7F31, 0xE7D7,
-       0x7F32, 0xE7D8,
-       0x7F33, 0xE7D9,
-       0x7F34, 0xBDC9,
-       0x7F35, 0xE7DA,
-       0x7F36, 0xF3BE,
-       0x7F38, 0xB8D7,
-       0x7F3A, 0xC8B1,
-       0x7F42, 0xF3BF,
-       0x7F44, 0xF3C0,
-       0x7F45, 0xF3C1,
-       0x7F50, 0xB9DE,
-       0x7F51, 0xCDF8,
-       0x7F54, 0xD8E8,
-       0x7F55, 0xBAB1,
-       0x7F57, 0xC2DE,
-       0x7F58, 0xEEB7,
-       0x7F5A, 0xB7A3,
-       0x7F5F, 0xEEB9,
-       0x7F61, 0xEEB8,
-       0x7F62, 0xB0D5,
-       0x7F68, 0xEEBB,
-       0x7F69, 0xD5D6,
-       0x7F6A, 0xD7EF,
-       0x7F6E, 0xD6C3,
-       0x7F71, 0xEEBD,
-       0x7F72, 0xCAF0,
-       0x7F74, 0xEEBC,
-       0x7F79, 0xEEBE,
-       0x7F7E, 0xEEC0,
-       0x7F81, 0xEEBF,
-       0x7F8A, 0xD1F2,
-       0x7F8C, 0xC7BC,
-       0x7F8E, 0xC3C0,
-       0x7F94, 0xB8E1,
-       0x7F9A, 0xC1E7,
-       0x7F9D, 0xF4C6,
-       0x7F9E, 0xD0DF,
-       0x7F9F, 0xF4C7,
-       0x7FA1, 0xCFDB,
-       0x7FA4, 0xC8BA,
-       0x7FA7, 0xF4C8,
-       0x7FAF, 0xF4C9,
-       0x7FB0, 0xF4CA,
-       0x7FB2, 0xF4CB,
-       0x7FB8, 0xD9FA,
-       0x7FB9, 0xB8FE,
-       0x7FBC, 0xE5F1,
-       0x7FBD, 0xD3F0,
-       0x7FBF, 0xF4E0,
-       0x7FC1, 0xCECC,
-       0x7FC5, 0xB3E1,
-       0x7FCA, 0xF1B4,
-       0x7FCC, 0xD2EE,
-       0x7FCE, 0xF4E1,
-       0x7FD4, 0xCFE8,
-       0x7FD5, 0xF4E2,
-       0x7FD8, 0xC7CC,
-       0x7FDF, 0xB5D4,
-       0x7FE0, 0xB4E4,
-       0x7FE1, 0xF4E4,
-       0x7FE5, 0xF4E3,
-       0x7FE6, 0xF4E5,
-       0x7FE9, 0xF4E6,
-       0x7FEE, 0xF4E7,
-       0x7FF0, 0xBAB2,
-       0x7FF1, 0xB0BF,
-       0x7FF3, 0xF4E8,
-       0x7FFB, 0xB7AD,
-       0x7FFC, 0xD2ED,
-       0x8000, 0xD2AB,
-       0x8001, 0xC0CF,
-       0x8003, 0xBFBC,
-       0x8004, 0xEBA3,
-       0x8005, 0xD5DF,
-       0x8006, 0xEAC8,
-       0x800B, 0xF1F3,
-       0x800C, 0xB6F8,
-       0x800D, 0xCBA3,
-       0x8010, 0xC4CD,
-       0x8012, 0xF1E7,
-       0x8014, 0xF1E8,
-       0x8015, 0xB8FB,
-       0x8016, 0xF1E9,
-       0x8017, 0xBAC4,
-       0x8018, 0xD4C5,
-       0x8019, 0xB0D2,
-       0x801C, 0xF1EA,
-       0x8020, 0xF1EB,
-       0x8022, 0xF1EC,
-       0x8025, 0xF1ED,
-       0x8026, 0xF1EE,
-       0x8027, 0xF1EF,
-       0x8028, 0xF1F1,
-       0x8029, 0xF1F0,
-       0x802A, 0xC5D5,
-       0x8031, 0xF1F2,
-       0x8033, 0xB6FA,
-       0x8035, 0xF1F4,
-       0x8036, 0xD2AE,
-       0x8037, 0xDEC7,
-       0x8038, 0xCBCA,
-       0x803B, 0xB3DC,
-       0x803D, 0xB5A2,
-       0x803F, 0xB9A2,
-       0x8042, 0xC4F4,
-       0x8043, 0xF1F5,
-       0x8046, 0xF1F6,
-       0x804A, 0xC1C4,
-       0x804B, 0xC1FB,
-       0x804C, 0xD6B0,
-       0x804D, 0xF1F7,
-       0x8052, 0xF1F8,
-       0x8054, 0xC1AA,
-       0x8058, 0xC6B8,
-       0x805A, 0xBEDB,
-       0x8069, 0xF1F9,
-       0x806A, 0xB4CF,
-       0x8071, 0xF1FA,
-       0x807F, 0xEDB2,
-       0x8080, 0xEDB1,
-       0x8083, 0xCBE0,
-       0x8084, 0xD2DE,
-       0x8086, 0xCBC1,
-       0x8087, 0xD5D8,
-       0x8089, 0xC8E2,
-       0x808B, 0xC0DF,
-       0x808C, 0xBCA1,
-       0x8093, 0xEBC1,
-       0x8096, 0xD0A4,
-       0x8098, 0xD6E2,
-       0x809A, 0xB6C7,
-       0x809B, 0xB8D8,
-       0x809C, 0xEBC0,
-       0x809D, 0xB8CE,
-       0x809F, 0xEBBF,
-       0x80A0, 0xB3A6,
-       0x80A1, 0xB9C9,
-       0x80A2, 0xD6AB,
-       0x80A4, 0xB7F4,
-       0x80A5, 0xB7CA,
-       0x80A9, 0xBCE7,
-       0x80AA, 0xB7BE,
-       0x80AB, 0xEBC6,
-       0x80AD, 0xEBC7,
-       0x80AE, 0xB0B9,
-       0x80AF, 0xBFCF,
-       0x80B1, 0xEBC5,
-       0x80B2, 0xD3FD,
-       0x80B4, 0xEBC8,
-       0x80B7, 0xEBC9,
-       0x80BA, 0xB7CE,
-       0x80BC, 0xEBC2,
-       0x80BD, 0xEBC4,
-       0x80BE, 0xC9F6,
-       0x80BF, 0xD6D7,
-       0x80C0, 0xD5CD,
-       0x80C1, 0xD0B2,
-       0x80C2, 0xEBCF,
-       0x80C3, 0xCEB8,
-       0x80C4, 0xEBD0,
-       0x80C6, 0xB5A8,
-       0x80CC, 0xB1B3,
-       0x80CD, 0xEBD2,
-       0x80CE, 0xCCA5,
-       0x80D6, 0xC5D6,
-       0x80D7, 0xEBD3,
-       0x80D9, 0xEBD1,
-       0x80DA, 0xC5DF,
-       0x80DB, 0xEBCE,
-       0x80DC, 0xCAA4,
-       0x80DD, 0xEBD5,
-       0x80DE, 0xB0FB,
-       0x80E1, 0xBAFA,
-       0x80E4, 0xD8B7,
-       0x80E5, 0xF1E3,
-       0x80E7, 0xEBCA,
-       0x80E8, 0xEBCB,
-       0x80E9, 0xEBCC,
-       0x80EA, 0xEBCD,
-       0x80EB, 0xEBD6,
-       0x80EC, 0xE6C0,
-       0x80ED, 0xEBD9,
-       0x80EF, 0xBFE8,
-       0x80F0, 0xD2C8,
-       0x80F1, 0xEBD7,
-       0x80F2, 0xEBDC,
-       0x80F3, 0xB8EC,
-       0x80F4, 0xEBD8,
-       0x80F6, 0xBDBA,
-       0x80F8, 0xD0D8,
-       0x80FA, 0xB0B7,
-       0x80FC, 0xEBDD,
-       0x80FD, 0xC4DC,
-       0x8102, 0xD6AC,
-       0x8106, 0xB4E0,
-       0x8109, 0xC2F6,
-       0x810A, 0xBCB9,
-       0x810D, 0xEBDA,
-       0x810E, 0xEBDB,
-       0x810F, 0xD4E0,
-       0x8110, 0xC6EA,
-       0x8111, 0xC4D4,
-       0x8112, 0xEBDF,
-       0x8113, 0xC5A7,
-       0x8114, 0xD9F5,
-       0x8116, 0xB2B1,
-       0x8118, 0xEBE4,
-       0x811A, 0xBDC5,
-       0x811E, 0xEBE2,
-       0x812C, 0xEBE3,
-       0x812F, 0xB8AC,
-       0x8131, 0xCDD1,
-       0x8132, 0xEBE5,
-       0x8136, 0xEBE1,
-       0x8138, 0xC1B3,
-       0x813E, 0xC6A2,
-       0x8146, 0xCCF3,
-       0x8148, 0xEBE6,
-       0x814A, 0xC0B0,
-       0x814B, 0xD2B8,
-       0x814C, 0xEBE7,
-       0x8150, 0xB8AF,
-       0x8151, 0xB8AD,
-       0x8153, 0xEBE8,
-       0x8154, 0xC7BB,
-       0x8155, 0xCDF3,
-       0x8159, 0xEBEA,
-       0x815A, 0xEBEB,
-       0x8160, 0xEBED,
-       0x8165, 0xD0C8,
-       0x8167, 0xEBF2,
-       0x8169, 0xEBEE,
-       0x816D, 0xEBF1,
-       0x816E, 0xC8F9,
-       0x8170, 0xD1FC,
-       0x8171, 0xEBEC,
-       0x8174, 0xEBE9,
-       0x8179, 0xB8B9,
-       0x817A, 0xCFD9,
-       0x817B, 0xC4E5,
-       0x817C, 0xEBEF,
-       0x817D, 0xEBF0,
-       0x817E, 0xCCDA,
-       0x817F, 0xCDC8,
-       0x8180, 0xB0F2,
-       0x8182, 0xEBF6,
-       0x8188, 0xEBF5,
-       0x818A, 0xB2B2,
-       0x818F, 0xB8E0,
-       0x8191, 0xEBF7,
-       0x8198, 0xB1EC,
-       0x819B, 0xCCC5,
-       0x819C, 0xC4A4,
-       0x819D, 0xCFA5,
-       0x81A3, 0xEBF9,
-       0x81A6, 0xECA2,
-       0x81A8, 0xC5F2,
-       0x81AA, 0xEBFA,
-       0x81B3, 0xC9C5,
-       0x81BA, 0xE2DF,
-       0x81BB, 0xEBFE,
-       0x81C0, 0xCDCE,
-       0x81C1, 0xECA1,
-       0x81C2, 0xB1DB,
-       0x81C3, 0xD3B7,
-       0x81C6, 0xD2DC,
-       0x81CA, 0xEBFD,
-       0x81CC, 0xEBFB,
-       0x81E3, 0xB3BC,
-       0x81E7, 0xEAB0,
-       0x81EA, 0xD7D4,
-       0x81EC, 0xF4AB,
-       0x81ED, 0xB3F4,
-       0x81F3, 0xD6C1,
-       0x81F4, 0xD6C2,
-       0x81FB, 0xD5E9,
-       0x81FC, 0xBECA,
-       0x81FE, 0xF4A7,
-       0x8200, 0xD2A8,
-       0x8201, 0xF4A8,
-       0x8202, 0xF4A9,
-       0x8204, 0xF4AA,
-       0x8205, 0xBECB,
-       0x8206, 0xD3DF,
-       0x820C, 0xC9E0,
-       0x820D, 0xC9E1,
-       0x8210, 0xF3C2,
-       0x8212, 0xCAE6,
-       0x8214, 0xCCF2,
-       0x821B, 0xE2B6,
-       0x821C, 0xCBB4,
-       0x821E, 0xCEE8,
-       0x821F, 0xD6DB,
-       0x8221, 0xF4AD,
-       0x8222, 0xF4AE,
-       0x8223, 0xF4AF,
-       0x8228, 0xF4B2,
-       0x822A, 0xBABD,
-       0x822B, 0xF4B3,
-       0x822C, 0xB0E3,
-       0x822D, 0xF4B0,
-       0x822F, 0xF4B1,
-       0x8230, 0xBDA2,
-       0x8231, 0xB2D5,
-       0x8233, 0xF4B6,
-       0x8234, 0xF4B7,
-       0x8235, 0xB6E6,
-       0x8236, 0xB2B0,
-       0x8237, 0xCFCF,
-       0x8238, 0xF4B4,
-       0x8239, 0xB4AC,
-       0x823B, 0xF4B5,
-       0x823E, 0xF4B8,
-       0x8244, 0xF4B9,
-       0x8247, 0xCDA7,
-       0x8249, 0xF4BA,
-       0x824B, 0xF4BB,
-       0x824F, 0xF4BC,
-       0x8258, 0xCBD2,
-       0x825A, 0xF4BD,
-       0x825F, 0xF4BE,
-       0x8268, 0xF4BF,
-       0x826E, 0xF4DE,
-       0x826F, 0xC1BC,
-       0x8270, 0xBCE8,
-       0x8272, 0xC9AB,
-       0x8273, 0xD1DE,
-       0x8274, 0xE5F5,
-       0x8279, 0xDCB3,
-       0x827A, 0xD2D5,
-       0x827D, 0xDCB4,
-       0x827E, 0xB0AC,
-       0x827F, 0xDCB5,
-       0x8282, 0xBDDA,
-       0x8284, 0xDCB9,
-       0x8288, 0xD8C2,
-       0x828A, 0xDCB7,
-       0x828B, 0xD3F3,
-       0x828D, 0xC9D6,
-       0x828E, 0xDCBA,
-       0x828F, 0xDCB6,
-       0x8291, 0xDCBB,
-       0x8292, 0xC3A2,
-       0x8297, 0xDCBC,
-       0x8298, 0xDCC5,
-       0x8299, 0xDCBD,
-       0x829C, 0xCEDF,
-       0x829D, 0xD6A5,
-       0x829F, 0xDCCF,
-       0x82A1, 0xDCCD,
-       0x82A4, 0xDCD2,
-       0x82A5, 0xBDE6,
-       0x82A6, 0xC2AB,
-       0x82A8, 0xDCB8,
-       0x82A9, 0xDCCB,
-       0x82AA, 0xDCCE,
-       0x82AB, 0xDCBE,
-       0x82AC, 0xB7D2,
-       0x82AD, 0xB0C5,
-       0x82AE, 0xDCC7,
-       0x82AF, 0xD0BE,
-       0x82B0, 0xDCC1,
-       0x82B1, 0xBBA8,
-       0x82B3, 0xB7BC,
-       0x82B4, 0xDCCC,
-       0x82B7, 0xDCC6,
-       0x82B8, 0xDCBF,
-       0x82B9, 0xC7DB,
-       0x82BD, 0xD1BF,
-       0x82BE, 0xDCC0,
-       0x82C1, 0xDCCA,
-       0x82C4, 0xDCD0,
-       0x82C7, 0xCEAD,
-       0x82C8, 0xDCC2,
-       0x82CA, 0xDCC3,
-       0x82CB, 0xDCC8,
-       0x82CC, 0xDCC9,
-       0x82CD, 0xB2D4,
-       0x82CE, 0xDCD1,
-       0x82CF, 0xCBD5,
-       0x82D1, 0xD4B7,
-       0x82D2, 0xDCDB,
-       0x82D3, 0xDCDF,
-       0x82D4, 0xCCA6,
-       0x82D5, 0xDCE6,
-       0x82D7, 0xC3E7,
-       0x82D8, 0xDCDC,
-       0x82DB, 0xBFC1,
-       0x82DC, 0xDCD9,
-       0x82DE, 0xB0FA,
-       0x82DF, 0xB9B6,
-       0x82E0, 0xDCE5,
-       0x82E1, 0xDCD3,
-       0x82E3, 0xDCC4,
-       0x82E4, 0xDCD6,
-       0x82E5, 0xC8F4,
-       0x82E6, 0xBFE0,
-       0x82EB, 0xC9BB,
-       0x82EF, 0xB1BD,
-       0x82F1, 0xD3A2,
-       0x82F4, 0xDCDA,
-       0x82F7, 0xDCD5,
-       0x82F9, 0xC6BB,
-       0x82FB, 0xDCDE,
-       0x8301, 0xD7C2,
-       0x8302, 0xC3AF,
-       0x8303, 0xB7B6,
-       0x8304, 0xC7D1,
-       0x8305, 0xC3A9,
-       0x8306, 0xDCE2,
-       0x8307, 0xDCD8,
-       0x8308, 0xDCEB,
-       0x8309, 0xDCD4,
-       0x830C, 0xDCDD,
-       0x830E, 0xBEA5,
-       0x830F, 0xDCD7,
-       0x8311, 0xDCE0,
-       0x8314, 0xDCE3,
-       0x8315, 0xDCE4,
-       0x8317, 0xDCF8,
-       0x831A, 0xDCE1,
-       0x831B, 0xDDA2,
-       0x831C, 0xDCE7,
-       0x8327, 0xBCEB,
-       0x8328, 0xB4C4,
-       0x832B, 0xC3A3,
-       0x832C, 0xB2E7,
-       0x832D, 0xDCFA,
-       0x832F, 0xDCF2,
-       0x8331, 0xDCEF,
-       0x8333, 0xDCFC,
-       0x8334, 0xDCEE,
-       0x8335, 0xD2F0,
-       0x8336, 0xB2E8,
-       0x8338, 0xC8D7,
-       0x8339, 0xC8E3,
-       0x833A, 0xDCFB,
-       0x833C, 0xDCED,
-       0x8340, 0xDCF7,
-       0x8343, 0xDCF5,
-       0x8346, 0xBEA3,
-       0x8347, 0xDCF4,
-       0x8349, 0xB2DD,
-       0x834F, 0xDCF3,
-       0x8350, 0xBCF6,
-       0x8351, 0xDCE8,
-       0x8352, 0xBBC4,
-       0x8354, 0xC0F3,
-       0x835A, 0xBCD4,
-       0x835B, 0xDCE9,
-       0x835C, 0xDCEA,
-       0x835E, 0xDCF1,
-       0x835F, 0xDCF6,
-       0x8360, 0xDCF9,
-       0x8361, 0xB5B4,
-       0x8363, 0xC8D9,
-       0x8364, 0xBBE7,
-       0x8365, 0xDCFE,
-       0x8366, 0xDCFD,
-       0x8367, 0xD3AB,
-       0x8368, 0xDDA1,
-       0x8369, 0xDDA3,
-       0x836A, 0xDDA5,
-       0x836B, 0xD2F1,
-       0x836C, 0xDDA4,
-       0x836D, 0xDDA6,
-       0x836E, 0xDDA7,
-       0x836F, 0xD2A9,
-       0x8377, 0xBAC9,
-       0x8378, 0xDDA9,
-       0x837B, 0xDDB6,
-       0x837C, 0xDDB1,
-       0x837D, 0xDDB4,
-       0x8385, 0xDDB0,
-       0x8386, 0xC6CE,
-       0x8389, 0xC0F2,
-       0x838E, 0xC9AF,
-       0x8392, 0xDCEC,
-       0x8393, 0xDDAE,
-       0x8398, 0xDDB7,
-       0x839B, 0xDCF0,
-       0x839C, 0xDDAF,
-       0x839E, 0xDDB8,
-       0x83A0, 0xDDAC,
-       0x83A8, 0xDDB9,
-       0x83A9, 0xDDB3,
-       0x83AA, 0xDDAD,
-       0x83AB, 0xC4AA,
-       0x83B0, 0xDDA8,
-       0x83B1, 0xC0B3,
-       0x83B2, 0xC1AB,
-       0x83B3, 0xDDAA,
-       0x83B4, 0xDDAB,
-       0x83B6, 0xDDB2,
-       0x83B7, 0xBBF1,
-       0x83B8, 0xDDB5,
-       0x83B9, 0xD3A8,
-       0x83BA, 0xDDBA,
-       0x83BC, 0xDDBB,
-       0x83BD, 0xC3A7,
-       0x83C0, 0xDDD2,
-       0x83C1, 0xDDBC,
-       0x83C5, 0xDDD1,
-       0x83C7, 0xB9BD,
-       0x83CA, 0xBED5,
-       0x83CC, 0xBEFA,
-       0x83CF, 0xBACA,
-       0x83D4, 0xDDCA,
-       0x83D6, 0xDDC5,
-       0x83D8, 0xDDBF,
-       0x83DC, 0xB2CB,
-       0x83DD, 0xDDC3,
-       0x83DF, 0xDDCB,
-       0x83E0, 0xB2A4,
-       0x83E1, 0xDDD5,
-       0x83E5, 0xDDBE,
-       0x83E9, 0xC6D0,
-       0x83EA, 0xDDD0,
-       0x83F0, 0xDDD4,
-       0x83F1, 0xC1E2,
-       0x83F2, 0xB7C6,
-       0x83F8, 0xDDCE,
-       0x83F9, 0xDDCF,
-       0x83FD, 0xDDC4,
-       0x8401, 0xDDBD,
-       0x8403, 0xDDCD,
-       0x8404, 0xCCD1,
-       0x8406, 0xDDC9,
-       0x840B, 0xDDC2,
-       0x840C, 0xC3C8,
-       0x840D, 0xC6BC,
-       0x840E, 0xCEAE,
-       0x840F, 0xDDCC,
-       0x8411, 0xDDC8,
-       0x8418, 0xDDC1,
-       0x841C, 0xDDC6,
-       0x841D, 0xC2DC,
-       0x8424, 0xD3A9,
-       0x8425, 0xD3AA,
-       0x8426, 0xDDD3,
-       0x8427, 0xCFF4,
-       0x8428, 0xC8F8,
-       0x8431, 0xDDE6,
-       0x8438, 0xDDC7,
-       0x843C, 0xDDE0,
-       0x843D, 0xC2E4,
-       0x8446, 0xDDE1,
-       0x8451, 0xDDD7,
-       0x8457, 0xD6F8,
-       0x8459, 0xDDD9,
-       0x845A, 0xDDD8,
-       0x845B, 0xB8F0,
-       0x845C, 0xDDD6,
-       0x8461, 0xC6CF,
-       0x8463, 0xB6AD,
-       0x8469, 0xDDE2,
-       0x846B, 0xBAF9,
-       0x846C, 0xD4E1,
-       0x846D, 0xDDE7,
-       0x8471, 0xB4D0,
-       0x8473, 0xDDDA,
-       0x8475, 0xBFFB,
-       0x8476, 0xDDE3,
-       0x8478, 0xDDDF,
-       0x847A, 0xDDDD,
-       0x8482, 0xB5D9,
-       0x8487, 0xDDDB,
-       0x8488, 0xDDDC,
-       0x8489, 0xDDDE,
-       0x848B, 0xBDAF,
-       0x848C, 0xDDE4,
-       0x848E, 0xDDE5,
-       0x8497, 0xDDF5,
-       0x8499, 0xC3C9,
-       0x849C, 0xCBE2,
-       0x84A1, 0xDDF2,
-       0x84AF, 0xD8E1,
-       0x84B2, 0xC6D1,
-       0x84B4, 0xDDF4,
-       0x84B8, 0xD5F4,
-       0x84B9, 0xDDF3,
-       0x84BA, 0xDDF0,
-       0x84BD, 0xDDEC,
-       0x84BF, 0xDDEF,
-       0x84C1, 0xDDE8,
-       0x84C4, 0xD0EE,
-       0x84C9, 0xC8D8,
-       0x84CA, 0xDDEE,
-       0x84CD, 0xDDE9,
-       0x84D0, 0xDDEA,
-       0x84D1, 0xCBF2,
-       0x84D3, 0xDDED,
-       0x84D6, 0xB1CD,
-       0x84DD, 0xC0B6,
-       0x84DF, 0xBCBB,
-       0x84E0, 0xDDF1,
-       0x84E3, 0xDDF7,
-       0x84E5, 0xDDF6,
-       0x84E6, 0xDDEB,
-       0x84EC, 0xC5EE,
-       0x84F0, 0xDDFB,
-       0x84FC, 0xDEA4,
-       0x84FF, 0xDEA3,
-       0x850C, 0xDDF8,
-       0x8511, 0xC3EF,
-       0x8513, 0xC2FB,
-       0x8517, 0xD5E1,
-       0x851A, 0xCEB5,
-       0x851F, 0xDDFD,
-       0x8521, 0xB2CC,
-       0x852B, 0xC4E8,
-       0x852C, 0xCADF,
-       0x8537, 0xC7BE,
-       0x8538, 0xDDFA,
-       0x8539, 0xDDFC,
-       0x853A, 0xDDFE,
-       0x853B, 0xDEA2,
-       0x853C, 0xB0AA,
-       0x853D, 0xB1CE,
-       0x8543, 0xDEAC,
-       0x8548, 0xDEA6,
-       0x8549, 0xBDB6,
-       0x854A, 0xC8EF,
-       0x8556, 0xDEA1,
-       0x8559, 0xDEA5,
-       0x855E, 0xDEA9,
-       0x8564, 0xDEA8,
-       0x8568, 0xDEA7,
-       0x8572, 0xDEAD,
-       0x8574, 0xD4CC,
-       0x8579, 0xDEB3,
-       0x857A, 0xDEAA,
-       0x857B, 0xDEAE,
-       0x857E, 0xC0D9,
-       0x8584, 0xB1A1,
-       0x8585, 0xDEB6,
-       0x8587, 0xDEB1,
-       0x858F, 0xDEB2,
-       0x859B, 0xD1A6,
-       0x859C, 0xDEB5,
-       0x85A4, 0xDEAF,
-       0x85A8, 0xDEB0,
-       0x85AA, 0xD0BD,
-       0x85AE, 0xDEB4,
-       0x85AF, 0xCAED,
-       0x85B0, 0xDEB9,
-       0x85B7, 0xDEB8,
-       0x85B9, 0xDEB7,
-       0x85C1, 0xDEBB,
-       0x85C9, 0xBDE5,
-       0x85CF, 0xB2D8,
-       0x85D0, 0xC3EA,
-       0x85D3, 0xDEBA,
-       0x85D5, 0xC5BA,
-       0x85DC, 0xDEBC,
-       0x85E4, 0xCCD9,
-       0x85E9, 0xB7AA,
-       0x85FB, 0xD4E5,
-       0x85FF, 0xDEBD,
-       0x8605, 0xDEBF,
-       0x8611, 0xC4A2,
-       0x8616, 0xDEC1,
-       0x8627, 0xDEBE,
-       0x8629, 0xDEC0,
-       0x8638, 0xD5BA,
-       0x863C, 0xDEC2,
-       0x864D, 0xF2AE,
-       0x864E, 0xBBA2,
-       0x864F, 0xC2B2,
-       0x8650, 0xC5B0,
-       0x8651, 0xC2C7,
-       0x8654, 0xF2AF,
-       0x865A, 0xD0E9,
-       0x865E, 0xD3DD,
-       0x8662, 0xEBBD,
-       0x866B, 0xB3E6,
-       0x866C, 0xF2B0,
-       0x866E, 0xF2B1,
-       0x8671, 0xCAAD,
-       0x8679, 0xBAE7,
-       0x867A, 0xF2B3,
-       0x867B, 0xF2B5,
-       0x867C, 0xF2B4,
-       0x867D, 0xCBE4,
-       0x867E, 0xCFBA,
-       0x867F, 0xF2B2,
-       0x8680, 0xCAB4,
-       0x8681, 0xD2CF,
-       0x8682, 0xC2EC,
-       0x868A, 0xCEC3,
-       0x868B, 0xF2B8,
-       0x868C, 0xB0F6,
-       0x868D, 0xF2B7,
-       0x8693, 0xF2BE,
-       0x8695, 0xB2CF,
-       0x869C, 0xD1C1,
-       0x869D, 0xF2BA,
-       0x86A3, 0xF2BC,
-       0x86A4, 0xD4E9,
-       0x86A7, 0xF2BB,
-       0x86A8, 0xF2B6,
-       0x86A9, 0xF2BF,
-       0x86AA, 0xF2BD,
-       0x86AC, 0xF2B9,
-       0x86AF, 0xF2C7,
-       0x86B0, 0xF2C4,
-       0x86B1, 0xF2C6,
-       0x86B4, 0xF2CA,
-       0x86B5, 0xF2C2,
-       0x86B6, 0xF2C0,
-       0x86BA, 0xF2C5,
-       0x86C0, 0xD6FB,
-       0x86C4, 0xF2C1,
-       0x86C6, 0xC7F9,
-       0x86C7, 0xC9DF,
-       0x86C9, 0xF2C8,
-       0x86CA, 0xB9C6,
-       0x86CB, 0xB5B0,
-       0x86CE, 0xF2C3,
-       0x86CF, 0xF2C9,
-       0x86D0, 0xF2D0,
-       0x86D1, 0xF2D6,
-       0x86D4, 0xBBD7,
-       0x86D8, 0xF2D5,
-       0x86D9, 0xCDDC,
-       0x86DB, 0xD6EB,
-       0x86DE, 0xF2D2,
-       0x86DF, 0xF2D4,
-       0x86E4, 0xB8F2,
-       0x86E9, 0xF2CB,
-       0x86ED, 0xF2CE,
-       0x86EE, 0xC2F9,
-       0x86F0, 0xD5DD,
-       0x86F1, 0xF2CC,
-       0x86F2, 0xF2CD,
-       0x86F3, 0xF2CF,
-       0x86F4, 0xF2D3,
-       0x86F8, 0xF2D9,
-       0x86F9, 0xD3BC,
-       0x86FE, 0xB6EA,
-       0x8700, 0xCAF1,
-       0x8702, 0xB7E4,
-       0x8703, 0xF2D7,
-       0x8707, 0xF2D8,
-       0x8708, 0xF2DA,
-       0x8709, 0xF2DD,
-       0x870A, 0xF2DB,
-       0x870D, 0xF2DC,
-       0x8712, 0xD1D1,
-       0x8713, 0xF2D1,
-       0x8715, 0xCDC9,
-       0x8717, 0xCECF,
-       0x8718, 0xD6A9,
-       0x871A, 0xF2E3,
-       0x871C, 0xC3DB,
-       0x871E, 0xF2E0,
-       0x8721, 0xC0AF,
-       0x8722, 0xF2EC,
-       0x8723, 0xF2DE,
-       0x8725, 0xF2E1,
-       0x8729, 0xF2E8,
-       0x872E, 0xF2E2,
-       0x8731, 0xF2E7,
-       0x8734, 0xF2E6,
-       0x8737, 0xF2E9,
-       0x873B, 0xF2DF,
-       0x873E, 0xF2E4,
-       0x873F, 0xF2EA,
-       0x8747, 0xD3AC,
-       0x8748, 0xF2E5,
-       0x8749, 0xB2F5,
-       0x874C, 0xF2F2,
-       0x874E, 0xD0AB,
-       0x8753, 0xF2F5,
-       0x8757, 0xBBC8,
-       0x8759, 0xF2F9,
-       0x8760, 0xF2F0,
-       0x8763, 0xF2F6,
-       0x8764, 0xF2F8,
-       0x8765, 0xF2FA,
-       0x876E, 0xF2F3,
-       0x8770, 0xF2F1,
-       0x8774, 0xBAFB,
-       0x8776, 0xB5FB,
-       0x877B, 0xF2EF,
-       0x877C, 0xF2F7,
-       0x877D, 0xF2ED,
-       0x877E, 0xF2EE,
-       0x8782, 0xF2EB,
-       0x8783, 0xF3A6,
-       0x8785, 0xF3A3,
-       0x8788, 0xF3A2,
-       0x878B, 0xF2F4,
-       0x878D, 0xC8DA,
-       0x8793, 0xF2FB,
-       0x8797, 0xF3A5,
-       0x879F, 0xC3F8,
-       0x87A8, 0xF2FD,
-       0x87AB, 0xF3A7,
-       0x87AC, 0xF3A9,
-       0x87AD, 0xF3A4,
-       0x87AF, 0xF2FC,
-       0x87B3, 0xF3AB,
-       0x87B5, 0xF3AA,
-       0x87BA, 0xC2DD,
-       0x87BD, 0xF3AE,
-       0x87C0, 0xF3B0,
-       0x87C6, 0xF3A1,
-       0x87CA, 0xF3B1,
-       0x87CB, 0xF3AC,
-       0x87D1, 0xF3AF,
-       0x87D2, 0xF2FE,
-       0x87D3, 0xF3AD,
-       0x87DB, 0xF3B2,
-       0x87E0, 0xF3B4,
-       0x87E5, 0xF3A8,
-       0x87EA, 0xF3B3,
-       0x87EE, 0xF3B5,
-       0x87F9, 0xD0B7,
-       0x87FE, 0xF3B8,
-       0x8803, 0xD9F9,
-       0x880A, 0xF3B9,
-       0x8813, 0xF3B7,
-       0x8815, 0xC8E4,
-       0x8816, 0xF3B6,
-       0x881B, 0xF3BA,
-       0x8821, 0xF3BB,
-       0x8822, 0xB4C0,
-       0x8832, 0xEEC3,
-       0x8839, 0xF3BC,
-       0x883C, 0xF3BD,
-       0x8840, 0xD1AA,
-       0x8844, 0xF4AC,
-       0x8845, 0xD0C6,
-       0x884C, 0xD0D0,
-       0x884D, 0xD1DC,
-       0x8854, 0xCFCE,
-       0x8857, 0xBDD6,
-       0x8859, 0xD1C3,
-       0x8861, 0xBAE2,
-       0x8862, 0xE1E9,
-       0x8863, 0xD2C2,
-       0x8864, 0xF1C2,
-       0x8865, 0xB2B9,
-       0x8868, 0xB1ED,
-       0x8869, 0xF1C3,
-       0x886B, 0xC9C0,
-       0x886C, 0xB3C4,
-       0x886E, 0xD9F2,
-       0x8870, 0xCBA5,
-       0x8872, 0xF1C4,
-       0x8877, 0xD6D4,
-       0x887D, 0xF1C5,
-       0x887E, 0xF4C0,
-       0x887F, 0xF1C6,
-       0x8881, 0xD4AC,
-       0x8882, 0xF1C7,
-       0x8884, 0xB0C0,
-       0x8885, 0xF4C1,
-       0x8888, 0xF4C2,
-       0x888B, 0xB4FC,
-       0x888D, 0xC5DB,
-       0x8892, 0xCCBB,
-       0x8896, 0xD0E4,
-       0x889C, 0xCDE0,
-       0x88A2, 0xF1C8,
-       0x88A4, 0xD9F3,
-       0x88AB, 0xB1BB,
-       0x88AD, 0xCFAE,
-       0x88B1, 0xB8A4,
-       0x88B7, 0xF1CA,
-       0x88BC, 0xF1CB,
-       0x88C1, 0xB2C3,
-       0x88C2, 0xC1D1,
-       0x88C5, 0xD7B0,
-       0x88C6, 0xF1C9,
-       0x88C9, 0xF1CC,
-       0x88CE, 0xF1CE,
-       0x88D2, 0xD9F6,
-       0x88D4, 0xD2E1,
-       0x88D5, 0xD4A3,
-       0x88D8, 0xF4C3,
-       0x88D9, 0xC8B9,
-       0x88DF, 0xF4C4,
-       0x88E2, 0xF1CD,
-       0x88E3, 0xF1CF,
-       0x88E4, 0xBFE3,
-       0x88E5, 0xF1D0,
-       0x88E8, 0xF1D4,
-       0x88F0, 0xF1D6,
-       0x88F1, 0xF1D1,
-       0x88F3, 0xC9D1,
-       0x88F4, 0xC5E1,
-       0x88F8, 0xC2E3,
-       0x88F9, 0xB9FC,
-       0x88FC, 0xF1D3,
-       0x88FE, 0xF1D5,
-       0x8902, 0xB9D3,
-       0x890A, 0xF1DB,
-       0x8910, 0xBAD6,
-       0x8912, 0xB0FD,
-       0x8913, 0xF1D9,
-       0x8919, 0xF1D8,
-       0x891A, 0xF1D2,
-       0x891B, 0xF1DA,
-       0x8921, 0xF1D7,
-       0x8925, 0xC8EC,
-       0x892A, 0xCDCA,
-       0x892B, 0xF1DD,
-       0x8930, 0xE5BD,
-       0x8934, 0xF1DC,
-       0x8936, 0xF1DE,
-       0x8941, 0xF1DF,
-       0x8944, 0xCFE5,
-       0x895E, 0xF4C5,
-       0x895F, 0xBDF3,
-       0x8966, 0xF1E0,
-       0x897B, 0xF1E1,
-       0x897F, 0xCEF7,
-       0x8981, 0xD2AA,
-       0x8983, 0xF1FB,
-       0x8986, 0xB8B2,
-       0x89C1, 0xBCFB,
-       0x89C2, 0xB9DB,
-       0x89C4, 0xB9E6,
-       0x89C5, 0xC3D9,
-       0x89C6, 0xCAD3,
-       0x89C7, 0xEAE8,
-       0x89C8, 0xC0C0,
-       0x89C9, 0xBEF5,
-       0x89CA, 0xEAE9,
-       0x89CB, 0xEAEA,
-       0x89CC, 0xEAEB,
-       0x89CE, 0xEAEC,
-       0x89CF, 0xEAED,
-       0x89D0, 0xEAEE,
-       0x89D1, 0xEAEF,
-       0x89D2, 0xBDC7,
-       0x89D6, 0xF5FB,
-       0x89DA, 0xF5FD,
-       0x89DC, 0xF5FE,
-       0x89DE, 0xF5FC,
-       0x89E3, 0xBDE2,
-       0x89E5, 0xF6A1,
-       0x89E6, 0xB4A5,
-       0x89EB, 0xF6A2,
-       0x89EF, 0xF6A3,
-       0x89F3, 0xECB2,
-       0x8A00, 0xD1D4,
-       0x8A07, 0xD9EA,
-       0x8A3E, 0xF6A4,
-       0x8A48, 0xEEBA,
-       0x8A79, 0xD5B2,
-       0x8A89, 0xD3FE,
-       0x8A8A, 0xCCDC,
-       0x8A93, 0xCAC4,
-       0x8B07, 0xE5C0,
-       0x8B26, 0xF6A5,
-       0x8B66, 0xBEAF,
-       0x8B6C, 0xC6A9,
-       0x8BA0, 0xDAA5,
-       0x8BA1, 0xBCC6,
-       0x8BA2, 0xB6A9,
-       0x8BA3, 0xB8BC,
-       0x8BA4, 0xC8CF,
-       0x8BA5, 0xBCA5,
-       0x8BA6, 0xDAA6,
-       0x8BA7, 0xDAA7,
-       0x8BA8, 0xCCD6,
-       0x8BA9, 0xC8C3,
-       0x8BAA, 0xDAA8,
-       0x8BAB, 0xC6FD,
-       0x8BAD, 0xD1B5,
-       0x8BAE, 0xD2E9,
-       0x8BAF, 0xD1B6,
-       0x8BB0, 0xBCC7,
-       0x8BB2, 0xBDB2,
-       0x8BB3, 0xBBE4,
-       0x8BB4, 0xDAA9,
-       0x8BB5, 0xDAAA,
-       0x8BB6, 0xD1C8,
-       0x8BB7, 0xDAAB,
-       0x8BB8, 0xD0ED,
-       0x8BB9, 0xB6EF,
-       0x8BBA, 0xC2DB,
-       0x8BBC, 0xCBCF,
-       0x8BBD, 0xB7ED,
-       0x8BBE, 0xC9E8,
-       0x8BBF, 0xB7C3,
-       0x8BC0, 0xBEF7,
-       0x8BC1, 0xD6A4,
-       0x8BC2, 0xDAAC,
-       0x8BC3, 0xDAAD,
-       0x8BC4, 0xC6C0,
-       0x8BC5, 0xD7E7,
-       0x8BC6, 0xCAB6,
-       0x8BC8, 0xD5A9,
-       0x8BC9, 0xCBDF,
-       0x8BCA, 0xD5EF,
-       0x8BCB, 0xDAAE,
-       0x8BCC, 0xD6DF,
-       0x8BCD, 0xB4CA,
-       0x8BCE, 0xDAB0,
-       0x8BCF, 0xDAAF,
-       0x8BD1, 0xD2EB,
-       0x8BD2, 0xDAB1,
-       0x8BD3, 0xDAB2,
-       0x8BD4, 0xDAB3,
-       0x8BD5, 0xCAD4,
-       0x8BD6, 0xDAB4,
-       0x8BD7, 0xCAAB,
-       0x8BD8, 0xDAB5,
-       0x8BD9, 0xDAB6,
-       0x8BDA, 0xB3CF,
-       0x8BDB, 0xD6EF,
-       0x8BDC, 0xDAB7,
-       0x8BDD, 0xBBB0,
-       0x8BDE, 0xB5AE,
-       0x8BDF, 0xDAB8,
-       0x8BE0, 0xDAB9,
-       0x8BE1, 0xB9EE,
-       0x8BE2, 0xD1AF,
-       0x8BE3, 0xD2E8,
-       0x8BE4, 0xDABA,
-       0x8BE5, 0xB8C3,
-       0x8BE6, 0xCFEA,
-       0x8BE7, 0xB2EF,
-       0x8BE8, 0xDABB,
-       0x8BE9, 0xDABC,
-       0x8BEB, 0xBDEB,
-       0x8BEC, 0xCEDC,
-       0x8BED, 0xD3EF,
-       0x8BEE, 0xDABD,
-       0x8BEF, 0xCEF3,
-       0x8BF0, 0xDABE,
-       0x8BF1, 0xD3D5,
-       0x8BF2, 0xBBE5,
-       0x8BF3, 0xDABF,
-       0x8BF4, 0xCBB5,
-       0x8BF5, 0xCBD0,
-       0x8BF6, 0xDAC0,
-       0x8BF7, 0xC7EB,
-       0x8BF8, 0xD6EE,
-       0x8BF9, 0xDAC1,
-       0x8BFA, 0xC5B5,
-       0x8BFB, 0xB6C1,
-       0x8BFC, 0xDAC2,
-       0x8BFD, 0xB7CC,
-       0x8BFE, 0xBFCE,
-       0x8BFF, 0xDAC3,
-       0x8C00, 0xDAC4,
-       0x8C01, 0xCBAD,
-       0x8C02, 0xDAC5,
-       0x8C03, 0xB5F7,
-       0x8C04, 0xDAC6,
-       0x8C05, 0xC1C2,
-       0x8C06, 0xD7BB,
-       0x8C07, 0xDAC7,
-       0x8C08, 0xCCB8,
-       0x8C0A, 0xD2EA,
-       0x8C0B, 0xC4B1,
-       0x8C0C, 0xDAC8,
-       0x8C0D, 0xB5FD,
-       0x8C0E, 0xBBD1,
-       0x8C0F, 0xDAC9,
-       0x8C10, 0xD0B3,
-       0x8C11, 0xDACA,
-       0x8C12, 0xDACB,
-       0x8C13, 0xCEBD,
-       0x8C14, 0xDACC,
-       0x8C15, 0xDACD,
-       0x8C16, 0xDACE,
-       0x8C17, 0xB2F7,
-       0x8C18, 0xDAD1,
-       0x8C19, 0xDACF,
-       0x8C1A, 0xD1E8,
-       0x8C1B, 0xDAD0,
-       0x8C1C, 0xC3D5,
-       0x8C1D, 0xDAD2,
-       0x8C1F, 0xDAD3,
-       0x8C20, 0xDAD4,
-       0x8C21, 0xDAD5,
-       0x8C22, 0xD0BB,
-       0x8C23, 0xD2A5,
-       0x8C24, 0xB0F9,
-       0x8C25, 0xDAD6,
-       0x8C26, 0xC7AB,
-       0x8C27, 0xDAD7,
-       0x8C28, 0xBDF7,
-       0x8C29, 0xC3A1,
-       0x8C2A, 0xDAD8,
-       0x8C2B, 0xDAD9,
-       0x8C2C, 0xC3FD,
-       0x8C2D, 0xCCB7,
-       0x8C2E, 0xDADA,
-       0x8C2F, 0xDADB,
-       0x8C30, 0xC0BE,
-       0x8C31, 0xC6D7,
-       0x8C32, 0xDADC,
-       0x8C33, 0xDADD,
-       0x8C34, 0xC7B4,
-       0x8C35, 0xDADE,
-       0x8C36, 0xDADF,
-       0x8C37, 0xB9C8,
-       0x8C41, 0xBBED,
-       0x8C46, 0xB6B9,
-       0x8C47, 0xF4F8,
-       0x8C49, 0xF4F9,
-       0x8C4C, 0xCDE3,
-       0x8C55, 0xF5B9,
-       0x8C5A, 0xEBE0,
-       0x8C61, 0xCFF3,
-       0x8C62, 0xBBBF,
-       0x8C6A, 0xBAC0,
-       0x8C6B, 0xD4A5,
-       0x8C73, 0xE1D9,
-       0x8C78, 0xF5F4,
-       0x8C79, 0xB1AA,
-       0x8C7A, 0xB2F2,
-       0x8C82, 0xF5F5,
-       0x8C85, 0xF5F7,
-       0x8C89, 0xBAD1,
-       0x8C8A, 0xF5F6,
-       0x8C8C, 0xC3B2,
-       0x8C94, 0xF5F9,
-       0x8C98, 0xF5F8,
-       0x8D1D, 0xB1B4,
-       0x8D1E, 0xD5EA,
-       0x8D1F, 0xB8BA,
-       0x8D21, 0xB9B1,
-       0x8D22, 0xB2C6,
-       0x8D23, 0xD4F0,
-       0x8D24, 0xCFCD,
-       0x8D25, 0xB0DC,
-       0x8D26, 0xD5CB,
-       0x8D27, 0xBBF5,
-       0x8D28, 0xD6CA,
-       0x8D29, 0xB7B7,
-       0x8D2A, 0xCCB0,
-       0x8D2B, 0xC6B6,
-       0x8D2C, 0xB1E1,
-       0x8D2D, 0xB9BA,
-       0x8D2E, 0xD6FC,
-       0x8D2F, 0xB9E1,
-       0x8D30, 0xB7A1,
-       0x8D31, 0xBCFA,
-       0x8D32, 0xEADA,
-       0x8D33, 0xEADB,
-       0x8D34, 0xCCF9,
-       0x8D35, 0xB9F3,
-       0x8D36, 0xEADC,
-       0x8D37, 0xB4FB,
-       0x8D38, 0xC3B3,
-       0x8D39, 0xB7D1,
-       0x8D3A, 0xBAD8,
-       0x8D3B, 0xEADD,
-       0x8D3C, 0xD4F4,
-       0x8D3D, 0xEADE,
-       0x8D3E, 0xBCD6,
-       0x8D3F, 0xBBDF,
-       0x8D40, 0xEADF,
-       0x8D41, 0xC1DE,
-       0x8D42, 0xC2B8,
-       0x8D43, 0xD4DF,
-       0x8D44, 0xD7CA,
-       0x8D45, 0xEAE0,
-       0x8D46, 0xEAE1,
-       0x8D47, 0xEAE4,
-       0x8D48, 0xEAE2,
-       0x8D49, 0xEAE3,
-       0x8D4A, 0xC9DE,
-       0x8D4B, 0xB8B3,
-       0x8D4C, 0xB6C4,
-       0x8D4D, 0xEAE5,
-       0x8D4E, 0xCAEA,
-       0x8D4F, 0xC9CD,
-       0x8D50, 0xB4CD,
-       0x8D53, 0xE2D9,
-       0x8D54, 0xC5E2,
-       0x8D55, 0xEAE6,
-       0x8D56, 0xC0B5,
-       0x8D58, 0xD7B8,
-       0x8D59, 0xEAE7,
-       0x8D5A, 0xD7AC,
-       0x8D5B, 0xC8FC,
-       0x8D5C, 0xD8D3,
-       0x8D5D, 0xD8CD,
-       0x8D5E, 0xD4DE,
-       0x8D60, 0xD4F9,
-       0x8D61, 0xC9C4,
-       0x8D62, 0xD3AE,
-       0x8D63, 0xB8D3,
-       0x8D64, 0xB3E0,
-       0x8D66, 0xC9E2,
-       0x8D67, 0xF4F6,
-       0x8D6B, 0xBAD5,
-       0x8D6D, 0xF4F7,
-       0x8D70, 0xD7DF,
-       0x8D73, 0xF4F1,
-       0x8D74, 0xB8B0,
-       0x8D75, 0xD5D4,
-       0x8D76, 0xB8CF,
-       0x8D77, 0xC6F0,
-       0x8D81, 0xB3C3,
-       0x8D84, 0xF4F2,
-       0x8D85, 0xB3AC,
-       0x8D8A, 0xD4BD,
-       0x8D8B, 0xC7F7,
-       0x8D91, 0xF4F4,
-       0x8D94, 0xF4F3,
-       0x8D9F, 0xCCCB,
-       0x8DA3, 0xC8A4,
-       0x8DB1, 0xF4F5,
-       0x8DB3, 0xD7E3,
-       0x8DB4, 0xC5BF,
-       0x8DB5, 0xF5C0,
-       0x8DB8, 0xF5BB,
-       0x8DBA, 0xF5C3,
-       0x8DBC, 0xF5C2,
-       0x8DBE, 0xD6BA,
-       0x8DBF, 0xF5C1,
-       0x8DC3, 0xD4BE,
-       0x8DC4, 0xF5C4,
-       0x8DC6, 0xF5CC,
-       0x8DCB, 0xB0CF,
-       0x8DCC, 0xB5F8,
-       0x8DCE, 0xF5C9,
-       0x8DCF, 0xF5CA,
-       0x8DD1, 0xC5DC,
-       0x8DD6, 0xF5C5,
-       0x8DD7, 0xF5C6,
-       0x8DDA, 0xF5C7,
-       0x8DDB, 0xF5CB,
-       0x8DDD, 0xBEE0,
-       0x8DDE, 0xF5C8,
-       0x8DDF, 0xB8FA,
-       0x8DE3, 0xF5D0,
-       0x8DE4, 0xF5D3,
-       0x8DE8, 0xBFE7,
-       0x8DEA, 0xB9F2,
-       0x8DEB, 0xF5BC,
-       0x8DEC, 0xF5CD,
-       0x8DEF, 0xC2B7,
-       0x8DF3, 0xCCF8,
-       0x8DF5, 0xBCF9,
-       0x8DF7, 0xF5CE,
-       0x8DF8, 0xF5CF,
-       0x8DF9, 0xF5D1,
-       0x8DFA, 0xB6E5,
-       0x8DFB, 0xF5D2,
-       0x8DFD, 0xF5D5,
-       0x8E05, 0xF5BD,
-       0x8E09, 0xF5D4,
-       0x8E0A, 0xD3BB,
-       0x8E0C, 0xB3EC,
-       0x8E0F, 0xCCA4,
-       0x8E14, 0xF5D6,
-       0x8E1D, 0xF5D7,
-       0x8E1E, 0xBEE1,
-       0x8E1F, 0xF5D8,
-       0x8E22, 0xCCDF,
-       0x8E23, 0xF5DB,
-       0x8E29, 0xB2C8,
-       0x8E2A, 0xD7D9,
-       0x8E2C, 0xF5D9,
-       0x8E2E, 0xF5DA,
-       0x8E2F, 0xF5DC,
-       0x8E31, 0xF5E2,
-       0x8E35, 0xF5E0,
-       0x8E39, 0xF5DF,
-       0x8E3A, 0xF5DD,
-       0x8E3D, 0xF5E1,
-       0x8E40, 0xF5DE,
-       0x8E41, 0xF5E4,
-       0x8E42, 0xF5E5,
-       0x8E44, 0xCCE3,
-       0x8E47, 0xE5BF,
-       0x8E48, 0xB5B8,
-       0x8E49, 0xF5E3,
-       0x8E4A, 0xF5E8,
-       0x8E4B, 0xCCA3,
-       0x8E51, 0xF5E6,
-       0x8E52, 0xF5E7,
-       0x8E59, 0xF5BE,
-       0x8E66, 0xB1C4,
-       0x8E69, 0xF5BF,
-       0x8E6C, 0xB5C5,
-       0x8E6D, 0xB2E4,
-       0x8E6F, 0xF5EC,
-       0x8E70, 0xF5E9,
-       0x8E72, 0xB6D7,
-       0x8E74, 0xF5ED,
-       0x8E76, 0xF5EA,
-       0x8E7C, 0xF5EB,
-       0x8E7F, 0xB4DA,
-       0x8E81, 0xD4EA,
-       0x8E85, 0xF5EE,
-       0x8E87, 0xB3F9,
-       0x8E8F, 0xF5EF,
-       0x8E90, 0xF5F1,
-       0x8E94, 0xF5F0,
-       0x8E9C, 0xF5F2,
-       0x8E9E, 0xF5F3,
-       0x8EAB, 0xC9ED,
-       0x8EAC, 0xB9AA,
-       0x8EAF, 0xC7FB,
-       0x8EB2, 0xB6E3,
-       0x8EBA, 0xCCC9,
-       0x8ECE, 0xEAA6,
-       0x8F66, 0xB3B5,
-       0x8F67, 0xD4FE,
-       0x8F68, 0xB9EC,
-       0x8F69, 0xD0F9,
-       0x8F6B, 0xE9ED,
-       0x8F6C, 0xD7AA,
-       0x8F6D, 0xE9EE,
-       0x8F6E, 0xC2D6,
-       0x8F6F, 0xC8ED,
-       0x8F70, 0xBAE4,
-       0x8F71, 0xE9EF,
-       0x8F72, 0xE9F0,
-       0x8F73, 0xE9F1,
-       0x8F74, 0xD6E1,
-       0x8F75, 0xE9F2,
-       0x8F76, 0xE9F3,
-       0x8F77, 0xE9F5,
-       0x8F78, 0xE9F4,
-       0x8F79, 0xE9F6,
-       0x8F7A, 0xE9F7,
-       0x8F7B, 0xC7E1,
-       0x8F7C, 0xE9F8,
-       0x8F7D, 0xD4D8,
-       0x8F7E, 0xE9F9,
-       0x8F7F, 0xBDCE,
-       0x8F81, 0xE9FA,
-       0x8F82, 0xE9FB,
-       0x8F83, 0xBDCF,
-       0x8F84, 0xE9FC,
-       0x8F85, 0xB8A8,
-       0x8F86, 0xC1BE,
-       0x8F87, 0xE9FD,
-       0x8F88, 0xB1B2,
-       0x8F89, 0xBBD4,
-       0x8F8A, 0xB9F5,
-       0x8F8B, 0xE9FE,
-       0x8F8D, 0xEAA1,
-       0x8F8E, 0xEAA2,
-       0x8F8F, 0xEAA3,
-       0x8F90, 0xB7F8,
-       0x8F91, 0xBCAD,
-       0x8F93, 0xCAE4,
-       0x8F94, 0xE0CE,
-       0x8F95, 0xD4AF,
-       0x8F96, 0xCFBD,
-       0x8F97, 0xD5B7,
-       0x8F98, 0xEAA4,
-       0x8F99, 0xD5DE,
-       0x8F9A, 0xEAA5,
-       0x8F9B, 0xD0C1,
-       0x8F9C, 0xB9BC,
-       0x8F9E, 0xB4C7,
-       0x8F9F, 0xB1D9,
-       0x8FA3, 0xC0B1,
-       0x8FA8, 0xB1E6,
-       0x8FA9, 0xB1E7,
-       0x8FAB, 0xB1E8,
-       0x8FB0, 0xB3BD,
-       0x8FB1, 0xC8E8,
-       0x8FB6, 0xE5C1,
-       0x8FB9, 0xB1DF,
-       0x8FBD, 0xC1C9,
-       0x8FBE, 0xB4EF,
-       0x8FC1, 0xC7A8,
-       0x8FC2, 0xD3D8,
-       0x8FC4, 0xC6F9,
-       0x8FC5, 0xD1B8,
-       0x8FC7, 0xB9FD,
-       0x8FC8, 0xC2F5,
-       0x8FCE, 0xD3AD,
-       0x8FD0, 0xD4CB,
-       0x8FD1, 0xBDFC,
-       0x8FD3, 0xE5C2,
-       0x8FD4, 0xB7B5,
-       0x8FD5, 0xE5C3,
-       0x8FD8, 0xBBB9,
-       0x8FD9, 0xD5E2,
-       0x8FDB, 0xBDF8,
-       0x8FDC, 0xD4B6,
-       0x8FDD, 0xCEA5,
-       0x8FDE, 0xC1AC,
-       0x8FDF, 0xB3D9,
-       0x8FE2, 0xCCF6,
-       0x8FE4, 0xE5C6,
-       0x8FE5, 0xE5C4,
-       0x8FE6, 0xE5C8,
-       0x8FE8, 0xE5CA,
-       0x8FE9, 0xE5C7,
-       0x8FEA, 0xB5CF,
-       0x8FEB, 0xC6C8,
-       0x8FED, 0xB5FC,
-       0x8FEE, 0xE5C5,
-       0x8FF0, 0xCAF6,
-       0x8FF3, 0xE5C9,
-       0x8FF7, 0xC3D4,
-       0x8FF8, 0xB1C5,
-       0x8FF9, 0xBCA3,
-       0x8FFD, 0xD7B7,
-       0x9000, 0xCDCB,
-       0x9001, 0xCBCD,
-       0x9002, 0xCACA,
-       0x9003, 0xCCD3,
-       0x9004, 0xE5CC,
-       0x9005, 0xE5CB,
-       0x9006, 0xC4E6,
-       0x9009, 0xD1A1,
-       0x900A, 0xD1B7,
-       0x900B, 0xE5CD,
-       0x900D, 0xE5D0,
-       0x900F, 0xCDB8,
-       0x9010, 0xD6F0,
-       0x9011, 0xE5CF,
-       0x9012, 0xB5DD,
-       0x9014, 0xCDBE,
-       0x9016, 0xE5D1,
-       0x9017, 0xB6BA,
-       0x901A, 0xCDA8,
-       0x901B, 0xB9E4,
-       0x901D, 0xCAC5,
-       0x901E, 0xB3D1,
-       0x901F, 0xCBD9,
-       0x9020, 0xD4EC,
-       0x9021, 0xE5D2,
-       0x9022, 0xB7EA,
-       0x9026, 0xE5CE,
-       0x902D, 0xE5D5,
-       0x902E, 0xB4FE,
-       0x902F, 0xE5D6,
-       0x9035, 0xE5D3,
-       0x9036, 0xE5D4,
-       0x9038, 0xD2DD,
-       0x903B, 0xC2DF,
-       0x903C, 0xB1C6,
-       0x903E, 0xD3E2,
-       0x9041, 0xB6DD,
-       0x9042, 0xCBEC,
-       0x9044, 0xE5D7,
-       0x9047, 0xD3F6,
-       0x904D, 0xB1E9,
-       0x904F, 0xB6F4,
-       0x9050, 0xE5DA,
-       0x9051, 0xE5D8,
-       0x9052, 0xE5D9,
-       0x9053, 0xB5C0,
-       0x9057, 0xD2C5,
-       0x9058, 0xE5DC,
-       0x905B, 0xE5DE,
-       0x9062, 0xE5DD,
-       0x9063, 0xC7B2,
-       0x9065, 0xD2A3,
-       0x9068, 0xE5DB,
-       0x906D, 0xD4E2,
-       0x906E, 0xD5DA,
-       0x9074, 0xE5E0,
-       0x9075, 0xD7F1,
-       0x907D, 0xE5E1,
-       0x907F, 0xB1DC,
-       0x9080, 0xD1FB,
-       0x9082, 0xE5E2,
-       0x9083, 0xE5E4,
-       0x9088, 0xE5E3,
-       0x908B, 0xE5E5,
-       0x9091, 0xD2D8,
-       0x9093, 0xB5CB,
-       0x9095, 0xE7DF,
-       0x9097, 0xDAF5,
-       0x9099, 0xDAF8,
-       0x909B, 0xDAF6,
-       0x909D, 0xDAF7,
-       0x90A1, 0xDAFA,
-       0x90A2, 0xD0CF,
-       0x90A3, 0xC4C7,
-       0x90A6, 0xB0EE,
-       0x90AA, 0xD0B0,
-       0x90AC, 0xDAF9,
-       0x90AE, 0xD3CA,
-       0x90AF, 0xBAAA,
-       0x90B0, 0xDBA2,
-       0x90B1, 0xC7F1,
-       0x90B3, 0xDAFC,
-       0x90B4, 0xDAFB,
-       0x90B5, 0xC9DB,
-       0x90B6, 0xDAFD,
-       0x90B8, 0xDBA1,
-       0x90B9, 0xD7DE,
-       0x90BA, 0xDAFE,
-       0x90BB, 0xC1DA,
-       0x90BE, 0xDBA5,
-       0x90C1, 0xD3F4,
-       0x90C4, 0xDBA7,
-       0x90C5, 0xDBA4,
-       0x90C7, 0xDBA8,
-       0x90CA, 0xBDBC,
-       0x90CE, 0xC0C9,
-       0x90CF, 0xDBA3,
-       0x90D0, 0xDBA6,
-       0x90D1, 0xD6A3,
-       0x90D3, 0xDBA9,
-       0x90D7, 0xDBAD,
-       0x90DB, 0xDBAE,
-       0x90DC, 0xDBAC,
-       0x90DD, 0xBAC2,
-       0x90E1, 0xBFA4,
-       0x90E2, 0xDBAB,
-       0x90E6, 0xDBAA,
-       0x90E7, 0xD4C7,
-       0x90E8, 0xB2BF,
-       0x90EB, 0xDBAF,
-       0x90ED, 0xB9F9,
-       0x90EF, 0xDBB0,
-       0x90F4, 0xB3BB,
-       0x90F8, 0xB5A6,
-       0x90FD, 0xB6BC,
-       0x90FE, 0xDBB1,
-       0x9102, 0xB6F5,
-       0x9104, 0xDBB2,
-       0x9119, 0xB1C9,
-       0x911E, 0xDBB4,
-       0x9122, 0xDBB3,
-       0x9123, 0xDBB5,
-       0x912F, 0xDBB7,
-       0x9131, 0xDBB6,
-       0x9139, 0xDBB8,
-       0x9143, 0xDBB9,
-       0x9146, 0xDBBA,
-       0x9149, 0xD3CF,
-       0x914A, 0xF4FA,
-       0x914B, 0xC7F5,
-       0x914C, 0xD7C3,
-       0x914D, 0xC5E4,
-       0x914E, 0xF4FC,
-       0x914F, 0xF4FD,
-       0x9150, 0xF4FB,
-       0x9152, 0xBEC6,
-       0x9157, 0xD0EF,
-       0x915A, 0xB7D3,
-       0x915D, 0xD4CD,
-       0x915E, 0xCCAA,
-       0x9161, 0xF5A2,
-       0x9162, 0xF5A1,
-       0x9163, 0xBAA8,
-       0x9164, 0xF4FE,
-       0x9165, 0xCBD6,
-       0x9169, 0xF5A4,
-       0x916A, 0xC0D2,
-       0x916C, 0xB3EA,
-       0x916E, 0xCDAA,
-       0x916F, 0xF5A5,
-       0x9170, 0xF5A3,
-       0x9171, 0xBDB4,
-       0x9172, 0xF5A8,
-       0x9174, 0xF5A9,
-       0x9175, 0xBDCD,
-       0x9176, 0xC3B8,
-       0x9177, 0xBFE1,
-       0x9178, 0xCBE1,
-       0x9179, 0xF5AA,
-       0x917D, 0xF5A6,
-       0x917E, 0xF5A7,
-       0x917F, 0xC4F0,
-       0x9185, 0xF5AC,
-       0x9187, 0xB4BC,
-       0x9189, 0xD7ED,
-       0x918B, 0xB4D7,
-       0x918C, 0xF5AB,
-       0x918D, 0xF5AE,
-       0x9190, 0xF5AD,
-       0x9191, 0xF5AF,
-       0x9192, 0xD0D1,
-       0x919A, 0xC3D1,
-       0x919B, 0xC8A9,
-       0x91A2, 0xF5B0,
-       0x91A3, 0xF5B1,
-       0x91AA, 0xF5B2,
-       0x91AD, 0xF5B3,
-       0x91AE, 0xF5B4,
-       0x91AF, 0xF5B5,
-       0x91B4, 0xF5B7,
-       0x91B5, 0xF5B6,
-       0x91BA, 0xF5B8,
-       0x91C7, 0xB2C9,
-       0x91C9, 0xD3D4,
-       0x91CA, 0xCACD,
-       0x91CC, 0xC0EF,
-       0x91CD, 0xD6D8,
-       0x91CE, 0xD2B0,
-       0x91CF, 0xC1BF,
-       0x91D1, 0xBDF0,
-       0x91DC, 0xB8AA,
-       0x9274, 0xBCF8,
-       0x928E, 0xF6C6,
-       0x92AE, 0xF6C7,
-       0x92C8, 0xF6C8,
-       0x933E, 0xF6C9,
-       0x936A, 0xF6CA,
-       0x938F, 0xF6CC,
-       0x93CA, 0xF6CB,
-       0x93D6, 0xF7E9,
-       0x943E, 0xF6CD,
-       0x946B, 0xF6CE,
-       0x9485, 0xEEC4,
-       0x9486, 0xEEC5,
-       0x9487, 0xEEC6,
-       0x9488, 0xD5EB,
-       0x9489, 0xB6A4,
-       0x948A, 0xEEC8,
-       0x948B, 0xEEC7,
-       0x948C, 0xEEC9,
-       0x948D, 0xEECA,
-       0x948E, 0xC7A5,
-       0x948F, 0xEECB,
-       0x9490, 0xEECC,
-       0x9492, 0xB7B0,
-       0x9493, 0xB5F6,
-       0x9494, 0xEECD,
-       0x9495, 0xEECF,
-       0x9497, 0xEECE,
-       0x9499, 0xB8C6,
-       0x949A, 0xEED0,
-       0x949B, 0xEED1,
-       0x949C, 0xEED2,
-       0x949D, 0xB6DB,
-       0x949E, 0xB3AE,
-       0x949F, 0xD6D3,
-       0x94A0, 0xC4C6,
-       0x94A1, 0xB1B5,
-       0x94A2, 0xB8D6,
-       0x94A3, 0xEED3,
-       0x94A4, 0xEED4,
-       0x94A5, 0xD4BF,
-       0x94A6, 0xC7D5,
-       0x94A7, 0xBEFB,
-       0x94A8, 0xCED9,
-       0x94A9, 0xB9B3,
-       0x94AA, 0xEED6,
-       0x94AB, 0xEED5,
-       0x94AC, 0xEED8,
-       0x94AD, 0xEED7,
-       0x94AE, 0xC5A5,
-       0x94AF, 0xEED9,
-       0x94B0, 0xEEDA,
-       0x94B1, 0xC7AE,
-       0x94B2, 0xEEDB,
-       0x94B3, 0xC7AF,
-       0x94B4, 0xEEDC,
-       0x94B5, 0xB2A7,
-       0x94B6, 0xEEDD,
-       0x94B7, 0xEEDE,
-       0x94B8, 0xEEDF,
-       0x94B9, 0xEEE0,
-       0x94BA, 0xEEE1,
-       0x94BB, 0xD7EA,
-       0x94BC, 0xEEE2,
-       0x94BD, 0xEEE3,
-       0x94BE, 0xBCD8,
-       0x94BF, 0xEEE4,
-       0x94C0, 0xD3CB,
-       0x94C1, 0xCCFA,
-       0x94C2, 0xB2AC,
-       0x94C3, 0xC1E5,
-       0x94C4, 0xEEE5,
-       0x94C5, 0xC7A6,
-       0x94C6, 0xC3AD,
-       0x94C8, 0xEEE6,
-       0x94C9, 0xEEE7,
-       0x94CA, 0xEEE8,
-       0x94CB, 0xEEE9,
-       0x94CC, 0xEEEA,
-       0x94CD, 0xEEEB,
-       0x94CE, 0xEEEC,
-       0x94D0, 0xEEED,
-       0x94D1, 0xEEEE,
-       0x94D2, 0xEEEF,
-       0x94D5, 0xEEF0,
-       0x94D6, 0xEEF1,
-       0x94D7, 0xEEF2,
-       0x94D8, 0xEEF4,
-       0x94D9, 0xEEF3,
-       0x94DB, 0xEEF5,
-       0x94DC, 0xCDAD,
-       0x94DD, 0xC2C1,
-       0x94DE, 0xEEF6,
-       0x94DF, 0xEEF7,
-       0x94E0, 0xEEF8,
-       0x94E1, 0xD5A1,
-       0x94E2, 0xEEF9,
-       0x94E3, 0xCFB3,
-       0x94E4, 0xEEFA,
-       0x94E5, 0xEEFB,
-       0x94E7, 0xEEFC,
-       0x94E8, 0xEEFD,
-       0x94E9, 0xEFA1,
-       0x94EA, 0xEEFE,
-       0x94EB, 0xEFA2,
-       0x94EC, 0xB8F5,
-       0x94ED, 0xC3FA,
-       0x94EE, 0xEFA3,
-       0x94EF, 0xEFA4,
-       0x94F0, 0xBDC2,
-       0x94F1, 0xD2BF,
-       0x94F2, 0xB2F9,
-       0x94F3, 0xEFA5,
-       0x94F4, 0xEFA6,
-       0x94F5, 0xEFA7,
-       0x94F6, 0xD2F8,
-       0x94F7, 0xEFA8,
-       0x94F8, 0xD6FD,
-       0x94F9, 0xEFA9,
-       0x94FA, 0xC6CC,
-       0x94FC, 0xEFAA,
-       0x94FD, 0xEFAB,
-       0x94FE, 0xC1B4,
-       0x94FF, 0xEFAC,
-       0x9500, 0xCFFA,
-       0x9501, 0xCBF8,
-       0x9502, 0xEFAE,
-       0x9503, 0xEFAD,
-       0x9504, 0xB3FA,
-       0x9505, 0xB9F8,
-       0x9506, 0xEFAF,
-       0x9507, 0xEFB0,
-       0x9508, 0xD0E2,
-       0x9509, 0xEFB1,
-       0x950A, 0xEFB2,
-       0x950B, 0xB7E6,
-       0x950C, 0xD0BF,
-       0x950D, 0xEFB3,
-       0x950E, 0xEFB4,
-       0x950F, 0xEFB5,
-       0x9510, 0xC8F1,
-       0x9511, 0xCCE0,
-       0x9512, 0xEFB6,
-       0x9513, 0xEFB7,
-       0x9514, 0xEFB8,
-       0x9515, 0xEFB9,
-       0x9516, 0xEFBA,
-       0x9517, 0xD5E0,
-       0x9518, 0xEFBB,
-       0x9519, 0xB4ED,
-       0x951A, 0xC3AA,
-       0x951B, 0xEFBC,
-       0x951D, 0xEFBD,
-       0x951E, 0xEFBE,
-       0x951F, 0xEFBF,
-       0x9521, 0xCEFD,
-       0x9522, 0xEFC0,
-       0x9523, 0xC2E0,
-       0x9524, 0xB4B8,
-       0x9525, 0xD7B6,
-       0x9526, 0xBDF5,
-       0x9528, 0xCFC7,
-       0x9529, 0xEFC3,
-       0x952A, 0xEFC1,
-       0x952B, 0xEFC2,
-       0x952C, 0xEFC4,
-       0x952D, 0xB6A7,
-       0x952E, 0xBCFC,
-       0x952F, 0xBEE2,
-       0x9530, 0xC3CC,
-       0x9531, 0xEFC5,
-       0x9532, 0xEFC6,
-       0x9534, 0xEFC7,
-       0x9535, 0xEFCF,
-       0x9536, 0xEFC8,
-       0x9537, 0xEFC9,
-       0x9538, 0xEFCA,
-       0x9539, 0xC7C2,
-       0x953A, 0xEFF1,
-       0x953B, 0xB6CD,
-       0x953C, 0xEFCB,
-       0x953E, 0xEFCC,
-       0x953F, 0xEFCD,
-       0x9540, 0xB6C6,
-       0x9541, 0xC3BE,
-       0x9542, 0xEFCE,
-       0x9544, 0xEFD0,
-       0x9545, 0xEFD1,
-       0x9546, 0xEFD2,
-       0x9547, 0xD5F2,
-       0x9549, 0xEFD3,
-       0x954A, 0xC4F7,
-       0x954C, 0xEFD4,
-       0x954D, 0xC4F8,
-       0x954E, 0xEFD5,
-       0x954F, 0xEFD6,
-       0x9550, 0xB8E4,
-       0x9551, 0xB0F7,
-       0x9552, 0xEFD7,
-       0x9553, 0xEFD8,
-       0x9554, 0xEFD9,
-       0x9556, 0xEFDA,
-       0x9557, 0xEFDB,
-       0x9558, 0xEFDC,
-       0x9559, 0xEFDD,
-       0x955B, 0xEFDE,
-       0x955C, 0xBEB5,
-       0x955D, 0xEFE1,
-       0x955E, 0xEFDF,
-       0x955F, 0xEFE0,
-       0x9561, 0xEFE2,
-       0x9562, 0xEFE3,
-       0x9563, 0xC1CD,
-       0x9564, 0xEFE4,
-       0x9565, 0xEFE5,
-       0x9566, 0xEFE6,
-       0x9567, 0xEFE7,
-       0x9568, 0xEFE8,
-       0x9569, 0xEFE9,
-       0x956A, 0xEFEA,
-       0x956B, 0xEFEB,
-       0x956C, 0xEFEC,
-       0x956D, 0xC0D8,
-       0x956F, 0xEFED,
-       0x9570, 0xC1AD,
-       0x9571, 0xEFEE,
-       0x9572, 0xEFEF,
-       0x9573, 0xEFF0,
-       0x9576, 0xCFE2,
-       0x957F, 0xB3A4,
-       0x95E8, 0xC3C5,
-       0x95E9, 0xE3C5,
-       0x95EA, 0xC9C1,
-       0x95EB, 0xE3C6,
-       0x95ED, 0xB1D5,
-       0x95EE, 0xCECA,
-       0x95EF, 0xB4B3,
-       0x95F0, 0xC8F2,
-       0x95F1, 0xE3C7,
-       0x95F2, 0xCFD0,
-       0x95F3, 0xE3C8,
-       0x95F4, 0xBCE4,
-       0x95F5, 0xE3C9,
-       0x95F6, 0xE3CA,
-       0x95F7, 0xC3C6,
-       0x95F8, 0xD5A2,
-       0x95F9, 0xC4D6,
-       0x95FA, 0xB9EB,
-       0x95FB, 0xCEC5,
-       0x95FC, 0xE3CB,
-       0x95FD, 0xC3F6,
-       0x95FE, 0xE3CC,
-       0x9600, 0xB7A7,
-       0x9601, 0xB8F3,
-       0x9602, 0xBAD2,
-       0x9603, 0xE3CD,
-       0x9604, 0xE3CE,
-       0x9605, 0xD4C4,
-       0x9606, 0xE3CF,
-       0x9608, 0xE3D0,
-       0x9609, 0xD1CB,
-       0x960A, 0xE3D1,
-       0x960B, 0xE3D2,
-       0x960C, 0xE3D3,
-       0x960D, 0xE3D4,
-       0x960E, 0xD1D6,
-       0x960F, 0xE3D5,
-       0x9610, 0xB2FB,
-       0x9611, 0xC0BB,
-       0x9612, 0xE3D6,
-       0x9614, 0xC0AB,
-       0x9615, 0xE3D7,
-       0x9616, 0xE3D8,
-       0x9617, 0xE3D9,
-       0x9619, 0xE3DA,
-       0x961A, 0xE3DB,
-       0x961C, 0xB8B7,
-       0x961D, 0xDAE2,
-       0x961F, 0xB6D3,
-       0x9621, 0xDAE4,
-       0x9622, 0xDAE3,
-       0x962A, 0xDAE6,
-       0x962E, 0xC8EE,
-       0x9631, 0xDAE5,
-       0x9632, 0xB7C0,
-       0x9633, 0xD1F4,
-       0x9634, 0xD2F5,
-       0x9635, 0xD5F3,
-       0x9636, 0xBDD7,
-       0x963B, 0xD7E8,
-       0x963C, 0xDAE8,
-       0x963D, 0xDAE7,
-       0x963F, 0xB0A2,
-       0x9640, 0xCDD3,
-       0x9642, 0xDAE9,
-       0x9644, 0xB8BD,
-       0x9645, 0xBCCA,
-       0x9646, 0xC2BD,
-       0x9647, 0xC2A4,
-       0x9648, 0xB3C2,
-       0x9649, 0xDAEA,
-       0x964B, 0xC2AA,
-       0x964C, 0xC4B0,
-       0x964D, 0xBDB5,
-       0x9650, 0xCFDE,
-       0x9654, 0xDAEB,
-       0x9655, 0xC9C2,
-       0x965B, 0xB1DD,
-       0x965F, 0xDAEC,
-       0x9661, 0xB6B8,
-       0x9662, 0xD4BA,
-       0x9664, 0xB3FD,
-       0x9667, 0xDAED,
-       0x9668, 0xD4C9,
-       0x9669, 0xCFD5,
-       0x966A, 0xC5E3,
-       0x966C, 0xDAEE,
-       0x9672, 0xDAEF,
-       0x9674, 0xDAF0,
-       0x9675, 0xC1EA,
-       0x9676, 0xCCD5,
-       0x9677, 0xCFDD,
-       0x9685, 0xD3E7,
-       0x9686, 0xC2A1,
-       0x9688, 0xDAF1,
-       0x968B, 0xCBE5,
-       0x968D, 0xDAF2,
-       0x968F, 0xCBE6,
-       0x9690, 0xD2FE,
-       0x9694, 0xB8F4,
-       0x9697, 0xDAF3,
-       0x9698, 0xB0AF,
-       0x9699, 0xCFB6,
-       0x969C, 0xD5CF,
-       0x96A7, 0xCBED,
-       0x96B0, 0xDAF4,
-       0x96B3, 0xE3C4,
-       0x96B6, 0xC1A5,
-       0x96B9, 0xF6BF,
-       0x96BC, 0xF6C0,
-       0x96BD, 0xF6C1,
-       0x96BE, 0xC4D1,
-       0x96C0, 0xC8B8,
-       0x96C1, 0xD1E3,
-       0x96C4, 0xD0DB,
-       0x96C5, 0xD1C5,
-       0x96C6, 0xBCAF,
-       0x96C7, 0xB9CD,
-       0x96C9, 0xEFF4,
-       0x96CC, 0xB4C6,
-       0x96CD, 0xD3BA,
-       0x96CE, 0xF6C2,
-       0x96CF, 0xB3FB,
-       0x96D2, 0xF6C3,
-       0x96D5, 0xB5F1,
-       0x96E0, 0xF6C5,
-       0x96E8, 0xD3EA,
-       0x96E9, 0xF6A7,
-       0x96EA, 0xD1A9,
-       0x96EF, 0xF6A9,
-       0x96F3, 0xF6A8,
-       0x96F6, 0xC1E3,
-       0x96F7, 0xC0D7,
-       0x96F9, 0xB1A2,
-       0x96FE, 0xCEED,
-       0x9700, 0xD0E8,
-       0x9701, 0xF6AB,
-       0x9704, 0xCFF6,
-       0x9706, 0xF6AA,
-       0x9707, 0xD5F0,
-       0x9708, 0xF6AC,
-       0x9709, 0xC3B9,
-       0x970D, 0xBBF4,
-       0x970E, 0xF6AE,
-       0x970F, 0xF6AD,
-       0x9713, 0xC4DE,
-       0x9716, 0xC1D8,
-       0x971C, 0xCBAA,
-       0x971E, 0xCFBC,
-       0x972A, 0xF6AF,
-       0x972D, 0xF6B0,
-       0x9730, 0xF6B1,
-       0x9732, 0xC2B6,
-       0x9738, 0xB0D4,
-       0x9739, 0xC5F9,
-       0x973E, 0xF6B2,
-       0x9752, 0xC7E0,
-       0x9753, 0xF6A6,
-       0x9756, 0xBEB8,
-       0x9759, 0xBEB2,
-       0x975B, 0xB5E5,
-       0x975E, 0xB7C7,
-       0x9760, 0xBFBF,
-       0x9761, 0xC3D2,
-       0x9762, 0xC3E6,
-       0x9765, 0xD8CC,
-       0x9769, 0xB8EF,
-       0x9773, 0xBDF9,
-       0x9774, 0xD1A5,
-       0x9776, 0xB0D0,
-       0x977C, 0xF7B0,
-       0x9785, 0xF7B1,
-       0x978B, 0xD0AC,
-       0x978D, 0xB0B0,
-       0x9791, 0xF7B2,
-       0x9792, 0xF7B3,
-       0x9794, 0xF7B4,
-       0x9798, 0xC7CA,
-       0x97A0, 0xBECF,
-       0x97A3, 0xF7B7,
-       0x97AB, 0xF7B6,
-       0x97AD, 0xB1DE,
-       0x97AF, 0xF7B5,
-       0x97B2, 0xF7B8,
-       0x97B4, 0xF7B9,
-       0x97E6, 0xCEA4,
-       0x97E7, 0xC8CD,
-       0x97E9, 0xBAAB,
-       0x97EA, 0xE8B8,
-       0x97EB, 0xE8B9,
-       0x97EC, 0xE8BA,
-       0x97ED, 0xBEC2,
-       0x97F3, 0xD2F4,
-       0x97F5, 0xD4CF,
-       0x97F6, 0xC9D8,
-       0x9875, 0xD2B3,
-       0x9876, 0xB6A5,
-       0x9877, 0xC7EA,
-       0x9878, 0xF1FC,
-       0x9879, 0xCFEE,
-       0x987A, 0xCBB3,
-       0x987B, 0xD0EB,
-       0x987C, 0xE7EF,
-       0x987D, 0xCDE7,
-       0x987E, 0xB9CB,
-       0x987F, 0xB6D9,
-       0x9880, 0xF1FD,
-       0x9881, 0xB0E4,
-       0x9882, 0xCBCC,
-       0x9883, 0xF1FE,
-       0x9884, 0xD4A4,
-       0x9885, 0xC2AD,
-       0x9886, 0xC1EC,
-       0x9887, 0xC6C4,
-       0x9888, 0xBEB1,
-       0x9889, 0xF2A1,
-       0x988A, 0xBCD5,
-       0x988C, 0xF2A2,
-       0x988D, 0xF2A3,
-       0x988F, 0xF2A4,
-       0x9890, 0xD2C3,
-       0x9891, 0xC6B5,
-       0x9893, 0xCDC7,
-       0x9894, 0xF2A5,
-       0x9896, 0xD3B1,
-       0x9897, 0xBFC5,
-       0x9898, 0xCCE2,
-       0x989A, 0xF2A6,
-       0x989B, 0xF2A7,
-       0x989C, 0xD1D5,
-       0x989D, 0xB6EE,
-       0x989E, 0xF2A8,
-       0x989F, 0xF2A9,
-       0x98A0, 0xB5DF,
-       0x98A1, 0xF2AA,
-       0x98A2, 0xF2AB,
-       0x98A4, 0xB2FC,
-       0x98A5, 0xF2AC,
-       0x98A6, 0xF2AD,
-       0x98A7, 0xC8A7,
-       0x98CE, 0xB7E7,
-       0x98D1, 0xECA9,
-       0x98D2, 0xECAA,
-       0x98D3, 0xECAB,
-       0x98D5, 0xECAC,
-       0x98D8, 0xC6AE,
-       0x98D9, 0xECAD,
-       0x98DA, 0xECAE,
-       0x98DE, 0xB7C9,
-       0x98DF, 0xCAB3,
-       0x98E7, 0xE2B8,
-       0x98E8, 0xF7CF,
-       0x990D, 0xF7D0,
-       0x9910, 0xB2CD,
-       0x992E, 0xF7D1,
-       0x9954, 0xF7D3,
-       0x9955, 0xF7D2,
-       0x9963, 0xE2BB,
-       0x9965, 0xBCA2,
-       0x9967, 0xE2BC,
-       0x9968, 0xE2BD,
-       0x9969, 0xE2BE,
-       0x996A, 0xE2BF,
-       0x996B, 0xE2C0,
-       0x996C, 0xE2C1,
-       0x996D, 0xB7B9,
-       0x996E, 0xD2FB,
-       0x996F, 0xBDA4,
-       0x9970, 0xCACE,
-       0x9971, 0xB1A5,
-       0x9972, 0xCBC7,
-       0x9974, 0xE2C2,
-       0x9975, 0xB6FC,
-       0x9976, 0xC8C4,
-       0x9977, 0xE2C3,
-       0x997A, 0xBDC8,
-       0x997C, 0xB1FD,
-       0x997D, 0xE2C4,
-       0x997F, 0xB6F6,
-       0x9980, 0xE2C5,
-       0x9981, 0xC4D9,
-       0x9984, 0xE2C6,
-       0x9985, 0xCFDA,
-       0x9986, 0xB9DD,
-       0x9987, 0xE2C7,
-       0x9988, 0xC0A1,
-       0x998A, 0xE2C8,
-       0x998B, 0xB2F6,
-       0x998D, 0xE2C9,
-       0x998F, 0xC1F3,
-       0x9990, 0xE2CA,
-       0x9991, 0xE2CB,
-       0x9992, 0xC2F8,
-       0x9993, 0xE2CC,
-       0x9994, 0xE2CD,
-       0x9995, 0xE2CE,
-       0x9996, 0xCAD7,
-       0x9997, 0xD8B8,
-       0x9998, 0xD9E5,
-       0x9999, 0xCFE3,
-       0x99A5, 0xF0A5,
-       0x99A8, 0xDCB0,
-       0x9A6C, 0xC2ED,
-       0x9A6D, 0xD4A6,
-       0x9A6E, 0xCDD4,
-       0x9A6F, 0xD1B1,
-       0x9A70, 0xB3DB,
-       0x9A71, 0xC7FD,
-       0x9A73, 0xB2B5,
-       0x9A74, 0xC2BF,
-       0x9A75, 0xE6E0,
-       0x9A76, 0xCABB,
-       0x9A77, 0xE6E1,
-       0x9A78, 0xE6E2,
-       0x9A79, 0xBED4,
-       0x9A7A, 0xE6E3,
-       0x9A7B, 0xD7A4,
-       0x9A7C, 0xCDD5,
-       0x9A7D, 0xE6E5,
-       0x9A7E, 0xBCDD,
-       0x9A7F, 0xE6E4,
-       0x9A80, 0xE6E6,
-       0x9A81, 0xE6E7,
-       0x9A82, 0xC2EE,
-       0x9A84, 0xBDBE,
-       0x9A85, 0xE6E8,
-       0x9A86, 0xC2E6,
-       0x9A87, 0xBAA7,
-       0x9A88, 0xE6E9,
-       0x9A8A, 0xE6EA,
-       0x9A8B, 0xB3D2,
-       0x9A8C, 0xD1E9,
-       0x9A8F, 0xBFA5,
-       0x9A90, 0xE6EB,
-       0x9A91, 0xC6EF,
-       0x9A92, 0xE6EC,
-       0x9A93, 0xE6ED,
-       0x9A96, 0xE6EE,
-       0x9A97, 0xC6AD,
-       0x9A98, 0xE6EF,
-       0x9A9A, 0xC9A7,
-       0x9A9B, 0xE6F0,
-       0x9A9C, 0xE6F1,
-       0x9A9D, 0xE6F2,
-       0x9A9E, 0xE5B9,
-       0x9A9F, 0xE6F3,
-       0x9AA0, 0xE6F4,
-       0x9AA1, 0xC2E2,
-       0x9AA2, 0xE6F5,
-       0x9AA3, 0xE6F6,
-       0x9AA4, 0xD6E8,
-       0x9AA5, 0xE6F7,
-       0x9AA7, 0xE6F8,
-       0x9AA8, 0xB9C7,
-       0x9AB0, 0xF7BB,
-       0x9AB1, 0xF7BA,
-       0x9AB6, 0xF7BE,
-       0x9AB7, 0xF7BC,
-       0x9AB8, 0xBAA1,
-       0x9ABA, 0xF7BF,
-       0x9ABC, 0xF7C0,
-       0x9AC0, 0xF7C2,
-       0x9AC1, 0xF7C1,
-       0x9AC2, 0xF7C4,
-       0x9AC5, 0xF7C3,
-       0x9ACB, 0xF7C5,
-       0x9ACC, 0xF7C6,
-       0x9AD1, 0xF7C7,
-       0x9AD3, 0xCBE8,
-       0x9AD8, 0xB8DF,
-       0x9ADF, 0xF7D4,
-       0x9AE1, 0xF7D5,
-       0x9AE6, 0xF7D6,
-       0x9AEB, 0xF7D8,
-       0x9AED, 0xF7DA,
-       0x9AEF, 0xF7D7,
-       0x9AF9, 0xF7DB,
-       0x9AFB, 0xF7D9,
-       0x9B03, 0xD7D7,
-       0x9B08, 0xF7DC,
-       0x9B0F, 0xF7DD,
-       0x9B13, 0xF7DE,
-       0x9B1F, 0xF7DF,
-       0x9B23, 0xF7E0,
-       0x9B2F, 0xDBCB,
-       0x9B32, 0xD8AA,
-       0x9B3B, 0xE5F7,
-       0x9B3C, 0xB9ED,
-       0x9B41, 0xBFFD,
-       0x9B42, 0xBBEA,
-       0x9B43, 0xF7C9,
-       0x9B44, 0xC6C7,
-       0x9B45, 0xF7C8,
-       0x9B47, 0xF7CA,
-       0x9B48, 0xF7CC,
-       0x9B49, 0xF7CB,
-       0x9B4D, 0xF7CD,
-       0x9B4F, 0xCEBA,
-       0x9B51, 0xF7CE,
-       0x9B54, 0xC4A7,
-       0x9C7C, 0xD3E3,
-       0x9C7F, 0xF6CF,
-       0x9C81, 0xC2B3,
-       0x9C82, 0xF6D0,
-       0x9C85, 0xF6D1,
-       0x9C86, 0xF6D2,
-       0x9C87, 0xF6D3,
-       0x9C88, 0xF6D4,
-       0x9C8B, 0xF6D6,
-       0x9C8D, 0xB1AB,
-       0x9C8E, 0xF6D7,
-       0x9C90, 0xF6D8,
-       0x9C91, 0xF6D9,
-       0x9C92, 0xF6DA,
-       0x9C94, 0xF6DB,
-       0x9C95, 0xF6DC,
-       0x9C9A, 0xF6DD,
-       0x9C9B, 0xF6DE,
-       0x9C9C, 0xCFCA,
-       0x9C9E, 0xF6DF,
-       0x9C9F, 0xF6E0,
-       0x9CA0, 0xF6E1,
-       0x9CA1, 0xF6E2,
-       0x9CA2, 0xF6E3,
-       0x9CA3, 0xF6E4,
-       0x9CA4, 0xC0F0,
-       0x9CA5, 0xF6E5,
-       0x9CA6, 0xF6E6,
-       0x9CA7, 0xF6E7,
-       0x9CA8, 0xF6E8,
-       0x9CA9, 0xF6E9,
-       0x9CAB, 0xF6EA,
-       0x9CAD, 0xF6EB,
-       0x9CAE, 0xF6EC,
-       0x9CB0, 0xF6ED,
-       0x9CB1, 0xF6EE,
-       0x9CB2, 0xF6EF,
-       0x9CB3, 0xF6F0,
-       0x9CB4, 0xF6F1,
-       0x9CB5, 0xF6F2,
-       0x9CB6, 0xF6F3,
-       0x9CB7, 0xF6F4,
-       0x9CB8, 0xBEA8,
-       0x9CBA, 0xF6F5,
-       0x9CBB, 0xF6F6,
-       0x9CBC, 0xF6F7,
-       0x9CBD, 0xF6F8,
-       0x9CC3, 0xC8FA,
-       0x9CC4, 0xF6F9,
-       0x9CC5, 0xF6FA,
-       0x9CC6, 0xF6FB,
-       0x9CC7, 0xF6FC,
-       0x9CCA, 0xF6FD,
-       0x9CCB, 0xF6FE,
-       0x9CCC, 0xF7A1,
-       0x9CCD, 0xF7A2,
-       0x9CCE, 0xF7A3,
-       0x9CCF, 0xF7A4,
-       0x9CD0, 0xF7A5,
-       0x9CD3, 0xF7A6,
-       0x9CD4, 0xF7A7,
-       0x9CD5, 0xF7A8,
-       0x9CD6, 0xB1EE,
-       0x9CD7, 0xF7A9,
-       0x9CD8, 0xF7AA,
-       0x9CD9, 0xF7AB,
-       0x9CDC, 0xF7AC,
-       0x9CDD, 0xF7AD,
-       0x9CDE, 0xC1DB,
-       0x9CDF, 0xF7AE,
-       0x9CE2, 0xF7AF,
-       0x9E1F, 0xC4F1,
-       0x9E20, 0xF0AF,
-       0x9E21, 0xBCA6,
-       0x9E22, 0xF0B0,
-       0x9E23, 0xC3F9,
-       0x9E25, 0xC5B8,
-       0x9E26, 0xD1BB,
-       0x9E28, 0xF0B1,
-       0x9E29, 0xF0B2,
-       0x9E2A, 0xF0B3,
-       0x9E2B, 0xF0B4,
-       0x9E2C, 0xF0B5,
-       0x9E2D, 0xD1BC,
-       0x9E2F, 0xD1EC,
-       0x9E31, 0xF0B7,
-       0x9E32, 0xF0B6,
-       0x9E33, 0xD4A7,
-       0x9E35, 0xCDD2,
-       0x9E36, 0xF0B8,
-       0x9E37, 0xF0BA,
-       0x9E38, 0xF0B9,
-       0x9E39, 0xF0BB,
-       0x9E3A, 0xF0BC,
-       0x9E3D, 0xB8EB,
-       0x9E3E, 0xF0BD,
-       0x9E3F, 0xBAE8,
-       0x9E41, 0xF0BE,
-       0x9E42, 0xF0BF,
-       0x9E43, 0xBEE9,
-       0x9E44, 0xF0C0,
-       0x9E45, 0xB6EC,
-       0x9E46, 0xF0C1,
-       0x9E47, 0xF0C2,
-       0x9E48, 0xF0C3,
-       0x9E49, 0xF0C4,
-       0x9E4A, 0xC8B5,
-       0x9E4B, 0xF0C5,
-       0x9E4C, 0xF0C6,
-       0x9E4E, 0xF0C7,
-       0x9E4F, 0xC5F4,
-       0x9E51, 0xF0C8,
-       0x9E55, 0xF0C9,
-       0x9E57, 0xF0CA,
-       0x9E58, 0xF7BD,
-       0x9E5A, 0xF0CB,
-       0x9E5B, 0xF0CC,
-       0x9E5C, 0xF0CD,
-       0x9E5E, 0xF0CE,
-       0x9E63, 0xF0CF,
-       0x9E64, 0xBAD7,
-       0x9E66, 0xF0D0,
-       0x9E67, 0xF0D1,
-       0x9E68, 0xF0D2,
-       0x9E69, 0xF0D3,
-       0x9E6A, 0xF0D4,
-       0x9E6B, 0xF0D5,
-       0x9E6C, 0xF0D6,
-       0x9E6D, 0xF0D8,
-       0x9E70, 0xD3A5,
-       0x9E71, 0xF0D7,
-       0x9E73, 0xF0D9,
-       0x9E7E, 0xF5BA,
-       0x9E7F, 0xC2B9,
-       0x9E82, 0xF7E4,
-       0x9E87, 0xF7E5,
-       0x9E88, 0xF7E6,
-       0x9E8B, 0xF7E7,
-       0x9E92, 0xF7E8,
-       0x9E93, 0xC2B4,
-       0x9E9D, 0xF7EA,
-       0x9E9F, 0xF7EB,
-       0x9EA6, 0xC2F3,
-       0x9EB4, 0xF4F0,
-       0x9EB8, 0xF4EF,
-       0x9EBB, 0xC2E9,
-       0x9EBD, 0xF7E1,
-       0x9EBE, 0xF7E2,
-       0x9EC4, 0xBBC6,
-       0x9EC9, 0xD9E4,
-       0x9ECD, 0xCAF2,
-       0x9ECE, 0xC0E8,
-       0x9ECF, 0xF0A4,
-       0x9ED1, 0xBADA,
-       0x9ED4, 0xC7AD,
-       0x9ED8, 0xC4AC,
-       0x9EDB, 0xF7EC,
-       0x9EDC, 0xF7ED,
-       0x9EDD, 0xF7EE,
-       0x9EDF, 0xF7F0,
-       0x9EE0, 0xF7EF,
-       0x9EE2, 0xF7F1,
-       0x9EE5, 0xF7F4,
-       0x9EE7, 0xF7F3,
-       0x9EE9, 0xF7F2,
-       0x9EEA, 0xF7F5,
-       0x9EEF, 0xF7F6,
-       0x9EF9, 0xEDE9,
-       0x9EFB, 0xEDEA,
-       0x9EFC, 0xEDEB,
-       0x9EFE, 0xF6BC,
-       0x9F0B, 0xF6BD,
-       0x9F0D, 0xF6BE,
-       0x9F0E, 0xB6A6,
-       0x9F10, 0xD8BE,
-       0x9F13, 0xB9C4,
-       0x9F17, 0xD8BB,
-       0x9F19, 0xDCB1,
-       0x9F20, 0xCAF3,
-       0x9F22, 0xF7F7,
-       0x9F2C, 0xF7F8,
-       0x9F2F, 0xF7F9,
-       0x9F37, 0xF7FB,
-       0x9F39, 0xF7FA,
-       0x9F3B, 0xB1C7,
-       0x9F3D, 0xF7FC,
-       0x9F3E, 0xF7FD,
-       0x9F44, 0xF7FE,
-       0x9F50, 0xC6EB,
-       0x9F51, 0xECB4,
-       0x9F7F, 0xB3DD,
-       0x9F80, 0xF6B3,
-       0x9F83, 0xF6B4,
-       0x9F84, 0xC1E4,
-       0x9F85, 0xF6B5,
-       0x9F86, 0xF6B6,
-       0x9F87, 0xF6B7,
-       0x9F88, 0xF6B8,
-       0x9F89, 0xF6B9,
-       0x9F8A, 0xF6BA,
-       0x9F8B, 0xC8A3,
-       0x9F8C, 0xF6BB,
-       0x9F99, 0xC1FA,
-       0x9F9A, 0xB9A8,
-       0x9F9B, 0xEDE8,
-       0x9F9F, 0xB9EA,
-       0x9FA0, 0xD9DF,
-       0xFF01, 0xA3A1,
-       0xFF02, 0xA3A2,
-       0xFF03, 0xA3A3,
-       0xFF04, 0xA1E7,
-       0xFF05, 0xA3A5,
-       0xFF06, 0xA3A6,
-       0xFF07, 0xA3A7,
-       0xFF08, 0xA3A8,
-       0xFF09, 0xA3A9,
-       0xFF0A, 0xA3AA,
-       0xFF0B, 0xA3AB,
-       0xFF0C, 0xA3AC,
-       0xFF0D, 0xA3AD,
-       0xFF0E, 0xA3AE,
-       0xFF0F, 0xA3AF,
-       0xFF10, 0xA3B0,
-       0xFF11, 0xA3B1,
-       0xFF12, 0xA3B2,
-       0xFF13, 0xA3B3,
-       0xFF14, 0xA3B4,
-       0xFF15, 0xA3B5,
-       0xFF16, 0xA3B6,
-       0xFF17, 0xA3B7,
-       0xFF18, 0xA3B8,
-       0xFF19, 0xA3B9,
-       0xFF1A, 0xA3BA,
-       0xFF1B, 0xA3BB,
-       0xFF1C, 0xA3BC,
-       0xFF1D, 0xA3BD,
-       0xFF1E, 0xA3BE,
-       0xFF1F, 0xA3BF,
-       0xFF20, 0xA3C0,
-       0xFF21, 0xA3C1,
-       0xFF22, 0xA3C2,
-       0xFF23, 0xA3C3,
-       0xFF24, 0xA3C4,
-       0xFF25, 0xA3C5,
-       0xFF26, 0xA3C6,
-       0xFF27, 0xA3C7,
-       0xFF28, 0xA3C8,
-       0xFF29, 0xA3C9,
-       0xFF2A, 0xA3CA,
-       0xFF2B, 0xA3CB,
-       0xFF2C, 0xA3CC,
-       0xFF2D, 0xA3CD,
-       0xFF2E, 0xA3CE,
-       0xFF2F, 0xA3CF,
-       0xFF30, 0xA3D0,
-       0xFF31, 0xA3D1,
-       0xFF32, 0xA3D2,
-       0xFF33, 0xA3D3,
-       0xFF34, 0xA3D4,
-       0xFF35, 0xA3D5,
-       0xFF36, 0xA3D6,
-       0xFF37, 0xA3D7,
-       0xFF38, 0xA3D8,
-       0xFF39, 0xA3D9,
-       0xFF3A, 0xA3DA,
-       0xFF3B, 0xA3DB,
-       0xFF3C, 0xA3DC,
-       0xFF3D, 0xA3DD,
-       0xFF3E, 0xA3DE,
-       0xFF3F, 0xA3DF,
-       0xFF40, 0xA3E0,
-       0xFF41, 0xA3E1,
-       0xFF42, 0xA3E2,
-       0xFF43, 0xA3E3,
-       0xFF44, 0xA3E4,
-       0xFF45, 0xA3E5,
-       0xFF46, 0xA3E6,
-       0xFF47, 0xA3E7,
-       0xFF48, 0xA3E8,
-       0xFF49, 0xA3E9,
-       0xFF4A, 0xA3EA,
-       0xFF4B, 0xA3EB,
-       0xFF4C, 0xA3EC,
-       0xFF4D, 0xA3ED,
-       0xFF4E, 0xA3EE,
-       0xFF4F, 0xA3EF,
-       0xFF50, 0xA3F0,
-       0xFF51, 0xA3F1,
-       0xFF52, 0xA3F2,
-       0xFF53, 0xA3F3,
-       0xFF54, 0xA3F4,
-       0xFF55, 0xA3F5,
-       0xFF56, 0xA3F6,
-       0xFF57, 0xA3F7,
-       0xFF58, 0xA3F8,
-       0xFF59, 0xA3F9,
-       0xFF5A, 0xA3FA,
-       0xFF5B, 0xA3FB,
-       0xFF5C, 0xA3FC,
-       0xFF5D, 0xA3FD,
-       0xFF5E, 0xA1AB,
-       0xFFE0, 0xA1E9,
-       0xFFE1, 0xA1EA,
-       0xFFE3, 0xA3FE,
-       0xFFE5, 0xA3A4
-};
+#ifndef GB2312_H
+#define GB2312_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+INTERNAL int gb2312_wctomb_zint(unsigned int* r, unsigned int wc);
+INTERNAL int gb2312_utf8tomb(struct zint_symbol *symbol, const unsigned char source[], size_t* p_length, unsigned int* gbdata);
+INTERNAL int gb2312_utf8tosb(int eci, const unsigned char source[], size_t* p_length, unsigned int* gbdata, int full_multibyte);
+INTERNAL void gb2312_cpy(const unsigned char source[], size_t* p_length, unsigned int* gbdata, int full_multibyte);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* GB2312_H */
diff --git a/backend/general_field.c b/backend/general_field.c
new file mode 100644 (file)
index 0000000..13c5ed0
--- /dev/null
@@ -0,0 +1,187 @@
+/* general_field.c - Handles general field compaction (GS1 DataBar and composites) */
+
+/*
+    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 : */
+
+#include <string.h>
+#include "common.h"
+#include "general_field.h"
+
+static char alphanum_puncs[] = "*,-./";
+static char isoiec_puncs[] = "!\"%&'()*+,-./:;<=>?_ ";
+
+/* Returns type of char at `i`. FNC1 counted as NUMERIC. Returns 0 if invalid char */
+static int general_field_type(char* general_field, int i) {
+    if (general_field[i] == '[' || (general_field[i] >= '0' && general_field[i] <= '9')) {
+        return NUMERIC;
+    }
+    if ((general_field[i] >= 'A' && general_field[i] <= 'Z') || strchr(alphanum_puncs, general_field[i])) {
+        return ALPHA;
+    }
+    if ((general_field[i] >= 'a' && general_field[i] <= 'z') || strchr(isoiec_puncs, general_field[i])) {
+        return ISOIEC;
+    }
+    return 0;
+}
+
+/* Returns true if next (including `i`) `num` chars of type `type`, or if given (non-zero), `type2` */
+static int general_field_next(char* general_field, int i, int general_field_len, int num, int type, int type2) {
+    if (i + num > general_field_len) {
+        return 0;
+    }
+    for (; i < general_field_len && num; i++, num--) {
+        int type_i = general_field_type(general_field, i);
+        if ((type_i != type && !type2) || (type_i != type && type_i != type2)) {
+            return 0;
+        }
+    }
+    return num == 0;
+}
+
+/* Returns true if next (including `i`) `num` up to `max_num` chars of type `type` and occur at end */
+static int general_field_next_terminate(char* general_field, int i, int general_field_len, int num, int max_num, int type) {
+    if (i + max_num < general_field_len) {
+        return 0;
+    }
+    for (; i < general_field_len; i++, num--) {
+        if (general_field_type(general_field, i) != type) {
+            return 0;
+        }
+    }
+    return i == general_field_len && num <= 0;
+}
+
+/* Returns true if none of the next (including `i`) `num` chars (or end occurs) of type `type` */
+static int general_field_next_none(char* general_field, int i, int general_field_len, int num, int type) {
+    for (; i < general_field_len && num; i++, num--) {
+        if (general_field_type(general_field, i) == type) {
+            return 0;
+        }
+    }
+    return num == 0 || i == general_field_len;
+}
+
+/* Attempts to apply encoding rules from sections 7.2.5.5.1 to 7.2.5.5.3
+ * of ISO/IEC 24724:2011 (same as sections 5.4.1 to 5.4.3 of ISO/IEC 24723:2010) */
+INTERNAL int general_field_encode(char* general_field, int* p_mode, int* p_last_digit, char binary_string[]) {
+    int i, d1, d2;
+    int mode = *p_mode;
+    int last_digit = 0; /* Set to odd remaining digit at end if any */
+    int general_field_len = strlen(general_field);
+
+    for (i = 0; i < general_field_len; ) {
+        int type = general_field_type(general_field, i);
+        if (!type) {
+            return 0;
+        }
+        switch (mode) {
+            case NUMERIC:
+                if (i < general_field_len - 1) { /* If at least 2 characters remain */
+                    if (type != NUMERIC || general_field_type(general_field, i + 1) != NUMERIC) { /* 7.2.5.5.1/5.4.1 a) */
+                        strcat(binary_string, "0000"); /* Alphanumeric latch */
+                        mode = ALPHA;
+                    } else {
+                        d1 = general_field[i] == '[' ? 10 : ctoi(general_field[i]);
+                        d2 = general_field[i + 1] == '[' ? 10 : ctoi(general_field[i + 1]);
+                        bin_append((11 * d1) + d2 + 8, 7, binary_string);
+                        i += 2;
+                    }
+                } else { /* If 1 character remains */
+                    if (type != NUMERIC) { /* 7.2.5.5.1/5.4.1 b) */
+                        strcat(binary_string, "0000"); /* Alphanumeric latch */
+                        mode = ALPHA;
+                    } else {
+                        last_digit = general_field[i]; /* Ending with single digit. 7.2.5.5.1 c) and 5.4.1 c) dealt with separately outside this procedure */
+                        i++;
+                    }
+                }
+                break;
+            case ALPHA:
+                if (general_field[i] == '[') { /* 7.2.5.5.2/5.4.2 a) */
+                    strcat(binary_string, "01111");
+                    mode = NUMERIC;
+                    i++;
+                } else if (type == ISOIEC) { /* 7.2.5.5.2/5.4.2 b) */
+                    strcat(binary_string, "00100"); /* ISO/IEC 646 latch */
+                    mode = ISOIEC;
+                } else if (general_field_next(general_field, i, general_field_len, 6, NUMERIC, 0)) { /* 7.2.5.5.2/5.4.2 c) */
+                    strcat(binary_string, "000"); /* Numeric latch */
+                    mode = NUMERIC;
+                } else if (general_field_next_terminate(general_field, i, general_field_len, 4, 5 /*Can limit to 5 max due to above*/, NUMERIC)) { /* 7.2.5.5.2/5.4.2 d) */
+                    strcat(binary_string, "000"); /* Numeric latch */
+                    mode = NUMERIC;
+                } else if ((general_field[i] >= '0') && (general_field[i] <= '9')) {
+                    bin_append(general_field[i] - 43, 5, binary_string);
+                    i++;
+                } else if ((general_field[i] >= 'A') && (general_field[i] <= 'Z')) {
+                    bin_append(general_field[i] - 33, 6, binary_string);
+                    i++;
+                } else {
+                    bin_append(posn(alphanum_puncs, general_field[i]) + 58, 6, binary_string);
+                    i++;
+                }
+                break;
+            case ISOIEC:
+                if (general_field[i] == '[') { /* 7.2.5.5.3/5.4.3 a) */
+                    strcat(binary_string, "01111");
+                    mode = NUMERIC;
+                    i++;
+                } else {
+                    int next_10_not_isoiec = general_field_next_none(general_field, i, general_field_len, 10, ISOIEC);
+                    if (next_10_not_isoiec && general_field_next(general_field, i, general_field_len, 4, NUMERIC, 0)) { /* 7.2.5.5.3/5.4.3 b) */
+                        strcat(binary_string, "000"); /* Numeric latch */
+                        mode = NUMERIC;
+                    } else if (next_10_not_isoiec && general_field_next(general_field, i, general_field_len, 5, ALPHA, NUMERIC)) { /* 7.2.5.5.3/5.4.3 c) */
+                        /* Note this rule can produce longer bitstreams if most of the alphanumerics are numeric */
+                        strcat(binary_string, "00100"); /* Alphanumeric latch */
+                        mode = ALPHA;
+                    } else if ((general_field[i] >= '0') && (general_field[i] <= '9')) {
+                        bin_append(general_field[i] - 43, 5, binary_string);
+                        i++;
+                    } else if ((general_field[i] >= 'A') && (general_field[i] <= 'Z')) {
+                        bin_append(general_field[i] - 1, 7, binary_string);
+                        i++;
+                    } else if ((general_field[i] >= 'a') && (general_field[i] <= 'z')) {
+                        bin_append(general_field[i] - 7, 7, binary_string);
+                        i++;
+                    } else {
+                        bin_append(posn(isoiec_puncs, general_field[i]) + 232, 8, binary_string);
+                        i++;
+                    }
+                }
+                break;
+        }
+    }
+
+    *p_mode = mode;
+    *p_last_digit = last_digit;
+    return 1;
+}
diff --git a/backend/general_field.h b/backend/general_field.h
new file mode 100644 (file)
index 0000000..11db071
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+    libzint - the open source barcode library
+    Copyright (C) 2007-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 : */
+
+#ifndef __GENERAL_FIELD_H
+#define __GENERAL_FIELD_H
+
+#define NUMERIC         110
+#define ALPHA           97
+#define ISOIEC          105
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+    INTERNAL int general_field_encode(char* general_field, int* p_mode, int* p_last_digit, char binary_string[]);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __GENERAL_FIELD_H */
diff --git a/backend/gif.c b/backend/gif.c
new file mode 100644 (file)
index 0000000..c5b19ee
--- /dev/null
@@ -0,0 +1,584 @@
+/* gif.c - Handles output to gif 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 <string.h>
+#include "common.h"
+#include <math.h>
+#ifdef _MSC_VER
+#include <io.h>
+#include <fcntl.h>
+#include <malloc.h>
+#endif
+
+#define SSET    "0123456789ABCDEF"
+
+/* Index of transparent color, -1 for no transparent color
+ * This might be set into a variable if transparency is activated as an option
+ */
+#define TRANSPARENT_INDEX (-1)
+
+typedef struct s_statestruct {
+    unsigned char * pOut;
+    unsigned char *pIn;
+    unsigned int InLen;
+    unsigned int OutLength;
+    unsigned int OutPosCur;
+    unsigned int OutByteCountPos;
+    unsigned short ClearCode;
+    unsigned short FreeCode;
+    char fByteCountByteSet;
+    unsigned char OutBitsFree;
+    unsigned short NodeAxon[4096];
+    unsigned short NodeNext[4096];
+    unsigned char NodePix[4096];
+    unsigned char colourCode[10];
+    unsigned char colourPaletteIndex[10];
+    int colourCount;
+} statestruct;
+
+/* Transform a Pixel to a lzw colourmap index and move to next pixel.
+ * All colour values are listed in colourCode with corresponding palette index
+ */
+static unsigned char NextPaletteIndex(statestruct *pState)
+{
+    unsigned char pixelColour;
+    int colourIndex;
+    pixelColour = *(pState->pIn);
+    (pState->pIn)++;
+    (pState->InLen)--;
+    for (colourIndex = 0; colourIndex < pState->colourCount; colourIndex++) {
+        if (pixelColour == pState->colourCode[colourIndex])
+            return pState->colourPaletteIndex[colourIndex];
+
+    }
+    return 0; /* Not reached */
+}
+
+
+static char BufferNextByte(statestruct *pState) {
+    (pState->OutPosCur)++;
+    /* Check if this position is a byte count position
+     * fg_f_bytecountbyte_set indicates, if byte count position bytes should be
+     * inserted in general.
+     * If this is true, and the distance to the last byte count position is 256
+     * (e.g. 255 bytes in between), a byte count byte is inserted, and the value
+     * of the last one is set to 255.
+     * */
+    if (pState->fByteCountByteSet && (pState->OutByteCountPos + 256 == pState->OutPosCur)) {
+        (pState->pOut)[pState->OutByteCountPos] = 255;
+        pState->OutByteCountPos = pState->OutPosCur;
+        (pState->OutPosCur)++;
+    }
+    if (pState->OutPosCur >= pState->OutLength)
+        return 1;
+
+    (pState->pOut)[pState->OutPosCur] = 0x00;
+    return 0;
+}
+
+static char AddCodeToBuffer(statestruct *pState, unsigned short CodeIn, unsigned char CodeBits) {
+    /* Check, if we may fill up the current byte completely */
+    if (CodeBits >= pState->OutBitsFree) {
+        (pState->pOut)[pState->OutPosCur] |= (unsigned char)
+                (CodeIn << (8 - pState->OutBitsFree));
+        if (BufferNextByte(pState))
+            return -1;
+        CodeIn = (unsigned short) (CodeIn >> pState->OutBitsFree);
+        CodeBits -= pState->OutBitsFree;
+        pState->OutBitsFree = 8;
+        /* Write a full byte if there are at least 8 code bits left */
+        if (CodeBits >= pState->OutBitsFree) {
+            (pState->pOut)[pState->OutPosCur] = (unsigned char) CodeIn;
+            if (BufferNextByte(pState))
+                return -1;
+            CodeIn = (unsigned short) (CodeIn >> 8);
+            CodeBits -= 8;
+        }
+    }
+    /* The remaining bits of CodeIn fit in the current byte. */
+    if (CodeBits > 0) {
+        (pState->pOut)[pState->OutPosCur] |= (unsigned char)
+            (CodeIn << (8 - pState->OutBitsFree));
+        pState->OutBitsFree -= CodeBits;
+    }
+    return 0;
+}
+
+static void FlushStringTable(statestruct *pState) {
+    unsigned short Pos;
+    for (Pos = 0; Pos < pState->ClearCode; Pos++) {
+        (pState->NodeAxon)[Pos] = 0;
+    }
+}
+
+static unsigned short FindPixelOutlet(statestruct *pState, unsigned short HeadNode, unsigned char Byte) {
+    unsigned short Outlet;
+
+    Outlet = (pState->NodeAxon)[HeadNode];
+    while (Outlet) {
+        if ((pState->NodePix)[Outlet] == Byte)
+            return Outlet;
+        Outlet = (pState->NodeNext)[Outlet];
+    }
+    return 0;
+}
+
+static char NextCode(statestruct *pState, unsigned char * pPixelValueCur, unsigned char CodeBits) {
+    unsigned short UpNode;
+    unsigned short DownNode;
+    /* start with the root node for last pixel chain */
+    UpNode = *pPixelValueCur;
+    if ((pState->InLen) == 0)
+        return AddCodeToBuffer(pState, UpNode, CodeBits);
+
+    *pPixelValueCur = NextPaletteIndex(pState);
+    /* Follow the string table and the data stream to the end of the longest string that has a code */
+    while (0 != (DownNode = FindPixelOutlet(pState, UpNode, *pPixelValueCur))) {
+        UpNode = DownNode;
+        if ((pState->InLen) == 0)
+            return AddCodeToBuffer(pState, UpNode, CodeBits);
+
+        *pPixelValueCur = NextPaletteIndex(pState);
+    }
+    /* Submit 'UpNode' which is the code of the longest string */
+    if (AddCodeToBuffer(pState, UpNode, CodeBits))
+        return -1;
+    /* ... and extend the string by appending 'PixelValueCur' */
+    /* Create a successor node for 'PixelValueCur' whose code is 'freecode' */
+    (pState->NodePix)[pState->FreeCode] = *pPixelValueCur;
+    (pState->NodeAxon)[pState->FreeCode] = (pState->NodeNext)[pState->FreeCode] = 0;
+    /* ...and link it to the end of the chain emanating from fg_axon[UpNode]. */
+    DownNode = (pState->NodeAxon)[UpNode];
+    if (!DownNode) {
+        (pState->NodeAxon)[UpNode] = pState->FreeCode;
+    } else {
+        while ((pState->NodeNext)[DownNode]) {
+            DownNode = (pState->NodeNext)[DownNode];
+        }
+        (pState->NodeNext)[DownNode] = pState->FreeCode;
+    }
+    return 1;
+}
+
+static int gif_lzw(statestruct *pState, int paletteBitSize) {
+    unsigned char PixelValueCur;
+    unsigned char CodeBits;
+    unsigned short Pos;
+
+    // > Get first data byte
+    if (pState->InLen == 0)
+        return 0;
+    PixelValueCur = NextPaletteIndex(pState);
+    /* Number of bits per data item (=pixel)
+     * We need at least a value of 2, otherwise the cc and eoi code consumes
+     * the whole string table
+     */
+    if (paletteBitSize == 1)
+        paletteBitSize = 2;
+
+    /* initial size of compression codes */
+    CodeBits = paletteBitSize+1;
+    pState->ClearCode = (1 << paletteBitSize);
+    pState->FreeCode = pState->ClearCode+2;
+    pState->OutBitsFree = 8;
+    pState->OutPosCur = -1;
+    pState->fByteCountByteSet = 0;
+
+    if (BufferNextByte(pState))
+        return 0;
+
+    for (Pos = 0; Pos < pState->ClearCode; Pos++)
+        (pState->NodePix)[Pos] = (unsigned char) Pos;
+
+    FlushStringTable(pState);
+
+    /* Write what the GIF specification calls the "code size". */
+    (pState->pOut)[pState->OutPosCur] = paletteBitSize;
+    /* Reserve first bytecount byte */
+    if (BufferNextByte(pState))
+        return 0;
+    pState->OutByteCountPos = pState->OutPosCur;
+    if (BufferNextByte(pState))
+        return 0;
+    pState->fByteCountByteSet = 1;
+    /* Submit one 'ClearCode' as the first code */
+    if (AddCodeToBuffer(pState, pState->ClearCode, CodeBits))
+        return 0;
+
+    for (;;) {
+        char Res;
+        /* generate and save the next code, which may consist of multiple input pixels. */
+        Res = NextCode(pState, &PixelValueCur, CodeBits);
+        if (Res < 0)
+            return 0;
+        //* Check for end of data stream */
+        if (!Res) {
+            /* submit 'eoi' as the last item of the code stream */
+            if (AddCodeToBuffer(pState, (unsigned short) (pState->ClearCode + 1), CodeBits))
+                return 0;
+            pState->fByteCountByteSet = 0;
+            if (pState->OutBitsFree < 8) {
+                if (BufferNextByte(pState))
+                    return 0;
+            }
+            // > Update last bytecount byte;
+            if (pState->OutByteCountPos < pState->OutPosCur) {
+                (pState->pOut)[pState->OutByteCountPos] = (unsigned char) (pState->OutPosCur - pState->OutByteCountPos - 1);
+            }
+            pState->OutPosCur++;
+            return pState->OutPosCur;
+        }
+        /* Check for currently last code */
+        if (pState->FreeCode == (1U << CodeBits))
+            CodeBits++;
+        pState->FreeCode++;
+        /* Check for full stringtable */
+        if (pState->FreeCode == 0xfff) {
+            FlushStringTable(pState);
+            if (AddCodeToBuffer(pState, pState->ClearCode, CodeBits))
+                return 0;
+
+            CodeBits = (unsigned char) (1 + paletteBitSize);
+            pState->FreeCode = (unsigned short) (pState->ClearCode + 2);
+        }
+    }
+}
+
+/*
+ * Called function to save in gif format
+ */
+INTERNAL int gif_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) {
+    unsigned char outbuf[10];
+    FILE *gif_file;
+    unsigned short usTemp;
+    int byte_out;
+    int colourCount;
+    unsigned char paletteRGB[10][3];
+    int paletteCount, paletteCountCur, paletteIndex;
+    int pixelIndex;
+    int paletteBitSize;
+    int paletteSize;
+    statestruct State;
+
+    unsigned char backgroundColourIndex;
+    unsigned char RGBCur[3];
+
+    int colourIndex;
+
+    int fFound;
+
+    unsigned char pixelColour;
+
+    /* Allow for overhead of 4 == code size + byte count + overflow byte + zero terminator */
+    unsigned int lzoutbufSize = symbol->bitmap_height * symbol->bitmap_width + 4;
+#ifdef _MSC_VER
+    char * lzwoutbuf;
+#endif
+
+#ifndef _MSC_VER
+    char lzwoutbuf[lzoutbufSize];
+#else
+    lzwoutbuf = (char *) _alloca(lzoutbufSize);
+#endif /* _MSC_VER */
+
+    /* 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, "610: Can't open output file");
+            return ZINT_ERROR_FILE_ACCESS;
+        }
+#endif
+        gif_file = stdout;
+    } else {
+        if (!(gif_file = fopen(symbol->outfile, "wb"))) {
+            strcpy(symbol->errtxt, "611: Can't open output file");
+            return ZINT_ERROR_FILE_ACCESS;
+        }
+    }
+
+    /*
+     * Build a table of the used palette items.
+     * Currently, there are the following 10 colour codes:
+     * '0': standard background
+     * '1': standard foreground
+     * 'W': white
+     * 'C': cyan
+     * 'B': blue
+     * 'M': magenta
+     * 'R': red
+     * 'Y': yellow
+     * 'G': green
+     * 'K': black
+     * '0' and '1' may be identical to one of the other values
+     *
+     * A data structure is set up as follows:
+     * state.colourCode: list of colour codes
+     * paletteIndex: palette index of the corresponding colour code
+     *  There are colourCount entries in the upper lists.
+     * paletteRGB: RGB value at the palette position
+     *  There are paletteCount entries.
+     *  This value is smaller to colourCount, if multiple colour codes have the
+     *  same RGB value and point to the same palette value.
+     * Example:
+     *  0 1 W K are present. 0 is equal to white, while 1 is blue
+     *  The resulting tables are:
+     *  paletteItem: ['0']=0 (white), ['1']=1 (blue), ['W']=0 (white),
+     *               ['K']=2 (black)
+     *  Thus, there are 4 colour codes and 3 palette entries.
+
+     */
+    colourCount = 0;
+    paletteCount = 0;
+    /* loop over all pixels */
+    for ( pixelIndex = 0; pixelIndex < (symbol->bitmap_height * symbol->bitmap_width); pixelIndex++)
+    {
+        fFound = 0;
+        /* get pixel colour code */
+        pixelColour = pixelbuf[pixelIndex];
+        /* look, if colour code is already in colour list */
+        for (colourIndex = 0; colourIndex < colourCount; colourIndex++) {
+            if ((State.colourCode)[colourIndex] == pixelColour) {
+                fFound = 1;
+                break;
+            }
+        }
+        /* If colour is already present, go to next colour code */
+        if (fFound)
+            continue;
+
+        /* Colour code not present - add colour code */
+        /* Get RGB value */
+        switch (pixelColour) {
+            case '0': /* standard background */
+                RGBCur[0] = (unsigned char) (16 * ctoi(symbol->bgcolour[0])) + ctoi(symbol->bgcolour[1]);
+                RGBCur[1] = (unsigned char) (16 * ctoi(symbol->bgcolour[2])) + ctoi(symbol->bgcolour[3]);
+                RGBCur[2] = (unsigned char) (16 * ctoi(symbol->bgcolour[4])) + ctoi(symbol->bgcolour[5]);
+                break;
+            case '1': /* standard foreground */
+                RGBCur[0] = (unsigned char) (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]);
+                RGBCur[1] = (unsigned char) (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]);
+                RGBCur[2] = (unsigned char) (16 * ctoi(symbol->fgcolour[4])) + ctoi(symbol->fgcolour[5]);
+                break;
+            case 'W': /* white */
+                RGBCur[0] = 255; RGBCur[1] = 255; RGBCur[2] = 255;
+                break;
+            case 'C': /* cyan */
+                RGBCur[0] = 0; RGBCur[1] = 255; RGBCur[2] = 255;
+                break;
+            case 'B': /* blue */
+                RGBCur[0] = 0; RGBCur[1] = 0; RGBCur[2] = 255;
+                break;
+            case 'M': /* magenta */
+                RGBCur[0] = 255; RGBCur[1] = 0; RGBCur[2] = 255;
+                break;
+            case 'R': /* red */
+                RGBCur[0] = 255; RGBCur[1] = 0; RGBCur[2] = 0;
+                break;
+            case 'Y': /* yellow */
+                RGBCur[0] = 255; RGBCur[1] = 255; RGBCur[2] = 0;
+                break;
+            case 'G': /* green */
+                RGBCur[0] = 0; RGBCur[1] = 255; RGBCur[2] = 0;
+                break;
+            case 'K': /* black */
+                RGBCur[0] = 0; RGBCur[1] = 0; RGBCur[2] = 0;
+                break;
+            default: /* error case - return  */
+                strcpy(symbol->errtxt, "611: unknown pixel colour");
+                return ZINT_ERROR_INVALID_DATA;
+        }
+        /* Search, if RGB value is already present */
+        fFound = 0;
+        for (paletteIndex = 0; paletteIndex < paletteCount; paletteIndex++) {
+            if (RGBCur[0] == paletteRGB[paletteIndex][0]
+                && RGBCur[1] == paletteRGB[paletteIndex][1]
+                && RGBCur[2] == paletteRGB[paletteIndex][2])
+            {
+                fFound = 1;
+                break;
+            }
+        }
+        /* RGB not present, add it */
+        if (!fFound) {
+            paletteIndex = paletteCount;
+            paletteRGB[paletteIndex][0] = RGBCur[0];
+            paletteRGB[paletteIndex][1] = RGBCur[1];
+
+            paletteRGB[paletteIndex][2] = RGBCur[2];
+
+            paletteCount++;
+        }
+        /* Add palette index to current colour code */
+        (State.colourCode)[colourCount] = pixelColour;
+        (State.colourPaletteIndex)[colourCount] = paletteIndex;
+        colourCount++;
+    }
+    State.colourCount = colourCount;
+
+    /* find palette bit size from palette size*/
+
+    /* 1,2 -> 1, 3,4 ->2, 5,6,7,8->3 */
+    paletteBitSize = 0;
+    paletteCountCur = paletteCount-1;
+    while (paletteCountCur != 0) {
+        paletteBitSize++;
+        paletteCountCur >>= 1;
+    }
+    /* Minimum is 1 */
+    if (paletteBitSize == 0)
+        paletteBitSize = 1;
+
+    /* palette size 2 ^ bit size */
+    paletteSize = 1<<paletteBitSize;
+
+    /* GIF signature (6) */
+    memcpy(outbuf, "GIF87a", 6);
+    if (TRANSPARENT_INDEX != -1)
+        outbuf[4] = '9';
+
+    fwrite(outbuf, 6, 1, gif_file);
+    /* Screen Descriptor (7) */
+    /* Screen Width */
+    usTemp = (unsigned short) symbol->bitmap_width;
+    outbuf[0] = (unsigned char) (0xff & usTemp);
+    outbuf[1] = (unsigned char) ((0xff00 & usTemp) / 0x100);
+    /* Screen Height */
+    usTemp = (unsigned short) symbol->bitmap_height;
+    outbuf[2] = (unsigned char) (0xff & usTemp);
+    outbuf[3] = (unsigned char) ((0xff00 & usTemp) / 0x100);
+    /* write ImageBits-1 to the three least significant bits of byte 5  of
+     * the Screen Descriptor
+     * Bits 76543210
+     *      1        : Global colour map
+     *       111     : 8 bit colour depth of the palette
+     *          0    : Not ordered in decreasing importance
+     *           xxx : palette bit zize - 1
+     */
+    outbuf[4] = (unsigned char) (0xf0 | (0x7 & (paletteBitSize - 1)));
+
+    /*
+     * Background colour index
+     * Default to 0. If colour code 0 or K is present, it is used as index
+     */
+
+    backgroundColourIndex = 0;
+    for (colourIndex = 0; colourIndex < colourCount; colourIndex++) {
+        if ((State.colourCode)[colourIndex] == '0' || (State.colourCode)[colourIndex] == 'W') {
+            backgroundColourIndex = (State.colourPaletteIndex)[colourIndex];
+            break;
+        }
+    }
+    outbuf[5] = backgroundColourIndex;
+    /* Byte 7 must be 0x00  */
+    outbuf[6] = 0x00;
+    fwrite(outbuf, 7, 1, gif_file);
+    /* Global Color Table (paletteSize*3) */
+    fwrite(paletteRGB, 3*paletteCount, 1, gif_file);
+    /* add unused palette items to fill palette size */
+    for (paletteIndex = paletteCount; paletteIndex < paletteSize; paletteIndex++) {
+        unsigned char RGBCur[3] = {0,0,0};
+        fwrite(RGBCur, 3, 1, gif_file);
+    }
+
+    /* Graphic control extension (8) */
+    /* A graphic control extension block is used for overlay gifs.
+     * This is necessary to define a transparent color.
+     */
+    if (TRANSPARENT_INDEX != -1) {
+        /* Extension Introducer = '!' */
+        outbuf[0] = '\x21';
+        /* Graphic Control Label */
+        outbuf[1] = '\xf9';
+        /* Block Size */
+        outbuf[2] = 4;
+        /* Packet fields:
+         * 3 Reserved
+         * 3 Disposal Method: 0 No Action, 1 No Dispose, 2: Background, 3: Prev.
+         * 1 User Input Flag: 0: no user input, 1: user input
+         * 1 Transparent Color Flag: 0: No Transparency, 1: Transparency index
+         */
+        outbuf[3] = 1;
+        /* Delay Time */
+        outbuf[4] = 0;
+        outbuf[5] = 0;
+        /* Transparent Color Index */
+        outbuf[6] = (unsigned char) TRANSPARENT_INDEX;
+        /* Block Terminator */
+        outbuf[7] = 0;
+        fwrite(outbuf, 8, 1, gif_file);
+    }
+    /* Image Descriptor */
+    /* Image separator character = ',' */
+    outbuf[0] = 0x2c;
+    /* "Image Left" */
+    outbuf[1] = 0x00;
+    outbuf[2] = 0x00;
+    /* "Image Top" */
+    outbuf[3] = 0x00;
+    outbuf[4] = 0x00;
+    /* Image Width (low byte first) */
+    outbuf[5] = (unsigned char) (0xff & symbol->bitmap_width);
+    outbuf[6] = (unsigned char) ((0xff00 & symbol->bitmap_width) / 0x100);
+    /* Image Height */
+    outbuf[7] = (unsigned char) (0xff & symbol->bitmap_height);
+    outbuf[8] = (unsigned char) ((0xff00 & symbol->bitmap_height) / 0x100);
+
+    /* Byte 10 contains the interlaced flag and
+     * information on the local color table.
+     * There is no local color table if its most significant bit is reset.
+     */
+    outbuf[9] = 0x00;
+    fwrite(outbuf, 10, 1, gif_file);
+
+    /* prepare state array */
+    State.pIn = (unsigned char *) pixelbuf;
+    State.InLen = symbol->bitmap_height * symbol->bitmap_width;
+    State.pOut = (unsigned char *) lzwoutbuf;
+    State.OutLength = lzoutbufSize;
+
+    /* call lzw encoding */
+    byte_out = gif_lzw(&State, paletteBitSize);
+    if (byte_out <= 0) {
+        fclose(gif_file);
+        return ZINT_ERROR_MEMORY;
+    }
+    fwrite(lzwoutbuf, byte_out, 1, gif_file);
+
+    /* GIF terminator */
+    fputc('\x3b', gif_file);
+    fclose(gif_file);
+
+    return 0;
+}
diff --git a/backend/gridmtx.c b/backend/gridmtx.c
new file mode 100644 (file)
index 0000000..627057d
--- /dev/null
@@ -0,0 +1,1123 @@
+/*  gridmtx.c - Grid Matrix
+
+    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 : */
+
+/* This file implements Grid Matrix as specified in
+   AIM Global Document Number AIMD014 Rev. 1.63 Revised 9 Dec 2008 */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "reedsol.h"
+#include "gridmtx.h"
+#include "gb2312.h"
+
+/* define_mode() stuff */
+
+/* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */
+#define GM_MULT 6
+
+static const char numeral_nondigits[] = " +-.,"; /* Non-digit numeral set, excluding EOL (carriage return/linefeed) */
+
+/* Whether in numeral or not. If in numeral, *p_numeral_end is set to position after numeral, and *p_numeral_cost is set to per-numeral cost */
+static int in_numeral(const unsigned int gbdata[], const size_t length, const unsigned int posn, unsigned int* p_numeral_end, unsigned int* p_numeral_cost) {
+    unsigned int i, digit_cnt, nondigit, nondigit_posn;
+
+    if (posn < *p_numeral_end) {
+        return 1;
+    }
+
+    /* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times GM_MULT) */
+    /* Also ensures that numeric mode is not selected when it cannot be used: for example in
+       a string which has "2.2.0" (cannot have more than one non-numeric character for each
+       block of three numeric characters) */
+    for (i = posn, digit_cnt = 0, nondigit = 0, nondigit_posn = 0; i < length && i < posn + 4 && digit_cnt < 3; i++) {
+        if (gbdata[i] >= '0' && gbdata[i] <= '9') {
+            digit_cnt++;
+        } else if (strchr(numeral_nondigits, gbdata[i])) {
+            if (nondigit) {
+                break;
+            }
+            nondigit = 1;
+            nondigit_posn = i;
+        } else if (i < length - 1 && gbdata[i] == 13 && gbdata[i + 1] == 10) {
+            if (nondigit) {
+                break;
+            }
+            i++;
+            nondigit = 2;
+            nondigit_posn = i;
+        } else {
+            break;
+        }
+    }
+    if (digit_cnt == 0) { /* Must have at least one digit */
+        *p_numeral_end = 0;
+        return 0;
+    }
+    if (nondigit && nondigit_posn == i - 1) { /* Non-digit can't be at end */
+        nondigit = 0;
+    }
+    *p_numeral_end = posn + digit_cnt + nondigit;
+    /* Calculate per-numeral cost where 120 == (10 + 10) * GM_MULT, 60 == 10 * GM_MULT */
+    if (digit_cnt == 3) {
+        *p_numeral_cost = nondigit == 2 ? 24 /* (120 / 5) */ : nondigit == 1 ? 30 /* (120 / 4) */ : 20 /* (60 / 3) */;
+    } else if (digit_cnt == 2) {
+        *p_numeral_cost = nondigit == 2 ? 30 /* (120 / 4) */ : nondigit == 1 ? 40 /* (120 / 3) */ : 30 /* (60 / 2) */;
+    } else {
+        *p_numeral_cost = nondigit == 2 ? 40 /* (120 / 3) */ : nondigit == 1 ? 60 /* (120 / 2) */ : 60 /* (60 / 1) */;
+    }
+    return 1;
+}
+
+/* Encoding modes */
+#define GM_CHINESE  'H'
+#define GM_NUMBER   'N'
+#define GM_LOWER    'L'
+#define GM_UPPER    'U'
+#define GM_MIXED    'M'
+#define GM_BYTE     'B'
+/* Note Control is a submode of Lower, Upper and Mixed modes */
+
+/* Indexes into mode_types array */
+#define GM_H   0 /* Chinese (Hanzi) */
+#define GM_N   1 /* Numeral */
+#define GM_L   2 /* Lower case */
+#define GM_U   3 /* Upper case */
+#define GM_M   4 /* Mixed */
+#define GM_B   5 /* Byte */
+
+#define GM_NUM_MODES 6
+
+/* Initial mode costs */
+static unsigned int head_costs[GM_NUM_MODES] = {
+/*  H            N (+pad prefix)    L            U            M            B (+byte count) */
+    4 * GM_MULT, (4 + 2) * GM_MULT, 4 * GM_MULT, 4 * GM_MULT, 4 * GM_MULT, (4 + 9) * GM_MULT
+};
+
+static unsigned int* gm_head_costs(unsigned int state[]) {
+    (void)state; /* Unused */
+    return head_costs;
+}
+
+/* Cost of switching modes from k to j - see AIMD014 Rev. 1.63 Table 9 – Type conversion codes */
+static unsigned int gm_switch_cost(unsigned int state[], const int k, const int j) {
+    static const unsigned int switch_costs[GM_NUM_MODES][GM_NUM_MODES] = {
+        /*      H             N                   L             U             M             B  */
+        /*H*/ {            0, (13 + 2) * GM_MULT, 13 * GM_MULT, 13 * GM_MULT, 13 * GM_MULT, (13 + 9) * GM_MULT },
+        /*N*/ { 10 * GM_MULT,                  0, 10 * GM_MULT, 10 * GM_MULT, 10 * GM_MULT, (10 + 9) * GM_MULT },
+        /*L*/ {  5 * GM_MULT,  (5 + 2) * GM_MULT,            0,  5 * GM_MULT,  7 * GM_MULT,  (7 + 9) * GM_MULT },
+        /*U*/ {  5 * GM_MULT,  (5 + 2) * GM_MULT,  5 * GM_MULT,            0,  7 * GM_MULT,  (7 + 9) * GM_MULT },
+        /*M*/ { 10 * GM_MULT, (10 + 2) * GM_MULT, 10 * GM_MULT, 10 * GM_MULT,            0, (10 + 9) * GM_MULT },
+        /*B*/ {  4 * GM_MULT,  (4 + 2) * GM_MULT,  4 * GM_MULT,  4 * GM_MULT,  4 * GM_MULT,                  0 },
+    };
+
+    (void)state; /* Unused */
+    return switch_costs[k][j];
+}
+
+/* Final end-of-data cost - see AIMD014 Rev. 1.63 Table 9 – Type conversion codes */
+static unsigned int gm_eod_cost(unsigned int state[], const int k) {
+    static const unsigned int eod_costs[GM_NUM_MODES] = {
+    /*  H             N             L            U            M             B  */
+        13 * GM_MULT, 10 * GM_MULT, 5 * GM_MULT, 5 * GM_MULT, 10 * GM_MULT, 4 * GM_MULT
+    };
+
+    (void)state; /* Unused */
+    return eod_costs[k];
+}
+
+/* Calculate cost of encoding current character */
+static void gm_cur_cost(unsigned int state[], const unsigned int gbdata[], const size_t length, const int i, char* char_modes, unsigned int prev_costs[], unsigned int cur_costs[]) {
+    int cm_i = i * GM_NUM_MODES;
+    int double_byte, space, numeric, lower, upper, control, double_digit, eol;
+    unsigned int* p_numeral_end = &state[0];
+    unsigned int* p_numeral_cost = &state[1];
+    unsigned int* p_byte_count = &state[2];
+
+    double_byte = gbdata[i] > 0xFF;
+    space = gbdata[i] == ' ';
+    numeric = gbdata[i] >= '0' && gbdata[i] <= '9';
+    lower = gbdata[i] >= 'a' && gbdata[i] <= 'z';
+    upper = gbdata[i] >= 'A' && gbdata[i] <= 'Z';
+    control = !space && !numeric && !lower && !upper && gbdata[i] < 0x7F; /* Exclude DEL */
+    double_digit = i < (int) length - 1 && numeric && gbdata[i + 1] >= '0' && gbdata[i + 1] <= '9';
+    eol = i < (int) length - 1 && gbdata[i] == 13 && gbdata[i + 1] == 10;
+
+    /* Hanzi mode can encode anything */
+    cur_costs[GM_H] = prev_costs[GM_H] + (double_digit || eol ? 39 : 78); /* (6.5 : 13) * GM_MULT */
+    char_modes[cm_i + GM_H] = GM_CHINESE;
+
+    /* Byte mode can encode anything */
+    if (*p_byte_count == 512 || (double_byte && *p_byte_count == 511)) {
+        cur_costs[GM_B] = head_costs[GM_B];
+        if (double_byte && *p_byte_count == 511) {
+            cur_costs[GM_B] += 48; /* 8 * GM_MULT */
+            double_byte = 0; /* Splitting double-byte so mark as single */
+        }
+        *p_byte_count = 0;
+    }
+    cur_costs[GM_B] += prev_costs[GM_B] + (double_byte ? 96 : 48); /* (16 : 8) * GM_MULT */
+    char_modes[cm_i + GM_B] = GM_BYTE;
+    *p_byte_count += double_byte ? 2 : 1;
+
+    if (in_numeral(gbdata, length, i, p_numeral_end, p_numeral_cost)) {
+        cur_costs[GM_N] = prev_costs[GM_N] + *p_numeral_cost;
+        char_modes[cm_i + GM_N] = GM_NUMBER;
+    }
+
+    if (control) {
+        cur_costs[GM_L] = prev_costs[GM_L] + 78; /* (7 + 6) * GM_MULT */
+        char_modes[cm_i + GM_L] = GM_LOWER;
+        cur_costs[GM_U] = prev_costs[GM_U] + 78; /* (7 + 6) * GM_MULT */
+        char_modes[cm_i + GM_U] = GM_UPPER;
+        cur_costs[GM_M] = prev_costs[GM_M] + 96; /* (10 + 6) * GM_MULT */
+        char_modes[cm_i + GM_M] = GM_MIXED;
+    } else {
+        if (lower || space) {
+            cur_costs[GM_L] = prev_costs[GM_L] + 30; /* 5 * GM_MULT */
+            char_modes[cm_i + GM_L] = GM_LOWER;
+        }
+        if (upper || space) {
+            cur_costs[GM_U] = prev_costs[GM_U] + 30; /* 5 * GM_MULT */
+            char_modes[cm_i + GM_U] = GM_UPPER;
+        }
+        if (numeric || lower || upper || space) {
+            cur_costs[GM_M] = prev_costs[GM_M] + 36; /* 6 * GM_MULT */
+            char_modes[cm_i + GM_M] = GM_MIXED;
+        }
+    }
+}
+
+/* Calculate optimized encoding modes */
+static void define_mode(char* mode, const unsigned int gbdata[], const size_t length, const int debug) {
+    static const char mode_types[] = { GM_CHINESE, GM_NUMBER, GM_LOWER, GM_UPPER, GM_MIXED, GM_BYTE }; /* Must be in same order as GM_H etc */
+    unsigned int state[3] = { 0 /*numeral_end*/, 0 /*numeral_cost*/, 0 /*byte_count*/ };
+
+    pn_define_mode(mode, gbdata, length, debug, state, mode_types, GM_NUM_MODES, gm_head_costs, gm_switch_cost, gm_eod_cost, gm_cur_cost);
+}
+
+/* Add the length indicator for byte encoded blocks */
+static void add_byte_count(char binary[], const size_t byte_count_posn, const int byte_count) {
+    /* AIMD014 6.3.7: "Let L be the number of bytes of input data to be encoded in the 8-bit binary data set.
+     * First output (L-1) as a 9-bit binary prefix to record the number of bytes..." */
+    bin_append_posn(byte_count - 1, 9, binary, byte_count_posn);
+}
+
+/* Add a control character to the data stream */
+static void add_shift_char(char binary[], int shifty, int debug) {
+    int i;
+    int glyph = 0;
+
+    for (i = 0; i < 64; i++) {
+        if (shift_set[i] == shifty) {
+            glyph = i;
+            break;
+        }
+    }
+
+    if (debug & ZINT_DEBUG_PRINT) {
+        printf("SHIFT [%d] ", glyph);
+    }
+
+    bin_append(glyph, 6, binary);
+}
+
+static int gm_encode(unsigned int gbdata[], const size_t length, char binary[], const int reader, const int eci, int debug) {
+    /* Create a binary stream representation of the input data.
+       7 sets are defined - Chinese characters, Numerals, Lower case letters, Upper case letters,
+       Mixed numerals and latters, Control characters and 8-bit binary data */
+    unsigned int sp;
+    int current_mode, last_mode;
+    unsigned int glyph = 0;
+    int c1, c2, done;
+    int p = 0, ppos;
+    int numbuf[3], punt = 0;
+    size_t number_pad_posn, byte_count_posn = 0;
+    int byte_count = 0;
+    int shift;
+#ifndef _MSC_VER
+    char mode[length];
+#else
+    char* mode = (char*) _alloca(length);
+#endif
+
+    strcpy(binary, "");
+
+    sp = 0;
+    current_mode = 0;
+    last_mode = 0;
+    number_pad_posn = 0;
+
+    if (reader) {
+        bin_append(10, 4, binary); /* FNC3 - Reader Initialisation */
+    }
+
+    if (eci != 0) {
+        /* ECI assignment according to Table 8 */
+        bin_append(12, 4, binary); /* ECI */
+        if (eci <= 1023) {
+            bin_append(eci, 11, binary);
+        }
+        if ((eci >= 1024) && (eci <= 32767)) {
+            strcat(binary, "10");
+            bin_append(eci, 15, binary);
+        }
+        if (eci >= 32768) {
+            strcat(binary, "11");
+            bin_append(eci, 20, binary);
+        }
+    }
+
+    define_mode(mode, gbdata, length, debug);
+
+    do {
+        int next_mode = mode[sp];
+
+        if (next_mode != current_mode) {
+            switch (current_mode) {
+                case 0:
+                    switch (next_mode) {
+                        case GM_CHINESE: bin_append(1, 4, binary);
+                            break;
+                        case GM_NUMBER: bin_append(2, 4, binary);
+                            break;
+                        case GM_LOWER: bin_append(3, 4, binary);
+                            break;
+                        case GM_UPPER: bin_append(4, 4, binary);
+                            break;
+                        case GM_MIXED: bin_append(5, 4, binary);
+                            break;
+                        case GM_BYTE: bin_append(6, 4, binary);
+                            break;
+                    }
+                    break;
+                case GM_CHINESE:
+                    switch (next_mode) {
+                        case GM_NUMBER: bin_append(8161, 13, binary);
+                            break;
+                        case GM_LOWER: bin_append(8162, 13, binary);
+                            break;
+                        case GM_UPPER: bin_append(8163, 13, binary);
+                            break;
+                        case GM_MIXED: bin_append(8164, 13, binary);
+                            break;
+                        case GM_BYTE: bin_append(8165, 13, binary);
+                            break;
+                    }
+                    break;
+                case GM_NUMBER:
+                    /* add numeric block padding value */
+                    switch (p) {
+                        case 1: binary[number_pad_posn] = '1';
+                            binary[number_pad_posn + 1] = '0';
+                            break; // 2 pad digits
+                        case 2: binary[number_pad_posn] = '0';
+                            binary[number_pad_posn + 1] = '1';
+                            break; // 1 pad digits
+                        case 3: binary[number_pad_posn] = '0';
+                            binary[number_pad_posn + 1] = '0';
+                            break; // 0 pad digits
+                    }
+                    switch (next_mode) {
+                        case GM_CHINESE: bin_append(1019, 10, binary);
+                            break;
+                        case GM_LOWER: bin_append(1020, 10, binary);
+                            break;
+                        case GM_UPPER: bin_append(1021, 10, binary);
+                            break;
+                        case GM_MIXED: bin_append(1022, 10, binary);
+                            break;
+                        case GM_BYTE: bin_append(1023, 10, binary);
+                            break;
+                    }
+                    break;
+                case GM_LOWER:
+                case GM_UPPER:
+                    switch (next_mode) {
+                        case GM_CHINESE: bin_append(28, 5, binary);
+                            break;
+                        case GM_NUMBER: bin_append(29, 5, binary);
+                            break;
+                        case GM_LOWER:
+                        case GM_UPPER: bin_append(30, 5, binary);
+                            break;
+                        case GM_MIXED: bin_append(124, 7, binary);
+                            break;
+                        case GM_BYTE: bin_append(126, 7, binary);
+                            break;
+                    }
+                    break;
+                case GM_MIXED:
+                    switch (next_mode) {
+                        case GM_CHINESE: bin_append(1009, 10, binary);
+                            break;
+                        case GM_NUMBER: bin_append(1010, 10, binary);
+                            break;
+                        case GM_LOWER: bin_append(1011, 10, binary);
+                            break;
+                        case GM_UPPER: bin_append(1012, 10, binary);
+                            break;
+                        case GM_BYTE: bin_append(1015, 10, binary);
+                            break;
+                    }
+                    break;
+                case GM_BYTE:
+                    /* add byte block length indicator */
+                    add_byte_count(binary, byte_count_posn, byte_count);
+                    byte_count = 0;
+                    switch (next_mode) {
+                        case GM_CHINESE: bin_append(1, 4, binary);
+                            break;
+                        case GM_NUMBER: bin_append(2, 4, binary);
+                            break;
+                        case GM_LOWER: bin_append(3, 4, binary);
+                            break;
+                        case GM_UPPER: bin_append(4, 4, binary);
+                            break;
+                        case GM_MIXED: bin_append(5, 4, binary);
+                            break;
+                    }
+                    break;
+            }
+            if (debug & ZINT_DEBUG_PRINT) {
+                switch (next_mode) {
+                    case GM_CHINESE: printf("CHIN ");
+                        break;
+                    case GM_NUMBER: printf("NUMB ");
+                        break;
+                    case GM_LOWER: printf("LOWR ");
+                        break;
+                    case GM_UPPER: printf("UPPR ");
+                        break;
+                    case GM_MIXED: printf("MIXD ");
+                        break;
+                    case GM_BYTE: printf("BYTE ");
+                        break;
+                }
+            }
+        }
+        last_mode = current_mode;
+        current_mode = next_mode;
+
+        switch (current_mode) {
+            case GM_CHINESE:
+                done = 0;
+                if (gbdata[sp] > 0xff) {
+                    /* GB2312 character */
+                    c1 = (gbdata[sp] & 0xff00) >> 8;
+                    c2 = gbdata[sp] & 0xff;
+
+                    if ((c1 >= 0xa1) && (c1 <= 0xa9)) {
+                        glyph = (0x60 * (c1 - 0xa1)) + (c2 - 0xa0);
+                    } else if ((c1 >= 0xb0) && (c1 <= 0xf7)) {
+                        glyph = (0x60 * (c1 - 0xb0 + 9)) + (c2 - 0xa0);
+                    }
+                    done = 1; /* GB 2312 always within above ranges */
+                }
+                if (!(done)) {
+                    if (sp != (length - 1)) {
+                        if ((gbdata[sp] == 13) && (gbdata[sp + 1] == 10)) {
+                            /* End of Line */
+                            glyph = 7776;
+                            sp++;
+                            done = 1;
+                        }
+                    }
+                }
+                if (!(done)) {
+                    if (sp != (length - 1)) {
+                        if (((gbdata[sp] >= '0') && (gbdata[sp] <= '9')) &&
+                                ((gbdata[sp + 1] >= '0') && (gbdata[sp + 1] <= '9'))) {
+                            /* Two digits */
+                            glyph = 8033 + (10 * (gbdata[sp] - '0')) + (gbdata[sp + 1] - '0');
+                            sp++;
+                            done = 1;
+                        }
+                    }
+                }
+                if (!(done)) {
+                    /* Byte value */
+                    glyph = 7777 + gbdata[sp];
+                }
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("[%d] ", glyph);
+                }
+
+                bin_append(glyph, 13, binary);
+                sp++;
+                break;
+
+            case GM_NUMBER:
+                if (last_mode != current_mode) {
+                    /* Reserve a space for numeric digit padding value (2 bits) */
+                    number_pad_posn = strlen(binary);
+                    strcat(binary, "XX");
+                }
+                p = 0;
+                ppos = -1;
+
+                /* Numeric compression can also include certain combinations of
+                   non-numeric character */
+
+                numbuf[0] = '0';
+                numbuf[1] = '0';
+                numbuf[2] = '0';
+                do {
+                    if ((gbdata[sp] >= '0') && (gbdata[sp] <= '9')) {
+                        numbuf[p] = gbdata[sp];
+                        p++;
+                    } else if (strchr(numeral_nondigits, gbdata[sp])) {
+                        if (ppos != -1) {
+                            break;
+                        }
+                        punt = gbdata[sp];
+                        ppos = p;
+                    } else if (sp < (length - 1) && (gbdata[sp] == 13) && (gbdata[sp + 1] == 10)) {
+                        /* <end of line> */
+                        if (ppos != -1) {
+                            break;
+                        }
+                        punt = gbdata[sp];
+                        sp++;
+                        ppos = p;
+                    } else {
+                        break;
+                    }
+                    sp++;
+                } while ((p < 3) && (sp < length) && mode[sp] == GM_NUMBER);
+
+                if (ppos != -1) {
+                    switch (punt) {
+                        case ' ': glyph = 0;
+                            break;
+                        case '+': glyph = 3;
+                            break;
+                        case '-': glyph = 6;
+                            break;
+                        case '.': glyph = 9;
+                            break;
+                        case ',': glyph = 12;
+                            break;
+                        case 13: glyph = 15;
+                            break;
+                    }
+                    glyph += ppos;
+                    glyph += 1000;
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("[%d] ", glyph);
+                    }
+
+                    bin_append(glyph, 10, binary);
+                }
+
+                glyph = (100 * (numbuf[0] - '0')) + (10 * (numbuf[1] - '0')) + (numbuf[2] - '0');
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("[%d] ", glyph);
+                }
+
+                bin_append(glyph, 10, binary);
+                break;
+
+            case GM_BYTE:
+                if (last_mode != current_mode) {
+                    /* Reserve space for byte block length indicator (9 bits) */
+                    byte_count_posn = strlen(binary);
+                    strcat(binary, "LLLLLLLLL");
+                }
+                glyph = gbdata[sp];
+                if (byte_count == 512 || (glyph > 0xFF && byte_count == 511)) {
+                    /* Maximum byte block size is 512 bytes. If longer is needed then start a new block */
+                    if (glyph > 0xFF && byte_count == 511) { /* Split double-byte */
+                        bin_append(glyph >> 8, 8, binary);
+                        glyph &= 0xFF;
+                        byte_count++;
+                    }
+                    add_byte_count(binary, byte_count_posn, byte_count);
+                    bin_append(7, 4, binary);
+                    byte_count_posn = strlen(binary);
+                    strcat(binary, "LLLLLLLLL");
+                    byte_count = 0;
+                }
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("[%d] ", glyph);
+                }
+                bin_append(glyph, glyph > 0xFF ? 16 : 8, binary);
+                sp++;
+                byte_count++;
+                if (glyph > 0xFF) {
+                    byte_count++;
+                }
+                break;
+
+            case GM_MIXED:
+                shift = 1;
+                if ((gbdata[sp] >= '0') && (gbdata[sp] <= '9')) {
+                    shift = 0;
+                }
+                if ((gbdata[sp] >= 'A') && (gbdata[sp] <= 'Z')) {
+                    shift = 0;
+                }
+                if ((gbdata[sp] >= 'a') && (gbdata[sp] <= 'z')) {
+                    shift = 0;
+                }
+                if (gbdata[sp] == ' ') {
+                    shift = 0;
+                }
+
+                if (shift == 0) {
+                    /* Mixed Mode character */
+                    glyph = posn(EUROPIUM, gbdata[sp]);
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("[%d] ", glyph);
+                    }
+
+                    bin_append(glyph, 6, binary);
+                } else {
+                    /* Shift Mode character */
+                    bin_append(1014, 10, binary); /* shift indicator */
+                    add_shift_char(binary, gbdata[sp], debug);
+                }
+
+                sp++;
+                break;
+
+            case GM_UPPER:
+                shift = 1;
+                if ((gbdata[sp] >= 'A') && (gbdata[sp] <= 'Z')) {
+                    shift = 0;
+                }
+                if (gbdata[sp] == ' ') {
+                    shift = 0;
+                }
+
+                if (shift == 0) {
+                    /* Upper Case character */
+                    glyph = posn("ABCDEFGHIJKLMNOPQRSTUVWXYZ ", gbdata[sp]);
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("[%d] ", glyph);
+                    }
+
+                    bin_append(glyph, 5, binary);
+                } else {
+                    /* Shift Mode character */
+                    bin_append(125, 7, binary); /* shift indicator */
+                    add_shift_char(binary, gbdata[sp], debug);
+                }
+
+                sp++;
+                break;
+
+            case GM_LOWER:
+                shift = 1;
+                if ((gbdata[sp] >= 'a') && (gbdata[sp] <= 'z')) {
+                    shift = 0;
+                }
+                if (gbdata[sp] == ' ') {
+                    shift = 0;
+                }
+
+                if (shift == 0) {
+                    /* Lower Case character */
+                    glyph = posn("abcdefghijklmnopqrstuvwxyz ", gbdata[sp]);
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("[%d] ", glyph);
+                    }
+
+                    bin_append(glyph, 5, binary);
+                } else {
+                    /* Shift Mode character */
+                    bin_append(125, 7, binary); /* shift indicator */
+                    add_shift_char(binary, gbdata[sp], debug);
+                }
+
+                sp++;
+                break;
+        }
+        if (strlen(binary) > 9191) {
+            return ZINT_ERROR_TOO_LONG;
+        }
+
+    } while (sp < length);
+
+    if (current_mode == GM_NUMBER) {
+        /* add numeric block padding value */
+        switch (p) {
+            case 1: binary[number_pad_posn] = '1';
+                binary[number_pad_posn + 1] = '0';
+                break; // 2 pad digits
+            case 2: binary[number_pad_posn] = '0';
+                binary[number_pad_posn + 1] = '1';
+                break; // 1 pad digit
+            case 3: binary[number_pad_posn] = '0';
+                binary[number_pad_posn + 1] = '0';
+                break; // 0 pad digits
+        }
+    }
+
+    if (current_mode == GM_BYTE) {
+        /* Add byte block length indicator */
+        add_byte_count(binary, byte_count_posn, byte_count);
+    }
+
+    /* Add "end of data" character */
+    switch (current_mode) {
+        case GM_CHINESE: bin_append(8160, 13, binary);
+            break;
+        case GM_NUMBER: bin_append(1018, 10, binary);
+            break;
+        case GM_LOWER:
+        case GM_UPPER: bin_append(27, 5, binary);
+            break;
+        case GM_MIXED: bin_append(1008, 10, binary);
+            break;
+        case GM_BYTE: bin_append(0, 4, binary);
+            break;
+    }
+
+    /* Add padding bits if required */
+    p = 7 - (strlen(binary) % 7);
+    if (p % 7) {
+        bin_append(0, p, binary);
+    }
+
+    if (strlen(binary) > 9191) {
+        return ZINT_ERROR_TOO_LONG;
+    }
+    return 0;
+}
+
+static void gm_add_ecc(const char binary[], const size_t data_posn, const int layers, const int ecc_level, unsigned char word[]) {
+    int data_cw, i, j, wp, p;
+    int n1, b1, n2, b2, e1, b3, e2;
+    int block_size, ecc_size;
+    unsigned char data[1320], block[130];
+    unsigned char data_block[115], ecc_block[70];
+
+    data_cw = gm_data_codewords[((layers - 1) * 5) + (ecc_level - 1)];
+
+    for (i = 0; i < 1320; i++) {
+        data[i] = 0;
+    }
+
+    /* Convert from binary stream to 7-bit codewords */
+    for (i = 0; i < (int) data_posn; i++) {
+        for (p = 0; p < 7; p++) {
+            if (binary[i * 7 + p] == '1') {
+                data[i] += (0x40 >> p);
+            }
+        }
+    }
+
+    /* Add padding codewords */
+    data[data_posn] = 0x00;
+    for (i = (int) (data_posn + 1); i < data_cw; i++) {
+        if (i & 1) {
+            data[i] = 0x7e;
+        } else {
+            data[i] = 0x00;
+        }
+    }
+
+    /* Get block sizes */
+    n1 = gm_n1[(layers - 1)];
+    b1 = gm_b1[(layers - 1)];
+    n2 = n1 - 1;
+    b2 = gm_b2[(layers - 1)];
+    e1 = gm_ebeb[((layers - 1) * 20) + ((ecc_level - 1) * 4)];
+    b3 = gm_ebeb[((layers - 1) * 20) + ((ecc_level - 1) * 4) + 1];
+    e2 = gm_ebeb[((layers - 1) * 20) + ((ecc_level - 1) * 4) + 2];
+
+    /* Split the data into blocks */
+    wp = 0;
+    for (i = 0; i < (b1 + b2); i++) {
+        int data_size;
+        if (i < b1) {
+            block_size = n1;
+        } else {
+            block_size = n2;
+        }
+        if (i < b3) {
+            ecc_size = e1;
+        } else {
+            ecc_size = e2;
+        }
+        data_size = block_size - ecc_size;
+
+        /* printf("block %d/%d: data %d / ecc %d\n", i + 1, (b1 + b2), data_size, ecc_size);*/
+
+        for (j = 0; j < data_size; j++) {
+            data_block[j] = data[wp];
+            wp++;
+        }
+
+        /* Calculate ECC data for this block */
+        rs_init_gf(0x89);
+        rs_init_code(ecc_size, 1);
+        rs_encode(data_size, data_block, ecc_block);
+        rs_free();
+
+        /* Correct error correction data but in reverse order */
+        for (j = 0; j < data_size; j++) {
+            block[j] = data_block[j];
+        }
+        for (j = 0; j < ecc_size; j++) {
+            block[(j + data_size)] = ecc_block[ecc_size - j - 1];
+        }
+
+        for (j = 0; j < n2; j++) {
+            word[((b1 + b2) * j) + i] = block[j];
+        }
+        if (block_size == n1) {
+            word[((b1 + b2) * (n1 - 1)) + i] = block[(n1 - 1)];
+        }
+    }
+}
+
+static void place_macromodule(char grid[], int x, int y, int word1, int word2, int size) {
+    int i, j;
+
+    i = (x * 6) + 1;
+    j = (y * 6) + 1;
+
+    if (word2 & 0x40) {
+        grid[(j * size) + i + 2] = '1';
+    }
+    if (word2 & 0x20) {
+        grid[(j * size) + i + 3] = '1';
+    }
+    if (word2 & 0x10) {
+        grid[((j + 1) * size) + i] = '1';
+    }
+    if (word2 & 0x08) {
+        grid[((j + 1) * size) + i + 1] = '1';
+    }
+    if (word2 & 0x04) {
+        grid[((j + 1) * size) + i + 2] = '1';
+    }
+    if (word2 & 0x02) {
+        grid[((j + 1) * size) + i + 3] = '1';
+    }
+    if (word2 & 0x01) {
+        grid[((j + 2) * size) + i] = '1';
+    }
+    if (word1 & 0x40) {
+        grid[((j + 2) * size) + i + 1] = '1';
+    }
+    if (word1 & 0x20) {
+        grid[((j + 2) * size) + i + 2] = '1';
+    }
+    if (word1 & 0x10) {
+        grid[((j + 2) * size) + i + 3] = '1';
+    }
+    if (word1 & 0x08) {
+        grid[((j + 3) * size) + i] = '1';
+    }
+    if (word1 & 0x04) {
+        grid[((j + 3) * size) + i + 1] = '1';
+    }
+    if (word1 & 0x02) {
+        grid[((j + 3) * size) + i + 2] = '1';
+    }
+    if (word1 & 0x01) {
+        grid[((j + 3) * size) + i + 3] = '1';
+    }
+}
+
+static void place_data_in_grid(unsigned char word[], char grid[], int modules, int size) {
+    int x, y, macromodule, offset;
+
+    offset = 13 - ((modules - 1) / 2);
+    for (y = 0; y < modules; y++) {
+        for (x = 0; x < modules; x++) {
+            macromodule = gm_macro_matrix[((y + offset) * 27) + (x + offset)];
+            place_macromodule(grid, x, y, word[macromodule * 2], word[(macromodule * 2) + 1], size);
+        }
+    }
+}
+
+/* Place the layer ID into each macromodule */
+static void place_layer_id(char* grid, int size, int layers, int modules, int ecc_level) {
+    int i, j, layer, start, stop;
+
+#ifndef _MSC_VER
+    int layerid[layers + 1];
+    int id[modules * modules];
+#else
+    int* layerid = (int *) _alloca((layers + 1) * sizeof (int));
+    int* id = (int *) _alloca((modules * modules) * sizeof (int));
+#endif
+
+    /* Calculate Layer IDs */
+    for (i = 0; i <= layers; i++) {
+        if (ecc_level == 1) {
+            layerid[i] = 3 - (i % 4);
+        } else {
+            layerid[i] = (i + 5 - ecc_level) % 4;
+        }
+    }
+
+    for (i = 0; i < modules; i++) {
+        for (j = 0; j < modules; j++) {
+            id[(i * modules) + j] = 0;
+        }
+    }
+
+    /* Calculate which value goes in each macromodule */
+    start = modules / 2;
+    stop = modules / 2;
+    for (layer = 0; layer <= layers; layer++) {
+        for (i = start; i <= stop; i++) {
+            id[(start * modules) + i] = layerid[layer];
+            id[(i * modules) + start] = layerid[layer];
+            id[((modules - start - 1) * modules) + i] = layerid[layer];
+            id[(i * modules) + (modules - start - 1)] = layerid[layer];
+        }
+        start--;
+        stop++;
+    }
+
+    /* Place the data in the grid */
+    for (i = 0; i < modules; i++) {
+        for (j = 0; j < modules; j++) {
+            if (id[(i * modules) + j] & 0x02) {
+                grid[(((i * 6) + 1) * size) + (j * 6) + 1] = '1';
+            }
+            if (id[(i * modules) + j] & 0x01) {
+                grid[(((i * 6) + 1) * size) + (j * 6) + 2] = '1';
+            }
+        }
+    }
+}
+
+INTERNAL int grid_matrix(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
+    int size, modules, error_number;
+    int auto_layers, min_layers, layers, auto_ecc_level, min_ecc_level, ecc_level;
+    int x, y, i;
+    int full_multibyte;
+    char binary[9300];
+    int data_cw, input_latch = 0;
+    unsigned char word[1460];
+    int data_max, reader = 0;
+
+#ifndef _MSC_VER
+    unsigned int gbdata[length + 1];
+#else
+    char* grid;
+    unsigned int* gbdata = (unsigned int *) _alloca((length + 1) * sizeof (unsigned int));
+#endif
+
+    for (i = 0; i < 1460; i++) {
+        word[i] = 0;
+    }
+
+    full_multibyte = symbol->option_3 == ZINT_FULL_MULTIBYTE; /* If set use Hanzi mode in DATA_MODE or for single-byte Latin */
+
+    if ((symbol->input_mode & 0x07) == DATA_MODE) {
+        gb2312_cpy(source, &length, gbdata, full_multibyte);
+    } else {
+        int done = 0;
+        if (symbol->eci != 29) { /* Unless ECI 29 (GB) */
+            /* Try single byte (Latin) conversion first */
+            int error_number = gb2312_utf8tosb(symbol->eci && symbol->eci <= 899 ? symbol->eci : 3, source, &length, gbdata, full_multibyte);
+            if (error_number == 0) {
+                done = 1;
+            } else if (symbol->eci && symbol->eci <= 899) {
+                strcpy(symbol->errtxt, "575: Invalid characters in input data");
+                return error_number;
+            }
+        }
+        if (!done) {
+            /* Try GB 2312 (EUC-CN) */
+            int error_number = gb2312_utf8tomb(symbol, source, &length, gbdata);
+            if (error_number != 0) {
+                return error_number;
+            }
+        }
+    }
+
+    if (symbol->output_options & READER_INIT) reader = 1;
+
+    if (symbol->eci > 811799) {
+        strcpy(symbol->errtxt, "533: Invalid ECI");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    error_number = gm_encode(gbdata, length, binary, reader, symbol->eci, symbol->debug);
+    if (error_number != 0) {
+        strcpy(symbol->errtxt, "531: Input data too long");
+        return error_number;
+    }
+
+    /* Determine the size of the symbol */
+    data_cw = (int)strlen(binary) / 7;
+
+    auto_layers = 13;
+    for (i = 12; i > 0; i--) {
+        if (gm_recommend_cw[(i - 1)] >= data_cw) {
+            auto_layers = i;
+        }
+    }
+    min_layers = 13;
+    for (i = 12; i > 0; i--) {
+        if (gm_max_cw[(i - 1)] >= data_cw) {
+            min_layers = i;
+        }
+    }
+    layers = auto_layers;
+
+    if ((symbol->option_2 >= 1) && (symbol->option_2 <= 13)) {
+        input_latch = 1;
+        if (symbol->option_2 >= min_layers) {
+            layers = symbol->option_2;
+        } else {
+            strcpy(symbol->errtxt, "534: Input data too long for selected symbol size");
+            return ZINT_ERROR_TOO_LONG;
+        }
+    }
+
+    auto_ecc_level = 3;
+    if (layers == 1) {
+        auto_ecc_level = 5;
+    }
+    if ((layers == 2) || (layers == 3)) {
+        auto_ecc_level = 4;
+    }
+    ecc_level = auto_ecc_level;
+
+    min_ecc_level = 1;
+    if (layers == 1) {
+        min_ecc_level = 4;
+    }
+    if (layers == 2) {
+        min_ecc_level = 2;
+    }
+
+    if ((symbol->option_1 >= 1) && (symbol->option_1 <= 5)) {
+        if (symbol->option_1 >= min_ecc_level) {
+            ecc_level = symbol->option_1;
+        } else {
+            ecc_level = min_ecc_level;
+        }
+    }
+    if (data_cw > gm_data_codewords[(5 * (layers - 1)) + (ecc_level - 1)]) {
+        if (input_latch && ecc_level > min_ecc_level) { /* If layers user-specified (option_2), try reducing ECC level first */
+            do {
+                ecc_level--;
+            } while ((data_cw > gm_data_codewords[(5 * (layers - 1)) + (ecc_level - 1)]) && (ecc_level > min_ecc_level));
+        }
+        while (data_cw > gm_data_codewords[(5 * (layers - 1)) + (ecc_level - 1)] && (layers < 13)) {
+            layers++;
+        }
+        while (data_cw > gm_data_codewords[(5 * (layers - 1)) + (ecc_level - 1)] && ecc_level > 1) { /* ECC min level 1 for layers > 2 */
+            ecc_level--;
+        }
+    }
+
+    data_max = 1313;
+    switch (ecc_level) {
+        case 2: data_max = 1167;
+            break;
+        case 3: data_max = 1021;
+            break;
+        case 4: data_max = 875;
+            break;
+        case 5: data_max = 729;
+            break;
+    }
+
+    if (data_cw > data_max) {
+        strcpy(symbol->errtxt, "532: Input data too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    gm_add_ecc(binary, data_cw, layers, ecc_level, word);
+#ifdef ZINT_TEST
+    if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, word, data_cw);
+#endif
+    size = 6 + (layers * 12);
+    modules = 1 + (layers * 2);
+
+#ifndef _MSC_VER
+    char grid[size * size];
+#else
+    grid = (char *) _alloca((size * size) * sizeof (char));
+#endif
+
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            grid[(y * size) + x] = '0';
+        }
+    }
+
+    place_data_in_grid(word, grid, modules, size);
+    place_layer_id(grid, size, layers, modules, ecc_level);
+
+    /* Add macromodule frames */
+    for (x = 0; x < modules; x++) {
+        int dark = 1 - (x & 1);
+        for (y = 0; y < modules; y++) {
+            if (dark == 1) {
+                for (i = 0; i < 5; i++) {
+                    grid[((y * 6) * size) + (x * 6) + i] = '1';
+                    grid[(((y * 6) + 5) * size) + (x * 6) + i] = '1';
+                    grid[(((y * 6) + i) * size) + (x * 6)] = '1';
+                    grid[(((y * 6) + i) * size) + (x * 6) + 5] = '1';
+                }
+                grid[(((y * 6) + 5) * size) + (x * 6) + 5] = '1';
+                dark = 0;
+            } else {
+                dark = 1;
+            }
+        }
+    }
+
+    /* Copy values to symbol */
+    symbol->width = size;
+    symbol->rows = size;
+
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            if (grid[(y * size) + x] == '1') {
+                set_module(symbol, y, x);
+            }
+        }
+        symbol->row_height[x] = 1;
+    }
+
+    return 0;
+}
diff --git a/backend/gridmtx.h b/backend/gridmtx.h
new file mode 100644 (file)
index 0000000..f0d58c8
--- /dev/null
@@ -0,0 +1,178 @@
+/*  gridmtx.h - definitions for Grid Matrix
+
+    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 : */
+
+#define EUROPIUM       "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz "
+
+static const char shift_set[] = {
+    /* From Table 7 - Encoding of control characters */
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* NULL -> SI */
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* DLE -> US */
+    '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':',
+    ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'
+};
+
+static const unsigned short int gm_recommend_cw[] = {
+    9, 30, 59, 114, 170, 237, 315, 405, 506, 618, 741, 875, 1021
+};
+
+static const unsigned short int gm_max_cw[] = {
+    11, 40, 79, 146, 218, 305, 405, 521, 650, 794, 953, 1125, 1313
+};
+
+static const unsigned short int gm_data_codewords[] = {
+    0, 15, 13, 11, 9,
+    45, 40, 35, 30, 25,
+    89, 79, 69, 59, 49,
+    146, 130, 114, 98, 81,
+    218, 194, 170, 146, 121,
+    305, 271, 237, 203, 169,
+    405, 360, 315, 270, 225,
+    521, 463, 405, 347, 289,
+    650, 578, 506, 434, 361,
+    794, 706, 618, 530, 441,
+    953, 847, 741, 635, 529,
+    1125, 1000, 875, 750, 625,
+    1313, 1167, 1021, 875, 729
+};
+
+static const char gm_n1[] = {
+    18, 50, 98, 81, 121, 113, 113, 116, 121, 126, 118, 125, 122
+};
+
+static const char gm_b1[] = {
+    1, 1, 1, 2, 2, 2, 2, 3, 2, 7, 5, 10, 6
+};
+
+static const char gm_b2[] = {
+    0, 0, 0, 0, 0, 1, 2, 2, 4, 0, 4, 0, 6
+};
+
+/* Values from table A.1 */
+static const char gm_ebeb[] = {
+    /* E1 B3 E2 B4 */
+    0, 0, 0, 0, // version 1
+    3, 1, 0, 0,
+    5, 1, 0, 0,
+    7, 1, 0, 0,
+    9, 1, 0, 0,
+    5, 1, 0, 0, // version 2
+    10, 1, 0, 0,
+    15, 1, 0, 0,
+    20, 1, 0, 0,
+    25, 1, 0, 0,
+    9, 1, 0, 0, // version 3
+    19, 1, 0, 0,
+    29, 1, 0, 0,
+    39, 1, 0, 0,
+    49, 1, 0, 0,
+    8, 2, 0, 0, // version 4
+    16, 2, 0, 0,
+    24, 2, 0, 0,
+    32, 2, 0, 0,
+    41, 1, 40, 1,
+    12, 2, 0, 0, // version 5
+    24, 2, 0, 0,
+    36, 2, 0, 0,
+    48, 2, 0, 0,
+    61, 1, 60, 1,
+    11, 3, 0, 0, // version 6
+    23, 1, 22, 2,
+    34, 2, 33, 1,
+    45, 3, 0, 0,
+    57, 1, 56, 2,
+    12, 1, 11, 3, // version 7
+    23, 2, 22, 2,
+    34, 3, 33, 1,
+    45, 4, 0, 0,
+    57, 1, 56, 3,
+    12, 2, 11, 3, // version 8
+    23, 5, 0, 0,
+    35, 3, 34, 2,
+    47, 1, 46, 4,
+    58, 4, 57, 1,
+    12, 6, 0, 0, // version 9
+    24, 6, 0, 0,
+    36, 6, 0, 0,
+    48, 6, 0, 0,
+    61, 1, 60, 5,
+    13, 4, 12, 3, // version 10
+    26, 1, 25, 6,
+    38, 5, 37, 2,
+    51, 2, 50, 5,
+    63, 7, 0, 0,
+    12, 6, 11, 3, // version 11
+    24, 4, 23, 5,
+    36, 2, 35, 7,
+    47, 9, 0, 0,
+    59, 7, 58, 2,
+    13, 5, 12, 5, // version 12
+    25, 10, 0, 0,
+    38, 5, 37, 5,
+    50, 10, 0, 0,
+    63, 5, 62, 5,
+    13, 1, 12, 11, //version 13
+    25, 3, 24, 9,
+    37, 5, 36, 7,
+    49, 7, 48, 5,
+    61, 9, 60, 3
+};
+
+static const unsigned short int gm_macro_matrix[] = {
+    728, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650,
+    727, 624, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 651,
+    726, 623, 528, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 553, 652,
+    725, 622, 527, 440, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 463, 554, 653,
+    724, 621, 526, 439, 360, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 381, 464, 555, 654,
+    723, 620, 525, 438, 359, 288, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 307, 382, 465, 556, 655,
+    722, 619, 524, 437, 358, 287, 224, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 241, 308, 383, 466, 557, 656,
+    721, 618, 523, 436, 357, 286, 223, 168, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 183, 242, 309, 384, 467, 558, 657,
+    720, 617, 522, 435, 356, 285, 222, 167, 120, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 133, 184, 243, 310, 385, 468, 559, 658,
+    719, 616, 521, 434, 355, 284, 221, 166, 119, 80, 49, 50, 51, 52, 53, 54, 55, 56, 91, 134, 185, 244, 311, 386, 469, 560, 659,
+    718, 615, 520, 433, 354, 283, 220, 165, 118, 79, 48, 25, 26, 27, 28, 29, 30, 57, 92, 135, 186, 245, 312, 387, 470, 561, 660,
+    717, 614, 519, 432, 353, 282, 219, 164, 117, 78, 47, 24, 9, 10, 11, 12, 31, 58, 93, 136, 187, 246, 313, 388, 471, 562, 661,
+    716, 613, 518, 431, 352, 281, 218, 163, 116, 77, 46, 23, 8, 1, 2, 13, 32, 59, 94, 137, 188, 247, 314, 389, 472, 563, 662,
+    715, 612, 517, 430, 351, 280, 217, 162, 115, 76, 45, 22, 7, 0, 3, 14, 33, 60, 95, 138, 189, 248, 315, 390, 473, 564, 663,
+    714, 611, 516, 429, 350, 279, 216, 161, 114, 75, 44, 21, 6, 5, 4, 15, 34, 61, 96, 139, 190, 249, 316, 391, 474, 565, 664,
+    713, 610, 515, 428, 349, 278, 215, 160, 113, 74, 43, 20, 19, 18, 17, 16, 35, 62, 97, 140, 191, 250, 317, 392, 475, 566, 665,
+    712, 609, 514, 427, 348, 277, 214, 159, 112, 73, 42, 41, 40, 39, 38, 37, 36, 63, 98, 141, 192, 251, 318, 393, 476, 567, 666,
+    711, 608, 513, 426, 347, 276, 213, 158, 111, 72, 71, 70, 69, 68, 67, 66, 65, 64, 99, 142, 193, 252, 319, 394, 477, 568, 667,
+    710, 607, 512, 425, 346, 275, 212, 157, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 143, 194, 253, 320, 395, 478, 569, 668,
+    709, 606, 511, 424, 345, 274, 211, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 195, 254, 321, 396, 479, 570, 669,
+    708, 605, 510, 423, 344, 273, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 255, 322, 397, 480, 571, 670,
+    707, 604, 509, 422, 343, 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, 259, 258, 257, 256, 323, 398, 481, 572, 671,
+    706, 603, 508, 421, 342, 341, 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, 324, 399, 482, 573, 672,
+    705, 602, 507, 420, 419, 418, 417, 416, 415, 414, 413, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 483, 574, 673,
+    704, 601, 506, 505, 504, 503, 502, 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, 489, 488, 487, 486, 485, 484, 575, 674,
+    703, 600, 599, 598, 597, 596, 595, 594, 593, 592, 591, 590, 589, 588, 587, 586, 585, 584, 583, 582, 581, 580, 579, 578, 577, 576, 675,
+    702, 701, 700, 699, 698, 697, 696, 695, 694, 693, 692, 691, 690, 689, 688, 687, 686, 685, 684, 683, 682, 681, 680, 679, 678, 677, 676,
+};
+
index dbad2ca..39791f8 100644 (file)
@@ -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
     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 <stdlib.h>
 #include <stdio.h>
 #ifdef _MSC_VER
-#include <malloc.h> 
+#include <malloc.h>
 #endif
 #include "common.h"
 #include "gs1.h"
    to be bulletproof, nor does it report very accurately what problem was found
    or where, but should prevent some of the more common encoding errors */
 
-void itostr(char ai_string[], int ai_value)
-{
-       int thou, hund, ten, unit;
-       char temp[2];
-       
-       strcpy(ai_string, "(");
-       thou = ai_value / 1000;
-       hund = (ai_value - (1000 * thou)) / 100;
-       ten = (ai_value - ((1000 * thou) + (100 * hund))) / 10;
-       unit = ai_value - ((1000 * thou) + (100 * hund) + (10 * ten));
-       
-       temp[1] = '\0';
-       if(ai_value >= 1000) { temp[0] = itoc(thou); concat(ai_string, temp); }
-       if(ai_value >= 100) { temp[0] = itoc(hund); concat(ai_string, temp); }
-       temp[0] = itoc(ten);
-       concat(ai_string, temp);
-       temp[0] = itoc(unit);
-       concat(ai_string, temp);
-       concat(ai_string, ")");
-}
+static void itostr(char ai_string[], int ai_value) {
+    int thou, hund, ten, unit;
+    char temp[2];
 
-int gs1_verify(struct zint_symbol *symbol, unsigned char source[], const unsigned int src_len, char reduced[])
-{
-       int i, j, last_ai, ai_latch;
-       char ai_string[6];
-       int bracket_level, max_bracket_level, ai_length, max_ai_length, min_ai_length;
-       int ai_value[100], ai_location[100], ai_count, data_location[100], data_length[100];
-       int error_latch;
-       
-       /* Detect extended ASCII characters */
-       for(i = 0; i < src_len; i++) {
-               if(source[i] >=128) {
-                       strcpy(symbol->errtxt, "Extended ASCII characters are not supported by GS1");
-                       return ERROR_INVALID_DATA;
-               }
-               if(source[i] < 32) {
-                       strcpy(symbol->errtxt, "Control characters are not supported by GS1");
-                       return ERROR_INVALID_DATA;
-               }
-       }
-       
-       if(source[0] != '[') {
-               strcpy(symbol->errtxt, "Data does not start with an AI");
-               return ERROR_INVALID_DATA;
-       }
-       
-       /* Check the position of the brackets */
-       bracket_level = 0;
-       max_bracket_level = 0;
-       ai_length = 0;
-       max_ai_length = 0;
-       min_ai_length = 5;
-       j = 0;
-       ai_latch = 0;
-       for(i = 0; i < src_len; i++) {
-               ai_length += j;
-               if(((j == 1) && (source[i] != ']')) && ((source[i] < '0') || (source[i] > '9'))) { ai_latch = 1; }
-               if(source[i] == '[') { bracket_level++; j = 1; }
-               if(source[i] == ']') {
-                       bracket_level--;
-                       if(ai_length < min_ai_length) { min_ai_length = ai_length; }
-                       j = 0;
-                       ai_length = 0; 
-               }
-               if(bracket_level > max_bracket_level) { max_bracket_level = bracket_level; }
-               if(ai_length > max_ai_length) { max_ai_length = ai_length; }
-       }
-       min_ai_length--;
-       
-       if(bracket_level != 0) {
-               /* Not all brackets are closed */
-               strcpy(symbol->errtxt, "Malformed AI in input data (brackets don\'t match)");
-               return ERROR_INVALID_DATA;
-       }
-       
-       if(max_bracket_level > 1) {
-               /* Nested brackets */
-               strcpy(symbol->errtxt, "Found nested brackets in input data");
-               return ERROR_INVALID_DATA;
-       }
-       
-       if(max_ai_length > 4) {
-               /* AI is too long */
-               strcpy(symbol->errtxt, "Invalid AI in input data (AI too long)");
-               return ERROR_INVALID_DATA;
-       }
-       
-       if(min_ai_length <= 1) {
-               /* AI is too short */
-               strcpy(symbol->errtxt, "Invalid AI in input data (AI too short)");
-               return ERROR_INVALID_DATA;
-       }
-       
-       if(ai_latch == 1) {
-               /* Non-numeric data in AI */
-               strcpy(symbol->errtxt, "Invalid AI in input data (non-numeric characters in AI)");
-               return ERROR_INVALID_DATA;
-       }
-       
-       ai_count = 0;
-       for(i = 1; i < src_len; i++) {
-               if(source[i - 1] == '[') {
-                       ai_location[ai_count] = i;
-                       j = 0;
-                       do {
-                               ai_string[j] = source[i + j];
-                               j++;
-                       } while (ai_string[j - 1] != ']');
-                       ai_string[j - 1] = '\0';
-                       ai_value[ai_count] = atoi(ai_string);
-                       ai_count++;
-               }
-       }
-       
-       for(i = 0; i < ai_count; i++) {
-               data_location[i] = ai_location[i] + 3;
-               if(ai_value[i] >= 100) { data_location[i]++; }
-               if(ai_value[i] >= 1000) { data_location[i]++; }
-               data_length[i] = 0;
-               do {
-                       data_length[i]++;
-               } while ((source[data_location[i] + data_length[i] - 1] != '[') && (source[data_location[i] + data_length[i] - 1] != '\0'));
-               data_length[i]--;
-       }
-       
-       for(i = 0; i < ai_count; i++) {
-               if(data_length[i] == 0) {
-                       /* No data for given AI */
-                       strcpy(symbol->errtxt, "Empty data field in input data");
-                       return ERROR_INVALID_DATA;
-               }
-       }
-       
-       error_latch = 0;
-       strcpy(ai_string, "");
-       for(i = 0; i < ai_count; i++) {
-               switch (ai_value[i]) {
-                       case 0: if(data_length[i] != 18) { error_latch = 1; } break;
-                       case 1:
-                       case 2:
-                       case 3: if(data_length[i] != 14) { error_latch = 1; } break;
-                       case 4: if(data_length[i] != 16) { error_latch = 1; } break;
-                       case 11:
-                       case 12:
-                       case 13:
-                       case 14:
-                       case 15:
-                       case 16:
-                       case 17:
-                       case 18:
-                       case 19: if(data_length[i] != 6) { error_latch = 1; } break;
-                       case 20: if(data_length[i] != 2) { error_latch = 1; } break;
-                       case 23:
-                       case 24:
-                       case 25:
-                       case 39:
-                       case 40:
-                       case 41:
-                       case 42:
-                       case 70:
-                       case 80:
-                       case 81: error_latch = 2; break;
-               }
-               if(
-                       ((ai_value[i] >= 100) && (ai_value[i] <= 179))
-                       || ((ai_value[i] >= 1000) && (ai_value[i] <= 1799))
-                       || ((ai_value[i] >= 200) && (ai_value[i] <= 229))
-                       || ((ai_value[i] >= 2000) && (ai_value[i] <= 2299))
-                       || ((ai_value[i] >= 300) && (ai_value[i] <= 309))
-                       || ((ai_value[i] >= 3000) && (ai_value[i] <= 3099))
-                       || ((ai_value[i] >= 31) && (ai_value[i] <= 36))
-                       || ((ai_value[i] >= 310) && (ai_value[i] <= 369))
-               ) {
-                       error_latch = 2;
-               }
-               if((ai_value[i] >= 3100) && (ai_value[i] <= 3699)) {
-                       if(data_length[i] != 6) {
-                               error_latch = 1;
-                       }
-               }
-               if(
-                       ((ai_value[i] >= 370) && (ai_value[i] <= 379))
-                       || ((ai_value[i] >= 3700) && (ai_value[i] <= 3799))
-               ) { 
-                       error_latch = 2; 
-               }
-               if((ai_value[i] >= 410) && (ai_value[i] <= 415)) {
-                       if(data_length[i] != 13) { 
-                               error_latch = 1; 
-                       } 
-               }
-               if(
-                       ((ai_value[i] >= 4100) && (ai_value[i] <= 4199))
-                       || ((ai_value[i] >= 700) && (ai_value[i] <= 703))
-                       || ((ai_value[i] >= 800) && (ai_value[i] <= 810))
-                       || ((ai_value[i] >= 900) && (ai_value[i] <= 999))
-                       || ((ai_value[i] >= 9000) && (ai_value[i] <= 9999))
-               ) {
-                       error_latch = 2; 
-               }
-               if((error_latch < 4) && (error_latch > 0)) {
-                       /* error has just been detected: capture AI */
-                       itostr(ai_string, ai_value[i]);
-                       error_latch += 4;
-               }
-       }
-       
-       if(error_latch == 5) {
-               strcpy(symbol->errtxt, "Invalid data length for AI ");
-               concat(symbol->errtxt, ai_string);
-               return ERROR_INVALID_DATA;
-       }
-       
-       if(error_latch == 6) {
-               strcpy(symbol->errtxt, "Invalid AI value ");
-               concat(symbol->errtxt, ai_string);
-               return ERROR_INVALID_DATA;
-       }
+    strcpy(ai_string, "(");
+    thou = ai_value / 1000;
+    hund = (ai_value - (1000 * thou)) / 100;
+    ten = (ai_value - ((1000 * thou) + (100 * hund))) / 10;
+    unit = ai_value - ((1000 * thou) + (100 * hund) + (10 * ten));
 
-       /* Resolve AI data - put resulting string in 'reduced' */
-       j = 0;
-       last_ai = 0;
-       ai_latch = 1;
-       for(i = 0; i < src_len; i++) {
-               if((source[i] != '[') && (source[i] != ']')) {
-                       reduced[j++] = source[i];
-               }
-               if(source[i] == '[') {
-                       /* Start of an AI string */
-                       if(ai_latch == 0) {
-                               reduced[j++] = '[';
-                       }
-                       ai_string[0] = source[i + 1];
-                       ai_string[1] = source[i + 2];
-                       ai_string[2] = '\0';
-                       last_ai = atoi(ai_string);
-                       ai_latch = 0;
-                       /* The following values from "GS-1 General Specification version 8.0 issue 2, May 2008"
-                       figure 5.4.8.2.1 - 1 "Element Strings with Pre-Defined Length Using Application Identifiers" */
-                       if(
-                               ((last_ai >= 0) && (last_ai <= 4))
-                               || ((last_ai >= 11) && (last_ai <= 20))
-                               || (last_ai == 23) /* legacy support - see 5.3.8.2.2 */
-                               || ((last_ai >= 31) && (last_ai <= 36))
-                               || (last_ai == 41)
-                       ) {
-                               ai_latch = 1; 
-                       }
-               }
-               /* The ']' character is simply dropped from the input */
-       }
-       reduced[j] = '\0';
-       
-       /* the character '[' in the reduced string refers to the FNC1 character */
-       return 0;
+    temp[1] = '\0';
+    if (ai_value >= 1000) {
+        temp[0] = itoc(thou);
+        strcat(ai_string, temp);
+    }
+    if (ai_value >= 100) {
+        temp[0] = itoc(hund);
+        strcat(ai_string, temp);
+    }
+    temp[0] = itoc(ten);
+    strcat(ai_string, temp);
+    temp[0] = itoc(unit);
+    strcat(ai_string, temp);
+    strcat(ai_string, ")");
 }
 
-int ugs1_verify(struct zint_symbol *symbol, unsigned char source[], const unsigned int src_len, unsigned char reduced[])
-{
-       /* Only to keep the compiler happy */
+INTERNAL int gs1_verify(struct zint_symbol *symbol, const unsigned char source[], const size_t src_len, char reduced[]) {
+    int i, j, last_ai, ai_latch;
+    char ai_string[7]; /* 6 char max "(NNNN)" */
+    int bracket_level, max_bracket_level, ai_length, max_ai_length, min_ai_length;
+    int ai_count;
+    int error_latch;
+#ifdef _MSC_VER
+    int *ai_value;
+    int *ai_location;
+    int *data_location;
+    int *data_length;
+#endif
+    int ai_max = ustrchr_cnt(source, src_len, '[') + 1; /* Plus 1 so non-zero */
 #ifndef _MSC_VER
-       char temp[src_len + 5];
+    int ai_value[ai_max], ai_location[ai_max], data_location[ai_max], data_length[ai_max];
 #else
-        char* temp = (char*)_alloca(src_len + 5);
+    ai_value = (int*) _alloca(ai_max * sizeof(int));
+    ai_location = (int*) _alloca(ai_max * sizeof(int));
+    data_location = (int*) _alloca(ai_max * sizeof(int));
+    data_length = (int*) _alloca(ai_max * sizeof(int));
 #endif
-       int error_number;
-       
-       error_number = gs1_verify(symbol, source, src_len, temp);
-       if(error_number != 0) { return error_number; }
-       
-       if (strlen(temp) < src_len + 5) {
-               ustrcpy(reduced, (unsigned char*)temp);
-               return 0;
-       }
-       strcpy(symbol->errtxt, "ugs1_verify overflow");
-       return ERROR_INVALID_DATA;
+
+    /* Detect extended ASCII characters */
+    for (i = 0; i < (int) src_len; i++) {
+        if (source[i] >= 128) {
+            strcpy(symbol->errtxt, "250: Extended ASCII characters are not supported by GS1");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+        if (source[i] == '\0') {
+            strcpy(symbol->errtxt, "262: NUL characters not permitted in GS1 mode");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+        if (source[i] < 32) {
+            strcpy(symbol->errtxt, "251: Control characters are not supported by GS1");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+        if (source[i] == 127) {
+            strcpy(symbol->errtxt, "263: DEL characters are not supported by GS1");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+    }
+
+    if (source[0] != '[') {
+        strcpy(symbol->errtxt, "252: Data does not start with an AI");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    /* Check the position of the brackets */
+    bracket_level = 0;
+    max_bracket_level = 0;
+    ai_length = 0;
+    max_ai_length = 0;
+    min_ai_length = 5;
+    j = 0;
+    ai_latch = 0;
+    for (i = 0; i < (int) src_len; i++) {
+        ai_length += j;
+        if (((j == 1) && (source[i] != ']')) && ((source[i] < '0') || (source[i] > '9'))) {
+            ai_latch = 1;
+        }
+        if (source[i] == '[') {
+            bracket_level++;
+            j = 1;
+        }
+        if (source[i] == ']') {
+            bracket_level--;
+            if (ai_length < min_ai_length) {
+                min_ai_length = ai_length;
+            }
+            j = 0;
+            ai_length = 0;
+        }
+        if (bracket_level > max_bracket_level) {
+            max_bracket_level = bracket_level;
+        }
+        if (ai_length > max_ai_length) {
+            max_ai_length = ai_length;
+        }
+    }
+    min_ai_length--;
+
+    if (bracket_level != 0) {
+        /* Not all brackets are closed */
+        strcpy(symbol->errtxt, "253: Malformed AI in input data (brackets don\'t match)");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    if (max_bracket_level > 1) {
+        /* Nested brackets */
+        strcpy(symbol->errtxt, "254: Found nested brackets in input data");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    if (max_ai_length > 4) {
+        /* AI is too long */
+        strcpy(symbol->errtxt, "255: Invalid AI in input data (AI too long)");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    if (min_ai_length <= 1) {
+        /* AI is too short */
+        strcpy(symbol->errtxt, "256: Invalid AI in input data (AI too short)");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    if (ai_latch == 1) {
+        /* Non-numeric data in AI */
+        strcpy(symbol->errtxt, "257: Invalid AI in input data (non-numeric characters in AI)");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    ai_count = 0;
+    for (i = 1; i < (int) src_len; i++) {
+        if (source[i - 1] == '[') {
+            ai_location[ai_count] = i;
+            j = 0;
+            do {
+                ai_string[j] = source[i + j];
+                j++;
+            } while (ai_string[j - 1] != ']');
+            ai_string[j - 1] = '\0';
+            ai_value[ai_count] = atoi(ai_string);
+            ai_count++;
+        }
+    }
+
+    for (i = 0; i < ai_count; i++) {
+        data_location[i] = ai_location[i] + 3;
+        if (ai_value[i] >= 100) {
+            data_location[i]++;
+        }
+        if (ai_value[i] >= 1000) {
+            data_location[i]++;
+        }
+        data_length[i] = 0;
+        do {
+            data_length[i]++;
+        } while ((source[data_location[i] + data_length[i] - 1] != '[') && (data_location[i] + data_length[i] <= (int) src_len));
+        data_length[i]--;
+    }
+
+    for (i = 0; i < ai_count; i++) {
+        if (data_length[i] == 0) {
+            /* No data for given AI */
+            strcpy(symbol->errtxt, "258: Empty data field in input data");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+    }
+    
+    strcpy(ai_string, "");
+    
+    // Check for valid AI values and data lengths according to GS1 General
+    // Specification Release 19, January 2019
+    for (i = 0; i < ai_count; i++) {
+        
+        error_latch = 2;
+        switch (ai_value[i]) {
+            // Length 2 Fixed
+            case 20: // VARIANT
+                if (data_length[i] != 2) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 3 Fixed
+            case 422: // ORIGIN
+            case 424: // COUNTRY PROCESS
+            case 426: // COUNTRY FULL PROCESS
+                if (data_length[i] != 3) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 4 Fixed
+            case 7040: // UIC+EXT
+            case 8111: // POINTS
+                if (data_length[i] != 4) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 6 Fixed
+            case 11: // PROD DATE
+            case 12: // DUE DATE
+            case 13: // PACK DATE
+            case 15: // BEST BY
+            case 16: // SELL BY
+            case 17: // USE BY
+            case 7006: // FIRST FREEZE DATE
+            case 8005: // PRICE PER UNIT
+                if (data_length[i] != 6) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 10 Fixed
+            case 7003: // EXPIRY TIME
+                if (data_length[i] != 10) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 13 Fixed
+            case 410: // SHIP TO LOC
+            case 411: // BILL TO
+            case 412: // PURCHASE FROM
+            case 413: // SHIP FOR LOC
+            case 414: // LOC NO
+            case 415: // PAY TO
+            case 416: // PROD/SERV LOC
+            case 417: // PARTY GLN
+            case 7001: // NSN
+                if (data_length[i] != 13) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 14 Fixed
+            case 1: // GTIN
+            case 2: // CONTENT
+            case 8001: // DIMENSIONS
+                if (data_length[i] != 14) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 17 Fixed
+            case 402: // GSIN
+                if (data_length[i] != 17) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 18 Fixed
+            case 0: // SSCC
+            case 8006: // ITIP
+            case 8017: // GSRN PROVIDER
+            case 8018: // GSRN RECIPIENT
+            case 8026: // ITIP CONTENT
+                if (data_length[i] != 18) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 2 Max
+            case 7010: // PROD METHOD
+                if (data_length[i] > 2) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 3 Max
+            case 427: // ORIGIN SUBDIVISION
+            case 7008: // AQUATIC SPECIES
+                if (data_length[i] > 3) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 4 Max
+            case 7004: // ACTIVE POTENCY
+                if (data_length[i] > 4) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 6 Max
+            case 242: // MTO VARIANT
+                if (data_length[i] > 6) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 8 Max
+            case 30: // VAR COUNT
+            case 37: // COUNT
+                if (data_length[i] > 8) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 10 Max
+            case 7009: // FISHING GEAR TYPE
+            case 8019: // SRIN
+                if (data_length[i] > 10) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 12 Max
+            case 7005: // CATCH AREA
+            case 8011: // CPID SERIAL
+                if (data_length[i] > 12) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 20 Max
+            case 10: // BATCH/LOT
+            case 21: // SERIAL
+            case 22: // CPV
+            case 243: // PCN
+            case 254: // GLN EXTENSION COMPONENT
+            case 420: // SHIP TO POST
+            case 7020: // REFURB LOT
+            case 7021: // FUNC STAT
+            case 7022: // REV STAT
+            case 710: // NHRN PZN
+            case 711: // NHRN CIP
+            case 712: // NHRN CN
+            case 713: // NHRN DRN
+            case 714: // NHRN AIM
+            case 7240: // PROTOCOL
+            case 8002: // CMT NO
+            case 8012: // VERSION
+                if (data_length[i] > 20) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 25 Max
+            case 8020: // REF NO
+                if (data_length[i] > 25) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 28 Max
+            case 235: // TPX
+                if (data_length[i] > 28) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+
+            // Length 30 Max
+            case 240: // ADDITIONAL ID
+            case 241: // CUST PART NO
+            case 250: // SECONDARY SERIAL
+            case 251: // REF TO SOURCE
+            case 400: // ORDER NUMBER
+            case 401: // GINC
+            case 403: // ROUTE
+            case 7002: // MEAT CUT
+            case 7023: // GIAI ASSEMBLY
+            case 8004: // GIAI
+            case 8010: // CPID
+            case 8013: // BUDI-DI
+            case 90: // INTERNAL
+                if (data_length[i] > 30) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 34 Max
+            case 8007: // IBAN
+                if (data_length[i] > 34) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 50 Max
+            case 8009: // OPTSEN
+                if (data_length[i] > 50) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+            // Length 70 Max
+            case 8110: // Coupon code
+            case 8112: // Paperless coupon code
+            case 8200: // PRODUCT URL
+                if (data_length[i] > 70) {
+                    error_latch = 1;
+                } else {
+                    error_latch = 0;
+                }
+                break;
+                
+        }
+        
+        if (ai_value[i] == 253) { // GDTI
+            if ((data_length[i] < 13) || (data_length[i] > 30)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if (ai_value[i] == 255) { // GCN
+            if ((data_length[i] < 13) || (data_length[i] > 25)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 3100) && (ai_value[i] <= 3169)) {
+            if (data_length[i] != 6) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 3200) && (ai_value[i] <= 3379)) {
+            if (data_length[i] != 6) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 3400) && (ai_value[i] <= 3579)) {
+            if (data_length[i] != 6) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 3600) && (ai_value[i] <= 3699)) {
+            if (data_length[i] != 6) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 3900) && (ai_value[i] <= 3909)) { // AMOUNT
+            if (data_length[i] > 15) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 3910) && (ai_value[i] <= 3919)) { // AMOUNT
+            if ((data_length[i] < 4) || (data_length[i] > 18)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 3920) && (ai_value[i] <= 3929)) { // PRICE
+            if (data_length[i] > 15) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 3930) && (ai_value[i] <= 3939)) { // PRICE
+            if ((data_length[i] < 4) || (data_length[i] > 18)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 3940) && (ai_value[i] <= 3949)) { // PRCNT OFF
+            if (data_length[i] != 4) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if (ai_value[i] == 421) { // SHIP TO POST
+            if ((data_length[i] < 4) || (data_length[i] > 12)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] == 423) || (ai_value[i] == 425)) {
+            // COUNTRY INITIAL PROCESS || COUNTRY DISASSEMBLY
+            if ((data_length[i] < 4) || (data_length[i] > 15)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if (ai_value[i] == 7007) { // HARVEST DATE
+            if ((data_length[i] != 6) && (data_length[i] != 12)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 7030) && (ai_value[i] <= 7039)) { // PROCESSOR #
+            if ((data_length[i] < 4) || (data_length[i] > 30)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 7230) && (ai_value[i] <= 7239)) { // CERT #
+            if ((data_length[i] < 3) || (data_length[i] > 30)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if (ai_value[i] == 8003) { // GRAI
+            if ((data_length[i] < 15) || (data_length[i] > 30)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if (ai_value[i] == 8008) { // PROD TIME
+            if ((data_length[i] != 8) && (data_length[i] != 10) && (data_length[i] != 12)) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+        
+        if ((ai_value[i] >= 91) && (ai_value[i] <= 99)) { // INTERNAL
+            if (data_length[i] > 90) {
+                error_latch = 1;
+            } else {
+                error_latch = 0;
+            }
+        }
+
+        if (error_latch == 1) {
+            itostr(ai_string, ai_value[i]);
+            strcpy(symbol->errtxt, "259: Invalid data length for AI ");
+            strcat(symbol->errtxt, ai_string);
+            return ZINT_ERROR_INVALID_DATA;
+        }
+
+        if (error_latch == 2) {
+            itostr(ai_string, ai_value[i]);
+            strcpy(symbol->errtxt, "260: Invalid AI value ");
+            strcat(symbol->errtxt, ai_string);
+            return ZINT_ERROR_INVALID_DATA;
+        }
+    }
+
+    /* Resolve AI data - put resulting string in 'reduced' */
+    j = 0;
+    last_ai = 0;
+    ai_latch = 1;
+    for (i = 0; i < (int) src_len; i++) {
+        if ((source[i] != '[') && (source[i] != ']')) {
+            reduced[j++] = source[i];
+        }
+        if (source[i] == '[') {
+            /* Start of an AI string */
+            if (ai_latch == 0) {
+                reduced[j++] = '[';
+            }
+            ai_string[0] = source[i + 1];
+            ai_string[1] = source[i + 2];
+            ai_string[2] = '\0';
+            last_ai = atoi(ai_string);
+            ai_latch = 0;
+            /* The following values from "GS-1 General Specification version 8.0 issue 2, May 2008"
+            figure 5.4.8.2.1 - 1 "Element Strings with Pre-Defined Length Using Application Identifiers" */
+            if (
+                    ((last_ai >= 0) && (last_ai <= 4))
+                    || ((last_ai >= 11) && (last_ai <= 20))
+                    || (last_ai == 23) /* legacy support - see 5.3.8.2.2 */
+                    || ((last_ai >= 31) && (last_ai <= 36))
+                    || (last_ai == 41)
+                    ) {
+                ai_latch = 1;
+            }
+        }
+        /* The ']' character is simply dropped from the input */
+    }
+    reduced[j] = '\0';
+
+    /* the character '[' in the reduced string refers to the FNC1 character */
+    return 0;
 }
index 8b345a2..228af50 100644 (file)
@@ -2,7 +2,7 @@
 
 /*
     libzint - the open source barcode library
-    Copyright (C) 2009 Robin Stuart <robin@zint.org.uk>
+    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
@@ -28,7 +28,8 @@
     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     SUCH DAMAGE.
-*/
+ */
+/* vim: set ts=4 sw=4 et : */
 #ifndef __GS1_H
 #define __GS1_H
 
 extern "C" {
 #endif /* __cplusplus */
 
-extern int gs1_verify(struct zint_symbol *symbol, unsigned char source[], const unsigned int src_len, char reduced[]);
-extern int ugs1_verify(struct zint_symbol *symbol, unsigned char source[], const unsigned int src_len, unsigned char reduced[]);
+    extern int gs1_verify(struct zint_symbol *symbol, const unsigned char source[], const size_t src_len, char reduced[]);
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 
-#endif /* __GS1_H */
\ No newline at end of file
+#endif /* __GS1_H */
diff --git a/backend/hanxin.c b/backend/hanxin.c
new file mode 100644 (file)
index 0000000..15dff6b
--- /dev/null
@@ -0,0 +1,1665 @@
+/*  hanxin.c - Han Xin Code
+
+    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 : */
+
+/* This code attempts to implement Han Xin Code according to ISO/IEC 20830 (draft 2019-10-10) (previously AIMD-015:2010 (Rev 0.8)) */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "reedsol.h"
+#include "hanxin.h"
+#include "gb2312.h"
+#include "gb18030.h"
+#include "assert.h"
+
+/* Find which submode to use for a text character */
+static int getsubmode(unsigned int input) {
+    int submode = 2;
+
+    if ((input >= '0') && (input <= '9')) {
+        submode = 1;
+    }
+
+    if ((input >= 'A') && (input <= 'Z')) {
+        submode = 1;
+    }
+
+    if ((input >= 'a') && (input <= 'z')) {
+        submode = 1;
+    }
+
+    return submode;
+}
+
+/* Return length of terminator for encoding mode */
+static int terminator_length(char mode) {
+    int result = 0;
+
+    switch (mode) {
+        case 'n':
+            result = 10;
+            break;
+        case 't':
+            result = 6;
+            break;
+        case '1':
+        case '2':
+            result = 12;
+            break;
+        case 'd':
+            result = 15;
+            break;
+    }
+
+    return result;
+}
+
+/* Calculate the length of the binary string */
+static int calculate_binlength(char mode[], unsigned int source[], const size_t length, int eci) {
+    size_t i;
+    char lastmode = '\0';
+    int est_binlen = 0;
+    int submode = 1;
+    int numeric_run = 0;
+
+    if (eci != 0) {
+        est_binlen += 4;
+        if (eci <= 127) {
+            est_binlen += 8;
+        } else if ((eci >= 128) && (eci <= 16383)) {
+            est_binlen += 16;
+        } else {
+            est_binlen += 24;
+        }
+    }
+
+    i = 0;
+    do {
+        if (mode[i] != lastmode) {
+            if (i > 0) {
+                est_binlen += terminator_length(lastmode);
+            }
+            /* GB 4-byte has indicator for each character (and no terminator) so not included here */
+            /* Region1/Region2 have special terminator to go directly into each other's mode so not included here */
+            if (mode[i] != 'f' || ((mode[i] == '1' && lastmode == '2') || (mode[i] == '2' && lastmode == '1'))) {
+                est_binlen += 4;
+            }
+            if (mode[i] == 'b') { /* Byte mode has byte count (and no terminator) */
+                est_binlen += 13;
+            }
+            lastmode = mode[i];
+            submode = 1;
+            numeric_run = 0;
+        }
+        switch (mode[i]) {
+            case 'n':
+                if (numeric_run % 3 == 0) {
+                    est_binlen += 10;
+                }
+                numeric_run++;
+                break;
+            case 't':
+                if (getsubmode(source[i]) != submode) {
+                    est_binlen += 6;
+                    submode = getsubmode(source[i]);
+                }
+                est_binlen += 6;
+                break;
+            case 'b':
+                est_binlen += source[i] > 0xFF ? 16 : 8;
+                break;
+            case '1':
+            case '2':
+                est_binlen += 12;
+                break;
+            case 'd':
+                est_binlen += 15;
+                break;
+            case 'f':
+                est_binlen += 25;
+                i++;
+                break;
+        }
+        i++;
+    } while (i < length);
+
+    est_binlen += terminator_length(lastmode);
+
+    return est_binlen;
+}
+
+static int isRegion1(unsigned int glyph) {
+    int first_byte, second_byte;
+    int valid = 0;
+
+    first_byte = (glyph & 0xff00) >> 8;
+    second_byte = glyph & 0xff;
+
+    if ((first_byte >= 0xb0) && (first_byte <= 0xd7)) {
+        if ((second_byte >= 0xa1) && (second_byte <= 0xfe)) {
+            valid = 1;
+        }
+    }
+
+    if ((first_byte >= 0xa1) && (first_byte <= 0xa3)) {
+        if ((second_byte >= 0xa1) && (second_byte <= 0xfe)) {
+            valid = 1;
+        }
+    }
+
+    if ((glyph >= 0xa8a1) && (glyph <= 0xa8c0)) {
+        valid = 1;
+    }
+
+    return valid;
+}
+
+static int isRegion2(unsigned int glyph) {
+    int first_byte, second_byte;
+    int valid = 0;
+
+    first_byte = (glyph & 0xff00) >> 8;
+    second_byte = glyph & 0xff;
+
+    if ((first_byte >= 0xd8) && (first_byte <= 0xf7)) {
+        if ((second_byte >= 0xa1) && (second_byte <= 0xfe)) {
+            valid = 1;
+        }
+    }
+
+    return valid;
+}
+
+static int isDoubleByte(unsigned int glyph) {
+    int first_byte, second_byte;
+    int valid = 0;
+
+    first_byte = (glyph & 0xff00) >> 8;
+    second_byte = glyph & 0xff;
+
+    if ((first_byte >= 0x81) && (first_byte <= 0xfe)) {
+        if ((second_byte >= 0x40) && (second_byte <= 0x7e)) {
+            valid = 1;
+        }
+
+        if ((second_byte >= 0x80) && (second_byte <= 0xfe)) {
+            valid = 1;
+        }
+    }
+
+    return valid;
+}
+
+static int isFourByte(unsigned int glyph, unsigned int glyph2) {
+    int first_byte, second_byte;
+    int third_byte, fourth_byte;
+    int valid = 0;
+
+    first_byte = (glyph & 0xff00) >> 8;
+    second_byte = glyph & 0xff;
+    third_byte = (glyph2 & 0xff00) >> 8;
+    fourth_byte = glyph2 & 0xff;
+
+    if ((first_byte >= 0x81) && (first_byte <= 0xfe)) {
+        if ((second_byte >= 0x30) && (second_byte <= 0x39)) {
+            if ((third_byte >= 0x81) && (third_byte <= 0xfe)) {
+                if ((fourth_byte >= 0x30) && (fourth_byte <= 0x39)) {
+                    valid = 1;
+                }
+            }
+        }
+    }
+
+    return valid;
+}
+
+/* Convert Text 1 sub-mode character to encoding value, as given in table 3 */
+static int lookup_text1(unsigned int input) {
+    int encoding_value = -1;
+
+    if ((input >= '0') && (input <= '9')) {
+        encoding_value = input - '0';
+    }
+
+    if ((input >= 'A') && (input <= 'Z')) {
+        encoding_value = input - 'A' + 10;
+    }
+
+    if ((input >= 'a') && (input <= 'z')) {
+        encoding_value = input - 'a' + 36;
+    }
+
+    return encoding_value;
+}
+
+/* Convert Text 2 sub-mode character to encoding value, as given in table 4 */
+static int lookup_text2(unsigned int input) {
+    int encoding_value = -1;
+
+    if (input <= 27) {
+        encoding_value = input;
+    }
+
+    if ((input >= ' ') && (input <= '/')) {
+        encoding_value = input - ' ' + 28;
+    }
+
+    if ((input >= ':') && (input <= '@')) {
+        encoding_value = input - ':' + 44;
+    }
+
+    if ((input >= '[') && (input <= 96)) {
+        encoding_value = input - '[' + 51;
+    }
+
+    if ((input >= '{') && (input <= 127)) {
+        encoding_value = input - '{' + 57;
+    }
+
+    return encoding_value;
+}
+
+/* hx_define_mode() stuff */
+
+/* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */
+#define HX_MULT 6
+
+/* Whether in numeric or not. If in numeric, *p_end is set to position after numeric, and *p_cost is set to per-numeric cost */
+static int in_numeric(const unsigned int gbdata[], const size_t length, const unsigned int posn, unsigned int* p_end, unsigned int* p_cost) {
+    unsigned int i, digit_cnt;
+
+    if (posn < *p_end) {
+        return 1;
+    }
+
+    /* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times HX_MULT) */
+    for (i = posn; i < length && i < posn + 4 && gbdata[i] >= '0' && gbdata[i] <= '9'; i++);
+
+    digit_cnt = i - posn;
+
+    if (digit_cnt == 0) {
+        *p_end = 0;
+        return 0;
+    }
+    *p_end = i;
+    *p_cost = digit_cnt == 1 ? 60 /* 10 * HX_MULT */ : digit_cnt == 2 ? 30 /* (10 / 2) * HX_MULT */ : 20 /* (10 / 3) * HX_MULT */;
+    return 1;
+}
+
+/* Whether in four-byte or not. If in four-byte, *p_fourbyte is set to position after four-byte, and *p_fourbyte_cost is set to per-position cost */
+static int in_fourbyte(const unsigned int gbdata[], const size_t length, const unsigned int posn, unsigned int* p_end, unsigned int* p_cost) {
+    if (posn < *p_end) {
+        return 1;
+    }
+
+    if (posn == length - 1 || !isFourByte(gbdata[posn], gbdata[posn + 1])) {
+        *p_end = 0;
+        return 0;
+    }
+    *p_end = posn + 2;
+    *p_cost = 75; /* ((4 + 21) / 2) * HX_MULT */
+    return 1;
+}
+
+/* Indexes into mode_types array */
+#define HX_N   0 /* Numeric */
+#define HX_T   1 /* Text */
+#define HX_B   2 /* Binary */
+#define HX_1   3 /* Common Chinese Region One */
+#define HX_2   4 /* Common Chinese Region Two */
+#define HX_D   5 /* GB 18030 2-byte Region */
+#define HX_F   6 /* GB 18030 4-byte Region */
+/* Note Unicode, GS1 and URI modes not implemented */
+
+#define HX_NUM_MODES 7
+
+/* Initial mode costs */
+static unsigned int* hx_head_costs(unsigned int state[]) {
+    static unsigned int head_costs[HX_NUM_MODES] = {
+    /*  N            T            B                   1            2            D            F */
+        4 * HX_MULT, 4 * HX_MULT, (4 + 13) * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 0
+    };
+
+    (void)state; /* Unused */
+    return head_costs;
+}
+
+/* Cost of switching modes from k to j */
+static unsigned int hx_switch_cost(unsigned int state[], const int k, const int j) {
+    static const unsigned int switch_costs[HX_NUM_MODES][HX_NUM_MODES] = {
+        /*      N                   T                   B                        1                   2                   D                   F */
+        /*N*/ {                  0, (10 + 4) * HX_MULT, (10 + 4 + 13) * HX_MULT, (10 + 4) * HX_MULT, (10 + 4) * HX_MULT, (10 + 4) * HX_MULT, 10 * HX_MULT },
+        /*T*/ {  (6 + 4) * HX_MULT,                  0,  (6 + 4 + 13) * HX_MULT,  (6 + 4) * HX_MULT,  (6 + 4) * HX_MULT,  (6 + 4) * HX_MULT,  6 * HX_MULT },
+        /*B*/ {        4 * HX_MULT,        4 * HX_MULT,                       0,        4 * HX_MULT,        4 * HX_MULT,        4 * HX_MULT,  0 },
+        /*1*/ { (12 + 4) * HX_MULT, (12 + 4) * HX_MULT, (12 + 4 + 13) * HX_MULT,                  0,       12 * HX_MULT, (12 + 4) * HX_MULT, 12 * HX_MULT },
+        /*2*/ { (12 + 4) * HX_MULT, (12 + 4) * HX_MULT, (12 + 4 + 13) * HX_MULT,       12 * HX_MULT,                  0, (12 + 4) * HX_MULT, 12 * HX_MULT },
+        /*D*/ { (15 + 4) * HX_MULT, (15 + 4) * HX_MULT, (15 + 4 + 13) * HX_MULT, (15 + 4) * HX_MULT, (15 + 4) * HX_MULT,                  0, 15 * HX_MULT },
+        /*F*/ {        4 * HX_MULT,        4 * HX_MULT,      (4 + 13) * HX_MULT,        4 * HX_MULT,        4 * HX_MULT,        4 * HX_MULT,  0 },
+    };
+
+    (void)state; /* Unused */
+    return switch_costs[k][j];
+}
+
+/* Final end-of-data costs */
+static unsigned int hx_eod_cost(unsigned int state[], const int k) {
+    static const unsigned int eod_costs[HX_NUM_MODES] = {
+    /*  N             T            B  1             2             D             F */
+        10 * HX_MULT, 6 * HX_MULT, 0, 12 * HX_MULT, 12 * HX_MULT, 15 * HX_MULT, 0
+    };
+
+    (void)state; /* Unused */
+    return eod_costs[k];
+}
+
+/* Calculate cost of encoding character */
+static void hx_cur_cost(unsigned int state[], const unsigned int gbdata[], const size_t length, const int i, char* char_modes, unsigned int prev_costs[], unsigned int cur_costs[]) {
+    int cm_i = i * HX_NUM_MODES;
+    int text1, text2;
+    unsigned int* p_numeric_end = &state[0];
+    unsigned int* p_numeric_cost = &state[1];
+    unsigned int* p_text_submode = &state[2];
+    unsigned int* p_fourbyte_end = &state[3];
+    unsigned int* p_fourbyte_cost = &state[4];
+
+    if (in_numeric(gbdata, length, i, p_numeric_end, p_numeric_cost)) {
+        cur_costs[HX_N] = prev_costs[HX_N] + *p_numeric_cost;
+        char_modes[cm_i + HX_N] = 'n';
+    }
+
+    text1 = lookup_text1(gbdata[i]) != -1;
+    text2 = lookup_text2(gbdata[i]) != -1;
+
+    if (text1 || text2) {
+        if ((*p_text_submode == 1 && text2) || (*p_text_submode == 2 && text1)) {
+            cur_costs[HX_T] = prev_costs[HX_T] + 72; /* (6 + 6) * HX_MULT */
+            *p_text_submode = text2 ? 2 : 1;
+        } else {
+            cur_costs[HX_T] = prev_costs[HX_T] + 36; /* 6 * HX_MULT */
+        }
+        char_modes[cm_i + HX_T] = 't';
+    } else {
+        *p_text_submode = 1;
+    }
+
+    /* Binary mode can encode anything */
+    cur_costs[HX_B] = prev_costs[HX_B] + (gbdata[i] > 0xFF ? 96 : 48); /* (16 : 8) * HX_MULT */
+    char_modes[cm_i + HX_B] = 'b';
+
+    if (isRegion1(gbdata[i])) {
+        cur_costs[HX_1] = prev_costs[HX_1] + 72; /* 12 * HX_MULT */
+        char_modes[cm_i + HX_1] = '1';
+    }
+    if (isRegion2(gbdata[i])) {
+        cur_costs[HX_2] = prev_costs[HX_2] + 72; /* 12 * HX_MULT */
+        char_modes[cm_i + HX_2] = '2';
+    }
+    if (isDoubleByte(gbdata[i])) {
+        cur_costs[HX_D] = prev_costs[HX_D] + 90; /* 15 * HX_MULT */
+        char_modes[cm_i + HX_D] = 'd';
+    }
+    if (in_fourbyte(gbdata, length, i, p_fourbyte_end, p_fourbyte_cost)) {
+        cur_costs[HX_F] = prev_costs[HX_F] + *p_fourbyte_cost;
+        char_modes[cm_i + HX_F] = 'f';
+    }
+}
+
+/* Calculate optimized encoding modes */
+static void hx_define_mode(char* mode, const unsigned int gbdata[], const size_t length, const int debug) {
+    static const char mode_types[] = { 'n', 't', 'b', '1', '2', 'd', 'f' }; /* Must be in same order as HX_N etc */
+    unsigned int state[5] = { 0 /*numeric_end*/, 0 /*numeric_cost*/, 1 /*text_submode*/, 0 /*fourbyte_end*/, 0 /*fourbyte_cost*/ };
+
+    pn_define_mode(mode, gbdata, length, debug, state, mode_types, HX_NUM_MODES, hx_head_costs, hx_switch_cost, hx_eod_cost, hx_cur_cost);
+}
+
+/* Convert input data to binary stream */
+static void calculate_binary(char binary[], char mode[], unsigned int source[], const size_t length, const int eci, int debug) {
+    unsigned int position = 0;
+    int i, count, encoding_value;
+    int first_byte, second_byte;
+    int third_byte, fourth_byte;
+    int glyph;
+    int submode;
+
+    if (eci != 0) {
+        /* Encoding ECI assignment number, according to Table 5 */
+        bin_append(8, 4, binary); // ECI
+        if (eci <= 127) {
+            bin_append(eci, 8, binary);
+        }
+        if ((eci >= 128) && (eci <= 16383)) {
+            strcat(binary, "10");
+            bin_append(eci, 14, binary);
+        }
+        if (eci >= 16384) {
+            strcat(binary, "110");
+            bin_append(eci, 21, binary);
+        }
+    }
+
+    do {
+        int block_length = 0;
+        int double_byte = 0;
+        do {
+            if (mode[position] == 'b' && source[position + block_length] > 0xFF) {
+                double_byte++;
+            }
+            block_length++;
+        } while (position + block_length < length && mode[position + block_length] == mode[position]);
+
+        switch (mode[position]) {
+            case 'n':
+                /* Numeric mode */
+                /* Mode indicator */
+                bin_append(1, 4, binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Numeric\n");
+                }
+
+                count = 0; /* Suppress gcc -Wmaybe-uninitialized */
+                i = 0;
+
+                while (i < block_length) {
+                    int first = 0;
+
+                    first = posn(NEON, (char) source[position + i]);
+                    count = 1;
+                    encoding_value = first;
+
+                    if (i + 1 < block_length && mode[position + i + 1] == 'n') {
+                        int second = posn(NEON, (char) source[position + i + 1]);
+                        count = 2;
+                        encoding_value = (encoding_value * 10) + second;
+
+                        if (i + 2 < block_length && mode[position + i + 2] == 'n') {
+                            int third = posn(NEON, (char) source[position + i + 2]);
+                            count = 3;
+                            encoding_value = (encoding_value * 10) + third;
+                        }
+                    }
+
+                    bin_append(encoding_value, 10, binary);
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("0x%4x (%d)", encoding_value, encoding_value);
+                    }
+
+                    i += count;
+                }
+
+                /* Mode terminator depends on number of characters in last group (Table 2) */
+                switch (count) {
+                    case 1:
+                        bin_append(1021, 10, binary);
+                        break;
+                    case 2:
+                        bin_append(1022, 10, binary);
+                        break;
+                    case 3:
+                        bin_append(1023, 10, binary);
+                        break;
+                }
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf(" (TERM %d)\n", count);
+                }
+
+                break;
+            case 't':
+                /* Text mode */
+                /* Mode indicator */
+                bin_append(2, 4, binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Text\n");
+                }
+
+                submode = 1;
+
+                i = 0;
+
+                while (i < block_length) {
+
+                    if (getsubmode(source[i + position]) != submode) {
+                        /* Change submode */
+                        bin_append(62, 6, binary);
+                        submode = getsubmode(source[i + position]);
+                        if (debug & ZINT_DEBUG_PRINT) {
+                            printf("SWITCH ");
+                        }
+                    }
+
+                    if (submode == 1) {
+                        encoding_value = lookup_text1(source[i + position]);
+                    } else {
+                        encoding_value = lookup_text2(source[i + position]);
+                    }
+
+                    bin_append(encoding_value, 6, binary);
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("%.2x [ASC %.2x] ", encoding_value, source[i + position]);
+                    }
+                    i++;
+                }
+
+                /* Terminator */
+                bin_append(63, 6, binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("\n");
+                }
+                break;
+            case 'b':
+                /* Binary Mode */
+                /* Mode indicator */
+                bin_append(3, 4, binary);
+
+                /* Count indicator */
+                bin_append(block_length + double_byte, 13, binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Binary (length %d)\n", block_length + double_byte);
+                }
+
+                i = 0;
+
+                while (i < block_length) {
+
+                    /* 8-bit bytes with no conversion */
+                    bin_append(source[i + position], source[i + position] > 0xFF ? 16 : 8, binary);
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("%d ", source[i + position]);
+                    }
+
+                    i++;
+                }
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("\n");
+                }
+                break;
+            case '1':
+                /* Region 1 encoding */
+                /* Mode indicator */
+                if (position == 0 || mode[position - 1] != '2') { /* Unless previous mode Region 2 */
+                    bin_append(4, 4, binary);
+                }
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Region 1\n");
+                }
+
+                i = 0;
+
+                while (i < block_length) {
+                    first_byte = (source[i + position] & 0xff00) >> 8;
+                    second_byte = source[i + position] & 0xff;
+
+                    /* Subset 1 */
+                    glyph = (0x5e * (first_byte - 0xb0)) + (second_byte - 0xa1);
+
+                    /* Subset 2 */
+                    if ((first_byte >= 0xa1) && (first_byte <= 0xa3)) {
+                        if ((second_byte >= 0xa1) && (second_byte <= 0xfe)) {
+                            glyph = (0x5e * (first_byte - 0xa1)) + (second_byte - 0xa1) + 0xeb0;
+                        }
+                    }
+
+                    /* Subset 3 */
+                    if ((source[i + position] >= 0xa8a1) && (source[i + position] <= 0xa8c0)) {
+                        glyph = (second_byte - 0xa1) + 0xfca;
+                    }
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("%.4x [GB %.4x] ", glyph, source[i + position]);
+                    }
+
+                    bin_append(glyph, 12, binary);
+                    i++;
+                }
+
+                /* Terminator */
+                bin_append(position == length - 1 || mode[position + 1] != '2' ? 4095 : 4094, 12, binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("\n");
+                }
+
+                break;
+            case '2':
+                /* Region 2 encoding */
+                /* Mode indicator */
+                if (position == 0 || mode[position - 1] != '1') { /* Unless previous mode Region 1 */
+                    bin_append(5, 4, binary);
+                }
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Region 2\n");
+                }
+
+                i = 0;
+
+                while (i < block_length) {
+                    first_byte = (source[i + position] & 0xff00) >> 8;
+                    second_byte = source[i + position] & 0xff;
+
+                    glyph = (0x5e * (first_byte - 0xd8)) + (second_byte - 0xa1);
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("%.4x [GB %.4x] ", glyph, source[i + position]);
+                    }
+
+                    bin_append(glyph, 12, binary);
+                    i++;
+                }
+
+                /* Terminator */
+                bin_append(position == length - 1 || mode[position + 1] != '1' ? 4095 : 4094, 12, binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("\n");
+                }
+                break;
+            case 'd':
+                /* Double byte encoding */
+                /* Mode indicator */
+                bin_append(6, 4, binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Double byte\n");
+                }
+
+                i = 0;
+
+                while (i < block_length) {
+                    first_byte = (source[i + position] & 0xff00) >> 8;
+                    second_byte = source[i + position] & 0xff;
+
+                    if (second_byte <= 0x7e) {
+                        glyph = (0xbe * (first_byte - 0x81)) + (second_byte - 0x40);
+                    } else {
+                        glyph = (0xbe * (first_byte - 0x81)) + (second_byte - 0x41);
+                    }
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("%.4x ", glyph);
+                    }
+
+                    bin_append(glyph, 15, binary);
+                    i++;
+                }
+
+                /* Terminator */
+                bin_append(32767, 15, binary);
+                /* Terminator sequence of length 12 is a mistake
+                   - confirmed by Wang Yi */
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("\n");
+                }
+                break;
+            case 'f':
+                /* Four-byte encoding */
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Four byte\n");
+                }
+
+                i = 0;
+
+                while (i < block_length) {
+
+                    /* Mode indicator */
+                    bin_append(7, 4, binary);
+
+                    first_byte = (source[i + position] & 0xff00) >> 8;
+                    second_byte = source[i + position] & 0xff;
+                    third_byte = (source[i + position + 1] & 0xff00) >> 8;
+                    fourth_byte = source[i + position + 1] & 0xff;
+
+                    glyph = (0x3138 * (first_byte - 0x81)) + (0x04ec * (second_byte - 0x30)) +
+                            (0x0a * (third_byte - 0x81)) + (fourth_byte - 0x30);
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("%d ", glyph);
+                    }
+
+                    bin_append(glyph, 21, binary);
+                    i += 2;
+                }
+
+                /* No terminator */
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("\n");
+                }
+                break;
+
+        }
+
+        position += block_length;
+
+    } while (position < length);
+}
+
+/* Finder pattern for top left of symbol */
+static void hx_place_finder_top_left(unsigned char* grid, int size) {
+    int xp, yp;
+    int x = 0, y = 0;
+    char finder[] = {0x7F, 0x40, 0x5F, 0x50, 0x57, 0x57, 0x57};
+
+    for (xp = 0; xp < 7; xp++) {
+        for (yp = 0; yp < 7; yp++) {
+            if (finder[yp] & 0x40 >> xp) {
+                grid[((yp + y) * size) + (xp + x)] = 0x11;
+            } else {
+                grid[((yp + y) * size) + (xp + x)] = 0x10;
+            }
+        }
+    }
+}
+
+/* Finder pattern for top right and bottom left of symbol */
+static void hx_place_finder(unsigned char* grid, int size, int x, int y) {
+    int xp, yp;
+    char finder[] = {0x7F, 0x01, 0x7D, 0x05, 0x75, 0x75, 0x75};
+
+    for (xp = 0; xp < 7; xp++) {
+        for (yp = 0; yp < 7; yp++) {
+            if (finder[yp] & 0x40 >> xp) {
+                grid[((yp + y) * size) + (xp + x)] = 0x11;
+            } else {
+                grid[((yp + y) * size) + (xp + x)] = 0x10;
+            }
+        }
+    }
+}
+
+/* Finder pattern for bottom right of symbol */
+static void hx_place_finder_bottom_right(unsigned char* grid, int size) {
+    int xp, yp;
+    int x = size - 7, y = size - 7;
+    char finder[] = {0x75, 0x75, 0x75, 0x05, 0x7D, 0x01, 0x7F};
+
+    for (xp = 0; xp < 7; xp++) {
+        for (yp = 0; yp < 7; yp++) {
+            if (finder[yp] & 0x40 >> xp) {
+                grid[((yp + y) * size) + (xp + x)] = 0x11;
+            } else {
+                grid[((yp + y) * size) + (xp + x)] = 0x10;
+            }
+        }
+    }
+}
+
+/* Avoid plotting outside symbol or over finder patterns */
+static void hx_safe_plot(unsigned char *grid, int size, int x, int y, int value) {
+    if ((x >= 0) && (x < size)) {
+        if ((y >= 0) && (y < size)) {
+            if (grid[(y * size) + x] == 0) {
+                grid[(y * size) + x] = value;
+            }
+        }
+    }
+}
+
+/* Plot an alignment pattern around top and right of a module */
+static void hx_plot_alignment(unsigned char *grid, int size, int x, int y, int w, int h) {
+    int i;
+    hx_safe_plot(grid, size, x, y, 0x11);
+    hx_safe_plot(grid, size, x - 1, y + 1, 0x10);
+
+    for (i = 1; i <= w; i++) {
+        /* Top */
+        hx_safe_plot(grid, size, x - i, y, 0x11);
+        hx_safe_plot(grid, size, x - i - 1, y + 1, 0x10);
+    }
+
+    for (i = 1; i < h; i++) {
+        /* Right */
+        hx_safe_plot(grid, size, x, y + i, 0x11);
+        hx_safe_plot(grid, size, x - 1, y + i + 1, 0x10);
+    }
+}
+
+/* Plot assistant alignment patterns */
+static void hx_plot_assistant(unsigned char *grid, int size, int x, int y) {
+    hx_safe_plot(grid, size, x - 1, y - 1, 0x10);
+    hx_safe_plot(grid, size, x, y - 1, 0x10);
+    hx_safe_plot(grid, size, x + 1, y - 1, 0x10);
+    hx_safe_plot(grid, size, x - 1, y, 0x10);
+    hx_safe_plot(grid, size, x, y, 0x11);
+    hx_safe_plot(grid, size, x + 1, y, 0x10);
+    hx_safe_plot(grid, size, x - 1, y + 1, 0x10);
+    hx_safe_plot(grid, size, x, y + 1, 0x10);
+    hx_safe_plot(grid, size, x + 1, y + 1, 0x10);
+}
+
+/* Put static elements in the grid */
+static void hx_setup_grid(unsigned char* grid, int size, int version) {
+    int i, j;
+
+    for (i = 0; i < size; i++) {
+        for (j = 0; j < size; j++) {
+            grid[(i * size) + j] = 0;
+        }
+    }
+
+    /* Add finder patterns */
+    hx_place_finder_top_left(grid, size);
+    hx_place_finder(grid, size, 0, size - 7);
+    hx_place_finder(grid, size, size - 7, 0);
+    hx_place_finder_bottom_right(grid, size);
+
+    /* Add finder pattern separator region */
+    for (i = 0; i < 8; i++) {
+        /* Top left */
+        grid[(7 * size) + i] = 0x10;
+        grid[(i * size) + 7] = 0x10;
+
+        /* Top right */
+        grid[(7 * size) + (size - i - 1)] = 0x10;
+        grid[((size - i - 1) * size) + 7] = 0x10;
+
+        /* Bottom left */
+        grid[(i * size) + (size - 8)] = 0x10;
+        grid[((size - 8) * size) + i] = 0x10;
+
+        /* Bottom right */
+        grid[((size - 8) * size) + (size - i - 1)] = 0x10;
+        grid[((size - i - 1) * size) + (size - 8)] = 0x10;
+    }
+
+    /* Reserve function information region */
+    for (i = 0; i < 9; i++) {
+        /* Top left */
+        grid[(8 * size) + i] = 0x10;
+        grid[(i * size) + 8] = 0x10;
+
+        /* Top right */
+        grid[(8 * size) + (size - i - 1)] = 0x10;
+        grid[((size - i - 1) * size) + 8] = 0x10;
+
+        /* Bottom left */
+        grid[(i * size) + (size - 9)] = 0x10;
+        grid[((size - 9) * size) + i] = 0x10;
+
+        /* Bottom right */
+        grid[((size - 9) * size) + (size - i - 1)] = 0x10;
+        grid[((size - i - 1) * size) + (size - 9)] = 0x10;
+    }
+
+    if (version > 3) {
+        int k = hx_module_k[version - 1];
+        int r = hx_module_r[version - 1];
+        int m = hx_module_m[version - 1];
+        int x, y, row_switch, column_switch;
+        int module_height, module_width;
+        int mod_x, mod_y;
+
+        /* Add assistant alignment patterns to left and right */
+        y = 0;
+        mod_y = 0;
+        do {
+            if (mod_y < m) {
+                module_height = k;
+            } else {
+                module_height = r - 1;
+            }
+
+            if ((mod_y % 2) == 0) {
+                if ((m % 2) == 1) {
+                    hx_plot_assistant(grid, size, 0, y);
+                }
+            } else {
+                if ((m % 2) == 0) {
+                    hx_plot_assistant(grid, size, 0, y);
+                }
+                hx_plot_assistant(grid, size, size - 1, y);
+            }
+
+            mod_y++;
+            y += module_height;
+        } while (y < size);
+
+        /* Add assistant alignment patterns to top and bottom */
+        x = (size - 1);
+        mod_x = 0;
+        do {
+            if (mod_x < m) {
+                module_width = k;
+            } else {
+                module_width = r - 1;
+            }
+
+            if ((mod_x % 2) == 0) {
+                if ((m % 2) == 1) {
+                    hx_plot_assistant(grid, size, x, (size - 1));
+                }
+            } else {
+                if ((m % 2) == 0) {
+                    hx_plot_assistant(grid, size, x, (size - 1));
+                }
+                hx_plot_assistant(grid, size, x, 0);
+            }
+
+            mod_x++;
+            x -= module_width;
+        } while (x >= 0);
+
+        /* Add alignment pattern */
+        column_switch = 1;
+        y = 0;
+        mod_y = 0;
+        do {
+            if (mod_y < m) {
+                module_height = k;
+            } else {
+                module_height = r - 1;
+            }
+
+            if (column_switch == 1) {
+                row_switch = 1;
+                column_switch = 0;
+            } else {
+                row_switch = 0;
+                column_switch = 1;
+            }
+
+            x = (size - 1);
+            mod_x = 0;
+            do {
+                if (mod_x < m) {
+                    module_width = k;
+                } else {
+                    module_width = r - 1;
+                }
+
+                if (row_switch == 1) {
+                    if (!(y == 0 && x == (size - 1))) {
+                        hx_plot_alignment(grid, size, x, y, module_width, module_height);
+                    }
+                    row_switch = 0;
+                } else {
+                    row_switch = 1;
+                }
+                mod_x++;
+                x -= module_width;
+            } while (x >= 0);
+
+            mod_y++;
+            y += module_height;
+        } while (y < size);
+    }
+}
+
+/* Calculate error correction codes */
+static void hx_add_ecc(unsigned char fullstream[], unsigned char datastream[], int data_codewords, int version, int ecc_level) {
+    unsigned char data_block[180];
+    unsigned char ecc_block[36];
+    int i, j, block;
+    int input_position = -1;
+    int output_position = -1;
+    int table_d1_pos = ((version - 1) * 36) + ((ecc_level - 1) * 9);
+
+    for (i = 0; i < 3; i++) {
+        int batch_size = hx_table_d1[table_d1_pos + (3 * i)];
+        int data_length = hx_table_d1[table_d1_pos + (3 * i) + 1];
+        int ecc_length = hx_table_d1[table_d1_pos + (3 * i) + 2];
+
+        for (block = 0; block < batch_size; block++) {
+            for (j = 0; j < data_length; j++) {
+                input_position++;
+                output_position++;
+                data_block[j] = input_position < data_codewords ? datastream[input_position] : 0;
+                fullstream[output_position] = data_block[j];
+            }
+
+            rs_init_gf(0x163); // x^8 + x^6 + x^5 + x + 1 = 0
+            rs_init_code(ecc_length, 1);
+            rs_encode(data_length, data_block, ecc_block);
+            rs_free();
+
+            for (j = 0; j < ecc_length; j++) {
+                output_position++;
+                fullstream[output_position] = ecc_block[ecc_length - j - 1];
+            }
+        }
+    }
+}
+
+/* Rearrange data in batches of 13 codewords (section 5.8.2) */
+static void make_picket_fence(unsigned char fullstream[], unsigned char picket_fence[], int streamsize) {
+    int i, start;
+    int output_position = 0;
+
+    for (start = 0; start < 13; start++) {
+        for (i = start; i < streamsize; i += 13) {
+            if (i < streamsize) {
+                picket_fence[output_position] = fullstream[i];
+                output_position++;
+            }
+        }
+    }
+}
+
+/* Evaluate a bitmask according to table 9 */
+static int hx_evaluate(unsigned char *eval, int size, int pattern) {
+    int x, y, block, weight;
+    int result = 0;
+    char state;
+    int p;
+    int a, b, afterCount, beforeCount;
+#ifndef _MSC_VER
+    char local[size * size];
+#else
+    char* local = (char *) _alloca((size * size) * sizeof (char));
+#endif
+
+    /* all four bitmask variants have been encoded in the 4 bits of the bytes
+     * that make up the grid array. select them for evaluation according to the
+     * desired pattern.*/
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            if (eval[(y * size) + x] & 0xf0) {
+                local[(y * size) + x] = 0;
+            } else if ((eval[(y * size) + x] & (0x01 << pattern)) != 0) {
+                local[(y * size) + x] = '1';
+            } else {
+                local[(y * size) + x] = '0';
+            }
+        }
+    }
+
+    /* Test 1: 1:1:1:1:3  or 3:1:1:1:1 ratio pattern in row/column */
+    /* Vertical */
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < (size - 7); y++) {
+            if (local[(y * size) + x] == 0) {
+                continue;
+            }
+            p = 0;
+            for (weight = 0; weight < 7; weight++) {
+                if (local[((y + weight) * size) + x] == '1') {
+                    p += (0x40 >> weight);
+                }
+            }
+            if ((p == 0x57) || (p == 0x75)) {
+                /* Pattern found, check before and after */
+                beforeCount = 0;
+                for (b = (y - 3); b < y; b++) {
+                    if (b < 0) {
+                        beforeCount++;
+                    } else {
+                        if (local[(b * size) + x] == '0') {
+                            beforeCount++;
+                        } else {
+                            break;
+                        }
+                    }
+                }
+
+                afterCount = 0;
+                for (a = (y + 7); a <= (y + 9); a++) {
+                    if (a >= size) {
+                        afterCount++;
+                    } else {
+                        if (local[(a * size) + x] == '0') {
+                            afterCount++;
+                        } else {
+                            break;
+                        }
+                    }
+                }
+
+                if ((beforeCount == 3) || (afterCount == 3)) {
+                    /* Pattern is preceeded or followed by light area
+                       3 modules wide */
+                    result += 50;
+                }
+            }
+        }
+    }
+
+    /* Horizontal */
+    for (y = 0; y < size; y++) {
+        for (x = 0; x < (size - 7); x++) {
+            if (local[(y * size) + x] == 0) {
+                continue;
+            }
+            p = 0;
+            for (weight = 0; weight < 7; weight++) {
+                if (local[(y * size) + x + weight] == '1') {
+                    p += (0x40 >> weight);
+                }
+            }
+            if ((p == 0x57) || (p == 0x75)) {
+                /* Pattern found, check before and after */
+                beforeCount = 0;
+                for (b = (x - 3); b < x; b++) {
+                    if (b < 0) {
+                        beforeCount++;
+                    } else {
+                        if (local[(y * size) + b] == '0') {
+                            beforeCount++;
+                        } else {
+                            break;
+                        }
+                    }
+                }
+
+                afterCount = 0;
+                for (a = (x + 7); a <= (x + 9); a++) {
+                    if (a >= size) {
+                        afterCount++;
+                    } else {
+                        if (local[(y * size) + a] == '0') {
+                            afterCount++;
+                        } else {
+                            break;
+                        }
+                    }
+                }
+
+                if ((beforeCount == 3) || (afterCount == 3)) {
+                    /* Pattern is preceeded or followed by light area
+                       3 modules wide */
+                    result += 50;
+                }
+            }
+        }
+    }
+
+    /* Test 2: Adjacent modules in row/column in same colour */
+    /* In AIMD-15 section 5.8.3.2 it is stated... “In Table 9 below, i refers to the row
+     * position of the module.” - however i being the length of the run of the
+     * same colour (i.e. "block" below) in the same fashion as ISO/IEC 18004
+     * makes more sense. -- Confirmed by Wang Yi */
+    /* Fixed in ISO/IEC 20830 (draft 2019-10-10) section 5.8.3.2 "In Table 12 below, i refers to the modules with same color." */
+
+    /* Vertical */
+    for (x = 0; x < size; x++) {
+        block = 0;
+        state = 0;
+        for (y = 0; y < size; y++) {
+            if (local[(y * size) + x] == 0) {
+                if (block >= 3) {
+                    result += (3 + block) * 4;
+                }
+                block = 0;
+                state = 0;
+            } else if (local[(y * size) + x] == state || state == 0) {
+                block++;
+                state = local[(y * size) + x];
+            } else {
+                if (block >= 3) {
+                    result += (3 + block) * 4;
+                }
+                block = 1;
+                state = local[(y * size) + x];
+            }
+        }
+        if (block >= 3) {
+            result += (3 + block) * 4;
+        }
+    }
+
+    /* Horizontal */
+    for (y = 0; y < size; y++) {
+        state = local[y * size];
+        block = 0;
+        for (x = 0; x < size; x++) {
+            if (local[(y * size) + x] == 0) {
+                if (block >= 3) {
+                    result += (3 + block) * 4;
+                }
+                block = 0;
+                state = 0;
+            } else if (local[(y * size) + x] == state || state == 0) {
+                block++;
+                state = local[(y * size) + x];
+            } else {
+                if (block >= 3) {
+                    result += (3 + block) * 4;
+                }
+                block = 1;
+                state = local[(y * size) + x];
+            }
+        }
+        if (block >= 3) {
+            result += (3 + block) * 4;
+        }
+    }
+
+    return result;
+}
+
+/* Apply the four possible bitmasks for evaluation */
+/* TODO: Haven't been able to replicate (or even get close to) the penalty scores in ISO/IEC 20830 (draft 2019-10-10) Annex K examples */
+static int hx_apply_bitmask(unsigned char *grid, int size) {
+    int x, y;
+    int i, j;
+    int pattern, penalty[4];
+    int best_pattern, best_val;
+    int bit;
+    unsigned char p;
+
+#ifndef _MSC_VER
+    unsigned char mask[(unsigned int)(size * size)]; /* Cast to suppress gcc -Walloc-size-larger-than */
+    unsigned char eval[(unsigned int)(size * size)];
+#else
+    unsigned char* mask = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
+    unsigned char* eval = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
+#endif
+
+    /* Perform data masking */
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            mask[(y * size) + x] = 0x00;
+            j = x + 1;
+            i = y + 1;
+
+            if (!(grid[(y * size) + x] & 0xf0)) {
+                if ((i + j) % 2 == 0) {
+                    mask[(y * size) + x] += 0x02;
+                }
+                if ((((i + j) % 3) + (j % 3)) % 2 == 0) {
+                    mask[(y * size) + x] += 0x04;
+                }
+                if (((i % j) + (j % i) + (i % 3) + (j % 3)) % 2 == 0) {
+                    mask[(y * size) + x] += 0x08;
+                }
+            }
+        }
+    }
+
+    // apply data masks to grid, result in eval
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            if (grid[(y * size) + x] & 0xf0) {
+                p = 0xf0;
+            } else if (grid[(y * size) + x] & 0x01) {
+                p = 0x0f;
+            } else {
+                p = 0x00;
+            }
+
+            eval[(y * size) + x] = mask[(y * size) + x] ^ p;
+        }
+    }
+
+    /* Evaluate result */
+    for (pattern = 0; pattern < 4; pattern++) {
+        penalty[pattern] = hx_evaluate(eval, size, pattern);
+    }
+
+    best_pattern = 0;
+    best_val = penalty[0];
+    for (pattern = 1; pattern < 4; pattern++) {
+        if (penalty[pattern] < best_val) {
+            best_pattern = pattern;
+            best_val = penalty[pattern];
+        }
+    }
+
+    /* Apply mask */
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            bit = 0;
+            switch (best_pattern) {
+                case 0: if (mask[(y * size) + x] & 0x01) {
+                        bit = 1;
+                    }
+                    break;
+                case 1: if (mask[(y * size) + x] & 0x02) {
+                        bit = 1;
+                    }
+                    break;
+                case 2: if (mask[(y * size) + x] & 0x04) {
+                        bit = 1;
+                    }
+                    break;
+                case 3: if (mask[(y * size) + x] & 0x08) {
+                        bit = 1;
+                    }
+                    break;
+            }
+            if (bit == 1) {
+                if (grid[(y * size) + x] & 0x01) {
+                    grid[(y * size) + x] = 0x00;
+                } else {
+                    grid[(y * size) + x] = 0x01;
+                }
+            }
+        }
+    }
+
+    return best_pattern;
+}
+
+/* Han Xin Code - main */
+INTERNAL int han_xin(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
+    int est_binlen;
+    int ecc_level = symbol->option_1;
+    int i, j, version;
+    int full_multibyte;
+    int data_codewords = 0, size;
+    int codewords;
+    int bitmask;
+    int bin_len;
+    char function_information[36];
+    unsigned char fi_cw[3] = {0, 0, 0};
+    unsigned char fi_ecc[4];
+
+#ifndef _MSC_VER
+    unsigned int gbdata[(length + 1) * 2];
+    char mode[length + 1];
+#else
+    unsigned int* gbdata = (unsigned int *) _alloca(((length + 1) * 2) * sizeof (unsigned int));
+    char* mode = (char *) _alloca((length + 1) * sizeof (char));
+    char* binary;
+    unsigned char *datastream;
+    unsigned char *fullstream;
+    unsigned char *picket_fence;
+    unsigned char *grid;
+#endif
+
+    full_multibyte = symbol->option_3 == ZINT_FULL_MULTIBYTE; /* If set use Hanzi mode in DATA_MODE or for single-byte Latin */
+
+    if ((symbol->input_mode & 0x07) == DATA_MODE) {
+        gb18030_cpy(source, &length, gbdata, full_multibyte);
+    } else {
+        int done = 0;
+        if (symbol->eci != 29) { /* Unless ECI 29 (GB) */
+            /* Try single byte (Latin) conversion first */
+            int error_number = gb18030_utf8tosb(symbol->eci && symbol->eci <= 899 ? symbol->eci : 3, source, &length, gbdata, full_multibyte);
+            if (error_number == 0) {
+                done = 1;
+            } else if (symbol->eci && symbol->eci <= 899) {
+                strcpy(symbol->errtxt, "575: Invalid characters in input data");
+                return error_number;
+            }
+        }
+        if (!done) {
+            /* Try GB 18030 */
+            int error_number = gb18030_utf8tomb(symbol, source, &length, gbdata);
+            if (error_number != 0) {
+                return error_number;
+            }
+        }
+    }
+
+    hx_define_mode(mode, gbdata, length, symbol->debug);
+
+    est_binlen = calculate_binlength(mode, gbdata, length, symbol->eci);
+
+#ifndef _MSC_VER
+    char binary[est_binlen + 1];
+#else
+    binary = (char *) _alloca((est_binlen + 1) * sizeof (char));
+#endif
+    memset(binary, 0, (est_binlen + 1) * sizeof (char));
+
+    if ((ecc_level <= 0) || (ecc_level >= 5)) {
+        ecc_level = 1;
+    }
+
+    calculate_binary(binary, mode, gbdata, length, symbol->eci, symbol->debug);
+    bin_len = strlen(binary);
+    codewords = bin_len / 8;
+    if (bin_len % 8 != 0) {
+        codewords++;
+    }
+
+    version = 85;
+    for (i = 84; i > 0; i--) {
+        switch (ecc_level) {
+            case 1:
+                if (hx_data_codewords_L1[i - 1] > codewords) {
+                    version = i;
+                    data_codewords = hx_data_codewords_L1[i - 1];
+                }
+                break;
+            case 2:
+                if (hx_data_codewords_L2[i - 1] > codewords) {
+                    version = i;
+                    data_codewords = hx_data_codewords_L2[i - 1];
+                }
+                break;
+            case 3:
+                if (hx_data_codewords_L3[i - 1] > codewords) {
+                    version = i;
+                    data_codewords = hx_data_codewords_L3[i - 1];
+                }
+                break;
+            case 4:
+                if (hx_data_codewords_L4[i - 1] > codewords) {
+                    version = i;
+                    data_codewords = hx_data_codewords_L4[i - 1];
+                }
+                break;
+            default:
+                assert(0);
+                break;
+        }
+    }
+
+    if (version == 85) {
+        strcpy(symbol->errtxt, "541: Input too long for selected error correction level");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    if ((symbol->option_2 < 0) || (symbol->option_2 > 84)) {
+        symbol->option_2 = 0;
+    }
+
+    if (symbol->option_2 > version) {
+        version = symbol->option_2;
+    }
+
+    if ((symbol->option_2 != 0) && (symbol->option_2 < version)) {
+        strcpy(symbol->errtxt, "542: Input too long for selected symbol size");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    /* If there is spare capacity, increase the level of ECC */
+
+    if (symbol->option_1 == -1 || symbol->option_1 != ecc_level) { /* Unless explicitly specified (within min/max bounds) by user */
+        if ((ecc_level == 1) && (codewords < hx_data_codewords_L2[version - 1])) {
+            ecc_level = 2;
+            data_codewords = hx_data_codewords_L2[version - 1];
+        }
+
+        if ((ecc_level == 2) && (codewords < hx_data_codewords_L3[version - 1])) {
+            ecc_level = 3;
+            data_codewords = hx_data_codewords_L3[version - 1];
+        }
+
+        if ((ecc_level == 3) && (codewords < hx_data_codewords_L4[version - 1])) {
+            ecc_level = 4;
+            data_codewords = hx_data_codewords_L4[version - 1];
+        }
+    }
+
+    size = (version * 2) + 21;
+
+#ifndef _MSC_VER
+    unsigned char datastream[data_codewords];
+    unsigned char fullstream[hx_total_codewords[version - 1]];
+    unsigned char picket_fence[hx_total_codewords[version - 1]];
+    unsigned char grid[size * size];
+#else
+    datastream = (unsigned char *) _alloca((data_codewords) * sizeof (unsigned char));
+    fullstream = (unsigned char *) _alloca((hx_total_codewords[version - 1]) * sizeof (unsigned char));
+    picket_fence = (unsigned char *) _alloca((hx_total_codewords[version - 1]) * sizeof (unsigned char));
+    grid = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
+#endif
+
+    for (i = 0; i < data_codewords; i++) {
+        datastream[i] = 0;
+    }
+
+    for (i = 0; i < bin_len; i++) {
+        if (binary[i] == '1') {
+            datastream[i / 8] += 0x80 >> (i % 8);
+        }
+    }
+
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("Datastream length: %d\n", data_codewords);
+        printf("Datastream:\n");
+        for (i = 0; i < data_codewords; i++) {
+            printf("%.2x ", datastream[i]);
+        }
+        printf("\n");
+    }
+#ifdef ZINT_TEST
+    if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, data_codewords);
+#endif
+
+    hx_setup_grid(grid, size, version);
+
+    hx_add_ecc(fullstream, datastream, data_codewords, version, ecc_level);
+
+    make_picket_fence(fullstream, picket_fence, hx_total_codewords[version - 1]);
+
+    /* Populate grid */
+    j = 0;
+    for (i = 0; i < (size * size); i++) {
+        if (grid[i] == 0x00) {
+            if (j < (hx_total_codewords[version - 1] * 8)) {
+                if (picket_fence[(j / 8)] & (0x80 >> (j % 8))) {
+                    grid[i] = 0x01;
+                }
+                j++;
+            }
+        }
+    }
+
+    bitmask = hx_apply_bitmask(grid, size);
+
+    /* Form function information string */
+    for (i = 0; i < 34; i++) {
+        if (i % 2) {
+            function_information[i] = '1';
+        } else {
+            function_information[i] = '0';
+        }
+    }
+    function_information[34] = '\0';
+
+    for (i = 0; i < 8; i++) {
+        if ((version + 20) & (0x80 >> i)) {
+            function_information[i] = '1';
+        } else {
+            function_information[i] = '0';
+        }
+    }
+
+    for (i = 0; i < 2; i++) {
+        if ((ecc_level - 1) & (0x02 >> i)) {
+            function_information[i + 8] = '1';
+        } else {
+            function_information[i + 8] = '0';
+        }
+    }
+
+    for (i = 0; i < 2; i++) {
+        if (bitmask & (0x02 >> i)) {
+            function_information[i + 10] = '1';
+        } else {
+            function_information[i + 10] = '0';
+        }
+    }
+
+    for (i = 0; i < 3; i++) {
+        for (j = 0; j < 4; j++) {
+            if (function_information[(i * 4) + j] == '1') {
+                fi_cw[i] += (0x08 >> j);
+            }
+        }
+    }
+
+    rs_init_gf(0x13);
+    rs_init_code(4, 1);
+    rs_encode(3, fi_cw, fi_ecc);
+    rs_free();
+
+    for (i = 0; i < 4; i++) {
+        for (j = 0; j < 4; j++) {
+            if (fi_ecc[3 - i] & (0x08 >> j)) {
+                function_information[(i * 4) + j + 12] = '1';
+            } else {
+                function_information[(i * 4) + j + 12] = '0';
+            }
+        }
+    }
+
+    /* Add function information to symbol */
+    for (i = 0; i < 9; i++) {
+        if (function_information[i] == '1') {
+            grid[(8 * size) + i] = 0x01;
+            grid[((size - 8 - 1) * size) + (size - i - 1)] = 0x01;
+        }
+        if (function_information[i + 8] == '1') {
+            grid[((8 - i) * size) + 8] = 0x01;
+            grid[((size - 8 - 1 + i) * size) + (size - 8 - 1)] = 0x01;
+        }
+        if (function_information[i + 17] == '1') {
+            grid[(i * size) + (size - 1 - 8)] = 0x01;
+            grid[((size - 1 - i) * size) + 8] = 0x01;
+        }
+        if (function_information[i + 25] == '1') {
+            grid[(8 * size) + (size - 1 - 8 + i)] = 0x01;
+            grid[((size - 1 - 8) * size) + (8 - i)] = 0x01;
+        }
+    }
+
+    symbol->width = size;
+    symbol->rows = size;
+
+    for (i = 0; i < size; i++) {
+        for (j = 0; j < size; j++) {
+            if (grid[(i * size) + j] & 0x01) {
+                set_module(symbol, i, j);
+            }
+        }
+        symbol->row_height[i] = 1;
+    }
+
+    return 0;
+}
diff --git a/backend/hanxin.h b/backend/hanxin.h
new file mode 100644 (file)
index 0000000..a5258d7
--- /dev/null
@@ -0,0 +1,460 @@
+/*  hanxin.h - definitions for Han Xin code
+
+    libzint - the open source barcode library
+    Copyright (C) 2009-2017 Robin Stuart <rstuart114@gmail.com>
+    Copyright (C) 2016 Zoe Stuart
+
+    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.
+ */
+
+/* Data from table B1: Data capacity of Han Xin Code */
+static const unsigned short int hx_total_codewords[] = {
+    25, 37, 50, 54, 69, 84, 100, 117, 136, 155, 161, 181, 203, 225, 249,
+    273, 299, 325, 353, 381, 411, 422, 453, 485, 518, 552, 587, 623, 660,
+    698, 737, 754, 794, 836, 878, 922, 966, 1011, 1058, 1105, 1126, 1175,
+    1224, 1275, 1327, 1380, 1434, 1489, 1513, 1569, 1628, 1686, 1745, 1805,
+    1867, 1929, 1992, 2021, 2086, 2151, 2218, 2286, 2355, 2425, 2496, 2528,
+    2600, 2673, 2749, 2824, 2900, 2977, 3056, 3135, 3171, 3252, 3334, 3416,
+    3500, 3585, 3671, 3758, 3798, 3886
+};
+
+static const unsigned short int hx_data_codewords_L1[] = {
+    21, 31, 42, 46, 57, 70, 84, 99, 114, 131, 135, 153, 171, 189, 209, 229,
+    251, 273, 297, 321, 345, 354, 381, 407, 436, 464, 493, 523, 554, 586, 619,
+    634, 666, 702, 738, 774, 812, 849, 888, 929, 946, 987, 1028, 1071, 1115,
+    1160, 1204, 1251, 1271, 1317, 1368, 1416, 1465, 1517, 1569, 1621, 1674,
+    1697, 1752, 1807, 1864, 1920, 1979, 2037, 2096, 2124, 2184, 2245, 2309,
+    2372, 2436, 2501, 2568, 2633, 2663, 2732, 2800, 2870, 2940, 3011,
+    3083, 3156, 3190, 3264
+};
+
+static const unsigned short int hx_data_codewords_L2[] = {
+    17, 25, 34, 38, 49, 58, 70, 81, 96, 109, 113, 127, 143, 157, 175, 191, 209,
+    227, 247, 267, 287, 296, 317, 339, 362, 386, 411, 437, 462, 488, 515, 528,
+    556, 586, 614, 646, 676, 707, 740, 773, 788, 823, 856, 893, 929, 966, 1004,
+    1043, 1059, 1099, 1140, 1180, 1221, 1263, 1307, 1351, 1394, 1415, 1460,
+    1505, 1552, 1600, 1649, 1697, 1748, 1770, 1820, 1871, 1925, 1976, 2030,
+    2083, 2140, 2195, 2219, 2276, 2334, 2392, 2450, 2509, 2569, 2630, 2658,
+    2720
+};
+
+static const unsigned short int hx_data_codewords_L3[] = {
+    13, 19, 26, 30, 37, 46, 54, 63, 74, 83, 87, 97, 109, 121, 135, 147, 161,
+    175, 191, 205, 221, 228, 245, 261, 280, 298, 317, 337, 358, 376, 397, 408,
+    428, 452, 474, 498, 522, 545, 572, 597, 608, 635, 660, 689, 717, 746, 774,
+    805, 817, 847, 880, 910, 943, 975, 1009, 1041, 1076, 1091, 1126, 1161, 1198,
+    1234, 1271, 1309, 1348, 1366, 1404, 1443, 1485, 1524, 1566, 1607, 1650, 1693,
+    1713, 1756, 1800, 1844, 1890, 1935, 1983, 2030, 2050, 2098
+};
+
+static const unsigned short int hx_data_codewords_L4[] = {
+    9, 15, 20, 22, 27, 34, 40, 47, 54, 61, 65, 73, 81, 89, 99, 109, 119, 129,
+    141, 153, 165, 168, 181, 195, 208, 220, 235, 251, 264, 280, 295, 302, 318,
+    334, 352, 368, 386, 405, 424, 441, 450, 469, 490, 509, 531, 552, 574, 595, 605,
+    627, 652, 674, 697, 721, 747, 771, 796, 809, 834, 861, 892, 914, 941, 969, 998,
+    1012, 1040, 1069, 1099, 1130, 1160, 1191, 1222, 1253, 1269, 1300, 1334,
+    1366, 1400, 1433, 1469, 1504, 1520, 1554
+};
+
+/* Value 'k' from Annex A */
+static const char hx_module_k[] = {
+    0, 0, 0, 14, 16, 16, 17, 18, 19, 20,
+    14, 15, 16, 16, 17, 17, 18, 19, 20, 20,
+    21, 16, 17, 17, 18, 18, 19, 19, 20, 20,
+    21, 17, 17, 18, 18, 19, 19, 19, 20, 20,
+    17, 17, 18, 18, 18, 19, 19, 19, 17, 17,
+    18, 18, 18, 18, 19, 19, 19, 17, 17, 18,
+    18, 18, 18, 19, 19, 17, 17, 17, 18, 18,
+    18, 18, 19, 19, 17, 17, 17, 18, 18, 18,
+    18, 18, 17, 17
+};
+
+/* Value 'r' from Annex A */
+static const char hx_module_r[] = {
+    0, 0, 0, 15, 15, 17, 18, 19, 20, 21,
+    15, 15, 15, 17, 17, 19, 19, 19, 19, 21,
+    21, 17, 16, 18, 17, 19, 18, 20, 19, 21,
+    20, 17, 19, 17, 19, 17, 19, 21, 19, 21,
+    18, 20, 17, 19, 21, 18, 20, 22, 17, 19,
+    15, 17, 19, 21, 17, 19, 21, 18, 20, 15,
+    17, 19, 21, 16, 18, 17, 19, 21, 15, 17,
+    19, 21, 15, 17, 18, 20, 22, 15, 17, 19,
+    21, 23, 17, 19
+};
+
+/* Value of 'm' from Annex A */
+static const char hx_module_m[] = {
+    0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    3, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    5, 5, 5, 5, 5, 5, 5, 5, 6, 6,
+    6, 6, 6, 6, 6, 6, 6, 7, 7, 7,
+    7, 7, 7, 7, 7, 8, 8, 8, 8, 8,
+    8, 8, 8, 8, 9, 9, 9, 9, 9, 9,
+    9, 9, 10, 10
+};
+
+/* Error correction block sizes from Table D1 */
+static const unsigned short int hx_table_d1[] = {
+    /* #blocks, k, 2t, #blocks, k, 2t, #blocks, k, 2t */
+    1, 21, 4, 0, 0, 0, 0, 0, 0, // version 1
+    1, 17, 8, 0, 0, 0, 0, 0, 0,
+    1, 13, 12, 0, 0, 0, 0, 0, 0,
+    1, 9, 16, 0, 0, 0, 0, 0, 0,
+    1, 31, 6, 0, 0, 0, 0, 0, 0, // version 2
+    1, 25, 12, 0, 0, 0, 0, 0, 0,
+    1, 19, 18, 0, 0, 0, 0, 0, 0,
+    1, 15, 22, 0, 0, 0, 0, 0, 0,
+    1, 42, 8, 0, 0, 0, 0, 0, 0, // version 3
+    1, 34, 16, 0, 0, 0, 0, 0, 0,
+    1, 26, 24, 0, 0, 0, 0, 0, 0,
+    1, 20, 30, 0, 0, 0, 0, 0, 0,
+    1, 46, 8, 0, 0, 0, 0, 0, 0, // version 4
+    1, 38, 16, 0, 0, 0, 0, 0, 0,
+    1, 30, 24, 0, 0, 0, 0, 0, 0,
+    1, 22, 32, 0, 0, 0, 0, 0, 0,
+    1, 57, 12, 0, 0, 0, 0, 0, 0, // version 5
+    1, 49, 20, 0, 0, 0, 0, 0, 0,
+    1, 37, 32, 0, 0, 0, 0, 0, 0,
+    1, 14, 20, 1, 13, 22, 0, 0, 0,
+    1, 70, 14, 0, 0, 0, 0, 0, 0, // version 6
+    1, 58, 26, 0, 0, 0, 0, 0, 0,
+    1, 24, 20, 1, 22, 18, 0, 0, 0,
+    1, 16, 24, 1, 18, 26, 0, 0, 0,
+    1, 84, 16, 0, 0, 0, 0, 0, 0, // version 7
+    1, 70, 30, 0, 0, 0, 0, 0, 0,
+    1, 26, 22, 1, 28, 24, 0, 0, 0,
+    2, 14, 20, 1, 12, 20, 0, 0, 0,
+    1, 99, 18, 0, 0, 0, 0, 0, 0, // version 8
+    1, 40, 18, 1, 41, 18, 0, 0, 0,
+    1, 31, 26, 1, 32, 28, 0, 0, 0,
+    2, 16, 24, 1, 15, 22, 0, 0, 0,
+    1, 114, 22, 0, 0, 0, 0, 0, 0, // version 9
+    2, 48, 20, 0, 0, 0, 0, 0, 0,
+    2, 24, 20, 1, 26, 22, 0, 0, 0,
+    2, 18, 28, 1, 18, 26, 0, 0, 0,
+    1, 131, 24, 0, 0, 0, 0, 0, 0, // version 10
+    1, 52, 22, 1, 57, 24, 0, 0, 0,
+    2, 27, 24, 1, 29, 24, 0, 0, 0,
+    2, 21, 32, 1, 19, 30, 0, 0, 0,
+    1, 135, 26, 0, 0, 0, 0, 0, 0, // version 11
+    1, 56, 24, 1, 57, 24, 0, 0, 0,
+    2, 28, 24, 1, 31, 26, 0, 0, 0,
+    2, 22, 32, 1, 21, 32, 0, 0, 0,
+    1, 153, 28, 0, 0, 0, 0, 0, 0, // version 12
+    1, 62, 26, 1, 65, 28, 0, 0, 0,
+    2, 32, 28, 1, 33, 28, 0, 0, 0,
+    3, 17, 26, 1, 22, 30, 0, 0, 0,
+    1, 86, 16, 1, 85, 16, 0, 0, 0, // version 13
+    1, 71, 30, 1, 72, 30, 0, 0, 0,
+    2, 37, 32, 1, 35, 30, 0, 0, 0,
+    3, 20, 30, 1, 21, 32, 0, 0, 0,
+    1, 94, 18, 1, 95, 18, 0, 0, 0, // version 14
+    2, 51, 22, 1, 55, 24, 0, 0, 0,
+    3, 30, 26, 1, 31, 26, 0, 0, 0,
+    4, 18, 28, 1, 17, 24, 0, 0, 0,
+    1, 104, 20, 1, 105, 20, 0, 0, 0, // version 15
+    2, 57, 24, 1, 61, 26, 0, 0, 0,
+    3, 33, 28, 1, 36, 30, 0, 0, 0,
+    4, 20, 30, 1, 19, 30, 0, 0, 0,
+    1, 115, 22, 1, 114, 22, 0, 0, 0, // version 16
+    2, 65, 28, 1, 61, 26, 0, 0, 0,
+    3, 38, 32, 1, 33, 30, 0, 0, 0,
+    5, 19, 28, 1, 14, 24, 0, 0, 0,
+    1, 126, 24, 1, 125, 24, 0, 0, 0, // version 17
+    2, 70, 30, 1, 69, 30, 0, 0, 0,
+    4, 33, 28, 1, 29, 26, 0, 0, 0,
+    5, 20, 30, 1, 19, 30, 0, 0, 0,
+    1, 136, 26, 1, 137, 26, 0, 0, 0, //version 18
+    3, 56, 24, 1, 59, 26, 0, 0, 0,
+    5, 35, 30, 0, 0, 0, 0, 0, 0,
+    6, 18, 28, 1, 21, 28, 0, 0, 0,
+    1, 148, 28, 1, 149, 28, 0, 0, 0, // version 19
+    3, 61, 26, 1, 64, 28, 0, 0, 0,
+    7, 24, 20, 1, 23, 22, 0, 0, 0,
+    6, 20, 30, 1, 21, 32, 0, 0, 0,
+    3, 107, 20, 0, 0, 0, 0, 0, 0, // version 20
+    3, 65, 28, 1, 72, 30, 0, 0, 0,
+    7, 26, 22, 1, 23, 22, 0, 0, 0,
+    7, 19, 28, 1, 20, 32, 0, 0, 0,
+    3, 115, 22, 0, 0, 0, 0, 0, 0, // version 21
+    4, 56, 24, 1, 63, 28, 0, 0, 0,
+    7, 28, 24, 1, 25, 22, 0, 0, 0,
+    8, 18, 28, 1, 21, 22, 0, 0, 0,
+    2, 116, 22, 1, 122, 24, 0, 0, 0, // version 22
+    4, 56, 24, 1, 72, 30, 0, 0, 0,
+    7, 28, 24, 1, 32, 26, 0, 0, 0,
+    8, 18, 28, 1, 24, 30, 0, 0, 0,
+    3, 127, 24, 0, 0, 0, 0, 0, 0, // version 23
+    5, 51, 22, 1, 62, 26, 0, 0, 0,
+    7, 30, 26, 1, 35, 26, 0, 0, 0,
+    8, 20, 30, 1, 21, 32, 0, 0, 0,
+    2, 135, 26, 1, 137, 26, 0, 0, 0, // version 24
+    5, 56, 24, 1, 59, 26, 0, 0, 0,
+    7, 33, 28, 1, 30, 28, 0, 0, 0,
+    11, 16, 24, 1, 19, 26, 0, 0, 0,
+    3, 105, 20, 1, 121, 22, 0, 0, 0, // version 25
+    5, 61, 26, 1, 57, 26, 0, 0, 0,
+    9, 28, 24, 1, 28, 22, 0, 0, 0,
+    10, 19, 28, 1, 18, 30, 0, 0, 0,
+    2, 157, 30, 1, 150, 28, 0, 0, 0, // version 26
+    5, 65, 28, 1, 61, 26, 0, 0, 0,
+    8, 33, 28, 1, 34, 30, 0, 0, 0,
+    10, 19, 28, 2, 15, 26, 0, 0, 0,
+    3, 126, 24, 1, 115, 22, 0, 0, 0, // version 27
+    7, 51, 22, 1, 54, 22, 0, 0, 0,
+    8, 35, 30, 1, 37, 30, 0, 0, 0,
+    15, 15, 22, 1, 10, 22, 0, 0, 0,
+    4, 105, 20, 1, 103, 20, 0, 0, 0, // version 28
+    7, 56, 24, 1, 45, 18, 0, 0, 0,
+    10, 31, 26, 1, 27, 26, 0, 0, 0,
+    10, 17, 26, 3, 20, 28, 1, 21, 28,
+    3, 139, 26, 1, 137, 28, 0, 0, 0, // version 29
+    6, 66, 28, 1, 66, 30, 0, 0, 0,
+    9, 36, 30, 1, 34, 32, 0, 0, 0,
+    13, 19, 28, 1, 17, 32, 0, 0, 0,
+    6, 84, 16, 1, 82, 16, 0, 0, 0, // version 30
+    6, 70, 30, 1, 68, 30, 0, 0, 0,
+    7, 35, 30, 3, 33, 28, 1, 32, 28,
+    13, 20, 30, 1, 20, 28, 0, 0, 0,
+    5, 105, 20, 1, 94, 18, 0, 0, 0, // version 31
+    6, 74, 32, 1, 71, 30, 0, 0, 0,
+    11, 33, 28, 1, 34, 32, 0, 0, 0,
+    13, 19, 28, 3, 16, 26, 0, 0, 0,
+    4, 127, 24, 1, 126, 24, 0, 0, 0, // version 32
+    7, 66, 28, 1, 66, 30, 0, 0, 0,
+    12, 30, 24, 1, 24, 28, 1, 24, 30,
+    15, 19, 28, 1, 17, 32, 0, 0, 0,
+    7, 84, 16, 1, 78, 16, 0, 0, 0, // version 33
+    7, 70, 30, 1, 66, 28, 0, 0, 0,
+    12, 33, 28, 1, 32, 30, 0, 0, 0,
+    14, 21, 32, 1, 24, 28, 0, 0, 0,
+    5, 117, 22, 1, 117, 24, 0, 0, 0, // version 34
+    8, 66, 28, 1, 58, 26, 0, 0, 0,
+    11, 38, 32, 1, 34, 32, 0, 0, 0,
+    15, 20, 30, 2, 17, 26, 0, 0, 0,
+    4, 148, 28, 1, 146, 28, 0, 0, 0, // version 35
+    8, 68, 30, 1, 70, 24, 0, 0, 0,
+    10, 36, 32, 3, 38, 28, 0, 0, 0,
+    16, 19, 28, 3, 16, 26, 0, 0, 0,
+    4, 126, 24, 2, 135, 26, 0, 0, 0, // version 36
+    8, 70, 28, 2, 43, 26, 0, 0, 0,
+    13, 32, 28, 2, 41, 30, 0, 0, 0,
+    17, 19, 28, 3, 15, 26, 0, 0, 0,
+    5, 136, 26, 1, 132, 24, 0, 0, 0, // version 37
+    5, 67, 30, 4, 68, 28, 1, 69, 28,
+    14, 35, 30, 1, 32, 24, 0, 0, 0,
+    18, 18, 26, 3, 16, 28, 1, 14, 28,
+    3, 142, 26, 3, 141, 28, 0, 0, 0, // version 38
+    8, 70, 30, 1, 73, 32, 1, 74, 32,
+    12, 34, 30, 3, 34, 26, 1, 35, 28,
+    18, 21, 32, 1, 27, 30, 0, 0, 0,
+    5, 116, 22, 2, 103, 20, 1, 102, 20, // version 39
+    9, 74, 32, 1, 74, 30, 0, 0, 0,
+    14, 34, 28, 2, 32, 32, 1, 32, 30,
+    19, 21, 32, 1, 25, 26, 0, 0, 0,
+    7, 116, 22, 1, 117, 22, 0, 0, 0, // version 40
+    11, 65, 28, 1, 58, 24, 0, 0, 0,
+    15, 38, 32, 1, 27, 28, 0, 0, 0,
+    20, 20, 30, 1, 20, 32, 1, 21, 32,
+    6, 136, 26, 1, 130, 24, 0, 0, 0, // version 41
+    11, 66, 28, 1, 62, 30, 0, 0, 0,
+    14, 34, 28, 3, 34, 32, 1, 30, 30,
+    18, 20, 30, 3, 20, 28, 2, 15, 26,
+    5, 105, 20, 2, 115, 22, 2, 116, 22, // version 42
+    10, 75, 32, 1, 73, 32, 0, 0, 0,
+    16, 38, 32, 1, 27, 28, 0, 0, 0,
+    22, 19, 28, 2, 16, 30, 1, 19, 30,
+    6, 147, 28, 1, 146, 28, 0, 0, 0, // version 43
+    11, 66, 28, 2, 65, 30, 0, 0, 0,
+    18, 33, 28, 2, 33, 30, 0, 0, 0,
+    22, 21, 32, 1, 28, 30, 0, 0, 0,
+    6, 116, 22, 3, 125, 24, 0, 0, 0, // version 44
+    11, 75, 32, 1, 68, 30, 0, 0, 0,
+    13, 35, 28, 6, 34, 32, 1, 30, 30,
+    23, 21, 32, 1, 26, 30, 0, 0, 0,
+    7, 105, 20, 4, 95, 18, 0, 0, 0, // version 45
+    12, 67, 28, 1, 63, 30, 1, 62, 32,
+    21, 31, 26, 2, 33, 32, 0, 0, 0,
+    23, 21, 32, 2, 24, 30, 0, 0, 0,
+    10, 116, 22, 0, 0, 0, 0, 0, 0, // version 46
+    12, 74, 32, 1, 78, 30, 0, 0, 0,
+    18, 37, 32, 1, 39, 30, 1, 41, 28,
+    25, 21, 32, 1, 27, 28, 0, 0, 0,
+    5, 126, 24, 4, 115, 22, 1, 114, 22, // version 47
+    12, 67, 28, 2, 66, 32, 1, 68, 30,
+    21, 35, 30, 1, 39, 30, 0, 0, 0,
+    26, 21, 32, 1, 28, 28, 0, 0, 0,
+    9, 126, 24, 1, 117, 22, 0, 0, 0, // version 48
+    13, 75, 32, 1, 68, 30, 0, 0, 0,
+    20, 35, 30, 3, 35, 28, 0, 0, 0,
+    27, 21, 32, 1, 28, 30, 0, 0, 0,
+    9, 126, 24, 1, 137, 26, 0, 0, 0, // version 49
+    13, 71, 30, 2, 68, 32, 0, 0, 0,
+    20, 37, 32, 1, 39, 28, 1, 38, 28,
+    24, 20, 32, 5, 25, 28, 0, 0, 0,
+    8, 147, 28, 1, 141, 28, 0, 0, 0, // version 50
+    10, 73, 32, 4, 74, 30, 1, 73, 30,
+    16, 36, 32, 6, 39, 30, 1, 37, 30,
+    27, 21, 32, 3, 20, 26, 0, 0, 0,
+    9, 137, 26, 1, 135, 26, 0, 0, 0, // version 51
+    12, 70, 30, 4, 75, 32, 0, 0, 0,
+    24, 35, 30, 1, 40, 28, 0, 0, 0,
+    23, 20, 32, 8, 24, 30, 0, 0, 0,
+    14, 95, 18, 1, 86, 18, 0, 0, 0, // version 52
+    13, 73, 32, 3, 77, 30, 0, 0, 0,
+    24, 35, 30, 2, 35, 28, 0, 0, 0,
+    26, 21, 32, 5, 21, 30, 1, 23, 30,
+    9, 147, 28, 1, 142, 28, 0, 0, 0, // version 53
+    10, 73, 30, 6, 70, 32, 1, 71, 32,
+    25, 35, 30, 2, 34, 26, 0, 0, 0,
+    29, 21, 32, 4, 22, 30, 0, 0, 0,
+    11, 126, 24, 1, 131, 24, 0, 0, 0, // version 54
+    16, 74, 32, 1, 79, 30, 0, 0, 0,
+    25, 38, 32, 1, 25, 30, 0, 0, 0,
+    33, 21, 32, 1, 28, 28, 0, 0, 0,
+    14, 105, 20, 1, 99, 18, 0, 0, 0, // version 55
+    19, 65, 28, 1, 72, 28, 0, 0, 0,
+    24, 37, 32, 2, 40, 30, 1, 41, 30,
+    31, 21, 32, 4, 24, 32, 0, 0, 0,
+    10, 147, 28, 1, 151, 28, 0, 0, 0, // version 56
+    15, 71, 30, 3, 71, 32, 1, 73, 32,
+    24, 37, 32, 3, 38, 30, 1, 39, 30,
+    36, 19, 30, 3, 29, 26, 0, 0, 0,
+    15, 105, 20, 1, 99, 18, 0, 0, 0, // version 57
+    19, 70, 30, 1, 64, 28, 0, 0, 0,
+    27, 38, 32, 2, 25, 26, 0, 0, 0,
+    38, 20, 30, 2, 18, 28, 0, 0, 0,
+    14, 105, 20, 1, 113, 22, 1, 114, 22, // version 58
+    17, 67, 30, 3, 92, 32, 0, 0, 0,
+    30, 35, 30, 1, 41, 30, 0, 0, 0,
+    36, 21, 32, 1, 26, 30, 1, 27, 30,
+    11, 146, 28, 1, 146, 26, 0, 0, 0, // version 59
+    20, 70, 30, 1, 60, 26, 0, 0, 0,
+    29, 38, 32, 1, 24, 32, 0, 0, 0,
+    40, 20, 30, 2, 17, 26, 0, 0, 0,
+    3, 137, 26, 1, 136, 26, 10, 126, 24, // version 60
+    22, 65, 28, 1, 75, 30, 0, 0, 0,
+    30, 37, 32, 1, 51, 30, 0, 0, 0,
+    42, 20, 30, 1, 21, 30, 0, 0, 0,
+    12, 126, 24, 2, 118, 22, 1, 116, 22, // version 61
+    19, 74, 32, 1, 74, 30, 1, 72, 28,
+    30, 38, 32, 2, 29, 30, 0, 0, 0,
+    39, 20, 32, 2, 37, 26, 1, 38, 26,
+    12, 126, 24, 3, 136, 26, 0, 0, 0, // version 62
+    21, 70, 30, 2, 65, 28, 0, 0, 0,
+    34, 35, 30, 1, 44, 32, 0, 0, 0,
+    42, 20, 30, 2, 19, 28, 2, 18, 28,
+    12, 126, 24, 3, 117, 22, 1, 116, 22, // version 63
+    25, 61, 26, 2, 62, 28, 0, 0, 0,
+    34, 35, 30, 1, 40, 32, 1, 41, 32,
+    45, 20, 30, 1, 20, 32, 1, 21, 32,
+    15, 105, 20, 2, 115, 22, 2, 116, 22, // version 64
+    25, 65, 28, 1, 72, 28, 0, 0, 0,
+    18, 35, 30, 17, 37, 32, 1, 50, 32,
+    42, 20, 30, 6, 19, 28, 1, 15, 28,
+    19, 105, 20, 1, 101, 20, 0, 0, 0, // version 65
+    33, 51, 22, 1, 65, 22, 0, 0, 0,
+    40, 33, 28, 1, 28, 28, 0, 0, 0,
+    49, 20, 30, 1, 18, 28, 0, 0, 0,
+    18, 105, 20, 2, 117, 22, 0, 0, 0, // version 66
+    26, 65, 28, 1, 80, 30, 0, 0, 0,
+    35, 35, 30, 3, 35, 28, 1, 36, 28,
+    52, 18, 28, 2, 38, 30, 0, 0, 0,
+    26, 84, 16, 0, 0, 0, 0, 0, 0, // version 67
+    26, 70, 30, 0, 0, 0, 0, 0, 0,
+    45, 31, 26, 1, 9, 26, 0, 0, 0,
+    52, 20, 30, 0, 0, 0, 0, 0, 0,
+    16, 126, 24, 1, 114, 22, 1, 115, 22, // version 68
+    23, 70, 30, 3, 65, 28, 1, 66, 28,
+    40, 35, 30, 1, 43, 30, 0, 0, 0,
+    46, 20, 30, 7, 19, 28, 1, 16, 28,
+    19, 116, 22, 1, 105, 22, 0, 0, 0, // version 69
+    20, 70, 30, 7, 66, 28, 1, 63, 28,
+    40, 35, 30, 1, 42, 32, 1, 43, 32,
+    54, 20, 30, 1, 19, 30, 0, 0, 0,
+    17, 126, 24, 2, 115, 22, 0, 0, 0, // version 70
+    24, 70, 30, 4, 74, 32, 0, 0, 0,
+    48, 31, 26, 2, 18, 26, 0, 0, 0,
+    54, 19, 28, 6, 15, 26, 1, 14, 26,
+    29, 84, 16, 0, 0, 0, 0, 0, 0, // version 71
+    29, 70, 30, 0, 0, 0, 0, 0, 0,
+    6, 34, 30, 3, 36, 30, 38, 33, 28,
+    58, 20, 30, 0, 0, 0, 0, 0, 0,
+    16, 147, 28, 1, 149, 28, 0, 0, 0, // version 72
+    31, 66, 28, 1, 37, 26, 0, 0, 0,
+    48, 33, 28, 1, 23, 26, 0, 0, 0,
+    53, 20, 30, 6, 19, 28, 1, 17, 28,
+    20, 115, 22, 2, 134, 24, 0, 0, 0, // verdion 73
+    29, 66, 28, 2, 56, 26, 2, 57, 26,
+    45, 36, 30, 2, 15, 28, 0, 0, 0,
+    59, 20, 30, 2, 21, 32, 0, 0, 0,
+    17, 147, 28, 1, 134, 26, 0, 0, 0, // version 74
+    26, 70, 30, 5, 75, 32, 0, 0, 0,
+    47, 35, 30, 1, 48, 32, 0, 0, 0,
+    64, 18, 28, 2, 33, 30, 1, 35, 30,
+    22, 115, 22, 1, 133, 24, 0, 0, 0, // version 75
+    33, 65, 28, 1, 74, 28, 0, 0, 0,
+    43, 36, 30, 5, 27, 28, 1, 30, 28,
+    57, 20, 30, 5, 21, 32, 1, 24, 32,
+    18, 136, 26, 2, 142, 26, 0, 0, 0, // version 76
+    33, 66, 28, 2, 49, 26, 0, 0, 0,
+    48, 35, 30, 2, 38, 28, 0, 0, 0,
+    64, 20, 30, 1, 20, 32, 0, 0, 0,
+    19, 126, 24, 2, 135, 26, 1, 136, 26, // version 77
+    32, 66, 28, 2, 55, 26, 2, 56, 26,
+    49, 36, 30, 2, 18, 32, 0, 0, 0,
+    65, 18, 28, 5, 27, 30, 1, 29, 30,
+    20, 137, 26, 1, 130, 26, 0, 0, 0, // version 78
+    30, 75, 32, 2, 71, 32, 0, 0, 0,
+    46, 35, 30, 6, 39, 32, 0, 0, 0,
+    3, 12, 30, 70, 19, 28, 0, 0, 0,
+    20, 147, 28, 0, 0, 0, 0, 0, 0, // version 79
+    35, 70, 30, 0, 0, 0, 0, 0, 0,
+    49, 35, 30, 5, 35, 28, 0, 0, 0,
+    70, 20, 30, 0, 0, 0, 0, 0, 0,
+    21, 136, 26, 1, 155, 28, 0, 0, 0, // version 80
+    34, 70, 30, 1, 64, 28, 1, 65, 28,
+    54, 35, 30, 1, 45, 30, 0, 0, 0,
+    68, 20, 30, 3, 18, 28, 1, 19, 28,
+    19, 126, 24, 5, 115, 22, 1, 114, 22, // version 81
+    33, 70, 30, 3, 65, 28, 1, 64, 28,
+    52, 35, 30, 3, 41, 32, 1, 40, 32,
+    67, 20, 30, 5, 21, 32, 1, 24, 32,
+    2, 150, 28, 21, 136, 26, 0, 0, 0, // version 82
+    32, 70, 30, 6, 65, 28, 0, 0, 0,
+    52, 38, 32, 2, 27, 32, 0, 0, 0,
+    73, 20, 30, 2, 22, 32, 0, 0, 0,
+    21, 126, 24, 4, 136, 26, 0, 0, 0, // version 83
+    30, 74, 32, 6, 73, 30, 0, 0, 0,
+    54, 35, 30, 4, 40, 32, 0, 0, 0,
+    75, 20, 30, 1, 20, 28, 0, 0, 0,
+    30, 105, 20, 1, 114, 22, 0, 0, 0, // version 84
+    3, 45, 22, 55, 47, 20, 0, 0, 0,
+    2, 26, 26, 62, 33, 28, 0, 0, 0,
+    79, 18, 28, 4, 33, 30, 0, 0, 0
+};
diff --git a/backend/imail.c b/backend/imail.c
new file mode 100644 (file)
index 0000000..1b90efe
--- /dev/null
@@ -0,0 +1,442 @@
+/* imail.c - Handles Intelligent Mail (aka OneCode) for USPS */
+
+/*
+    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 : */
+
+/*  The function "USPS_MSB_Math_CRC11GenerateFrameCheckSequence"
+    is Copyright (C) 2006 United States Postal Service */
+
+#include <stdio.h>
+#include "common.h"
+#include "large.h"
+
+#define SODIUM  "0123456789-"
+
+/* The following lookup tables were generated using the code in Appendix C */
+
+static const unsigned short AppxD_I[1287] = {
+    /* Appendix D Table 1 - 5 of 13 characters */
+    0x001F, 0x1F00, 0x002F, 0x1E80, 0x0037, 0x1D80, 0x003B, 0x1B80, 0x003D, 0x1780,
+    0x003E, 0x0F80, 0x004F, 0x1E40, 0x0057, 0x1D40, 0x005B, 0x1B40, 0x005D, 0x1740,
+    0x005E, 0x0F40, 0x0067, 0x1CC0, 0x006B, 0x1AC0, 0x006D, 0x16C0, 0x006E, 0x0EC0,
+    0x0073, 0x19C0, 0x0075, 0x15C0, 0x0076, 0x0DC0, 0x0079, 0x13C0, 0x007A, 0x0BC0,
+    0x007C, 0x07C0, 0x008F, 0x1E20, 0x0097, 0x1D20, 0x009B, 0x1B20, 0x009D, 0x1720,
+    0x009E, 0x0F20, 0x00A7, 0x1CA0, 0x00AB, 0x1AA0, 0x00AD, 0x16A0, 0x00AE, 0x0EA0,
+    0x00B3, 0x19A0, 0x00B5, 0x15A0, 0x00B6, 0x0DA0, 0x00B9, 0x13A0, 0x00BA, 0x0BA0,
+    0x00BC, 0x07A0, 0x00C7, 0x1C60, 0x00CB, 0x1A60, 0x00CD, 0x1660, 0x00CE, 0x0E60,
+    0x00D3, 0x1960, 0x00D5, 0x1560, 0x00D6, 0x0D60, 0x00D9, 0x1360, 0x00DA, 0x0B60,
+    0x00DC, 0x0760, 0x00E3, 0x18E0, 0x00E5, 0x14E0, 0x00E6, 0x0CE0, 0x00E9, 0x12E0,
+    0x00EA, 0x0AE0, 0x00EC, 0x06E0, 0x00F1, 0x11E0, 0x00F2, 0x09E0, 0x00F4, 0x05E0,
+    0x00F8, 0x03E0, 0x010F, 0x1E10, 0x0117, 0x1D10, 0x011B, 0x1B10, 0x011D, 0x1710,
+    0x011E, 0x0F10, 0x0127, 0x1C90, 0x012B, 0x1A90, 0x012D, 0x1690, 0x012E, 0x0E90,
+    0x0133, 0x1990, 0x0135, 0x1590, 0x0136, 0x0D90, 0x0139, 0x1390, 0x013A, 0x0B90,
+    0x013C, 0x0790, 0x0147, 0x1C50, 0x014B, 0x1A50, 0x014D, 0x1650, 0x014E, 0x0E50,
+    0x0153, 0x1950, 0x0155, 0x1550, 0x0156, 0x0D50, 0x0159, 0x1350, 0x015A, 0x0B50,
+    0x015C, 0x0750, 0x0163, 0x18D0, 0x0165, 0x14D0, 0x0166, 0x0CD0, 0x0169, 0x12D0,
+    0x016A, 0x0AD0, 0x016C, 0x06D0, 0x0171, 0x11D0, 0x0172, 0x09D0, 0x0174, 0x05D0,
+    0x0178, 0x03D0, 0x0187, 0x1C30, 0x018B, 0x1A30, 0x018D, 0x1630, 0x018E, 0x0E30,
+    0x0193, 0x1930, 0x0195, 0x1530, 0x0196, 0x0D30, 0x0199, 0x1330, 0x019A, 0x0B30,
+    0x019C, 0x0730, 0x01A3, 0x18B0, 0x01A5, 0x14B0, 0x01A6, 0x0CB0, 0x01A9, 0x12B0,
+    0x01AA, 0x0AB0, 0x01AC, 0x06B0, 0x01B1, 0x11B0, 0x01B2, 0x09B0, 0x01B4, 0x05B0,
+    0x01B8, 0x03B0, 0x01C3, 0x1870, 0x01C5, 0x1470, 0x01C6, 0x0C70, 0x01C9, 0x1270,
+    0x01CA, 0x0A70, 0x01CC, 0x0670, 0x01D1, 0x1170, 0x01D2, 0x0970, 0x01D4, 0x0570,
+    0x01D8, 0x0370, 0x01E1, 0x10F0, 0x01E2, 0x08F0, 0x01E4, 0x04F0, 0x01E8, 0x02F0,
+    0x020F, 0x1E08, 0x0217, 0x1D08, 0x021B, 0x1B08, 0x021D, 0x1708, 0x021E, 0x0F08,
+    0x0227, 0x1C88, 0x022B, 0x1A88, 0x022D, 0x1688, 0x022E, 0x0E88, 0x0233, 0x1988,
+    0x0235, 0x1588, 0x0236, 0x0D88, 0x0239, 0x1388, 0x023A, 0x0B88, 0x023C, 0x0788,
+    0x0247, 0x1C48, 0x024B, 0x1A48, 0x024D, 0x1648, 0x024E, 0x0E48, 0x0253, 0x1948,
+    0x0255, 0x1548, 0x0256, 0x0D48, 0x0259, 0x1348, 0x025A, 0x0B48, 0x025C, 0x0748,
+    0x0263, 0x18C8, 0x0265, 0x14C8, 0x0266, 0x0CC8, 0x0269, 0x12C8, 0x026A, 0x0AC8,
+    0x026C, 0x06C8, 0x0271, 0x11C8, 0x0272, 0x09C8, 0x0274, 0x05C8, 0x0278, 0x03C8,
+    0x0287, 0x1C28, 0x028B, 0x1A28, 0x028D, 0x1628, 0x028E, 0x0E28, 0x0293, 0x1928,
+    0x0295, 0x1528, 0x0296, 0x0D28, 0x0299, 0x1328, 0x029A, 0x0B28, 0x029C, 0x0728,
+    0x02A3, 0x18A8, 0x02A5, 0x14A8, 0x02A6, 0x0CA8, 0x02A9, 0x12A8, 0x02AA, 0x0AA8,
+    0x02AC, 0x06A8, 0x02B1, 0x11A8, 0x02B2, 0x09A8, 0x02B4, 0x05A8, 0x02B8, 0x03A8,
+    0x02C3, 0x1868, 0x02C5, 0x1468, 0x02C6, 0x0C68, 0x02C9, 0x1268, 0x02CA, 0x0A68,
+    0x02CC, 0x0668, 0x02D1, 0x1168, 0x02D2, 0x0968, 0x02D4, 0x0568, 0x02D8, 0x0368,
+    0x02E1, 0x10E8, 0x02E2, 0x08E8, 0x02E4, 0x04E8, 0x0307, 0x1C18, 0x030B, 0x1A18,
+    0x030D, 0x1618, 0x030E, 0x0E18, 0x0313, 0x1918, 0x0315, 0x1518, 0x0316, 0x0D18,
+    0x0319, 0x1318, 0x031A, 0x0B18, 0x031C, 0x0718, 0x0323, 0x1898, 0x0325, 0x1498,
+    0x0326, 0x0C98, 0x0329, 0x1298, 0x032A, 0x0A98, 0x032C, 0x0698, 0x0331, 0x1198,
+    0x0332, 0x0998, 0x0334, 0x0598, 0x0338, 0x0398, 0x0343, 0x1858, 0x0345, 0x1458,
+    0x0346, 0x0C58, 0x0349, 0x1258, 0x034A, 0x0A58, 0x034C, 0x0658, 0x0351, 0x1158,
+    0x0352, 0x0958, 0x0354, 0x0558, 0x0361, 0x10D8, 0x0362, 0x08D8, 0x0364, 0x04D8,
+    0x0383, 0x1838, 0x0385, 0x1438, 0x0386, 0x0C38, 0x0389, 0x1238, 0x038A, 0x0A38,
+    0x038C, 0x0638, 0x0391, 0x1138, 0x0392, 0x0938, 0x0394, 0x0538, 0x03A1, 0x10B8,
+    0x03A2, 0x08B8, 0x03A4, 0x04B8, 0x03C1, 0x1078, 0x03C2, 0x0878, 0x03C4, 0x0478,
+    0x040F, 0x1E04, 0x0417, 0x1D04, 0x041B, 0x1B04, 0x041D, 0x1704, 0x041E, 0x0F04,
+    0x0427, 0x1C84, 0x042B, 0x1A84, 0x042D, 0x1684, 0x042E, 0x0E84, 0x0433, 0x1984,
+    0x0435, 0x1584, 0x0436, 0x0D84, 0x0439, 0x1384, 0x043A, 0x0B84, 0x043C, 0x0784,
+    0x0447, 0x1C44, 0x044B, 0x1A44, 0x044D, 0x1644, 0x044E, 0x0E44, 0x0453, 0x1944,
+    0x0455, 0x1544, 0x0456, 0x0D44, 0x0459, 0x1344, 0x045A, 0x0B44, 0x045C, 0x0744,
+    0x0463, 0x18C4, 0x0465, 0x14C4, 0x0466, 0x0CC4, 0x0469, 0x12C4, 0x046A, 0x0AC4,
+    0x046C, 0x06C4, 0x0471, 0x11C4, 0x0472, 0x09C4, 0x0474, 0x05C4, 0x0487, 0x1C24,
+    0x048B, 0x1A24, 0x048D, 0x1624, 0x048E, 0x0E24, 0x0493, 0x1924, 0x0495, 0x1524,
+    0x0496, 0x0D24, 0x0499, 0x1324, 0x049A, 0x0B24, 0x049C, 0x0724, 0x04A3, 0x18A4,
+    0x04A5, 0x14A4, 0x04A6, 0x0CA4, 0x04A9, 0x12A4, 0x04AA, 0x0AA4, 0x04AC, 0x06A4,
+    0x04B1, 0x11A4, 0x04B2, 0x09A4, 0x04B4, 0x05A4, 0x04C3, 0x1864, 0x04C5, 0x1464,
+    0x04C6, 0x0C64, 0x04C9, 0x1264, 0x04CA, 0x0A64, 0x04CC, 0x0664, 0x04D1, 0x1164,
+    0x04D2, 0x0964, 0x04D4, 0x0564, 0x04E1, 0x10E4, 0x04E2, 0x08E4, 0x0507, 0x1C14,
+    0x050B, 0x1A14, 0x050D, 0x1614, 0x050E, 0x0E14, 0x0513, 0x1914, 0x0515, 0x1514,
+    0x0516, 0x0D14, 0x0519, 0x1314, 0x051A, 0x0B14, 0x051C, 0x0714, 0x0523, 0x1894,
+    0x0525, 0x1494, 0x0526, 0x0C94, 0x0529, 0x1294, 0x052A, 0x0A94, 0x052C, 0x0694,
+    0x0531, 0x1194, 0x0532, 0x0994, 0x0534, 0x0594, 0x0543, 0x1854, 0x0545, 0x1454,
+    0x0546, 0x0C54, 0x0549, 0x1254, 0x054A, 0x0A54, 0x054C, 0x0654, 0x0551, 0x1154,
+    0x0552, 0x0954, 0x0561, 0x10D4, 0x0562, 0x08D4, 0x0583, 0x1834, 0x0585, 0x1434,
+    0x0586, 0x0C34, 0x0589, 0x1234, 0x058A, 0x0A34, 0x058C, 0x0634, 0x0591, 0x1134,
+    0x0592, 0x0934, 0x05A1, 0x10B4, 0x05A2, 0x08B4, 0x05C1, 0x1074, 0x05C2, 0x0874,
+    0x0607, 0x1C0C, 0x060B, 0x1A0C, 0x060D, 0x160C, 0x060E, 0x0E0C, 0x0613, 0x190C,
+    0x0615, 0x150C, 0x0616, 0x0D0C, 0x0619, 0x130C, 0x061A, 0x0B0C, 0x061C, 0x070C,
+    0x0623, 0x188C, 0x0625, 0x148C, 0x0626, 0x0C8C, 0x0629, 0x128C, 0x062A, 0x0A8C,
+    0x062C, 0x068C, 0x0631, 0x118C, 0x0632, 0x098C, 0x0643, 0x184C, 0x0645, 0x144C,
+    0x0646, 0x0C4C, 0x0649, 0x124C, 0x064A, 0x0A4C, 0x0651, 0x114C, 0x0652, 0x094C,
+    0x0661, 0x10CC, 0x0662, 0x08CC, 0x0683, 0x182C, 0x0685, 0x142C, 0x0686, 0x0C2C,
+    0x0689, 0x122C, 0x068A, 0x0A2C, 0x0691, 0x112C, 0x0692, 0x092C, 0x06A1, 0x10AC,
+    0x06A2, 0x08AC, 0x06C1, 0x106C, 0x06C2, 0x086C, 0x0703, 0x181C, 0x0705, 0x141C,
+    0x0706, 0x0C1C, 0x0709, 0x121C, 0x070A, 0x0A1C, 0x0711, 0x111C, 0x0712, 0x091C,
+    0x0721, 0x109C, 0x0722, 0x089C, 0x0741, 0x105C, 0x0742, 0x085C, 0x0781, 0x103C,
+    0x0782, 0x083C, 0x080F, 0x1E02, 0x0817, 0x1D02, 0x081B, 0x1B02, 0x081D, 0x1702,
+    0x081E, 0x0F02, 0x0827, 0x1C82, 0x082B, 0x1A82, 0x082D, 0x1682, 0x082E, 0x0E82,
+    0x0833, 0x1982, 0x0835, 0x1582, 0x0836, 0x0D82, 0x0839, 0x1382, 0x083A, 0x0B82,
+    0x0847, 0x1C42, 0x084B, 0x1A42, 0x084D, 0x1642, 0x084E, 0x0E42, 0x0853, 0x1942,
+    0x0855, 0x1542, 0x0856, 0x0D42, 0x0859, 0x1342, 0x085A, 0x0B42, 0x0863, 0x18C2,
+    0x0865, 0x14C2, 0x0866, 0x0CC2, 0x0869, 0x12C2, 0x086A, 0x0AC2, 0x0871, 0x11C2,
+    0x0872, 0x09C2, 0x0887, 0x1C22, 0x088B, 0x1A22, 0x088D, 0x1622, 0x088E, 0x0E22,
+    0x0893, 0x1922, 0x0895, 0x1522, 0x0896, 0x0D22, 0x0899, 0x1322, 0x089A, 0x0B22,
+    0x08A3, 0x18A2, 0x08A5, 0x14A2, 0x08A6, 0x0CA2, 0x08A9, 0x12A2, 0x08AA, 0x0AA2,
+    0x08B1, 0x11A2, 0x08B2, 0x09A2, 0x08C3, 0x1862, 0x08C5, 0x1462, 0x08C6, 0x0C62,
+    0x08C9, 0x1262, 0x08CA, 0x0A62, 0x08D1, 0x1162, 0x08D2, 0x0962, 0x08E1, 0x10E2,
+    0x0907, 0x1C12, 0x090B, 0x1A12, 0x090D, 0x1612, 0x090E, 0x0E12, 0x0913, 0x1912,
+    0x0915, 0x1512, 0x0916, 0x0D12, 0x0919, 0x1312, 0x091A, 0x0B12, 0x0923, 0x1892,
+    0x0925, 0x1492, 0x0926, 0x0C92, 0x0929, 0x1292, 0x092A, 0x0A92, 0x0931, 0x1192,
+    0x0932, 0x0992, 0x0943, 0x1852, 0x0945, 0x1452, 0x0946, 0x0C52, 0x0949, 0x1252,
+    0x094A, 0x0A52, 0x0951, 0x1152, 0x0961, 0x10D2, 0x0983, 0x1832, 0x0985, 0x1432,
+    0x0986, 0x0C32, 0x0989, 0x1232, 0x098A, 0x0A32, 0x0991, 0x1132, 0x09A1, 0x10B2,
+    0x09C1, 0x1072, 0x0A07, 0x1C0A, 0x0A0B, 0x1A0A, 0x0A0D, 0x160A, 0x0A0E, 0x0E0A,
+    0x0A13, 0x190A, 0x0A15, 0x150A, 0x0A16, 0x0D0A, 0x0A19, 0x130A, 0x0A1A, 0x0B0A,
+    0x0A23, 0x188A, 0x0A25, 0x148A, 0x0A26, 0x0C8A, 0x0A29, 0x128A, 0x0A2A, 0x0A8A,
+    0x0A31, 0x118A, 0x0A43, 0x184A, 0x0A45, 0x144A, 0x0A46, 0x0C4A, 0x0A49, 0x124A,
+    0x0A51, 0x114A, 0x0A61, 0x10CA, 0x0A83, 0x182A, 0x0A85, 0x142A, 0x0A86, 0x0C2A,
+    0x0A89, 0x122A, 0x0A91, 0x112A, 0x0AA1, 0x10AA, 0x0AC1, 0x106A, 0x0B03, 0x181A,
+    0x0B05, 0x141A, 0x0B06, 0x0C1A, 0x0B09, 0x121A, 0x0B11, 0x111A, 0x0B21, 0x109A,
+    0x0B41, 0x105A, 0x0B81, 0x103A, 0x0C07, 0x1C06, 0x0C0B, 0x1A06, 0x0C0D, 0x1606,
+    0x0C0E, 0x0E06, 0x0C13, 0x1906, 0x0C15, 0x1506, 0x0C16, 0x0D06, 0x0C19, 0x1306,
+    0x0C23, 0x1886, 0x0C25, 0x1486, 0x0C26, 0x0C86, 0x0C29, 0x1286, 0x0C31, 0x1186,
+    0x0C43, 0x1846, 0x0C45, 0x1446, 0x0C49, 0x1246, 0x0C51, 0x1146, 0x0C61, 0x10C6,
+    0x0C83, 0x1826, 0x0C85, 0x1426, 0x0C89, 0x1226, 0x0C91, 0x1126, 0x0CA1, 0x10A6,
+    0x0CC1, 0x1066, 0x0D03, 0x1816, 0x0D05, 0x1416, 0x0D09, 0x1216, 0x0D11, 0x1116,
+    0x0D21, 0x1096, 0x0D41, 0x1056, 0x0D81, 0x1036, 0x0E03, 0x180E, 0x0E05, 0x140E,
+    0x0E09, 0x120E, 0x0E11, 0x110E, 0x0E21, 0x108E, 0x0E41, 0x104E, 0x0E81, 0x102E,
+    0x0F01, 0x101E, 0x100F, 0x1E01, 0x1017, 0x1D01, 0x101B, 0x1B01, 0x101D, 0x1701,
+    0x1027, 0x1C81, 0x102B, 0x1A81, 0x102D, 0x1681, 0x1033, 0x1981, 0x1035, 0x1581,
+    0x1039, 0x1381, 0x1047, 0x1C41, 0x104B, 0x1A41, 0x104D, 0x1641, 0x1053, 0x1941,
+    0x1055, 0x1541, 0x1059, 0x1341, 0x1063, 0x18C1, 0x1065, 0x14C1, 0x1069, 0x12C1,
+    0x1071, 0x11C1, 0x1087, 0x1C21, 0x108B, 0x1A21, 0x108D, 0x1621, 0x1093, 0x1921,
+    0x1095, 0x1521, 0x1099, 0x1321, 0x10A3, 0x18A1, 0x10A5, 0x14A1, 0x10A9, 0x12A1,
+    0x10B1, 0x11A1, 0x10C3, 0x1861, 0x10C5, 0x1461, 0x10C9, 0x1261, 0x10D1, 0x1161,
+    0x1107, 0x1C11, 0x110B, 0x1A11, 0x110D, 0x1611, 0x1113, 0x1911, 0x1115, 0x1511,
+    0x1119, 0x1311, 0x1123, 0x1891, 0x1125, 0x1491, 0x1129, 0x1291, 0x1131, 0x1191,
+    0x1143, 0x1851, 0x1145, 0x1451, 0x1149, 0x1251, 0x1183, 0x1831, 0x1185, 0x1431,
+    0x1189, 0x1231, 0x1207, 0x1C09, 0x120B, 0x1A09, 0x120D, 0x1609, 0x1213, 0x1909,
+    0x1215, 0x1509, 0x1219, 0x1309, 0x1223, 0x1889, 0x1225, 0x1489, 0x1229, 0x1289,
+    0x1243, 0x1849, 0x1245, 0x1449, 0x1283, 0x1829, 0x1285, 0x1429, 0x1303, 0x1819,
+    0x1305, 0x1419, 0x1407, 0x1C05, 0x140B, 0x1A05, 0x140D, 0x1605, 0x1413, 0x1905,
+    0x1415, 0x1505, 0x1423, 0x1885, 0x1425, 0x1485, 0x1443, 0x1845, 0x1483, 0x1825,
+    0x1503, 0x1815, 0x1603, 0x180D, 0x1807, 0x1C03, 0x180B, 0x1A03, 0x1813, 0x1903,
+    0x1823, 0x1883, 0x1843, 0x1445, 0x1249, 0x1151, 0x10E1, 0x0C46, 0x0A4A, 0x0952,
+    0x08E2, 0x064C, 0x0554, 0x04E4, 0x0358, 0x02E8, 0x01F0
+};
+
+static const unsigned short AppxD_II[78] = {
+    /* Appendix D Table II - 2 of 13 characters */
+    0x0003, 0x1800, 0x0005, 0x1400, 0x0006, 0x0C00, 0x0009, 0x1200, 0x000A, 0x0A00,
+    0x000C, 0x0600, 0x0011, 0x1100, 0x0012, 0x0900, 0x0014, 0x0500, 0x0018, 0x0300,
+    0x0021, 0x1080, 0x0022, 0x0880, 0x0024, 0x0480, 0x0028, 0x0280, 0x0030, 0x0180,
+    0x0041, 0x1040, 0x0042, 0x0840, 0x0044, 0x0440, 0x0048, 0x0240, 0x0050, 0x0140,
+    0x0060, 0x00C0, 0x0081, 0x1020, 0x0082, 0x0820, 0x0084, 0x0420, 0x0088, 0x0220,
+    0x0090, 0x0120, 0x0101, 0x1010, 0x0102, 0x0810, 0x0104, 0x0410, 0x0108, 0x0210,
+    0x0201, 0x1008, 0x0202, 0x0808, 0x0204, 0x0408, 0x0401, 0x1004, 0x0402, 0x0804,
+    0x0801, 0x1002, 0x1001, 0x0802, 0x0404, 0x0208, 0x0110, 0x00A0
+};
+
+static const unsigned short int AppxD_IV[130] = {
+    /* Appendix D Table IV - Bar-to-Character Mapping (reverse lookup) */
+    67, 6, 78, 16, 86, 95, 34, 40, 45, 113, 117, 121, 62, 87, 18, 104, 41, 76, 57, 119, 115, 72, 97,
+    2, 127, 26, 105, 35, 122, 52, 114, 7, 24, 82, 68, 63, 94, 44, 77, 112, 70, 100, 39, 30, 107,
+    15, 125, 85, 10, 65, 54, 88, 20, 106, 46, 66, 8, 116, 29, 61, 99, 80, 90, 37, 123, 51, 25, 84,
+    129, 56, 4, 109, 96, 28, 36, 47, 11, 71, 33, 102, 21, 9, 17, 49, 124, 79, 64, 91, 42, 69, 53,
+    60, 14, 1, 27, 103, 126, 75, 89, 50, 120, 19, 32, 110, 92, 111, 130, 59, 31, 12, 81, 43, 55,
+    5, 74, 22, 101, 128, 58, 118, 48, 108, 38, 98, 93, 23, 83, 13, 73, 3
+};
+
+/***************************************************************************
+ ** USPS_MSB_Math_CRC11GenerateFrameCheckSequence
+ **
+ ** Inputs:
+ **   ByteAttayPtr is the address of a 13 byte array holding 102 bits which
+ **   are right justified - ie: the leftmost 2 bits of the first byte do not
+ **   hold data and must be set to zero.
+ **
+ ** Outputs:
+ **   return unsigned short - 11 bit Frame Check Sequence (right justified)
+ ***************************************************************************/
+static unsigned short USPS_MSB_Math_CRC11GenerateFrameCheckSequence(unsigned char *ByteArrayPtr) {
+    unsigned short GeneratorPolynomial = 0x0F35;
+    unsigned short FrameCheckSequence = 0x07FF;
+    unsigned short Data;
+    int ByteIndex, Bit;
+
+    /* Do most significant byte skipping the 2 most significant bits */
+    Data = *ByteArrayPtr << 5;
+    ByteArrayPtr++;
+    for (Bit = 2; Bit < 8; Bit++) {
+        if ((FrameCheckSequence ^ Data) & 0x400)
+            FrameCheckSequence = (FrameCheckSequence << 1) ^ GeneratorPolynomial;
+        else
+            FrameCheckSequence = (FrameCheckSequence << 1);
+        FrameCheckSequence &= 0x7FF;
+        Data <<= 1;
+    }
+    /* Do rest of the bytes */
+    for (ByteIndex = 1; ByteIndex < 13; ByteIndex++) {
+        Data = *ByteArrayPtr << 3;
+        ByteArrayPtr++;
+        for (Bit = 0; Bit < 8; Bit++) {
+            if ((FrameCheckSequence ^ Data) & 0x0400) {
+                FrameCheckSequence = (FrameCheckSequence << 1) ^ GeneratorPolynomial;
+            } else {
+                FrameCheckSequence = (FrameCheckSequence << 1);
+            }
+            FrameCheckSequence &= 0x7FF;
+            Data <<= 1;
+        }
+    }
+    return FrameCheckSequence;
+}
+
+INTERNAL int imail(struct zint_symbol *symbol, unsigned char source[], int length) {
+    char data_pattern[200];
+    int error_number;
+    int i, j, read;
+    char zip[35], tracker[35], temp[2];
+    large_int accum;
+    large_int byte_array_reg;
+    unsigned char byte_array[13];
+    unsigned short usps_crc;
+    int codeword[10];
+    unsigned short characters[10];
+    short int bar_map[130];
+    int zip_len, len;
+
+    if (length > 32) {
+        strcpy(symbol->errtxt, "450: 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, "451: Invalid characters in data");
+        return error_number;
+    }
+
+    strcpy(zip, "");
+    strcpy(tracker, "");
+
+    /* separate the tracking code from the routing code */
+
+    read = 0;
+    j = 0;
+    for (i = 0; i < length; i++) {
+        if (source[i] == '-') {
+            tracker[read] = '\0';
+            j = 1;
+            read = 0;
+        } else {
+            if (j == 0) {
+                /* reading tracker */
+                tracker[read] = source[i];
+                read++;
+            } else {
+                /* reading zip code */
+                zip[read] = source[i];
+                read++;
+            }
+        }
+    }
+    if (j == 0) {
+        tracker[read] = '\0';
+    } else {
+        zip[read] = '\0';
+    }
+
+    if (strlen(tracker) != 20) {
+        strcpy(symbol->errtxt, "452: Invalid length tracking code");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+    if (tracker[1] > '4') {
+        strcpy(symbol->errtxt, "454: Invalid Barcode Identifier");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    zip_len = strlen(zip);
+    if (zip_len != 0 && zip_len != 5 && zip_len != 9 && zip_len != 11) {
+        strcpy(symbol->errtxt, "453: Invalid ZIP code");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    /* *** Step 1 - Conversion of Data Fields into Binary Data *** */
+
+    /* Routing code first */
+
+    large_load_str_u64(&accum, (unsigned char *) zip, zip_len);
+
+    /* add weight to routing code */
+    if (zip_len > 9) {
+        large_add_u64(&accum, 1000100001);
+    } else if (zip_len > 5) {
+        large_add_u64(&accum, 100001);
+    } else if (zip_len > 0) {
+        large_add_u64(&accum, 1);
+    }
+
+    /* tracking code */
+
+    /* multiply by 10 */
+    large_mul_u64(&accum, 10);
+
+    /* add first digit of tracker */
+    large_add_u64(&accum, ctoi(tracker[0]));
+
+    /* multiply by 5 */
+    large_mul_u64(&accum, 5);
+
+    /* add second digit */
+    large_add_u64(&accum, ctoi(tracker[1]));
+
+    /* and then the rest */
+
+    for (read = 2, len = strlen(tracker); read < len; read++) {
+
+        large_mul_u64(&accum, 10);
+        large_add_u64(&accum, ctoi(tracker[read]));
+    }
+
+    /* *** Step 2 - Generation of 11-bit CRC on Binary Data *** */
+
+    large_load(&byte_array_reg, &accum);
+
+    large_unset_bit(&byte_array_reg, 102);
+    large_unset_bit(&byte_array_reg, 103);
+
+    large_uchar_array(&byte_array_reg, byte_array, 13, 8 /*bits*/);
+
+    usps_crc = USPS_MSB_Math_CRC11GenerateFrameCheckSequence(byte_array);
+
+    /* *** Step 3 - Conversion from Binary Data to Codewords *** */
+
+    /* start with codeword J which is base 636 */
+    codeword[9] = large_div_u64(&accum, 636);
+
+    /* then codewords I to B with base 1365 */
+
+    for (j = 8; j > 0; j--) {
+        codeword[j] = large_div_u64(&accum, 1365);
+    }
+
+    codeword[0] = large_lo(&accum);
+
+    /* *** Step 4 - Inserting Additional Information into Codewords *** */
+
+    codeword[9] = codeword[9] * 2;
+
+    if (usps_crc >= 1024) {
+        codeword[0] += 659;
+    }
+
+    /* *** Step 5 - Conversion from Codewords to Characters *** */
+
+    for (i = 0; i < 10; i++) {
+        if (codeword[i] < 1287) {
+            characters[i] = AppxD_I[codeword[i]];
+        } else {
+            characters[i] = AppxD_II[codeword[i] - 1287];
+        }
+    }
+
+    for (i = 0; i < 10; i++) {
+        if (usps_crc & (1 << i)) {
+            characters[i] = 0x1FFF - characters[i];
+        }
+    }
+
+    /* *** Step 6 - Conversion from Characters to the Intelligent Mail Barcode *** */
+    for (i = 0; i < 10; i++) {
+        for (j = 0; j < 13; j++) {
+            if (characters[i] & (1 << j)) {
+                bar_map[AppxD_IV[(13 * i) + j] - 1] = 1;
+            } else {
+                bar_map[AppxD_IV[(13 * i) + j] - 1] = 0;
+            }
+        }
+    }
+
+    strcpy(data_pattern, "");
+    temp[1] = '\0';
+    for (i = 0; i < 65; i++) {
+        j = 0;
+        if (bar_map[i] == 0)
+            j += 1;
+        if (bar_map[i + 65] == 0)
+            j += 2;
+        temp[0] = itoc(j);
+        strcat(data_pattern, temp);
+    }
+
+    /* Translate 4-state data pattern to symbol */
+    read = 0;
+    for (i = 0, len = strlen(data_pattern); i < len; i++) {
+        if ((data_pattern[i] == '1') || (data_pattern[i] == '0')) {
+            set_module(symbol, 0, read);
+        }
+        set_module(symbol, 1, read);
+        if ((data_pattern[i] == '2') || (data_pattern[i] == '0')) {
+            set_module(symbol, 2, read);
+        }
+        read += 2;
+    }
+
+    symbol->row_height[0] = 3;
+    symbol->row_height[1] = 2;
+    symbol->row_height[2] = 3;
+
+    symbol->rows = 3;
+    symbol->width = read - 1;
+    return error_number;
+}
index ff44ecd..6f7d7af 100644 (file)
@@ -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
     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 : */
 
+/* `large_mul_u64()` and `large_div_u64()` are adapted from articles by F. W. Jacob
+ *   https://www.codeproject.com/Tips/618570/UInt-Multiplication-Squaring
+ *   "This article, along with any associated source code and files, is licensed under The BSD License"
+ *   http://www.codeproject.com/Tips/785014/UInt-Division-Modulus
+ *   "This article, along with any associated source code and files, is licensed under The BSD License"
+ *
+ * These in turn are based on Hacker's Delight (2nd Edition, 2012) by Henry S. Warren, Jr.
+ *   "You are free to use, copy, and distribute any of the code on this web site, whether modified by you or not."
+ *   https://web.archive.org/web/20190716204559/http://www.hackersdelight.org/permissions.htm
+ *
+ * `clz_u64()` and other bits and pieces are adapted from r128.h by Alan Hickman (fahickman)
+ *   https://github.com/fahickman/r128/blob/master/r128.h
+ *   "R128 is released into the public domain. See LICENSE for details." LICENSE is The Unlicense.
+ */
 #include <stdio.h>
-#include <string.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
 #include "common.h"
 #include "large.h"
 
-static const short int BCD[40] = {
-       0, 0, 0, 0,
-       1, 0, 0, 0,
-       0, 1, 0, 0,
-       1, 1, 0, 0,
-       0, 0, 1, 0,
-       1, 0, 1, 0,
-       0, 1, 1, 0,
-       1, 1, 1, 0,
-       0, 0, 0, 1,
-       1, 0, 0, 1 };
-
-void binary_add(short int accumulator[], short int input_buffer[])
-{ /* Binary addition */
-       int i, carry, done;
-       carry = 0;
-
-       for(i = 0; i < 112; i++) {
-               done = 0;
-               if(((input_buffer[i] == 0) && (accumulator[i] == 0)) && ((carry == 0) && (done == 0))) {
-                       accumulator[i] = 0;
-                       carry = 0;
-                       done = 1;
-               }
-               if(((input_buffer[i] == 0) && (accumulator[i] == 0)) && ((carry == 1) && (done == 0))) {
-                       accumulator[i] = 1;
-                       carry = 0;
-                       done = 1;
-               }
-               if(((input_buffer[i] == 0) && (accumulator[i] == 1)) && ((carry == 0) && (done == 0))) {
-                       accumulator[i] = 1;
-                       carry = 0;
-                       done = 1;
-               }
-               if(((input_buffer[i] == 0) && (accumulator[i] == 1)) && ((carry == 1) && (done == 0))) {
-                       accumulator[i] = 0;
-                       carry = 1;
-                       done = 1;
-               }
-               if(((input_buffer[i] == 1) && (accumulator[i] == 0)) && ((carry == 0) && (done == 0))) {
-                       accumulator[i] = 1;
-                       carry = 0;
-                       done = 1;
-               }
-               if(((input_buffer[i] == 1) && (accumulator[i] == 0)) && ((carry == 1) && (done == 0))) {
-                       accumulator[i] = 0;
-                       carry = 1;
-                       done = 1;
-               }
-               if(((input_buffer[i] == 1) && (accumulator[i] == 1)) && ((carry == 0) && (done == 0))) {
-                       accumulator[i] = 0;
-                       carry = 1;
-                       done = 1;
-               }
-               if(((input_buffer[i] == 1) && (accumulator[i] == 1)) && ((carry == 1) && (done == 0))) {
-                       accumulator[i] = 1;
-                       carry = 1;
-                       done = 1;
-               }
-       }
+#define MASK32  0xFFFFFFFF
+
+/* Convert decimal string `s` of (at most) length `length` to 64-bit and place in 128-bit `t` */
+INTERNAL void large_load_str_u64(large_int *t, const unsigned char *s, int length) {
+    uint64_t val = 0;
+    const unsigned char *se = s + length;
+    for (; s < se && *s >= '0' && *s <= '9'; s++) {
+        val *= 10;
+        val += *s - '0';
+    }
+    t->lo = val;
+    t->hi = 0;
 }
 
-void binary_subtract(short int accumulator[], short int input_buffer[])
-{      /* 2's compliment subtraction */
-       /* take input_buffer from accumulator and put answer in accumulator */
-       int i;
-       short int sub_buffer[112];
-       
-       for(i = 0; i < 112; i++) {
-               if(input_buffer[i] == 0) {
-                       sub_buffer[i] = 1;
-               } else {
-                       sub_buffer[i] = 0;
-               }
-       }
-       binary_add(accumulator, sub_buffer);
-       
-       sub_buffer[0] = 1;
-       
-       for(i = 1; i < 112; i++) {
-               sub_buffer[i] = 0;
-       }
-       binary_add(accumulator, sub_buffer);
+/* Add 128-bit `s` to 128-bit `t` */
+INTERNAL void large_add(large_int *t, const large_int *s) {
+    t->lo += s->lo;
+    t->hi += s->hi + (t->lo < s->lo);
 }
 
-void shiftdown(short int buffer[])
-{
-       int i;
-       
-       buffer[102] = 0;
-       buffer[103] = 0;
+/* Add 64-bit `s` to 128-bit `t` */
+INTERNAL void large_add_u64(large_int *t, uint64_t s) {
+    t->lo += s;
+    if (t->lo < s) {
+        t->hi++;
+    }
+}
 
-       for(i = 0; i < 102; i++) {
-               buffer[i] = buffer[i + 1];
-       }
+/* Subtract 64-bit `s` from 128-bit `t` */
+INTERNAL void large_sub_u64(large_int *t, uint64_t s) {
+    uint64_t r = t->lo - s;
+    if (r > t->lo) {
+        t->hi--;
+    }
+    t->lo = r;
 }
 
-void shiftup(short int buffer[])
-{
-       int i;
-       
-       for(i = 102; i > 0; i--) {
-               buffer[i] = buffer[i - 1];
-       }
-       
-       buffer[0] = 0;
+/* Multiply 128-bit `t` by 64-bit `s`
+ * See Jacob `mult64to128()` and Warren Section 8-2
+ * Note '0' denotes low 32-bits, '1' high 32-bits
+ * if   p00 == s0 * tlo0
+ *      k00 == carry of p00
+ *      p01 == s0 * tlo1
+ *      k01 == carry of (p01 + k00)
+ *      p10 == s1 * tlo0
+ *      k10 == carry of p10
+ *      p11 == s1 * tlo1 (unmasked, i.e. including unshifted carry if any)
+ * then t->lo == (p01 + p10 + k00) << 32 + p00
+ * and  t->hi == p11 + k10 + k01 + thi * s
+ *
+ *      (thi)      tlo1      tlo0
+ * x                 s1        s0
+ *      -------------------------
+ *                            p00
+ *      k01        p01 + k00
+ *                 p10
+ *      p11 + k10
+ */
+INTERNAL void large_mul_u64(large_int *t, uint64_t s) {
+    uint64_t thi = t->hi;
+    uint64_t tlo0 = t->lo & MASK32;
+    uint64_t tlo1 = t->lo >> 32;
+
+    uint64_t s0 = s & MASK32;
+    uint64_t s1 = s >> 32;
+
+    uint64_t tmp = s0 * tlo0; /* p00 (unmasked) */
+    uint64_t p00 = tmp & MASK32;
+    uint64_t k10;
+
+    tmp = (s1 * tlo0) + (tmp >> 32); /* (p10 + k00) (p10 unmasked) */
+    k10 = tmp >> 32;
+
+    tmp = (s0 * tlo1) + (tmp & MASK32); /* (p01 + p10 + k00) (p01 unmasked) */
+
+    t->lo = (tmp << 32) + p00; /* (p01 + p10 + k00) << 32 + p00 (note any carry from unmasked p01 shifted out) */
+    t->hi = (s1 * tlo1) + k10 + (tmp >> 32) + thi * s; /* p11 + k10 + k01 + thi * s */
 }
 
-short int islarger(short int accum[], short int reg[])
-{
-       /* Returns 1 if accum[] is larger than reg[], else 0 */
-       int i, latch, larger;
-       latch = 0;
-       i = 103;
-       larger = 0;
-       
-       
-       do {
-               if((accum[i] == 1) && (reg[i] == 0)) {
-                       latch = 1;
-                       larger = 1;
-               }
-               if((accum[i] == 0) && (reg[i] == 1)) {
-                       latch = 1;
-               }
-               i--;
-       } while ((latch == 0) && (i >= -1));
-       
-       return larger;
+/* Count leading zeroes. See Hickman `r128__clz64()` */
+STATIC_UNLESS_ZINT_TEST int clz_u64(uint64_t x) {
+   uint64_t n = 64, y;
+   y = x >> 32; if (y) { n -= 32; x = y; }
+   y = x >> 16; if (y) { n -= 16; x = y; }
+   y = x >>  8; if (y) { n -=  8; x = y; }
+   y = x >>  4; if (y) { n -=  4; x = y; }
+   y = x >>  2; if (y) { n -=  2; x = y; }
+   y = x >>  1; if (y) { n -=  1; x = y; }
+   return (int) (n - x);
 }
 
-void binary_load(short int reg[], char data[], const unsigned int src_len)
-{
-       int read, i;
-       short int temp[112] = { 0 };
-       
-       for(i = 0; i < 112; i++) {
-               reg[i] = 0;
-       }
-       
-       for(read = 0; read < src_len; read++) {
-
-               for(i = 0; i < 112; i++) {
-                       temp[i] = reg[i];
-               }
-               
-               for(i = 0; i < 9; i++) {
-                       binary_add(reg, temp);
-               }
-               
-               temp[0] = BCD[ctoi(data[read]) * 4];
-               temp[1] = BCD[(ctoi(data[read]) * 4) + 1];
-               temp[2] = BCD[(ctoi(data[read]) * 4) + 2];
-               temp[3] = BCD[(ctoi(data[read]) * 4) + 3];
-               for(i = 4; i < 112; i++) {
-                       temp[i] = 0;
-               }
-               
-               binary_add(reg, temp);
-       }
+/* Divide 128-bit dividend `t` by 64-bit divisor `v`
+ * See Jacob `divmod128by128/64()` and Warren Section 9–2 (divmu64.c.txt)
+ * Note digits are 32-bit parts */
+INTERNAL uint64_t large_div_u64(large_int *t, uint64_t v) {
+    const uint64_t b = 0x100000000; /* Number base (2**32) */
+    uint64_t qhi = 0; /* High digit of returned quotient */
+
+    uint64_t tnhi, tnlo, tnlo1, tnlo0, vn1, vn0; /* Normalized forms of (parts of) t and v */
+    uint64_t rnhilo1; /* Remainder after dividing 1st 3 digits of t by v */
+    uint64_t qhat1, qhat0; /* Estimated quotient digits */
+    uint64_t rhat; /* Remainder of estimated quotient digit */
+    uint64_t tmp;
+    int norm_shift;
+
+    /* Deal with single-digit (i.e. 32-bit) divisor here */
+    if (v < b) {
+        qhi = t->hi / v;
+        tmp = ((t->hi - qhi * v) << 32) + (t->lo >> 32); /* k * b + tlo1 */
+        qhat1 = tmp / v;
+        tmp = ((tmp - qhat1 * v) << 32) + (t->lo & MASK32); /* k * b + tlo0 */
+        qhat0 = tmp / v;
+        t->lo = (qhat1 << 32) | qhat0;
+        t->hi = qhi;
+        return tmp - qhat0 * v;
+    }
+
+    /* Main algorithm requires t->hi < v */
+    if (t->hi >= v) {
+        qhi = t->hi / v;
+        t->hi %= v;
+    }
+
+    /* Normalize by shifting v left just enough so that its high-order
+     * bit is on, and shift t left the same amount. Note don't need extra
+     * high-end digit for dividend as t->hi < v */
+
+    norm_shift = clz_u64(v);
+    v <<= norm_shift;
+    vn1 = v >> 32;
+    vn0 = v & MASK32;
+
+    if (norm_shift > 0) {
+        tnhi = (t->hi << norm_shift) | (t->lo >> (64 - norm_shift));
+        tnlo = t->lo << norm_shift;
+    } else {
+        tnhi = t->hi;
+        tnlo = t->lo;
+    }
+
+    tnlo1 = tnlo >> 32;
+    tnlo0 = tnlo & MASK32;
+
+    /* Compute qhat1 estimate */
+
+    qhat1 = tnhi / vn1; /* Divide first digit of v into first 2 digits of t */
+    rhat = tnhi % vn1;
+
+    /* Loop until qhat1 one digit and <= (rhat * b + 3rd digit of t) / vn0 */
+    for (tmp = qhat1 * vn0; qhat1 >= b || tmp > (rhat << 32) + tnlo1; tmp -= vn0) {
+        --qhat1;
+        rhat += vn1;
+        if (rhat >= b) { /* Must check here as (rhat << 32) would overflow */
+            break; /* qhat1 * vn0 < b * b (since vn0 < b) */
+        }
+    }
+    /* Note qhat1 will be exact as have fully divided by 2-digit divisor
+     * (can only be too high by 1 (and require "add back" step) if divisor at least 3 digits) */
+
+    rnhilo1 = (tnhi << 32) + tnlo1 - (qhat1 * v); /* Note high digit (if any) of both tnhi and (qhat1 * v) shifted out */
+
+    /* Compute qhat0 estimate */
+
+    qhat0 = rnhilo1 / vn1; /* Divide first digit of v into 2-digit remains of first 3 digits of t */
+    rhat = rnhilo1 % vn1;
+
+    /* Loop until qhat0 one digit and <= (rhat * b + 4th digit of t) / vn0 */
+    for (tmp = qhat0 * vn0; qhat0 >= b || tmp > (rhat << 32) + tnlo0; tmp -= vn0) {
+        --qhat0;
+        rhat += vn1;
+        if (rhat >= b) {
+            break;
+        }
+    }
+    /* Similarly qhat0 will be exact */
+
+    t->lo = (qhat1 << 32) | qhat0;
+    t->hi = qhi;
+
+    /* Unnormalize remainder */
+    return ((rnhilo1 << 32) + tnlo0 - (qhat0 * v)) >> norm_shift;
+}
+
+/* Unset a bit (zero-based) */
+INTERNAL void large_unset_bit(large_int *t, int bit) {
+    if (bit < 64) {
+        t->lo &= ~(((uint64_t) 1) << bit);
+    } else if (bit < 128) {
+        t->hi &= ~(((uint64_t) 1) << (bit - 64));
+    }
+}
+
+/* Ouput large_int into an unsigned int array of size `size`, each element containing `bits` bits */
+INTERNAL void large_uint_array(const large_int *t, unsigned int *uint_array, int size, int bits) {
+    int i, j;
+    uint64_t mask;
+    if (bits <= 0) {
+        bits = 8;
+    } else if (bits > 32) {
+        bits = 32;
+    }
+    mask = ~(((uint64_t) -1) << bits);
+    for (i = 0, j = 0; i < size && j < 64; i++, j += bits) {
+        uint_array[size - 1 - i] = (t->lo >> j) & mask; /* Little-endian order */
+    }
+    if (i < size) {
+        if (j != 64) {
+            j -= 64;
+            /* (first j bits of t->hi) << (bits - j) | (last (bits - j) bits of t->lo) */
+            uint_array[size - i] = ((t->hi & ~((((uint64_t) -1) << j))) << (bits - j)) | (t->lo >> (64 - (bits - j)) & mask);
+        } else {
+            j = 0;
+        }
+        for (; i < size && j < 64; i++, j += bits) {
+            uint_array[size - 1 - i] = (t->hi >> j) & mask;
+        }
+        if (i < size && j != 128) {
+            uint_array[size - 1 - i] = t->hi >> (j - bits) & mask;
+        }
+    }
 }
 
-void hex_dump(short int input_buffer[]) 
-{
-       int i, digit, byte_space;
-
-       byte_space = 1;
-       for(i = 100; i >= 0; i-=4) {
-               digit = 0;
-               digit += 1 * input_buffer[i];
-               digit += 2 * input_buffer[i + 1];
-               digit += 4 * input_buffer[i + 2];
-               digit += 8 * input_buffer[i + 3];
-
-               switch(digit) {
-                       case 0: printf("0"); break;
-                       case 1: printf("1"); break;
-                       case 2: printf("2"); break;
-                       case 3: printf("3"); break;
-                       case 4: printf("4"); break;
-                       case 5: printf("5"); break;
-                       case 6: printf("6"); break;
-                       case 7: printf("7"); break;
-                       case 8: printf("8"); break;
-                       case 9: printf("9"); break;
-                       case 10: printf("A"); break;
-                       case 11: printf("B"); break;
-                       case 12: printf("C"); break;
-                       case 13: printf("D"); break;
-                       case 14: printf("E"); break;
-                       case 15: printf("F"); break;
-               }
-               if(byte_space == 1) {
-                       byte_space = 0;
-               } else {
-                       byte_space = 1;
-                       printf(" ");
-               }
-       }
-       printf("\n");
+/* As `large_uint_array()` above, except output to unsigned char array */
+INTERNAL void large_uchar_array(const large_int *t, unsigned char *uchar_array, int size, int bits) {
+    int i;
+#ifndef _MSC_VER
+    unsigned int uint_array[size ? size : 1]; /* Avoid run-time warning if size is 0 */
+#else
+    unsigned int *uint_array = (unsigned int *) _alloca((size ? size : 1) * sizeof(unsigned int));
+#endif
+
+    large_uint_array(t, uint_array, size, bits);
+
+    for (i = 0; i < size; i++) {
+        uchar_array[i] = uint_array[i];
+    }
+}
+
+/* Output formatted large_int to stdout */
+INTERNAL void large_print(large_int *t) {
+    char buf[35]; /* 2 (0x) + 32 (hex) + 1 */
+
+    puts(large_dump(t, buf));
+}
+
+/* Format large_int into buffer, which should be at least 35 chars in size */
+INTERNAL char *large_dump(large_int *t, char *buf) {
+    unsigned int tlo1 = large_lo(t) >> 32;
+    unsigned int tlo0 = large_lo(t) & MASK32;
+    unsigned int thi1 = large_hi(t) >> 32;
+    unsigned int thi0 = large_hi(t) & MASK32;
+
+    if (thi1) {
+        sprintf(buf, "0x%X%08X%08X%08X", thi1, thi0, tlo1, tlo0);
+    } else if (thi0) {
+        sprintf(buf, "0x%X%08X%08X", thi0, tlo1, tlo0);
+    } else if (tlo1) {
+        sprintf(buf, "0x%X%08X", tlo1, tlo0);
+    } else {
+        sprintf(buf, "0x%X", tlo0);
+    }
+    return buf;
 }
index 74f9a61..06325f5 100644 (file)
@@ -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
     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     SUCH DAMAGE.
 */
+/* vim: set ts=4 sw=4 et : */
 #ifndef __LARGE_H
 #define __LARGE_H
 
+#ifndef _MSC_VER
+#include <stdint.h>
+#else
+#include "ms_stdint.h"
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
-extern void binary_load(short int reg[], char data[], const unsigned int src_len);
-extern void binary_add(short int accumulator[], short int input_buffer[]);
-extern void binary_subtract(short int accumulator[], short int input_buffer[]);
-extern void shiftdown(short int buffer[]);
-extern void shiftup(short int buffer[]);
-extern short int islarger(short int accum[], short int reg[]);
-extern void hex_dump(short int input_buffer[]);
+typedef struct { uint64_t lo; uint64_t hi; } large_int;
+
+#define large_lo(s) ((s)->lo)
+#define large_hi(s) ((s)->hi)
+
+/* Set 128-bit `t` from 128-bit `s` */
+#define large_load(t, s) do { (t)->lo = (s)->lo; (t)->hi = (s)->hi; } while (0)
+
+/* Set 128-bit `t` from 64-bit `s` */
+#define large_load_u64(t, s) do { (t)->lo = (s); (t)->hi = 0; } while (0)
+
+INTERNAL void large_load_str_u64(large_int *t, const unsigned char *s, int length);
+
+INTERNAL void large_add(large_int *t, const large_int *s);
+INTERNAL void large_add_u64(large_int *t, uint64_t s);
+
+INTERNAL void large_sub_u64(large_int *t, uint64_t s);
+
+INTERNAL void large_mul_u64(large_int *t, uint64_t s);
+
+INTERNAL uint64_t large_div_u64(large_int *t, uint64_t v);
+
+INTERNAL void large_unset_bit(large_int *t, int bit);
+
+INTERNAL void large_uint_array(const large_int *t, unsigned int *uint_array, int size, int bits);
+INTERNAL void large_uchar_array(const large_int *t, unsigned char *uchar_array, int size, int bits);
+
+INTERNAL void large_print(large_int *t);
+INTERNAL char *large_dump(large_int *t, char *buf);
 
 #ifdef __cplusplus
 }
index cbedb1f..a9714af 100644 (file)
@@ -1,7 +1,7 @@
 /*  library.c - external functions of libzint
 
     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
     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 <stdlib.h>
-#include <string.h>
 #include <errno.h>
 #ifdef _MSC_VER
-#include <malloc.h> 
+#include <malloc.h>
 #endif
 #include "common.h"
 #include "gs1.h"
 
-#define TECHNETIUM     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"
-
-struct zint_symbol *ZBarcode_Create()
-{
-       struct zint_symbol *symbol = (struct zint_symbol*)calloc(1, sizeof(struct zint_symbol));
-       
-       if (!symbol) return NULL;
-
-       symbol->symbology = BARCODE_CODE128;
-       strcpy(symbol->fgcolour, "000000");
-       strcpy(symbol->bgcolour, "ffffff");
-       strcpy(symbol->outfile, "out.png");
-       symbol->scale = 1.0;
-       symbol->option_1 = -1;
-       symbol->option_3 = 928; // PDF_MAX
-       symbol->show_hrt = 1; // Show human readable text
-       return symbol;
+#define TECHNETIUM  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"
+
+struct zint_symbol *ZBarcode_Create() {
+    struct zint_symbol *symbol;
+
+    symbol = (struct zint_symbol*) malloc(sizeof (*symbol));
+    if (!symbol) return NULL;
+
+    memset(symbol, 0, sizeof (*symbol));
+    symbol->symbology = BARCODE_CODE128;
+    symbol->height = 0;
+    symbol->whitespace_width = 0;
+    symbol->border_width = 0;
+    symbol->output_options = 0;
+    symbol->rows = 0;
+    symbol->width = 0;
+    strcpy(symbol->fgcolour, "000000");
+    strcpy(symbol->bgcolour, "ffffff");
+    strcpy(symbol->outfile, "out.png");
+    symbol->scale = 1.0;
+    symbol->option_1 = -1;
+    symbol->option_2 = 0;
+    symbol->option_3 = 0;
+    symbol->show_hrt = 1; // Show human readable text
+    symbol->fontsize = 8;
+    symbol->input_mode = DATA_MODE;
+    symbol->bitmap = NULL;
+    symbol->bitmap_width = 0;
+    symbol->bitmap_height = 0;
+    symbol->eci = 0; // Default 0 uses ECI 3
+    symbol->dot_size = 4.0 / 5.0;
+    symbol->vector = NULL;
+    symbol->debug = 0;
+    return symbol;
 }
 
-void ZBarcode_Clear(struct zint_symbol *symbol)
-{
-       int i, j;
-       
-       for(i = 0; i < symbol->rows; i++) {
-               for(j = 0; j < symbol->width; j++) {
-                       unset_module(symbol, i, j);
-               }
-       }
-       symbol->rows = 0;
-       symbol->width = 0;
-       symbol->text[0] = '\0';
-       symbol->errtxt[0] = '\0';
-       if (symbol->bitmap != NULL) {
-               free(symbol->bitmap);
-               symbol->bitmap = NULL;
-       }
-       symbol->bitmap_width = 0;
-       symbol->bitmap_height = 0;
+INTERNAL void vector_free(struct zint_symbol *symbol); /* Free vector structures */
+
+void ZBarcode_Clear(struct zint_symbol *symbol) {
+    int i, j;
+
+    for (i = 0; i < symbol->rows; i++) {
+        for (j = 0; j < symbol->width; j++) {
+            unset_module(symbol, i, j);
+        }
+    }
+    symbol->rows = 0;
+    symbol->width = 0;
+    memset(symbol->text, 0, sizeof(symbol->text));
+    symbol->errtxt[0] = '\0';
+    if (symbol->bitmap != NULL) {
+        free(symbol->bitmap);
+        symbol->bitmap = NULL;
+    }
+    symbol->bitmap_width = 0;
+    symbol->bitmap_height = 0;
+
+    // If there is a rendered version, ensure its memory is released
+    vector_free(symbol);
 }
 
-void ZBarcode_Delete(struct zint_symbol *symbol)
-{
-       if (symbol->bitmap != NULL)
-               free(symbol->bitmap);
-
-       // If there is a rendered version, ensure it's memory is released
-       if (symbol->rendered != NULL) {
-               struct zint_render_line *line, *l;
-               struct zint_render_string *string, *s;
-
-               // Free lines
-               line = symbol->rendered->lines;
-               while(line) {
-                       l = line;
-                       line = line->next;
-                       free(l);
-               }
-               // Free Strings
-               string = symbol->rendered->strings;
-               while (string) {
-                       s = string;
-                       string = string->next;
-                       free(s->text);
-                       free(s);
-               }
-
-               // Free Render
-               free(symbol->rendered);
-       }
-       free(symbol);
+void ZBarcode_Delete(struct zint_symbol *symbol) {
+    if (symbol->bitmap != NULL)
+        free(symbol->bitmap);
+
+    // If there is a rendered version, ensure its memory is released
+    vector_free(symbol);
+
+    free(symbol);
 }
 
-extern int eanx(struct zint_symbol *symbol, unsigned char source[], int length); /* EAN system barcodes */
-extern int c39(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 3 from 9 (or Code 39) */
-extern int interleaved_two_of_five(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 Interleaved */
-extern int code_128(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 128 and NVE-18 */
-extern int qr_code(struct zint_symbol *symbol, unsigned char source[], int length); /* QR Code */
-
-extern int render_plot(struct zint_symbol *symbol, float width, float height);
-
-extern int bmp_handle(struct zint_symbol *symbol, int rotate_angle);
-
-void error_tag(char error_string[], int error_number)
-{
-       char error_buffer[100];
-       
-       if(error_number != 0) {
-               strcpy(error_buffer, error_string);
-               
-               if(error_number > 4) {
-                       strcpy(error_string, "error: ");
-               } else {
-                       strcpy(error_string, "warning: ");
-               }
-               
-               concat(error_string, error_buffer);
-       }
+INTERNAL int get_best_eci(unsigned char source[], size_t length); /* Calculate suitable ECI mode */
+INTERNAL int utf_to_eci(const int eci, const unsigned char source[], unsigned char dest[], size_t *length); /* Convert Unicode to other encodings */
+
+
+INTERNAL int eanx(struct zint_symbol *symbol, unsigned char source[], int length); /* EAN system barcodes */
+INTERNAL int c39(struct zint_symbol *symbol, unsigned char source[], const size_t length); /* Code 3 from 9 (or Code 39) */
+INTERNAL int pharmazentral(struct zint_symbol *symbol, unsigned char source[], int length); /* Pharmazentral Nummer (PZN) */
+INTERNAL int ec39(struct zint_symbol *symbol, unsigned char source[], int length); /* Extended Code 3 from 9 (or Code 39+) */
+INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int length); /* Codabar - a simple substitution cipher */
+INTERNAL int matrix_two_of_five(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 Standard (& Matrix) */
+INTERNAL int industrial_two_of_five(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 Industrial */
+INTERNAL int iata_two_of_five(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 IATA */
+INTERNAL int interleaved_two_of_five(struct zint_symbol *symbol, const unsigned char source[], size_t length); /* Code 2 of 5 Interleaved */
+INTERNAL int logic_two_of_five(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 Data Logic */
+INTERNAL int itf14(struct zint_symbol *symbol, unsigned char source[], int length); /* ITF-14 */
+INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int length); /* Deutsche Post Leitcode */
+INTERNAL int dpident(struct zint_symbol *symbol, unsigned char source[], int length); /* Deutsche Post Identcode */
+INTERNAL int c93(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 93 - a re-working of Code 39+, generates 2 check digits */
+INTERNAL int code_128(struct zint_symbol *symbol, const unsigned char source[], const size_t length); /* Code 128 and NVE-18 */
+INTERNAL int ean_128(struct zint_symbol *symbol, unsigned char source[], const size_t length); /* EAN-128 (GS1-128) */
+INTERNAL int code_11(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 11 */
+INTERNAL int msi_handle(struct zint_symbol *symbol, unsigned char source[], int length); /* MSI Plessey */
+INTERNAL int telepen(struct zint_symbol *symbol, unsigned char source[], const size_t length); /* Telepen ASCII */
+INTERNAL int telepen_num(struct zint_symbol *symbol, unsigned char source[], const size_t length); /* Telepen Numeric */
+INTERNAL int plessey(struct zint_symbol *symbol, unsigned char source[], const size_t length); /* Plessey Code */
+INTERNAL int pharma_one(struct zint_symbol *symbol, unsigned char source[], int length); /* Pharmacode One Track */
+INTERNAL int flattermarken(struct zint_symbol *symbol, unsigned char source[], int length); /* Flattermarken */
+INTERNAL int fim(struct zint_symbol *symbol, unsigned char source[], int length); /* Facing Identification Mark */
+INTERNAL int pharma_two(struct zint_symbol *symbol, unsigned char source[], int length); /* Pharmacode Two Track */
+INTERNAL int post_plot(struct zint_symbol *symbol, unsigned char source[], int length); /* Postnet */
+INTERNAL int planet_plot(struct zint_symbol *symbol, unsigned char source[], int length); /* PLANET */
+INTERNAL int imail(struct zint_symbol *symbol, unsigned char source[], int length); /* Intelligent Mail (aka USPS OneCode) */
+INTERNAL int royal_plot(struct zint_symbol *symbol, unsigned char source[], int length); /* RM4SCC */
+INTERNAL int australia_post(struct zint_symbol *symbol, unsigned char source[], int length); /* Australia Post 4-state */
+INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[],const size_t length); /* Code 16k */
+INTERNAL int pdf417enc(struct zint_symbol *symbol, unsigned char source[], const size_t length); /* PDF417 */
+INTERNAL int micro_pdf417(struct zint_symbol *symbol, unsigned char chaine[], const size_t length); /* Micro PDF417 */
+INTERNAL int maxicode(struct zint_symbol *symbol, unsigned char source[], int length); /* Maxicode */
+INTERNAL int rss14(struct zint_symbol *symbol, unsigned char source[], int length); /* RSS-14 */
+INTERNAL int rsslimited(struct zint_symbol *symbol, unsigned char source[], int length); /* RSS Limited */
+INTERNAL int rssexpanded(struct zint_symbol *symbol, unsigned char source[], int length); /* RSS Expanded */
+INTERNAL int composite(struct zint_symbol *symbol, unsigned char source[], int length); /* Composite Symbology */
+INTERNAL int kix_code(struct zint_symbol *symbol, unsigned char source[], int length); /* TNT KIX Code */
+INTERNAL int aztec(struct zint_symbol *symbol, unsigned char source[], const size_t length); /* Aztec Code */
+INTERNAL int code32(struct zint_symbol *symbol, unsigned char source[], int length); /* Italian Pharmacode */
+INTERNAL int daft_code(struct zint_symbol *symbol, unsigned char source[], int length); /* DAFT Code */
+INTERNAL int ean_14(struct zint_symbol *symbol, unsigned char source[], int length); /* EAN-14 */
+INTERNAL int nve_18(struct zint_symbol *symbol, unsigned char source[], int length); /* NVE-18 */
+INTERNAL int microqr(struct zint_symbol *symbol, const unsigned char source[], size_t length); /* Micro QR Code */
+INTERNAL int aztec_runes(struct zint_symbol *symbol, unsigned char source[], int length); /* Aztec Runes */
+INTERNAL int korea_post(struct zint_symbol *symbol, unsigned char source[], int length); /* Korea Post */
+INTERNAL int japan_post(struct zint_symbol *symbol, unsigned char source[], int length); /* Japanese Post */
+INTERNAL int code_49(struct zint_symbol *symbol, unsigned char source[], const int length); /* Code 49 */
+INTERNAL int channel_code(struct zint_symbol *symbol, unsigned char source[], int length); /* Channel Code */
+INTERNAL int code_one(struct zint_symbol *symbol, unsigned char source[], int length); /* Code One */
+INTERNAL int grid_matrix(struct zint_symbol *symbol, const unsigned char source[], size_t length); /* Grid Matrix */
+INTERNAL int han_xin(struct zint_symbol * symbol, const unsigned char source[], size_t length); /* Han Xin */
+INTERNAL int dotcode(struct zint_symbol * symbol, const unsigned char source[], int length); /* DotCode */
+INTERNAL int codablock(struct zint_symbol * symbol, const unsigned char source[], const size_t length); /* Codablock */
+INTERNAL int upnqr(struct zint_symbol *symbol, const unsigned char source[], size_t length); /* UPNQR */
+INTERNAL int qr_code(struct zint_symbol *symbol, const unsigned char source[], size_t length); /* QR Code */
+INTERNAL int dmatrix(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length); /* Data Matrix (IEC16022) */
+INTERNAL int vin(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length); /* VIN Code (Vehicle Identification Number) */
+INTERNAL int mailmark(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length); /* Royal Mail 4-state Mailmark */
+INTERNAL int ultracode(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length); /* Ultracode */
+INTERNAL int rmqr(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length); /* rMQR */
+
+INTERNAL int plot_raster(struct zint_symbol *symbol, int rotate_angle, int file_type); /* Plot to PNG/BMP/PCX */
+INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type); /* Plot to EPS/EMF/SVG */
+
+static void error_tag(char error_string[], int error_number) {
+
+    if (error_number != 0) {
+        char error_buffer[100];
+        strcpy(error_buffer, error_string);
+
+        if (error_number > 4) {
+            strcpy(error_string, "Error ");
+        } else {
+            strcpy(error_string, "Warning ");
+        }
+
+        strcat(error_string, error_buffer);
+    }
 }
 
-int dump_plot(struct zint_symbol *symbol)
-{
-       FILE *f;
-       int i, r;
-
-       if(symbol->output_options & BARCODE_STDOUT) {
-               f = stdout;
-       } else {
-               f = fopen(symbol->outfile, "w");
-               if(!f) {
-                       strcpy(symbol->errtxt, "Could not open output file");
-                       return ERROR_FILE_ACCESS;
-               }
-       }
-
-       fputs("[\n", f);
-       for (r = 0; r < symbol->rows; r++) {
-               fputs(" [ ", f);
-               for (i = 0; i < symbol->width; i++) {
-                       fputs(module_is_set(symbol, r, i) ? "1 " : "0 ", f);
-               }
-               fputs("]\n", f);
-       }
-       fputs("]\n", f);
-
-       if(!(symbol->output_options & BARCODE_STDOUT))
+/* Output a hexadecimal representation of the rendered symbol */
+static int dump_plot(struct zint_symbol *symbol) {
+    FILE *f;
+    int i, r;
+    char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
+        '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+    int space = 0;
+
+    if (symbol->output_options & BARCODE_STDOUT) {
+        f = stdout;
+    } else {
+        f = fopen(symbol->outfile, "w");
+        if (!f) {
+            strcpy(symbol->errtxt, "201: Could not open output file");
+            return ZINT_ERROR_FILE_ACCESS;
+        }
+    }
+
+    for (r = 0; r < symbol->rows; r++) {
+        int byt = 0;
+        for (i = 0; i < symbol->width; i++) {
+            byt = byt << 1;
+            if (module_is_set(symbol, r, i)) {
+                byt += 1;
+            }
+            if (((i + 1) % 4) == 0) {
+                fputc(hex[byt], f);
+                space++;
+                byt = 0;
+            }
+            if (space == 2) {
+                fputc(' ', f);
+                space = 0;
+            }
+        }
+
+        if ((symbol->width % 4) != 0) {
+            byt = byt << (4 - (symbol->width % 4));
+            fputc(hex[byt], f);
+        }
+        fputs("\n", f);
+        space = 0;
+    }
+
+    if (symbol->output_options & BARCODE_STDOUT) {
+        fflush(f);
+    } else {
         fclose(f);
+    }
+
+    return 0;
+}
+
+/* Process health industry bar code data */
+static int hibc(struct zint_symbol *symbol, unsigned char source[], size_t length) {
+    size_t i;
+    int    counter, error_number;
+    char to_process[113], temp[2], check_digit;
+
+    /* without "+" and check: max 110 characters in HIBC 2.6 */
+    if (length > 110) {
+        strcpy(symbol->errtxt, "202: Data too long for HIBC LIC");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    to_upper(source);
+    error_number = is_sane(TECHNETIUM, source, length);
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "203: Invalid characters in data");
+        return error_number;
+    }
+
+    strcpy(to_process, "+");
+    counter = 41;
+    for (i = 0; i < length; i++) {
+        counter += posn(TECHNETIUM, source[i]);
+    }
+    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 = '%';
+                    break;
+                default: check_digit = ' ';
+                    break; /* Keep compiler happy */
+            }
+        }
+    }
+
+    temp[0] = check_digit;
+    temp[1] = '\0';
+
+    strcat(to_process, (char *) source);
+    strcat(to_process, temp);
+    length = strlen(to_process);
+
+    switch (symbol->symbology) {
+        case BARCODE_HIBC_128:
+            error_number = code_128(symbol, (unsigned char *) to_process, length);
+            ustrcpy(symbol->text, (unsigned char*) "*");
+            strcat((char*) symbol->text, to_process);
+            strcat((char*) symbol->text, "*");
+            break;
+        case BARCODE_HIBC_39:
+            symbol->option_2 = 0;
+            error_number = c39(symbol, (unsigned char *) to_process, length);
+            ustrcpy(symbol->text, (unsigned char*) "*");
+            strcat((char*) symbol->text, to_process);
+            strcat((char*) symbol->text, "*");
+            break;
+        case BARCODE_HIBC_DM:
+            error_number = dmatrix(symbol, (unsigned char *) to_process, length);
+            break;
+        case BARCODE_HIBC_QR:
+            error_number = qr_code(symbol, (unsigned char *) to_process, length);
+            break;
+        case BARCODE_HIBC_PDF:
+            error_number = pdf417enc(symbol, (unsigned char *) to_process, length);
+            break;
+        case BARCODE_HIBC_MICPDF:
+            error_number = micro_pdf417(symbol, (unsigned char *) to_process, length);
+            break;
+        case BARCODE_HIBC_AZTEC:
+            error_number = aztec(symbol, (unsigned char *) to_process, length);
+            break;
+        case BARCODE_HIBC_BLOCKF:
+            error_number = codablock(symbol, (unsigned char *) to_process, length);
+            break;
+    }
+
+    return error_number;
+}
+
+static void check_row_heights(struct zint_symbol *symbol) {
+    /* Check that rows with undefined heights are never less than 5x  */
+    int large_bar_count = 0;
+    int i;
+    int preset_height = 0;
+    int large_bar_height = 0;
+
+    for (i = 0; i < symbol->rows; i++) {
+        preset_height += symbol->row_height[i];
+        if (symbol->row_height[i] == 0) {
+            large_bar_count++;
+        }
+    }
+
+    if (large_bar_count == 0) {
+        symbol->height = preset_height;
+    } else {
+        large_bar_height = (symbol->height - preset_height) / large_bar_count;
+    }
+
+    if (large_bar_height < 5) {
+        for (i = 0; i < symbol->rows; i++) {
+            if (symbol->row_height[i] == 0) {
+                symbol->row_height[i] = 5;
+                preset_height += 5;
+            }
+        }
+        symbol->height = preset_height;
+    }
+}
+
+static int check_force_gs1(const int symbology) {
+    /* Returns 1 if symbology MUST have GS1 data */
 
-       return 0;
+    int result = is_composite(symbology);
+
+    switch (symbology) {
+        case BARCODE_EAN128:
+        case BARCODE_EAN14:
+        case BARCODE_NVE18:
+        case BARCODE_RSS_EXP:
+        case BARCODE_RSS_EXPSTACK:
+            result = 1;
+            break;
+    }
+
+    return result;
 }
 
-int hibc(struct zint_symbol *symbol, unsigned char source[], int length)
-{
-       int counter, error_number, i;
-       char to_process[40], temp[2], check_digit;
-       
-       if(length > 36) {
-               strcpy(symbol->errtxt, "Data too long for HIBC LIC");
-               return ERROR_TOO_LONG;
-       }
-       to_upper(source);
-       error_number = is_sane(TECHNETIUM , source, length);
-       if(error_number == ERROR_INVALID_DATA) {
-               strcpy(symbol->errtxt, "Invalid characters in data");
-               return error_number;
-       }
-       
-       strcpy(to_process, "+");
-       counter = 41;
-       for(i = 0; i < length; i++) {
-               counter += posn(TECHNETIUM, source[i]);
-       }
-       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 = '%'; break;
-                               default: check_digit = ' '; break; /* Keep compiler happy */
-                       }
-               }
-       }
-       
-       temp[0] = check_digit;
-       temp[1] = '\0';
-       
-       concat(to_process, (char *)source);
-       concat(to_process, temp);
-       length = strlen(to_process);
-       
-       switch(symbol->symbology) {
-               case BARCODE_HIBC_128:
-                       error_number = code_128(symbol, (unsigned char *)to_process, length);
-                       ustrcpy(symbol->text, (unsigned char*)"*");
-                       uconcat(symbol->text, (unsigned char*)to_process);
-                       uconcat(symbol->text, (unsigned char*)"*");
-                       break;
-               case BARCODE_HIBC_39:
-                       symbol->option_2 = 0;
-                       error_number = c39(symbol, (unsigned char *)to_process, length);
-                       ustrcpy(symbol->text, (unsigned char*)"*");
-                       uconcat(symbol->text, (unsigned char*)to_process);
-                       uconcat(symbol->text, (unsigned char*)"*");
-                       break;
-               case BARCODE_HIBC_QR:
-                       error_number = qr_code(symbol, (unsigned char *)to_process, length);
-                       break;
-       }
-       
-       return error_number;
+static int gs1_compliant(const int symbology) {
+    /* Returns 1 if symbology supports GS1 data */
+
+    int result = check_force_gs1(symbology);
+
+    switch (symbology) {
+        case BARCODE_CODE16K:
+        case BARCODE_AZTEC:
+        case BARCODE_DATAMATRIX:
+        case BARCODE_CODEONE:
+        case BARCODE_CODE49:
+        case BARCODE_QRCODE:
+        case BARCODE_DOTCODE:
+        case BARCODE_RMQR:
+        case BARCODE_ULTRA:
+            result = 1;
+            break;
+    }
+
+    return result;
 }
 
-int gs1_compliant(int symbology)
-{
-       /* Returns 1 if symbology supports GS1 data */
-       
-       int result = 0;
-       
-       switch(symbology) {
-               case BARCODE_EAN128:
-               case BARCODE_RSS_EXP:
-               case BARCODE_RSS_EXPSTACK:
-               case BARCODE_EANX_CC:
-               case BARCODE_EAN128_CC:
-               case BARCODE_RSS14_CC:
-               case BARCODE_RSS_LTD_CC:
-               case BARCODE_RSS_EXP_CC:
-               case BARCODE_UPCA_CC:
-               case BARCODE_UPCE_CC:
-               case BARCODE_RSS14STACK_CC:
-               case BARCODE_RSS14_OMNI_CC:
-               case BARCODE_RSS_EXPSTACK_CC:
-               case BARCODE_CODE16K:
-               case BARCODE_AZTEC:
-               case BARCODE_DATAMATRIX:
-               case BARCODE_CODEONE:
-               case BARCODE_CODE49:
-               case BARCODE_QRCODE:
-                       result = 1;
-                       break;
-       }
-       
-       return result;
+static int is_matrix(const int symbology) {
+    /* Returns 1 if symbology is a matrix design */
+
+    int result = 0;
+
+    switch (symbology) {
+        case BARCODE_QRCODE:
+        case BARCODE_DATAMATRIX:
+        case BARCODE_MICROQR:
+        case BARCODE_HIBC_DM:
+        case BARCODE_AZTEC:
+        case BARCODE_HIBC_QR:
+        case BARCODE_HIBC_AZTEC:
+        case BARCODE_AZRUNE:
+        case BARCODE_CODEONE:
+        case BARCODE_GRIDMATRIX:
+        case BARCODE_HANXIN:
+        case BARCODE_DOTCODE:
+        case BARCODE_UPNQR:
+        case BARCODE_RMQR:
+            result = 1;
+            break;
+    }
+
+    return result;
 }
 
-int ZBarcode_ValidID(int symbol_id)
-{
-       /* Checks whether a symbology is supported */
-       
-       int result = 0;
-
-       switch(symbol_id) {
-               case BARCODE_CODE11:
-               case BARCODE_C25MATRIX:
-               case BARCODE_C25INTER:
-               case BARCODE_C25IATA:
-               case BARCODE_C25LOGIC:
-               case BARCODE_C25IND:
-               case BARCODE_CODE39:
-               case BARCODE_EXCODE39:
-               case BARCODE_EANX:
-               case BARCODE_EAN128:
-               case BARCODE_CODABAR:
-               case BARCODE_CODE128:
-               case BARCODE_DPLEIT:
-               case BARCODE_DPIDENT:
-               case BARCODE_CODE16K:
-               case BARCODE_CODE49:
-               case BARCODE_CODE93:
-               case BARCODE_FLAT:
-               case BARCODE_RSS14:
-               case BARCODE_RSS_LTD:
-               case BARCODE_RSS_EXP:
-               case BARCODE_TELEPEN:
-               case BARCODE_UPCA:
-               case BARCODE_UPCE:
-               case BARCODE_POSTNET:
-               case BARCODE_MSI_PLESSEY:
-               case BARCODE_FIM:
-               case BARCODE_LOGMARS:
-               case BARCODE_PHARMA:
-               case BARCODE_PZN:
-               case BARCODE_PHARMA_TWO:
-               case BARCODE_PDF417:
-               case BARCODE_PDF417TRUNC:
-               case BARCODE_MAXICODE:
-               case BARCODE_QRCODE:
-               case BARCODE_CODE128B:
-               case BARCODE_AUSPOST:
-               case BARCODE_AUSREPLY:
-               case BARCODE_AUSROUTE:
-               case BARCODE_AUSREDIRECT:
-               case BARCODE_ISBNX:
-               case BARCODE_RM4SCC:
-               case BARCODE_DATAMATRIX:
-               case BARCODE_EAN14:
-               case BARCODE_NVE18:
-               case BARCODE_JAPANPOST:
-               case BARCODE_KOREAPOST:
-               case BARCODE_RSS14STACK:
-               case BARCODE_RSS14STACK_OMNI:
-               case BARCODE_RSS_EXPSTACK:
-               case BARCODE_PLANET:
-               case BARCODE_MICROPDF417:
-               case BARCODE_ONECODE:
-               case BARCODE_PLESSEY:
-               case BARCODE_TELEPEN_NUM:
-               case BARCODE_ITF14:
-               case BARCODE_KIX:
-               case BARCODE_AZTEC:
-               case BARCODE_DAFT:
-               case BARCODE_MICROQR:
-               case BARCODE_HIBC_128:
-               case BARCODE_HIBC_39:
-               case BARCODE_HIBC_DM:
-               case BARCODE_HIBC_QR:
-               case BARCODE_HIBC_PDF:
-               case BARCODE_HIBC_MICPDF:
-               case BARCODE_HIBC_AZTEC:
-               case BARCODE_AZRUNE:
-               case BARCODE_CODE32:
-               case BARCODE_EANX_CC:
-               case BARCODE_EAN128_CC:
-               case BARCODE_RSS14_CC:
-               case BARCODE_RSS_LTD_CC:
-               case BARCODE_RSS_EXP_CC:
-               case BARCODE_UPCA_CC:
-               case BARCODE_UPCE_CC:
-               case BARCODE_RSS14STACK_CC:
-               case BARCODE_RSS14_OMNI_CC:
-               case BARCODE_RSS_EXPSTACK_CC:
-               case BARCODE_CHANNEL:
-               case BARCODE_CODEONE:
-               case BARCODE_GRIDMATRIX:
-                       result = 1;
-                       break;
-       }
-       
-       return result;
+static int is_linear(const int symbology) {
+    /* Returns 1 if symbology is linear (1 dimensional) */
+
+    int result = 0;
+    switch (symbology) {
+        case BARCODE_CODE11:
+        case BARCODE_C25MATRIX:
+        case BARCODE_C25INTER:
+        case BARCODE_C25IATA:
+        case BARCODE_C25LOGIC:
+        case BARCODE_C25IND:
+        case BARCODE_CODE39:
+        case BARCODE_EXCODE39:
+        case BARCODE_EANX:
+        case BARCODE_EANX_CHK:
+        case BARCODE_EAN128:
+        case BARCODE_CODABAR:
+        case BARCODE_CODE128:
+        case BARCODE_DPLEIT:
+        case BARCODE_DPIDENT:
+        case BARCODE_CODE93:
+        case BARCODE_FLAT:
+        case BARCODE_RSS14:
+        case BARCODE_RSS_LTD:
+        case BARCODE_RSS_EXP:
+        case BARCODE_TELEPEN:
+        case BARCODE_UPCA:
+        case BARCODE_UPCA_CHK:
+        case BARCODE_UPCE:
+        case BARCODE_UPCE_CHK:
+        case BARCODE_MSI_PLESSEY:
+        case BARCODE_FIM:
+        case BARCODE_LOGMARS:
+        case BARCODE_PHARMA:
+        case BARCODE_PZN:
+        case BARCODE_CODE128B:
+        case BARCODE_ISBNX:
+        case BARCODE_EAN14:
+        case BARCODE_NVE18:
+        case BARCODE_KOREAPOST:
+        case BARCODE_ONECODE:
+        case BARCODE_PLESSEY:
+        case BARCODE_TELEPEN_NUM:
+        case BARCODE_ITF14:
+        case BARCODE_HIBC_128:
+        case BARCODE_HIBC_39:
+        case BARCODE_CODE32:
+        case BARCODE_EANX_CC:
+        case BARCODE_EAN128_CC:
+        case BARCODE_RSS14_CC:
+        case BARCODE_RSS_LTD_CC:
+        case BARCODE_RSS_EXP_CC:
+        case BARCODE_UPCA_CC:
+        case BARCODE_UPCE_CC:
+        case BARCODE_CHANNEL:
+        case BARCODE_VIN:
+            result = 1;
+            break;
+    }
+
+    return result;
 }
 
-int extended_charset(struct zint_symbol *symbol, unsigned char *source, int length)
-{
-       int error_number = 0;
-       
-       /* These are the "elite" standards which can support multiple character sets */
-       switch(symbol->symbology) {
-               case BARCODE_QRCODE: error_number = qr_code(symbol, source, length); break;
-       }
+static int supports_eci(const int symbology) {
+    /* Returns 1 if symbology can encode the ECI character */
 
-       return error_number;
+    int result = 0;
+
+    switch (symbology) {
+        case BARCODE_AZTEC:
+        case BARCODE_DATAMATRIX:
+        case BARCODE_MAXICODE:
+        case BARCODE_MICROPDF417:
+        case BARCODE_PDF417:
+        case BARCODE_PDF417TRUNC:
+        case BARCODE_QRCODE:
+        case BARCODE_DOTCODE:
+        case BARCODE_GRIDMATRIX:
+        case BARCODE_HANXIN:
+        case BARCODE_ULTRA:
+            result = 1;
+            break;
+    }
+
+    return result;
 }
 
-int reduced_charset(struct zint_symbol *symbol, unsigned char *source, int length)
-{
-       /* These are the "norm" standards which only support Latin-1 at most */
-       int error_number = 0;
-       
+int ZBarcode_ValidID(int symbol_id) {
+    /* Checks whether a symbology is supported */
+
+    int result = 0;
+
+    switch (symbol_id) {
+        case BARCODE_CODE11:
+        case BARCODE_C25MATRIX:
+        case BARCODE_C25INTER:
+        case BARCODE_C25IATA:
+        case BARCODE_C25LOGIC:
+        case BARCODE_C25IND:
+        case BARCODE_CODE39:
+        case BARCODE_EXCODE39:
+        case BARCODE_EANX:
+        case BARCODE_EANX_CHK:
+        case BARCODE_EAN128:
+        case BARCODE_CODABAR:
+        case BARCODE_CODE128:
+        case BARCODE_DPLEIT:
+        case BARCODE_DPIDENT:
+        case BARCODE_CODE16K:
+        case BARCODE_CODE49:
+        case BARCODE_CODE93:
+        case BARCODE_FLAT:
+        case BARCODE_RSS14:
+        case BARCODE_RSS_LTD:
+        case BARCODE_RSS_EXP:
+        case BARCODE_TELEPEN:
+        case BARCODE_UPCA:
+        case BARCODE_UPCA_CHK:
+        case BARCODE_UPCE:
+        case BARCODE_UPCE_CHK:
+        case BARCODE_POSTNET:
+        case BARCODE_MSI_PLESSEY:
+        case BARCODE_FIM:
+        case BARCODE_LOGMARS:
+        case BARCODE_PHARMA:
+        case BARCODE_PZN:
+        case BARCODE_PHARMA_TWO:
+        case BARCODE_PDF417:
+        case BARCODE_PDF417TRUNC:
+        case BARCODE_MAXICODE:
+        case BARCODE_QRCODE:
+        case BARCODE_CODE128B:
+        case BARCODE_AUSPOST:
+        case BARCODE_AUSREPLY:
+        case BARCODE_AUSROUTE:
+        case BARCODE_AUSREDIRECT:
+        case BARCODE_ISBNX:
+        case BARCODE_RM4SCC:
+        case BARCODE_DATAMATRIX:
+        case BARCODE_EAN14:
+        case BARCODE_NVE18:
+        case BARCODE_JAPANPOST:
+        case BARCODE_KOREAPOST:
+        case BARCODE_RSS14STACK:
+        case BARCODE_RSS14STACK_OMNI:
+        case BARCODE_RSS_EXPSTACK:
+        case BARCODE_PLANET:
+        case BARCODE_MICROPDF417:
+        case BARCODE_ONECODE:
+        case BARCODE_PLESSEY:
+        case BARCODE_TELEPEN_NUM:
+        case BARCODE_ITF14:
+        case BARCODE_KIX:
+        case BARCODE_AZTEC:
+        case BARCODE_DAFT:
+        case BARCODE_MICROQR:
+        case BARCODE_HIBC_128:
+        case BARCODE_HIBC_39:
+        case BARCODE_HIBC_DM:
+        case BARCODE_HIBC_QR:
+        case BARCODE_HIBC_PDF:
+        case BARCODE_HIBC_MICPDF:
+        case BARCODE_HIBC_AZTEC:
+        case BARCODE_HIBC_BLOCKF:
+        case BARCODE_AZRUNE:
+        case BARCODE_CODE32:
+        case BARCODE_EANX_CC:
+        case BARCODE_EAN128_CC:
+        case BARCODE_RSS14_CC:
+        case BARCODE_RSS_LTD_CC:
+        case BARCODE_RSS_EXP_CC:
+        case BARCODE_UPCA_CC:
+        case BARCODE_UPCE_CC:
+        case BARCODE_RSS14STACK_CC:
+        case BARCODE_RSS14_OMNI_CC:
+        case BARCODE_RSS_EXPSTACK_CC:
+        case BARCODE_CHANNEL:
+        case BARCODE_CODEONE:
+        case BARCODE_GRIDMATRIX:
+        case BARCODE_HANXIN:
+        case BARCODE_DOTCODE:
+        case BARCODE_CODABLOCKF:
+        case BARCODE_UPNQR:
+        case BARCODE_VIN:
+        case BARCODE_MAILMARK:
+        case BARCODE_ULTRA:
+        case BARCODE_RMQR:
+            result = 1;
+            break;
+    }
+
+    return result;
+}
+
+static int reduced_charset(struct zint_symbol *symbol, const unsigned char *source, size_t in_length);
+
+static int extended_or_reduced_charset(struct zint_symbol *symbol, const unsigned char *source, const int length) {
+    int error_number = 0;
+
+    switch (symbol->symbology) {
+        /* These are the "elite" standards which have support for specific character sets */
+        case BARCODE_QRCODE: error_number = qr_code(symbol, source, length);
+            break;
+        case BARCODE_MICROQR: error_number = microqr(symbol, source, length);
+            break;
+        case BARCODE_GRIDMATRIX: error_number = grid_matrix(symbol, source, length);
+            break;
+        case BARCODE_HANXIN: error_number = han_xin(symbol, source, length);
+            break;
+        case BARCODE_UPNQR: error_number = upnqr(symbol, source, length);
+            break;
+        case BARCODE_RMQR: error_number = rmqr(symbol, source, length);
+            break;
+        default: error_number = reduced_charset(symbol, source, length);
+            break;
+    }
+
+    return error_number;
+}
+
+static int reduced_charset(struct zint_symbol *symbol, const unsigned char *source, size_t in_length) {
+    /* These are the "norm" standards which only support Latin-1 at most, though a few support ECI */
+    int error_number = 0;
+
+#ifndef _MSC_VER
+    unsigned char preprocessed[in_length + 1];
+#else
+    unsigned char* preprocessed = (unsigned char*) _alloca(in_length + 1);
+#endif
+
+    if (symbol->symbology == BARCODE_ITF14) {
+        symbol->whitespace_width = 20;
+        symbol->border_width = 8;
+        if (!(symbol->output_options & BARCODE_BOX)) {
+            symbol->output_options += BARCODE_BOX;
+        }
+    }
+
+    switch (symbol->input_mode & 0x07) {
+        case DATA_MODE:
+        case GS1_MODE:
+            memcpy(preprocessed, source, in_length);
+            preprocessed[in_length] = '\0';
+            break;
+        case UNICODE_MODE:
+            /* Prior check ensures ECI only set for those that support it */
+            error_number = utf_to_eci(symbol->eci && symbol->eci <= 899 ? symbol->eci : 3, source, preprocessed, &in_length);
+            if (error_number != 0) {
+                strcpy(symbol->errtxt, "204: Invalid characters in input data");
+                return error_number;
+            }
+            break;
+    }
+
+    if ((symbol->height == 0) && is_linear(symbol->symbology)) {
+        symbol->height = 50;
+    }
+
+    switch (symbol->symbology) {
+        case BARCODE_C25MATRIX: error_number = matrix_two_of_five(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_C25IND: error_number = industrial_two_of_five(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_C25INTER: error_number = interleaved_two_of_five(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_C25IATA: error_number = iata_two_of_five(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_C25LOGIC: error_number = logic_two_of_five(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_DPLEIT: error_number = dpleit(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_DPIDENT: error_number = dpident(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_UPCA:
+        case BARCODE_UPCA_CHK:
+        case BARCODE_UPCE:
+        case BARCODE_UPCE_CHK:
+        case BARCODE_EANX:
+        case BARCODE_EANX_CHK:
+            error_number = eanx(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_EAN128: error_number = ean_128(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CODE39: error_number = c39(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_PZN: error_number = pharmazentral(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_EXCODE39: error_number = ec39(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CODABAR: error_number = codabar(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CODE93: error_number = c93(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_LOGMARS: error_number = c39(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CODE128:
+        case BARCODE_CODE128B:
+            error_number = code_128(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_NVE18: error_number = nve_18(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CODE11: error_number = code_11(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_MSI_PLESSEY: error_number = msi_handle(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_TELEPEN: error_number = telepen(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_TELEPEN_NUM: error_number = telepen_num(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_PHARMA: error_number = pharma_one(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_PLESSEY: error_number = plessey(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_ITF14: error_number = itf14(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_FLAT: error_number = flattermarken(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_FIM: error_number = fim(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_POSTNET: error_number = post_plot(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_PLANET: error_number = planet_plot(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_RM4SCC: error_number = royal_plot(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_AUSPOST:
+        case BARCODE_AUSREPLY:
+        case BARCODE_AUSROUTE:
+        case BARCODE_AUSREDIRECT:
+            error_number = australia_post(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CODE16K: error_number = code16k(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_PHARMA_TWO: error_number = pharma_two(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_ONECODE: error_number = imail(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_ISBNX: error_number = eanx(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_RSS14:
+        case BARCODE_RSS14STACK:
+        case BARCODE_RSS14STACK_OMNI:
+            error_number = rss14(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_RSS_LTD: error_number = rsslimited(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_RSS_EXP:
+        case BARCODE_RSS_EXPSTACK:
+            error_number = rssexpanded(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_EANX_CC:
+        case BARCODE_EAN128_CC:
+        case BARCODE_RSS14_CC:
+        case BARCODE_RSS_LTD_CC:
+        case BARCODE_RSS_EXP_CC:
+        case BARCODE_UPCA_CC:
+        case BARCODE_UPCE_CC:
+        case BARCODE_RSS14STACK_CC:
+        case BARCODE_RSS14_OMNI_CC:
+        case BARCODE_RSS_EXPSTACK_CC:
+            error_number = composite(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_KIX: error_number = kix_code(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CODE32: error_number = code32(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_DAFT: error_number = daft_code(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_EAN14:
+            error_number = ean_14(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_AZRUNE: error_number = aztec_runes(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_KOREAPOST: error_number = korea_post(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_HIBC_128:
+        case BARCODE_HIBC_39:
+        case BARCODE_HIBC_DM:
+        case BARCODE_HIBC_QR:
+        case BARCODE_HIBC_PDF:
+        case BARCODE_HIBC_MICPDF:
+        case BARCODE_HIBC_AZTEC:
+        case BARCODE_HIBC_BLOCKF:
+            error_number = hibc(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_JAPANPOST: error_number = japan_post(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CODE49: error_number = code_49(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CHANNEL: error_number = channel_code(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CODEONE: error_number = code_one(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_DATAMATRIX: error_number = dmatrix(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_PDF417:
+        case BARCODE_PDF417TRUNC:
+            error_number = pdf417enc(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_MICROPDF417: error_number = micro_pdf417(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_MAXICODE: error_number = maxicode(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_AZTEC: error_number = aztec(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_DOTCODE: error_number = dotcode(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_CODABLOCKF: error_number = codablock(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_VIN: error_number = vin(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_MAILMARK: error_number = mailmark(symbol, preprocessed, in_length);
+            break;
+        case BARCODE_ULTRA: error_number = ultracode(symbol, preprocessed, in_length);
+            break;
+    }
+
+    return error_number;
+}
+
+static void strip_bom(unsigned char *source, int *input_length) {
+    int i;
+
+    if (*input_length > 3) {
+        if((source[0] == 0xef) && (source[1] == 0xbb) && (source[2] == 0xbf)) {
+            /* BOM at start of input data, strip in accordance with RFC 3629 */
+            for (i = 3; i < *input_length; i++) {
+                source[i - 3] = source[i];
+            }
+            *input_length -= 3;
+        }
+    }
+}
+
+static int escape_char_process(struct zint_symbol *symbol, unsigned char *input_string, int *length) {
+    int error_number;
+    int in_posn, out_posn;
+    int hex1, hex2;
+
 #ifndef _MSC_VER
-       unsigned char preprocessed[length + 1];
+    unsigned char escaped_string[*length + 1];
 #else
-        unsigned char* preprocessed = (unsigned char*)_alloca(length + 1);
+    unsigned char* escaped_string = (unsigned char*) _alloca(*length + 1);
 #endif
-       
-       if(symbol->symbology == BARCODE_CODE16K) {
-               symbol->whitespace_width = 16;
-               symbol->border_width = 2;
-               symbol->output_options = BARCODE_BIND;
-       }
-       
-       if(symbol->symbology == BARCODE_ITF14) {
-               symbol->whitespace_width = 20;
-               symbol->border_width = 8;
-               symbol->output_options = BARCODE_BOX;
-       }
-       
-       switch(symbol->input_mode) {
-               case DATA_MODE:
-               case GS1_MODE:
-                       memcpy(preprocessed, source, length);
-                       preprocessed[length] = '\0';
-                       break;
-               case UNICODE_MODE:
-                       error_number = latin1_process(source, preprocessed, &length);
-                       if(error_number != 0) { 
-                               strcpy(symbol->errtxt, "error: Invalid character in input string (only Latin-1 characters supported)");
-                               return error_number; 
-                       }
-                       break;
-       }
-
-       switch(symbol->symbology) {
-               case BARCODE_C25INTER: error_number = interleaved_two_of_five(symbol, preprocessed, length); break;
-               case BARCODE_UPCA: error_number = eanx(symbol, preprocessed, length); break;
-               case BARCODE_UPCE: error_number = eanx(symbol, preprocessed, length); break;
-               case BARCODE_EANX: error_number = eanx(symbol, preprocessed, length); break;
-               case BARCODE_CODE39: error_number = c39(symbol, preprocessed, length); break;
-               case BARCODE_LOGMARS: error_number = c39(symbol, preprocessed, length); break;
-               case BARCODE_CODE128: error_number = code_128(symbol, preprocessed, length); break;
-               case BARCODE_CODE128B: error_number = code_128(symbol, preprocessed, length); break;
-               case BARCODE_ISBNX: error_number = eanx(symbol, preprocessed, length); break;
-               case BARCODE_HIBC_128: error_number = hibc(symbol, preprocessed, length); break;
-               case BARCODE_HIBC_39: error_number = hibc(symbol, preprocessed, length); break;
-               case BARCODE_HIBC_DM: error_number = hibc(symbol, preprocessed, length); break;
-               case BARCODE_HIBC_QR: error_number = hibc(symbol, preprocessed, length); break;
-               case BARCODE_HIBC_PDF: error_number = hibc(symbol, preprocessed, length); break;
-               case BARCODE_HIBC_MICPDF: error_number = hibc(symbol, preprocessed, length); break;
-               case BARCODE_HIBC_AZTEC: error_number = hibc(symbol, preprocessed, length); break;
-       }
-       
-       return error_number;
+
+    in_posn = 0;
+    out_posn = 0;
+
+    do {
+        if (input_string[in_posn] == '\\') {
+            if (in_posn + 1 >= *length) {
+                strcpy(symbol->errtxt, "236: Incomplete escape character in input data");
+                return ZINT_ERROR_INVALID_DATA;
+            }
+            switch (input_string[in_posn + 1]) {
+                case '0': escaped_string[out_posn] = 0x00; /* Null */
+                    in_posn += 2;
+                    break;
+                case 'E': escaped_string[out_posn] = 0x04; /* End of Transmission */
+                    in_posn += 2;
+                    break;
+                case 'a': escaped_string[out_posn] = 0x07; /* Bell */
+                    in_posn += 2;
+                    break;
+                case 'b': escaped_string[out_posn] = 0x08; /* Backspace */
+                    in_posn += 2;
+                    break;
+                case 't': escaped_string[out_posn] = 0x09; /* Horizontal tab */
+                    in_posn += 2;
+                    break;
+                case 'n': escaped_string[out_posn] = 0x0a; /* Line feed */
+                    in_posn += 2;
+                    break;
+                case 'v': escaped_string[out_posn] = 0x0b; /* Vertical tab */
+                    in_posn += 2;
+                    break;
+                case 'f': escaped_string[out_posn] = 0x0c; /* Form feed */
+                    in_posn += 2;
+                    break;
+                case 'r': escaped_string[out_posn] = 0x0d; /* Carriage return */
+                    in_posn += 2;
+                    break;
+                case 'e': escaped_string[out_posn] = 0x1b; /* Escape */
+                    in_posn += 2;
+                    break;
+                case 'G': escaped_string[out_posn] = 0x1d; /* Group Separator */
+                    in_posn += 2;
+                    break;
+                case 'R': escaped_string[out_posn] = 0x1e; /* Record Separator */
+                    in_posn += 2;
+                    break;
+                case 'x': if (in_posn + 4 > *length) {
+                        strcpy(symbol->errtxt, "232: Incomplete escape character in input data");
+                        return ZINT_ERROR_INVALID_DATA;
+                    }
+                    hex1 = ctoi(input_string[in_posn + 2]);
+                    hex2 = ctoi(input_string[in_posn + 3]);
+                    if ((hex1 >= 0) && (hex2 >= 0)) {
+                        if (hex1 > 7 && (symbol->input_mode & 0x07) == UNICODE_MODE) {
+                            // Convert to UTF-8
+                            escaped_string[out_posn] = 0xc0 + (hex1 >> 2);
+                            out_posn++;
+                            escaped_string[out_posn] = 0x80 + ((hex1 & 0x03) << 4) + hex2;
+                        } else {
+                            escaped_string[out_posn] = (hex1 << 4) + hex2;
+                        }
+                        in_posn += 4;
+                    } else {
+                        strcpy(symbol->errtxt, "233: Corrupt escape character in input data");
+                        return ZINT_ERROR_INVALID_DATA;
+                    }
+                    break;
+                case '\\': escaped_string[out_posn] = '\\';
+                    in_posn += 2;
+                    break;
+                default: strcpy(symbol->errtxt, "234: Unrecognised escape character in input data");
+                    return ZINT_ERROR_INVALID_DATA;
+                    break;
+            }
+        } else {
+            escaped_string[out_posn] = input_string[in_posn];
+            in_posn++;
+        }
+        out_posn++;
+    } while (in_posn < *length);
+
+    memcpy(input_string, escaped_string, out_posn);
+    input_string[out_posn] = '\0';
+    *length = out_posn;
+
+    error_number = 0;
+
+    return error_number;
 }
 
-int ZBarcode_Encode(struct zint_symbol *symbol, unsigned char *source, int length)
-{
-       int error_number, error_buffer, i;
-        error_number = 0;
-
-       if(length == 0) {
-               length = ustrlen(source);
-       }
-       if(length == 0) {
-               strcpy(symbol->errtxt, "No input data");
-               error_tag(symbol->errtxt, ERROR_INVALID_DATA);
-               return ERROR_INVALID_DATA;
-       }
-
-       
+int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int in_length) {
+    int error_number, error_buffer, i;
+#ifdef _MSC_VER
+    unsigned char* local_source;
+#endif
+    error_number = 0;
+
+    if (in_length <= 0) {
+        in_length = (int)ustrlen(source);
+    }
+    if (in_length <= 0) {
+        strcpy(symbol->errtxt, "205: No input data");
+        error_tag(symbol->errtxt, ZINT_ERROR_INVALID_DATA);
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    if (strcmp(symbol->outfile, "") == 0) {
+#ifdef NO_PNG
+        strcpy(symbol->outfile, "out.gif");
+#else
+        strcpy(symbol->outfile, "out.png");
+#endif
+    }
 #ifndef _MSC_VER
-        unsigned char local_source[length + 1];
+    unsigned char local_source[in_length + 1];
 #else
-        unsigned char* local_source = (unsigned char*)_alloca(length + 1);
+    local_source = (unsigned char*) _alloca(in_length + 1);
 #endif
-       
-       /* First check the symbology field */
-       if(symbol->symbology < 1) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; }
-
-       /* symbol->symbologys 1 to 86 are defined by tbarcode */
-       if(symbol->symbology == 5) { symbol->symbology = BARCODE_C25MATRIX; }
-       if((symbol->symbology >= 10) && (symbol->symbology <= 12)) { symbol->symbology = BARCODE_EANX; }
-       if((symbol->symbology == 14) || (symbol->symbology == 15)) { symbol->symbology = BARCODE_EANX; }
-       if(symbol->symbology == 17) { symbol->symbology = BARCODE_UPCA; }
-       if(symbol->symbology == 19) { strcpy(symbol->errtxt, "Codabar 18 not supported, using Codabar"); symbol->symbology = BARCODE_CODABAR; error_number = WARN_INVALID_OPTION; }
-       if(symbol->symbology == 26) { symbol->symbology = BARCODE_UPCA; }
-       if(symbol->symbology == 27) { strcpy(symbol->errtxt, "UPCD1 not supported"); error_number = ERROR_INVALID_OPTION; }
-       if(symbol->symbology == 33) { symbol->symbology = BARCODE_EAN128; }
-       if((symbol->symbology == 35) || (symbol->symbology == 36)) { symbol->symbology = BARCODE_UPCA; }
-       if((symbol->symbology == 38) || (symbol->symbology == 39)) { symbol->symbology = BARCODE_UPCE; }
-       if((symbol->symbology >= 41) && (symbol->symbology <= 45)) { symbol->symbology = BARCODE_POSTNET; }
-       if(symbol->symbology == 46) { symbol->symbology = BARCODE_PLESSEY; }
-       if(symbol->symbology == 48) { symbol->symbology = BARCODE_NVE18; }
-       if(symbol->symbology == 54) { strcpy(symbol->errtxt, "General Parcel Code not supported, using Code 128"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; }
-       if((symbol->symbology == 59) || (symbol->symbology == 61)) { symbol->symbology = BARCODE_CODE128; }
-       if(symbol->symbology == 62) { symbol->symbology = BARCODE_CODE93; }
-       if((symbol->symbology == 64) || (symbol->symbology == 65)) { symbol->symbology = BARCODE_AUSPOST; }
-       if(symbol->symbology == 73) { strcpy(symbol->errtxt, "Codablock E not supported"); error_number = ERROR_INVALID_OPTION; }
-       if(symbol->symbology == 78) { symbol->symbology = BARCODE_RSS14; }
-       if(symbol->symbology == 83) { symbol->symbology = BARCODE_PLANET; }
-       if(symbol->symbology == 88) { symbol->symbology = BARCODE_EAN128; }
-       if(symbol->symbology == 91) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; }
-       if((symbol->symbology >= 94) && (symbol->symbology <= 96)) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; }
-       if(symbol->symbology == 100) { symbol->symbology = BARCODE_HIBC_128; }
-       if(symbol->symbology == 101) { symbol->symbology = BARCODE_HIBC_39; }
-       if(symbol->symbology == 103) { symbol->symbology = BARCODE_HIBC_DM; }
-       if(symbol->symbology == 105) { symbol->symbology = BARCODE_HIBC_QR; }
-       if(symbol->symbology == 107) { symbol->symbology = BARCODE_HIBC_PDF; }
-       if(symbol->symbology == 109) { symbol->symbology = BARCODE_HIBC_MICPDF; }
-       if(symbol->symbology == 111) { symbol->symbology = BARCODE_HIBC_BLOCKF; }
-       if((symbol->symbology >= 113) && (symbol->symbology <= 127)) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; }
-       /* Everything from 128 up is Zint-specific */
-       if(symbol->symbology >= 143) { strcpy(symbol->errtxt, "Symbology out of range, using Code 128"); symbol->symbology = BARCODE_CODE128; error_number = WARN_INVALID_OPTION; }
-       if((symbol->symbology == BARCODE_CODABLOCKF) || (symbol->symbology == BARCODE_HIBC_BLOCKF)) { strcpy(symbol->errtxt, "Codablock F not supported"); error_number = ERROR_INVALID_OPTION; }
-       
-       if(error_number > 4) {
-               error_tag(symbol->errtxt, error_number);
-               return error_number;
-       } else {
-               error_buffer = error_number;
-       }
-       
-       if((symbol->input_mode < 0) || (symbol->input_mode > 2)) { symbol->input_mode = DATA_MODE; }
-       
-       if(symbol->input_mode == GS1_MODE) {
-               for(i = 0; i < length; i++) {
-                       if(source[i] == '\0') {
-                               strcpy(symbol->errtxt, "NULL characters not permitted in GS1 mode");
-                               return ERROR_INVALID_DATA;
-                       }
-               }
-               if(gs1_compliant(symbol->symbology) == 1) {
-                       error_number = ugs1_verify(symbol, source, length, local_source);
-                       if(error_number != 0) { return error_number; }
-                       length = ustrlen(local_source);
-               } else {
-                       strcpy(symbol->errtxt, "Selected symbology does not support GS1 mode");
-                       return ERROR_INVALID_OPTION;
-               }
-       } else {
-               memcpy(local_source, source, length);
-               local_source[length] = '\0';
-       }
-       
-       switch(symbol->symbology) {
-               case BARCODE_QRCODE:
-               case BARCODE_MICROQR:
-               case BARCODE_GRIDMATRIX:
-                       error_number = extended_charset(symbol, local_source, length);
-                       break;
-               default:
-                       error_number = reduced_charset(symbol, local_source, length);
-                       break;
-       }
-       
-       if((symbol->symbology == BARCODE_CODE128) || (symbol->symbology == BARCODE_CODE128B)) {
-               for(i = 0; i < length; i++) {
-                       if(local_source[i] == '\0') {
-                               symbol->text[i] = ' ';
-                       } else {
-                               symbol->text[i] = local_source[i];
-                       }
-               }
-       }
-       
-       if(error_number == 0) {
-               error_number = error_buffer;
-       }
-       error_tag(symbol->errtxt, error_number);
-       /*printf("%s\n",symbol->text);*/
-       return error_number;
+
+    /* First check the symbology field */
+    if (symbol->symbology < 1) {
+        strcpy(symbol->errtxt, "206: Symbology out of range, using Code 128");
+        symbol->symbology = BARCODE_CODE128;
+        error_number = ZINT_WARN_INVALID_OPTION;
+    }
+
+    /* symbol->symbologys 1 to 86 are defined by tbarcode */
+    if (symbol->symbology == 5) {
+        symbol->symbology = BARCODE_C25MATRIX;
+    }
+    if ((symbol->symbology >= 10) && (symbol->symbology <= 12)) {
+        symbol->symbology = BARCODE_EANX;
+    }
+    if (symbol->symbology == 15) {
+        symbol->symbology = BARCODE_EANX;
+    }
+    if (symbol->symbology == 17) {
+        symbol->symbology = BARCODE_UPCA;
+    }
+    if (symbol->symbology == 19) {
+        strcpy(symbol->errtxt, "207: Codabar 18 not supported, using Codabar");
+        symbol->symbology = BARCODE_CODABAR;
+        error_number = ZINT_WARN_INVALID_OPTION;
+    }
+    if (symbol->symbology == 26) {
+        symbol->symbology = BARCODE_UPCA;
+    }
+    if (symbol->symbology == 27) {
+        strcpy(symbol->errtxt, "208: UPCD1 not supported");
+        error_number = ZINT_ERROR_INVALID_OPTION;
+    }
+    if (symbol->symbology == 33) {
+        symbol->symbology = BARCODE_EAN128;
+    }
+    if (symbol->symbology == 36) {
+        symbol->symbology = BARCODE_UPCA;
+    }
+    if ((symbol->symbology >= 41) && (symbol->symbology <= 45)) {
+        symbol->symbology = BARCODE_POSTNET;
+    }
+    if (symbol->symbology == 46) {
+        symbol->symbology = BARCODE_PLESSEY;
+    }
+    if (symbol->symbology == 48) {
+        symbol->symbology = BARCODE_NVE18;
+    }
+    if (symbol->symbology == 54) {
+        strcpy(symbol->errtxt, "210: General Parcel Code not supported, using Code 128");
+        symbol->symbology = BARCODE_CODE128;
+        error_number = ZINT_WARN_INVALID_OPTION;
+    }
+    if ((symbol->symbology == 59) || (symbol->symbology == 61)) {
+        symbol->symbology = BARCODE_CODE128;
+    }
+    if (symbol->symbology == 62) {
+        symbol->symbology = BARCODE_CODE93;
+    }
+    if ((symbol->symbology == 64) || (symbol->symbology == 65)) {
+        symbol->symbology = BARCODE_AUSPOST;
+    }
+    if (symbol->symbology == 78) {
+        symbol->symbology = BARCODE_RSS14;
+    }
+    if (symbol->symbology == 83) {
+        symbol->symbology = BARCODE_PLANET;
+    }
+    if (symbol->symbology == 88) {
+        symbol->symbology = BARCODE_EAN128;
+    }
+    if (symbol->symbology == 91) {
+        strcpy(symbol->errtxt, "212: Symbology out of range, using Code 128");
+        symbol->symbology = BARCODE_CODE128;
+        error_number = ZINT_WARN_INVALID_OPTION;
+    }
+    if ((symbol->symbology >= 94) && (symbol->symbology <= 96)) {
+        strcpy(symbol->errtxt, "213: Symbology out of range, using Code 128");
+        symbol->symbology = BARCODE_CODE128;
+        error_number = ZINT_WARN_INVALID_OPTION;
+    }
+    if (symbol->symbology == 100) {
+        symbol->symbology = BARCODE_HIBC_128;
+    }
+    if (symbol->symbology == 101) {
+        symbol->symbology = BARCODE_HIBC_39;
+    }
+    if (symbol->symbology == 103) {
+        symbol->symbology = BARCODE_HIBC_DM;
+    }
+    if (symbol->symbology == 105) {
+        symbol->symbology = BARCODE_HIBC_QR;
+    }
+    if (symbol->symbology == 107) {
+        symbol->symbology = BARCODE_HIBC_PDF;
+    }
+    if (symbol->symbology == 109) {
+        symbol->symbology = BARCODE_HIBC_MICPDF;
+    }
+    if (symbol->symbology == 111) {
+        symbol->symbology = BARCODE_HIBC_BLOCKF;
+    }
+    if ((symbol->symbology == 113) || (symbol->symbology == 114)) {
+        strcpy(symbol->errtxt, "214: Symbology out of range, using Code 128");
+        symbol->symbology = BARCODE_CODE128;
+        error_number = ZINT_WARN_INVALID_OPTION;
+    }
+    if (symbol->symbology == 115) {
+        symbol->symbology = BARCODE_DOTCODE;
+    }
+    if ((symbol->symbology >= 117) && (symbol->symbology <= 127)) {
+        if (symbol->symbology != 121) {
+            strcpy(symbol->errtxt, "215: Symbology out of range, using Code 128");
+            symbol->symbology = BARCODE_CODE128;
+            error_number = ZINT_WARN_INVALID_OPTION;
+        }
+    }
+    /* Everything from 128 up is Zint-specific */
+    if (symbol->symbology > 145) {
+        strcpy(symbol->errtxt, "216: Symbology out of range, using Code 128");
+        symbol->symbology = BARCODE_CODE128;
+        error_number = ZINT_WARN_INVALID_OPTION;
+    }
+
+    if ((!(supports_eci(symbol->symbology))) && (symbol->eci != 0)) {
+        strcpy(symbol->errtxt, "217: Symbology does not support ECI switching");
+        error_number = ZINT_ERROR_INVALID_OPTION;
+    }
+
+    if ((symbol->eci < 0) || (symbol->eci == 1) || (symbol->eci == 2) || (symbol->eci > 999999)) {
+        strcpy(symbol->errtxt, "218: Invalid ECI mode");
+        error_number = ZINT_ERROR_INVALID_OPTION;
+    }
+
+    if ((symbol->dot_size < 0.01) || (symbol->dot_size > 20.0)) {
+        strcpy(symbol->errtxt, "221: Invalid dot size");
+        error_number = ZINT_ERROR_INVALID_OPTION;
+    }
+
+    if ((symbol->input_mode & 0x07) > 2) {
+        symbol->input_mode = DATA_MODE; /* Reset completely */
+    }
+
+    if (error_number > 4) {
+        error_tag(symbol->errtxt, error_number);
+        return error_number;
+    } else {
+        error_buffer = error_number;
+    }
+
+    memcpy(local_source, source, in_length);
+    local_source[in_length] = '\0';
+
+    /* Start acting on input mode */
+    if (symbol->input_mode & ESCAPE_MODE) {
+        error_number = escape_char_process(symbol, local_source, &in_length);
+        if (error_number != 0) {
+            error_tag(symbol->errtxt, error_number);
+            return error_number;
+        }
+    }
+
+    if ((symbol->input_mode & 0x07) == UNICODE_MODE) {
+        strip_bom(local_source, &in_length);
+    }
+
+    if (((symbol->input_mode & 0x07) == GS1_MODE) || (check_force_gs1(symbol->symbology))) {
+        if (gs1_compliant(symbol->symbology) == 1) {
+            // Reduce input for composite and non-forced symbologies, others (EAN128 and RSS_EXP based) will handle it themselves
+            if (is_composite(symbol->symbology) || !check_force_gs1(symbol->symbology)) {
+#ifndef _MSC_VER
+                char reduced[in_length + 1];
+#else
+                char* reduced = (char*) _alloca(in_length + 1);
+#endif
+                error_number = gs1_verify(symbol, local_source, in_length, reduced);
+                if (error_number != 0) {
+                    error_tag(symbol->errtxt, error_number);
+                    return error_number;
+                }
+                ustrcpy(local_source, reduced); // Cannot contain nul char
+                in_length = (int) ustrlen(local_source);
+            }
+        } else {
+            strcpy(symbol->errtxt, "220: Selected symbology does not support GS1 mode");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_OPTION);
+            return ZINT_ERROR_INVALID_OPTION;
+        }
+    }
+
+    error_number = extended_or_reduced_charset(symbol, local_source, in_length);
+
+    if ((error_number == ZINT_ERROR_INVALID_DATA) && symbol->eci == 0 && supports_eci(symbol->symbology)
+            && (symbol->input_mode & 0x07) == UNICODE_MODE) {
+        /* Try another ECI mode */
+        symbol->eci = get_best_eci(local_source, in_length);
+
+        error_number = extended_or_reduced_charset(symbol, local_source, in_length);
+
+        if (error_number == 0) {
+            error_number = ZINT_WARN_USES_ECI;
+            if (!(symbol->debug & ZINT_DEBUG_TEST)) {
+                strcpy(symbol->errtxt, "222: Encoded data includes ECI");
+            }
+            if (symbol->debug & ZINT_DEBUG_PRINT) printf("Data ECI %d\n", symbol->eci);
+        }
+    }
+
+    if (error_number == 0) {
+        if ((symbol->symbology == BARCODE_CODE128) || (symbol->symbology == BARCODE_CODE128B)) {
+            for (i = 0; i < in_length; i++) {
+                if (local_source[i] == '\0') {
+                    symbol->text[i] = ' ';
+                } else {
+                    symbol->text[i] = local_source[i];
+                }
+            }
+        }
+        error_number = error_buffer;
+    }
+    error_tag(symbol->errtxt, error_number);
+
+    if (error_number < 5) {
+        check_row_heights(symbol);
+    }
+
+    return error_number;
+}
+
+int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) {
+    int error_number;
+
+    switch (rotate_angle) {
+        case 0:
+        case 90:
+        case 180:
+        case 270:
+            break;
+        default:
+            strcpy(symbol->errtxt, "223: Invalid rotation angle");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_OPTION);
+            return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    if (symbol->output_options & BARCODE_DOTTY_MODE) {
+        if (!(is_matrix(symbol->symbology))) {
+            strcpy(symbol->errtxt, "224: Selected symbology cannot be rendered as dots");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_OPTION);
+            return ZINT_ERROR_INVALID_OPTION;
+        }
+    }
+
+    if (strlen(symbol->outfile) > 3) {
+        char output[4];
+        output[0] = symbol->outfile[strlen(symbol->outfile) - 3];
+        output[1] = symbol->outfile[strlen(symbol->outfile) - 2];
+        output[2] = symbol->outfile[strlen(symbol->outfile) - 1];
+        output[3] = '\0';
+        to_upper((unsigned char*) output);
+
+        if (!(strcmp(output, "PNG"))) {
+            if (symbol->scale < 1.0) {
+                symbol->text[0] = '\0';
+            }
+            error_number = plot_raster(symbol, rotate_angle, OUT_PNG_FILE);
+        } else
+            if (!(strcmp(output, "BMP"))) {
+            if (symbol->scale < 1.0) {
+                symbol->text[0] = '\0';
+            }
+            error_number = plot_raster(symbol, rotate_angle, OUT_BMP_FILE);
+        } else
+            if (!(strcmp(output, "PCX"))) {
+            if (symbol->scale < 1.0) {
+                symbol->text[0] = '\0';
+            }
+            error_number = plot_raster(symbol, rotate_angle, OUT_PCX_FILE);
+        } else
+            if (!(strcmp(output, "GIF"))) {
+            if (symbol->scale < 1.0) {
+                symbol->text[0] = '\0';
+            }
+            error_number = plot_raster(symbol, rotate_angle, OUT_GIF_FILE);
+        } else
+            if (!(strcmp(output, "TIF"))) {
+            if (symbol->scale < 1.0) {
+                symbol->text[0] = '\0';
+            }
+            error_number = plot_raster(symbol, rotate_angle, OUT_TIF_FILE);
+        } else
+            if (!(strcmp(output, "TXT"))) {
+            error_number = dump_plot(symbol);
+        } else
+            if (!(strcmp(output, "EPS"))) {
+            error_number = plot_vector(symbol, rotate_angle, OUT_EPS_FILE);
+        } else
+            if (!(strcmp(output, "SVG"))) {
+            error_number = plot_vector(symbol, rotate_angle, OUT_SVG_FILE);
+        } else
+            if (!(strcmp(output, "EMF"))) {
+            error_number = plot_vector(symbol, rotate_angle, OUT_EMF_FILE);
+        } else {
+            strcpy(symbol->errtxt, "225: Unknown output format");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_OPTION);
+            return ZINT_ERROR_INVALID_OPTION;
+        }
+    } else {
+        strcpy(symbol->errtxt, "226: Unknown output format");
+        error_tag(symbol->errtxt, ZINT_ERROR_INVALID_OPTION);
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    error_tag(symbol->errtxt, error_number);
+    return error_number;
 }
 
-int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle)
-{
-       return ERROR_INVALID_OPTION;
+int ZBarcode_Buffer(struct zint_symbol *symbol, int rotate_angle) {
+    int error_number;
+
+    switch (rotate_angle) {
+        case 0:
+        case 90:
+        case 180:
+        case 270:
+            break;
+        default:
+            strcpy(symbol->errtxt, "228: Invalid rotation angle");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_OPTION);
+            return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    if (symbol->output_options & BARCODE_DOTTY_MODE) {
+        if (!(is_matrix(symbol->symbology))) {
+            strcpy(symbol->errtxt, "237: Selected symbology cannot be rendered as dots");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_OPTION);
+            return ZINT_ERROR_INVALID_OPTION;
+        }
+    }
+
+    error_number = plot_raster(symbol, rotate_angle, OUT_BUFFER);
+    error_tag(symbol->errtxt, error_number);
+    return error_number;
 }
 
-int ZBarcode_Buffer(struct zint_symbol *symbol, int rotate_angle)
-{
-       int error_number;
-       
-       switch(rotate_angle) {
-               case 0:
-               case 90:
-               case 180:
-               case 270:
-                       break;
-               default:
-                       strcpy(symbol->errtxt, "Invalid rotation angle");
-                       return ERROR_INVALID_OPTION;
-                       break;
-       }
-       
-       error_number = bmp_handle(symbol, rotate_angle);
-       error_tag(symbol->errtxt, error_number);
-       return error_number;
+int ZBarcode_Buffer_Vector(struct zint_symbol *symbol, int rotate_angle) {
+    int error_number;
+
+    switch (rotate_angle) {
+        case 0:
+        case 90:
+        case 180:
+        case 270:
+            break;
+        default:
+            strcpy(symbol->errtxt, "228: Invalid rotation angle");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_OPTION);
+            return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    if (symbol->output_options & BARCODE_DOTTY_MODE) {
+        if (!(is_matrix(symbol->symbology))) {
+            strcpy(symbol->errtxt, "238: Selected symbology cannot be rendered as dots");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_OPTION);
+            return ZINT_ERROR_INVALID_OPTION;
+        }
+    }
+
+    error_number = plot_vector(symbol, rotate_angle, OUT_BUFFER);
+    error_tag(symbol->errtxt, error_number);
+    return error_number;
 }
 
-int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle)
-{
-       int error_number;
-       
-       error_number = 0;
-       
-       error_number = ZBarcode_Encode(symbol, input, length);
-       if(error_number != 0) {
-               return error_number;
-       }
-
-       error_number = ZBarcode_Print(symbol, rotate_angle);
-       return error_number;
+int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle) {
+    int error_number;
+    int first_err;
+
+    error_number = ZBarcode_Encode(symbol, input, length);
+    if (error_number >= 5) {
+        return error_number;
+    }
+
+    first_err = error_number;
+    error_number = ZBarcode_Print(symbol, rotate_angle);
+    if (error_number == 0) {
+        error_number = first_err;
+    }
+    return error_number;
 }
 
-int ZBarcode_Encode_and_Buffer(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle)
-{
-       int error_number;
-       
-       error_number = 0;
-       
-       error_number = ZBarcode_Encode(symbol, input, length);
-       if(error_number != 0) {
-               return error_number;
-       }
-
-       error_number = ZBarcode_Buffer(symbol, rotate_angle);
-       return error_number;
+int ZBarcode_Encode_and_Buffer(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle) {
+    int error_number;
+    int first_err;
+
+    error_number = ZBarcode_Encode(symbol, input, length);
+    if (error_number >= 5) {
+        return error_number;
+    }
+
+    first_err = error_number;
+    error_number = ZBarcode_Buffer(symbol, rotate_angle);
+    if (error_number == 0) {
+        error_number = first_err;
+    }
+
+    return error_number;
 }
 
-int ZBarcode_Encode_File(struct zint_symbol *symbol, char *filename)
-{
-       FILE *file;
-       unsigned char *buffer;
-       unsigned long fileLen;
-       unsigned int nRead = 0, n = 0;
-       int ret;
-
-       if (!strcmp(filename, "-")) {
-               file = stdin;
-               fileLen = 7100;
-       } else {
-               file = fopen(filename, "rb");
-               if (!file) {
-                       strcpy(symbol->errtxt, "Unable to read input file");
-                       return ERROR_INVALID_DATA;
-               }
-       
-               /* Get file length */
-               fseek(file, 0, SEEK_END);
-               fileLen = ftell(file);
-               fseek(file, 0, SEEK_SET);
-       
-               if(fileLen > 7100) {
-                       /* The largest amount of data that can be encoded is 7089 numeric digits in QR Code */
-                       strcpy(symbol->errtxt, "Input file too long");
-                       fclose(file);
-                       return ERROR_INVALID_DATA;
-               }
-       }
-       
-       /* Allocate memory */
-       buffer = (unsigned char *)malloc(fileLen * sizeof(unsigned char));
-       if(!buffer) {
-               strcpy(symbol->errtxt, "Internal memory error");
-        if (strcmp(filename, "-"))
-                   fclose(file);
-               return ERROR_MEMORY;
-       }
-       
-       /* Read file contents into buffer */
-
-       do
-       {
-               n = fread(buffer + nRead, 1, fileLen - nRead, file);
-               if (ferror(file))
-               {
-                       strcpy(symbol->errtxt, strerror(errno));
-                       nRead = 0;
-                       return ERROR_INVALID_DATA;
-               }
-               nRead += n;
-       } while (!feof(file) && (0 < n) && (nRead < fileLen));
-       
-    if (strcmp(filename, "-"))
-           fclose(file);
-
-       ret = ZBarcode_Encode(symbol, buffer, nRead);
-       free(buffer);
-       return ret;
+int ZBarcode_Encode_and_Buffer_Vector(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle) {
+    int error_number;
+    int first_err;
+
+    error_number = ZBarcode_Encode(symbol, input, length);
+    if (error_number >= 5) {
+        return error_number;
+    }
+
+    first_err = error_number;
+    error_number = ZBarcode_Buffer_Vector(symbol, rotate_angle);
+    if (error_number == 0) {
+        error_number = first_err;
+    }
+
+    return error_number;
 }
 
-int ZBarcode_Encode_File_and_Print(struct zint_symbol *symbol, char *filename, int rotate_angle)
-{
-       int error_number;
-       
-       error_number = 0;
-       
-       error_number = ZBarcode_Encode_File(symbol, filename);
-       if(error_number != 0) {
-               return error_number;
-       }
-       
-       return ZBarcode_Print(symbol, rotate_angle);
+int ZBarcode_Encode_File(struct zint_symbol *symbol, char *filename) {
+    FILE *file;
+    unsigned char *buffer;
+    long fileLen;
+    size_t n;
+    int nRead = 0;
+    int ret;
+
+    if (!strcmp(filename, "-")) {
+        file = stdin;
+        fileLen = 7900;
+    } else {
+        file = fopen(filename, "rb");
+        if (!file) {
+            strcpy(symbol->errtxt, "229: Unable to read input file");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_OPTION);
+            return ZINT_ERROR_INVALID_DATA;
+        }
+
+        /* Get file length */
+        fseek(file, 0, SEEK_END);
+        fileLen = ftell(file);
+        fseek(file, 0, SEEK_SET);
+
+        if (fileLen > 7900) {
+            /* The largest amount of data that can be encoded is 7827 numeric digits in Han Xin Code */
+            strcpy(symbol->errtxt, "230: Input file too long");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_DATA);
+            fclose(file);
+            return ZINT_ERROR_INVALID_DATA;
+        }
+        if (fileLen <= 0) {
+            strcpy(symbol->errtxt, "235: Input file empty or unseekable");
+            error_tag(symbol->errtxt, ZINT_ERROR_INVALID_DATA);
+            fclose(file);
+            return ZINT_ERROR_INVALID_DATA;
+        }
+    }
+
+    /* Allocate memory */
+    buffer = (unsigned char *) malloc(fileLen * sizeof (unsigned char));
+    if (!buffer) {
+        strcpy(symbol->errtxt, "231: Internal memory error");
+        error_tag(symbol->errtxt, ZINT_ERROR_MEMORY);
+        if (strcmp(filename, "-")) {
+            fclose(file);
+        }
+        return ZINT_ERROR_MEMORY;
+    }
+
+    /* Read file contents into buffer */
+
+    do {
+        n = fread(buffer + nRead, 1, fileLen - nRead, file);
+        if (ferror(file)) {
+            strcpy(symbol->errtxt, strerror(errno));
+            if (strcmp(filename, "-")) {
+                fclose(file);
+            }
+            free(buffer);
+            return ZINT_ERROR_INVALID_DATA;
+        }
+        nRead += n;
+    } while (!feof(file) && (0 < n) && (nRead < fileLen));
+
+    if (strcmp(filename, "-")) {
+        fclose(file);
+    }
+    ret = ZBarcode_Encode(symbol, buffer, nRead);
+    free(buffer);
+    return ret;
 }
 
-int ZBarcode_Encode_File_and_Buffer(struct zint_symbol *symbol, char *filename, int rotate_angle)
-{
-       int error_number;
-       
-       error_number = 0;
-       
-       error_number = ZBarcode_Encode_File(symbol, filename);
-       if(error_number != 0) {
-               return error_number;
-       }
-       
-       return ZBarcode_Buffer(symbol, rotate_angle);
+int ZBarcode_Encode_File_and_Print(struct zint_symbol *symbol, char *filename, int rotate_angle) {
+    int error_number;
+    int first_err;
+
+    error_number = ZBarcode_Encode_File(symbol, filename);
+    if (error_number >= 5) {
+        return error_number;
+    }
+
+    first_err = error_number;
+    error_number = ZBarcode_Print(symbol, rotate_angle);
+    if (error_number == 0) {
+        error_number = first_err;
+    }
+
+    return error_number;
 }
 
-/*
- * Rendering support, initially added by Sam Lown.
- *
- * Converts encoded data into an intermediate format to be interpreted
- * in other applications using this library.
- *
- * If the width and height are not set to zero, the barcode will be resized to those
- * dimensions. The symbol->scale and symbol->height values are totally ignored in this case.
- *
- */
-int ZBarcode_Render(struct zint_symbol *symbol, float width, float height)
-{
-       // Send the request to the render_plot method
-       return render_plot(symbol, width, height);
+int ZBarcode_Encode_File_and_Buffer(struct zint_symbol *symbol, char *filename, int rotate_angle) {
+    int error_number;
+    int first_err;
+
+    error_number = ZBarcode_Encode_File(symbol, filename);
+    if (error_number >= 5) {
+        return error_number;
+    }
+
+    first_err = error_number;
+    error_number = ZBarcode_Buffer(symbol, rotate_angle);
+    if (error_number == 0) {
+        error_number = first_err;
+    }
+
+    return error_number;
+}
+
+int ZBarcode_Encode_File_and_Buffer_Vector(struct zint_symbol *symbol, char *filename, int rotate_angle) {
+    int error_number;
+    int first_err;
+
+    error_number = ZBarcode_Encode_File(symbol, filename);
+    if (error_number >= 5) {
+        return error_number;
+    }
+
+    first_err = error_number;
+    error_number = ZBarcode_Buffer_Vector(symbol, rotate_angle);
+    if (error_number == 0) {
+        error_number = first_err;
+    }
+
+    return error_number;
+}
+
+int ZBarcode_Version() {
+    return (ZINT_VERSION_MAJOR * 10000) + (ZINT_VERSION_MINOR * 100) + ZINT_VERSION_RELEASE;
 }
index 1930f69..ba08f73 100644 (file)
@@ -1,12 +1,14 @@
+#define WIN32_LEAN_AND_MEAN\r
 #include <windows.h>\r
+#include <winver.h>\r
 \r
 #ifdef GCC_WINDRES\r
 VS_VERSION_INFO                VERSIONINFO\r
 #else\r
 VS_VERSION_INFO                VERSIONINFO\r
 #endif\r
-  FILEVERSION          2,3,0,0\r
-  PRODUCTVERSION       2,3,0,0\r
+  FILEVERSION          2,8,1,0\r
+  PRODUCTVERSION       2,8,1,0\r
   FILEFLAGSMASK                VS_FFI_FILEFLAGSMASK\r
 #ifdef _DEBUG\r
   FILEFLAGS            VS_FF_DEBUG\r
@@ -23,14 +25,14 @@ BEGIN
     //language ID = U.S. English, char set = Windows, Multilingual\r
     BEGIN\r
       VALUE "FileDescription", "libzint barcode library\0"\r
-      VALUE "FileVersion",     "2.3.0.0\0"\r
+      VALUE "FileVersion",     "2.8.1.0\0"\r
       VALUE "InternalName",    "zint.dll\0"\r
-      VALUE "LegalCopyright",  "Copyright © 2009 Robin Stuart & BogDan Vatra\0"\r
+      VALUE "LegalCopyright",  "Copyright © 2020 Robin Stuart & BogDan Vatra\0"\r
       VALUE "OriginalFilename",        "zint.dll\0"\r
       VALUE "ProductName",     "libzint\0"\r
-      VALUE "ProductVersion",  "2.3.0.0\0"\r
+      VALUE "ProductVersion",  "2.8.1.0\0"\r
       VALUE "License",  "BSD License version 3\0"\r
-      VALUE "WWW", "http://www.sourceforge.net/projects/zint\0"      \r
+      VALUE "WWW", "http://www.sourceforge.net/projects/zint"      \r
     END\r
   END\r
   BLOCK "VarFileInfo"\r
diff --git a/backend/mailmark.c b/backend/mailmark.c
new file mode 100644 (file)
index 0000000..6e0588f
--- /dev/null
@@ -0,0 +1,498 @@
+/* mailmark.c - Royal Mail 4-state Mailmark barcodes */
+
+/*
+    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 : */
+
+/* 
+ * Developed in accordance with "Royal Mail Mailmark barcode C encoding and deconding instructions"
+ * (https://www.royalmail.com/sites/default/files/Mailmark-4-state-barcode-C-encoding-and-decoding-instructions-Sept-2015.pdf)
+ * and "Royal Mail Mailmark barcode L encoding and decoding"
+ * (https://www.royalmail.com/sites/default/files/Mailmark-4-state-barcode-L-encoding-and-decoding-instructions-Sept-2015.pdf)
+ * 
+ */
+
+#include <string.h>
+#include <stdio.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "large.h"
+#include "reedsol.h"
+
+#define RUBIDIUM "01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ "
+
+// Allowed character values from Table 3
+#define SET_F "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define SET_L "ABDEFGHJLNPQRSTUWXYZ"
+#define SET_N "0123456789"
+#define SET_S " "
+
+static const char *postcode_format[6] = {
+    "FNFNLLNLS", "FFNNLLNLS", "FFNNNLLNL", "FFNFNLLNL", "FNNLLNLSS", "FNNNLLNLS"
+};
+
+// Data/Check Symbols from Table 5
+static const unsigned short data_symbol_odd[32] = {
+    0x01, 0x02, 0x04, 0x07, 0x08, 0x0B, 0x0D, 0x0E, 0x10, 0x13, 0x15, 0x16,
+    0x19, 0x1A, 0x1C, 0x1F, 0x20, 0x23, 0x25, 0x26, 0x29, 0x2A, 0x2C, 0x2F,
+    0x31, 0x32, 0x34, 0x37, 0x38, 0x3B, 0x3D, 0x3E
+};
+
+static const unsigned short data_symbol_even[30] = {
+    0x03, 0x05, 0x06, 0x09, 0x0A, 0x0C, 0x0F, 0x11, 0x12, 0x14, 0x17, 0x18,
+    0x1B, 0x1D, 0x1E, 0x21, 0x22, 0x24, 0x27, 0x28, 0x2B, 0x2D, 0x2E, 0x30,
+    0x33, 0x35, 0x36, 0x39, 0x3A, 0x3C
+};
+
+static const unsigned short extender_group_c[22] = {
+    3, 5, 7, 11, 13, 14, 16, 17, 19, 0, 1, 2, 4, 6, 8, 9, 10, 12, 15, 18, 20, 21
+};
+
+static const unsigned short extender_group_l[26] = {
+    2, 5, 7, 8, 13, 14, 15, 16, 21, 22, 23, 0, 1, 3, 4, 6, 9, 10, 11, 12, 17, 18, 19, 20, 24, 25
+};
+
+static int verify_character(char input, char type) {
+    int val = 0;
+    
+    switch (type) {
+        case 'F':
+            val = posn(SET_F, input);
+            break;
+        case 'L':
+            val = posn(SET_L, input);
+            break;
+        case 'N':
+            val = posn(SET_N, input);
+            break;
+        case 'S':
+            val = posn(SET_S, input);
+            break;
+    }
+    
+    if (val == -1) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
+static int verify_postcode(char* postcode, int type) {
+    int i;
+    char pattern[11];
+    
+    strcpy(pattern, postcode_format[type - 1]);
+
+    for (i = 0; i < 9; i++) {
+        if (!(verify_character(postcode[i], pattern[i]))) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/* Royal Mail Mailmark */
+INTERNAL int mailmark(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) {
+    
+    char local_source[28];
+    int format;
+    int version_id;
+    int mail_class;
+    int supply_chain_id;
+    long item_id;
+    char postcode[10];
+    int postcode_type;
+    char pattern[10];
+    large_int destination_postcode;
+    large_int b;
+    large_int cdv;
+    unsigned char data[26];
+    int data_top, data_step;
+    unsigned char check[7];
+    short int extender[27];
+    char bar[80];
+    int check_count;
+    int i, j, len;
+    int length = (int) in_length;
+    
+    if (length > 26) {
+        strcpy(symbol->errtxt, "580: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    
+    strcpy(local_source, (char*) source);
+    
+    if (length < 22) {
+        for (i = length; i <= 22; i++) {
+            strcat(local_source, " ");
+        }
+        length = 22;
+    }
+    
+    if ((length > 22) && (length < 26)) {
+        for (i = length; i <= 26; i++) {
+            strcat(local_source, " ");
+        }
+        length = 26;
+    } 
+    
+    to_upper((unsigned char*) local_source);
+    
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("Producing Mailmark %s\n", local_source);
+    }
+    
+    if (is_sane(RUBIDIUM, (unsigned char *) local_source, length) != 0) {
+        strcpy(symbol->errtxt, "581: Invalid characters in input data");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    // Format is in the range 0-4
+    format = ctoi(local_source[0]);
+    if ((format < 0) || (format > 4)) {
+        strcpy(symbol->errtxt, "582: Invalid format");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+    
+    // Version ID is in the range 1-4
+    version_id = ctoi(local_source[1]) - 1;
+    if ((version_id < 0) || (version_id > 3)) {
+        strcpy(symbol->errtxt, "583: Invalid Version ID");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+    
+    // Class is in the range 0-9,A-E
+    mail_class = ctoi(local_source[2]);
+    if ((mail_class < 0) || (mail_class > 14)) {
+        strcpy(symbol->errtxt, "584: Invalid Class");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+    
+    // Supply Chain ID is 2 digits for barcode C and 6 digits for barcode L
+    supply_chain_id = 0;
+    for (i = 3; i < (length - 17); i++) {
+        if ((local_source[i] >= '0') && (local_source[i] <= '9')) {
+            supply_chain_id *= 10;
+            supply_chain_id += ctoi(local_source[i]);
+        } else {
+            strcpy(symbol->errtxt, "585: Invalid Supply Chain ID");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+    }
+    
+    // Item ID is 8 digits
+    item_id = 0;
+    for (i = length - 17; i < (length - 9); i++) {
+        if ((local_source[i] >= '0') && (local_source[i] <= '9')) {
+            item_id *= 10;
+            item_id += (long) ctoi(local_source[i]);
+        } else {
+            strcpy(symbol->errtxt, "586: Invalid Item ID");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+    }
+    
+    // Separate Destination Post Code plus DPS field
+    for (i = 0; i < 9; i++) {
+        postcode[i] = local_source[(length - 9) + i];
+    }
+    postcode[9] = '\0';
+    
+    // Detect postcode type
+    /* postcode_type is used to select which format of postcode 
+     * 
+     * 1 = FNFNLLNLS
+     * 2 = FFNNLLNLS
+     * 3 = FFNNNLLNL
+     * 4 = FFNFNLLNL
+     * 5 = FNNLLNLSS
+     * 6 = FNNNLLNLS
+     * 7 = International designation
+     */
+    
+    if (strcmp(postcode, "XY11     ") == 0) {
+        postcode_type = 7;
+    } else {
+        if (postcode[7] == ' ') {
+            postcode_type = 5;
+        } else {
+            if (postcode[8] == ' ') {
+                // Types 1, 2 and 6
+                if ((postcode[1] >= '0') && (postcode[1] <= '9')) {
+                    if ((postcode[2] >= '0') && (postcode[2] <= '9')) {
+                        postcode_type = 6;
+                    } else {
+                        postcode_type = 1;
+                    }
+                } else {
+                    postcode_type = 2;
+                }
+            } else {
+                // Types 3 and 4
+                if ((postcode[3] >= '0') && (postcode[3] <= '9')) {
+                    postcode_type = 3;
+                } else {
+                    postcode_type = 4;
+                }
+            }
+        }
+    }
+    
+    // Verify postcode type
+    if (postcode_type != 7) {
+        if (verify_postcode(postcode, postcode_type) != 0) {
+            strcpy(symbol->errtxt, "587: Invalid postcode");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+    }
+    
+    // Convert postcode to internal user field
+
+    large_load_u64(&destination_postcode, 0);
+
+    if (postcode_type != 7) {
+        strcpy(pattern, postcode_format[postcode_type - 1]);
+
+        large_load_u64(&b, 0);
+
+        for (i = 0; i < 9; i++) {
+            switch (pattern[i]) {
+                case 'F':
+                    large_mul_u64(&b, 26);
+                    large_add_u64(&b, posn(SET_F, postcode[i]));
+                    break;
+                case 'L':
+                    large_mul_u64(&b, 20);
+                    large_add_u64(&b, posn(SET_L, postcode[i]));
+                    break;
+                case 'N':
+                    large_mul_u64(&b, 10);
+                    large_add_u64(&b, posn(SET_N, postcode[i]));
+                    break;
+                // case 'S' ignored as value is 0
+            }
+        }
+
+        large_load(&destination_postcode, &b);
+
+        // destination_postcode = a + b
+        large_load_u64(&b, 1);
+        if (postcode_type == 1) {
+            large_add(&destination_postcode, &b);
+        }
+        large_add_u64(&b, 5408000000);
+        if (postcode_type == 2) {
+            large_add(&destination_postcode, &b);
+        }
+        large_add_u64(&b, 5408000000);
+        if (postcode_type == 3) {
+            large_add(&destination_postcode, &b);
+        }
+        large_add_u64(&b, 54080000000);
+        if (postcode_type == 4) {
+            large_add(&destination_postcode, &b);
+        }
+        large_add_u64(&b, 140608000000);
+        if (postcode_type == 5) {
+            large_add(&destination_postcode, &b);
+        }
+        large_add_u64(&b, 208000000);
+        if (postcode_type == 6) {
+            large_add(&destination_postcode, &b);
+        }
+    }
+    
+    // Conversion from Internal User Fields to Consolidated Data Value
+    // Set CDV to 0
+    large_load_u64(&cdv, 0);
+
+    // Add Destination Post Code plus DPS
+    large_add(&cdv, &destination_postcode);
+
+    // Multiply by 100,000,000
+    large_mul_u64(&cdv, 100000000);
+
+    // Add Item ID
+    large_add_u64(&cdv, item_id);
+
+    if (length == 22) {  
+        // Barcode C - Multiply by 100
+        large_mul_u64(&cdv, 100);
+    } else {
+        // Barcode L - Multiply by 1,000,000
+        large_mul_u64(&cdv, 1000000);
+    }
+
+    // Add Supply Chain ID
+    large_add_u64(&cdv, supply_chain_id);
+
+    // Multiply by 15
+    large_mul_u64(&cdv, 15);
+
+    // Add Class
+    large_add_u64(&cdv, mail_class);
+
+    // Multiply by 5
+    large_mul_u64(&cdv, 5);
+
+    // Add Format
+    large_add_u64(&cdv, format);
+
+    // Multiply by 4
+    large_mul_u64(&cdv, 4);
+
+    // Add Version ID
+    large_add_u64(&cdv, version_id);
+
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("DPC type %d\n", postcode_type);
+        printf("CDV: ");
+        large_print(&cdv);
+    }
+    
+    
+    if (length == 22) {
+        data_top = 15;
+        data_step = 8;
+        check_count = 6;
+    } else {
+        data_top = 18;
+        data_step = 10;
+        check_count = 7;
+    }
+    
+    // Conversion from Consolidated Data Value to Data Numbers
+
+    for (j = data_top; j >= (data_step + 1); j--) {
+        data[j] = large_div_u64(&cdv, 32);
+    }
+    
+    for (j = data_step; j >= 0; j--) {
+        data[j] = large_div_u64(&cdv, 30);
+    }
+    
+    // Generation of Reed-Solomon Check Numbers
+    rs_init_gf(0x25);
+    rs_init_code(check_count, 1);
+    rs_encode((data_top + 1), data, check);
+    rs_free();
+    
+    // Append check digits to data
+    for (i = 1; i <= check_count; i++) {
+        data[data_top + i] = check[check_count - i];
+    }
+    
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("Codewords:  ");
+        for (i = 0; i <= data_top + check_count; i++) {
+            printf("%d  ", (int) data[i]);
+        }
+        printf("\n");
+    }
+    
+    // Conversion from Data Numbers and Check Numbers to Data Symbols and Check Symbols
+    for (i = 0; i <= data_step; i++) {
+        data[i] = data_symbol_even[data[i]];
+    }
+    for (i = data_step + 1; i <= (data_top + check_count); i++) {
+        data[i] = data_symbol_odd[data[i]];
+    }
+    
+    // Conversion from Data Symbols and Check Symbols to Extender Groups
+    for (i = 0; i < length; i++) {
+        if (length == 22) {
+            extender[extender_group_c[i]] = data[i];
+        } else {
+            extender[extender_group_l[i]] = data[i];
+        }
+    }
+    
+    // Conversion from Extender Groups to Bar Identifiers
+    strcpy(bar, "");
+    
+    for (i = 0; i < length; i++) {
+        for (j = 0; j < 3; j++) {
+            switch(extender[i] & 0x24) {
+                case 0x24:
+                    strcat(bar, "F");
+                    break;
+                case 0x20:
+                    if (i % 2) {
+                        strcat(bar, "D");
+                    } else {
+                        strcat(bar, "A");
+                    }
+                    break;
+                case 0x04:
+                    if (i % 2) {
+                        strcat(bar, "A");
+                    } else {
+                        strcat(bar, "D");
+                    }
+                    break;
+                default:
+                    strcat(bar, "T");
+                    break;
+            }
+            extender[i] = extender[i] << 1;
+        }
+    }
+    
+    bar[(length * 3)] = '\0';
+    
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("Bar pattern: %s\n", bar);
+    }
+    
+    /* Translate 4-state data pattern to symbol */
+    j = 0;
+    for (i = 0, len = strlen(bar); i < len; i++) {
+        if ((bar[i] == 'F') || (bar[i] == 'A')) {
+            set_module(symbol, 0, j);
+        }
+        set_module(symbol, 1, j);
+        if ((bar[i] == 'F') || (bar[i] == 'D')) {
+            set_module(symbol, 2, j);
+        }
+        j += 2;
+    }
+
+    symbol->row_height[0] = 4;
+    symbol->row_height[1] = 2;
+    symbol->row_height[2] = 4;
+
+    symbol->rows = 3;
+    symbol->width = j - 1;
+    
+    return 0;
+}
diff --git a/backend/maxicode.c b/backend/maxicode.c
new file mode 100644 (file)
index 0000000..cf7200f
--- /dev/null
@@ -0,0 +1,736 @@
+/* maxicode.c - Handles Maxicode */
+
+/*
+    libzint - the open source barcode library
+    Copyright (C) 2010-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 : */
+
+/* Includes corrections thanks to Monica Swanson @ Source Technologies */
+#include "common.h"
+#include "maxicode.h"
+#include "reedsol.h"
+#include <string.h>
+
+static int maxi_codeword[144];
+
+/* Handles error correction of primary message */
+static void maxi_do_primary_check() {
+    unsigned char data[15];
+    unsigned char results[15];
+    int j;
+    int datalen = 10;
+    int ecclen = 10;
+
+    rs_init_gf(0x43);
+    rs_init_code(ecclen, 1);
+
+    for (j = 0; j < datalen; j += 1)
+        data[j] = maxi_codeword[j];
+
+    rs_encode(datalen, data, results);
+
+    for (j = 0; j < ecclen; j += 1)
+        maxi_codeword[ datalen + j] = results[ecclen - 1 - j];
+    rs_free();
+}
+
+/* Handles error correction of odd characters in secondary */
+static void maxi_do_secondary_chk_odd(int ecclen) {
+    unsigned char data[100];
+    unsigned char results[30];
+    int j;
+    int datalen = 68;
+
+    rs_init_gf(0x43);
+    rs_init_code(ecclen, 1);
+
+    if (ecclen == 20)
+        datalen = 84;
+
+    for (j = 0; j < datalen; j += 1)
+        if (j & 1) // odd
+            data[(j - 1) / 2] = maxi_codeword[j + 20];
+
+    rs_encode(datalen / 2, data, results);
+
+    for (j = 0; j < (ecclen); j += 1)
+        maxi_codeword[ datalen + (2 * j) + 1 + 20 ] = results[ecclen - 1 - j];
+    rs_free();
+}
+
+/* Handles error correction of even characters in secondary */
+static void maxi_do_secondary_chk_even(int ecclen) {
+    unsigned char data[100];
+    unsigned char results[30];
+    int j;
+    int datalen = 68;
+
+    if (ecclen == 20)
+        datalen = 84;
+
+    rs_init_gf(0x43);
+    rs_init_code(ecclen, 1);
+
+    for (j = 0; j < datalen + 1; j += 1)
+        if (!(j & 1)) // even
+            data[j / 2] = maxi_codeword[j + 20];
+
+    rs_encode(datalen / 2, data, results);
+
+    for (j = 0; j < (ecclen); j += 1)
+        maxi_codeword[ datalen + (2 * j) + 20] = results[ecclen - 1 - j];
+    rs_free();
+}
+
+/* Moves everything up so that a shift or latch can be inserted */
+static void maxi_bump(int set[], int character[], int bump_posn) {
+    int i;
+
+    for (i = 143; i > bump_posn; i--) {
+        set[i] = set[i - 1];
+        character[i] = character[i - 1];
+    }
+}
+
+/* If the value is present in  array, return the value, else return badvalue */
+static int value_in_array(int val, int arr[], int badvalue, int arrLength) {
+    int i;
+    for(i = 0; i < arrLength; i++){
+        if(arr[i] == val) return val;
+    }
+    return badvalue;
+}
+
+/* Choose the best set from previous and next set in the range of the setval array, if no value can be found we return setval[0] */
+static int bestSurroundingSet(int index, int length, int set[], int setval[], int setLength) {
+    int badValue = -1;
+    int option1 = value_in_array(set[index - 1], setval, badValue, setLength);
+    if (index + 1 < length) {
+        // we have two options to check (previous & next)
+        int option2 = value_in_array(set[index + 1], setval, badValue, setLength);
+        if (option2 != badValue && option1 > option2) {
+          return option2;
+        }
+    }
+    //
+    if (option1 != badValue) {
+      return option1;
+    }
+    return setval[0];
+}
+
+/* Format text according to Appendix A */
+static int maxi_text_process(int mode, unsigned char source[], int length, int eci) {
+    /* This code doesn't make use of [Lock in C], [Lock in D]
+    and [Lock in E] and so is not always the most efficient at
+    compressing data, but should suffice for most applications */
+
+    int set[144], character[144], i, j, done, count, current_set;
+
+    int set15[2] = { 1, 5 };
+    int set12[2] = { 1, 2 };
+    int set12345[5] = { 1, 2, 3, 4, 5 };
+
+    if (length > 138) {
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    for (i = 0; i < 144; i++) {
+        set[i] = -1;
+        character[i] = 0;
+    }
+
+    for (i = 0; i < length; i++) {
+        /* Look up characters in table from Appendix A - this gives
+         value and code set for most characters */
+        set[i] = maxiCodeSet[source[i]];
+        character[i] = maxiSymbolChar[source[i]];
+    }
+
+    /* If a character can be represented in more than one code set,
+    pick which version to use */
+    if (set[0] == 0) {
+        if (character[0] == 13) {
+            character[0] = 0;
+        }
+        set[0] = 1;
+    }
+
+    for (i = 1; i < length; i++) {
+        if (set[i] == 0) {
+            done = 0;
+            /* Special character */
+            if (character[i] == 13) {
+                /* Carriage Return */
+                set[i] = bestSurroundingSet(i, length, set, set15, 2);
+                if (set[i] == 5) {
+                    character[i] = 13;
+                } else {
+                    character[i] = 0;
+                }
+                done = 1;
+            }
+
+            if ((done == 0) && (character[i] == 28)) {
+                /* FS */
+                set[i] = bestSurroundingSet(i, length, set, set12345, 5);
+                if (set[i] == 5) {
+                    character[i] = 32;                   
+                }
+                done = 1;
+            }
+
+            if ((done == 0) && (character[i] == 29)) {
+                /* GS */
+                set[i] = bestSurroundingSet(i, length, set, set12345, 5);
+                if (set[i] == 5) {
+                    character[i] = 33;
+                }       
+                done = 1;
+            }
+
+            if ((done == 0) && (character[i] == 30)) {
+                /* RS */
+                set[i] = bestSurroundingSet(i, length, set, set12345, 5);         
+                if (set[i] == 5) {
+                    character[i] = 34;
+                }
+                done = 1;
+            }
+
+            if ((done == 0) && (character[i] == 32)) {
+                /* Space */
+                set[i] = bestSurroundingSet(i, length, set, set12345, 5);
+                if (set[i] == 1) {
+                    character[i] = 32;
+                } else if (set[i] == 2) {
+                    character[i] = 47;
+                } else {
+                    character[i] = 59;
+                }
+                done = 1;
+            }
+
+            if ((done == 0) && (character[i] == 44)) {
+                /* Comma */
+                set[i] = bestSurroundingSet(i, length, set, set12, 2);
+                if (set[i] == 2) {
+                    character[i] = 48;
+                }
+                done = 1;
+            }
+
+            if ((done == 0) && (character[i] == 46)) {
+                /* Full Stop */
+                set[i] = bestSurroundingSet(i, length, set, set12, 2);
+                if (set[i] == 2) {
+                    character[i] = 49;
+                } 
+                done = 1;
+            }
+
+            if ((done == 0) && (character[i] == 47)) {
+                /* Slash */
+                set[i] = bestSurroundingSet(i, length, set, set12, 2);
+                if (set[i] == 2) {
+                    character[i] = 50;
+                }
+               done = 1;
+            }
+
+            if ((done == 0) && (character[i] == 58)) {
+                /* Colon */
+                set[i] = bestSurroundingSet(i, length, set, set12, 2);
+                if (set[i] == 2) {
+                    character[i] = 51;
+                }
+                done = 1;
+            }
+        }
+    }
+
+    for (i = length; i < 144; i++) {
+        /* Add the padding */
+        if (set[length - 1] == 2) {
+            set[i] = 2;
+        } else {
+            set[i] = 1;
+        }
+        character[i] = 33;
+    }
+
+    /* Find candidates for number compression */
+    if ((mode == 2) || (mode == 3)) {
+        j = 0;
+    } else {
+        j = 9;
+    }
+    /* Number compression not allowed in primary message */
+    count = 0;
+    for (i = j; i < 144; i++) {
+        if ((set[i] == 1) && ((character[i] >= 48) && (character[i] <= 57))) {
+            /* Character is a number */
+            count++;
+        } else {
+            count = 0;
+        }
+        if (count == 9) {
+            /* Nine digits in a row can be compressed */
+            set[i] = 6;
+            set[i - 1] = 6;
+            set[i - 2] = 6;
+            set[i - 3] = 6;
+            set[i - 4] = 6;
+            set[i - 5] = 6;
+            set[i - 6] = 6;
+            set[i - 7] = 6;
+            set[i - 8] = 6;
+            count = 0;
+        }
+    }
+
+    /* Add shift and latch characters */
+    current_set = 1;
+    i = 0;
+    do {
+
+        if ((set[i] != current_set) && (set[i] != 6)) {
+            switch (set[i]) {
+                case 1:
+                    if (i+1 < 144 &&  set[i + 1] == 1) {
+                        if (i+2 < 144 && set[i + 2] == 1) {
+                            if (i+3 < 144 && set[i + 3] == 1) {
+                                /* Latch A */
+                                maxi_bump(set, character, i);
+                                character[i] = 63;
+                                current_set = 1;
+                                length++;
+                            } else {
+                                /* 3 Shift A */
+                                maxi_bump(set, character, i);
+                                character[i] = 57;
+                                length++;
+                                i += 2;
+                            }
+                        } else {
+                            /* 2 Shift A */
+                            maxi_bump(set, character, i);
+                            character[i] = 56;
+                            length++;
+                            i++;
+                        }
+                    } else {
+                        /* Shift A */
+                        maxi_bump(set, character, i);
+                        character[i] = 59;
+                        length++;
+                    }
+                    break;
+                case 2:
+                    if (i+1 < 144 &&  set[i + 1] == 2) {
+                        /* Latch B */
+                        maxi_bump(set, character, i);
+                        character[i] = 63;
+                        current_set = 2;
+                        length++;
+                    } else {
+                        /* Shift B */
+                        maxi_bump(set, character, i);
+                        character[i] = 59;
+                        length++;
+                    }
+                    break;
+                case 3:
+                    if (i + 3 < 144 && set[i + 1] == 3 && set[i + 2] == 3 && set[i + 3] == 3) {
+                        maxi_bump(set, character, i);
+                        character[i] = 60;
+                        maxi_bump(set, character, i);
+                        character[i] = 60;    
+                        current_set = 3;
+                        length++;
+                        i += 3;
+                    } else {
+                       /* Shift C */
+                       maxi_bump(set, character, i);
+                       character[i] = 60;
+                       length++;
+                    }
+                    break;
+                case 4:
+                    /* Shift D */
+                    if (i + 3 < 144 && set[i + 1] == 4 && set[i + 2] == 4 && set[i + 3] == 4) {
+                        maxi_bump(set, character, i);
+                        character[i] = 61;
+                        maxi_bump(set, character, i);
+                        character[i] = 61;
+                        current_set = 4;
+                        length++;
+                        i += 3;
+                    } else {
+                        maxi_bump(set, character, i);
+                        character[i] = 61;
+                        length++;
+                    }
+                    break;
+                case 5:
+                    /* Shift E */
+                    if (i + 3 < 144 && set[i + 1] == 5 && set[i + 2] == 5 && set[i + 3] == 5) {
+                        maxi_bump(set, character, i);
+                        character[i] = 62;
+                        maxi_bump(set, character, i);
+                        character[i] = 62;
+                        current_set = 5;
+                        length++;
+                        i += 3;
+                    } else {
+                        maxi_bump(set, character, i);
+                        character[i] = 62;
+                        length++;
+            }
+                    break;
+            }
+            i++;
+        }
+        i++;
+    } while (i < 144);
+
+    /* Number compression has not been forgotten! - It's handled below */
+    i = 0;
+    do {
+        if (set[i] == 6) {
+            /* Number compression */
+            char substring[10];
+            int value;
+
+            for (j = 0; j < 9; j++) {
+                substring[j] = character[i + j];
+            }
+            substring[9] = '\0';
+            value = atoi(substring);
+
+            character[i] = 31; /* NS */
+            character[i + 1] = (value & 0x3f000000) >> 24;
+            character[i + 2] = (value & 0xfc0000) >> 18;
+            character[i + 3] = (value & 0x3f000) >> 12;
+            character[i + 4] = (value & 0xfc0) >> 6;
+            character[i + 5] = (value & 0x3f);
+
+            i += 6;
+            for (j = i; j < 141; j++) {
+                set[j] = set[j + 3];
+                character[j] = character[j + 3];
+            }
+            length -= 3;
+        } else {
+            i++;
+        }
+    } while (i <= 135); /* 144 - 9 */
+
+    /* Insert ECI at the beginning of message if needed */
+    /* Encode ECI assignment numbers according to table 3 */
+    if (eci != 0) {
+        maxi_bump(set, character, 0);
+        character[0] = 27; // ECI
+        if (eci <= 31) {
+            maxi_bump(set, character, 1);
+            character[1] = eci;
+            length += 2;
+        }
+        if ((eci >= 32) && (eci <= 1023)) {
+            maxi_bump(set, character, 1);
+            maxi_bump(set, character, 1);
+            character[1] = 0x20 + ((eci >> 6) & 0x0F);
+            character[2] = eci & 0x3F;
+            length += 3;
+        }
+        if ((eci >= 1024) && (eci <= 32767)) {
+            maxi_bump(set, character, 1);
+            maxi_bump(set, character, 1);
+            maxi_bump(set, character, 1);
+            character[1] = 0x30 + ((eci >> 12) & 0x03);
+            character[2] = (eci >> 6) & 0x3F;
+            character[3] = eci & 0x3F;
+            length += 4;
+        }
+        if (eci >= 32768) {
+            maxi_bump(set, character, 1);
+            maxi_bump(set, character, 1);
+            maxi_bump(set, character, 1);
+            maxi_bump(set, character, 1);
+            character[1] = 0x38 + ((eci >> 18) & 0x02);
+            character[2] = (eci >> 12) & 0x3F;
+            character[3] = (eci >> 6) & 0x3F;
+            character[4] = eci & 0x3F;
+            length += 5;
+        }
+    }
+
+    if (((mode == 2) || (mode == 3)) && (length > 84)) {
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    if (((mode == 4) || (mode == 6)) && (length > 93)) {
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    if ((mode == 5) && (length > 77)) {
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+
+    /* Copy the encoded text into the codeword array */
+    if ((mode == 2) || (mode == 3)) {
+        for (i = 0; i < 84; i++) { /* secondary only */
+            maxi_codeword[i + 20] = character[i];
+        }
+    }
+
+    if ((mode == 4) || (mode == 6)) {
+        for (i = 0; i < 9; i++) { /* primary */
+            maxi_codeword[i + 1] = character[i];
+        }
+        for (i = 0; i < 84; i++) { /* secondary */
+            maxi_codeword[i + 20] = character[i + 9];
+        }
+    }
+
+    if (mode == 5) {
+        for (i = 0; i < 9; i++) { /* primary */
+            maxi_codeword[i + 1] = character[i];
+        }
+        for (i = 0; i < 68; i++) { /* secondary */
+            maxi_codeword[i + 20] = character[i + 9];
+        }
+    }
+
+    return 0;
+}
+
+/* Format structured primary for Mode 2 */
+static void maxi_do_primary_2(char postcode[], int country, int service) {
+    size_t postcode_length;
+   int    postcode_num, i;
+
+    for (i = 0; i < 10; i++) {
+        if ((postcode[i] < '0') || (postcode[i] > '9')) {
+            postcode[i] = '\0';
+        }
+    }
+
+    postcode_length = strlen(postcode);
+    postcode_num = atoi(postcode);
+
+    maxi_codeword[0] = ((postcode_num & 0x03) << 4) | 2;
+    maxi_codeword[1] = ((postcode_num & 0xfc) >> 2);
+    maxi_codeword[2] = ((postcode_num & 0x3f00) >> 8);
+    maxi_codeword[3] = ((postcode_num & 0xfc000) >> 14);
+    maxi_codeword[4] = ((postcode_num & 0x3f00000) >> 20);
+    maxi_codeword[5] = ((postcode_num & 0x3c000000) >> 26) | ((postcode_length & 0x3) << 4);
+    maxi_codeword[6] = ((postcode_length & 0x3c) >> 2) | ((country & 0x3) << 4);
+    maxi_codeword[7] = (country & 0xfc) >> 2;
+    maxi_codeword[8] = ((country & 0x300) >> 8) | ((service & 0xf) << 2);
+    maxi_codeword[9] = ((service & 0x3f0) >> 4);
+}
+
+/* Format structured primary for Mode 3 */
+static void maxi_do_primary_3(char postcode[], int country, int service) {
+    int i, h;
+
+    h = strlen(postcode);
+    to_upper((unsigned char*) postcode);
+    for (i = 0; i < h; i++) {
+        if ((postcode[i] >= 'A') && (postcode[i] <= 'Z')) {
+            /* (Capital) letters shifted to Code Set A values */
+            postcode[i] -= 64;
+        }
+        if (((postcode[i] == 27) || (postcode[i] == 31)) || ((postcode[i] == 33) || (postcode[i] >= 59))) {
+            /* Not a valid postcode character */
+            postcode[i] = ' ';
+        }
+        /* Input characters lower than 27 (NUL - SUB) in postcode are
+        interpreted as capital letters in Code Set A (e.g. LF becomes 'J') */
+    }
+
+    maxi_codeword[0] = ((postcode[5] & 0x03) << 4) | 3;
+    maxi_codeword[1] = ((postcode[4] & 0x03) << 4) | ((postcode[5] & 0x3c) >> 2);
+    maxi_codeword[2] = ((postcode[3] & 0x03) << 4) | ((postcode[4] & 0x3c) >> 2);
+    maxi_codeword[3] = ((postcode[2] & 0x03) << 4) | ((postcode[3] & 0x3c) >> 2);
+    maxi_codeword[4] = ((postcode[1] & 0x03) << 4) | ((postcode[2] & 0x3c) >> 2);
+    maxi_codeword[5] = ((postcode[0] & 0x03) << 4) | ((postcode[1] & 0x3c) >> 2);
+    maxi_codeword[6] = ((postcode[0] & 0x3c) >> 2) | ((country & 0x3) << 4);
+    maxi_codeword[7] = (country & 0xfc) >> 2;
+    maxi_codeword[8] = ((country & 0x300) >> 8) | ((service & 0xf) << 2);
+    maxi_codeword[9] = ((service & 0x3f0) >> 4);
+}
+
+INTERNAL int maxicode(struct zint_symbol *symbol, unsigned char local_source[], const int length) {
+    int i, j, block, bit, mode, lp = 0;
+    int bit_pattern[7], internal_error = 0, eclen;
+    char postcode[12], countrystr[4], servicestr[4];
+
+    mode = symbol->option_1;
+    strcpy(postcode, "");
+    strcpy(countrystr, "");
+    strcpy(servicestr, "");
+
+    memset(maxi_codeword, 0, sizeof (maxi_codeword));
+
+    if (mode == -1) { /* If mode is unspecified */
+        lp = strlen(symbol->primary);
+        if (lp == 0) {
+            mode = 4;
+        } else {
+            mode = 2;
+            for (i = 0; i < 10 && i < lp; i++) {
+                if ((symbol->primary[i] < 48) || (symbol->primary[i] > 57)) {
+                    mode = 3;
+                    break;
+                }
+            }
+        }
+    }
+
+    if ((mode < 2) || (mode > 6)) { /* Only codes 2 to 6 supported */
+        strcpy(symbol->errtxt, "550: Invalid Maxicode Mode");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    if ((mode == 2) || (mode == 3)) { /* Modes 2 and 3 need data in symbol->primary */
+        int countrycode;
+        int service;
+        if (lp == 0) { /* Mode set manually means lp doesn't get set */
+            lp = strlen(symbol->primary);
+        }
+        if (lp != 15) {
+            strcpy(symbol->errtxt, "551: Invalid Primary String");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+
+        for (i = 9; i < 15; i++) { /* check that country code and service are numeric */
+            if ((symbol->primary[i] < '0') || (symbol->primary[i] > '9')) {
+                strcpy(symbol->errtxt, "552: Invalid Primary String");
+                return ZINT_ERROR_INVALID_DATA;
+            }
+        }
+
+        memcpy(postcode, symbol->primary, 9);
+        postcode[9] = '\0';
+
+        if (mode == 2) {
+            for (i = 0; i < 10; i++) {
+                if (postcode[i] == ' ') {
+                    postcode[i] = '\0';
+                }
+            }
+        } else if (mode == 3) {
+            postcode[6] = '\0';
+        }
+
+        countrystr[0] = symbol->primary[9];
+        countrystr[1] = symbol->primary[10];
+        countrystr[2] = symbol->primary[11];
+        countrystr[3] = '\0';
+
+        servicestr[0] = symbol->primary[12];
+        servicestr[1] = symbol->primary[13];
+        servicestr[2] = symbol->primary[14];
+        servicestr[3] = '\0';
+
+        countrycode = atoi(countrystr);
+        service = atoi(servicestr);
+
+        if (mode == 2) {
+            maxi_do_primary_2(postcode, countrycode, service);
+        }
+        if (mode == 3) {
+            maxi_do_primary_3(postcode, countrycode, service);
+        }
+    } else {
+        maxi_codeword[0] = mode;
+    }
+
+    i = maxi_text_process(mode, local_source, length, symbol->eci);
+    if (i == ZINT_ERROR_TOO_LONG) {
+        strcpy(symbol->errtxt, "553: Input data too long");
+        return i;
+    }
+
+    /* All the data is sorted - now do error correction */
+    maxi_do_primary_check(); /* always EEC */
+
+    if (mode == 5)
+        eclen = 56; // 68 data codewords , 56 error corrections
+    else
+        eclen = 40; // 84 data codewords,  40 error corrections
+
+    maxi_do_secondary_chk_even(eclen / 2); // do error correction of even
+    maxi_do_secondary_chk_odd(eclen / 2); // do error correction of odd
+
+    /* Copy data into symbol grid */
+    for (i = 0; i < 33; i++) {
+        for (j = 0; j < 30; j++) {
+            block = (MaxiGrid[(i * 30) + j] + 5) / 6;
+            bit = (MaxiGrid[(i * 30) + j] + 5) % 6;
+
+            if (block != 0) {
+
+                bit_pattern[0] = (maxi_codeword[block - 1] & 0x20) >> 5;
+                bit_pattern[1] = (maxi_codeword[block - 1] & 0x10) >> 4;
+                bit_pattern[2] = (maxi_codeword[block - 1] & 0x8) >> 3;
+                bit_pattern[3] = (maxi_codeword[block - 1] & 0x4) >> 2;
+                bit_pattern[4] = (maxi_codeword[block - 1] & 0x2) >> 1;
+                bit_pattern[5] = (maxi_codeword[block - 1] & 0x1);
+
+                if (bit_pattern[bit] != 0) {
+                    set_module(symbol, i, j);
+                }
+            }
+        }
+    }
+
+    /* Add orientation markings */
+    set_module(symbol, 0, 28); // Top right filler
+    set_module(symbol, 0, 29);
+    set_module(symbol, 9, 10); // Top left marker
+    set_module(symbol, 9, 11);
+    set_module(symbol, 10, 11);
+    set_module(symbol, 15, 7); // Left hand marker
+    set_module(symbol, 16, 8);
+    set_module(symbol, 16, 20); // Right hand marker
+    set_module(symbol, 17, 20);
+    set_module(symbol, 22, 10); // Bottom left marker
+    set_module(symbol, 23, 10);
+    set_module(symbol, 22, 17); // Bottom right marker
+    set_module(symbol, 23, 17);
+
+    symbol->width = 30;
+    symbol->rows = 33;
+
+    return internal_error;
+}
diff --git a/backend/maxicode.h b/backend/maxicode.h
new file mode 100644 (file)
index 0000000..2d22459
--- /dev/null
@@ -0,0 +1,104 @@
+/* maxicode.h - Handles Maxicode */
+
+/*
+    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.
+ */
+
+static const unsigned short int MaxiGrid[] = {
+    /* ISO/IEC 16023 Figure 5 - MaxiCode Module Sequence */ /* 30 x 33 data grid */
+    122, 121, 128, 127, 134, 133, 140, 139, 146, 145, 152, 151, 158, 157, 164, 163, 170, 169, 176, 175, 182, 181, 188, 187, 194, 193, 200, 199, 0, 0,
+    124, 123, 130, 129, 136, 135, 142, 141, 148, 147, 154, 153, 160, 159, 166, 165, 172, 171, 178, 177, 184, 183, 190, 189, 196, 195, 202, 201, 817, 0,
+    126, 125, 132, 131, 138, 137, 144, 143, 150, 149, 156, 155, 162, 161, 168, 167, 174, 173, 180, 179, 186, 185, 192, 191, 198, 197, 204, 203, 819, 818,
+    284, 283, 278, 277, 272, 271, 266, 265, 260, 259, 254, 253, 248, 247, 242, 241, 236, 235, 230, 229, 224, 223, 218, 217, 212, 211, 206, 205, 820, 0,
+    286, 285, 280, 279, 274, 273, 268, 267, 262, 261, 256, 255, 250, 249, 244, 243, 238, 237, 232, 231, 226, 225, 220, 219, 214, 213, 208, 207, 822, 821,
+    288, 287, 282, 281, 276, 275, 270, 269, 264, 263, 258, 257, 252, 251, 246, 245, 240, 239, 234, 233, 228, 227, 222, 221, 216, 215, 210, 209, 823, 0,
+    290, 289, 296, 295, 302, 301, 308, 307, 314, 313, 320, 319, 326, 325, 332, 331, 338, 337, 344, 343, 350, 349, 356, 355, 362, 361, 368, 367, 825, 824,
+    292, 291, 298, 297, 304, 303, 310, 309, 316, 315, 322, 321, 328, 327, 334, 333, 340, 339, 346, 345, 352, 351, 358, 357, 364, 363, 370, 369, 826, 0,
+    294, 293, 300, 299, 306, 305, 312, 311, 318, 317, 324, 323, 330, 329, 336, 335, 342, 341, 348, 347, 354, 353, 360, 359, 366, 365, 372, 371, 828, 827,
+    410, 409, 404, 403, 398, 397, 392, 391, 80, 79, 0, 0, 14, 13, 38, 37, 3, 0, 45, 44, 110, 109, 386, 385, 380, 379, 374, 373, 829, 0,
+    412, 411, 406, 405, 400, 399, 394, 393, 82, 81, 41, 0, 16, 15, 40, 39, 4, 0, 0, 46, 112, 111, 388, 387, 382, 381, 376, 375, 831, 830,
+    414, 413, 408, 407, 402, 401, 396, 395, 84, 83, 42, 0, 0, 0, 0, 0, 6, 5, 48, 47, 114, 113, 390, 389, 384, 383, 378, 377, 832, 0,
+    416, 415, 422, 421, 428, 427, 104, 103, 56, 55, 17, 0, 0, 0, 0, 0, 0, 0, 21, 20, 86, 85, 434, 433, 440, 439, 446, 445, 834, 833,
+    418, 417, 424, 423, 430, 429, 106, 105, 58, 57, 0, 0, 0, 0, 0, 0, 0, 0, 23, 22, 88, 87, 436, 435, 442, 441, 448, 447, 835, 0,
+    420, 419, 426, 425, 432, 431, 108, 107, 60, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 90, 89, 438, 437, 444, 443, 450, 449, 837, 836,
+    482, 481, 476, 475, 470, 469, 49, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 54, 53, 464, 463, 458, 457, 452, 451, 838, 0,
+    484, 483, 478, 477, 472, 471, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 466, 465, 460, 459, 454, 453, 840, 839,
+    486, 485, 480, 479, 474, 473, 52, 51, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 43, 468, 467, 462, 461, 456, 455, 841, 0,
+    488, 487, 494, 493, 500, 499, 98, 97, 62, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 92, 91, 506, 505, 512, 511, 518, 517, 843, 842,
+    490, 489, 496, 495, 502, 501, 100, 99, 64, 63, 0, 0, 0, 0, 0, 0, 0, 0, 29, 28, 94, 93, 508, 507, 514, 513, 520, 519, 844, 0,
+    492, 491, 498, 497, 504, 503, 102, 101, 66, 65, 18, 0, 0, 0, 0, 0, 0, 0, 19, 30, 96, 95, 510, 509, 516, 515, 522, 521, 846, 845,
+    560, 559, 554, 553, 548, 547, 542, 541, 74, 73, 33, 0, 0, 0, 0, 0, 0, 11, 68, 67, 116, 115, 536, 535, 530, 529, 524, 523, 847, 0,
+    562, 561, 556, 555, 550, 549, 544, 543, 76, 75, 0, 0, 8, 7, 36, 35, 12, 0, 70, 69, 118, 117, 538, 537, 532, 531, 526, 525, 849, 848,
+    564, 563, 558, 557, 552, 551, 546, 545, 78, 77, 0, 34, 10, 9, 26, 25, 0, 0, 72, 71, 120, 119, 540, 539, 534, 533, 528, 527, 850, 0,
+    566, 565, 572, 571, 578, 577, 584, 583, 590, 589, 596, 595, 602, 601, 608, 607, 614, 613, 620, 619, 626, 625, 632, 631, 638, 637, 644, 643, 852, 851,
+    568, 567, 574, 573, 580, 579, 586, 585, 592, 591, 598, 597, 604, 603, 610, 609, 616, 615, 622, 621, 628, 627, 634, 633, 640, 639, 646, 645, 853, 0,
+    570, 569, 576, 575, 582, 581, 588, 587, 594, 593, 600, 599, 606, 605, 612, 611, 618, 617, 624, 623, 630, 629, 636, 635, 642, 641, 648, 647, 855, 854,
+    728, 727, 722, 721, 716, 715, 710, 709, 704, 703, 698, 697, 692, 691, 686, 685, 680, 679, 674, 673, 668, 667, 662, 661, 656, 655, 650, 649, 856, 0,
+    730, 729, 724, 723, 718, 717, 712, 711, 706, 705, 700, 699, 694, 693, 688, 687, 682, 681, 676, 675, 670, 669, 664, 663, 658, 657, 652, 651, 858, 857,
+    732, 731, 726, 725, 720, 719, 714, 713, 708, 707, 702, 701, 696, 695, 690, 689, 684, 683, 678, 677, 672, 671, 666, 665, 660, 659, 654, 653, 859, 0,
+    734, 733, 740, 739, 746, 745, 752, 751, 758, 757, 764, 763, 770, 769, 776, 775, 782, 781, 788, 787, 794, 793, 800, 799, 806, 805, 812, 811, 861, 860,
+    736, 735, 742, 741, 748, 747, 754, 753, 760, 759, 766, 765, 772, 771, 778, 777, 784, 783, 790, 789, 796, 795, 802, 801, 808, 807, 814, 813, 862, 0,
+    738, 737, 744, 743, 750, 749, 756, 755, 762, 761, 768, 767, 774, 773, 780, 779, 786, 785, 792, 791, 798, 797, 804, 803, 810, 809, 816, 815, 864, 863
+};
+
+static const char maxiCodeSet[256] = {
+    /* from Appendix A - ASCII character to Code Set (e.g. 2 = Set B) */
+    /* set 0 refers to special characters that fit into more than one set (e.g. GS) */
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 5, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0, 2, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2,
+    2, 2, 2, 2, 2, 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, 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, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+    5, 4, 5, 5, 5, 5, 5, 5, 4, 5, 3, 4, 3, 5, 5, 4, 4, 3, 3, 3,
+    4, 3, 5, 4, 4, 3, 3, 4, 3, 3, 3, 4, 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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+static const char maxiSymbolChar[256] = {
+    /* from Appendix A - ASCII character to symbol 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, 30, 28, 29, 30, 35, 32, 53, 34, 35, 36, 37, 38, 39,
+    40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 37,
+    38, 39, 40, 41, 52, 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, 42, 43, 44, 45, 46, 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, 32, 54, 34, 35, 36, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 47, 48,
+    49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 36,
+    37, 37, 38, 39, 40, 41, 42, 43, 38, 44, 37, 39, 38, 45, 46, 40, 41, 39, 40, 41,
+    42, 42, 47, 43, 44, 43, 44, 45, 45, 46, 47, 46, 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, 32,
+    33, 34, 35, 36, 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, 32, 33, 34, 35, 36
+};
+
diff --git a/backend/maxipng.h b/backend/maxipng.h
deleted file mode 100644 (file)
index f39c51e..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/* maxipng.h - Shapes for Maxicode output to PNG file */
-
-/*
-    libzint - the open source barcode library
-    Copyright (C) 2008 Robin Stuart <robin@zint.org.uk>
-
-    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 file contains the pixel-by-pixel representation of maxicode glyphs
-   at a resolution of 12 pixels per millimeter. hexagon[] is taken directly
-   from ISO 16023 Annex J. bullseye[] was calculated by the Gimp */
-
-#define SSET   "0123456789ABCDEF"
-
-static const int hexagon[120] = {
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
-       0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
-       0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
-       0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
-       0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
-       0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-static const unsigned int bullseye_compressed[] = {
-       0,0,0,0,0,255,248,0,0,0,0,0,
-       0,0,0,0,31,255,255,192,0,0,0,0,
-       0,0,0,1,255,255,255,252,0,0,0,0,
-       0,0,0,7,255,255,255,255,0,0,0,0,
-       0,0,0,31,255,255,255,255,192,0,0,0,
-       0,0,0,127,255,255,255,255,240,0,0,0,
-       0,0,1,255,255,255,255,255,252,0,0,0,
-       0,0,7,255,255,255,255,255,255,0,0,0,
-       0,0,15,255,255,0,7,255,255,128,0,0,
-       0,0,63,255,240,0,0,127,255,224,0,0,
-       0,0,127,255,128,0,0,15,255,240,0,0,
-       0,0,255,252,0,0,0,1,255,248,0,0,
-       0,1,255,240,0,0,0,0,127,252,0,0,
-       0,3,255,224,0,0,0,0,63,254,0,0,
-       0,7,255,128,0,0,0,0,15,255,0,0,
-       0,15,255,0,0,0,0,0,7,255,128,0,
-       0,31,252,0,0,127,240,0,1,255,192,0,
-       0,63,248,0,7,255,255,0,0,255,224,0,
-       0,127,240,0,63,255,255,224,0,127,240,0,
-       0,127,224,0,255,255,255,248,0,63,240,0,
-       0,255,192,1,255,255,255,252,0,31,248,0,
-       1,255,128,7,255,255,255,255,0,15,252,0,
-       1,255,0,15,255,255,255,255,128,7,252,0,
-       3,255,0,63,255,255,255,255,224,7,254,0,
-       3,254,0,127,255,192,31,255,240,3,254,0,
-       7,252,0,255,252,0,1,255,248,1,255,0,
-       7,252,1,255,240,0,0,127,252,1,255,0,
-       15,248,1,255,192,0,0,31,252,0,255,128,
-       15,240,3,255,128,0,0,15,254,0,127,128,
-       31,240,7,255,0,0,0,7,255,0,127,192,
-       31,224,7,254,0,0,0,3,255,0,63,192,
-       63,224,15,252,0,0,0,1,255,128,63,224,
-       63,224,31,248,0,63,192,0,255,192,63,224,
-       63,192,31,240,0,255,240,0,127,192,31,224,
-       63,192,63,224,3,255,252,0,63,224,31,224,
-       127,192,63,224,7,255,254,0,63,224,31,240,
-       127,128,63,192,15,255,255,0,31,224,15,240,
-       127,128,127,192,31,255,255,128,31,240,15,240,
-       127,128,127,128,63,255,255,192,15,240,15,240,
-       127,128,127,128,63,255,255,192,15,240,15,240,
-       255,0,127,128,127,240,255,224,15,240,7,240,
-       255,0,255,128,127,192,63,224,15,248,7,240,
-       255,0,255,0,255,128,31,240,7,248,7,240,
-       255,0,255,0,255,128,31,240,7,248,7,240,
-       255,0,255,0,255,0,15,240,7,248,7,240,
-       255,0,255,0,255,0,15,240,7,248,7,240,
-       255,0,255,0,255,0,15,240,7,248,7,240,
-       255,0,255,0,255,0,15,240,7,248,7,240,
-       255,0,255,0,255,128,31,240,7,248,7,240,
-       255,0,255,0,255,128,31,240,7,248,7,240,
-       255,0,255,0,127,192,63,224,7,248,7,240,
-       255,0,255,128,127,240,255,224,15,248,7,240,
-       255,0,127,128,63,255,255,192,15,240,7,240,
-       127,128,127,128,63,255,255,192,15,240,15,240,
-       127,128,127,128,31,255,255,128,15,240,15,240,
-       127,128,127,192,15,255,255,0,31,240,15,240,
-       127,128,63,192,7,255,254,0,31,224,15,240,
-       127,192,63,224,3,255,252,0,63,224,31,240,
-       63,192,63,224,0,255,240,0,63,224,31,224,
-       63,192,31,240,0,63,192,0,127,192,31,224,
-       63,224,31,248,0,0,0,0,255,192,63,224,
-       63,224,15,252,0,0,0,1,255,128,63,224,
-       31,224,7,254,0,0,0,3,255,0,63,192,
-       31,240,7,255,0,0,0,7,255,0,127,192,
-       15,240,3,255,128,0,0,15,254,0,127,128,
-       15,248,1,255,192,0,0,31,252,0,255,128,
-       7,252,1,255,240,0,0,127,252,1,255,0,
-       7,252,0,255,252,0,1,255,248,1,255,0,
-       3,254,0,127,255,192,31,255,240,3,254,0,
-       3,255,0,63,255,255,255,255,224,7,254,0,
-       1,255,0,15,255,255,255,255,128,7,252,0,
-       1,255,128,7,255,255,255,255,0,15,252,0,
-       0,255,192,1,255,255,255,252,0,31,248,0,
-       0,127,224,0,255,255,255,248,0,63,240,0,
-       0,127,240,0,63,255,255,224,0,127,240,0,
-       0,63,248,0,7,255,255,0,0,255,224,0,
-       0,31,252,0,0,127,240,0,1,255,192,0,
-       0,15,255,0,0,0,0,0,7,255,128,0,
-       0,7,255,128,0,0,0,0,15,255,0,0,
-       0,3,255,224,0,0,0,0,63,254,0,0,
-       0,1,255,240,0,0,0,0,127,252,0,0,
-       0,0,255,252,0,0,0,1,255,248,0,0,
-       0,0,127,255,128,0,0,15,255,240,0,0,
-       0,0,63,255,240,0,0,127,255,224,0,0,
-       0,0,15,255,255,0,7,255,255,128,0,0,
-       0,0,7,255,255,255,255,255,255,0,0,0,
-       0,0,1,255,255,255,255,255,252,0,0,0,
-       0,0,0,127,255,255,255,255,240,0,0,0,
-       0,0,0,31,255,255,255,255,192,0,0,0,
-       0,0,0,7,255,255,255,255,0,0,0,0,
-       0,0,0,1,255,255,255,252,0,0,0,0,
-       0,0,0,0,31,255,255,192,0,0,0,0,
-       0,0,0,0,0,255,248,0,0,0,0,0
-};
-
diff --git a/backend/medical.c b/backend/medical.c
new file mode 100644 (file)
index 0000000..51e77eb
--- /dev/null
@@ -0,0 +1,334 @@
+/* medical.c - Handles 1 track and 2 track pharmacode and Codabar */
+
+/*
+    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 : */
+
+#include <stdio.h>
+#include "common.h"
+
+INTERNAL int c39(struct zint_symbol *symbol, unsigned char source[], const size_t length);
+
+/* Codabar table checked against EN 798:1995 */
+
+#define CALCIUM         "0123456789-$:/.+ABCD"
+#define CALCIUM_INNER   "0123456789-$:/.+"
+
+static const char *CodaTable[20] = {
+    "11111221", "11112211", "11121121", "22111111", "11211211", "21111211",
+    "12111121", "12112111", "12211111", "21121111", "11122111", "11221111", "21112121", "21211121",
+    "21212111", "11212121", "11221211", "12121121", "11121221", "11122211"
+};
+
+INTERNAL int pharma_one(struct zint_symbol *symbol, unsigned char source[], int length) {
+    /* "Pharmacode can represent only a single integer from 3 to 131070. Unlike other
+       commonly used one-dimensional barcode schemes, pharmacode does not store the data in a
+       form corresponding to the human-readable digits; the number is encoded in binary, rather
+       than decimal. Pharmacode is read from right to left: with n as the bar position starting
+       at 0 on the right, each narrow bar adds 2n to the value and each wide bar adds 2(2^n).
+       The minimum barcode is 2 bars and the maximum 16, so the smallest number that could
+       be encoded is 3 (2 narrow bars) and the biggest is 131070 (16 wide bars)."
+       - http://en.wikipedia.org/wiki/Pharmacode */
+
+    /* This code uses the One Track Pharamacode calculating algorithm as recommended by
+       the specification at http://www.laetus.com/laetus.php?request=file&id=69 */
+
+    unsigned long int tester;
+    int counter, error_number, h;
+    char inter[18] = {0}; /* 131070 -> 17 bits */
+    char dest[64]; /* 17 * 2 + 1 */
+
+    if (length > 6) {
+        strcpy(symbol->errtxt, "350: 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, "351: Invalid characters in data");
+        return error_number;
+    }
+
+    tester = atoi((char*) source);
+
+    if ((tester < 3) || (tester > 131070)) {
+        strcpy(symbol->errtxt, "352: Data out of range");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    do {
+        if (!(tester & 1)) {
+            strcat(inter, "W");
+            tester = (tester - 2) / 2;
+        } else {
+            strcat(inter, "N");
+            tester = (tester - 1) / 2;
+        }
+    } while (tester != 0);
+
+    h = strlen(inter) - 1;
+    *dest = '\0';
+    for (counter = h; counter >= 0; counter--) {
+        if (inter[counter] == 'W') {
+            strcat(dest, "32");
+        } else {
+            strcat(dest, "12");
+        }
+    }
+
+    expand(symbol, dest);
+
+    return error_number;
+}
+
+static int pharma_two_calc(struct zint_symbol *symbol, unsigned char source[], char dest[]) {
+    /* This code uses the Two Track Pharamacode defined in the document at
+       http://www.laetus.com/laetus.php?request=file&id=69 and using a modified
+       algorithm from the One Track system. This standard accepts integet values
+       from 4 to 64570080. */
+
+    unsigned long int tester;
+    int counter, h;
+    char inter[17];
+    int error_number;
+
+    tester = atoi((char*) source);
+
+    if ((tester < 4) || (tester > 64570080)) {
+        strcpy(symbol->errtxt, "353: Data out of range");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+    error_number = 0;
+    strcpy(inter, "");
+    do {
+        switch (tester % 3) {
+            case 0:
+                strcat(inter, "3");
+                tester = (tester - 3) / 3;
+                break;
+            case 1:
+                strcat(inter, "1");
+                tester = (tester - 1) / 3;
+                break;
+            case 2:
+                strcat(inter, "2");
+                tester = (tester - 2) / 3;
+                break;
+        }
+    } while (tester != 0);
+
+    h = strlen(inter) - 1;
+    for (counter = h; counter >= 0; counter--) {
+        dest[h - counter] = inter[counter];
+    }
+    dest[h + 1] = '\0';
+
+    return error_number;
+}
+
+INTERNAL int pharma_two(struct zint_symbol *symbol, unsigned char source[], int length) {
+    /* Draws the patterns for two track pharmacode */
+    char height_pattern[200];
+    unsigned int loopey, h;
+    int writer;
+    int error_number = 0;
+    strcpy(height_pattern, "");
+
+    if (length > 8) {
+        strcpy(symbol->errtxt, "354: 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, "355: Invalid characters in data");
+        return error_number;
+    }
+    error_number = pharma_two_calc(symbol, source, height_pattern);
+    if (error_number != 0) {
+        return error_number;
+    }
+
+    writer = 0;
+    h = strlen(height_pattern);
+    for (loopey = 0; loopey < h; loopey++) {
+        if ((height_pattern[loopey] == '2') || (height_pattern[loopey] == '3')) {
+            set_module(symbol, 0, writer);
+        }
+        if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '3')) {
+            set_module(symbol, 1, writer);
+        }
+        writer += 2;
+    }
+    symbol->rows = 2;
+    symbol->width = writer - 1;
+
+
+    return error_number;
+}
+
+/* The Codabar system consisting of simple substitution */
+INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int length) {
+
+    int i, error_number;
+    char dest[512];
+    int add_checksum, count, checksum;
+
+    strcpy(dest, "");
+
+    if (length > 60) { /* No stack smashing please */
+        strcpy(symbol->errtxt, "356: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    /* BS EN 798:1995 4.2 "'Codabar' symbols shall consist of ... b) start character;
+     * c) one or more symbol characters representing data ... d) stop character ..." */
+    if (length < 3) {
+        strcpy(symbol->errtxt, "362: Input too short");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    to_upper(source);
+
+    /* Codabar must begin and end with the characters A, B, C or D */
+    if ((source[0] != 'A') && (source[0] != 'B') && (source[0] != 'C')
+            && (source[0] != 'D')) {
+        strcpy(symbol->errtxt, "358: Does not begin with \"A\", \"B\", \"C\" or \"D\"");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+    if ((source[length - 1] != 'A') && (source[length - 1] != 'B') &&
+            (source[length - 1] != 'C') && (source[length - 1] != 'D')) {
+        strcpy(symbol->errtxt, "359: Does not end with \"A\", \"B\", \"C\" or \"D\"");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    /* And must not use A, B, C or D otherwise (BS EN 798:1995 4.3.2) */
+    error_number = is_sane(CALCIUM_INNER, source + 1, length - 2);
+    if (error_number) {
+        strcpy(symbol->errtxt, "363: Cannot contain \"A\", \"B\", \"C\" or \"D\"");
+        return error_number;
+    }
+
+    add_checksum = symbol->option_2 == 1;
+    if (add_checksum) {
+        count = 0;
+    }
+
+    for (i = 0; i < length; i++) {
+        if (add_checksum) {
+            count += strchr(CALCIUM, source[i]) - CALCIUM;
+            if (i + 1 == length) {
+                checksum = count % 16;
+                if (checksum) {
+                    checksum = 16 - checksum;
+                }
+                if (symbol->debug & ZINT_DEBUG_PRINT) {
+                    printf("Codabar: %s, count %d, checksum %d\n", source, count, checksum);
+                }
+                strcat(dest, CodaTable[checksum]);
+            }
+        }
+        lookup(CALCIUM, CodaTable, source[i], dest);
+    }
+
+    expand(symbol, dest);
+    ustrcpy(symbol->text, source);
+    return error_number;
+}
+
+/* Italian Pharmacode */
+INTERNAL int code32(struct zint_symbol *symbol, unsigned char source[], int length) {
+    int i, zeroes, error_number, checksum, checkpart, checkdigit;
+    char localstr[10], risultante[7];
+    long int pharmacode, devisor;
+    int codeword[6];
+    char tabella[34];
+
+    /* Validate the input */
+    if (length > 8) {
+        strcpy(symbol->errtxt, "360: 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, "361: Invalid characters in data");
+        return error_number;
+    }
+
+    /* Add leading zeros as required */
+    zeroes = 8 - length;
+    memset(localstr, '0', zeroes);
+    ustrcpy(localstr + zeroes, source);
+
+    /* Calculate the check digit */
+    checksum = 0;
+    for (i = 0; i < 4; i++) {
+        checkpart = ctoi(localstr[i * 2]);
+        checksum += checkpart;
+        checkpart = 2 * (ctoi(localstr[(i * 2) + 1]));
+        if (checkpart >= 10) {
+            checksum += (checkpart - 10) + 1;
+        } else {
+            checksum += checkpart;
+        }
+    }
+
+    /* Add check digit to data string */
+    checkdigit = checksum % 10;
+    localstr[8] = itoc(checkdigit);
+    localstr[9] = '\0';
+
+    /* Convert string into an integer value */
+    pharmacode = atoi(localstr);
+
+    /* Convert from decimal to base-32 */
+    devisor = 33554432;
+    for (i = 5; i >= 0; i--) {
+        long int remainder;
+        codeword[i] = pharmacode / devisor;
+        remainder = pharmacode % devisor;
+        pharmacode = remainder;
+        devisor /= 32;
+    }
+
+    /* Look up values in 'Tabella di conversione' */
+    strcpy(tabella, "0123456789BCDFGHJKLMNPQRSTUVWXYZ");
+    for (i = 5; i >= 0; i--) {
+        risultante[5 - i] = tabella[codeword[i]];
+    }
+    risultante[6] = '\0';
+    /* Plot the barcode using Code 39 */
+    error_number = c39(symbol, (unsigned char*) risultante, strlen(risultante));
+    if (error_number != 0) {
+        return error_number;
+    }
+
+    /* Override the normal text output with the Pharmacode number */
+    ustrcpy(symbol->text, "A");
+    ustrcat(symbol->text, localstr);
+
+    return error_number;
+}
diff --git a/backend/ms_stdint.h b/backend/ms_stdint.h
new file mode 100644 (file)
index 0000000..f137450
--- /dev/null
@@ -0,0 +1,235 @@
+// ISO C9x  compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+//  Copyright (c) 2006-2008 Alexander Chemeris
+//
+// 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. The name of the author may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+/* @(#) $Id: ms_stdint.h,v 1.1 2009/09/19 08:16:21 hooper114 Exp $ */
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#if (_MSC_VER < 1300) && defined(__cplusplus)
+   extern "C++" {
+#endif
+#     include <wchar.h>
+#if (_MSC_VER < 1300) && defined(__cplusplus)
+   }
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+#     define _W64 __w64
+#  else
+#     define _W64
+#  endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+typedef __int8            int8_t;
+typedef __int16           int16_t;
+typedef __int32           int32_t;
+typedef __int64           int64_t;
+typedef unsigned __int8   uint8_t;
+typedef unsigned __int16  uint16_t;
+typedef unsigned __int32  uint32_t;
+typedef unsigned __int64  uint64_t;
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t    int_least8_t;
+typedef int16_t   int_least16_t;
+typedef int32_t   int_least32_t;
+typedef int64_t   int_least64_t;
+typedef uint8_t   uint_least8_t;
+typedef uint16_t  uint_least16_t;
+typedef uint32_t  uint_least32_t;
+typedef uint64_t  uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t    int_fast8_t;
+typedef int16_t   int_fast16_t;
+typedef int32_t   int_fast32_t;
+typedef int64_t   int_fast64_t;
+typedef uint8_t   uint_fast8_t;
+typedef uint16_t  uint_fast16_t;
+typedef uint32_t  uint_fast32_t;
+typedef uint64_t  uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+   typedef __int64           intptr_t;
+   typedef unsigned __int64  uintptr_t;
+#else // _WIN64 ][
+   typedef _W64 int               intptr_t;
+   typedef _W64 unsigned int      uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t   intmax_t;
+typedef uint64_t  uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN     ((int8_t)_I8_MIN)
+#define INT8_MAX     _I8_MAX
+#define INT16_MIN    ((int16_t)_I16_MIN)
+#define INT16_MAX    _I16_MAX
+#define INT32_MIN    ((int32_t)_I32_MIN)
+#define INT32_MAX    _I32_MAX
+#define INT64_MIN    ((int64_t)_I64_MIN)
+#define INT64_MAX    _I64_MAX
+#define UINT8_MAX    _UI8_MAX
+#define UINT16_MAX   _UI16_MAX
+#define UINT32_MAX   _UI32_MAX
+#define UINT64_MAX   _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN    INT8_MIN
+#define INT_LEAST8_MAX    INT8_MAX
+#define INT_LEAST16_MIN   INT16_MIN
+#define INT_LEAST16_MAX   INT16_MAX
+#define INT_LEAST32_MIN   INT32_MIN
+#define INT_LEAST32_MAX   INT32_MAX
+#define INT_LEAST64_MIN   INT64_MIN
+#define INT_LEAST64_MAX   INT64_MAX
+#define UINT_LEAST8_MAX   UINT8_MAX
+#define UINT_LEAST16_MAX  UINT16_MAX
+#define UINT_LEAST32_MAX  UINT32_MAX
+#define UINT_LEAST64_MAX  UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN    INT8_MIN
+#define INT_FAST8_MAX    INT8_MAX
+#define INT_FAST16_MIN   INT16_MIN
+#define INT_FAST16_MAX   INT16_MAX
+#define INT_FAST32_MIN   INT32_MIN
+#define INT_FAST32_MAX   INT32_MAX
+#define INT_FAST64_MIN   INT64_MIN
+#define INT_FAST64_MAX   INT64_MAX
+#define UINT_FAST8_MAX   UINT8_MAX
+#define UINT_FAST16_MAX  UINT16_MAX
+#define UINT_FAST32_MAX  UINT32_MAX
+#define UINT_FAST64_MAX  UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+#  define INTPTR_MIN   INT64_MIN
+#  define INTPTR_MAX   INT64_MAX
+#  define UINTPTR_MAX  UINT64_MAX
+#else // _WIN64 ][
+#  define INTPTR_MIN   INT32_MIN
+#  define INTPTR_MAX   INT32_MAX
+#  define UINTPTR_MAX  UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN   INT64_MIN
+#define INTMAX_MAX   INT64_MAX
+#define UINTMAX_MAX  UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+#  define PTRDIFF_MIN  _I64_MIN
+#  define PTRDIFF_MAX  _I64_MAX
+#else  // _WIN64 ][
+#  define PTRDIFF_MIN  _I32_MIN
+#  define PTRDIFF_MAX  _I32_MAX
+#endif  // _WIN64 ]
+
+#define SIG_ATOMIC_MIN  INT_MIN
+#define SIG_ATOMIC_MAX  INT_MAX
+
+#ifndef SIZE_MAX // [
+#  ifdef _WIN64 // [
+#     define SIZE_MAX  _UI64_MAX
+#  else // _WIN64 ][
+#     define SIZE_MAX  _UI32_MAX
+#  endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+#  define WCHAR_MIN  0
+#endif  // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+#  define WCHAR_MAX  _UI16_MAX
+#endif  // WCHAR_MAX ]
+
+#define WINT_MIN  0
+#define WINT_MAX  _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val)  val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val)  val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C   INT64_C
+#define UINTMAX_C  UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
+
diff --git a/backend/output.c b/backend/output.c
new file mode 100644 (file)
index 0000000..07c9885
--- /dev/null
@@ -0,0 +1,114 @@
+/*  output.c - Common routines for raster/vector
+
+    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 : */
+
+#include <string.h>
+#include "common.h"
+#include "output.h"
+
+#define SSET "0123456789ABCDEF"
+
+/* Check colour options are good. Note: using raster.c error nos 651-654 */
+INTERNAL int check_colour_options(struct zint_symbol *symbol) {
+    int error_number;
+
+    if (strlen(symbol->fgcolour) != 6) {
+        strcpy(symbol->errtxt, "651: Malformed foreground colour target");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+    if (strlen(symbol->bgcolour) != 6) {
+        strcpy(symbol->errtxt, "652: Malformed background colour target");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    to_upper((unsigned char *) symbol->fgcolour);
+    to_upper((unsigned char *) symbol->bgcolour);
+
+    error_number = is_sane(SSET, (unsigned char *) symbol->fgcolour, strlen(symbol->fgcolour));
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "653: Malformed foreground colour target");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    error_number = is_sane(SSET, (unsigned char *) symbol->bgcolour, strlen(symbol->fgcolour));
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "654: Malformed background colour target");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    return 0;
+}
+
+/* Return minimum quiet zones for each symbology */
+static void quiet_zones(struct zint_symbol *symbol, int *left, int *right, int *top, int *bottom) {
+    *left = *right = *top = *bottom = 0;
+
+    switch (symbol->symbology) {
+        case BARCODE_CODE16K:
+            /* BS EN 12323:2005 Section 4.5 c) */
+            *left = 10;
+            *right = 1;
+            break;
+        case BARCODE_CODE49:
+            /* ANSI/AIM BC6-2000 Section 2.4 */
+            *left = 10;
+            *right = 1;
+            break;
+        case BARCODE_CODABLOCKF:
+        case BARCODE_HIBC_BLOCKF:
+            /* AIM ISS-X-24 Section 4.6.1 */
+            *left = 10;
+            *right = 10;
+            break;
+        /* TODO: others */
+    }
+}
+
+/* Set left (x), top (y), right and bottom offsets for whitespace */
+INTERNAL void set_whitespace_offsets(struct zint_symbol *symbol, int *xoffset, int *yoffset, int *roffset, int *boffset) {
+    int qz_left, qz_right, qz_top, qz_bottom;
+
+    quiet_zones(symbol, &qz_left, &qz_right, &qz_top, &qz_bottom);
+
+    *xoffset = symbol->whitespace_width + qz_left;
+    *roffset = symbol->whitespace_width + qz_right;
+    if (symbol->output_options & BARCODE_BOX) {
+        *xoffset += symbol->border_width;
+        *roffset += symbol->border_width;
+    }
+
+    *yoffset = qz_top;
+    *boffset = qz_bottom;
+    if (symbol->output_options & (BARCODE_BOX | BARCODE_BIND)) {
+        *yoffset += symbol->border_width;
+        *boffset += symbol->border_width;
+    }
+}
diff --git a/backend/output.h b/backend/output.h
new file mode 100644 (file)
index 0000000..7e5ecd6
--- /dev/null
@@ -0,0 +1,47 @@
+/*  output.h - Common routines for raster/vector
+
+    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 OUTPUT_H
+#define OUTPUT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+INTERNAL int check_colour_options(struct zint_symbol *symbol);
+INTERNAL void set_whitespace_offsets(struct zint_symbol *symbol, int *xoffset, int *yoffset, int *roffset, int *boffset);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* OUTPUT_H */
diff --git a/backend/pcx.c b/backend/pcx.c
new file mode 100644 (file)
index 0000000..22bd3bd
--- /dev/null
@@ -0,0 +1,222 @@
+/* pcx.c - Handles output to ZSoft PCX file */
+/* ZSoft PCX File Format Technical Reference Manual http://bespin.org/~qz/pc-gpe/pcx.txt */
+
+/*
+    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>
+#include "common.h"
+#include "pcx.h"        /* PCX header structure */
+#include <math.h>
+#ifdef _MSC_VER
+#include <io.h>
+#include <fcntl.h>
+#include <malloc.h>
+#endif
+
+INTERNAL int pcx_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) {
+    int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
+    int row, column, i, colour;
+    int run_count;
+    FILE *pcx_file;
+    pcx_header_t header;
+    int bytes_per_line = symbol->bitmap_width + (symbol->bitmap_width & 1); // Must be even
+    unsigned char previous;
+#ifdef _MSC_VER
+    unsigned char* rle_row;
+#endif
+
+#ifndef _MSC_VER
+    unsigned char rle_row[bytes_per_line];
+#else
+    rle_row = (unsigned char *) _alloca(bytes_per_line);
+#endif /* _MSC_VER */
+
+    rle_row[bytes_per_line - 1] = 0; // Will remain zero if bitmap_width odd
+
+    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]);
+
+
+    header.manufacturer = 10; // ZSoft
+    header.version = 5; // Version 3.0
+    header.encoding = 1; // Run length encoding
+    header.bits_per_pixel = 8;
+    header.window_xmin = 0;
+    header.window_ymin = 0;
+    header.window_xmax = symbol->bitmap_width - 1;
+    header.window_ymax = symbol->bitmap_height - 1;
+    header.horiz_dpi = 300;
+    header.vert_dpi = 300;
+
+    for (i = 0; i < 48; i++) {
+        header.colourmap[i] = 0x00;
+    }
+
+    header.reserved = 0;
+    header.number_of_planes = 3;
+
+    header.bytes_per_line = bytes_per_line;
+
+    header.palette_info = 1; // Colour
+    header.horiz_screen_size = 0;
+    header.vert_screen_size = 0;
+
+    for (i = 0; i < 54; i++) {
+        header.filler[i] = 0x00;
+    }
+
+    /* Open output file in binary mode */
+    if (symbol->output_options & BARCODE_STDOUT) {
+#ifdef _MSC_VER
+        if (-1 == _setmode(_fileno(stdout), _O_BINARY)) {
+            strcpy(symbol->errtxt, "620: Can't open output file");
+            return ZINT_ERROR_FILE_ACCESS;
+        }
+#endif
+        pcx_file = stdout;
+    } else {
+        if (!(pcx_file = fopen(symbol->outfile, "wb"))) {
+            strcpy(symbol->errtxt, "621: Can't open output file");
+            return ZINT_ERROR_FILE_ACCESS;
+        }
+    }
+
+    fwrite(&header, sizeof (pcx_header_t), 1, pcx_file);
+
+    for (row = 0; row < symbol->bitmap_height; row++) {
+        for (colour = 0; colour < 3; colour++) {
+            for (column = 0; column < symbol->bitmap_width; column++) {
+                switch (colour) {
+                    case 0:
+                        switch(pixelbuf[(row * symbol->bitmap_width) + column]) {
+                            case 'W': // White
+                            case 'M': // Magenta
+                            case 'R': // Red
+                            case 'Y': // Yellow
+                                rle_row[column] = 255;
+                                break;
+                            case 'C': // Cyan
+                            case 'B': // Blue
+                            case 'G': // Green
+                            case 'K': // Black
+                                rle_row[column] = 0;
+                                break;
+                            case '1':
+                                rle_row[column] = fgred;
+                                break;
+                            default:
+                                rle_row[column] = bgred;
+                                break;
+                        }
+                        break;
+                    case 1:
+                        switch(pixelbuf[(row * symbol->bitmap_width) + column]) {
+                            case 'W': // White
+                            case 'C': // Cyan
+                            case 'Y': // Yellow
+                            case 'G': // Green
+                                rle_row[column] = 255;
+                                break;
+                            case 'B': // Blue
+                            case 'M': // Magenta
+                            case 'R': // Red
+                            case 'K': // Black
+                                rle_row[column] = 0;
+                                break;
+                            case '1':
+                                rle_row[column] = fggrn;
+                                break;
+                            default:
+                                rle_row[column] = bggrn;
+                                break;
+                        }
+                        break;
+                    case 2:
+                        switch(pixelbuf[(row * symbol->bitmap_width) + column]) {
+                            case 'W': // White
+                            case 'C': // Cyan
+                            case 'B': // Blue
+                            case 'M': // Magenta
+                                rle_row[column] = 255;
+                                break;
+                            case 'R': // Red
+                            case 'Y': // Yellow
+                            case 'G': // Green
+                            case 'K': // Black
+                                rle_row[column] = 0;
+                                break;
+                            case '1':
+                                rle_row[column] = fgblu;
+                                break;
+                            default:
+                                rle_row[column] = bgblu;
+                                break;
+                        }
+                        break;
+                }
+            }
+
+            /* Based on ImageMagick/coders/pcx.c PCXWritePixels()
+             * Copyright 1999-2020 ImageMagick Studio LLC */
+            previous = rle_row[0];
+            run_count = 1;
+            for (column = 1; column < bytes_per_line; column++) { // Note going up to bytes_per_line
+                if ((previous == rle_row[column]) && (run_count < 63)) {
+                    run_count++;
+                } else {
+                    if (run_count > 1 || (previous & 0xc0) == 0xc0) {
+                        run_count += 0xc0;
+                        fputc(run_count, pcx_file);
+                    }
+                    fputc(previous, pcx_file);
+                    previous = rle_row[column];
+                    run_count = 1;
+                }
+            }
+
+            if (run_count > 1 || (previous & 0xc0) == 0xc0) {
+                run_count += 0xc0;
+                fputc(run_count, pcx_file);
+            }
+            fputc(previous, pcx_file);
+        }
+    }
+
+    fclose(pcx_file);
+
+    return 0;
+}
diff --git a/backend/pcx.h b/backend/pcx.h
new file mode 100644 (file)
index 0000000..9915e83
--- /dev/null
@@ -0,0 +1,77 @@
+/*  pcx.h - header structure for ZSoft PCX files
+
+    libzint - the open source barcode library
+    Copyright (C) 2016-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 PCX_H
+#define PCX_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 pcx_header {
+        uint8_t manufacturer;
+        uint8_t version;
+        uint8_t encoding;
+        uint8_t bits_per_pixel;
+        uint16_t window_xmin;
+        uint16_t window_ymin;
+        uint16_t window_xmax;
+        uint16_t window_ymax;
+        uint16_t horiz_dpi;
+        uint16_t vert_dpi;
+        uint8_t colourmap[48];
+        uint8_t reserved;
+        uint8_t number_of_planes;
+        uint16_t bytes_per_line;
+        uint16_t palette_info;
+        uint16_t horiz_screen_size;
+        uint16_t vert_screen_size;
+        uint8_t filler[54];
+    } pcx_header_t;
+
+#pragma pack ()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PCX_H */
+
+
diff --git a/backend/pdf417.c b/backend/pdf417.c
new file mode 100644 (file)
index 0000000..eb39741
--- /dev/null
@@ -0,0 +1,1327 @@
+/* pdf417.c - Handles PDF417 stacked symbology */
+
+/*  Zint - A barcode generating program using libpng
+    Copyright (C) 2008-2020 Robin Stuart <rstuart114@gmail.com>
+    Portions Copyright (C) 2004 Grandzebu
+    Bug Fixes thanks to KL Chin <klchin@users.sourceforge.net>
+
+    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 : */
+
+/*  This code is adapted from "Code barre PDF 417 / PDF 417 barcode" v2.5.0
+    which is Copyright (C) 2004 (Grandzebu).
+    The original code can be downloaded from http://grandzebu.net/index.php */
+
+/* NOTE: symbol->option_1 is used to specify the security level (i.e. control the
+   number of check codewords)
+
+   symbol->option_2 is used to adjust the width of the resulting symbol (i.e. the
+   number of codeword columns not including row start and end data) */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#ifndef _MSC_VER
+#include <stdint.h>
+#else
+#include <malloc.h>
+#include "ms_stdint.h"
+#endif
+#include "pdf417.h"
+#include "common.h"
+/*
+   Three figure numbers in comments give the location of command equivalents in the
+   original Visual Basic source code file pdf417.frm
+   this code retains some original (French) procedure and variable names to ease conversion */
+
+/* text mode processing tables */
+
+static const char asciix[95] = {
+    7, 8, 8, 4, 12, 4, 4, 8, 8, 8, 12, 4, 12, 12, 12, 12, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 12, 8, 8, 4, 8, 8, 8, 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, 8, 8, 8, 4, 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, 8, 8, 8, 8
+};
+
+static const char asciiy[95] = {
+    26, 10, 20, 15, 18, 21, 10, 28, 23, 24, 22, 20, 13, 16, 17, 19, 0, 1, 2, 3,
+    4, 5, 6, 7, 8, 9, 14, 0, 1, 23, 2, 25, 3, 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, 4, 5, 6, 24, 7, 8, 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, 21, 27, 9
+};
+
+/* Automatic sizing table */
+
+static const char MicroAutosize[56] = {
+    4, 6, 7, 8, 10, 12, 13, 14, 16, 18, 19, 20, 24, 29, 30, 33, 34, 37, 39, 46, 54, 58, 70, 72, 82, 90, 108, 126,
+    1, 14, 2, 7, 3, 25, 8, 16, 5, 17, 9, 6, 10, 11, 28, 12, 19, 13, 29, 20, 30, 21, 22, 31, 23, 32, 33, 34
+};
+
+#define PDF417_MAX_LEN          2710    /* ISO/IEC 15438:2015 5.1.1 c) 3) Max possible number of characters at error correction level 0 (Numeric Compaction mode) */
+#define MICRO_PDF417_MAX_LEN    366     /* ISO/IEC 24728:2006 5.1.1 c) 3) Max possible number of characters (Numeric Compaction mode) */
+
+static int liste[2][PDF417_MAX_LEN]; /* global */
+
+/* 866 */
+
+static int quelmode(char codeascii) {
+    int mode = BYT;
+    if ((codeascii == '\t') || (codeascii == '\n') || (codeascii == '\r') || ((codeascii >= ' ') && (codeascii <= '~'))) {
+        mode = TEX;
+    }
+    if ((codeascii >= '0') && (codeascii <= '9')) {
+        mode = NUM;
+    }
+    /* 876 */
+
+    return mode;
+}
+
+/* 844 */
+static void regroupe(int *indexliste) {
+
+    /* bring together same type blocks */
+    if (*(indexliste) > 1) {
+        int i = 1;
+        while (i < *(indexliste)) {
+            if (liste[1][i - 1] == liste[1][i]) {
+                int j;
+                /* bring together */
+                liste[0][i - 1] = liste[0][i - 1] + liste[0][i];
+                j = i + 1;
+
+                /* decreace the list */
+                while (j < *(indexliste)) {
+                    liste[0][j - 1] = liste[0][j];
+                    liste[1][j - 1] = liste[1][j];
+                    j++;
+                }
+                *(indexliste) = *(indexliste) - 1;
+                i--;
+            }
+            i++;
+        }
+    }
+    /* 865 */
+}
+
+/* 478 */
+static void pdfsmooth(int *indexliste) {
+    int i, crnt, last, next, length;
+
+    for (i = 0; i < *(indexliste); i++) {
+        crnt = liste[1][i];
+        length = liste[0][i];
+        if (i != 0) {
+            last = liste[1][i - 1];
+        } else {
+            last = FALSE;
+        }
+        if (i != *(indexliste) - 1) {
+            next = liste[1][i + 1];
+        } else {
+            next = FALSE;
+        }
+
+        if (crnt == NUM) {
+            if (i == 0) {
+                /* first block */
+                if (*(indexliste) > 1) {
+                    /* and there are others */
+                    if ((next == TEX) && (length < 8)) {
+                        liste[1][i] = TEX;
+                    }
+                    if ((next == BYT) && (length == 1)) {
+                        liste[1][i] = BYT;
+                    }
+                }
+            } else {
+                if (i == *(indexliste) - 1) {
+                    /* last block */
+                    if ((last == TEX) && (length < 7)) {
+                        liste[1][i] = TEX;
+                    }
+                    if ((last == BYT) && (length == 1)) {
+                        liste[1][i] = BYT;
+                    }
+                } else {
+                    /* not first or last block */
+                    if (((last == BYT) && (next == BYT)) && (length < 4)) {
+                        liste[1][i] = BYT;
+                    }
+                    if (((last == BYT) && (next == TEX)) && (length < 4)) {
+                        liste[1][i] = TEX;
+                    }
+                    if (((last == TEX) && (next == BYT)) && (length < 5)) {
+                        liste[1][i] = TEX;
+                    }
+                    if (((last == TEX) && (next == TEX)) && (length < 8)) {
+                        liste[1][i] = TEX;
+                    }
+                }
+            }
+        }
+    }
+    regroupe(indexliste);
+    /* 520 */
+    for (i = 0; i < *(indexliste); i++) {
+        crnt = liste[1][i];
+        length = liste[0][i];
+        if (i != 0) {
+            last = liste[1][i - 1];
+        } else {
+            last = FALSE;
+        }
+        if (i != *(indexliste) - 1) {
+            next = liste[1][i + 1];
+        } else {
+            next = FALSE;
+        }
+
+        if ((crnt == TEX) && (i > 0)) {
+            /* not the first */
+            if (i == *(indexliste) - 1) {
+                /* the last one */
+                if ((last == BYT) && (length == 1)) {
+                    liste[1][i] = BYT;
+                }
+            } else {
+                /* not the last one */
+                if (((last == BYT) && (next == BYT)) && (length < 5)) {
+                    liste[1][i] = BYT;
+                }
+                if ((((last == BYT) && (next != BYT)) || ((last != BYT)
+                        && (next == BYT))) && (length < 3)) {
+                    liste[1][i] = BYT;
+                }
+            }
+        }
+    }
+    /* 540 */
+    regroupe(indexliste);
+}
+
+/* 547 */
+static void textprocess(int *chainemc, int *mclength, char chaine[], int start, int length) {
+    int j, indexlistet, curtable, listet[2][PDF417_MAX_LEN], chainet[PDF417_MAX_LEN], wnet;
+
+    wnet = 0;
+
+    for (j = 0; j < PDF417_MAX_LEN; j++) {
+        listet[0][j] = 0;
+    }
+    /* listet will contain the table numbers and the value of each characters */
+    for (indexlistet = 0; indexlistet < length; indexlistet++) {
+        char codeascii = chaine[start + indexlistet];
+        switch (codeascii) {
+            case '\t': listet[0][indexlistet] = 12;
+                listet[1][indexlistet] = 12;
+                break;
+            case '\n': listet[0][indexlistet] = 8;
+                listet[1][indexlistet] = 15;
+                break;
+            case 13: listet[0][indexlistet] = 12;
+                listet[1][indexlistet] = 11;
+                break;
+            default: listet[0][indexlistet] = asciix[codeascii - 32];
+                listet[1][indexlistet] = asciiy[codeascii - 32];
+                break;
+        }
+    }
+
+    /* 570 */
+    curtable = 1; /* default table */
+    for (j = 0; j < length; j++) {
+        if (listet[0][j] & curtable) {
+            /* The character is in the current table */
+            chainet[wnet] = listet[1][j];
+            wnet++;
+        } else {
+            /* Obliged to change table */
+            int flag = FALSE; /* True if we change table for only one character */
+            if (j == (length - 1)) {
+                flag = TRUE;
+            } else {
+                if (!(listet[0][j] & listet[0][j + 1])) {
+                    flag = TRUE;
+                }
+            }
+
+            if (flag) {
+                /* we change only one character - look for temporary switch */
+                if ((listet[0][j] & 1) && (curtable == 2)) { /* T_UPP */
+                    chainet[wnet] = 27;
+                    chainet[wnet + 1] = listet[1][j];
+                    wnet += 2;
+                }
+                if (listet[0][j] & 8) { /* T_PUN */
+                    chainet[wnet] = 29;
+                    chainet[wnet + 1] = listet[1][j];
+                    wnet += 2;
+                }
+                if (!(((listet[0][j] & 1) && (curtable == 2)) || (listet[0][j] & 8))) {
+                    /* No temporary switch available */
+                    flag = FALSE;
+                }
+            }
+
+            /* 599 */
+            if (!(flag)) {
+                int newtable;
+
+                if (j == (length - 1)) {
+                    newtable = listet[0][j];
+                } else {
+                    if (!(listet[0][j] & listet[0][j + 1])) {
+                        newtable = listet[0][j];
+                    } else {
+                        newtable = listet[0][j] & listet[0][j + 1];
+                    }
+                }
+
+                /* Maintain the first if several tables are possible */
+                switch (newtable) {
+                    case 3:
+                    case 5:
+                    case 7:
+                    case 9:
+                    case 11:
+                    case 13:
+                    case 15:
+                        newtable = 1;
+                        break;
+                    case 6:
+                    case 10:
+                    case 14:
+                        newtable = 2;
+                        break;
+                    case 12:
+                        newtable = 4;
+                        break;
+                }
+
+                /* 619 - select the switch */
+                switch (curtable) {
+                    case 1:
+                        switch (newtable) {
+                            case 2: chainet[wnet] = 27;
+                                wnet++;
+                                break;
+                            case 4: chainet[wnet] = 28;
+                                wnet++;
+                                break;
+                            case 8: chainet[wnet] = 28;
+                                wnet++;
+                                chainet[wnet] = 25;
+                                wnet++;
+                                break;
+                        }
+                        break;
+                    case 2:
+                        switch (newtable) {
+                            case 1: chainet[wnet] = 28;
+                                wnet++;
+                                chainet[wnet] = 28;
+                                wnet++;
+                                break;
+                            case 4: chainet[wnet] = 28;
+                                wnet++;
+                                break;
+                            case 8: chainet[wnet] = 28;
+                                wnet++;
+                                chainet[wnet] = 25;
+                                wnet++;
+                                break;
+                        }
+                        break;
+                    case 4:
+                        switch (newtable) {
+                            case 1: chainet[wnet] = 28;
+                                wnet++;
+                                break;
+                            case 2: chainet[wnet] = 27;
+                                wnet++;
+                                break;
+                            case 8: chainet[wnet] = 25;
+                                wnet++;
+                                break;
+                        }
+                        break;
+                    case 8:
+                        switch (newtable) {
+                            case 1: chainet[wnet] = 29;
+                                wnet++;
+                                break;
+                            case 2: chainet[wnet] = 29;
+                                wnet++;
+                                chainet[wnet] = 27;
+                                wnet++;
+                                break;
+                            case 4: chainet[wnet] = 29;
+                                wnet++;
+                                chainet[wnet] = 28;
+                                wnet++;
+                                break;
+                        }
+                        break;
+                }
+                curtable = newtable;
+                /* 659 - at last we add the character */
+                chainet[wnet] = listet[1][j];
+                wnet++;
+            }
+        }
+    }
+
+    /* 663 */
+    if (wnet & 1) {
+        chainet[wnet] = 29;
+        wnet++;
+    }
+    /* Now translate the string chainet into codewords */
+    chainemc[*(mclength)] = 900;
+    *(mclength) = *(mclength) + 1;
+
+    for (j = 0; j < wnet; j += 2) {
+        int cw_number;
+
+        cw_number = (30 * chainet[j]) + chainet[j + 1];
+        chainemc[*(mclength)] = cw_number;
+        *(mclength) = *(mclength) + 1;
+
+    }
+}
+
+/* 671 */
+INTERNAL void byteprocess(int *chainemc, int *mclength, unsigned char chaine[], int start, int length) {
+    int debug = 0;
+
+    if (debug) printf("\nEntering byte mode at position %d\n", start);
+
+    if (length == 1) {
+        chainemc[(*mclength)++] = 913;
+        chainemc[(*mclength)++] = chaine[start];
+        if (debug) {
+            printf("913 %d\n", chainemc[*mclength - 1]);
+        }
+    } else {
+        int len;
+        /* select the switch for multiple of 6 bytes */
+        if (length % 6 == 0) {
+            chainemc[(*mclength)++] = 924;
+            if (debug) printf("924 ");
+        } else {
+            chainemc[(*mclength)++] = 901;
+            if (debug) printf("901 ");
+        }
+
+        len = 0;
+
+        while (len < length) {
+            uint64_t total;
+            unsigned int chunkLen = length - len;
+            if (6 <= chunkLen) /* Take groups of 6 */ {
+                chunkLen = 6;
+                len += chunkLen;
+#if defined(_MSC_VER) && _MSC_VER == 1200
+                total = 0;
+#else
+                total = 0ULL;
+#endif
+
+                while (chunkLen--) {
+                    uint64_t mantisa = chaine[start++];
+#if defined(_MSC_VER) && _MSC_VER == 1200
+                    total |= mantisa << (uint64_t) (chunkLen * 8);
+#else
+                    total |= mantisa << (uint64_t) (chunkLen * 8ULL);
+#endif
+                }
+
+                chunkLen = 5;
+
+                while (chunkLen--) {
+#if defined(_MSC_VER) && _MSC_VER == 1200
+                    chainemc[*mclength + chunkLen] = (int) (total % 900);
+                    total /= 900;
+#else
+                    chainemc[*mclength + chunkLen] = (int) (total % 900ULL);
+                    total /= 900ULL;
+#endif
+                }
+                *mclength += 5;
+            } else /*  If it remain a group of less than 6 bytes   */ {
+                len += chunkLen;
+                while (chunkLen--) {
+                    chainemc[(*mclength)++] = chaine[start++];
+                }
+            }
+        }
+    }
+}
+
+/* 712 */
+static void numbprocess(int *chainemc, int *mclength, char chaine[], int start, int length) {
+    int j, loop, dummy[100], diviseur, nombre;
+    char chainemod[50], chainemult[100], temp;
+
+    strcpy(chainemod, "");
+    for (loop = 0; loop <= 50; loop++) {
+        dummy[loop] = 0;
+    }
+
+    chainemc[*(mclength)] = 902;
+    *(mclength) = *(mclength) + 1;
+
+    j = 0;
+    while (j < length) {
+        int longueur;
+        int dumlength = 0;
+        strcpy(chainemod, "");
+        longueur = length - j;
+        if (longueur > 44) {
+            longueur = 44;
+        }
+        strcat(chainemod, "1");
+        for (loop = 1; loop <= longueur; loop++) {
+            chainemod[loop] = chaine[start + loop + j - 1];
+        }
+        chainemod[longueur + 1] = '\0';
+        do {
+            diviseur = 900;
+
+            /* 877 - gosub Modulo */
+            strcpy(chainemult, "");
+            nombre = 0;
+            while (strlen(chainemod) != 0) {
+                nombre *= 10;
+                nombre += ctoi(chainemod[0]);
+                for (loop = 0; loop < (int)strlen(chainemod); loop++) {
+                    chainemod[loop] = chainemod[loop + 1];
+                }
+                if (nombre < diviseur) {
+                    if (strlen(chainemult) != 0) {
+                        strcat(chainemult, "0");
+                    }
+                } else {
+                    temp = (nombre / diviseur) + '0';
+                    chainemult[strlen(chainemult) + 1] = '\0';
+                    chainemult[strlen(chainemult)] = temp;
+                }
+                nombre = nombre % diviseur;
+            }
+            diviseur = nombre;
+            /* return to 723 */
+
+            for (loop = dumlength; loop > 0; loop--) {
+                dummy[loop] = dummy[loop - 1];
+            }
+            dummy[0] = diviseur;
+            dumlength++;
+            strcpy(chainemod, chainemult);
+        } while (strlen(chainemult) != 0);
+        for (loop = 0; loop < dumlength; loop++) {
+            chainemc[*(mclength)] = dummy[loop];
+            *(mclength) = *(mclength) + 1;
+        }
+        j += longueur;
+    }
+}
+
+/* 366 */
+static int pdf417(struct zint_symbol *symbol, unsigned char chaine[], const size_t length) {
+    int i, k, j, indexchaine, indexliste, mode, longueur, loop, mccorrection[520], offset;
+    int total, chainemc[PDF417_MAX_LEN], mclength, c1, c2, c3, dummy[35], calcheight;
+    char pattern[580];
+    int debug = symbol->debug;
+
+    if (length > PDF417_MAX_LEN) {
+        return 2;
+    }
+
+    /* 456 */
+    indexliste = 0;
+    indexchaine = 0;
+
+    mode = quelmode(chaine[indexchaine]);
+
+    for (i = 0; i < PDF417_MAX_LEN; i++) {
+        liste[0][i] = 0;
+    }
+
+    /* 463 */
+    do {
+        liste[1][indexliste] = mode;
+        while ((liste[1][indexliste] == mode) && (indexchaine < (int)length)) {
+            liste[0][indexliste]++;
+            indexchaine++;
+            mode = quelmode(chaine[indexchaine]);
+        }
+        indexliste++;
+    } while (indexchaine < (int)length);
+
+    /* 474 */
+    pdfsmooth(&indexliste);
+
+    if (debug) {
+        printf("Initial block pattern:\n");
+        for (i = 0; i < indexliste; i++) {
+            printf("Len: %d  Type: ", liste[0][i]);
+            switch (liste[1][i]) {
+                case TEX: printf("Text\n");
+                    break;
+                case BYT: printf("Byte\n");
+                    break;
+                case NUM: printf("Number\n");
+                    break;
+                default: printf("ERROR\n");
+                    break;
+            }
+        }
+    }
+
+    /* 541 - now compress the data */
+    indexchaine = 0;
+    mclength = 0;
+
+    if (symbol->output_options & READER_INIT) {
+        chainemc[mclength] = 921; /* Reader Initialisation */
+        mclength++;
+    }
+
+    if (symbol->eci != 0) {
+        /* Encoding ECI assignment number, according to Table 8 */
+        if (symbol->eci <= 899) {
+            chainemc[mclength] = 927; /* ECI */
+            mclength++;
+            chainemc[mclength] = symbol->eci;
+            mclength++;
+        }
+        if ((symbol->eci >= 900) && (symbol->eci <= 810899)) {
+            chainemc[mclength] = 926; /* ECI */
+            mclength++;
+            chainemc[mclength] = (symbol->eci / 900) - 1;
+            mclength++;
+            chainemc[mclength] = symbol->eci % 900;
+            mclength++;
+        }
+        if (symbol->eci >= 810900) {
+            chainemc[mclength] = 925; /* ECI */
+            mclength++;
+            chainemc[mclength] = symbol->eci - 810900;
+            mclength++;
+        }
+    }
+
+    if (symbol->eci > 811799) {
+        strcpy(symbol->errtxt, "472: Invalid ECI");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    for (i = 0; i < indexliste; i++) {
+        switch (liste[1][i]) {
+            case TEX: /* 547 - text mode */
+                textprocess(chainemc, &mclength, (char*) chaine, indexchaine, liste[0][i]);
+                break;
+            case BYT: /* 670 - octet stream mode */
+                byteprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i]);
+                break;
+            case NUM: /* 712 - numeric mode */
+                numbprocess(chainemc, &mclength, (char*) chaine, indexchaine, liste[0][i]);
+                break;
+        }
+        indexchaine = indexchaine + liste[0][i];
+    }
+
+    if (debug) {
+        printf("\nCompressed data stream:\n");
+        for (i = 0; i < mclength; i++) {
+            printf("%d ", chainemc[i]);
+        }
+        printf("\n\n");
+    }
+
+    /* 752 - Now take care of the number of CWs per row */
+    if (symbol->option_1 < 0) {
+        symbol->option_1 = 6;
+        if (mclength <= 863) {
+            symbol->option_1 = 5;
+        }
+        if (mclength <= 320) {
+            symbol->option_1 = 4;
+        }
+        if (mclength <= 160) {
+            symbol->option_1 = 3;
+        }
+        if (mclength <= 40) {
+            symbol->option_1 = 2;
+        }
+    }
+    k = 1;
+    for (loop = 1; loop <= (symbol->option_1 + 1); loop++) {
+        k *= 2;
+    }
+    longueur = mclength;
+    if (symbol->option_2 > 30) {
+        symbol->option_2 = 30;
+    }
+    if (symbol->option_2 < 1) {
+        symbol->option_2 =(int)(0.5 + sqrt((longueur + k) / 3.0));
+    }
+    if (((longueur + k) / symbol->option_2) > 90) {
+        /* stop the symbol from becoming too high */
+        symbol->option_2 = symbol->option_2 + 1;
+    }
+
+    if (longueur + k > 928) {
+        /* Enforce maximum codeword limit */
+        return 2;
+    }
+
+    if (((longueur + k) / symbol->option_2) > 90) {
+        return 4;
+    }
+
+    /* 781 - Padding calculation */
+    longueur = mclength + 1 + k;
+    i = 0;
+    if ((longueur / symbol->option_2) < 3) {
+        i = (symbol->option_2 * 3) - longueur; /* A bar code must have at least three rows */
+    } else {
+        if ((longueur % symbol->option_2) > 0) {
+            i = symbol->option_2 - (longueur % symbol->option_2);
+        }
+    }
+    /* We add the padding */
+    while (i > 0) {
+        chainemc[mclength] = 900;
+        mclength++;
+        i--;
+    }
+    /* we add the length descriptor */
+    for (i = mclength; i > 0; i--) {
+        chainemc[i] = chainemc[i - 1];
+    }
+    chainemc[0] = mclength + 1;
+    mclength++;
+
+    /* 796 - we now take care of the Reed Solomon codes */
+    switch (symbol->option_1) {
+        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;
+    }
+    total = 0;
+    for (i = 0; i < longueur; i++) {
+        total = (chainemc[i] + mccorrection[k - 1]) % 929;
+        for (j = k - 1; j > 0; j--) {
+            mccorrection[j] = (mccorrection[j - 1] + 929 - (total * coefrs[offset + j]) % 929) % 929;
+        }
+        mccorrection[0] = (929 - (total * coefrs[offset + j]) % 929) % 929;
+    }
+
+    /* we add these codes to the string */
+    for (i = k - 1; i >= 0; i--) {
+        chainemc[mclength++] = mccorrection[i] ? 929 - mccorrection[i] : 0;
+    }
+    
+    if (debug) {
+        printf("Complete CW string:\n");
+        for (i = 0; i < mclength; i++) {
+            printf("%d ", chainemc[i]);
+        }
+        printf("\n");
+    }
+
+    /* 818 - The CW string is finished */
+    c1 = (mclength / symbol->option_2 - 1) / 3;
+    c2 = symbol->option_1 * 3 + (mclength / symbol->option_2 - 1) % 3;
+    c3 = symbol->option_2 - 1;
+
+    /* we now encode each row */
+    for (i = 0; i <= (mclength / symbol->option_2) - 1; i++) {
+        for (j = 0; j < symbol->option_2; j++) {
+            dummy[j + 1] = chainemc[i * symbol->option_2 + j];
+        }
+        k = (i / 3) * 30;
+        switch (i % 3) {
+            case 0:
+                dummy[0] = k + c1;
+                dummy[symbol->option_2 + 1] = k + c3;
+                offset = 0; /* cluster(0) */
+                break;
+            case 1:
+                dummy[0] = k + c2;
+                dummy[symbol->option_2 + 1] = k + c1;
+                offset = 929; /* cluster(3) */
+                break;
+            case 2:
+                dummy[0] = k + c3;
+                dummy[symbol->option_2 + 1] = k + c2;
+                offset = 1858; /* cluster(6) */
+                break;
+        }
+        strcpy(pattern, "");
+        bin_append(0x1FEA8, 17, pattern); /* Row start */
+
+        for (j = 0; j <= symbol->option_2; j++) {
+            bin_append(pdf_bitpattern[offset + dummy[j]], 16, pattern);
+            strcat(pattern, "0");
+        }
+
+        if (symbol->symbology != BARCODE_PDF417TRUNC) {
+            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);
+            }
+        }
+    }
+    
+    /* Allow user to adjust height of symbol, but enforce minimum row height of 3X */
+    calcheight = (int)(symbol->height / i);
+    if (calcheight < 3) {
+        calcheight = 3;
+    }
+    
+    for (j = 0; j < i; j++) {
+        symbol->row_height[j] = calcheight;
+    }
+    
+    symbol->rows = (mclength / symbol->option_2);
+    symbol->width =(int)strlen(pattern);
+
+    /* 843 */
+    return 0;
+}
+
+/* 345 */
+INTERNAL int pdf417enc(struct zint_symbol *symbol, unsigned char source[], const size_t length) {
+    int codeerr, error_number;
+
+    error_number = 0;
+
+    if ((symbol->option_1 < -1) || (symbol->option_1 > 8)) {
+        strcpy(symbol->errtxt, "460: Security value out of range");
+        symbol->option_1 = -1;
+        error_number = ZINT_WARN_INVALID_OPTION;
+    }
+    if ((symbol->option_2 < 0) || (symbol->option_2 > 30)) {
+        strcpy(symbol->errtxt, "461: Number of columns out of range");
+        symbol->option_2 = 0;
+        error_number = ZINT_WARN_INVALID_OPTION;
+    }
+
+    /* 349 */
+    codeerr = pdf417(symbol, source, length);
+
+    /* 352 */
+    if (codeerr != 0) {
+        switch (codeerr) {
+            case 1:
+                strcpy(symbol->errtxt, "462: No such file or file unreadable");
+                error_number = ZINT_ERROR_INVALID_OPTION;
+                break;
+            case 2:
+                strcpy(symbol->errtxt, "463: Input string too long");
+                error_number = ZINT_ERROR_TOO_LONG;
+                break;
+            case 3:
+                strcpy(symbol->errtxt, "464: Number of codewords per row too small");
+                error_number = ZINT_WARN_INVALID_OPTION;
+                break;
+            case 4:
+                strcpy(symbol->errtxt, "465: Data too long for specified number of columns");
+                error_number = ZINT_ERROR_TOO_LONG;
+                break;
+            case ZINT_ERROR_INVALID_OPTION:
+                error_number = codeerr;
+                break;
+            default:
+                strcpy(symbol->errtxt, "466: Something strange happened");
+                error_number = ZINT_ERROR_ENCODING_PROBLEM;
+                break;
+        }
+    }
+
+    /* 364 */
+    return error_number;
+}
+
+/* like PDF417 only much smaller! */
+INTERNAL int micro_pdf417(struct zint_symbol *symbol, unsigned char chaine[], const size_t length) {
+    int i, k, j, indexchaine, indexliste, mode, longueur, mccorrection[50], offset;
+    int total, chainemc[PDF417_MAX_LEN], mclength, dummy[5], codeerr;
+    char pattern[580];
+    int variant, LeftRAPStart, CentreRAPStart, RightRAPStart, StartCluster;
+    int LeftRAP, CentreRAP, RightRAP, Cluster, loop, calcheight;
+    int debug = 0;
+
+    if (length > MICRO_PDF417_MAX_LEN) {
+        strcpy(symbol->errtxt, "474: Input data too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    /* Encoding starts out the same as PDF417, so use the same code */
+    codeerr = 0;
+
+    /* 456 */
+    indexliste = 0;
+    indexchaine = 0;
+
+    mode = quelmode(chaine[indexchaine]);
+
+    for (i = 0; i < PDF417_MAX_LEN; i++) {
+        liste[0][i] = 0;
+    }
+
+    /* 463 */
+    do {
+        liste[1][indexliste] = mode;
+        while ((liste[1][indexliste] == mode) && (indexchaine < (int)length)) {
+            liste[0][indexliste]++;
+            indexchaine++;
+            mode = quelmode(chaine[indexchaine]);
+        }
+        indexliste++;
+    } while (indexchaine < (int)length);
+
+    /* 474 */
+    pdfsmooth(&indexliste);
+
+    if (debug) {
+        printf("Initial mapping:\n");
+        for (i = 0; i < indexliste; i++) {
+            printf("len: %d   type: ", liste[0][i]);
+            switch (liste[1][i]) {
+                case TEX: printf("TEXT\n");
+                    break;
+                case BYT: printf("BYTE\n");
+                    break;
+                case NUM: printf("NUMBER\n");
+                    break;
+                default: printf("*ERROR*\n");
+                    break;
+            }
+        }
+    }
+
+    /* 541 - now compress the data */
+    indexchaine = 0;
+    mclength = 0;
+
+    if (symbol->output_options & READER_INIT) {
+        chainemc[mclength] = 921; /* Reader Initialisation */
+        mclength++;
+    }
+
+    if (symbol->eci > 811799) {
+        strcpy(symbol->errtxt, "473: Invalid ECI");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    if (symbol->eci != 0) {
+        /* Encoding ECI assignment number, according to Table 8 */
+        if (symbol->eci <= 899) {
+            chainemc[mclength] = 927; /* ECI */
+            mclength++;
+            chainemc[mclength] = symbol->eci;
+            mclength++;
+        }
+        if ((symbol->eci >= 900) && (symbol->eci <= 810899)) {
+            chainemc[mclength] = 926; /* ECI */
+            mclength++;
+            chainemc[mclength] = (symbol->eci / 900) - 1;
+            mclength++;
+            chainemc[mclength] = symbol->eci % 900;
+            mclength++;
+        }
+        if (symbol->eci >= 810900) {
+            chainemc[mclength] = 925; /* ECI */
+            mclength++;
+            chainemc[mclength] = symbol->eci - 810900;
+            mclength++;
+        }
+    }
+
+    for (i = 0; i < indexliste; i++) {
+        switch (liste[1][i]) {
+            case TEX: /* 547 - text mode */
+                textprocess(chainemc, &mclength, (char*) chaine, indexchaine, liste[0][i]);
+                break;
+            case BYT: /* 670 - octet stream mode */
+                byteprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i]);
+                break;
+            case NUM: /* 712 - numeric mode */
+                numbprocess(chainemc, &mclength, (char*) chaine, indexchaine, liste[0][i]);
+                break;
+        }
+        indexchaine = indexchaine + liste[0][i];
+    }
+
+    /* This is where it all changes! */
+
+    if (mclength > 126) {
+        strcpy(symbol->errtxt, "467: Input data too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    if (symbol->option_2 > 4) {
+        strcpy(symbol->errtxt, "468: Specified width out of range");
+        symbol->option_2 = 0;
+        codeerr = ZINT_WARN_INVALID_OPTION;
+    }
+
+    if (debug) {
+        printf("\nEncoded Data Stream:\n");
+        for (i = 0; i < mclength; i++) {
+            printf("0x%02X ", chainemc[i]);
+        }
+        printf("\n");
+    }
+
+    /* Now figure out which variant of the symbol to use and load values accordingly */
+
+    variant = 0;
+
+    if ((symbol->option_2 == 1) && (mclength > 20)) {
+        /* the user specified 1 column but the data doesn't fit - go to automatic */
+        symbol->option_2 = 0;
+        strcpy(symbol->errtxt, "469: Specified symbol size too small for data");
+        codeerr = ZINT_WARN_INVALID_OPTION;
+    }
+
+    if ((symbol->option_2 == 2) && (mclength > 37)) {
+        /* the user specified 2 columns but the data doesn't fit - go to automatic */
+        symbol->option_2 = 0;
+        strcpy(symbol->errtxt, "470: Specified symbol size too small for data");
+        codeerr = ZINT_WARN_INVALID_OPTION;
+    }
+
+    if ((symbol->option_2 == 3) && (mclength > 82)) {
+        /* the user specified 3 columns but the data doesn't fit - go to automatic */
+        symbol->option_2 = 0;
+        strcpy(symbol->errtxt, "471: Specified symbol size too small for data");
+        codeerr = ZINT_WARN_INVALID_OPTION;
+    }
+
+    if (symbol->option_2 == 1) {
+        /* the user specified 1 column and the data does fit */
+        variant = 6;
+        if (mclength <= 16) {
+            variant = 5;
+        }
+        if (mclength <= 12) {
+            variant = 4;
+        }
+        if (mclength <= 10) {
+            variant = 3;
+        }
+        if (mclength <= 7) {
+            variant = 2;
+        }
+        if (mclength <= 4) {
+            variant = 1;
+        }
+    }
+
+    if (symbol->option_2 == 2) {
+        /* the user specified 2 columns and the data does fit */
+        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 (symbol->option_2 == 3) {
+        /* the user specified 3 columns and the data does fit */
+        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 (symbol->option_2 == 4) {
+        /* the user specified 4 columns and the data does fit */
+        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;
+        }
+    }
+
+    if (variant == 0) {
+        /* Zint can choose automatically from all available variations */
+        for (i = 27; i >= 0; i--) {
+
+            if (MicroAutosize[i] >= mclength) {
+                variant = MicroAutosize[i + 28];
+            }
+        }
+    }
+
+    /* Now we have the variant we can load the data */
+    variant--;
+    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 */
+
+    if (debug) {
+        printf("\nChoose symbol size:\n");
+        printf("%d columns x %d rows\n", symbol->option_2, symbol->rows);
+        printf("%d data codewords (including %d pads), %d ecc codewords\n", longueur, i, k);
+        printf("\n");
+    }
+
+    /* 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;
+    }
+    total = 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++;
+    }
+
+    if (debug) {
+        printf("Encoded Data Stream with ECC:\n");
+        for (i = 0; i < mclength; i++) {
+            printf("0x%02X ", chainemc[i]);
+        }
+        printf("\n");
+    }
+
+    /* 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) */
+
+    if (debug) printf("\nInternal row representation:\n");
+    for (i = 0; i < symbol->rows; i++) {
+        if (debug) printf("row %d: ", 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];
+            if (debug) printf("[%d] ", dummy[j + 1]);
+        }
+
+        /* 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 (symbol->option_2 == 3) {
+            bin_append(rap_centre[CentreRAP - 1], 10, pattern);
+        }
+        if (symbol->option_2 >= 2) {
+            bin_append(pdf_bitpattern[offset + dummy[2]], 16, pattern);
+            strcat(pattern, "0");
+        }
+        if (symbol->option_2 == 4) {
+            bin_append(rap_centre[CentreRAP - 1], 10, pattern);
+        }
+        if (symbol->option_2 >= 3) {
+            bin_append(pdf_bitpattern[offset + dummy[3]], 16, pattern);
+            strcat(pattern, "0");
+        }
+        if (symbol->option_2 == 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 */
+        if (debug) printf("%s\n", pattern);
+
+        /* 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;
+        }
+    }
+    
+    /* Allow user to adjust height of symbol, but enforce minimum row height of 2X */
+    calcheight = (int)(symbol->height / i);
+    if (calcheight < 2) {
+        calcheight = 2;
+    }
+    
+    for (j = 0; j < i; j++) {
+        symbol->row_height[j] = calcheight;
+    }
+
+    return codeerr;
+}
diff --git a/backend/pdf417.h b/backend/pdf417.h
new file mode 100644 (file)
index 0000000..90e8b4a
--- /dev/null
@@ -0,0 +1,514 @@
+/* pdf417.h - PDF417 tables and coefficients */
+
+/*
+    libzint - the open source barcode library
+    Copyright (C) 2008-2017 Robin Stuart <rstuart114@gmail.com>
+    Portions Copyright (C) 2004 Grandzebu
+
+    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 file contains the character table, the pre-calculated coefficients and the
+   codeword patterns taken from lines 416 to 454 of pdf417.frm */
+
+#define TRUE 1
+#define FALSE 0
+#define TEX 900
+#define BYT 901
+#define NUM 902
+
+/* PDF417 error correction coefficients from Grand Zebu */
+static const unsigned short int coefrs[1022] = {
+    /* k = 2 */
+    27, 917,
+
+    /* k = 4 */
+    522, 568, 723, 809,
+
+    /* k = 8 */
+    237, 308, 436, 284, 646, 653, 428, 379,
+
+    /* k = 16 */
+    274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, 42, 176, 65,
+
+    /* k = 32 */
+    361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, 284, 193, 517,
+    273, 494, 263, 147, 593, 800, 571, 320, 803, 133, 231, 390, 685, 330, 63, 410,
+
+    /* k = 64 */
+    539, 422, 6, 93, 862, 771, 453, 106, 610, 287, 107, 505, 733, 877, 381, 612,
+    723, 476, 462, 172, 430, 609, 858, 822, 543, 376, 511, 400, 672, 762, 283, 184,
+    440, 35, 519, 31, 460, 594, 225, 535, 517, 352, 605, 158, 651, 201, 488, 502,
+    648, 733, 717, 83, 404, 97, 280, 771, 840, 629, 4, 381, 843, 623, 264, 543,
+
+    /* k = 128 */
+    521, 310, 864, 547, 858, 580, 296, 379, 53, 779, 897, 444, 400, 925, 749, 415,
+    822, 93, 217, 208, 928, 244, 583, 620, 246, 148, 447, 631, 292, 908, 490, 704,
+    516, 258, 457, 907, 594, 723, 674, 292, 272, 96, 684, 432, 686, 606, 860, 569,
+    193, 219, 129, 186, 236, 287, 192, 775, 278, 173, 40, 379, 712, 463, 646, 776,
+    171, 491, 297, 763, 156, 732, 95, 270, 447, 90, 507, 48, 228, 821, 808, 898,
+    784, 663, 627, 378, 382, 262, 380, 602, 754, 336, 89, 614, 87, 432, 670, 616,
+    157, 374, 242, 726, 600, 269, 375, 898, 845, 454, 354, 130, 814, 587, 804, 34,
+    211, 330, 539, 297, 827, 865, 37, 517, 834, 315, 550, 86, 801, 4, 108, 539,
+
+    /* k = 256 */
+    524, 894, 75, 766, 882, 857, 74, 204, 82, 586, 708, 250, 905, 786, 138, 720,
+    858, 194, 311, 913, 275, 190, 375, 850, 438, 733, 194, 280, 201, 280, 828, 757,
+    710, 814, 919, 89, 68, 569, 11, 204, 796, 605, 540, 913, 801, 700, 799, 137,
+    439, 418, 592, 668, 353, 859, 370, 694, 325, 240, 216, 257, 284, 549, 209, 884,
+    315, 70, 329, 793, 490, 274, 877, 162, 749, 812, 684, 461, 334, 376, 849, 521,
+    307, 291, 803, 712, 19, 358, 399, 908, 103, 511, 51, 8, 517, 225, 289, 470,
+    637, 731, 66, 255, 917, 269, 463, 830, 730, 433, 848, 585, 136, 538, 906, 90,
+    2, 290, 743, 199, 655, 903, 329, 49, 802, 580, 355, 588, 188, 462, 10, 134,
+    628, 320, 479, 130, 739, 71, 263, 318, 374, 601, 192, 605, 142, 673, 687, 234,
+    722, 384, 177, 752, 607, 640, 455, 193, 689, 707, 805, 641, 48, 60, 732, 621,
+    895, 544, 261, 852, 655, 309, 697, 755, 756, 60, 231, 773, 434, 421, 726, 528,
+    503, 118, 49, 795, 32, 144, 500, 238, 836, 394, 280, 566, 319, 9, 647, 550,
+    73, 914, 342, 126, 32, 681, 331, 792, 620, 60, 609, 441, 180, 791, 893, 754,
+    605, 383, 228, 749, 760, 213, 54, 297, 134, 54, 834, 299, 922, 191, 910, 532,
+    609, 829, 189, 20, 167, 29, 872, 449, 83, 402, 41, 656, 505, 579, 481, 173,
+    404, 251, 688, 95, 497, 555, 642, 543, 307, 159, 924, 558, 648, 55, 497, 10,
+
+    /* k = 512 */
+    352, 77, 373, 504, 35, 599, 428, 207, 409, 574, 118, 498, 285, 380, 350, 492,
+    197, 265, 920, 155, 914, 299, 229, 643, 294, 871, 306, 88, 87, 193, 352, 781,
+    846, 75, 327, 520, 435, 543, 203, 666, 249, 346, 781, 621, 640, 268, 794, 534,
+    539, 781, 408, 390, 644, 102, 476, 499, 290, 632, 545, 37, 858, 916, 552, 41,
+    542, 289, 122, 272, 383, 800, 485, 98, 752, 472, 761, 107, 784, 860, 658, 741,
+    290, 204, 681, 407, 855, 85, 99, 62, 482, 180, 20, 297, 451, 593, 913, 142,
+    808, 684, 287, 536, 561, 76, 653, 899, 729, 567, 744, 390, 513, 192, 516, 258,
+    240, 518, 794, 395, 768, 848, 51, 610, 384, 168, 190, 826, 328, 596, 786, 303,
+    570, 381, 415, 641, 156, 237, 151, 429, 531, 207, 676, 710, 89, 168, 304, 402,
+    40, 708, 575, 162, 864, 229, 65, 861, 841, 512, 164, 477, 221, 92, 358, 785,
+    288, 357, 850, 836, 827, 736, 707, 94, 8, 494, 114, 521, 2, 499, 851, 543,
+    152, 729, 771, 95, 248, 361, 578, 323, 856, 797, 289, 51, 684, 466, 533, 820,
+    669, 45, 902, 452, 167, 342, 244, 173, 35, 463, 651, 51, 699, 591, 452, 578,
+    37, 124, 298, 332, 552, 43, 427, 119, 662, 777, 475, 850, 764, 364, 578, 911,
+    283, 711, 472, 420, 245, 288, 594, 394, 511, 327, 589, 777, 699, 688, 43, 408,
+    842, 383, 721, 521, 560, 644, 714, 559, 62, 145, 873, 663, 713, 159, 672, 729,
+    624, 59, 193, 417, 158, 209, 563, 564, 343, 693, 109, 608, 563, 365, 181, 772,
+    677, 310, 248, 353, 708, 410, 579, 870, 617, 841, 632, 860, 289, 536, 35, 777,
+    618, 586, 424, 833, 77, 597, 346, 269, 757, 632, 695, 751, 331, 247, 184, 45,
+    787, 680, 18, 66, 407, 369, 54, 492, 228, 613, 830, 922, 437, 519, 644, 905,
+    789, 420, 305, 441, 207, 300, 892, 827, 141, 537, 381, 662, 513, 56, 252, 341,
+    242, 797, 838, 837, 720, 224, 307, 631, 61, 87, 560, 310, 756, 665, 397, 808,
+    851, 309, 473, 795, 378, 31, 647, 915, 459, 806, 590, 731, 425, 216, 548, 249,
+    321, 881, 699, 535, 673, 782, 210, 815, 905, 303, 843, 922, 281, 73, 469, 791,
+    660, 162, 498, 308, 155, 422, 907, 817, 187, 62, 16, 425, 535, 336, 286, 437,
+    375, 273, 610, 296, 183, 923, 116, 667, 751, 353, 62, 366, 691, 379, 687, 842,
+    37, 357, 720, 742, 330, 5, 39, 923, 311, 424, 242, 749, 321, 54, 669, 316,
+    342, 299, 534, 105, 667, 488, 640, 672, 576, 540, 316, 486, 721, 610, 46, 656,
+    447, 171, 616, 464, 190, 531, 297, 321, 762, 752, 533, 175, 134, 14, 381, 433,
+    717, 45, 111, 20, 596, 284, 736, 138, 646, 411, 877, 669, 141, 919, 45, 780,
+    407, 164, 332, 899, 165, 726, 600, 325, 498, 655, 357, 752, 768, 223, 849, 647,
+    63, 310, 863, 251, 366, 304, 282, 738, 675, 410, 389, 244, 31, 121, 303, 263
+};
+
+static const unsigned short int pdf_bitpattern[2787] = {
+    0xEAE0, 0xF578, 0xFABE, 0xEA70, 0xF53C, 0xFA9F, 0xD460, 0xEA38, 0xD430, 0xA820,
+    0xD418, 0xA810, 0xD6E0, 0xEB78, 0xF5BE, 0xD670, 0xEB3C, 0xF59F, 0xAC60, 0xD638,
+    0xAC30, 0xAEE0, 0xD778, 0xEBBE, 0xAE70, 0xD73C, 0xEB9F, 0xAE38, 0xD71E, 0xAF78,
+    0xD7BE, 0xAF3C, 0xD79F, 0xAFBE, 0xFAFD, 0xE970, 0xF4BC, 0xFA5F, 0xD260, 0xE938,
+    0xF49E, 0xD230, 0xE91C, 0xA420, 0xD218, 0xE90E, 0xA410, 0xD20C, 0xA408, 0xD370,
+    0xE9BC, 0xF4DF, 0xA660, 0xD338, 0xE99E, 0xA630, 0xD31C, 0xE98F, 0xA618, 0xD30E,
+    0xA770, 0xD3BC, 0xE9DF, 0xA738, 0xD39E, 0xA71C, 0xD38F, 0xA7BC, 0xD3DF, 0xA79E,
+    0xA78F, 0xD160, 0xE8B8, 0xF45E, 0xD130, 0xE89C, 0xF44F, 0xA220, 0xD118, 0xE88E,
+    0xA210, 0xD10C, 0xA208, 0xA204, 0xA360, 0xD1B8, 0xE8DE, 0xA330, 0xD19C, 0xE8CF,
+    0xA318, 0xD18E, 0xA30C, 0xA306, 0xA3B8, 0xD1DE, 0xA39C, 0xD1CF, 0xA38E, 0xA3DE,
+    0xD0B0, 0xE85C, 0xF42F, 0xA120, 0xD098, 0xE84E, 0xA110, 0xD08C, 0xE847, 0xA108,
+    0xD086, 0xA104, 0xD083, 0xA1B0, 0xD0DC, 0xE86F, 0xA198, 0xD0CE, 0xA18C, 0xD0C7,
+    0xA186, 0xA183, 0xD0EF, 0xA1C7, 0xA0A0, 0xD058, 0xE82E, 0xA090, 0xD04C, 0xE827,
+    0xA088, 0xD046, 0xA084, 0xD043, 0xA082, 0xA0D8, 0xA0CC, 0xA0C6, 0xA050, 0xE817,
+    0xD026, 0xD023, 0xA041, 0xE570, 0xF2BC, 0xF95F, 0xCA60, 0xE538, 0xF29E, 0xCA30,
+    0xE51C, 0xF28F, 0x9420, 0xCA18, 0x9410, 0xCB70, 0xE5BC, 0xF2DF, 0x9660, 0xCB38,
+    0xE59E, 0x9630, 0xCB1C, 0x9618, 0x960C, 0x9770, 0xCBBC, 0xE5DF, 0x9738, 0xCB9E,
+    0x971C, 0x970E, 0x97BC, 0xCBDF, 0x979E, 0x97DF, 0xED60, 0xF6B8, 0xFB5E, 0xED30,
+    0xF69C, 0xFB4F, 0xDA20, 0xED18, 0xF68E, 0xDA10, 0xED0C, 0xF687, 0xDA08, 0xED06,
+    0xC960, 0xE4B8, 0xF25E, 0xDB60, 0xC930, 0xE49C, 0xF24F, 0xDB30, 0xED9C, 0xF6CF,
+    0xB620, 0x9210, 0xC90C, 0xE487, 0xB610, 0xDB0C, 0xB608, 0x9360, 0xC9B8, 0xE4DE,
+    0xB760, 0x9330, 0xC99C, 0xE4CF, 0xB730, 0xDB9C, 0xEDCF, 0xB718, 0x930C, 0xB70C,
+    0x93B8, 0xC9DE, 0xB7B8, 0x939C, 0xC9CF, 0xB79C, 0xDBCF, 0xB78E, 0x93DE, 0xB7DE,
+    0x93CF, 0xB7CF, 0xECB0, 0xF65C, 0xFB2F, 0xD920, 0xEC98, 0xF64E, 0xD910, 0xEC8C,
+    0xF647, 0xD908, 0xEC86, 0xD904, 0xD902, 0xC8B0, 0xE45C, 0xF22F, 0xD9B0, 0xC898,
+    0xE44E, 0xB320, 0x9110, 0xECCE, 0xE447, 0xB310, 0x9108, 0xC886, 0xB308, 0xD986,
+    0xC883, 0x9102, 0x91B0, 0xC8DC, 0xE46F, 0xB3B0, 0x9198, 0xC8CE, 0xB398, 0xD9CE,
+    0xC8C7, 0xB38C, 0x9186, 0x9183, 0x91DC, 0xC8EF, 0xB3DC, 0x91CE, 0xB3CE, 0x91C7,
+    0xB3C7, 0xB3EF, 0xD8A0, 0xEC58, 0xF62E, 0xD890, 0xEC4C, 0xF627, 0xD888, 0xEC46,
+    0xD884, 0xEC43, 0xD882, 0xD881, 0x90A0, 0xC858, 0xE42E, 0xB1A0, 0x9090, 0xC84C,
+    0xE427, 0xB190, 0xD8CC, 0xEC67, 0xB188, 0x9084, 0xC843, 0xB184, 0xD8C3, 0xB182,
+    0x90D8, 0xC86E, 0xB1D8, 0x90CC, 0xC867, 0xB1CC, 0xD8E7, 0xB1C6, 0x90C3, 0xB1C3,
+    0xB1EE, 0xB1E7, 0xD850, 0xEC2C, 0xF617, 0xD848, 0xEC26, 0xD844, 0xEC23, 0xD842,
+    0xD841, 0x9050, 0xC82C, 0xE417, 0xB0D0, 0x9048, 0xC826, 0xB0C8, 0xD866, 0xC823,
+    0xB0C4, 0x9042, 0xB0C2, 0x9041, 0x906C, 0xB0EC, 0xB0E6, 0xB0E3, 0xEC16, 0xEC13,
+    0xD821, 0xC816, 0x9024, 0xB064, 0xB062, 0xB061, 0xC560, 0xE2B8, 0xF15E, 0xC530,
+    0xE29C, 0x8A20, 0xC518, 0xE28E, 0x8A10, 0xC50C, 0x8A08, 0x8A04, 0x8B60, 0xC5B8,
+    0xE2DE, 0x8B30, 0xC59C, 0xE2CF, 0x8B18, 0xC58E, 0x8B0C, 0x8B06, 0x8BB8, 0xC5DE,
+    0x8B9C, 0xC5CF, 0x8B8E, 0x8BDE, 0x8BCF, 0xE6B0, 0xF35C, 0xF9AF, 0xCD20, 0xE698,
+    0xF34E, 0xCD10, 0xE68C, 0xF347, 0xCD08, 0xE686, 0xCD04, 0xE683, 0xC4B0, 0xE25C,
+    0xF12F, 0xCDB0, 0xC498, 0xE24E, 0x9B20, 0x8910, 0xE6CE, 0xE247, 0x9B10, 0xCD8C,
+    0xC486, 0x9B08, 0x8904, 0x9B04, 0x89B0, 0xC4DC, 0xE26F, 0x9BB0, 0x8998, 0xE6EF,
+    0x9B98, 0xCDCE, 0xC4C7, 0x9B8C, 0x8986, 0x9B86, 0x89DC, 0xC4EF, 0x9BDC, 0x89CE,
+    0x9BCE, 0x89C7, 0x89EF, 0x9BEF, 0xEEA0, 0xF758, 0xFBAE, 0xEE90, 0xF74C, 0xFBA7,
+    0xEE88, 0xF746, 0xEE84, 0xF743, 0xEE82, 0xCCA0, 0xE658, 0xF32E, 0xDDA0, 0xCC90,
+    0xF76E, 0xF327, 0xDD90, 0xEECC, 0xF767, 0xDD88, 0xCC84, 0xE643, 0xDD84, 0xEEC3,
+    0xCC81, 0x88A0, 0xC458, 0xE22E, 0x99A0, 0x8890, 0xC44C, 0xE227, 0xBBA0, 0x9990,
+    0xCCCC, 0xE667, 0xBB90, 0xDDCC, 0xEEE7, 0xC443, 0xBB88, 0x9984, 0xCCC3, 0xBB84,
+    0x8881, 0x88D8, 0xC46E, 0x99D8, 0x88CC, 0xC467, 0xBBD8, 0x99CC, 0xCCE7, 0xBBCC,
+    0xDDE7, 0x88C3, 0x99C3, 0x88EE, 0x99EE, 0x88E7, 0xBBEE, 0x99E7, 0xEE50, 0xF72C,
+    0xFB97, 0xEE48, 0xF726, 0xEE44, 0xF723, 0xEE42, 0xEE41, 0xCC50, 0xE62C, 0xF317,
+    0xDCD0, 0xCC48, 0xF737, 0xDCC8, 0xEE66, 0xE623, 0xDCC4, 0xCC42, 0xDCC2, 0xCC41,
+    0xDCC1, 0x8850, 0xC42C, 0xE217, 0x98D0, 0x8848, 0xC426, 0xB9D0, 0x98C8, 0xCC66,
+    0xC423, 0xB9C8, 0xDCE6, 0x8842, 0xB9C4, 0x98C2, 0x8841, 0x98C1, 0x886C, 0xC437,
+    0x98EC, 0x8866, 0xB9EC, 0x98E6, 0x8863, 0xB9E6, 0x98E3, 0x8877, 0xB9F7, 0xEE28,
+    0xF716, 0xEE24, 0xF713, 0xEE22, 0xEE21, 0xCC28, 0xE616, 0xDC68, 0xCC24, 0xE613,
+    0xDC64, 0xEE33, 0xDC62, 0xCC21, 0xDC61, 0x8828, 0xC416, 0x9868, 0x8824, 0xC413,
+    0xB8E8, 0x9864, 0xCC33, 0xB8E4, 0xDC73, 0x8821, 0xB8E2, 0x9861, 0xB8E1, 0x9876,
+    0xB8F6, 0xB8F3, 0xF70B, 0xEE11, 0xE60B, 0xCC12, 0xCC11, 0x8814, 0x9834, 0xB874,
+    0x8811, 0x9831, 0xC2B0, 0x8520, 0xC298, 0x8510, 0xC28C, 0xE147, 0x8508, 0xC286,
+    0x8504, 0xC283, 0x85B0, 0xC2DC, 0xE16F, 0x8598, 0xC2CE, 0x858C, 0xC2C7, 0x8586,
+    0x8583, 0x85DC, 0xC2EF, 0x85CE, 0x85C7, 0x85EF, 0xC6A0, 0xE358, 0xF1AE, 0xC690,
+    0xE34C, 0xC688, 0xE346, 0xC684, 0xE343, 0xC682, 0x84A0, 0xC258, 0xE12E, 0x8DA0,
+    0x8490, 0xE36E, 0xE127, 0x8D90, 0xC6CC, 0xE367, 0x8D88, 0x8484, 0xC243, 0x8D84,
+    0xC6C3, 0x8481, 0x84D8, 0xC26E, 0x8DD8, 0x84CC, 0xC267, 0x8DCC, 0xC6E7, 0x8DC6,
+    0x84C3, 0x84EE, 0x8DEE, 0x84E7, 0x8DE7, 0xE750, 0xF3AC, 0xF9D7, 0xE748, 0xF3A6,
+    0xE744, 0xF3A3, 0xE742, 0xE741, 0xC650, 0xE32C, 0xCED0, 0xC648, 0xE326, 0xCEC8,
+    0xE766, 0xE323, 0xCEC4, 0xC642, 0xCEC2, 0xC641, 0xCEC1, 0x8450, 0xC22C, 0x8CD0,
+    0x8448, 0xE337, 0x9DD0, 0x8CC8, 0xC666, 0xC223, 0x9DC8, 0xCEE6, 0x8442, 0x9DC4,
+    0x8CC2, 0x8441, 0x8CC1, 0x846C, 0xC237, 0x8CEC, 0x8466, 0x9DEC, 0x8CE6, 0x8463,
+    0x9DE6, 0x8CE3, 0x8477, 0x8CF7, 0x9DF7, 0xF7A8, 0xFBD6, 0xF7A4, 0xFBD3, 0xF7A2,
+    0xF7A1, 0xE728, 0xF396, 0xEF68, 0xF7B6, 0xF393, 0xEF64, 0xF7B3, 0xEF62, 0xE721,
+    0xEF61, 0xC628, 0xE316, 0xCE68, 0xC624, 0xE313, 0xDEE8, 0xCE64, 0xE733, 0xDEE4,
+    0xEF73, 0xC621, 0xDEE2, 0xCE61, 0xDEE1, 0x8428, 0xC216, 0x8C68, 0x8424, 0xC213,
+    0x9CE8, 0x8C64, 0xC633, 0xBDE8, 0x9CE4, 0xCE73, 0x8421, 0xBDE4, 0xDEF3, 0x8C61,
+    0xBDE2, 0x8436, 0x8C76, 0x8433, 0x9CF6, 0x8C73, 0xBDF6, 0x9CF3, 0xBDF3, 0xF794,
+    0xFBCB, 0xF792, 0xF791, 0xE714, 0xF38B, 0xEF34, 0xF79B, 0xEF32, 0xE711, 0xEF31,
+    0xC614, 0xE30B, 0xCE34, 0xC612, 0xDE74, 0xCE32, 0xC611, 0xDE72, 0xCE31, 0xDE71,
+    0x8414, 0xC20B, 0x8C34, 0xC61B, 0x9C74, 0x8C32, 0x8411, 0xBCF4, 0x9C72, 0x8C31,
+    0xBCF2, 0x9C71, 0xBCF1, 0x8C3B, 0xBCFB, 0xF789, 0xEF1A, 0xEF19, 0xCE1A, 0xDE3A,
+    0xDE39, 0x8C1A, 0x9C3A, 0xBC7A, 0xBC79, 0x82A0, 0x8290, 0xC14C, 0x8288, 0x8284,
+    0x8282, 0x82D8, 0x82CC, 0x82C6, 0x82C3, 0x82EE, 0x82E7, 0xC350, 0xC348, 0xE1A6,
+    0xC344, 0xE1A3, 0xC342, 0xC341, 0x8250, 0xC12C, 0x86D0, 0xC36C, 0xC126, 0x86C8,
+    0xC366, 0x86C4, 0xC363, 0x86C2, 0x8241, 0x86C1, 0x826C, 0xC137, 0x86EC, 0xC377,
+    0x86E6, 0x8263, 0x86E3, 0x8277, 0x86F7, 0xE3A8, 0xE3A4, 0xE3A2, 0xE3A1, 0xC328,
+    0xC768, 0xE3B6, 0xE193, 0xC764, 0xE3B3, 0xC762, 0xC321, 0xC761, 0x8228, 0x8668,
+    0x8224, 0xC113, 0x8EE8, 0x8664, 0x8222, 0x8EE4, 0x8662, 0x8221, 0x8EE2, 0x8661,
+    0x8236, 0x8676, 0x8233, 0x8EF6, 0x8673, 0x8EF3, 0xF3D4, 0xF3D2, 0xF3D1, 0xE394,
+    0xE7B4, 0xF3DB, 0xE7B2, 0xE391, 0xE7B1, 0xC314, 0xE18B, 0xC734, 0xE39B, 0xCF74,
+    0xC732, 0xC311, 0xCF72, 0xC731, 0xCF71, 0x8214, 0xC10B, 0x8634, 0xC31B, 0x8E74,
+    0x8632, 0x8211, 0x9EF4, 0x8E72, 0x8631, 0x9EF2, 0x8E71, 0x821B, 0x863B, 0x8E7B,
+    0x9EFB, 0xFBEA, 0xFBE9, 0xF3CA, 0xF7DA, 0xF3C9, 0xF7D9, 0xE38A, 0xE79A, 0xE389,
+    0xEFBA, 0xE799, 0xEFB9, 0xC30A, 0xC71A, 0xC309, 0xCF3A, 0xC719, 0xDF7A, 0xFAB0,
+    0xFD5C, 0xF520, 0xFA98, 0xFD4E, 0xF510, 0xFA8C, 0xFD47, 0xF508, 0xFA86, 0xF504,
+    0xFA83, 0xF502, 0xF5B0, 0xFADC, 0xFD6F, 0xEB20, 0xF598, 0xFACE, 0xEB10, 0xF58C,
+    0xFAC7, 0xEB08, 0xF586, 0xEB04, 0xF583, 0xEB02, 0xEBB0, 0xF5DC, 0xFAEF, 0xD720,
+    0xEB98, 0xF5CE, 0xD710, 0xEB8C, 0xF5C7, 0xD708, 0xEB86, 0xD704, 0xEB83, 0xD702,
+    0xD7B0, 0xEBDC, 0xF5EF, 0xAF20, 0xD798, 0xEBCE, 0xAF10, 0xD78C, 0xEBC7, 0xAF08,
+    0xD786, 0xAF04, 0xD783, 0xAFB0, 0xD7DC, 0xEBEF, 0xAF98, 0xD7CE, 0xAF8C, 0xD7C7,
+    0xAF86, 0xAFDC, 0xD7EF, 0xAFCE, 0xAFC7, 0xF4A0, 0xFA58, 0xFD2E, 0xF490, 0xFA4C,
+    0xFD27, 0xF488, 0xFA46, 0xF484, 0xFA43, 0xF482, 0xF481, 0xE9A0, 0xF4D8, 0xFA6E,
+    0xE990, 0xF4CC, 0xFA67, 0xE988, 0xF4C6, 0xE984, 0xF4C3, 0xE982, 0xE981, 0xD3A0,
+    0xE9D8, 0xF4EE, 0xD390, 0xE9CC, 0xF4E7, 0xD388, 0xE9C6, 0xD384, 0xE9C3, 0xD382,
+    0xD381, 0xA7A0, 0xD3D8, 0xE9EE, 0xA790, 0xD3CC, 0xE9E7, 0xA788, 0xD3C6, 0xA784,
+    0xD3C3, 0xA782, 0xA7D8, 0xD3EE, 0xA7CC, 0xD3E7, 0xA7C6, 0xA7C3, 0xA7EE, 0xA7E7,
+    0xF450, 0xFA2C, 0xFD17, 0xF448, 0xFA26, 0xF444, 0xFA23, 0xF442, 0xF441, 0xE8D0,
+    0xF46C, 0xFA37, 0xE8C8, 0xF466, 0xE8C4, 0xF463, 0xE8C2, 0xE8C1, 0xD1D0, 0xE8EC,
+    0xF477, 0xD1C8, 0xE8E6, 0xD1C4, 0xE8E3, 0xD1C2, 0xD1C1, 0xA3D0, 0xD1EC, 0xE8F7,
+    0xA3C8, 0xD1E6, 0xA3C4, 0xD1E3, 0xA3C2, 0xA3C1, 0xA3EC, 0xD1F7, 0xA3E6, 0xA3E3,
+    0xA3F7, 0xF428, 0xFA16, 0xF424, 0xFA13, 0xF422, 0xF421, 0xE868, 0xF436, 0xE864,
+    0xF433, 0xE862, 0xE861, 0xD0E8, 0xE876, 0xD0E4, 0xE873, 0xD0E2, 0xD0E1, 0xA1E8,
+    0xD0F6, 0xA1E4, 0xD0F3, 0xA1E2, 0xA1E1, 0xA1F6, 0xA1F3, 0xF414, 0xFA0B, 0xF412,
+    0xF411, 0xE834, 0xF41B, 0xE832, 0xE831, 0xD074, 0xE83B, 0xD072, 0xD071, 0xA0F4,
+    0xD07B, 0xA0F2, 0xA0F1, 0xF40A, 0xF409, 0xE81A, 0xE819, 0xD03A, 0xD039, 0xF2A0,
+    0xF958, 0xFCAE, 0xF290, 0xF94C, 0xFCA7, 0xF288, 0xF946, 0xF284, 0xF943, 0xF282,
+    0xF281, 0xE5A0, 0xF2D8, 0xF96E, 0xE590, 0xF2CC, 0xF967, 0xE588, 0xF2C6, 0xE584,
+    0xF2C3, 0xE582, 0xE581, 0xCBA0, 0xE5D8, 0xF2EE, 0xCB90, 0xE5CC, 0xF2E7, 0xCB88,
+    0xE5C6, 0xCB84, 0xE5C3, 0xCB82, 0xCB81, 0x97A0, 0xCBD8, 0xE5EE, 0x9790, 0xCBCC,
+    0xE5E7, 0x9788, 0xCBC6, 0x9784, 0xCBC3, 0x9782, 0x97D8, 0xCBEE, 0x97CC, 0xCBE7,
+    0x97C6, 0x97C3, 0x97EE, 0x97E7, 0xFB50, 0xFDAC, 0xB5F8, 0xFB48, 0xFDA6, 0xB4FC,
+    0xFB44, 0xFDA3, 0xB47E, 0xFB42, 0xFB41, 0xF250, 0xF92C, 0xFC97, 0xF6D0, 0xF248,
+    0xFDB7, 0xF6C8, 0xFB66, 0xF923, 0xF6C4, 0xF242, 0xF6C2, 0xF241, 0xF6C1, 0xE4D0,
+    0xF26C, 0xF937, 0xEDD0, 0xE4C8, 0xF266, 0xEDC8, 0xF6E6, 0xF263, 0xEDC4, 0xE4C2,
+    0xEDC2, 0xE4C1, 0xEDC1, 0xC9D0, 0xE4EC, 0xF277, 0xDBD0, 0xC9C8, 0xE4E6, 0xDBC8,
+    0xEDE6, 0xE4E3, 0xDBC4, 0xC9C2, 0xDBC2, 0xC9C1, 0xDBC1, 0x93D0, 0xC9EC, 0xE4F7,
+    0xB7D0, 0x93C8, 0xC9E6, 0xB7C8, 0xDBE6, 0xC9E3, 0xB7C4, 0x93C2, 0xB7C2, 0x93C1,
+    0x93EC, 0xC9F7, 0xB7EC, 0x93E6, 0xB7E6, 0x93E3, 0xB7E3, 0x93F7, 0xFB28, 0xFD96,
+    0xB2FC, 0xFB24, 0xFD93, 0xB27E, 0xFB22, 0xB23F, 0xFB21, 0xF228, 0xF916, 0xF668,
+    0xF224, 0xF913, 0xF664, 0xFB33, 0xF662, 0xF221, 0xF661, 0xE468, 0xF236, 0xECE8,
+    0xE464, 0xF233, 0xECE4, 0xF673, 0xECE2, 0xE461, 0xECE1, 0xC8E8, 0xE476, 0xD9E8,
+    0xC8E4, 0xE473, 0xD9E4, 0xECF3, 0xD9E2, 0xC8E1, 0xD9E1, 0x91E8, 0xC8F6, 0xB3E8,
+    0x91E4, 0xC8F3, 0xB3E4, 0xD9F3, 0xB3E2, 0x91E1, 0xB3E1, 0x91F6, 0xB3F6, 0x91F3,
+    0xB3F3, 0xFB14, 0xFD8B, 0xB17E, 0xFB12, 0xB13F, 0xFB11, 0xF214, 0xF90B, 0xF634,
+    0xFB1B, 0xF632, 0xF211, 0xF631, 0xE434, 0xF21B, 0xEC74, 0xE432, 0xEC72, 0xE431,
+    0xEC71, 0xC874, 0xE43B, 0xD8F4, 0xEC7B, 0xD8F2, 0xC871, 0xD8F1, 0x90F4, 0xC87B,
+    0xB1F4, 0x90F2, 0xB1F2, 0x90F1, 0xB1F1, 0x90FB, 0xB1FB, 0xFB0A, 0xB0BF, 0xFB09,
+    0xF20A, 0xF61A, 0xF209, 0xF619, 0xE41A, 0xEC3A, 0xE419, 0xEC39, 0xC83A, 0xD87A,
+    0xC839, 0xD879, 0x907A, 0xB0FA, 0x9079, 0xB0F9, 0xFB05, 0xF205, 0xF60D, 0xE40D,
+    0xEC1D, 0xC81D, 0xD83D, 0xF150, 0xF8AC, 0xFC57, 0xF148, 0xF8A6, 0xF144, 0xF8A3,
+    0xF142, 0xF141, 0xE2D0, 0xF16C, 0xF8B7, 0xE2C8, 0xF166, 0xE2C4, 0xF163, 0xE2C2,
+    0xE2C1, 0xC5D0, 0xE2EC, 0xF177, 0xC5C8, 0xE2E6, 0xC5C4, 0xE2E3, 0xC5C2, 0xC5C1,
+    0x8BD0, 0xC5EC, 0xE2F7, 0x8BC8, 0xC5E6, 0x8BC4, 0xC5E3, 0x8BC2, 0x8BC1, 0x8BEC,
+    0xC5F7, 0x8BE6, 0x8BE3, 0x8BF7, 0xF9A8, 0xFCD6, 0x9AFC, 0xF9A4, 0xFCD3, 0x9A7E,
+    0xF9A2, 0x9A3F, 0xF9A1, 0xF128, 0xF896, 0xF368, 0xF124, 0xF893, 0xF364, 0xF9B3,
+    0xF362, 0xF121, 0xF361, 0xE268, 0xF136, 0xE6E8, 0xE264, 0xF133, 0xE6E4, 0xF373,
+    0xE6E2, 0xE261, 0xE6E1, 0xC4E8, 0xE276, 0xCDE8, 0xC4E4, 0xE273, 0xCDE4, 0xE6F3,
+    0xCDE2, 0xC4E1, 0xCDE1, 0x89E8, 0xC4F6, 0x9BE8, 0x89E4, 0xC4F3, 0x9BE4, 0xCDF3,
+    0x9BE2, 0x89E1, 0x9BE1, 0x89F6, 0x9BF6, 0x89F3, 0x9BF3, 0xFDD4, 0xBAF8, 0xDD7E,
+    0xFDD2, 0xBA7C, 0xDD3F, 0xFDD1, 0xBA3E, 0xBA1F, 0xF994, 0xFCCB, 0x997E, 0xFBB4,
+    0xFDDB, 0xBB7E, 0x993F, 0xFBB2, 0xF991, 0xBB3F, 0xFBB1, 0xF114, 0xF88B, 0xF334,
+    0xF112, 0xF774, 0xFBBB, 0xF111, 0xF772, 0xF331, 0xF771, 0xE234, 0xF11B, 0xE674,
+    0xE232, 0xEEF4, 0xE672, 0xE231, 0xEEF2, 0xE671, 0xEEF1, 0xC474, 0xE23B, 0xCCF4,
+    0xC472, 0xDDF4, 0xCCF2, 0xC471, 0xDDF2, 0xCCF1, 0xDDF1, 0x88F4, 0xC47B, 0x99F4,
+    0x88F2, 0xBBF4, 0x99F2, 0x88F1, 0xBBF2, 0x99F1, 0xBBF1, 0x88FB, 0x99FB, 0xFDCA,
+    0xB97C, 0xDCBF, 0xFDC9, 0xB93E, 0xB91F, 0xF98A, 0x98BF, 0xFB9A, 0xF989, 0xB9BF,
+    0xFB99, 0xF10A, 0xF31A, 0xF109, 0xF73A, 0xF319, 0xF739, 0xE21A, 0xE63A, 0xE219,
+    0xEE7A, 0xE639, 0xEE79, 0xC43A, 0xCC7A, 0xC439, 0xDCFA, 0xCC79, 0xDCF9, 0x887A,
+    0x98FA, 0x8879, 0xB9FA, 0x98F9, 0xB9F9, 0xFDC5, 0xB8BE, 0xB89F, 0xF985, 0xFB8D,
+    0xF105, 0xF30D, 0xF71D, 0xE20D, 0xE61D, 0xEE3D, 0xC41D, 0xCC3D, 0xDC7D, 0x883D,
+    0x987D, 0xB8FD, 0xB85F, 0xF0A8, 0xF856, 0xF0A4, 0xF853, 0xF0A2, 0xF0A1, 0xE168,
+    0xF0B6, 0xE164, 0xF0B3, 0xE162, 0xE161, 0xC2E8, 0xE176, 0xC2E4, 0xE173, 0xC2E2,
+    0xC2E1, 0x85E8, 0xC2F6, 0x85E4, 0xC2F3, 0x85E2, 0x85E1, 0x85F6, 0x85F3, 0xF8D4,
+    0xFC6B, 0x8D7E, 0xF8D2, 0x8D3F, 0xF8D1, 0xF094, 0xF84B, 0xF1B4, 0xF092, 0xF1B2,
+    0xF091, 0xF1B1, 0xE134, 0xF09B, 0xE374, 0xE132, 0xE372, 0xE131, 0xE371, 0xC274,
+    0xE13B, 0xC6F4, 0xC272, 0xC6F2, 0xC271, 0xC6F1, 0x84F4, 0xC27B, 0x8DF4, 0x84F2,
+    0x8DF2, 0x84F1, 0x8DF1, 0x84FB, 0x8DFB, 0xFCEA, 0x9D7C, 0xCEBF, 0xFCE9, 0x9D3E,
+    0x9D1F, 0xF8CA, 0x8CBF, 0xF9DA, 0xF8C9, 0x9DBF, 0xF9D9, 0xF08A, 0xF19A, 0xF089,
+    0xF3BA, 0xF199, 0xF3B9, 0xE11A, 0xE33A, 0xE119, 0xE77A, 0xE339, 0xE779, 0xC23A,
+    0xC67A, 0xC239, 0xCEFA, 0xC679, 0xCEF9, 0x847A, 0x8CFA, 0x8479, 0x9DFA, 0x8CF9,
+    0x9DF9, 0xBD78, 0xDEBE, 0xBD3C, 0xDE9F, 0xBD1E, 0xBD0F, 0xFCE5, 0x9CBE, 0xFDED,
+    0xBDBE, 0x9C9F, 0xBD9F, 0xF8C5, 0xF9CD, 0xFBDD, 0xF085, 0xF18D, 0xF39D, 0xF7BD,
+    0xE10D, 0xE31D, 0xE73D, 0xEF7D, 0xC21D, 0xC63D, 0xCE7D, 0xDEFD, 0x843D, 0x8C7D,
+    0x9CFD, 0xBCBC, 0xDE5F, 0xBC9E, 0xBC8F, 0x9C5F, 0xBCDF, 0xBC5E, 0xBC4F, 0xBC2F,
+    0xF054, 0xF052, 0xF051, 0xE0B4, 0xF05B, 0xE0B2, 0xE0B1, 0xC174, 0xE0BB, 0xC172,
+    0xC171, 0x82F4, 0xC17B, 0x82F2, 0x82F1, 0x82FB, 0xF86A, 0x86BF, 0xF869, 0xF04A,
+    0xF0DA, 0xF049, 0xF0D9, 0xE09A, 0xE1BA, 0xE099, 0xE1B9, 0xC13A, 0xC37A, 0xC139,
+    0xC379, 0x827A, 0x86FA, 0x8279, 0x86F9, 0xFC75, 0x8EBE, 0x8E9F, 0xF865, 0xF8ED,
+    0xF045, 0xF0CD, 0xF1DD, 0xE08D, 0xE19D, 0xE3BD, 0xC11D, 0xC33D, 0xC77D, 0x823D,
+    0x867D, 0x8EFD, 0x9EBC, 0xCF5F, 0x9E9E, 0x9E8F, 0x8E5F, 0x9EDF, 0xBEB8, 0xDF5E,
+    0xBE9C, 0xDF4F, 0xBE8E, 0xBE87, 0x9E5E, 0xBEDE, 0x9E4F, 0xBECF, 0xBE5C, 0xDF2F,
+    0xBE4E, 0xBE47, 0x9E2F, 0xBE6F, 0xBE2E, 0xBE27, 0xBE17, 0xE05A, 0xE059, 0xC0BA,
+    0xC0B9, 0x817A, 0x8179, 0xF06D, 0xE04D, 0xE0DD, 0xC09D, 0xC1BD, 0x813D, 0x837D,
+    0x875F, 0x8F5E, 0x8F4F, 0x9F5C, 0xCFAF, 0x9F4E, 0x9F47, 0x8F2F, 0x9F6F, 0xBF58,
+    0xDFAE, 0xBF4C, 0xDFA7, 0xBF46, 0xBF43, 0x9F2E, 0xBF6E, 0x9F27, 0xBF67, 0xBF2C,
+    0xDF97, 0xBF26, 0xBF23, 0x9F17, 0xBF37, 0xBF16, 0xBF13, 0x87AF, 0x8FAE, 0x8FA7,
+    0x9FAC, 0xCFD7, 0x9FA6, 0x9FA3, 0x8F97, 0x9FB7, 0x9F96, 0x9F93, 0xD5F0, 0xEAFC,
+    0xA9E0, 0xD4F8, 0xEA7E, 0xA8F0, 0xD47C, 0xEA3F, 0xA878, 0xD43E, 0xA83C, 0xFD68,
+    0xADF0, 0xD6FC, 0xFD64, 0xACF8, 0xD67E, 0xFD62, 0xAC7C, 0xD63F, 0xFD61, 0xAC3E,
+    0xFAE8, 0xFD76, 0xAEFC, 0xFAE4, 0xFD73, 0xAE7E, 0xFAE2, 0xAE3F, 0xFAE1, 0xF5E8,
+    0xFAF6, 0xF5E4, 0xFAF3, 0xF5E2, 0xF5E1, 0xEBE8, 0xF5F6, 0xEBE4, 0xF5F3, 0xEBE2,
+    0xEBE1, 0xD7E8, 0xEBF6, 0xD7E4, 0xEBF3, 0xD7E2, 0xA5E0, 0xD2F8, 0xE97E, 0xA4F0,
+    0xD27C, 0xE93F, 0xA478, 0xD23E, 0xA43C, 0xD21F, 0xA41E, 0xFD34, 0xA6F8, 0xD37E,
+    0xFD32, 0xA67C, 0xD33F, 0xFD31, 0xA63E, 0xA61F, 0xFA74, 0xFD3B, 0xA77E, 0xFA72,
+    0xA73F, 0xFA71, 0xF4F4, 0xFA7B, 0xF4F2, 0xF4F1, 0xE9F4, 0xF4FB, 0xE9F2, 0xE9F1,
+    0xD3F4, 0xE9FB, 0xD3F2, 0xD3F1, 0xA2F0, 0xD17C, 0xE8BF, 0xA278, 0xD13E, 0xA23C,
+    0xD11F, 0xA21E, 0xA20F, 0xFD1A, 0xA37C, 0xD1BF, 0xFD19, 0xA33E, 0xA31F, 0xFA3A,
+    0xA3BF, 0xFA39, 0xF47A, 0xF479, 0xE8FA, 0xE8F9, 0xD1FA, 0xD1F9, 0xA178, 0xD0BE,
+    0xA13C, 0xD09F, 0xA11E, 0xA10F, 0xFD0D, 0xA1BE, 0xA19F, 0xFA1D, 0xF43D, 0xE87D,
+    0xA0BC, 0xD05F, 0xA09E, 0xA08F, 0xA0DF, 0xA05E, 0xA04F, 0x95E0, 0xCAF8, 0xE57E,
+    0x94F0, 0xCA7C, 0xE53F, 0x9478, 0xCA3E, 0x943C, 0xCA1F, 0x941E, 0xFCB4, 0x96F8,
+    0xCB7E, 0xFCB2, 0x967C, 0xCB3F, 0xFCB1, 0x963E, 0x961F, 0xF974, 0xFCBB, 0x977E,
+    0xF972, 0x973F, 0xF971, 0xF2F4, 0xF97B, 0xF2F2, 0xF2F1, 0xE5F4, 0xF2FB, 0xE5F2,
+    0xE5F1, 0xCBF4, 0xE5FB, 0xCBF2, 0xCBF1, 0xDAF0, 0xED7C, 0xF6BF, 0xB4E0, 0xDA78,
+    0xED3E, 0xB470, 0xDA3C, 0xED1F, 0xB438, 0xDA1E, 0xB41C, 0xDA0F, 0xB40E, 0x92F0,
+    0xC97C, 0xE4BF, 0xB6F0, 0x9278, 0xC93E, 0xB678, 0xDB3E, 0xC91F, 0xB63C, 0x921E,
+    0xB61E, 0x920F, 0xB60F, 0xFC9A, 0x937C, 0xC9BF, 0xFDBA, 0xFC99, 0xB77C, 0x933E,
+    0xFDB9, 0xB73E, 0x931F, 0xB71F, 0xF93A, 0x93BF, 0xFB7A, 0xF939, 0xB7BF, 0xFB79,
+    0xF27A, 0xF6FA, 0xF279, 0xF6F9, 0xE4FA, 0xEDFA, 0xE4F9, 0xEDF9, 0xC9FA, 0xC9F9,
+    0xB2E0, 0xD978, 0xECBE, 0xB270, 0xD93C, 0xEC9F, 0xB238, 0xD91E, 0xB21C, 0xD90F,
+    0xB20E, 0xB207, 0x9178, 0xC8BE, 0xB378, 0x913C, 0xC89F, 0xB33C, 0xD99F, 0xB31E,
+    0x910F, 0xB30F, 0xFC8D, 0x91BE, 0xFD9D, 0xB3BE, 0x919F, 0xB39F, 0xF91D, 0xFB3D,
+    0xF23D, 0xF67D, 0xE47D, 0xECFD, 0xC8FD, 0xB170, 0xD8BC, 0xEC5F, 0xB138, 0xD89E,
+    0xB11C, 0xD88F, 0xB10E, 0xB107, 0x90BC, 0xC85F, 0xB1BC, 0x909E, 0xB19E, 0x908F,
+    0xB18F, 0x90DF, 0xB1DF, 0xB0B8, 0xD85E, 0xB09C, 0xD84F, 0xB08E, 0xB087, 0x905E,
+    0xB0DE, 0x904F, 0xB0CF, 0xB05C, 0xD82F, 0xB04E, 0xB047, 0x902F, 0xB06F, 0xB02E,
+    0xB027, 0x8AF0, 0xC57C, 0xE2BF, 0x8A78, 0xC53E, 0x8A3C, 0xC51F, 0x8A1E, 0x8A0F,
+    0xFC5A, 0x8B7C, 0xC5BF, 0xFC59, 0x8B3E, 0x8B1F, 0xF8BA, 0x8BBF, 0xF8B9, 0xF17A,
+    0xF179, 0xE2FA, 0xE2F9, 0xC5FA, 0xC5F9, 0x9AE0, 0xCD78, 0xE6BE, 0x9A70, 0xCD3C,
+    0xE69F, 0x9A38, 0xCD1E, 0x9A1C, 0xCD0F, 0x9A0E, 0x9A07, 0x8978, 0xC4BE, 0x9B78,
+    0x893C, 0xC49F, 0x9B3C, 0xCD9F, 0x9B1E, 0x890F, 0x9B0F, 0xFC4D, 0x89BE, 0xFCDD,
+    0x9BBE, 0x899F, 0x9B9F, 0xF89D, 0xF9BD, 0xF13D, 0xF37D, 0xE27D, 0xE6FD, 0xC4FD,
+    0xDD70, 0xEEBC, 0xF75F, 0xBA60, 0xDD38, 0xEE9E, 0xBA30, 0xDD1C, 0xEE8F, 0xBA18,
+    0xDD0E, 0xBA0C, 0xDD07, 0xBA06, 0x9970, 0xCCBC, 0xE65F, 0xBB70, 0x9938, 0xCC9E,
+    0xBB38, 0xDD9E, 0xCC8F, 0xBB1C, 0x990E, 0xBB0E, 0x9907, 0xBB07, 0x88BC, 0xC45F,
+    0x99BC, 0x889E, 0xBBBC, 0x999E, 0x888F, 0xBB9E, 0x998F, 0xBB8F, 0x88DF, 0x99DF,
+    0xBBDF, 0xB960, 0xDCB8, 0xEE5E, 0xB930, 0xDC9C, 0xEE4F, 0xB918, 0xDC8E, 0xB90C,
+    0xDC87, 0xB906, 0xB903, 0x98B8, 0xCC5E, 0xB9B8, 0x989C, 0xCC4F, 0xB99C, 0xDCCF,
+    0xB98E, 0x9887, 0xB987, 0x885E, 0x98DE, 0x884F, 0xB9DE, 0x98CF, 0xB9CF, 0xB8B0,
+    0xDC5C, 0xEE2F, 0xB898, 0xDC4E, 0xB88C, 0xDC47, 0xB886, 0xB883, 0x985C, 0xCC2F,
+    0xB8DC, 0x984E, 0xB8CE, 0x9847, 0xB8C7, 0x882F, 0x986F, 0xB8EF, 0xB858, 0xDC2E,
+    0xB84C, 0xDC27, 0xB846, 0xB843, 0x982E, 0xB86E, 0x9827, 0xB867, 0xB82C, 0xDC17,
+    0xB826, 0xB823, 0x9817, 0xB837, 0xB816, 0xB813, 0x8578, 0xC2BE, 0x853C, 0xC29F,
+    0x851E, 0x850F, 0x85BE, 0x859F, 0xF85D, 0xF0BD, 0xE17D, 0xC2FD, 0x8D70, 0xC6BC,
+    0xE35F, 0x8D38, 0xC69E, 0x8D1C, 0xC68F, 0x8D0E, 0x8D07, 0x84BC, 0xC25F, 0x8DBC,
+    0x849E, 0x8D9E, 0x848F, 0x8D8F, 0x84DF, 0x8DDF, 0x9D60, 0xCEB8, 0xE75E, 0x9D30,
+    0xCE9C, 0xE74F, 0x9D18, 0xCE8E, 0x9D0C, 0xCE87, 0x9D06, 0x9D03, 0x8CB8, 0xC65E,
+    0x9DB8, 0x8C9C, 0xC64F, 0x9D9C, 0x8C8E, 0x9D8E, 0x8C87, 0x9D87, 0x845E, 0x8CDE,
+    0x844F, 0x9DDE, 0x8CCF, 0x9DCF, 0xDEB0, 0xEF5C, 0xF7AF, 0xBD20, 0xDE98, 0xEF4E,
+    0xBD10, 0xDE8C, 0xEF47, 0xBD08, 0xDE86, 0xBD04, 0xDE83, 0xBD02, 0x9CB0, 0xCE5C,
+    0xE72F, 0xBDB0, 0x9C98, 0xCE4E, 0xBD98, 0xDECE, 0xCE47, 0xBD8C, 0x9C86, 0xBD86,
+    0x9C83, 0xBD83, 0x8C5C, 0xC62F, 0x9CDC, 0x8C4E, 0xBDDC, 0x9CCE, 0x8C47, 0xBDCE,
+    0x9CC7, 0xBDC7, 0x842F, 0x8C6F, 0x9CEF, 0xBDEF, 0xBCA0, 0xDE58, 0xEF2E, 0xBC90,
+    0xDE4C, 0xEF27, 0xBC88, 0xDE46, 0xBC84, 0xDE43, 0xBC82, 0xBC81, 0x9C58, 0xCE2E,
+    0xBCD8, 0x9C4C, 0xCE27, 0xBCCC, 0xDE67, 0xBCC6, 0x9C43, 0xBCC3, 0x8C2E, 0x9C6E,
+    0x8C27, 0xBCEE, 0x9C67, 0xBCE7, 0xBC50, 0xDE2C, 0xEF17, 0xBC48, 0xDE26, 0xBC44,
+    0xDE23, 0xBC42, 0xBC41, 0x9C2C, 0xCE17, 0xBC6C, 0x9C26, 0xBC66, 0x9C23, 0xBC63,
+    0x8C17, 0x9C37, 0xBC77, 0xBC28, 0xDE16, 0xBC24, 0xDE13, 0xBC22, 0xBC21, 0x9C16,
+    0xBC36, 0x9C13, 0xBC33, 0xBC14, 0xDE0B, 0xBC12, 0xBC11, 0x9C0B, 0xBC1B, 0x82BC,
+    0xC15F, 0x829E, 0x828F, 0x82DF, 0x86B8, 0xC35E, 0x869C, 0xC34F, 0x868E, 0x8687,
+    0x825E, 0x86DE, 0x824F, 0x86CF, 0x8EB0, 0xC75C, 0xE3AF, 0x8E98, 0xC74E, 0x8E8C,
+    0xC747, 0x8E86, 0x8E83, 0x865C, 0xC32F, 0x8EDC, 0x864E, 0x8ECE, 0x8647, 0x8EC7,
+    0x822F, 0x866F, 0x8EEF, 0x9EA0, 0xCF58, 0xE7AE, 0x9E90, 0xCF4C, 0xE7A7, 0x9E88,
+    0xCF46, 0x9E84, 0xCF43, 0x9E82, 0x9E81, 0x8E58, 0xC72E, 0x9ED8, 0x8E4C, 0xC727,
+    0x9ECC, 0xCF67, 0x9EC6, 0x8E43, 0x9EC3, 0x862E, 0x8E6E, 0x8627, 0x9EEE, 0x8E67,
+    0x9EE7, 0xDF50, 0xEFAC, 0xF7D7, 0xDF48, 0xEFA6, 0xDF44, 0xEFA3, 0xDF42, 0xDF41,
+    0x9E50, 0xCF2C, 0xE797, 0xBED0, 0x9E48, 0xCF26, 0xBEC8, 0xDF66, 0xCF23, 0xBEC4,
+    0x9E42, 0xBEC2, 0x9E41, 0xBEC1, 0x8E2C, 0xC717, 0x9E6C, 0x8E26, 0xBEEC, 0x9E66,
+    0x8E23, 0xBEE6, 0x9E63, 0xBEE3, 0x8617, 0x8E37, 0x9E77, 0xBEF7, 0xDF28, 0xEF96,
+    0xDF24, 0xEF93, 0xDF22, 0xDF21, 0x9E28, 0xCF16, 0xBE68, 0x9E24, 0xCF13, 0xBE64,
+    0xDF33, 0xBE62, 0x9E21, 0xBE61, 0x8E16, 0x9E36, 0x8E13, 0xBE76, 0x9E33, 0xBE73,
+    0xDF14, 0xEF8B, 0xDF12, 0xDF11, 0x9E14, 0xCF0B, 0xBE34, 0x9E12, 0xBE32, 0x9E11,
+    0xBE31, 0x8E0B, 0x9E1B, 0xBE3B, 0xDF0A, 0xDF09, 0x9E0A, 0xBE1A, 0x9E09, 0xBE19,
+    0x815E, 0x814F, 0x835C, 0xC1AF, 0x834E, 0x8347, 0x812F, 0x836F, 0x8758, 0xC3AE,
+    0x874C, 0xC3A7, 0x8746, 0x8743, 0x832E, 0x876E, 0x8327, 0x8767, 0x8F50, 0xC7AC,
+    0xE3D7, 0x8F48, 0xC7A6, 0x8F44, 0xC7A3, 0x8F42, 0x8F41, 0x872C, 0xC397, 0x8F6C,
+    0xC7B7, 0x8F66, 0x8723, 0x8F63, 0x8317, 0x8737, 0x8F77, 0xCFA8, 0xE7D6, 0xCFA4,
+    0xE7D3, 0xCFA2, 0xCFA1, 0x8F28, 0xC796, 0x9F68, 0xCFB6, 0xC793, 0x9F64, 0x8F22,
+    0x9F62, 0x8F21, 0x9F61, 0x8716, 0x8F36, 0x8713, 0x9F76, 0x8F33, 0x9F73, 0xEFD4,
+    0xF7EB, 0xEFD2, 0xEFD1, 0xCF94, 0xE7CB, 0xDFB4, 0xCF92, 0xDFB2, 0xCF91, 0xDFB1,
+    0x8F14, 0xC78B, 0x9F34, 0x8F12, 0xBF74, 0x9F32, 0x8F11, 0xBF72, 0x9F31, 0xBF71,
+    0x870B, 0x8F1B, 0x9F3B, 0xBF7B, 0xEFCA, 0xEFC9, 0xCF8A, 0xDF9A, 0xCF89, 0xDF99,
+    0x8F0A, 0x9F1A, 0x8F09, 0xBF3A, 0x9F19, 0xBF39, 0xEFC5, 0xCF85, 0xDF8D, 0x8F05,
+    0x9F0D, 0xBF1D, 0x81AE, 0x81A7, 0x83AC, 0xC1D7, 0x83A6, 0x83A3, 0x8197, 0x83B7,
+    0x87A8, 0xC3D6, 0x87A4, 0xC3D3, 0x87A2, 0x87A1, 0x8396, 0x87B6, 0x8393, 0x87B3,
+    0xC7D4, 0xE3EB, 0xC7D2, 0xC7D1, 0x8794, 0xC3CB, 0x8FB4, 0xC7DB, 0x8FB2, 0x8791,
+    0x8FB1, 0x838B, 0x879B, 0x8FBB, 0xE7EA, 0xE7E9, 0xC7CA, 0xCFDA, 0xC7C9, 0xCFD9,
+    0x878A, 0x8F9A, 0x8789, 0x9FBA, 0x8F99, 0x9FB9, 0xE7E5, 0xC7C5, 0xCFCD, 0x8785,
+    0x8F8D, 0x9F9D, 0x81D6, 0x81D3, 0x83D4, 0xC1EB, 0x83D2, 0x83D1, 0x81CB, 0x83DB,
+    0xC3EA, 0xC3E9, 0x83CA, 0x87DA, 0x83C9, 0x87D9, 0xE3F5
+};
+
+/* MicroPDF417 coefficients from ISO/IEC 24728:2006 Annex F */
+static const unsigned short int Microcoeffs[344] = {
+    /* k = 7 */
+    76, 925, 537, 597, 784, 691, 437,
+
+    /* k = 8 */
+    237, 308, 436, 284, 646, 653, 428, 379,
+
+    /* k = 9 */
+    567, 527, 622, 257, 289, 362, 501, 441, 205,
+
+    /* k = 10 */
+    377, 457, 64, 244, 826, 841, 818, 691, 266, 612,
+
+    /* k = 11 */
+    462, 45, 565, 708, 825, 213, 15, 68, 327, 602, 904,
+
+    /* k = 12 */
+    597, 864, 757, 201, 646, 684, 347, 127, 388, 7, 69, 851,
+
+    /* k = 13 */
+    764, 713, 342, 384, 606, 583, 322, 592, 678, 204, 184, 394, 692,
+
+    /* k = 14 */
+    669, 677, 154, 187, 241, 286, 274, 354, 478, 915, 691, 833, 105, 215,
+
+    /* k = 15 */
+    460, 829, 476, 109, 904, 664, 230, 5, 80, 74, 550, 575, 147, 868, 642,
+
+    /* k = 16 */
+    274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, 42, 176, 65,
+
+    /* k = 18 */
+    279, 577, 315, 624, 37, 855, 275, 739, 120, 297, 312, 202, 560, 321, 233, 756,
+    760, 573,
+
+    /* k = 21 */
+    108, 519, 781, 534, 129, 425, 681, 553, 422, 716, 763, 693, 624, 610, 310, 691,
+    347, 165, 193, 259, 568,
+
+    /* k = 26 */
+    443, 284, 887, 544, 788, 93, 477, 760, 331, 608, 269, 121, 159, 830, 446, 893,
+    699, 245, 441, 454, 325, 858, 131, 847, 764, 169,
+
+    /* k = 32 */
+    361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, 284, 193, 517,
+    273, 494, 263, 147, 593, 800, 571, 320, 803, 133, 231, 390, 685, 330, 63, 410,
+
+    /* k = 38 */
+    234, 228, 438, 848, 133, 703, 529, 721, 788, 322, 280, 159, 738, 586, 388, 684,
+    445, 680, 245, 595, 614, 233, 812, 32, 284, 658, 745, 229, 95, 689, 920, 771,
+    554, 289, 231, 125, 117, 518,
+
+    /* k = 44 */
+    476, 36, 659, 848, 678, 64, 764, 840, 157, 915, 470, 876, 109, 25, 632, 405,
+    417, 436, 714, 60, 376, 97, 413, 706, 446, 21, 3, 773, 569, 267, 272, 213,
+    31, 560, 231, 758, 103, 271, 572, 436, 339, 730, 82, 285,
+
+    /* k = 50 */
+    923, 797, 576, 875, 156, 706, 63, 81, 257, 874, 411, 416, 778, 50, 205, 303,
+    188, 535, 909, 155, 637, 230, 534, 96, 575, 102, 264, 233, 919, 593, 865, 26,
+    579, 623, 766, 146, 10, 739, 246, 127, 71, 244, 211, 477, 920, 876, 427, 820,
+    718, 435
+};
+
+/* rows, columns, error codewords, k-offset of valid MicroPDF417 sizes from ISO/IEC 24728:2006 */
+static const unsigned short int MicroVariants[170] ={
+    1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    11, 14, 17, 20, 24, 28, 8, 11, 14, 17, 20, 23, 26, 6, 8, 10, 12, 15, 20, 26, 32, 38, 44, 4, 6, 8, 10, 12, 15, 20, 26, 32, 38, 44,
+    7, 7, 7, 8, 8, 8, 8, 9, 9, 10, 11, 13, 15, 12, 14, 16, 18, 21, 26, 32, 38, 44, 50, 8, 12, 14, 16, 18, 21, 26, 32, 38, 44, 50,
+    0, 0, 0, 7, 7, 7, 7, 15, 15, 24, 34, 57, 84, 45, 70, 99, 115, 133, 154, 180, 212, 250, 294, 7, 45, 70, 99, 115, 133, 154, 180, 212, 250, 294
+};
+/* rows, columns, error codewords, k-offset */
+
+/* following is Left RAP, Centre RAP, Right RAP and Start Cluster from ISO/IEC 24728:2006 tables 10, 11 and 12 */
+static const char RAPTable[136] ={
+    1, 8, 36, 19, 9, 25, 1, 1, 8, 36, 19, 9, 27, 1, 7, 15, 25, 37, 1, 1, 21, 15, 1, 47, 1, 7, 15, 25, 37, 1, 1, 21, 15, 1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 7, 15, 25, 37, 17, 9, 29, 31, 25, 19, 1, 7, 15, 25, 37, 17, 9, 29, 31, 25,
+    9, 8, 36, 19, 17, 33, 1, 9, 8, 36, 19, 17, 35, 1, 7, 15, 25, 37, 33, 17, 37, 47, 49, 43, 1, 7, 15, 25, 37, 33, 17, 37, 47, 49,
+    0, 3, 6, 0, 6, 0, 0, 0, 3, 6, 0, 6, 6, 0, 0, 6, 0, 0, 0, 0, 6, 6, 0, 3, 0, 0, 6, 0, 0, 0, 0, 6, 6, 0
+};
+
+/* Left and Right Row Address Pattern from Table 2 */
+static const unsigned short int rap_side[52] = {
+    0x322, 0x3A2, 0x3B2, 0x332, 0x372, 0x37A, 0x33A, 0x3BA, 0x39A, 0x3DA,
+    0x3CA, 0x38A, 0x30A, 0x31A, 0x312, 0x392, 0x3D2, 0x3D6, 0x3D4, 0x394,
+    0x3B4, 0x3A4, 0x3A6, 0x3AE, 0x3AC, 0x3A8, 0x328, 0x32C, 0x32E, 0x326,
+    0x336, 0x3B6, 0x396, 0x316, 0x314, 0x334, 0x374, 0x364, 0x366, 0x36E,
+    0x36C, 0x368, 0x348, 0x358, 0x35C, 0x35E, 0x34E, 0x34C, 0x344, 0x346,
+    0x342, 0x362
+};
+
+/* Centre Row Address Pattern from Table 2 */
+static const unsigned short int rap_centre[52] = {
+    0x2CE, 0x24E, 0x26E, 0x22E, 0x226, 0x236, 0x216, 0x212, 0x21A, 0x23A,
+    0x232, 0x222, 0x262, 0x272, 0x27A, 0x2FA, 0x2F2, 0x2F6, 0x276, 0x274,
+    0x264, 0x266, 0x246, 0x242, 0x2C2, 0x2E2, 0x2E6, 0x2E4, 0x2EC, 0x26C,
+    0x22C, 0x228, 0x268, 0x2E8, 0x2C8, 0x2CC, 0x2C4, 0x2C6, 0x286, 0x28E,
+    0x28C, 0x29C, 0x298, 0x2B8, 0x2B0, 0x290, 0x2D0, 0x250, 0x258, 0x25C,
+    0x2DC, 0x2DE
+};
+
+void byteprocess(int *chainemc, int *mclength, unsigned char chaine[], int start, int length);
\ No newline at end of file
diff --git a/backend/plessey.c b/backend/plessey.c
new file mode 100644 (file)
index 0000000..dcc7eaf
--- /dev/null
@@ -0,0 +1,494 @@
+/* plessey.c - Handles Plessey and MSI Plessey */
+
+/*
+    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 : */
+
+#include <stdio.h>
+#include "common.h"
+
+#define SSET    "0123456789ABCDEF"
+
+static const char *PlessTable[16] = {
+    "13131313", "31131313", "13311313", "31311313", "13133113", "31133113",
+    "13313113", "31313113", "13131331", "31131331", "13311331", "31311331", "13133131",
+    "31133131", "13313131", "31313131"
+};
+
+static const char *MSITable[10] = {
+    "12121212", "12121221", "12122112", "12122121", "12211212", "12211221",
+    "12212112", "12212121", "21121212", "21121221"
+};
+
+/* Not MSI/Plessey but the older Plessey standard */
+INTERNAL int plessey(struct zint_symbol *symbol, unsigned char source[], const size_t length) {
+
+    unsigned int i;
+    unsigned char *checkptr;
+    static const char grid[9] = {1, 1, 1, 1, 0, 1, 0, 0, 1};
+    char dest[1024]; /* 8 + 65 * 8 + 8 * 2 + 9 + 1 ~ 1024 */
+    int error_number;
+
+    if (length > 65) {
+        strcpy(symbol->errtxt, "370: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    error_number = is_sane(SSET, source, length);
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "371: Invalid characters in data");
+        return error_number;
+    }
+    checkptr = (unsigned char *) calloc(1, length * 4 + 8);
+
+    /* Start character */
+    strcpy(dest, "31311331");
+
+    /* Data area */
+    for (i = 0; i < length; i++) {
+        unsigned int check = posn(SSET, source[i]);
+        lookup(SSET, PlessTable, source[i], dest);
+        checkptr[4 * i] = check & 1;
+        checkptr[4 * i + 1] = (check >> 1) & 1;
+        checkptr[4 * i + 2] = (check >> 2) & 1;
+        checkptr[4 * i + 3] = (check >> 3) & 1;
+    }
+
+    /* CRC check digit code adapted from code by Leonid A. Broukhis
+       used in GNU Barcode */
+
+    for (i = 0; i < (4 * length); i++) {
+        if (checkptr[i]) {
+            int j;
+            for (j = 0; j < 9; j++)
+                checkptr[i + j] ^= grid[j];
+        }
+    }
+
+    for (i = 0; i < 8; i++) {
+        switch (checkptr[length * 4 + i]) {
+            case 0: strcat(dest, "13");
+                break;
+            case 1: strcat(dest, "31");
+                break;
+        }
+    }
+
+    /* Stop character */
+    strcat(dest, "331311313");
+
+    expand(symbol, dest);
+    ustrcpy(symbol->text, source);
+    free(checkptr);
+    return error_number;
+}
+
+/* Plain MSI Plessey - does not calculate any check character */
+static int msi_plessey(struct zint_symbol *symbol, unsigned char source[], const int length) {
+
+    int i;
+    char dest[512]; /* 2 + 55 * 8 + 3 + 1 ~ 512 */
+
+    if (length > 55) {
+        strcpy(symbol->errtxt, "372: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    /* start character */
+    strcpy(dest, "21");
+
+    for (i = 0; i < length; i++) {
+        lookup(NEON, MSITable, source[i], dest);
+    }
+
+    /* Stop character */
+    strcat(dest, "121");
+
+    expand(symbol, dest);
+    ustrcpy(symbol->text, source);
+    return 0;
+}
+
+/* MSI Plessey with Modulo 10 check digit - algorithm from Barcode Island
+ * http://www.barcodeisland.com/ */
+static int msi_plessey_mod10(struct zint_symbol *symbol, unsigned char source[], int length) {
+
+    int i, wright, pump, n;
+    unsigned long dau, pedwar;
+    char un[200], tri[32];
+    int error_number, h;
+    char dest[1000];
+
+    error_number = 0;
+
+    if (length > 18) {
+        strcpy(symbol->errtxt, "373: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    /* start character */
+    strcpy(dest, "21");
+
+    /* draw data section */
+    for (i = 0; i < length; i++) {
+        lookup(NEON, MSITable, source[i], dest);
+    }
+
+    /* calculate check digit */
+    wright = 0;
+    n = !(length & 1);
+    for (i = n; i < length; i += 2) {
+        un[wright++] = source[i];
+    }
+    un[wright] = '\0';
+
+    dau = strtoul(un, NULL, 10);
+    dau *= 2;
+
+    sprintf(tri, "%lu", dau);
+
+    pedwar = 0;
+    h = strlen(tri);
+    for (i = 0; i < h; i++) {
+        pedwar += ctoi(tri[i]);
+    }
+
+    n = length & 1;
+    for (i = n; i < length; i += 2) {
+        pedwar += ctoi(source[i]);
+    }
+
+    pump = (10 - pedwar % 10);
+    if (pump == 10) {
+        pump = 0;
+    }
+
+    /* draw check digit */
+    lookup(NEON, MSITable, itoc(pump), dest);
+
+    /* Stop character */
+    strcat(dest, "121");
+    expand(symbol, dest);
+
+    ustrcpy(symbol->text, source);
+    symbol->text[length] = itoc(pump);
+    symbol->text[length + 1] = '\0';
+    return error_number;
+}
+
+/* MSI Plessey with two Modulo 10 check digits - algorithm from
+ * Barcode Island http://www.barcodeisland.com/ */
+static int msi_plessey_mod1010(struct zint_symbol *symbol, unsigned char source[], const int src_len) {
+
+    int i, n, wright, pump;
+    unsigned long dau, pedwar, chwech;
+    char un[16], tri[32];
+    int error_number, h;
+    char dest[1000];
+
+    error_number = 0;
+
+    if (src_len > 18) {
+        /* No Entry Stack Smashers! limit because of str->number conversion*/
+        strcpy(symbol->errtxt, "374: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    /* start character */
+    strcpy(dest, "21");
+
+    /* draw data section */
+    for (i = 0; i < src_len; i++) {
+        lookup(NEON, MSITable, source[i], dest);
+    }
+
+    /* calculate first check digit */
+    wright = 0;
+
+    n = !(src_len & 1);
+    for (i = n; i < src_len; i += 2) {
+        un[wright++] = source[i];
+    }
+    un[wright] = '\0';
+
+    dau = strtoul(un, NULL, 10);
+    dau *= 2;
+
+    sprintf(tri, "%lu", dau);
+
+    pedwar = 0;
+    h = strlen(tri);
+    for (i = 0; i < h; i++) {
+        pedwar += ctoi(tri[i]);
+    }
+
+    n = src_len & 1;
+    for (i = n; i < src_len; i += 2) {
+        pedwar += ctoi(source[i]);
+    }
+
+    pump = 10 - pedwar % 10;
+    if (pump == 10) {
+        pump = 0;
+    }
+
+    /* calculate second check digit */
+    wright = 0;
+    n = src_len & 1;
+    for (i = n; i < src_len; i += 2) {
+        un[wright++] = source[i];
+    }
+    un[wright++] = itoc(pump);
+    un[wright] = '\0';
+
+    dau = strtoul(un, NULL, 10);
+    dau *= 2;
+
+    sprintf(tri, "%lu", dau);
+
+    pedwar = 0;
+    h = strlen(tri);
+    for (i = 0; i < h; i++) {
+        pedwar += ctoi(tri[i]);
+    }
+
+
+    i = !(src_len & 1);
+    for (; i < src_len; i += 2) {
+        pedwar += ctoi(source[i]);
+    }
+
+    chwech = 10 - pedwar % 10;
+    if (chwech == 10) {
+        chwech = 0;
+    }
+
+    /* Draw check digits */
+    lookup(NEON, MSITable, itoc(pump), dest);
+    lookup(NEON, MSITable, itoc(chwech), dest);
+
+    /* Stop character */
+    strcat(dest, "121");
+
+    expand(symbol, dest);
+
+    ustrcpy(symbol->text, source);
+    symbol->text[src_len] = itoc(pump);
+    symbol->text[src_len + 1] = itoc(chwech);
+    symbol->text[src_len + 2] = '\0';
+
+    return error_number;
+}
+
+/* Calculate a Modulo 11 check digit using the system discussed on Wikipedia -
+    see http://en.wikipedia.org/wiki/Talk:MSI_Barcode */
+static int msi_plessey_mod11(struct zint_symbol *symbol, unsigned char source[], const int src_len) {
+    /* uses the IBM weight system */
+    int i, weight, check;
+    unsigned long x;
+    int error_number;
+    char dest[1000];
+
+    error_number = 0;
+
+    if (src_len > 55) {
+        strcpy(symbol->errtxt, "375: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    /* start character */
+    strcpy(dest, "21");
+
+    /* draw data section */
+    for (i = 0; i < src_len; i++) {
+        lookup(NEON, MSITable, source[i], dest);
+    }
+
+    /* calculate check digit */
+    x = 0;
+    weight = 2;
+    for (i = src_len - 1; i >= 0; i--) {
+        x += weight * ctoi(source[i]);
+        weight++;
+        if (weight > 7) {
+            weight = 2;
+        }
+    }
+
+    check = (11 - (x % 11)) % 11;
+    if (check == 10) {
+        lookup(NEON, MSITable, '1', dest);
+        lookup(NEON, MSITable, '0', dest);
+    } else {
+        lookup(NEON, MSITable, itoc(check), dest);
+    }
+
+    /* stop character */
+    strcat(dest, "121");
+
+    expand(symbol, dest);
+
+    ustrcpy(symbol->text, source);
+    if (check == 10) {
+        strcat((char*) symbol->text, "10");
+    } else {
+        symbol->text[src_len] = itoc(check);
+        symbol->text[src_len + 1] = '\0';
+    }
+
+    return error_number;
+}
+
+/* Combining the Barcode Island and Wikipedia code
+ * Verified against http://www.bokai.com/BarcodeJSP/applet/BarcodeSampleApplet.htm */
+static int msi_plessey_mod1110(struct zint_symbol *symbol, unsigned char source[], const int src_len) {
+    /* Weighted using the IBM system */
+    int i, weight, check, wright, pump;
+    unsigned long x, dau, pedwar;
+    int h;
+    int si;
+    char un[16], tri[16];
+    int error_number;
+    char dest[1000];
+    unsigned char temp[32];
+    int temp_len;
+
+    error_number = 0;
+
+    if (src_len > 18) {
+        strcpy(symbol->errtxt, "376: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    /* start character */
+    strcpy(dest, "21");
+
+    /* draw data section */
+    for (i = 0; i < src_len; i++) {
+        lookup(NEON, MSITable, source[i], dest);
+    }
+
+    /* calculate first (mod 11) digit */
+    x = 0;
+    weight = 2;
+    for (si = src_len - 1; si >= 0; si--) {
+        x += weight * ctoi(source[si]);
+        weight++;
+        if (weight > 7) {
+            weight = 2;
+        }
+    }
+
+    check = (11 - (x % 11)) % 11;
+    ustrcpy(temp, source);
+    temp_len = src_len;
+    if (check == 10) {
+        lookup(NEON, MSITable, '1', dest);
+        lookup(NEON, MSITable, '0', dest);
+        strcat((char*) temp, "10");
+        temp_len += 2;
+    } else {
+        lookup(NEON, MSITable, itoc(check), dest);
+        temp[temp_len++] = itoc(check);
+        temp[temp_len] = '\0';
+    }
+
+    /* calculate second (mod 10) check digit */
+    wright = 0;
+    i = !(temp_len & 1);
+    for (; i < temp_len; i += 2) {
+        un[wright++] = temp[i];
+    }
+    un[wright] = '\0';
+
+    dau = strtoul(un, NULL, 10);
+    dau *= 2;
+
+    sprintf(tri, "%lu", dau);
+
+    pedwar = 0;
+    h = strlen(tri);
+    for (i = 0; i < h; i++) {
+        pedwar += ctoi(tri[i]);
+    }
+
+    i = temp_len & 1;
+    for (; i < temp_len; i += 2) {
+        pedwar += ctoi(temp[i]);
+    }
+
+    pump = 10 - pedwar % 10;
+    if (pump == 10) {
+        pump = 0;
+    }
+
+    /* draw check digit */
+    lookup(NEON, MSITable, itoc(pump), dest);
+
+    /* stop character */
+    strcat(dest, "121");
+    expand(symbol, dest);
+
+    temp[temp_len++] = itoc(pump);
+    temp[temp_len] = '\0';
+
+
+    ustrcpy(symbol->text, temp);
+    return error_number;
+}
+
+INTERNAL int msi_handle(struct zint_symbol *symbol, unsigned char source[], int length) {
+    int error_number;
+
+    error_number = is_sane(NEON, source, length);
+    if (error_number != 0) {
+        strcpy(symbol->errtxt, "377: Invalid characters in input data");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+
+    if ((symbol->option_2 < 0) || (symbol->option_2 > 4)) {
+        symbol->option_2 = 0;
+    }
+
+    switch (symbol->option_2) {
+        case 0: error_number = msi_plessey(symbol, source, length);
+            break;
+        case 1: error_number = msi_plessey_mod10(symbol, source, length);
+            break;
+        case 2: error_number = msi_plessey_mod1010(symbol, source, length);
+            break;
+        case 3: error_number = msi_plessey_mod11(symbol, source, length);
+            break;
+        case 4: error_number = msi_plessey_mod1110(symbol, source, length);
+            break;
+    }
+
+    return error_number;
+}
index 085bbec..f2e41f1 100644 (file)
@@ -2,7 +2,7 @@
 
 /*
     libzint - the open source barcode library
-    Copyright (C) 2009 Robin Stuart <robin@zint.org.uk>
+    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
     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>
 #ifdef _MSC_VER
 #include <fcntl.h>
 #include <io.h>
+#include <malloc.h>
 #endif
 #include <stdlib.h>
 #include <string.h>
 #include "common.h"
 
-#ifdef _MSC_VER
-#include <malloc.h> 
-#endif /* _MSC_VER */
-
 #ifndef NO_PNG
-#include "png.h"        /* libpng header; includes zlib.h and setjmp.h */
-#endif /* NO_PNG */
-#include "maxipng.h"   /* Maxicode shapes */
-
-#include "font.h"      /* Font for human readable text */
+#include <png.h>
+#include <zlib.h>
+#include <setjmp.h>
 
 #define SSET   "0123456789ABCDEF"
 
-#define        PNG_DATA        100
-#define        BMP_DATA        200
-
-#ifndef NO_PNG
 struct mainprog_info_type {
     long width;
     long height;
@@ -63,1093 +55,178 @@ struct mainprog_info_type {
     jmp_buf jmpbuf;
 };
 
-static void writepng_error_handler(png_structp png_ptr, png_const_charp msg)
-{
-    struct mainprog_info_type  *graphic;
+static void writepng_error_handler(png_structp png_ptr, png_const_charp msg) {
+    struct mainprog_info_type *graphic;
 
-    fprintf(stderr, "writepng libpng error: %s\n", msg);
+    fprintf(stderr, "writepng libpng error: %s (F30)\n", msg);
     fflush(stderr);
 
-    graphic = (struct mainprog_info_type*)png_get_error_ptr(png_ptr);
-    if (graphic == NULL) {         /* we are completely hosed now */
+    graphic = (struct mainprog_info_type*) png_get_error_ptr(png_ptr);
+    if (graphic == NULL) {
+        /* we are completely hosed now */
         fprintf(stderr,
-          "writepng severe error:  jmpbuf not recoverable; terminating.\n");
+                "writepng severe error:  jmpbuf not recoverable; terminating. (F31)\n");
         fflush(stderr);
         return;
     }
     longjmp(graphic->jmpbuf, 1);
 }
 
-int png_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle)
-{
-       struct mainprog_info_type wpng_info;
-       struct mainprog_info_type *graphic;
-       
-#ifndef _MSC_VER
-       unsigned char outdata[image_width * 3];
-#else
-       unsigned char* outdata = (unsigned char*)_alloca(image_width * 3);
-#endif
-       png_structp  png_ptr;
-       png_infop  info_ptr;
-       graphic = &wpng_info;
-       unsigned char *image_data;
-       int i, row, column, err_no;
-       int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
-       
-       switch(rotate_angle) {
-               case 0:
-               case 180:
-                       graphic->width = image_width;
-                       graphic->height = image_height;
-                       break;
-               case 90:
-               case 270:
-                       graphic->width = image_height;
-                       graphic->height = image_width;
-                       break;
-       }
-       
-       /* sort out colour options */
-       to_upper((unsigned char*)symbol->fgcolour);
-       to_upper((unsigned char*)symbol->bgcolour);
-       
-       if(strlen(symbol->fgcolour) != 6) {
-               strcpy(symbol->errtxt, "Malformed foreground colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       if(strlen(symbol->bgcolour) != 6) {
-               strcpy(symbol->errtxt, "Malformed background colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       err_no = is_sane(SSET, (unsigned char*)symbol->fgcolour, strlen(symbol->fgcolour));
-       if (err_no == ERROR_INVALID_DATA) {
-               strcpy(symbol->errtxt, "Malformed foreground colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       err_no = is_sane(SSET, (unsigned char*)symbol->bgcolour, strlen(symbol->bgcolour));
-       if (err_no == ERROR_INVALID_DATA) {
-               strcpy(symbol->errtxt, "Malformed background colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       
-       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]);
-       
-       /* 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, "Can't open output file");
-                       return ERROR_FILE_ACCESS;
-               }
-#endif
-               graphic->outfile = stdout;
-       } else {
-               if (!(graphic->outfile = fopen(symbol->outfile, "wb"))) {
-                       strcpy(symbol->errtxt, "Can't open output file");
-                       return ERROR_FILE_ACCESS;
-               }
-       }
-       
-       /* Set up error handling routine as proc() above */
-       png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, graphic, writepng_error_handler, NULL);
-       if (!png_ptr) {
-               strcpy(symbol->errtxt, "Out of memory");
-               return ERROR_MEMORY;
-       }
-
-       info_ptr = png_create_info_struct(png_ptr);
-       if (!info_ptr) {
-               png_destroy_write_struct(&png_ptr, NULL);
-               strcpy(symbol->errtxt, "Out of memory");
-               return ERROR_MEMORY;
-       }
-
-       /* catch jumping here */
-       if (setjmp(graphic->jmpbuf)) {
-               png_destroy_write_struct(&png_ptr, &info_ptr);
-               strcpy(symbol->errtxt, "libpng error occurred");
-               return ERROR_MEMORY;
-       }
-
-       /* open output file with libpng */
-       png_init_io(png_ptr, graphic->outfile);
-
-       /* set compression */
-       png_set_compression_level(png_ptr,9);
-
-       /* set Header block */
-       png_set_IHDR(png_ptr, info_ptr, graphic->width, graphic->height,
-                    8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
-       PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
-
-       /* write all chunks up to (but not including) first IDAT */
-       png_write_info(png_ptr, info_ptr);
-
-       /* set up the transformations:  for now, just pack low-bit-depth pixels
-       into bytes (one, two or four pixels per byte) */
-       png_set_packing(png_ptr);
-
-       /* Pixel Plotting */
-
-       switch(rotate_angle) {
-               case 0: /* Plot the right way up */
-                       for(row = 0; row < image_height; row++) {
-                               for(column = 0; column < image_width; column++) {
-                                       i = column * 3;
-                                       switch(*(pixelbuf + (image_width * row) + column))
-                                       {
-                                               case '1':
-                                                       outdata[i] = fgred;
-                                                       outdata[i + 1] = fggrn;
-                                                       outdata[i + 2] = fgblu;
-                                                       break;
-                                               default:
-                                                       outdata[i] = bgred;
-                                                       outdata[i + 1] = bggrn;
-                                                       outdata[i + 2] = bgblu;
-                                                       break;
-                               
-                                       }
-                               }
-                               /* write row contents to file */
-                               image_data = outdata;
-                               png_write_row(png_ptr, image_data);
-                       }
-                       break;
-               case 90: /* Plot 90 degrees clockwise */
-                       for(row = 0; row < image_width; row++) {
-                               for(column = 0; column < image_height; column++) {
-                                       i = column * 3;
-                                       switch(*(pixelbuf + (image_width * (image_height - column - 1)) + row))
-                                       {
-                                               case '1':
-                                                       outdata[i] = fgred;
-                                                       outdata[i + 1] = fggrn;
-                                                       outdata[i + 2] = fgblu;
-                                                       break;
-                                               default:
-                                                       outdata[i] = bgred;
-                                                       outdata[i + 1] = bggrn;
-                                                       outdata[i + 2] = bgblu;
-                                                       break;
-                       
-                                       }
-                               }
-               
-                               /* write row contents to file */
-                               image_data = outdata;
-                               png_write_row(png_ptr, image_data);
-                       }
-                       break;
-               case 180: /* Plot upside down */
-                       for(row = 0; row < image_height; row++) {
-                               for(column = 0; column < image_width; column++) {
-                                       i = column * 3;
-                                       switch(*(pixelbuf + (image_width * (image_height - row - 1)) + (image_width - column - 1)))
-                                       {
-                                               case '1':
-                                                       outdata[i] = fgred;
-                                                       outdata[i + 1] = fggrn;
-                                                       outdata[i + 2] = fgblu;
-                                                       break;
-                                               default:
-                                                       outdata[i] = bgred;
-                                                       outdata[i + 1] = bggrn;
-                                                       outdata[i + 2] = bgblu;
-                                                       break;
-                       
-                                       }
-                               }
-               
-                               /* write row contents to file */
-                               image_data = outdata;
-                               png_write_row(png_ptr, image_data);
-                       }
-                       break;
-               case 270: /* Plot 90 degrees anti-clockwise */
-                       for(row = 0; row < image_width; row++) {
-                               for(column = 0; column < image_height; column++) {
-                                       i = column * 3;
-                                       switch(*(pixelbuf + (image_width * column) + (image_width - row - 1)))
-                                       {
-                                               case '1':
-                                                       outdata[i] = fgred;
-                                                       outdata[i + 1] = fggrn;
-                                                       outdata[i + 2] = fgblu;
-                                                       break;
-                                               default:
-                                                       outdata[i] = bgred;
-                                                       outdata[i + 1] = bggrn;
-                                                       outdata[i + 2] = bgblu;
-                                                       break;
-       
-                                       }
-                               }
-
-                               /* write row contents to file */
-                               image_data = outdata;
-                               png_write_row(png_ptr, image_data);
-                       }
-                       break;
-       }
-
-       /* End the file */
-       png_write_end(png_ptr, NULL);
-
-       /* make sure we have disengaged */
-       if (png_ptr && info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
-       fclose(wpng_info.outfile);
-       return 0;
-}
-#endif /* NO_PNG */
-
-int bmp_pixel_plot(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle)
-{
-       int i, row, column, err_no;
-       int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
-       
-       switch(rotate_angle) {
-               case 0:
-               case 180:
-                       symbol->bitmap_width = image_width;
-                       symbol->bitmap_height = image_height;
-                       break;
-               case 90:
-               case 270:                       
-                       symbol->bitmap_width = image_height;
-                       symbol->bitmap_height = image_width;
-                       break;
-       }
-       
-       if (symbol->bitmap != NULL)
-               free(symbol->bitmap);
-
-    symbol->bitmap = (char *) malloc(image_width * image_height * 3);
-
-       
-       /* sort out colour options */
-       to_upper((unsigned char*)symbol->fgcolour);
-       to_upper((unsigned char*)symbol->bgcolour);
-       
-       if(strlen(symbol->fgcolour) != 6) {
-               strcpy(symbol->errtxt, "Malformed foreground colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       if(strlen(symbol->bgcolour) != 6) {
-               strcpy(symbol->errtxt, "Malformed background colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       err_no = is_sane(SSET, (unsigned char*)symbol->fgcolour, strlen(symbol->fgcolour));
-       if (err_no == ERROR_INVALID_DATA) {
-               strcpy(symbol->errtxt, "Malformed foreground colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       err_no = is_sane(SSET, (unsigned char*)symbol->bgcolour, strlen(symbol->fgcolour));
-       if (err_no == ERROR_INVALID_DATA) {
-               strcpy(symbol->errtxt, "Malformed background colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       
-       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 */
-       i = 0;  
-       switch(rotate_angle) {
-               case 0: /* Plot the right way up */
-                       for(row = 0; row < image_height; row++) {
-                               for(column = 0; column < image_width; column++) {
-                                       switch(*(pixelbuf + (image_width * row) + column))
-                                       {
-                                               case '1':
-                                                       symbol->bitmap[i++] = fgred;
-                                                       symbol->bitmap[i++] = fggrn;
-                                                       symbol->bitmap[i++] = fgblu;
-                                                       break;
-                                               default:
-                                                       symbol->bitmap[i++] = bgred;
-                                                       symbol->bitmap[i++] = bggrn;
-                                                       symbol->bitmap[i++] = bgblu;
-                                                       break;
-                               
-                                       }
-                               }
-                       }
-                       break;
-               case 90: /* Plot 90 degrees clockwise */                        
-                       for(row = 0; row < image_width; row++) {
-                               for(column = 0; column < image_height; column++) {
-                                       switch(*(pixelbuf + (image_width * (image_height - column - 1)) + row))
-                                       {
-                                               case '1':
-                                                       symbol->bitmap[i++] = fgred;
-                                                       symbol->bitmap[i++] = fggrn;
-                                                       symbol->bitmap[i++] = fgblu;
-                                                       break;
-                                               default:
-                                                       symbol->bitmap[i++] = bgred;
-                                                       symbol->bitmap[i++] = bggrn;
-                                                       symbol->bitmap[i++] = bgblu;
-                                                       break;
-                       
-                                       }
-                               }
-                       }
-                       break;
-               case 180: /* Plot upside down */
-                       for(row = 0; row < image_height; row++) {
-                               for(column = 0; column < image_width; column++) {
-                                       switch(*(pixelbuf + (image_width * (image_height - row - 1)) + (image_width - column - 1)))
-                                       {
-                                               case '1':
-                                                       symbol->bitmap[i++] = fgred;
-                                                       symbol->bitmap[i++] = fggrn;
-                                                       symbol->bitmap[i++] = fgblu;
-                                                       break;
-                                               default:
-                                                       symbol->bitmap[i++] = bgred;
-                                                       symbol->bitmap[i++] = bggrn;
-                                                       symbol->bitmap[i++] = bgblu;
-                                                       break;
-                       
-                                       }
-                               }
-                       }
-                       break;
-               case 270: /* Plot 90 degrees anti-clockwise */
-                       for(row = 0; row < image_width; row++) {
-                               for(column = 0; column < image_height; column++) {
-                                       switch(*(pixelbuf + (image_width * column) + (image_width - row - 1)))
-                                       {
-                                               case '1':
-                                                       symbol->bitmap[i++] = fgred;
-                                                       symbol->bitmap[i++] = fggrn;
-                                                       symbol->bitmap[i++] = fgblu;
-                                                       break;
-                                               default:
-                                                       symbol->bitmap[i++] = bgred;
-                                                       symbol->bitmap[i++] = bggrn;
-                                                       symbol->bitmap[i++] = bgblu;
-                                                       break;
-       
-                                       }
-                               }
-                       }
-                       break;
-       }
-
-       return 0;
-}
-
-int png_to_file(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle, int image_type)
-{
-       int error_number;
-       float scaler = symbol->scale;
-       char *scaled_pixelbuf;
-       int horiz, vert;
-       int scale_width, scale_height;
-       
-       if(scaler == 0) { scaler = 0.5; }
-       scale_width = image_width * scaler;
-       scale_height = image_height * scaler;
-       
-       /* Apply scale options by creating another pixel buffer */
-       if ((scaled_pixelbuf = (char *) malloc(scale_width * scale_height)) == NULL) {
-               printf("Insufficient memory for pixel buffer");
-               return ERROR_ENCODING_PROBLEM;
-       }
-       memset(scaled_pixelbuf, '0', scale_width * scale_height);
-       
-       for(vert = 0; vert < scale_height; vert++) {
-               for(horiz = 0; horiz < scale_width; horiz++) {
-                       *(scaled_pixelbuf + (vert * scale_width) + horiz) = *(pixelbuf + ((int)(vert / scaler) * image_width) + (int)(horiz / scaler));
-               }
-       }
-       
-       if(image_type == PNG_DATA) {
-#ifndef NO_PNG
-               error_number = png_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle);
-#else
-               error_number = ERROR_INVALID_OPTION;
-#endif
-       } else {
-               error_number = bmp_pixel_plot(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle);
-       }
-       
-       free(scaled_pixelbuf);
-       
-       return error_number;
-}
-
-void draw_bar(char *pixelbuf, int xpos, int xlen, int ypos, int ylen, int image_width, int image_height)
-{
-       /* Draw a rectangle */
-       int i, j, png_ypos;
-       
-       png_ypos = image_height - ypos - ylen;
-       /* This fudge is needed because EPS measures height from the bottom up but
-       PNG measures y position from the top down */
-       
-       for(i = (xpos); i < (xpos + xlen); i++) {
-               for( j = (png_ypos); j < (png_ypos + ylen); j++) {
-                       *(pixelbuf + (image_width * j) + i) = '1';
-               }
-       }
-}
-
-int bullseye_pixel(int row, int col) {
-       int block_val, block_pos, return_val;
-       
-       block_val = bullseye_compressed[(row * 12) + (col / 8)];
-       return_val = 0;
-       block_pos = col % 8;
-       
-       switch(block_pos) {
-               case 0: if((block_val & 0x80) != 0) { return_val = 1; } break;
-               case 1: if((block_val & 0x40) != 0) { return_val = 1; } break;
-               case 2: if((block_val & 0x20) != 0) { return_val = 1; } break;
-               case 3: if((block_val & 0x10) != 0) { return_val = 1; } break;
-               case 4: if((block_val & 0x08) != 0) { return_val = 1; } break;
-               case 5: if((block_val & 0x04) != 0) { return_val = 1; } break;
-               case 6: if((block_val & 0x02) != 0) { return_val = 1; } break;
-               case 7: if((block_val & 0x01) != 0) { return_val = 1; } break;
-       }
-       
-       return return_val;
-}
-
-void draw_bullseye(char *pixelbuf, int image_width, int xoffset, int yoffset)
-{
-       /* Central bullseye in Maxicode symbols */
-       int i, j;
-       
-       for(j = 103; j < 196; j++) {
-               for(i = 0; i < 93; i++) {
-                       if(bullseye_pixel(j - 103, i)) {
-                       /* if(bullseye[(((j - 103) * 93) + i)] == 1) { */
-                               *(pixelbuf + (image_width * j) + (image_width * yoffset) + i + 99 + xoffset) = '1';
-                       }
-               }
-       }
-}
-
-void draw_hexagon(char *pixelbuf, int image_width, int xposn, int yposn)
-{
-       /* Put a hexagon into the pixel buffer */
-       int i, j;
-       
-       for(i = 0; i < 12; i++) {
-               for(j = 0; j < 10; j++) {
-                       if(hexagon[(i * 10) + j] == 1) {
-                               *(pixelbuf + (image_width * i) + (image_width * yposn) + xposn + j) = '1';
-                       }
-               }
-       }
-}
+INTERNAL int png_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) {
+    struct mainprog_info_type wpng_info;
+    struct mainprog_info_type *graphic;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    int i, row, column;
+    int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
 
-void draw_letter(char *pixelbuf, unsigned char letter, int xposn, int yposn, int smalltext, int image_width, int image_height)
-{
-       /* Put a letter into a position */
-       int skip, i, j, glyph_no, alphabet;
-       
-       skip = 0;
-       alphabet = 0;
-
-       if(letter < 33) { skip = 1; }
-       if((letter > 127) && (letter < 161)) { skip = 1; }
-       
-       if(skip == 0) {
-               if(letter > 128) {
-                       alphabet = 1;
-                       glyph_no = letter - 161;
-               } else {
-                       glyph_no = letter - 33;
-               }
-               
-               if(smalltext) {
-                       for(i = 0; i <= 8; i++) {
-                               for(j = 0; j < 5; j++) {
-                                       if(alphabet == 0) {
-                                               if(small_font[(glyph_no * 5) + (i * 475) + j - 1] == 1) {
-                                                       *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1';
-                                               }
-                                       } else {
-                                               if(small_font_extended[(glyph_no * 5) + (i * 475) + j - 1] == 1) {
-                                                       *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1';
-                                               }
-                                       }
-                               }
-                       }
-               } else {
-                       for(i = 0; i <= 13; i++) {
-                               for(j = 0; j < 7; j++) {
-                                       if(alphabet == 0) {
-                                               if(ascii_font[(glyph_no * 7) + (i * 665) + j - 1] == 1) {
-                                                       *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1';
-                                               }
-                                       } else {
-                                               if(ascii_ext_font[(glyph_no * 7) + (i * 665) + j - 1] == 1) {
-                                                       *(pixelbuf + (i * image_width) + (yposn * image_width) + xposn + j) = '1';
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-}
-
-void draw_string(char *pixbuf, char input_string[], int xposn, int yposn, int smalltext, int image_width, int image_height)
-{
-       /* Plot a string into the pixel buffer */
-       int i, string_length, string_left_hand;
-       
-       string_length = strlen(input_string);
-       string_left_hand = xposn - ((7 * string_length) / 2);
-       
-       for(i = 0; i < string_length; i++) {
-               draw_letter(pixbuf, input_string[i], string_left_hand + (i * 7), yposn, smalltext, image_width, image_height);
-       }
-       
-}
-
-int maxi_png_plot(struct zint_symbol *symbol, int rotate_angle, int data_type)
-{
-       int i, row, column, xposn, yposn;
-       int image_height, image_width;
-       char *pixelbuf;
-       int error_number;
-       int xoffset, yoffset;
-
-       xoffset = symbol->border_width + symbol->whitespace_width;
-       yoffset = symbol->border_width;
-       image_width = 300 + (2 * xoffset * 2);
-       image_height = 300 + (2 * yoffset * 2);
-       
-       if (!(pixelbuf = (char *) malloc(image_width * image_height))) {
-               printf("Insifficient memory for pixel buffer");
-               return ERROR_ENCODING_PROBLEM;
-       } else {
-               for(i = 0; i < (image_width * image_height); i++) {
-                       *(pixelbuf + i) = '0';
-               }
-       }
-       
-       draw_bullseye(pixelbuf, image_width, (2 * xoffset), (2 * yoffset));
-       
-       for(row = 0; row < symbol->rows; row++) {
-               yposn = row * 9;
-               for(column = 0; column < symbol->width; column++) {
-                       xposn = column * 10;
-                       if(module_is_set(symbol, row, column)) {
-                               if(row & 1) {
-                                       /* Odd (reduced) row */
-                                       xposn += 5;
-                                       draw_hexagon(pixelbuf, image_width, xposn + (2 * xoffset), yposn + (2 * yoffset));
-                               } else {
-                                       /* Even (full) row */
-                                       draw_hexagon(pixelbuf, image_width, xposn + (2 * xoffset), yposn + (2 * yoffset));
-                               }
-                       }
-               }
-       }
-
-       if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) {
-               /* boundary bars */
-               draw_bar(pixelbuf, 0, image_width, 0, symbol->border_width * 2, image_width, image_height);
-               draw_bar(pixelbuf, 0, image_width, 300 + (symbol->border_width * 2), symbol->border_width * 2, image_width, image_height);
-       }
-       
-       if((symbol->output_options & BARCODE_BOX) != 0) {
-               /* side bars */
-               draw_bar(pixelbuf, 0, symbol->border_width * 2, 0, image_height, image_width, image_height);
-               draw_bar(pixelbuf, 300 + ((symbol->border_width + symbol->whitespace_width + symbol->whitespace_width) * 2), symbol->border_width * 2, 0, image_height, image_width, image_height);
-       }
-       
-       error_number=png_to_file(symbol, image_height, image_width, pixelbuf, rotate_angle, data_type);
-       free(pixelbuf);
-       return error_number;
-}
-
-void to_latin1(unsigned char source[], unsigned char preprocessed[])
-{
-       int j, i, input_length;
-
-       input_length = ustrlen(source);
-
-       j = 0;
-       i = 0;
-       do {
-               if(source[i] < 128) {
-                       preprocessed[j] = source[i];
-                       j++;
-                       i++;
-               } else {
-                       if(source[i] == 0xC2) {
-                               preprocessed[j] = source[i + 1];
-                               j++;
-                               i += 2;
-                       }
-                       if(source[i] == 0xC3) {
-                               preprocessed[j] = source[i + 1] + 64;
-                               j++;
-                               i += 2;
-                       }
-               }
-       } while (i < input_length);
-       preprocessed[j] = '\0';
-
-       return;
-}
-
-int png_plot(struct zint_symbol *symbol, int rotate_angle, int data_type)
-{
-       int textdone, main_width, comp_offset, large_bar_count;
-       char textpart[10], addon[6];
-       float addon_text_posn, preset_height, large_bar_height;
-       int i, r, textoffset, yoffset, xoffset, latch, image_width, image_height;
-       char *pixelbuf = NULL;
-       int addon_latch = 0, smalltext = 0;
-       int this_row, block_width, plot_height, plot_yposn, textpos;
-       float row_height, row_posn;
-       int error_number;
-       int default_text_posn;
-       int next_yposn;
-       int tlen = ustrlen(symbol->text);
 #ifndef _MSC_VER
-       unsigned char local_text[tlen + 1];
+    unsigned char outdata[symbol->bitmap_width * 3];
 #else
-       unsigned char* local_text = (unsigned char*)_alloca(tlen+ 1);
+    unsigned char* outdata = (unsigned char*) _alloca(symbol->bitmap_width * 3);
 #endif
 
-       if(symbol->show_hrt != 0) {
-               to_latin1(symbol->text, local_text);
-       } else {
-               local_text[0] = '\0';
-       }
-
-       textdone = (symbol->show_hrt != 0) ? 0 : 1;
-       main_width = symbol->width;
-       strcpy(addon, "");
-       comp_offset = 0;
-       addon_text_posn = 0.0;
-       row_height = 0;
-       if(symbol->output_options & SMALL_TEXT) {
-               smalltext = 1;
-       }
-
-       if (symbol->height == 0) {
-               symbol->height = 50;
-       }
-       
-       large_bar_count = 0;
-       preset_height = 0.0;
-       for(i = 0; i < symbol->rows; i++) {
-               preset_height += symbol->row_height[i];
-               if(symbol->row_height[i] == 0) {
-                       large_bar_count++;
-               }
-       }
-
-       if (large_bar_count == 0) {
-               symbol->height = preset_height;
-               large_bar_height = 10;
-       } else {
-               large_bar_height = (symbol->height - preset_height) / large_bar_count;
-       }
-       
-       while(!(module_is_set(symbol, symbol->rows - 1, comp_offset))) {
-               comp_offset++;
-       }
-
-       /* Certain symbols need whitespace otherwise characters get chopped off the sides */
-       if ((((symbol->symbology == BARCODE_EANX) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_EANX_CC))
-               || (symbol->symbology == BARCODE_ISBNX)) {
-               switch(tlen) {
-                       case 13: /* EAN 13 */
-                       case 16:
-                       case 19:
-                               if(symbol->whitespace_width == 0) {
-                                       symbol->whitespace_width = 10;
-                               }
-                               main_width = 96 + comp_offset;
-                               break;
-                       default:
-                               main_width = 68 + comp_offset;
-               }
-       }
-       
-       if (((symbol->symbology == BARCODE_UPCA) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCA_CC)) {
-               if(symbol->whitespace_width == 0) {
-                       symbol->whitespace_width = 10;
-                       main_width = 96 + comp_offset;
-               }
-       }
-       
-       if (((symbol->symbology == BARCODE_UPCE) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCE_CC)) {
-               if(symbol->whitespace_width == 0) {
-                       symbol->whitespace_width = 10;
-                       main_width = 51 + comp_offset;
-               }
-       }
-       
-       latch = 0;
-       r = 0;
-       /* Isolate add-on text */
-       if(is_extendable(symbol->symbology)) {
-               for(i = 0; i < tlen; i++) {
-                       if (latch == 1) {
-                               addon[r] = local_text[i];
-                               r++;
-                       }
-                       if (symbol->text[i] == '+') {
-                               latch = 1;
-                       }
-               }
-       }
-       addon[r] = '\0';
-
-       if((symbol->show_hrt != 0) && tlen) {
-               textoffset = 9;
-       } else {
-               textoffset = 0;
-       }
-       xoffset = symbol->border_width + symbol->whitespace_width;
-       yoffset = symbol->border_width;
-       image_width = 2 * (symbol->width + xoffset + xoffset);
-       image_height = 2 * (symbol->height + textoffset + yoffset + yoffset);
-
-       if (!(pixelbuf = (char *) malloc(image_width * image_height))) {
-               printf("Insufficient memory for pixel buffer");
-               return ERROR_ENCODING_PROBLEM;
-       } else {
-               for(i = 0; i < (image_width * image_height); i++) {
-                       *(pixelbuf + i) = '0';
-               }
-       }
-
-       if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) {
-               default_text_posn = image_height - 17;
-       } else {
-               default_text_posn = image_height - 17 - symbol->border_width - symbol->border_width;
-       }
-
-       row_posn = textoffset + yoffset;
-       next_yposn = textoffset + yoffset;
-       row_height = 0;
+    graphic = &wpng_info;
 
-       /* Plot the body of the symbol to the pixel buffer */
-       for(r = 0; r < symbol->rows; r++) {
-               this_row = symbol->rows - r - 1; /* invert r otherwise plots upside down */
-               row_posn += row_height;
-               plot_yposn = next_yposn;
-               if(symbol->row_height[this_row] == 0) {
-                       row_height = large_bar_height;
-               } else {
-                       row_height = symbol->row_height[this_row];
-               }
-               next_yposn = (int)(row_posn + row_height);
-               plot_height = next_yposn - plot_yposn;
-               
-               i = 0;
-               if(module_is_set(symbol, this_row, 0)) {
-                       latch = 1;
-               } else {
-                       latch = 0;
-               }
-                       
-               do {
-                       block_width = 0;
-                       do {
-                               block_width++;
-                       } while (module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i));
-                       if((addon_latch == 0) && (r == 0) && (i > main_width)) {
-                               plot_height = (int)(row_height - 5.0);
-                               plot_yposn = (int)(row_posn - 5.0);
-                               addon_text_posn = row_posn + row_height - 8.0;
-                               addon_latch = 1;
-                       } 
-                       if(latch == 1) { 
-                               /* a bar */
-                               draw_bar(pixelbuf, (i + xoffset) * 2, block_width * 2, plot_yposn * 2, plot_height * 2, image_width, image_height);
-                               latch = 0;
-                       } else {
-                               /* a space */
-                               latch = 1;
-                       }
-                       i += block_width;
-                               
-               } while (i < symbol->width);
-       }
-       
-       xoffset += comp_offset;
+    graphic->width = symbol->bitmap_width;
+    graphic->height = symbol->bitmap_height;
 
-       if ((((symbol->symbology == BARCODE_EANX) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_EANX_CC)) || (symbol->symbology == BARCODE_ISBNX)) {
-               /* guard bar extensions and text formatting for EAN8 and EAN13 */
-               switch(tlen) {
-                       case 8: /* EAN-8 */
-                       case 11:
-                       case 14:
-                               draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               draw_bar(pixelbuf, (32 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               draw_bar(pixelbuf, (34 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               draw_bar(pixelbuf, (64 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               draw_bar(pixelbuf, (66 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
+    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]);
 
-                               if(symbol->show_hrt != 0) {
-                                       for(i = 0; i < 4; i++) {
-                                               textpart[i] = symbol->text[i];
-                                       }
-                                       textpart[4] = '\0';
-                                       textpos = 2 * (17 + xoffset);
-
-                                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                                       for(i = 0; i < 4; i++) {
-                                               textpart[i] = symbol->text[i + 4];
-                                       }
-                                       textpart[4] = '\0';
-                                       textpos = 2 * (50 + xoffset);
-                                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                                       textdone = 1;
-                                       switch(strlen(addon)) {
-                                               case 2:
-                                                       textpos = 2 * (xoffset + 86);
-                                                       draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height);
-                                                       break;
-                                               case 5:
-                                                       textpos = 2 * (xoffset + 100);
-                                                       draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height);
-                                                       break;
-                                       }
-                               }
-
-                               break;
-                       case 13: /* EAN 13 */
-                       case 16:
-                       case 19:
-                               draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               draw_bar(pixelbuf, (92 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               draw_bar(pixelbuf, (94 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-
-                               if (symbol->show_hrt != 0) {
-                                       textpart[0] = symbol->text[0];
-                                       textpart[1] = '\0';
-                                       textpos = 2 * (-7 + xoffset);
-                                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                                       for(i = 0; i < 6; i++) {
-                                               textpart[i] = symbol->text[i + 1];
-                                       }
-                                       textpart[6] = '\0';
-                                       textpos = 2 * (24 + xoffset);
-                                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                                       for(i = 0; i < 6; i++) {
-                                               textpart[i] = symbol->text[i + 7];
-                                       }
-                                       textpart[6] = '\0';
-                                       textpos = 2 * (71 + xoffset);
-                                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                                       textdone = 1;
-                                       switch(strlen(addon)) {
-                                               case 2:
-                                                       textpos = 2 * (xoffset + 114);
-                                                       draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height);
-                                                       break;
-                                               case 5:
-                                                       textpos = 2 * (xoffset + 128);
-                                                       draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height);
-                                                       break;
-                                       }
-                                       break;
-                               }
-
-               }
-       }
-
-       if (((symbol->symbology == BARCODE_UPCA) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCA_CC)) {
-               /* guard bar extensions and text formatting for UPCA */
-               latch = 1;
-
-               i = 0 + comp_offset;
-               do {
-                       block_width = 0;
-                       do {
-                               block_width++;
-                       } while (module_is_set(symbol, symbol->rows - 1, i + block_width) == module_is_set(symbol, symbol->rows - 1, i));
-                       if(latch == 1) {
-                               /* a bar */
-                               draw_bar(pixelbuf, (i + xoffset - comp_offset) * 2, block_width * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               latch = 0;
-                       } else {
-                               /* a space */
-                               latch = 1;
-                       }
-                       i += block_width;
-               } while (i < 11 + comp_offset);
-               draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-               draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-               latch = 1;
-               i = 85 + comp_offset;
-               do {
-                       block_width = 0;
-                       do {
-                               block_width++;
-                       } while (module_is_set(symbol, symbol->rows - 1, i + block_width) == module_is_set(symbol, symbol->rows - 1, i));
-                       if(latch == 1) {
-                               /* a bar */
-                               draw_bar(pixelbuf, (i + xoffset - comp_offset) * 2, block_width * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-                               latch = 0;
-                       } else {
-                               /* a space */
-                               latch = 1;
-                       }
-                       i += block_width;
-               } while (i < 96 + comp_offset);
-
-               if(symbol->show_hrt != 0) {
-                       textpart[0] = symbol->text[0];
-                       textpart[1] = '\0';
-                       textpos = 2 * (-5 + xoffset);
-                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                       for(i = 0; i < 5; i++) {
-                               textpart[i] = symbol->text[i + 1];
-                       }
-                       textpart[5] = '\0';
-                       textpos = 2 * (27 + xoffset);
-                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                       for(i = 0; i < 5; i++) {
-                               textpart[i] = symbol->text[i + 6];
-                       }
-                       textpart[6] = '\0';
-                       textpos = 2 * (68 + xoffset);
-                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                       textpart[0] = symbol->text[11];
-                       textpart[1] = '\0';
-                       textpos = 2 * (100 + xoffset);
-                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                       textdone = 1;
-                       switch(strlen(addon)) {
-                               case 2:
-                                       textpos = 2 * (xoffset + 116);
-                                       draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height);
-                                       break;
-                               case 5:
-                                       textpos = 2 * (xoffset + 130);
-                                       draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height);
-                                       break;
-                       }
-               }
-       }
-
-       if (((symbol->symbology == BARCODE_UPCE) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCE_CC)) {
-               /* guard bar extensions and text formatting for UPCE */
-               draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-               draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-               draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-               draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
-               draw_bar(pixelbuf, (50 + xoffset) * 2, 1 * 2, (4 + (int)yoffset) * 2, 5 * 2, image_width, image_height);
+    /* Open output file in binary mode */
+    if (symbol->output_options & BARCODE_STDOUT) {
+#ifdef _MSC_VER
+        if (-1 == _setmode(_fileno(stdout), _O_BINARY)) {
+            strcpy(symbol->errtxt, "631: Can't open output file");
+            return ZINT_ERROR_FILE_ACCESS;
+        }
+#endif
+        graphic->outfile = stdout;
+    } else {
+        if (!(graphic->outfile = fopen(symbol->outfile, "wb"))) {
+            strcpy(symbol->errtxt, "632: Can't open output file");
+            return ZINT_ERROR_FILE_ACCESS;
+        }
+    }
 
-               if (symbol->show_hrt != 0) {
-                       textpart[0] = symbol->text[0];
-                       textpart[1] = '\0';
-                       textpos = 2 * (-5 + xoffset);
-                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                       for(i = 0; i < 6; i++) {
-                               textpart[i] = symbol->text[i + 1];
-                       }
-                       textpart[6] = '\0';
-                       textpos = 2 * (24 + xoffset);
-                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                       textpart[0] = symbol->text[7];
-                       textpart[1] = '\0';
-                       textpos = 2 * (55 + xoffset);
-                       draw_string(pixelbuf, textpart, textpos, default_text_posn, smalltext, image_width, image_height);
-                       textdone = 1;
-                       switch(strlen(addon)) {
-                               case 2:
-                                       textpos = 2 * (xoffset + 70);
-                                       draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height);
-                                       break;
-                               case 5:
-                                       textpos = 2 * (xoffset + 84);
-                                       draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, smalltext, image_width, image_height);
-                                       break;
-                       }
-               }
+    /* Set up error handling routine as proc() above */
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, graphic, writepng_error_handler, NULL);
+    if (!png_ptr) {
+        strcpy(symbol->errtxt, "633: Out of memory");
+        return ZINT_ERROR_MEMORY;
+    }
 
-       }
+    info_ptr = png_create_info_struct(png_ptr);
+    if (!info_ptr) {
+        png_destroy_write_struct(&png_ptr, NULL);
+        strcpy(symbol->errtxt, "634: Out of memory");
+        return ZINT_ERROR_MEMORY;
+    }
 
-       xoffset -= comp_offset;
+    /* catch jumping here */
+    if (setjmp(graphic->jmpbuf)) {
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+        strcpy(symbol->errtxt, "635: libpng error occurred");
+        return ZINT_ERROR_MEMORY;
+    }
 
-       /* Put boundary bars or box around symbol */
-       if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) {
-               /* boundary bars */
-               draw_bar(pixelbuf, 0, (symbol->width + xoffset + xoffset) * 2, textoffset * 2, symbol->border_width * 2, image_width, image_height);
-               draw_bar(pixelbuf, 0, (symbol->width + xoffset + xoffset) * 2, (textoffset + symbol->height + symbol->border_width) * 2, symbol->border_width * 2, image_width, image_height);
-               if((symbol->output_options & BARCODE_BIND) != 0) {
-                       if((symbol->rows > 1) && (is_stackable(symbol->symbology) == 1)) {
-                               /* row binding */
-                               for(r = 1; r < symbol->rows; r++) {
-                                       draw_bar(pixelbuf, xoffset * 2, symbol->width * 2, ((r * row_height) + textoffset + yoffset - 1) * 2, 2 * 2, image_width, image_height);
-                               }
-                       }
-               }
-       }
-       
-       if((symbol->output_options & BARCODE_BOX) != 0) {
-               /* side bars */
-               draw_bar(pixelbuf, 0, symbol->border_width * 2, textoffset * 2, (symbol->height + (2 * symbol->border_width)) * 2, image_width, image_height);
-               draw_bar(pixelbuf, (symbol->width + xoffset + xoffset - symbol->border_width) * 2, symbol->border_width * 2, textoffset * 2, (symbol->height + (2 * symbol->border_width)) * 2, image_width, image_height);
-       }
-       
-       /* Put the human readable text at the bottom */
-       if((textdone == 0) && tlen) {
-               textpos = (image_width / 2);
-               draw_string(pixelbuf, (char*)local_text, textpos, default_text_posn, smalltext, image_width, image_height);
-       }
+    /* open output file with libpng */
+    png_init_io(png_ptr, graphic->outfile);
+
+    /* set compression */
+    png_set_compression_level(png_ptr, 9);
+
+    /* set Header block */
+    png_set_IHDR(png_ptr, info_ptr, graphic->width, graphic->height,
+            8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+            PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+    /* write all chunks up to (but not including) first IDAT */
+    png_write_info(png_ptr, info_ptr);
+
+    /* set up the transformations:  for now, just pack low-bit-depth pixels
+    into bytes (one, two or four pixels per byte) */
+    png_set_packing(png_ptr);
+
+    /* Pixel Plotting */
+    for (row = 0; row < symbol->bitmap_height; row++) {
+        unsigned char *image_data;
+        for (column = 0; column < symbol->bitmap_width; column++) {
+            i = column * 3;
+            switch (*(pixelbuf + (symbol->bitmap_width * row) + column)) {
+                case 'W': // White
+                    outdata[i] = 255;
+                    outdata[i + 1] = 255;
+                    outdata[i + 2] = 255;
+                    break;
+                case 'C': // Cyan
+                    outdata[i] = 0;
+                    outdata[i + 1] = 255;
+                    outdata[i + 2] = 255;
+                    break;
+                case 'B': // Blue
+                    outdata[i] = 0;
+                    outdata[i + 1] = 0;
+                    outdata[i + 2] = 255;
+                    break;
+                case 'M': // Magenta
+                    outdata[i] = 255;
+                    outdata[i + 1] = 0;
+                    outdata[i + 2] = 255;
+                    break;
+                case 'R': // Red
+                    outdata[i] = 255;
+                    outdata[i + 1] = 0;
+                    outdata[i + 2] = 0;
+                    break;
+                case 'Y': // Yellow
+                    outdata[i] = 255;
+                    outdata[i + 1] = 255;
+                    outdata[i + 2] = 0;
+                    break;
+                case 'G': // Green
+                    outdata[i] = 0;
+                    outdata[i + 1] = 255;
+                    outdata[i + 2] = 0;
+                    break;
+                case 'K': // Black
+                    outdata[i] = 0;
+                    outdata[i + 1] = 0;
+                    outdata[i + 2] = 0;
+                    break;
+                case '1':
+                    outdata[i] = fgred;
+                    outdata[i + 1] = fggrn;
+                    outdata[i + 2] = fgblu;
+                    break;
+                default:
+                    outdata[i] = bgred;
+                    outdata[i + 1] = bggrn;
+                    outdata[i + 2] = bgblu;
+                    break;
+
+            }
+        }
+        /* write row contents to file */
+        image_data = outdata;
+        png_write_row(png_ptr, image_data);
+    }
 
-       error_number=png_to_file(symbol, image_height, image_width, pixelbuf, rotate_angle, data_type);
-       free(pixelbuf);
-       return error_number;
-}
+    /* End the file */
+    png_write_end(png_ptr, NULL);
 
-#ifndef NO_PNG
-int png_handle(struct zint_symbol *symbol, int rotate_angle)
-{
-       int error;
-       
-       if(symbol->symbology == BARCODE_MAXICODE) {
-               error = maxi_png_plot(symbol, rotate_angle, PNG_DATA);
-       } else {
-               error = png_plot(symbol, rotate_angle, PNG_DATA);
-       }
-       
-       return error;
+    /* make sure we have disengaged */
+    if (png_ptr && info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
+    if (symbol->output_options & BARCODE_STDOUT) {
+        fflush(wpng_info.outfile);
+    } else {
+        fclose(wpng_info.outfile);
+    }
+    return 0;
 }
 #endif /* NO_PNG */
-
-int bmp_handle(struct zint_symbol *symbol, int rotate_angle)
-{
-       int error;
-       
-       if(symbol->symbology == BARCODE_MAXICODE) {
-               error = maxi_png_plot(symbol, rotate_angle, BMP_DATA);
-       } else {
-               error = png_plot(symbol, rotate_angle, BMP_DATA);
-       }
-       
-       return error;
-}
-
diff --git a/backend/postal.c b/backend/postal.c
new file mode 100644 (file)
index 0000000..b90743d
--- /dev/null
@@ -0,0 +1,596 @@
+/* postal.c - Handles PostNet, PLANET, FIM. RM4SCC and Flattermarken */
+
+/*
+    libzint - the open source barcode library
+    Copyright (C) 2008 - 2020 Robin Stuart <rstuart114@gmail.com>
+    Including bug fixes by Bryan Hatton
+
+    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>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+
+#define DAFTSET "DAFT"
+#define KRSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define KASUTSET "1234567890-abcdefgh"
+#define CHKASUTSET "0123456789-abcdefgh"
+#define SHKASUTSET "1234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+/* PostNet number encoding table - In this table L is long as S is short */
+static const char *PNTable[10] = {
+    "LLSSS", "SSSLL", "SSLSL", "SSLLS", "SLSSL", "SLSLS", "SLLSS", "LSSSL",
+    "LSSLS", "LSLSS"
+};
+
+static const char *PLTable[10] = {
+    "SSLLL", "LLLSS", "LLSLS", "LLSSL", "LSLLS", "LSLSL", "LSSLL", "SLLLS",
+    "SLLSL", "SLSLL"
+};
+
+static const char *RoyalValues[36] = {
+    "11", "12", "13", "14", "15", "10", "21", "22", "23", "24", "25",
+    "20", "31", "32", "33", "34", "35", "30", "41", "42", "43", "44", "45", "40", "51", "52",
+    "53", "54", "55", "50", "01", "02", "03", "04", "05", "00"
+};
+
+/* 0 = Full, 1 = Ascender, 2 = Descender, 3 = Tracker */
+static const char *RoyalTable[36] = {
+    "3300", "3210", "3201", "2310", "2301", "2211", "3120", "3030", "3021",
+    "2130", "2121", "2031", "3102", "3012", "3003", "2112", "2103", "2013", "1320", "1230",
+    "1221", "0330", "0321", "0231", "1302", "1212", "1203", "0312", "0303", "0213", "1122",
+    "1032", "1023", "0132", "0123", "0033"
+};
+
+static const char *FlatTable[10] = {
+    "0504", "18", "0117", "0216", "0315", "0414", "0513", "0612", "0711", "0810"
+};
+
+static const char *KoreaTable[10] = {
+    "1313150613", "0713131313", "0417131313", "1506131313",
+    "0413171313", "17171313", "1315061313", "0413131713", "17131713", "13171713"
+};
+
+static const char *JapanTable[19] = {
+    "114", "132", "312", "123", "141", "321", "213", "231", "411", "144",
+    "414", "324", "342", "234", "432", "243", "423", "441", "111"
+};
+
+/* Handles the PostNet system used for Zip codes in the US */
+static int postnet(struct zint_symbol *symbol, unsigned char source[], char dest[], int length) {
+    int i, sum, check_digit;
+    int error_number;
+
+    if (length != 5 && length != 9 && length != 11) {
+        strcpy(symbol->errtxt, "480: 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, "481: Invalid characters in data");
+        return error_number;
+    }
+    sum = 0;
+
+    /* start character */
+    strcpy(dest, "L");
+
+    for (i = 0; i < length; i++) {
+        lookup(NEON, PNTable, source[i], dest);
+        sum += ctoi(source[i]);
+    }
+
+    check_digit = (10 - (sum % 10)) % 10;
+    strcat(dest, PNTable[check_digit]);
+
+    /* stop character */
+    strcat(dest, "L");
+
+    return error_number;
+}
+
+/* Puts PostNet barcodes into the pattern matrix */
+INTERNAL int post_plot(struct zint_symbol *symbol, unsigned char source[], int length) {
+    char height_pattern[256]; /* 5 + 38 * 5 + 5 + 5 +  1 ~ 256 */
+    unsigned int loopey, h;
+    int writer;
+    int error_number;
+
+    error_number = postnet(symbol, source, height_pattern, length);
+    if (error_number != 0) {
+        return error_number;
+    }
+
+    writer = 0;
+    h = strlen(height_pattern);
+    for (loopey = 0; loopey < h; loopey++) {
+        if (height_pattern[loopey] == 'L') {
+            set_module(symbol, 0, writer);
+        }
+        set_module(symbol, 1, writer);
+        writer += 3;
+    }
+    symbol->row_height[0] = 6;
+    symbol->row_height[1] = 6;
+    symbol->rows = 2;
+    symbol->width = writer - 1;
+
+    return error_number;
+}
+
+/* Handles the PLANET  system used for item tracking in the US */
+static int planet(struct zint_symbol *symbol, unsigned char source[], char dest[], int length) {
+    int i, sum, check_digit;
+    int error_number;
+
+    if (length != 11 && length != 13) {
+        strcpy(symbol->errtxt, "482: 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, "483: Invalid characters in data");
+        return error_number;
+    }
+    sum = 0;
+
+    /* start character */
+    strcpy(dest, "L");
+
+    for (i = 0; i < length; i++) {
+        lookup(NEON, PLTable, source[i], dest);
+        sum += ctoi(source[i]);
+    }
+
+    check_digit = (10 - (sum % 10)) % 10;
+    strcat(dest, PLTable[check_digit]);
+
+    /* stop character */
+    strcat(dest, "L");
+
+    return error_number;
+}
+
+/* Puts PLANET barcodes into the pattern matrix */
+INTERNAL int planet_plot(struct zint_symbol *symbol, unsigned char source[], int length) {
+    char height_pattern[256]; /* 5 + 38 * 5 + 5 + 5 +  1 ~ 256 */
+    unsigned int loopey, h;
+    int writer;
+    int error_number;
+
+    error_number = planet(symbol, source, height_pattern, length);
+    if (error_number != 0) {
+        return error_number;
+    }
+
+    writer = 0;
+    h = strlen(height_pattern);
+    for (loopey = 0; loopey < h; loopey++) {
+        if (height_pattern[loopey] == 'L') {
+            set_module(symbol, 0, writer);
+        }
+        set_module(symbol, 1, writer);
+        writer += 3;
+    }
+    symbol->row_height[0] = 6;
+    symbol->row_height[1] = 6;
+    symbol->rows = 2;
+    symbol->width = writer - 1;
+    return error_number;
+}
+
+/* Korean Postal Authority */
+INTERNAL int korea_post(struct zint_symbol *symbol, unsigned char source[], int length) {
+    int total, loop, check, zeroes, error_number;
+    char localstr[8], dest[80];
+
+    if (length > 6) {
+        strcpy(symbol->errtxt, "484: 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, "485: Invalid characters in data");
+        return error_number;
+    }
+    zeroes = 6 - length;
+    memset(localstr, '0', zeroes);
+    strcpy(localstr + zeroes, (char *) source);
+
+    total = 0;
+    for (loop = 0; loop < 6; loop++) {
+        total += ctoi(localstr[loop]);
+    }
+    check = 10 - (total % 10);
+    if (check == 10) {
+        check = 0;
+    }
+    localstr[6] = itoc(check);
+    localstr[7] = '\0';
+    *dest = '\0';
+    for (loop = 5; loop >= 0; loop--) {
+        lookup(NEON, KoreaTable, localstr[loop], dest);
+    }
+    lookup(NEON, KoreaTable, localstr[6], dest);
+    expand(symbol, dest);
+    ustrcpy(symbol->text, (unsigned char*) localstr);
+    return error_number;
+}
+
+/* The simplest barcode symbology ever! Supported by MS Word, so here it is!
+    glyphs from http://en.wikipedia.org/wiki/Facing_Identification_Mark */
+INTERNAL int fim(struct zint_symbol *symbol, unsigned char source[], int length) {
+
+    char dest[16] = {0};
+
+    if (length > 1) {
+        strcpy(symbol->errtxt, "486: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    switch ((char) source[0]) {
+        case 'a':
+        case 'A':
+            strcpy(dest, "111515111");
+            break;
+        case 'b':
+        case 'B':
+            strcpy(dest, "13111311131");
+            break;
+        case 'c':
+        case 'C':
+            strcpy(dest, "11131313111");
+            break;
+        case 'd':
+        case 'D':
+            strcpy(dest, "1111131311111");
+            break;
+        default:
+            strcpy(symbol->errtxt, "487: Invalid characters in data");
+            return ZINT_ERROR_INVALID_DATA;
+            break;
+    }
+
+    expand(symbol, dest);
+    return 0;
+}
+
+/* Handles the 4 State barcodes used in the UK by Royal Mail */
+static char rm4scc(char source[], unsigned char dest[], int length) {
+    int i;
+    int top, bottom, row, column, check_digit;
+    char values[3], set_copy[] = KRSET;
+
+    top = 0;
+    bottom = 0;
+
+    /* start character */
+    strcpy((char*) dest, "1");
+
+    for (i = 0; i < length; i++) {
+        lookup(KRSET, RoyalTable, source[i], (char*) dest);
+        strcpy(values, RoyalValues[posn(KRSET, source[i])]);
+        top += ctoi(values[0]);
+        bottom += ctoi(values[1]);
+    }
+
+    /* Calculate the check digit */
+    row = (top % 6) - 1;
+    column = (bottom % 6) - 1;
+    if (row == -1) {
+        row = 5;
+    }
+    if (column == -1) {
+        column = 5;
+    }
+    check_digit = (6 * row) + column;
+    strcat((char*) dest, RoyalTable[check_digit]);
+
+    /* stop character */
+    strcat((char*) dest, "0");
+
+    return set_copy[check_digit];
+}
+
+/* Puts RM4SCC into the data matrix */
+INTERNAL int royal_plot(struct zint_symbol *symbol, unsigned char source[], int length) {
+    char height_pattern[210];
+    int loopey, h;
+    int writer;
+    int error_number;
+    strcpy(height_pattern, "");
+
+    if (length > 50) {
+        strcpy(symbol->errtxt, "488: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    to_upper(source);
+    error_number = is_sane(KRSET, source, length);
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "489: Invalid characters in data");
+        return error_number;
+    }
+    /*check = */rm4scc((char*) source, (unsigned char*) height_pattern, length);
+
+    writer = 0;
+    h = strlen(height_pattern);
+    for (loopey = 0; loopey < h; loopey++) {
+        if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '0')) {
+            set_module(symbol, 0, writer);
+        }
+        set_module(symbol, 1, writer);
+        if ((height_pattern[loopey] == '2') || (height_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;
+}
+
+/* Handles Dutch Post TNT KIX symbols
+   The same as RM4SCC but without check digit
+   Specification at http://www.tntpost.nl/zakelijk/klantenservice/downloads/kIX_code/download.aspx */
+INTERNAL int kix_code(struct zint_symbol *symbol, unsigned char source[], int length) {
+    char height_pattern[75], localstr[20];
+    int loopey;
+    int writer, i, h;
+    int error_number;
+    strcpy(height_pattern, "");
+
+    if (length > 18) {
+        strcpy(symbol->errtxt, "490: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    to_upper(source);
+    error_number = is_sane(KRSET, source, length);
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "491: Invalid characters in data");
+        return error_number;
+    }
+
+    strcpy(localstr, (char *) source);
+
+    /* Encode data */
+    for (i = 0; i < length; i++) {
+        lookup(KRSET, RoyalTable, localstr[i], height_pattern);
+    }
+
+    writer = 0;
+    h = strlen(height_pattern);
+    for (loopey = 0; loopey < h; loopey++) {
+        if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '0')) {
+            set_module(symbol, 0, writer);
+        }
+        set_module(symbol, 1, writer);
+        if ((height_pattern[loopey] == '2') || (height_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;
+}
+
+/* Handles DAFT Code symbols */
+INTERNAL int daft_code(struct zint_symbol *symbol, unsigned char source[], int length) {
+    char height_pattern[100];
+    unsigned int loopey, h;
+    int writer, i, error_number;
+    strcpy(height_pattern, "");
+
+    if (length > 50) {
+        strcpy(symbol->errtxt, "492: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    to_upper((unsigned char*) source);
+    error_number = is_sane(DAFTSET, (unsigned char*) source, length);
+
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "493: Invalid characters in data");
+        return error_number;
+    }
+
+    for (i = 0; i < length; i++) {
+        if (source[i] == 'D') {
+            strcat(height_pattern, "2");
+        }
+        if (source[i] == 'A') {
+            strcat(height_pattern, "1");
+        }
+        if (source[i] == 'F') {
+            strcat(height_pattern, "0");
+        }
+        if (source[i] == 'T') {
+            strcat(height_pattern, "3");
+        }
+    }
+
+    writer = 0;
+    h = strlen(height_pattern);
+    for (loopey = 0; loopey < h; loopey++) {
+        if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '0')) {
+            set_module(symbol, 0, writer);
+        }
+        set_module(symbol, 1, writer);
+        if ((height_pattern[loopey] == '2') || (height_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;
+}
+
+/* Flattermarken - Not really a barcode symbology! */
+INTERNAL int flattermarken(struct zint_symbol *symbol, unsigned char source[], int length) {
+    int loop, error_number;
+    char dest[512]; /* 90 * 4 + 1 ~ */
+
+    if (length > 90) {
+        strcpy(symbol->errtxt, "494: 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, "495: Invalid characters in data");
+        return error_number;
+    }
+    *dest = '\0';
+    for (loop = 0; loop < length; loop++) {
+        lookup(NEON, FlatTable, source[loop], dest);
+    }
+
+    expand(symbol, dest);
+    return error_number;
+}
+
+/* Japanese Postal Code (Kasutama Barcode) */
+INTERNAL int japan_post(struct zint_symbol *symbol, unsigned char source[], int length) {
+    int error_number, h;
+    char pattern[69];
+    int writer, loopey, inter_posn, i, sum, check;
+    char check_char;
+    char inter[23];
+
+#ifndef _MSC_VER
+    char local_source[length + 1];
+#else
+    char* local_source = (char*) _alloca(length + 1);
+#endif
+
+    if (length > 20) {
+        strcpy(symbol->errtxt, "496: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    error_number = 0;
+
+    strcpy(local_source, (char*) source);
+    to_upper((unsigned char*) local_source);
+
+    if (is_sane(SHKASUTSET, (unsigned char*) local_source, length) == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "497: Invalid characters in data");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+    memset(inter, 'd', 20); /* Pad character CC4 */
+    inter[20] = '\0';
+
+    i = 0;
+    inter_posn = 0;
+    do {
+        if (((local_source[i] >= '0') && (local_source[i] <= '9')) || (local_source[i] == '-')) {
+            inter[inter_posn] = local_source[i];
+            inter_posn++;
+        } else {
+            if ((local_source[i] >= 'A') && (local_source[i] <= 'J')) {
+                inter[inter_posn] = 'a';
+                inter[inter_posn + 1] = local_source[i] - 'A' + '0';
+                inter_posn += 2;
+            }
+            if ((local_source[i] >= 'K') && (local_source[i] <= 'T')) {
+                inter[inter_posn] = 'b';
+                inter[inter_posn + 1] = local_source[i] - 'K' + '0';
+                inter_posn += 2;
+            }
+            if ((local_source[i] >= 'U') && (local_source[i] <= 'Z')) {
+                inter[inter_posn] = 'c';
+                inter[inter_posn + 1] = local_source[i] - 'U' + '0';
+                inter_posn += 2;
+            }
+        }
+        i++;
+    } while ((i < length) && (inter_posn < 20));
+    inter[20] = '\0';
+
+    strcpy(pattern, "13"); /* Start */
+
+    sum = 0;
+    for (i = 0; i < 20; i++) {
+        strcat(pattern, JapanTable[posn(KASUTSET, inter[i])]);
+        sum += posn(CHKASUTSET, inter[i]);
+    }
+
+    /* Calculate check digit */
+    check = 19 - (sum % 19);
+    if (check == 19) {
+        check = 0;
+    }
+    if (check <= 9) {
+        check_char = check + '0';
+    } else if (check == 10) {
+        check_char = '-';
+    } else {
+        check_char = (check - 11) + 'a';
+    }
+    strcat(pattern, JapanTable[posn(KASUTSET, check_char)]);
+
+    strcat(pattern, "31"); /* Stop */
+
+    /* Resolve pattern to 4-state symbols */
+    writer = 0;
+    h = strlen(pattern);
+    for (loopey = 0; loopey < h; loopey++) {
+        if ((pattern[loopey] == '2') || (pattern[loopey] == '1')) {
+            set_module(symbol, 0, writer);
+        }
+        set_module(symbol, 1, writer);
+        if ((pattern[loopey] == '3') || (pattern[loopey] == '1')) {
+            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;
+}
index 771d186..31a2f39 100644 (file)
@@ -2,7 +2,7 @@
 
 /*
     libzint - the open source barcode library
-    Copyright (C) 2009 Robin Stuart <robin@zint.org.uk>
+    Copyright (C) 2009-2018 Robin Stuart <rstuart114@gmail.com>
 
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
     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 <locale.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <math.h>
 #include "common.h"
 
-#define SSET   "0123456789ABCDEF"
-
-/* This file has expanded quite a bit since version 1.5 in order to accomodate
-   the formatting rules for EAN and UPC symbols as set out in EN 797:1995 - the
-   down side of this support is that the code is now vertually unreadable! */
-
-int ps_plot(struct zint_symbol *symbol)
-{
-       int i, block_width, latch, r, this_row;
-       float textpos, large_bar_height, preset_height, row_height, row_posn;
-       FILE *feps;
-       int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
-       float red_ink, green_ink, blue_ink, red_paper, green_paper, blue_paper;
-       int error_number = 0;
-       int textoffset, xoffset, yoffset, textdone, main_width;
-       char textpart[10], addon[6];
-       int large_bar_count, comp_offset;
-       float addon_text_posn;
-       float scaler = symbol->scale;
-       float default_text_posn;
-       int plot_text = 1;
-       const char *locale = NULL;
-       
-       row_height=0;
-       textdone = 0;
-       main_width = symbol->width;
-       strcpy(addon, "");
-       comp_offset = 0;
-       addon_text_posn = 0.0;
-
-       if((symbol->output_options & BARCODE_STDOUT) != 0) {
-               feps = stdout;
-       } else {
-               feps = fopen(symbol->outfile, "w");
-       }
-       if(feps == NULL) {
-               strcpy(symbol->errtxt, "Could not open output file");
-               return ERROR_FILE_ACCESS;
-       }
-
-       /* sort out colour options */
-       to_upper((unsigned char*)symbol->fgcolour);
-       to_upper((unsigned char*)symbol->bgcolour);
-       
-       if(strlen(symbol->fgcolour) != 6) {
-               strcpy(symbol->errtxt, "Malformed foreground colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       if(strlen(symbol->bgcolour) != 6) {
-               strcpy(symbol->errtxt, "Malformed background colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       error_number = is_sane(SSET, (unsigned char*)symbol->fgcolour, strlen(symbol->fgcolour));
-       if (error_number == ERROR_INVALID_DATA) {
-               strcpy(symbol->errtxt, "Malformed foreground colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       error_number = is_sane(SSET, (unsigned char*)symbol->bgcolour, strlen(symbol->bgcolour));
-       if (error_number == ERROR_INVALID_DATA) {
-               strcpy(symbol->errtxt, "Malformed background colour target");
-               return ERROR_INVALID_OPTION;
-       }
-       locale = setlocale(LC_ALL, "C");
-       
-       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]);
-       red_ink = fgred / 256.0;
-       green_ink = fggrn / 256.0;
-       blue_ink = fgblu / 256.0;
-       red_paper = bgred / 256.0;
-       green_paper = bggrn / 256.0;
-       blue_paper = bgblu / 256.0;
-       
-       if (symbol->height == 0) {
-               symbol->height = 50;
-       }
-       
-       large_bar_count = 0;
-       preset_height = 0.0;
-       for(i = 0; i < symbol->rows; i++) {
-               preset_height += symbol->row_height[i];
-               if(symbol->row_height[i] == 0) {
-                       large_bar_count++;
-               }
-       }
-       large_bar_height = (symbol->height - preset_height) / large_bar_count;
-
-       if (large_bar_count == 0) {
-               symbol->height = preset_height;
-       }
-       
-       while(!(module_is_set(symbol, symbol->rows - 1, comp_offset))) {
-               comp_offset++;
-       }
-
-       /* Certain symbols need whitespace otherwise characters get chopped off the sides */
-       if ((((symbol->symbology == BARCODE_EANX) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_EANX_CC))
-               || (symbol->symbology == BARCODE_ISBNX)) {
-               switch(ustrlen(symbol->text)) {
-                       case 13: /* EAN 13 */
-                       case 16:
-                       case 19:
-                               if(symbol->whitespace_width == 0) {
-                                       symbol->whitespace_width = 10;
-                               }
-                               main_width = 96 + comp_offset;
-                               break;
-                       default:
-                               main_width = 68 + comp_offset;
-               }
-       }
-       
-       if (((symbol->symbology == BARCODE_UPCA) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCA_CC)) {
-               if(symbol->whitespace_width == 0) {
-                       symbol->whitespace_width = 10;
-                       main_width = 96 + comp_offset;
-               }
-       }
-       
-       if (((symbol->symbology == BARCODE_UPCE) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCE_CC)) {
-               if(symbol->whitespace_width == 0) {
-                       symbol->whitespace_width = 10;
-                       main_width = 51 + comp_offset;
-               }
-       }
-       
-       latch = 0;
-       r = 0;
-       /* Isolate add-on text */
-       if(is_extendable(symbol->symbology)) {
-               for(i = 0; i < ustrlen(symbol->text); i++) {
-                       if (latch == 1) {
-                               addon[r] = symbol->text[i];
-                               r++;
-                       }
-                       if (symbol->text[i] == '+') {
-                               latch = 1;
-                       }
-               }
-       }
-       addon[r] = '\0';
-
-       if((symbol->show_hrt == 0) || (ustrlen(symbol->text) == 0)) {
-               plot_text = 0;
-               textdone = 1;
-       }
-       if(plot_text) {
-               textoffset = 9;
-       } else {
-               textoffset = 0;
-       }
-       xoffset = symbol->border_width + symbol->whitespace_width;
-       yoffset = symbol->border_width;
-
-       /* Start writing the header */
-       fprintf(feps, "%%!PS-Adobe-3.0 EPSF-3.0\n");
-       fprintf(feps, "%%%%Creator: Zint %s\n", ZINT_VERSION);
-       if(ustrlen(symbol->text) != 0) {
-               fprintf(feps, "%%%%Title: %s\n",symbol->text);
-       } else {
-               fprintf(feps, "%%%%Title: Zint Generated Symbol\n");
-       }
-       fprintf(feps, "%%%%Pages: 0\n");
-       if(symbol->symbology != BARCODE_MAXICODE) {
-               fprintf(feps, "%%%%BoundingBox: 0 0 %d %d\n", roundup((symbol->width + xoffset + xoffset) * scaler), roundup((symbol->height + textoffset + yoffset + yoffset) * scaler));
-       } else {
-               fprintf(feps, "%%%%BoundingBox: 0 0 %d %d\n", roundup((74.0 + xoffset + xoffset) * scaler), roundup((72.0 + yoffset + yoffset) * scaler));
-       }
-       fprintf(feps, "%%%%EndComments\n");
-       
-       /* Definitions */
-       fprintf(feps, "/TL { setlinewidth moveto lineto stroke } bind def\n");
-       fprintf(feps, "/TC { moveto 0 360 arc 360 0 arcn fill } bind def\n");
-       fprintf(feps, "/TH { 0 setlinewidth moveto lineto lineto lineto lineto lineto closepath fill } bind def\n");
-       fprintf(feps, "/TB { 2 copy } bind def\n");
-       fprintf(feps, "/TR { newpath 4 1 roll exch moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill } bind def\n");
-       fprintf(feps, "/TE { pop pop } bind def\n");
-       
-       fprintf(feps, "newpath\n");
-       
-       /* Now the actual representation */
-       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_paper, green_paper, blue_paper);
-       fprintf(feps, "%.2f 0.00 TB 0.00 %.2f TR\n", (symbol->height + textoffset + yoffset + yoffset) * scaler, (symbol->width + xoffset + xoffset) * scaler);
-       
-       if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) {
-               default_text_posn = 0.5 * scaler;
-       } else {
-               default_text_posn = (symbol->border_width + 0.5) * scaler;
-       }
-
-       if(symbol->symbology == BARCODE_MAXICODE) {
-               /* Maxicode uses hexagons */
-               float ax, ay, bx, by, cx, cy, dx, dy, ex, ey, fx, fy, mx, my;
-               
-                               
-               textoffset = 0.0;
-               if (((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) {
-                       fprintf(feps, "TE\n");
-                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                       fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", symbol->border_width * scaler, textoffset * scaler, 0.0, (74.0 + xoffset + xoffset) * scaler);
-                       fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", symbol->border_width * scaler, (textoffset + 72.0 + symbol->border_width) * scaler, 0.0, (74.0 + xoffset + xoffset) * scaler);
-               }
-               if((symbol->output_options & BARCODE_BOX) != 0) {
-                       /* side bars */
-                       fprintf(feps, "TE\n");
-                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                       fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", (72.0 + (2 * symbol->border_width)) * scaler, textoffset * scaler, 0.0, symbol->border_width * scaler);
-                       fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", (72.0 + (2 * symbol->border_width)) * scaler, textoffset * scaler, (74.0 + xoffset + xoffset - symbol->border_width) * scaler, symbol->border_width * scaler);
-               }
-               
-               fprintf(feps, "TE\n");
-               fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-               fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-               fprintf(feps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f TC\n", (35.76 + xoffset) * scaler, (35.60 + yoffset) * scaler, 10.85 * scaler, (35.76 + xoffset) * scaler, (35.60 + yoffset) * scaler, 8.97 * scaler, (44.73 + xoffset) * scaler, (35.60 + yoffset) * scaler);
-               fprintf(feps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f TC\n", (35.76 + xoffset) * scaler, (35.60 + yoffset) * scaler, 7.10 * scaler, (35.76 + xoffset) * scaler, (35.60 + yoffset) * scaler, 5.22 * scaler, (40.98 + xoffset) * scaler, (35.60 + yoffset) * scaler);
-               fprintf(feps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f TC\n", (35.76 + xoffset) * scaler, (35.60 + yoffset) * scaler, 3.31 * scaler, (35.76 + xoffset) * scaler, (35.60 + yoffset) * scaler, 1.43 * scaler, (37.19 + xoffset) * scaler, (35.60 + yoffset) * scaler);
-               for(r = 0; r < symbol->rows; r++) {
-                       for(i = 0; i < symbol->width; i++) {
-                               if(module_is_set(symbol, r, i)) {
-                                       /* Dump a hexagon */
-                                       my = ((symbol->rows - r - 1)) * 2.135 + 1.43;
-                                       ay = my + 1.0 + yoffset;
-                                       by = my + 0.5 + yoffset;
-                                       cy = my - 0.5 + yoffset;
-                                       dy = my - 1.0 + yoffset;
-                                       ey = my - 0.5 + yoffset;
-                                       fy = my + 0.5 + yoffset;
-
-                                       mx = 2.46 * i + 1.23 + (r & 1 ? 1.23 : 0);
-
-                                       ax = mx + xoffset;
-                                       bx = mx + 0.86 + xoffset;
-                                       cx = mx + 0.86 + xoffset;
-                                       dx = mx + xoffset;
-                                       ex = mx - 0.86 + xoffset;
-                                       fx = mx - 0.86 + xoffset;
-                                       fprintf(feps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f TH\n", ax * scaler, ay * scaler, bx * scaler, by * scaler, cx * scaler, cy * scaler, dx * scaler, dy * scaler, ex * scaler, ey * scaler, fx * scaler, fy * scaler);
-                               }
-                       }
-               }
-       }
-
-       if(symbol->symbology != BARCODE_MAXICODE) {
-               /* everything else uses rectangles (or squares) */
-               /* Works from the bottom of the symbol up */
-               int addon_latch = 0;
-
-               for(r = 0; r < symbol->rows; r++) {
-                       this_row = symbol->rows - r - 1; /* invert r otherwise plots upside down */
-                       if(symbol->row_height[this_row] == 0) {
-                               row_height = large_bar_height;
-                       } else {
-                               row_height = symbol->row_height[this_row];
-                       }
-                       row_posn = 0;
-                       for(i = 0; i < r; i++) {
-                               if(symbol->row_height[symbol->rows - i - 1] == 0) {
-                                       row_posn += large_bar_height;
-                               } else {
-                                       row_posn += symbol->row_height[symbol->rows - i - 1];
-                               }
-                       }
-                       row_posn += (textoffset + yoffset);
-
-                       fprintf(feps, "TE\n");
-                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                       fprintf(feps, "%.2f %.2f ", row_height * scaler, row_posn * scaler);
-                       i = 0;
-                       if(module_is_set(symbol, this_row, 0)) {
-                               latch = 1;
-                       } else {
-                               latch = 0;
-                       }
-                       
-                       do {
-                               block_width = 0;
-                               do {
-                                       block_width++;
-                               } while (module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i));
-                               if((addon_latch == 0) && (r == 0) && (i > main_width)) {
-                                       fprintf(feps, "TE\n");
-                                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                                       fprintf(feps, "%.2f %.2f ", (row_height - 5.0) * scaler, (row_posn - 5.0) * scaler);
-                                       addon_text_posn = row_posn + row_height - 8.0;
-                                       addon_latch = 1;
-                               }
-                               if(latch == 1) {
-                                       /* a bar */
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (i + xoffset) * scaler, block_width * scaler);
-                                       latch = 0;
-                               } else {
-                                       /* a space */
-                                       latch = 1;
-                               }
-                               i += block_width;
-
-                       } while (i < symbol->width);
-               }
-       }
-       /* That's done the actual data area, everything else is human-friendly */
-
-       xoffset += comp_offset;
-
-       if (plot_text) {
-               if ((((symbol->symbology == BARCODE_EANX) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_EANX_CC)) ||
-                       (symbol->symbology == BARCODE_ISBNX)) {
-                       /* guard bar extensions and text formatting for EAN8 and EAN13 */
-                       switch(ustrlen(symbol->text)) {
-                               case 8: /* EAN-8 */
-                               case 11:
-                               case 14:
-                                       fprintf(feps, "TE\n");
-                                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                                       fprintf(feps, "%.2f %.2f ", 5.0 * scaler, (4.0 + yoffset) * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (0 + xoffset) * scaler, 1 * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (2 + xoffset) * scaler, 1 * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (32 + xoffset) * scaler, 1 * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (34 + xoffset) * scaler, 1 * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (64 + xoffset) * scaler, 1 * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (66 + xoffset) * scaler, 1 * scaler);
-                                       for(i = 0; i < 4; i++) {
-                                               textpart[i] = symbol->text[i];
-                                       }
-                                       textpart[4] = '\0';
-                                       fprintf(feps, "TE\n");
-                                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                                       fprintf(feps, "matrix currentmatrix\n");
-                                       fprintf(feps, "/Helvetica findfont\n");
-                                       fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                       textpos = 17;
-                                       fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                                       fprintf(feps, " (%s) stringwidth\n", textpart);
-                                       fprintf(feps, "pop\n");
-                                       fprintf(feps, "-2 div 0 rmoveto\n");
-                                       fprintf(feps, " (%s) show\n", textpart);
-                                       fprintf(feps, "setmatrix\n");
-                                       for(i = 0; i < 4; i++) {
-                                               textpart[i] = symbol->text[i + 4];
-                                       }
-                                       textpart[4] = '\0';
-                                       fprintf(feps, "matrix currentmatrix\n");
-                                       fprintf(feps, "/Helvetica findfont\n");
-                                       fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                       textpos = 50;
-                                       fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                                       fprintf(feps, " (%s) stringwidth\n", textpart);
-                                       fprintf(feps, "pop\n");
-                                       fprintf(feps, "-2 div 0 rmoveto\n");
-                                       fprintf(feps, " (%s) show\n", textpart);
-                                       fprintf(feps, "setmatrix\n");
-                                       textdone = 1;
-                                       switch(strlen(addon)) {
-                                               case 2: 
-                                                       fprintf(feps, "matrix currentmatrix\n");
-                                                       fprintf(feps, "/Helvetica findfont\n");
-                                                       fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                                       textpos = xoffset + 86;
-                                                       fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", textpos * scaler, addon_text_posn * scaler);
-                                                       fprintf(feps, " (%s) stringwidth\n", addon);
-                                                       fprintf(feps, "pop\n");
-                                                       fprintf(feps, "-2 div 0 rmoveto\n");
-                                                       fprintf(feps, " (%s) show\n", addon);
-                                                       fprintf(feps, "setmatrix\n");
-                                                       break;
-                                               case 5:
-                                                       fprintf(feps, "matrix currentmatrix\n");
-                                                       fprintf(feps, "/Helvetica findfont\n");
-                                                       fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                                       textpos = xoffset + 100;
-                                                       fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", textpos * scaler, addon_text_posn * scaler);
-                                                       fprintf(feps, " (%s) stringwidth\n", addon);
-                                                       fprintf(feps, "pop\n");
-                                                       fprintf(feps, "-2 div 0 rmoveto\n");
-                                                       fprintf(feps, " (%s) show\n", addon);
-                                                       fprintf(feps, "setmatrix\n");
-                                                       break;
-                                       }
-
-                                       break;
-                               case 13: /* EAN 13 */
-                               case 16:
-                               case 19:
-                                       fprintf(feps, "TE\n");
-                                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                                       fprintf(feps, "%.2f %.2f ", 5.0 * scaler, (4.0 + yoffset) * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (0 + xoffset) * scaler, 1 * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (2 + xoffset) * scaler, 1 * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (46 + xoffset) * scaler, 1 * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (48 + xoffset) * scaler, 1 * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (92 + xoffset) * scaler, 1 * scaler);
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (94 + xoffset) * scaler, 1 * scaler);
-                                       textpart[0] = symbol->text[0];
-                                       textpart[1] = '\0';
-                                       fprintf(feps, "TE\n");
-                                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                                       fprintf(feps, "matrix currentmatrix\n");
-                                       fprintf(feps, "/Helvetica findfont\n");
-                                       fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                       textpos = -7;
-                                       fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                                       fprintf(feps, " (%s) stringwidth\n", textpart);
-                                       fprintf(feps, "pop\n");
-                                       fprintf(feps, "-2 div 0 rmoveto\n");
-                                       fprintf(feps, " (%s) show\n", textpart);
-                                       fprintf(feps, "setmatrix\n");
-                                       for(i = 0; i < 6; i++) {
-                                               textpart[i] = symbol->text[i + 1];
-                                       }
-                                       textpart[6] = '\0';
-                                       fprintf(feps, "matrix currentmatrix\n");
-                                       fprintf(feps, "/Helvetica findfont\n");
-                                       fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                       textpos = 24;
-                                       fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                                       fprintf(feps, " (%s) stringwidth\n", textpart);
-                                       fprintf(feps, "pop\n");
-                                       fprintf(feps, "-2 div 0 rmoveto\n");
-                                       fprintf(feps, " (%s) show\n", textpart);
-                                       fprintf(feps, "setmatrix\n");
-                                       for(i = 0; i < 6; i++) {
-                                               textpart[i] = symbol->text[i + 7];
-                                       }
-                                       textpart[6] = '\0';
-                                       fprintf(feps, "matrix currentmatrix\n");
-                                       fprintf(feps, "/Helvetica findfont\n");
-                                       fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                       textpos = 71;
-                                       fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                                       fprintf(feps, " (%s) stringwidth\n", textpart);
-                                       fprintf(feps, "pop\n");
-                                       fprintf(feps, "-2 div 0 rmoveto\n");
-                                       fprintf(feps, " (%s) show\n", textpart);
-                                       fprintf(feps, "setmatrix\n");
-                                       textdone = 1;
-                                       switch(strlen(addon)) {
-                                               case 2:
-                                                       fprintf(feps, "matrix currentmatrix\n");
-                                                       fprintf(feps, "/Helvetica findfont\n");
-                                                       fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                                       textpos = xoffset + 114;
-                                                       fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", textpos * scaler, addon_text_posn * scaler);
-                                                       fprintf(feps, " (%s) stringwidth\n", addon);
-                                                       fprintf(feps, "pop\n");
-                                                       fprintf(feps, "-2 div 0 rmoveto\n");
-                                                       fprintf(feps, " (%s) show\n", addon);
-                                                       fprintf(feps, "setmatrix\n");
-                                                       break;
-                                               case 5:
-                                                       fprintf(feps, "matrix currentmatrix\n");
-                                                       fprintf(feps, "/Helvetica findfont\n");
-                                                       fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                                       textpos = xoffset + 128;
-                                                       fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", textpos * scaler, addon_text_posn * scaler);
-                                                       fprintf(feps, " (%s) stringwidth\n", addon);
-                                                       fprintf(feps, "pop\n");
-                                                       fprintf(feps, "-2 div 0 rmoveto\n");
-                                                       fprintf(feps, " (%s) show\n", addon);
-                                                       fprintf(feps, "setmatrix\n");
-                                                       break;
-                                       }
-                                       break;
-
-                       }
-               }       
-
-               if (((symbol->symbology == BARCODE_UPCA) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCA_CC)) {
-                       /* guard bar extensions and text formatting for UPCA */
-                       fprintf(feps, "TE\n");
-                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                       fprintf(feps, "%.2f %.2f ", 5.0 * scaler, (4.0 + yoffset) * scaler);
-                       latch = 1;
-                       
-                       i = 0 + comp_offset;
-                       do {
-                               block_width = 0;
-                               do {
-                                       block_width++;
-                               } while (module_is_set(symbol, symbol->rows - 1, i + block_width) == module_is_set(symbol, symbol->rows - 1, i));
-                               if(latch == 1) {
-                                       /* a bar */
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (i + xoffset - comp_offset) * scaler, block_width * scaler);
-                                       latch = 0;
-                               } else {
-                                       /* a space */
-                                       latch = 1;
-                               }
-                               i += block_width;
-                       } while (i < 11 + comp_offset);
-                       fprintf(feps, "TB %.2f %.2f TR\n", (46 + xoffset) * scaler, 1 * scaler);
-                       fprintf(feps, "TB %.2f %.2f TR\n", (48 + xoffset) * scaler, 1 * scaler);
-                       latch = 1;
-                       i = 85 + comp_offset;
-                       do {
-                               block_width = 0;
-                               do {
-                                       block_width++;
-                               } while (module_is_set(symbol, symbol->rows - 1, i + block_width) == module_is_set(symbol, symbol->rows - 1, i));
-                               if(latch == 1) {
-                                       /* a bar */
-                                       fprintf(feps, "TB %.2f %.2f TR\n", (i + xoffset - comp_offset) * scaler, block_width * scaler);
-                                       latch = 0;
-                               } else {
-                                       /* a space */
-                                       latch = 1;
-                               }
-                               i += block_width;
-                       } while (i < 96 + comp_offset);
-
-                       if(plot_text) {
-                               textpart[0] = symbol->text[0];
-                               textpart[1] = '\0';
-                               fprintf(feps, "TE\n");
-                               fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                               fprintf(feps, "matrix currentmatrix\n");
-                               fprintf(feps, "/Helvetica findfont\n");
-                               fprintf(feps, "%.2f scalefont setfont\n", 8.0 * scaler);
-                               textpos = -5;
-                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                               fprintf(feps, " (%s) stringwidth\n", textpart);
-                               fprintf(feps, "pop\n");
-                               fprintf(feps, "-2 div 0 rmoveto\n");
-                               fprintf(feps, " (%s) show\n", textpart);
-                               fprintf(feps, "setmatrix\n");
-                               for(i = 0; i < 5; i++) {
-                                       textpart[i] = symbol->text[i + 1];
-                               }
-                               textpart[5] = '\0';
-                               fprintf(feps, "matrix currentmatrix\n");
-                               fprintf(feps, "/Helvetica findfont\n");
-                               fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                               textpos = 27;
-                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                               fprintf(feps, " (%s) stringwidth\n", textpart);
-                               fprintf(feps, "pop\n");
-                               fprintf(feps, "-2 div 0 rmoveto\n");
-                               fprintf(feps, " (%s) show\n", textpart);
-                               fprintf(feps, "setmatrix\n");
-                               for(i = 0; i < 5; i++) {
-                                       textpart[i] = symbol->text[i + 6];
-                               }
-                               textpart[6] = '\0';
-                               fprintf(feps, "matrix currentmatrix\n");
-                               fprintf(feps, "/Helvetica findfont\n");
-                               fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                               textpos = 68;
-                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                               fprintf(feps, " (%s) stringwidth\n", textpart);
-                               fprintf(feps, "pop\n");
-                               fprintf(feps, "-2 div 0 rmoveto\n");
-                               fprintf(feps, " (%s) show\n", textpart);
-                               fprintf(feps, "setmatrix\n");
-                               textpart[0] = symbol->text[11];
-                               textpart[1] = '\0';
-                               fprintf(feps, "matrix currentmatrix\n");
-                               fprintf(feps, "/Helvetica findfont\n");
-                               fprintf(feps, "%.2f scalefont setfont\n", 8.0 * scaler);
-                               textpos = 100;
-                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                               fprintf(feps, " (%s) stringwidth\n", textpart);
-                               fprintf(feps, "pop\n");
-                               fprintf(feps, "-2 div 0 rmoveto\n");
-                               fprintf(feps, " (%s) show\n", textpart);
-                               fprintf(feps, "setmatrix\n");
-                               textdone = 1;
-                               switch(strlen(addon)) {
-                                       case 2:
-                                               fprintf(feps, "matrix currentmatrix\n");
-                                               fprintf(feps, "/Helvetica findfont\n");
-                                               fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                               textpos = xoffset + 116;
-                                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", textpos * scaler, addon_text_posn * scaler);
-                                               fprintf(feps, " (%s) stringwidth\n", addon);
-                                               fprintf(feps, "pop\n");
-                                               fprintf(feps, "-2 div 0 rmoveto\n");
-                                               fprintf(feps, " (%s) show\n", addon);
-                                               fprintf(feps, "setmatrix\n");
-                                               break;
-                                       case 5:
-                                               fprintf(feps, "matrix currentmatrix\n");
-                                               fprintf(feps, "/Helvetica findfont\n");
-                                               fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                               textpos = xoffset + 130;
-                                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", textpos * scaler, addon_text_posn * scaler);
-                                               fprintf(feps, " (%s) stringwidth\n", addon);
-                                               fprintf(feps, "pop\n");
-                                               fprintf(feps, "-2 div 0 rmoveto\n");
-                                               fprintf(feps, " (%s) show\n", addon);
-                                               fprintf(feps, "setmatrix\n");
-                                               break;
-                               }
-                       }
-               }
-
-               if (((symbol->symbology == BARCODE_UPCE) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCE_CC)) {
-                       /* guard bar extensions and text formatting for UPCE */
-                       fprintf(feps, "TE\n");
-                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                       fprintf(feps, "%.2f %.2f ", 5.0 * scaler, (4.0 + yoffset) * scaler);
-                       fprintf(feps, "TB %.2f %.2f TR\n", (0 + xoffset) * scaler, 1 * scaler);
-                       fprintf(feps, "TB %.2f %.2f TR\n", (2 + xoffset) * scaler, 1 * scaler);
-                       fprintf(feps, "TB %.2f %.2f TR\n", (46 + xoffset) * scaler, 1 * scaler);
-                       fprintf(feps, "TB %.2f %.2f TR\n", (48 + xoffset) * scaler, 1 * scaler);
-                       fprintf(feps, "TB %.2f %.2f TR\n", (50 + xoffset) * scaler, 1 * scaler);
-                       if(plot_text) {
-                               textpart[0] = symbol->text[0];
-                               textpart[1] = '\0';
-                               fprintf(feps, "TE\n");
-                               fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                               fprintf(feps, "matrix currentmatrix\n");
-                               fprintf(feps, "/Helvetica findfont\n");
-                               fprintf(feps, "%.2f scalefont setfont\n", 8.0 * scaler);
-                               textpos = -5;
-                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                               fprintf(feps, " (%s) stringwidth\n", textpart);
-                               fprintf(feps, "pop\n");
-                               fprintf(feps, "-2 div 0 rmoveto\n");
-                               fprintf(feps, " (%s) show\n", textpart);
-                               fprintf(feps, "setmatrix\n");
-                               for(i = 0; i < 6; i++) {
-                                       textpart[i] = symbol->text[i + 1];
-                               }
-                               textpart[6] = '\0';
-                               fprintf(feps, "matrix currentmatrix\n");
-                               fprintf(feps, "/Helvetica findfont\n");
-                               fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                               textpos = 24;
-                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                               fprintf(feps, " (%s) stringwidth\n", textpart);
-                               fprintf(feps, "pop\n");
-                               fprintf(feps, "-2 div 0 rmoveto\n");
-                               fprintf(feps, " (%s) show\n", textpart);
-                               fprintf(feps, "setmatrix\n");
-                               textpart[0] = symbol->text[7];
-                               textpart[1] = '\0';
-                               fprintf(feps, "matrix currentmatrix\n");
-                               fprintf(feps, "/Helvetica findfont\n");
-                               fprintf(feps, "%.2f scalefont setfont\n", 8.0 * scaler);
-                               textpos = 55;
-                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-                               fprintf(feps, " (%s) stringwidth\n", textpart);
-                               fprintf(feps, "pop\n");
-                               fprintf(feps, "-2 div 0 rmoveto\n");
-                               fprintf(feps, " (%s) show\n", textpart);
-                               fprintf(feps, "setmatrix\n");
-                               textdone = 1;
-                               switch(strlen(addon)) {
-                                       case 2:
-                                               fprintf(feps, "matrix currentmatrix\n");
-                                               fprintf(feps, "/Helvetica findfont\n");
-                                               fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                               textpos = xoffset + 70;
-                                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", textpos * scaler, addon_text_posn * scaler);
-                                               fprintf(feps, " (%s) stringwidth\n", addon);
-                                               fprintf(feps, "pop\n");
-                                               fprintf(feps, "-2 div 0 rmoveto\n");
-                                               fprintf(feps, " (%s) show\n", addon);
-                                               fprintf(feps, "setmatrix\n");
-                                               break;
-                                       case 5:
-                                               fprintf(feps, "matrix currentmatrix\n");
-                                               fprintf(feps, "/Helvetica findfont\n");
-                                               fprintf(feps, "%.2f scalefont setfont\n", 11.0 * scaler);
-                                               textpos = xoffset + 84;
-                                               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", textpos * scaler, addon_text_posn * scaler);
-                                               fprintf(feps, " (%s) stringwidth\n", addon);
-                                               fprintf(feps, "pop\n");
-                                               fprintf(feps, "-2 div 0 rmoveto\n");
-                                               fprintf(feps, " (%s) show\n", addon);
-                                               fprintf(feps, "setmatrix\n");
-                                               break;
-                               }
-                       }
-
-               }
-       } /* if (plot_text) */
-
-       xoffset -= comp_offset;
-
-       switch(symbol->symbology) {
-               case BARCODE_MAXICODE:
-                       /* Do nothing! (It's already been done) */
-                       break;
-               default:
-                       if((symbol->output_options & BARCODE_BIND) != 0) {
-                               if((symbol->rows > 1) && (is_stackable(symbol->symbology) == 1)) {
-                                       /* row binding */
-                                       fprintf(feps, "TE\n");
-                                       fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                                       for(r = 1; r < symbol->rows; r++) {
-                                               fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", 2.0 * scaler, ((r * row_height) + textoffset + yoffset - 1) * scaler, xoffset * scaler, symbol->width * scaler);
-                                       }
-                               }
-                       }
-                       if (((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) {
-                               fprintf(feps, "TE\n");
-                               fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                               fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", symbol->border_width * scaler, textoffset * scaler, 0.0, (symbol->width + xoffset + xoffset) * scaler);
-                               fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", symbol->border_width * scaler, (textoffset + symbol->height + symbol->border_width) * scaler, 0.0, (symbol->width + xoffset + xoffset) * scaler);
-                       }
-                       if((symbol->output_options & BARCODE_BOX) != 0) {
-                               /* side bars */
-                               fprintf(feps, "TE\n");
-                               fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-                               fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", (symbol->height + (2 * symbol->border_width)) * scaler, textoffset * scaler, 0.0, symbol->border_width * scaler);
-                               fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", (symbol->height + (2 * symbol->border_width)) * scaler, textoffset * scaler, (symbol->width + xoffset + xoffset - symbol->border_width) * scaler, symbol->border_width * scaler);
-                       }
-                       break;
-       }
-       
-       /* Put the human readable text at the bottom */
-       if(plot_text && (textdone == 0)) {
-               fprintf(feps, "TE\n");
-               fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
-               fprintf(feps, "matrix currentmatrix\n");
-               fprintf(feps, "/Helvetica findfont\n");
-               fprintf(feps, "%.2f scalefont setfont\n", 8.0 * scaler);
-               textpos = symbol->width / 2.0;
-               fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", (textpos + xoffset) * scaler, default_text_posn);
-               fprintf(feps, " (%s) stringwidth\n", symbol->text);
-               fprintf(feps, "pop\n");
-               fprintf(feps, "-2 div 0 rmoveto\n");
-               fprintf(feps, " (%s) show\n", symbol->text);
-               fprintf(feps, "setmatrix\n");
-       }
-       fprintf(feps, "\nshowpage\n");
-    if((symbol->output_options & BARCODE_STDOUT) == 0) 
-           fclose(feps);
-       
-       if (locale)
-               setlocale(LC_ALL, locale);
-       
-       return error_number;
+void colour_to_pscolor(int option, int colour, char* output) {
+    strcpy(output, "");
+    if ((option & CMYK_COLOUR) == 0) {
+        // Use RGB colour space
+        switch(colour) {
+            case 0: // White
+                strcat(output, "1.00 1.00 1.00");
+                break;
+            case 1: // Cyan
+                strcat(output, "0.00 1.00 1.00");
+                break;
+            case 2: // Blue
+                strcat(output, "0.00 0.00 1.00");
+                break;
+            case 3: // Magenta
+                strcat(output, "1.00 0.00 1.00");
+                break;
+            case 4: // Red
+                strcat(output, "1.00 0.00 0.00");
+                break;
+            case 5: // Yellow
+                strcat(output, "1.00 1.00 0.00");
+                break;
+            case 6: // Green
+                strcat(output, "0.00 1.00 0.00");
+                break;
+            default: // Black
+                strcat(output, "0.00 0.00 0.00");
+                break;
+        }
+        strcat(output, " setrgbcolor");
+    } else {
+        // Use CMYK colour space
+        switch(colour) {
+            case 0: // White
+                strcat(output, "0.00 0.00 0.00 0.00");
+                break;
+            case 1: // Cyan
+                strcat(output, "1.00 0.00 0.00 0.00");
+                break;
+            case 2: // Blue
+                strcat(output, "1.00 1.00 0.00 0.00");
+                break;
+            case 3: // Magenta
+                strcat(output, "0.00 1.00 0.00 0.00");
+                break;
+            case 4: // Red
+                strcat(output, "0.00 1.00 1.00 0.00");
+                break;
+            case 5: // Yellow
+                strcat(output, "0.00 0.00 1.00 0.00");
+                break;
+            case 6: // Green
+                strcat(output, "1.00 0.00 1.00 0.00");
+                break;
+            default: // Black
+                strcat(output, "0.00 0.00 0.00 1.00");
+                break;
+        }
+        strcat(output, " setcmykcolor");
+    }
 }
 
+INTERNAL int ps_plot(struct zint_symbol *symbol) {
+    FILE *feps;
+    int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
+    float red_ink, green_ink, blue_ink, red_paper, green_paper, blue_paper;
+    float cyan_ink, magenta_ink, yellow_ink, black_ink;
+    float cyan_paper, magenta_paper, yellow_paper, black_paper;
+    int error_number = 0;
+    float ax, ay, bx, by, cx, cy, dx, dy, ex, ey, fx, fy;
+    float radius;
+    int colour_index, colour_rect_counter;
+    char ps_color[30];
+
+    struct zint_vector_rect *rect;
+    struct zint_vector_hexagon *hex;
+    struct zint_vector_circle *circle;
+    struct zint_vector_string *string;
+    const char *locale = NULL;
+
+    if (symbol->output_options & BARCODE_STDOUT) {
+        feps = stdout;
+    } else {
+        feps = fopen(symbol->outfile, "w");
+    }
+    if (feps == NULL) {
+        strcpy(symbol->errtxt, "645: Could not open output file");
+        return ZINT_ERROR_FILE_ACCESS;
+    }
+
+    locale = setlocale(LC_ALL, "C");
+
+    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]);
+    red_ink = fgred / 256.0;
+    green_ink = fggrn / 256.0;
+    blue_ink = fgblu / 256.0;
+    red_paper = bgred / 256.0;
+    green_paper = bggrn / 256.0;
+    blue_paper = bgblu / 256.0;
+
+    /* Convert RGB to CMYK */
+    if (red_ink > green_ink) {
+        if (blue_ink > red_ink) {
+            black_ink = 1 - blue_ink;
+        } else {
+            black_ink = 1 - red_ink;
+        }
+    } else {
+        if (blue_ink > red_ink) {
+            black_ink = 1 - blue_ink;
+        } else {
+            black_ink = 1 - green_ink;
+        }
+    }
+    if (black_ink < 1.0) {
+        cyan_ink = (1 - red_ink - black_ink) / (1 - black_ink);
+        magenta_ink = (1 - green_ink - black_ink) / (1 - black_ink);
+        yellow_ink = (1 - blue_ink - black_ink) / (1 - black_ink);
+    } else {
+        cyan_ink = 0.0;
+        magenta_ink = 0.0;
+        yellow_ink = 0.0;
+    }
+
+    if (red_paper > green_paper) {
+        if (blue_paper > red_paper) {
+            black_paper = 1 - blue_paper;
+        } else {
+            black_paper = 1 - red_paper;
+        }
+    } else {
+        if (blue_paper > red_paper) {
+            black_paper = 1 - blue_paper;
+        } else {
+            black_paper = 1 - green_paper;
+        }
+    }
+    if (black_paper < 1.0) {
+        cyan_paper = (1 - red_paper - black_paper) / (1 - black_paper);
+        magenta_paper = (1 - green_paper - black_paper) / (1 - black_paper);
+        yellow_paper = (1 - blue_paper - black_paper) / (1 - black_paper);
+    } else {
+        cyan_paper = 0.0;
+        magenta_paper = 0.0;
+        yellow_paper = 0.0;
+    }
+
+    /* Start writing the header */
+    fprintf(feps, "%%!PS-Adobe-3.0 EPSF-3.0\n");
+    fprintf(feps, "%%%%Creator: Zint %d.%d.%d\n", ZINT_VERSION_MAJOR, ZINT_VERSION_MINOR, ZINT_VERSION_RELEASE);
+    fprintf(feps, "%%%%Title: Zint Generated Symbol\n");
+    fprintf(feps, "%%%%Pages: 0\n");
+    fprintf(feps, "%%%%BoundingBox: 0 0 %d %d\n", (int) ceil(symbol->vector->width), (int) ceil(symbol->vector->height));
+    fprintf(feps, "%%%%EndComments\n");
+
+    /* Definitions */
+    fprintf(feps, "/TL { setlinewidth moveto lineto stroke } bind def\n");
+    fprintf(feps, "/TD { newpath 0 360 arc fill } bind def\n");
+    fprintf(feps, "/TH { 0 setlinewidth moveto lineto lineto lineto lineto lineto closepath fill } bind def\n");
+    fprintf(feps, "/TB { 2 copy } bind def\n");
+    fprintf(feps, "/TR { newpath 4 1 roll exch moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill } bind def\n");
+    fprintf(feps, "/TE { pop pop } bind def\n");
+
+    fprintf(feps, "newpath\n");
+
+    /* Now the actual representation */
+    if ((symbol->output_options & CMYK_COLOUR) == 0) {
+        fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_paper, green_paper, blue_paper);
+    } else {
+        fprintf(feps, "%.2f %.2f %.2f %.2f setcmykcolor\n", cyan_paper, magenta_paper, yellow_paper, black_paper);
+    }
+    fprintf(feps, "%.2f 0.00 TB 0.00 %.2f TR\n", symbol->vector->height, symbol->vector->width);
+
+    fprintf(feps, "TE\n");
+    if (symbol->symbology != BARCODE_ULTRA) {
+        if ((symbol->output_options & CMYK_COLOUR) == 0) {
+            fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
+        } else {
+            fprintf(feps, "%.2f %.2f %.2f %.2f setcmykcolor\n", cyan_ink, magenta_ink, yellow_ink, black_ink);
+        }
+    }
+
+    // Rectangles
+    if (symbol->symbology == BARCODE_ULTRA) {
+        for (colour_index = 0; colour_index <= 7; colour_index++) {
+            colour_rect_counter = 0;
+            rect = symbol->vector->rectangles;
+            while (rect) {
+                if (rect->colour == colour_index) {
+                    if (colour_rect_counter == 0) {
+                        //Set new colour
+                        colour_to_pscolor(symbol->output_options, colour_index, ps_color);
+                        fprintf(feps, "%s\n", ps_color);
+                    }
+                    colour_rect_counter++;
+                    fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", rect->height, (symbol->vector->height - rect->y) - rect->height, rect->x, rect->width);
+                    fprintf(feps, "TE\n");
+                }
+                rect = rect->next;
+            }
+        }
+    } else {
+        rect = symbol->vector->rectangles;
+        while (rect) {
+            fprintf(feps, "%.2f %.2f TB %.2f %.2f TR\n", rect->height, (symbol->vector->height - rect->y) - rect->height, rect->x, rect->width);
+            fprintf(feps, "TE\n");
+            rect = rect->next;
+        }
+    }
+
+    // Hexagons
+    hex = symbol->vector->hexagons;
+    while (hex) {
+        radius = hex->diameter / 2.0;
+        ay = (symbol->vector->height - hex->y) + (1.0 * radius);
+        by = (symbol->vector->height - hex->y) + (0.5 * radius);
+        cy = (symbol->vector->height - hex->y) - (0.5 * radius);
+        dy = (symbol->vector->height - hex->y) - (1.0 * radius);
+        ey = (symbol->vector->height - hex->y) - (0.5 * radius);
+        fy = (symbol->vector->height - hex->y) + (0.5 * radius);
+        ax = hex->x;
+        bx = hex->x + (0.86 * radius);
+        cx = hex->x + (0.86 * radius);
+        dx = hex->x;
+        ex = hex->x - (0.86 * radius);
+        fx = hex->x - (0.86 * radius);
+        fprintf(feps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f TH\n", ax, ay, bx, by, cx, cy, dx, dy, ex, ey, fx, fy);
+        hex = hex->next;
+    }
+
+    // Circles
+    circle = symbol->vector->circles;
+    while (circle) {
+        if (circle->colour) {
+            // A 'white' circle
+            if ((symbol->output_options & CMYK_COLOUR) == 0) {
+                fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_paper, green_paper, blue_paper);
+            } else {
+                fprintf(feps, "%.2f %.2f %.2f %.2f setcmykcolor\n", cyan_paper, magenta_paper, yellow_paper, black_paper);
+            }
+            fprintf(feps, "%.2f %.2f %.2f TD\n", circle->x, (symbol->vector->height - circle->y), circle->diameter / 2.0);
+            if (circle->next) {
+                if ((symbol->output_options & CMYK_COLOUR) == 0) {
+                    fprintf(feps, "%.2f %.2f %.2f setrgbcolor\n", red_ink, green_ink, blue_ink);
+                } else {
+                    fprintf(feps, "%.2f %.2f %.2f %.2f setcmykcolor\n", cyan_ink, magenta_ink, yellow_ink, black_ink);
+                }
+            }
+        } else {
+            // A 'black' circle
+            fprintf(feps, "%.2f %.2f %.2f TD\n", circle->x, (symbol->vector->height - circle->y), circle->diameter / 2.0);
+        }
+        circle = circle->next;
+    }
+
+    // Text
+    string = symbol->vector->strings;
+    while (string) {
+        fprintf(feps, "matrix currentmatrix\n");
+        fprintf(feps, "/Helvetica findfont\n");
+        fprintf(feps, "%.2f scalefont setfont\n", string->fsize);
+        fprintf(feps, " 0 0 moveto %.2f %.2f translate 0.00 rotate 0 0 moveto\n", string->x, (symbol->vector->height - string->y));
+        fprintf(feps, " (%s) stringwidth\n", string->text);
+        fprintf(feps, "pop\n");
+        fprintf(feps, "-2 div 0 rmoveto\n");
+        fprintf(feps, " (%s) show\n", string->text);
+        fprintf(feps, "setmatrix\n");
+        string = string->next;
+    }
+
+    //fprintf(feps, "\nshowpage\n");
+
+    if (symbol->output_options & BARCODE_STDOUT) {
+        fflush(feps);
+    } else {
+        fclose(feps);
+    }
+
+    if (locale)
+        setlocale(LC_ALL, locale);
+
+    return error_number;
+}
index 2fe6412..40a1c32 100644 (file)
@@ -1,8 +1,7 @@
-/* qr.c Handles QR Code */
+/* qr.c Handles QR Code, Micro QR Code, UPNQR and rMQR
 
-/*
     libzint - the open source barcode library
-    Copyright (C) 2009 Robin Stuart <robin@zint.org.uk>
+    Copyright (C) 2009 - 2020 Robin Stuart <rstuart114@gmail.com>
 
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
@@ -28,7 +27,8 @@
     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     SUCH DAMAGE.
-*/
+ */
+/* vim: set ts=4 sw=4 et : */
 
 #include <string.h>
 #ifdef _MSC_VER
 #include "sjis.h"
 #include "qr.h"
 #include "reedsol.h"
+#include <assert.h>
+
+INTERNAL int utf_to_eci(const int eci, const unsigned char source[], unsigned char dest[], size_t *length); /* Convert Unicode to other encodings */
+
+/* Returns true if input glyph is in the Alphanumeric set */
+static int is_alpha(const unsigned int glyph, const int gs1) {
+    int retval = 0;
+
+    if ((glyph >= '0') && (glyph <= '9')) {
+        retval = 1;
+    } else if ((glyph >= 'A') && (glyph <= 'Z')) {
+        retval = 1;
+    } else if (gs1 && glyph == '[') {
+        retval = 1;
+    } else {
+        switch (glyph) {
+            case ' ':
+            case '$':
+            case '%':
+            case '*':
+            case '+':
+            case '-':
+            case '.':
+            case '/':
+            case ':':
+                retval = 1;
+                break;
+        }
+    }
+
+    return retval;
+}
+
+/* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */
+#define QR_MULT 6
+
+/* Whether in numeric or not. If in numeric, *p_end is set to position after numeric, and *p_cost is set to per-numeric cost */
+static int in_numeric(const unsigned int jisdata[], const size_t length, const unsigned int posn, unsigned int* p_end, unsigned int* p_cost) {
+    unsigned int i, digit_cnt;
+
+    if (posn < *p_end) {
+        return 1;
+    }
+
+    /* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times QR_MULT) */
+    for (i = posn; i < length && i < posn + 4 && jisdata[i] >= '0' && jisdata[i] <= '9'; i++);
+
+    digit_cnt = i - posn;
+
+    if (digit_cnt == 0) {
+        *p_end = 0;
+        return 0;
+    }
+    *p_end = i;
+    *p_cost = digit_cnt == 1 ? 24 /* 4 * QR_MULT */ : digit_cnt == 2 ? 21 /* (7 / 2) * QR_MULT */ : 20 /* (10 / 3) * QR_MULT) */;
+    return 1;
+}
+
+/* Whether in alpha or not. If in alpha, *p_end is set to position after alpha, and *p_cost is set to per-alpha cost. For GS1, *p_pcent set if 2nd char percent */
+static int in_alpha(const unsigned int jisdata[], const size_t length, const unsigned int posn, unsigned int* p_end, unsigned int* p_cost, unsigned int* p_pcent, unsigned int gs1) {
+    int two_alphas;
+
+    if (posn < *p_end) {
+        if (gs1 && *p_pcent) {
+            /* Previous 2nd char was a percent, so allow for second half of doubled-up percent here */
+            two_alphas = posn < length - 1 && is_alpha(jisdata[posn + 1], gs1);
+            *p_cost = two_alphas ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */;
+            *p_pcent = 0;
+        }
+        return 1;
+    }
+
+    /* Attempt to calculate the average 'cost' of using alphanumeric mode in number of bits (times QR_MULT) */
+    if (!is_alpha(jisdata[posn], gs1)) {
+        *p_end = 0;
+        *p_pcent = 0;
+        return 0;
+    }
+
+    if (gs1 && jisdata[posn] == '%') { /* Must double-up so counts as 2 chars */
+        *p_end = posn + 1;
+        *p_cost = 66; /* 11 * QR_MULT */
+        *p_pcent = 0;
+        return 1;
+    }
+
+    two_alphas = posn < length - 1 && is_alpha(jisdata[posn + 1], gs1);
+
+    *p_end = two_alphas ? posn + 2 : posn + 1;
+    *p_cost = two_alphas ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */;
+    *p_pcent = two_alphas && gs1 && jisdata[posn + 1] == '%'; /* 2nd char is percent */
+    return 1;
+}
 
-int in_alpha(int glyph) {
-       /* Returns true if input glyph is in the Alphanumeric set */
-       int retval = 0;
-       char cglyph = (char) glyph;
-       
-       if((cglyph >= '0') && (cglyph <= '9')) {
-               retval = 1;
-       }
-       if((cglyph >= 'A') && (cglyph <= 'Z')) {
-               retval = 1;
-       }
-       switch (cglyph) {
-               case ' ':
-               case '$':
-               case '%':
-               case '*':
-               case '+':
-               case '-':
-               case '.':
-               case '/':
-               case ':':
-                       retval = 1;
-                       break;
-       }
-       
-       return retval;
+/* Indexes into mode_types array (and state array) */
+#define QR_N   0 /* Numeric */
+#define QR_A   1 /* Alphanumeric */
+#define QR_B   2 /* Byte */
+#define QR_K   3 /* Kanji */
+
+static const char mode_types[] = { 'N', 'A', 'B', 'K', }; /* Must be in same order as QR_N etc */
+
+#define QR_NUM_MODES 4
+
+/* Indexes into state array (0..3 head costs) */
+#define QR_VER      4   /* Version */
+#define QR_GS1      5   /* GS1 mode (boolean) */
+#define QR_N_END    6   /* Numeric end index */
+#define QR_N_COST   7   /* Numeric cost */
+#define QR_A_END    8   /* Alpha end index */
+#define QR_A_COST   9   /* Alpha cost */
+#define QR_A_PCENT  10  /* Alpha 2nd char percent (GS1-specific) */
+
+/* Costs set to this for invalid MICROQR modes for versions M1 and M2.
+ * 128 is the max number of data bits for M4-L (ISO/IEC 18004:2015 Table 7) */
+#define QR_MICROQR_MAX 774 /* (128 + 1) * QR_MULT */
+
+/* Initial mode costs */
+static unsigned int* qr_head_costs(unsigned int state[]) {
+    static const int head_costs[7][QR_NUM_MODES] = {
+        /* N                    A                   B                   K */
+        { (10 + 4) * QR_MULT,  (9 + 4) * QR_MULT,  (8 + 4) * QR_MULT,  (8 + 4) * QR_MULT, }, /* QR */
+        { (12 + 4) * QR_MULT, (11 + 4) * QR_MULT, (16 + 4) * QR_MULT, (10 + 4) * QR_MULT, },
+        { (14 + 4) * QR_MULT, (13 + 4) * QR_MULT, (16 + 4) * QR_MULT, (12 + 4) * QR_MULT, },
+        {        3 * QR_MULT,     QR_MICROQR_MAX,     QR_MICROQR_MAX,     QR_MICROQR_MAX, }, /* MICROQR */
+        {  (4 + 1) * QR_MULT,  (3 + 1) * QR_MULT,     QR_MICROQR_MAX,     QR_MICROQR_MAX, },
+        {  (5 + 2) * QR_MULT,  (4 + 2) * QR_MULT,  (4 + 2) * QR_MULT,  (3 + 2) * QR_MULT, },
+        {  (6 + 3) * QR_MULT,  (5 + 3) * QR_MULT,  (5 + 3) * QR_MULT,  (4 + 3) * QR_MULT, }
+    };
+    int version;
+
+    /* Head costs kept in states 0..3 */
+    if (state[QR_N] != 0) { /* Numeric non-zero in all configs */
+        return state; /* Already set */
+    }
+
+    version = state[QR_VER];
+
+    if (version < RMQR_VERSION) { /* QRCODE */
+        if (version < 10) {
+            memcpy(state, head_costs, QR_NUM_MODES * sizeof(unsigned int));
+        } else if (version < 27) {
+            memcpy(state, head_costs + 1, QR_NUM_MODES * sizeof(unsigned int));
+        } else {
+            memcpy(state, head_costs + 2, QR_NUM_MODES * sizeof(unsigned int));
+        }
+    } else if (version < MICROQR_VERSION) { /* RMQR */
+        version -= RMQR_VERSION;
+        state[QR_N] = (rmqr_numeric_cci[version] + 3) * QR_MULT;
+        state[QR_A] = (rmqr_alphanum_cci[version] + 3) * QR_MULT;
+        state[QR_B] = (rmqr_byte_cci[version] + 3) * QR_MULT;
+        state[QR_K] = (rmqr_kanji_cci[version] + 3) * QR_MULT;
+    } else { /* MICROQR */
+        memcpy(state, head_costs + 3 + (version - MICROQR_VERSION), QR_NUM_MODES * sizeof(unsigned int));
+    }
+
+    return state;
 }
 
-void define_mode(char mode[], int jisdata[], int length, int gs1)
-{
-       /* Values placed into mode[] are: K = Kanji, B = Binary, A = Alphanumeric, N = Numeric */
-       int i, mlen, j;
-       
-       for(i = 0; i < length; i++) {
-               if(jisdata[i] > 0xff) { 
-                       mode[i] = 'K';
-               } else {
-                       mode[i] = 'B';
-                       if(in_alpha(jisdata[i])) { mode[i] = 'A'; }
-                       if(gs1 && (jisdata[i] == '[')) { mode[i] = 'A'; }
-                       if((jisdata[i] >= '0') && (jisdata[i] <= '9')) { mode[i] = 'N'; }
-               }
-       }
-       
-       /* If less than 6 numeric digits together then don't use numeric mode */
-       for(i = 0; i < length; i++) {
-               if(mode[i] == 'N') {
-                       if(((i != 0) && (mode[i - 1] != 'N')) || (i == 0)) {
-                               mlen = 0;
-                               while (((mlen + i) < length) && (mode[mlen + i] == 'N')) {
-                                       mlen++;
-                               };
-                               if(mlen < 6) {
-                                       for(j = 0; j < mlen; j++) {
-                                               mode[i + j] = 'A';
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       /* If less than 4 alphanumeric characters together then don't use alphanumeric mode */
-       for(i = 0; i < length; i++) {
-               if(mode[i] == 'A') {
-                       if(((i != 0) && (mode[i - 1] != 'A')) || (i == 0)) {
-                               mlen = 0;
-                               while (((mlen + i) < length) && (mode[mlen + i] == 'A')) {
-                                       mlen++;
-                               };
-                               if(mlen < 6) {
-                                       for(j = 0; j < mlen; j++) {
-                                               mode[i + j] = 'B';
-                                       }
-                               }
-                       }
-               }
-       }
+/* Costs of switching modes from k to j */
+static unsigned int qr_switch_cost(unsigned int state[], const int k, const int j) {
+    (void)k; /* Unused */
+    return state[j]; /* Same as head cost */
 }
 
-int estimate_binary_length(char mode[], int length, int gs1)
-{
-       /* Make an estimate (worst case scenario) of how long the binary string will be */
-       int i, count = 0;
-       char current = 0;
-       int a_count = 0;
-       int n_count = 0;
-
-       if(gs1) { count += 4; }
-       
-       for(i = 0; i < length; i++) {
-               if(mode[i] != current) {
-                       switch(mode[i]) {
-                               case 'K': count += 12 + 4; current = 'K'; break;
-                               case 'B': count += 16 + 4; current = 'B'; break;
-                               case 'A': count += 13 + 4; current = 'A'; a_count = 0; break;
-                               case 'N': count += 14 + 4; current = 'N'; n_count = 0; break;
-                       }
-               }
-
-               switch(mode[i]) {
-               case 'K': count += 13; break;
-               case 'B': count += 8; break;
-               case 'A':
-                       a_count++;
-                       if((a_count & 1) == 0) {
-                               count += 5;        // 11 in total
-                               a_count = 0;
-                       }
-                       else
-                               count += 6;
-                       break;
-               case 'N':
-                       n_count++;
-                       if((n_count % 3) == 0) {
-                               count += 3;        // 10 in total
-                               n_count = 0;
-                       }
-                       else if ((n_count & 1) == 0)
-                               count += 3;        // 7 in total
-                       else
-                               count += 4;
-                       break;
-               }
-       }
-
-       return count;
+/* Calculate cost of encoding character */
+static void qr_cur_cost(unsigned int state[], const unsigned int jisdata[], const size_t length, const int i, char* char_modes, unsigned int prev_costs[], unsigned int cur_costs[]) {
+    int cm_i = i * QR_NUM_MODES, m1, m2;
+    unsigned int version = state[QR_VER];
+    unsigned int gs1 = state[QR_GS1];
+    unsigned int* p_numeric_end = &state[QR_N_END];
+    unsigned int* p_numeric_cost = &state[QR_N_COST];
+    unsigned int* p_alpha_end = &state[QR_A_END];
+    unsigned int* p_alpha_cost = &state[QR_A_COST];
+    unsigned int* p_alpha_pcent = &state[QR_A_PCENT];
+
+    m1 = version == MICROQR_VERSION;
+    m2 = version == MICROQR_VERSION + 1;
+
+    if (jisdata[i] > 0xFF) {
+        cur_costs[QR_B] = prev_costs[QR_B] + ((m1 || m2) ? QR_MICROQR_MAX : 96); /* 16 * QR_MULT */
+        char_modes[cm_i + QR_B] = 'B';
+        cur_costs[QR_K] = prev_costs[QR_K] + ((m1 || m2) ? QR_MICROQR_MAX : 78); /* 13 * QR_MULT */
+        char_modes[cm_i + QR_K] = 'K';
+    } else {
+        if (in_numeric(jisdata, length, i, p_numeric_end, p_numeric_cost)) {
+            cur_costs[QR_N] = prev_costs[QR_N] + *p_numeric_cost;
+            char_modes[cm_i + QR_N] = 'N';
+        }
+        if (in_alpha(jisdata, length, i, p_alpha_end, p_alpha_cost, p_alpha_pcent, gs1)) {
+            cur_costs[QR_A] = prev_costs[QR_A] + (m1 ? QR_MICROQR_MAX : *p_alpha_cost);
+            char_modes[cm_i + QR_A] = 'A';
+        }
+        cur_costs[QR_B] = prev_costs[QR_B] + ((m1 || m2) ? QR_MICROQR_MAX : 48); /* 8 * QR_MULT */
+        char_modes[cm_i + QR_B] = 'B';
+    }
 }
 
-static inline void qr_bscan(char *binary, int data, int h)
-{
-       for (; h; h>>=1) {
-               concat(binary, data & h ? "1" : "0");
-       }
+static void qr_define_mode(char mode[], const unsigned int jisdata[], const size_t length, const int gs1, const int version, const int debug) {
+    unsigned int state[11] = {
+        0 /*N*/, 0 /*A*/, 0 /*B*/, 0 /*K*/,
+        (unsigned int) version, (unsigned int) gs1,
+        0 /*numeric_end*/, 0 /*numeric_cost*/, 0 /*alpha_end*/, 0 /*alpha_cost*/, 0 /*alpha_pcent*/
+    };
+
+    pn_define_mode(mode, jisdata, length, debug, state, mode_types, QR_NUM_MODES, qr_head_costs, qr_switch_cost, NULL, qr_cur_cost);
+}
+
+/* Return mode indicator bits based on version */
+static int mode_bits(const int version) {
+    if (version < RMQR_VERSION) {
+        return 4; /* QRCODE */
+    }
+    if (version < MICROQR_VERSION) {
+        return 3; /* RMQR */
+    }
+    return version - MICROQR_VERSION; /* MICROQR */
+}
+
+/* Return character count indicator bits based on version and mode */
+static int cci_bits(const int version, const int mode) {
+    static const int cci_bits[7][QR_NUM_MODES] = {
+        /* N   A   B   K */
+        { 10,  9,  8,  8, }, /* QRCODE */
+        { 12, 11, 16, 10, },
+        { 14, 13, 16, 12, },
+        {  3,  0,  0,  0, }, /* MICROQR */
+        {  4,  3,  0,  0, },
+        {  5,  4,  4,  3, },
+        {  6,  5,  5,  4, }
+    };
+    static const unsigned short int* rmqr_ccis[QR_NUM_MODES] = {
+        rmqr_numeric_cci, rmqr_alphanum_cci, rmqr_byte_cci, rmqr_kanji_cci,
+    };
+    int mode_index = strchr(mode_types, mode) - mode_types;
+
+    if (version < RMQR_VERSION) { /* QRCODE */
+        if (version < 10) {
+            return cci_bits[0][mode_index];
+        }
+        if (version < 27) {
+            return cci_bits[1][mode_index];
+        }
+        return cci_bits[2][mode_index];
+    }
+    if (version < MICROQR_VERSION) { /* RMQR */
+        return rmqr_ccis[mode_index][version - RMQR_VERSION];
+    }
+    return cci_bits[3 + (version - MICROQR_VERSION)][mode_index]; /* MICROQR */
 }
 
-void qr_binary(int datastream[], int version, int target_binlen, char mode[], int jisdata[], int length, int gs1, int est_binlen)
-{
-       /* Convert input data to a binary stream and add padding */
-       int position = 0;
-       int short_data_block_length, i, scheme = 1;
-       char data_block, padbits;
-       int current_binlen, current_bytes;
-       int toggle, percent;
-       
+/* Returns mode indicator based on version and mode */
+static const char* mode_indicator(const int version, const int mode) {
+    static const char* mode_indicators[6][QR_NUM_MODES] = {
+        /*    N       A       B       K */
+        { "0001", "0010", "0100", "1000", }, /* QRCODE */
+        {  "001",  "010",  "011",  "100", }, /* RMQR */
+        {     "",     "",     "",     "", }, /* MICROQR */
+        {    "0",    "1",     "",     "", },
+        {   "00",   "01",   "10",   "11", },
+        {  "000",  "001",  "010",  "011", },
+    };
+
+    int mode_index = strchr(mode_types, mode) - mode_types;
+
+    if (version < RMQR_VERSION) {
+        return mode_indicators[0][mode_index]; /* QRCODE */
+    }
+    if (version < MICROQR_VERSION) {
+        return mode_indicators[1][mode_index] /* RMQR */;
+    }
+    return mode_indicators[2 + version - MICROQR_VERSION][mode_index]; /* MICROQR */
+}
+
+/* Returns terminator bits based on version */
+static int terminator_bits(const int version) {
+    if (version < RMQR_VERSION) {
+        return 4; /* QRCODE */
+    }
+    if (version < MICROQR_VERSION) {
+        return 3; /* RMQR */
+    }
+    return 3 + (version - MICROQR_VERSION) * 2; /* MICROQR (Note not actually using this at the moment) */
+}
+
+/* Convert input data to a binary stream and add padding */
+static void qr_binary(unsigned char datastream[], const int version, const int target_codewords, const char mode[], const unsigned int jisdata[], const size_t length,
+            const int gs1, const int eci, const int est_binlen, const int debug) {
+    unsigned int position = 0;
+    int i;
+    int termbits, padbits;
+    int current_binlen, current_bytes;
+    int toggle, percent;
+    int percent_count;
+
 #ifndef _MSC_VER
-       char binary[est_binlen + 12];
+    char binary[est_binlen + 12];
 #else
-       char* binary = (char *)_alloca(est_binlen + 12);
-#endif
-       strcpy(binary, "");
-       
-       if(gs1) {
-               concat(binary, "0101"); /* FNC1 */
-       }
-       
-       if(version <= 9) {
-               scheme = 1;
-       } else if((version >= 10) && (version <= 26)) {
-               scheme = 2;
-       } else if(version >= 27) {
-               scheme = 3;
-       }
-       
-#ifdef _DEBUG_MODE_
-               for(i = 0; i < length; i++) {
-                       printf("%c", mode[i]);
-               }
-               printf("\n");
+    char* binary = (char *) _alloca(est_binlen + 12);
 #endif
+    strcpy(binary, "");
+
+    if (gs1) { /* Not applicable to MICROQR */
+        if (version < RMQR_VERSION) {
+            strcat(binary, "0101"); /* FNC1 */
+        } else {
+            strcat(binary, "101");
+        }
+    }
+
+    if (eci != 0) { /* Not applicable to RMQR or MICROQR */
+        strcat(binary, "0111"); /* ECI (Table 4) */
+        if (eci <= 127) {
+            bin_append(eci, 8, binary); /* 000000 to 000127 */
+        } else if (eci <= 16383) {
+            bin_append(0x8000 + eci, 16, binary); /* 000000 to 016383 */
+        } else {
+            bin_append(0xC00000 + eci, 24, binary); /* 000000 to 999999 */
+        }
+    }
+
+    if (debug & ZINT_DEBUG_PRINT) {
+        for (i = 0; i < (int) length; i++) {
+            printf("%c", mode[i]);
+        }
+        printf("\n");
+    }
+
+    percent = 0;
+
+    do {
+        char data_block = mode[position];
+        int short_data_block_length = 0;
+        int double_byte = 0;
+        do {
+            if (data_block == 'B' && jisdata[position + short_data_block_length] > 0xFF) {
+                double_byte++;
+            }
+            short_data_block_length++;
+        } while (((short_data_block_length + position) < length)
+                && (mode[position + short_data_block_length] == data_block));
+
+        switch (data_block) {
+            case 'K':
+                /* Kanji mode */
+                /* Mode indicator */
+                strcat(binary, mode_indicator(version, data_block));
+
+                /* Character count indicator */
+                bin_append(short_data_block_length, cci_bits(version, data_block), binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Kanji block (length %d)\n\t", short_data_block_length);
+                }
+
+                /* Character representation */
+                for (i = 0; i < short_data_block_length; i++) {
+                    unsigned int jis = jisdata[position + i];
+                    int prod;
+
+                    if (jis >= 0x8140 && jis <= 0x9ffc)
+                        jis -= 0x8140;
+
+                    else if (jis >= 0xe040 && jis <= 0xebbf)
+                        jis -= 0xc140;
+
+                    prod = ((jis >> 8) * 0xc0) + (jis & 0xff);
+
+                    bin_append(prod, 13, binary);
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("0x%04X ", prod);
+                    }
+                }
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("\n");
+                }
+
+                break;
+            case 'B':
+                /* Byte mode */
+                /* Mode indicator */
+                strcat(binary, mode_indicator(version, data_block));
+
+                /* Character count indicator */
+                bin_append(short_data_block_length + double_byte, cci_bits(version, data_block), binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Byte block (length %d)\n\t", short_data_block_length + double_byte);
+                }
+
+                /* Character representation */
+                for (i = 0; i < short_data_block_length; i++) {
+                    unsigned int byte = jisdata[position + i];
+
+                    if (gs1 && (byte == '[')) {
+                        byte = 0x1d; /* FNC1 */
+                    }
+
+                    bin_append(byte, byte > 0xFF ? 16 : 8, binary);
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("0x%02X(%d) ", byte, byte);
+                    }
+                }
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("\n");
+                }
+
+                break;
+            case 'A':
+                /* Alphanumeric mode */
+                /* Mode indicator */
+                strcat(binary, mode_indicator(version, data_block));
+
+                percent_count = 0;
+                if (gs1) {
+                    for (i = 0; i < short_data_block_length; i++) {
+                        if (jisdata[position + i] == '%') {
+                            percent_count++;
+                        }
+                    }
+                }
+
+                /* Character count indicator */
+                bin_append(short_data_block_length + percent_count, cci_bits(version, data_block), binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Alpha block (length %d)\n\t", short_data_block_length + percent_count);
+                }
+
+                /* Character representation */
+                i = 0;
+                while (i < short_data_block_length) {
+                    int count;
+                    int first = 0, second = 0, prod;
+
+                    if (percent == 0) {
+                        if (gs1 && (jisdata[position + i] == '%')) {
+                            first = posn(RHODIUM, '%');
+                            second = posn(RHODIUM, '%');
+                            count = 2;
+                            prod = (first * 45) + second;
+                            i++;
+                        } else {
+                            if (gs1 && (jisdata[position + i] == '[')) {
+                                first = posn(RHODIUM, '%'); /* FNC1 */
+                            } else {
+                                first = posn(RHODIUM, (char) jisdata[position + i]);
+                            }
+                            count = 1;
+                            i++;
+                            prod = first;
+
+                            if (i < short_data_block_length && mode[position + i] == 'A') {
+                                if (gs1 && (jisdata[position + i] == '%')) {
+                                    second = posn(RHODIUM, '%');
+                                    count = 2;
+                                    prod = (first * 45) + second;
+                                    percent = 1;
+                                } else {
+                                    if (gs1 && (jisdata[position + i] == '[')) {
+                                        second = posn(RHODIUM, '%'); /* FNC1 */
+                                    } else {
+                                        second = posn(RHODIUM, (char) jisdata[position + i]);
+                                    }
+                                    count = 2;
+                                    i++;
+                                    prod = (first * 45) + second;
+                                }
+                            }
+                        }
+                    } else {
+                        first = posn(RHODIUM, '%');
+                        count = 1;
+                        i++;
+                        prod = first;
+                        percent = 0;
+
+                        if (i < short_data_block_length && mode[position + i] == 'A') {
+                            if (gs1 && (jisdata[position + i] == '%')) {
+                                second = posn(RHODIUM, '%');
+                                count = 2;
+                                prod = (first * 45) + second;
+                                percent = 1;
+                            } else {
+                                if (gs1 && (jisdata[position + i] == '[')) {
+                                    second = posn(RHODIUM, '%'); /* FNC1 */
+                                } else {
+                                    second = posn(RHODIUM, (char) jisdata[position + i]);
+                                }
+                                count = 2;
+                                i++;
+                                prod = (first * 45) + second;
+                            }
+                        }
+                    }
+
+                    bin_append(prod, 1 + (5 * count), binary);
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("0x%X ", prod);
+                    }
+                }
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("\n");
+                }
+
+                break;
+            case 'N':
+                /* Numeric mode */
+                /* Mode indicator */
+                strcat(binary, mode_indicator(version, data_block));
+
+                /* Character count indicator */
+                bin_append(short_data_block_length, cci_bits(version, data_block), binary);
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("Number block (length %d)\n\t", short_data_block_length);
+                }
+
+                /* Character representation */
+                i = 0;
+                while (i < short_data_block_length) {
+                    int count;
+                    int first = 0, prod;
+
+                    first = posn(NEON, (char) jisdata[position + i]);
+                    count = 1;
+                    prod = first;
+
+                    if (i + 1 < short_data_block_length && mode[position + i + 1] == 'N') {
+                        int second = posn(NEON, (char) jisdata[position + i + 1]);
+                        count = 2;
+                        prod = (prod * 10) + second;
+
+                        if (i + 2 < short_data_block_length && mode[position + i + 2] == 'N') {
+                            int third = posn(NEON, (char) jisdata[position + i + 2]);
+                            count = 3;
+                            prod = (prod * 10) + third;
+                        }
+                    }
+
+                    bin_append(prod, 1 + (3 * count), binary);
+
+                    if (debug & ZINT_DEBUG_PRINT) {
+                        printf("0x%X(%d) ", prod, prod);
+                    }
+
+                    i += count;
+                };
+
+                if (debug & ZINT_DEBUG_PRINT) {
+                    printf("\n");
+                }
+
+                break;
+        }
+
+        position += short_data_block_length;
+    } while (position < length);
+
+    if (version >= MICROQR_VERSION && version < MICROQR_VERSION + 4) {
+        /* MICROQR does its own terminating/padding */
+        strcpy((char*)datastream, binary);
+        return;
+    }
+
+    /* Terminator */
+    current_binlen = (int)strlen(binary);
+    termbits = 8 - current_binlen % 8;
+    if (termbits == 8) {
+        termbits = 0;
+    }
+    current_bytes = (current_binlen + termbits) / 8;
+    if (termbits || current_bytes < target_codewords) {
+        int max_termbits = terminator_bits(version);
+        termbits = termbits < max_termbits && current_bytes == target_codewords ? termbits : max_termbits;
+        bin_append(0, termbits, binary);
+        current_binlen += termbits;
+    }
+
+    /* Padding bits */
+    padbits = 8 - current_binlen % 8;
+    if (padbits == 8) {
+        padbits = 0;
+    }
+    if (padbits) {
+        current_bytes = (current_binlen + padbits) / 8;
+        bin_append(0, padbits, binary);
+    }
+
+    /* Put data into 8-bit codewords */
+    for (i = 0; i < current_bytes; i++) {
+        int p;
+        datastream[i] = 0x00;
+        for (p = 0; p < 8; p++) {
+            if (binary[i * 8 + p] == '1') {
+                datastream[i] += (0x80 >> p);
+            }
+        }
+    }
+
+    /* Add pad codewords */
+    toggle = 0;
+    for (i = current_bytes; i < target_codewords; i++) {
+        if (toggle == 0) {
+            datastream[i] = 0xec;
+            toggle = 1;
+        } else {
+            datastream[i] = 0x11;
+            toggle = 0;
+        }
+    }
+
+    if (debug & ZINT_DEBUG_PRINT) {
+        printf("Resulting codewords:\n\t");
+        for (i = 0; i < target_codewords; i++) {
+            printf("0x%02X ", datastream[i]);
+        }
+        printf("\n");
+    }
+}
 
-       percent = 0;
-       
-       do {
-               data_block = mode[position];
-               short_data_block_length = 0;
-               do {
-                       short_data_block_length++;
-               } while (((short_data_block_length + position) < length) && (mode[position + short_data_block_length] == data_block));
-               
-               switch(data_block) {
-                       case 'K':
-                               /* Kanji mode */
-                               /* Mode indicator */
-                               concat(binary, "1000");
-                               
-                               /* Character count indicator */
-                               qr_bscan(binary, short_data_block_length, 0x20 << (scheme*2)); /* scheme = 1..3 */
-#ifdef _DEBUG_MODE_
-                               printf("Kanji block (length %d)\n\t", short_data_block_length);
-#endif
-                               
-                               /* Character representation */
-                               for(i = 0; i < short_data_block_length; i++) {
-                                       int jis = jisdata[position + i];
-                                       int msb, lsb, prod;
-                                       
-                                       if(jis > 0x9fff) { jis -= 0xc140; }
-                                       msb = (jis & 0xff00) >> 4;
-                                       lsb = (jis & 0xff);
-                                       prod = (msb * 0xc0) + lsb;
-                                       
-                                       qr_bscan(binary, prod, 0x1000);
-#ifdef _DEBUG_MODE_
-                                       printf("0x%4X ", prod);
-#endif
-                               }
-#ifdef _DEBUG_MODE_
-                               printf("\n");
+/* Split data into blocks, add error correction and then interleave the blocks and error correction data */
+static void add_ecc(unsigned char fullstream[], const unsigned char datastream[], const int version, const int data_cw, const int blocks, int debug) {
+    int ecc_cw;
+    int short_data_block_length;
+    int qty_long_blocks;
+    int qty_short_blocks;
+    int ecc_block_length;
+    int i, j, length_this_block, posn;
+#ifdef _MSC_VER
+    unsigned char* data_block;
+    unsigned char* ecc_block;
+    unsigned char* interleaved_data;
+    unsigned char* interleaved_ecc;
 #endif
-                               
-                               break;
-                       case 'B':
-                               /* Byte mode */
-                               /* Mode indicator */
-                               concat(binary, "0100");
-                               
-                               /* Character count indicator */
-                               qr_bscan(binary, short_data_block_length, scheme > 1 ? 0x8000 : 0x80); /* scheme = 1..3 */
-#ifdef _DEBUG_MODE_
-                               printf("Byte block (length %d)\n\t", short_data_block_length);
+
+    if (version < RMQR_VERSION) {
+        ecc_cw = qr_total_codewords[version - 1] - data_cw;
+    } else {
+        ecc_cw = rmqr_total_codewords[version - RMQR_VERSION] - data_cw;
+    }
+
+    short_data_block_length = data_cw / blocks;
+    qty_long_blocks = data_cw % blocks;
+    qty_short_blocks = blocks - qty_long_blocks;
+    ecc_block_length = ecc_cw / blocks;
+
+
+#ifndef _MSC_VER
+    unsigned char data_block[short_data_block_length + 1];
+    unsigned char ecc_block[ecc_block_length];
+    unsigned char interleaved_data[data_cw];
+    unsigned char interleaved_ecc[ecc_cw];
+#else
+    data_block = (unsigned char *) _alloca(short_data_block_length + 1);
+    ecc_block = (unsigned char *) _alloca(ecc_block_length);
+    interleaved_data = (unsigned char *) _alloca(data_cw);
+    interleaved_ecc = (unsigned char *) _alloca(ecc_cw);
 #endif
-                               /* Character representation */
-                               for(i = 0; i < short_data_block_length; i++) {
-                                       int byte = jisdata[position + i];
-                                       
-                                       if(gs1 && (byte == '[')) {
-                                               byte = 0x1d; /* FNC1 */
-                                       }
-                                       
-                                       qr_bscan(binary, byte, 0x80);
-#ifdef _DEBUG_MODE_
-                                       printf("0x%2X(%d) ", byte, byte);
+
+    posn = 0;
+
+    for (i = 0; i < blocks; i++) {
+        if (i < qty_short_blocks) {
+            length_this_block = short_data_block_length;
+        } else {
+            length_this_block = short_data_block_length + 1;
+        }
+
+        for (j = 0; j < ecc_block_length; j++) {
+            ecc_block[j] = 0;
+        }
+
+        for (j = 0; j < length_this_block; j++) {
+            data_block[j] = datastream[posn + j];
+        }
+
+        rs_init_gf(0x11d);
+        rs_init_code(ecc_block_length, 0);
+        rs_encode(length_this_block, data_block, ecc_block);
+        rs_free();
+
+        if (debug & ZINT_DEBUG_PRINT) {
+            printf("Block %d: ", i + 1);
+            for (j = 0; j < length_this_block; j++) {
+                printf("%2X ", data_block[j]);
+            }
+            if (i < qty_short_blocks) {
+                printf("   ");
+            }
+            printf(" // ");
+            for (j = 0; j < ecc_block_length; j++) {
+                printf("%2X ", ecc_block[ecc_block_length - j - 1]);
+            }
+            printf("\n");
+        }
+
+        for (j = 0; j < short_data_block_length; j++) {
+            interleaved_data[(j * blocks) + i] = data_block[j];
+        }
+
+        if (i >= qty_short_blocks) {
+            /* NOLINT suppress clang-tidy warning: data_block[short_data_block_length] set for i >= qty_short_blocks */
+            interleaved_data[(short_data_block_length * blocks) + (i - qty_short_blocks)] = data_block[short_data_block_length]; // NOLINT
+        }
+
+        for (j = 0; j < ecc_block_length; j++) {
+            interleaved_ecc[(j * blocks) + i] = ecc_block[ecc_block_length - j - 1];
+        }
+
+        posn += length_this_block;
+    }
+
+    for (j = 0; j < data_cw; j++) {
+        fullstream[j] = interleaved_data[j]; // NOLINT suppress clang-tidy warning: interleaved_data[data_cw] fully set
+    }
+    for (j = 0; j < ecc_cw; j++) {
+        fullstream[j + data_cw] = interleaved_ecc[j]; // NOLINT suppress clang-tidy warning: interleaved_ecc[ecc_cw] fully set
+    }
+
+    if (debug & ZINT_DEBUG_PRINT) {
+        printf("\nData Stream: \n");
+        for (j = 0; j < (data_cw + ecc_cw); j++) {
+            printf("%2X ", fullstream[j]);
+        }
+        printf("\n");
+    }
+}
+
+static void place_finder(unsigned char grid[],const int size,const int x,const int y) {
+    int xp, yp;
+    char finder[] = {0x7F, 0x41, 0x5D, 0x5D, 0x5D, 0x41, 0x7F};
+
+    for (xp = 0; xp < 7; xp++) {
+        for (yp = 0; yp < 7; yp++) {
+            if (finder[yp] & 0x40 >> xp) {
+                grid[((yp + y) * size) + (xp + x)] = 0x11;
+            } else {
+                grid[((yp + y) * size) + (xp + x)] = 0x10;
+            }
+        }
+    }
+}
+
+static void place_align(unsigned char grid[],const int size,int x,int y) {
+    int xp, yp;
+    char alignment[] = {0x1F, 0x11, 0x15, 0x11, 0x1F};
+
+    x -= 2;
+    y -= 2; /* Input values represent centre of pattern */
+
+    for (xp = 0; xp < 5; xp++) {
+        for (yp = 0; yp < 5; yp++) {
+            if (alignment[yp] & 0x10 >> xp) {
+                grid[((yp + y) * size) + (xp + x)] = 0x11;
+            } else {
+                grid[((yp + y) * size) + (xp + x)] = 0x10;
+            }
+        }
+    }
+}
+
+static void setup_grid(unsigned char* grid,const int size,const int version) {
+    int i, toggle = 1;
+
+    /* Add timing patterns */
+    for (i = 0; i < size; i++) {
+        if (toggle == 1) {
+            grid[(6 * size) + i] = 0x21;
+            grid[(i * size) + 6] = 0x21;
+            toggle = 0;
+        } else {
+            grid[(6 * size) + i] = 0x20;
+            grid[(i * size) + 6] = 0x20;
+            toggle = 1;
+        }
+    }
+
+    /* Add finder patterns */
+    place_finder(grid, size, 0, 0);
+    place_finder(grid, size, 0, size - 7);
+    place_finder(grid, size, size - 7, 0);
+
+    /* Add separators */
+    for (i = 0; i < 7; i++) {
+        grid[(7 * size) + i] = 0x10;
+        grid[(i * size) + 7] = 0x10;
+        grid[(7 * size) + (size - 1 - i)] = 0x10;
+        grid[(i * size) + (size - 8)] = 0x10;
+        grid[((size - 8) * size) + i] = 0x10;
+        grid[((size - 1 - i) * size) + 7] = 0x10;
+    }
+    grid[(7 * size) + 7] = 0x10;
+    grid[(7 * size) + (size - 8)] = 0x10;
+    grid[((size - 8) * size) + 7] = 0x10;
+
+    /* Add alignment patterns */
+    if (version != 1) {
+        /* Version 1 does not have alignment patterns */
+
+        int loopsize = qr_align_loopsize[version - 1];
+        int x, y;
+        for (x = 0; x < loopsize; x++) {
+            for (y = 0; y < loopsize; y++) {
+                int xcoord = qr_table_e1[((version - 2) * 7) + x];
+                int ycoord = qr_table_e1[((version - 2) * 7) + y];
+
+                if (!(grid[(ycoord * size) + xcoord] & 0x10)) {
+                    place_align(grid, size, xcoord, ycoord);
+                }
+            }
+        }
+    }
+
+    /* Reserve space for format information */
+    for (i = 0; i < 8; i++) {
+        grid[(8 * size) + i] += 0x20;
+        grid[(i * size) + 8] += 0x20;
+        grid[(8 * size) + (size - 1 - i)] = 0x20;
+        grid[((size - 1 - i) * size) + 8] = 0x20;
+    }
+    grid[(8 * size) + 8] += 0x20;
+    grid[((size - 1 - 7) * size) + 8] = 0x21; /* Dark Module from Figure 25 */
+
+    /* Reserve space for version information */
+    if (version >= 7) {
+        for (i = 0; i < 6; i++) {
+            grid[((size - 9) * size) + i] = 0x20;
+            grid[((size - 10) * size) + i] = 0x20;
+            grid[((size - 11) * size) + i] = 0x20;
+            grid[(i * size) + (size - 9)] = 0x20;
+            grid[(i * size) + (size - 10)] = 0x20;
+            grid[(i * size) + (size - 11)] = 0x20;
+        }
+    }
+}
+
+static int cwbit(const unsigned char* fullstream, const int i) {
+    int resultant = 0;
+
+    if (fullstream[(i / 8)] & (0x80 >> (i % 8))) {
+        resultant = 1;
+    }
+
+    return resultant;
+}
+
+static void populate_grid(unsigned char* grid, const int h_size, const int v_size, const unsigned char* fullstream, const int cw) {
+    int direction = 1; /* up */
+    int row = 0; /* right hand side */
+
+    int i, n, y;
+
+    n = cw * 8;
+    y = v_size - 1;
+    i = 0;
+    while (i < n) {
+        int x = (h_size - 2) - (row * 2);
+
+        if ((x < 6) && (v_size == h_size))
+            x--; /* skip over vertical timing pattern */
+
+        if (!(grid[(y * h_size) + (x + 1)] & 0xf0)) {
+            if (cwbit(fullstream, i)) {
+                grid[(y * h_size) + (x + 1)] = 0x01;
+            } else {
+                grid[(y * h_size) + (x + 1)] = 0x00;
+            }
+            i++;
+        }
+
+        if (i < n) {
+            if (!(grid[(y * h_size) + x] & 0xf0)) {
+                if (cwbit(fullstream, i)) {
+                    grid[(y * h_size) + x] = 0x01;
+                } else {
+                    grid[(y * h_size) + x] = 0x00;
+                }
+                i++;
+            }
+        }
+
+        if (direction) {
+            y--;
+        } else {
+            y++;
+        }
+        if (y == -1) {
+            /* reached the top */
+            row++;
+            y = 0;
+            direction = 0;
+        }
+        if (y == v_size) {
+            /* reached the bottom */
+            row++;
+            y = v_size - 1;
+            direction = 1;
+        }
+    }
+}
+
+#ifdef ZINTLOG
+
+static int append_log(char log) {
+    FILE *file;
+
+    file = fopen("zintlog.txt", "a+");
+    fprintf(file, "%c", log);
+    fclose(file);
+    return 0;
+}
+
+static int write_log(char log[]) {
+    FILE *file;
+
+    file = fopen("zintlog.txt", "a+");
+    fprintf(file, log); /*writes*/
+    fprintf(file, "\r\n"); /*writes*/
+    fclose(file);
+    return 0;
+}
 #endif
-                               }
-#ifdef _DEBUG_MODE_
-                               printf("\n");
+
+static int evaluate(unsigned char *eval,const int size,const int pattern) {
+    int x, y, block, weight;
+    int result = 0;
+    char state;
+    int p;
+    int dark_mods;
+    int percentage, k;
+    int a, b, afterCount, beforeCount;
+#ifdef ZINTLOG
+    int result_b = 0;
+    char str[15];
 #endif
-                               break;
-                       case 'A':
-                               /* Alphanumeric mode */
-                               /* Mode indicator */
-                               concat(binary, "0010");
-                               
-                               /* Character count indicator */
-                               qr_bscan(binary, short_data_block_length, 0x40 << (2 * scheme)); /* scheme = 1..3 */
-#ifdef _DEBUG_MODE_
-                               printf("Alpha block (length %d)\n\t", short_data_block_length);
+
+#ifndef _MSC_VER
+    char local[size * size];
+#else
+    char* local = (char *) _alloca((size * size) * sizeof (char));
 #endif
-                               /* Character representation */
-                               i = 0; 
-                               while ( i < short_data_block_length ) {
-                                       int count;
-                                       int first = 0, second = 0, prod;
-                       
-                                       if(percent == 0) {
-                                               if(gs1 && (jisdata[position + i] == '%')) {
-                                                       first = posn(RHODIUM, '%');
-                                                       second = posn(RHODIUM, '%');
-                                                       count = 2;
-                                                       prod = (first * 45) + second;
-                                                       i++;
-                                               } else {
-                                                       if(gs1 && (jisdata[position + i] == '[')) {
-                                                               first = posn(RHODIUM, '%'); /* FNC1 */
-                                                       } else {
-                                                               first = posn(RHODIUM, (char) jisdata[position + i]);
-                                                       }
-                                                       count = 1;
-                                                       i++;
-                                                       prod = first;
-                                               
-                                                       if(mode[position + i] == 'A') {
-                                                               if(gs1 && (jisdata[position + i] == '%')) {
-                                                                       second = posn(RHODIUM, '%');
-                                                                       count = 2;
-                                                                       prod = (first * 45) + second;
-                                                                       percent = 1;
-                                                               } else {
-                                                                       if(gs1 && (jisdata[position + i] == '[')) {
-                                                                               second = posn(RHODIUM, '%'); /* FNC1 */
-                                                                       } else {
-                                                                               second = posn(RHODIUM, (char) jisdata[position + i]);
-                                                                       }
-                                                                       count = 2;
-                                                                       i++;
-                                                                       prod = (first * 45) + second;
-                                                               }
-                                                       }
-                                               }
-                                       } else {
-                                               first = posn(RHODIUM, '%');
-                                               count = 1;
-                                               i++;
-                                               prod = first;
-                                               percent = 0;
-                                               
-                                               if(mode[position + i] == 'A') {
-                                                       if(gs1 && (jisdata[position + i] == '%')) {
-                                                               second = posn(RHODIUM, '%');
-                                                               count = 2;
-                                                               prod = (first * 45) + second;
-                                                               percent = 1;
-                                                       } else {
-                                                               if(gs1 && (jisdata[position + i] == '[')) {
-                                                                       second = posn(RHODIUM, '%'); /* FNC1 */
-                                                               } else {
-                                                                       second = posn(RHODIUM, (char) jisdata[position + i]);
-                                                               }
-                                                               count = 2;
-                                                               i++;
-                                                               prod = (first * 45) + second;
-                                                       }
-                                               }
-                                       }
-
-                                       qr_bscan(binary, prod, count == 2 ? 0x400 : 0x20); /* count = 1..2 */
-#ifdef _DEBUG_MODE_
-                                       printf("0x%4X ", prod);
+
+
+#ifdef ZINTLOG
+    write_log("");
+    sprintf(str, "%d", pattern);
+    write_log(str);
 #endif
-                               };
-#ifdef _DEBUG_MODE_
-                               printf("\n");
+
+    /* all eight bitmask variants have been encoded in the 8 bits of the bytes
+     * that make up the grid array. select them for evaluation according to the
+     * desired pattern.*/
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            if ((eval[(y * size) + x] & (0x01 << pattern)) != 0) {
+                local[(y * size) + x] = '1';
+            } else {
+                local[(y * size) + x] = '0';
+            }
+        }
+    }
+
+#ifdef ZINTLOG
+    //bitmask output
+    for (y = 0; y < size; y++) {
+        strcpy(str, "");
+        for (x = 0; x < size; x++) {
+            state = local[(y * size) + x];
+            append_log(state);
+        }
+        write_log("");
+    }
+    write_log("");
 #endif
-                               
-                               break;
-                       case 'N':
-                               /* Numeric mode */
-                               /* Mode indicator */
-                               concat(binary, "0001");
-                               
-                               /* Character count indicator */
-                               qr_bscan(binary, short_data_block_length, 0x80 << (2 * scheme)); /* scheme = 1..3 */
-#ifdef _DEBUG_MODE_
-                               printf("Number block (length %d)\n\t", short_data_block_length);
+
+    /* Test 1: Adjacent modules in row/column in same colour */
+    /* Vertical */
+    for (x = 0; x < size; x++) {
+        state = local[x];
+        block = 0;
+        for (y = 0; y < size; y++) {
+            if (local[(y * size) + x] == state) {
+                block++;
+            } else {
+                if (block > 5) {
+                    result += (3 + (block - 5));
+                }
+                block = 0;
+                state = local[(y * size) + x];
+            }
+        }
+        if (block > 5) {
+            result += (3 + (block - 5));
+        }
+    }
+
+    /* Horizontal */
+    for (y = 0; y < size; y++) {
+        state = local[y * size];
+        block = 0;
+        for (x = 0; x < size; x++) {
+            if (local[(y * size) + x] == state) {
+                block++;
+            } else {
+                if (block > 5) {
+                    result += (3 + (block - 5));
+                }
+                block = 0;
+                state = local[(y * size) + x];
+            }
+        }
+        if (block > 5) {
+            result += (3 + (block - 5));
+        }
+    }
+
+#ifdef ZINTLOG
+    /* output Test 1 */
+    sprintf(str, "%d", result);
+    result_b = result;
+    write_log(str);
 #endif
-                               /* Character representation */
-                               i = 0; 
-                               while ( i < short_data_block_length ) {
-                                       int count;
-                                       int first = 0, second = 0, third = 0, prod;
-                                       
-                                       first = posn(NEON, (char) jisdata[position + i]);
-                                       count = 1;
-                                       prod = first;
-                                       
-                                       if(mode[position + i + 1] == 'N') {
-                                               second = posn(NEON, (char) jisdata[position + i + 1]);
-                                               count = 2;
-                                               prod = (prod * 10) + second;
-                                               
-                                               if(mode[position + i + 2] == 'N') {
-                                                       third = posn(NEON, (char) jisdata[position + i + 2]);
-                                                       count = 3;
-                                                       prod = (prod * 10) + third;
-                                               }
-                                       }
-                                       
-                                       qr_bscan(binary, prod, 1 << (3 * count)); /* count = 1..3 */
-#ifdef _DEBUG_MODE_
-                                       printf("0x%4X (%d)", prod, prod);
+
+    /* Test 2: Block of modules in same color */
+    for (x = 0; x < size - 1; x++) {
+        for (y = 0; y < size - 1; y++) {
+            /* NOLINT suppress clang-tidy warning: local[size * size] fully set */
+            if (((local[(y * size) + x] == local[((y + 1) * size) + x]) && // NOLINT
+                    (local[(y * size) + x] == local[(y * size) + (x + 1)])) &&
+                    (local[(y * size) + x] == local[((y + 1) * size) + (x + 1)])) { // NOLINT
+                result += 3;
+            }
+        }
+    }
+
+#ifdef ZINTLOG
+    /* output Test 2 */
+    sprintf(str, "%d", result - result_b);
+    result_b = result;
+    write_log(str);
 #endif
-                                       
-                                       i += count;
-                               };
-#ifdef _DEBUG_MODE_
-                               printf("\n");
+
+    /* Test 3: 1:1:3:1:1 ratio pattern in row/column */
+    /* Vertical */
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < (size - 7); y++) {
+            p = 0;
+            for (weight = 0; weight < 7; weight++) {
+                if (local[((y + weight) * size) + x] == '1') {
+                    p += (0x40 >> weight);
+                }
+            }
+            if (p == 0x5d) {
+                /* Pattern found, check before and after */
+                beforeCount = 0;
+                for (b = (y - 4); b < y; b++) {
+                    if (b < 0) {
+                        beforeCount++;
+                    } else {
+                        if (local[(b * size) + x] == '0') {
+                            beforeCount++;
+                        } else {
+                            beforeCount = 0;
+                        }
+                    }
+                }
+
+                afterCount = 0;
+                for (a = (y + 7); a <= (y + 10); a++) {
+                    if (a >= size) {
+                        afterCount++;
+                    } else {
+                        if (local[(a * size) + x] == '0') {
+                            afterCount++;
+                        } else {
+                            afterCount = 0;
+                        }
+                    }
+                }
+
+                if ((beforeCount == 4) || (afterCount == 4)) {
+                    /* Pattern is preceeded or followed by light area
+                       4 modules wide */
+                    result += 40;
+                }
+            }
+        }
+    }
+
+    /* Horizontal */
+    for (y = 0; y < size; y++) {
+        for (x = 0; x < (size - 7); x++) {
+            p = 0;
+            for (weight = 0; weight < 7; weight++) {
+                if (local[(y * size) + x + weight] == '1') {
+                    p += (0x40 >> weight);
+                }
+            }
+            if (p == 0x5d) {
+                /* Pattern found, check before and after */
+                beforeCount = 0;
+                for (b = (x - 4); b < x; b++) {
+                    if (b < 0) {
+                        beforeCount++;
+                    } else {
+                        if (local[(y * size) + b] == '0') {
+                            beforeCount++;
+                        } else {
+                            beforeCount = 0;
+                        }
+                    }
+                }
+
+                afterCount = 0;
+                for (a = (x + 7); a <= (x + 10); a++) {
+                    if (a >= size) {
+                        afterCount++;
+                    } else {
+                        if (local[(y * size) + a] == '0') {
+                            afterCount++;
+                        } else {
+                            afterCount = 0;
+                        }
+                    }
+                }
+
+                if ((beforeCount == 4) || (afterCount == 4)) {
+                    /* Pattern is preceeded or followed by light area
+                       4 modules wide */
+                    result += 40;
+                }
+            }
+        }
+    }
+
+#ifdef ZINTLOG
+    /* output Test 3 */
+    sprintf(str, "%d", result - result_b);
+    result_b = result;
+    write_log(str);
 #endif
-                               
-                               break;
-               }
-               
-               position += short_data_block_length;
-       } while (position < length) ;
-       
-       /* Terminator */
-       concat(binary, "0000");
-
-       current_binlen = strlen(binary);
-       padbits = 8 - (current_binlen % 8);
-       if(padbits == 8) { padbits = 0; }
-       current_bytes = (current_binlen + padbits) / 8;
-       
-       /* Padding bits */
-       for(i = 0; i < padbits; i++) {
-               concat(binary, "0");
-       }
-
-       /* Put data into 8-bit codewords */
-       for(i = 0; i < current_bytes; i++) {
-               datastream[i] = 0x00;
-               if(binary[i * 8] == '1') { datastream[i] += 0x80; }
-               if(binary[i * 8 + 1] == '1') { datastream[i] += 0x40; }
-               if(binary[i * 8 + 2] == '1') { datastream[i] += 0x20; }
-               if(binary[i * 8 + 3] == '1') { datastream[i] += 0x10; }
-               if(binary[i * 8 + 4] == '1') { datastream[i] += 0x08; }
-               if(binary[i * 8 + 5] == '1') { datastream[i] += 0x04; }
-               if(binary[i * 8 + 6] == '1') { datastream[i] += 0x02; }
-               if(binary[i * 8 + 7] == '1') { datastream[i] += 0x01; }
-       }
-       
-       /* Add pad codewords */
-       toggle = 0;
-       for(i = current_bytes; i < target_binlen; i++) {
-               if(toggle == 0) {
-                       datastream[i] = 0xec;
-                       toggle = 1;
-               } else {
-                       datastream[i] = 0x11;
-                       toggle = 0;
-               }
-       }
-
-#ifdef _DEBUG_MODE_
-               printf("Resulting codewords:\n\t");
-               for(i = 0; i < target_binlen; i++) {
-                       printf("0x%2X ", datastream[i]);
-               }
-               printf("\n");
+
+    /* Test 4: Proportion of dark modules in entire symbol */
+    dark_mods = 0;
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            if (local[(y * size) + x] == '1') {
+                dark_mods++;
+            }
+        }
+    }
+    percentage = 100 * (dark_mods / (size * size));
+    if (percentage <= 50) {
+        k = ((100 - percentage) - 50) / 5;
+    } else {
+        k = (percentage - 50) / 5;
+    }
+
+    result += 10 * k;
+
+#ifdef ZINTLOG
+    /* output Test 4+summary */
+    sprintf(str, "%d", result - result_b);
+    write_log(str);
+    write_log("==========");
+    sprintf(str, "%d", result);
+    write_log(str);
 #endif
+
+    return result;
 }
 
-void add_ecc(int fullstream[], int datastream[], int version, int data_cw, int blocks)
-{
-       /* Split data into blocks, add error correction and then interleave the blocks and error correction data */
-       int ecc_cw = qr_total_codewords[version - 1] - data_cw;
-       int short_data_block_length = data_cw / blocks;
-       int qty_long_blocks = data_cw % blocks;
-       int qty_short_blocks = blocks - qty_long_blocks;
-       int ecc_block_length = ecc_cw / blocks;
-       int i, j, length_this_block, posn;
-       
-       
+static void add_format_info_eval(unsigned char *eval,const int size,const int ecc_level,const int pattern) {
+    /* Add format information to grid */
+
+    int format = pattern;
+    unsigned int seq;
+    int i;
+
+    switch (ecc_level) {
+        case LEVEL_L: format += 0x08;
+            break;
+        case LEVEL_Q: format += 0x18;
+            break;
+        case LEVEL_H: format += 0x10;
+            break;
+    }
+
+    seq = qr_annex_c[format];
+
+    for (i = 0; i < 6; i++) {
+        eval[(i * size) + 8] = ((seq >> i) & 0x01) ? (0x01 >> pattern) : 0x00;
+    }
+
+    for (i = 0; i < 8; i++) {
+        eval[(8 * size) + (size - i - 1)] = ((seq >> i) & 0x01) ? (0x01 >> pattern) : 0x00;
+    }
+
+    for (i = 0; i < 6; i++) {
+        eval[(8 * size) + (5 - i)] = ((seq >> (i + 9)) & 0x01) ? (0x01 >> pattern) : 0x00;
+    }
+
+    for (i = 0; i < 7; i++) {
+        eval[(((size - 7) + i) * size) + 8] = ((seq >> (i + 8)) & 0x01) ? (0x01 >> pattern) : 0x00;
+    }
+
+    eval[(7 * size) + 8] = ((seq >> 6) & 0x01) ? (0x01 >> pattern) : 0x00;
+    eval[(8 * size) + 8] = ((seq >> 7) & 0x01) ? (0x01 >> pattern) : 0x00;
+    eval[(8 * size) + 7] = ((seq >> 8) & 0x01) ? (0x01 >> pattern) : 0x00;
+}
+
+static int apply_bitmask(unsigned char *grid,const int size,const int ecc_level) {
+    int x, y;
+    unsigned char p;
+    int pattern, penalty[8];
+    int best_val, best_pattern;
+
 #ifndef _MSC_VER
-       unsigned char data_block[short_data_block_length + 2];
-       unsigned char ecc_block[ecc_block_length + 2];
-       int interleaved_data[data_cw + 2];
-       int interleaved_ecc[ecc_cw + 2];
+    unsigned char mask[size * size];
+    unsigned char eval[size * size];
 #else
-       unsigned char* data_block = (unsigned char *)_alloca(short_data_block_length + 2);
-       unsigned char* ecc_block = (unsigned char *)_alloca(ecc_block_length + 2);
-       int* interleaved_data = (int *)_alloca((data_cw + 2) * sizeof(int));
-       int* interleaved_ecc = (int *)_alloca((ecc_cw + 2) * sizeof(int));
+    unsigned char* mask = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
+    unsigned char* eval = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
 #endif
 
-       posn = 0;
-       
-       for(i = 0; i < blocks; i++) {
-               if(i < qty_short_blocks) { length_this_block = short_data_block_length; } else { length_this_block = short_data_block_length + 1; }
-               
-               for(j = 0; j < ecc_block_length; j++) {
-                       ecc_block[j] = 0;
-               }
-               
-               for(j = 0; j < length_this_block; j++) {
-                       data_block[j] = (unsigned char) datastream[posn + j];
-               }
-               
-               rs_init_gf(0x11d);
-               rs_init_code(ecc_block_length, 0);
-               rs_encode(length_this_block, data_block, ecc_block);
-               rs_free();
-
-#ifdef _DEBUG_MODE_
-                       printf("Block %d: ", i + 1);
-                       for(j = 0; j < length_this_block; j++) {
-                               printf("%2X ", data_block[j]);
-                       }
-                       if(i < qty_short_blocks) {
-                               printf("   ");
-                       }
-                       printf(" // ");
-                       for(j = 0; j < ecc_block_length; j++) {
-                               printf("%2X ", ecc_block[ecc_block_length - j - 1]);
-                       }
-                       printf("\n");
+    /* Perform data masking */
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            mask[(y * size) + x] = 0x00;
+
+            // all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array.
+            if (!(grid[(y * size) + x] & 0xf0)) { // exclude areas not to be masked.
+                if (((y + x) & 1) == 0) {
+                    mask[(y * size) + x] += 0x01;
+                }
+                if ((y & 1) == 0) {
+                    mask[(y * size) + x] += 0x02;
+                }
+                if ((x % 3) == 0) {
+                    mask[(y * size) + x] += 0x04;
+                }
+                if (((y + x) % 3) == 0) {
+                    mask[(y * size) + x] += 0x08;
+                }
+                if ((((y / 2) + (x / 3)) & 1) == 0) {
+                    mask[(y * size) + x] += 0x10;
+                }
+                if ((((y * x) & 1) + ((y * x) % 3)) == 0) {
+                    mask[(y * size) + x] += 0x20;
+                }
+                if (((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) {
+                    mask[(y * size) + x] += 0x40;
+                }
+                if (((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) {
+                    mask[(y * size) + x] += 0x80;
+                }
+            }
+        }
+    }
+
+    // apply data masks to grid, result in eval
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            if (grid[(y * size) + x] & 0x01) {
+                p = 0xff;
+            } else {
+                p = 0x00;
+            }
+
+            eval[(y * size) + x] = mask[(y * size) + x] ^ p;
+        }
+    }
+
+
+    /* Evaluate result */
+    for (pattern = 0; pattern < 8; pattern++) {
+
+        add_format_info_eval(eval, size, ecc_level, pattern);
+
+        penalty[pattern] = evaluate(eval, size, pattern);
+    }
+
+    best_pattern = 0;
+    best_val = penalty[0];
+    for (pattern = 1; pattern < 8; pattern++) {
+        if (penalty[pattern] < best_val) {
+            best_pattern = pattern;
+            best_val = penalty[pattern];
+        }
+    }
+
+#ifdef ZINTLOG
+    char str[15];
+    sprintf(str, "%d", best_val);
+    write_log("choosed pattern:");
+    write_log(str);
 #endif
-               
-               for(j = 0; j < short_data_block_length; j++) {
-                       interleaved_data[(j * blocks) + i] = (int) data_block[j];
-               }
-               
-               if(i >= qty_short_blocks){
-                       interleaved_data[(short_data_block_length * blocks) + (i - qty_short_blocks)] = (int) data_block[short_data_block_length];
-               }
-               
-               for(j = 0; j < ecc_block_length; j++) {
-                       interleaved_ecc[(j * blocks) + i] = (int) ecc_block[ecc_block_length - j - 1];
-               }
-               
-               posn += length_this_block;
-       }
-       
-       for(j = 0; j < data_cw; j++) {
-               fullstream[j] = interleaved_data[j];
-       }
-       for(j = 0; j < ecc_cw; j++) {
-               fullstream[j + data_cw] = interleaved_ecc[j];
-       }
-       
-#ifdef _DEBUG_MODE_
-               printf("\nData Stream: \n");
-               for(j = 0; j < (data_cw + ecc_cw); j++) {
-                       printf("%2X ", fullstream[j]);
-               }
-               printf("\n");
-#endif
-}
 
-void place_finder(unsigned char grid[], int size, int x, int y)
-{
-       int xp, yp;
-       
-       int finder[] = {
-               1, 1, 1, 1, 1, 1, 1,
-               1, 0, 0, 0, 0, 0, 1,
-               1, 0, 1, 1, 1, 0, 1,
-               1, 0, 1, 1, 1, 0, 1,
-               1, 0, 1, 1, 1, 0, 1,
-               1, 0, 0, 0, 0, 0, 1,
-               1, 1, 1, 1, 1, 1, 1
-       };
-       
-       for(xp = 0; xp < 7; xp++) {
-               for(yp = 0; yp < 7; yp++) {
-                       if (finder[xp + (7 * yp)] == 1) {
-                               grid[((yp + y) * size) + (xp + x)] = 0x11;
-                       } else {
-                               grid[((yp + y) * size) + (xp + x)] = 0x10;
-                       }
-               }
-       }
+    /* Apply mask */
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            if (mask[(y * size) + x] & (0x01 << best_pattern)) {
+                if (grid[(y * size) + x] & 0x01) {
+                    grid[(y * size) + x] = 0x00;
+                } else {
+                    grid[(y * size) + x] = 0x01;
+                }
+            }
+        }
+    }
+
+    return best_pattern;
 }
 
-void place_align(unsigned char grid[], int size, int x, int y)
-{
-       int xp, yp;
-       
-       int alignment[] = {
-               1, 1, 1, 1, 1,
-               1, 0, 0, 0, 1,
-               1, 0, 1, 0, 1,
-               1, 0, 0, 0, 1,
-               1, 1, 1, 1, 1
-       };
-       
-       x -= 2;
-       y -= 2; /* Input values represent centre of pattern */
-       
-       for(xp = 0; xp < 5; xp++) {
-               for(yp = 0; yp < 5; yp++) {
-                       if (alignment[xp + (5 * yp)] == 1) {
-                               grid[((yp + y) * size) + (xp + x)] = 0x11;
-                       } else {
-                               grid[((yp + y) * size) + (xp + x)] = 0x10;
-                       }
-               }
-       }
+/* Add format information to grid */
+static void add_format_info(unsigned char *grid,const int size,const int ecc_level,const int pattern) {
+    int format = pattern;
+    unsigned int seq;
+    int i;
+
+    switch (ecc_level) {
+        case LEVEL_L: format += 0x08;
+            break;
+        case LEVEL_Q: format += 0x18;
+            break;
+        case LEVEL_H: format += 0x10;
+            break;
+    }
+
+    seq = qr_annex_c[format];
+
+    for (i = 0; i < 6; i++) {
+        grid[(i * size) + 8] += (seq >> i) & 0x01;
+    }
+
+    for (i = 0; i < 8; i++) {
+        grid[(8 * size) + (size - i - 1)] += (seq >> i) & 0x01;
+    }
+
+    for (i = 0; i < 6; i++) {
+        grid[(8 * size) + (5 - i)] += (seq >> (i + 9)) & 0x01;
+    }
+
+    for (i = 0; i < 7; i++) {
+        grid[(((size - 7) + i) * size) + 8] += (seq >> (i + 8)) & 0x01;
+    }
+
+    grid[(7 * size) + 8] += (seq >> 6) & 0x01;
+    grid[(8 * size) + 8] += (seq >> 7) & 0x01;
+    grid[(8 * size) + 7] += (seq >> 8) & 0x01;
 }
 
-void setup_grid(unsigned char* grid, int size, int version)
-{
-       int i, toggle = 1;
-       int loopsize, x, y, xcoord, ycoord;
-
-       /* Add timing patterns */
-       for(i = 0; i < size; i++) {
-               if(toggle == 1) {
-                       grid[(6 * size) + i] = 0x21;
-                       grid[(i * size) + 6] = 0x21;
-                       toggle = 0;
-               } else {
-                       grid[(6 * size) + i] = 0x20;
-                       grid[(i * size) + 6] = 0x20;
-                       toggle = 1;
-               }
-       }
-       
-       /* Add finder patterns */
-       place_finder(grid, size, 0, 0);
-       place_finder(grid, size, 0, size - 7);
-       place_finder(grid, size, size - 7, 0);
-       
-       /* Add separators */
-       for(i = 0; i < 7; i++) {
-               grid[(7 * size) + i] = 0x10;
-               grid[(i * size) + 7] = 0x10;
-               grid[(7 * size) + (size - 1 - i)] = 0x10;
-               grid[(i * size) + (size - 8)] = 0x10;
-               grid[((size - 8) * size) + i] = 0x10;
-               grid[((size - 1 - i) * size) + 7] = 0x10;
-       }
-       grid[(7 * size) + 7] = 0x10;
-       grid[(7 * size) + (size - 8)] = 0x10;
-       grid[((size - 8) * size) + 7] = 0x10;
-       
-       /* Add alignment patterns */
-       if(version != 1) {
-               /* Version 1 does not have alignment patterns */
-               
-               loopsize = qr_align_loopsize[version - 1];
-               for(x = 0; x < loopsize; x++) {
-                       for(y = 0; y < loopsize; y++) {
-                               xcoord = qr_table_e1[((version - 2) * 7) + x];
-                               ycoord = qr_table_e1[((version - 2) * 7) + y];
-                               
-                               if(!(grid[(ycoord * size) + xcoord] & 0x10)) {
-                                       place_align(grid, size, xcoord, ycoord);
-                               }
-                       }
-               }
-       }
-       
-       /* Reserve space for format information */
-       for(i = 0; i < 8; i++) {
-               grid[(8 * size) + i] += 0x20;
-               grid[(i * size) + 8] += 0x20;
-               grid[(8 * size) + (size - 1 - i)] = 0x20;
-               grid[((size - 1 - i) * size) + 8] = 0x20;
-       }
-       grid[(8 * size) + 8] += 20;
-       grid[((size - 1 - 7) * size) + 8] = 0x21; /* Dark Module from Figure 25 */
-       
-       /* Reserve space for version information */
-       if(version >= 7) {
-               for(i = 0; i < 6; i++) {
-                       grid[((size - 9) * size) + i] = 0x20;
-                       grid[((size - 10) * size) + i] = 0x20;
-                       grid[((size - 11) * size) + i] = 0x20;
-                       grid[(i * size) + (size - 9)] = 0x20;
-                       grid[(i * size) + (size - 10)] = 0x20;
-                       grid[(i * size) + (size - 11)] = 0x20;
-               }
-       }
+/* Add version information */
+static void add_version_info(unsigned char *grid,const int size,const int version) {
+    int i;
+
+    long int version_data = qr_annex_d[version - 7];
+    for (i = 0; i < 6; i++) {
+        grid[((size - 11) * size) + i] += (version_data >> (i * 3)) & 0x41;
+        grid[((size - 10) * size) + i] += (version_data >> ((i * 3) + 1)) & 0x41;
+        grid[((size - 9) * size) + i] += (version_data >> ((i * 3) + 2)) & 0x41;
+        grid[(i * size) + (size - 11)] += (version_data >> (i * 3)) & 0x41;
+        grid[(i * size) + (size - 10)] += (version_data >> ((i * 3) + 1)) & 0x41;
+        grid[(i * size) + (size - 9)] += (version_data >> ((i * 3) + 2)) & 0x41;
+    }
 }
 
-int cwbit(int* datastream, int i) {
-       int word = i / 8;
-       int bit = i % 8;
-       int resultant = 0;
-       
-       switch(bit) {
-               case 0: if(datastream[word] & 0x80) { resultant = 1; } else { resultant = 0; } break;
-               case 1: if(datastream[word] & 0x40) { resultant = 1; } else { resultant = 0; } break;
-               case 2: if(datastream[word] & 0x20) { resultant = 1; } else { resultant = 0; } break;
-               case 3: if(datastream[word] & 0x10) { resultant = 1; } else { resultant = 0; } break;
-               case 4: if(datastream[word] & 0x08) { resultant = 1; } else { resultant = 0; } break;
-               case 5: if(datastream[word] & 0x04) { resultant = 1; } else { resultant = 0; } break;
-               case 6: if(datastream[word] & 0x02) { resultant = 1; } else { resultant = 0; } break;
-               case 7: if(datastream[word] & 0x01) { resultant = 1; } else { resultant = 0; } break;
-       }
-       
-       return resultant;
+static size_t blockLength(const size_t start,const char inputMode[],const size_t inputLength) {
+    /* Find the length of the block starting from 'start' */
+    size_t i;
+    int    count;
+    char mode = inputMode[start];
+
+    count = 0;
+    i = start;
+
+    do {
+        count++;
+    } while (((i + count) < inputLength) && (inputMode[i + count] == mode));
+
+    return count;
 }
 
-void populate_grid(unsigned char* grid, int size, int* datastream, int cw)
-{
-       int direction = 1; /* up */
-       int row = 0; /* right hand side */
-       
-       int i, n, x, y;
-       
-       n = cw * 8;
-       y = size - 1;
-       i = 0;
-       do {
-               x = (size - 2) - (row * 2);
-               if(x < 6)
-                       x--; /* skip over vertical timing pattern */
-
-               if(!(grid[(y * size) + (x + 1)] & 0xf0)) {
-                       if (cwbit(datastream, i)) {
-                               grid[(y * size) + (x + 1)] = 0x01;
-                       } else {
-                               grid[(y * size) + (x + 1)] = 0x00;
-                       }
-                       i++;
-               }
-               
-               if(i < n) {
-                       if(!(grid[(y * size) + x] & 0xf0)) {
-                               if (cwbit(datastream, i)) {
-                                       grid[(y * size) + x] = 0x01;
-                               } else {
-                                       grid[(y * size) + x] = 0x00;
-                               }
-                               i++;
-                       }
-               }
-               
-               if(direction) { y--; } else { y++; }
-               if(y == -1) {
-                       /* reached the top */
-                       row++;
-                       y = 0;
-                       direction = 0;
-               }
-               if(y == size) {
-                       /* reached the bottom */
-                       row++;
-                       y = size - 1;
-                       direction = 1;
-               }
-       } while (i < n);
+static int getBinaryLength(const int version, char inputMode[], const unsigned int inputData[], const size_t inputLength, const int gs1, const int eci, const int debug) {
+    /* Calculate the actual bitlength of the proposed binary string */
+    size_t i, j;
+    char currentMode;
+    int count = 0;
+    int alphalength;
+    int blocklength;
+
+    qr_define_mode(inputMode, inputData, inputLength, gs1, version, debug);
+
+    currentMode = ' '; // Null
+
+    if (gs1 == 1) { /* Not applicable to MICROQR */
+        if (version < RMQR_VERSION) {
+            count += 4;
+        } else {
+            count += 3;
+        }
+    }
+
+    if (eci != 0) { // RMQR and MICROQR do not support ECI
+        count += 4;
+        if (eci <= 127) {
+            count += 8;
+        } else if (eci <= 16383) {
+            count += 16;
+        } else {
+            count += 24;
+        }
+    }
+
+    for (i = 0; i < inputLength; i++) {
+        if (inputMode[i] != currentMode) {
+            count += mode_bits(version) + cci_bits(version, inputMode[i]);
+            blocklength = blockLength(i, inputMode, inputLength);
+            switch (inputMode[i]) {
+                case 'K':
+                    count += (blocklength * 13);
+                    break;
+                case 'B':
+                    for (j = i; j < (i + blocklength); j++) {
+                        if (inputData[j] > 0xff) {
+                            count += 16;
+                        } else {
+                            count += 8;
+                        }
+                    }
+                    break;
+                case 'A':
+                    alphalength = blocklength;
+                    if (gs1) {
+                        // In alphanumeric mode % becomes %%
+                        for (j = i; j < (i + blocklength); j++) {
+                            if (inputData[j] == '%') {
+                                alphalength++;
+                            }
+                        }
+                    }
+                    switch (alphalength % 2) {
+                        case 0:
+                            count += (alphalength / 2) * 11;
+                            break;
+                        case 1:
+                            count += ((alphalength - 1) / 2) * 11;
+                            count += 6;
+                            break;
+                    }
+                    break;
+                case 'N':
+                    switch (blocklength % 3) {
+                        case 0:
+                            count += (blocklength / 3) * 10;
+                            break;
+                        case 1:
+                            count += ((blocklength - 1) / 3) * 10;
+                            count += 4;
+                            break;
+                        case 2:
+                            count += ((blocklength - 2) / 3) * 10;
+                            count += 7;
+                            break;
+                    }
+                    break;
+            }
+            currentMode = inputMode[i];
+        }
+    }
+
+    if (debug & ZINT_DEBUG_PRINT) {
+        printf("Estimated Binary Length: %d (version %d, eci %d, gs1 %d)\n", count, version, eci, gs1);
+    }
+
+    return count;
 }
 
-int evaluate(unsigned char *grid, int size, int pattern)
-{
-       int x, y, block;
-       int result = 0;
-       char state;
-       int p;
-       int dark_mods;
-       int percentage, k, k2;
+INTERNAL int qr_code(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
+    int i, j, est_binlen;
+    int ecc_level, autosize, version, max_cw, target_codewords, blocks, size;
+    int bitmask, gs1;
+    int full_multibyte;
+    int canShrink;
 
 #ifndef _MSC_VER
-       char local[size * size];
+    unsigned int jisdata[length + 1];
+    char mode[length + 1];
 #else
-       char* local = (char *)_alloca((size * size) * sizeof(char));
+    unsigned char* datastream;
+    unsigned char* fullstream;
+    unsigned char* grid;
+    unsigned int* jisdata = (unsigned int *) _alloca((length + 1) * sizeof (unsigned int));
+    char* mode = (char *) _alloca(length + 1);
 #endif
 
-       for(x = 0; x < size; x++) {
-               for(y = 0; y < size; y++) {
-                       switch(pattern) {
-                               case 0: if (grid[(y * size) + x] & 0x01) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break;
-                               case 1: if (grid[(y * size) + x] & 0x02) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break;
-                               case 2: if (grid[(y * size) + x] & 0x04) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break;
-                               case 3: if (grid[(y * size) + x] & 0x08) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break;
-                               case 4: if (grid[(y * size) + x] & 0x10) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break;
-                               case 5: if (grid[(y * size) + x] & 0x20) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break;
-                               case 6: if (grid[(y * size) + x] & 0x40) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break;
-                               case 7: if (grid[(y * size) + x] & 0x80) { local[(y * size) + x] = '1'; } else { local[(y * size) + x] = '0'; } break;
-                       }
-               }
-       }
-       
-       /* Test 1: Adjacent modules in row/column in same colour */
-       /* Vertical */
-       for(x = 0; x < size; x++) {
-               state = local[x];
-               block = 0;
-               for(y = 0; y < size; y++) {
-                       if(local[(y * size) + x] == state) {
-                               block++;
-                               if(block ==5)
-                                       result += 3;
-
-                               if(block>5)
-                                       result +=1;
-                       } else {
-                               block=0;
-                       }
-               }
-       }
-       
-       /* Horizontal */
-       for(y = 0; y < size; y++) {
-               state = local[y * size];
-               block = 0;
-               for(x = 0; x < size; x++) {
-                       if(local[(y * size) + x] == state) {
-                               block++;
-                               if(block ==5)
-                                       result += 3;
-
-                               if(block>5)
-                                       result +=1;
-                       } else {
-                               block=0;
-                       }
-               }
-       }
-       
-       /* Test 2 fd02131114 */
-       for(x = 0; x < size-1; x++) {
-               for(y = 0; y < (size - 7) -1; y++) {
-                       // y + 1???
-                       if((local[((y + 1) * size) + x] == '1') &&
-                               (local[((y + 1) * size) + x+1] == '1') &&
-                               (local[(((y + 1)+1) * size) + x] == '1') &&
-                               (local[(((y + 1)+1) * size) + x+1] == '1')
-                               ) { result += 3; }
-
-                       if((local[((y + 1) * size) + x] == '0') &&
-                               (local[((y + 1) * size) + x+1] == '0') &&
-                               (local[(((y + 1)+1) * size) + x] == '0') &&
-                               (local[(((y + 1)+1) * size) + x+1] == '0')
-                               ) { result += 3; }
-               }
-       }
-
-       /* Test 3: fd02131114 */
-       /*pattern 10111010000 */
-       /* Vertical */
-       for(x = 0; x < size; x++) {
-               for(y = 0; y < (size - 11); y++) {
-                       p = 0;
-                       if(local[(y * size) + x] == '1') { p += 1; }
-                       if(local[((y + 1) * size) + x] == '0') { p += 1; }
-                       if(local[((y + 2) * size) + x] == '1') { p += 1; }
-                       if(local[((y + 3) * size) + x] == '1') { p += 1; }
-                       if(local[((y + 4) * size) + x] == '1') { p += 1; }
-                       if(local[((y + 5) * size) + x] == '0') { p += 1; }
-                       if(local[((y + 6) * size) + x] == '1') { p += 1; }
-                       if(local[((y + 7) * size) + x] == '0') { p += 1; }
-                       if(local[((y + 8) * size) + x] == '0') { p += 1; }
-                       if(local[((y + 9) * size) + x] == '0') { p += 1; }
-                       if(local[((y + 10) * size) + x] == '0') { p += 1; }
-                       if(p == 11) {
-                               result += 40;
-                       }
-               }
-       }
-
-       /* Horizontal */
-       for(y = 0; y < size; y++) {
-               for(x = 0; x < (size - 11); x++) {
-                       p = 0;
-                       if(local[(y * size) + x] == '1') { p += 1; }
-                       if(local[(y * size) + x + 1] == '0') { p += 1; }
-                       if(local[(y * size) + x + 2] == '1') { p += 1; }
-                       if(local[(y * size) + x + 3] == '1') { p += 1; }
-                       if(local[(y * size) + x + 4] == '1') { p += 1; }
-                       if(local[(y * size) + x + 5] == '0') { p += 1; }
-                       if(local[(y * size) + x + 6] == '1') { p += 1; }
-                       if(local[(y * size) + x + 7] == '0') { p += 1; }
-                       if(local[(y * size) + x + 8] == '0') { p += 1; }
-                       if(local[(y * size) + x + 9] == '0') { p += 1; }
-                       if(local[(y * size) + x + 10] == '0') { p += 1; }
-                       if(p == 11) {
-                               result += 40;
-                       }
-               }
-       }
-
-       /*pattern 00001011101 */
-       /* Vertical */
-       for(x = 0; x < size; x++) {
-               for(y = 0; y < (size - 11); y++) {
-                       p = 0;
-                       if(local[(y * size) + x] == '0') { p += 1; }
-                       if(local[((y + 1) * size) + x] == '0') { p += 1; }
-                       if(local[((y + 2) * size) + x] == '0') { p += 1; }
-                       if(local[((y + 3) * size) + x] == '0') { p += 1; }
-                       if(local[((y + 4) * size) + x] == '1') { p += 1; }
-                       if(local[((y + 5) * size) + x] == '0') { p += 1; }
-                       if(local[((y + 6) * size) + x] == '1') { p += 1; }
-                       if(local[((y + 7) * size) + x] == '1') { p += 1; }
-                       if(local[((y + 8) * size) + x] == '1') { p += 1; }
-                       if(local[((y + 9) * size) + x] == '0') { p += 1; }
-                       if(local[((y + 10) * size) + x] == '1') { p += 1; }
-                       if(p == 11) {
-                               result += 40;
-                       }
-               }
-       }
-
-       /* Horizontal */
-       for(y = 0; y < size; y++) {
-               for(x = 0; x < (size - 11); x++) {
-                       p = 0;
-                       if(local[(y * size) + x] == '0') { p += 1; }
-                       if(local[(y * size) + x + 1] == '0') { p += 1; }
-                       if(local[(y * size) + x + 2] == '0') { p += 1; }
-                       if(local[(y * size) + x + 3] == '0') { p += 1; }
-                       if(local[(y * size) + x + 4] == '1') { p += 1; }
-                       if(local[(y * size) + x + 5] == '0') { p += 1; }
-                       if(local[(y * size) + x + 6] == '1') { p += 1; }
-                       if(local[(y * size) + x + 7] == '1') { p += 1; }
-                       if(local[(y * size) + x + 8] == '1') { p += 1; }
-                       if(local[(y * size) + x + 9] == '0') { p += 1; }
-                       if(local[(y * size) + x + 10] == '1') { p += 1; }
-                       if(p == 11) {
-                               result += 40;
-                       }
-               }
-       }
-
-       /* Test 4: Proportion of dark modules in entire symbol */
-       dark_mods = 0;
-       for(x = 0; x < size; x++) {
-               for(y = 0; y < size; y++) {
-                       if(local[(y * size) + x] == '1') {
-                               dark_mods++;
-                       }
-               }
-       }
-       percentage = 100 * (dark_mods / (size * size));
-       int m=0;
-       for(x = 0; x < 100; x+=5) {
-               if(x<percentage)
-                       m=x;
-       }
-
-       k=abs((m-50)/5);
-       k2=abs((m+5-50)/5);
-
-       int smallest=k;
-       if(k2<smallest)
-               smallest=k2;
-
-       result += 10 * smallest;
-
-       return result;
-}
+    gs1 = ((symbol->input_mode & 0x07) == GS1_MODE);
+    full_multibyte = symbol->option_3 == ZINT_FULL_MULTIBYTE; /* If set use Kanji mode in DATA_MODE or for single-byte Latin */
+
+    if ((symbol->input_mode & 0x07) == DATA_MODE) {
+        sjis_cpy(source, &length, jisdata, full_multibyte);
+    } else {
+        int done = 0;
+        if (symbol->eci != 20) { /* Unless ECI 20 (Shift JIS) */
+            /* Try single byte (Latin) conversion first */
+            int error_number = sjis_utf8tosb(symbol->eci && symbol->eci <= 899 ? symbol->eci : 3, source, &length, jisdata, full_multibyte);
+            if (error_number == 0) {
+                done = 1;
+            } else if (symbol->eci && symbol->eci <= 899) {
+                strcpy(symbol->errtxt, "575: Invalid characters in input data");
+                return error_number;
+            }
+        }
+        if (!done) {
+            /* Try Shift-JIS */
+            int error_number = sjis_utf8tomb(symbol, source, &length, jisdata);
+            if (error_number != 0) {
+                return error_number;
+            }
+        }
+    }
+
+    est_binlen = getBinaryLength(40, mode, jisdata, length, gs1, symbol->eci, symbol->debug);
+
+    ecc_level = LEVEL_L;
+    max_cw = 2956;
+    if ((symbol->option_1 >= 1) && (symbol->option_1 <= 4)) {
+        switch (symbol->option_1) {
+            case 1:
+                break;
+            case 2: ecc_level = LEVEL_M;
+                max_cw = 2334;
+                break;
+            case 3: ecc_level = LEVEL_Q;
+                max_cw = 1666;
+                break;
+            case 4: ecc_level = LEVEL_H;
+                max_cw = 1276;
+                break;
+        }
+    }
+
+    if (est_binlen > (8 * max_cw)) {
+        strcpy(symbol->errtxt, "561: Input too long for selected error correction level");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    autosize = 40;
+    for (i = 39; i >= 0; i--) {
+        switch (ecc_level) {
+            case LEVEL_L:
+                if ((8 * qr_data_codewords_L[i]) >= est_binlen) {
+                    autosize = i + 1;
+                }
+                break;
+            case LEVEL_M:
+                if ((8 * qr_data_codewords_M[i]) >= est_binlen) {
+                    autosize = i + 1;
+                }
+                break;
+            case LEVEL_Q:
+                if ((8 * qr_data_codewords_Q[i]) >= est_binlen) {
+                    autosize = i + 1;
+                }
+                break;
+            case LEVEL_H:
+                if ((8 * qr_data_codewords_H[i]) >= est_binlen) {
+                    autosize = i + 1;
+                }
+                break;
+        }
+    }
+    if (autosize != 40) {
+        est_binlen = getBinaryLength(autosize, mode, jisdata, length, gs1, symbol->eci, symbol->debug);
+    }
+
+    // Now see if the optimised binary will fit in a smaller symbol.
+    canShrink = 1;
+
+    do {
+        if (autosize == 1) {
+            canShrink = 0;
+        } else {
+            est_binlen = getBinaryLength(autosize - 1, mode, jisdata, length, gs1, symbol->eci, symbol->debug);
+
+            switch (ecc_level) {
+                case LEVEL_L:
+                    if ((8 * qr_data_codewords_L[autosize - 2]) < est_binlen) {
+                        canShrink = 0;
+                    }
+                    break;
+                case LEVEL_M:
+                    if ((8 * qr_data_codewords_M[autosize - 2]) < est_binlen) {
+                        canShrink = 0;
+                    }
+                    break;
+                case LEVEL_Q:
+                    if ((8 * qr_data_codewords_Q[autosize - 2]) < est_binlen) {
+                        canShrink = 0;
+                    }
+                    break;
+                case LEVEL_H:
+                    if ((8 * qr_data_codewords_H[autosize - 2]) < est_binlen) {
+                        canShrink = 0;
+                    }
+                    break;
+            }
+
+            if (canShrink == 1) {
+                // Optimisation worked - data will fit in a smaller symbol
+                autosize--;
+            } else {
+                // Data did not fit in the smaller symbol, revert to original size
+                est_binlen = getBinaryLength(autosize, mode, jisdata, length, gs1, symbol->eci, symbol->debug);
+            }
+        }
+    } while (canShrink == 1);
+
+    version = autosize;
+
+    if ((symbol->option_2 >= 1) && (symbol->option_2 <= 40)) {
+        /* If the user has selected a larger symbol than the smallest available,
+         then use the size the user has selected, and re-optimise for this
+         symbol size.
+         */
+        if (symbol->option_2 > version) {
+            version = symbol->option_2;
+            est_binlen = getBinaryLength(symbol->option_2, mode, jisdata, length, gs1, symbol->eci, symbol->debug);
+        }
+
+        if (symbol->option_2 < version) {
+            strcpy(symbol->errtxt, "569: Input too long for selected symbol size");
+            return ZINT_ERROR_TOO_LONG;
+        }
+    }
+
+    /* Ensure maxium error correction capacity unless user-specified */
+    if (symbol->option_1 == -1 || symbol->option_1 != ecc_level) {
+        if (est_binlen <= qr_data_codewords_M[version - 1] * 8) {
+            ecc_level = LEVEL_M;
+        }
+        if (est_binlen <= qr_data_codewords_Q[version - 1] * 8) {
+            ecc_level = LEVEL_Q;
+        }
+        if (est_binlen <= qr_data_codewords_H[version - 1] * 8) {
+            ecc_level = LEVEL_H;
+        }
+    }
+
+    target_codewords = qr_data_codewords_L[version - 1];
+    blocks = qr_blocks_L[version - 1];
+    switch (ecc_level) {
+        case LEVEL_M: target_codewords = qr_data_codewords_M[version - 1];
+            blocks = qr_blocks_M[version - 1];
+            break;
+        case LEVEL_Q: target_codewords = qr_data_codewords_Q[version - 1];
+            blocks = qr_blocks_Q[version - 1];
+            break;
+        case LEVEL_H: target_codewords = qr_data_codewords_H[version - 1];
+            blocks = qr_blocks_H[version - 1];
+            break;
+    }
+
+#ifndef _MSC_VER
+    unsigned char datastream[target_codewords + 1];
+    unsigned char fullstream[qr_total_codewords[version - 1] + 1];
+#else
+    datastream = (unsigned char *) _alloca(target_codewords + 1);
+    fullstream = (unsigned char *) _alloca(qr_total_codewords[version - 1] + 1);
+#endif
+
+    qr_binary(datastream, version, target_codewords, mode, jisdata, length, gs1, symbol->eci, est_binlen, symbol->debug);
+#ifdef ZINT_TEST
+    if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords);
+#endif
+    add_ecc(fullstream, datastream, version, target_codewords, blocks, symbol->debug);
 
-void add_format_info_eval(unsigned char *eval, int size, int ecc_level, int pattern)
-{
-       /* Add format information to grid */
+    size = qr_sizes[version - 1];
+#ifndef _MSC_VER
+    unsigned char grid[size * size];
+#else
+    grid = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
+#endif
 
-       int format = pattern;
-       unsigned int seq;
-       int i;
+    for (i = 0; i < size; i++) {
+        for (j = 0; j < size; j++) {
+            grid[(i * size) + j] = 0;
+        }
+    }
 
-       switch(ecc_level) {
-               case LEVEL_L: format += 0x08; break;
-               case LEVEL_Q: format += 0x18; break;
-               case LEVEL_H: format += 0x10; break;
-       }
+    setup_grid(grid, size, version);
+    populate_grid(grid, size, size, fullstream, qr_total_codewords[version - 1]);
 
-       seq = qr_annex_c[format];
+    if (version >= 7) {
+        add_version_info(grid, size, version);
+    }
 
-       for(i = 0; i < 6; i++) {
-               eval[(i * size) + 8] = (seq >> i) & 0x01 ? (0x01 >> pattern) : 0x00;
-       }
+    bitmask = apply_bitmask(grid, size, ecc_level);
 
-       for(i = 0; i < 8; i++) {
-               eval[(8 * size) + (size - i - 1)] = (seq >> i) & 0x01 ? (0x01 >> pattern) : 0x00;
-       }
+    add_format_info(grid, size, ecc_level, bitmask);
 
-       for(i = 0; i < 6; i++) {
-               eval[(8 * size) + (5 - i)] = (seq >> (i + 9)) & 0x01 ? (0x01 >> pattern) : 0x00;
-       }
+    symbol->width = size;
+    symbol->rows = size;
 
-       for(i = 0; i < 7; i++) {
-               eval[(((size - 7) + i) * size) + 8] = (seq >> (i + 8)) & 0x01 ? (0x01 >> pattern) : 0x00;
-       }
+    for (i = 0; i < size; i++) {
+        for (j = 0; j < size; j++) {
+            if (grid[(i * size) + j] & 0x01) {
+                set_module(symbol, i, j);
+            }
+        }
+        symbol->row_height[i] = 1;
+    }
 
-       eval[(7 * size) + 8] = (seq >> 6) & 0x01 ? (0x01 >> pattern) : 0x00;
-       eval[(8 * size) + 8] = (seq >> 7) & 0x01 ? (0x01 >> pattern) : 0x00;
-       eval[(8 * size) + 7] = (seq >> 8) & 0x01 ? (0x01 >> pattern) : 0x00;
+    return 0;
 }
 
-int apply_bitmask(unsigned char *grid, int size, int ecc_level)
-{
-       int x, y;
-       unsigned char p;
-       int pattern, penalty[8];
-       int best_val, best_pattern;
-       int bit;
-       
-#ifndef _MSC_VER
-       unsigned char mask[size * size];
-       unsigned char eval[size * size];
+static void micro_qr_m1(struct zint_symbol *symbol, char binary_data[]) {
+    int i, j, latch;
+    int bits_total, bits_left;
+    int data_codewords, ecc_codewords;
+    unsigned char data_blocks[4], ecc_blocks[3];
+
+    bits_total = 20;
+    latch = 0;
+
+    /* Add terminator */
+    bits_left = bits_total - (int)strlen(binary_data);
+    if (bits_left <= 3) {
+        for (i = 0; i < bits_left; i++) {
+            strcat(binary_data, "0");
+        }
+        latch = 1;
+    } else {
+        strcat(binary_data, "000");
+    }
+
+    if (latch == 0) {
+        /* Manage last (4-bit) block */
+        bits_left = bits_total - (int)strlen(binary_data);
+        if (bits_left <= 4) {
+            for (i = 0; i < bits_left; i++) {
+                strcat(binary_data, "0");
+            }
+            latch = 1;
+        }
+    }
+
+    if (latch == 0) {
+        /* Complete current byte */
+        int remainder = 8 - (strlen(binary_data) % 8);
+        if (remainder == 8) {
+            remainder = 0;
+        }
+        for (i = 0; i < remainder; i++) {
+            strcat(binary_data, "0");
+        }
+
+        /* Add padding */
+        bits_left = bits_total - (int)strlen(binary_data);
+        if (bits_left > 4) {
+            remainder = (bits_left - 4) / 8;
+            for (i = 0; i < remainder; i++) {
+                strcat(binary_data, (i & 1) ? "00010001" : "11101100");
+            }
+        }
+        bin_append(0, 4, binary_data);
+    }
+
+    data_codewords = 3;
+    ecc_codewords = 2;
+
+    /* Copy data into codewords */
+    for (i = 0; i < (data_codewords - 1); i++) {
+        data_blocks[i] = 0;
+        for (j = 0; j < 8; j++) {
+            if (binary_data[(i * 8) + j] == '1') {
+                data_blocks[i] += 0x80 >> j;
+            }
+        }
+    }
+    data_blocks[2] = 0;
+    for (j = 0; j < 4; j++) {
+        if (binary_data[16 + j] == '1') {
+            data_blocks[2] += 0x80 >> j;
+        }
+    }
+#ifdef ZINT_TEST
+    if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, data_blocks, data_codewords);
 #else
-       unsigned char* mask = (unsigned char *)_alloca((size * size) * sizeof(unsigned char));
-       unsigned char* eval = (unsigned char *)_alloca((size * size) * sizeof(unsigned char));
+    (void)symbol; /* Unused */
 #endif
 
-       /* Perform data masking */
-       for(x = 0; x < size; x++) {
-               for(y = 0; y < size; y++) {
-                       mask[(y * size) + x] = 0x00;
-                       
-                       // all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array.
-                       if (!(grid[(y * size) + x] & 0xf0)) { // exclude areas not to be masked.
-                               if(((y + x) & 1) == 0) { mask[(y * size) + x] += 0x01; }
-                               if((y & 1) == 0) { mask[(y * size) + x] += 0x02; }
-                               if((x % 3) == 0) { mask[(y * size) + x] += 0x04; }
-                               if(((y + x) % 3) == 0) { mask[(y * size) + x] += 0x08; }
-                               if((((y / 2) + (x / 3)) & 1) == 0) { mask[(y * size) + x] += 0x10; }
-                               if((((y * x) & 1) + ((y * x) % 3)) == 0) { mask[(y * size) + x] += 0x20; }
-                               if(((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) { mask[(y * size) + x] += 0x40; }
-                               if(((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) { mask[(y * size) + x] += 0x80; }
-                       }
-               }
-       }
-
-       // apply data masks to grid, result in eval
-       for(x = 0; x < size; x++) {
-               for(y = 0; y < size; y++) {
-                       if(grid[(y * size) + x] & 0x01) { p = 0xff; } else { p = 0x00; }
-                       
-                       eval[(y * size) + x] = mask[(y * size) + x] ^ p;
-               }
-       }
-
-       /* Evaluate result */
-       for(pattern = 0; pattern < 8; pattern++) {
-               add_format_info_eval(eval, size, ecc_level, pattern);
-
-               penalty[pattern] = evaluate(eval, size, pattern);
-       }
-       
-       best_pattern = 0;
-       best_val = penalty[0];
-       for(pattern = 1; pattern < 8; pattern++) {
-               if(penalty[pattern] < best_val) {
-                       best_pattern = pattern;
-                       best_val = penalty[pattern];
-               }
-       }
-       
-       /* Apply mask */
-       for(x = 0; x < size; x++) {
-               for(y = 0; y < size; y++) {
-                       bit = 0;
-                       switch(best_pattern) {
-                               case 0: if(mask[(y * size) + x] & 0x01) { bit = 1; } break;
-                               case 1: if(mask[(y * size) + x] & 0x02) { bit = 1; } break;
-                               case 2: if(mask[(y * size) + x] & 0x04) { bit = 1; } break;
-                               case 3: if(mask[(y * size) + x] & 0x08) { bit = 1; } break;
-                               case 4: if(mask[(y * size) + x] & 0x10) { bit = 1; } break;
-                               case 5: if(mask[(y * size) + x] & 0x20) { bit = 1; } break;
-                               case 6: if(mask[(y * size) + x] & 0x40) { bit = 1; } break;
-                               case 7: if(mask[(y * size) + x] & 0x80) { bit = 1; } break;
-                       }
-                       if(bit == 1) {
-                               if(grid[(y * size) + x] & 0x01) {
-                                       grid[(y * size) + x] = 0x00;
-                               } else {
-                                       grid[(y * size) + x] = 0x01;
-                               }
-                       }
-               }
-       }
-       
-       return best_pattern;
-}
+    /* Calculate Reed-Solomon error codewords */
+    rs_init_gf(0x11d);
+    rs_init_code(ecc_codewords, 0);
+    rs_encode(data_codewords, data_blocks, ecc_blocks);
+    rs_free();
 
-void add_format_info(unsigned char *grid, int size, int ecc_level, int pattern)
-{
-       /* Add format information to grid */
-       
-       int format = pattern;
-       unsigned int seq;
-       int i;
-       
-       switch(ecc_level) {
-               case LEVEL_L: format += 0x08; break;
-               case LEVEL_Q: format += 0x18; break;
-               case LEVEL_H: format += 0x10; break;
-       }
-
-       seq = qr_annex_c[format];
-       
-       for(i = 0; i < 6; i++) {
-               grid[(i * size) + 8] += (seq >> i) & 0x01;
-       }
-       
-       for(i = 0; i < 8; i++) {
-               grid[(8 * size) + (size - i - 1)] += (seq >> i) & 0x01;
-       }
-       
-       for(i = 0; i < 6; i++) {
-               grid[(8 * size) + (5 - i)] += (seq >> (i + 9)) & 0x01;
-       }
-       
-       for(i = 0; i < 7; i++) {
-               grid[(((size - 7) + i) * size) + 8] += (seq >> (i + 8)) & 0x01;
-       }
-       
-       grid[(7 * size) + 8] += (seq >> 6) & 0x01;
-       grid[(8 * size) + 8] += (seq >> 7) & 0x01;
-       grid[(8 * size) + 7] += (seq >> 8) & 0x01;
+    /* Add Reed-Solomon codewords to binary data */
+    for (i = 0; i < ecc_codewords; i++) {
+        bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data);
+    }
 }
 
-void add_version_info(unsigned char *grid, int size, int version)
-{
-       /* Add version information */
-       int i;
-       
-       long int version_data = qr_annex_d[version - 7];
-       for(i = 0; i < 6; i++) {
-               grid[((size - 11) * size) + i] += (version_data >> (i * 3)) & 0x41;
-               grid[((size - 10) * size) + i] += (version_data >> ((i * 3) + 1)) & 0x41;
-               grid[((size - 9) * size) + i] += (version_data >> ((i * 3) + 2)) & 0x41;
-               grid[(i * size) + (size - 11)] += (version_data >> (i * 3)) & 0x41;
-               grid[(i * size) + (size - 10)] += (version_data >> ((i * 3) + 1)) & 0x41;
-               grid[(i * size) + (size - 9)] += (version_data >> ((i * 3) + 2)) & 0x41;
-       }
+static void micro_qr_m2(struct zint_symbol *symbol, char binary_data[], const int ecc_mode) {
+    int i, j, latch;
+    int bits_total=0, bits_left;
+    int data_codewords=0, ecc_codewords=0;
+    unsigned char data_blocks[6], ecc_blocks[7];
+
+    latch = 0;
+
+    if (ecc_mode == LEVEL_L) {
+        bits_total = 40;
+    }
+    else if (ecc_mode == LEVEL_M) {
+        bits_total = 32;
+    }
+    else assert(0);
+
+    /* Add terminator */
+    bits_left = bits_total - (int)strlen(binary_data);
+    if (bits_left <= 5) {
+        for (i = 0; i < bits_left; i++) {
+            strcat(binary_data, "0");
+        }
+        latch = 1;
+    } else {
+        bin_append(0, 5, binary_data);
+    }
+
+    if (latch == 0) {
+        /* Complete current byte */
+        int remainder = 8 - (strlen(binary_data) % 8);
+        if (remainder == 8) {
+            remainder = 0;
+        }
+        for (i = 0; i < remainder; i++) {
+            strcat(binary_data, "0");
+        }
+
+        /* Add padding */
+        bits_left = bits_total - (int)strlen(binary_data);
+        remainder = bits_left / 8;
+        for (i = 0; i < remainder; i++) {
+            strcat(binary_data, (i & 1) ? "00010001" : "11101100");
+        }
+    }
+
+    if (ecc_mode == LEVEL_L) {
+        data_codewords = 5;
+        ecc_codewords = 5;
+    }
+    else if (ecc_mode == LEVEL_M) {
+        data_codewords = 4;
+        ecc_codewords = 6;
+    }
+    else assert(0);
+
+    /* Copy data into codewords */
+    for (i = 0; i < data_codewords; i++) {
+        data_blocks[i] = 0;
+
+        for (j = 0; j < 8; j++) {
+            if (binary_data[(i * 8) + j] == '1') {
+                data_blocks[i] += 0x80 >> j;
+            }
+        }
+    }
+#ifdef ZINT_TEST
+    if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, data_blocks, data_codewords);
+#else
+    (void)symbol; /* Unused */
+#endif
+
+    /* Calculate Reed-Solomon error codewords */
+    rs_init_gf(0x11d);
+    rs_init_code(ecc_codewords, 0);
+    rs_encode(data_codewords, data_blocks, ecc_blocks);
+    rs_free();
+
+    /* Add Reed-Solomon codewords to binary data */
+    for (i = 0; i < ecc_codewords; i++) {
+        bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data);
+    }
+
+    return;
 }
 
-int qr_code(struct zint_symbol *symbol, unsigned char source[], int length)
-{
-       int error_number, i, j, glyph, est_binlen;
-       int ecc_level, autosize, version, max_cw, target_binlen, blocks, size;
-       int bitmask, gs1;
-       
-#ifndef _MSC_VER
-       int utfdata[length + 1];
-       int jisdata[length + 1];
-       char mode[length + 1];
+static void micro_qr_m3(struct zint_symbol *symbol, char binary_data[], const int ecc_mode) {
+    int i, j, latch;
+    int bits_total=0, bits_left;
+    int data_codewords=0, ecc_codewords=0;
+    unsigned char data_blocks[12], ecc_blocks[9];
+
+    latch = 0;
+
+    if (ecc_mode == LEVEL_L) {
+        bits_total = 84;
+    }
+    else if (ecc_mode == LEVEL_M) {
+        bits_total = 68;
+    }
+    else assert(0);
+
+    /* Add terminator */
+    bits_left = bits_total - (int)strlen(binary_data);
+    if (bits_left <= 7) {
+        for (i = 0; i < bits_left; i++) {
+            strcat(binary_data, "0");
+        }
+        latch = 1;
+    } else {
+        bin_append(0, 7, binary_data);
+    }
+
+    if (latch == 0) {
+        /* Manage last (4-bit) block */
+        bits_left = bits_total - (int)strlen(binary_data);
+        if (bits_left <= 4) {
+            for (i = 0; i < bits_left; i++) {
+                strcat(binary_data, "0");
+            }
+            latch = 1;
+        }
+    }
+
+    if (latch == 0) {
+        /* Complete current byte */
+        int remainder = 8 - (strlen(binary_data) % 8);
+        if (remainder == 8) {
+            remainder = 0;
+        }
+        for (i = 0; i < remainder; i++) {
+            strcat(binary_data, "0");
+        }
+
+        /* Add padding */
+        bits_left = bits_total - (int)strlen(binary_data);
+        if (bits_left > 4) {
+            remainder = (bits_left - 4) / 8;
+            for (i = 0; i < remainder; i++) {
+                strcat(binary_data, (i & 1) ? "00010001" : "11101100");
+            }
+        }
+        bin_append(0, 4, binary_data);
+    }
+
+    if (ecc_mode == LEVEL_L) {
+        data_codewords = 11;
+        ecc_codewords = 6;
+    }
+    else if (ecc_mode == LEVEL_M) {
+        data_codewords = 9;
+        ecc_codewords = 8;
+    }
+    else assert(0);
+
+    /* Copy data into codewords */
+    for (i = 0; i < (data_codewords - 1); i++) {
+        data_blocks[i] = 0;
+
+        for (j = 0; j < 8; j++) {
+            if (binary_data[(i * 8) + j] == '1') {
+                data_blocks[i] += 0x80 >> j;
+            }
+        }
+    }
+
+    if (ecc_mode == LEVEL_L) {
+        data_blocks[10] = 0;
+        for (j = 0; j < 4; j++) {
+            if (binary_data[80 + j] == '1') {
+                data_blocks[10] += 0x80 >> j;
+            }
+        }
+    }
+
+    if (ecc_mode == LEVEL_M) {
+        data_blocks[8] = 0;
+        for (j = 0; j < 4; j++) {
+            if (binary_data[64 + j] == '1') {
+                data_blocks[8] += 0x80 >> j;
+            }
+        }
+    }
+#ifdef ZINT_TEST
+    if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, data_blocks, data_codewords);
 #else
-       int* utfdata = (int *)_alloca((length + 1) * sizeof(int));
-       int* jisdata = (int *)_alloca((length + 1) * sizeof(int));
-       char* mode = (char *)_alloca(length + 1);
+    (void)symbol; /* Unused */
 #endif
-       
-       gs1 = (symbol->input_mode == GS1_MODE);
-       
-       switch(symbol->input_mode) {
-               case DATA_MODE:
-                       for(i = 0; i < length; i++) {
-                               jisdata[i] = (int)source[i];
-                       }
-                       break;
-               default:
-                       /* Convert Unicode input to Shift-JIS */
-                       error_number = utf8toutf16(symbol, source, utfdata, &length);
-                       if(error_number != 0) { return error_number; }
-                       
-                       for(i = 0; i < length; i++) {
-                               if(utfdata[i] <= 0xff) {
-                                       jisdata[i] = utfdata[i];
-                               } else {
-                                       j = 0;
-                                       glyph = 0;
-                                       do {
-                                               if(sjis_lookup[j * 2] == utfdata[i]) {
-                                                       glyph = sjis_lookup[(j * 2) + 1];
-                                               }
-                                               j++;
-                                       } while ((j < 6843) && (glyph == 0));
-                                       if(glyph == 0) {
-                                               strcpy(symbol->errtxt, "Invalid character in input data");
-                                               return ERROR_INVALID_DATA;
-                                       }
-                                       jisdata[i] = glyph;
-                               }
-                       }
-                       break;
-       }
-       
-       define_mode(mode, jisdata, length, gs1);
-       est_binlen = estimate_binary_length(mode, length, gs1);
-       
-       ecc_level = LEVEL_L;
-       max_cw = 2956;
-       if((symbol->option_1 >= 1) && (symbol->option_1 <= 4)) {
-               switch (symbol->option_1) {
-                       case 1: ecc_level = LEVEL_L; max_cw = 2956; break;
-                       case 2: ecc_level = LEVEL_M; max_cw = 2334; break;
-                       case 3: ecc_level = LEVEL_Q; max_cw = 1666; break;
-                       case 4: ecc_level = LEVEL_H; max_cw = 1276; break;
-               }
-       }
-       
-       if(est_binlen > (8 * max_cw)) {
-               strcpy(symbol->errtxt, "Input too long for selected error correction level");
-               return ERROR_TOO_LONG;
-       }
-       
-       autosize = 40;
-       for(i = 39; i >= 0; i--) {
-               switch(ecc_level) {
-                       case LEVEL_L:
-                               if ((8 * qr_data_codewords_L[i]) >= est_binlen) {
-                                       autosize = i + 1;
-                               }
-                               break;
-                       case LEVEL_M:
-                               if ((8 * qr_data_codewords_M[i]) >= est_binlen) {
-                                       autosize = i + 1;
-                               }
-                               break;
-                       case LEVEL_Q:
-                               if ((8 * qr_data_codewords_Q[i]) >= est_binlen) {
-                                       autosize = i + 1;
-                               }
-                               break;
-                       case LEVEL_H:
-                               if ((8 * qr_data_codewords_H[i]) >= est_binlen) {
-                                       autosize = i + 1;
-                               }
-                               break;
-               }
-       }
-       
-       if((symbol->option_2 >= 1) && (symbol->option_2 <= 40)) {
-               if (symbol->option_2 > autosize) {
-                       version = symbol->option_2;
-               } else {
-                       version = autosize;
-               }
-       } else {
-               version = autosize;
-       }
-       
-       /* Ensure maxium error correction capacity */
-       if(est_binlen <= qr_data_codewords_M[version - 1]) { ecc_level = LEVEL_M; }
-       if(est_binlen <= qr_data_codewords_Q[version - 1]) { ecc_level = LEVEL_Q; }
-       if(est_binlen <= qr_data_codewords_H[version - 1]) { ecc_level = LEVEL_H; }
-
-       target_binlen = qr_data_codewords_L[version - 1]; blocks = qr_blocks_L[version - 1];
-       switch(ecc_level) {
-               case LEVEL_M: target_binlen = qr_data_codewords_M[version - 1]; blocks = qr_blocks_M[version - 1]; break;
-               case LEVEL_Q: target_binlen = qr_data_codewords_Q[version - 1]; blocks = qr_blocks_Q[version - 1]; break;
-               case LEVEL_H: target_binlen = qr_data_codewords_H[version - 1]; blocks = qr_blocks_H[version - 1]; break;
-       }
-       
-#ifndef _MSC_VER
-       int datastream[target_binlen + 1];
-       int fullstream[qr_total_codewords[version - 1] + 1];
+
+    /* Calculate Reed-Solomon error codewords */
+    rs_init_gf(0x11d);
+    rs_init_code(ecc_codewords, 0);
+    rs_encode(data_codewords, data_blocks, ecc_blocks);
+    rs_free();
+
+    /* Add Reed-Solomon codewords to binary data */
+    for (i = 0; i < ecc_codewords; i++) {
+        bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data);
+    }
+
+    return;
+}
+
+static void micro_qr_m4(struct zint_symbol *symbol, char binary_data[], const int ecc_mode) {
+    int i, j, latch;
+    int bits_total=0, bits_left;
+    int data_codewords=0, ecc_codewords=0;
+    unsigned char data_blocks[17], ecc_blocks[15];
+
+    latch = 0;
+
+    if (ecc_mode == LEVEL_L) {
+        bits_total = 128;
+    }
+    else if (ecc_mode == LEVEL_M) {
+        bits_total = 112;
+    }
+    else if (ecc_mode == LEVEL_Q) {
+        bits_total = 80;
+    }
+    else assert(0);
+
+    /* Add terminator */
+    bits_left = bits_total - (int)strlen(binary_data);
+    if (bits_left <= 9) {
+        for (i = 0; i < bits_left; i++) {
+            strcat(binary_data, "0");
+        }
+        latch = 1;
+    } else {
+        bin_append(0, 9, binary_data);
+    }
+
+    if (latch == 0) {
+        /* Complete current byte */
+        int remainder = 8 - (strlen(binary_data) % 8);
+        if (remainder == 8) {
+            remainder = 0;
+        }
+        for (i = 0; i < remainder; i++) {
+            strcat(binary_data, "0");
+        }
+
+        /* Add padding */
+        bits_left = bits_total - (int)strlen(binary_data);
+        remainder = bits_left / 8;
+        for (i = 0; i < remainder; i++) {
+            strcat(binary_data, (i & 1) ? "00010001" : "11101100");
+        }
+    }
+
+    if (ecc_mode == LEVEL_L) {
+        data_codewords = 16;
+        ecc_codewords = 8;
+    }
+    else if (ecc_mode == LEVEL_M) {
+        data_codewords = 14;
+        ecc_codewords = 10;
+    }
+    else if (ecc_mode == LEVEL_Q) {
+        data_codewords = 10;
+        ecc_codewords = 14;
+    }
+    else assert(0);
+
+    /* Copy data into codewords */
+    for (i = 0; i < data_codewords; i++) {
+        data_blocks[i] = 0;
+
+        for (j = 0; j < 8; j++) {
+            if (binary_data[(i * 8) + j] == '1') {
+                data_blocks[i] += 0x80 >> j;
+            }
+        }
+    }
+#ifdef ZINT_TEST
+    if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, data_blocks, data_codewords);
 #else
-       int* datastream = (int *)_alloca((target_binlen + 1) * sizeof(int));
-       int* fullstream = (int *)_alloca((qr_total_codewords[version - 1] + 1) * sizeof(int));
+    (void)symbol; /* Unused */
 #endif
 
-       qr_binary(datastream, version, target_binlen, mode, jisdata, length, gs1, est_binlen);
-       add_ecc(fullstream, datastream, version, target_binlen, blocks);
-       
-       size = qr_sizes[version - 1];
+    /* Calculate Reed-Solomon error codewords */
+    rs_init_gf(0x11d);
+    rs_init_code(ecc_codewords, 0);
+    rs_encode(data_codewords, data_blocks, ecc_blocks);
+    rs_free();
+
+    /* Add Reed-Solomon codewords to binary data */
+    for (i = 0; i < ecc_codewords; i++) {
+        bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data);
+    }
+}
+
+static void micro_setup_grid(unsigned char* grid,const int size) {
+    int i, toggle = 1;
+
+    /* Add timing patterns */
+    for (i = 0; i < size; i++) {
+        if (toggle == 1) {
+            grid[i] = 0x21;
+            grid[(i * size)] = 0x21;
+            toggle = 0;
+        } else {
+            grid[i] = 0x20;
+            grid[(i * size)] = 0x20;
+            toggle = 1;
+        }
+    }
+
+    /* Add finder patterns */
+    place_finder(grid, size, 0, 0);
+
+    /* Add separators */
+    for (i = 0; i < 7; i++) {
+        grid[(7 * size) + i] = 0x10;
+        grid[(i * size) + 7] = 0x10;
+    }
+    grid[(7 * size) + 7] = 0x10;
+
+
+    /* Reserve space for format information */
+    for (i = 0; i < 8; i++) {
+        grid[(8 * size) + i] += 0x20;
+        grid[(i * size) + 8] += 0x20;
+    }
+    grid[(8 * size) + 8] += 20;
+}
+
+static void micro_populate_grid(unsigned char* grid,const int size,const char full_stream[]) {
+    int direction = 1; /* up */
+    int row = 0; /* right hand side */
+    size_t n, i;
+    int y;
+
+    n = strlen(full_stream);
+    y = size - 1;
+    i = 0;
+    do {
+        int x = (size - 2) - (row * 2);
+
+        if (!(grid[(y * size) + (x + 1)] & 0xf0)) {
+            if (full_stream[i] == '1') {
+                grid[(y * size) + (x + 1)] = 0x01;
+            } else {
+                grid[(y * size) + (x + 1)] = 0x00;
+            }
+            i++;
+        }
+
+        if (i < n) {
+            if (!(grid[(y * size) + x] & 0xf0)) {
+                if (full_stream[i] == '1') {
+                    grid[(y * size) + x] = 0x01;
+                } else {
+                    grid[(y * size) + x] = 0x00;
+                }
+                i++;
+            }
+        }
+
+        if (direction) {
+            y--;
+        } else {
+            y++;
+        }
+        if (y == 0) {
+            /* reached the top */
+            row++;
+            y = 1;
+            direction = 0;
+        }
+        if (y == size) {
+            /* reached the bottom */
+            row++;
+            y = size - 1;
+            direction = 1;
+        }
+    } while (i < n);
+}
+
+static int micro_evaluate(const unsigned char *grid,const int size,const int pattern) {
+    int sum1, sum2, i, filter = 0, retval;
+
+    switch (pattern) {
+        case 0: filter = 0x01;
+            break;
+        case 1: filter = 0x02;
+            break;
+        case 2: filter = 0x04;
+            break;
+        case 3: filter = 0x08;
+            break;
+    }
+
+    sum1 = 0;
+    sum2 = 0;
+    for (i = 1; i < size; i++) {
+        if (grid[(i * size) + size - 1] & filter) {
+            sum1++;
+        }
+        if (grid[((size - 1) * size) + i] & filter) {
+            sum2++;
+        }
+    }
+
+    if (sum1 <= sum2) {
+        retval = (sum1 * 16) + sum2;
+    } else {
+        retval = (sum2 * 16) + sum1;
+    }
+
+    return retval;
+}
+
+static int micro_apply_bitmask(unsigned char *grid,const int size) {
+    int x, y;
+    unsigned char p;
+    int pattern, value[8];
+    int best_val, best_pattern;
+
 #ifndef _MSC_VER
-       unsigned char grid[size * size];
+    unsigned char mask[size * size];
+    unsigned char eval[size * size];
 #else
-       unsigned char* grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char));
+    unsigned char* mask = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
+    unsigned char* eval = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
 #endif
-       
-       for(i = 0; i < size; i++) {
-               for(j = 0; j < size; j++) {
-                       grid[(i * size) + j] = 0;
-               }
-       }
-       
-       setup_grid(grid, size, version);
-       populate_grid(grid, size, fullstream, qr_total_codewords[version - 1]);
-
-       if(version >= 7) {
-               add_version_info(grid, size, version);
-       }
-       
-       bitmask = apply_bitmask(grid, size, ecc_level);
-
-       add_format_info(grid, size, ecc_level, bitmask);
-
-       symbol->width = size;
-       symbol->rows = size;
-       
-       for(i = 0; i < size; i++) {
-               for(j = 0; j < size; j++) {
-                       if(grid[(i * size) + j] & 0x01) {
-                               set_module(symbol, i, j);
-                       }
-               }
-               symbol->row_height[i] = 1;
-       }
-       
-       return 0;
+
+    /* Perform data masking */
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            mask[(y * size) + x] = 0x00;
+
+            if (!(grid[(y * size) + x] & 0xf0)) {
+                if ((y & 1) == 0) {
+                    mask[(y * size) + x] += 0x01;
+                }
+
+                if ((((y / 2) + (x / 3)) & 1) == 0) {
+                    mask[(y * size) + x] += 0x02;
+                }
+
+                if (((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) {
+                    mask[(y * size) + x] += 0x04;
+                }
+
+                if (((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) {
+                    mask[(y * size) + x] += 0x08;
+                }
+            }
+        }
+    }
+
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            if (grid[(y * size) + x] & 0x01) {
+                p = 0xff;
+            } else {
+                p = 0x00;
+            }
+
+            eval[(y * size) + x] = mask[(y * size) + x] ^ p;
+        }
+    }
+
+
+    /* Evaluate result */
+    for (pattern = 0; pattern < 8; pattern++) {
+        value[pattern] = micro_evaluate(eval, size, pattern);
+    }
+
+    best_pattern = 0;
+    best_val = value[0];
+    for (pattern = 1; pattern < 4; pattern++) {
+        if (value[pattern] > best_val) {
+            best_pattern = pattern;
+            best_val = value[pattern];
+        }
+    }
+
+    /* Apply mask */
+    for (x = 0; x < size; x++) {
+        for (y = 0; y < size; y++) {
+            if (mask[(y * size) + x] & (0x01 << best_pattern)) {
+                if (grid[(y * size) + x] & 0x01) {
+                    grid[(y * size) + x] = 0x00;
+                } else {
+                    grid[(y * size) + x] = 0x01;
+                }
+            }
+        }
+    }
+
+    return best_pattern;
 }
 
-/* NOTE: From this point forward concerns Micro QR Code only */
-
-int micro_qr_intermediate(char binary[], int jisdata[], char mode[], int length, int *kanji_used, int *alphanum_used, int *byte_used)
-{
-       /* Convert input data to an "intermediate stage" where data is binary encoded but
-          control information is not */
-       int position = 0;
-       int short_data_block_length, i;
-       char data_block;
-       char buffer[2];
-       
-       strcpy(binary, "");
-
-#ifdef _DEBUG_MODE_
-               for(i = 0; i < length; i++) {
-                       printf("%c", mode[i]);
-               }
-               printf("\n");
+INTERNAL int microqr(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
+    size_t i, size, j;
+    char full_stream[200];
+    int full_multibyte;
+
+    unsigned int jisdata[40];
+    char mode[40];
+    int alpha_used = 0, byte_or_kanji_used = 0;
+    int version_valid[4];
+    int binary_count[4];
+    int ecc_level, autoversion, version;
+    int bitmask, format, format_full;
+#ifdef _MSC_VER
+    unsigned char* grid;
 #endif
 
-       do {
-               if(strlen(binary) > 128) {
-                       return ERROR_TOO_LONG;
-               }
-               
-               data_block = mode[position];
-               short_data_block_length = 0;
-               do {
-                       short_data_block_length++;
-               } while (((short_data_block_length + position) < length) && (mode[position + short_data_block_length] == data_block));
-               
-               switch(data_block) {
-                       case 'K':
-                               /* Kanji mode */
-                               /* Mode indicator */
-                               concat(binary, "K");
-                               *kanji_used = 1;
-                               
-                               /* Character count indicator */
-                               buffer[0] = short_data_block_length;
-                               buffer[1] = '\0';
-                               concat(binary, buffer);
-#ifdef _DEBUG_MODE_
-                               printf("Kanji block (length %d)\n\t", short_data_block_length);
-#endif
-                               
-                               /* Character representation */
-                               for(i = 0; i < short_data_block_length; i++) {
-                                       int jis = jisdata[position + i];
-                                       int msb, lsb, prod;
-                                       
-                                       if(jis > 0x9fff) { jis -= 0xc140; }
-                                       msb = (jis & 0xff00) >> 4;
-                                       lsb = (jis & 0xff);
-                                       prod = (msb * 0xc0) + lsb;
-                                       
-                                       qr_bscan(binary, prod, 0x1000);
-#ifdef _DEBUG_MODE_
-                                       printf("0x%4X ", prod);
-#endif
-                                       if(strlen(binary) > 128) {
-                                               return ERROR_TOO_LONG;
-                                       }
-                               }
-#ifdef _DEBUG_MODE_
-                               printf("\n");
-#endif
-                               
-                               break;
-                       case 'B':
-                               /* Byte mode */
-                               /* Mode indicator */
-                               concat(binary, "B");
-                               *byte_used = 1;
-                               
-                               /* Character count indicator */
-                               buffer[0] = short_data_block_length;
-                               buffer[1] = '\0';
-                               concat(binary, buffer);
-#ifdef _DEBUG_MODE_
-                               printf("Byte block (length %d)\n\t", short_data_block_length);
-#endif
-                               
-                               /* Character representation */
-                               for(i = 0; i < short_data_block_length; i++) {
-                                       int byte = jisdata[position + i];
-                                       
-                                       qr_bscan(binary, byte, 0x80);
-#ifdef _DEBUG_MODE_
-                                       printf("0x%4X ", byte);
-#endif
-                                       if(strlen(binary) > 128) {
-                                               return ERROR_TOO_LONG;
-                                       }
-                               }
-#ifdef _DEBUG_MODE_
-                               printf("\n");
-#endif
-                               break;
-                       case 'A':
-                               /* Alphanumeric mode */
-                               /* Mode indicator */
-                               concat(binary, "A");
-                               *alphanum_used = 1;
-                               
-                               /* Character count indicator */
-                               buffer[0] = short_data_block_length;
-                               buffer[1] = '\0';
-                               concat(binary, buffer);
-#ifdef _DEBUG_MODE_
-                               printf("Alpha block (length %d)\n\t", short_data_block_length);
+    if (length > 35) {
+        strcpy(symbol->errtxt, "562: Input data too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    /* Check option 1 in combination with option 2 */
+    ecc_level = LEVEL_L;
+    if (symbol->option_1 >= 1 && symbol->option_1 <= 4) {
+        if (symbol->option_1 == 4) {
+            strcpy(symbol->errtxt, "566: Error correction level H not available");
+            return ZINT_ERROR_INVALID_OPTION;
+        }
+        if (symbol->option_2 >= 1 && symbol->option_2 <= 4) {
+            if (symbol->option_2 == 1 && symbol->option_1 != 1) {
+                strcpy(symbol->errtxt, "574: Version M1 supports error correction level L only");
+                return ZINT_ERROR_INVALID_OPTION;
+            }
+            if (symbol->option_2 != 4 && symbol->option_1 == 3) {
+                strcpy(symbol->errtxt, "575: Error correction level Q requires Version M4");
+                return ZINT_ERROR_INVALID_OPTION;
+            }
+        }
+        ecc_level = symbol->option_1;
+    }
+
+    full_multibyte = symbol->option_3 == ZINT_FULL_MULTIBYTE; /* If set use Kanji mode in DATA_MODE or for single-byte Latin */
+
+    if ((symbol->input_mode & 0x07) == DATA_MODE) {
+        sjis_cpy(source, &length, jisdata, full_multibyte);
+    } else {
+        /* Try ISO 8859-1 conversion first */
+        int error_number = sjis_utf8tosb(3, source, &length, jisdata, full_multibyte);
+        if (error_number != 0) {
+            /* Try Shift-JIS */
+            error_number = sjis_utf8tomb(symbol, source, &length, jisdata);
+            if (error_number != 0) {
+                return error_number;
+            }
+        }
+    }
+
+    /* Determine if alpha (excluding numerics), byte or kanji used */
+    for (i = 0; i < length && (alpha_used == 0 || byte_or_kanji_used == 0); i++) {
+        if (jisdata[i] < '0' || jisdata[i] > '9') {
+            if (is_alpha(jisdata[i], 0 /*gs1*/)) {
+                alpha_used = 1;
+            } else {
+                byte_or_kanji_used = 1;
+            }
+        }
+    }
+
+    for (i = 0; i < 4; i++) {
+        version_valid[i] = 1;
+    }
+
+    /* Eliminate possible versions depending on type of content */
+    if (byte_or_kanji_used) {
+        version_valid[0] = 0;
+        version_valid[1] = 0;
+    } else if (alpha_used) {
+        version_valid[0] = 0;
+    }
+
+    /* Eliminate possible versions depending on error correction level specified */
+    if (ecc_level == LEVEL_Q) {
+        version_valid[0] = 0;
+        version_valid[1] = 0;
+        version_valid[2] = 0;
+    } else if (ecc_level == LEVEL_M) {
+        version_valid[0] = 0;
+    }
+
+    /* Determine length of binary data */
+    for (i = 0; i < 4; i++) {
+        if (version_valid[i]) {
+            binary_count[i] = getBinaryLength(MICROQR_VERSION + i, mode, jisdata, length, 0 /*gs1*/, 0 /*eci*/, symbol->debug);
+        } else {
+            binary_count[i] = 128 + 1;
+        }
+    }
+
+    /* Eliminate possible versions depending on length of binary data */
+    if (binary_count[0] > 20) {
+        version_valid[0] = 0;
+    }
+    if (binary_count[1] > 40) {
+        version_valid[1] = 0;
+    }
+    if (binary_count[2] > 84) {
+        version_valid[2] = 0;
+    }
+    if (binary_count[3] > 128) {
+        strcpy(symbol->errtxt, "565: Input data too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    /* Eliminate possible versions depending on binary length and error correction level specified */
+    if (ecc_level == LEVEL_Q) {
+        if (binary_count[3] > 80) {
+            strcpy(symbol->errtxt, "567: Input data too long");
+            return ZINT_ERROR_TOO_LONG;
+        }
+    } else if (ecc_level == LEVEL_M) {
+        if (binary_count[1] > 32) {
+            version_valid[1] = 0;
+        }
+        if (binary_count[2] > 68) {
+            version_valid[2] = 0;
+        }
+        if (binary_count[3] > 112) {
+            strcpy(symbol->errtxt, "568: Input data too long");
+            return ZINT_ERROR_TOO_LONG;
+        }
+    }
+
+    autoversion = 3;
+    if (version_valid[2]) {
+        autoversion = 2;
+    }
+    if (version_valid[1]) {
+        autoversion = 1;
+    }
+    if (version_valid[0]) {
+        autoversion = 0;
+    }
+
+    version = autoversion;
+    /* Get version from user */
+    if ((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) {
+        if (symbol->option_2 - 1 >= autoversion) {
+            version = symbol->option_2 - 1;
+        } else {
+            strcpy(symbol->errtxt, "570: Input too long for selected symbol size");
+            return ZINT_ERROR_TOO_LONG;
+        }
+    }
+
+    /* If there is enough unused space then increase the error correction level, unless user-specified */
+    if (symbol->option_1 == -1 || symbol->option_1 != ecc_level) {
+        if (version == 3) {
+            if (binary_count[3] <= 112) {
+                ecc_level = LEVEL_M;
+            }
+            if (binary_count[3] <= 80) {
+                ecc_level = LEVEL_Q;
+            }
+        } else if (version == 2) {
+            if (binary_count[2] <= 68) {
+                ecc_level = LEVEL_M;
+            }
+        } else if (version == 1) {
+            if (binary_count[1] <= 32) {
+                ecc_level = LEVEL_M;
+            }
+        }
+    }
+
+    qr_define_mode(mode, jisdata, length, 0 /*gs1*/, MICROQR_VERSION + version, symbol->debug);
+
+    qr_binary((unsigned char*)full_stream, MICROQR_VERSION + version, 0 /*target_codewords*/, mode, jisdata, length, 0 /*gs1*/, 0 /*eci*/, binary_count[version], symbol->debug);
+
+    switch (version) {
+        case 0: micro_qr_m1(symbol, full_stream);
+            break;
+        case 1: micro_qr_m2(symbol, full_stream, ecc_level);
+            break;
+        case 2: micro_qr_m3(symbol, full_stream, ecc_level);
+            break;
+        case 3: micro_qr_m4(symbol, full_stream, ecc_level);
+            break;
+    }
+
+    size = micro_qr_sizes[version];
+#ifndef _MSC_VER
+    unsigned char grid[size * size];
+#else
+    grid = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
 #endif
-                               /* Character representation */
-                               i = 0; 
-                               while ( i < short_data_block_length ) {
-                                       int count;
-                                       int first = 0, second = 0, prod;
-                                       
-                                       first = posn(RHODIUM, (char) jisdata[position + i]);
-                                       count = 1;
-                                       prod = first;
-                                       
-                                       if(mode[position + i + 1] == 'A') {
-                                               second = posn(RHODIUM, (char) jisdata[position + i + 1]);
-                                               count = 2;
-                                               prod = (first * 45) + second;
-                                       }
-                                       
-                                       qr_bscan(binary, prod, 1 << (5 * count)); /* count = 1..2 */
-#ifdef _DEBUG_MODE_
-                                       printf("0x%4X ", prod);
+
+    for (i = 0; i < size; i++) {
+        for (j = 0; j < size; j++) {
+            grid[(i * size) + j] = 0;
+        }
+    }
+
+    micro_setup_grid(grid, size);
+    micro_populate_grid(grid, size, full_stream);
+    bitmask = micro_apply_bitmask(grid, size);
+
+    /* Add format data */
+    format = 0;
+    switch (version) {
+        case 1: switch (ecc_level) {
+                case 1: format = 1;
+                    break;
+                case 2: format = 2;
+                    break;
+            }
+            break;
+        case 2: switch (ecc_level) {
+                case 1: format = 3;
+                    break;
+                case 2: format = 4;
+                    break;
+            }
+            break;
+        case 3: switch (ecc_level) {
+                case 1: format = 5;
+                    break;
+                case 2: format = 6;
+                    break;
+                case 3: format = 7;
+                    break;
+            }
+            break;
+    }
+
+    format_full = qr_annex_c1[(format << 2) + bitmask];
+
+    if (format_full & 0x4000) {
+        grid[(8 * size) + 1] += 0x01;
+    }
+    if (format_full & 0x2000) {
+        grid[(8 * size) + 2] += 0x01;
+    }
+    if (format_full & 0x1000) {
+        grid[(8 * size) + 3] += 0x01;
+    }
+    if (format_full & 0x800) {
+        grid[(8 * size) + 4] += 0x01;
+    }
+    if (format_full & 0x400) {
+        grid[(8 * size) + 5] += 0x01;
+    }
+    if (format_full & 0x200) {
+        grid[(8 * size) + 6] += 0x01;
+    }
+    if (format_full & 0x100) {
+        grid[(8 * size) + 7] += 0x01;
+    }
+    if (format_full & 0x80) {
+        grid[(8 * size) + 8] += 0x01;
+    }
+    if (format_full & 0x40) {
+        grid[(7 * size) + 8] += 0x01;
+    }
+    if (format_full & 0x20) {
+        grid[(6 * size) + 8] += 0x01;
+    }
+    if (format_full & 0x10) {
+        grid[(5 * size) + 8] += 0x01;
+    }
+    if (format_full & 0x08) {
+        grid[(4 * size) + 8] += 0x01;
+    }
+    if (format_full & 0x04) {
+        grid[(3 * size) + 8] += 0x01;
+    }
+    if (format_full & 0x02) {
+        grid[(2 * size) + 8] += 0x01;
+    }
+    if (format_full & 0x01) {
+        grid[(1 * size) + 8] += 0x01;
+    }
+
+    symbol->width = size;
+    symbol->rows = size;
+
+    for (i = 0; i < size; i++) {
+        for (j = 0; j < size; j++) {
+            if (grid[(i * size) + j] & 0x01) {
+                set_module(symbol, i, j);
+            }
+        }
+        symbol->row_height[i] = 1;
+    }
+
+    return 0;
+}
+
+/* For UPNQR the symbol size and error correction capacity is fixed */
+INTERNAL int upnqr(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
+    int i, j, est_binlen;
+    int ecc_level, version, target_codewords, blocks, size;
+    int bitmask, error_number;
+
+#ifndef _MSC_VER
+    unsigned int jisdata[length + 1];
+    char mode[length + 1];
+#else
+    unsigned char* datastream;
+    unsigned char* fullstream;
+    unsigned char* grid;
+    unsigned int* jisdata = (unsigned int *) _alloca((length + 1) * sizeof (unsigned int));
+    char* mode = (char *) _alloca(length + 1);
 #endif
-                                       if(strlen(binary) > 128) {
-                                               return ERROR_TOO_LONG;
-                                       }
-                                       
-                                       i += 2;
-                               };
-#ifdef _DEBUG_MODE_
-                               printf("\n");
+
+#ifndef _MSC_VER
+    unsigned char preprocessed[length + 1];
+#else
+    unsigned char* preprocessed = (unsigned char*) _alloca(length + 1);
 #endif
-                               break;
-                       case 'N':
-                               /* Numeric mode */
-                               /* Mode indicator */
-                               concat(binary, "N");
-                               
-                               /* Character count indicator */
-                               buffer[0] = short_data_block_length;
-                               buffer[1] = '\0';
-                               concat(binary, buffer);
-#ifdef _DEBUG_MODE_
-                               printf("Number block (length %d)\n\t", short_data_block_length);
+
+    symbol->eci = 4; /* Set before any processing */
+
+    switch (symbol->input_mode & 0x07) {
+        case DATA_MODE:
+            /* Input is already in ISO-8859-2 format */
+            for (i = 0; i < (int) length; i++) {
+                jisdata[i] = source[i];
+                mode[i] = 'B';
+            }
+            break;
+        case GS1_MODE:
+            strcpy(symbol->errtxt, "571: UPNQR does not support GS-1 encoding");
+            return ZINT_ERROR_INVALID_OPTION;
+            break;
+        case UNICODE_MODE:
+            error_number = utf_to_eci(4, source, preprocessed, &length);
+            if (error_number != 0) {
+                strcpy(symbol->errtxt, "572: Invalid characters in input data");
+                return error_number;
+            }
+            for (i = 0; i < (int) length; i++) {
+                jisdata[i] = preprocessed[i];
+                mode[i] = 'B';
+            }
+            break;
+    }
+
+    est_binlen = getBinaryLength(15, mode, jisdata, length, 0, symbol->eci, symbol->debug);
+
+    ecc_level = LEVEL_M;
+
+    if (est_binlen > 3320) {
+        strcpy(symbol->errtxt, "573: Input too long for selected symbol");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    version = 15; // 77 x 77
+
+    target_codewords = qr_data_codewords_M[version - 1];
+    blocks = qr_blocks_M[version - 1];
+#ifndef _MSC_VER
+    unsigned char datastream[target_codewords + 1];
+    unsigned char fullstream[qr_total_codewords[version - 1] + 1];
+#else
+    datastream = (unsigned char *) _alloca(target_codewords + 1);
+    fullstream = (unsigned char *) _alloca(qr_total_codewords[version - 1] + 1);
 #endif
-                               /* Character representation */
-                               i = 0; 
-                               while ( i < short_data_block_length ) {
-                                       int count;
-                                       int first = 0, second = 0, third = 0, prod;
-                                       
-                                       first = posn(NEON, (char) jisdata[position + i]);
-                                       count = 1;
-                                       prod = first;
-                                       
-                                       if(mode[position + i + 1] == 'N') {
-                                               second = posn(NEON, (char) jisdata[position + i + 1]);
-                                               count = 2;
-                                               prod = (prod * 10) + second;
-                                       }
-                                       
-                                       if(mode[position + i + 2] == 'N') {
-                                               third = posn(NEON, (char) jisdata[position + i + 2]);
-                                               count = 3;
-                                               prod = (prod * 10) + third;
-                                       }
-                                       
-                                       qr_bscan(binary, prod, 1 << (3 * count)); /* count = 1..3 */
-#ifdef _DEBUG_MODE_
-                                       printf("0x%4X (%d)", prod, prod);
+
+    qr_binary(datastream, version, target_codewords, mode, jisdata, length, 0, symbol->eci, est_binlen, symbol->debug);
+#ifdef ZINT_TEST
+    if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords);
 #endif
-                                       if(strlen(binary) > 128) {
-                                               return ERROR_TOO_LONG;
-                                       }
-                                       
-                                       i += 3;
-                               };
-#ifdef _DEBUG_MODE_
-                               printf("\n");
+    add_ecc(fullstream, datastream, version, target_codewords, blocks, symbol->debug);
+
+    size = qr_sizes[version - 1];
+#ifndef _MSC_VER
+    unsigned char grid[size * size];
+#else
+    grid = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
 #endif
-                               break;
-               }
-               
-               position += short_data_block_length;
-       } while (position < length - 1) ;
-       
-       return 0;
-}
 
-void get_bitlength(int count[], char stream[]) {
-       int length, i;
-       
-       length = strlen(stream);
-       
-       for(i = 0; i < 4; i++) {
-               count[i] = 0;
-       }
-       
-       i = 0;
-       do {
-               if((stream[i] == '0') || (stream[i] == '1')) {
-                       count[0]++;
-                       count[1]++;
-                       count[2]++;
-                       count[3]++;
-                       i++;
-               } else {
-                       switch(stream[i]) {
-                               case 'K':
-                                       count[2] += 5;
-                                       count[3] += 7;
-                                       i += 2;
-                                       break;
-                               case 'B':
-                                       count[2] += 6;
-                                       count[3] += 8;
-                                       i += 2;
-                                       break;
-                               case 'A':
-                                       count[1] += 4;
-                                       count[2] += 6;
-                                       count[3] += 8;
-                                       i += 2;
-                                       break;
-                               case 'N':
-                                       count[0] += 3;
-                                       count[1] += 5;
-                                       count[2] += 7;
-                                       count[3] += 9;
-                                       i += 2;
-                                       break;
-                       }
-               }
-       } while (i < length);
-}
+    for (i = 0; i < size; i++) {
+        for (j = 0; j < size; j++) {
+            grid[(i * size) + j] = 0;
+        }
+    }
 
-void microqr_expand_binary(char binary_stream[], char full_stream[], int version)
-{
-       int i, length;
-       
-       length = strlen(binary_stream);
-       
-       i = 0;
-       do {
-               switch(binary_stream[i]) {
-                       case '1': concat(full_stream, "1"); i++; break;
-                       case '0': concat(full_stream, "0"); i++; break;
-                       case 'N':
-                               /* Numeric Mode */
-                               /* Mode indicator */
-                               switch(version) {
-                                       case 1: concat(full_stream, "0"); break;
-                                       case 2: concat(full_stream, "00"); break;
-                                       case 3: concat(full_stream, "000"); break;
-                               }
-                               
-                               /* Character count indicator */
-                               qr_bscan(full_stream, binary_stream[i + 1], 4 << version); /* version = 0..3 */
-                               
-                               i += 2;
-                               break;
-                       case 'A':
-                               /* Alphanumeric Mode */
-                               /* Mode indicator */
-                               switch(version) {
-                                       case 1: concat(full_stream, "1"); break;
-                                       case 2: concat(full_stream, "01"); break;
-                                       case 3: concat(full_stream, "001"); break;
-                               }
-                               
-                               /* Character count indicator */
-                               qr_bscan(full_stream, binary_stream[i + 1], 2 << version); /* version = 1..3 */
-                               
-                               i += 2;
-                               break;
-                       case 'B':
-                               /* Byte Mode */
-                               /* Mode indicator */
-                               switch(version) {
-                                       case 2: concat(full_stream, "10"); break;
-                                       case 3: concat(full_stream, "010"); break;
-                               }
-                               
-                               /* Character count indicator */
-                               qr_bscan(full_stream, binary_stream[i + 1], 2 << version); /* version = 2..3 */
-                               
-                               i += 2;
-                               break;
-                       case 'K':
-                               /* Kanji Mode */
-                               /* Mode indicator */
-                               switch(version) {
-                                       case 2: concat(full_stream, "11"); break;
-                                       case 3: concat(full_stream, "011"); break;
-                               }
-                               
-                               /* Character count indicator */
-                               qr_bscan(full_stream, binary_stream[i + 1], 1 << version); /* version = 2..3 */
-                               
-                               i += 2;
-                               break;
-               }
-                       
-       } while (i < length);
-}
+    setup_grid(grid, size, version);
+    populate_grid(grid, size, size, fullstream, qr_total_codewords[version - 1]);
 
-void micro_qr_m1(char binary_data[])
-{
-       int i, latch;
-       int bits_total, bits_left, remainder;
-       int data_codewords, ecc_codewords;
-       unsigned char data_blocks[4], ecc_blocks[3];
-       
-       bits_total = 20;
-       latch = 0;
-       
-       /* Add terminator */
-       bits_left = bits_total - strlen(binary_data);
-       if(bits_left <= 3) {
-               for(i = 0; i < bits_left; i++) {
-                       concat(binary_data, "0");
-               }
-               latch = 1;
-       } else {
-               concat(binary_data, "000");
-       }
-       
-       if(latch == 0) {
-               /* Manage last (4-bit) block */
-               bits_left = bits_total - strlen(binary_data);
-               if(bits_left <= 4) {
-                       for(i = 0; i < bits_left; i++) {
-                               concat(binary_data, "0");
-                       }
-                       latch = 1;
-               }
-       }
-
-       if(latch == 0) {
-               /* Complete current byte */
-               remainder = 8 - (strlen(binary_data) % 8);
-               if(remainder == 8) { remainder = 0; }
-               for(i = 0; i < remainder; i++) {
-                       concat(binary_data, "0");
-               }
-               
-               /* Add padding */
-               bits_left = bits_total - strlen(binary_data);
-               if(bits_left > 4) {
-                       remainder = (bits_left - 4) / 8;
-                       for(i = 0; i < remainder; i++) {
-                               concat(binary_data, i & 1 ? "00010001" : "11101100"); 
-                       }
-               }
-               concat(binary_data, "0000");
-       }
-       
-       data_codewords = 3;
-       ecc_codewords = 2;
-       
-       /* Copy data into codewords */
-       for(i = 0; i < (data_codewords - 1); i++) {
-               data_blocks[i] = 0;
-               if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; }
-               if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; }
-               if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; }
-               if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; }
-               if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; }
-               if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; }
-               if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; }
-               if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; }
-       }
-       data_blocks[2] = 0;
-       if(binary_data[16] == '1') { data_blocks[2] += 0x08; }
-       if(binary_data[17] == '1') { data_blocks[2] += 0x04; }
-       if(binary_data[18] == '1') { data_blocks[2] += 0x02; }
-       if(binary_data[19] == '1') { data_blocks[2] += 0x01; }
-       
-       /* Calculate Reed-Solomon error codewords */
-       rs_init_gf(0x11d);
-       rs_init_code(ecc_codewords, 0);
-       rs_encode(data_codewords,data_blocks,ecc_blocks);
-       rs_free();
-       
-       /* Add Reed-Solomon codewords to binary data */
-       for(i = 0; i < ecc_codewords; i++) {
-               qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80);
-       }
-}
+    add_version_info(grid, size, version);
 
-void micro_qr_m2(char binary_data[], int ecc_mode)
-{
-       int i, latch;
-       int bits_total, bits_left, remainder;
-       int data_codewords, ecc_codewords;
-       unsigned char data_blocks[6], ecc_blocks[7];
-       
-       latch = 0;
-       
-       if(ecc_mode == LEVEL_L) { bits_total = 40; }
-       if(ecc_mode == LEVEL_M) { bits_total = 32; }
-       
-       /* Add terminator */
-       bits_left = bits_total - strlen(binary_data);
-       if(bits_left <= 5) {
-               for(i = 0; i < bits_left; i++) {
-                       concat(binary_data, "0");
-               }
-               latch = 1;
-       } else {
-               concat(binary_data, "00000");
-       }
-
-       if(latch == 0) {
-               /* Complete current byte */
-               remainder = 8 - (strlen(binary_data) % 8);
-               if(remainder == 8) { remainder = 0; }
-               for(i = 0; i < remainder; i++) {
-                       concat(binary_data, "0");
-               }
-               
-               /* Add padding */
-               bits_left = bits_total - strlen(binary_data);
-               remainder = bits_left / 8;
-               for(i = 0; i < remainder; i++) {
-                       concat(binary_data, i & 1 ? "00010001" : "11101100"); 
-               }
-       }
-       
-       if(ecc_mode == LEVEL_L) { data_codewords = 5; ecc_codewords = 5; }
-       if(ecc_mode == LEVEL_M) { data_codewords = 4; ecc_codewords = 6; }
-       
-       /* Copy data into codewords */
-       for(i = 0; i < data_codewords; i++) {
-               data_blocks[i] = 0;
-               if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; }
-               if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; }
-               if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; }
-               if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; }
-               if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; }
-               if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; }
-               if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; }
-               if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; }
-       }
-       
-       /* Calculate Reed-Solomon error codewords */
-       rs_init_gf(0x11d);
-       rs_init_code(ecc_codewords, 0);
-       rs_encode(data_codewords,data_blocks,ecc_blocks);
-       rs_free();
-       
-       /* Add Reed-Solomon codewords to binary data */
-       for(i = 0; i < ecc_codewords; i++) {
-               qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80);
-       }
-       
-       return;
-}
+    bitmask = apply_bitmask(grid, size, ecc_level);
 
-void micro_qr_m3(char binary_data[], int ecc_mode)
-{
-       int i, latch;
-       int bits_total, bits_left, remainder;
-       int data_codewords, ecc_codewords;
-       unsigned char data_blocks[12], ecc_blocks[9];
-       
-       latch = 0;
-       
-       if(ecc_mode == LEVEL_L) { bits_total = 84; }
-       if(ecc_mode == LEVEL_M) { bits_total = 68; }
-       
-       /* Add terminator */
-       bits_left = bits_total - strlen(binary_data);
-       if(bits_left <= 7) {
-               for(i = 0; i < bits_left; i++) {
-                       concat(binary_data, "0");
-               }
-               latch = 1;
-       } else {
-               concat(binary_data, "0000000");
-       }
-       
-       if(latch == 0) {
-               /* Manage last (4-bit) block */
-               bits_left = bits_total - strlen(binary_data);
-               if(bits_left <= 4) {
-                       for(i = 0; i < bits_left; i++) {
-                               concat(binary_data, "0");
-                       }
-                       latch = 1;
-               }
-       }
-       
-       if(latch == 0) {
-               /* Complete current byte */
-               remainder = 8 - (strlen(binary_data) % 8);
-               if(remainder == 8) { remainder = 0; }
-               for(i = 0; i < remainder; i++) {
-                       concat(binary_data, "0");
-               }
-               
-               /* Add padding */
-               bits_left = bits_total - strlen(binary_data);
-               if(bits_left > 4) {
-                       remainder = (bits_left - 4) / 8;
-                       for(i = 0; i < remainder; i++) {
-                               concat(binary_data, i & 1 ? "00010001" : "11101100");
-                       }
-               }
-               concat(binary_data, "0000");
-       }
-       
-       if(ecc_mode == LEVEL_L) { data_codewords = 11; ecc_codewords = 6; }
-       if(ecc_mode == LEVEL_M) { data_codewords = 9; ecc_codewords = 8; }
-       
-       /* Copy data into codewords */
-       for(i = 0; i < (data_codewords - 1); i++) {
-               data_blocks[i] = 0;
-               if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; }
-               if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; }
-               if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; }
-               if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; }
-               if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; }
-               if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; }
-               if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; }
-               if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; }
-       }
-       
-       if(ecc_mode == LEVEL_L) {
-               data_blocks[11] = 0;
-               if(binary_data[80] == '1') { data_blocks[2] += 0x08; }
-               if(binary_data[81] == '1') { data_blocks[2] += 0x04; }
-               if(binary_data[82] == '1') { data_blocks[2] += 0x02; }
-               if(binary_data[83] == '1') { data_blocks[2] += 0x01; }
-       }
-       
-       if(ecc_mode == LEVEL_M) {
-               data_blocks[9] = 0;
-               if(binary_data[64] == '1') { data_blocks[2] += 0x08; }
-               if(binary_data[65] == '1') { data_blocks[2] += 0x04; }
-               if(binary_data[66] == '1') { data_blocks[2] += 0x02; }
-               if(binary_data[67] == '1') { data_blocks[2] += 0x01; }
-       }
-       
-       /* Calculate Reed-Solomon error codewords */
-       rs_init_gf(0x11d);
-       rs_init_code(ecc_codewords, 0);
-       rs_encode(data_codewords,data_blocks,ecc_blocks);
-       rs_free();
-       
-       /* Add Reed-Solomon codewords to binary data */
-       for(i = 0; i < ecc_codewords; i++) {
-               qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80);
-       }
-       
-       return;
-}
+    add_format_info(grid, size, ecc_level, bitmask);
 
-void micro_qr_m4(char binary_data[], int ecc_mode)
-{
-       int i, latch;
-       int bits_total, bits_left, remainder;
-       int data_codewords, ecc_codewords;
-       unsigned char data_blocks[17], ecc_blocks[15];
-       
-       latch = 0;
-       
-       if(ecc_mode == LEVEL_L) { bits_total = 128; }
-       if(ecc_mode == LEVEL_M) { bits_total = 112; }
-       if(ecc_mode == LEVEL_Q) { bits_total = 80; }
-       
-       /* Add terminator */
-       bits_left = bits_total - strlen(binary_data);
-       if(bits_left <= 9) {
-               for(i = 0; i < bits_left; i++) {
-                       concat(binary_data, "0");
-               }
-               latch = 1;
-       } else {
-               concat(binary_data, "000000000");
-       }
-       
-       if(latch == 0) {
-               /* Complete current byte */
-               remainder = 8 - (strlen(binary_data) % 8);
-               if(remainder == 8) { remainder = 0; }
-               for(i = 0; i < remainder; i++) {
-                       concat(binary_data, "0");
-               }
-       
-               /* Add padding */
-               bits_left = bits_total - strlen(binary_data);
-               remainder = bits_left / 8;
-               for(i = 0; i < remainder; i++) {
-                       concat(binary_data, i & 1 ? "00010001" : "11101100");
-               }
-       }
-       
-       if(ecc_mode == LEVEL_L) { data_codewords = 16; ecc_codewords = 8; }
-       if(ecc_mode == LEVEL_M) { data_codewords = 14; ecc_codewords = 10; }
-       if(ecc_mode == LEVEL_Q) { data_codewords = 10; ecc_codewords = 14; }
-       
-       /* Copy data into codewords */
-       for(i = 0; i < data_codewords; i++) {
-               data_blocks[i] = 0;
-               if(binary_data[i * 8] == '1') { data_blocks[i] += 0x80; }
-               if(binary_data[(i * 8) + 1] == '1') { data_blocks[i] += 0x40; }
-               if(binary_data[(i * 8) + 2] == '1') { data_blocks[i] += 0x20; }
-               if(binary_data[(i * 8) + 3] == '1') { data_blocks[i] += 0x10; }
-               if(binary_data[(i * 8) + 4] == '1') { data_blocks[i] += 0x08; }
-               if(binary_data[(i * 8) + 5] == '1') { data_blocks[i] += 0x04; }
-               if(binary_data[(i * 8) + 6] == '1') { data_blocks[i] += 0x02; }
-               if(binary_data[(i * 8) + 7] == '1') { data_blocks[i] += 0x01; }
-       }
-       
-       /* Calculate Reed-Solomon error codewords */
-       rs_init_gf(0x11d);
-       rs_init_code(ecc_codewords, 0);
-       rs_encode(data_codewords,data_blocks,ecc_blocks);
-       rs_free();
-       
-       /* Add Reed-Solomon codewords to binary data */
-       for(i = 0; i < ecc_codewords; i++) {
-               qr_bscan(binary_data, ecc_blocks[ecc_codewords - i - 1], 0x80);
-       }
-}
+    symbol->width = size;
+    symbol->rows = size;
 
-void micro_setup_grid(unsigned char* grid, int size)
-{
-       int i, toggle = 1;
-
-       /* Add timing patterns */
-       for(i = 0; i < size; i++) {
-               if(toggle == 1) {
-                       grid[i] = 0x21;
-                       grid[(i * size)] = 0x21;
-                       toggle = 0;
-               } else {
-                       grid[i] = 0x20;
-                       grid[(i * size)] = 0x20;
-                       toggle = 1;
-               }
-       }
-       
-       /* Add finder patterns */
-       place_finder(grid, size, 0, 0);
-       
-       /* Add separators */
-       for(i = 0; i < 7; i++) {
-               grid[(7 * size) + i] = 0x10;
-               grid[(i * size) + 7] = 0x10;
-       }
-       grid[(7 * size) + 7] = 0x10;
-       
-       
-       /* Reserve space for format information */
-       for(i = 0; i < 8; i++) {
-               grid[(8 * size) + i] += 0x20;
-               grid[(i * size) + 8] += 0x20;
-       }
-       grid[(8 * size) + 8] += 20;
-}
+    for (i = 0; i < size; i++) {
+        for (j = 0; j < size; j++) {
+            if (grid[(i * size) + j] & 0x01) {
+                set_module(symbol, i, j);
+            }
+        }
+        symbol->row_height[i] = 1;
+    }
 
-void micro_populate_grid(unsigned char* grid, int size, char full_stream[])
-{
-       int direction = 1; /* up */
-       int row = 0; /* right hand side */
-       
-       int i, n, x, y;
-       
-       n = strlen(full_stream);
-       y = size - 1;
-       i = 0;
-       do {
-               x = (size - 2) - (row * 2);
-
-               if(!(grid[(y * size) + (x + 1)] & 0xf0)) {
-                       if (full_stream[i] == '1') {
-                               grid[(y * size) + (x + 1)] = 0x01;
-                       } else {
-                               grid[(y * size) + (x + 1)] = 0x00;
-                       }
-                       i++;
-               }
-               
-               if(i < n) {
-                       if(!(grid[(y * size) + x] & 0xf0)) {
-                               if (full_stream[i] == '1') {
-                                       grid[(y * size) + x] = 0x01;
-                               } else {
-                                       grid[(y * size) + x] = 0x00;
-                               }
-                               i++;
-                       }
-               }
-               
-               if(direction) { y--; } else { y++; }
-               if(y == 0) {
-                       /* reached the top */
-                       row++;
-                       y = 1;
-                       direction = 0;
-               }
-               if(y == size) {
-                       /* reached the bottom */
-                       row++;
-                       y = size - 1;
-                       direction = 1;
-               }
-       } while (i < n);
+    return 0;
 }
 
-int micro_evaluate(unsigned char *grid, int size, int pattern)
-{
-       int sum1, sum2, i, filter = 0, retval;
-       
-       switch(pattern) {
-               case 0: filter = 0x01; break;
-               case 1: filter = 0x02; break;
-               case 2: filter = 0x04; break;
-               case 3: filter = 0x08; break;
-       }
-       
-       sum1 = 0;
-       sum2 = 0;
-       for(i = 1; i < size; i++) {
-               if(grid[(i * size) + size - 1] & filter) { sum1++; }
-               if(grid[((size - 1) * size) + i] & filter) { sum2++; }
-       }
-       
-       if(sum1 <= sum2) { retval = (sum1 * 16) + sum2; } else { retval = (sum2 * 16) + sum1; }
-       
-       return retval;
+static void setup_rmqr_grid(unsigned char* grid, const int h_size, const int v_size) {
+    int i, j;
+    char alignment[] = {0x1F, 0x11, 0x15, 0x11, 0x1F};
+    int h_version, finder_position;
+
+    /* Add timing patterns - top and bottom */
+    for (i = 0; i < h_size; i++) {
+        if (i % 2) {
+            grid[i] = 0x20;
+            grid[((v_size - 1) * h_size) + i] = 0x20;
+        } else {
+            grid[i] = 0x21;
+            grid[((v_size - 1) * h_size) + i] = 0x21;
+        }
+    }
+
+    /* Add timing patterns - left and right */
+    for (i = 0; i < v_size; i++) {
+        if (i % 2) {
+            grid[i * h_size] = 0x20;
+            grid[(i * h_size) + (h_size - 1)] = 0x20;
+        } else {
+            grid[i * h_size] = 0x21;
+            grid[(i * h_size) + (h_size - 1)] = 0x21;
+        }
+    }
+
+    /* Add finder pattern */
+    place_finder(grid, h_size, 0, 0); // This works because finder is always top left
+
+    /* Add finder sub-pattern to bottom right */
+    for (i = 0; i < 5; i++) {
+        for (j = 0; j < 5; j++) {
+            if (alignment[j] & 0x10 >> i) {
+                grid[((v_size - 5) * h_size) + (h_size * i) + (h_size - 5) + j] = 0x11;
+            } else {
+                grid[((v_size - 5) * h_size) + (h_size * i) + (h_size - 5) + j] = 0x10;
+            }
+        }
+    }
+
+    /* Add corner finder pattern - bottom left */
+    grid[(v_size - 2) * h_size] = 0x11;
+    grid[((v_size - 2) * h_size) + 1] = 0x10;
+    grid[((v_size - 1) * h_size) + 1] = 0x11;
+
+    /* Add corner finder pattern - top right */
+    grid[h_size - 2] = 0x11;
+    grid[(h_size * 2) - 2] = 0x10;
+    grid[(h_size * 2) - 1] = 0x11;
+
+    /* Add seperator */
+    for (i = 0; i < 7; i++) {
+        grid[(i * h_size) + 7] = 0x20;
+    }
+    if (v_size > 7) {
+        // Note for v_size = 9 this overrides the bottom right corner finder pattern
+        for(i = 0; i < 8; i++) {
+            grid[(7 * h_size) + i] = 0x20;
+        }
+    }
+
+    /* Add alignment patterns */
+    if (h_size > 27) {
+        for(i = 0; i < 5; i++) {
+            if (h_size == rmqr_width[i]) {
+                h_version = i;
+            }
+        }
+
+        for(i = 0; i < 4; i++) {
+            finder_position = rmqr_table_d1[(h_version * 4) + i];
+
+            if (finder_position != 0) {
+                for (j = 0; j < v_size; j++) {
+                    if (j % 2) {
+                        grid[(j * h_size) + finder_position] = 0x10;
+                    } else {
+                        grid[(j * h_size) + finder_position] = 0x11;
+                    }
+                }
+
+                // Top square
+                grid[h_size + finder_position - 1] = 0x11;
+                grid[(h_size * 2) + finder_position - 1] = 0x11;
+                grid[h_size + finder_position + 1] = 0x11;
+                grid[(h_size * 2) + finder_position + 1] = 0x11;
+
+                // Bottom square
+                grid[(h_size * (v_size - 3)) + finder_position - 1] = 0x11;
+                grid[(h_size * (v_size - 2)) + finder_position - 1] = 0x11;
+                grid[(h_size * (v_size - 3)) + finder_position + 1] = 0x11;
+                grid[(h_size * (v_size - 2)) + finder_position + 1] = 0x11;
+            }
+        }
+    }
+
+    /* Reserve space for format information */
+    for (i = 0; i < 5; i++) {
+        for (j = 0; j < 3; j++) {
+            grid[(h_size * (i + 1)) + j + 8] = 0x20;
+            grid[(h_size * (v_size - 6)) + (h_size * i) + j + (h_size - 8)] = 0x20;
+        }
+    }
+    grid[(h_size * 1) + 11] = 0x20;
+    grid[(h_size * 2) + 11] = 0x20;
+    grid[(h_size * 3) + 11] = 0x20;
+    grid[(h_size * (v_size - 6)) + (h_size - 5)] = 0x20;
+    grid[(h_size * (v_size - 6)) + (h_size - 4)] = 0x20;
+    grid[(h_size * (v_size - 6)) + (h_size - 3)] = 0x20;
 }
 
-int micro_apply_bitmask(unsigned char *grid, int size)
-{
-       int x, y;
-       unsigned char p;
-       int pattern, value[8];
-       int best_val, best_pattern;
-       int bit;
-       
+/* rMQR according to 2018 draft standard */
+INTERNAL int rmqr(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
+    int i, j, est_binlen;
+    int ecc_level, autosize, version, max_cw, target_codewords, blocks, h_size, v_size;
+    int gs1;
+    int full_multibyte;
+    int footprint, best_footprint, format_data;
+    unsigned int left_format_info, right_format_info;
+
 #ifndef _MSC_VER
-       unsigned char mask[size * size];
-       unsigned char eval[size * size];
+    unsigned int jisdata[length + 1];
+    char mode[length + 1];
 #else
-       unsigned char* mask = (unsigned char *)_alloca((size * size) * sizeof(unsigned char));
-       unsigned char* eval = (unsigned char *)_alloca((size * size) * sizeof(unsigned char));
+    unsigned char* datastream;
+    unsigned char* fullstream;
+    unsigned char* grid;
+    unsigned int* jisdata = (unsigned int *) _alloca((length + 1) * sizeof (unsigned int));
+    char* mode = (char *) _alloca(length + 1);
 #endif
 
-       /* Perform data masking */
-       for(x = 0; x < size; x++) {
-               for(y = 0; y < size; y++) {
-                       mask[(y * size) + x] = 0x00;
-                       
-                       if (!(grid[(y * size) + x] & 0xf0)) {
-                               if((y & 1) == 0) {
-                                       mask[(y * size) + x] += 0x01;
-                               }
-
-                               if((((y / 2) + (x / 3)) & 1) == 0) {
-                                       mask[(y * size) + x] += 0x02;
-                               }
-                               
-                               if(((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) {
-                                       mask[(y * size) + x] += 0x04;
-                               }
-                               
-                               if(((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) {
-                                       mask[(y * size) + x] += 0x08;
-                               }
-                       }
-               }
-       }
-       
-       for(x = 0; x < size; x++) {
-               for(y = 0; y < size; y++) {
-                       if(grid[(y * size) + x] & 0x01) { p = 0xff; } else { p = 0x00; }
-                       
-                       eval[(y * size) + x] = mask[(y * size) + x] ^ p;
-               }
-       }
-       
-       
-       /* Evaluate result */
-       for(pattern = 0; pattern < 8; pattern++) {
-               value[pattern] = micro_evaluate(eval, size, pattern);
-       }
-       
-       best_pattern = 0;
-       best_val = value[0];
-       for(pattern = 1; pattern < 4; pattern++) {
-               if(value[pattern] > best_val) {
-                       best_pattern = pattern;
-                       best_val = value[pattern];
-               }
-       }
-       
-       /* Apply mask */
-       for(x = 0; x < size; x++) {
-               for(y = 0; y < size; y++) {
-                       bit = 0;
-                       switch(best_pattern) {
-                               case 0: if(mask[(y * size) + x] & 0x01) { bit = 1; } break;
-                               case 1: if(mask[(y * size) + x] & 0x02) { bit = 1; } break;
-                               case 2: if(mask[(y * size) + x] & 0x04) { bit = 1; } break;
-                               case 3: if(mask[(y * size) + x] & 0x08) { bit = 1; } break;
-                       }
-                       if(bit == 1) {
-                               if(grid[(y * size) + x] & 0x01) {
-                                       grid[(y * size) + x] = 0x00;
-                               } else {
-                                       grid[(y * size) + x] = 0x01;
-                               }
-                       }
-               }
-       }
-       
-       return best_pattern;
-}
+    gs1 = ((symbol->input_mode & 0x07) == GS1_MODE);
+    full_multibyte = symbol->option_3 == ZINT_FULL_MULTIBYTE; /* If set use Kanji mode in DATA_MODE or for single-byte Latin */
+
+    if ((symbol->input_mode & 0x07) == DATA_MODE) {
+        sjis_cpy(source, &length, jisdata, full_multibyte);
+    } else {
+        /* Try ISO 8859-1 conversion first */
+        int error_number = sjis_utf8tosb(3, source, &length, jisdata, full_multibyte);
+        if (error_number != 0) {
+            /* Try Shift-JIS */
+            error_number = sjis_utf8tomb(symbol, source, &length, jisdata);
+            if (error_number != 0) {
+                return error_number;
+            }
+        }
+    }
+
+    est_binlen = getBinaryLength(RMQR_VERSION + 31, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug);
+
+    ecc_level = LEVEL_M;
+    max_cw = 152;
+    if (symbol->option_1 == 1) {
+        strcpy(symbol->errtxt, "576: Error correction level L not available in rMQR");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    if (symbol->option_1 == 3) {
+        strcpy(symbol->errtxt, "577: Error correction level Q not available in rMQR");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    if (symbol->option_1 == 4) {
+        ecc_level = LEVEL_H;
+        max_cw = 76;
+    }
+
+    if (est_binlen > (8 * max_cw)) {
+        strcpy(symbol->errtxt, "578: Input too long for selected error correction level");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    if ((symbol->option_2 < 0) || (symbol->option_2 > 38)) {
+        strcpy(symbol->errtxt, "579: Invalid rMQR symbol size");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+    version = 31; // Set default to keep compiler happy
+
+    if (symbol->option_2 == 0) {
+        // Automatic symbol size
+        autosize = 31;
+        best_footprint = rmqr_height[31] * rmqr_width[31];
+        for (version = 30; version >= 0; version--) {
+            est_binlen = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug);
+            footprint = rmqr_height[version] * rmqr_width[version];
+            if (ecc_level == LEVEL_M) {
+                if (8 * rmqr_data_codewords_M[version] >= est_binlen) {
+                    if (footprint < best_footprint) {
+                        autosize = version;
+                        best_footprint = footprint;
+                    }
+                }
+            } else {
+                if (8 * rmqr_data_codewords_H[version] >= est_binlen) {
+                    if (footprint < best_footprint) {
+                        autosize = version;
+                        best_footprint = footprint;
+                    }
+                }
+            }
+        }
+        version = autosize;
+        est_binlen = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug);
+    }
+
+    if ((symbol->option_2 >= 1) && (symbol->option_2 <= 32)) {
+        // User specified symbol size
+        version = symbol->option_2 - 1;
+        est_binlen = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug);
+    }
+
+    if (symbol->option_2 >= 33) {
+        // User has specified symbol height only
+        version = rmqr_fixed_height_upper_bound[symbol->option_2 - 32];
+        for(i = version - 1; i > rmqr_fixed_height_upper_bound[symbol->option_2 - 33]; i--) {
+            est_binlen = getBinaryLength(RMQR_VERSION + i, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug);
+            if (ecc_level == LEVEL_M) {
+                if (8 * rmqr_data_codewords_M[i] >= est_binlen) {
+                    version = i;
+                }
+            } else {
+                if (8 * rmqr_data_codewords_H[i] >= est_binlen) {
+                    version = i;
+                }
+            }
+        }
+        est_binlen = getBinaryLength(RMQR_VERSION + version, mode, jisdata, length, gs1, 0 /*eci*/, symbol->debug);
+    }
+
+    if (symbol->option_1 == -1) {
+        // Detect if there is enough free space to increase ECC level
+        if (est_binlen < (rmqr_data_codewords_H[version] * 8)) {
+            ecc_level = LEVEL_H;
+        }
+    }
+
+    if (ecc_level == LEVEL_M) {
+        target_codewords = rmqr_data_codewords_M[version];
+        blocks = rmqr_blocks_M[version];
+    } else {
+        target_codewords = rmqr_data_codewords_H[version];
+        blocks = rmqr_blocks_H[version];
+    }
+
+    if (est_binlen > (target_codewords * 8)) {
+        // User has selected a symbol too small for the data
+        strcpy(symbol->errtxt, "580: Input too long for selected symbol size");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("Minimum codewords = %d\n", est_binlen / 8);
+        printf("Selected version: %d = R%dx%d-", (version + 1), rmqr_height[version], rmqr_width[version]);
+        if (ecc_level == LEVEL_M) {
+            printf("M\n");
+        } else {
+            printf("H\n");
+        }
+        printf("Number of data codewords in symbol = %d\n", target_codewords);
+        printf("Number of ECC blocks = %d\n", blocks);
+    }
 
-int microqr(struct zint_symbol *symbol, unsigned char source[], int length)
-{
-       int i, j, glyph, size;
-       char binary_stream[200];
-       char full_stream[200];
-       int utfdata[40];
-       int jisdata[40];
-       char mode[40];
-       int error_number, kanji_used = 0, alphanum_used = 0, byte_used = 0;
-       int version_valid[4];
-       int binary_count[4];
-       int ecc_level, autoversion, version;
-       int n_count, a_count, bitmask, format, format_full;
-       
-       if(length > 35) {
-               strcpy(symbol->errtxt, "Input data too long");
-               return ERROR_TOO_LONG;
-       }
-       
-       for(i = 0; i < 4; i++) {
-               version_valid[i] = 1;
-       }
-
-       switch(symbol->input_mode) {
-               case DATA_MODE:
-                       for(i = 0; i < length; i++) {
-                               jisdata[i] = (int)source[i];
-                       }
-                       break;
-               default:
-                       /* Convert Unicode input to Shift-JIS */
-                       error_number = utf8toutf16(symbol, source, utfdata, &length);
-                       if(error_number != 0) { return error_number; }
-                       
-                       for(i = 0; i < length; i++) {
-                               if(utfdata[i] <= 0xff) {
-                                       jisdata[i] = utfdata[i];
-                               } else {
-                                       j = 0;
-                                       glyph = 0;
-                                       do {
-                                               if(sjis_lookup[j * 2] == utfdata[i]) {
-                                                       glyph = sjis_lookup[(j * 2) + 1];
-                                               }
-                                               j++;
-                                       } while ((j < 6843) && (glyph == 0));
-                                       if(glyph == 0) {
-                                               strcpy(symbol->errtxt, "Invalid character in input data");
-                                               return ERROR_INVALID_DATA;
-                                       }
-                                       jisdata[i] = glyph;
-                               }
-                       }
-                       break;
-       }
-       
-       define_mode(mode, jisdata, length, 0);
-       
-       n_count = 0;
-       a_count = 0;
-       for(i = 0; i < length; i++) {
-               if((jisdata[i] >= '0') && (jisdata[i] <= '9')) { n_count++; }
-               if(in_alpha(jisdata[i])) { a_count++; }
-       }
-       
-       if(a_count == length) {
-               /* All data can be encoded in Alphanumeric mode */
-               for(i = 0; i < length; i++) {
-                       mode[i] = 'A';
-               }
-       }
-       
-       if(n_count == length) {
-               /* All data can be encoded in Numeric mode */
-               for(i = 0; i < length; i++) {
-                       mode[i] = 'N';
-               }
-       }
-       
-       error_number = micro_qr_intermediate(binary_stream, jisdata, mode, length, &kanji_used, &alphanum_used, &byte_used);
-       if(error_number != 0) {
-               strcpy(symbol->errtxt, "Input data too long");
-               return error_number;
-       }
-       
-       get_bitlength(binary_count, binary_stream);
-       
-       /* Eliminate possivle versions depending on type of content */
-       if(byte_used) {
-               version_valid[0] = 0;
-               version_valid[1] = 0;
-       }
-       
-       if(alphanum_used) {
-               version_valid[0] = 0;
-       }
-       
-       if(kanji_used) {
-               version_valid[0] = 0;
-               version_valid[1] = 0;
-       }
-       
-       /* Eliminate possible versions depending on length of binary data */
-       if(binary_count[0] > 20) { version_valid[0] = 0; }
-       if(binary_count[1] > 40) { version_valid[1] = 0; }
-       if(binary_count[2] > 84) { version_valid[2] = 0; }
-       if(binary_count[3] > 128) { 
-               strcpy(symbol->errtxt, "Input data too long");
-               return ERROR_TOO_LONG;
-       }
-       
-       /* Eliminate possible versions depending on error correction level specified */
-       ecc_level = LEVEL_L;
-       if((symbol->option_1 >= 1) && (symbol->option_2 <= 4)) {
-               ecc_level = symbol->option_1;
-       }
-       
-       if(ecc_level == LEVEL_H) {
-               strcpy(symbol->errtxt, "Error correction level H not available");
-               return ERROR_INVALID_OPTION;
-       }
-       
-       if(ecc_level == LEVEL_Q) {
-               version_valid[0] = 0;
-               version_valid[1] = 0;
-               version_valid[2] = 0;
-               if(binary_count[3] > 80) {
-                       strcpy(symbol->errtxt, "Input data too long");
-                       return ERROR_TOO_LONG;
-               }
-       }
-       
-       if(ecc_level == LEVEL_M) {
-               version_valid[0] = 0;
-               if(binary_count[1] > 32) { version_valid[1] = 0; }
-               if(binary_count[2] > 68) { version_valid[2] = 0; }
-               if(binary_count[3] > 112) {
-                       strcpy(symbol->errtxt, "Input data too long");
-                       return ERROR_TOO_LONG;
-               }
-       }
-       
-       autoversion = 3;
-       if(version_valid[2]) { autoversion = 2; }
-       if(version_valid[1]) { autoversion = 1; }
-       if(version_valid[0]) { autoversion = 0; }
-       
-       version = autoversion;
-       /* Get version from user */
-       if((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) {
-               if((symbol->option_2 - 1) >= autoversion) {
-                       version = symbol->option_2 - 1;
-               }
-       }
-       
-       /* If there is enough unused space then increase the error correction level */
-       if(version == 3) {
-               if(binary_count[3] <= 112) { ecc_level = LEVEL_M; }
-               if(binary_count[3] <= 80) { ecc_level = LEVEL_Q; }
-       }
-       
-       if(version == 2) {
-               if(binary_count[2] <= 68) { ecc_level = LEVEL_M; }
-       }
-       
-       if(version == 1) {
-               if(binary_count[1] <= 32) { ecc_level = LEVEL_M; }
-       }
-       
-       strcpy(full_stream, "");
-       microqr_expand_binary(binary_stream, full_stream, version);
-       
-       switch(version) {
-               case 0: micro_qr_m1(full_stream); break;
-               case 1: micro_qr_m2(full_stream, ecc_level); break;
-               case 2: micro_qr_m3(full_stream, ecc_level); break;
-               case 3: micro_qr_m4(full_stream, ecc_level); break;
-       }
-       
-       size = micro_qr_sizes[version];
 #ifndef _MSC_VER
-       unsigned char grid[size * size];
+    unsigned char datastream[target_codewords + 1];
+    unsigned char fullstream[rmqr_total_codewords[version] + 1];
 #else
-       unsigned char* grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char));
+    datastream = (unsigned char *) _alloca((target_codewords + 1) * sizeof (unsigned char));
+    fullstream = (unsigned char *) _alloca((rmqr_total_codewords[version] + 1) * sizeof (unsigned char));
+#endif
+
+    qr_binary(datastream, RMQR_VERSION + version, target_codewords, mode, jisdata, length, gs1, 0 /*eci*/, est_binlen, symbol->debug);
+#ifdef ZINT_TEST
+    if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords);
 #endif
-       
-       for(i = 0; i < size; i++) {
-               for(j = 0; j < size; j++) {
-                       grid[(i * size) + j] = 0;
-               }
-       }
-       
-       micro_setup_grid(grid, size);
-       micro_populate_grid(grid, size, full_stream);
-       bitmask = micro_apply_bitmask(grid, size);
-       
-       /* Add format data */
-       format = 0;
-       switch(version) {
-               case 1: switch(ecc_level) {
-                               case 1: format = 1; break;
-                               case 2: format = 2; break;
-                       }
-                       break;
-               case 2: switch(ecc_level) {
-                               case 1: format = 3; break;
-                               case 2: format = 4; break;
-                       }
-                       break;
-               case 3: switch(ecc_level) {
-                               case 1: format = 5; break;
-                               case 2: format = 6; break;
-                               case 3: format = 7; break;
-                       }
-                       break;
-       }
-       
-       format_full = qr_annex_c1[(format << 2) + bitmask];
-       
-       if(format_full & 0x4000) { grid[(8 * size) + 1] += 0x01; } 
-       if(format_full & 0x2000) { grid[(8 * size) + 2] += 0x01; } 
-       if(format_full & 0x1000) { grid[(8 * size) + 3] += 0x01; } 
-       if(format_full & 0x800) { grid[(8 * size) + 4] += 0x01; } 
-       if(format_full & 0x400) { grid[(8 * size) + 5] += 0x01; } 
-       if(format_full & 0x200) { grid[(8 * size) + 6] += 0x01; } 
-       if(format_full & 0x100) { grid[(8 * size) + 7] += 0x01; } 
-       if(format_full & 0x80) { grid[(8 * size) + 8] += 0x01; } 
-       if(format_full & 0x40) { grid[(7 * size) + 8] += 0x01; } 
-       if(format_full & 0x20) { grid[(6 * size) + 8] += 0x01; } 
-       if(format_full & 0x10) { grid[(5 * size) + 8] += 0x01; } 
-       if(format_full & 0x08) { grid[(4 * size) + 8] += 0x01; } 
-       if(format_full & 0x04) { grid[(3 * size) + 8] += 0x01; } 
-       if(format_full & 0x02) { grid[(2 * size) + 8] += 0x01; } 
-       if(format_full & 0x01) { grid[(1 * size) + 8] += 0x01; } 
-       
-       symbol->width = size;
-       symbol->rows = size;
-       
-       for(i = 0; i < size; i++) {
-               for(j = 0; j < size; j++) {
-                       if(grid[(i * size) + j] & 0x01) {
-                               set_module(symbol, i, j);
-                       }
-               }
-               symbol->row_height[i] = 1;
-       }
-       
-       return 0;
+    add_ecc(fullstream, datastream, RMQR_VERSION + version, target_codewords, blocks, symbol->debug);
+
+    h_size = rmqr_width[version];
+    v_size = rmqr_height[version];
+
+#ifndef _MSC_VER
+    unsigned char grid[h_size * v_size];
+#else
+    grid = (unsigned char *) _alloca((h_size * v_size) * sizeof (unsigned char));
+#endif
+
+    for (i = 0; i < v_size; i++) {
+        for (j = 0; j < h_size; j++) {
+            grid[(i * h_size) + j] = 0;
+        }
+    }
+
+    setup_rmqr_grid(grid, h_size, v_size);
+    populate_grid(grid, h_size, v_size, fullstream, rmqr_total_codewords[version]);
+
+    /* apply bitmask */
+    for (i = 0; i < v_size; i++) {
+        for (j = 0; j < h_size; j++) {
+            if ((grid[(i * h_size) + j] & 0xf0) == 0) {
+                // This is a data module
+                if (((i / 2) + (j / 3)) % 2 == 0) { // < This is the data mask from section 7.8.2
+                    // This module needs to be changed
+                    if (grid[(i * h_size) + j] == 0x01) {
+                        grid[(i * h_size) + j] = 0x00;
+                    } else {
+                        grid[(i * h_size) + j] = 0x01;
+                    }
+                }
+            }
+        }
+    }
+
+    /* add format information */
+    format_data = version;
+    if (ecc_level == LEVEL_H) {
+        format_data += 32;
+    }
+    left_format_info = rmqr_format_info_left[format_data];
+    right_format_info = rmqr_format_info_right[format_data];
+
+    for (i = 0; i < 5; i++) {
+        for (j = 0; j < 3; j++) {
+            grid[(h_size * (i + 1)) + j + 8] = (left_format_info >> ((j * 5) + i)) & 0x01;
+            grid[(h_size * (v_size - 6)) + (h_size * i) + j + (h_size - 8)] = (right_format_info >> ((j * 5) + i)) & 0x01;
+        }
+    }
+    grid[(h_size * 1) + 11] = (left_format_info >> 15) & 0x01;
+    grid[(h_size * 2) + 11] = (left_format_info >> 16) & 0x01;
+    grid[(h_size * 3) + 11] = (left_format_info >> 17) & 0x01;
+    grid[(h_size * (v_size - 6)) + (h_size - 5)] = (right_format_info >> 15) & 0x01;
+    grid[(h_size * (v_size - 6)) + (h_size - 4)] = (right_format_info >> 16) & 0x01;
+    grid[(h_size * (v_size - 6)) + (h_size - 3)] = (right_format_info >> 17) & 0x01;
+
+
+    symbol->width = h_size;
+    symbol->rows = v_size;
+
+    for (i = 0; i < v_size; i++) {
+        for (j = 0; j < h_size; j++) {
+            if (grid[(i * h_size) + j] & 0x01) {
+                set_module(symbol, i, j);
+            }
+        }
+        symbol->row_height[i] = 1;
+    }
+
+    return 0;
 }
index 0efb263..b19ded6 100644 (file)
@@ -1,8 +1,7 @@
-/* qr.h Data for QR Code */
+/* qr.h Data for QR Code, Micro QR Code and rMQR
 
-/*
     libzint - the open source barcode library
-    Copyright (C) 2008 Robin Stuart <robin@zint.org.uk>
+    Copyright (C) 2008-2019 Robin Stuart <rstuart114@gmail.com>
     Copyright (C) 2006 Kentaro Fukuchi <fukuchi@megaui.net>
 
     Redistribution and use in source and binary forms, with or without
     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 LEVEL_L        1
-#define LEVEL_M        2
-#define LEVEL_Q        3
-#define LEVEL_H        4
+#define LEVEL_L    1
+#define LEVEL_M    2
+#define LEVEL_Q    3
+#define LEVEL_H    4
 
 #define RHODIUM "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
 
+#define RMQR_VERSION    100
+#define MICROQR_VERSION 200
+
 /* From ISO/IEC 18004:2006 Table 7 */
-static int qr_data_codewords_L[] = {
-       19, 34, 55, 80, 108, 136, 156, 194, 232, 274, 324, 370, 428, 461, 523, 589, 647,
-       721, 795, 861, 932, 1006, 1094, 1174, 1276, 1370, 1468, 1531, 1631,
-       1735, 1843, 1955, 2071, 2191, 2306, 2434, 2566, 2702, 2812, 2956
+static const unsigned short int qr_data_codewords_L[] = {
+    19, 34, 55, 80, 108, 136, 156, 194, 232, 274, 324, 370, 428, 461, 523, 589, 647,
+    721, 795, 861, 932, 1006, 1094, 1174, 1276, 1370, 1468, 1531, 1631,
+    1735, 1843, 1955, 2071, 2191, 2306, 2434, 2566, 2702, 2812, 2956
+};
+
+static const unsigned short int qr_data_codewords_M[] = {
+    16, 28, 44, 64, 86, 108, 124, 154, 182, 216, 254, 290, 334, 365, 415, 453, 507,
+    563, 627, 669, 714, 782, 860, 914, 1000, 1062, 1128, 1193, 1267,
+    1373, 1455, 1541, 1631, 1725, 1812, 1914, 1992, 2102, 2216, 2334
+};
+
+static const unsigned short int qr_data_codewords_Q[] = {
+    13, 22, 34, 48, 62, 76, 88, 110, 132, 154, 180, 206, 244, 261, 295, 325, 367,
+    397, 445, 485, 512, 568, 614, 664, 718, 754, 808, 871, 911,
+    985, 1033, 1115, 1171, 1231, 1286, 1354, 1426, 1502, 1582, 1666
+};
+
+static const unsigned short int qr_data_codewords_H[] = {
+    9, 16, 26, 36, 46, 60, 66, 86, 100, 122, 140, 158, 180, 197, 223, 253, 283,
+    313, 341, 385, 406, 442, 464, 514, 538, 596, 628, 661, 701,
+    745, 793, 845, 901, 961, 986, 1054, 1096, 1142, 1222, 1276
+};
+
+static const unsigned short int qr_total_codewords[] = {
+    26, 44, 70, 100, 134, 172, 196, 242, 292, 346, 404, 466, 532, 581, 655, 733, 815,
+    901, 991, 1085, 1156, 1258, 1364, 1474, 1588, 1706, 1828, 1921, 2051,
+    2185, 2323, 2465, 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706
+};
+
+static const unsigned short int rmqr_height[] = {
+    7, 7, 7, 7, 7,
+    9, 9, 9, 9, 9,
+    11, 11, 11, 11, 11, 11,
+    13, 13, 13, 13, 13, 13,
+    15, 15, 15, 15, 15,
+    17, 17, 17, 17, 17
+};
+
+static const unsigned short int rmqr_width[] = {
+    43, 59, 77, 99, 139,
+    43, 59, 77, 99, 139,
+    27, 43, 59, 77, 99, 139,
+    27, 43, 59, 77, 99, 139,
+    43, 59, 77, 99, 139,
+    43, 59, 77, 99, 139
+};
+
+static const unsigned short int rmqr_data_codewords_M[] = {
+    6, 12, 20, 28, 44, // R7x
+    12, 21, 31, 42, 63, // R9x
+    7, 19, 31, 43, 57, 84, // R11x
+    12, 27, 38, 53, 73, 106, // R13x
+    33, 48, 67, 88, 127, // R15x
+    39, 56, 78, 100, 152 // R17x
+};
+
+static const unsigned short int rmqr_data_codewords_H[] = {
+    3, 7, 10, 14, 24, // R7x
+    7, 11, 17, 22, 33, // R9x
+    5, 11, 15, 23, 29, 42, // R11x
+    7, 13, 20, 29, 35, 54, // R13x
+    15, 26, 31, 48, 69, // R15x
+    21, 28, 38, 56, 76 // R17x
+};
+
+static const short int rmqr_fixed_height_upper_bound[] = {
+    -1, 4, 9, 15, 21, 26, 31
+};
+
+static const unsigned short int rmqr_total_codewords[] = {
+    13, 21, 32, 44, 68, // R7x
+    21, 33, 49, 66, 99, // R9x
+    15, 31, 47, 67, 89, 132, // R11x
+    21, 41, 60, 85, 113, 166, // R13x
+    51, 74, 103, 136, 199, // R15x
+    61, 88, 122, 160, 232 // R17x
+};
+
+
+static const unsigned short int rmqr_numeric_cci[] = {
+    4, 5, 6, 7, 7,
+    5, 6, 7, 7, 8,
+    5, 6, 7, 7, 8, 8,
+    5, 7, 7, 8, 8, 8,
+    7, 7, 8, 8, 9,
+    7, 8, 8, 8, 9
+};
+
+static const unsigned short int rmqr_alphanum_cci[] = {
+    4, 5, 5, 6, 6,
+    5, 5, 6, 6, 7,
+    4, 5, 6, 6, 7, 7,
+    5, 6, 6, 7, 7, 8,
+    6, 7, 7, 7, 8,
+    6, 7, 7, 8, 8
+};
+
+static const unsigned short int rmqr_byte_cci[] = {
+    3, 4, 5, 5, 6,
+    4, 5, 5, 6, 6,
+    3, 5, 5, 6, 6, 7,
+    4, 5, 6, 6, 7, 7,
+    6, 6, 7, 7, 7,
+    6, 6, 7, 7, 8
 };
 
-static int qr_data_codewords_M[] = {
-       16, 28, 44, 64, 86, 108, 124, 154, 182, 216, 254, 290, 334, 365, 415, 453, 507,
-       563, 627, 669, 714, 782, 860, 914, 1000, 1062, 1128, 1193, 1267,
-       1373, 1455, 1541, 1631, 1725, 1812, 1914, 1992, 2102, 2216, 2334
+static const unsigned short int rmqr_kanji_cci[] = {
+    2, 3, 4, 5, 5,
+    3, 4, 5, 5, 6,
+    2, 4, 5, 5, 6, 6,
+    3, 5, 5, 6, 6, 7,
+    5, 5, 6, 6, 7,
+    5, 6, 6, 6, 7
 };
 
-static int qr_data_codewords_Q[] = {
-       13, 22, 34, 48, 62, 76, 88, 110, 132, 154, 180, 206, 244, 261, 295, 325, 367,
-       397, 445, 485, 512, 568, 614, 664, 718, 754, 808, 871, 911,
-       985, 1033, 1115, 1171, 1231, 1286, 1354, 1426, 1502, 1582, 1666
-};
-
-static int qr_data_codewords_H[] = {
-       9, 16, 26, 36, 46, 60, 66, 86, 100, 122, 140, 158, 180, 197, 223, 253, 283,
-       313, 341, 385, 406, 442, 464, 514, 538, 596, 628, 661, 701,
-       745, 793, 845, 901, 961, 986, 1054, 1096, 1142, 1222, 1276
+static const char qr_blocks_L[] = {
+    1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12,
+    12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25
 };
-
-static int qr_total_codewords[] = {
-       26, 44, 70, 100, 134, 172, 196, 242, 292, 346, 404, 466, 532, 581, 655, 733, 815,
-       901, 991, 1085, 1156, 1258, 1364, 1474, 1588, 1706, 1828, 1921, 2051,
-       2185, 2323, 2465, 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706
-};
-
-static int qr_blocks_L[] = {
-       1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12,
-       12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25
-};
-
-static int qr_blocks_M[] = {
-       1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20,
-       21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49
-};
-
-static int qr_blocks_Q[] = {
-       1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25,
-       27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68
-};
-
-static int qr_blocks_H[] = {
-       1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30,
-       32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81
-};
-
-static int qr_sizes[] = {
-       21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97,
-       101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177
-};
-
-static int micro_qr_sizes[] = {
-       11, 13, 15, 17
-};
-
-static int qr_align_loopsize[] = {
-       0, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7
-};
-
-static int qr_table_e1[] = {
-       6, 18, 0, 0, 0, 0, 0,
-       6, 22, 0, 0, 0, 0, 0,
-       6, 26, 0, 0, 0, 0, 0,
-       6, 30, 0, 0, 0, 0, 0,
-       6, 34, 0, 0, 0, 0, 0,
-       6, 22, 38, 0, 0, 0, 0,
-       6, 24, 42, 0, 0, 0, 0,
-       6, 26, 46, 0, 0, 0, 0,
-       6, 28, 50, 0, 0, 0, 0,
-       6, 30, 54, 0, 0, 0, 0,
-       6, 32, 58, 0, 0, 0, 0,
-       6, 34, 62, 0, 0, 0, 0,
-       6, 26, 46, 66, 0, 0, 0,
-       6, 26, 48, 70, 0, 0, 0,
-       6, 26, 50, 74, 0, 0, 0,
-       6, 30, 54, 78, 0, 0, 0,
-       6, 30, 56, 82, 0, 0, 0,
-       6, 30, 58, 86, 0, 0, 0,
-       6, 34, 62, 90, 0, 0, 0,
-       6, 28, 50, 72, 94, 0, 0,
-       6, 26, 50, 74, 98, 0, 0,
-       6, 30, 54, 78, 102, 0, 0,
-       6, 28, 54, 80, 106, 0, 0,
-       6, 32, 58, 84, 110, 0, 0,
-       6, 30, 58, 86, 114, 0, 0,
-       6, 34, 62, 90, 118, 0, 0,
-       6, 26, 50, 74, 98, 122, 0,
-       6, 30, 54, 78, 102, 126, 0,
-       6, 26, 52, 78, 104, 130, 0,
-       6, 30, 56, 82, 108, 134, 0,
-       6, 34, 60, 86, 112, 138, 0,
-       6, 30, 58, 86, 114, 142, 0,
-       6, 34, 62, 90, 118, 146, 0,
-       6, 30, 54, 78, 102, 126, 150,
-       6, 24, 50, 76, 102, 128, 154,
-       6, 28, 54, 80, 106, 132, 158,
-       6, 32, 58, 84, 110, 136, 162,
-       6, 26, 54, 82, 110, 138, 166,
-       6, 30, 58, 86, 114, 142, 170
+
+static const char qr_blocks_M[] = {
+    1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20,
+    21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49
+};
+
+static const char qr_blocks_Q[] = {
+    1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25,
+    27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68
+};
+
+static const char qr_blocks_H[] = {
+    1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30,
+    32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81
+};
+
+static const char rmqr_blocks_M[] = {
+    1, 1, 1, 1, 1, // R7x
+    1, 1, 1, 1, 2, // R9x
+    1, 1, 1, 1, 2, 2, // R11x
+    1, 1, 1, 2, 2, 3, // R13x
+    1, 1, 2, 2, 3, // R15x
+    1, 2, 2, 3, 4 // R17x
+};
+
+static const char rmqr_blocks_H[] = {
+    1, 1, 1, 1, 2, // R7x
+    1, 1, 2, 2, 3, // R9x
+    1, 1, 2, 2, 2, 3, // R11x
+    1, 1, 2, 2, 3, 4, // R13x
+    2, 2, 3, 4, 5, // R15x
+    2, 2, 3, 4, 6 // R17x
+};
+
+static const unsigned short int qr_sizes[] = {
+    21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97,
+    101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177
+};
+
+static const char micro_qr_sizes[] = {
+    11, 13, 15, 17
+};
+
+static const char qr_align_loopsize[] = {
+    0, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7
+};
+
+// Table E1 - Row/column coordinates of center module of alignment patterns
+static const unsigned short int qr_table_e1[] = {
+    6, 18, 0, 0, 0, 0, 0,
+    6, 22, 0, 0, 0, 0, 0,
+    6, 26, 0, 0, 0, 0, 0,
+    6, 30, 0, 0, 0, 0, 0,
+    6, 34, 0, 0, 0, 0, 0,
+    6, 22, 38, 0, 0, 0, 0,
+    6, 24, 42, 0, 0, 0, 0,
+    6, 26, 46, 0, 0, 0, 0,
+    6, 28, 50, 0, 0, 0, 0,
+    6, 30, 54, 0, 0, 0, 0,
+    6, 32, 58, 0, 0, 0, 0,
+    6, 34, 62, 0, 0, 0, 0,
+    6, 26, 46, 66, 0, 0, 0,
+    6, 26, 48, 70, 0, 0, 0,
+    6, 26, 50, 74, 0, 0, 0,
+    6, 30, 54, 78, 0, 0, 0,
+    6, 30, 56, 82, 0, 0, 0,
+    6, 30, 58, 86, 0, 0, 0,
+    6, 34, 62, 90, 0, 0, 0,
+    6, 28, 50, 72, 94, 0, 0,
+    6, 26, 50, 74, 98, 0, 0,
+    6, 30, 54, 78, 102, 0, 0,
+    6, 28, 54, 80, 106, 0, 0,
+    6, 32, 58, 84, 110, 0, 0,
+    6, 30, 58, 86, 114, 0, 0,
+    6, 34, 62, 90, 118, 0, 0,
+    6, 26, 50, 74, 98, 122, 0,
+    6, 30, 54, 78, 102, 126, 0,
+    6, 26, 52, 78, 104, 130, 0,
+    6, 30, 56, 82, 108, 134, 0,
+    6, 34, 60, 86, 112, 138, 0,
+    6, 30, 58, 86, 114, 142, 0,
+    6, 34, 62, 90, 118, 146, 0,
+    6, 30, 54, 78, 102, 126, 150,
+    6, 24, 50, 76, 102, 128, 154,
+    6, 28, 54, 80, 106, 132, 158,
+    6, 32, 58, 84, 110, 136, 162,
+    6, 26, 54, 82, 110, 138, 166,
+    6, 30, 58, 86, 114, 142, 170
+};
+
+// Table D1 - Column coordinates of centre module of alignment patterns
+static const unsigned short int rmqr_table_d1[] = {
+    21, 0, 0, 0,
+    19, 39, 0, 0,
+    25, 51, 0, 0,
+    23, 49, 75, 0,
+    27, 55, 83, 111
+};
+
+static const unsigned int qr_annex_c[] = {
+    /* Format information bit sequences */
+    0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4, 0x72f3, 0x7daa, 0x789d,
+    0x662f, 0x6318, 0x6c41, 0x6976, 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b,
+    0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed
 };
 
-static unsigned int qr_annex_c[] = {
-       /* Format information bit sequences */
-       0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4, 0x72f3, 0x7daa, 0x789d,
-       0x662f, 0x6318, 0x6c41, 0x6976, 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b,
-       0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed
-};
-
-static long int qr_annex_d[] = {
-       /* Version information bit sequences */
-       0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 0x0f928, 0x10b78,
-       0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1, 0x1afab,
-       0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b,
-       0x2542e, 0x26a64, 0x27541, 0x28c69
-};
-
-static int qr_annex_c1[] = {
-       /* Micro QR Code format information */
-       0x4445, 0x4172, 0x4e2b, 0x4b1c, 0x55ae, 0x5099, 0x5fc0, 0x5af7, 0x6793, 0x62a4, 0x6dfd, 0x68ca, 0x7678, 0x734f,
-       0x7c16, 0x7921, 0x06de, 0x03e9, 0x0cb0, 0x0987, 0x1735, 0x1202, 0x1d5b, 0x186c, 0x2508, 0x203f, 0x2f66, 0x2a51, 0x34e3,
-       0x31d4, 0x3e8d, 0x3bba
-};
\ No newline at end of file
+static const unsigned int qr_annex_d[] = {
+    /* Version information bit sequences */
+    0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 0x0f928, 0x10b78,
+    0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1, 0x1afab,
+    0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b,
+    0x2542e, 0x26a64, 0x27541, 0x28c69
+};
+
+static const unsigned int qr_annex_c1[] = {
+    /* Micro QR Code format information */
+    0x4445, 0x4172, 0x4e2b, 0x4b1c, 0x55ae, 0x5099, 0x5fc0, 0x5af7, 0x6793, 0x62a4, 0x6dfd, 0x68ca, 0x7678, 0x734f,
+    0x7c16, 0x7921, 0x06de, 0x03e9, 0x0cb0, 0x0987, 0x1735, 0x1202, 0x1d5b, 0x186c, 0x2508, 0x203f, 0x2f66, 0x2a51, 0x34e3,
+    0x31d4, 0x3e8d, 0x3bba
+};
+
+static const unsigned int rmqr_format_info_left[] = {
+    /* rMQR format information for finder pattern side */
+    0x1FAB2, 0x1E597, 0x1DBDD, 0x1C4F8, 0x1B86C, 0x1A749, 0x19903, 0x18626, 0x17F0E, 0x1602B,
+    0x15E61, 0x14144, 0x13DD0, 0x122F5, 0x11CBF, 0x1039A, 0x0F1CA, 0x0EEEF, 0x0D0A5, 0x0CF80,
+    0x0B314, 0x0AC31, 0x0927B, 0x08D5E, 0x07476, 0x06B53, 0x05519, 0x04A3C, 0x036A8, 0x0298D,
+    0x017C7, 0x008E2, 0x3F367, 0x3EC42, 0x3D208, 0x3CD2D, 0x3B1B9, 0x3AE9C, 0x390D6, 0x38FF3,
+    0x376DB, 0x369FE, 0x357B4, 0x34891, 0x33405, 0x32B20, 0x3156A, 0x30A4F, 0x2F81F, 0x2E73A,
+    0x2D970, 0x2C655, 0x2BAC1, 0x2A5E4, 0x29BAE, 0x2848B, 0x27DA3, 0x26286, 0x25CCC, 0x243E9,
+    0x23F7D, 0x22058, 0x21E12, 0x20137
+};
+
+static const unsigned int rmqr_format_info_right[] = {
+    /* rMQR format information for subfinder pattern side */
+    0x20A7B, 0x2155E, 0x22B14, 0x23431, 0x248A5, 0x25780, 0x269CA, 0x276EF, 0x28FC7, 0x290E2,
+    0x2AEA8, 0x2B18D, 0x2CD19, 0x2D23C, 0x2EC76, 0x2F353, 0x30103, 0x31E26, 0x3206C, 0x33F49,
+    0x343DD, 0x35CF8, 0x362B2, 0x37D97, 0x384BF, 0x39B9A, 0x3A5D0, 0x3BAF5, 0x3C661, 0x3D944,
+    0x3E70E, 0x3F82B, 0x003AE, 0x01C8B, 0x022C1, 0x03DE4, 0x04170, 0x05E55, 0x0601F, 0x07F3A,
+    0x08612, 0x09937, 0x0A77D, 0x0B858, 0x0C4CC, 0x0DBE9, 0x0E5A3, 0x0FA86, 0x108D6, 0x117F3,
+    0x129B9, 0x1369C, 0x14A08, 0x1552D, 0x16B67, 0x17442, 0x18D6A, 0x1924F, 0x1AC05, 0x1B320,
+    0x1CFB4, 0x1D091, 0x1EEDB, 0x1F1FE
+};
diff --git a/backend/raster.c b/backend/raster.c
new file mode 100644 (file)
index 0000000..434ab8f
--- /dev/null
@@ -0,0 +1,1170 @@
+/* raster.c - Handles output to raster files */
+
+/*
+    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>
+#ifdef _MSC_VER
+#include <fcntl.h>
+#include <io.h>
+#endif
+#include <string.h>
+#include "common.h"
+#include "output.h"
+
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif /* _MSC_VER */
+
+#include "font.h" /* Font for human readable text */
+
+#define SSET   "0123456789ABCDEF"
+
+#define DEFAULT_INK '1'
+#define DEFAULT_PAPER '0'
+
+#ifndef NO_PNG
+INTERNAL int png_pixel_plot(struct zint_symbol *symbol, char *pixelbuf);
+#endif /* NO_PNG */
+INTERNAL int bmp_pixel_plot(struct zint_symbol *symbol, char *pixelbuf);
+INTERNAL int pcx_pixel_plot(struct zint_symbol *symbol, char *pixelbuf);
+INTERNAL int gif_pixel_plot(struct zint_symbol *symbol, char *pixelbuf);
+INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, char *pixelbuf);
+
+static const char ultra_colour[] = "WCBMRYGK";
+
+static int buffer_plot(struct zint_symbol *symbol, char *pixelbuf) {
+    /* Place pixelbuffer into symbol */
+    int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
+    int row, column, i;
+
+    if (symbol->bitmap != NULL) {
+        free(symbol->bitmap);
+        symbol->bitmap = NULL;
+    }
+    symbol->bitmap = (unsigned char *) malloc(symbol->bitmap_width * symbol->bitmap_height * 3);
+    if (symbol->bitmap == NULL) {
+        strcpy(symbol->errtxt, "661: Insufficient memory for bitmap buffer");
+        return ZINT_ERROR_MEMORY;
+    }
+
+    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]);
+    
+    for (row = 0; row < symbol->bitmap_height; row++) {
+        for (column = 0; column < symbol->bitmap_width; column++) {
+            i = ((row * symbol->bitmap_width) + column) * 3;
+            switch (*(pixelbuf + (symbol->bitmap_width * row) + column)) {
+                case 'W': // White
+                    symbol->bitmap[i] = 255;
+                    symbol->bitmap[i + 1] = 255;
+                    symbol->bitmap[i + 2] = 255;
+                    break;
+                case 'C': // Cyan
+                    symbol->bitmap[i] = 0;
+                    symbol->bitmap[i + 1] = 255;
+                    symbol->bitmap[i + 2] = 255;
+                    break;
+                case 'B': // Blue
+                    symbol->bitmap[i] = 0;
+                    symbol->bitmap[i + 1] = 0;
+                    symbol->bitmap[i + 2] = 255;
+                    break;
+                case 'M': // Magenta
+                    symbol->bitmap[i] = 255;
+                    symbol->bitmap[i + 1] = 0;
+                    symbol->bitmap[i + 2] = 255;
+                    break;
+                case 'R': // Red
+                    symbol->bitmap[i] = 255;
+                    symbol->bitmap[i + 1] = 0;
+                    symbol->bitmap[i + 2] = 0;
+                    break;
+                case 'Y': // Yellow
+                    symbol->bitmap[i] = 255;
+                    symbol->bitmap[i + 1] = 255;
+                    symbol->bitmap[i + 2] = 0;
+                    break;
+                case 'G': // Green
+                    symbol->bitmap[i] = 0;
+                    symbol->bitmap[i + 1] = 255;
+                    symbol->bitmap[i + 2] = 0;
+                    break;
+                case 'K': // Black
+                    symbol->bitmap[i] = 0;
+                    symbol->bitmap[i + 1] = 0;
+                    symbol->bitmap[i + 2] = 0;
+                    break;
+                case DEFAULT_INK:
+                    symbol->bitmap[i] = fgred;
+                    symbol->bitmap[i + 1] = fggrn;
+                    symbol->bitmap[i + 2] = fgblu;
+                    break;
+                default: // DEFAULT_PAPER
+                    symbol->bitmap[i] = bgred;
+                    symbol->bitmap[i + 1] = bggrn;
+                    symbol->bitmap[i + 2] = bgblu;
+                    break;
+
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int save_raster_image_to_file(struct zint_symbol *symbol, int image_height, int image_width, char *pixelbuf, int rotate_angle, int image_type) {
+    int error_number;
+    int row, column;
+
+    char *rotated_pixbuf = pixelbuf;
+
+    switch (rotate_angle) {
+        case 0:
+        case 180:
+            symbol->bitmap_width = image_width;
+            symbol->bitmap_height = image_height;
+            break;
+        case 90:
+        case 270:
+            symbol->bitmap_width = image_height;
+            symbol->bitmap_height = image_width;
+            break;
+    }
+
+    if (rotate_angle) {
+        if (!(rotated_pixbuf = (char *) malloc(image_width * image_height))) {
+            strcpy(symbol->errtxt, "650: Insufficient memory for pixel buffer");
+            return ZINT_ERROR_ENCODING_PROBLEM;
+        }
+    }
+
+    /* Rotate image before plotting */
+    switch (rotate_angle) {
+        case 0: /* Plot the right way up */
+            /* Nothing to do */
+            break;
+        case 90: /* Plot 90 degrees clockwise */
+            for (row = 0; row < image_width; row++) {
+                for (column = 0; column < image_height; column++) {
+                    rotated_pixbuf[(row * image_height) + column] =
+                            *(pixelbuf + (image_width * (image_height - column - 1)) + row);
+                }
+            }
+            break;
+        case 180: /* Plot upside down */
+            for (row = 0; row < image_height; row++) {
+                for (column = 0; column < image_width; column++) {
+                    rotated_pixbuf[(row * image_width) + column] =
+                            *(pixelbuf + (image_width * (image_height - row - 1)) + (image_width - column - 1));
+                }
+            }
+            break;
+        case 270: /* Plot 90 degrees anti-clockwise */
+            for (row = 0; row < image_width; row++) {
+                for (column = 0; column < image_height; column++) {
+                    rotated_pixbuf[(row * image_height) + column] =
+                            *(pixelbuf + (image_width * column) + (image_width - row - 1));
+                }
+            }
+            break;
+    }
+
+    switch (image_type) {
+        case OUT_BUFFER:
+            error_number = buffer_plot(symbol, rotated_pixbuf);
+            break;
+        case OUT_PNG_FILE:
+#ifndef NO_PNG
+            error_number = png_pixel_plot(symbol, rotated_pixbuf);
+#else
+            if (rotate_angle) {
+                free(rotated_pixbuf);
+            }
+            return ZINT_ERROR_INVALID_OPTION;
+#endif
+            break;
+        case OUT_PCX_FILE:
+            error_number = pcx_pixel_plot(symbol, rotated_pixbuf);
+            break;
+        case OUT_GIF_FILE:
+            error_number = gif_pixel_plot(symbol, rotated_pixbuf);
+            break;
+        case OUT_TIF_FILE:
+            error_number = tif_pixel_plot(symbol, rotated_pixbuf);
+            break;
+        default:
+            error_number = bmp_pixel_plot(symbol, rotated_pixbuf);
+            break;
+    }
+
+    if (rotate_angle) {
+        free(rotated_pixbuf);
+    }
+    return error_number;
+}
+
+static void draw_bar(char *pixelbuf, int xpos, int xlen, int ypos, int ylen, int image_width, int image_height, char fill) {
+    /* Draw a rectangle */
+    int i, j, png_ypos;
+
+    png_ypos = image_height - ypos - ylen;
+    /* This fudge is needed because EPS measures height from the bottom up but
+    PNG measures y position from the top down */
+
+    for (i = (xpos); i < (xpos + xlen); i++) {
+        for (j = (png_ypos); j < (png_ypos + ylen); j++) {
+            *(pixelbuf + (image_width * j) + i) = fill;
+        }
+    }
+}
+
+static void draw_circle(char *pixelbuf, int image_width, int image_height, int x0, int y0, float radius, char fill) {
+    int x, y;
+    int radius_i = (int) radius;
+
+    for (y = -radius_i; y <= radius_i; y++) {
+        for (x = -radius_i; x <= radius_i; x++) {
+            if ((x * x) + (y * y) <= (radius_i * radius_i)) {
+                if ((y + y0 >= 0) && (y + y0 < image_height)
+                        && (x + x0 >= 0) && (x + x0 < image_width)) {
+                    *(pixelbuf + ((y + y0) * image_width) + (x + x0)) = fill;
+                }
+            }
+        }
+    }
+}
+
+static void draw_bullseye(char *pixelbuf, int image_width, int image_height, int xoffset, int yoffset, int scaler) {
+    /* Central bullseye in Maxicode symbols */
+    float x = 14.5 * scaler;
+    float y = 15.0 * scaler;
+    if(scaler < 10) {
+        x = 16.0 * scaler;
+        y = 16.5 * scaler;
+    }
+
+    draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (4.571 * scaler) + 1, DEFAULT_INK);
+    draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (3.779 * scaler) + 1, DEFAULT_PAPER);
+    draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (2.988 * scaler) + 1, DEFAULT_INK);
+    draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (2.196 * scaler) + 1, DEFAULT_PAPER);
+    draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (1.394 * scaler) + 1, DEFAULT_INK);
+    draw_circle(pixelbuf, image_width, image_height, x + xoffset, y + yoffset, (0.602 * scaler) + 1, DEFAULT_PAPER);
+}
+
+static void draw_hexagon(char *pixelbuf, int image_width, char *scaled_hexagon, int hexagon_size, int xposn, int yposn) {
+    /* Put a hexagon into the pixel buffer */
+    int i, j;
+
+    for (i = 0; i < hexagon_size; i++) {
+        for (j = 0; j < hexagon_size; j++) {
+            if (scaled_hexagon[(i * hexagon_size) + j] == DEFAULT_INK) {
+                *(pixelbuf + (image_width * i) + (image_width * yposn) + xposn + j) = DEFAULT_INK;
+            }
+        }
+    }
+}
+
+static void draw_letter(char *pixelbuf, unsigned char letter, int xposn, int yposn, int textflags, int image_width, int image_height) {
+    /* Put a letter into a position */
+    int skip;
+
+    skip = 0;
+
+    if (letter < 33) {
+        skip = 1;
+    }
+
+    if ((letter > 127) && (letter < 161)) {
+        skip = 1;
+    }
+
+    if (xposn < 0 || yposn < 0) {
+        skip = 1;
+    }
+
+    if (skip == 0) {
+        int glyph_no;
+        int x, y;
+        if (letter > 128) {
+            glyph_no = letter - 66;
+        } else {
+            glyph_no = letter - 33;
+        }
+
+
+        switch (textflags) {
+            int max_x, max_y;
+            case 1: // small font 5x9
+                max_x = 5;
+                max_y = 9;
+
+                if (xposn + max_x >= image_width) {
+                    max_x = image_width - xposn - 1;
+                }
+
+                if (yposn + max_y >= image_height) {
+                    max_y = image_height - yposn - 1;
+                }
+
+                for (y = 0; y < max_y; y++) {
+                    for (x = 0; x < max_x; x++) {
+                        if (small_font[(glyph_no * 9) + y] & (0x10 >> x)) {
+                            *(pixelbuf + (y * image_width) + (yposn * image_width) + xposn + x) = DEFAULT_INK;
+                        }
+                    }
+                }
+                break;
+
+            case 2: // bold font -> twice the regular font
+            {
+                char * linePtr;
+                max_x = 7;
+                max_y = 14;
+
+                if (xposn + max_x + 1 >= image_width) {
+                    max_x = image_width - xposn - 2;
+                }
+
+                if (yposn + max_y >= image_height) {
+                    max_y = image_height - yposn - 1;
+                }
+
+                linePtr = pixelbuf + (yposn * image_width) + xposn + 1;
+                for (y = 0; y < max_y; y++) {
+                    char * pixelPtr = linePtr;
+                    int extra_dot = 0;
+                    for (x = 0; x < max_x; x++) {
+                        if (ascii_font[(glyph_no * 14) + y] & (0x40 >> x)) {
+                            *pixelPtr = DEFAULT_INK;
+                            extra_dot = 1;
+                        } else {
+                            if (extra_dot) {
+                                *pixelPtr = DEFAULT_INK;
+                            }
+
+                            extra_dot = 0;
+                        }
+
+                        ++pixelPtr;
+                    }
+
+                    if (extra_dot) {
+                        *pixelPtr = DEFAULT_INK;
+                    }
+
+                    linePtr += image_width;
+                }
+            }
+                break;
+
+            default: // regular font 7x14
+                max_x = 7;
+                max_y = 14;
+
+                if (xposn + max_x >= image_width) {
+                    max_x = image_width - xposn - 1;
+                }
+
+                if (yposn + max_y >= image_height) {
+                    max_y = image_height - yposn - 1;
+                }
+
+                for (y = 0; y < max_y; y++) {
+                    for (x = 0; x < max_x; x++) {
+                        if (ascii_font[(glyph_no * 14) + y] & (0x40 >> x)) {
+                            *(pixelbuf + (y * image_width) + (yposn * image_width) + xposn + x) = DEFAULT_INK;
+                        }
+                    }
+                }
+                break;
+        }
+    }
+}
+
+/* Plot a string into the pixel buffer */
+static void draw_string(char *pixbuf, char input_string[], int xposn, int yposn, int textflags, int image_width, int image_height) {
+    int i, string_length, string_left_hand, letter_width = 7;
+
+    switch (textflags) {
+        case 1: // small font 5x9
+            letter_width = 5;
+            break;
+
+        case 2: // bold font -> width of the regular font + 1 extra dot + 1 extra space
+            letter_width = 9;
+            break;
+
+        default: // regular font 7x15
+            letter_width = 7;
+            break;
+    }
+
+    string_length = strlen(input_string);
+    string_left_hand = xposn - ((letter_width * string_length) / 2);
+
+    for (i = 0; i < string_length; i++) {
+        // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage) suppress false positive about 2nd arg input_string[i] being uninitialized
+        draw_letter(pixbuf, input_string[i], string_left_hand + (i * letter_width), yposn, textflags, image_width, image_height);
+    }
+
+}
+
+static void plot_hexline(char *scaled_hexagon, int hexagon_size, float start_x, float start_y, float end_x, float end_y) {
+    /* Draw a straight line from start to end */
+    int i;
+    float inc_x, inc_y;
+
+    inc_x = (end_x - start_x) / hexagon_size;
+    inc_y = (end_y - start_y) / hexagon_size;
+
+    for (i = 0; i < hexagon_size; i++) {
+        float this_x = start_x + ((float)i * inc_x);
+        float this_y = start_y + ((float)i * inc_y);
+        if (((this_x >= 0) && (this_x < hexagon_size)) && ((this_y >= 0) && (this_y < hexagon_size))) {
+                scaled_hexagon[(hexagon_size * (int)this_y) + (int)this_x] = DEFAULT_INK;
+        }
+    }
+}
+
+static void plot_hexagon(char *scaled_hexagon, int hexagon_size) {
+    /* Create a hexagon shape and fill it */
+    int line, i;
+
+    float x_offset[6];
+    float y_offset[6];
+    float start_x, start_y;
+    float end_x, end_y;
+
+    x_offset[0] = 0.0;
+    x_offset[1] = 0.86;
+    x_offset[2] = 0.86;
+    x_offset[3] = 0.0;
+    x_offset[4] = -0.86;
+    x_offset[5] = -0.86;
+
+    y_offset[0] = 1.0;
+    y_offset[1] = 0.5;
+    y_offset[2] = -0.5;
+    y_offset[3] = -1.0;
+    y_offset[4] = -0.5;
+    y_offset[5] = 0.5;
+
+    /* Plot hexagon outline */
+    for (line = 0; line < 5; line++) {
+        start_x = ((float)hexagon_size / 2.0) + (((float)hexagon_size / 2.0) * x_offset[line]);
+        start_y = ((float)hexagon_size / 2.0) + (((float)hexagon_size / 2.0) * y_offset[line]);
+        end_x = ((float)hexagon_size / 2.0) + (((float)hexagon_size / 2.0) * x_offset[line + 1]);
+        end_y = ((float)hexagon_size / 2.0) + (((float)hexagon_size / 2.0) * y_offset[line + 1]);
+        plot_hexline(scaled_hexagon, hexagon_size, start_x, start_y, end_x, end_y);
+    }
+    start_x = ((float)hexagon_size / 2.0) + (((float)hexagon_size / 2.0) * x_offset[line]);
+    start_y = ((float)hexagon_size / 2.0) + (((float)hexagon_size / 2.0) * y_offset[line]);
+    end_x = ((float)hexagon_size / 2.0) + (((float)hexagon_size / 2.0) * x_offset[0]);
+    end_y = ((float)hexagon_size / 2.0) + (((float)hexagon_size / 2.0) * y_offset[0]);
+    plot_hexline(scaled_hexagon, hexagon_size, start_x, start_y, end_x, end_y);
+
+    /* Fill hexagon */
+    for (line = 0; line < hexagon_size; line++) {
+        char ink = DEFAULT_PAPER;
+        for (i = 0; i < hexagon_size; i++) {
+            if (scaled_hexagon[(hexagon_size * line) + i] == DEFAULT_INK) {
+                if (i < (hexagon_size / 2)) {
+                    ink = DEFAULT_INK;
+                } else {
+                    ink = DEFAULT_PAPER;
+                }
+            }
+
+            if (ink == DEFAULT_INK) {
+                scaled_hexagon[(hexagon_size * line) + i] = ink;
+            }
+        }
+    }
+}
+
+static int plot_raster_maxicode(struct zint_symbol *symbol, int rotate_angle, int data_type) {
+    /* Plot a MaxiCode symbol with hexagons and bullseye */
+    int row, column, xposn;
+    int image_height, image_width;
+    char *pixelbuf;
+    int error_number;
+    int xoffset, yoffset;
+    int roffset, boffset;
+    float scaler = symbol->scale;
+    char *scaled_hexagon;
+    int hexagon_size;
+
+    if (scaler <= 0) {
+        scaler = 0.5;
+    }
+
+    set_whitespace_offsets(symbol, &xoffset, &yoffset, &roffset, &boffset);
+
+    image_width = (300 + 2 * (xoffset + roffset)) * scaler;
+    image_height = (300 + 2 * (yoffset + boffset)) * scaler;
+
+    if (!(pixelbuf = (char *) malloc(image_width * image_height))) {
+        strcpy(symbol->errtxt, "655: Insufficient memory for pixel buffer");
+        return ZINT_ERROR_ENCODING_PROBLEM;
+    }
+    memset(pixelbuf, DEFAULT_PAPER, image_width * image_height);
+
+    hexagon_size = (int)(scaler * 10);
+
+    if (!(scaled_hexagon = (char *) malloc(hexagon_size * hexagon_size))) {
+        strcpy(symbol->errtxt, "656: Insufficient memory for pixel buffer");
+        free(pixelbuf);
+        return ZINT_ERROR_ENCODING_PROBLEM;
+    }
+    memset(scaled_hexagon, DEFAULT_PAPER, hexagon_size * hexagon_size);
+
+    plot_hexagon(scaled_hexagon, hexagon_size);
+
+    for (row = 0; row < symbol->rows; row++) {
+        int yposn = row * 9;
+        for (column = 0; column < symbol->width; column++) {
+            xposn = column * 10;
+            if (module_is_set(symbol, row, column)) {
+                if (row & 1) {
+                    /* Odd (reduced) row */
+                    xposn += 5;
+                    draw_hexagon(pixelbuf, image_width, scaled_hexagon, hexagon_size, (xposn + (2 * xoffset)) * scaler, (yposn + (2 * yoffset)) * scaler);
+                } else {
+                    /* Even (full) row */
+                    draw_hexagon(pixelbuf, image_width, scaled_hexagon, hexagon_size, (xposn + (2 * xoffset)) * scaler, (yposn + (2 * yoffset)) * scaler);
+                }
+            }
+        }
+    }
+
+    draw_bullseye(pixelbuf, image_width, image_height, (2.0 * xoffset), (2.0 * yoffset), scaler * 10);
+
+    // Virtual hexagon
+    //draw_hexagon(pixelbuf, image_width, scaled_hexagon, hexagon_size, ((14 * 10) + (2 * xoffset)) * scaler, ((16 * 9) + (2 * yoffset)) * scaler);
+
+    if ((symbol->output_options & BARCODE_BOX) || (symbol->output_options & BARCODE_BIND)) {
+        /* boundary bars */
+        draw_bar(pixelbuf, 0, image_width, 0, symbol->border_width * 2, image_width, image_height, DEFAULT_INK);
+        draw_bar(pixelbuf, 0, image_width, 300 + (symbol->border_width * 2), symbol->border_width * 2, image_width, image_height, DEFAULT_INK);
+    }
+
+    if (symbol->output_options & BARCODE_BOX) {
+        /* side bars */
+        draw_bar(pixelbuf, 0, symbol->border_width * 2, 0, image_height, image_width, image_height, DEFAULT_INK);
+        draw_bar(pixelbuf, 300 + ((symbol->border_width + symbol->whitespace_width + symbol->whitespace_width) * 2), symbol->border_width * 2, 0, image_height, image_width, image_height, DEFAULT_INK);
+    }
+
+    error_number = save_raster_image_to_file(symbol, image_height, image_width, pixelbuf, rotate_angle, data_type);
+    free(scaled_hexagon);
+    free(pixelbuf);
+    return error_number;
+}
+
+/* Convert UTF-8 to Latin1 Codepage for the interpretation line */
+static void to_latin1(unsigned char source[], unsigned char preprocessed[]) {
+    int j, i, input_length;
+
+    input_length = ustrlen(source);
+
+    j = 0;
+    i = 0;
+    while (i < input_length) {
+        switch (source[i]) {
+            case 0xC2:
+                /* UTF-8 C2xxh */
+                /* Character range: C280h (latin: 80h) to C2BFh (latin: BFh) */
+                i++;
+                preprocessed[j] = source[i];
+                j++;
+                break;
+            case 0xC3:
+                /* UTF-8 C3xx */
+                /* Character range: C380h (latin: C0h) to C3BFh (latin: FFh) */
+                i++;
+                preprocessed[j] = source[i] + 64;
+                j++;
+                break;
+            default:
+                /* Process ASCII (< 80h), all other unicode points are ignored */
+                if (source[i] < 128) {
+                    preprocessed[j] = source[i];
+                    j++;
+                }
+                break;
+        }
+        i++;
+    }
+    preprocessed[j] = '\0';
+
+    return;
+}
+
+static int plot_raster_dotty(struct zint_symbol *symbol, int rotate_angle, int data_type) {
+    float scaler = 2 * symbol->scale;
+    char *scaled_pixelbuf;
+    int r, i;
+    int scale_width, scale_height;
+    int error_number = 0;
+    int xoffset, yoffset, image_width, image_height;
+    int roffset, boffset;
+
+    symbol->height = symbol->rows; // This is true because only 2d matrix symbols are processed here
+
+    set_whitespace_offsets(symbol, &xoffset, &yoffset, &roffset, &boffset);
+
+    image_width = symbol->width + xoffset + roffset;
+    image_height = symbol->height + yoffset + boffset;
+
+    if (scaler < 2.0) {
+        scaler = 2.0;
+    }
+    scale_width = (image_width * scaler) + 1;
+    scale_height = (image_height * scaler) + 1;
+
+    /* Apply scale options by creating another pixel buffer */
+    if (!(scaled_pixelbuf = (char *) malloc(scale_width * scale_height))) {
+        strcpy(symbol->errtxt, "657: Insufficient memory for pixel buffer");
+        return ZINT_ERROR_ENCODING_PROBLEM;
+    }
+    memset(scaled_pixelbuf, DEFAULT_PAPER, scale_width * scale_height);
+
+    /* Plot the body of the symbol to the pixel buffer */
+    for (r = 0; r < symbol->rows; r++) {
+        for (i = 0; i < symbol->width; i++) {
+            if (module_is_set(symbol, r, i)) {
+                draw_circle(scaled_pixelbuf, scale_width, scale_height,
+                        (int) ((i + xoffset) * scaler) + (scaler / 2.0),
+                        (int) ((r + yoffset) * scaler) + (scaler / 2.0),
+                        (symbol->dot_size / 2.0) * scaler,
+                        DEFAULT_INK);
+            }
+        }
+    }
+
+    error_number = save_raster_image_to_file(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle, data_type);
+    free(scaled_pixelbuf);
+
+    return error_number;
+}
+
+static int plot_raster_default(struct zint_symbol *symbol, int rotate_angle, int data_type) {
+    int textdone, main_width, comp_offset, large_bar_count;
+    char textpart[10], addon[6];
+    float addon_text_posn, preset_height, large_bar_height;
+    int i, r, textoffset, yoffset, xoffset, latch, image_width, image_height;
+    int roffset, boffset;
+    char *pixelbuf;
+    int addon_latch = 0, textflags = 0;
+    int block_width, textpos;
+    float row_height, row_posn;
+    int error_number;
+    int default_text_posn;
+    int next_yposn;
+    float scaler = symbol->scale;
+    char *scaled_pixelbuf;
+    int horiz, vert;
+    int scale_width, scale_height;
+#ifndef _MSC_VER
+    unsigned char local_text[ustrlen(symbol->text) + 1];
+#else
+    unsigned char* local_text = (unsigned char*) _alloca(ustrlen(symbol->text) + 1);
+#endif
+
+    if (symbol->show_hrt != 0) {
+        /* Copy text from symbol */
+        to_latin1(symbol->text, local_text);
+    } else {
+        /* No text needed */
+        if (is_extendable(symbol->symbology)) {
+            /* For these symbols use dummy text to ensure formatting is done
+             * properly even if no text is required */
+            for (i = 0; i < (int) ustrlen(symbol->text); i++) {
+                if (symbol->text[i] == '+') {
+                    local_text[i] = '+';
+                } else {
+                    local_text[i] = ' ';
+                }
+            }
+            local_text[ustrlen(symbol->text)] = '\0';
+        } else {
+            /* For everything else, just remove the text */
+            memset(local_text, 0, ustrlen(symbol->text) + 1); /* Note using memset() here to suppress clang-tidy false positives */
+        }
+    }
+
+    textdone = 0;
+    main_width = symbol->width;
+    comp_offset = 0;
+    addon_text_posn = 0.0;
+    if (symbol->output_options & SMALL_TEXT) {
+        textflags = 1;
+    } else if (symbol->output_options & BOLD_TEXT) {
+        textflags = 2;
+    }
+
+    if (symbol->height == 0) {
+        symbol->height = 50;
+    }
+
+    large_bar_count = 0;
+    preset_height = 0.0;
+    for (i = 0; i < symbol->rows; i++) {
+        preset_height += symbol->row_height[i];
+        if (symbol->row_height[i] == 0) {
+            large_bar_count++;
+        }
+    }
+
+    if (large_bar_count == 0) {
+        symbol->height = preset_height;
+        large_bar_height = 10;
+    } else {
+        large_bar_height = (symbol->height - preset_height) / large_bar_count;
+    }
+
+    if (is_composite(symbol->symbology)) {
+        while (!(module_is_set(symbol, symbol->rows - 1, comp_offset))) {
+            comp_offset++;
+        }
+    }
+
+    /* Certain symbols need whitespace otherwise characters get chopped off the sides */
+    if ((symbol->symbology == BARCODE_EANX) || (symbol->symbology == BARCODE_EANX_CHK)
+            || (symbol->symbology == BARCODE_EANX_CC) || (symbol->symbology == BARCODE_ISBNX)) {
+        switch (ustrlen(local_text)) {
+            case 13: /* EAN 13 */
+            case 16:
+            case 19:
+                if (symbol->whitespace_width == 0) {
+                    symbol->whitespace_width = 10;
+                }
+                main_width = 96 + comp_offset;
+                break;
+            default:
+                main_width = 68 + comp_offset;
+        }
+    } else if ((symbol->symbology == BARCODE_UPCA) || (symbol->symbology == BARCODE_UPCA_CHK)
+            || (symbol->symbology == BARCODE_UPCA_CC)) {
+        if (symbol->whitespace_width == 0) {
+            symbol->whitespace_width = 10;
+        }
+        main_width = 96 + comp_offset;
+    } else if ((symbol->symbology == BARCODE_UPCE) || (symbol->symbology == BARCODE_UPCE_CHK)
+            || (symbol->symbology == BARCODE_UPCE_CC)) {
+        if (symbol->whitespace_width == 0) {
+            symbol->whitespace_width = 10;
+        }
+        main_width = 51 + comp_offset;
+    }
+
+    latch = 0;
+    r = 0;
+    /* Isolate add-on text */
+    if (is_extendable(symbol->symbology)) {
+        for (i = 0; i < (int) ustrlen(local_text); i++) {
+            if (latch == 1) {
+                addon[r] = local_text[i];
+                r++;
+            }
+            if (symbol->text[i] == '+') {
+                latch = 1;
+            }
+        }
+    }
+    addon[r] = '\0';
+
+    if (ustrlen(local_text) != 0) {
+        textoffset = 9;
+    } else {
+        textoffset = 0;
+    }
+
+    set_whitespace_offsets(symbol, &xoffset, &yoffset, &roffset, &boffset);
+
+    image_width = 2 * (symbol->width + xoffset + roffset);
+    image_height = 2 * (symbol->height + textoffset + yoffset + boffset);
+
+    if (!(pixelbuf = (char *) malloc(image_width * image_height))) {
+        strcpy(symbol->errtxt, "658: Insufficient memory for pixel buffer");
+        return ZINT_ERROR_ENCODING_PROBLEM;
+    }
+    memset(pixelbuf, DEFAULT_PAPER, image_width * image_height);
+
+    default_text_posn = image_height - 17;
+
+    row_posn = textoffset + yoffset;
+    next_yposn = textoffset + yoffset;
+    row_height = 0;
+
+    /* Plot the body of the symbol to the pixel buffer */
+    for (r = 0; r < symbol->rows; r++) {
+        int plot_yposn;
+        int plot_height;
+        int this_row = symbol->rows - r - 1; /* invert r otherwise plots upside down */
+        int module_fill;
+        row_posn += row_height;
+        plot_yposn = next_yposn;
+        if (symbol->row_height[this_row] == 0) {
+            row_height = large_bar_height;
+        } else {
+            row_height = symbol->row_height[this_row];
+        }
+        next_yposn = (int) (row_posn + row_height);
+        plot_height = next_yposn - plot_yposn;
+
+        i = 0;
+
+        do {
+            module_fill = module_is_set(symbol, this_row, i);
+            block_width = 0;
+            do {
+                block_width++;
+            } while ((i + block_width < symbol->width) && module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i));
+
+            if ((addon_latch == 0) && (r == 0) && (i > main_width)) {
+                plot_height = (int) (row_height - 5.0);
+                plot_yposn = (int) (row_posn - 5.0);
+                addon_text_posn = row_posn + row_height - 8.0;
+                addon_latch = 1;
+            }
+            if (module_fill) {
+                /* a bar */
+                if (symbol->symbology == BARCODE_ULTRA) {
+                    draw_bar(pixelbuf, (i + xoffset) * 2, block_width * 2, plot_yposn * 2, plot_height * 2, image_width, image_height, ultra_colour[module_fill]);
+                } else {
+                    draw_bar(pixelbuf, (i + xoffset) * 2, block_width * 2, plot_yposn * 2, plot_height * 2, image_width, image_height, DEFAULT_INK);
+                }
+            }
+            i += block_width;
+
+        } while (i < symbol->width);
+    }
+
+    xoffset += comp_offset;
+
+    if ((symbol->symbology == BARCODE_EANX) || (symbol->symbology == BARCODE_EANX_CHK)
+            || (symbol->symbology == BARCODE_EANX_CC) || (symbol->symbology == BARCODE_ISBNX)) {
+        /* guard bar extensions and text formatting for EAN8 and EAN13 */
+        switch (ustrlen(local_text)) {
+            case 8: /* EAN-8 */
+            case 11:
+            case 14:
+                draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                draw_bar(pixelbuf, (32 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                draw_bar(pixelbuf, (34 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                draw_bar(pixelbuf, (64 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                draw_bar(pixelbuf, (66 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                for (i = 0; i < 4; i++) {
+                    textpart[i] = local_text[i];
+                }
+                textpart[4] = '\0';
+                textpos = 2 * (17 + xoffset);
+
+                draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+                for (i = 0; i < 4; i++) {
+                    textpart[i] = local_text[i + 4];
+                }
+                textpart[4] = '\0';
+                textpos = 2 * (50 + xoffset);
+                draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+                textdone = 1;
+                switch (strlen(addon)) {
+                    case 2:
+                        textpos = 2 * (xoffset + 86);
+                        draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, textflags, image_width, image_height);
+                        break;
+                    case 5:
+                        textpos = 2 * (xoffset + 100);
+                        draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, textflags, image_width, image_height);
+                        break;
+                }
+
+                break;
+            case 13: /* EAN 13 */
+            case 16:
+            case 19:
+                draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                draw_bar(pixelbuf, (92 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                draw_bar(pixelbuf, (94 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+
+                textpart[0] = local_text[0];
+                textpart[1] = '\0';
+                textpos = 2 * (-7 + xoffset);
+                draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+                for (i = 0; i < 6; i++) {
+                    textpart[i] = local_text[i + 1];
+                }
+                textpart[6] = '\0';
+                textpos = 2 * (24 + xoffset);
+                draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+                for (i = 0; i < 6; i++) {
+                    textpart[i] = local_text[i + 7];
+                }
+                textpart[6] = '\0';
+                textpos = 2 * (71 + xoffset);
+                draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+                textdone = 1;
+                switch (strlen(addon)) {
+                    case 2:
+                        textpos = 2 * (xoffset + 114);
+                        draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, textflags, image_width, image_height);
+                        break;
+                    case 5:
+                        textpos = 2 * (xoffset + 128);
+                        draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, textflags, image_width, image_height);
+                        break;
+                }
+                break;
+
+        }
+
+    } else if ((symbol->symbology == BARCODE_UPCA) || (symbol->symbology == BARCODE_UPCA_CHK)
+            || (symbol->symbology == BARCODE_UPCA_CC)) {
+        /* guard bar extensions and text formatting for UPCA */
+        latch = 1;
+
+        i = 0 + comp_offset;
+        do {
+            block_width = 0;
+            do {
+                block_width++;
+            } while ((i + block_width < symbol->width) && module_is_set(symbol, symbol->rows - 1, i + block_width) == module_is_set(symbol, symbol->rows - 1, i));
+            if (latch == 1) {
+                /* a bar */
+                draw_bar(pixelbuf, (i + xoffset - comp_offset) * 2, block_width * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                latch = 0;
+            } else {
+                /* a space */
+                latch = 1;
+            }
+            i += block_width;
+        } while (i < 11 + comp_offset);
+        draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+        draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+        latch = 1;
+        i = 85 + comp_offset;
+        do {
+            block_width = 0;
+            do {
+                block_width++;
+            } while ((i + block_width < symbol->width) && module_is_set(symbol, symbol->rows - 1, i + block_width) == module_is_set(symbol, symbol->rows - 1, i));
+            if (latch == 1) {
+                /* a bar */
+                draw_bar(pixelbuf, (i + xoffset - comp_offset) * 2, block_width * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+                latch = 0;
+            } else {
+                /* a space */
+                latch = 1;
+            }
+            i += block_width;
+        } while (i < 96 + comp_offset);
+        textpart[0] = local_text[0];
+        textpart[1] = '\0';
+        textpos = 2 * (-5 + xoffset);
+        draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+        for (i = 0; i < 5; i++) {
+            textpart[i] = local_text[i + 1];
+        }
+        textpart[5] = '\0';
+        textpos = 2 * (27 + xoffset);
+        draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+        for (i = 0; i < 5; i++) {
+            textpart[i] = local_text[i + 6];
+        }
+        textpart[6] = '\0';
+        textpos = 2 * (68 + xoffset);
+        draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+        textpart[0] = local_text[11];
+        textpart[1] = '\0';
+        textpos = 2 * (100 + xoffset);
+        draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+        textdone = 1;
+        switch (strlen(addon)) {
+            case 2:
+                textpos = 2 * (xoffset + 116);
+                draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, textflags, image_width, image_height);
+                break;
+            case 5:
+                textpos = 2 * (xoffset + 130);
+                draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, textflags, image_width, image_height);
+                break;
+        }
+
+    } else if ((symbol->symbology == BARCODE_UPCE) || (symbol->symbology == BARCODE_UPCE_CHK)
+            || (symbol->symbology == BARCODE_UPCE_CC)) {
+        /* guard bar extensions and text formatting for UPCE */
+        draw_bar(pixelbuf, (0 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+        draw_bar(pixelbuf, (2 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+        draw_bar(pixelbuf, (46 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+        draw_bar(pixelbuf, (48 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+        draw_bar(pixelbuf, (50 + xoffset) * 2, 1 * 2, (4 + (int) yoffset) * 2, 5 * 2, image_width, image_height, DEFAULT_INK);
+
+        textpart[0] = local_text[0];
+        textpart[1] = '\0';
+        textpos = 2 * (-5 + xoffset);
+        draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+        for (i = 0; i < 6; i++) {
+            textpart[i] = local_text[i + 1];
+        }
+        textpart[6] = '\0';
+        textpos = 2 * (24 + xoffset);
+        draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+        textpart[0] = local_text[7];
+        textpart[1] = '\0';
+        textpos = 2 * (55 + xoffset);
+        draw_string(pixelbuf, textpart, textpos, default_text_posn, textflags, image_width, image_height);
+        textdone = 1;
+        switch (strlen(addon)) {
+            case 2:
+                textpos = 2 * (xoffset + 70);
+                draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, textflags, image_width, image_height);
+                break;
+            case 5:
+                textpos = 2 * (xoffset + 84);
+                draw_string(pixelbuf, addon, textpos, image_height - (addon_text_posn * 2) - 13, textflags, image_width, image_height);
+                break;
+        }
+
+    }
+
+    xoffset -= comp_offset;
+
+    /* Put boundary bars or box around symbol */
+    if ((symbol->output_options & BARCODE_BOX) || (symbol->output_options & BARCODE_BIND)) {
+        /* boundary bars */
+        if ((symbol->output_options & BARCODE_BOX) || (symbol->symbology != BARCODE_CODABLOCKF && symbol->symbology != BARCODE_HIBC_BLOCKF)) {
+            draw_bar(pixelbuf, 0, (symbol->width + xoffset + roffset) * 2, textoffset * 2, symbol->border_width * 2, image_width, image_height, DEFAULT_INK);
+            draw_bar(pixelbuf, 0, (symbol->width + xoffset + roffset) * 2, (textoffset + symbol->height + symbol->border_width) * 2, symbol->border_width * 2, image_width, image_height, DEFAULT_INK);
+        } else {
+            draw_bar(pixelbuf, xoffset * 2, symbol->width * 2, textoffset * 2, symbol->border_width * 2, image_width, image_height, DEFAULT_INK);
+            draw_bar(pixelbuf, xoffset * 2, symbol->width * 2, (textoffset + symbol->height + symbol->border_width) * 2, symbol->border_width * 2, image_width, image_height, DEFAULT_INK);
+        }
+        if ((symbol->output_options & BARCODE_BIND) != 0) {
+            if ((symbol->rows > 1) && (is_stackable(symbol->symbology) == 1)) {
+                double sep_height = 1;
+                if (symbol->option_3 > 0 && symbol->option_3 <= 4) {
+                    sep_height = symbol->option_3;
+                }
+                /* row binding */
+                if (symbol->symbology != BARCODE_CODABLOCKF && symbol->symbology != BARCODE_HIBC_BLOCKF) {
+                    for (r = 1; r < symbol->rows; r++) {
+                        draw_bar(pixelbuf, xoffset * 2, symbol->width * 2, ((r * row_height) + textoffset + yoffset - sep_height / 2) * 2, sep_height * 2, image_width, image_height, DEFAULT_INK);
+                    }
+                } else {
+                    for (r = 1; r < symbol->rows; r++) {
+                        /* Avoid 11-module start and 13-module stop chars */
+                        draw_bar(pixelbuf, (xoffset + 11) * 2, (symbol->width - 24) * 2, ((r * row_height) + textoffset + yoffset - sep_height / 2) * 2, sep_height * 2, image_width, image_height, DEFAULT_INK);
+                    }
+                }
+            }
+        }
+    }
+
+    if (symbol->output_options & BARCODE_BOX) {
+        /* side bars */
+        draw_bar(pixelbuf, 0, symbol->border_width * 2, textoffset * 2, (symbol->height + (2 * symbol->border_width)) * 2, image_width, image_height, DEFAULT_INK);
+        draw_bar(pixelbuf, (symbol->width + xoffset + roffset - symbol->border_width) * 2, symbol->border_width * 2, textoffset * 2, (symbol->height + (2 * symbol->border_width)) * 2, image_width, image_height, DEFAULT_INK);
+    }
+
+    /* Put the human readable text at the bottom */
+    if ((textdone == 0) && (ustrlen(local_text) != 0)) {
+        textpos = (image_width / 2);
+        draw_string(pixelbuf, (char*) local_text, textpos, default_text_posn, textflags, image_width, image_height);
+    }
+
+
+    if (scaler <= 0) {
+        scaler = 0.5;
+    }
+
+    if (scaler != 1.0) {
+        scale_width = image_width * scaler;
+        scale_height = image_height * scaler;
+
+        /* Apply scale options by creating another pixel buffer */
+        if (!(scaled_pixelbuf = (char *) malloc(scale_width * scale_height))) {
+            free(pixelbuf);
+            strcpy(symbol->errtxt, "659: Insufficient memory for pixel buffer");
+            return ZINT_ERROR_ENCODING_PROBLEM;
+        }
+        memset(scaled_pixelbuf, DEFAULT_PAPER, scale_width * scale_height);
+
+        for (vert = 0; vert < scale_height; vert++) {
+            for (horiz = 0; horiz < scale_width; horiz++) {
+                *(scaled_pixelbuf + (vert * scale_width) + horiz) = *(pixelbuf + ((int) (vert / scaler) * image_width) + (int) (horiz / scaler));
+            }
+        }
+
+        error_number = save_raster_image_to_file(symbol, scale_height, scale_width, scaled_pixelbuf, rotate_angle, data_type);
+        free(scaled_pixelbuf);
+    } else {
+        error_number = save_raster_image_to_file(symbol, image_height, image_width, pixelbuf, rotate_angle, data_type);
+    }
+    free(pixelbuf);
+    return error_number;
+}
+
+INTERNAL int plot_raster(struct zint_symbol *symbol, int rotate_angle, int file_type) {
+    int error;
+
+#ifdef NO_PNG
+    if (file_type == OUT_PNG_FILE) {
+        strcpy(symbol->errtxt, "660: PNG format disabled at compile time");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+#endif /* NO_PNG */
+
+    error = check_colour_options(symbol);
+    if (error != 0) {
+        return error;
+    }
+
+    if (symbol->output_options & BARCODE_DOTTY_MODE) {
+        error = plot_raster_dotty(symbol, rotate_angle, file_type);
+    } else {
+        if (symbol->symbology == BARCODE_MAXICODE) {
+            error = plot_raster_maxicode(symbol, rotate_angle, file_type);
+        } else {
+            error = plot_raster_default(symbol, rotate_angle, file_type);
+        }
+    }
+
+    return error;
+}
index ef9e402..6d908e4 100644 (file)
@@ -27,7 +27,8 @@
     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     SUCH DAMAGE.
-*/
+ */
+/* vim: set ts=4 sw=4 et : */
 
 // It is not written with high efficiency in mind, so is probably
 // not suitable for real-time encoding.  The aim was to keep it
 // malloc/free can be avoided by using static arrays of a suitable
 // size.
 
-#include <stdio.h>             // only needed for debug (main)
-#include <stdlib.h>            // only needed for malloc/free
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
 #include "reedsol.h"
-static int gfpoly;
-static int symsize;            // in bits
-static int logmod;             // 2**symsize - 1
+static int logmod; // 2**symsize - 1
 static int rlen;
 
 static int *logt = NULL, *alog = NULL, *rspoly = NULL;
@@ -68,30 +69,32 @@ static int *logt = NULL, *alog = NULL, *rspoly = NULL;
 // polynomial.  e.g. for ECC200 (8-bit symbols) the polynomial is
 // a**8 + a**5 + a**3 + a**2 + 1, which translates to 0x12d.
 
-void rs_init_gf(int poly)
-{
-       int m, b, p, v;
-
-       // Find the top bit, and hence the symbol size
-       for (b = 1, m = 0; b <= poly; b <<= 1)
-               m++;
-       b >>= 1;
-       m--;
-       gfpoly = poly;
-       symsize = m;
-
-       // Calculate the log/alog tables
-       logmod = (1 << m) - 1;
-       logt = (int *)malloc(sizeof(int) * (logmod + 1));
-       alog = (int *)malloc(sizeof(int) * logmod);
-
-       for (p = 1, v = 0; v < logmod; v++) {
-               alog[v] = p;
-               logt[p] = v;
-               p <<= 1;
-               if (p & b)
-                       p ^= poly;
-       }
+INTERNAL void rs_init_gf(const int poly) {
+    int m, b, p, v;
+
+    // Find the top bit, and hence the symbol size
+    for (b = 1, m = 0; b <= poly; b <<= 1)
+        m++;
+    b >>= 1;
+    m--;
+
+    // Ensure m not negative to supress gcc -Walloc-size-larger-than
+    if (m < 0) {
+        m = 0;
+    }
+
+    // Calculate the log/alog tables
+    logmod = (1 << m) - 1;
+    logt = (int *) malloc(sizeof (int) * (logmod + 1));
+    alog = (int *) malloc(sizeof (int) * logmod);
+
+    for (p = 1, v = 0; v < logmod; v++) {
+        alog[v] = p;
+        logt[p] = v;
+        p <<= 1;
+        if (p & b)
+            p ^= poly;
+    }
 }
 
 // rs_init_code(nsym, index) initialises the Reed-Solomon encoder
@@ -101,71 +104,69 @@ void rs_init_gf(int poly)
 // (x + 2**i)*(x + 2**(i+1))*...   [nsym terms]
 // For ECC200, index is 1.
 
-void rs_init_code(int nsym, int index)
-{
-       int i, k;
-
-       rspoly = (int *)malloc(sizeof(int) * (nsym + 1));
-
-       rlen = nsym;
-
-       rspoly[0] = 1;
-       for (i = 1; i <= nsym; i++) {
-               rspoly[i] = 1;
-               for (k = i - 1; k > 0; k--) {
-                       if (rspoly[k])
-                               rspoly[k] = alog[(logt[rspoly[k]] + index) % logmod];
-                       rspoly[k] ^= rspoly[k - 1];
-               }
-               rspoly[0] = alog[(logt[rspoly[0]] + index) % logmod];
-               index++;
-       }
+INTERNAL void rs_init_code(const int nsym, int index) {
+    int i, k;
+
+    rspoly = (int *) malloc(sizeof (int) * (nsym + 1));
+
+    rlen = nsym;
+
+    rspoly[0] = 1;
+    for (i = 1; i <= nsym; i++) {
+        rspoly[i] = 1;
+        for (k = i - 1; k > 0; k--) {
+            if (rspoly[k])
+                rspoly[k] = alog[(logt[rspoly[k]] + index) % logmod];
+            rspoly[k] ^= rspoly[k - 1];
+        }
+        rspoly[0] = alog[(logt[rspoly[0]] + index) % logmod];
+        index++;
+    }
 }
 
-void rs_encode(int len, unsigned char *data, unsigned char *res)
-{
-       int i, k, m;
-       for (i = 0; i < rlen; i++)
-               res[i] = 0;
-       for (i = 0; i < len; i++) {
-               m = res[rlen - 1] ^ data[i];
-               for (k = rlen - 1; k > 0; k--) {
-                       if (m && rspoly[k])
-                               res[k] = res[k - 1] ^ alog[(logt[m] + logt[rspoly[k]]) % logmod];
-                       else
-                               res[k] = res[k - 1];
-               }
-               if (m && rspoly[0])
-                       res[0] = alog[(logt[m] + logt[rspoly[0]]) % logmod];
-               else
-                       res[0] = 0;
-       }
+INTERNAL void rs_encode(const size_t len, const unsigned char *data, unsigned char *res) {
+    int i, k;
+    for (i = 0; i < rlen; i++)
+        res[i] = 0;
+    for (i = 0; i < (int) len; i++) {
+        int m = res[rlen - 1] ^ data[i];
+        for (k = rlen - 1; k > 0; k--) {
+            if (m && rspoly[k])
+                res[k] = (unsigned char) (res[k - 1] ^ alog[(logt[m] + logt[rspoly[k]]) % logmod]);
+            else
+                res[k] = res[k - 1];
+        }
+        if (m && rspoly[0])
+            res[0] = (unsigned char) (alog[(logt[m] + logt[rspoly[0]]) % logmod]);
+        else
+            res[0] = 0;
+    }
 }
 
-void rs_encode_long(int len, unsigned int *data, unsigned int *res)
-{ /* The same as above but for larger bitlengths - Aztec code compatible */
-       int i, k, m;
-       for (i = 0; i < rlen; i++)
-               res[i] = 0;
-       for (i = 0; i < len; i++) {
-               m = res[rlen - 1] ^ data[i];
-               for (k = rlen - 1; k > 0; k--) {
-                       if (m && rspoly[k])
-                               res[k] = res[k - 1] ^ alog[(logt[m] + logt[rspoly[k]]) % logmod];
-                       else
-                               res[k] = res[k - 1];
-               }
-               if (m && rspoly[0])
-                       res[0] = alog[(logt[m] + logt[rspoly[0]]) % logmod];
-               else
-                       res[0] = 0;
-       }
+/* The same as above but for larger bitlengths - Aztec code compatible */
+INTERNAL void rs_encode_long(const int len, const unsigned int *data, unsigned int *res) {
+    int i, k;
+    for (i = 0; i < rlen; i++)
+        res[i] = 0;
+    for (i = 0; i < len; i++) {
+        int m = res[rlen - 1] ^ data[i];
+        for (k = rlen - 1; k > 0; k--) {
+            if (m && rspoly[k])
+                res[k] = res[k - 1] ^ alog[(logt[m] + logt[rspoly[k]]) % logmod];
+            else
+                res[k] = res[k - 1];
+        }
+        if (m && rspoly[0])
+            res[0] = alog[(logt[m] + logt[rspoly[0]]) % logmod];
+        else
+            res[0] = 0;
+    }
 }
 
-void rs_free(void)
-{ /* Free memory */
-       free(logt);
-       free(alog);
-       free(rspoly);
-       rspoly = NULL;
+/* Free memory */
+INTERNAL void rs_free(void) {
+    free(logt);
+    free(alog);
+    free(rspoly);
+    rspoly = NULL;
 }
index d61af2c..d0703c9 100644 (file)
     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     SUCH DAMAGE.
 
-*/
+ */
+/* vim: set ts=4 sw=4 et : */
 
 #ifndef __REEDSOL_H
 #define __REEDSOL_H
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif /* __cplusplus */
 
-extern void rs_init_gf(int poly);
-extern void rs_init_code(int nsym, int index);
-extern void rs_encode(int len, unsigned char *data, unsigned char *res);
-extern void rs_encode_long(int len, unsigned int *data, unsigned int *res);
-extern void rs_free(void);
+INTERNAL void rs_init_gf(const int poly);
+INTERNAL void rs_init_code(const int nsym,int index);
+INTERNAL void rs_encode(const size_t len,const unsigned char *data, unsigned char *res);
+INTERNAL void rs_encode_long(const int len,const unsigned int *data, unsigned int *res);
+INTERNAL void rs_free(void);
 
 #ifdef __cplusplus
 }
diff --git a/backend/render.c b/backend/render.c
deleted file mode 100644 (file)
index 6c7968c..0000000
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * render.c - Generic Rendered Format 
- *
- * Initiall written by Sam Lown for use in gLabels. Converts encoded
- * data into a generic internal structure of lines and characters
- * usable in external applications.
- */
-
-/*
-    libzint - the open source barcode library
-    Copyright (C) 2009 Robin Stuart <robin@zint.org.uk>
-
-    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.
-*/
-
-#include <locale.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "common.h"
-
-#define   GL_CONST  2.8346
-
-struct zint_render_line *render_plot_create_line(float x, float y, float width, float length);
-int render_plot_add_line(struct zint_symbol *symbol, struct zint_render_line *line, struct zint_render_line **last_line);
-struct zint_render_ring *render_plot_create_ring(float x, float y, float radius, float line_width);
-int render_plot_add_ring(struct zint_symbol *symbol, struct zint_render_ring *ring, struct zint_render_ring **last_ring);
-struct zint_render_hexagon *render_plot_create_hexagon(float x, float y);
-int render_plot_add_hexagon(struct zint_symbol *symbol, struct zint_render_hexagon *ring, struct zint_render_hexagon **last_hexagon);
-
-int render_plot_add_string(struct zint_symbol *symbol, unsigned char *text, float x, float y, float fsize, float width, struct zint_render_string **last_string);
-
-int render_plot(struct zint_symbol *symbol, float width, float height)
-{
-       struct zint_render           *render;
-       struct zint_render_line      *line, *last_line = NULL;
-       struct zint_render_string    *last_string = NULL;
-       struct zint_render_ring      *ring, *last_ring = NULL;
-       struct zint_render_hexagon   *hexagon, *last_hexagon = NULL;
-
-       int i, r, block_width, latch, this_row;
-       float textpos, textwidth, large_bar_height, preset_height, row_height, row_posn = 0.0;
-       // int error_number = 0;
-       int text_offset, text_height, xoffset, yoffset, textdone, main_symbol_width_x, addon_width_x;
-       char addon[6], textpart[10];
-       int large_bar_count, symbol_lead_in, total_symbol_width_x, total_area_width_x;
-       float addon_text_posn;
-       float default_text_posn;
-       float scaler;
-       const char *locale = NULL;
-       int hide_text = 0;
-       float required_aspect;
-       float symbol_aspect = 1;
-       float x_dimension;
-       int upceanflag = 0;
-
-       // Allocate memory for the rendered version
-       render = symbol->rendered = (struct zint_render*)malloc(sizeof(struct zint_render));
-       render->lines = NULL;
-       render->strings = NULL;
-       render->rings = NULL;
-       render->hexagons = NULL;
-
-       locale = setlocale(LC_ALL, "C");
-
-       row_height = 0;
-       textdone = 0;
-       textpos = 0.0;
-       main_symbol_width_x = symbol->width;
-       strcpy(addon, "");
-       symbol_lead_in = 0;
-       addon_text_posn = 0.0;
-       addon_width_x = 0;
-
-  /*
-   * Determine if there will be any addon texts and text height 
-   */
-       latch = 0;
-       r = 0;
-       /* Isolate add-on text */
-       if(is_extendable(symbol->symbology)) {
-               for(i = 0; i < ustrlen(symbol->text); i++) {
-                       if (latch == 1) {
-                               addon[r] = symbol->text[i];
-                               r++;
-                       }
-                       if (symbol->text[i] == '+') {
-                               latch = 1;
-                       }
-               }
-       }
-       addon[r] = '\0';
-       
-       if((!symbol->show_hrt) || (ustrlen(symbol->text) == 0)) {
-               hide_text = 1;
-               text_height = text_offset = 0.0;
-       } else {
-               text_height = 9.0;
-               text_offset = 2.0;
-       }
-
-
-  /*
-   * Calculate the width of the barcode, especially if there are any extra
-   * borders or white space to add.
-   */
-       
-       while(!(module_is_set(symbol, symbol->rows - 1, symbol_lead_in))) {
-               symbol_lead_in++;
-       }
-
-       /* Certain symbols need whitespace otherwise characters get chopped off the sides */
-       if ((((symbol->symbology == BARCODE_EANX) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_EANX_CC))
-               || (symbol->symbology == BARCODE_ISBNX)) {
-               switch(ustrlen(symbol->text)) {
-                       case 13: /* EAN 13 */
-                       case 16:
-                       case 19:
-                               if(symbol->whitespace_width == 0) {
-                                       symbol->whitespace_width = 10;
-                               }
-                               main_symbol_width_x = 96 + symbol_lead_in;
-                               upceanflag = 13;
-                               break;
-                       case 2:
-                               main_symbol_width_x = 22 + symbol_lead_in;
-                               upceanflag = 2;
-                               break;
-                       case 5:
-                               main_symbol_width_x = 49 + symbol_lead_in;
-                               upceanflag = 5;
-                               break;
-                       default:
-                               main_symbol_width_x = 68 + symbol_lead_in;
-                               upceanflag = 8;
-               }
-               switch(ustrlen(symbol->text)) {
-                       case 11:
-                       case 16:
-                               /* EAN-2 add-on */
-                               addon_width_x = 31;
-                               break;
-                       case 14:
-                       case 19:
-                               /* EAN-5 add-on */
-                               addon_width_x = 58;
-                               break;
-               }
-       }
-
-       if (((symbol->symbology == BARCODE_UPCA) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCA_CC)) {
-               upceanflag = 12;
-               if(symbol->whitespace_width < 10) {
-                       symbol->whitespace_width = 10;
-                       main_symbol_width_x = 96 + symbol_lead_in;
-               }
-               switch(ustrlen(symbol->text)) {
-                       case 15:
-                               /* EAN-2 add-on */
-                               addon_width_x = 31;
-                               break;
-                       case 18:
-                               /* EAN-5 add-on */
-                               addon_width_x = 58;
-                               break;
-               }
-       }
-       
-       if (((symbol->symbology == BARCODE_UPCE) && (symbol->rows == 1)) || (symbol->symbology == BARCODE_UPCE_CC)) {
-               upceanflag = 6;
-               if(symbol->whitespace_width == 0) {
-                       symbol->whitespace_width = 10;
-                       main_symbol_width_x = 51 + symbol_lead_in;
-               }
-               switch(ustrlen(symbol->text)) {
-                       case 11:
-                               /* EAN-2 add-on */
-                               addon_width_x = 31;
-                               break;
-                       case 14:
-                               /* EAN-5 add-on */
-                               addon_width_x = 58;
-                               break;
-               }
-       }
-       
-       total_symbol_width_x = main_symbol_width_x + addon_width_x;
-       total_area_width_x = total_symbol_width_x + (2 * (symbol->border_width + symbol->whitespace_width));
-
-       xoffset = symbol->border_width + symbol->whitespace_width;
-       yoffset = symbol->border_width;
-
-       // Determine if height should be overridden
-       large_bar_count = 0;
-       preset_height = 0.0;
-       for(i = 0; i < symbol->rows; i++) {
-               preset_height += symbol->row_height[i];
-               if(symbol->row_height[i] == 0) {
-                       large_bar_count++;
-               }
-       }
-
-       if (large_bar_count == 0) {
-               required_aspect = width / height;
-               symbol_aspect = (total_symbol_width_x + (2 * xoffset)) / (preset_height + (2 * yoffset) + text_offset + text_height);
-               symbol->height = preset_height;
-               if (required_aspect > symbol_aspect) {
-                       /* the area is too wide */
-                       scaler = height / (preset_height + (2 * yoffset) + text_offset + text_height);
-                       render->width = symbol_aspect * height;
-                       render->height = height;
-               } else {
-                       /* the area is too high */
-                       scaler = width / (total_symbol_width_x + (2 * xoffset));
-                       render->width = width;
-                       render->height = width / symbol_aspect;
-               }
-       } else {
-               scaler = width / (total_symbol_width_x + (2 * xoffset));
-               symbol->height = (height / scaler) - ((2 * yoffset) + text_offset + text_height);
-               
-               render->width = width;
-               render->height = height;
-       }
-       large_bar_height = (symbol->height - preset_height) / large_bar_count;
-
-       if(((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) {
-               default_text_posn = (symbol->height + text_offset + symbol->border_width + symbol->border_width) * scaler;
-       } else {
-               default_text_posn = (symbol->height + text_offset + symbol->border_width) * scaler;
-       }
-
-       x_dimension = render->width / total_area_width_x;
-       x_dimension /= GL_CONST;
-       
-       /* Set minimum size of symbol */
-       /* Barcode must be at least 2mm high by 2mm across */
-       if(render->height < ((x_dimension * ((2 * symbol->border_width) + text_offset + text_height)) + 2.0) * GL_CONST) {
-               render->height = ((x_dimension * ((2 * symbol->border_width) + text_offset + text_height)) + 2.0) * GL_CONST;
-       }
-       if(render->width < (2.0 * GL_CONST)) {
-               render->width = (2.0 * GL_CONST);
-       }
-       
-       if(symbol->symbology == BARCODE_CODABAR) {
-               /* The minimum X-dimension of Codabar is 0.191mm. The minimum bar height is 5mm */
-               if(x_dimension < 0.191) {
-                       render->width = 0.191 * GL_CONST * total_area_width_x;
-               }
-               if(render->height < ((x_dimension * ((2 * symbol->border_width) + text_offset + text_height)) + 5.0) * GL_CONST) {
-                       render->height = ((x_dimension * ((2 * symbol->border_width) + text_offset + text_height)) + 5.0) * GL_CONST;
-               }
-       }
-       
-       if(symbol->symbology == BARCODE_CODE49) {
-               /* The minimum X-dimension of Code 49 is 0.191mm */
-               if(x_dimension < 0.191) {
-                       render->width = 0.191 * GL_CONST * total_area_width_x;
-                       render->height = render->width / symbol_aspect;
-               }
-       }
-       
-       if(upceanflag != 0) {
-               /* The X-dimension of UPC/EAN symbols is fixed at 0.330mm */
-               /* NOTE: This code will need adjustment before it correctly deals with composite symbols */
-               render->width = 0.330 * GL_CONST * total_area_width_x;
-               /* The height is also fixed */
-               switch (upceanflag) {
-                       case 6:
-                       case 12:
-                       case 13:
-                               /* UPC-A, UPC-E and EAN-13 */
-                               /* Height of bars should be 22.85mm */
-                               render->height = ((0.330 * ((2 * symbol->border_width) + text_offset + text_height)) + 22.85) * GL_CONST;
-                               break;
-                       case 8:
-                               /* EAN-8 */
-                               /* Height of bars should be 18.23mm */
-                               render->height = ((0.330 * ((2 * symbol->border_width) + text_offset + text_height)) + 18.23) * GL_CONST;
-                               break;
-                       default:
-                               /* EAN-2 and EAN-5 */
-                               /* Height of bars should be 21.10mm */
-                               render->height = ((0.330 * ((2 * symbol->border_width) + text_offset + text_height)) + 21.10) * GL_CONST;
-               }
-       }
-       
-       if(symbol->symbology == BARCODE_ONECODE) {
-               /* The size of USPS Intelligent Mail barcode is fixed */
-               render->width = 0.508 * GL_CONST * total_area_width_x;
-               render->height = 4.064 * GL_CONST;
-       }
-
-       if((symbol->symbology == BARCODE_POSTNET) || (symbol->symbology == BARCODE_PLANET)) {
-               /* The size of PostNet and PLANET are fized */
-               render->width = 0.508 * GL_CONST * total_area_width_x;
-               render->height = 2.921 * GL_CONST;
-       }
-
-       if(((symbol->symbology == BARCODE_AUSPOST) || (symbol->symbology == BARCODE_AUSREPLY)) ||
-               ((symbol->symbology == BARCODE_AUSROUTE) || (symbol->symbology == BARCODE_AUSREDIRECT))) {
-               /* Australia Post use the same sizes as USPS */
-               render->width = 0.508 * GL_CONST * total_area_width_x;
-               render->height = 4.064 * GL_CONST;
-       }
-       
-       if((symbol->symbology == BARCODE_RM4SCC) || (symbol->symbology == BARCODE_KIX)) {
-               /* Royal Mail and KIX Code uses 22 bars per inch */
-               render->width = 0.577 * GL_CONST * total_area_width_x;
-               render->height = 5.22 * GL_CONST;
-       }
-       
-       if(symbol->symbology == BARCODE_MAXICODE) {
-               /* Maxicode is a fixed size */
-               scaler = GL_CONST; /* Converts from millimeters to the scale used by glabels */
-               render->width = 28.16 * scaler;
-               render->height = 26.86 * scaler;
-               
-               /* Central bullseye pattern */
-               ring = render_plot_create_ring(13.64 * scaler, 13.43 * scaler, 0.85 * scaler, 0.67 * scaler);
-               render_plot_add_ring(symbol, ring, &last_ring);
-               ring = render_plot_create_ring(13.64 * scaler, 13.43 * scaler, 2.20 * scaler, 0.67 * scaler);
-               render_plot_add_ring(symbol, ring, &last_ring);
-               ring = render_plot_create_ring(13.64 * scaler, 13.43 * scaler, 3.54 * scaler, 0.67 * scaler);
-               render_plot_add_ring(symbol, ring, &last_ring);
-               
-               /* Hexagons */
-               for(r = 0; r < symbol->rows; r++) {
-                       for(i = 0; i < symbol->width; i++) {
-                               if(module_is_set(symbol, r, i)) {
-                                       hexagon = render_plot_create_hexagon(((i * 0.88) + (r & 1 ? 1.76 : 1.32)) * scaler, ((r * 0.76) + 0.76) * scaler);
-                                       render_plot_add_hexagon(symbol, hexagon, &last_hexagon);
-                               }
-                       }
-               }
-       
-       } else {
-               /* everything else uses rectangles (or squares) */
-               /* Works from the bottom of the symbol up */
-               int addon_latch = 0;
-               
-               for(r = 0; r < symbol->rows; r++) {
-                       this_row = r;
-                       if(symbol->row_height[this_row] == 0) {
-                               row_height = large_bar_height;
-                       } else {
-                               row_height = symbol->row_height[this_row];
-                       }
-                       row_posn = 0;
-                       for(i = 0; i < r; i++) {
-                               if(symbol->row_height[i] == 0) {
-                                       row_posn += large_bar_height;
-                               } else {
-                                       row_posn += symbol->row_height[i];
-                               }
-                       }
-                       row_posn += yoffset;
-                       
-                       i = 0;
-                       if(module_is_set(symbol, this_row, 0)) {
-                               latch = 1;
-                       } else {
-                               latch = 0;
-                       }
-
-                       do {
-                               block_width = 0;
-                               do {
-                                       block_width++;
-                               } while (module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i));
-                               if((addon_latch == 0) && (r == (symbol->rows - 1)) && (i > main_symbol_width_x)) {
-                                       addon_text_posn = row_posn * scaler;
-                                       addon_latch = 1;
-                               } 
-                               if(latch == 1) {
-                                       /* a bar */
-                                       if(addon_latch == 0) {
-                                               line = render_plot_create_line((i + xoffset) * scaler, (row_posn) * scaler, block_width * scaler, row_height * scaler);
-                                       } else {
-                                               line = render_plot_create_line((i + xoffset) * scaler, (row_posn + 10.0) * scaler, block_width * scaler, (row_height - 5.0) * scaler);
-                                       }
-                                       latch = 0;
-                                       
-                                       render_plot_add_line(symbol, line, &last_line);
-                               } else {
-                                       /* a space */
-                                       latch = 1;
-                               }
-                               i += block_width;
-                               
-                       } while (i < symbol->width);
-               }
-       }
-       /* That's done the actual data area, everything else is human-friendly */
-
-
-       /* Add the text */
-       xoffset -= symbol_lead_in;
-       row_posn = (row_posn + large_bar_height) * scaler;
-
-       if (!hide_text) {
-               if(upceanflag == 8) {
-                       /* guard bar extensions and text formatting for EAN-8 */
-                       i = 0;
-                       for (line = symbol->rendered->lines; line != NULL; line = line->next) {
-                               switch(i) {
-                                       case 0:
-                                       case 1:
-                                       case 10:
-                                       case 11:
-                                       case 20:
-                                       case 21:
-                                               line->length += (5.0 * scaler);
-                                               break;
-                               }
-                               i++;
-                       }
-
-                       for(i = 0; i < 4; i++) {
-                               textpart[i] = symbol->text[i];
-                       }
-                       textpart[4] = '\0';
-                       textpos = 17;
-                       textwidth = 4.0 * 8.5; 
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
-                       for(i = 0; i < 4; i++) {
-                               textpart[i] = symbol->text[i + 4];
-                       }
-                       textpart[4] = '\0';
-                       textpos = 50;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
-                       textdone = 1;
-                       switch(strlen(addon)) {
-                               case 2: 
-                                       textpos = xoffset + 86;
-                                       textwidth = 2.0 * 8.5;
-                                       render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
-                                       break;
-                               case 5:
-                                       textpos = xoffset + 100;
-                                       textwidth = 5.0 * 8.5;
-                                       render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
-                                       break;
-                       }
-
-               }
-               
-               if(upceanflag == 13) {
-                       /* guard bar extensions and text formatting for EAN-13 */
-                       i = 0;
-                       for (line = symbol->rendered->lines; line != NULL; line = line->next) {
-                               switch(i) {
-                                       case 0:
-                                       case 1:
-                                       case 14:
-                                       case 15:
-                                       case 28:
-                                       case 29:
-                                               line->length += (5.0 * scaler);
-                                               break;
-                               }
-                               i++;
-                       }
-
-                       textpart[0] = symbol->text[0];
-                       textpart[1] = '\0';
-                       textpos = -5; // 7
-                       textwidth = 8.5;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
-
-                       for(i = 0; i < 6; i++) {
-                               textpart[i] = symbol->text[i + 1];
-                       }
-                       textpart[6] = '\0';
-                       textpos = 25;
-                       textwidth = 6.0 * 8.5;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
-                       for(i = 0; i < 6; i++) {
-                               textpart[i] = symbol->text[i + 7];
-                       }
-                       textpart[6] = '\0';
-                       textpos = 72;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
-                       textdone = 1;
-                       switch(strlen(addon)) {
-                               case 2: 
-                                       textpos = xoffset + 114;
-                                       textwidth = 2.0 * 8.5;
-                                       render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
-                                       break;
-                               case 5:
-                                       textpos = xoffset + 128;
-                                       textwidth = 5.0 * 8.5;
-                                       render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
-                                       break;
-                       }
-               }
-               
-               if (upceanflag == 12) {
-                       /* guard bar extensions and text formatting for UPCA */
-                       i = 0;
-                       for (line = symbol->rendered->lines; line != NULL; line = line->next) {
-                               switch(i) {
-                                       case 0:
-                                       case 1:
-                                       case 2:
-                                       case 3:
-                                       case 14:
-                                       case 15:
-                                       case 26:
-                                       case 27:
-                                       case 28:
-                                       case 29:
-                                               line->length += (5.0 * scaler);
-                                               break;
-                               }
-                               i++;
-                       }
-                       
-                       textpart[0] = symbol->text[0];
-                       textpart[1] = '\0';
-                       textpos = -5;
-                       textwidth = 6.2;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn + (2.0 * scaler), 8.0 * scaler, textwidth * scaler, &last_string);
-                       for(i = 0; i < 5; i++) {
-                               textpart[i] = symbol->text[i + 1];
-                       }
-                       textpart[5] = '\0';
-                       textpos = 27;
-                       textwidth = 5.0 * 8.5;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
-                       for(i = 0; i < 5; i++) {
-                               textpart[i] = symbol->text[i + 6];
-                       }
-                       textpos = 68;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
-                       textpart[0] = symbol->text[11];
-                       textpart[1] = '\0';
-                       textpos = 100;
-                       textwidth = 6.2;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn + (2.0 * scaler), 8.0 * scaler, textwidth * scaler, &last_string);
-                       textdone = 1;
-                       switch(strlen(addon)) {
-                               case 2: 
-                                       textpos = xoffset + 116;
-                                       textwidth = 2.0 * 8.5;
-                                       render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
-                                       break;
-                               case 5:
-                                       textpos = xoffset + 130;
-                                       textwidth = 5.0 * 8.5;
-                                       render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
-                                       break;
-                       }
-               }
-               
-               if (upceanflag == 6) {
-                       /* guard bar extensions and text formatting for UPCE */
-                       i = 0;
-                       for (line = symbol->rendered->lines; line != NULL; line = line->next) {
-                               switch(i) {
-                                       case 0:
-                                       case 1:
-                                       case 14:
-                                       case 15:
-                                       case 16:
-                                               line->length += (5.0 * scaler);
-                                               break;
-                               }
-                               i++;
-                       }
-                       
-                       textpart[0] = symbol->text[0];
-                       textpart[1] = '\0';
-                       textpos = -5;
-                       textwidth = 6.2;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn + (2.0 * scaler), 8.0 * scaler, textwidth * scaler, &last_string);
-                       for(i = 0; i < 6; i++) {
-                               textpart[i] = symbol->text[i + 1];
-                       }
-                       textpart[6] = '\0';
-                       textpos = 24;
-                       textwidth = 6.0 * 8.5;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn, 11.0 * scaler, textwidth * scaler, &last_string);
-                       textpart[0] = symbol->text[7];
-                       textpart[1] = '\0';
-                       textpos = 55;
-                       textwidth = 6.2;
-                       render_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset) * scaler, default_text_posn + (2.0 * scaler), 8.0 * scaler, textwidth * scaler, &last_string);
-                       textdone = 1;
-                       switch(strlen(addon)) {
-                               case 2: 
-                                       textpos = xoffset + 70;
-                                       textwidth = 2.0 * 8.5;
-                                       render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
-                                       break;
-                               case 5:
-                                       textpos = xoffset + 84;
-                                       textwidth = 5.0 * 8.5;
-                                       render_plot_add_string(symbol, (unsigned char *) addon, textpos * scaler, addon_text_posn * scaler, 11.0 * scaler, textwidth * scaler, &last_string);
-                                       break;
-                       }
-               }
-
-               /* Put normal human readable text at the bottom (and centered) */
-               if (textdone == 0) {
-                       // caculate start xoffset to center text
-                       render_plot_add_string(symbol, symbol->text, ((symbol->width / 2.0) + xoffset) * scaler, default_text_posn, 9.0 * scaler, 0.0, &last_string); 
-               }
-       }
-       
-       switch(symbol->symbology) {
-               case BARCODE_MAXICODE:
-                       /* Do nothing! */
-                       break;
-               default:
-                       if((symbol->output_options & BARCODE_BIND) != 0) {
-                               if((symbol->rows > 1) && (is_stackable(symbol->symbology) == 1)) {
-                                       /* row binding */
-                                       for(r = 1; r < symbol->rows; r++) {
-                                               line = render_plot_create_line(xoffset * scaler, ((r * row_height) + yoffset - 1) * scaler, symbol->width * scaler, 2.0 * scaler);
-                                               render_plot_add_line(symbol, line, &last_line);
-                                       }
-                               }
-                       }
-                       if (((symbol->output_options & BARCODE_BOX) != 0) || ((symbol->output_options & BARCODE_BIND) != 0)) {
-                               line = render_plot_create_line(0, 0, (symbol->width + xoffset + xoffset) * scaler, symbol->border_width * scaler);
-                               render_plot_add_line(symbol, line, &last_line);
-                               line = render_plot_create_line(0, (symbol->height + symbol->border_width) * scaler, (symbol->width + xoffset + xoffset) * scaler, symbol->border_width * scaler);
-                               render_plot_add_line(symbol, line, &last_line);
-                       }
-                       if((symbol->output_options & BARCODE_BOX) != 0) {
-                               /* side bars */
-                               line = render_plot_create_line(0, 0, symbol->border_width * scaler, (symbol->height + (2 * symbol->border_width)) * scaler);
-                               render_plot_add_line(symbol, line, &last_line);
-                               line = render_plot_create_line((symbol->width + xoffset + xoffset - symbol->border_width) * scaler, 0, symbol->border_width * scaler, (symbol->height + (2 * symbol->border_width)) * scaler);
-                               render_plot_add_line(symbol, line, &last_line);
-                       }
-                       break;
-       }
-
-       if (locale)
-               setlocale(LC_ALL, locale);
-
-       return 1;
-}
-
-
-/*
- * Create a new line with its memory allocated ready for adding to the 
- * rendered structure.
- *
- * This is much quicker than writing out each line manually (in some cases!)
- */
-struct zint_render_line *render_plot_create_line(float x, float y, float width, float length)
-{
-       struct zint_render_line *line;
-       
-       line = (struct zint_render_line*)malloc(sizeof(struct zint_render_line));
-    if (line) 
-    {
-       line->next = NULL;
-       line->x = x;
-       line->y = y;
-       line->width = width;
-       line->length = length;  
-    }
-       return line;
-}
-
-/*
- * Add the line to the current rendering and update the last line's 
- * next value.
- */
-int render_plot_add_line(struct zint_symbol *symbol, struct zint_render_line *line, struct zint_render_line **last_line)
-{
-       if (*last_line)
-               (*last_line)->next = line;
-       else
-               symbol->rendered->lines = line; // first line
-
-       *last_line = line;
-       return 1;
-}
-
-struct zint_render_ring *render_plot_create_ring(float x, float y, float radius, float line_width)
-{
-       struct zint_render_ring *ring;
-       
-       ring = (struct zint_render_ring*)malloc(sizeof(struct zint_render_ring));
-    if (ring)
-    {
-       ring->next = NULL;
-       ring->x = x;
-       ring->y = y;
-       ring->radius = radius;
-       ring->line_width = line_width;
-    }  
-       return ring;
-}
-
-int render_plot_add_ring(struct zint_symbol *symbol, struct zint_render_ring *ring, struct zint_render_ring **last_ring)
-{
-       if (*last_ring)
-               (*last_ring)->next = ring;
-       else
-               symbol->rendered->rings = ring; // first ring
-               
-       *last_ring = ring;
-       return 1;
-}
-
-struct zint_render_hexagon *render_plot_create_hexagon(float x, float y)
-{
-       struct zint_render_hexagon *hexagon;
-       
-       hexagon = (struct zint_render_hexagon*)malloc(sizeof(struct zint_render_hexagon));
-    if (hexagon)
-    {
-       hexagon->next = NULL;
-       hexagon->x = x;
-       hexagon->y = y;
-    }  
-       return hexagon;
-}
-
-int render_plot_add_hexagon(struct zint_symbol *symbol, struct zint_render_hexagon *hexagon, struct zint_render_hexagon **last_hexagon)
-{
-       if (*last_hexagon)
-               (*last_hexagon)->next = hexagon;
-       else
-               symbol->rendered->hexagons = hexagon; // first hexagon
-               
-       *last_hexagon = hexagon;
-       return 1;
-}
-
-/*
- * Add a string structure to the symbol.
- * Coordinates assumed to be from top-center.
- */
-int render_plot_add_string(struct zint_symbol *symbol,
-               unsigned char *text, float x, float y, float fsize, float width,
-               struct zint_render_string **last_string)
-{
-       struct zint_render_string *string;
-
-       string = (struct zint_render_string*)malloc(sizeof(struct zint_render_string));
-    if (string)
-    {
-       string->next = NULL;
-       string->x = x;
-       string->y = y;
-       string->width = width; 
-       string->fsize = fsize;
-       string->length = ustrlen(text);
-       string->text = (unsigned char*)malloc(sizeof(unsigned char) * (ustrlen(text) + 1));
-
-        if (string->text)
-              ustrcpy(string->text, text);
-
-       if (*last_string)
-               (*last_string)->next = string;
-       else
-               symbol->rendered->strings = string; // First character
-       *last_string = string;
-    }
-       return 1;
-}
diff --git a/backend/rss.c b/backend/rss.c
new file mode 100644 (file)
index 0000000..d71177b
--- /dev/null
@@ -0,0 +1,1765 @@
+/* rss.c - Handles Reduced Space Symbology (GS1 DataBar) */
+
+/*
+    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 : */
+
+/* The functions "combins" and "getRSSwidths" 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 30 November 2006
+ */
+
+/* Includes numerous bugfixes thanks to Pablo Orduña @ the PIRAmIDE project */
+
+/* Note: This code reflects the symbol names as used in ISO/IEC 24724:2006. These names
+ * were updated in ISO/IEC 24724:2011 as follows:
+ *
+ * RSS-14 > GS1 DataBar Omnidirectional
+ * RSS-14 Truncated > GS1 DataBar Truncated
+ * RSS-14 Stacked > GS1 DataBar Stacked
+ * RSS-14 Stacked Omnidirectional > GS1 DataBar Stacked Omnidirectional
+ * RSS Limited > GS1 DataBar Limited
+ * RSS Expanded > GS1 DataBar Expanded Omnidirectional
+ * RSS Expanded Stacked > GS1 DataBar Expanded Stacked Omnidirectional
+ */
+
+#include <stdio.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "large.h"
+#include "rss.h"
+#include "gs1.h"
+#include "general_field.h"
+
+/**********************************************************************
+ * combins(n,r): returns the number of Combinations of r selected from n:
+ *   Combinations = n! / ((n - r)! * r!)
+ **********************************************************************/
+static int combins(int n, int r) {
+    int i, j;
+    int maxDenom, minDenom;
+    int val;
+
+    if (n - r > r) {
+        minDenom = r;
+        maxDenom = n - r;
+    } else {
+        minDenom = n - r;
+        maxDenom = r;
+    }
+    val = 1;
+    j = 1;
+    for (i = n; i > maxDenom; i--) {
+        val *= i;
+        if (j <= minDenom) {
+            val /= j;
+            j++;
+        }
+    }
+    for (; j <= minDenom; j++) {
+        val /= j;
+    }
+    return (val);
+}
+
+/**********************************************************************
+ * getRSSwidths
+ * routine to generate widths for RSS elements for a given value.#
+ *
+ * Calling arguments:
+ * val = required value
+ * n = number of modules
+ * elements = elements in a set (RSS-14 & Expanded = 4; RSS Limited = 7)
+ * maxWidth = maximum module width of an element
+ * noNarrow = 0 will skip patterns without a one module wide element
+ *
+ * Return:
+ * static int widths[] = element widths
+ **********************************************************************/
+static void getRSSwidths(int val, int n, int elements, int maxWidth, int noNarrow) {
+    int bar;
+    int elmWidth;
+    int mxwElement;
+    int subVal, lessVal;
+    int narrowMask = 0;
+    for (bar = 0; bar < elements - 1; bar++) {
+        for (elmWidth = 1, narrowMask |= (1 << bar);
+                ;
+                elmWidth++, narrowMask &= ~(1 << bar)) {
+            /* get all combinations */
+            subVal = combins(n - elmWidth - 1, elements - bar - 2);
+            /* less combinations with no single-module element */
+            if ((!noNarrow) && (!narrowMask) &&
+                    (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) {
+                subVal -= combins(n - elmWidth - (elements - bar), elements - bar - 2);
+            }
+            /* less combinations with elements > maxVal */
+            if (elements - bar - 1 > 1) {
+                lessVal = 0;
+                for (mxwElement = n - elmWidth - (elements - bar - 2);
+                        mxwElement > maxWidth;
+                        mxwElement--) {
+                    lessVal += combins(n - elmWidth - mxwElement - 1, elements - bar - 3);
+                }
+                subVal -= lessVal * (elements - 1 - bar);
+            } else if (n - elmWidth > maxWidth) {
+                subVal--;
+            }
+            val -= subVal;
+            if (val < 0) break;
+        }
+        val += subVal;
+        n -= elmWidth;
+        widths[bar] = elmWidth;
+    }
+    widths[bar] = n;
+    return;
+}
+
+/* GS1 DataBar-14 */
+INTERNAL int rss14(struct zint_symbol *symbol, unsigned char source[], int src_len) {
+    int error_number = 0, i, j;
+    large_int accum;
+    uint64_t left_pair, right_pair;
+    int data_character[4] = {0}, data_group[4] = {0}, v_odd[4], v_even[4];
+    int data_widths[8][4], checksum, c_left, c_right, total_widths[46], writer;
+    char latch;
+    int separator_row;
+
+    separator_row = 0;
+
+    if (src_len > 13) {
+        strcpy(symbol->errtxt, "380: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    error_number = is_sane(NEON, source, src_len);
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "381: Invalid characters in data");
+        return error_number;
+    }
+
+    /* make some room for a separator row for composite symbols */
+    switch (symbol->symbology) {
+        case BARCODE_RSS14_CC:
+        case BARCODE_RSS14STACK_CC:
+        case BARCODE_RSS14_OMNI_CC:
+            separator_row = symbol->rows;
+            symbol->row_height[separator_row] = 1;
+            symbol->rows += 1;
+            break;
+    }
+
+    large_load_str_u64(&accum, source, src_len);
+
+    if (symbol->option_1 == 2) {
+        /* Add symbol linkage flag */
+        large_add_u64(&accum, 10000000000000);
+    }
+
+    /* Calculate left and right pair values */
+
+    right_pair = large_div_u64(&accum, 4537077);
+    left_pair = large_lo(&accum);
+
+    /* Calculate four data characters */
+
+    data_character[0] = left_pair / 1597;
+    data_character[1] = left_pair % 1597;
+
+    data_character[2] = right_pair / 1597;
+    data_character[3] = right_pair % 1597;
+
+    /* Calculate odd and even subset values */
+
+    if ((data_character[0] >= 0) && (data_character[0] <= 160)) {
+        data_group[0] = 0;
+    }
+    if ((data_character[0] >= 161) && (data_character[0] <= 960)) {
+        data_group[0] = 1;
+    }
+    if ((data_character[0] >= 961) && (data_character[0] <= 2014)) {
+        data_group[0] = 2;
+    }
+    if ((data_character[0] >= 2015) && (data_character[0] <= 2714)) {
+        data_group[0] = 3;
+    }
+    if ((data_character[0] >= 2715) && (data_character[0] <= 2840)) {
+        data_group[0] = 4;
+    }
+    if ((data_character[1] >= 0) && (data_character[1] <= 335)) {
+        data_group[1] = 5;
+    }
+    if ((data_character[1] >= 336) && (data_character[1] <= 1035)) {
+        data_group[1] = 6;
+    }
+    if ((data_character[1] >= 1036) && (data_character[1] <= 1515)) {
+        data_group[1] = 7;
+    }
+    if ((data_character[1] >= 1516) && (data_character[1] <= 1596)) {
+        data_group[1] = 8;
+    }
+    if ((data_character[3] >= 0) && (data_character[3] <= 335)) {
+        data_group[3] = 5;
+    }
+    if ((data_character[3] >= 336) && (data_character[3] <= 1035)) {
+        data_group[3] = 6;
+    }
+    if ((data_character[3] >= 1036) && (data_character[3] <= 1515)) {
+        data_group[3] = 7;
+    }
+    if ((data_character[3] >= 1516) && (data_character[3] <= 1596)) {
+        data_group[3] = 8;
+    }
+    if ((data_character[2] >= 0) && (data_character[2] <= 160)) {
+        data_group[2] = 0;
+    }
+    if ((data_character[2] >= 161) && (data_character[2] <= 960)) {
+        data_group[2] = 1;
+    }
+    if ((data_character[2] >= 961) && (data_character[2] <= 2014)) {
+        data_group[2] = 2;
+    }
+    if ((data_character[2] >= 2015) && (data_character[2] <= 2714)) {
+        data_group[2] = 3;
+    }
+    if ((data_character[2] >= 2715) && (data_character[2] <= 2840)) {
+        data_group[2] = 4;
+    }
+
+    v_odd[0] = (data_character[0] - g_sum_table[data_group[0]]) / t_table[data_group[0]];
+    v_even[0] = (data_character[0] - g_sum_table[data_group[0]]) % t_table[data_group[0]];
+    v_odd[1] = (data_character[1] - g_sum_table[data_group[1]]) % t_table[data_group[1]];
+    v_even[1] = (data_character[1] - g_sum_table[data_group[1]]) / t_table[data_group[1]];
+    v_odd[3] = (data_character[3] - g_sum_table[data_group[3]]) % t_table[data_group[3]];
+    v_even[3] = (data_character[3] - g_sum_table[data_group[3]]) / t_table[data_group[3]];
+    v_odd[2] = (data_character[2] - g_sum_table[data_group[2]]) / t_table[data_group[2]];
+    v_even[2] = (data_character[2] - g_sum_table[data_group[2]]) % t_table[data_group[2]];
+
+
+    /* Use RSS subset width algorithm */
+    for (i = 0; i < 4; i++) {
+        if ((i == 0) || (i == 2)) {
+            getRSSwidths(v_odd[i], modules_odd[data_group[i]], 4, widest_odd[data_group[i]], 1);
+            data_widths[0][i] = widths[0];
+            data_widths[2][i] = widths[1];
+            data_widths[4][i] = widths[2];
+            data_widths[6][i] = widths[3];
+            getRSSwidths(v_even[i], modules_even[data_group[i]], 4, widest_even[data_group[i]], 0);
+            data_widths[1][i] = widths[0];
+            data_widths[3][i] = widths[1];
+            data_widths[5][i] = widths[2];
+            data_widths[7][i] = widths[3];
+        } else {
+            getRSSwidths(v_odd[i], modules_odd[data_group[i]], 4, widest_odd[data_group[i]], 0);
+            data_widths[0][i] = widths[0];
+            data_widths[2][i] = widths[1];
+            data_widths[4][i] = widths[2];
+            data_widths[6][i] = widths[3];
+            getRSSwidths(v_even[i], modules_even[data_group[i]], 4, widest_even[data_group[i]], 1);
+            data_widths[1][i] = widths[0];
+            data_widths[3][i] = widths[1];
+            data_widths[5][i] = widths[2];
+            data_widths[7][i] = widths[3];
+        }
+    }
+
+
+    checksum = 0;
+    /* Calculate the checksum */
+    for (i = 0; i < 8; i++) {
+        checksum += checksum_weight[i] * data_widths[i][0];
+        checksum += checksum_weight[i + 8] * data_widths[i][1];
+        checksum += checksum_weight[i + 16] * data_widths[i][2];
+        checksum += checksum_weight[i + 24] * data_widths[i][3];
+    }
+    checksum %= 79;
+
+    /* Calculate the two check characters */
+    if (checksum >= 8) {
+        checksum++;
+    }
+    if (checksum >= 72) {
+        checksum++;
+    }
+    c_left = checksum / 9;
+    c_right = checksum % 9;
+
+    /* Put element widths together */
+    total_widths[0] = 1;
+    total_widths[1] = 1;
+    total_widths[44] = 1;
+    total_widths[45] = 1;
+    for (i = 0; i < 8; i++) {
+        total_widths[i + 2] = data_widths[i][0];
+        total_widths[i + 15] = data_widths[7 - i][1];
+        total_widths[i + 23] = data_widths[i][3];
+        total_widths[i + 36] = data_widths[7 - i][2];
+    }
+    for (i = 0; i < 5; i++) {
+        total_widths[i + 10] = finder_pattern[i + (5 * c_left)];
+        total_widths[i + 31] = finder_pattern[(4 - i) + (5 * c_right)];
+    }
+
+    /* Put this data into the symbol */
+    if ((symbol->symbology == BARCODE_RSS14) || (symbol->symbology == BARCODE_RSS14_CC)) {
+        int count;
+        int check_digit;
+        char hrt[15];
+        writer = 0;
+        latch = '0';
+        for (i = 0; i < 46; i++) {
+            for (j = 0; j < total_widths[i]; j++) {
+                if (latch == '1') {
+                    set_module(symbol, symbol->rows, writer);
+                }
+                writer++;
+            }
+            if (latch == '1') {
+                latch = '0';
+            } else {
+                latch = '1';
+            }
+        }
+        if (symbol->width < writer) {
+            symbol->width = writer;
+        }
+        if (symbol->symbology == BARCODE_RSS14_CC) {
+            /* separator pattern for composite symbol */
+            for (i = 4; i < 92; i++) {
+                if (!(module_is_set(symbol, separator_row + 1, i))) {
+                    set_module(symbol, separator_row, i);
+                }
+            }
+            latch = '1';
+            for (i = 16; i < 32; i++) {
+                if (!(module_is_set(symbol, separator_row + 1, i))) {
+                    if (latch == '1') {
+                        set_module(symbol, separator_row, i);
+                        latch = '0';
+                    } else {
+                        unset_module(symbol, separator_row, i);
+                        latch = '1';
+                    }
+                } else {
+                    unset_module(symbol, separator_row, i);
+                    latch = '1';
+                }
+            }
+            latch = '1';
+            for (i = 63; i < 78; i++) {
+                if (!(module_is_set(symbol, separator_row + 1, i))) {
+                    if (latch == '1') {
+                        set_module(symbol, separator_row, i);
+                        latch = '0';
+                    } else {
+                        unset_module(symbol, separator_row, i);
+                        latch = '1';
+                    }
+                } else {
+                    unset_module(symbol, separator_row, i);
+                    latch = '1';
+                }
+            }
+        }
+        symbol->rows = symbol->rows + 1;
+
+        count = 0;
+        check_digit = 0;
+
+        /* Calculate check digit from Annex A and place human readable text */
+        ustrcpy(symbol->text, (unsigned char*) "(01)");
+        for (i = 0; i < 14; i++) {
+            hrt[i] = '0';
+        }
+        for (i = 0; i < src_len; i++) {
+            hrt[12 - i] = source[src_len - i - 1];
+        }
+        hrt[14] = '\0';
+
+        for (i = 0; i < 13; i++) {
+            count += ctoi(hrt[i]);
+
+            if (!(i & 1)) {
+                count += 2 * (ctoi(hrt[i]));
+            }
+        }
+
+        check_digit = 10 - (count % 10);
+        if (check_digit == 10) {
+            check_digit = 0;
+        }
+        hrt[13] = itoc(check_digit);
+
+        strcat((char*) symbol->text, hrt);
+
+        set_minimum_height(symbol, 14); // Minimum height is 14X for truncated symbol
+    }
+
+    if ((symbol->symbology == BARCODE_RSS14STACK) || (symbol->symbology == BARCODE_RSS14STACK_CC)) {
+        /* top row */
+        writer = 0;
+        latch = '0';
+        for (i = 0; i < 23; i++) {
+            for (j = 0; j < total_widths[i]; j++) {
+                if (latch == '1') {
+                    set_module(symbol, symbol->rows, writer);
+                } else {
+                    unset_module(symbol, symbol->rows, writer);
+                }
+                writer++;
+            }
+            if (latch == '1') {
+                latch = '0';
+            } else {
+                latch = '1';
+            }
+        }
+        set_module(symbol, symbol->rows, writer);
+        unset_module(symbol, symbol->rows, writer + 1);
+        symbol->row_height[symbol->rows] = 5;
+        /* bottom row */
+        symbol->rows = symbol->rows + 2;
+        set_module(symbol, symbol->rows, 0);
+        unset_module(symbol, symbol->rows, 1);
+        writer = 0;
+        latch = '1';
+        for (i = 23; i < 46; i++) {
+            for (j = 0; j < total_widths[i]; j++) {
+                if (latch == '1') {
+                    set_module(symbol, symbol->rows, writer + 2);
+                } else {
+                    unset_module(symbol, symbol->rows, writer + 2);
+                }
+                writer++;
+            }
+            if (latch == '1') {
+                latch = '0';
+            } else {
+                latch = '1';
+            }
+        }
+        symbol->row_height[symbol->rows] = 7;
+        /* separator pattern */
+        for (i = 1; i < 46; i++) {
+            if (module_is_set(symbol, symbol->rows - 2, i) == module_is_set(symbol, symbol->rows, i)) {
+                if (!(module_is_set(symbol, symbol->rows - 2, i))) {
+                    set_module(symbol, symbol->rows - 1, i);
+                }
+            } else {
+                if (!(module_is_set(symbol, symbol->rows - 1, i - 1))) {
+                    set_module(symbol, symbol->rows - 1, i);
+                }
+            }
+        }
+        unset_module(symbol, symbol->rows - 1, 1);
+        unset_module(symbol, symbol->rows - 1, 2);
+        unset_module(symbol, symbol->rows - 1, 3);
+        symbol->row_height[symbol->rows - 1] = 1;
+        if (symbol->symbology == BARCODE_RSS14STACK_CC) {
+            /* separator pattern for composite symbol */
+            for (i = 4; i < 46; i++) {
+                if (!(module_is_set(symbol, separator_row + 1, i))) {
+                    set_module(symbol, separator_row, i);
+                }
+            }
+            latch = '1';
+            for (i = 16; i < 32; i++) {
+                if (!(module_is_set(symbol, separator_row + 1, i))) {
+                    if (latch == '1') {
+                        set_module(symbol, separator_row, i);
+                        latch = '0';
+                    } else {
+                        unset_module(symbol, separator_row, i);
+                        latch = '1';
+                    }
+                } else {
+                    unset_module(symbol, separator_row, i);
+                    latch = '1';
+                }
+            }
+        }
+        symbol->rows = symbol->rows + 1;
+        if (symbol->width < 50) {
+            symbol->width = 50;
+        }
+    }
+
+    if ((symbol->symbology == BARCODE_RSS14STACK_OMNI) || (symbol->symbology == BARCODE_RSS14_OMNI_CC)) {
+        /* top row */
+        writer = 0;
+        latch = '0';
+        for (i = 0; i < 23; i++) {
+            for (j = 0; j < total_widths[i]; j++) {
+                if (latch == '1') {
+                    set_module(symbol, symbol->rows, writer);
+                } else {
+                    unset_module(symbol, symbol->rows, writer);
+                }
+                writer++;
+            }
+            latch = (latch == '1' ? '0' : '1');
+        }
+        set_module(symbol, symbol->rows, writer);
+        unset_module(symbol, symbol->rows, writer + 1);
+        /* bottom row */
+        symbol->rows = symbol->rows + 4;
+        set_module(symbol, symbol->rows, 0);
+        unset_module(symbol, symbol->rows, 1);
+        writer = 0;
+        latch = '1';
+        for (i = 23; i < 46; i++) {
+            for (j = 0; j < total_widths[i]; j++) {
+                if (latch == '1') {
+                    set_module(symbol, symbol->rows, writer + 2);
+                } else {
+                    unset_module(symbol, symbol->rows, writer + 2);
+                }
+                writer++;
+            }
+            if (latch == '1') {
+                latch = '0';
+            } else {
+                latch = '1';
+            }
+        }
+        /* middle separator */
+        for (i = 5; i < 46; i += 2) {
+            set_module(symbol, symbol->rows - 2, i);
+        }
+        symbol->row_height[symbol->rows - 2] = 1;
+        /* top separator */
+        for (i = 4; i < 46; i++) {
+            if (!(module_is_set(symbol, symbol->rows - 4, i))) {
+                set_module(symbol, symbol->rows - 3, i);
+            }
+        }
+        latch = '1';
+        for (i = 17; i < 33; i++) {
+            if (!(module_is_set(symbol, symbol->rows - 4, i))) {
+                if (latch == '1') {
+                    set_module(symbol, symbol->rows - 3, i);
+                    latch = '0';
+                } else {
+                    unset_module(symbol, symbol->rows - 3, i);
+                    latch = '1';
+                }
+            } else {
+                unset_module(symbol, symbol->rows - 3, i);
+                latch = '1';
+            }
+        }
+        symbol->row_height[symbol->rows - 3] = 1;
+        /* bottom separator */
+        for (i = 4; i < 46; i++) {
+            if (!(module_is_set(symbol, symbol->rows, i))) {
+                set_module(symbol, symbol->rows - 1, i);
+            }
+        }
+        latch = '1';
+        for (i = 16; i < 32; i++) {
+            if (!(module_is_set(symbol, symbol->rows, i))) {
+                if (latch == '1') {
+                    set_module(symbol, symbol->rows - 1, i);
+                    latch = '0';
+                } else {
+                    unset_module(symbol, symbol->rows - 1, i);
+                    latch = '1';
+                }
+            } else {
+                unset_module(symbol, symbol->rows - 1, i);
+                latch = '1';
+            }
+        }
+        symbol->row_height[symbol->rows - 1] = 1;
+        if (symbol->width < 50) {
+            symbol->width = 50;
+        }
+        if (symbol->symbology == BARCODE_RSS14_OMNI_CC) {
+            /* separator pattern for composite symbol */
+            for (i = 4; i < 46; i++) {
+                if (!(module_is_set(symbol, separator_row + 1, i))) {
+                    set_module(symbol, separator_row, i);
+                }
+            }
+            latch = '1';
+            for (i = 16; i < 32; i++) {
+                if (!(module_is_set(symbol, separator_row + 1, i))) {
+                    if (latch == '1') {
+                        set_module(symbol, separator_row, i);
+                        latch = '0';
+                    } else {
+                        unset_module(symbol, separator_row, i);
+                        latch = '1';
+                    }
+                } else {
+                    unset_module(symbol, separator_row, i);
+                    latch = '1';
+                }
+            }
+        }
+        symbol->rows = symbol->rows + 1;
+
+        set_minimum_height(symbol, 33);
+    }
+
+
+    return error_number;
+}
+
+/* GS1 DataBar Limited */
+INTERNAL int rsslimited(struct zint_symbol *symbol, unsigned char source[], int src_len) {
+    int error_number = 0, i;
+    large_int accum;
+    uint64_t left_character, right_character;
+    int left_group, right_group, left_odd, left_even, right_odd, right_even;
+    int left_widths[14], right_widths[14];
+    int checksum, check_elements[14], total_widths[46], writer, j, check_digit, count;
+    char latch, hrt[15];
+    int separator_row;
+
+    separator_row = 0;
+
+    if (src_len > 13) {
+        strcpy(symbol->errtxt, "382: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    error_number = is_sane(NEON, source, src_len);
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "383: Invalid characters in data");
+        return error_number;
+    }
+    if (src_len == 13) {
+        if ((source[0] != '0') && (source[0] != '1')) {
+            strcpy(symbol->errtxt, "384: Input out of range");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+    }
+
+    /* make some room for a separator row for composite symbols */
+    if (symbol->symbology == BARCODE_RSS_LTD_CC) {
+        separator_row = symbol->rows;
+        symbol->row_height[separator_row] = 1;
+        symbol->rows += 1;
+    }
+
+    large_load_str_u64(&accum, source, src_len);
+
+    if (symbol->option_1 == 2) {
+        /* Add symbol linkage flag */
+        large_add_u64(&accum, 2015133531096);
+    }
+
+    /* Calculate left and right pair values */
+
+    right_character = large_div_u64(&accum, 2013571);
+    left_character = large_lo(&accum);
+
+    if (left_character >= 1996939) {
+        left_group = 6;
+        left_character -= 1996939;
+    } else if (left_character >= 1979845) {
+        left_group = 5;
+        left_character -= 1979845;
+    } else if (left_character >= 1491021) {
+        left_group = 4;
+        left_character -= 1491021;
+    } else if (left_character >= 1000776) {
+        left_group = 3;
+        left_character -= 1000776;
+    } else if (left_character >= 820064) {
+        left_group = 2;
+        left_character -= 820064;
+    } else if (left_character >= 183064) {
+        left_group = 1;
+        left_character -= 183064;
+    } else {
+        left_group = 0;
+    }
+
+    if (right_character >= 1996939) {
+        right_group = 6;
+        right_character -= 1996939;
+    } else if (right_character >= 1979845) {
+        right_group = 5;
+        right_character -= 1979845;
+    } else if (right_character >= 1491021) {
+        right_group = 4;
+        right_character -= 1491021;
+    } else if (right_character >= 1000776) {
+        right_group = 3;
+        right_character -= 1000776;
+    } else if (right_character >= 820064) {
+        right_group = 2;
+        right_character -= 820064;
+    } else if (right_character >= 183064) {
+        right_group = 1;
+        right_character -= 183064;
+    } else {
+        right_group = 0;
+    }
+
+    left_odd = left_character / t_even_ltd[left_group];
+    left_even = left_character % t_even_ltd[left_group];
+    right_odd = right_character / t_even_ltd[right_group];
+    right_even = right_character % t_even_ltd[right_group];
+
+    getRSSwidths(left_odd, modules_odd_ltd[left_group], 7, widest_odd_ltd[left_group], 1);
+    left_widths[0] = widths[0];
+    left_widths[2] = widths[1];
+    left_widths[4] = widths[2];
+    left_widths[6] = widths[3];
+    left_widths[8] = widths[4];
+    left_widths[10] = widths[5];
+    left_widths[12] = widths[6];
+    getRSSwidths(left_even, modules_even_ltd[left_group], 7, widest_even_ltd[left_group], 0);
+    left_widths[1] = widths[0];
+    left_widths[3] = widths[1];
+    left_widths[5] = widths[2];
+    left_widths[7] = widths[3];
+    left_widths[9] = widths[4];
+    left_widths[11] = widths[5];
+    left_widths[13] = widths[6];
+    getRSSwidths(right_odd, modules_odd_ltd[right_group], 7, widest_odd_ltd[right_group], 1);
+    right_widths[0] = widths[0];
+    right_widths[2] = widths[1];
+    right_widths[4] = widths[2];
+    right_widths[6] = widths[3];
+    right_widths[8] = widths[4];
+    right_widths[10] = widths[5];
+    right_widths[12] = widths[6];
+    getRSSwidths(right_even, modules_even_ltd[right_group], 7, widest_even_ltd[right_group], 0);
+    right_widths[1] = widths[0];
+    right_widths[3] = widths[1];
+    right_widths[5] = widths[2];
+    right_widths[7] = widths[3];
+    right_widths[9] = widths[4];
+    right_widths[11] = widths[5];
+    right_widths[13] = widths[6];
+
+    checksum = 0;
+    /* Calculate the checksum */
+    for (i = 0; i < 14; i++) {
+        checksum += checksum_weight_ltd[i] * left_widths[i];
+        checksum += checksum_weight_ltd[i + 14] * right_widths[i];
+    }
+    checksum %= 89;
+
+    for (i = 0; i < 14; i++) {
+        check_elements[i] = finder_pattern_ltd[i + (checksum * 14)];
+    }
+
+    total_widths[0] = 1;
+    total_widths[1] = 1;
+    total_widths[44] = 1;
+    total_widths[45] = 1;
+    for (i = 0; i < 14; i++) {
+        total_widths[i + 2] = left_widths[i];
+        total_widths[i + 16] = check_elements[i];
+        total_widths[i + 30] = right_widths[i];
+    }
+
+    writer = 0;
+    latch = '0';
+    for (i = 0; i < 46; i++) {
+        for (j = 0; j < total_widths[i]; j++) {
+            if (latch == '1') {
+                set_module(symbol, symbol->rows, writer);
+            } else {
+                unset_module(symbol, symbol->rows, writer);
+            }
+            writer++;
+        }
+        latch = (latch == '1' ? '0' : '1');
+    }
+    if (symbol->width < writer) {
+        symbol->width = writer;
+    }
+    symbol->rows = symbol->rows + 1;
+
+    /* add separator pattern if composite symbol */
+    if (symbol->symbology == BARCODE_RSS_LTD_CC) {
+        for (i = 4; i < 70; i++) {
+            if (!(module_is_set(symbol, separator_row + 1, i))) {
+                set_module(symbol, separator_row, i);
+            }
+        }
+    }
+
+    /* Calculate check digit from Annex A and place human readable text */
+
+    check_digit = 0;
+    count = 0;
+
+    ustrcpy(symbol->text, (unsigned char*) "(01)");
+    for (i = 0; i < 14; i++) {
+        hrt[i] = '0';
+    }
+    for (i = 0; i < src_len; i++) {
+        hrt[12 - i] = source[src_len - i - 1];
+    }
+
+    for (i = 0; i < 13; i++) {
+        count += ctoi(hrt[i]);
+
+        if (!(i & 1)) {
+            count += 2 * (ctoi(hrt[i]));
+        }
+    }
+
+    check_digit = 10 - (count % 10);
+    if (check_digit == 10) {
+        check_digit = 0;
+    }
+
+    hrt[13] = itoc(check_digit);
+    hrt[14] = '\0';
+
+    strcat((char*) symbol->text, hrt);
+
+    set_minimum_height(symbol, 10);
+
+    return error_number;
+}
+
+/* Handles all data encodation from section 7.2.5 of ISO/IEC 24724 */
+static int rss_binary_string(struct zint_symbol *symbol, char source[], char binary_string[]) {
+    int encoding_method, i, j, read_posn, last_digit, debug = (symbol->debug & ZINT_DEBUG_PRINT), mode = NUMERIC;
+    int symbol_characters, characters_per_row;
+#ifndef _MSC_VER
+    char general_field[strlen(source) + 1];
+#else
+    char* general_field = (char*) _alloca(strlen(source) + 1);
+#endif
+    int remainder, d1, d2;
+    char padstring[40];
+
+    read_posn = 0;
+
+    /* Decide whether a compressed data field is required and if so what
+    method to use - method 2 = no compressed data field */
+
+    if ((strlen(source) >= 16) && ((source[0] == '0') && (source[1] == '1'))) {
+        /* (01) and other AIs */
+        encoding_method = 1;
+        if (debug) printf("Choosing Method 1\n");
+    } else {
+        /* any AIs */
+        encoding_method = 2;
+        if (debug) printf("Choosing Method 2\n");
+    }
+
+    if (((strlen(source) >= 20) && (encoding_method == 1)) && ((source[2] == '9') && (source[16] == '3'))) {
+        /* Possibly encoding method > 2 */
+        if (debug) printf("Checking for other methods\n");
+
+        if ((strlen(source) >= 26) && (source[17] == '1')) {
+            /* Methods 3, 7, 9, 11 and 13 */
+
+            if (source[18] == '0') {
+                /* (01) and (310x) */
+                char weight_str[7];
+
+                for (i = 0; i < 6; i++) {
+                    weight_str[i] = source[20 + i];
+                }
+                weight_str[6] = '\0';
+
+                if (weight_str[0] == '0') { /* Maximum weight = 99999 */
+
+                    if ((source[19] == '3') && (strlen(source) == 26)) {
+                        /* (01) and (3103) */
+                        float weight; /* In kilos */
+                        weight = atof(weight_str) / 1000.0;
+
+                        if (weight <= 32.767) {
+                            encoding_method = 3;
+                        }
+                    }
+
+                    if (strlen(source) == 34) {
+                        if ((source[26] == '1') && (source[27] == '1')) {
+                            /* (01), (310x) and (11) - metric weight and production date */
+                            encoding_method = 7;
+                        }
+
+                        if ((source[26] == '1') && (source[27] == '3')) {
+                            /* (01), (310x) and (13) - metric weight and packaging date */
+                            encoding_method = 9;
+                        }
+
+                        if ((source[26] == '1') && (source[27] == '5')) {
+                            /* (01), (310x) and (15) - metric weight and "best before" date */
+                            encoding_method = 11;
+                        }
+
+                        if ((source[26] == '1') && (source[27] == '7')) {
+                            /* (01), (310x) and (17) - metric weight and expiration date */
+                            encoding_method = 13;
+                        }
+                    }
+                }
+            }
+            if (debug) printf("Now using method %d\n", encoding_method);
+        }
+
+        if ((strlen(source) >= 26) && (source[17] == '2')) {
+            /* Methods 4, 8, 10, 12 and 14 */
+
+            if (source[18] == '0') {
+                /* (01) and (320x) */
+                char weight_str[7];
+
+                for (i = 0; i < 6; i++) {
+                    weight_str[i] = source[20 + i];
+                }
+                weight_str[6] = '\0';
+
+                if (weight_str[0] == '0') { /* Maximum weight = 99999 */
+
+                    if (((source[19] == '2') || (source[19] == '3')) && (strlen(source) == 26)) {
+                        /* (01) and (3202)/(3203) */
+                        float weight; /* In pounds */
+
+                        if (source[19] == '3') {
+                            weight = (float) (atof(weight_str) / 1000.0F);
+                            if (weight <= 22.767) {
+                                encoding_method = 4;
+                            }
+                        } else {
+                            weight = (float) (atof(weight_str) / 100.0F);
+                            if (weight <= 99.99) {
+                                encoding_method = 4;
+                            }
+                        }
+
+                    }
+
+                    if (strlen(source) == 34) {
+                        if ((source[26] == '1') && (source[27] == '1')) {
+                            /* (01), (320x) and (11) - English weight and production date */
+                            encoding_method = 8;
+                        }
+
+                        if ((source[26] == '1') && (source[27] == '3')) {
+                            /* (01), (320x) and (13) - English weight and packaging date */
+                            encoding_method = 10;
+                        }
+
+                        if ((source[26] == '1') && (source[27] == '5')) {
+                            /* (01), (320x) and (15) - English weight and "best before" date */
+                            encoding_method = 12;
+                        }
+
+                        if ((source[26] == '1') && (source[27] == '7')) {
+                            /* (01), (320x) and (17) - English weight and expiration date */
+                            encoding_method = 14;
+                        }
+                    }
+                }
+            }
+            if (debug) printf("Now using method %d\n", encoding_method);
+
+        }
+
+        if (source[17] == '9') {
+            /* Methods 5 and 6 */
+            if ((source[18] == '2') && ((source[19] >= '0') && (source[19] <= '3'))) {
+                /* (01) and (392x) */
+                encoding_method = 5;
+            }
+            if ((source[18] == '3') && ((source[19] >= '0') && (source[19] <= '3'))) {
+                /* (01) and (393x) */
+                encoding_method = 6;
+            }
+            if (debug) printf("Now using method %d\n", encoding_method);
+        }
+    }
+
+    switch (encoding_method) { /* Encoding method - Table 10 */
+        case 1: strcat(binary_string, "1XX");
+            read_posn = 16;
+            break;
+        case 2: strcat(binary_string, "00XX");
+            read_posn = 0;
+            break;
+        case 3: // 0100
+        case 4: // 0101
+            bin_append(4 + (encoding_method - 3), 4, binary_string);
+            read_posn = strlen(source);
+            break;
+        case 5: strcat(binary_string, "01100XX");
+            read_posn = 20;
+            break;
+        case 6: strcat(binary_string, "01101XX");
+            read_posn = 23;
+            break;
+        default: /* modes 7 to 14 */
+            bin_append(56 + (encoding_method - 7), 7, binary_string);
+            read_posn = strlen(source);
+            break;
+    }
+    if (debug) printf("Setting binary = %s\n", binary_string);
+
+    /* Variable length symbol bit field is just given a place holder (XX)
+    for the time being */
+
+    /* Verify that the data to be placed in the compressed data field is all
+    numeric data before carrying out compression */
+    for (i = 0; i < read_posn; i++) {
+        if ((source[i] < '0') || (source[i] > '9')) {
+            if ((source[i] != '[') && (source[i] != ']')) {
+                /* Something is wrong */
+                strcpy(symbol->errtxt, "385: Invalid characters in input data");
+                return ZINT_ERROR_INVALID_DATA;
+            }
+        }
+    }
+
+    /* Now encode the compressed data field */
+
+    if (debug) printf("Proceeding to encode data\n");
+    if (encoding_method == 1) {
+        /* Encoding method field "1" - general item identification data */
+        char group[4];
+
+        group[0] = source[2];
+        group[1] = '\0';
+
+        bin_append(atoi(group), 4, binary_string);
+
+        for (i = 1; i < 5; i++) {
+            group[0] = source[(i * 3)];
+            group[1] = source[(i * 3) + 1];
+            group[2] = source[(i * 3) + 2];
+            group[3] = '\0';
+
+            bin_append(atoi(group), 10, binary_string);
+        }
+    }
+
+    if ((encoding_method == 3) || (encoding_method == 4)) {
+        /* Encoding method field "0100" - variable weight item
+        (0,001 kilogram icrements) */
+        /* Encoding method field "0101" - variable weight item (0,01 or
+        0,001 pound increment) */
+        char group[4];
+        char weight_str[7];
+
+        for (i = 1; i < 5; i++) {
+            group[0] = source[(i * 3)];
+            group[1] = source[(i * 3) + 1];
+            group[2] = source[(i * 3) + 2];
+            group[3] = '\0';
+
+            bin_append(atoi(group), 10, binary_string);
+        }
+
+        for (i = 0; i < 6; i++) {
+            weight_str[i] = source[20 + i];
+        }
+        weight_str[6] = '\0';
+
+        if ((encoding_method == 4) && (source[19] == '3')) {
+            bin_append(atoi(weight_str) + 10000, 15, binary_string);
+        } else {
+            bin_append(atoi(weight_str), 15, binary_string);
+        }
+    }
+
+    if ((encoding_method == 5) || (encoding_method == 6)) {
+        /* Encoding method "01100" - variable measure item and price */
+        /* Encoding method "01101" - variable measure item and price with ISO 4217
+        Currency Code */
+
+        char group[4];
+
+        for (i = 1; i < 5; i++) {
+            group[0] = source[(i * 3)];
+            group[1] = source[(i * 3) + 1];
+            group[2] = source[(i * 3) + 2];
+            group[3] = '\0';
+
+            bin_append(atoi(group), 10, binary_string);
+        }
+
+        bin_append(source[19] - '0', 2, binary_string);
+
+        if (encoding_method == 6) {
+            char currency_str[5];
+
+            for (i = 0; i < 3; i++) {
+                currency_str[i] = source[20 + i];
+            }
+            currency_str[3] = '\0';
+
+            bin_append(atoi(currency_str), 10, binary_string);
+        }
+    }
+
+    if ((encoding_method >= 7) && (encoding_method <= 14)) {
+        /* Encoding method fields "0111000" through "0111111" - variable
+        weight item plus date */
+        char group[4];
+        int group_val;
+        char weight_str[8];
+
+        for (i = 1; i < 5; i++) {
+            group[0] = source[(i * 3)];
+            group[1] = source[(i * 3) + 1];
+            group[2] = source[(i * 3) + 2];
+            group[3] = '\0';
+
+            bin_append(atoi(group), 10, binary_string);
+        }
+
+        weight_str[0] = source[19];
+
+        for (i = 0; i < 5; i++) {
+            weight_str[i + 1] = source[21 + i];
+        }
+        weight_str[6] = '\0';
+
+        bin_append(atoi(weight_str), 20, binary_string);
+
+        if (strlen(source) == 34) {
+            /* Date information is included */
+            char date_str[4];
+            date_str[0] = source[28];
+            date_str[1] = source[29];
+            date_str[2] = '\0';
+            group_val = atoi(date_str) * 384;
+
+            date_str[0] = source[30];
+            date_str[1] = source[31];
+            group_val += (atoi(date_str) - 1) * 32;
+
+            date_str[0] = source[32];
+            date_str[1] = source[33];
+            group_val += atoi(date_str);
+        } else {
+            group_val = 38400;
+        }
+
+        bin_append(group_val, 16, binary_string);
+    }
+
+    /* 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;
+    for (i = read_posn; i < (int) strlen(source); i++) {
+        general_field[j] = source[i];
+        j++;
+    }
+    general_field[j] = '\0';
+    if (debug) printf("General field data = %s\n", general_field);
+
+    if (!general_field_encode(general_field, &mode, &last_digit, binary_string)) {
+        /* Invalid characters in input data */
+        strcpy(symbol->errtxt, "386: Invalid characters in input data");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+    if (debug) printf("Resultant binary = %s\n", binary_string);
+    if (debug) printf("\tLength: %d\n", (int) strlen(binary_string));
+
+    remainder = 12 - (strlen(binary_string) % 12);
+    if (remainder == 12) {
+        remainder = 0;
+    }
+    symbol_characters = ((strlen(binary_string) + remainder) / 12) + 1;
+
+    if ((symbol->symbology == BARCODE_RSS_EXPSTACK) || (symbol->symbology == BARCODE_RSS_EXPSTACK_CC)) {
+        characters_per_row = symbol->option_2 * 2;
+
+        if ((characters_per_row < 2) || (characters_per_row > 20)) {
+            characters_per_row = 4;
+        }
+
+        if ((symbol_characters % characters_per_row) == 1) {
+            symbol_characters++;
+        }
+    }
+
+    if (symbol_characters < 4) {
+        symbol_characters = 4;
+    }
+
+    remainder = (12 * (symbol_characters - 1)) - strlen(binary_string);
+
+    if (last_digit) {
+        /* There is still one more numeric digit to encode */
+        if (debug) printf("Adding extra (odd) numeric digit\n");
+
+        if ((remainder >= 4) && (remainder <= 6)) {
+            bin_append(ctoi(last_digit) + 1, 4, binary_string);
+        } else {
+            d1 = ctoi(last_digit);
+            d2 = 10;
+
+            bin_append((11 * d1) + d2 + 8, 7, binary_string);
+        }
+
+        remainder = 12 - (strlen(binary_string) % 12);
+        if (remainder == 12) {
+            remainder = 0;
+        }
+        symbol_characters = ((strlen(binary_string) + remainder) / 12) + 1;
+
+        if ((symbol->symbology == BARCODE_RSS_EXPSTACK) || (symbol->symbology == BARCODE_RSS_EXPSTACK_CC)) {
+            characters_per_row = symbol->option_2 * 2;
+
+            if ((characters_per_row < 2) || (characters_per_row > 20)) {
+                characters_per_row = 4;
+            }
+
+            if ((symbol_characters % characters_per_row) == 1) {
+                symbol_characters++;
+            }
+        }
+
+        if (symbol_characters < 4) {
+            symbol_characters = 4;
+        }
+
+        remainder = (12 * (symbol_characters - 1)) - strlen(binary_string);
+
+        if (debug) printf("Resultant binary = %s\n", binary_string);
+        if (debug) printf("\tLength: %d\n", (int) strlen(binary_string));
+    }
+
+    if (strlen(binary_string) > 252) { /* 252 = (21 * 12) */
+        strcpy(symbol->errtxt, "387: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    /* Now add padding to binary string (7.2.5.5.4) */
+    i = remainder;
+    if (mode == NUMERIC) {
+        strcpy(padstring, "0000");
+        i -= 4;
+    } else {
+        strcpy(padstring, "");
+    }
+    for (; i > 0; i -= 5) {
+        strcat(padstring, "00100");
+    }
+
+    padstring[remainder] = '\0';
+    strcat(binary_string, padstring);
+
+    /* Patch variable length symbol bit field */
+    d1 = symbol_characters & 1;
+
+    if (symbol_characters <= 14) {
+        d2 = 0;
+    } else {
+        d2 = 1;
+    }
+
+    if (encoding_method == 1) {
+        binary_string[2] = d1 ? '1' : '0';
+        binary_string[3] = d2 ? '1' : '0';
+    }
+    if (encoding_method == 2) {
+        binary_string[3] = d1 ? '1' : '0';
+        binary_string[4] = d2 ? '1' : '0';
+    }
+    if ((encoding_method == 5) || (encoding_method == 6)) {
+        binary_string[6] = d1 ? '1' : '0';
+        binary_string[7] = d2 ? '1' : '0';
+    }
+    if (debug) printf("Resultant binary = %s\n", binary_string);
+    if (debug) printf("\tLength: %d\n", (int) strlen(binary_string));
+    return 0;
+}
+
+/* GS1 DataBar Expanded */
+INTERNAL int rssexpanded(struct zint_symbol *symbol, unsigned char source[], int src_len) {
+    int i, j, k, p, data_chars, vs[21], group[21], v_odd[21], v_even[21];
+    char substring[21][14], latch;
+    int char_widths[21][8], checksum, check_widths[8], c_group;
+    int check_char, c_odd, c_even, elements[235], pattern_width, reader, writer;
+    int separator_row;
+    unsigned int bin_len = 13 * src_len + 200 + 1; /* Allow for 8 bits + 5-bit latch per char + 200 bits overhead/padding */
+#ifndef _MSC_VER
+    char reduced[src_len + 1], binary_string[bin_len];
+#else
+    char* reduced = (char*) _alloca(src_len + 1);
+    char* binary_string = (char*) _alloca(bin_len);
+#endif
+
+    separator_row = 0;
+    reader = 0;
+
+    i = gs1_verify(symbol, source, src_len, reduced);
+    if (i != 0) {
+        return i;
+    }
+
+    if ((symbol->symbology == BARCODE_RSS_EXP_CC) || (symbol->symbology == BARCODE_RSS_EXPSTACK_CC)) {
+        /* make space for a composite separator pattern */
+        separator_row = symbol->rows;
+        symbol->row_height[separator_row] = 1;
+        symbol->rows += 1;
+    }
+
+    strcpy(binary_string, "");
+
+    if (symbol->option_1 == 2) {
+        strcat(binary_string, "1");
+    } else {
+        strcat(binary_string, "0");
+    }
+
+    i = rss_binary_string(symbol, reduced, binary_string);
+    if (i != 0) {
+        return i;
+    }
+
+    data_chars = strlen(binary_string) / 12;
+
+    for (i = 0; i < data_chars; i++) {
+        for (j = 0; j < 12; j++) {
+            substring[i][j] = binary_string[(i * 12) + j];
+        }
+        substring[i][12] = '\0';
+    }
+
+    for (i = 0; i < data_chars; i++) {
+        vs[i] = 0;
+        for (p = 0; p < 12; p++) {
+            if (substring[i][p] == '1') {
+                vs[i] += (0x800 >> p);
+            }
+        }
+    }
+
+    for (i = 0; i < data_chars; i++) {
+        if (vs[i] <= 347) {
+            group[i] = 1;
+        }
+        if ((vs[i] >= 348) && (vs[i] <= 1387)) {
+            group[i] = 2;
+        }
+        if ((vs[i] >= 1388) && (vs[i] <= 2947)) {
+            group[i] = 3;
+        }
+        if ((vs[i] >= 2948) && (vs[i] <= 3987)) {
+            group[i] = 4;
+        }
+        if (vs[i] >= 3988) {
+            group[i] = 5;
+        }
+        v_odd[i] = (vs[i] - g_sum_exp[group[i] - 1]) / t_even_exp[group[i] - 1];
+        v_even[i] = (vs[i] - g_sum_exp[group[i] - 1]) % t_even_exp[group[i] - 1];
+
+        getRSSwidths(v_odd[i], modules_odd_exp[group[i] - 1], 4, widest_odd_exp[group[i] - 1], 0);
+        char_widths[i][0] = widths[0];
+        char_widths[i][2] = widths[1];
+        char_widths[i][4] = widths[2];
+        char_widths[i][6] = widths[3];
+        getRSSwidths(v_even[i], modules_even_exp[group[i] - 1], 4, widest_even_exp[group[i] - 1], 1);
+        char_widths[i][1] = widths[0];
+        char_widths[i][3] = widths[1];
+        char_widths[i][5] = widths[2];
+        char_widths[i][7] = widths[3];
+    }
+
+    /* 7.2.6 Check character */
+    /* The checksum value is equal to the mod 211 residue of the weighted sum of the widths of the
+       elements in the data characters. */
+    checksum = 0;
+    for (i = 0; i < data_chars; i++) {
+        int row = weight_rows[(((data_chars - 2) / 2) * 21) + i];
+        for (j = 0; j < 8; j++) {
+            checksum += (char_widths[i][j] * checksum_weight_exp[(row * 8) + j]);
+
+        }
+    }
+
+    check_char = (211 * ((data_chars + 1) - 4)) + (checksum % 211);
+
+    if (check_char <= 347) {
+        c_group = 1;
+    }
+    if ((check_char >= 348) && (check_char <= 1387)) {
+        c_group = 2;
+    }
+    if ((check_char >= 1388) && (check_char <= 2947)) {
+        c_group = 3;
+    }
+    if ((check_char >= 2948) && (check_char <= 3987)) {
+        c_group = 4;
+    }
+    if (check_char >= 3988) {
+        c_group = 5;
+    }
+
+    c_odd = (check_char - g_sum_exp[c_group - 1]) / t_even_exp[c_group - 1];
+    c_even = (check_char - g_sum_exp[c_group - 1]) % t_even_exp[c_group - 1];
+
+    getRSSwidths(c_odd, modules_odd_exp[c_group - 1], 4, widest_odd_exp[c_group - 1], 0);
+    check_widths[0] = widths[0];
+    check_widths[2] = widths[1];
+    check_widths[4] = widths[2];
+    check_widths[6] = widths[3];
+    getRSSwidths(c_even, modules_even_exp[c_group - 1], 4, widest_even_exp[c_group - 1], 1);
+    check_widths[1] = widths[0];
+    check_widths[3] = widths[1];
+    check_widths[5] = widths[2];
+    check_widths[7] = widths[3];
+
+    /* Initialise element array */
+    pattern_width = ((((data_chars + 1) / 2) + ((data_chars + 1) & 1)) * 5) + ((data_chars + 1) * 8) + 4;
+    for (i = 0; i < pattern_width; i++) {
+        elements[i] = 0;
+    }
+
+    /* Put finder patterns in element array */
+    for (i = 0; i < (((data_chars + 1) / 2) + ((data_chars + 1) & 1)); i++) {
+        k = ((((((data_chars + 1) - 2) / 2) + ((data_chars + 1) & 1)) - 1) * 11) + i;
+        for (j = 0; j < 5; j++) {
+            elements[(21 * i) + j + 10] = finder_pattern_exp[((finder_sequence[k] - 1) * 5) + j];
+        }
+    }
+
+    /* Put check character in element array */
+    for (i = 0; i < 8; i++) {
+        elements[i + 2] = check_widths[i];
+    }
+
+    /* Put forward reading data characters in element array */
+    for (i = 1; i < data_chars; i += 2) {
+        for (j = 0; j < 8; j++) {
+            elements[(((i - 1) / 2) * 21) + 23 + j] = char_widths[i][j];
+        }
+    }
+
+    /* Put reversed data characters in element array */
+    for (i = 0; i < data_chars; i += 2) {
+        for (j = 0; j < 8; j++) {
+            elements[((i / 2) * 21) + 15 + j] = char_widths[i][7 - j];
+        }
+    }
+
+    if ((symbol->symbology == BARCODE_RSS_EXP) || (symbol->symbology == BARCODE_RSS_EXP_CC)) {
+        /* Copy elements into symbol */
+
+        elements[0] = 1; // left guard
+        elements[1] = 1;
+
+        elements[pattern_width - 2] = 1; // right guard
+        elements[pattern_width - 1] = 1;
+
+        writer = 0;
+        latch = '0';
+        for (i = 0; i < pattern_width; i++) {
+            for (j = 0; j < elements[i]; j++) {
+                if (latch == '1') {
+                    set_module(symbol, symbol->rows, writer);
+                } else {
+                    unset_module(symbol, symbol->rows, writer);
+                }
+                writer++;
+            }
+            if (latch == '1') {
+                latch = '0';
+            } else {
+                latch = '1';
+            }
+        }
+        if (symbol->width < writer) {
+            symbol->width = writer;
+        }
+        symbol->rows = symbol->rows + 1;
+        if (symbol->symbology == BARCODE_RSS_EXP_CC) {
+            for (j = 4; j < (symbol->width - 4); j++) {
+                if (module_is_set(symbol, separator_row + 1, j)) {
+                    unset_module(symbol, separator_row, j);
+                } else {
+                    set_module(symbol, separator_row, j);
+                }
+            }
+            /* finder bar adjustment */
+            for (j = 0; j < (writer / 49); j++) {
+                k = (49 * j) + 18;
+                for (i = 0; i < 15; i++) {
+                    if ((!(module_is_set(symbol, separator_row + 1, i + k - 1))) &&
+                            (!(module_is_set(symbol, separator_row + 1, i + k))) &&
+                            module_is_set(symbol, separator_row, i + k - 1)) {
+                        unset_module(symbol, separator_row, i + k);
+                    }
+                }
+            }
+        }
+
+        /* Add human readable text */
+        for (i = 0; i <= src_len; i++) {
+            if ((source[i] != '[') && (source[i] != ']')) {
+                symbol->text[i] = source[i];
+            } else {
+                if (source[i] == '[') {
+                    symbol->text[i] = '(';
+                }
+                if (source[i] == ']') {
+                    symbol->text[i] = ')';
+                }
+            }
+        }
+
+    } else {
+        int stack_rows;
+        int current_row, current_block, left_to_right;
+        /* RSS Expanded Stacked */
+
+        /* Bug corrected: Character missing for message
+         * [01]90614141999996[10]1234222222222221
+         * Patch by Daniel Frede
+         */
+        int codeblocks = (data_chars + 1) / 2 + ((data_chars + 1) % 2);
+
+
+        if ((symbol->option_2 < 1) || (symbol->option_2 > 10)) {
+            symbol->option_2 = 2;
+        }
+        if ((symbol->option_1 == 2) && (symbol->option_2 == 1)) {
+            /* "There shall be a minimum of four symbol characters in the
+            first row of an RSS Expanded Stacked symbol when it is the linear
+            component of an EAN.UCC Composite symbol." */
+            symbol->option_2 = 2;
+        }
+
+        stack_rows = codeblocks / symbol->option_2;
+        if (codeblocks % symbol->option_2 > 0) {
+            stack_rows++;
+        }
+
+        current_block = 0;
+        for (current_row = 1; current_row <= stack_rows; current_row++) {
+            int special_case_row = 0;
+            int elements_in_sub;
+            int sub_elements[235];
+            for (i = 0; i < 235; i++) {
+                sub_elements[i] = 0;
+            }
+
+            /* Row Start */
+            sub_elements[0] = 1; // left guard
+            sub_elements[1] = 1;
+            elements_in_sub = 2;
+
+            /* Row Data */
+            reader = 0;
+            do {
+                if (((symbol->option_2 & 1) || (current_row & 1)) ||
+                        ((current_row == stack_rows) && (codeblocks != (current_row * symbol->option_2)) &&
+                        (((current_row * symbol->option_2) - codeblocks) & 1))) {
+                    /* left to right */
+                     left_to_right = 1;
+                    i = 2 + (current_block * 21);
+                    for (j = 0; j < 21; j++) {
+                        if ((i + j) < pattern_width) {
+                                sub_elements[j + (reader * 21) + 2] = elements[i + j];
+                        }
+                        elements_in_sub++;
+                    }
+                } else {
+                    /* right to left */
+                    left_to_right = 0;
+                    i = 2 + (((current_row * symbol->option_2) - reader - 1) * 21);
+                    for (j = 0; j < 21; j++) {
+                        if ((i + j) < pattern_width) {
+                                sub_elements[(20 - j) + (reader * 21) + 2] = elements[i + j];
+                        }
+                        elements_in_sub++;
+                    }
+                }
+                reader++;
+                current_block++;
+            } while ((reader < symbol->option_2) && (current_block < codeblocks));
+
+            /* Row Stop */
+            sub_elements[elements_in_sub] = 1; // right guard
+            sub_elements[elements_in_sub + 1] = 1;
+            elements_in_sub += 2;
+
+            latch = (current_row & 1) ? '0' : '1';
+
+            if ((current_row == stack_rows) && (codeblocks != (current_row * symbol->option_2)) &&
+                    ((current_row & 1) == 0) && ((symbol->option_2 & 1) == 0)) {
+                /* Special case bottom row */
+                special_case_row = 1;
+                sub_elements[0] = 2;
+                latch = '0';
+            }
+
+            writer = 0;
+            for (i = 0; i < elements_in_sub; i++) {
+                for (j = 0; j < sub_elements[i]; j++) {
+                    if (latch == '1') {
+                        set_module(symbol, symbol->rows, writer);
+                    } else {
+                        unset_module(symbol, symbol->rows, writer);
+                    }
+                    writer++;
+                }
+                if (latch == '1') {
+                    latch = '0';
+                } else {
+                    latch = '1';
+                }
+            }
+            if (symbol->width < writer) {
+                symbol->width = writer;
+            }
+
+            if (current_row != 1) {
+                /* middle separator pattern (above current row) */
+                for (j = 5; j < (49 * symbol->option_2); j += 2) {
+                    set_module(symbol, symbol->rows - 2, j);
+                }
+                symbol->row_height[symbol->rows - 2] = 1;
+                /* bottom separator pattern (above current row) */
+                for (j = 4 + special_case_row; j < (writer - 4); j++) {
+                    if (module_is_set(symbol, symbol->rows, j)) {
+                        unset_module(symbol, symbol->rows - 1, j);
+                    } else {
+                        set_module(symbol, symbol->rows - 1, j);
+                    }
+                }
+                symbol->row_height[symbol->rows - 1] = 1;
+                /* finder bar adjustment */
+                for (j = 0; j < reader; j++) {
+                    k = (49 * j) + 18 + special_case_row;
+                    if (left_to_right) {
+                        for (i = 0; i < 15; i++) {
+                            if ((!(module_is_set(symbol, symbol->rows, i + k - 1))) &&
+                                    (!(module_is_set(symbol, symbol->rows, i + k))) &&
+                                    module_is_set(symbol, symbol->rows - 1, i + k - 1)) {
+                                unset_module(symbol, symbol->rows - 1, i + k);
+                            }
+                        }
+                    } else {
+                        if ((current_row == stack_rows) && (data_chars % 2 == 0)) {
+                            k -= 18;
+                        }
+                        for (i = 14; i >= 0; i--) {
+                            if ((!(module_is_set(symbol, symbol->rows, i + k + 1))) &&
+                                    (!(module_is_set(symbol, symbol->rows, i + k))) &&
+                                    module_is_set(symbol, symbol->rows - 1, i + k + 1)) {
+                                unset_module(symbol, symbol->rows - 1, i + k);
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (current_row != stack_rows) {
+                /* top separator pattern (below current row) */
+                for (j = 4; j < (writer - 4); j++) {
+                    if (module_is_set(symbol, symbol->rows, j)) {
+                        unset_module(symbol, symbol->rows + 1, j);
+                    } else {
+                        set_module(symbol, symbol->rows + 1, j);
+                    }
+                }
+                symbol->row_height[symbol->rows + 1] = 1;
+                /* finder bar adjustment */
+                for (j = 0; j < reader; j++) {
+                    k = (49 * j) + 18;
+                    if (left_to_right) {
+                        for (i = 0; i < 15; i++) {
+                            if ((!(module_is_set(symbol, symbol->rows, i + k - 1))) &&
+                                    (!(module_is_set(symbol, symbol->rows, i + k))) &&
+                                    module_is_set(symbol, symbol->rows + 1, i + k - 1)) {
+                                unset_module(symbol, symbol->rows + 1, i + k);
+                            }
+                        }
+                    } else {
+                        for (i = 14; i >= 0; i--) {
+                            if ((!(module_is_set(symbol, symbol->rows, i + k + 1))) &&
+                                    (!(module_is_set(symbol, symbol->rows, i + k))) &&
+                                    module_is_set(symbol, symbol->rows + 1, i + k + 1)) {
+                                unset_module(symbol, symbol->rows + 1, i + k);
+                            }
+                        }
+                    }
+                }
+            }
+
+            symbol->rows = symbol->rows + 4;
+        }
+        symbol->rows = symbol->rows - 3;
+        if (symbol->symbology == BARCODE_RSS_EXPSTACK_CC) {
+            for (j = 4; j < (symbol->width - 4); j++) {
+                if (module_is_set(symbol, separator_row + 1, j)) {
+                    unset_module(symbol, separator_row, j);
+                } else {
+                    set_module(symbol, separator_row, j);
+                }
+            }
+            /* finder bar adjustment */
+            for (j = 0; j < reader; j++) {
+                k = (49 * j) + 18;
+                for (i = 0; i < 15; i++) {
+                    if ((!(module_is_set(symbol, separator_row + 1, i + k - 1))) &&
+                            (!(module_is_set(symbol, separator_row + 1, i + k))) &&
+                            module_is_set(symbol, separator_row, i + k - 1)) {
+                        unset_module(symbol, separator_row, i + k);
+                    }
+                }
+            }
+        }
+
+    }
+
+    for (i = 0; i < symbol->rows; i++) {
+        if (symbol->row_height[i] == 0) {
+            symbol->row_height[i] = 34;
+        }
+    }
+
+    return 0;
+}
diff --git a/backend/rss.h b/backend/rss.h
new file mode 100644 (file)
index 0000000..d6c1fb9
--- /dev/null
@@ -0,0 +1,293 @@
+/* rss.h - Data tables for Reduced Space Symbology */
+
+/*
+    libzint - the open source barcode library
+    Copyright (C) 2007-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 : */
+
+/* RSS-14 Tables */
+static const unsigned short int g_sum_table[9] = {
+    0, 161, 961, 2015, 2715, 0, 336, 1036, 1516
+};
+
+static const char t_table[9] = {
+    1, 10, 34, 70, 126, 4, 20, 48, 81
+};
+
+static const char modules_odd[9] = {
+    12, 10, 8, 6, 4, 5, 7, 9, 11
+};
+
+static const char modules_even[9] = {
+    4, 6, 8, 10, 12, 10, 8, 6, 4
+};
+
+static const char widest_odd[9] = {
+    8, 6, 4, 3, 1, 2, 4, 6, 8
+};
+
+static const char widest_even[9] = {
+    1, 3, 5, 6, 8, 7, 5, 3, 1
+};
+
+static int widths[8];
+static const char finder_pattern[45] = {
+    3, 8, 2, 1, 1,
+    3, 5, 5, 1, 1,
+    3, 3, 7, 1, 1,
+    3, 1, 9, 1, 1,
+    2, 7, 4, 1, 1,
+    2, 5, 6, 1, 1,
+    2, 3, 8, 1, 1,
+    1, 5, 7, 1, 1,
+    1, 3, 9, 1, 1
+};
+
+static const char checksum_weight[32] = {
+    /* Table 5 */
+    1, 3, 9, 27, 2, 6, 18, 54,
+    4, 12, 36, 29, 8, 24, 72, 58,
+    16, 48, 65, 37, 32, 17, 51, 74,
+    64, 34, 23, 69, 49, 68, 46, 59
+};
+
+/* RSS Limited Tables */
+static const unsigned short int t_even_ltd[7] = {
+    28, 728, 6454, 203, 2408, 1, 16632
+};
+
+static const char modules_odd_ltd[7] = {
+    17, 13, 9, 15, 11, 19, 7
+};
+
+static const char modules_even_ltd[7] = {
+    9, 13, 17, 11, 15, 7, 19
+};
+
+static const char widest_odd_ltd[7] = {
+    6, 5, 3, 5, 4, 8, 1
+};
+
+static const char widest_even_ltd[7] = {
+    3, 4, 6, 4, 5, 1, 8
+};
+
+static const char checksum_weight_ltd[28] = {
+    /* Table 7 */
+    1, 3, 9, 27, 81, 65, 17, 51, 64, 14, 42, 37, 22, 66,
+    20, 60, 2, 6, 18, 54, 73, 41, 34, 13, 39, 28, 84, 74
+};
+
+static const char finder_pattern_ltd[1246] = {
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 3, 2, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 3, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 1,
+    1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 2, 1, 1,
+    1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 3, 1, 1, 1,
+    1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 3, 1, 1, 1,
+    1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1,
+    1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1,
+    1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1,
+    1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 3, 1, 1, 1,
+    1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1,
+    1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1,
+    1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1,
+    1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1,
+    1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 1,
+    1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1,
+    1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1,
+    1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 3, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 1, 1, 1,
+    1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1,
+    1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1,
+    1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 1,
+    1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 2, 1, 1, 1,
+    1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1,
+    1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1,
+    1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1,
+    1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1,
+    1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1,
+    1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1,
+    1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1,
+    1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1,
+    1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1,
+    1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1,
+    1, 3, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1,
+    1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1,
+    1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1,
+    1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 3, 1, 1,
+    1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1,
+    1, 1, 1, 1, 1, 1, 2, 1, 1, 3, 2, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1,
+    1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1,
+    1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1,
+    1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1,
+    1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1,
+    1, 1, 1, 3, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1,
+    1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1,
+    1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1,
+    1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1,
+    1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 3, 1, 1,
+    1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1,
+    1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 2, 1, 1, 1,
+    1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1,
+    1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1, 1,
+    1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
+    1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1,
+    1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1,
+    1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1,
+    1, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1,
+    1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1,
+    1, 3, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1,
+    1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1,
+    1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1,
+    1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1,
+    1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1,
+    1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1,
+    1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1,
+    1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1,
+    1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1,
+    1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1,
+    2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1,
+    2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1,
+    2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1,
+    2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1,
+    2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1,
+    2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1,
+    2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1,
+    2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1,
+    2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1
+};
+
+/* RSS Expanded Tables */
+static const unsigned short int g_sum_exp[5] = {
+    0, 348, 1388, 2948, 3988
+};
+
+static const unsigned short int t_even_exp[5] = {
+    4, 20, 52, 104, 204
+};
+
+static const char modules_odd_exp[5] = {
+    12, 10, 8, 6, 4
+};
+
+static const char modules_even_exp[5] = {
+    5, 7, 9, 11, 13
+};
+
+static const char widest_odd_exp[5] = {
+    7, 5, 4, 3, 1
+};
+
+static const char widest_even_exp[5] = {
+    2, 4, 5, 6, 8
+};
+
+static const unsigned short int checksum_weight_exp[184] = {
+    /* Table 14 */
+    1, 3, 9, 27, 81, 32, 96, 77,
+    20, 60, 180, 118, 143, 7, 21, 63,
+    189, 145, 13, 39, 117, 140, 209, 205,
+    193, 157, 49, 147, 19, 57, 171, 91,
+    62, 186, 136, 197, 169, 85, 44, 132,
+    185, 133, 188, 142, 4, 12, 36, 108,
+    113, 128, 173, 97, 80, 29, 87, 50,
+    150, 28, 84, 41, 123, 158, 52, 156,
+    46, 138, 203, 187, 139, 206, 196, 166,
+    76, 17, 51, 153, 37, 111, 122, 155,
+    43, 129, 176, 106, 107, 110, 119, 146,
+    16, 48, 144, 10, 30, 90, 59, 177,
+    109, 116, 137, 200, 178, 112, 125, 164,
+    70, 210, 208, 202, 184, 130, 179, 115,
+    134, 191, 151, 31, 93, 68, 204, 190,
+    148, 22, 66, 198, 172, 94, 71, 2,
+    6, 18, 54, 162, 64, 192, 154, 40,
+    120, 149, 25, 75, 14, 42, 126, 167,
+    79, 26, 78, 23, 69, 207, 199, 175,
+    103, 98, 83, 38, 114, 131, 182, 124,
+    161, 61, 183, 127, 170, 88, 53, 159,
+    55, 165, 73, 8, 24, 72, 5, 15,
+    45, 135, 194, 160, 58, 174, 100, 89
+};
+
+static const char finder_pattern_exp[60] = {
+    /* Table 15 */
+    1, 8, 4, 1, 1,
+    1, 1, 4, 8, 1,
+    3, 6, 4, 1, 1,
+    1, 1, 4, 6, 3,
+    3, 4, 6, 1, 1,
+    1, 1, 6, 4, 3,
+    3, 2, 8, 1, 1,
+    1, 1, 8, 2, 3,
+    2, 6, 5, 1, 1,
+    1, 1, 5, 6, 2,
+    2, 2, 9, 1, 1,
+    1, 1, 9, 2, 2
+};
+
+static const char finder_sequence[198] = {
+    /* Table 16 */
+    1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    1, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0,
+    1, 6, 3, 8, 0, 0, 0, 0, 0, 0, 0,
+    1, 10, 3, 8, 5, 0, 0, 0, 0, 0, 0,
+    1, 10, 3, 8, 7, 12, 0, 0, 0, 0, 0,
+    1, 10, 3, 8, 9, 12, 11, 0, 0, 0, 0,
+    1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0,
+    1, 2, 3, 4, 5, 6, 7, 10, 9, 0, 0,
+    1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 0,
+    1, 2, 3, 4, 5, 8, 7, 10, 9, 12, 11
+};
+
+static const char weight_rows[210] = {
+    0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 5, 6, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 9, 10, 3, 4, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 17, 18, 3, 4, 13, 14, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 17, 18, 3, 4, 13, 14, 11, 12, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 17, 18, 3, 4, 13, 14, 15, 16, 21, 22, 19, 20, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0,
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 17, 18, 15, 16, 0, 0, 0, 0,
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 17, 18, 19, 20, 21, 22, 0, 0,
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 13, 14, 11, 12, 17, 18, 15, 16, 21, 22, 19, 20
+};
+
diff --git a/backend/sjis.c b/backend/sjis.c
new file mode 100644 (file)
index 0000000..daa8aae
--- /dev/null
@@ -0,0 +1,1591 @@
+/*
+    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 : */
+/*
+ * Adapted from the GNU LIBICONV library and patched to make compatible with
+ * https://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT
+ * with the exception of one duplicate mapping to reverse solidus 0x815F
+ * and the mapping of user-defined PUA codepoints U+E000..E757.
+ */
+/*
+ * Copyright (C) 1999-2002, 2016 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <string.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "sjis.h"
+
+INTERNAL int utf_to_eci(const int eci, const unsigned char source[], unsigned char dest[], size_t *length); /* Convert Unicode to other encodings */
+
+/*
+ * JISX0201.1976-0 (libiconv-1.16/lib/jisx0201.h)
+ */
+
+static int jisx0201_wctomb(unsigned int* r, unsigned int wc) {
+    if (wc < 0x0080 && !(wc == 0x005c || wc == 0x007e)) {
+        *r = wc;
+        return 1;
+    }
+    if (wc == 0x00a5) {
+        *r = 0x5c;
+        return 1;
+    }
+    if (wc == 0x203e) {
+        *r = 0x7e;
+        return 1;
+    }
+    if (wc >= 0xff61 && wc < 0xffa0) {
+        *r = wc - 0xfec0;
+        return 1;
+    }
+    return 0;
+}
+
+/*
+ * JISX0208.1990-0 (libiconv-1.16/lib/jisx0208.h)
+ */
+
+/* ZINT: Table converted from JIS X 0208 to Shift JIS values using tools/cnv_sjis.php:
+ * 
+while ($line = fgets(STDIN)) {
+    echo preg_replace_callback('/0x([0-9a-f]{4})/', function ($matches) {
+        $dec = hexdec($matches[1]);
+        $c1 = $dec >> 8;
+        $c2 = ($dec & 0xFF);
+        $t1 = ($c1 - 0x21) >> 1;
+        $t2 = ((($c1 - 0x21) & 1) ? 0x5e : 0) + ($c2 - 0x21);
+        $r = (($t1 < 0x1f ? ($t1 + 0x81) : ($t1 + 0xc1)) << 8) | ($t2 < 0x3f ? ($t2 + 0x40) : ($t2 + 0x41));
+        return '0x' . dechex($r);
+    }, $line);
+}
+ */
+static const unsigned short jisx0208_2charset[6879] = {
+  0x8191, 0x8192, 0x8198, 0x814e, 0x81ca, 0x818b, 0x817d, 0x814c,
+  0x81f7, 0x817e, 0x8180, 0x839f, 0x83a0, 0x83a1, 0x83a2, 0x83a3,
+  0x83a4, 0x83a5, 0x83a6, 0x83a7, 0x83a8, 0x83a9, 0x83aa, 0x83ab,
+  0x83ac, 0x83ad, 0x83ae, 0x83af, 0x83b0, 0x83b1, 0x83b2, 0x83b3,
+  0x83b4, 0x83b5, 0x83b6, 0x83bf, 0x83c0, 0x83c1, 0x83c2, 0x83c3,
+  0x83c4, 0x83c5, 0x83c6, 0x83c7, 0x83c8, 0x83c9, 0x83ca, 0x83cb,
+  0x83cc, 0x83cd, 0x83ce, 0x83cf, 0x83d0, 0x83d1, 0x83d2, 0x83d3,
+  0x83d4, 0x83d5, 0x83d6, 0x8446, 0x8440, 0x8441, 0x8442, 0x8443,
+  0x8444, 0x8445, 0x8447, 0x8448, 0x8449, 0x844a, 0x844b, 0x844c,
+  0x844d, 0x844e, 0x844f, 0x8450, 0x8451, 0x8452, 0x8453, 0x8454,
+  0x8455, 0x8456, 0x8457, 0x8458, 0x8459, 0x845a, 0x845b, 0x845c,
+  0x845d, 0x845e, 0x845f, 0x8460, 0x8470, 0x8471, 0x8472, 0x8473,
+  0x8474, 0x8475, 0x8477, 0x8478, 0x8479, 0x847a, 0x847b, 0x847c,
+  0x847d, 0x847e, 0x8480, 0x8481, 0x8482, 0x8483, 0x8484, 0x8485,
+  0x8486, 0x8487, 0x8488, 0x8489, 0x848a, 0x848b, 0x848c, 0x848d,
+  0x848e, 0x848f, 0x8490, 0x8491, 0x8476, 0x815d, 0x815c, 0x8161,
+  0x8165, 0x8166, 0x8167, 0x8168, 0x81f5, 0x81f6, 0x8164, 0x8163,
+  0x81f1, 0x818c, 0x818d, 0x81a6, 0x818e, 0x81f0, 0x81a9, 0x81aa,
+  0x81a8, 0x81ab, 0x81cb, 0x81cc, 0x81cd, 0x81dd, 0x81ce, 0x81de,
+  0x81b8, 0x81b9, 0x817c, 0x81e3, 0x81e5, 0x8187, 0x81da, 0x81c8,
+  0x81c9, 0x81bf, 0x81be, 0x81e7, 0x81e8, 0x8188, 0x81e6, 0x81e4,
+  0x81e0, 0x8182, 0x81df, 0x8185, 0x8186, 0x81e1, 0x81e2, 0x81bc,
+  0x81bd, 0x81ba, 0x81bb, 0x81db, 0x81dc, 0x849f, 0x84aa, 0x84a0,
+  0x84ab, 0x84a1, 0x84ac, 0x84a2, 0x84ad, 0x84a4, 0x84af, 0x84a3,
+  0x84ae, 0x84a5, 0x84ba, 0x84b5, 0x84b0, 0x84a7, 0x84bc, 0x84b7,
+  0x84b2, 0x84a6, 0x84b6, 0x84bb, 0x84b1, 0x84a8, 0x84b8, 0x84bd,
+  0x84b3, 0x84a9, 0x84b9, 0x84be, 0x84b4, 0x81a1, 0x81a0, 0x81a3,
+  0x81a2, 0x81a5, 0x81a4, 0x819f, 0x819e, 0x819b, 0x819d, 0x819c,
+  0x81fc, 0x819a, 0x8199, 0x818a, 0x8189, 0x81f4, 0x81f3, 0x81f2,
+  0x8140, 0x8141, 0x8142, 0x8156, 0x8158, 0x8159, 0x815a, 0x8171,
+  0x8172, 0x8173, 0x8174, 0x8175, 0x8176, 0x8177, 0x8178, 0x8179,
+  0x817a, 0x81a7, 0x81ac, 0x816b, 0x816c, 0x8160, 0x829f, 0x82a0,
+  0x82a1, 0x82a2, 0x82a3, 0x82a4, 0x82a5, 0x82a6, 0x82a7, 0x82a8,
+  0x82a9, 0x82aa, 0x82ab, 0x82ac, 0x82ad, 0x82ae, 0x82af, 0x82b0,
+  0x82b1, 0x82b2, 0x82b3, 0x82b4, 0x82b5, 0x82b6, 0x82b7, 0x82b8,
+  0x82b9, 0x82ba, 0x82bb, 0x82bc, 0x82bd, 0x82be, 0x82bf, 0x82c0,
+  0x82c1, 0x82c2, 0x82c3, 0x82c4, 0x82c5, 0x82c6, 0x82c7, 0x82c8,
+  0x82c9, 0x82ca, 0x82cb, 0x82cc, 0x82cd, 0x82ce, 0x82cf, 0x82d0,
+  0x82d1, 0x82d2, 0x82d3, 0x82d4, 0x82d5, 0x82d6, 0x82d7, 0x82d8,
+  0x82d9, 0x82da, 0x82db, 0x82dc, 0x82dd, 0x82de, 0x82df, 0x82e0,
+  0x82e1, 0x82e2, 0x82e3, 0x82e4, 0x82e5, 0x82e6, 0x82e7, 0x82e8,
+  0x82e9, 0x82ea, 0x82eb, 0x82ec, 0x82ed, 0x82ee, 0x82ef, 0x82f0,
+  0x82f1, 0x814a, 0x814b, 0x8154, 0x8155, 0x8340, 0x8341, 0x8342,
+  0x8343, 0x8344, 0x8345, 0x8346, 0x8347, 0x8348, 0x8349, 0x834a,
+  0x834b, 0x834c, 0x834d, 0x834e, 0x834f, 0x8350, 0x8351, 0x8352,
+  0x8353, 0x8354, 0x8355, 0x8356, 0x8357, 0x8358, 0x8359, 0x835a,
+  0x835b, 0x835c, 0x835d, 0x835e, 0x835f, 0x8360, 0x8361, 0x8362,
+  0x8363, 0x8364, 0x8365, 0x8366, 0x8367, 0x8368, 0x8369, 0x836a,
+  0x836b, 0x836c, 0x836d, 0x836e, 0x836f, 0x8370, 0x8371, 0x8372,
+  0x8373, 0x8374, 0x8375, 0x8376, 0x8377, 0x8378, 0x8379, 0x837a,
+  0x837b, 0x837c, 0x837d, 0x837e, 0x8380, 0x8381, 0x8382, 0x8383,
+  0x8384, 0x8385, 0x8386, 0x8387, 0x8388, 0x8389, 0x838a, 0x838b,
+  0x838c, 0x838d, 0x838e, 0x838f, 0x8390, 0x8391, 0x8392, 0x8393,
+  0x8394, 0x8395, 0x8396, 0x8145, 0x815b, 0x8152, 0x8153, 0x88ea,
+  0x929a, 0x8eb5, 0x969c, 0x8fe4, 0x8e4f, 0x8fe3, 0x89ba, 0x9573,
+  0x975e, 0x98a0, 0x894e, 0x8a8e, 0x98a1, 0x90a2, 0x99c0, 0x8b75,
+  0x95b8, 0x8fe5, 0x97bc, 0x95c0, 0x98a2, 0x9286, 0x98a3, 0x8bf8,
+  0x98a4, 0x8adb, 0x924f, 0x8ee5, 0x98a5, 0x98a6, 0x98a7, 0x9454,
+  0x8b76, 0x9456, 0x93e1, 0x8cc1, 0x9652, 0xe568, 0x98a8, 0x8fe6,
+  0x98a9, 0x89b3, 0x8be3, 0x8cee, 0x96e7, 0x9ba4, 0x9790, 0x93fb,
+  0x8aa3, 0x8b54, 0x98aa, 0x98ab, 0x97b9, 0x975c, 0x9188, 0x98ad,
+  0x8e96, 0x93f1, 0x98b0, 0x895d, 0x8cdd, 0x8cdc, 0x88e4, 0x986a,
+  0x9869, 0x8db1, 0x889f, 0x98b1, 0x98b2, 0x98b3, 0x9653, 0x98b4,
+  0x8cf0, 0x88e5, 0x9692, 0x8b9c, 0x8b9d, 0x8b9e, 0x92e0, 0x97ba,
+  0x98b5, 0x98b6, 0x98b7, 0x906c, 0x8f59, 0x906d, 0x98bc, 0x98ba,
+  0x98bb, 0x8b77, 0x8da1, 0x89ee, 0x98b9, 0x98b8, 0x95a7, 0x8e65,
+  0x8e64, 0x91bc, 0x98bd, 0x9574, 0x90e5, 0x8157, 0x98be, 0x98c0,
+  0x91e3, 0x97df, 0x88c8, 0x98bf, 0x89bc, 0x8bc2, 0x9287, 0x8c8f,
+  0x98c1, 0x9443, 0x8ae9, 0x98c2, 0x88c9, 0x8cde, 0x8aea, 0x959a,
+  0x94b0, 0x8b78, 0x89ef, 0x98e5, 0x9360, 0x948c, 0x98c4, 0x94ba,
+  0x97e0, 0x904c, 0x8e66, 0x8e97, 0x89be, 0x92cf, 0x9241, 0x98c8,
+  0x88ca, 0x92e1, 0x8f5a, 0x8db2, 0x9743, 0x91cc, 0x89bd, 0x98c7,
+  0x975d, 0x98c3, 0x98c5, 0x8dec, 0x98c6, 0x9b43, 0x98ce, 0x98d1,
+  0x98cf, 0x89c0, 0x95b9, 0x98c9, 0x98cd, 0x8cf1, 0x8e67, 0x8aa4,
+  0x98d2, 0x98ca, 0x97e1, 0x8e98, 0x98cb, 0x98d0, 0x98d3, 0x98cc,
+  0x8b9f, 0x88cb, 0x8ba0, 0x89bf, 0x9b44, 0x9699, 0x958e, 0x8cf2,
+  0x904e, 0x97b5, 0x95d6, 0x8c57, 0x91a3, 0x89e2, 0x8f72, 0x98d7,
+  0x98dc, 0x98da, 0x98d5, 0x91ad, 0x98d8, 0x98db, 0x98d9, 0x95db,
+  0x98d6, 0x904d, 0x9693, 0x98dd, 0x98de, 0x8f43, 0x98eb, 0x946f,
+  0x9555, 0x98e6, 0x95ee, 0x89b4, 0x98ea, 0x98e4, 0x98ed, 0x9171,
+  0x8cc2, 0x947b, 0xe0c5, 0x98ec, 0x937c, 0x98e1, 0x8cf4, 0x8cf3,
+  0x98df, 0x8ed8, 0x98e7, 0x95ed, 0x926c, 0x98e3, 0x8c91, 0x98e0,
+  0x98e8, 0x98e2, 0x97cf, 0x98e9, 0x9860, 0x8be4, 0x8c90, 0x98ee,
+  0x98ef, 0x98f3, 0x88cc, 0x95ce, 0x98f2, 0x98f1, 0x98f5, 0x98f4,
+  0x92e2, 0x8c92, 0x98f6, 0x8ec3, 0x91a4, 0x92e3, 0x8bf4, 0x98f7,
+  0x8b55, 0x98f8, 0x98fa, 0x9654, 0x8c86, 0x8e50, 0x94f5, 0x98f9,
+  0x8dc3, 0x9762, 0x98fc, 0x9942, 0x98fb, 0x8dc2, 0x8f9d, 0x8c58,
+  0x9943, 0x8bcd, 0x9940, 0x9941, 0x93ad, 0x919c, 0x8ba1, 0x966c,
+  0x9944, 0x97bb, 0x9945, 0x9948, 0x9946, 0x916d, 0x9947, 0x9949,
+  0x994b, 0x994a, 0x95c6, 0x8b56, 0x994d, 0x994e, 0x89ad, 0x994c,
+  0x8ef2, 0x9951, 0x9950, 0x994f, 0x98d4, 0x9952, 0x8f9e, 0x9953,
+  0x9744, 0x96d7, 0x9955, 0x9954, 0x9957, 0x9956, 0x9958, 0x9959,
+  0x88f2, 0x8cb3, 0x8c5a, 0x8f5b, 0x929b, 0x8ba2, 0x90e6, 0x8cf5,
+  0x8d8e, 0x995b, 0x96c6, 0x9365, 0x8e99, 0x995a, 0x995c, 0x937d,
+  0x8a95, 0x995d, 0x93fc, 0x9153, 0x995f, 0x9960, 0x94aa, 0x8cf6,
+  0x985a, 0x9961, 0x8ba4, 0x95ba, 0x91b4, 0x8bef, 0x9354, 0x8c93,
+  0x9962, 0x9963, 0x93e0, 0x897e, 0x9966, 0x8dfb, 0x9965, 0x8dc4,
+  0x9967, 0xe3ec, 0x9968, 0x9660, 0x9969, 0x996a, 0x996b, 0x8fe7,
+  0x8eca, 0x8aa5, 0x996e, 0x996c, 0x96bb, 0x996d, 0x9579, 0x996f,
+  0x9970, 0x9971, 0x937e, 0x9975, 0x9973, 0x9974, 0x9972, 0x8de1,
+  0x9976, 0x96e8, 0x97e2, 0x9977, 0x90a6, 0x9978, 0x8f79, 0x9979,
+  0x929c, 0x97bd, 0x9380, 0x99c3, 0x997a, 0xeaa3, 0x8bc3, 0x997b,
+  0x967d, 0x8f88, 0x91fa, 0x997d, 0x93e2, 0x997e, 0x9980, 0x8a4d,
+  0x9981, 0x8ba5, 0x93ca, 0x899a, 0x8f6f, 0x949f, 0x9982, 0x9381,
+  0x906e, 0x9983, 0x95aa, 0x90d8, 0x8aa0, 0x8aa7, 0x9984, 0x9986,
+  0x8c59, 0x9985, 0x97f1, 0x8f89, 0x94bb, 0x95ca, 0x9987, 0x9798,
+  0x9988, 0x9989, 0x939e, 0x998a, 0x90a7, 0x8dfc, 0x8c94, 0x998b,
+  0x8e68, 0x8d8f, 0x92e4, 0x998d, 0x91a5, 0x8ded, 0x998e, 0x998f,
+  0x914f, 0x998c, 0x9991, 0x9655, 0x8d84, 0x9990, 0x8c95, 0x8ddc,
+  0x948d, 0x9994, 0x9992, 0x959b, 0x8fe8, 0x999b, 0x8a84, 0x9995,
+  0x9993, 0x916e, 0x9997, 0x9996, 0x8a63, 0x8c80, 0x999c, 0x97ab,
+  0x9998, 0x999d, 0x999a, 0x9999, 0x97cd, 0x8cf7, 0x89c1, 0x97f2,
+  0x8f95, 0x9377, 0x8d85, 0x99a0, 0x99a1, 0x97e3, 0x984a, 0x99a3,
+  0x8cf8, 0x99a2, 0x8a4e, 0x99a4, 0x9675, 0x92ba, 0x9745, 0x95d7,
+  0x99a5, 0xe8d3, 0x93ae, 0x99a6, 0x8aa8, 0x96b1, 0x8f9f, 0x99a7,
+  0x95e5, 0x99ab, 0x90a8, 0x99a8, 0x8bce, 0x99a9, 0x8aa9, 0x8c4d,
+  0x99ac, 0x99ad, 0x99ae, 0x99af, 0x8ed9, 0x8cf9, 0x96dc, 0x96e6,
+  0x93f5, 0x95ef, 0x99b0, 0x99b1, 0x99b3, 0x99b5, 0x99b4, 0x99b6,
+  0x89bb, 0x966b, 0x8dfa, 0x99b7, 0x9178, 0x8fa0, 0x8ba7, 0x99b8,
+  0x94d9, 0x99b9, 0x99ba, 0x99bb, 0x99bc, 0x9543, 0x8be6, 0x88e3,
+  0x93bd, 0x99bd, 0x8f5c, 0x90e7, 0x99bf, 0x99be, 0x8fa1, 0x8cdf,
+  0x99c1, 0x94bc, 0x99c2, 0x94da, 0x91b2, 0x91ec, 0x8ba6, 0x93ec,
+  0x9250, 0x948e, 0x966d, 0x99c4, 0x90e8, 0x8c54, 0x99c5, 0x99c6,
+  0x894b, 0x88f3, 0x8aeb, 0x91a6, 0x8b70, 0x9791, 0x99c9, 0x89b5,
+  0x99c8, 0x8ba8, 0x99ca, 0x96ef, 0x99cb, 0x97d0, 0x8cfa, 0x8cb4,
+  0x99cc, 0x99ce, 0x99cd, 0x907e, 0x8958, 0x897d, 0x99cf, 0x99d0,
+  0x8cb5, 0x99d1, 0x8b8e, 0x8e51, 0x99d2, 0x9694, 0x8db3, 0x8b79,
+  0x9746, 0x916f, 0x94bd, 0x8efb, 0x8f66, 0x8ee6, 0x8ef3, 0x8f96,
+  0x94be, 0x99d5, 0x8962, 0x9170, 0x8cfb, 0x8cc3, 0x8be5, 0x99d9,
+  0x9240, 0x91fc, 0x8ba9, 0x8fa2, 0x99da, 0x99d8, 0x89c2, 0x91e4,
+  0x8eb6, 0x8e6a, 0x8945, 0x8a90, 0x8d86, 0x8e69, 0x99db, 0x99dc,
+  0x8b68, 0x8a65, 0x8d87, 0x8b67, 0x92dd, 0x8944, 0x93af, 0x96bc,
+  0x8d40, 0x9799, 0x9366, 0x8cfc, 0x8c4e, 0x99e5, 0x8be1, 0x9669,
+  0x94db, 0x99e4, 0x8adc, 0x99df, 0x99e0, 0x99e2, 0x99e3, 0x8b7a,
+  0x9081, 0x95ab, 0x99e1, 0x99dd, 0x8ce1, 0x99de, 0x9843, 0x95f0,
+  0x92e6, 0x8ce0, 0x8d90, 0x99e6, 0x93db, 0x99ea, 0x8efc, 0x8ef4,
+  0x99ed, 0x99eb, 0x96a1, 0x99e8, 0x99f1, 0x99ec, 0x99ef, 0x8cc4,
+  0x96bd, 0x99f0, 0x99f2, 0x99f4, 0x8dee, 0x9861, 0x99e9, 0x99e7,
+  0x99f3, 0x99ee, 0x99f6, 0x9a42, 0x99f8, 0x99fc, 0x9a40, 0x99f9,
+  0x9a5d, 0x8de7, 0x8a50, 0x99f7, 0x9a44, 0x88f4, 0x9a43, 0x88a3,
+  0x9569, 0x9a41, 0x99fa, 0x99f5, 0x99fb, 0x8dc6, 0x9a45, 0x88f5,
+  0x9a4e, 0x9a46, 0x9a47, 0x8fa3, 0x9689, 0x9a4c, 0x9a4b, 0x934e,
+  0x9a4d, 0x9a4a, 0x8953, 0x8db4, 0x904f, 0x9a48, 0x9382, 0x9a49,
+  0x88a0, 0x9a53, 0x9742, 0x8fa5, 0x9a59, 0x9a58, 0x9a4f, 0x91c1,
+  0x9a50, 0x91ed, 0x9a55, 0x8fa4, 0x9a52, 0x96e2, 0x8c5b, 0x9a56,
+  0x9a57, 0x9a54, 0x9a5a, 0x9a51, 0x9a60, 0x9a65, 0x9a61, 0x9a5c,
+  0x9a66, 0x9150, 0x9a68, 0x8d41, 0x9a5e, 0x929d, 0x9a62, 0x9a5b,
+  0x8aab, 0x8aec, 0x8a85, 0x9a63, 0x9a5f, 0x8c96, 0x9a69, 0x9a67,
+  0x9172, 0x8b69, 0x8baa, 0x9a64, 0x8bf2, 0x8963, 0x9a6d, 0x9a6b,
+  0x9aa5, 0x9a70, 0x9a6a, 0x9a6e, 0x9a6c, 0x8e6b, 0x9a6f, 0x9a72,
+  0x9a77, 0x9a75, 0x9a74, 0x9251, 0x89c3, 0x9a71, 0x9a73, 0x8fa6,
+  0x8952, 0x9a76, 0x89dc, 0x9a82, 0x8ffa, 0x9a7d, 0x9a7b, 0x9a7c,
+  0x9a7e, 0x895c, 0x9158, 0x9a78, 0x9a79, 0x8a9a, 0x9a81, 0x8aed,
+  0x9a84, 0x9a80, 0x9a83, 0x95ac, 0x93d3, 0x94b6, 0x9a86, 0x9a85,
+  0x8a64, 0x9a87, 0x9a8a, 0x9a89, 0x9a88, 0x9458, 0x9a8b, 0x9a8c,
+  0x9a8e, 0x9a8d, 0x9a90, 0x9a93, 0x9a91, 0x9a8f, 0x9a92, 0x9a94,
+  0x9a95, 0x9a96, 0x9a97, 0x9a98, 0x9964, 0x8efa, 0x8e6c, 0x89f1,
+  0x88f6, 0x9263, 0x9a99, 0x8da2, 0x88cd, 0x907d, 0x9a9a, 0x8cc5,
+  0x8d91, 0x9a9c, 0x9a9b, 0x95de, 0x9a9d, 0x9a9f, 0x9a9e, 0x9aa0,
+  0x9aa1, 0x8c97, 0x8980, 0x9aa2, 0x9aa4, 0x9aa3, 0x9aa6, 0x9379,
+  0x9aa7, 0x88b3, 0x8ddd, 0x8c5c, 0x926e, 0x9aa8, 0x9aa9, 0x9aab,
+  0x9aac, 0x8de2, 0x8bcf, 0x9656, 0x9aaa, 0x9aad, 0x8dbf, 0x8d42,
+  0x9ab1, 0x8da3, 0x9252, 0x9aae, 0x92d8, 0x9ab2, 0x9082, 0x9ab0,
+  0x9ab3, 0x8c5e, 0x9ab4, 0x9ab5, 0x8d43, 0x8a5f, 0x9ab7, 0x9ab8,
+  0x9ab9, 0x9ab6, 0x9aaf, 0x9aba, 0x9abb, 0x9684, 0x8fe9, 0x9abd,
+  0x9abe, 0x9abc, 0x9ac0, 0x9457, 0x88e6, 0x9575, 0x9ac1, 0x8ffb,
+  0x8eb7, 0x947c, 0x8aee, 0x8de9, 0x9678, 0x93b0, 0x8c98, 0x91cd,
+  0x9abf, 0x9ac2, 0x91c2, 0x9ac3, 0x9ac4, 0x9ac6, 0x92e7, 0x8aac,
+  0xea9f, 0x8981, 0x95f1, 0x8fea, 0x9367, 0x8de4, 0x9acc, 0x95bb,
+  0x97db, 0x89f2, 0x9ac8, 0x9159, 0x9acb, 0x9383, 0x9368, 0x9384,
+  0x94b7, 0x92cb, 0x8dc7, 0x9ac7, 0x8996, 0x9355, 0x9ac9, 0x9ac5,
+  0x906f, 0x9acd, 0x8f6d, 0x8bab, 0x9ace, 0x95e6, 0x919d, 0x92c4,
+  0x9ad0, 0x966e, 0x9ad1, 0x9ad6, 0x95ad, 0x9ad5, 0x9acf, 0x9ad2,
+  0x9ad4, 0x8da4, 0x95c7, 0x9ad7, 0x9264, 0x89f3, 0x8feb, 0x9ad9,
+  0x9ad8, 0x8d88, 0x9ada, 0x9adc, 0x9adb, 0x9ade, 0x9ad3, 0x9ae0,
+  0x9adf, 0x9add, 0x8e6d, 0x9070, 0x9173, 0x9ae1, 0x90ba, 0x88eb,
+  0x9484, 0x92d9, 0x9ae3, 0x9ae2, 0x9ae4, 0x9ae5, 0x9ae6, 0x9ae7,
+  0x95cf, 0x9ae8, 0x89c4, 0x9ae9, 0x975b, 0x8a4f, 0x99c7, 0x8f67,
+  0x91bd, 0x9aea, 0x96e9, 0x96b2, 0x9aec, 0x91e5, 0x9356, 0x91be,
+  0x9576, 0x9aed, 0x9aee, 0x899b, 0x8eb8, 0x9aef, 0x88ce, 0x9af0,
+  0x9af1, 0x8982, 0x8aef, 0x93de, 0x95f2, 0x9af5, 0x9174, 0x9af4,
+  0x8c5f, 0x967a, 0x9af3, 0x9385, 0x9af7, 0x9af6, 0x9af9, 0x9af8,
+  0x899c, 0x9afa, 0x8fa7, 0x9afc, 0x9244, 0x9afb, 0x95b1, 0x8f97,
+  0x937a, 0x9b40, 0x8d44, 0x9b41, 0x9440, 0x94dc, 0x96cf, 0x9444,
+  0x9b4a, 0x8b57, 0x9764, 0x96ad, 0x9baa, 0x9b42, 0x9b45, 0x91c3,
+  0x9657, 0x9369, 0x9b46, 0x9685, 0x8dc8, 0x8fa8, 0x9b47, 0x8e6f,
+  0x8e6e, 0x88b7, 0x8cc6, 0x90a9, 0x88cf, 0x9b4b, 0x9b4c, 0x9b49,
+  0x8957, 0x8aad, 0x9b48, 0x96c3, 0x9550, 0x88a6, 0x88f7, 0x8e70,
+  0x88d0, 0x88a1, 0x9b51, 0x9b4f, 0x96ba, 0x9b52, 0x9b50, 0x9b4e,
+  0x9050, 0x9b4d, 0x95d8, 0x8ce2, 0x9b56, 0x9b57, 0x8fa9, 0x9b53,
+  0x984b, 0x946b, 0x9b55, 0x8da5, 0x9b58, 0x9577, 0x9b59, 0x9b54,
+  0x96b9, 0x947d, 0x9b5a, 0x9551, 0x9b5b, 0x9b5f, 0x9b5c, 0x89c5,
+  0x9b5e, 0x8eb9, 0x9b5d, 0x8c99, 0x9b6b, 0x9b64, 0x9b61, 0x9284,
+  0x9b60, 0x9b62, 0x9b63, 0x9b65, 0x9b66, 0x8af0, 0x9b68, 0x9b67,
+  0x9b69, 0x8fec, 0x9b6c, 0x92da, 0x8964, 0x9b6a, 0x9b6d, 0x9b6e,
+  0x9b71, 0x9b6f, 0x9b70, 0x8e71, 0x9b72, 0x8d45, 0x9b73, 0x8e9a,
+  0x91b6, 0x9b74, 0x9b75, 0x8e79, 0x8d46, 0x96d0, 0x8b47, 0x8cc7,
+  0x9b76, 0x8a77, 0x9b77, 0x91b7, 0x9b78, 0x9ba1, 0x9b79, 0x9b7a,
+  0x9b7b, 0x9b7d, 0x9b7e, 0x9b80, 0x91ee, 0x8946, 0x8ee7, 0x88c0,
+  0x9176, 0x8aae, 0x8eb3, 0x8d47, 0x9386, 0x8f40, 0x8aaf, 0x9288,
+  0x92e8, 0x88b6, 0x8b58, 0x95f3, 0x8ec0, 0x8b71, 0x90e9, 0x8eba,
+  0x9747, 0x9b81, 0x8b7b, 0x8dc9, 0x8a51, 0x8983, 0x8faa, 0x89c6,
+  0x9b82, 0x9765, 0x8f68, 0x8ee2, 0x9b83, 0x8af1, 0x93d0, 0x96a7,
+  0x9b84, 0x9b85, 0x9578, 0x9b87, 0x8aa6, 0x8bf5, 0x9b86, 0x8ab0,
+  0x9051, 0x9b8b, 0x8e40, 0x89c7, 0x9b8a, 0x9b88, 0x9b8c, 0x9b89,
+  0x944a, 0x9ecb, 0x9052, 0x9b8d, 0x97be, 0x9b8e, 0x9b90, 0x929e,
+  0x9b8f, 0x90a1, 0x8e9b, 0x91ce, 0x8ef5, 0x9595, 0x90ea, 0x8ecb,
+  0x9b91, 0x8fab, 0x9b92, 0x9b93, 0x88d1, 0x91b8, 0x9071, 0x9b94,
+  0x93b1, 0x8fac, 0x8fad, 0x9b95, 0x90eb, 0x8fae, 0x9b96, 0x9b97,
+  0x96de, 0x9b98, 0x8bc4, 0x8f41, 0x9b99, 0x9b9a, 0x8eda, 0x904b,
+  0x93f2, 0x9073, 0x94f6, 0x9441, 0x8bc7, 0x9b9b, 0x8b8f, 0x9b9c,
+  0x8bfc, 0x93cd, 0x89ae, 0x8e72, 0x9b9d, 0x9ba0, 0x9b9f, 0x8bfb,
+  0x9b9e, 0x9357, 0x91ae, 0x936a, 0x8ec6, 0x9177, 0x979a, 0x9ba2,
+  0x9ba3, 0x93d4, 0x8e52, 0x9ba5, 0x9ba6, 0x9ba7, 0x8af2, 0x9ba8,
+  0x9ba9, 0x89aa, 0x915a, 0x8ae2, 0x9bab, 0x96a6, 0x91d0, 0x8a78,
+  0x9bad, 0x9baf, 0x8add, 0x9bac, 0x9bae, 0x9bb1, 0x9bb0, 0x9bb2,
+  0x9bb3, 0x93bb, 0x8bac, 0x89e3, 0x9bb4, 0x9bb9, 0x9bb7, 0x95f5,
+  0x95f4, 0x9387, 0x9bb6, 0x8f73, 0x9bb5, 0x9092, 0x9bba, 0x8de8,
+  0x9bc0, 0x9bc1, 0x9bbb, 0x8a52, 0x9bbc, 0x9bc5, 0x9bc4, 0x9bc3,
+  0x9bbf, 0x9bbe, 0x9bc2, 0x95f6, 0x9bc9, 0x9bc6, 0x9bc8, 0x9792,
+  0x9bc7, 0x9bbd, 0x9093, 0x9bca, 0x8db5, 0x9bcb, 0x9bcc, 0x9bcf,
+  0x9bce, 0x9bcd, 0x9388, 0x9bb8, 0x9bd5, 0x9bd1, 0x9bd0, 0x9bd2,
+  0x9bd3, 0x9bd6, 0x97e4, 0x9bd7, 0x9bd4, 0x9bd8, 0x8ade, 0x9bd9,
+  0x9bdb, 0x9bda, 0x9bdc, 0x9bdd, 0x90ec, 0x8f42, 0x8f84, 0x9183,
+  0x8d48, 0x8db6, 0x8d49, 0x8b90, 0x9bde, 0x8db7, 0x8cc8, 0x9bdf,
+  0x96a4, 0x9462, 0x9be0, 0x8d4a, 0x8aaa, 0x9246, 0x8bd0, 0x8e73,
+  0x957a, 0x94bf, 0x9be1, 0x8af3, 0x9be4, 0x929f, 0x9be3, 0x9be2,
+  0x9be5, 0x92e9, 0x9083, 0x8e74, 0x90c8, 0x91d1, 0x8b41, 0x92a0,
+  0x9be6, 0x9be7, 0x8fed, 0x9658, 0x9bea, 0x9be9, 0x9be8, 0x959d,
+  0x9bf1, 0x9679, 0x9beb, 0x9bed, 0x968b, 0x9bec, 0x9bee, 0x94a6,
+  0x9bef, 0x95bc, 0x9bf0, 0x8ab1, 0x95bd, 0x944e, 0x9bf2, 0x9bf3,
+  0x8d4b, 0x8ab2, 0x9bf4, 0x8cb6, 0x9763, 0x9748, 0x8af4, 0x9bf6,
+  0x92a1, 0x8d4c, 0x8faf, 0x94dd, 0x8fb0, 0x8f98, 0x92ea, 0x95f7,
+  0x9358, 0x8d4d, 0x957b, 0x9bf7, 0x9378, 0x8dc0, 0x8cc9, 0x92eb,
+  0x88c1, 0x8f8e, 0x8d4e, 0x9766, 0x9bf8, 0x9bf9, 0x9470, 0x9bfa,
+  0x97f5, 0x984c, 0x9bfc, 0x9bfb, 0x8a66, 0x9c40, 0x9c43, 0x9c44,
+  0x9c42, 0x955f, 0x8fb1, 0x9c46, 0x9c45, 0x9c41, 0x9c47, 0x9c48,
+  0x9c49, 0x9c4c, 0x9c4a, 0x9c4b, 0x9c4d, 0x8984, 0x92ec, 0x9c4e,
+  0x8c9a, 0x89f4, 0x9455, 0x9c4f, 0x93f9, 0x95d9, 0x9c50, 0x984d,
+  0x9c51, 0x95be, 0x9c54, 0x989f, 0x98af, 0x8eae, 0x93f3, 0x9c55,
+  0x8b7c, 0x92a2, 0x88f8, 0x9c56, 0x95a4, 0x8d4f, 0x926f, 0x92ed,
+  0x96ed, 0x8cb7, 0x8cca, 0x9c57, 0x9c58, 0x9c5e, 0x8ee3, 0x92a3,
+  0x8bad, 0x9c59, 0x954a, 0x9265, 0x9c5a, 0x9c5b, 0x8bae, 0x9c5c,
+  0x9c5d, 0x9c5f, 0x9396, 0x9c60, 0x9c61, 0x9c62, 0x9c53, 0x9c52,
+  0x9c63, 0x8c60, 0x9546, 0x8dca, 0x9556, 0x92a4, 0x956a, 0x9c64,
+  0x8fb2, 0x8965, 0x9c65, 0x9c66, 0x96f0, 0x94de, 0x9c69, 0x899d,
+  0x90aa, 0x9c68, 0x9c67, 0x8c61, 0x91d2, 0x9c6d, 0x9c6b, 0x9c6a,
+  0x97a5, 0x8ce3, 0x8f99, 0x9c6c, 0x936b, 0x8f5d, 0x93be, 0x9c70,
+  0x9c6f, 0x9c6e, 0x9c71, 0x8ce4, 0x9c72, 0x959c, 0x8f7a, 0x9c73,
+  0x94f7, 0x93bf, 0x92a5, 0x934f, 0x9c74, 0x8b4a, 0x9053, 0x954b,
+  0x8af5, 0x9445, 0x9c75, 0x8e75, 0x9659, 0x965a, 0x899e, 0x9c7a,
+  0x9289, 0x9c77, 0x89f5, 0x9cab, 0x9c79, 0x944f, 0x9c78, 0x9c76,
+  0x8d9a, 0x9c7c, 0x9c83, 0x9c89, 0x9c81, 0x937b, 0x9c86, 0x957c,
+  0x9c80, 0x9c85, 0x97e5, 0x8e76, 0x91d3, 0x9c7d, 0x8b7d, 0x9c88,
+  0x90ab, 0x8985, 0x9c82, 0x89f6, 0x9c87, 0x8baf, 0x9c84, 0x9c8a,
+  0x9c8c, 0x9c96, 0x9c94, 0x9c91, 0x9c90, 0x97f6, 0x9c92, 0x8bb0,
+  0x8d50, 0x8f9a, 0x9c99, 0x9c8b, 0x9c8f, 0x9c7e, 0x89f8, 0x9c93,
+  0x9c95, 0x9270, 0x8da6, 0x89b6, 0x9c8d, 0x9c98, 0x9c97, 0x8bb1,
+  0x91a7, 0x8a86, 0x8c62, 0x9c8e, 0x9c9a, 0x9c9d, 0x9c9f, 0x8ebb,
+  0x9ca5, 0x92ee, 0x9c9b, 0x9ca3, 0x89f7, 0x9ca1, 0x9ca2, 0x9c9e,
+  0x9ca0, 0x8ce5, 0x9749, 0x8ab3, 0x8978, 0x9ca4, 0x9459, 0x88ab,
+  0x94df, 0x9c7b, 0x9caa, 0x9cae, 0x96e3, 0x9ca7, 0x9389, 0x9cac,
+  0x8fee, 0x9cad, 0x93d5, 0x9866, 0x9ca9, 0x9caf, 0x8d9b, 0x90c9,
+  0x88d2, 0x9ca8, 0x9ca6, 0x9179, 0x9c9c, 0x8e53, 0x91c4, 0x9cbb,
+  0x917a, 0x9cb6, 0x9cb3, 0x9cb4, 0x8ee4, 0x9cb7, 0x9cba, 0x9cb5,
+  0x8f44, 0x9cb8, 0x9cb2, 0x96fa, 0x96f9, 0x9cbc, 0x9cbd, 0x88d3,
+  0x9cb1, 0x8bf0, 0x88a4, 0x8ab4, 0x9cb9, 0x9cc1, 0x9cc0, 0x9cc5,
+  0x9cc6, 0x9cc4, 0x9cc7, 0x9cbf, 0x9cc3, 0x9cc8, 0x9cc9, 0x9cbe,
+  0x8e9c, 0x9cc2, 0x91d4, 0x8d51, 0x9cb0, 0x9054, 0x9cd6, 0x95e7,
+  0x9ccc, 0x9ccd, 0x9cce, 0x9cd5, 0x9cd4, 0x969d, 0x8ab5, 0x9cd2,
+  0x8c64, 0x8a53, 0x9ccf, 0x97b6, 0x9cd1, 0x88d4, 0x9cd3, 0x9cca,
+  0x9cd0, 0x9cd7, 0x8c63, 0x9ccb, 0x977c, 0x974a, 0x9cda, 0x9cde,
+  0x919e, 0x97f7, 0x9cdf, 0x9cdc, 0x9cd9, 0x9cd8, 0x9cdd, 0x95ae,
+  0x93b2, 0x8c65, 0x9ce0, 0x9cdb, 0x9ce1, 0x8c9b, 0x89af, 0x9ce9,
+  0x8ab6, 0x9ce7, 0x9ce8, 0x8da7, 0x9ce6, 0x9ce4, 0x9ce3, 0x9cea,
+  0x9ce2, 0x9cec, 0x89f9, 0x9cee, 0x9ced, 0x92a6, 0x9cf1, 0x9cef,
+  0x9ce5, 0x8c9c, 0x9cf0, 0x9cf4, 0x9cf3, 0x9cf5, 0x9cf2, 0x9cf6,
+  0x9cf7, 0x9cf8, 0x95e8, 0x9cfa, 0x9cf9, 0x8f5e, 0x90ac, 0x89e4,
+  0x89fa, 0x9cfb, 0x88bd, 0x90ca, 0x9cfc, 0xe6c1, 0x9d40, 0x8c81,
+  0x9d41, 0x90ed, 0x9d42, 0x9d43, 0x8b59, 0x9d44, 0x9d45, 0x9d46,
+  0x91d5, 0x8ccb, 0x96df, 0x965b, 0x8f8a, 0x9d47, 0x90ee, 0xe7bb,
+  0x94e0, 0x8ee8, 0x8dcb, 0x9d48, 0x91c5, 0x95a5, 0x91ef, 0x9d4b,
+  0x9d49, 0x9d4c, 0x9d4a, 0x9d4d, 0x95af, 0x88b5, 0x957d, 0x94e1,
+  0x9d4e, 0x9d51, 0x8fb3, 0x8b5a, 0x9d4f, 0x9d56, 0x8fb4, 0x9d50,
+  0x9463, 0x977d, 0x9d52, 0x9d53, 0x9d57, 0x938a, 0x9d54, 0x8d52,
+  0x90dc, 0x9d65, 0x94b2, 0x91f0, 0x94e2, 0x9dab, 0x95f8, 0x92ef,
+  0x9695, 0x9d5a, 0x899f, 0x928a, 0x9d63, 0x9253, 0x9d5d, 0x9d64,
+  0x9d5f, 0x9d66, 0x9d62, 0x9d61, 0x948f, 0x9d5b, 0x89fb, 0x9d59,
+  0x8b91, 0x91f1, 0x9d55, 0x9d58, 0x8d53, 0x90d9, 0x8fb5, 0x9d60,
+  0x9471, 0x8b92, 0x8a67, 0x8a87, 0x9040, 0x9d68, 0x9d6d, 0x9d69,
+  0x8c9d, 0x9d6e, 0x8e41, 0x8d89, 0x8f45, 0x9d5c, 0x8e9d, 0x9d6b,
+  0x8e77, 0x9d6c, 0x88c2, 0x9d67, 0x92a7, 0x8b93, 0x8bb2, 0x9d6a,
+  0x88a5, 0x8dc1, 0x9055, 0x92f0, 0x94d2, 0x9d70, 0x917d, 0x91a8,
+  0x8e4a, 0x9d71, 0x9d73, 0x9d6f, 0x95df, 0x92bb, 0x917b, 0x95f9,
+  0x8ecc, 0x9d80, 0x9d7e, 0x9098, 0x8c9e, 0x9d78, 0x8fb7, 0x93e6,
+  0x9450, 0x9d76, 0x917c, 0x8ef6, 0x9d7b, 0x8fb6, 0x9d75, 0x9d7a,
+  0x9472, 0x9d74, 0x8c40, 0x8a7c, 0x9d7c, 0x97a9, 0x8dcc, 0x9254,
+  0x9d79, 0x90da, 0x8d54, 0x9084, 0x8986, 0x915b, 0x9d77, 0x8b64,
+  0x8c66, 0x92cd, 0x9d7d, 0x917e, 0x9d81, 0x9d83, 0x91b5, 0x9d89,
+  0x9d84, 0x9d86, 0x9560, 0x92f1, 0x9d87, 0x974b, 0x9767, 0x8ab7,
+  0x88ac, 0x9d85, 0x9d82, 0x8af6, 0x8987, 0x9d88, 0x9768, 0x9d8c,
+  0x91b9, 0x9d93, 0x9d8d, 0x9d8a, 0x9d91, 0x9d72, 0x9d8e, 0x9d92,
+  0x94c0, 0x938b, 0x9d8b, 0x9d8f, 0x8c67, 0x8def, 0x90db, 0x9d97,
+  0x9345, 0x9d94, 0x9680, 0x9d95, 0x9d96, 0x96cc, 0x90a0, 0x8c82,
+  0x9d9d, 0x8e54, 0x9d9a, 0x9d99, 0x9451, 0x93b3, 0x9350, 0x9d9b,
+  0x9d9c, 0x958f, 0x9464, 0x8e42, 0x90ef, 0x966f, 0x8a68, 0x9da3,
+  0x9d9e, 0x9769, 0x9da5, 0x9da1, 0x9da2, 0x9180, 0x9da0, 0x9d5e,
+  0x9da4, 0x9d9f, 0x9da9, 0x9daa, 0x9346, 0x9dac, 0x8e43, 0x9da7,
+  0x8b5b, 0x9dad, 0x9da6, 0x9db1, 0x9db0, 0x9daf, 0x9db2, 0x9db4,
+  0x8fef, 0x9db3, 0x9db7, 0x9db5, 0x9db6, 0x9d90, 0x9db9, 0x9db8,
+  0x9d98, 0x9dba, 0x9dae, 0x8e78, 0x9dbb, 0x9dbc, 0x9dbe, 0x9dbd,
+  0x9dbf, 0x89fc, 0x8d55, 0x95fa, 0x90ad, 0x8ccc, 0x9dc1, 0x9dc4,
+  0x9571, 0x8b7e, 0x9dc3, 0x9dc2, 0x9473, 0x9dc5, 0x8bb3, 0x9dc7,
+  0x9dc6, 0x8ab8, 0x8e55, 0x93d6, 0x8c68, 0x9094, 0x9dc8, 0x90ae,
+  0x9347, 0x957e, 0x9dc9, 0x9dca, 0x9dcb, 0x95b6, 0x9b7c, 0x90c4,
+  0x956b, 0x8dd6, 0x94e3, 0x94c1, 0x936c, 0x97bf, 0x9dcd, 0x8ece,
+  0x9dce, 0x88b4, 0x8bd2, 0x90cb, 0x9580, 0x9dcf, 0x8e61, 0x9266,
+  0x8e7a, 0x9056, 0x9dd0, 0x95fb, 0x8997, 0x8e7b, 0x9dd3, 0x9dd1,
+  0x9dd4, 0x97b7, 0x9dd2, 0x90f9, 0x9dd5, 0x91b0, 0x9dd6, 0x8af8,
+  0x9dd8, 0x9dd7, 0x9dd9, 0x9dda, 0x8af9, 0x93fa, 0x9255, 0x8b8c,
+  0x8e7c, 0x9181, 0x8f7b, 0x88ae, 0x9ddb, 0x89a0, 0x9ddf, 0x8d56,
+  0x9dde, 0x8da9, 0x8fb8, 0x9ddd, 0x8fb9, 0x96be, 0x8da8, 0x88d5,
+  0x90cc, 0x9de4, 0x90af, 0x8966, 0x8f74, 0x9686, 0x8df0, 0x8fba,
+  0x90a5, 0x9de3, 0x9de1, 0x9de2, 0x928b, 0x9e45, 0x9de8, 0x8e9e,
+  0x8d57, 0x9de6, 0x9de7, 0x9057, 0x9de5, 0x8e4e, 0x9dea, 0x9de9,
+  0x9dee, 0x9def, 0x9deb, 0x8a41, 0x9dec, 0x9ded, 0x94d3, 0x9581,
+  0x8c69, 0x9df0, 0x90b0, 0x8fbb, 0x9271, 0x8bc5, 0x9df1, 0x9df5,
+  0x89c9, 0x9df2, 0x9df4, 0x9df3, 0x8f8b, 0x9267, 0x88c3, 0x9df6,
+  0x9df7, 0x92a8, 0x97ef, 0x8e62, 0x95e9, 0x965c, 0x9e41, 0x9df9,
+  0x9dfc, 0x9dfb, 0x9df8, 0x9e40, 0x93dc, 0x9dfa, 0x9e42, 0x8f8c,
+  0x9e43, 0x976a, 0x9498, 0x9e44, 0x9e46, 0x9e47, 0x9e48, 0x8bc8,
+  0x8967, 0x8d58, 0x9e49, 0x9e4a, 0x8f91, 0x9182, 0x99d6, 0x915d,
+  0x915c, 0x91d6, 0x8dc5, 0x98f0, 0x8c8e, 0x974c, 0x95fc, 0x959e,
+  0x9e4b, 0x8df1, 0x92bd, 0x9e4c, 0x984e, 0x965d, 0x92a9, 0x9e4d,
+  0x8afa, 0x9e4e, 0x9e4f, 0x96d8, 0x96a2, 0x9696, 0x967b, 0x8e44,
+  0x9e51, 0x8ee9, 0x9670, 0x9e53, 0x9e56, 0x9e55, 0x8af7, 0x8b80,
+  0x9e52, 0x9e54, 0x9e57, 0x9099, 0x979b, 0x88c7, 0x8dde, 0x91ba,
+  0x8edb, 0x8ff1, 0x9e5a, 0x936d, 0x9e58, 0x91a9, 0x9e59, 0x8ff0,
+  0x96db, 0x9e5b, 0x9e5c, 0x9788, 0x9e61, 0x8d59, 0x9474, 0x9e5e,
+  0x938c, 0x9ddc, 0x9de0, 0x8b6e, 0x9466, 0x9e60, 0x8fbc, 0x94c2,
+  0x9e66, 0x94f8, 0x9e5d, 0x9e63, 0x9e62, 0x90cd, 0x968d, 0x97d1,
+  0x9687, 0x89ca, 0x8e7d, 0x9867, 0x9e65, 0x9095, 0x9e64, 0x9e5f,
+  0x8ccd, 0x9e6b, 0x9e69, 0x89cb, 0x9e67, 0x9e6d, 0x9e73, 0x91c6,
+  0x95bf, 0x9e75, 0x9541, 0x9e74, 0x9490, 0x965e, 0x8ab9, 0x90f5,
+  0x8f5f, 0x92d1, 0x974d, 0x9e70, 0x9e6f, 0x9e71, 0x9e6e, 0x9e76,
+  0x9e6c, 0x9e6a, 0x9e72, 0x9e68, 0x928c, 0x96f6, 0x8ec4, 0x8df2,
+  0x8db8, 0x968f, 0x8a60, 0x92cc, 0x93c8, 0x8968, 0x90f0, 0x90b2,
+  0x8c49, 0x9e78, 0x8d5a, 0x8a9c, 0x9e7a, 0x8a94, 0x9e81, 0x9e7d,
+  0x90f1, 0x8a6a, 0x8daa, 0x8a69, 0x8dcd, 0x9e7b, 0x8c85, 0x8c6a,
+  0x938d, 0x9e79, 0x88c4, 0x9e7c, 0x9e7e, 0x8bcb, 0x8c4b, 0x8aba,
+  0x8b6a, 0x9e82, 0x8df7, 0x9691, 0x8e56, 0x9e83, 0x954f, 0x9e8f,
+  0x89b1, 0x9e84, 0x9e95, 0x9e85, 0x97c0, 0x9e8c, 0x947e, 0x9e94,
+  0x9e87, 0x88b2, 0x9e89, 0x8d5b, 0x9e8b, 0x9e8a, 0x9e86, 0x9e91,
+  0x8fbd, 0x9aeb, 0x8ce6, 0x979c, 0x9e88, 0x92f2, 0x8a42, 0x8dab,
+  0x9e80, 0x9e90, 0x8a81, 0x9e8e, 0x9e92, 0x938e, 0x8afc, 0x9eb0,
+  0x96c7, 0x9e97, 0x8afb, 0x9e9e, 0x965f, 0x9e9f, 0x9ea1, 0x9ea5,
+  0x9e99, 0x9249, 0x938f, 0x9ea9, 0x9e9c, 0x9ea6, 0x9ea0, 0x9058,
+  0x9eaa, 0x90b1, 0x9ea8, 0x8abb, 0x986f, 0x9e96, 0x9ea4, 0x88d6,
+  0x9e98, 0x96b8, 0x9e9d, 0x9041, 0x92c5, 0x9e93, 0x9ea3, 0x909a,
+  0x9ead, 0x8a91, 0x8c9f, 0x9eaf, 0x9e9a, 0x9eae, 0x9ea7, 0x9e9b,
+  0x9eab, 0x9eac, 0x9ebd, 0x93cc, 0x9ea2, 0x9eb9, 0x9ebb, 0x92d6,
+  0x976b, 0x9596, 0x9eb6, 0x91c8, 0x9ebc, 0x915e, 0x9eb3, 0x9ec0,
+  0x9ebf, 0x93ed, 0x9ebe, 0x93e8, 0x9ec2, 0x9eb5, 0x8bc6, 0x9eb8,
+  0x8f7c, 0x9480, 0x9eba, 0x8bc9, 0x9eb2, 0x9eb4, 0x9eb1, 0x984f,
+  0x8a79, 0x9eb7, 0x9ec1, 0x8a54, 0x8de5, 0x897c, 0x9ed2, 0x9850,
+  0x9ed5, 0x9059, 0x9ed4, 0x9ed3, 0x9ed0, 0x9ec4, 0x9ee1, 0x9ec3,
+  0x9ed6, 0x9ece, 0x9ec9, 0x9ec6, 0x9ec7, 0x9ecf, 0xeaa0, 0x9ecc,
+  0x8d5c, 0x92c6, 0x9184, 0x9eca, 0x9ec5, 0x9ec8, 0x976c, 0x968a,
+  0x9ecd, 0x9ed7, 0x9edf, 0x9ed8, 0x9ee5, 0x9ee3, 0x9ede, 0x9edd,
+  0x92ce, 0x9185, 0x9edb, 0x9ed9, 0x9ee0, 0x9ee6, 0x94f3, 0x9eec,
+  0x9ee7, 0x9eea, 0x9ee4, 0x9294, 0x9557, 0x9eda, 0x9ee2, 0x8fbe,
+  0x96cd, 0x9ef6, 0x9ee9, 0x8ca0, 0x89a1, 0x8a7e, 0x9ed1, 0x8fbf,
+  0x9eee, 0x9ef5, 0x8ef7, 0x8a92, 0x924d, 0x9eeb, 0x9ef0, 0x9ef4,
+  0x8bb4, 0x8b6b, 0x9ef2, 0x8b40, 0x93c9, 0x9ef1, 0x9ef3, 0x9eed,
+  0x9eef, 0x8a80, 0x9268, 0x9efa, 0x9ef8, 0x8ce7, 0x9ef7, 0x9f40,
+  0x9e77, 0x9ef9, 0x9efb, 0x9efc, 0x9f4b, 0x9f47, 0x9e8d, 0x9f46,
+  0x9f45, 0x9f42, 0x9ee8, 0x9f44, 0x9f43, 0x9f49, 0x9845, 0x9f4c,
+  0x8bf9, 0x9f48, 0x9f4a, 0x94a5, 0x9f4d, 0x9f51, 0x9f4e, 0x9793,
+  0x9f4f, 0x9edc, 0x9f52, 0x9f53, 0x8954, 0x9f55, 0x8c87, 0x8e9f,
+  0x8bd3, 0x89a2, 0x977e, 0x9f57, 0x9f56, 0x9f59, 0x8b5c, 0x8bd4,
+  0x8abc, 0x9f5c, 0x9f5b, 0x9f5d, 0x89cc, 0x9256, 0x9f5e, 0x8abd,
+  0x9f60, 0x9f5f, 0x9f61, 0x9f62, 0x9f63, 0x8e7e, 0x90b3, 0x8d9f,
+  0x9590, 0x95e0, 0x9863, 0x8e95, 0x8dce, 0x97f0, 0x9f64, 0x9f65,
+  0x8e80, 0x9f66, 0x9f67, 0x9f69, 0x9f68, 0x9677, 0x8f7d, 0x8eea,
+  0x8e63, 0x9f6a, 0x9f6c, 0x9042, 0x9f6b, 0x9f6d, 0x9f6e, 0x9f6f,
+  0x9f70, 0x9f71, 0x9f73, 0x9f72, 0x9f74, 0x89a3, 0x9269, 0x9f75,
+  0x8e45, 0x8a6b, 0x9f76, 0x9361, 0x9aca, 0x8b42, 0x9f77, 0x9f78,
+  0x95ea, 0x9688, 0x93c5, 0x9f79, 0x94e4, 0x94f9, 0x96d1, 0x9f7a,
+  0x9f7c, 0x9f7b, 0x9f7e, 0x9f7d, 0x9f81, 0x8e81, 0x96af, 0x9f82,
+  0x9f83, 0x8b43, 0x9f84, 0x9f86, 0x9f85, 0x9085, 0x9558, 0x8969,
+  0x94c3, 0x92f3, 0x8f60, 0x8b81, 0x94c4, 0x8eac, 0x9f88, 0x8abe,
+  0x8998, 0x93f0, 0x9f87, 0x8d5d, 0x9272, 0x9f89, 0x9f91, 0x9f8a,
+  0x91bf, 0x8b82, 0x9f92, 0x8c88, 0x8b44, 0x9f90, 0x9f8e, 0x9f8b,
+  0x9780, 0x92be, 0x93d7, 0x9f8c, 0x9f94, 0x9f93, 0x8c42, 0x89ab,
+  0x8db9, 0x9f8d, 0x9f8f, 0x9676, 0x91f2, 0x9697, 0x9f9c, 0x9f9d,
+  0x89cd, 0x95a6, 0x96fb, 0x9f9f, 0x8ea1, 0x8fc0, 0x9f98, 0x9f9e,
+  0x8988, 0x8bb5, 0x9f95, 0x9f9a, 0x90f2, 0x9491, 0x94e5, 0x9f97,
+  0x9640, 0x9f99, 0x9fa2, 0x9fa0, 0x9f9b, 0x9641, 0x9467, 0x8b83,
+  0x9344, 0x928d, 0x9fa3, 0x9fa1, 0x91d7, 0x9f96, 0x896a, 0x976d,
+  0x9fae, 0x9fad, 0x90f4, 0x9faa, 0x978c, 0x93b4, 0x9fa4, 0x92c3,
+  0x896b, 0x8d5e, 0x9fa7, 0x8f46, 0x9fac, 0x9fab, 0x9fa6, 0x9fa9,
+  0x8a88, 0x9fa8, 0x9468, 0x97ac, 0x8ff2, 0x90f3, 0x9fb4, 0x9fb2,
+  0x956c, 0x9faf, 0x9fb1, 0x8959, 0x8d5f, 0x9851, 0x8a5c, 0x9582,
+  0x9781, 0x8a43, 0x905a, 0x9fb3, 0x9fb8, 0x8fc1, 0x974f, 0x9fb5,
+  0x9fb0, 0x9fb6, 0x97dc, 0x9393, 0x93c0, 0x8a55, 0x8974, 0x9fbc,
+  0x9fbf, 0x97c1, 0x9784, 0x9fc6, 0x9fc0, 0x9fbd, 0x97d2, 0x9fc3,
+  0x8f69, 0x9fc5, 0x9fca, 0x9391, 0x9fc8, 0x9fc2, 0x9257, 0x9fc9,
+  0x9fbe, 0x9fc4, 0x9fcb, 0x88fa, 0x9fc1, 0x9fcc, 0x905b, 0x8f7e,
+  0x95a3, 0x8dac, 0x9fb9, 0x9fc7, 0x9359, 0x90b4, 0x8a89, 0x8dcf,
+  0x8fc2, 0x9fbb, 0x8f61, 0x8c6b, 0x9fba, 0x9fd0, 0x8f8d, 0x8cb8,
+  0x9fdf, 0x9fd9, 0x8b94, 0x936e, 0x9fd4, 0x9fdd, 0x88ad, 0x8951,
+  0x89b7, 0x9fd6, 0x91aa, 0x9fcd, 0x9fcf, 0x8d60, 0x9fe0, 0x9fdb,
+  0x9fd3, 0x9fda, 0x96a9, 0x9fd8, 0x9fdc, 0x8cce, 0x8fc3, 0x9258,
+  0x9fd2, 0x974e, 0x9fd5, 0x9fce, 0x9392, 0x9fd1, 0x9fd7, 0x9870,
+  0x8ebc, 0x969e, 0x9fe1, 0x94ac, 0x9fed, 0x8cb9, 0x8f80, 0x9fe3,
+  0x97ad, 0x8d61, 0x9ff0, 0x88ec, 0x9fee, 0x9fe2, 0x9fe8, 0x9fea,
+  0x976e, 0x9fe5, 0x934d, 0x9fe7, 0x9fef, 0x9fe9, 0x96c5, 0x9fe4,
+  0x8ea0, 0x9ffc, 0x8a8a, 0x9fe6, 0x9feb, 0x9fec, 0x91ea, 0x91d8,
+  0x9ff4, 0x9ffa, 0x9ff8, 0x9348, 0xe042, 0x9ff5, 0x9ff6, 0x9fde,
+  0x8b99, 0x9559, 0x8ebd, 0x8d97, 0x9852, 0x9ff2, 0xe041, 0x8989,
+  0x9186, 0x9499, 0x8abf, 0x97f8, 0x969f, 0x92d0, 0x9ff9, 0x9ffb,
+  0x9151, 0xe040, 0x9ff7, 0x9ff1, 0x8ac1, 0x8c89, 0xe04e, 0xe049,
+  0x90f6, 0x8a83, 0x8f81, 0xe052, 0xe04b, 0x92aa, 0xe048, 0x92d7,
+  0xe06b, 0xe045, 0xe044, 0xe04d, 0xe047, 0xe046, 0xe04c, 0x909f,
+  0xe043, 0xe04f, 0xe050, 0x8ac0, 0xe055, 0xe054, 0xe056, 0xe059,
+  0x9362, 0xe053, 0xe057, 0x8c83, 0x91f7, 0xe051, 0x945a, 0xe058,
+  0xe05d, 0xe05b, 0xe05e, 0xe061, 0xe05a, 0x8d8a, 0x9447, 0x9fb7,
+  0x9794, 0xe05c, 0xe060, 0x91f3, 0xe05f, 0xe04a, 0xe889, 0xe064,
+  0xe068, 0xe066, 0xe062, 0xe063, 0xe067, 0xe065, 0x956d, 0xe06d,
+  0xe06a, 0xe069, 0xe06c, 0x93d2, 0xe06e, 0x9295, 0x91eb, 0x90a3,
+  0xe06f, 0xe071, 0xe070, 0x9ff3, 0xe072, 0x93e5, 0xe073, 0x89ce,
+  0x9394, 0x8a44, 0x8b84, 0x8edc, 0x8dd0, 0x9846, 0x9086, 0x898a,
+  0xe075, 0xe074, 0xe078, 0x9259, 0xe07b, 0xe076, 0xe07a, 0xe079,
+  0x935f, 0x88d7, 0x97f3, 0xe07d, 0x8947, 0xe080, 0xe07e, 0xe07c,
+  0xe077, 0x9642, 0xe082, 0xe081, 0x898b, 0xe084, 0x95b0, 0xe083,
+  0x96b3, 0x8fc5, 0x9152, 0x8fc4, 0x97f9, 0xe08a, 0x90f7, 0xe086,
+  0xe08b, 0x898c, 0xe089, 0x9481, 0xe085, 0xe088, 0x8fc6, 0x94cf,
+  0xe08c, 0x8ecf, 0x90f8, 0xe08f, 0xe087, 0x8c46, 0xe08d, 0x976f,
+  0xe090, 0xeaa4, 0x8f6e, 0xe091, 0xe092, 0x944d, 0xe094, 0xe095,
+  0x9452, 0x9395, 0xe097, 0xe099, 0x97d3, 0xe096, 0xe098, 0x898d,
+  0xe093, 0x9a7a, 0xe09a, 0x9187, 0x8e57, 0xe09c, 0xe09b, 0x9043,
+  0x99d7, 0xe09d, 0xe09f, 0xe08e, 0xe09e, 0xe0a0, 0x949a, 0xe0a1,
+  0xe0a2, 0xe0a3, 0xe0a4, 0x92dc, 0xe0a6, 0xe0a5, 0xe0a7, 0xe0a8,
+  0x8edd, 0x9583, 0x96ea, 0xe0a9, 0xe0aa, 0x9175, 0x8ea2, 0xe0ab,
+  0xe0ac, 0xe0ad, 0x95d0, 0x94c5, 0xe0ae, 0x9476, 0x92ab, 0xe0af,
+  0x89e5, 0x8b8d, 0x96c4, 0x96b4, 0x89b2, 0x9853, 0x9671, 0x95a8,
+  0x90b5, 0xe0b0, 0x93c1, 0x8ca1, 0xe0b1, 0x8dd2, 0xe0b3, 0xe0b2,
+  0xe0b4, 0xe0b5, 0xe0b6, 0x8b5d, 0xe0b7, 0xe0b8, 0x8ca2, 0x94c6,
+  0xe0ba, 0x8ff3, 0xe0b9, 0x8bb6, 0xe0bb, 0xe0bd, 0xe0bc, 0xe0be,
+  0x8ccf, 0xe0bf, 0x8be7, 0x915f, 0x8d9d, 0xe0c1, 0xe0c2, 0xe0c0,
+  0x8eeb, 0x93c6, 0x8bb7, 0xe0c4, 0x924b, 0xe0c3, 0x9854, 0x9482,
+  0xe0c7, 0xe0c9, 0xe0c6, 0x96d2, 0xe0c8, 0xe0ca, 0x97c2, 0xe0ce,
+  0xe0cd, 0x9296, 0x944c, 0x8ca3, 0xe0cc, 0xe0cb, 0x9750, 0x9751,
+  0xe0cf, 0x898e, 0x8d96, 0x8e82, 0xe0d0, 0xe0d1, 0xe0d3, 0x8f62,
+  0xe0d5, 0xe0d4, 0xe0d6, 0x8a6c, 0xe0d8, 0xe0d7, 0xe0da, 0xe0d9,
+  0x8cba, 0x97a6, 0x8bca, 0x89a4, 0x8be8, 0x8adf, 0x97e6, 0xe0dc,
+  0xe0de, 0xe0df, 0x89cf, 0xe0db, 0x8e58, 0x92bf, 0xe0dd, 0xe0e2,
+  0x8eec, 0xe0e0, 0x8c5d, 0x94c7, 0xe0e1, 0xe0fc, 0xe0e7, 0x8cbb,
+  0x8b85, 0xe0e4, 0x979d, 0x97ae, 0x91f4, 0xe0e6, 0xe0e8, 0x97d4,
+  0x8bd5, 0x94fa, 0x9469, 0xe0e9, 0xe0eb, 0xe0ee, 0xe0ea, 0xe0ed,
+  0x8ce8, 0x896c, 0xe0ef, 0x9090, 0xe0ec, 0x97da, 0xe0f2, 0xeaa2,
+  0xe0f0, 0xe0f3, 0xe0e5, 0xe0f1, 0x8dba, 0xe0f4, 0xe0f5, 0x979e,
+  0xe0f6, 0xe0f7, 0xe0e3, 0xe0f8, 0x8ac2, 0x8ea3, 0xe0f9, 0xe0fa,
+  0xe0fb, 0x895a, 0xe140, 0x955a, 0xe141, 0x8aa2, 0xe142, 0xe143,
+  0xe144, 0xe146, 0xe147, 0xe145, 0x9572, 0xe149, 0xe148, 0xe14b,
+  0xe14a, 0xe14c, 0xe14d, 0xe14f, 0xe14e, 0x8d99, 0xe151, 0xe150,
+  0x8ac3, 0x9072, 0x935b, 0xe152, 0x90b6, 0x8e59, 0x8999, 0xe153,
+  0x9770, 0x95e1, 0xe154, 0x9363, 0x9752, 0x8d62, 0x905c, 0x926a,
+  0x99b2, 0x92ac, 0x89e6, 0xe155, 0xe156, 0xe15b, 0xe159, 0xe158,
+  0x9dc0, 0x8a45, 0xe157, 0x88d8, 0x94a8, 0x94c8, 0x97af, 0xe15c,
+  0xe15a, 0x927b, 0x90a4, 0x94a9, 0x954c, 0xe15e, 0x97aa, 0x8c6c,
+  0xe15f, 0xe15d, 0x94d4, 0xe160, 0xe161, 0x88d9, 0x8ff4, 0xe166,
+  0xe163, 0x93eb, 0xe162, 0x8b45, 0xe169, 0xe164, 0xe165, 0xe168,
+  0xe167, 0x9544, 0x9161, 0x9160, 0x8b5e, 0xe16a, 0xe16b, 0xe16c,
+  0xe16e, 0xe16d, 0x8975, 0xe176, 0x94e6, 0xe170, 0xe172, 0xe174,
+  0x905d, 0xe175, 0xe173, 0x8ebe, 0xe16f, 0xe171, 0x9561, 0x8fc7,
+  0xe178, 0xe177, 0xe179, 0x8ea4, 0x8dad, 0x9397, 0xe17a, 0x92c9,
+  0xe17c, 0x979f, 0xe17b, 0x9189, 0xe182, 0xe184, 0xe185, 0x9273,
+  0xe183, 0xe180, 0xe17d, 0xe17e, 0xe181, 0xe188, 0xe186, 0xe187,
+  0xe189, 0xe18b, 0xe18c, 0xe18d, 0xe18e, 0xe18a, 0xe190, 0xe18f,
+  0xe191, 0x97c3, 0xe194, 0xe192, 0xe193, 0x8ae0, 0x96fc, 0x95c8,
+  0xe196, 0xe195, 0xe197, 0xe198, 0xe19c, 0xe199, 0xe19a, 0xe19b,
+  0xe19d, 0xe19e, 0xe19f, 0xe1a0, 0xe1a1, 0x94ad, 0x936f, 0xe1a2,
+  0x9492, 0x9553, 0xe1a3, 0xe1a4, 0x9349, 0x8a46, 0x8d63, 0xe1a5,
+  0xe1a6, 0xe1a7, 0x8e48, 0xe1a9, 0xe1a8, 0xe1aa, 0xe1ab, 0x94e7,
+  0xe1ac, 0xe1ad, 0xea89, 0xe1ae, 0xe1af, 0xe1b0, 0x8e4d, 0xe1b1,
+  0x9475, 0x967e, 0x896d, 0x8976, 0xe1b2, 0xe1b4, 0xe1b3, 0x9390,
+  0x90b7, 0x9f58, 0xe1b5, 0x96bf, 0xe1b6, 0x8ac4, 0x94d5, 0xe1b7,
+  0xe1b8, 0xe1b9, 0x96da, 0x96d3, 0x92bc, 0x918a, 0xe1bb, 0x8f82,
+  0x8fc8, 0xe1be, 0xe1bd, 0xe1bc, 0x94fb, 0x8ac5, 0x8ca7, 0xe1c4,
+  0xe1c1, 0x905e, 0x96b0, 0xe1c0, 0xe1c2, 0xe1c3, 0xe1bf, 0xe1c5,
+  0xe1c6, 0x92ad, 0x8ae1, 0x9285, 0xe1c7, 0xe1c8, 0xe1cb, 0x9087,
+  0x93c2, 0xe1cc, 0x9672, 0xe1c9, 0xe1ca, 0xe1cf, 0xe1ce, 0xe1cd,
+  0xe1d1, 0xe1d0, 0xe1d2, 0xe1d4, 0xe1d3, 0x95cb, 0x8f75, 0x97c4,
+  0xe1d5, 0x93b5, 0xe1d6, 0xe1d7, 0xe1db, 0xe1d9, 0xe1da, 0xe1d8,
+  0xe1dc, 0xe1dd, 0xe1de, 0xe1df, 0x96b5, 0xe1e0, 0x96ee, 0xe1e1,
+  0x926d, 0x948a, 0x8be9, 0x925a, 0xe1e2, 0x8bb8, 0x90ce, 0xe1e3,
+  0x8dbb, 0xe1e4, 0xe1e5, 0x8ca4, 0x8dd3, 0xe1e7, 0x9375, 0x8dd4,
+  0x8b6d, 0x9643, 0x946a, 0x9376, 0x8d7b, 0xe1e9, 0x8fc9, 0x97b0,
+  0x8d64, 0x8ca5, 0x94a1, 0xe1eb, 0xe1ed, 0x8ce9, 0xe1ec, 0x92f4,
+  0xe1ef, 0x8a56, 0xe1ea, 0x94e8, 0x894f, 0x8dea, 0x9871, 0xe1ee,
+  0xe1f0, 0x95c9, 0x90d7, 0xe1f2, 0xe1f3, 0xe1f1, 0x8a6d, 0xe1f9,
+  0xe1f8, 0x8ea5, 0xe1fa, 0xe1f5, 0xe1fb, 0xe1f6, 0x94d6, 0xe1f4,
+  0xe1f7, 0xe241, 0xe240, 0x9681, 0xe1fc, 0x88e9, 0xe243, 0xe242,
+  0x8fca, 0xe244, 0x9162, 0xe246, 0xe245, 0xe247, 0xe1e6, 0xe1e8,
+  0xe249, 0xe248, 0x8ea6, 0x97e7, 0x8ed0, 0xe24a, 0x8c56, 0x8b5f,
+  0x8b46, 0x8e83, 0x9753, 0xe250, 0xe24f, 0x9163, 0xe24c, 0xe24e,
+  0x8f6a, 0x905f, 0xe24d, 0xe24b, 0x9449, 0x8fcb, 0x955b, 0x8dd5,
+  0x9398, 0xe251, 0xe252, 0xe268, 0x8bd6, 0x985c, 0x9154, 0xe253,
+  0x89d0, 0x92f5, 0x959f, 0xe254, 0x8b9a, 0xe255, 0xe257, 0xe258,
+  0x9448, 0xe259, 0xe25a, 0xe25b, 0x8bd7, 0x89d1, 0x93c3, 0x8f47,
+  0x8e84, 0xe25c, 0x8f48, 0x89c8, 0x9562, 0xe25d, 0x94e9, 0x9164,
+  0xe260, 0xe261, 0x9489, 0x9060, 0xe25e, 0x9281, 0xe25f, 0x8fcc,
+  0x88da, 0x8b48, 0xe262, 0x92f6, 0xe263, 0x90c5, 0x96ab, 0x9542,
+  0xe264, 0xe265, 0x9274, 0x97c5, 0xe267, 0xe266, 0x8eed, 0xe269,
+  0x88ee, 0xe26c, 0xe26a, 0x89d2, 0x8c6d, 0xe26b, 0x8d65, 0x8d92,
+  0x95e4, 0xe26d, 0x9673, 0xe26f, 0x90cf, 0x896e, 0x89b8, 0x88aa,
+  0xe26e, 0xe270, 0xe271, 0x8ff5, 0xe272, 0x8a6e, 0xe274, 0x8c8a,
+  0x8b86, 0xe275, 0x8bf3, 0xe276, 0x90fa, 0x93cb, 0x90de, 0x8df3,
+  0xe277, 0x9282, 0x918b, 0xe279, 0xe27b, 0xe278, 0xe27a, 0x8c41,
+  0xe27c, 0x8c45, 0x8b87, 0x9771, 0xe27e, 0xe280, 0x894d, 0xe283,
+  0x8a96, 0xe282, 0xe281, 0xe285, 0xe27d, 0xe286, 0x97a7, 0xe287,
+  0xe288, 0x9af2, 0xe28a, 0xe289, 0xe28b, 0xe28c, 0x97b3, 0xe28d,
+  0xe8ed, 0x8fcd, 0xe28e, 0xe28f, 0x8f76, 0x93b6, 0xe290, 0x9247,
+  0xe291, 0x925b, 0xe292, 0x8ba3, 0x995e, 0x927c, 0x8eb1, 0x8ac6,
+  0xe293, 0xe2a0, 0xe296, 0x8b88, 0xe295, 0xe2a2, 0xe294, 0x8fce,
+  0xe298, 0xe299, 0x934a, 0xe29a, 0x8a7d, 0x9079, 0x9584, 0xe29c,
+  0x91e6, 0xe297, 0xe29b, 0xe29d, 0x8df9, 0xe2a4, 0x954d, 0x94a4,
+  0x9399, 0x8bd8, 0xe2a3, 0xe2a1, 0x94b3, 0xe29e, 0x927d, 0x939b,
+  0x939a, 0x8df4, 0xe2b6, 0xe2a6, 0xe2a8, 0xe2ab, 0xe2ac, 0xe2a9,
+  0xe2aa, 0xe2a7, 0xe2a5, 0xe29f, 0x95cd, 0x89d3, 0xe2b3, 0xe2b0,
+  0xe2b5, 0xe2b4, 0x9493, 0x96a5, 0x8e5a, 0xe2ae, 0xe2b7, 0xe2b2,
+  0xe2b1, 0xe2ad, 0xe2af, 0x8ac7, 0x925c, 0x90fb, 0x94a0, 0xe2bc,
+  0x94a2, 0x90df, 0xe2b9, 0x94cd, 0xe2bd, 0x95d1, 0x927a, 0xe2b8,
+  0xe2ba, 0xe2bb, 0xe2be, 0x8ec2, 0x93c4, 0xe2c3, 0xe2c2, 0xe2bf,
+  0x9855, 0xe2c8, 0xe2cc, 0xe2c9, 0xe2c5, 0xe2c6, 0xe2cb, 0xe2c0,
+  0x99d3, 0xe2c7, 0xe2c1, 0xe2ca, 0xe2d0, 0x8ac8, 0xe2cd, 0xe2ce,
+  0xe2cf, 0xe2d2, 0xe2d1, 0x94f4, 0xe2d3, 0x97fa, 0x95eb, 0xe2d8,
+  0xe2d5, 0xe2d4, 0x90d0, 0xe2d7, 0xe2d9, 0xe2d6, 0xe2dd, 0xe2da,
+  0xe2db, 0xe2c4, 0xe2dc, 0xe2de, 0xe2df, 0x95c4, 0xe2e0, 0x96e0,
+  0x8bcc, 0x8c48, 0xe2e1, 0x95b2, 0x9088, 0x96ae, 0xe2e2, 0x97b1,
+  0x9494, 0x9165, 0x9453, 0x8f6c, 0x88be, 0xe2e7, 0xe2e5, 0xe2e3,
+  0x8a9f, 0x8fcf, 0xe2e8, 0xe2e6, 0xe2e4, 0xe2ec, 0xe2eb, 0xe2ea,
+  0xe2e9, 0xe2ed, 0xe2ee, 0x90b8, 0xe2ef, 0xe2f1, 0xe2f0, 0x8cd0,
+  0x9157, 0xe2f3, 0x939c, 0xe2f2, 0xe2f4, 0x95b3, 0x918c, 0x8d66,
+  0xe2f5, 0x97c6, 0xe2f7, 0xe2f8, 0xe2f9, 0xe2fa, 0x8e85, 0xe2fb,
+  0x8c6e, 0x8b8a, 0x8b49, 0xe340, 0x96f1, 0x8d67, 0xe2fc, 0xe343,
+  0x96e4, 0x945b, 0x9552, 0x8f83, 0xe342, 0x8ed1, 0x8d68, 0x8e86,
+  0x8b89, 0x95b4, 0xe341, 0x9166, 0x9661, 0x8df5, 0x8e87, 0x92db,
+  0xe346, 0x97dd, 0x8dd7, 0xe347, 0x9061, 0xe349, 0x8fd0, 0x8dae,
+  0xe348, 0x8f49, 0x8cbc, 0x9167, 0xe344, 0xe34a, 0xe345, 0x8c6f,
+  0xe34d, 0xe351, 0x8c8b, 0xe34c, 0xe355, 0x8d69, 0x978d, 0x88ba,
+  0xe352, 0x8b8b, 0xe34f, 0xe350, 0x939d, 0xe34e, 0xe34b, 0x8a47,
+  0x90e2, 0x8ca6, 0xe357, 0xe354, 0xe356, 0xe353, 0x8c70, 0x91b1,
+  0xe358, 0x918e, 0xe365, 0xe361, 0xe35b, 0xe35f, 0x8ef8, 0x88db,
+  0xe35a, 0xe362, 0xe366, 0x8d6a, 0x96d4, 0x92d4, 0xe35c, 0xe364,
+  0xe359, 0x925d, 0xe35e, 0x88bb, 0x96c8, 0xe35d, 0x8bd9, 0x94ea,
+  0x918d, 0x97ce, 0x8f8f, 0xe38e, 0xe367, 0x90fc, 0xe363, 0xe368,
+  0xe36a, 0x92f7, 0xe36d, 0xe369, 0x95d2, 0x8ac9, 0x96c9, 0x88dc,
+  0xe36c, 0x97fb, 0xe36b, 0x898f, 0x93ea, 0xe36e, 0xe375, 0xe36f,
+  0xe376, 0xe372, 0x949b, 0x8ec8, 0xe374, 0xe371, 0xe377, 0xe370,
+  0x8f63, 0x9644, 0x8f6b, 0xe373, 0xe380, 0xe37b, 0xe37e, 0xe37c,
+  0xe381, 0xe37a, 0xe360, 0x90d1, 0x94c9, 0xe37d, 0xe378, 0x9140,
+  0x8c71, 0x8f4a, 0x9044, 0x9155, 0xe384, 0xe386, 0xe387, 0xe383,
+  0xe385, 0xe379, 0xe382, 0xe38a, 0xe389, 0x969a, 0x8c4a, 0xe388,
+  0xe38c, 0xe38b, 0xe38f, 0xe391, 0x8e5b, 0xe38d, 0xe392, 0xe393,
+  0xe394, 0xe39a, 0x935a, 0xe396, 0xe395, 0xe397, 0xe398, 0xe399,
+  0xe39b, 0xe39c, 0x8aca, 0xe39d, 0xe39e, 0xe39f, 0xe3a0, 0xe3a1,
+  0xe3a2, 0xe3a3, 0xe3a4, 0xe3a6, 0xe3a5, 0xe3a7, 0xe3a8, 0xe3a9,
+  0xe3ac, 0xe3aa, 0xe3ab, 0x8ddf, 0x8c72, 0x9275, 0x94b1, 0x8f90,
+  0x946c, 0x94eb, 0xe3ad, 0x9ceb, 0xe3ae, 0xe3b0, 0x9785, 0xe3af,
+  0xe3b2, 0xe3b1, 0x9772, 0xe3b3, 0x94fc, 0xe3b4, 0xe3b7, 0xe3b6,
+  0xe3b5, 0xe3b8, 0x8c51, 0x9141, 0x8b60, 0xe3bc, 0xe3b9, 0xe3ba,
+  0xe3bd, 0xe3be, 0xe3bb, 0x8948, 0x89a5, 0xe3c0, 0xe3c1, 0xe3c2,
+  0x9782, 0x8f4b, 0xe3c4, 0xe3c3, 0x9089, 0xe3c5, 0xe3c6, 0xe3c7,
+  0x8ae3, 0x8acb, 0xe3c8, 0xe3c9, 0x967c, 0x9783, 0x9773, 0x9856,
+  0x8d6c, 0xe3cc, 0x8ed2, 0xe3cb, 0xe3cd, 0x8ea7, 0x91cf, 0xe3ce,
+  0x8d6b, 0x96d5, 0xe3cf, 0xe3d0, 0xe3d1, 0xe3d2, 0xe3d3, 0x8ea8,
+  0x96eb, 0xe3d5, 0x925e, 0xe3d4, 0xe3d7, 0xe3d6, 0xe3d8, 0x90b9,
+  0xe3d9, 0xe3da, 0x95b7, 0xe3db, 0x918f, 0xe3dc, 0xe3dd, 0x97fc,
+  0xe3e0, 0xe3df, 0xe3de, 0x92ae, 0xe3e1, 0x9045, 0xe3e2, 0xe3e3,
+  0x9857, 0xe3e4, 0xe3e5, 0xe3e7, 0xe3e6, 0x94a3, 0x93f7, 0x985d,
+  0x94a7, 0xe3e9, 0x8fd1, 0x9549, 0xe3ea, 0xe3e8, 0x8acc, 0x8cd2,
+  0x8e88, 0x94ec, 0x8ca8, 0x9662, 0xe3ed, 0xe3eb, 0x8d6d, 0x8d6e,
+  0x88e7, 0x8de6, 0x9478, 0x88dd, 0xe3f2, 0x925f, 0x9477, 0x91d9,
+  0xe3f4, 0xe3f0, 0xe3f3, 0xe3ee, 0xe3f1, 0x9645, 0x8cd3, 0x88fb,
+  0xe3ef, 0xe3f6, 0xe3f7, 0x93b7, 0x8bb9, 0xe445, 0x945c, 0x8e89,
+  0x8bba, 0x90c6, 0x9865, 0x96ac, 0xe3f5, 0x90d2, 0x8b72, 0xe3f8,
+  0xe3fa, 0xe3f9, 0xe3fb, 0x9245, 0x945d, 0x92af, 0xe442, 0xe441,
+  0xe3fc, 0x9074, 0x9585, 0xe444, 0xe443, 0x8d6f, 0x9872, 0xe454,
+  0xe448, 0xe449, 0x8eee, 0xe447, 0x8d98, 0xe446, 0xe44a, 0x92b0,
+  0x95a0, 0x9142, 0x91da, 0xe44e, 0xe44f, 0xe44b, 0xe44c, 0xe44d,
+  0x8d70, 0xe455, 0xe451, 0x9586, 0x968c, 0x9547, 0xe450, 0xe453,
+  0xe452, 0x9663, 0xe456, 0xe457, 0x9156, 0xe458, 0xe45a, 0xe45e,
+  0xe45b, 0xe459, 0x945e, 0xe45c, 0xe45d, 0x89b0, 0xe464, 0xe45f,
+  0xe460, 0xe461, 0x919f, 0xe463, 0xe462, 0xe465, 0xe466, 0xe467,
+  0x9062, 0x89e7, 0xe468, 0x97d5, 0x8ea9, 0x8f4c, 0x8e8a, 0x9276,
+  0xe469, 0xe46a, 0x8950, 0xe46b, 0xe46c, 0xe46d, 0xe46e, 0xe46f,
+  0x8bbb, 0x9da8, 0xe470, 0x90e3, 0xe471, 0x8ec9, 0xe472, 0x98ae,
+  0xe473, 0x95dc, 0x8ada, 0x9143, 0x8f77, 0x9591, 0x8f4d, 0xe474,
+  0x8d71, 0xe475, 0x94ca, 0xe484, 0xe477, 0x91c7, 0x9495, 0x8cbd,
+  0xe476, 0x9144, 0xe478, 0x92f8, 0xe47a, 0xe479, 0xe47c, 0xe47b,
+  0xe47d, 0xe480, 0xe47e, 0x8acd, 0xe481, 0xe482, 0xe483, 0x8daf,
+  0x97c7, 0xe485, 0x9046, 0x8990, 0xe486, 0xe487, 0xe488, 0x88f0,
+  0xe489, 0xe48a, 0x9587, 0x8ec5, 0xe48c, 0x8a48, 0x88b0, 0xe48b,
+  0xe48e, 0x946d, 0x9063, 0x89d4, 0x9646, 0x8c7c, 0x8bda, 0xe48d,
+  0x89e8, 0x8aa1, 0x8991, 0xe492, 0x97e8, 0x91db, 0x9563, 0xe49e,
+  0x89d5, 0xe49c, 0xe49a, 0xe491, 0xe48f, 0xe490, 0x8ee1, 0x8bea,
+  0x9297, 0x93cf, 0x8970, 0xe494, 0xe493, 0xe499, 0xe495, 0xe498,
+  0x96ce, 0xe497, 0x89d6, 0x8a9d, 0xe49b, 0xe49d, 0x8c73, 0xe4a1,
+  0xe4aa, 0xe4ab, 0x88a9, 0xe4b2, 0x88ef, 0xe4a9, 0xe4a8, 0xe4a3,
+  0xe4a2, 0xe4a0, 0xe49f, 0x9283, 0x91f9, 0xe4a5, 0xe4a4, 0xe4a7,
+  0x9190, 0x8c74, 0x8960, 0xe4a6, 0x8d72, 0x9191, 0xe4b8, 0xe4b9,
+  0x89d7, 0x89ac, 0xe4b6, 0xe4ac, 0xe4b4, 0xe4bb, 0xe4b5, 0xe4b3,
+  0xe496, 0xe4b1, 0xe4ad, 0x8ace, 0xe4af, 0xe4ba, 0xe4b0, 0xe4bc,
+  0xe4ae, 0x949c, 0x9789, 0xe4b7, 0xe4cd, 0xe4c5, 0x909b, 0x8b65,
+  0x8bdb, 0xe4c0, 0x89d9, 0x8fd2, 0xe4c3, 0x8dd8, 0x9370, 0xe4c8,
+  0x95ec, 0xe4bf, 0x89d8, 0x8cd4, 0x9548, 0xe4c9, 0xe4bd, 0xe4c6,
+  0xe4d0, 0xe4c1, 0xe4c2, 0x93b8, 0xe4c7, 0xe4c4, 0x9647, 0xe4ca,
+  0x88de, 0xe4be, 0xe4cc, 0xe4cb, 0x948b, 0xe4d2, 0xe4dd, 0x8a9e,
+  0xe4e0, 0xe4ce, 0xe4d3, 0x978e, 0xe4dc, 0x9774, 0x97a8, 0x9298,
+  0x8a8b, 0x9592, 0xe4e2, 0x939f, 0x88af, 0xe4db, 0xe4d7, 0x9192,
+  0xe4d1, 0xe4d9, 0xe4de, 0x944b, 0x88a8, 0xe4d6, 0xe4df, 0x9598,
+  0xe4da, 0xe4d5, 0x8fd3, 0x8f4e, 0x8eaa, 0x96d6, 0x9566, 0xe4e5,
+  0xe4ee, 0xe4d8, 0x8a97, 0x8ff6, 0xe4e3, 0xe4e8, 0x9193, 0xe4e4,
+  0xe4eb, 0x927e, 0xe4ec, 0x9775, 0xe4e1, 0x8a57, 0xe4e7, 0xe4ea,
+  0x96aa, 0xe4ed, 0xe4e6, 0xe4e9, 0x9648, 0x9840, 0xe4f1, 0xe4f8,
+  0xe4f0, 0x8ec1, 0xe4cf, 0x95cc, 0x96a0, 0xe4f7, 0xe4f6, 0xe4f2,
+  0xe4f3, 0x8955, 0xe4f5, 0xe4ef, 0x92d3, 0xe4f4, 0x88fc, 0x91a0,
+  0x95c1, 0xe4f9, 0xe540, 0x94d7, 0xe4fc, 0x8fd4, 0x8ec7, 0xe542,
+  0x8bbc, 0xe543, 0x9599, 0xe4fb, 0xe4d4, 0xe4fa, 0x986e, 0x93a0,
+  0x9593, 0xe54a, 0xe550, 0xe551, 0xe544, 0x9496, 0xe54e, 0xe546,
+  0xe548, 0xe552, 0xe547, 0xe54b, 0x8992, 0x93e3, 0xe54c, 0xe54f,
+  0xe545, 0x9145, 0xe549, 0x8e46, 0x9064, 0x8c4f, 0x96f2, 0x96f7,
+  0x8f92, 0xe556, 0xe554, 0x986d, 0xe553, 0x9795, 0xe555, 0xe557,
+  0xe558, 0xe55b, 0xe559, 0x93a1, 0xe55a, 0x94cb, 0xe54d, 0x8f93,
+  0xe55c, 0xe561, 0x9194, 0xe560, 0xe541, 0xe562, 0x9168, 0xe55d,
+  0xe55f, 0xe55e, 0x9f50, 0x9f41, 0xe564, 0xe563, 0x9796, 0xe1ba,
+  0xe565, 0xe566, 0xe567, 0x8cd5, 0x8b73, 0xe569, 0x997c, 0x8b95,
+  0x97b8, 0x8bf1, 0xe56a, 0xe56b, 0x928e, 0xe56c, 0x93f8, 0x88b8,
+  0x89e1, 0xe571, 0xe572, 0xe56d, 0x8e5c, 0xe56e, 0x9461, 0xe56f,
+  0xe570, 0xe57a, 0xe574, 0xe577, 0xe573, 0xe575, 0xe576, 0x8ed6,
+  0xe578, 0x9260, 0x8c75, 0x8a61, 0xe57b, 0x8a5e, 0xe581, 0xe57c,
+  0xe580, 0x94b8, 0xe57d, 0xe57e, 0x9567, 0x94d8, 0xe582, 0x91fb,
+  0xe58c, 0xe588, 0x89e9, 0xe586, 0x9649, 0xe587, 0xe584, 0xe585,
+  0xe58a, 0xe58d, 0xe58b, 0xe589, 0xe583, 0x9277, 0xe594, 0x96a8,
+  0xe592, 0xe593, 0xe58e, 0xe590, 0xe591, 0xe58f, 0x90e4, 0x9858,
+  0xe598, 0xe599, 0xe59f, 0x9049, 0xe59b, 0xe59e, 0xe596, 0xe595,
+  0xe5a0, 0x89da, 0xe59c, 0xe5a1, 0xe59d, 0xe59a, 0x92b1, 0xe597,
+  0x9488, 0xe5a5, 0x975a, 0xe5a4, 0xe5a3, 0xe5ac, 0xe5a6, 0xe5ae,
+  0x9786, 0xe5b1, 0xe5a8, 0xe5a9, 0xe5ad, 0xe5b0, 0xe5af, 0xe5a7,
+  0xe5aa, 0xe5bb, 0xe5b4, 0xe5b2, 0xe5b3, 0xe5b8, 0xe5b9, 0x8a49,
+  0x8b61, 0xe5b7, 0xe5a2, 0xe5b6, 0xe5ba, 0xe5b5, 0xe5bc, 0xe5be,
+  0xe5bd, 0xe5c0, 0xe5bf, 0xe579, 0xe5c4, 0xe5c1, 0xe5c2, 0xe5c3,
+  0xe5c5, 0x8c8c, 0xe5c7, 0xe5c6, 0x8f4f, 0x8d73, 0x9fa5, 0xe5c8,
+  0x8f70, 0x8a58, 0xe5c9, 0x8971, 0x8fd5, 0xe5ca, 0x8d74, 0xe5cb,
+  0x88df, 0x955c, 0xe5cc, 0x908a, 0xe5d3, 0xe5d0, 0x928f, 0xe5d1,
+  0xe5ce, 0x8bdc, 0xe5cd, 0xe5d4, 0x8c55, 0x91dc, 0xe5da, 0xe5d6,
+  0x91b3, 0xe5d5, 0xe5d8, 0xe5cf, 0xe5d9, 0xe5db, 0x94ed, 0xe5d7,
+  0xe5dc, 0xe5de, 0x8cd1, 0xe5d2, 0x88bf, 0xe5dd, 0x8dd9, 0x97f4,
+  0xe5df, 0xe5e0, 0x9195, 0x97a0, 0xe5e1, 0x9754, 0xe5e2, 0xe5e3,
+  0x95e2, 0xe5e4, 0x8dbe, 0x97a1, 0xe5e9, 0xe5ea, 0x8fd6, 0xe5e8,
+  0x9787, 0xe5e5, 0xe5e7, 0x90bb, 0x909e, 0xe5e6, 0xe5eb, 0x95a1,
+  0xe5ed, 0xe5ec, 0x8a8c, 0x964a, 0xe5ee, 0xe5fa, 0xe5f0, 0xe5f1,
+  0xe5f2, 0xe5f3, 0xe5f7, 0xe5f8, 0xe5f6, 0xe5f4, 0xe5ef, 0xe5f5,
+  0xe5f9, 0xe8b5, 0x89a6, 0xe5fc, 0x8bdd, 0xe5fb, 0xe641, 0xe640,
+  0xe643, 0xe642, 0xe644, 0x8f50, 0xe645, 0xe646, 0xe647, 0x90bc,
+  0x9776, 0xe648, 0x95a2, 0x9465, 0xe649, 0xe64a, 0x8ca9, 0x8b4b,
+  0xe64b, 0x8e8b, 0x9460, 0xe64c, 0x8a6f, 0xe64d, 0xe64f, 0x9797,
+  0xe64e, 0x9065, 0xe650, 0xe651, 0xe652, 0x8acf, 0xe653, 0xe654,
+  0xe655, 0xe656, 0x8a70, 0xe657, 0xe658, 0xe659, 0x89f0, 0x9047,
+  0xe65a, 0xe65b, 0xe65c, 0x8cbe, 0x92f9, 0xe65d, 0x8c76, 0x9075,
+  0xe660, 0x93a2, 0xe65f, 0x8c50, 0xe65e, 0x91f5, 0x8b4c, 0xe661,
+  0xe662, 0x8fd7, 0x8c8d, 0xe663, 0x964b, 0x90dd, 0x8b96, 0x96f3,
+  0x9169, 0xe664, 0x9066, 0x9290, 0x8fd8, 0xe665, 0xe668, 0xe669,
+  0x8dbc, 0x91c0, 0xe667, 0x8fd9, 0x955d, 0xe666, 0x8e8c, 0x8972,
+  0xe66d, 0x8c77, 0x8e8e, 0x8e8d, 0x986c, 0xe66c, 0xe66b, 0x9146,
+  0x8b6c, 0x9862, 0x8a59, 0x8fda, 0xe66a, 0xe66f, 0xe670, 0xe66e,
+  0x8cd6, 0x975f, 0x8e8f, 0x9446, 0xe673, 0x90be, 0x9261, 0x9755,
+  0xe676, 0x8cea, 0x90bd, 0xe672, 0xe677, 0x8ceb, 0xe674, 0xe675,
+  0xe671, 0x90e0, 0x93c7, 0x924e, 0x89db, 0x94ee, 0x8b62, 0x92b2,
+  0xe67a, 0xe678, 0x926b, 0x90bf, 0x8ad0, 0xe679, 0x907a, 0x97c8,
+  0x985f, 0xe67b, 0xe687, 0x92b3, 0xe686, 0xe683, 0xe68b, 0xe684,
+  0xe680, 0x92fa, 0xe67e, 0xe67c, 0x9740, 0x8e90, 0xe681, 0xe67d,
+  0xe685, 0x8f94, 0x8cbf, 0x91f8, 0x9664, 0x8979, 0x88e0, 0x93a3,
+  0xe689, 0xe688, 0x93e4, 0xe68d, 0xe682, 0xe68c, 0xe68e, 0x8caa,
+  0xe68a, 0x8d75, 0x8ed3, 0xe68f, 0x9777, 0xe692, 0xe695, 0xe693,
+  0x9554, 0xe690, 0x8bde, 0xe694, 0xe696, 0xe69a, 0xe697, 0xe699,
+  0xe698, 0xe69b, 0x8eaf, 0xe69d, 0xe69c, 0x9588, 0xe69f, 0x8c78,
+  0xe69e, 0xe6a0, 0xe6a1, 0x8b63, 0xe3bf, 0x8ff7, 0xe6a2, 0x8cec,
+  0xe6a3, 0xe6a4, 0x8e5d, 0x9dcc, 0xe6a5, 0xe6a6, 0x8f51, 0xe6a7,
+  0xe6a8, 0xe6a9, 0xe6aa, 0xe6ab, 0x924a, 0xe6ac, 0xe6ae, 0xe6ad,
+  0x93a4, 0xe6af, 0x964c, 0xe6b0, 0xe6b1, 0xe6b2, 0xe6b3, 0x93d8,
+  0x8fdb, 0xe6b4, 0x8d8b, 0x98ac, 0xe6b5, 0xe6b6, 0x955e, 0xe6b7,
+  0xe6bf, 0xe6b8, 0xe6ba, 0xe6b9, 0xe6bb, 0x9665, 0xe6bc, 0xe6bd,
+  0xe6be, 0xe6c0, 0x8a4c, 0x92e5, 0x9589, 0x8de0, 0x8d76, 0x956e,
+  0x89dd, 0x94cc, 0xe6c3, 0x8ad1, 0x90d3, 0xe6c2, 0xe6c7, 0x9299,
+  0x96e1, 0xe6c5, 0xe6c6, 0x8b4d, 0xe6c8, 0x9483, 0x91dd, 0x94ef,
+  0x935c, 0xe6c4, 0x9666, 0x89ea, 0xe6ca, 0x9847, 0x92c0, 0x9864,
+  0x8e91, 0xe6c9, 0x91af, 0xe6da, 0x9147, 0x93f6, 0x956f, 0xe6cd,
+  0x8e5e, 0x8e92, 0x8fdc, 0x9485, 0x8cab, 0xe6cc, 0xe6cb, 0x958a,
+  0x8ebf, 0x9371, 0xe6cf, 0xe6d0, 0x8d77, 0xe6ce, 0xe6d1, 0xe6d2,
+  0xe6d4, 0x91a1, 0xe6d3, 0x8ae4, 0xe6d6, 0xe6d5, 0xe6d7, 0xe6d9,
+  0xe6db, 0xe6dc, 0x90d4, 0x8ecd, 0xe6dd, 0x8a71, 0xe6de, 0x9196,
+  0xe6df, 0xe6e0, 0x958b, 0x8b4e, 0xe6e1, 0x92b4, 0x897a, 0xe6e2,
+  0x8eef, 0x9096, 0x91ab, 0xe6e5, 0xe6e4, 0xe6e3, 0xe6eb, 0xe6e9,
+  0xe6e6, 0xe6e8, 0xe6e7, 0xe6ea, 0x8b97, 0xe6ee, 0x90d5, 0xe6ef,
+  0x8cd7, 0xe6ec, 0xe6ed, 0x9848, 0x92b5, 0x9148, 0xe6f0, 0xe6f3,
+  0xe6f1, 0xe6f2, 0x9778, 0x93a5, 0xe6f6, 0xe6f4, 0xe6f5, 0xe6f7,
+  0xe748, 0xe6fa, 0xe6fb, 0xe6f9, 0xe6f8, 0x92fb, 0xe740, 0xe744,
+  0xe741, 0xe6fc, 0xe742, 0xe743, 0xe74a, 0xe745, 0x90d6, 0xe747,
+  0xe749, 0xe746, 0xe74c, 0x8f52, 0xe74b, 0xe74d, 0xe74e, 0xe751,
+  0xe750, 0xe74f, 0xe753, 0xe752, 0x96f4, 0xe755, 0xe754, 0xe756,
+  0xe757, 0xe759, 0xe758, 0x9067, 0xe75a, 0x8beb, 0xe75b, 0xe75d,
+  0xe75e, 0xe75f, 0xe75c, 0xe760, 0x8ed4, 0xe761, 0x8b4f, 0x8c52,
+  0x8cac, 0xe762, 0x93ee, 0x935d, 0xe763, 0xe766, 0x8eb2, 0xe765,
+  0xe764, 0x8c79, 0xe767, 0x8a72, 0xe769, 0x8dda, 0xe768, 0xe771,
+  0xe76b, 0xe76d, 0x95e3, 0xe76a, 0xe76c, 0xe770, 0xe76e, 0x8b50,
+  0xe76f, 0xe772, 0x9479, 0x97d6, 0x8f53, 0xe773, 0x9741, 0xe775,
+  0xe774, 0xe778, 0x9760, 0xe777, 0x8a8d, 0xe776, 0xe77b, 0xe77a,
+  0xe779, 0x9351, 0xe77c, 0xe77d, 0xe77e, 0x8d8c, 0x8c44, 0xe780,
+  0xe781, 0xe782, 0x9068, 0xe783, 0x8eab, 0xe784, 0xe785, 0x999f,
+  0x999e, 0xe786, 0xe390, 0xe787, 0x9243, 0x904a, 0x945f, 0xe788,
+  0x95d3, 0x92d2, 0x8d9e, 0x9248, 0x8949, 0x9698, 0x9076, 0x8c7d,
+  0x8bdf, 0x95d4, 0xe789, 0xe78b, 0xe78a, 0x89de, 0x93f4, 0xe78c,
+  0x9497, 0x9352, 0xe78d, 0x8f71, 0xe78f, 0x96c0, 0xe79e, 0xe791,
+  0xe792, 0x92c7, 0x91de, 0x9197, 0x93a6, 0xe790, 0x8b74, 0xe799,
+  0xe796, 0xe7a3, 0x93a7, 0x9280, 0xe793, 0x92fc, 0x9372, 0xe794,
+  0xe798, 0x9080, 0x9487, 0x92ca, 0x90c0, 0xe797, 0x91ac, 0x91a2,
+  0xe795, 0x88a7, 0x9841, 0xe79a, 0x91df, 0x8f54, 0x9069, 0xe79c,
+  0xe79b, 0x88ed, 0xe79d, 0x954e, 0xe7a5, 0x93d9, 0x908b, 0x9278,
+  0x8bf6, 0xe7a4, 0x9756, 0x895e, 0x95d5, 0x89df, 0xe79f, 0xe7a0,
+  0xe7a1, 0xe7a2, 0x93b9, 0x9242, 0x88e1, 0xe7a6, 0xe7a7, 0xeaa1,
+  0x91bb, 0xe7a8, 0x8993, 0x916b, 0x8cad, 0x9779, 0xe7a9, 0x934b,
+  0x9198, 0x8ed5, 0xe7aa, 0xe7ad, 0x8f85, 0xe7ab, 0x914a, 0x9149,
+  0x88e2, 0x97c9, 0xe7af, 0x94f0, 0xe7b1, 0xe7b0, 0xe7ae, 0xe284,
+  0x8ad2, 0xe78e, 0xe7b3, 0xe7b2, 0xe7b4, 0x9757, 0x93df, 0x964d,
+  0xe7b5, 0x8ed7, 0xe7b6, 0xe7b7, 0xe7b8, 0x9340, 0x88e8, 0x8d78,
+  0x9859, 0xe7bc, 0x8c53, 0xe7b9, 0xe7ba, 0x9594, 0x8a73, 0x9758,
+  0x8bbd, 0x9373, 0xe7bd, 0xe7be, 0xe7bf, 0x9341, 0xe7c1, 0xe7c0,
+  0x93d1, 0xe7c2, 0x8f55, 0x8ede, 0x947a, 0x9291, 0x8ef0, 0x908c,
+  0xe7c3, 0xe7c4, 0x907c, 0xe7c5, 0xe7c6, 0xe7c7, 0x978f, 0x8f56,
+  0xe7c9, 0xe7c8, 0x8d79, 0x8d93, 0x8e5f, 0xe7cc, 0x8f86, 0xe7cb,
+  0xe7ca, 0x91e7, 0x8ced, 0x90c1, 0x94ae, 0x8f58, 0xe7cd, 0x8fdd,
+  0xe7d0, 0xe7ce, 0xe7cf, 0xe7d2, 0xe7d1, 0x8ff8, 0xe7d3, 0xe7d4,
+  0xe7d5, 0x94ce, 0x8dd1, 0x8edf, 0xe7d6, 0xe7d7, 0x97a2, 0x8f64,
+  0x96ec, 0x97ca, 0xe7d8, 0x8be0, 0xe7d9, 0x9342, 0xe7dc, 0x8a98,
+  0x906a, 0xe7da, 0xe7db, 0x92de, 0x9674, 0x8bfa, 0xe7de, 0xe7df,
+  0xe7dd, 0xe7e1, 0x93dd, 0x8a62, 0xe7e5, 0xe7e2, 0xe7e4, 0xe7e0,
+  0xe86e, 0xe7e3, 0x97e9, 0x8cd8, 0xe7ed, 0x9353, 0xe7e8, 0xe7eb,
+  0xe7e9, 0xe7ee, 0xe7ef, 0xe7e7, 0xe7f4, 0x8994, 0xe7e6, 0x94ab,
+  0xe7ea, 0x8fde, 0x8d7a, 0x9667, 0x8be2, 0x8f65, 0x93ba, 0x914c,
+  0xe7f2, 0xe7ec, 0xe7f1, 0x96c1, 0x92b6, 0xe7f3, 0xe7f0, 0x914b,
+  0xe7f7, 0xe7f6, 0xe7f5, 0x964e, 0x8f9b, 0xe7f8, 0x95dd, 0x8973,
+  0x9565, 0x9292, 0x8b98, 0xe7fa, 0x8d7c, 0x8e4b, 0xe7f9, 0x908d,
+  0x908e, 0xe840, 0xe842, 0x8ff9, 0xe841, 0xe843, 0x8bd1, 0x9564,
+  0x8ee0, 0x9842, 0xe7fc, 0x8df6, 0x985e, 0xe845, 0xe844, 0xe846,
+  0xe7fb, 0x93e7, 0x9374, 0x92d5, 0xe84b, 0x9262, 0xe847, 0xe848,
+  0x8c4c, 0xe84a, 0x8cae, 0xe849, 0x8fdf, 0x8a99, 0xe84f, 0x8dbd,
+  0x9199, 0x92c8, 0x8a5a, 0xe84d, 0xe84e, 0x92c1, 0xe84c, 0xe850,
+  0xe856, 0xe859, 0xe858, 0x934c, 0xe851, 0xe852, 0xe855, 0xe857,
+  0x8bbe, 0xe85a, 0xe854, 0xe853, 0xe85e, 0xe85f, 0xe860, 0xe85d,
+  0xe85c, 0x8fe0, 0x93a8, 0xe85b, 0xe864, 0xe862, 0xe863, 0xe861,
+  0x91f6, 0xe865, 0xe866, 0xe868, 0x8ad3, 0xe867, 0x96f8, 0xe873,
+  0xe869, 0xe86c, 0xe86a, 0xe86b, 0xe86d, 0xe86f, 0xe870, 0xe871,
+  0xe874, 0xe872, 0xe875, 0xe877, 0xe876, 0x92b7, 0x96e5, 0xe878,
+  0x914d, 0xe879, 0x95c2, 0xe87a, 0x8a4a, 0x895b, 0x8ad5, 0x8ad4,
+  0xe87b, 0xe87c, 0xe87d, 0xe87e, 0xe880, 0x8ad6, 0x8a74, 0x8d7d,
+  0x94b4, 0xe882, 0xe881, 0xe883, 0x897b, 0xe886, 0xe885, 0xe884,
+  0xe887, 0xe88a, 0x88c5, 0xe888, 0xe88c, 0xe88b, 0xe88e, 0xe88d,
+  0xe88f, 0x93ac, 0xe890, 0xe891, 0xe893, 0xe892, 0x958c, 0xe894,
+  0xe895, 0x8de3, 0xe896, 0xe897, 0x9668, 0x916a, 0x88a2, 0x91c9,
+  0xe898, 0x958d, 0xe89b, 0xe899, 0x8d7e, 0xe89a, 0x8cc0, 0x95c3,
+  0xe89d, 0xe89f, 0xe89e, 0xe8a0, 0x8940, 0x9077, 0x8f9c, 0x8ad7,
+  0xe8a1, 0x9486, 0xe8a3, 0x8941, 0xe8a2, 0x92c2, 0x97cb, 0x93a9,
+  0xe89c, 0x97a4, 0x8caf, 0x977a, 0x8bf7, 0x97b2, 0x8c47, 0x91e0,
+  0xe440, 0xe8a4, 0x8a4b, 0x908f, 0x8a75, 0xe8a6, 0xe8a7, 0xe8a5,
+  0x8c84, 0x8ddb, 0x8fe1, 0x8942, 0x97d7, 0xe8a9, 0xe7ac, 0xe8a8,
+  0xe8ac, 0xe8aa, 0xe8ab, 0xe8ad, 0xe8ae, 0x97ea, 0xe8af, 0xe8b0,
+  0x90c7, 0x94b9, 0x909d, 0x8ae5, 0x9759, 0x89eb, 0x8f57, 0x8cd9,
+  0xe8b3, 0xe8b2, 0x8e93, 0xe8b4, 0xe8b1, 0x8e47, 0xe8b8, 0xe5ab,
+  0x99d4, 0x9097, 0xe8b6, 0x97a3, 0x93ef, 0x894a, 0x90e1, 0x8eb4,
+  0x95b5, 0x895f, 0x97eb, 0x978b, 0xe8b9, 0x9364, 0x8ef9, 0xe8ba,
+  0xe8bb, 0x906b, 0xe8bc, 0x97ec, 0xe8b7, 0xe8be, 0xe8c0, 0xe8bf,
+  0xe8bd, 0xe8c1, 0xe8c2, 0x919a, 0x89e0, 0xe8c3, 0x96b6, 0xe8c4,
+  0xe8c5, 0x9849, 0x9e50, 0xe8c6, 0xe8c7, 0xe8c8, 0xe8cc, 0xe8c9,
+  0xe8ca, 0xe8cb, 0xe8cd, 0x90c2, 0x96f5, 0x90c3, 0xe8ce, 0x94f1,
+  0xe8cf, 0xea72, 0x96ca, 0xe8d0, 0xe8d1, 0xe8d2, 0x8a76, 0xe8d4,
+  0x9078, 0xe8d5, 0x8c43, 0xe8d6, 0xe8da, 0xe8d8, 0xe8d9, 0x8a93,
+  0xe8d7, 0xe8db, 0xe8dc, 0x88c6, 0xe8dd, 0xe8de, 0x8fe2, 0xe8df,
+  0x8b66, 0xe8e2, 0xe8e1, 0xe8e0, 0xe691, 0x95da, 0xe8e3, 0xe8e4,
+  0xe8e5, 0xe8e6, 0xe8e7, 0xe8e8, 0x8ad8, 0xe8e9, 0xe8ea, 0x9442,
+  0xe8ec, 0x89b9, 0xe8ef, 0xe8ee, 0x8943, 0x8bbf, 0x95c5, 0x92b8,
+  0x8da0, 0x8d80, 0x8f87, 0x907b, 0xe8f1, 0xe8f0, 0x9761, 0x8ae6,
+  0x94d0, 0x93da, 0x909c, 0x97cc, 0x8c7a, 0xe8f4, 0xe8f3, 0x966a,
+  0x93aa, 0x896f, 0xe8f5, 0xe8f2, 0x9570, 0x978a, 0xe8f6, 0xe8f7,
+  0xe8f9, 0x91e8, 0x8a7a, 0x8a7b, 0xe8f8, 0x8ae7, 0x8cb0, 0x8ae8,
+  0x935e, 0x97de, 0x8cda, 0xe8fa, 0xe8fb, 0xe8fc, 0xe940, 0xe942,
+  0xe941, 0x9597, 0xe943, 0xe944, 0xe945, 0xe946, 0xe948, 0xe947,
+  0xe949, 0x94f2, 0xe3ca, 0x9048, 0x8b51, 0xe94a, 0xe94b, 0x99aa,
+  0x9f5a, 0x94d1, 0x88f9, 0x88b9, 0x8e94, 0x964f, 0x8ffc, 0xe94c,
+  0x96dd, 0xe94d, 0x977b, 0x8961, 0x8e60, 0xe94e, 0x89ec, 0xe94f,
+  0xe950, 0xe952, 0xe953, 0xe955, 0xe951, 0xe954, 0x8ad9, 0xe956,
+  0xe957, 0xe958, 0xe959, 0xe95a, 0xe95c, 0xe95b, 0xe95e, 0xe961,
+  0xe95d, 0xe95f, 0xe960, 0xe962, 0x8bc0, 0x8ef1, 0xe963, 0xe964,
+  0x8d81, 0xe965, 0x8a5d, 0x946e, 0xe966, 0xe967, 0x9279, 0x93e9,
+  0xe968, 0x949d, 0x91ca, 0x8977, 0x8bec, 0x8bed, 0x9293, 0xe96d,
+  0x8bee, 0x89ed, 0xe96c, 0xe96a, 0xe96b, 0xe969, 0xe977, 0xe96e,
+  0xe96f, 0xe970, 0xe971, 0xe973, 0xe972, 0x8f78, 0xe974, 0xe976,
+  0x8b52, 0xe975, 0x919b, 0x8cb1, 0xe978, 0x91cb, 0xe979, 0x93ab,
+  0xe97a, 0xe980, 0xe97d, 0xe97c, 0xe97e, 0xe97b, 0xe982, 0xe981,
+  0xe984, 0x8bc1, 0xe983, 0xe985, 0xe986, 0xe988, 0xe987, 0xe989,
+  0xe98b, 0xe98a, 0x8d9c, 0xe98c, 0xe98d, 0x8a5b, 0xe98e, 0xe98f,
+  0x9091, 0xe990, 0xe991, 0xe992, 0xe993, 0x8d82, 0xe994, 0xe995,
+  0xe996, 0xe997, 0xe998, 0x94af, 0xe99a, 0x9545, 0xe99b, 0xe999,
+  0xe99d, 0xe99c, 0xe99e, 0xe99f, 0xe9a0, 0xe9a1, 0xe9a2, 0xe9a3,
+  0xe9a4, 0xe9a5, 0xe9a6, 0xe9a7, 0xe9a8, 0xe9a9, 0xe9aa, 0xe9ab,
+  0xe9ac, 0x9f54, 0xe9ad, 0xe2f6, 0x8b53, 0x8a40, 0x8db0, 0xe9af,
+  0xe9ae, 0x96a3, 0xe9b1, 0xe9b2, 0xe9b0, 0xe9b3, 0x9682, 0xe9b4,
+  0x8b9b, 0x9844, 0xe9b5, 0xe9b7, 0x88bc, 0xe9b8, 0x95a9, 0xe9b6,
+  0xe9b9, 0xe9ba, 0xe9bb, 0xe9bc, 0xe9bd, 0x968e, 0x8e4c, 0x8df8,
+  0x914e, 0xe9be, 0xe9c1, 0xe9bf, 0xe9c2, 0x8cef, 0xe9c0, 0xe9c3,
+  0xe9c4, 0xe9c5, 0xe9c9, 0x8e49, 0x91e2, 0xe9ca, 0xe9c7, 0xe9c6,
+  0xe9c8, 0x8c7e, 0xe9ce, 0xe9cd, 0xe9cc, 0x88b1, 0xe9d8, 0xe9d4,
+  0xe9d5, 0xe9d1, 0xe9d7, 0xe9d3, 0x8a82, 0x986b, 0xe9d6, 0xe9d2,
+  0xe9d0, 0xe9cf, 0xe9da, 0xe9dd, 0xe9dc, 0xe9db, 0x9568, 0xe9d9,
+  0x88f1, 0xe9de, 0xe9e0, 0x8a8f, 0xe9cb, 0x8956, 0xe9e2, 0xe9e1,
+  0xe9df, 0x924c, 0x9690, 0x97d8, 0xe9e3, 0xe9e4, 0xe9e5, 0xe9e6,
+  0xe9e7, 0x92b9, 0xe9e8, 0x94b5, 0xe9ed, 0xe9e9, 0xe9ea, 0x9650,
+  0x96c2, 0x93ce, 0xe9ee, 0xe9ef, 0x93bc, 0xe9ec, 0xe9eb, 0x89a8,
+  0xe9f7, 0xe9f6, 0x8995, 0xe9f4, 0xe9f3, 0xe9f1, 0x8a9b, 0xe9f0,
+  0x8eb0, 0x89a7, 0x8d83, 0xe9fa, 0xe9f9, 0xe9f8, 0xe9f5, 0xe9fb,
+  0xe9fc, 0xea44, 0xea43, 0xea45, 0x894c, 0xea40, 0xea41, 0x8d94,
+  0x96b7, 0xea42, 0x9651, 0xea4a, 0xea46, 0xea4b, 0xea48, 0xea47,
+  0x8c7b, 0xea4c, 0xea4d, 0xea4e, 0xea49, 0xe9f2, 0xea4f, 0x92df,
+  0xea53, 0xea54, 0xea52, 0xea51, 0xea57, 0xea50, 0xea55, 0xea56,
+  0xea59, 0xea58, 0xea5b, 0xea5c, 0xea5d, 0x9868, 0xea5a, 0x91e9,
+  0x8deb, 0xea5e, 0xea5f, 0xea60, 0xea61, 0xea62, 0x8cb2, 0xea63,
+  0xea64, 0x8ead, 0xea65, 0xea66, 0xea67, 0xea68, 0xea6b, 0xea69,
+  0x985b, 0xea6a, 0x97ed, 0xea6c, 0x97d9, 0xea6d, 0x949e, 0xea6e,
+  0xea70, 0xea71, 0xea6f, 0x8d8d, 0x96cb, 0x9683, 0x9bf5, 0x9f80,
+  0x969b, 0x89a9, 0xea73, 0x8b6f, 0xea74, 0xea75, 0xea76, 0x8d95,
+  0xea77, 0xe0d2, 0x96d9, 0x91e1, 0xea78, 0xea7a, 0xea79, 0xea7b,
+  0xea7c, 0xea7d, 0xea7e, 0xea80, 0xea81, 0xea82, 0xea83, 0xea84,
+  0xea85, 0xea86, 0xea87, 0xea88, 0x9343, 0x8cdb, 0xea8a, 0x916c,
+  0xea8b, 0xea8c, 0x9540, 0xea8d, 0xea8e, 0xe256, 0xe6d8, 0xe8eb,
+  0xea8f, 0xea90, 0xea92, 0xea93, 0xea94, 0x97ee, 0xea91, 0xea95,
+  0xea96, 0xea98, 0xea97, 0xea9a, 0xea9b, 0xea99, 0x97b4, 0xea9c,
+  0xea9d, 0xe273, 0xea9e, 0x8149, 0x8194, 0x8190, 0x8193, 0x8195,
+  0x8169, 0x816a, 0x8196, 0x817b, 0x8143, 0x8144, 0x815e, 0x824f,
+  0x8250, 0x8251, 0x8252, 0x8253, 0x8254, 0x8255, 0x8256, 0x8257,
+  0x8258, 0x8146, 0x8147, 0x8183, 0x8181, 0x8184, 0x8148, 0x8197,
+  0x8260, 0x8261, 0x8262, 0x8263, 0x8264, 0x8265, 0x8266, 0x8267,
+  0x8268, 0x8269, 0x826a, 0x826b, 0x826c, 0x826d, 0x826e, 0x826f,
+  0x8270, 0x8271, 0x8272, 0x8273, 0x8274, 0x8275, 0x8276, 0x8277,
+  0x8278, 0x8279, 0x816d, 0x815f, 0x816e, 0x814f, 0x8151, 0x814d,
+  0x8281, 0x8282, 0x8283, 0x8284, 0x8285, 0x8286, 0x8287, 0x8288,
+  0x8289, 0x828a, 0x828b, 0x828c, 0x828d, 0x828e, 0x828f, 0x8290,
+  0x8291, 0x8292, 0x8293, 0x8294, 0x8295, 0x8296, 0x8297, 0x8298,
+  0x8299, 0x829a, 0x816f, 0x8162, 0x8170, 0x8150, 0x818f,
+};
+
+typedef struct {
+  unsigned short indx; /* index into big table */
+  unsigned short used; /* bitmask of used entries */
+} Summary16;
+
+static const Summary16 jisx0208_uni2indx_page00[16] = {
+  /* 0x0000 */
+  {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x0000 },
+  {    0, 0x0000 }, { 6843, 0x1000 }, {    0, 0x0000 }, {    0, 0x0000 }, /* ZINT: Patched reverse solidus (backslash) mapping U+005C to 0x815F */
+  {    0, 0x0000 }, {    0, 0x0000 }, {    0, 0x118c }, {    5, 0x0053 },
+  {    9, 0x0000 }, {    9, 0x0080 }, {   10, 0x0000 }, {   10, 0x0080 },
+};
+static const Summary16 jisx0208_uni2indx_page03[22] = {
+  /* 0x0300 */
+  {   11, 0x0000 }, {   11, 0x0000 }, {   11, 0x0000 }, {   11, 0x0000 },
+  {   11, 0x0000 }, {   11, 0x0000 }, {   11, 0x0000 }, {   11, 0x0000 },
+  {   11, 0x0000 }, {   11, 0xfffe }, {   26, 0x03fb }, {   35, 0xfffe },
+  {   50, 0x03fb }, {   59, 0x0000 }, {   59, 0x0000 }, {   59, 0x0000 },
+  /* 0x0400 */
+  {   59, 0x0002 }, {   60, 0xffff }, {   76, 0xffff }, {   92, 0xffff },
+  {  108, 0xffff }, {  124, 0x0002 },
+};
+static const Summary16 jisx0208_uni2indx_page20[50] = {
+  /* 0x2000 */
+  {  125, 0x0000 }, {  125, 0x3361 }, {  132, 0x0063 }, {  136, 0x080d },
+  {  140, 0x0000 }, {  140, 0x0000 }, {  140, 0x0000 }, {  140, 0x0000 },
+  {  140, 0x0000 }, {  140, 0x0000 }, {  140, 0x0000 }, {  140, 0x0000 },
+  {  140, 0x0000 }, {  140, 0x0000 }, {  140, 0x0000 }, {  140, 0x0000 },
+  /* 0x2100 */
+  {  140, 0x0008 }, {  141, 0x0000 }, {  141, 0x0800 }, {  142, 0x0000 },
+  {  142, 0x0000 }, {  142, 0x0000 }, {  142, 0x0000 }, {  142, 0x0000 },
+  {  142, 0x0000 }, {  142, 0x000f }, {  146, 0x0000 }, {  146, 0x0000 },
+  {  146, 0x0000 }, {  146, 0x0014 }, {  148, 0x0000 }, {  148, 0x0000 },
+  /* 0x2200 */
+  {  148, 0x098d }, {  154, 0x6404 }, {  158, 0x1f81 }, {  165, 0x2030 },
+  {  168, 0x0000 }, {  168, 0x0004 }, {  169, 0x0cc3 }, {  175, 0x0000 },
+  {  175, 0x00cc }, {  179, 0x0000 }, {  179, 0x0020 }, {  180, 0x0000 },
+  {  180, 0x0000 }, {  180, 0x0000 }, {  180, 0x0000 }, {  180, 0x0000 },
+  /* 0x2300 */
+  {  180, 0x0000 }, {  180, 0x0004 },
+};
+static const Summary16 jisx0208_uni2indx_page25[23] = {
+  /* 0x2500 */
+  {  181, 0x900f }, {  187, 0x3999 }, {  195, 0x9939 }, {  203, 0x9999 },
+  {  211, 0x0804 }, {  213, 0x0000 }, {  213, 0x0000 }, {  213, 0x0000 },
+  {  213, 0x0000 }, {  213, 0x0000 }, {  213, 0x0003 }, {  215, 0x300c },
+  {  219, 0xc8c0 }, {  224, 0x0000 }, {  224, 0x8000 }, {  225, 0x0000 },
+  /* 0x2600 */
+  {  225, 0x0060 }, {  227, 0x0000 }, {  227, 0x0000 }, {  227, 0x0000 },
+  {  227, 0x0005 }, {  229, 0x0000 }, {  229, 0xa400 },
+};
+static const Summary16 jisx0208_uni2indx_page30[16] = {
+  /* 0x3000 */
+  {  232, 0xffef }, {  247, 0x103f }, {  254, 0x0000 }, {  254, 0x0000 },
+  {  254, 0xfffe }, {  269, 0xffff }, {  285, 0xffff }, {  301, 0xffff },
+  {  317, 0xffff }, {  333, 0x780f }, {  341, 0xfffe }, {  356, 0xffff },
+  {  372, 0xffff }, {  388, 0xffff }, {  404, 0xffff }, {  420, 0x787f },
+};
+static const Summary16 jisx0208_uni2indx_page4e[1307] = {
+  /* 0x4e00 */
+  {  431, 0x6f8b }, {  441, 0x43f3 }, {  450, 0x2442 }, {  454, 0x9b46 },
+  {  462, 0xe82c }, {  469, 0xe3e0 }, {  477, 0x0004 }, {  478, 0x400a },
+  {  481, 0x5f65 }, {  491, 0xdb36 }, {  501, 0x7977 }, {  512, 0x0449 },
+  {  516, 0xecd7 }, {  527, 0xe3f0 }, {  536, 0x6038 }, {  541, 0x08c5 },
+  /* 0x4f00 */
+  {  546, 0xe602 }, {  552, 0x3403 }, {  557, 0x8000 }, {  558, 0x3551 },
+  {  565, 0xe0c8 }, {  571, 0x7eab }, {  582, 0x8200 }, {  584, 0x9869 },
+  {  591, 0xa948 }, {  597, 0x2942 }, {  602, 0xe803 }, {  608, 0x8060 },
+  {  611, 0x441c }, {  616, 0xad93 }, {  625, 0xc03a }, {  631, 0x4568 },
+  /* 0x5000 */
+  {  637, 0xaa60 }, {  643, 0x8656 }, {  650, 0x3f7a }, {  661, 0x0240 },
+  {  663, 0x8388 }, {  668, 0x1461 }, {  673, 0x1020 }, {  675, 0x2174 },
+  {  681, 0x2021 }, {  684, 0x0702 }, {  688, 0x3000 }, {  690, 0x40bc },
+  {  696, 0xa624 }, {  702, 0x4462 }, {  707, 0x60a8 }, {  712, 0x0a20 },
+  /* 0x5100 */
+  {  715, 0x0217 }, {  720, 0x8574 }, {  727, 0x0402 }, {  729, 0x9c84 },
+  {  735, 0x7bfb }, {  748, 0x1415 }, {  753, 0x7f24 }, {  762, 0x11e2 },
+  {  768, 0xb665 }, {  777, 0x02ef }, {  785, 0x1f75 }, {  795, 0x20ff },
+  {  804, 0x3a70 }, {  811, 0x3840 }, {  815, 0x26c3 }, {  822, 0x6763 },
+  /* 0x5200 */
+  {  831, 0x4dd9 }, {  840, 0x2092 }, {  844, 0x46b0 }, {  850, 0x0fc9 },
+  {  858, 0xbc98 }, {  866, 0x4850 }, {  870, 0x8638 }, {  876, 0xa03f },
+  {  884, 0x2388 }, {  889, 0x8816 }, {  894, 0x3e09 }, {  901, 0x5232 },
+  {  907, 0x22aa }, {  913, 0xe3a4 }, {  921, 0x00dd }, {  927, 0xc72c },
+  /* 0x5300 */
+  {  935, 0xa166 }, {  942, 0x26e1 }, {  949, 0x840b }, {  954, 0x8f0a },
+  {  961, 0x27eb }, {  971, 0x559e }, {  980, 0xc241 }, {  985, 0x89bb },
+  {  994, 0x0014 }, {  996, 0x8540 }, { 1000, 0x6361 }, { 1007, 0x0849 },
+  { 1011, 0x7f0c }, { 1020, 0x8ad0 }, { 1026, 0xff3e }, { 1039, 0x05cf },
+  /* 0x5400 */
+  { 1047, 0xff1a }, { 1058, 0xa803 }, { 1063, 0x7a41 }, { 1070, 0x7b40 },
+  { 1077, 0x4745 }, { 1084, 0x8002 }, { 1086, 0x0500 }, { 1088, 0x38eb },
+  { 1097, 0xd851 }, { 1104, 0x0005 }, { 1106, 0x9934 }, { 1113, 0x710c },
+  { 1119, 0x0397 }, { 1126, 0x0100 }, { 1127, 0x6366 }, { 1135, 0x2404 },
+  /* 0x5500 */
+  { 1138, 0x80d0 }, { 1142, 0x0051 }, { 1145, 0xc000 }, { 1147, 0x430a },
+  { 1152, 0x9071 }, { 1158, 0x30c8 }, { 1163, 0x0008 }, { 1164, 0x5800 },
+  { 1167, 0x0e99 }, { 1174, 0xf700 }, { 1181, 0x5f80 }, { 1188, 0x0041 },
+  { 1190, 0x00b0 }, { 1193, 0x9410 }, { 1197, 0x0018 }, { 1199, 0x6280 },
+  /* 0x5600 */
+  { 1203, 0x0240 }, { 1205, 0x09d0 }, { 1210, 0x8200 }, { 1212, 0x0156 },
+  { 1217, 0x5004 }, { 1220, 0x0801 }, { 1222, 0x1d10 }, { 1227, 0x0510 },
+  { 1230, 0x84c1 }, { 1235, 0x0010 }, { 1236, 0x4025 }, { 1240, 0x1050 },
+  { 1243, 0x410f }, { 1249, 0x4d8a }, { 1256, 0x4009 }, { 1259, 0xa60d },
+  /* 0x5700 */
+  { 1266, 0xab19 }, { 1274, 0x914c }, { 1280, 0x21c0 }, { 1284, 0x0981 },
+  { 1288, 0xc485 }, { 1294, 0x0003 }, { 1296, 0x0652 }, { 1301, 0x8000 },
+  { 1302, 0x0b04 }, { 1306, 0x0008 }, { 1307, 0x041d }, { 1312, 0x0009 },
+  { 1314, 0x4849 }, { 1319, 0x905c }, { 1325, 0x0009 }, { 1327, 0x1690 },
+  /* 0x5800 */
+  { 1332, 0x0c65 }, { 1338, 0x2220 }, { 1341, 0x8412 }, { 1345, 0x2433 },
+  { 1351, 0x0c03 }, { 1355, 0x4796 }, { 1363, 0x0a04 }, { 1366, 0x4225 },
+  { 1371, 0x0028 }, { 1373, 0x9088 }, { 1377, 0x4900 }, { 1380, 0x4f08 },
+  { 1386, 0x14a2 }, { 1391, 0xd3aa }, { 1400, 0xd830 }, { 1406, 0x3e87 },
+  /* 0x5900 */
+  { 1415, 0x8604 }, { 1419, 0x1f61 }, { 1427, 0x7ea4 }, { 1436, 0x4186 },
+  { 1441, 0xc390 }, { 1447, 0x05b3 }, { 1454, 0x57a5 }, { 1463, 0x2118 },
+  { 1467, 0x241e }, { 1473, 0x2a48 }, { 1478, 0x1128 }, { 1482, 0x4a04 },
+  { 1486, 0x0a40 }, { 1489, 0x161b }, { 1496, 0x0d60 }, { 1501, 0x8840 },
+  /* 0x5a00 */
+  { 1504, 0x020a }, { 1507, 0x9502 }, { 1512, 0x8221 }, { 1516, 0x1060 },
+  { 1519, 0x0243 }, { 1523, 0x0400 }, { 1524, 0x1444 }, { 1528, 0x8000 },
+  { 1529, 0x0000 }, { 1529, 0x0c04 }, { 1532, 0x0000 }, { 1532, 0x7000 },
+  { 1535, 0x1a06 }, { 1540, 0x00c1 }, { 1543, 0x024a }, { 1547, 0x0c00 },
+  /* 0x5b00 */
+  { 1549, 0x1a00 }, { 1552, 0x0040 }, { 1553, 0x1404 }, { 1556, 0x4045 },
+  { 1560, 0x0029 }, { 1563, 0xbdb3 }, { 1574, 0x0a78 }, { 1580, 0x052b },
+  { 1586, 0xbba9 }, { 1596, 0xbfa0 }, { 1605, 0x407c }, { 1611, 0x8379 },
+  { 1619, 0x12fc }, { 1627, 0xe81d }, { 1635, 0x4bf6 }, { 1645, 0xc569 },
+  /* 0x5c00 */
+  { 1653, 0xeff6 }, { 1666, 0x044a }, { 1670, 0x2115 }, { 1675, 0xff02 },
+  { 1684, 0xed63 }, { 1694, 0x402b }, { 1699, 0xd033 }, { 1706, 0x0242 },
+  { 1709, 0x1000 }, { 1710, 0x0013 }, { 1713, 0x1b02 }, { 1718, 0x59ca },
+  { 1726, 0x00a0 }, { 1728, 0x0200 }, { 1729, 0xa703 }, { 1736, 0x2c41 },
+  /* 0x5d00 */
+  { 1741, 0x4880 }, { 1744, 0x8ff2 }, { 1754, 0x0204 }, { 1756, 0x0000 },
+  { 1756, 0x5800 }, { 1759, 0x1005 }, { 1762, 0x9200 }, { 1765, 0x0048 },
+  { 1767, 0x1894 }, { 1772, 0x2001 }, { 1774, 0x5004 }, { 1777, 0x3480 },
+  { 1781, 0x3200 }, { 1784, 0x684c }, { 1790, 0x49ea }, { 1798, 0x68be },
+  /* 0x5e00 */
+  { 1807, 0x184c }, { 1812, 0x2e42 }, { 1818, 0xa820 }, { 1822, 0x21c9 },
+  { 1828, 0x50b9 }, { 1835, 0x80b0 }, { 1839, 0x001e }, { 1843, 0xff7c },
+  { 1856, 0x849a }, { 1862, 0x14e0 }, { 1867, 0x28c1 }, { 1872, 0x01e0 },
+  { 1876, 0x870e }, { 1883, 0xac49 }, { 1890, 0x130f }, { 1897, 0xdddb },
+  /* 0x5f00 */
+  { 1909, 0xbe1a }, { 1918, 0x89fb }, { 1928, 0xa2e0 }, { 1934, 0x51a2 },
+  { 1940, 0x5502 }, { 1945, 0x32ca }, { 1952, 0x3e46 }, { 1960, 0x928b },
+  { 1967, 0x1dbf }, { 1978, 0x438f }, { 1986, 0x6703 }, { 1993, 0x3218 },
+  { 1998, 0x3028 }, { 2002, 0x33c0 }, { 2008, 0x0811 }, { 2011, 0xa923 },
+  /* 0x6000 */
+  { 2018, 0xc000 }, { 2020, 0x3a65 }, { 2028, 0x8fe3 }, { 2038, 0x0402 },
+  { 2040, 0x2c4e }, { 2047, 0x8625 }, { 2053, 0xbf3d }, { 2065, 0x00a1 },
+  { 2068, 0x3a1a }, { 2075, 0x8cd4 }, { 2082, 0x06c9 }, { 2088, 0x317c },
+  { 2096, 0x00e0 }, { 2099, 0x950a }, { 2105, 0x018b }, { 2110, 0x0edb },
+  /* 0x6100 */
+  { 2119, 0xe34b }, { 2128, 0x8c20 }, { 2132, 0x1182 }, { 2136, 0xf010 },
+  { 2141, 0x7d94 }, { 2150, 0xa728 }, { 2157, 0xc9ac }, { 2165, 0x40fb },
+  { 2173, 0x4484 }, { 2177, 0x0653 }, { 2183, 0x5a90 }, { 2189, 0x4444 },
+  { 2193, 0x3fc8 }, { 2202, 0x0001 }, { 2203, 0x0048 }, { 2205, 0xf5d4 },
+  /* 0x6200 */
+  { 2215, 0x7701 }, { 2222, 0xec57 }, { 2232, 0xc442 }, { 2237, 0x891d },
+  { 2244, 0x6b83 }, { 2252, 0x4928 }, { 2257, 0x4109 }, { 2261, 0xd242 },
+  { 2267, 0x061d }, { 2273, 0x59fe }, { 2284, 0x1800 }, { 2286, 0x3a22 },
+  { 2292, 0xb7e4 }, { 2302, 0x3b9f }, { 2313, 0xf003 }, { 2319, 0xc0ea },
+  /* 0x6300 */
+  { 2326, 0x1386 }, { 2332, 0x8202 }, { 2335, 0x8980 }, { 2339, 0xe400 },
+  { 2343, 0xb200 }, { 2347, 0x10a1 }, { 2351, 0x4b80 }, { 2356, 0x0cc4 },
+  { 2361, 0xd309 }, { 2368, 0x8944 }, { 2373, 0x1faf }, { 2384, 0x4834 },
+  { 2389, 0x8259 }, { 2395, 0x0c45 }, { 2400, 0x420a }, { 2404, 0x0450 },
+  /* 0x6400 */
+  { 2407, 0xa040 }, { 2410, 0x10c8 }, { 2414, 0x3140 }, { 2418, 0x4450 },
+  { 2422, 0x4004 }, { 2424, 0x0100 }, { 2425, 0x8280 }, { 2428, 0x0540 },
+  { 2431, 0x0108 }, { 2433, 0x442c }, { 2438, 0x6a30 }, { 2444, 0x1a05 },
+  { 2449, 0x20a6 }, { 2454, 0x0514 }, { 2458, 0x90cf }, { 2466, 0x6456 },
+  /* 0x6500 */
+  { 2473, 0x0021 }, { 2475, 0x3100 }, { 2478, 0x9c18 }, { 2484, 0xcbf0 },
+  { 2493, 0xa120 }, { 2497, 0x63e2 }, { 2505, 0x104c }, { 2509, 0x01b5 },
+  { 2515, 0x538c }, { 2522, 0x9a83 }, { 2529, 0xb8b2 }, { 2537, 0x3281 },
+  { 2542, 0x987a }, { 2550, 0x0a84 }, { 2554, 0x33e7 }, { 2564, 0x0c02 },
+  /* 0x6600 */
+  { 2567, 0xd4cc }, { 2575, 0x9018 }, { 2579, 0xa1a1 }, { 2585, 0x9070 },
+  { 2590, 0x8a1e }, { 2597, 0xe004 }, { 2601, 0xc3d4 }, { 2609, 0x0451 },
+  { 2613, 0x439a }, { 2620, 0x21c2 }, { 2625, 0x4844 }, { 2629, 0x5310 },
+  { 2634, 0x0292 }, { 2638, 0x3640 }, { 2643, 0x0241 }, { 2646, 0xf3bd },
+  /* 0x6700 */
+  { 2658, 0xab09 }, { 2665, 0xe8f0 }, { 2673, 0x7dc0 }, { 2681, 0xa5d2 },
+  { 2689, 0xc242 }, { 2694, 0xd24b }, { 2702, 0xa43f }, { 2711, 0xd0af },
+  { 2720, 0x1aa0 }, { 2725, 0x34a1 }, { 2731, 0x8247 }, { 2737, 0x03d8 },
+  { 2743, 0xc452 }, { 2749, 0x651b }, { 2757, 0xd294 }, { 2764, 0xc83a },
+  /* 0x6800 */
+  { 2771, 0x001c }, { 2774, 0x40c8 }, { 2778, 0x0e06 }, { 2783, 0x3314 },
+  { 2789, 0x614f }, { 2797, 0xb21b }, { 2805, 0x0088 }, { 2807, 0xc0d0 },
+  { 2812, 0xa02a }, { 2817, 0xa898 }, { 2823, 0xa1c5 }, { 2830, 0x166b },
+  { 2838, 0x2e50 }, { 2844, 0x85b4 }, { 2851, 0xc08b }, { 2857, 0x0604 },
+  /* 0x6900 */
+  { 2860, 0xf933 }, { 2870, 0x1e04 }, { 2875, 0x056e }, { 2882, 0xa251 },
+  { 2888, 0x0400 }, { 2889, 0x7638 }, { 2897, 0xec07 }, { 2905, 0x73b8 },
+  { 2914, 0x4406 }, { 2918, 0x1832 }, { 2923, 0x4081 }, { 2926, 0xc816 },
+  { 2932, 0x7c8a }, { 2940, 0x6309 }, { 2946, 0x2980 }, { 2950, 0xaa04 },
+  /* 0x6a00 */
+  { 2955, 0x1c24 }, { 2960, 0xca9c }, { 2968, 0x4e0e }, { 2975, 0x2760 },
+  { 2981, 0x0990 }, { 2985, 0x8300 }, { 2988, 0x0046 }, { 2991, 0x8104 },
+  { 2994, 0x6011 }, { 2998, 0x1081 }, { 3001, 0x540d }, { 3007, 0x0908 },
+  { 3010, 0x000e }, { 3013, 0xcc0a }, { 3019, 0x0500 }, { 3021, 0x0c00 },
+  /* 0x6b00 */
+  { 3023, 0x0430 }, { 3026, 0xa044 }, { 3030, 0x008b }, { 3034, 0x6784 },
+  { 3041, 0x5288 }, { 3046, 0x8a19 }, { 3052, 0x865e }, { 3060, 0x8b18 },
+  { 3066, 0x2e59 }, { 3074, 0x4160 }, { 3078, 0x8c10 }, { 3082, 0x9cbe },
+  { 3092, 0x6861 }, { 3098, 0x891c }, { 3104, 0x9800 }, { 3107, 0x0008 },
+  /* 0x6c00 */
+  { 3108, 0x8100 }, { 3110, 0x089a }, { 3115, 0x0018 }, { 3117, 0x4190 },
+  { 3121, 0x4007 }, { 3125, 0xe4a1 }, { 3132, 0x0505 }, { 3136, 0x640d },
+  { 3142, 0x310e }, { 3148, 0x0e4d }, { 3155, 0x4806 }, { 3159, 0xff0a },
+  { 3169, 0x1632 }, { 3175, 0x2aa8 }, { 3181, 0x852e }, { 3188, 0x000b },
+  /* 0x6d00 */
+  { 3191, 0x1800 }, { 3193, 0xca84 }, { 3199, 0x0e20 }, { 3203, 0x696c },
+  { 3211, 0x0032 }, { 3214, 0x1600 }, { 3217, 0x5658 }, { 3224, 0x0390 },
+  { 3228, 0x5120 }, { 3232, 0x1a28 }, { 3237, 0x8000 }, { 3238, 0x1124 },
+  { 3242, 0x18e1 }, { 3248, 0x4326 }, { 3254, 0x5d52 }, { 3262, 0x0eaa },
+  /* 0x6e00 */
+  { 3269, 0x0fa0 }, { 3275, 0xae28 }, { 3282, 0xfa7b }, { 3294, 0x4500 },
+  { 3297, 0x6408 }, { 3301, 0x8940 }, { 3305, 0xc880 }, { 3309, 0xc044 },
+  { 3313, 0x9005 }, { 3317, 0xb141 }, { 3323, 0x8424 }, { 3327, 0x24c4 },
+  { 3332, 0x1a34 }, { 3338, 0x603a }, { 3344, 0x9000 }, { 3346, 0xc194 },
+  /* 0x6f00 */
+  { 3352, 0x8246 }, { 3357, 0x003a }, { 3361, 0x180d }, { 3366, 0xc106 },
+  { 3371, 0x0022 }, { 3373, 0x9910 }, { 3378, 0xe050 }, { 3383, 0x1511 },
+  { 3388, 0x4057 }, { 3394, 0x0082 }, { 3396, 0x041a }, { 3400, 0x020a },
+  { 3403, 0x004f }, { 3408, 0x8930 }, { 3413, 0xd813 }, { 3420, 0x444a },
+  /* 0x7000 */
+  { 3425, 0x8a02 }, { 3429, 0xed22 }, { 3437, 0x10c0 }, { 3440, 0x4005 },
+  { 3443, 0x1000 }, { 3444, 0x0102 }, { 3446, 0x8808 }, { 3449, 0x3101 },
+  { 3453, 0x4600 }, { 3456, 0x0204 }, { 3458, 0xf000 }, { 3462, 0x0708 },
+  { 3466, 0x8900 }, { 3469, 0xa200 }, { 3472, 0x0000 }, { 3472, 0x2202 },
+  /* 0x7100 */
+  { 3475, 0x0200 }, { 3476, 0x1610 }, { 3480, 0x0042 }, { 3482, 0x1040 },
+  { 3484, 0x5200 }, { 3487, 0x0260 }, { 3490, 0x52f4 }, { 3498, 0x2000 },
+  { 3499, 0x8510 }, { 3503, 0x8230 }, { 3507, 0x1100 }, { 3509, 0x4202 },
+  { 3512, 0x4308 }, { 3516, 0x80b5 }, { 3522, 0x70e1 }, { 3529, 0x9a20 },
+  /* 0x7200 */
+  { 3534, 0x2040 }, { 3536, 0x0801 }, { 3538, 0x3500 }, { 3542, 0xfc65 },
+  { 3552, 0x19c1 }, { 3558, 0xab04 }, { 3564, 0x0286 }, { 3568, 0x6214 },
+  { 3573, 0x0087 }, { 3577, 0x0044 }, { 3579, 0x9085 }, { 3584, 0x0244 },
+  { 3587, 0x405c }, { 3592, 0x0a85 }, { 3597, 0x3207 }, { 3603, 0x3380 },
+  /* 0x7300 */
+  { 3608, 0x0400 }, { 3609, 0xb8c0 }, { 3615, 0xce20 }, { 3621, 0xc0d0 },
+  { 3626, 0xc030 }, { 3630, 0x0080 }, { 3631, 0x0508 }, { 3634, 0x0d25 },
+  { 3640, 0x0a90 }, { 3644, 0x0040 }, { 3645, 0x0200 }, { 3646, 0x080c },
+  { 3649, 0x6505 }, { 3655, 0x4000 }, { 3656, 0x6421 }, { 3661, 0x4102 },
+  /* 0x7400 */
+  { 3664, 0x0268 }, { 3668, 0x0000 }, { 3668, 0x0024 }, { 3670, 0x847c },
+  { 3677, 0x0002 }, { 3678, 0xde20 }, { 3685, 0x8619 }, { 3691, 0x4049 },
+  { 3695, 0x0808 }, { 3697, 0x4000 }, { 3698, 0x0084 }, { 3700, 0x2001 },
+  { 3702, 0x8400 }, { 3704, 0x1010 }, { 3706, 0x42cd }, { 3713, 0x01c7 },
+  /* 0x7500 */
+  { 3719, 0x7038 }, { 3725, 0xd52a }, { 3733, 0x1968 }, { 3739, 0x1d8f },
+  { 3748, 0xbe50 }, { 3756, 0x3e12 }, { 3763, 0x2ef5 }, { 3773, 0x81d9 },
+  { 3780, 0xcec4 }, { 3788, 0x2412 }, { 3792, 0x0828 }, { 3795, 0x732e },
+  { 3804, 0x24ac }, { 3810, 0x4b34 }, { 3817, 0x020c }, { 3820, 0xd41d },
+  /* 0x7600 */
+  { 3828, 0x2a02 }, { 3832, 0x8000 }, { 3833, 0x0097 }, { 3838, 0x0811 },
+  { 3841, 0x11c4 }, { 3846, 0x1144 }, { 3850, 0x1786 }, { 3857, 0x7d45 },
+  { 3866, 0x49d9 }, { 3874, 0x0649 }, { 3879, 0x4000 }, { 3880, 0x8791 },
+  { 3887, 0x254c }, { 3893, 0xd8c4 }, { 3900, 0x44ba }, { 3907, 0x4914 },
+  /* 0x7700 */
+  { 3912, 0x1b92 }, { 3919, 0xc800 }, { 3922, 0x0271 }, { 3927, 0x1580 },
+  { 3931, 0x0081 }, { 3933, 0x0c00 }, { 3935, 0x096a }, { 3941, 0xc200 },
+  { 3944, 0x4800 }, { 3946, 0x4002 }, { 3948, 0x3021 }, { 3952, 0xba49 },
+  { 3960, 0x2080 }, { 3962, 0x1c80 }, { 3966, 0xe2ac }, { 3974, 0x1008 },
+  /* 0x7800 */
+  { 3976, 0x1004 }, { 3978, 0x0034 }, { 3981, 0x00e1 }, { 3985, 0x8414 },
+  { 3989, 0x0020 }, { 3990, 0x2000 }, { 3991, 0x9800 }, { 3994, 0x1014 },
+  { 3997, 0x70c2 }, { 4003, 0x04aa }, { 4008, 0x8688 }, { 4013, 0x5420 },
+  { 4017, 0x0c62 }, { 4022, 0x0413 }, { 4026, 0x9180 }, { 4030, 0x2010 },
+  /* 0x7900 */
+  { 4032, 0x4082 }, { 4035, 0x0206 }, { 4038, 0x1c40 }, { 4042, 0x5400 },
+  { 4045, 0x0383 }, { 4050, 0xe4e9 }, { 4059, 0x2125 }, { 4064, 0x8480 },
+  { 4067, 0xe433 }, { 4075, 0x2000 }, { 4076, 0x44c0 }, { 4080, 0xe609 },
+  { 4087, 0x0a03 }, { 4091, 0x8126 }, { 4096, 0x12da }, { 4103, 0x0801 },
+  /* 0x7a00 */
+  { 4105, 0x6901 }, { 4110, 0x9790 }, { 4117, 0x4001 }, { 4119, 0xf886 },
+  { 4127, 0xe24d }, { 4135, 0x0081 }, { 4137, 0x0a0e }, { 4142, 0xa651 },
+  { 4149, 0x011a }, { 4153, 0x81ec }, { 4160, 0xc600 }, { 4164, 0x8441 },
+  { 4168, 0xadb8 }, { 4177, 0xb62c }, { 4185, 0xa46f }, { 4194, 0x8741 },
+  /* 0x7b00 */
+  { 4200, 0x8d54 }, { 4207, 0x4b02 }, { 4212, 0x1161 }, { 4217, 0x0268 },
+  { 4221, 0xbb60 }, { 4229, 0x2057 }, { 4235, 0x50a0 }, { 4239, 0x0433 },
+  { 4244, 0xa8c0 }, { 4249, 0xb7b4 }, { 4259, 0x2402 }, { 4262, 0x0112 },
+  { 4265, 0x9ad3 }, { 4274, 0x2000 }, { 4275, 0x2271 }, { 4281, 0x00c8 },
+  /* 0x7c00 */
+  { 4284, 0x2081 }, { 4287, 0x809e }, { 4293, 0x0c8a }, { 4298, 0xe180 },
+  { 4303, 0xb009 }, { 4308, 0x8151 }, { 4313, 0x1031 }, { 4317, 0x4028 },
+  { 4320, 0x2a0e }, { 4326, 0x89a5 }, { 4333, 0x69b6 }, { 4342, 0x620e },
+  { 4348, 0x4425 }, { 4353, 0xd144 }, { 4359, 0x8085 }, { 4363, 0x4d54 },
+  /* 0x7d00 */
+  { 4370, 0x2c75 }, { 4378, 0x1fb1 }, { 4387, 0xd807 }, { 4394, 0x862d },
+  { 4401, 0xd87c }, { 4410, 0x4841 }, { 4414, 0x414e }, { 4420, 0x226e },
+  { 4427, 0x8200 }, { 4429, 0x9e08 }, { 4435, 0xf80c }, { 4442, 0xed37 },
+  { 4453, 0x8c80 }, { 4457, 0x7526 }, { 4465, 0x9313 }, { 4472, 0x0814 },
+  /* 0x7e00 */
+  { 4475, 0x0e32 }, { 4481, 0xc804 }, { 4485, 0x484e }, { 4491, 0x6ea6 },
+  { 4500, 0x2c4a }, { 4506, 0x6670 }, { 4513, 0x26c0 }, { 4518, 0xba01 },
+  { 4524, 0xd30c }, { 4531, 0x185d }, { 4538, 0x0000 }, { 4538, 0x0000 },
+  { 4538, 0x0000 }, { 4538, 0x0000 }, { 4538, 0x0000 }, { 4538, 0x0000 },
+  /* 0x7f00 */
+  { 4538, 0x0000 }, { 4538, 0x0000 }, { 4538, 0x0000 }, { 4538, 0x0540 },
+  { 4541, 0x7020 }, { 4545, 0x8133 }, { 4551, 0x4f81 }, { 4558, 0x03a5 },
+  { 4564, 0x55ec }, { 4573, 0x6410 }, { 4577, 0xc318 }, { 4583, 0x2344 },
+  { 4588, 0x1462 }, { 4593, 0x0034 }, { 4596, 0x0a43 }, { 4601, 0x1a09 },
+  /* 0x8000 */
+  { 4606, 0x187b }, { 4614, 0x13a5 }, { 4621, 0x0102 }, { 4623, 0xa848 },
+  { 4628, 0x0440 }, { 4630, 0xc544 }, { 4636, 0x8106 }, { 4640, 0xe2dd },
+  { 4650, 0x1af0 }, { 4657, 0x2d48 }, { 4663, 0xb626 }, { 4671, 0x0416 },
+  { 4675, 0x5058 }, { 4680, 0x6e40 }, { 4686, 0x8032 }, { 4690, 0x3112 },
+  /* 0x8100 */
+  { 4695, 0x07e4 }, { 4702, 0x0c00 }, { 4704, 0x8208 }, { 4707, 0x420a },
+  { 4711, 0x4840 }, { 4714, 0x803b }, { 4720, 0x4860 }, { 4724, 0x8713 },
+  { 4731, 0x850d }, { 4737, 0x3428 }, { 4742, 0x0319 }, { 4747, 0xe529 },
+  { 4755, 0x2345 }, { 4761, 0x870a }, { 4767, 0x25a9 }, { 4774, 0x5c18 },
+  /* 0x8200 */
+  { 4780, 0x77a6 }, { 4790, 0xd9c5 }, { 4799, 0x5e00 }, { 4804, 0x03e8 },
+  { 4810, 0x0081 }, { 4812, 0xa700 }, { 4817, 0xcd54 }, { 4825, 0x41c6 },
+  { 4831, 0x2800 }, { 4833, 0xa204 }, { 4837, 0xb860 }, { 4843, 0x2b0a },
+  { 4849, 0x0020 }, { 4850, 0xda9e }, { 4860, 0x08ea }, { 4866, 0x0e1a },
+  /* 0x8300 */
+  { 4872, 0x427c }, { 4879, 0x11c0 }, { 4883, 0x8908 }, { 4887, 0x0376 },
+  { 4894, 0x8621 }, { 4899, 0x0105 }, { 4902, 0x0000 }, { 4902, 0x18a8 },
+  { 4907, 0x46a0 }, { 4912, 0xc448 }, { 4917, 0x0d05 }, { 4922, 0x2022 },
+  { 4925, 0x5422 }, { 4930, 0x9148 }, { 4935, 0x8a01 }, { 4939, 0x2897 },
+  /* 0x8400 */
+  { 4946, 0x7898 }, { 4953, 0x0008 }, { 4954, 0x1605 }, { 4959, 0x3122 },
+  { 4964, 0x4240 }, { 4967, 0x0880 }, { 4969, 0xfa4e }, { 4979, 0x06a2 },
+  { 4984, 0x0814 }, { 4987, 0x9211 }, { 4992, 0x2002 }, { 4994, 0x9b04 },
+  { 5000, 0x2e52 }, { 5007, 0x0643 }, { 5012, 0x5000 }, { 5014, 0x9010 },
+  /* 0x8500 */
+  { 5017, 0x0041 }, { 5019, 0x85ba }, { 5027, 0x3042 }, { 5031, 0x2020 },
+  { 5033, 0x4f0b }, { 5041, 0x05a0 }, { 5045, 0x2708 }, { 5050, 0x4080 },
+  { 5052, 0x0591 }, { 5057, 0x1a93 }, { 5064, 0xdf50 }, { 5073, 0x0600 },
+  { 5075, 0xa202 }, { 5079, 0x3021 }, { 5083, 0x0630 }, { 5087, 0x4e80 },
+  /* 0x8600 */
+  { 5092, 0x0cc4 }, { 5097, 0x04c8 }, { 5101, 0xa004 }, { 5104, 0x8001 },
+  { 5106, 0x6000 }, { 5108, 0xd431 }, { 5115, 0x0880 }, { 5117, 0x0a02 },
+  { 5120, 0x1c00 }, { 5123, 0x0028 }, { 5125, 0x8e18 }, { 5131, 0x0041 },
+  { 5133, 0x6ad0 }, { 5140, 0xca10 }, { 5145, 0xf210 }, { 5151, 0x4b00 },
+  /* 0x8700 */
+  { 5155, 0x274d }, { 5163, 0x1506 }, { 5168, 0x0220 }, { 5170, 0x8890 },
+  { 5174, 0x5a00 }, { 5178, 0x82a8 }, { 5183, 0x4549 }, { 5189, 0x8150 },
+  { 5193, 0x2004 }, { 5195, 0x8000 }, { 5196, 0x8804 }, { 5199, 0x2c08 },
+  { 5203, 0x08d1 }, { 5208, 0x0005 }, { 5210, 0x8001 }, { 5212, 0x4ac4 },
+  /* 0x8800 */
+  { 5218, 0xe020 }, { 5222, 0x0062 }, { 5225, 0x008e }, { 5229, 0x0a42 },
+  { 5233, 0x3055 }, { 5239, 0x6a8c }, { 5246, 0x090e }, { 5251, 0xe0a5 },
+  { 5258, 0x2906 }, { 5263, 0x42c4 }, { 5268, 0x4814 }, { 5272, 0x80b3 },
+  { 5278, 0x803e }, { 5284, 0xb330 }, { 5291, 0x0102 }, { 5293, 0x731c },
+  /* 0x8900 */
+  { 5301, 0x1494 }, { 5306, 0x600d }, { 5311, 0x0c20 }, { 5314, 0x0940 },
+  { 5317, 0x301a }, { 5322, 0xc040 }, { 5325, 0xa451 }, { 5331, 0xc094 },
+  { 5336, 0x8dca }, { 5344, 0x05c8 }, { 5349, 0x96c2 }, { 5356, 0xa40c },
+  { 5361, 0x0001 }, { 5362, 0x3404 }, { 5366, 0x00c8 }, { 5369, 0x0110 },
+  /* 0x8a00 */
+  { 5371, 0x550d }, { 5378, 0xa9c9 }, { 5386, 0x2428 }, { 5390, 0x1c5a },
+  { 5397, 0x0142 }, { 5400, 0x4837 }, { 5407, 0x7a4d }, { 5416, 0x100f },
+  { 5421, 0x32b4 }, { 5428, 0x452a }, { 5434, 0x317b }, { 5443, 0x9205 },
+  { 5448, 0xb894 }, { 5455, 0x5c44 }, { 5461, 0x68d7 }, { 5470, 0x458a },
+  /* 0x8b00 */
+  { 5476, 0x5097 }, { 5483, 0x2ed1 }, { 5491, 0x1943 }, { 5497, 0x4208 },
+  { 5500, 0xd202 }, { 5505, 0x9d40 }, { 5511, 0x9840 }, { 5515, 0x2097 },
+  { 5521, 0x5409 }, { 5526, 0x064d }, { 5532, 0x0000 }, { 5532, 0x0000 },
+  { 5532, 0x0000 }, { 5532, 0x0000 }, { 5532, 0x0000 }, { 5532, 0x0000 },
+  /* 0x8c00 */
+  { 5532, 0x0000 }, { 5532, 0x0000 }, { 5532, 0x0000 }, { 5532, 0x8480 },
+  { 5535, 0x5542 }, { 5541, 0x0421 }, { 5544, 0x1c06 }, { 5549, 0x1700 },
+  { 5553, 0x7624 }, { 5560, 0x6110 }, { 5564, 0xff87 }, { 5576, 0xb9dd },
+  { 5587, 0x659f }, { 5597, 0x5c0a }, { 5603, 0x245d }, { 5610, 0x3c00 },
+  /* 0x8d00 */
+  { 5614, 0xadb0 }, { 5622, 0x0059 }, { 5626, 0x0000 }, { 5626, 0x0000 },
+  { 5626, 0x0000 }, { 5626, 0x0000 }, { 5626, 0x28d0 }, { 5631, 0x009b },
+  { 5636, 0x0422 }, { 5639, 0x0200 }, { 5640, 0x0108 }, { 5642, 0x4408 },
+  { 5645, 0x9804 }, { 5649, 0xac40 }, { 5654, 0x8d0a }, { 5660, 0x9028 },
+  /* 0x8e00 */
+  { 5664, 0x8700 }, { 5668, 0xe001 }, { 5672, 0x0400 }, { 5673, 0x0031 },
+  { 5676, 0x1794 }, { 5683, 0x8221 }, { 5687, 0x0019 }, { 5690, 0x1054 },
+  { 5694, 0x2cb2 }, { 5701, 0x021a }, { 5705, 0x9c02 }, { 5710, 0x4003 },
+  { 5713, 0x3d60 }, { 5720, 0x8804 }, { 5723, 0x080c }, { 5726, 0x7900 },
+  /* 0x8f00 */
+  { 5731, 0x1628 }, { 5736, 0xba3c }, { 5745, 0x8640 }, { 5749, 0xcb08 },
+  { 5755, 0x7274 }, { 5763, 0x9080 }, { 5766, 0x001e }, { 5770, 0x0000 },
+  { 5770, 0x0000 }, { 5770, 0xd800 }, { 5774, 0xe188 }, { 5780, 0x9c87 },
+  { 5788, 0x4034 }, { 5792, 0x0412 }, { 5795, 0xae64 }, { 5803, 0x2791 },
+  /* 0x9000 */
+  { 5810, 0xe86b }, { 5819, 0xe6fb }, { 5831, 0x408f }, { 5837, 0x5366 },
+  { 5845, 0xeea6 }, { 5855, 0x537f }, { 5866, 0xe32b }, { 5875, 0xb5e4 },
+  { 5884, 0x869f }, { 5893, 0x0002 }, { 5894, 0x8548 }, { 5899, 0x0122 },
+  { 5902, 0x4402 }, { 5905, 0x0800 }, { 5906, 0x2116 }, { 5911, 0x20a0 },
+  /* 0x9100 */
+  { 5914, 0x0004 }, { 5915, 0x0204 }, { 5917, 0x2000 }, { 5918, 0x0005 },
+  { 5920, 0x7e00 }, { 5926, 0x0154 }, { 5930, 0x162c }, { 5936, 0x01ac },
+  { 5941, 0x2a84 }, { 5946, 0x1085 }, { 5950, 0x8c14 }, { 5955, 0x0530 },
+  { 5959, 0xfbc3 }, { 5970, 0xb943 }, { 5978, 0x00ca }, { 5982, 0x9060 },
+  /* 0x9200 */
+  { 5986, 0x6000 }, { 5988, 0x4032 }, { 5992, 0x1200 }, { 5994, 0x8090 },
+  { 5997, 0x0b30 }, { 6002, 0x4c81 }, { 6007, 0x0054 }, { 6010, 0x4002 },
+  { 6012, 0x0029 }, { 6015, 0x1d6a }, { 6023, 0x2000 }, { 6024, 0x0280 },
+  { 6026, 0x8000 }, { 6027, 0x0004 }, { 6028, 0x2610 }, { 6032, 0x150c },
+  /* 0x9300 */
+  { 6037, 0x8040 }, { 6039, 0x0701 }, { 6043, 0xd94d }, { 6052, 0x0c24 },
+  { 6056, 0x2810 }, { 6059, 0x1850 }, { 6063, 0x5001 }, { 6066, 0x5020 },
+  { 6069, 0x1000 }, { 6070, 0x04d0 }, { 6074, 0x7080 }, { 6078, 0x0201 },
+  { 6080, 0x0108 }, { 6082, 0x21c3 }, { 6088, 0x0132 }, { 6092, 0x0000 },
+  /* 0x9400 */
+  { 6092, 0x0088 }, { 6094, 0x0719 }, { 6100, 0x0802 }, { 6102, 0x0560 },
+  { 6106, 0x0012 }, { 6108, 0x4c0e }, { 6114, 0x0405 }, { 6117, 0xf0a1 },
+  { 6124, 0x0002 }, { 6125, 0x0000 }, { 6125, 0x0000 }, { 6125, 0x0000 },
+  { 6125, 0x0000 }, { 6125, 0x0000 }, { 6125, 0x0000 }, { 6125, 0x0000 },
+  /* 0x9500 */
+  { 6125, 0x0000 }, { 6125, 0x0000 }, { 6125, 0x0000 }, { 6125, 0x0000 },
+  { 6125, 0x0000 }, { 6125, 0x0000 }, { 6125, 0x0000 }, { 6125, 0x0080 },
+  { 6126, 0x8e8d }, { 6134, 0x035a }, { 6140, 0x21bd }, { 6148, 0x5a04 },
+  { 6153, 0x3488 }, { 6158, 0x1170 }, { 6163, 0x0026 }, { 6166, 0x0000 },
+  /* 0x9600 */
+  { 6166, 0x0000 }, { 6166, 0x1000 }, { 6167, 0xc502 }, { 6172, 0x8804 },
+  { 6175, 0xb815 }, { 6182, 0xf801 }, { 6188, 0x147c }, { 6195, 0x25ed },
+  { 6204, 0xed60 }, { 6212, 0x1bb0 }, { 6219, 0x0589 }, { 6224, 0x1bd7 },
+  { 6234, 0x7af3 }, { 6245, 0x1a62 }, { 6251, 0x0d0c }, { 6256, 0x0ac5 },
+  /* 0x9700 */
+  { 6262, 0xe5d1 }, { 6271, 0x524a }, { 6277, 0x0490 }, { 6280, 0x6305 },
+  { 6286, 0x0354 }, { 6291, 0x5244 }, { 6296, 0x2b57 }, { 6305, 0x1612 },
+  { 6310, 0xa872 }, { 6317, 0x1101 }, { 6320, 0x2949 }, { 6326, 0x0018 },
+  { 6328, 0x0948 }, { 6332, 0x1008 }, { 6334, 0x6000 }, { 6336, 0x886c },
+  /* 0x9800 */
+  { 6342, 0x916e }, { 6350, 0x058f }, { 6357, 0x3012 }, { 6361, 0x3990 },
+  { 6367, 0xf840 }, { 6373, 0x4930 }, { 6378, 0x8880 }, { 6381, 0x001b },
+  { 6385, 0x0000 }, { 6385, 0x0000 }, { 6385, 0x8500 }, { 6388, 0x0042 },
+  { 6390, 0x0058 }, { 6393, 0x9800 }, { 6396, 0xea04 }, { 6402, 0x7014 },
+  /* 0x9900 */
+  { 6407, 0x1628 }, { 6412, 0x611d }, { 6419, 0x5113 }, { 6425, 0x6000 },
+  { 6427, 0x1a24 }, { 6432, 0x00a7 }, { 6437, 0x0000 }, { 6437, 0x0000 },
+  { 6437, 0x0000 }, { 6437, 0x03c0 }, { 6441, 0x7120 }, { 6446, 0x1018 },
+  { 6449, 0x0172 }, { 6454, 0xa927 }, { 6462, 0x6004 }, { 6465, 0x8906 },
+  /* 0x9a00 */
+  { 6470, 0xc022 }, { 6474, 0x020c }, { 6477, 0x0900 }, { 6479, 0x4081 },
+  { 6482, 0x202d }, { 6487, 0x8ca0 }, { 6492, 0x0e34 }, { 6498, 0x0000 },
+  { 6498, 0x0000 }, { 6498, 0x0000 }, { 6498, 0x2100 }, { 6500, 0x1101 },
+  { 6503, 0x8011 }, { 6506, 0xc11a }, { 6512, 0xec4c }, { 6520, 0x0892 },
+  /* 0x9b00 */
+  { 6524, 0x0040 }, { 6525, 0x8500 }, { 6528, 0xc7ac }, { 6537, 0x1806 },
+  { 6541, 0xe03e }, { 6549, 0x0512 }, { 6553, 0x8000 }, { 6554, 0x0010 },
+  { 6555, 0x4008 }, { 6557, 0x80ce }, { 6563, 0x6d01 }, { 6569, 0x0210 },
+  { 6571, 0x8641 }, { 6576, 0x0856 }, { 6581, 0x011e }, { 6586, 0x0027 },
+  /* 0x9c00 */
+  { 6590, 0x3750 }, { 6597, 0x083d }, { 6603, 0xe032 }, { 6609, 0x4e05 },
+  { 6615, 0x01c0 }, { 6618, 0x0484 }, { 6621, 0x0081 }, { 6623, 0x0140 },
+  { 6625, 0x0000 }, { 6625, 0x0000 }, { 6625, 0x0000 }, { 6625, 0x0000 },
+  { 6625, 0x0000 }, { 6625, 0x0000 }, { 6625, 0x1aa0 }, { 6630, 0x0059 },
+  /* 0x9d00 */
+  { 6634, 0x43c8 }, { 6640, 0x8824 }, { 6644, 0x1d48 }, { 6650, 0xc800 },
+  { 6653, 0x0152 }, { 6657, 0x7203 }, { 6663, 0x9013 }, { 6668, 0x0404 },
+  { 6670, 0x8280 }, { 6673, 0x0400 }, { 6674, 0x8a10 }, { 6678, 0x0d14 },
+  { 6683, 0x8056 }, { 6688, 0x0208 }, { 6690, 0xa040 }, { 6693, 0x2704 },
+  /* 0x9e00 */
+  { 6698, 0x0000 }, { 6698, 0x4c00 }, { 6701, 0x0000 }, { 6701, 0x0000 },
+  { 6701, 0x0000 }, { 6701, 0x0000 }, { 6701, 0x0000 }, { 6701, 0xa320 },
+  { 6706, 0x1902 }, { 6710, 0xa0ae }, { 6717, 0x2660 }, { 6722, 0xdf00 },
+  { 6729, 0xf010 }, { 6734, 0x7b15 }, { 6743, 0x8121 }, { 6747, 0x3ad0 },
+  /* 0x9f00 */
+  { 6754, 0x4180 }, { 6757, 0x0028 }, { 6759, 0x1003 }, { 6762, 0x4800 },
+  { 6764, 0xcc00 }, { 6768, 0x8014 }, { 6771, 0x14cf }, { 6779, 0x00c4 },
+  { 6782, 0x2000 }, { 6783, 0x3020 }, { 6786, 0x0001 },
+};
+
+static const Summary16 jisx0208_uni2indx_pageff[15] = {
+  /* 0xff00 */
+  { 6787, 0xdf7a }, { 6799, 0xffff }, { 6815, 0xffff }, { 6831, 0xffff },
+  { 6847, 0xffff }, { 6863, 0x3fff }, { 6877, 0x0000 }, { 6877, 0x0000 },
+  { 6877, 0x0000 }, { 6877, 0x0000 }, { 6877, 0x0000 }, { 6877, 0x0000 },
+  { 6877, 0x0000 }, { 6877, 0x0000 }, { 6877, 0x0028 },
+};
+
+static int jisx0208_wctomb(unsigned int* r, unsigned int wc) {
+    const Summary16 *summary = NULL;
+    if (wc < 0x0100) {
+        summary = &jisx0208_uni2indx_page00[(wc>>4)];
+    } else if (wc >= 0x0300 && wc < 0x0460) {
+        summary = &jisx0208_uni2indx_page03[(wc>>4)-0x030];
+    } else if (wc >= 0x2000 && wc < 0x2320) {
+        summary = &jisx0208_uni2indx_page20[(wc>>4)-0x200];
+    } else if (wc >= 0x2500 && wc < 0x2670) {
+        summary = &jisx0208_uni2indx_page25[(wc>>4)-0x250];
+    } else if (wc >= 0x3000 && wc < 0x3100) {
+        summary = &jisx0208_uni2indx_page30[(wc>>4)-0x300];
+    } else if (wc >= 0x4e00 && wc < 0x9fb0) {
+        summary = &jisx0208_uni2indx_page4e[(wc>>4)-0x4e0];
+    } else if (wc >= 0xff00 && wc < 0xfff0) {
+        summary = &jisx0208_uni2indx_pageff[(wc>>4)-0xff0];
+    }
+    if (summary) {
+        unsigned short used = summary->used;
+        unsigned int i = wc & 0x0f;
+        if (used & ((unsigned short) 1 << i)) {
+            /* Keep in 'used' only the bits 0..i-1. */
+            used &= ((unsigned short) 1 << i) - 1;
+            /* Add 'summary->indx' and the number of bits set in 'used'. */
+            used = (used & 0x5555) + ((used & 0xaaaa) >> 1);
+            used = (used & 0x3333) + ((used & 0xcccc) >> 2);
+            used = (used & 0x0f0f) + ((used & 0xf0f0) >> 4);
+            used = (used & 0x00ff) + (used >> 8);
+            *r = jisx0208_2charset[summary->indx + used];
+            return 2;
+        }
+    }
+    return 0;
+}
+
+/*
+ * SHIFT_JIS (libiconv-1.16/lib/sjis.h)
+ */
+
+/* Returns 1 or 2 on success, 0 if no mapping */
+INTERNAL int sjis_wctomb_zint(unsigned int* r, unsigned int wc) {
+    int ret;
+
+    /* Try JIS X 0201-1976. */
+    ret = jisx0201_wctomb(r, wc);
+    if (ret) {
+        return ret;
+    }
+
+    /* Try JIS X 0208-1990. */
+    /* ZINT: Note leaving mapping of full-width reverse solidus U+FF3C to 0x815F (duplicate of patched U+005C) to avoid having to regen tables */
+    ret = jisx0208_wctomb(r, wc);
+    if (ret) {
+        return ret;
+    }
+
+    /* User-defined range. See
+    * Ken Lunde's "CJKV Information Processing", table 4-66, p. 206. */
+    /* ZINT: https://file.allitebooks.com/20160708/CJKV%20Information%20Processing.pdf (table 4-86, p. 286, 2nd ed.) */
+    if (wc >= 0xe000 && wc < 0xe758) {
+        unsigned char c1, c2;
+        c1 = (unsigned int) (wc - 0xe000) / 188;
+        c2 = (unsigned int) (wc - 0xe000) % 188;
+        *r = ((c1 + 0xf0) << 8) | (c2 < 0x3f ? c2 + 0x40 : c2 + 0x41);
+        return 2;
+    }
+
+    return 0;
+}
+
+/* Convert UTF-8 string to Shift JIS and place in array of ints */
+INTERNAL int sjis_utf8tomb(struct zint_symbol *symbol, const unsigned char source[], size_t* p_length, unsigned int* jisdata) {
+    int error_number;
+    unsigned int i, length;
+#ifndef _MSC_VER
+    unsigned int utfdata[*p_length + 1];
+#else
+    unsigned int* utfdata = (unsigned int*) _alloca((*p_length + 1) * sizeof(unsigned int));
+#endif
+
+    error_number = utf8_to_unicode(symbol, source, utfdata, p_length, 1 /*disallow_4byte*/);
+    if (error_number != 0) {
+        return error_number;
+    }
+
+    for (i = 0, length = *p_length; i < length; i++) {
+        if (!sjis_wctomb_zint(jisdata + i, utfdata[i])) {
+            strcpy(symbol->errtxt, "800: Invalid character in input data");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+    }
+
+    return 0;
+}
+
+/* Convert UTF-8 string to single byte ECI and place in array of ints */
+INTERNAL int sjis_utf8tosb(int eci, const unsigned char source[], size_t* p_length, unsigned int* jisdata, int full_multibyte) {
+    int error_number;
+#ifndef _MSC_VER
+    unsigned char single_byte[*p_length + 1];
+#else
+    unsigned char* single_byte = (unsigned char*) _alloca(*p_length + 1);
+#endif
+
+    error_number = utf_to_eci(eci, source, single_byte, p_length);
+    if (error_number != 0) {
+        // Note not setting `symbol->errtxt`, up to caller
+        return error_number;
+    }
+
+    sjis_cpy(single_byte, p_length, jisdata, full_multibyte);
+
+    return 0;
+}
+
+/* If `full_multibyte` set, copy byte input stream to array of ints, putting double-bytes that match QR Kanji mode in a single entry.
+ * If `full_multibyte` not set, do a straight copy */
+INTERNAL void sjis_cpy(const unsigned char source[], size_t* p_length, unsigned int* jisdata, int full_multibyte) {
+    unsigned int i, j, jis, length;
+    unsigned char c;
+
+    if (full_multibyte) {
+        for (i = 0, j = 0, length = *p_length; i < length; i++, j++) {
+            c = source[i];
+            if (((c >= 0x81 && c <= 0x9F) || (c >= 0xE0 && c <= 0xEB)) && length - i >= 2) {
+                jis = (c << 8) | source[i + 1];
+                if ((jis >= 0x8140 && jis <= 0x9FFC) || (jis >= 0xE040 && jis <= 0xEBBF)) {
+                    /* This may or may not be valid Shift JIS, but don't care as long as it can be encoded in QR Kanji mode */
+                    jisdata[j] = jis;
+                    i++;
+                } else {
+                    jisdata[j] = c;
+                }
+            } else {
+                jisdata[j] = c;
+            }
+        }
+        *p_length = j;
+    } else {
+        /* Straight copy */
+        for (i = 0, length = *p_length; i < length; i++) {
+            jisdata[i] = source[i];
+        }
+    }
+}
index d5dd6e1..b019a1b 100644 (file)
@@ -1,7 +1,7 @@
-/*  sjis.h - Unicode to Shift JIS lookup table
+/*  sjis.h - Unicode to Shift JIS
 
     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
     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 : */
 
-/* Derived from :
-## Shift_JIS (JIS X 0208:1997 Appendix 1) vs Unicode mapping table
-## 
-## Date: 06 Mar 2002 06:01:22 GMT
-## License:
-##     Copyright (C) 2001 earthian@tama.or.jp, All Rights Reserved.
-##     Copyright (C) 2001 I'O, All Rights Reserved.
-##     You can use, modify, distribute this table freely.
-*/
+#ifndef SJIS_H
+#define SJIS_H
 
-unsigned long int sjis_lookup[] = {
-      0x005C,0x815F,      // REVERSE SOLIDUS
-      0x00A2,0x8191,      // CENT SIGN
-      0x00A3,0x8192,      // POUND SIGN
-      0x00A7,0x8198,      // SECTION SIGN
-      0x00A8,0x814E,      // DIAERESIS
-      0x00AC,0x81CA,      // NOT SIGN
-      0x00B0,0x818B,      // DEGREE SIGN
-      0x00B1,0x817D,      // PLUS-MINUS SIGN
-      0x00B4,0x814C,      // ACUTE ACCENT
-      0x00B6,0x81F7,      // PILCROW SIGN
-      0x00D7,0x817E,      // MULTIPLICATION SIGN
-      0x00F7,0x8180,      // DIVISION SIGN
-      0x0391,0x839F,      // GREEK CAPITAL LETTER ALPHA
-      0x0392,0x83A0,      // GREEK CAPITAL LETTER BETA
-      0x0393,0x83A1,      // GREEK CAPITAL LETTER GAMMA
-      0x0394,0x83A2,      // GREEK CAPITAL LETTER DELTA
-      0x0395,0x83A3,      // GREEK CAPITAL LETTER EPSILON
-      0x0396,0x83A4,      // GREEK CAPITAL LETTER ZETA
-      0x0397,0x83A5,      // GREEK CAPITAL LETTER ETA
-      0x0398,0x83A6,      // GREEK CAPITAL LETTER THETA
-      0x0399,0x83A7,      // GREEK CAPITAL LETTER IOTA
-      0x039A,0x83A8,      // GREEK CAPITAL LETTER KAPPA
-      0x039B,0x83A9,      // GREEK CAPITAL LETTER LAMDA
-      0x039C,0x83AA,      // GREEK CAPITAL LETTER MU
-      0x039D,0x83AB,      // GREEK CAPITAL LETTER NU
-      0x039E,0x83AC,      // GREEK CAPITAL LETTER XI
-      0x039F,0x83AD,      // GREEK CAPITAL LETTER OMICRON
-      0x03A0,0x83AE,      // GREEK CAPITAL LETTER PI
-      0x03A1,0x83AF,      // GREEK CAPITAL LETTER RHO
-      0x03A3,0x83B0,      // GREEK CAPITAL LETTER SIGMA
-      0x03A4,0x83B1,      // GREEK CAPITAL LETTER TAU
-      0x03A5,0x83B2,      // GREEK CAPITAL LETTER UPSILON
-      0x03A6,0x83B3,      // GREEK CAPITAL LETTER PHI
-      0x03A7,0x83B4,      // GREEK CAPITAL LETTER CHI
-      0x03A8,0x83B5,      // GREEK CAPITAL LETTER PSI
-      0x03A9,0x83B6,      // GREEK CAPITAL LETTER OMEGA
-      0x03B1,0x83BF,      // GREEK SMALL LETTER ALPHA
-      0x03B2,0x83C0,      // GREEK SMALL LETTER BETA
-      0x03B3,0x83C1,      // GREEK SMALL LETTER GAMMA
-      0x03B4,0x83C2,      // GREEK SMALL LETTER DELTA
-      0x03B5,0x83C3,      // GREEK SMALL LETTER EPSILON
-      0x03B6,0x83C4,      // GREEK SMALL LETTER ZETA
-      0x03B7,0x83C5,      // GREEK SMALL LETTER ETA
-      0x03B8,0x83C6,      // GREEK SMALL LETTER THETA
-      0x03B9,0x83C7,      // GREEK SMALL LETTER IOTA
-      0x03BA,0x83C8,      // GREEK SMALL LETTER KAPPA
-      0x03BB,0x83C9,      // GREEK SMALL LETTER LAMDA
-      0x03BC,0x83CA,      // GREEK SMALL LETTER MU
-      0x03BD,0x83CB,      // GREEK SMALL LETTER NU
-      0x03BE,0x83CC,      // GREEK SMALL LETTER XI
-      0x03BF,0x83CD,      // GREEK SMALL LETTER OMICRON
-      0x03C0,0x83CE,      // GREEK SMALL LETTER PI
-      0x03C1,0x83CF,      // GREEK SMALL LETTER RHO
-      0x03C3,0x83D0,      // GREEK SMALL LETTER SIGMA
-      0x03C4,0x83D1,      // GREEK SMALL LETTER TAU
-      0x03C5,0x83D2,      // GREEK SMALL LETTER UPSILON
-      0x03C6,0x83D3,      // GREEK SMALL LETTER PHI
-      0x03C7,0x83D4,      // GREEK SMALL LETTER CHI
-      0x03C8,0x83D5,      // GREEK SMALL LETTER PSI
-      0x03C9,0x83D6,      // GREEK SMALL LETTER OMEGA
-      0x0401,0x8446,      // CYRILLIC CAPITAL LETTER IO
-      0x0410,0x8440,      // CYRILLIC CAPITAL LETTER A
-      0x0411,0x8441,      // CYRILLIC CAPITAL LETTER BE
-      0x0412,0x8442,      // CYRILLIC CAPITAL LETTER VE
-      0x0413,0x8443,      // CYRILLIC CAPITAL LETTER GHE
-      0x0414,0x8444,      // CYRILLIC CAPITAL LETTER DE
-      0x0415,0x8445,      // CYRILLIC CAPITAL LETTER IE
-      0x0416,0x8447,      // CYRILLIC CAPITAL LETTER ZHE
-      0x0417,0x8448,      // CYRILLIC CAPITAL LETTER ZE
-      0x0418,0x8449,      // CYRILLIC CAPITAL LETTER I
-      0x0419,0x844A,      // CYRILLIC CAPITAL LETTER SHORT I
-      0x041A,0x844B,      // CYRILLIC CAPITAL LETTER KA
-      0x041B,0x844C,      // CYRILLIC CAPITAL LETTER EL
-      0x041C,0x844D,      // CYRILLIC CAPITAL LETTER EM
-      0x041D,0x844E,      // CYRILLIC CAPITAL LETTER EN
-      0x041E,0x844F,      // CYRILLIC CAPITAL LETTER O
-      0x041F,0x8450,      // CYRILLIC CAPITAL LETTER PE
-      0x0420,0x8451,      // CYRILLIC CAPITAL LETTER ER
-      0x0421,0x8452,      // CYRILLIC CAPITAL LETTER ES
-      0x0422,0x8453,      // CYRILLIC CAPITAL LETTER TE
-      0x0423,0x8454,      // CYRILLIC CAPITAL LETTER U
-      0x0424,0x8455,      // CYRILLIC CAPITAL LETTER EF
-      0x0425,0x8456,      // CYRILLIC CAPITAL LETTER HA
-      0x0426,0x8457,      // CYRILLIC CAPITAL LETTER TSE
-      0x0427,0x8458,      // CYRILLIC CAPITAL LETTER CHE
-      0x0428,0x8459,      // CYRILLIC CAPITAL LETTER SHA
-      0x0429,0x845A,      // CYRILLIC CAPITAL LETTER SHCHA
-      0x042B,0x845C,      // CYRILLIC CAPITAL LETTER YERU
-      0x042C,0x845D,      // CYRILLIC CAPITAL LETTER SOFT SIGN
-      0x042D,0x845E,      // CYRILLIC CAPITAL LETTER E
-      0x042E,0x845F,      // CYRILLIC CAPITAL LETTER YU
-      0x042F,0x8460,      // CYRILLIC CAPITAL LETTER YA
-      0x0430,0x8470,      // CYRILLIC SMALL LETTER A
-      0x0431,0x8471,      // CYRILLIC SMALL LETTER BE
-      0x0432,0x8472,      // CYRILLIC SMALL LETTER VE
-      0x0433,0x8473,      // CYRILLIC SMALL LETTER GHE
-      0x0434,0x8474,      // CYRILLIC SMALL LETTER DE
-      0x0435,0x8475,      // CYRILLIC SMALL LETTER IE
-      0x0436,0x8477,      // CYRILLIC SMALL LETTER ZHE
-      0x0437,0x8478,      // CYRILLIC SMALL LETTER ZE
-      0x0438,0x8479,      // CYRILLIC SMALL LETTER I
-      0x0439,0x847A,      // CYRILLIC SMALL LETTER SHORT I
-      0x043A,0x847B,      // CYRILLIC SMALL LETTER KA
-      0x043B,0x847C,      // CYRILLIC SMALL LETTER EL
-      0x043C,0x847D,      // CYRILLIC SMALL LETTER EM
-      0x043D,0x847E,      // CYRILLIC SMALL LETTER EN
-      0x043E,0x8480,      // CYRILLIC SMALL LETTER O
-      0x043F,0x8481,      // CYRILLIC SMALL LETTER PE
-      0x0440,0x8482,      // CYRILLIC SMALL LETTER ER
-      0x0441,0x8483,      // CYRILLIC SMALL LETTER ES
-      0x0442,0x8484,      // CYRILLIC SMALL LETTER TE
-      0x0443,0x8485,      // CYRILLIC SMALL LETTER U
-      0x0444,0x8486,      // CYRILLIC SMALL LETTER EF
-      0x0445,0x8487,      // CYRILLIC SMALL LETTER HA
-      0x0446,0x8488,      // CYRILLIC SMALL LETTER TSE
-      0x0447,0x8489,      // CYRILLIC SMALL LETTER CHE
-      0x0448,0x848A,      // CYRILLIC SMALL LETTER SHA
-      0x0449,0x848B,      // CYRILLIC SMALL LETTER SHCHA
-      0x044A,0x848C,      // CYRILLIC SMALL LETTER HARD SIGN
-      0x044B,0x848D,      // CYRILLIC SMALL LETTER YERU
-      0x044C,0x848E,      // CYRILLIC SMALL LETTER SOFT SIGN
-      0x044D,0x848F,      // CYRILLIC SMALL LETTER E
-      0x044E,0x8490,      // CYRILLIC SMALL LETTER YU
-      0x044F,0x8491,      // CYRILLIC SMALL LETTER YA
-      0x0451,0x8476,      // CYRILLIC SMALL LETTER IO
-      0x2010,0x815D,      // HYPHEN
-      0x2014,0x815C,      // EM DASH
-      0x2016,0x8161,      // DOUBLE VERTICAL LINE
-      0x2018,0x8165,      // LEFT SINGLE QUOTATION MARK
-      0x2019,0x8166,      // RIGHT SINGLE QUOTATION MARK
-      0x201C,0x8167,      // LEFT DOUBLE QUOTATION MARK
-      0x201D,0x8168,      // RIGHT DOUBLE QUOTATION MARK
-      0x2020,0x81F5,      // DAGGER
-      0x2021,0x81F6,      // DOUBLE DAGGER
-      0x2025,0x8164,      // TWO DOT LEADER
-      0x2026,0x8163,      // HORIZONTAL ELLIPSIS
-      0x2030,0x81F1,      // PER MILLE SIGN
-      0x2032,0x818C,      // PRIME
-      0x2033,0x818D,      // DOUBLE PRIME
-      0x203B,0x81A6,      // REFERENCE MARK
-      0x2103,0x818E,      // DEGREE CELSIUS
-      0x212B,0x81F0,      // ANGSTROM SIGN
-      0x2190,0x81A9,      // LEFTWARDS ARROW
-      0x2191,0x81AA,      // UPWARDS ARROW
-      0x2192,0x81A8,      // RIGHTWARDS ARROW
-      0x2193,0x81AB,      // DOWNWARDS ARROW
-      0x21D2,0x81CB,      // RIGHTWARDS DOUBLE ARROW
-      0x21D4,0x81CC,      // LEFT RIGHT DOUBLE ARROW
-      0x2200,0x81CD,      // FOR ALL
-      0x2202,0x81DD,      // PARTIAL DIFFERENTIAL
-      0x2203,0x81CE,      // THERE EXISTS
-      0x2207,0x81DE,      // NABLA
-      0x2208,0x81B8,      // ELEMENT OF
-      0x220B,0x81B9,      // CONTAINS AS MEMBER
-      0x2212,0x817C,      // MINUS SIGN
-      0x221A,0x81E3,      // SQUARE ROOT
-      0x221D,0x81E5,      // PROPORTIONAL TO
-      0x221E,0x8187,      // INFINITY
-      0x2220,0x81DA,      // ANGLE
-      0x2227,0x81C8,      // LOGICAL AND
-      0x2228,0x81C9,      // LOGICAL OR
-      0x2229,0x81BF,      // INTERSECTION
-      0x222A,0x81BE,      // UNION
-      0x222B,0x81E7,      // INTEGRAL
-      0x222C,0x81E8,      // DOUBLE INTEGRAL
-      0x2234,0x8188,      // THEREFORE
-      0x2235,0x81E6,      // BECAUSE
-      0x223D,0x81E4,      // REVERSED TILDE 
-      0x2252,0x81E0,      // APPROXIMATELY EQUAL TO OR THE IMAGE OF
-      0x2260,0x8182,      // NOT EQUAL TO
-      0x2261,0x81DF,      // IDENTICAL TO
-      0x2266,0x8185,      // LESS-THAN OVER EQUAL TO
-      0x2267,0x8186,      // GREATER-THAN OVER EQUAL TO
-      0x226A,0x81E1,      // MUCH LESS-THAN
-      0x226B,0x81E2,      // MUCH GREATER-THAN
-      0x2282,0x81BC,      // SUBSET OF
-      0x2283,0x81BD,      // SUPERSET OF
-      0x2286,0x81BA,      // SUBSET OF OR EQUAL TO
-      0x2287,0x81BB,      // SUPERSET OF OR EQUAL TO
-      0x22A5,0x81DB,      // UP TACK
-      0x2312,0x81DC,      // ARC
-      0x2500,0x849F,      // BOX DRAWINGS LIGHT HORIZONTAL
-      0x2501,0x84AA,      // BOX DRAWINGS HEAVY HORIZONTAL
-      0x2502,0x84A0,      // BOX DRAWINGS LIGHT VERTICAL
-      0x2503,0x84AB,      // BOX DRAWINGS HEAVY VERTICAL
-      0x250C,0x84A1,      // BOX DRAWINGS LIGHT DOWN AND RIGHT
-      0x250F,0x84AC,      // BOX DRAWINGS HEAVY DOWN AND RIGHT
-      0x2510,0x84A2,      // BOX DRAWINGS LIGHT DOWN AND LEFT
-      0x2513,0x84AD,      // BOX DRAWINGS HEAVY DOWN AND LEFT
-      0x2514,0x84A4,      // BOX DRAWINGS LIGHT UP AND RIGHT
-      0x2517,0x84AF,      // BOX DRAWINGS HEAVY UP AND RIGHT
-      0x2518,0x84A3,      // BOX DRAWINGS LIGHT UP AND LEFT
-      0x251B,0x84AE,      // BOX DRAWINGS HEAVY UP AND LEFT
-      0x251C,0x84A5,      // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
-      0x251D,0x84BA,      // BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY
-      0x2520,0x84B5,      // BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT
-      0x2523,0x84B0,      // BOX DRAWINGS HEAVY VERTICAL AND RIGHT
-      0x2524,0x84A7,      // BOX DRAWINGS LIGHT VERTICAL AND LEFT
-      0x2525,0x84BC,      // BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY
-      0x2528,0x84B7,      // BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT
-      0x252B,0x84B2,      // BOX DRAWINGS HEAVY VERTICAL AND LEFT
-      0x252C,0x84A6,      // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
-      0x252F,0x84B6,      // BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY
-      0x2530,0x84BB,      // BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT
-      0x2533,0x84B1,      // BOX DRAWINGS HEAVY DOWN AND HORIZONTAL
-      0x2534,0x84A8,      // BOX DRAWINGS LIGHT UP AND HORIZONTAL
-      0x2537,0x84B8,      // BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY
-      0x2538,0x84BD,      // BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT
-      0x253B,0x84B3,      // BOX DRAWINGS HEAVY UP AND HORIZONTAL
-      0x253C,0x84A9,      // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
-      0x253F,0x84B9,      // BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY
-      0x2542,0x84BE,      // BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT
-      0x254B,0x84B4,      // BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL
-      0x25A0,0x81A1,      // BLACK SQUARE
-      0x25A1,0x81A0,      // WHITE SQUARE
-      0x25B2,0x81A3,      // BLACK UP-POINTING TRIANGLE
-      0x25B3,0x81A2,      // WHITE UP-POINTING TRIANGLE
-      0x25BC,0x81A5,      // BLACK DOWN-POINTING TRIANGLE
-      0x25BD,0x81A4,      // WHITE DOWN-POINTING TRIANGLE
-      0x25C6,0x819F,      // BLACK DIAMOND
-      0x25C7,0x819E,      // WHITE DIAMOND
-      0x25CB,0x819B,      // WHITE CIRCLE
-      0x25CE,0x819D,      // BULLSEYE
-      0x25CF,0x819C,      // BLACK CIRCLE
-      0x25EF,0x81FC,      // LARGE CIRCLE
-      0x2605,0x819A,      // BLACK STAR
-      0x2606,0x8199,      // WHITE STAR
-      0x2640,0x818A,      // FEMALE SIGN
-      0x2642,0x8189,      // MALE SIGN
-      0x266A,0x81F4,      // EIGHTH NOTE
-      0x266D,0x81F3,      // MUSIC FLAT SIGN
-      0x266F,0x81F2,      // MUSIC SHARP SIGN
-      0x3000,0x8140,      // IDEOGRAPHIC SPACE
-      0x3001,0x8141,      // IDEOGRAPHIC COMMA
-      0x3002,0x8142,      // IDEOGRAPHIC FULL STOP
-      0x3003,0x8156,      // DITTO MARK
-      0x3005,0x8158,      // IDEOGRAPHIC ITERATION MARK
-      0x3006,0x8159,      // IDEOGRAPHIC CLOSING MARK
-      0x3007,0x815A,      // IDEOGRAPHIC NUMBER ZERO
-      0x3008,0x8171,      // LEFT ANGLE BRACKET
-      0x3009,0x8172,      // RIGHT ANGLE BRACKET
-      0x300A,0x8173,      // LEFT DOUBLE ANGLE BRACKET
-      0x300B,0x8174,      // RIGHT DOUBLE ANGLE BRACKET
-      0x300C,0x8175,      // LEFT CORNER BRACKET
-      0x300D,0x8176,      // RIGHT CORNER BRACKET
-      0x300E,0x8177,      // LEFT WHITE CORNER BRACKET
-      0x300F,0x8178,      // RIGHT WHITE CORNER BRACKET
-      0x3010,0x8179,      // LEFT BLACK LENTICULAR BRACKET
-      0x3011,0x817A,      // RIGHT BLACK LENTICULAR BRACKET
-      0x3012,0x81A7,      // POSTAL MARK
-      0x3013,0x81AC,      // GETA MARK
-      0x3014,0x816B,      // LEFT TORTOISE SHELL BRACKET
-      0x3015,0x816C,      // RIGHT TORTOISE SHELL BRACKET
-      0x301C,0x8160,      // WAVE DASH
-      0x3041,0x829F,      // HIRAGANA LETTER SMALL A
-      0x3042,0x82A0,      // HIRAGANA LETTER A
-      0x3043,0x82A1,      // HIRAGANA LETTER SMALL I
-      0x3044,0x82A2,      // HIRAGANA LETTER I
-      0x3045,0x82A3,      // HIRAGANA LETTER SMALL U
-      0x3046,0x82A4,      // HIRAGANA LETTER U
-      0x3047,0x82A5,      // HIRAGANA LETTER SMALL E
-      0x3048,0x82A6,      // HIRAGANA LETTER E
-      0x3049,0x82A7,      // HIRAGANA LETTER SMALL O
-      0x304A,0x82A8,      // HIRAGANA LETTER O
-      0x304B,0x82A9,      // HIRAGANA LETTER KA
-      0x304C,0x82AA,      // HIRAGANA LETTER GA
-      0x304D,0x82AB,      // HIRAGANA LETTER KI
-      0x304E,0x82AC,      // HIRAGANA LETTER GI
-      0x304F,0x82AD,      // HIRAGANA LETTER KU
-      0x3050,0x82AE,      // HIRAGANA LETTER GU
-      0x3051,0x82AF,      // HIRAGANA LETTER KE
-      0x3052,0x82B0,      // HIRAGANA LETTER GE
-      0x3053,0x82B1,      // HIRAGANA LETTER KO
-      0x3054,0x82B2,      // HIRAGANA LETTER GO
-      0x3055,0x82B3,      // HIRAGANA LETTER SA
-      0x3056,0x82B4,      // HIRAGANA LETTER ZA
-      0x3057,0x82B5,      // HIRAGANA LETTER SI
-      0x3058,0x82B6,      // HIRAGANA LETTER ZI
-      0x3059,0x82B7,      // HIRAGANA LETTER SU
-      0x305A,0x82B8,      // HIRAGANA LETTER ZU
-      0x305B,0x82B9,      // HIRAGANA LETTER SE
-      0x305C,0x82BA,      // HIRAGANA LETTER ZE
-      0x305D,0x82BB,      // HIRAGANA LETTER SO
-      0x305E,0x82BC,      // HIRAGANA LETTER ZO
-      0x305F,0x82BD,      // HIRAGANA LETTER TA
-      0x3060,0x82BE,      // HIRAGANA LETTER DA
-      0x3061,0x82BF,      // HIRAGANA LETTER TI
-      0x3062,0x82C0,      // HIRAGANA LETTER DI
-      0x3063,0x82C1,      // HIRAGANA LETTER SMALL TU
-      0x3064,0x82C2,      // HIRAGANA LETTER TU
-      0x3065,0x82C3,      // HIRAGANA LETTER DU
-      0x3066,0x82C4,      // HIRAGANA LETTER TE
-      0x3067,0x82C5,      // HIRAGANA LETTER DE
-      0x3068,0x82C6,      // HIRAGANA LETTER TO
-      0x3069,0x82C7,      // HIRAGANA LETTER DO
-      0x306A,0x82C8,      // HIRAGANA LETTER NA
-      0x306B,0x82C9,      // HIRAGANA LETTER NI
-      0x306C,0x82CA,      // HIRAGANA LETTER NU
-      0x306D,0x82CB,      // HIRAGANA LETTER NE
-      0x306E,0x82CC,      // HIRAGANA LETTER NO
-      0x306F,0x82CD,      // HIRAGANA LETTER HA
-      0x3070,0x82CE,      // HIRAGANA LETTER BA
-      0x3071,0x82CF,      // HIRAGANA LETTER PA
-      0x3072,0x82D0,      // HIRAGANA LETTER HI
-      0x3073,0x82D1,      // HIRAGANA LETTER BI
-      0x3074,0x82D2,      // HIRAGANA LETTER PI
-      0x3075,0x82D3,      // HIRAGANA LETTER HU
-      0x3076,0x82D4,      // HIRAGANA LETTER BU
-      0x3077,0x82D5,      // HIRAGANA LETTER PU
-      0x3078,0x82D6,      // HIRAGANA LETTER HE
-      0x3079,0x82D7,      // HIRAGANA LETTER BE
-      0x307A,0x82D8,      // HIRAGANA LETTER PE
-      0x307B,0x82D9,      // HIRAGANA LETTER HO
-      0x307C,0x82DA,      // HIRAGANA LETTER BO
-      0x307D,0x82DB,      // HIRAGANA LETTER PO
-      0x307E,0x82DC,      // HIRAGANA LETTER MA
-      0x307F,0x82DD,      // HIRAGANA LETTER MI
-      0x3080,0x82DE,      // HIRAGANA LETTER MU
-      0x3081,0x82DF,      // HIRAGANA LETTER ME
-      0x3082,0x82E0,      // HIRAGANA LETTER MO
-      0x3083,0x82E1,      // HIRAGANA LETTER SMALL YA
-      0x3084,0x82E2,      // HIRAGANA LETTER YA
-      0x3085,0x82E3,      // HIRAGANA LETTER SMALL YU
-      0x3086,0x82E4,      // HIRAGANA LETTER YU
-      0x3087,0x82E5,      // HIRAGANA LETTER SMALL YO
-      0x3088,0x82E6,      // HIRAGANA LETTER YO
-      0x3089,0x82E7,      // HIRAGANA LETTER RA
-      0x308A,0x82E8,      // HIRAGANA LETTER RI
-      0x308B,0x82E9,      // HIRAGANA LETTER RU
-      0x308C,0x82EA,      // HIRAGANA LETTER RE
-      0x308D,0x82EB,      // HIRAGANA LETTER RO
-      0x308E,0x82EC,      // HIRAGANA LETTER SMALL WA
-      0x308F,0x82ED,      // HIRAGANA LETTER WA
-      0x3090,0x82EE,      // HIRAGANA LETTER WI
-      0x3091,0x82EF,      // HIRAGANA LETTER WE
-      0x3092,0x82F0,      // HIRAGANA LETTER WO
-      0x3093,0x82F1,      // HIRAGANA LETTER N
-      0x309B,0x814A,      // KATAKANA-HIRAGANA VOICED SOUND MARK
-      0x309C,0x814B,      // KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
-      0x309D,0x8154,      // HIRAGANA ITERATION MARK
-      0x309E,0x8155,      // HIRAGANA VOICED ITERATION MARK
-      0x30A1,0x8340,      // KATAKANA LETTER SMALL A
-      0x30A2,0x8341,      // KATAKANA LETTER A
-      0x30A3,0x8342,      // KATAKANA LETTER SMALL I
-      0x30A4,0x8343,      // KATAKANA LETTER I
-      0x30A5,0x8344,      // KATAKANA LETTER SMALL U
-      0x30A6,0x8345,      // KATAKANA LETTER U
-      0x30A7,0x8346,      // KATAKANA LETTER SMALL E
-      0x30A8,0x8347,      // KATAKANA LETTER E
-      0x30A9,0x8348,      // KATAKANA LETTER SMALL O
-      0x30AA,0x8349,      // KATAKANA LETTER O
-      0x30AB,0x834A,      // KATAKANA LETTER KA
-      0x30AC,0x834B,      // KATAKANA LETTER GA
-      0x30AD,0x834C,      // KATAKANA LETTER KI
-      0x30AE,0x834D,      // KATAKANA LETTER GI
-      0x30AF,0x834E,      // KATAKANA LETTER KU
-      0x30B0,0x834F,      // KATAKANA LETTER GU
-      0x30B1,0x8350,      // KATAKANA LETTER KE
-      0x30B2,0x8351,      // KATAKANA LETTER GE
-      0x30B3,0x8352,      // KATAKANA LETTER KO
-      0x30B4,0x8353,      // KATAKANA LETTER GO
-      0x30B5,0x8354,      // KATAKANA LETTER SA
-      0x30B6,0x8355,      // KATAKANA LETTER ZA
-      0x30B7,0x8356,      // KATAKANA LETTER SI
-      0x30B8,0x8357,      // KATAKANA LETTER ZI
-      0x30B9,0x8358,      // KATAKANA LETTER SU
-      0x30BA,0x8359,      // KATAKANA LETTER ZU
-      0x30BB,0x835A,      // KATAKANA LETTER SE
-      0x30BD,0x835C,      // KATAKANA LETTER SO
-      0x30BE,0x835D,      // KATAKANA LETTER ZO
-      0x30BF,0x835E,      // KATAKANA LETTER TA
-      0x30C0,0x835F,      // KATAKANA LETTER DA
-      0x30C1,0x8360,      // KATAKANA LETTER TI
-      0x30C2,0x8361,      // KATAKANA LETTER DI
-      0x30C3,0x8362,      // KATAKANA LETTER SMALL TU
-      0x30C4,0x8363,      // KATAKANA LETTER TU
-      0x30C5,0x8364,      // KATAKANA LETTER DU
-      0x30C6,0x8365,      // KATAKANA LETTER TE
-      0x30C7,0x8366,      // KATAKANA LETTER DE
-      0x30C8,0x8367,      // KATAKANA LETTER TO
-      0x30C9,0x8368,      // KATAKANA LETTER DO
-      0x30CA,0x8369,      // KATAKANA LETTER NA
-      0x30CB,0x836A,      // KATAKANA LETTER NI
-      0x30CC,0x836B,      // KATAKANA LETTER NU
-      0x30CD,0x836C,      // KATAKANA LETTER NE
-      0x30CE,0x836D,      // KATAKANA LETTER NO
-      0x30CF,0x836E,      // KATAKANA LETTER HA
-      0x30D0,0x836F,      // KATAKANA LETTER BA
-      0x30D1,0x8370,      // KATAKANA LETTER PA
-      0x30D2,0x8371,      // KATAKANA LETTER HI
-      0x30D3,0x8372,      // KATAKANA LETTER BI
-      0x30D4,0x8373,      // KATAKANA LETTER PI
-      0x30D5,0x8374,      // KATAKANA LETTER HU
-      0x30D6,0x8375,      // KATAKANA LETTER BU
-      0x30D7,0x8376,      // KATAKANA LETTER PU
-      0x30D8,0x8377,      // KATAKANA LETTER HE
-      0x30D9,0x8378,      // KATAKANA LETTER BE
-      0x30DA,0x8379,      // KATAKANA LETTER PE
-      0x30DB,0x837A,      // KATAKANA LETTER HO
-      0x30DC,0x837B,      // KATAKANA LETTER BO
-      0x30DD,0x837C,      // KATAKANA LETTER PO
-      0x30DE,0x837D,      // KATAKANA LETTER MA
-      0x30DF,0x837E,      // KATAKANA LETTER MI
-      0x30E0,0x8380,      // KATAKANA LETTER MU
-      0x30E1,0x8381,      // KATAKANA LETTER ME
-      0x30E2,0x8382,      // KATAKANA LETTER MO
-      0x30E3,0x8383,      // KATAKANA LETTER SMALL YA
-      0x30E4,0x8384,      // KATAKANA LETTER YA
-      0x30E5,0x8385,      // KATAKANA LETTER SMALL YU
-      0x30E6,0x8386,      // KATAKANA LETTER YU
-      0x30E7,0x8387,      // KATAKANA LETTER SMALL YO
-      0x30E8,0x8388,      // KATAKANA LETTER YO
-      0x30E9,0x8389,      // KATAKANA LETTER RA
-      0x30EA,0x838A,      // KATAKANA LETTER RI
-      0x30EB,0x838B,      // KATAKANA LETTER RU
-      0x30EC,0x838C,      // KATAKANA LETTER RE
-      0x30ED,0x838D,      // KATAKANA LETTER RO
-      0x30EE,0x838E,      // KATAKANA LETTER SMALL WA
-      0x30EF,0x838F,      // KATAKANA LETTER WA
-      0x30F0,0x8390,      // KATAKANA LETTER WI
-      0x30F1,0x8391,      // KATAKANA LETTER WE
-      0x30F2,0x8392,      // KATAKANA LETTER WO
-      0x30F3,0x8393,      // KATAKANA LETTER N
-      0x30F4,0x8394,      // KATAKANA LETTER VU
-      0x30F5,0x8395,      // KATAKANA LETTER SMALL KA
-      0x30F6,0x8396,      // KATAKANA LETTER SMALL KE
-      0x30FB,0x8145,      // KATAKANA MIDDLE DOT
-      0x30FD,0x8152,      // KATAKANA ITERATION MARK
-      0x30FE,0x8153,      // KATAKANA VOICED ITERATION MARK
-      0x4E00,0x88EA,      // <cjk>
-      0x4E01,0x929A,      // <cjk>
-      0x4E03,0x8EB5,      // <cjk>
-      0x4E07,0x969C,      // <cjk>
-      0x4E08,0x8FE4,      // <cjk>
-      0x4E09,0x8E4F,      // <cjk>
-      0x4E0A,0x8FE3,      // <cjk>
-      0x4E0B,0x89BA,      // <cjk>
-      0x4E0D,0x9573,      // <cjk>
-      0x4E0E,0x975E,      // <cjk>
-      0x4E10,0x98A0,      // <cjk>
-      0x4E11,0x894E,      // <cjk>
-      0x4E14,0x8A8E,      // <cjk>
-      0x4E15,0x98A1,      // <cjk>
-      0x4E16,0x90A2,      // <cjk>
-      0x4E17,0x99C0,      // <cjk>
-      0x4E18,0x8B75,      // <cjk>
-      0x4E19,0x95B8,      // <cjk>
-      0x4E1E,0x8FE5,      // <cjk>
-      0x4E21,0x97BC,      // <cjk>
-      0x4E26,0x95C0,      // <cjk>
-      0x4E2A,0x98A2,      // <cjk>
-      0x4E2D,0x9286,      // <cjk>
-      0x4E31,0x98A3,      // <cjk>
-      0x4E32,0x8BF8,      // <cjk>
-      0x4E36,0x98A4,      // <cjk>
-      0x4E38,0x8ADB,      // <cjk>
-      0x4E39,0x924F,      // <cjk>
-      0x4E3B,0x8EE5,      // <cjk>
-      0x4E3C,0x98A5,      // <cjk>
-      0x4E3F,0x98A6,      // <cjk>
-      0x4E42,0x98A7,      // <cjk>
-      0x4E43,0x9454,      // <cjk>
-      0x4E45,0x8B76,      // <cjk>
-      0x4E4B,0x9456,      // <cjk>
-      0x4E4D,0x93E1,      // <cjk>
-      0x4E4E,0x8CC1,      // <cjk>
-      0x4E4F,0x9652,      // <cjk>
-      0x4E55,0xE568,      // <cjk>
-      0x4E56,0x98A8,      // <cjk>
-      0x4E57,0x8FE6,      // <cjk>
-      0x4E58,0x98A9,      // <cjk>
-      0x4E59,0x89B3,      // <cjk>
-      0x4E5D,0x8BE3,      // <cjk>
-      0x4E5E,0x8CEE,      // <cjk>
-      0x4E5F,0x96E7,      // <cjk>
-      0x4E62,0x9BA4,      // <cjk>
-      0x4E71,0x9790,      // <cjk>
-      0x4E73,0x93FB,      // <cjk>
-      0x4E7E,0x8AA3,      // <cjk>
-      0x4E80,0x8B54,      // <cjk>
-      0x4E82,0x98AA,      // <cjk>
-      0x4E85,0x98AB,      // <cjk>
-      0x4E86,0x97B9,      // <cjk>
-      0x4E88,0x975C,      // <cjk>
-      0x4E89,0x9188,      // <cjk>
-      0x4E8A,0x98AD,      // <cjk>
-      0x4E8B,0x8E96,      // <cjk>
-      0x4E8C,0x93F1,      // <cjk>
-      0x4E8E,0x98B0,      // <cjk>
-      0x4E91,0x895D,      // <cjk>
-      0x4E92,0x8CDD,      // <cjk>
-      0x4E94,0x8CDC,      // <cjk>
-      0x4E95,0x88E4,      // <cjk>
-      0x4E98,0x986A,      // <cjk>
-      0x4E99,0x9869,      // <cjk>
-      0x4E9B,0x8DB1,      // <cjk>
-      0x4E9C,0x889F,      // <cjk>
-      0x4E9E,0x98B1,      // <cjk>
-      0x4E9F,0x98B2,      // <cjk>
-      0x4EA0,0x98B3,      // <cjk>
-      0x4EA1,0x9653,      // <cjk>
-      0x4EA2,0x98B4,      // <cjk>
-      0x4EA4,0x8CF0,      // <cjk>
-      0x4EA5,0x88E5,      // <cjk>
-      0x4EA6,0x9692,      // <cjk>
-      0x4EA8,0x8B9C,      // <cjk>
-      0x4EAB,0x8B9D,      // <cjk>
-      0x4EAC,0x8B9E,      // <cjk>
-      0x4EAD,0x92E0,      // <cjk>
-      0x4EAE,0x97BA,      // <cjk>
-      0x4EB0,0x98B5,      // <cjk>
-      0x4EB3,0x98B6,      // <cjk>
-      0x4EB6,0x98B7,      // <cjk>
-      0x4EBA,0x906C,      // <cjk>
-      0x4EC0,0x8F59,      // <cjk>
-      0x4EC1,0x906D,      // <cjk>
-      0x4EC2,0x98BC,      // <cjk>
-      0x4EC4,0x98BA,      // <cjk>
-      0x4EC6,0x98BB,      // <cjk>
-      0x4EC7,0x8B77,      // <cjk>
-      0x4ECA,0x8DA1,      // <cjk>
-      0x4ECB,0x89EE,      // <cjk>
-      0x4ECD,0x98B9,      // <cjk>
-      0x4ECE,0x98B8,      // <cjk>
-      0x4ECF,0x95A7,      // <cjk>
-      0x4ED4,0x8E65,      // <cjk>
-      0x4ED5,0x8E64,      // <cjk>
-      0x4ED6,0x91BC,      // <cjk>
-      0x4ED7,0x98BD,      // <cjk>
-      0x4ED8,0x9574,      // <cjk>
-      0x4ED9,0x90E5,      // <cjk>
-      0x4EDD,0x8157,      // <cjk>
-      0x4EDE,0x98BE,      // <cjk>
-      0x4EDF,0x98C0,      // <cjk>
-      0x4EE3,0x91E3,      // <cjk>
-      0x4EE4,0x97DF,      // <cjk>
-      0x4EE5,0x88C8,      // <cjk>
-      0x4EED,0x98BF,      // <cjk>
-      0x4EEE,0x89BC,      // <cjk>
-      0x4EF0,0x8BC2,      // <cjk>
-      0x4EF2,0x9287,      // <cjk>
-      0x4EF6,0x8C8F,      // <cjk>
-      0x4EF7,0x98C1,      // <cjk>
-      0x4EFB,0x9443,      // <cjk>
-      0x4F01,0x8AE9,      // <cjk>
-      0x4F09,0x98C2,      // <cjk>
-      0x4F0A,0x88C9,      // <cjk>
-      0x4F0D,0x8CDE,      // <cjk>
-      0x4F0E,0x8AEA,      // <cjk>
-      0x4F0F,0x959A,      // <cjk>
-      0x4F10,0x94B0,      // <cjk>
-      0x4F11,0x8B78,      // <cjk>
-      0x4F1A,0x89EF,      // <cjk>
-      0x4F1C,0x98E5,      // <cjk>
-      0x4F1D,0x9360,      // <cjk>
-      0x4F2F,0x948C,      // <cjk>
-      0x4F30,0x98C4,      // <cjk>
-      0x4F34,0x94BA,      // <cjk>
-      0x4F36,0x97E0,      // <cjk>
-      0x4F38,0x904C,      // <cjk>
-      0x4F3A,0x8E66,      // <cjk>
-      0x4F3C,0x8E97,      // <cjk>
-      0x4F3D,0x89BE,      // <cjk>
-      0x4F43,0x92CF,      // <cjk>
-      0x4F46,0x9241,      // <cjk>
-      0x4F47,0x98C8,      // <cjk>
-      0x4F4D,0x88CA,      // <cjk>
-      0x4F4E,0x92E1,      // <cjk>
-      0x4F4F,0x8F5A,      // <cjk>
-      0x4F50,0x8DB2,      // <cjk>
-      0x4F51,0x9743,      // <cjk>
-      0x4F53,0x91CC,      // <cjk>
-      0x4F55,0x89BD,      // <cjk>
-      0x4F57,0x98C7,      // <cjk>
-      0x4F59,0x975D,      // <cjk>
-      0x4F5A,0x98C3,      // <cjk>
-      0x4F5B,0x98C5,      // <cjk>
-      0x4F5C,0x8DEC,      // <cjk>
-      0x4F5D,0x98C6,      // <cjk>
-      0x4F5E,0x9B43,      // <cjk>
-      0x4F69,0x98CE,      // <cjk>
-      0x4F6F,0x98D1,      // <cjk>
-      0x4F70,0x98CF,      // <cjk>
-      0x4F73,0x89C0,      // <cjk>
-      0x4F75,0x95B9,      // <cjk>
-      0x4F76,0x98C9,      // <cjk>
-      0x4F7B,0x98CD,      // <cjk>
-      0x4F7C,0x8CF1,      // <cjk>
-      0x4F7F,0x8E67,      // <cjk>
-      0x4F83,0x8AA4,      // <cjk>
-      0x4F86,0x98D2,      // <cjk>
-      0x4F88,0x98CA,      // <cjk>
-      0x4F8B,0x97E1,      // <cjk>
-      0x4F8D,0x8E98,      // <cjk>
-      0x4F8F,0x98CB,      // <cjk>
-      0x4F91,0x98D0,      // <cjk>
-      0x4F96,0x98D3,      // <cjk>
-      0x4F98,0x98CC,      // <cjk>
-      0x4F9B,0x8B9F,      // <cjk>
-      0x4F9D,0x88CB,      // <cjk>
-      0x4FA0,0x8BA0,      // <cjk>
-      0x4FA1,0x89BF,      // <cjk>
-      0x4FAB,0x9B44,      // <cjk>
-      0x4FAD,0x9699,      // <cjk>
-      0x4FAE,0x958E,      // <cjk>
-      0x4FAF,0x8CF2,      // <cjk>
-      0x4FB5,0x904E,      // <cjk>
-      0x4FB6,0x97B5,      // <cjk>
-      0x4FBF,0x95D6,      // <cjk>
-      0x4FC2,0x8C57,      // <cjk>
-      0x4FC3,0x91A3,      // <cjk>
-      0x4FC4,0x89E2,      // <cjk>
-      0x4FCA,0x8F72,      // <cjk>
-      0x4FCE,0x98D7,      // <cjk>
-      0x4FD0,0x98DC,      // <cjk>
-      0x4FD1,0x98DA,      // <cjk>
-      0x4FD4,0x98D5,      // <cjk>
-      0x4FD7,0x91AD,      // <cjk>
-      0x4FD8,0x98D8,      // <cjk>
-      0x4FDA,0x98DB,      // <cjk>
-      0x4FDB,0x98D9,      // <cjk>
-      0x4FDD,0x95DB,      // <cjk>
-      0x4FDF,0x98D6,      // <cjk>
-      0x4FE1,0x904D,      // <cjk>
-      0x4FE3,0x9693,      // <cjk>
-      0x4FE4,0x98DD,      // <cjk>
-      0x4FE5,0x98DE,      // <cjk>
-      0x4FEE,0x8F43,      // <cjk>
-      0x4FEF,0x98EB,      // <cjk>
-      0x4FF3,0x946F,      // <cjk>
-      0x4FF5,0x9555,      // <cjk>
-      0x4FF6,0x98E6,      // <cjk>
-      0x4FF8,0x95EE,      // <cjk>
-      0x4FFA,0x89B4,      // <cjk>
-      0x4FFE,0x98EA,      // <cjk>
-      0x5005,0x98E4,      // <cjk>
-      0x5006,0x98ED,      // <cjk>
-      0x5009,0x9171,      // <cjk>
-      0x500B,0x8CC2,      // <cjk>
-      0x500D,0x947B,      // <cjk>
-      0x500F,0xE0C5,      // <cjk>
-      0x5011,0x98EC,      // <cjk>
-      0x5012,0x937C,      // <cjk>
-      0x5014,0x98E1,      // <cjk>
-      0x5016,0x8CF4,      // <cjk>
-      0x5019,0x8CF3,      // <cjk>
-      0x501A,0x98DF,      // <cjk>
-      0x501F,0x8ED8,      // <cjk>
-      0x5021,0x98E7,      // <cjk>
-      0x5023,0x95ED,      // <cjk>
-      0x5024,0x926C,      // <cjk>
-      0x5025,0x98E3,      // <cjk>
-      0x5026,0x8C91,      // <cjk>
-      0x5028,0x98E0,      // <cjk>
-      0x5029,0x98E8,      // <cjk>
-      0x502A,0x98E2,      // <cjk>
-      0x502B,0x97CF,      // <cjk>
-      0x502C,0x98E9,      // <cjk>
-      0x502D,0x9860,      // <cjk>
-      0x5036,0x8BE4,      // <cjk>
-      0x5039,0x8C90,      // <cjk>
-      0x5043,0x98EE,      // <cjk>
-      0x5047,0x98EF,      // <cjk>
-      0x5048,0x98F3,      // <cjk>
-      0x5049,0x88CC,      // <cjk>
-      0x504F,0x95CE,      // <cjk>
-      0x5050,0x98F2,      // <cjk>
-      0x5055,0x98F1,      // <cjk>
-      0x5056,0x98F5,      // <cjk>
-      0x505A,0x98F4,      // <cjk>
-      0x505C,0x92E2,      // <cjk>
-      0x5065,0x8C92,      // <cjk>
-      0x506C,0x98F6,      // <cjk>
-      0x5072,0x8EC3,      // <cjk>
-      0x5074,0x91A4,      // <cjk>
-      0x5075,0x92E3,      // <cjk>
-      0x5076,0x8BF4,      // <cjk>
-      0x5078,0x98F7,      // <cjk>
-      0x507D,0x8B55,      // <cjk>
-      0x5080,0x98F8,      // <cjk>
-      0x5085,0x98FA,      // <cjk>
-      0x508D,0x9654,      // <cjk>
-      0x5091,0x8C86,      // <cjk>
-      0x5098,0x8E50,      // <cjk>
-      0x5099,0x94F5,      // <cjk>
-      0x509A,0x98F9,      // <cjk>
-      0x50AC,0x8DC3,      // <cjk>
-      0x50AD,0x9762,      // <cjk>
-      0x50B2,0x98FC,      // <cjk>
-      0x50B3,0x9942,      // <cjk>
-      0x50B4,0x98FB,      // <cjk>
-      0x50B5,0x8DC2,      // <cjk>
-      0x50B7,0x8F9D,      // <cjk>
-      0x50BE,0x8C58,      // <cjk>
-      0x50C2,0x9943,      // <cjk>
-      0x50C5,0x8BCD,      // <cjk>
-      0x50C9,0x9940,      // <cjk>
-      0x50CA,0x9941,      // <cjk>
-      0x50CD,0x93AD,      // <cjk>
-      0x50CF,0x919C,      // <cjk>
-      0x50D1,0x8BA1,      // <cjk>
-      0x50D5,0x966C,      // <cjk>
-      0x50D6,0x9944,      // <cjk>
-      0x50DA,0x97BB,      // <cjk>
-      0x50DE,0x9945,      // <cjk>
-      0x50E3,0x9948,      // <cjk>
-      0x50E5,0x9946,      // <cjk>
-      0x50E7,0x916D,      // <cjk>
-      0x50ED,0x9947,      // <cjk>
-      0x50EE,0x9949,      // <cjk>
-      0x50F5,0x994B,      // <cjk>
-      0x50F9,0x994A,      // <cjk>
-      0x50FB,0x95C6,      // <cjk>
-      0x5100,0x8B56,      // <cjk>
-      0x5101,0x994D,      // <cjk>
-      0x5102,0x994E,      // <cjk>
-      0x5104,0x89AD,      // <cjk>
-      0x5109,0x994C,      // <cjk>
-      0x5112,0x8EF2,      // <cjk>
-      0x5114,0x9951,      // <cjk>
-      0x5115,0x9950,      // <cjk>
-      0x5116,0x994F,      // <cjk>
-      0x5118,0x98D4,      // <cjk>
-      0x511A,0x9952,      // <cjk>
-      0x511F,0x8F9E,      // <cjk>
-      0x5121,0x9953,      // <cjk>
-      0x512A,0x9744,      // <cjk>
-      0x5132,0x96D7,      // <cjk>
-      0x5137,0x9955,      // <cjk>
-      0x513A,0x9954,      // <cjk>
-      0x513B,0x9957,      // <cjk>
-      0x513C,0x9956,      // <cjk>
-      0x513F,0x9958,      // <cjk>
-      0x5140,0x9959,      // <cjk>
-      0x5141,0x88F2,      // <cjk>
-      0x5143,0x8CB3,      // <cjk>
-      0x5144,0x8C5A,      // <cjk>
-      0x5146,0x929B,      // <cjk>
-      0x5147,0x8BA2,      // <cjk>
-      0x5148,0x90E6,      // <cjk>
-      0x5149,0x8CF5,      // <cjk>
-      0x514B,0x8D8E,      // <cjk>
-      0x514D,0x96C6,      // <cjk>
-      0x514E,0x9365,      // <cjk>
-      0x5150,0x8E99,      // <cjk>
-      0x5152,0x995A,      // <cjk>
-      0x5154,0x995C,      // <cjk>
-      0x515A,0x937D,      // <cjk>
-      0x515C,0x8A95,      // <cjk>
-      0x5162,0x995D,      // <cjk>
-      0x5165,0x93FC,      // <cjk>
-      0x5168,0x9153,      // <cjk>
-      0x5169,0x995F,      // <cjk>
-      0x516A,0x9960,      // <cjk>
-      0x516B,0x94AA,      // <cjk>
-      0x516C,0x8CF6,      // <cjk>
-      0x516D,0x985A,      // <cjk>
-      0x516E,0x9961,      // <cjk>
-      0x5171,0x8BA4,      // <cjk>
-      0x5175,0x95BA,      // <cjk>
-      0x5176,0x91B4,      // <cjk>
-      0x5177,0x8BEF,      // <cjk>
-      0x5178,0x9354,      // <cjk>
-      0x517C,0x8C93,      // <cjk>
-      0x5180,0x9962,      // <cjk>
-      0x5182,0x9963,      // <cjk>
-      0x5185,0x93E0,      // <cjk>
-      0x5186,0x897E,      // <cjk>
-      0x5189,0x9966,      // <cjk>
-      0x518A,0x8DFB,      // <cjk>
-      0x518C,0x9965,      // <cjk>
-      0x518D,0x8DC4,      // <cjk>
-      0x518F,0x9967,      // <cjk>
-      0x5190,0xE3EC,      // <cjk>
-      0x5191,0x9968,      // <cjk>
-      0x5192,0x9660,      // <cjk>
-      0x5193,0x9969,      // <cjk>
-      0x5195,0x996A,      // <cjk>
-      0x5196,0x996B,      // <cjk>
-      0x5197,0x8FE7,      // <cjk>
-      0x5199,0x8ECA,      // <cjk>
-      0x51A0,0x8AA5,      // <cjk>
-      0x51A2,0x996E,      // <cjk>
-      0x51A4,0x996C,      // <cjk>
-      0x51A5,0x96BB,      // <cjk>
-      0x51A6,0x996D,      // <cjk>
-      0x51A8,0x9579,      // <cjk>
-      0x51A9,0x996F,      // <cjk>
-      0x51AA,0x9970,      // <cjk>
-      0x51AB,0x9971,      // <cjk>
-      0x51AC,0x937E,      // <cjk>
-      0x51B0,0x9975,      // <cjk>
-      0x51B1,0x9973,      // <cjk>
-      0x51B2,0x9974,      // <cjk>
-      0x51B3,0x9972,      // <cjk>
-      0x51B4,0x8DE1,      // <cjk>
-      0x51B5,0x9976,      // <cjk>
-      0x51B6,0x96E8,      // <cjk>
-      0x51B7,0x97E2,      // <cjk>
-      0x51BD,0x9977,      // <cjk>
-      0x51C4,0x90A6,      // <cjk>
-      0x51C5,0x9978,      // <cjk>
-      0x51C6,0x8F79,      // <cjk>
-      0x51C9,0x9979,      // <cjk>
-      0x51CB,0x929C,      // <cjk>
-      0x51CC,0x97BD,      // <cjk>
-      0x51CD,0x9380,      // <cjk>
-      0x51D6,0x99C3,      // <cjk>
-      0x51DB,0x997A,      // <cjk>
-      0x51DC,0xEAA3,      // <cjk>
-      0x51DD,0x8BC3,      // <cjk>
-      0x51E0,0x997B,      // <cjk>
-      0x51E1,0x967D,      // <cjk>
-      0x51E6,0x8F88,      // <cjk>
-      0x51E7,0x91FA,      // <cjk>
-      0x51E9,0x997D,      // <cjk>
-      0x51EA,0x93E2,      // <cjk>
-      0x51ED,0x997E,      // <cjk>
-      0x51F0,0x9980,      // <cjk>
-      0x51F1,0x8A4D,      // <cjk>
-      0x51F5,0x9981,      // <cjk>
-      0x51F6,0x8BA5,      // <cjk>
-      0x51F8,0x93CA,      // <cjk>
-      0x51F9,0x899A,      // <cjk>
-      0x51FA,0x8F6F,      // <cjk>
-      0x51FD,0x949F,      // <cjk>
-      0x51FE,0x9982,      // <cjk>
-      0x5200,0x9381,      // <cjk>
-      0x5203,0x906E,      // <cjk>
-      0x5204,0x9983,      // <cjk>
-      0x5206,0x95AA,      // <cjk>
-      0x5207,0x90D8,      // <cjk>
-      0x5208,0x8AA0,      // <cjk>
-      0x520A,0x8AA7,      // <cjk>
-      0x520B,0x9984,      // <cjk>
-      0x520E,0x9986,      // <cjk>
-      0x5211,0x8C59,      // <cjk>
-      0x5214,0x9985,      // <cjk>
-      0x5217,0x97F1,      // <cjk>
-      0x521D,0x8F89,      // <cjk>
-      0x5224,0x94BB,      // <cjk>
-      0x5225,0x95CA,      // <cjk>
-      0x5227,0x9987,      // <cjk>
-      0x5229,0x9798,      // <cjk>
-      0x522A,0x9988,      // <cjk>
-      0x522E,0x9989,      // <cjk>
-      0x5230,0x939E,      // <cjk>
-      0x5233,0x998A,      // <cjk>
-      0x5236,0x90A7,      // <cjk>
-      0x5237,0x8DFC,      // <cjk>
-      0x5238,0x8C94,      // <cjk>
-      0x5239,0x998B,      // <cjk>
-      0x523A,0x8E68,      // <cjk>
-      0x523B,0x8D8F,      // <cjk>
-      0x5243,0x92E4,      // <cjk>
-      0x5244,0x998D,      // <cjk>
-      0x5247,0x91A5,      // <cjk>
-      0x524A,0x8DED,      // <cjk>
-      0x524B,0x998E,      // <cjk>
-      0x524C,0x998F,      // <cjk>
-      0x524D,0x914F,      // <cjk>
-      0x524F,0x998C,      // <cjk>
-      0x5254,0x9991,      // <cjk>
-      0x5256,0x9655,      // <cjk>
-      0x525B,0x8D84,      // <cjk>
-      0x525E,0x9990,      // <cjk>
-      0x5263,0x8C95,      // <cjk>
-      0x5264,0x8DDC,      // <cjk>
-      0x5265,0x948D,      // <cjk>
-      0x5269,0x9994,      // <cjk>
-      0x526A,0x9992,      // <cjk>
-      0x526F,0x959B,      // <cjk>
-      0x5270,0x8FE8,      // <cjk>
-      0x5271,0x999B,      // <cjk>
-      0x5272,0x8A84,      // <cjk>
-      0x5273,0x9995,      // <cjk>
-      0x5274,0x9993,      // <cjk>
-      0x5275,0x916E,      // <cjk>
-      0x527D,0x9997,      // <cjk>
-      0x527F,0x9996,      // <cjk>
-      0x5283,0x8A63,      // <cjk>
-      0x5287,0x8C80,      // <cjk>
-      0x5288,0x999C,      // <cjk>
-      0x5289,0x97AB,      // <cjk>
-      0x528D,0x9998,      // <cjk>
-      0x5291,0x999D,      // <cjk>
-      0x5292,0x999A,      // <cjk>
-      0x5294,0x9999,      // <cjk>
-      0x529B,0x97CD,      // <cjk>
-      0x529F,0x8CF7,      // <cjk>
-      0x52A0,0x89C1,      // <cjk>
-      0x52A3,0x97F2,      // <cjk>
-      0x52A9,0x8F95,      // <cjk>
-      0x52AA,0x9377,      // <cjk>
-      0x52AB,0x8D85,      // <cjk>
-      0x52AC,0x99A0,      // <cjk>
-      0x52AD,0x99A1,      // <cjk>
-      0x52B1,0x97E3,      // <cjk>
-      0x52B4,0x984A,      // <cjk>
-      0x52B5,0x99A3,      // <cjk>
-      0x52B9,0x8CF8,      // <cjk>
-      0x52BC,0x99A2,      // <cjk>
-      0x52BE,0x8A4E,      // <cjk>
-      0x52C1,0x99A4,      // <cjk>
-      0x52C3,0x9675,      // <cjk>
-      0x52C5,0x92BA,      // <cjk>
-      0x52C7,0x9745,      // <cjk>
-      0x52C9,0x95D7,      // <cjk>
-      0x52CD,0x99A5,      // <cjk>
-      0x52D2,0xE8D3,      // <cjk>
-      0x52D5,0x93AE,      // <cjk>
-      0x52D7,0x99A6,      // <cjk>
-      0x52D8,0x8AA8,      // <cjk>
-      0x52D9,0x96B1,      // <cjk>
-      0x52DD,0x8F9F,      // <cjk>
-      0x52DE,0x99A7,      // <cjk>
-      0x52DF,0x95E5,      // <cjk>
-      0x52E0,0x99AB,      // <cjk>
-      0x52E2,0x90A8,      // <cjk>
-      0x52E3,0x99A8,      // <cjk>
-      0x52E4,0x8BCE,      // <cjk>
-      0x52E6,0x99A9,      // <cjk>
-      0x52E7,0x8AA9,      // <cjk>
-      0x52F2,0x8C4D,      // <cjk>
-      0x52F3,0x99AC,      // <cjk>
-      0x52F5,0x99AD,      // <cjk>
-      0x52F8,0x99AE,      // <cjk>
-      0x52F9,0x99AF,      // <cjk>
-      0x52FA,0x8ED9,      // <cjk>
-      0x52FE,0x8CF9,      // <cjk>
-      0x52FF,0x96DC,      // <cjk>
-      0x5301,0x96E6,      // <cjk>
-      0x5302,0x93F5,      // <cjk>
-      0x5305,0x95EF,      // <cjk>
-      0x5306,0x99B0,      // <cjk>
-      0x5308,0x99B1,      // <cjk>
-      0x530D,0x99B3,      // <cjk>
-      0x530F,0x99B5,      // <cjk>
-      0x5310,0x99B4,      // <cjk>
-      0x5315,0x99B6,      // <cjk>
-      0x5316,0x89BB,      // <cjk>
-      0x5317,0x966B,      // <cjk>
-      0x5319,0x8DFA,      // <cjk>
-      0x531A,0x99B7,      // <cjk>
-      0x531D,0x9178,      // <cjk>
-      0x5320,0x8FA0,      // <cjk>
-      0x5321,0x8BA7,      // <cjk>
-      0x5323,0x99B8,      // <cjk>
-      0x532A,0x94D9,      // <cjk>
-      0x532F,0x99B9,      // <cjk>
-      0x5331,0x99BA,      // <cjk>
-      0x5333,0x99BB,      // <cjk>
-      0x5338,0x99BC,      // <cjk>
-      0x5339,0x9543,      // <cjk>
-      0x533A,0x8BE6,      // <cjk>
-      0x533B,0x88E3,      // <cjk>
-      0x533F,0x93BD,      // <cjk>
-      0x5340,0x99BD,      // <cjk>
-      0x5341,0x8F5C,      // <cjk>
-      0x5343,0x90E7,      // <cjk>
-      0x5345,0x99BF,      // <cjk>
-      0x5346,0x99BE,      // <cjk>
-      0x5347,0x8FA1,      // <cjk>
-      0x5348,0x8CDF,      // <cjk>
-      0x5349,0x99C1,      // <cjk>
-      0x534A,0x94BC,      // <cjk>
-      0x534D,0x99C2,      // <cjk>
-      0x5351,0x94DA,      // <cjk>
-      0x5352,0x91B2,      // <cjk>
-      0x5353,0x91EC,      // <cjk>
-      0x5354,0x8BA6,      // <cjk>
-      0x5357,0x93EC,      // <cjk>
-      0x5358,0x9250,      // <cjk>
-      0x535A,0x948E,      // <cjk>
-      0x535C,0x966D,      // <cjk>
-      0x535E,0x99C4,      // <cjk>
-      0x5360,0x90E8,      // <cjk>
-      0x5366,0x8C54,      // <cjk>
-      0x5369,0x99C5,      // <cjk>
-      0x536E,0x99C6,      // <cjk>
-      0x536F,0x894B,      // <cjk>
-      0x5370,0x88F3,      // <cjk>
-      0x5371,0x8AEB,      // <cjk>
-      0x5373,0x91A6,      // <cjk>
-      0x5374,0x8B70,      // <cjk>
-      0x5375,0x9791,      // <cjk>
-      0x5377,0x99C9,      // <cjk>
-      0x5378,0x89B5,      // <cjk>
-      0x537B,0x99C8,      // <cjk>
-      0x537F,0x8BA8,      // <cjk>
-      0x5382,0x99CA,      // <cjk>
-      0x5384,0x96EF,      // <cjk>
-      0x5396,0x99CB,      // <cjk>
-      0x5398,0x97D0,      // <cjk>
-      0x539A,0x8CFA,      // <cjk>
-      0x539F,0x8CB4,      // <cjk>
-      0x53A0,0x99CC,      // <cjk>
-      0x53A5,0x99CE,      // <cjk>
-      0x53A6,0x99CD,      // <cjk>
-      0x53A8,0x907E,      // <cjk>
-      0x53A9,0x8958,      // <cjk>
-      0x53AD,0x897D,      // <cjk>
-      0x53AE,0x99CF,      // <cjk>
-      0x53B0,0x99D0,      // <cjk>
-      0x53B3,0x8CB5,      // <cjk>
-      0x53B6,0x99D1,      // <cjk>
-      0x53BB,0x8B8E,      // <cjk>
-      0x53C2,0x8E51,      // <cjk>
-      0x53C3,0x99D2,      // <cjk>
-      0x53C8,0x9694,      // <cjk>
-      0x53C9,0x8DB3,      // <cjk>
-      0x53CA,0x8B79,      // <cjk>
-      0x53CB,0x9746,      // <cjk>
-      0x53CC,0x916F,      // <cjk>
-      0x53CD,0x94BD,      // <cjk>
-      0x53CE,0x8EFB,      // <cjk>
-      0x53D4,0x8F66,      // <cjk>
-      0x53D6,0x8EE6,      // <cjk>
-      0x53D7,0x8EF3,      // <cjk>
-      0x53D9,0x8F96,      // <cjk>
-      0x53DB,0x94BE,      // <cjk>
-      0x53DF,0x99D5,      // <cjk>
-      0x53E1,0x8962,      // <cjk>
-      0x53E2,0x9170,      // <cjk>
-      0x53E3,0x8CFB,      // <cjk>
-      0x53E4,0x8CC3,      // <cjk>
-      0x53E5,0x8BE5,      // <cjk>
-      0x53E8,0x99D9,      // <cjk>
-      0x53E9,0x9240,      // <cjk>
-      0x53EA,0x91FC,      // <cjk>
-      0x53EB,0x8BA9,      // <cjk>
-      0x53EC,0x8FA2,      // <cjk>
-      0x53ED,0x99DA,      // <cjk>
-      0x53EE,0x99D8,      // <cjk>
-      0x53EF,0x89C2,      // <cjk>
-      0x53F0,0x91E4,      // <cjk>
-      0x53F1,0x8EB6,      // <cjk>
-      0x53F2,0x8E6A,      // <cjk>
-      0x53F3,0x8945,      // <cjk>
-      0x53F6,0x8A90,      // <cjk>
-      0x53F7,0x8D86,      // <cjk>
-      0x53F8,0x8E69,      // <cjk>
-      0x53FA,0x99DB,      // <cjk>
-      0x5401,0x99DC,      // <cjk>
-      0x5403,0x8B68,      // <cjk>
-      0x5404,0x8A65,      // <cjk>
-      0x5408,0x8D87,      // <cjk>
-      0x5409,0x8B67,      // <cjk>
-      0x540A,0x92DD,      // <cjk>
-      0x540B,0x8944,      // <cjk>
-      0x540C,0x93AF,      // <cjk>
-      0x540D,0x96BC,      // <cjk>
-      0x540E,0x8D40,      // <cjk>
-      0x540F,0x9799,      // <cjk>
-      0x5410,0x9366,      // <cjk>
-      0x5411,0x8CFC,      // <cjk>
-      0x541B,0x8C4E,      // <cjk>
-      0x541D,0x99E5,      // <cjk>
-      0x541F,0x8BE1,      // <cjk>
-      0x5420,0x9669,      // <cjk>
-      0x5426,0x94DB,      // <cjk>
-      0x5429,0x99E4,      // <cjk>
-      0x542B,0x8ADC,      // <cjk>
-      0x542C,0x99DF,      // <cjk>
-      0x542D,0x99E0,      // <cjk>
-      0x542E,0x99E2,      // <cjk>
-      0x5436,0x99E3,      // <cjk>
-      0x5438,0x8B7A,      // <cjk>
-      0x5439,0x9081,      // <cjk>
-      0x543B,0x95AB,      // <cjk>
-      0x543C,0x99E1,      // <cjk>
-      0x543D,0x99DD,      // <cjk>
-      0x543E,0x8CE1,      // <cjk>
-      0x5440,0x99DE,      // <cjk>
-      0x5442,0x9843,      // <cjk>
-      0x5446,0x95F0,      // <cjk>
-      0x5448,0x92E6,      // <cjk>
-      0x5449,0x8CE0,      // <cjk>
-      0x544A,0x8D90,      // <cjk>
-      0x544E,0x99E6,      // <cjk>
-      0x5451,0x93DB,      // <cjk>
-      0x545F,0x99EA,      // <cjk>
-      0x5468,0x8EFC,      // <cjk>
-      0x546A,0x8EF4,      // <cjk>
-      0x5470,0x99ED,      // <cjk>
-      0x5471,0x99EB,      // <cjk>
-      0x5473,0x96A1,      // <cjk>
-      0x5475,0x99E8,      // <cjk>
-      0x5476,0x99F1,      // <cjk>
-      0x5477,0x99EC,      // <cjk>
-      0x547B,0x99EF,      // <cjk>
-      0x547C,0x8CC4,      // <cjk>
-      0x547D,0x96BD,      // <cjk>
-      0x5480,0x99F0,      // <cjk>
-      0x5484,0x99F2,      // <cjk>
-      0x5486,0x99F4,      // <cjk>
-      0x548B,0x8DEE,      // <cjk>
-      0x548C,0x9861,      // <cjk>
-      0x548E,0x99E9,      // <cjk>
-      0x548F,0x99E7,      // <cjk>
-      0x5490,0x99F3,      // <cjk>
-      0x5492,0x99EE,      // <cjk>
-      0x54A2,0x99F6,      // <cjk>
-      0x54A4,0x9A42,      // <cjk>
-      0x54A5,0x99F8,      // <cjk>
-      0x54A8,0x99FC,      // <cjk>
-      0x54AB,0x9A40,      // <cjk>
-      0x54AC,0x99F9,      // <cjk>
-      0x54AF,0x9A5D,      // <cjk>
-      0x54B2,0x8DE7,      // <cjk>
-      0x54B3,0x8A50,      // <cjk>
-      0x54B8,0x99F7,      // <cjk>
-      0x54BC,0x9A44,      // <cjk>
-      0x54BD,0x88F4,      // <cjk>
-      0x54BE,0x9A43,      // <cjk>
-      0x54C0,0x88A3,      // <cjk>
-      0x54C1,0x9569,      // <cjk>
-      0x54C2,0x9A41,      // <cjk>
-      0x54C4,0x99FA,      // <cjk>
-      0x54C7,0x99F5,      // <cjk>
-      0x54C8,0x99FB,      // <cjk>
-      0x54C9,0x8DC6,      // <cjk>
-      0x54D8,0x9A45,      // <cjk>
-      0x54E1,0x88F5,      // <cjk>
-      0x54E2,0x9A4E,      // <cjk>
-      0x54E5,0x9A46,      // <cjk>
-      0x54E6,0x9A47,      // <cjk>
-      0x54E8,0x8FA3,      // <cjk>
-      0x54E9,0x9689,      // <cjk>
-      0x54ED,0x9A4C,      // <cjk>
-      0x54EE,0x9A4B,      // <cjk>
-      0x54F2,0x934E,      // <cjk>
-      0x54FA,0x9A4D,      // <cjk>
-      0x54FD,0x9A4A,      // <cjk>
-      0x5504,0x8953,      // <cjk>
-      0x5506,0x8DB4,      // <cjk>
-      0x5507,0x904F,      // <cjk>
-      0x550F,0x9A48,      // <cjk>
-      0x5510,0x9382,      // <cjk>
-      0x5514,0x9A49,      // <cjk>
-      0x5516,0x88A0,      // <cjk>
-      0x552E,0x9A53,      // <cjk>
-      0x552F,0x9742,      // <cjk>
-      0x5531,0x8FA5,      // <cjk>
-      0x5533,0x9A59,      // <cjk>
-      0x5538,0x9A58,      // <cjk>
-      0x5539,0x9A4F,      // <cjk>
-      0x553E,0x91C1,      // <cjk>
-      0x5540,0x9A50,      // <cjk>
-      0x5544,0x91ED,      // <cjk>
-      0x5545,0x9A55,      // <cjk>
-      0x5546,0x8FA4,      // <cjk>
-      0x554C,0x9A52,      // <cjk>
-      0x554F,0x96E2,      // <cjk>
-      0x5556,0x9A56,      // <cjk>
-      0x5557,0x9A57,      // <cjk>
-      0x555C,0x9A54,      // <cjk>
-      0x555D,0x9A5A,      // <cjk>
-      0x5563,0x9A51,      // <cjk>
-      0x557B,0x9A60,      // <cjk>
-      0x557C,0x9A65,      // <cjk>
-      0x557E,0x9A61,      // <cjk>
-      0x5580,0x9A5C,      // <cjk>
-      0x5583,0x9A66,      // <cjk>
-      0x5584,0x9150,      // <cjk>
-      0x5587,0x9A68,      // <cjk>
-      0x5589,0x8D41,      // <cjk>
-      0x558A,0x9A5E,      // <cjk>
-      0x558B,0x929D,      // <cjk>
-      0x5598,0x9A62,      // <cjk>
-      0x559A,0x8AAB,      // <cjk>
-      0x559C,0x8AEC,      // <cjk>
-      0x559D,0x8A85,      // <cjk>
-      0x559E,0x9A63,      // <cjk>
-      0x559F,0x9A5F,      // <cjk>
-      0x55A7,0x8C96,      // <cjk>
-      0x55A8,0x9A69,      // <cjk>
-      0x55A9,0x9A67,      // <cjk>
-      0x55AA,0x9172,      // <cjk>
-      0x55AB,0x8B69,      // <cjk>
-      0x55AC,0x8BAA,      // <cjk>
-      0x55AE,0x9A64,      // <cjk>
-      0x55B0,0x8BF2,      // <cjk>
-      0x55B6,0x8963,      // <cjk>
-      0x55C4,0x9A6D,      // <cjk>
-      0x55C5,0x9A6B,      // <cjk>
-      0x55C7,0x9AA5,      // <cjk>
-      0x55D4,0x9A70,      // <cjk>
-      0x55DA,0x9A6A,      // <cjk>
-      0x55DC,0x9A6E,      // <cjk>
-      0x55DF,0x9A6C,      // <cjk>
-      0x55E3,0x8E6B,      // <cjk>
-      0x55E4,0x9A6F,      // <cjk>
-      0x55F7,0x9A72,      // <cjk>
-      0x55F9,0x9A77,      // <cjk>
-      0x55FD,0x9A75,      // <cjk>
-      0x55FE,0x9A74,      // <cjk>
-      0x5606,0x9251,      // <cjk>
-      0x5609,0x89C3,      // <cjk>
-      0x5614,0x9A71,      // <cjk>
-      0x5616,0x9A73,      // <cjk>
-      0x5617,0x8FA6,      // <cjk>
-      0x5618,0x8952,      // <cjk>
-      0x561B,0x9A76,      // <cjk>
-      0x5629,0x89DC,      // <cjk>
-      0x562F,0x9A82,      // <cjk>
-      0x5631,0x8FFA,      // <cjk>
-      0x5632,0x9A7D,      // <cjk>
-      0x5634,0x9A7B,      // <cjk>
-      0x5636,0x9A7C,      // <cjk>
-      0x5638,0x9A7E,      // <cjk>
-      0x5642,0x895C,      // <cjk>
-      0x564C,0x9158,      // <cjk>
-      0x564E,0x9A78,      // <cjk>
-      0x5650,0x9A79,      // <cjk>
-      0x565B,0x8A9A,      // <cjk>
-      0x5664,0x9A81,      // <cjk>
-      0x5668,0x8AED,      // <cjk>
-      0x566A,0x9A84,      // <cjk>
-      0x566B,0x9A80,      // <cjk>
-      0x566C,0x9A83,      // <cjk>
-      0x5674,0x95AC,      // <cjk>
-      0x5678,0x93D3,      // <cjk>
-      0x567A,0x94B6,      // <cjk>
-      0x5680,0x9A86,      // <cjk>
-      0x5686,0x9A85,      // <cjk>
-      0x5687,0x8A64,      // <cjk>
-      0x568A,0x9A87,      // <cjk>
-      0x568F,0x9A8A,      // <cjk>
-      0x5694,0x9A89,      // <cjk>
-      0x56A0,0x9A88,      // <cjk>
-      0x56A2,0x9458,      // <cjk>
-      0x56A5,0x9A8B,      // <cjk>
-      0x56AE,0x9A8C,      // <cjk>
-      0x56B4,0x9A8E,      // <cjk>
-      0x56B6,0x9A8D,      // <cjk>
-      0x56BC,0x9A90,      // <cjk>
-      0x56C0,0x9A93,      // <cjk>
-      0x56C1,0x9A91,      // <cjk>
-      0x56C2,0x9A8F,      // <cjk>
-      0x56C3,0x9A92,      // <cjk>
-      0x56C8,0x9A94,      // <cjk>
-      0x56CE,0x9A95,      // <cjk>
-      0x56D1,0x9A96,      // <cjk>
-      0x56D3,0x9A97,      // <cjk>
-      0x56D7,0x9A98,      // <cjk>
-      0x56D8,0x9964,      // <cjk>
-      0x56DA,0x8EFA,      // <cjk>
-      0x56DB,0x8E6C,      // <cjk>
-      0x56DE,0x89F1,      // <cjk>
-      0x56E0,0x88F6,      // <cjk>
-      0x56E3,0x9263,      // <cjk>
-      0x56EE,0x9A99,      // <cjk>
-      0x56F0,0x8DA2,      // <cjk>
-      0x56F2,0x88CD,      // <cjk>
-      0x56F3,0x907D,      // <cjk>
-      0x56F9,0x9A9A,      // <cjk>
-      0x56FA,0x8CC5,      // <cjk>
-      0x56FD,0x8D91,      // <cjk>
-      0x56FF,0x9A9C,      // <cjk>
-      0x5700,0x9A9B,      // <cjk>
-      0x5703,0x95DE,      // <cjk>
-      0x5704,0x9A9D,      // <cjk>
-      0x5708,0x9A9F,      // <cjk>
-      0x5709,0x9A9E,      // <cjk>
-      0x570B,0x9AA0,      // <cjk>
-      0x570D,0x9AA1,      // <cjk>
-      0x570F,0x8C97,      // <cjk>
-      0x5712,0x8980,      // <cjk>
-      0x5713,0x9AA2,      // <cjk>
-      0x5716,0x9AA4,      // <cjk>
-      0x5718,0x9AA3,      // <cjk>
-      0x571C,0x9AA6,      // <cjk>
-      0x571F,0x9379,      // <cjk>
-      0x5726,0x9AA7,      // <cjk>
-      0x5727,0x88B3,      // <cjk>
-      0x5728,0x8DDD,      // <cjk>
-      0x572D,0x8C5C,      // <cjk>
-      0x5730,0x926E,      // <cjk>
-      0x5737,0x9AA8,      // <cjk>
-      0x5738,0x9AA9,      // <cjk>
-      0x573B,0x9AAB,      // <cjk>
-      0x5740,0x9AAC,      // <cjk>
-      0x5742,0x8DE2,      // <cjk>
-      0x5747,0x8BCF,      // <cjk>
-      0x574A,0x9656,      // <cjk>
-      0x574E,0x9AAA,      // <cjk>
-      0x574F,0x9AAD,      // <cjk>
-      0x5750,0x8DBF,      // <cjk>
-      0x5751,0x8D42,      // <cjk>
-      0x5761,0x9AB1,      // <cjk>
-      0x5764,0x8DA3,      // <cjk>
-      0x5766,0x9252,      // <cjk>
-      0x5769,0x9AAE,      // <cjk>
-      0x576A,0x92D8,      // <cjk>
-      0x577F,0x9AB2,      // <cjk>
-      0x5782,0x9082,      // <cjk>
-      0x5788,0x9AB0,      // <cjk>
-      0x5789,0x9AB3,      // <cjk>
-      0x578B,0x8C5E,      // <cjk>
-      0x5793,0x9AB4,      // <cjk>
-      0x57A0,0x9AB5,      // <cjk>
-      0x57A2,0x8D43,      // <cjk>
-      0x57A3,0x8A5F,      // <cjk>
-      0x57A4,0x9AB7,      // <cjk>
-      0x57AA,0x9AB8,      // <cjk>
-      0x57B0,0x9AB9,      // <cjk>
-      0x57B3,0x9AB6,      // <cjk>
-      0x57C0,0x9AAF,      // <cjk>
-      0x57C3,0x9ABA,      // <cjk>
-      0x57C6,0x9ABB,      // <cjk>
-      0x57CB,0x9684,      // <cjk>
-      0x57CE,0x8FE9,      // <cjk>
-      0x57D2,0x9ABD,      // <cjk>
-      0x57D3,0x9ABE,      // <cjk>
-      0x57D4,0x9ABC,      // <cjk>
-      0x57D6,0x9AC0,      // <cjk>
-      0x57DC,0x9457,      // <cjk>
-      0x57DF,0x88E6,      // <cjk>
-      0x57E0,0x9575,      // <cjk>
-      0x57E3,0x9AC1,      // <cjk>
-      0x57F4,0x8FFB,      // <cjk>
-      0x57F7,0x8EB7,      // <cjk>
-      0x57F9,0x947C,      // <cjk>
-      0x57FA,0x8AEE,      // <cjk>
-      0x57FC,0x8DE9,      // <cjk>
-      0x5800,0x9678,      // <cjk>
-      0x5802,0x93B0,      // <cjk>
-      0x5805,0x8C98,      // <cjk>
-      0x5806,0x91CD,      // <cjk>
-      0x580A,0x9ABF,      // <cjk>
-      0x580B,0x9AC2,      // <cjk>
-      0x5815,0x91C2,      // <cjk>
-      0x5819,0x9AC3,      // <cjk>
-      0x581D,0x9AC4,      // <cjk>
-      0x5821,0x9AC6,      // <cjk>
-      0x5824,0x92E7,      // <cjk>
-      0x582A,0x8AAC,      // <cjk>
-      0x582F,0xEA9F,      // <cjk>
-      0x5830,0x8981,      // <cjk>
-      0x5831,0x95F1,      // <cjk>
-      0x5834,0x8FEA,      // <cjk>
-      0x5835,0x9367,      // <cjk>
-      0x583A,0x8DE4,      // <cjk>
-      0x583D,0x9ACC,      // <cjk>
-      0x5840,0x95BB,      // <cjk>
-      0x5841,0x97DB,      // <cjk>
-      0x584A,0x89F2,      // <cjk>
-      0x584B,0x9AC8,      // <cjk>
-      0x5851,0x9159,      // <cjk>
-      0x5852,0x9ACB,      // <cjk>
-      0x5854,0x9383,      // <cjk>
-      0x5857,0x9368,      // <cjk>
-      0x5858,0x9384,      // <cjk>
-      0x5859,0x94B7,      // <cjk>
-      0x585A,0x92CB,      // <cjk>
-      0x585E,0x8DC7,      // <cjk>
-      0x5862,0x9AC7,      // <cjk>
-      0x5869,0x8996,      // <cjk>
-      0x586B,0x9355,      // <cjk>
-      0x5870,0x9AC9,      // <cjk>
-      0x5872,0x9AC5,      // <cjk>
-      0x5875,0x906F,      // <cjk>
-      0x5879,0x9ACD,      // <cjk>
-      0x587E,0x8F6D,      // <cjk>
-      0x5883,0x8BAB,      // <cjk>
-      0x5885,0x9ACE,      // <cjk>
-      0x5893,0x95E6,      // <cjk>
-      0x5897,0x919D,      // <cjk>
-      0x589C,0x92C4,      // <cjk>
-      0x589F,0x9AD0,      // <cjk>
-      0x58A8,0x966E,      // <cjk>
-      0x58AB,0x9AD1,      // <cjk>
-      0x58AE,0x9AD6,      // <cjk>
-      0x58B3,0x95AD,      // <cjk>
-      0x58B8,0x9AD5,      // <cjk>
-      0x58B9,0x9ACF,      // <cjk>
-      0x58BA,0x9AD2,      // <cjk>
-      0x58BB,0x9AD4,      // <cjk>
-      0x58BE,0x8DA4,      // <cjk>
-      0x58C1,0x95C7,      // <cjk>
-      0x58C5,0x9AD7,      // <cjk>
-      0x58C7,0x9264,      // <cjk>
-      0x58CA,0x89F3,      // <cjk>
-      0x58CC,0x8FEB,      // <cjk>
-      0x58D1,0x9AD9,      // <cjk>
-      0x58D3,0x9AD8,      // <cjk>
-      0x58D5,0x8D88,      // <cjk>
-      0x58D7,0x9ADA,      // <cjk>
-      0x58D8,0x9ADC,      // <cjk>
-      0x58D9,0x9ADB,      // <cjk>
-      0x58DC,0x9ADE,      // <cjk>
-      0x58DE,0x9AD3,      // <cjk>
-      0x58DF,0x9AE0,      // <cjk>
-      0x58E4,0x9ADF,      // <cjk>
-      0x58E5,0x9ADD,      // <cjk>
-      0x58EB,0x8E6D,      // <cjk>
-      0x58EC,0x9070,      // <cjk>
-      0x58EE,0x9173,      // <cjk>
-      0x58EF,0x9AE1,      // <cjk>
-      0x58F0,0x90BA,      // <cjk>
-      0x58F1,0x88EB,      // <cjk>
-      0x58F2,0x9484,      // <cjk>
-      0x58F7,0x92D9,      // <cjk>
-      0x58F9,0x9AE3,      // <cjk>
-      0x58FA,0x9AE2,      // <cjk>
-      0x58FB,0x9AE4,      // <cjk>
-      0x58FC,0x9AE5,      // <cjk>
-      0x58FD,0x9AE6,      // <cjk>
-      0x5902,0x9AE7,      // <cjk>
-      0x5909,0x95CF,      // <cjk>
-      0x590A,0x9AE8,      // <cjk>
-      0x590F,0x89C4,      // <cjk>
-      0x5910,0x9AE9,      // <cjk>
-      0x5916,0x8A4F,      // <cjk>
-      0x5918,0x99C7,      // <cjk>
-      0x5919,0x8F67,      // <cjk>
-      0x591A,0x91BD,      // <cjk>
-      0x591B,0x9AEA,      // <cjk>
-      0x591C,0x96E9,      // <cjk>
-      0x5922,0x96B2,      // <cjk>
-      0x5925,0x9AEC,      // <cjk>
-      0x5927,0x91E5,      // <cjk>
-      0x5929,0x9356,      // <cjk>
-      0x592A,0x91BE,      // <cjk>
-      0x592B,0x9576,      // <cjk>
-      0x592C,0x9AED,      // <cjk>
-      0x592D,0x9AEE,      // <cjk>
-      0x592E,0x899B,      // <cjk>
-      0x5931,0x8EB8,      // <cjk>
-      0x5932,0x9AEF,      // <cjk>
-      0x5937,0x88CE,      // <cjk>
-      0x5938,0x9AF0,      // <cjk>
-      0x593E,0x9AF1,      // <cjk>
-      0x5944,0x8982,      // <cjk>
-      0x5947,0x8AEF,      // <cjk>
-      0x5948,0x93DE,      // <cjk>
-      0x5949,0x95F2,      // <cjk>
-      0x594E,0x9AF5,      // <cjk>
-      0x594F,0x9174,      // <cjk>
-      0x5950,0x9AF4,      // <cjk>
-      0x5951,0x8C5F,      // <cjk>
-      0x5954,0x967A,      // <cjk>
-      0x5955,0x9AF3,      // <cjk>
-      0x5957,0x9385,      // <cjk>
-      0x5958,0x9AF7,      // <cjk>
-      0x595A,0x9AF6,      // <cjk>
-      0x5960,0x9AF9,      // <cjk>
-      0x5962,0x9AF8,      // <cjk>
-      0x5965,0x899C,      // <cjk>
-      0x5967,0x9AFA,      // <cjk>
-      0x5968,0x8FA7,      // <cjk>
-      0x5969,0x9AFC,      // <cjk>
-      0x596A,0x9244,      // <cjk>
-      0x596C,0x9AFB,      // <cjk>
-      0x596E,0x95B1,      // <cjk>
-      0x5973,0x8F97,      // <cjk>
-      0x5974,0x937A,      // <cjk>
-      0x5978,0x9B40,      // <cjk>
-      0x597D,0x8D44,      // <cjk>
-      0x5981,0x9B41,      // <cjk>
-      0x5982,0x9440,      // <cjk>
-      0x5983,0x94DC,      // <cjk>
-      0x5984,0x96CF,      // <cjk>
-      0x598A,0x9444,      // <cjk>
-      0x598D,0x9B4A,      // <cjk>
-      0x5993,0x8B57,      // <cjk>
-      0x5996,0x9764,      // <cjk>
-      0x5999,0x96AD,      // <cjk>
-      0x599B,0x9BAA,      // <cjk>
-      0x599D,0x9B42,      // <cjk>
-      0x59A3,0x9B45,      // <cjk>
-      0x59A5,0x91C3,      // <cjk>
-      0x59A8,0x9657,      // <cjk>
-      0x59AC,0x9369,      // <cjk>
-      0x59B2,0x9B46,      // <cjk>
-      0x59B9,0x9685,      // <cjk>
-      0x59BB,0x8DC8,      // <cjk>
-      0x59BE,0x8FA8,      // <cjk>
-      0x59C6,0x9B47,      // <cjk>
-      0x59C9,0x8E6F,      // <cjk>
-      0x59CB,0x8E6E,      // <cjk>
-      0x59D0,0x88B7,      // <cjk>
-      0x59D1,0x8CC6,      // <cjk>
-      0x59D3,0x90A9,      // <cjk>
-      0x59D4,0x88CF,      // <cjk>
-      0x59D9,0x9B4B,      // <cjk>
-      0x59DA,0x9B4C,      // <cjk>
-      0x59DC,0x9B49,      // <cjk>
-      0x59E5,0x8957,      // <cjk>
-      0x59E6,0x8AAD,      // <cjk>
-      0x59E8,0x9B48,      // <cjk>
-      0x59EA,0x96C3,      // <cjk>
-      0x59EB,0x9550,      // <cjk>
-      0x59F6,0x88A6,      // <cjk>
-      0x59FB,0x88F7,      // <cjk>
-      0x59FF,0x8E70,      // <cjk>
-      0x5A01,0x88D0,      // <cjk>
-      0x5A03,0x88A1,      // <cjk>
-      0x5A09,0x9B51,      // <cjk>
-      0x5A11,0x9B4F,      // <cjk>
-      0x5A18,0x96BA,      // <cjk>
-      0x5A1A,0x9B52,      // <cjk>
-      0x5A1C,0x9B50,      // <cjk>
-      0x5A1F,0x9B4E,      // <cjk>
-      0x5A20,0x9050,      // <cjk>
-      0x5A25,0x9B4D,      // <cjk>
-      0x5A29,0x95D8,      // <cjk>
-      0x5A2F,0x8CE2,      // <cjk>
-      0x5A35,0x9B56,      // <cjk>
-      0x5A36,0x9B57,      // <cjk>
-      0x5A3C,0x8FA9,      // <cjk>
-      0x5A40,0x9B53,      // <cjk>
-      0x5A41,0x984B,      // <cjk>
-      0x5A46,0x946B,      // <cjk>
-      0x5A49,0x9B55,      // <cjk>
-      0x5A5A,0x8DA5,      // <cjk>
-      0x5A62,0x9B58,      // <cjk>
-      0x5A66,0x9577,      // <cjk>
-      0x5A6A,0x9B59,      // <cjk>
-      0x5A6C,0x9B54,      // <cjk>
-      0x5A7F,0x96B9,      // <cjk>
-      0x5A92,0x947D,      // <cjk>
-      0x5A9A,0x9B5A,      // <cjk>
-      0x5A9B,0x9551,      // <cjk>
-      0x5ABD,0x9B5F,      // <cjk>
-      0x5ABE,0x9B5C,      // <cjk>
-      0x5AC1,0x89C5,      // <cjk>
-      0x5AC2,0x9B5E,      // <cjk>
-      0x5AC9,0x8EB9,      // <cjk>
-      0x5ACB,0x9B5D,      // <cjk>
-      0x5ACC,0x8C99,      // <cjk>
-      0x5AD0,0x9B6B,      // <cjk>
-      0x5AD6,0x9B64,      // <cjk>
-      0x5AD7,0x9B61,      // <cjk>
-      0x5AE1,0x9284,      // <cjk>
-      0x5AE3,0x9B60,      // <cjk>
-      0x5AE6,0x9B62,      // <cjk>
-      0x5AE9,0x9B63,      // <cjk>
-      0x5AFA,0x9B65,      // <cjk>
-      0x5AFB,0x9B66,      // <cjk>
-      0x5B09,0x8AF0,      // <cjk>
-      0x5B0B,0x9B68,      // <cjk>
-      0x5B0C,0x9B67,      // <cjk>
-      0x5B16,0x9B69,      // <cjk>
-      0x5B22,0x8FEC,      // <cjk>
-      0x5B2A,0x9B6C,      // <cjk>
-      0x5B2C,0x92DA,      // <cjk>
-      0x5B30,0x8964,      // <cjk>
-      0x5B32,0x9B6A,      // <cjk>
-      0x5B36,0x9B6D,      // <cjk>
-      0x5B3E,0x9B6E,      // <cjk>
-      0x5B40,0x9B71,      // <cjk>
-      0x5B43,0x9B6F,      // <cjk>
-      0x5B45,0x9B70,      // <cjk>
-      0x5B50,0x8E71,      // <cjk>
-      0x5B51,0x9B72,      // <cjk>
-      0x5B54,0x8D45,      // <cjk>
-      0x5B55,0x9B73,      // <cjk>
-      0x5B57,0x8E9A,      // <cjk>
-      0x5B58,0x91B6,      // <cjk>
-      0x5B5A,0x9B74,      // <cjk>
-      0x5B5B,0x9B75,      // <cjk>
-      0x5B5C,0x8E79,      // <cjk>
-      0x5B5D,0x8D46,      // <cjk>
-      0x5B5F,0x96D0,      // <cjk>
-      0x5B63,0x8B47,      // <cjk>
-      0x5B64,0x8CC7,      // <cjk>
-      0x5B65,0x9B76,      // <cjk>
-      0x5B66,0x8A77,      // <cjk>
-      0x5B69,0x9B77,      // <cjk>
-      0x5B6B,0x91B7,      // <cjk>
-      0x5B70,0x9B78,      // <cjk>
-      0x5B71,0x9BA1,      // <cjk>
-      0x5B73,0x9B79,      // <cjk>
-      0x5B75,0x9B7A,      // <cjk>
-      0x5B78,0x9B7B,      // <cjk>
-      0x5B7A,0x9B7D,      // <cjk>
-      0x5B80,0x9B7E,      // <cjk>
-      0x5B83,0x9B80,      // <cjk>
-      0x5B85,0x91EE,      // <cjk>
-      0x5B87,0x8946,      // <cjk>
-      0x5B88,0x8EE7,      // <cjk>
-      0x5B89,0x88C0,      // <cjk>
-      0x5B8B,0x9176,      // <cjk>
-      0x5B8C,0x8AAE,      // <cjk>
-      0x5B8D,0x8EB3,      // <cjk>
-      0x5B8F,0x8D47,      // <cjk>
-      0x5B95,0x9386,      // <cjk>
-      0x5B97,0x8F40,      // <cjk>
-      0x5B98,0x8AAF,      // <cjk>
-      0x5B99,0x9288,      // <cjk>
-      0x5B9A,0x92E8,      // <cjk>
-      0x5B9B,0x88B6,      // <cjk>
-      0x5B9C,0x8B58,      // <cjk>
-      0x5B9D,0x95F3,      // <cjk>
-      0x5B9F,0x8EC0,      // <cjk>
-      0x5BA2,0x8B71,      // <cjk>
-      0x5BA3,0x90E9,      // <cjk>
-      0x5BA4,0x8EBA,      // <cjk>
-      0x5BA5,0x9747,      // <cjk>
-      0x5BA6,0x9B81,      // <cjk>
-      0x5BAE,0x8B7B,      // <cjk>
-      0x5BB0,0x8DC9,      // <cjk>
-      0x5BB3,0x8A51,      // <cjk>
-      0x5BB4,0x8983,      // <cjk>
-      0x5BB5,0x8FAA,      // <cjk>
-      0x5BB6,0x89C6,      // <cjk>
-      0x5BB8,0x9B82,      // <cjk>
-      0x5BB9,0x9765,      // <cjk>
-      0x5BBF,0x8F68,      // <cjk>
-      0x5BC2,0x8EE2,      // <cjk>
-      0x5BC3,0x9B83,      // <cjk>
-      0x5BC4,0x8AF1,      // <cjk>
-      0x5BC5,0x93D0,      // <cjk>
-      0x5BC6,0x96A7,      // <cjk>
-      0x5BC7,0x9B84,      // <cjk>
-      0x5BC9,0x9B85,      // <cjk>
-      0x5BCC,0x9578,      // <cjk>
-      0x5BD0,0x9B87,      // <cjk>
-      0x5BD2,0x8AA6,      // <cjk>
-      0x5BD3,0x8BF5,      // <cjk>
-      0x5BD4,0x9B86,      // <cjk>
-      0x5BDB,0x8AB0,      // <cjk>
-      0x5BDD,0x9051,      // <cjk>
-      0x5BDE,0x9B8B,      // <cjk>
-      0x5BDF,0x8E40,      // <cjk>
-      0x5BE1,0x89C7,      // <cjk>
-      0x5BE2,0x9B8A,      // <cjk>
-      0x5BE4,0x9B88,      // <cjk>
-      0x5BE5,0x9B8C,      // <cjk>
-      0x5BE6,0x9B89,      // <cjk>
-      0x5BE7,0x944A,      // <cjk>
-      0x5BE8,0x9ECB,      // <cjk>
-      0x5BE9,0x9052,      // <cjk>
-      0x5BEB,0x9B8D,      // <cjk>
-      0x5BEE,0x97BE,      // <cjk>
-      0x5BF0,0x9B8E,      // <cjk>
-      0x5BF3,0x9B90,      // <cjk>
-      0x5BF5,0x929E,      // <cjk>
-      0x5BF6,0x9B8F,      // <cjk>
-      0x5BF8,0x90A1,      // <cjk>
-      0x5BFA,0x8E9B,      // <cjk>
-      0x5BFE,0x91CE,      // <cjk>
-      0x5BFF,0x8EF5,      // <cjk>
-      0x5C01,0x9595,      // <cjk>
-      0x5C02,0x90EA,      // <cjk>
-      0x5C04,0x8ECB,      // <cjk>
-      0x5C05,0x9B91,      // <cjk>
-      0x5C06,0x8FAB,      // <cjk>
-      0x5C07,0x9B92,      // <cjk>
-      0x5C08,0x9B93,      // <cjk>
-      0x5C09,0x88D1,      // <cjk>
-      0x5C0A,0x91B8,      // <cjk>
-      0x5C0B,0x9071,      // <cjk>
-      0x5C0D,0x9B94,      // <cjk>
-      0x5C0E,0x93B1,      // <cjk>
-      0x5C0F,0x8FAC,      // <cjk>
-      0x5C11,0x8FAD,      // <cjk>
-      0x5C13,0x9B95,      // <cjk>
-      0x5C16,0x90EB,      // <cjk>
-      0x5C1A,0x8FAE,      // <cjk>
-      0x5C20,0x9B96,      // <cjk>
-      0x5C22,0x9B97,      // <cjk>
-      0x5C24,0x96DE,      // <cjk>
-      0x5C28,0x9B98,      // <cjk>
-      0x5C2D,0x8BC4,      // <cjk>
-      0x5C31,0x8F41,      // <cjk>
-      0x5C38,0x9B99,      // <cjk>
-      0x5C39,0x9B9A,      // <cjk>
-      0x5C3A,0x8EDA,      // <cjk>
-      0x5C3B,0x904B,      // <cjk>
-      0x5C3C,0x93F2,      // <cjk>
-      0x5C3D,0x9073,      // <cjk>
-      0x5C3E,0x94F6,      // <cjk>
-      0x5C3F,0x9441,      // <cjk>
-      0x5C40,0x8BC7,      // <cjk>
-      0x5C41,0x9B9B,      // <cjk>
-      0x5C45,0x8B8F,      // <cjk>
-      0x5C46,0x9B9C,      // <cjk>
-      0x5C48,0x8BFC,      // <cjk>
-      0x5C4A,0x93CD,      // <cjk>
-      0x5C4B,0x89AE,      // <cjk>
-      0x5C4D,0x8E72,      // <cjk>
-      0x5C4E,0x9B9D,      // <cjk>
-      0x5C4F,0x9BA0,      // <cjk>
-      0x5C50,0x9B9F,      // <cjk>
-      0x5C51,0x8BFB,      // <cjk>
-      0x5C53,0x9B9E,      // <cjk>
-      0x5C55,0x9357,      // <cjk>
-      0x5C5E,0x91AE,      // <cjk>
-      0x5C60,0x936A,      // <cjk>
-      0x5C61,0x8EC6,      // <cjk>
-      0x5C64,0x9177,      // <cjk>
-      0x5C65,0x979A,      // <cjk>
-      0x5C6C,0x9BA2,      // <cjk>
-      0x5C6E,0x9BA3,      // <cjk>
-      0x5C6F,0x93D4,      // <cjk>
-      0x5C71,0x8E52,      // <cjk>
-      0x5C76,0x9BA5,      // <cjk>
-      0x5C79,0x9BA6,      // <cjk>
-      0x5C8C,0x9BA7,      // <cjk>
-      0x5C90,0x8AF2,      // <cjk>
-      0x5C91,0x9BA8,      // <cjk>
-      0x5C94,0x9BA9,      // <cjk>
-      0x5CA1,0x89AA,      // <cjk>
-      0x5CA8,0x915A,      // <cjk>
-      0x5CA9,0x8AE2,      // <cjk>
-      0x5CAB,0x9BAB,      // <cjk>
-      0x5CAC,0x96A6,      // <cjk>
-      0x5CB1,0x91D0,      // <cjk>
-      0x5CB3,0x8A78,      // <cjk>
-      0x5CB6,0x9BAD,      // <cjk>
-      0x5CB7,0x9BAF,      // <cjk>
-      0x5CB8,0x8ADD,      // <cjk>
-      0x5CBB,0x9BAC,      // <cjk>
-      0x5CBC,0x9BAE,      // <cjk>
-      0x5CBE,0x9BB1,      // <cjk>
-      0x5CC5,0x9BB0,      // <cjk>
-      0x5CC7,0x9BB2,      // <cjk>
-      0x5CD9,0x9BB3,      // <cjk>
-      0x5CE0,0x93BB,      // <cjk>
-      0x5CE1,0x8BAC,      // <cjk>
-      0x5CE8,0x89E3,      // <cjk>
-      0x5CE9,0x9BB4,      // <cjk>
-      0x5CEA,0x9BB9,      // <cjk>
-      0x5CED,0x9BB7,      // <cjk>
-      0x5CEF,0x95F5,      // <cjk>
-      0x5CF0,0x95F4,      // <cjk>
-      0x5CF6,0x9387,      // <cjk>
-      0x5CFA,0x9BB6,      // <cjk>
-      0x5CFB,0x8F73,      // <cjk>
-      0x5CFD,0x9BB5,      // <cjk>
-      0x5D07,0x9092,      // <cjk>
-      0x5D0B,0x9BBA,      // <cjk>
-      0x5D0E,0x8DE8,      // <cjk>
-      0x5D11,0x9BC0,      // <cjk>
-      0x5D14,0x9BC1,      // <cjk>
-      0x5D15,0x9BBB,      // <cjk>
-      0x5D16,0x8A52,      // <cjk>
-      0x5D17,0x9BBC,      // <cjk>
-      0x5D18,0x9BC5,      // <cjk>
-      0x5D19,0x9BC4,      // <cjk>
-      0x5D1A,0x9BC3,      // <cjk>
-      0x5D1B,0x9BBF,      // <cjk>
-      0x5D1F,0x9BBE,      // <cjk>
-      0x5D22,0x9BC2,      // <cjk>
-      0x5D29,0x95F6,      // <cjk>
-      0x5D4B,0x9BC9,      // <cjk>
-      0x5D4C,0x9BC6,      // <cjk>
-      0x5D4E,0x9BC8,      // <cjk>
-      0x5D50,0x9792,      // <cjk>
-      0x5D52,0x9BC7,      // <cjk>
-      0x5D5C,0x9BBD,      // <cjk>
-      0x5D69,0x9093,      // <cjk>
-      0x5D6C,0x9BCA,      // <cjk>
-      0x5D6F,0x8DB5,      // <cjk>
-      0x5D73,0x9BCB,      // <cjk>
-      0x5D76,0x9BCC,      // <cjk>
-      0x5D82,0x9BCF,      // <cjk>
-      0x5D84,0x9BCE,      // <cjk>
-      0x5D87,0x9BCD,      // <cjk>
-      0x5D8B,0x9388,      // <cjk>
-      0x5D8C,0x9BB8,      // <cjk>
-      0x5D90,0x9BD5,      // <cjk>
-      0x5D9D,0x9BD1,      // <cjk>
-      0x5DA2,0x9BD0,      // <cjk>
-      0x5DAC,0x9BD2,      // <cjk>
-      0x5DAE,0x9BD3,      // <cjk>
-      0x5DB7,0x9BD6,      // <cjk>
-      0x5DBA,0x97E4,      // <cjk>
-      0x5DBC,0x9BD7,      // <cjk>
-      0x5DBD,0x9BD4,      // <cjk>
-      0x5DC9,0x9BD8,      // <cjk>
-      0x5DCC,0x8ADE,      // <cjk>
-      0x5DCD,0x9BD9,      // <cjk>
-      0x5DD2,0x9BDB,      // <cjk>
-      0x5DD3,0x9BDA,      // <cjk>
-      0x5DD6,0x9BDC,      // <cjk>
-      0x5DDB,0x9BDD,      // <cjk>
-      0x5DDD,0x90EC,      // <cjk>
-      0x5DDE,0x8F42,      // <cjk>
-      0x5DE1,0x8F84,      // <cjk>
-      0x5DE3,0x9183,      // <cjk>
-      0x5DE5,0x8D48,      // <cjk>
-      0x5DE6,0x8DB6,      // <cjk>
-      0x5DE7,0x8D49,      // <cjk>
-      0x5DE8,0x8B90,      // <cjk>
-      0x5DEB,0x9BDE,      // <cjk>
-      0x5DEE,0x8DB7,      // <cjk>
-      0x5DF1,0x8CC8,      // <cjk>
-      0x5DF2,0x9BDF,      // <cjk>
-      0x5DF3,0x96A4,      // <cjk>
-      0x5DF4,0x9462,      // <cjk>
-      0x5DF5,0x9BE0,      // <cjk>
-      0x5DF7,0x8D4A,      // <cjk>
-      0x5DFB,0x8AAA,      // <cjk>
-      0x5DFD,0x9246,      // <cjk>
-      0x5DFE,0x8BD0,      // <cjk>
-      0x5E02,0x8E73,      // <cjk>
-      0x5E03,0x957A,      // <cjk>
-      0x5E06,0x94BF,      // <cjk>
-      0x5E0B,0x9BE1,      // <cjk>
-      0x5E0C,0x8AF3,      // <cjk>
-      0x5E11,0x9BE4,      // <cjk>
-      0x5E16,0x929F,      // <cjk>
-      0x5E19,0x9BE3,      // <cjk>
-      0x5E1A,0x9BE2,      // <cjk>
-      0x5E1B,0x9BE5,      // <cjk>
-      0x5E1D,0x92E9,      // <cjk>
-      0x5E25,0x9083,      // <cjk>
-      0x5E2B,0x8E74,      // <cjk>
-      0x5E2D,0x90C8,      // <cjk>
-      0x5E2F,0x91D1,      // <cjk>
-      0x5E30,0x8B41,      // <cjk>
-      0x5E33,0x92A0,      // <cjk>
-      0x5E36,0x9BE6,      // <cjk>
-      0x5E37,0x9BE7,      // <cjk>
-      0x5E38,0x8FED,      // <cjk>
-      0x5E3D,0x9658,      // <cjk>
-      0x5E40,0x9BEA,      // <cjk>
-      0x5E43,0x9BE9,      // <cjk>
-      0x5E44,0x9BE8,      // <cjk>
-      0x5E45,0x959D,      // <cjk>
-      0x5E47,0x9BF1,      // <cjk>
-      0x5E4C,0x9679,      // <cjk>
-      0x5E4E,0x9BEB,      // <cjk>
-      0x5E54,0x9BED,      // <cjk>
-      0x5E55,0x968B,      // <cjk>
-      0x5E57,0x9BEC,      // <cjk>
-      0x5E5F,0x9BEE,      // <cjk>
-      0x5E61,0x94A6,      // <cjk>
-      0x5E62,0x9BEF,      // <cjk>
-      0x5E63,0x95BC,      // <cjk>
-      0x5E64,0x9BF0,      // <cjk>
-      0x5E72,0x8AB1,      // <cjk>
-      0x5E73,0x95BD,      // <cjk>
-      0x5E74,0x944E,      // <cjk>
-      0x5E75,0x9BF2,      // <cjk>
-      0x5E76,0x9BF3,      // <cjk>
-      0x5E78,0x8D4B,      // <cjk>
-      0x5E79,0x8AB2,      // <cjk>
-      0x5E7A,0x9BF4,      // <cjk>
-      0x5E7B,0x8CB6,      // <cjk>
-      0x5E7C,0x9763,      // <cjk>
-      0x5E7D,0x9748,      // <cjk>
-      0x5E7E,0x8AF4,      // <cjk>
-      0x5E7F,0x9BF6,      // <cjk>
-      0x5E81,0x92A1,      // <cjk>
-      0x5E83,0x8D4C,      // <cjk>
-      0x5E84,0x8FAF,      // <cjk>
-      0x5E87,0x94DD,      // <cjk>
-      0x5E8A,0x8FB0,      // <cjk>
-      0x5E8F,0x8F98,      // <cjk>
-      0x5E95,0x92EA,      // <cjk>
-      0x5E96,0x95F7,      // <cjk>
-      0x5E97,0x9358,      // <cjk>
-      0x5E9A,0x8D4D,      // <cjk>
-      0x5E9C,0x957B,      // <cjk>
-      0x5EA0,0x9BF7,      // <cjk>
-      0x5EA6,0x9378,      // <cjk>
-      0x5EA7,0x8DC0,      // <cjk>
-      0x5EAB,0x8CC9,      // <cjk>
-      0x5EAD,0x92EB,      // <cjk>
-      0x5EB5,0x88C1,      // <cjk>
-      0x5EB6,0x8F8E,      // <cjk>
-      0x5EB7,0x8D4E,      // <cjk>
-      0x5EB8,0x9766,      // <cjk>
-      0x5EC1,0x9BF8,      // <cjk>
-      0x5EC2,0x9BF9,      // <cjk>
-      0x5EC3,0x9470,      // <cjk>
-      0x5EC8,0x9BFA,      // <cjk>
-      0x5EC9,0x97F5,      // <cjk>
-      0x5ECA,0x984C,      // <cjk>
-      0x5ECF,0x9BFC,      // <cjk>
-      0x5ED0,0x9BFB,      // <cjk>
-      0x5ED3,0x8A66,      // <cjk>
-      0x5ED6,0x9C40,      // <cjk>
-      0x5EDA,0x9C43,      // <cjk>
-      0x5EDB,0x9C44,      // <cjk>
-      0x5EDD,0x9C42,      // <cjk>
-      0x5EDF,0x955F,      // <cjk>
-      0x5EE0,0x8FB1,      // <cjk>
-      0x5EE1,0x9C46,      // <cjk>
-      0x5EE2,0x9C45,      // <cjk>
-      0x5EE3,0x9C41,      // <cjk>
-      0x5EE8,0x9C47,      // <cjk>
-      0x5EE9,0x9C48,      // <cjk>
-      0x5EEC,0x9C49,      // <cjk>
-      0x5EF0,0x9C4C,      // <cjk>
-      0x5EF1,0x9C4A,      // <cjk>
-      0x5EF3,0x9C4B,      // <cjk>
-      0x5EF4,0x9C4D,      // <cjk>
-      0x5EF6,0x8984,      // <cjk>
-      0x5EF7,0x92EC,      // <cjk>
-      0x5EF8,0x9C4E,      // <cjk>
-      0x5EFA,0x8C9A,      // <cjk>
-      0x5EFB,0x89F4,      // <cjk>
-      0x5EFC,0x9455,      // <cjk>
-      0x5EFE,0x9C4F,      // <cjk>
-      0x5EFF,0x93F9,      // <cjk>
-      0x5F01,0x95D9,      // <cjk>
-      0x5F03,0x9C50,      // <cjk>
-      0x5F04,0x984D,      // <cjk>
-      0x5F09,0x9C51,      // <cjk>
-      0x5F0A,0x95BE,      // <cjk>
-      0x5F0B,0x9C54,      // <cjk>
-      0x5F0C,0x989F,      // <cjk>
-      0x5F0D,0x98AF,      // <cjk>
-      0x5F0F,0x8EAE,      // <cjk>
-      0x5F10,0x93F3,      // <cjk>
-      0x5F11,0x9C55,      // <cjk>
-      0x5F13,0x8B7C,      // <cjk>
-      0x5F14,0x92A2,      // <cjk>
-      0x5F15,0x88F8,      // <cjk>
-      0x5F16,0x9C56,      // <cjk>
-      0x5F17,0x95A4,      // <cjk>
-      0x5F18,0x8D4F,      // <cjk>
-      0x5F1B,0x926F,      // <cjk>
-      0x5F1F,0x92ED,      // <cjk>
-      0x5F25,0x96ED,      // <cjk>
-      0x5F26,0x8CB7,      // <cjk>
-      0x5F27,0x8CCA,      // <cjk>
-      0x5F29,0x9C57,      // <cjk>
-      0x5F2D,0x9C58,      // <cjk>
-      0x5F2F,0x9C5E,      // <cjk>
-      0x5F31,0x8EE3,      // <cjk>
-      0x5F35,0x92A3,      // <cjk>
-      0x5F37,0x8BAD,      // <cjk>
-      0x5F38,0x9C59,      // <cjk>
-      0x5F3C,0x954A,      // <cjk>
-      0x5F3E,0x9265,      // <cjk>
-      0x5F41,0x9C5A,      // <cjk>
-      0x5F4A,0x8BAE,      // <cjk>
-      0x5F4C,0x9C5C,      // <cjk>
-      0x5F4E,0x9C5D,      // <cjk>
-      0x5F51,0x9C5F,      // <cjk>
-      0x5F53,0x9396,      // <cjk>
-      0x5F56,0x9C60,      // <cjk>
-      0x5F57,0x9C61,      // <cjk>
-      0x5F59,0x9C62,      // <cjk>
-      0x5F5C,0x9C53,      // <cjk>
-      0x5F5D,0x9C52,      // <cjk>
-      0x5F61,0x9C63,      // <cjk>
-      0x5F62,0x8C60,      // <cjk>
-      0x5F66,0x9546,      // <cjk>
-      0x5F69,0x8DCA,      // <cjk>
-      0x5F6A,0x9556,      // <cjk>
-      0x5F6B,0x92A4,      // <cjk>
-      0x5F6C,0x956A,      // <cjk>
-      0x5F6D,0x9C64,      // <cjk>
-      0x5F70,0x8FB2,      // <cjk>
-      0x5F71,0x8965,      // <cjk>
-      0x5F73,0x9C65,      // <cjk>
-      0x5F77,0x9C66,      // <cjk>
-      0x5F79,0x96F0,      // <cjk>
-      0x5F7C,0x94DE,      // <cjk>
-      0x5F7F,0x9C69,      // <cjk>
-      0x5F80,0x899D,      // <cjk>
-      0x5F81,0x90AA,      // <cjk>
-      0x5F82,0x9C68,      // <cjk>
-      0x5F83,0x9C67,      // <cjk>
-      0x5F84,0x8C61,      // <cjk>
-      0x5F85,0x91D2,      // <cjk>
-      0x5F87,0x9C6D,      // <cjk>
-      0x5F88,0x9C6B,      // <cjk>
-      0x5F8A,0x9C6A,      // <cjk>
-      0x5F8B,0x97A5,      // <cjk>
-      0x5F8C,0x8CE3,      // <cjk>
-      0x5F90,0x8F99,      // <cjk>
-      0x5F91,0x9C6C,      // <cjk>
-      0x5F92,0x936B,      // <cjk>
-      0x5F93,0x8F5D,      // <cjk>
-      0x5F97,0x93BE,      // <cjk>
-      0x5F98,0x9C70,      // <cjk>
-      0x5F99,0x9C6F,      // <cjk>
-      0x5F9E,0x9C6E,      // <cjk>
-      0x5FA0,0x9C71,      // <cjk>
-      0x5FA1,0x8CE4,      // <cjk>
-      0x5FA8,0x9C72,      // <cjk>
-      0x5FA9,0x959C,      // <cjk>
-      0x5FAA,0x8F7A,      // <cjk>
-      0x5FAD,0x9C73,      // <cjk>
-      0x5FAE,0x94F7,      // <cjk>
-      0x5FB3,0x93BF,      // <cjk>
-      0x5FB4,0x92A5,      // <cjk>
-      0x5FB9,0x934F,      // <cjk>
-      0x5FBC,0x9C74,      // <cjk>
-      0x5FBD,0x8B4A,      // <cjk>
-      0x5FC3,0x9053,      // <cjk>
-      0x5FC5,0x954B,      // <cjk>
-      0x5FCC,0x8AF5,      // <cjk>
-      0x5FCD,0x9445,      // <cjk>
-      0x5FD6,0x9C75,      // <cjk>
-      0x5FD7,0x8E75,      // <cjk>
-      0x5FD8,0x9659,      // <cjk>
-      0x5FD9,0x965A,      // <cjk>
-      0x5FDC,0x899E,      // <cjk>
-      0x5FDD,0x9C7A,      // <cjk>
-      0x5FE0,0x9289,      // <cjk>
-      0x5FE4,0x9C77,      // <cjk>
-      0x5FEB,0x89F5,      // <cjk>
-      0x5FF0,0x9CAB,      // <cjk>
-      0x5FF1,0x9C79,      // <cjk>
-      0x5FF5,0x944F,      // <cjk>
-      0x5FF8,0x9C78,      // <cjk>
-      0x5FFB,0x9C76,      // <cjk>
-      0x5FFD,0x8D9A,      // <cjk>
-      0x5FFF,0x9C7C,      // <cjk>
-      0x600E,0x9C83,      // <cjk>
-      0x600F,0x9C89,      // <cjk>
-      0x6010,0x9C81,      // <cjk>
-      0x6012,0x937B,      // <cjk>
-      0x6015,0x9C86,      // <cjk>
-      0x6016,0x957C,      // <cjk>
-      0x6019,0x9C80,      // <cjk>
-      0x601B,0x9C85,      // <cjk>
-      0x601C,0x97E5,      // <cjk>
-      0x601D,0x8E76,      // <cjk>
-      0x6020,0x91D3,      // <cjk>
-      0x6021,0x9C7D,      // <cjk>
-      0x6025,0x8B7D,      // <cjk>
-      0x6026,0x9C88,      // <cjk>
-      0x6027,0x90AB,      // <cjk>
-      0x6028,0x8985,      // <cjk>
-      0x6029,0x9C82,      // <cjk>
-      0x602A,0x89F6,      // <cjk>
-      0x602B,0x9C87,      // <cjk>
-      0x602F,0x8BAF,      // <cjk>
-      0x6031,0x9C84,      // <cjk>
-      0x603A,0x9C8A,      // <cjk>
-      0x6041,0x9C8C,      // <cjk>
-      0x6042,0x9C96,      // <cjk>
-      0x6043,0x9C94,      // <cjk>
-      0x6046,0x9C91,      // <cjk>
-      0x604A,0x9C90,      // <cjk>
-      0x604B,0x97F6,      // <cjk>
-      0x604D,0x9C92,      // <cjk>
-      0x6050,0x8BB0,      // <cjk>
-      0x6052,0x8D50,      // <cjk>
-      0x6055,0x8F9A,      // <cjk>
-      0x6059,0x9C99,      // <cjk>
-      0x605A,0x9C8B,      // <cjk>
-      0x605F,0x9C8F,      // <cjk>
-      0x6060,0x9C7E,      // <cjk>
-      0x6062,0x89F8,      // <cjk>
-      0x6063,0x9C93,      // <cjk>
-      0x6064,0x9C95,      // <cjk>
-      0x6065,0x9270,      // <cjk>
-      0x6068,0x8DA6,      // <cjk>
-      0x6069,0x89B6,      // <cjk>
-      0x606A,0x9C8D,      // <cjk>
-      0x606B,0x9C98,      // <cjk>
-      0x606C,0x9C97,      // <cjk>
-      0x606D,0x8BB1,      // <cjk>
-      0x606F,0x91A7,      // <cjk>
-      0x6070,0x8A86,      // <cjk>
-      0x6075,0x8C62,      // <cjk>
-      0x6077,0x9C8E,      // <cjk>
-      0x6081,0x9C9A,      // <cjk>
-      0x6083,0x9C9D,      // <cjk>
-      0x6084,0x9C9F,      // <cjk>
-      0x6089,0x8EBB,      // <cjk>
-      0x608B,0x9CA5,      // <cjk>
-      0x608C,0x92EE,      // <cjk>
-      0x608D,0x9C9B,      // <cjk>
-      0x6092,0x9CA3,      // <cjk>
-      0x6094,0x89F7,      // <cjk>
-      0x6096,0x9CA1,      // <cjk>
-      0x6097,0x9CA2,      // <cjk>
-      0x609A,0x9C9E,      // <cjk>
-      0x609B,0x9CA0,      // <cjk>
-      0x609F,0x8CE5,      // <cjk>
-      0x60A0,0x9749,      // <cjk>
-      0x60A3,0x8AB3,      // <cjk>
-      0x60A6,0x8978,      // <cjk>
-      0x60A7,0x9CA4,      // <cjk>
-      0x60A9,0x9459,      // <cjk>
-      0x60AA,0x88AB,      // <cjk>
-      0x60B2,0x94DF,      // <cjk>
-      0x60B3,0x9C7B,      // <cjk>
-      0x60B4,0x9CAA,      // <cjk>
-      0x60B5,0x9CAE,      // <cjk>
-      0x60B6,0x96E3,      // <cjk>
-      0x60B8,0x9CA7,      // <cjk>
-      0x60BC,0x9389,      // <cjk>
-      0x60BD,0x9CAC,      // <cjk>
-      0x60C5,0x8FEE,      // <cjk>
-      0x60C6,0x9CAD,      // <cjk>
-      0x60C7,0x93D5,      // <cjk>
-      0x60D1,0x9866,      // <cjk>
-      0x60D3,0x9CA9,      // <cjk>
-      0x60D8,0x9CAF,      // <cjk>
-      0x60DA,0x8D9B,      // <cjk>
-      0x60DC,0x90C9,      // <cjk>
-      0x60DF,0x88D2,      // <cjk>
-      0x60E0,0x9CA8,      // <cjk>
-      0x60E1,0x9CA6,      // <cjk>
-      0x60E3,0x9179,      // <cjk>
-      0x60E7,0x9C9C,      // <cjk>
-      0x60E8,0x8E53,      // <cjk>
-      0x60F0,0x91C4,      // <cjk>
-      0x60F1,0x9CBB,      // <cjk>
-      0x60F3,0x917A,      // <cjk>
-      0x60F4,0x9CB6,      // <cjk>
-      0x60F6,0x9CB3,      // <cjk>
-      0x60F7,0x9CB4,      // <cjk>
-      0x60F9,0x8EE4,      // <cjk>
-      0x60FA,0x9CB7,      // <cjk>
-      0x60FB,0x9CBA,      // <cjk>
-      0x6100,0x9CB5,      // <cjk>
-      0x6101,0x8F44,      // <cjk>
-      0x6103,0x9CB8,      // <cjk>
-      0x6106,0x9CB2,      // <cjk>
-      0x6108,0x96FA,      // <cjk>
-      0x6109,0x96F9,      // <cjk>
-      0x610D,0x9CBC,      // <cjk>
-      0x610E,0x9CBD,      // <cjk>
-      0x610F,0x88D3,      // <cjk>
-      0x6115,0x9CB1,      // <cjk>
-      0x611A,0x8BF0,      // <cjk>
-      0x611B,0x88A4,      // <cjk>
-      0x611F,0x8AB4,      // <cjk>
-      0x6121,0x9CB9,      // <cjk>
-      0x6127,0x9CC1,      // <cjk>
-      0x6128,0x9CC0,      // <cjk>
-      0x612C,0x9CC5,      // <cjk>
-      0x6134,0x9CC6,      // <cjk>
-      0x613C,0x9CC4,      // <cjk>
-      0x613D,0x9CC7,      // <cjk>
-      0x613E,0x9CBF,      // <cjk>
-      0x613F,0x9CC3,      // <cjk>
-      0x6142,0x9CC8,      // <cjk>
-      0x6144,0x9CC9,      // <cjk>
-      0x6147,0x9CBE,      // <cjk>
-      0x6148,0x8E9C,      // <cjk>
-      0x614A,0x9CC2,      // <cjk>
-      0x614B,0x91D4,      // <cjk>
-      0x614C,0x8D51,      // <cjk>
-      0x614D,0x9CB0,      // <cjk>
-      0x614E,0x9054,      // <cjk>
-      0x6153,0x9CD6,      // <cjk>
-      0x6155,0x95E7,      // <cjk>
-      0x6158,0x9CCC,      // <cjk>
-      0x6159,0x9CCD,      // <cjk>
-      0x615A,0x9CCE,      // <cjk>
-      0x615D,0x9CD5,      // <cjk>
-      0x615F,0x9CD4,      // <cjk>
-      0x6162,0x969D,      // <cjk>
-      0x6163,0x8AB5,      // <cjk>
-      0x6165,0x9CD2,      // <cjk>
-      0x6167,0x8C64,      // <cjk>
-      0x6168,0x8A53,      // <cjk>
-      0x616B,0x9CCF,      // <cjk>
-      0x616E,0x97B6,      // <cjk>
-      0x616F,0x9CD1,      // <cjk>
-      0x6170,0x88D4,      // <cjk>
-      0x6171,0x9CD3,      // <cjk>
-      0x6173,0x9CCA,      // <cjk>
-      0x6174,0x9CD0,      // <cjk>
-      0x6175,0x9CD7,      // <cjk>
-      0x6176,0x8C63,      // <cjk>
-      0x6177,0x9CCB,      // <cjk>
-      0x617E,0x977C,      // <cjk>
-      0x6182,0x974A,      // <cjk>
-      0x6187,0x9CDA,      // <cjk>
-      0x618A,0x9CDE,      // <cjk>
-      0x618E,0x919E,      // <cjk>
-      0x6190,0x97F7,      // <cjk>
-      0x6191,0x9CDF,      // <cjk>
-      0x6194,0x9CDC,      // <cjk>
-      0x6196,0x9CD9,      // <cjk>
-      0x6199,0x9CD8,      // <cjk>
-      0x619A,0x9CDD,      // <cjk>
-      0x61A4,0x95AE,      // <cjk>
-      0x61A7,0x93B2,      // <cjk>
-      0x61A9,0x8C65,      // <cjk>
-      0x61AB,0x9CE0,      // <cjk>
-      0x61AC,0x9CDB,      // <cjk>
-      0x61AE,0x9CE1,      // <cjk>
-      0x61B2,0x8C9B,      // <cjk>
-      0x61B6,0x89AF,      // <cjk>
-      0x61BA,0x9CE9,      // <cjk>
-      0x61BE,0x8AB6,      // <cjk>
-      0x61C3,0x9CE7,      // <cjk>
-      0x61C6,0x9CE8,      // <cjk>
-      0x61C7,0x8DA7,      // <cjk>
-      0x61C8,0x9CE6,      // <cjk>
-      0x61C9,0x9CE4,      // <cjk>
-      0x61CA,0x9CE3,      // <cjk>
-      0x61CB,0x9CEA,      // <cjk>
-      0x61CC,0x9CE2,      // <cjk>
-      0x61CD,0x9CEC,      // <cjk>
-      0x61D0,0x89F9,      // <cjk>
-      0x61E3,0x9CEE,      // <cjk>
-      0x61E6,0x9CED,      // <cjk>
-      0x61F2,0x92A6,      // <cjk>
-      0x61F4,0x9CF1,      // <cjk>
-      0x61F6,0x9CEF,      // <cjk>
-      0x61F7,0x9CE5,      // <cjk>
-      0x61F8,0x8C9C,      // <cjk>
-      0x61FA,0x9CF0,      // <cjk>
-      0x61FC,0x9CF4,      // <cjk>
-      0x61FD,0x9CF3,      // <cjk>
-      0x61FE,0x9CF5,      // <cjk>
-      0x61FF,0x9CF2,      // <cjk>
-      0x6200,0x9CF6,      // <cjk>
-      0x6208,0x9CF7,      // <cjk>
-      0x6209,0x9CF8,      // <cjk>
-      0x620A,0x95E8,      // <cjk>
-      0x620C,0x9CFA,      // <cjk>
-      0x620D,0x9CF9,      // <cjk>
-      0x620E,0x8F5E,      // <cjk>
-      0x6210,0x90AC,      // <cjk>
-      0x6211,0x89E4,      // <cjk>
-      0x6212,0x89FA,      // <cjk>
-      0x6214,0x9CFB,      // <cjk>
-      0x6216,0x88BD,      // <cjk>
-      0x621A,0x90CA,      // <cjk>
-      0x621B,0x9CFC,      // <cjk>
-      0x621D,0xE6C1,      // <cjk>
-      0x621E,0x9D40,      // <cjk>
-      0x621F,0x8C81,      // <cjk>
-      0x6221,0x9D41,      // <cjk>
-      0x6226,0x90ED,      // <cjk>
-      0x622A,0x9D42,      // <cjk>
-      0x622E,0x9D43,      // <cjk>
-      0x622F,0x8B59,      // <cjk>
-      0x6230,0x9D44,      // <cjk>
-      0x6232,0x9D45,      // <cjk>
-      0x6233,0x9D46,      // <cjk>
-      0x6234,0x91D5,      // <cjk>
-      0x6238,0x8CCB,      // <cjk>
-      0x623B,0x96DF,      // <cjk>
-      0x6240,0x8F8A,      // <cjk>
-      0x6241,0x9D47,      // <cjk>
-      0x6247,0x90EE,      // <cjk>
-      0x6248,0xE7BB,      // <cjk>
-      0x6249,0x94E0,      // <cjk>
-      0x624B,0x8EE8,      // <cjk>
-      0x624D,0x8DCB,      // <cjk>
-      0x624E,0x9D48,      // <cjk>
-      0x6253,0x91C5,      // <cjk>
-      0x6255,0x95A5,      // <cjk>
-      0x6258,0x91EF,      // <cjk>
-      0x625B,0x9D4B,      // <cjk>
-      0x625E,0x9D49,      // <cjk>
-      0x6260,0x9D4C,      // <cjk>
-      0x6263,0x9D4A,      // <cjk>
-      0x6268,0x9D4D,      // <cjk>
-      0x626E,0x95AF,      // <cjk>
-      0x6271,0x88B5,      // <cjk>
-      0x6276,0x957D,      // <cjk>
-      0x6279,0x94E1,      // <cjk>
-      0x627C,0x9D4E,      // <cjk>
-      0x627E,0x9D51,      // <cjk>
-      0x627F,0x8FB3,      // <cjk>
-      0x6280,0x8B5A,      // <cjk>
-      0x6282,0x9D4F,      // <cjk>
-      0x6283,0x9D56,      // <cjk>
-      0x6284,0x8FB4,      // <cjk>
-      0x6289,0x9D50,      // <cjk>
-      0x628A,0x9463,      // <cjk>
-      0x6291,0x977D,      // <cjk>
-      0x6292,0x9D52,      // <cjk>
-      0x6293,0x9D53,      // <cjk>
-      0x6294,0x9D57,      // <cjk>
-      0x6295,0x938A,      // <cjk>
-      0x6296,0x9D54,      // <cjk>
-      0x6297,0x8D52,      // <cjk>
-      0x6298,0x90DC,      // <cjk>
-      0x629B,0x9D65,      // <cjk>
-      0x629C,0x94B2,      // <cjk>
-      0x629E,0x91F0,      // <cjk>
-      0x62AB,0x94E2,      // <cjk>
-      0x62AC,0x9DAB,      // <cjk>
-      0x62B1,0x95F8,      // <cjk>
-      0x62B5,0x92EF,      // <cjk>
-      0x62B9,0x9695,      // <cjk>
-      0x62BB,0x9D5A,      // <cjk>
-      0x62BC,0x899F,      // <cjk>
-      0x62BD,0x928A,      // <cjk>
-      0x62C2,0x9D63,      // <cjk>
-      0x62C5,0x9253,      // <cjk>
-      0x62C6,0x9D5D,      // <cjk>
-      0x62C7,0x9D64,      // <cjk>
-      0x62C8,0x9D5F,      // <cjk>
-      0x62C9,0x9D66,      // <cjk>
-      0x62CA,0x9D62,      // <cjk>
-      0x62CC,0x9D61,      // <cjk>
-      0x62CD,0x948F,      // <cjk>
-      0x62D0,0x89FB,      // <cjk>
-      0x62D1,0x9D59,      // <cjk>
-      0x62D2,0x8B91,      // <cjk>
-      0x62D3,0x91F1,      // <cjk>
-      0x62D4,0x9D55,      // <cjk>
-      0x62D7,0x9D58,      // <cjk>
-      0x62D8,0x8D53,      // <cjk>
-      0x62D9,0x90D9,      // <cjk>
-      0x62DB,0x8FB5,      // <cjk>
-      0x62DC,0x9D60,      // <cjk>
-      0x62DD,0x9471,      // <cjk>
-      0x62E0,0x8B92,      // <cjk>
-      0x62E1,0x8A67,      // <cjk>
-      0x62EC,0x8A87,      // <cjk>
-      0x62ED,0x9040,      // <cjk>
-      0x62EE,0x9D68,      // <cjk>
-      0x62EF,0x9D6D,      // <cjk>
-      0x62F1,0x9D69,      // <cjk>
-      0x62F3,0x8C9D,      // <cjk>
-      0x62F5,0x9D6E,      // <cjk>
-      0x62F6,0x8E41,      // <cjk>
-      0x62F7,0x8D89,      // <cjk>
-      0x62FE,0x8F45,      // <cjk>
-      0x62FF,0x9D5C,      // <cjk>
-      0x6301,0x8E9D,      // <cjk>
-      0x6302,0x9D6B,      // <cjk>
-      0x6307,0x8E77,      // <cjk>
-      0x6308,0x9D6C,      // <cjk>
-      0x6309,0x88C2,      // <cjk>
-      0x630C,0x9D67,      // <cjk>
-      0x6311,0x92A7,      // <cjk>
-      0x6319,0x8B93,      // <cjk>
-      0x631F,0x8BB2,      // <cjk>
-      0x6327,0x9D6A,      // <cjk>
-      0x6328,0x88A5,      // <cjk>
-      0x632B,0x8DC1,      // <cjk>
-      0x632F,0x9055,      // <cjk>
-      0x633A,0x92F0,      // <cjk>
-      0x633D,0x94D2,      // <cjk>
-      0x633E,0x9D70,      // <cjk>
-      0x633F,0x917D,      // <cjk>
-      0x6349,0x91A8,      // <cjk>
-      0x634C,0x8E4A,      // <cjk>
-      0x634D,0x9D71,      // <cjk>
-      0x634F,0x9D73,      // <cjk>
-      0x6350,0x9D6F,      // <cjk>
-      0x6355,0x95DF,      // <cjk>
-      0x6357,0x92BB,      // <cjk>
-      0x635C,0x917B,      // <cjk>
-      0x6367,0x95F9,      // <cjk>
-      0x6368,0x8ECC,      // <cjk>
-      0x6369,0x9D80,      // <cjk>
-      0x636B,0x9D7E,      // <cjk>
-      0x636E,0x9098,      // <cjk>
-      0x6372,0x8C9E,      // <cjk>
-      0x6376,0x9D78,      // <cjk>
-      0x6377,0x8FB7,      // <cjk>
-      0x637A,0x93E6,      // <cjk>
-      0x637B,0x9450,      // <cjk>
-      0x6380,0x9D76,      // <cjk>
-      0x6383,0x917C,      // <cjk>
-      0x6388,0x8EF6,      // <cjk>
-      0x6389,0x9D7B,      // <cjk>
-      0x638C,0x8FB6,      // <cjk>
-      0x638E,0x9D75,      // <cjk>
-      0x638F,0x9D7A,      // <cjk>
-      0x6392,0x9472,      // <cjk>
-      0x6396,0x9D74,      // <cjk>
-      0x6398,0x8C40,      // <cjk>
-      0x639B,0x8A7C,      // <cjk>
-      0x639F,0x9D7C,      // <cjk>
-      0x63A0,0x97A9,      // <cjk>
-      0x63A1,0x8DCC,      // <cjk>
-      0x63A2,0x9254,      // <cjk>
-      0x63A3,0x9D79,      // <cjk>
-      0x63A5,0x90DA,      // <cjk>
-      0x63A7,0x8D54,      // <cjk>
-      0x63A8,0x9084,      // <cjk>
-      0x63A9,0x8986,      // <cjk>
-      0x63AB,0x9D77,      // <cjk>
-      0x63AC,0x8B64,      // <cjk>
-      0x63B2,0x8C66,      // <cjk>
-      0x63B4,0x92CD,      // <cjk>
-      0x63B5,0x9D7D,      // <cjk>
-      0x63BB,0x917E,      // <cjk>
-      0x63BE,0x9D81,      // <cjk>
-      0x63C0,0x9D83,      // <cjk>
-      0x63C3,0x91B5,      // <cjk>
-      0x63C4,0x9D89,      // <cjk>
-      0x63C6,0x9D84,      // <cjk>
-      0x63C9,0x9D86,      // <cjk>
-      0x63CF,0x9560,      // <cjk>
-      0x63D0,0x92F1,      // <cjk>
-      0x63D2,0x9D87,      // <cjk>
-      0x63D6,0x974B,      // <cjk>
-      0x63DA,0x9767,      // <cjk>
-      0x63DB,0x8AB7,      // <cjk>
-      0x63E1,0x88AC,      // <cjk>
-      0x63E3,0x9D85,      // <cjk>
-      0x63E9,0x9D82,      // <cjk>
-      0x63EE,0x8AF6,      // <cjk>
-      0x63F4,0x8987,      // <cjk>
-      0x63F6,0x9D88,      // <cjk>
-      0x63FA,0x9768,      // <cjk>
-      0x6406,0x9D8C,      // <cjk>
-      0x640D,0x91B9,      // <cjk>
-      0x640F,0x9D93,      // <cjk>
-      0x6413,0x9D8D,      // <cjk>
-      0x6416,0x9D8A,      // <cjk>
-      0x6417,0x9D91,      // <cjk>
-      0x641C,0x9D72,      // <cjk>
-      0x6426,0x9D8E,      // <cjk>
-      0x6428,0x9D92,      // <cjk>
-      0x642C,0x94C0,      // <cjk>
-      0x642D,0x938B,      // <cjk>
-      0x6434,0x9D8B,      // <cjk>
-      0x6436,0x9D8F,      // <cjk>
-      0x643A,0x8C67,      // <cjk>
-      0x643E,0x8DEF,      // <cjk>
-      0x6442,0x90DB,      // <cjk>
-      0x644E,0x9D97,      // <cjk>
-      0x6458,0x9345,      // <cjk>
-      0x6467,0x9D94,      // <cjk>
-      0x6469,0x9680,      // <cjk>
-      0x646F,0x9D95,      // <cjk>
-      0x6476,0x9D96,      // <cjk>
-      0x6478,0x96CC,      // <cjk>
-      0x647A,0x90A0,      // <cjk>
-      0x6483,0x8C82,      // <cjk>
-      0x6488,0x9D9D,      // <cjk>
-      0x6492,0x8E54,      // <cjk>
-      0x6493,0x9D9A,      // <cjk>
-      0x6495,0x9D99,      // <cjk>
-      0x649A,0x9451,      // <cjk>
-      0x649E,0x93B3,      // <cjk>
-      0x64A4,0x9350,      // <cjk>
-      0x64A5,0x9D9B,      // <cjk>
-      0x64A9,0x9D9C,      // <cjk>
-      0x64AB,0x958F,      // <cjk>
-      0x64AD,0x9464,      // <cjk>
-      0x64AE,0x8E42,      // <cjk>
-      0x64B0,0x90EF,      // <cjk>
-      0x64B2,0x966F,      // <cjk>
-      0x64B9,0x8A68,      // <cjk>
-      0x64BB,0x9DA3,      // <cjk>
-      0x64BC,0x9D9E,      // <cjk>
-      0x64C1,0x9769,      // <cjk>
-      0x64C2,0x9DA5,      // <cjk>
-      0x64C5,0x9DA1,      // <cjk>
-      0x64C7,0x9DA2,      // <cjk>
-      0x64CD,0x9180,      // <cjk>
-      0x64D2,0x9DA0,      // <cjk>
-      0x64D4,0x9D5E,      // <cjk>
-      0x64D8,0x9DA4,      // <cjk>
-      0x64DA,0x9D9F,      // <cjk>
-      0x64E0,0x9DA9,      // <cjk>
-      0x64E1,0x9DAA,      // <cjk>
-      0x64E2,0x9346,      // <cjk>
-      0x64E3,0x9DAC,      // <cjk>
-      0x64E6,0x8E43,      // <cjk>
-      0x64E7,0x9DA7,      // <cjk>
-      0x64EF,0x9DAD,      // <cjk>
-      0x64F1,0x9DA6,      // <cjk>
-      0x64F2,0x9DB1,      // <cjk>
-      0x64F4,0x9DB0,      // <cjk>
-      0x64F6,0x9DAF,      // <cjk>
-      0x64FA,0x9DB2,      // <cjk>
-      0x64FD,0x9DB4,      // <cjk>
-      0x64FE,0x8FEF,      // <cjk>
-      0x6500,0x9DB3,      // <cjk>
-      0x6505,0x9DB7,      // <cjk>
-      0x6518,0x9DB5,      // <cjk>
-      0x651C,0x9DB6,      // <cjk>
-      0x651D,0x9D90,      // <cjk>
-      0x6523,0x9DB9,      // <cjk>
-      0x6524,0x9DB8,      // <cjk>
-      0x652A,0x9D98,      // <cjk>
-      0x652B,0x9DBA,      // <cjk>
-      0x652C,0x9DAE,      // <cjk>
-      0x652F,0x8E78,      // <cjk>
-      0x6534,0x9DBB,      // <cjk>
-      0x6535,0x9DBC,      // <cjk>
-      0x6536,0x9DBE,      // <cjk>
-      0x6537,0x9DBD,      // <cjk>
-      0x6538,0x9DBF,      // <cjk>
-      0x6539,0x89FC,      // <cjk>
-      0x653B,0x8D55,      // <cjk>
-      0x653E,0x95FA,      // <cjk>
-      0x653F,0x90AD,      // <cjk>
-      0x6545,0x8CCC,      // <cjk>
-      0x6548,0x9DC1,      // <cjk>
-      0x654D,0x9DC4,      // <cjk>
-      0x654F,0x9571,      // <cjk>
-      0x6551,0x8B7E,      // <cjk>
-      0x6555,0x9DC3,      // <cjk>
-      0x6556,0x9DC2,      // <cjk>
-      0x6557,0x9473,      // <cjk>
-      0x6558,0x9DC5,      // <cjk>
-      0x6559,0x8BB3,      // <cjk>
-      0x655D,0x9DC7,      // <cjk>
-      0x655E,0x9DC6,      // <cjk>
-      0x6562,0x8AB8,      // <cjk>
-      0x6563,0x8E55,      // <cjk>
-      0x6566,0x93D6,      // <cjk>
-      0x656C,0x8C68,      // <cjk>
-      0x6570,0x9094,      // <cjk>
-      0x6572,0x9DC8,      // <cjk>
-      0x6574,0x90AE,      // <cjk>
-      0x6575,0x9347,      // <cjk>
-      0x6577,0x957E,      // <cjk>
-      0x6578,0x9DC9,      // <cjk>
-      0x6582,0x9DCA,      // <cjk>
-      0x6583,0x9DCB,      // <cjk>
-      0x6587,0x95B6,      // <cjk>
-      0x6588,0x9B7C,      // <cjk>
-      0x6589,0x90C4,      // <cjk>
-      0x658C,0x956B,      // <cjk>
-      0x658E,0x8DD6,      // <cjk>
-      0x6590,0x94E3,      // <cjk>
-      0x6591,0x94C1,      // <cjk>
-      0x6597,0x936C,      // <cjk>
-      0x6599,0x97BF,      // <cjk>
-      0x659B,0x9DCD,      // <cjk>
-      0x659C,0x8ECE,      // <cjk>
-      0x659F,0x9DCE,      // <cjk>
-      0x65A1,0x88B4,      // <cjk>
-      0x65A4,0x8BD2,      // <cjk>
-      0x65A5,0x90CB,      // <cjk>
-      0x65A7,0x9580,      // <cjk>
-      0x65AB,0x9DCF,      // <cjk>
-      0x65AC,0x8E61,      // <cjk>
-      0x65AD,0x9266,      // <cjk>
-      0x65AF,0x8E7A,      // <cjk>
-      0x65B0,0x9056,      // <cjk>
-      0x65B7,0x9DD0,      // <cjk>
-      0x65B9,0x95FB,      // <cjk>
-      0x65BC,0x8997,      // <cjk>
-      0x65BD,0x8E7B,      // <cjk>
-      0x65C1,0x9DD3,      // <cjk>
-      0x65C3,0x9DD1,      // <cjk>
-      0x65C4,0x9DD4,      // <cjk>
-      0x65C5,0x97B7,      // <cjk>
-      0x65C6,0x9DD2,      // <cjk>
-      0x65CB,0x90F9,      // <cjk>
-      0x65CC,0x9DD5,      // <cjk>
-      0x65CF,0x91B0,      // <cjk>
-      0x65D2,0x9DD6,      // <cjk>
-      0x65D7,0x8AF8,      // <cjk>
-      0x65D9,0x9DD8,      // <cjk>
-      0x65DB,0x9DD7,      // <cjk>
-      0x65E0,0x9DD9,      // <cjk>
-      0x65E1,0x9DDA,      // <cjk>
-      0x65E2,0x8AF9,      // <cjk>
-      0x65E5,0x93FA,      // <cjk>
-      0x65E6,0x9255,      // <cjk>
-      0x65E7,0x8B8C,      // <cjk>
-      0x65E8,0x8E7C,      // <cjk>
-      0x65E9,0x9181,      // <cjk>
-      0x65EC,0x8F7B,      // <cjk>
-      0x65ED,0x88AE,      // <cjk>
-      0x65F1,0x9DDB,      // <cjk>
-      0x65FA,0x89A0,      // <cjk>
-      0x65FB,0x9DDF,      // <cjk>
-      0x6602,0x8D56,      // <cjk>
-      0x6603,0x9DDE,      // <cjk>
-      0x6606,0x8DA9,      // <cjk>
-      0x6607,0x8FB8,      // <cjk>
-      0x660A,0x9DDD,      // <cjk>
-      0x660C,0x8FB9,      // <cjk>
-      0x660E,0x96BE,      // <cjk>
-      0x660F,0x8DA8,      // <cjk>
-      0x6613,0x88D5,      // <cjk>
-      0x6614,0x90CC,      // <cjk>
-      0x661C,0x9DE4,      // <cjk>
-      0x661F,0x90AF,      // <cjk>
-      0x6620,0x8966,      // <cjk>
-      0x6625,0x8F74,      // <cjk>
-      0x6627,0x9686,      // <cjk>
-      0x6628,0x8DF0,      // <cjk>
-      0x662D,0x8FBA,      // <cjk>
-      0x662F,0x90A5,      // <cjk>
-      0x6634,0x9DE3,      // <cjk>
-      0x6635,0x9DE1,      // <cjk>
-      0x6636,0x9DE2,      // <cjk>
-      0x663C,0x928B,      // <cjk>
-      0x663F,0x9E45,      // <cjk>
-      0x6641,0x9DE8,      // <cjk>
-      0x6642,0x8E9E,      // <cjk>
-      0x6643,0x8D57,      // <cjk>
-      0x6644,0x9DE6,      // <cjk>
-      0x6649,0x9DE7,      // <cjk>
-      0x664B,0x9057,      // <cjk>
-      0x664F,0x9DE5,      // <cjk>
-      0x6652,0x8E4E,      // <cjk>
-      0x665D,0x9DEA,      // <cjk>
-      0x665E,0x9DE9,      // <cjk>
-      0x665F,0x9DEE,      // <cjk>
-      0x6662,0x9DEF,      // <cjk>
-      0x6664,0x9DEB,      // <cjk>
-      0x6666,0x8A41,      // <cjk>
-      0x6667,0x9DEC,      // <cjk>
-      0x6668,0x9DED,      // <cjk>
-      0x6669,0x94D3,      // <cjk>
-      0x666E,0x9581,      // <cjk>
-      0x666F,0x8C69,      // <cjk>
-      0x6670,0x9DF0,      // <cjk>
-      0x6674,0x90B0,      // <cjk>
-      0x6676,0x8FBB,      // <cjk>
-      0x667A,0x9271,      // <cjk>
-      0x6681,0x8BC5,      // <cjk>
-      0x6683,0x9DF1,      // <cjk>
-      0x6684,0x9DF5,      // <cjk>
-      0x6687,0x89C9,      // <cjk>
-      0x6688,0x9DF2,      // <cjk>
-      0x6689,0x9DF4,      // <cjk>
-      0x668E,0x9DF3,      // <cjk>
-      0x6691,0x8F8B,      // <cjk>
-      0x6696,0x9267,      // <cjk>
-      0x6697,0x88C3,      // <cjk>
-      0x6698,0x9DF6,      // <cjk>
-      0x669D,0x9DF7,      // <cjk>
-      0x66A2,0x92A8,      // <cjk>
-      0x66A6,0x97EF,      // <cjk>
-      0x66AB,0x8E62,      // <cjk>
-      0x66AE,0x95E9,      // <cjk>
-      0x66B4,0x965C,      // <cjk>
-      0x66B8,0x9E41,      // <cjk>
-      0x66B9,0x9DF9,      // <cjk>
-      0x66BC,0x9DFC,      // <cjk>
-      0x66BE,0x9DFB,      // <cjk>
-      0x66C1,0x9DF8,      // <cjk>
-      0x66C4,0x9E40,      // <cjk>
-      0x66C7,0x93DC,      // <cjk>
-      0x66C9,0x9DFA,      // <cjk>
-      0x66D6,0x9E42,      // <cjk>
-      0x66D9,0x8F8C,      // <cjk>
-      0x66DA,0x9E43,      // <cjk>
-      0x66DC,0x976A,      // <cjk>
-      0x66DD,0x9498,      // <cjk>
-      0x66E0,0x9E44,      // <cjk>
-      0x66E6,0x9E46,      // <cjk>
-      0x66E9,0x9E47,      // <cjk>
-      0x66F0,0x9E48,      // <cjk>
-      0x66F2,0x8BC8,      // <cjk>
-      0x66F3,0x8967,      // <cjk>
-      0x66F4,0x8D58,      // <cjk>
-      0x66F5,0x9E49,      // <cjk>
-      0x66F7,0x9E4A,      // <cjk>
-      0x66F8,0x8F91,      // <cjk>
-      0x66F9,0x9182,      // <cjk>
-      0x66FC,0x99D6,      // <cjk>
-      0x66FD,0x915D,      // <cjk>
-      0x66FE,0x915C,      // <cjk>
-      0x66FF,0x91D6,      // <cjk>
-      0x6700,0x8DC5,      // <cjk>
-      0x6703,0x98F0,      // <cjk>
-      0x6708,0x8C8E,      // <cjk>
-      0x6709,0x974C,      // <cjk>
-      0x670B,0x95FC,      // <cjk>
-      0x670D,0x959E,      // <cjk>
-      0x670F,0x9E4B,      // <cjk>
-      0x6714,0x8DF1,      // <cjk>
-      0x6715,0x92BD,      // <cjk>
-      0x6716,0x9E4C,      // <cjk>
-      0x6717,0x984E,      // <cjk>
-      0x671B,0x965D,      // <cjk>
-      0x671D,0x92A9,      // <cjk>
-      0x671E,0x9E4D,      // <cjk>
-      0x671F,0x8AFA,      // <cjk>
-      0x6726,0x9E4E,      // <cjk>
-      0x6727,0x9E4F,      // <cjk>
-      0x6728,0x96D8,      // <cjk>
-      0x672A,0x96A2,      // <cjk>
-      0x672B,0x9696,      // <cjk>
-      0x672C,0x967B,      // <cjk>
-      0x672D,0x8E44,      // <cjk>
-      0x672E,0x9E51,      // <cjk>
-      0x6731,0x8EE9,      // <cjk>
-      0x6734,0x9670,      // <cjk>
-      0x6736,0x9E53,      // <cjk>
-      0x6737,0x9E56,      // <cjk>
-      0x6738,0x9E55,      // <cjk>
-      0x673A,0x8AF7,      // <cjk>
-      0x673D,0x8B80,      // <cjk>
-      0x673F,0x9E52,      // <cjk>
-      0x6741,0x9E54,      // <cjk>
-      0x6746,0x9E57,      // <cjk>
-      0x6749,0x9099,      // <cjk>
-      0x674E,0x979B,      // <cjk>
-      0x674F,0x88C7,      // <cjk>
-      0x6750,0x8DDE,      // <cjk>
-      0x6751,0x91BA,      // <cjk>
-      0x6753,0x8EDB,      // <cjk>
-      0x6756,0x8FF1,      // <cjk>
-      0x6759,0x9E5A,      // <cjk>
-      0x675C,0x936D,      // <cjk>
-      0x675E,0x9E58,      // <cjk>
-      0x675F,0x91A9,      // <cjk>
-      0x6760,0x9E59,      // <cjk>
-      0x6761,0x8FF0,      // <cjk>
-      0x6762,0x96DB,      // <cjk>
-      0x6764,0x9E5C,      // <cjk>
-      0x6765,0x9788,      // <cjk>
-      0x676A,0x9E61,      // <cjk>
-      0x676D,0x8D59,      // <cjk>
-      0x676F,0x9474,      // <cjk>
-      0x6770,0x9E5E,      // <cjk>
-      0x6771,0x938C,      // <cjk>
-      0x6772,0x9DDC,      // <cjk>
-      0x6773,0x9DE0,      // <cjk>
-      0x6775,0x8B6E,      // <cjk>
-      0x6777,0x9466,      // <cjk>
-      0x677C,0x9E60,      // <cjk>
-      0x677E,0x8FBC,      // <cjk>
-      0x677F,0x94C2,      // <cjk>
-      0x6785,0x9E66,      // <cjk>
-      0x6787,0x94F8,      // <cjk>
-      0x6789,0x9E5D,      // <cjk>
-      0x678B,0x9E63,      // <cjk>
-      0x678C,0x9E62,      // <cjk>
-      0x6790,0x90CD,      // <cjk>
-      0x6795,0x968D,      // <cjk>
-      0x6797,0x97D1,      // <cjk>
-      0x679A,0x9687,      // <cjk>
-      0x679C,0x89CA,      // <cjk>
-      0x679D,0x8E7D,      // <cjk>
-      0x67A0,0x9867,      // <cjk>
-      0x67A1,0x9E65,      // <cjk>
-      0x67A2,0x9095,      // <cjk>
-      0x67A6,0x9E64,      // <cjk>
-      0x67A9,0x9E5F,      // <cjk>
-      0x67AF,0x8CCD,      // <cjk>
-      0x67B3,0x9E6B,      // <cjk>
-      0x67B4,0x9E69,      // <cjk>
-      0x67B6,0x89CB,      // <cjk>
-      0x67B7,0x9E67,      // <cjk>
-      0x67B8,0x9E6D,      // <cjk>
-      0x67B9,0x9E73,      // <cjk>
-      0x67C1,0x91C6,      // <cjk>
-      0x67C4,0x95BF,      // <cjk>
-      0x67C6,0x9E75,      // <cjk>
-      0x67CA,0x9541,      // <cjk>
-      0x67CE,0x9E74,      // <cjk>
-      0x67CF,0x9490,      // <cjk>
-      0x67D0,0x965E,      // <cjk>
-      0x67D1,0x8AB9,      // <cjk>
-      0x67D3,0x90F5,      // <cjk>
-      0x67D4,0x8F5F,      // <cjk>
-      0x67D8,0x92D1,      // <cjk>
-      0x67DA,0x974D,      // <cjk>
-      0x67DD,0x9E70,      // <cjk>
-      0x67DE,0x9E6F,      // <cjk>
-      0x67E2,0x9E71,      // <cjk>
-      0x67E4,0x9E6E,      // <cjk>
-      0x67E7,0x9E76,      // <cjk>
-      0x67E9,0x9E6C,      // <cjk>
-      0x67EC,0x9E6A,      // <cjk>
-      0x67EE,0x9E72,      // <cjk>
-      0x67EF,0x9E68,      // <cjk>
-      0x67F1,0x928C,      // <cjk>
-      0x67F3,0x96F6,      // <cjk>
-      0x67F4,0x8EC4,      // <cjk>
-      0x67F5,0x8DF2,      // <cjk>
-      0x67FB,0x8DB8,      // <cjk>
-      0x67FE,0x968F,      // <cjk>
-      0x67FF,0x8A60,      // <cjk>
-      0x6802,0x92CC,      // <cjk>
-      0x6803,0x93C8,      // <cjk>
-      0x6804,0x8968,      // <cjk>
-      0x6813,0x90F0,      // <cjk>
-      0x6816,0x90B2,      // <cjk>
-      0x6817,0x8C49,      // <cjk>
-      0x681E,0x9E78,      // <cjk>
-      0x6821,0x8D5A,      // <cjk>
-      0x6822,0x8A9C,      // <cjk>
-      0x6829,0x9E7A,      // <cjk>
-      0x682A,0x8A94,      // <cjk>
-      0x682B,0x9E81,      // <cjk>
-      0x6832,0x9E7D,      // <cjk>
-      0x6834,0x90F1,      // <cjk>
-      0x6838,0x8A6A,      // <cjk>
-      0x6839,0x8DAA,      // <cjk>
-      0x683C,0x8A69,      // <cjk>
-      0x683D,0x8DCD,      // <cjk>
-      0x6840,0x9E7B,      // <cjk>
-      0x6841,0x8C85,      // <cjk>
-      0x6842,0x8C6A,      // <cjk>
-      0x6843,0x938D,      // <cjk>
-      0x6846,0x9E79,      // <cjk>
-      0x6848,0x88C4,      // <cjk>
-      0x684D,0x9E7C,      // <cjk>
-      0x684E,0x9E7E,      // <cjk>
-      0x6850,0x8BCB,      // <cjk>
-      0x6851,0x8C4B,      // <cjk>
-      0x6853,0x8ABA,      // <cjk>
-      0x6854,0x8B6A,      // <cjk>
-      0x6859,0x9E82,      // <cjk>
-      0x685C,0x8DF7,      // <cjk>
-      0x685D,0x9691,      // <cjk>
-      0x685F,0x8E56,      // <cjk>
-      0x6863,0x9E83,      // <cjk>
-      0x6867,0x954F,      // <cjk>
-      0x6874,0x9E8F,      // <cjk>
-      0x6876,0x89B1,      // <cjk>
-      0x6877,0x9E84,      // <cjk>
-      0x687E,0x9E95,      // <cjk>
-      0x687F,0x9E85,      // <cjk>
-      0x6881,0x97C0,      // <cjk>
-      0x6883,0x9E8C,      // <cjk>
-      0x6885,0x947E,      // <cjk>
-      0x688D,0x9E94,      // <cjk>
-      0x688F,0x9E87,      // <cjk>
-      0x6893,0x88B2,      // <cjk>
-      0x6894,0x9E89,      // <cjk>
-      0x689B,0x9E8B,      // <cjk>
-      0x689D,0x9E8A,      // <cjk>
-      0x689F,0x9E86,      // <cjk>
-      0x68A0,0x9E91,      // <cjk>
-      0x68A2,0x8FBD,      // <cjk>
-      0x68A6,0x9AEB,      // <cjk>
-      0x68A7,0x8CE6,      // <cjk>
-      0x68A8,0x979C,      // <cjk>
-      0x68AD,0x9E88,      // <cjk>
-      0x68AF,0x92F2,      // <cjk>
-      0x68B0,0x8A42,      // <cjk>
-      0x68B1,0x8DAB,      // <cjk>
-      0x68B3,0x9E80,      // <cjk>
-      0x68B5,0x9E90,      // <cjk>
-      0x68B6,0x8A81,      // <cjk>
-      0x68B9,0x9E8E,      // <cjk>
-      0x68BA,0x9E92,      // <cjk>
-      0x68BC,0x938E,      // <cjk>
-      0x68C4,0x8AFC,      // <cjk>
-      0x68C6,0x9EB0,      // <cjk>
-      0x68C9,0x96C7,      // <cjk>
-      0x68CA,0x9E97,      // <cjk>
-      0x68CB,0x8AFB,      // <cjk>
-      0x68CD,0x9E9E,      // <cjk>
-      0x68D2,0x965F,      // <cjk>
-      0x68D4,0x9E9F,      // <cjk>
-      0x68D5,0x9EA1,      // <cjk>
-      0x68D7,0x9EA5,      // <cjk>
-      0x68D8,0x9E99,      // <cjk>
-      0x68DA,0x9249,      // <cjk>
-      0x68DF,0x938F,      // <cjk>
-      0x68E0,0x9EA9,      // <cjk>
-      0x68E1,0x9E9C,      // <cjk>
-      0x68E3,0x9EA6,      // <cjk>
-      0x68E7,0x9EA0,      // <cjk>
-      0x68EE,0x9058,      // <cjk>
-      0x68EF,0x9EAA,      // <cjk>
-      0x68F2,0x90B1,      // <cjk>
-      0x68F9,0x9EA8,      // <cjk>
-      0x68FA,0x8ABB,      // <cjk>
-      0x6900,0x986F,      // <cjk>
-      0x6901,0x9E96,      // <cjk>
-      0x6904,0x9EA4,      // <cjk>
-      0x6905,0x88D6,      // <cjk>
-      0x6908,0x9E98,      // <cjk>
-      0x690B,0x96B8,      // <cjk>
-      0x690C,0x9E9D,      // <cjk>
-      0x690D,0x9041,      // <cjk>
-      0x690E,0x92C5,      // <cjk>
-      0x690F,0x9E93,      // <cjk>
-      0x6912,0x9EA3,      // <cjk>
-      0x6919,0x909A,      // <cjk>
-      0x691A,0x9EAD,      // <cjk>
-      0x691B,0x8A91,      // <cjk>
-      0x691C,0x8C9F,      // <cjk>
-      0x6921,0x9EAF,      // <cjk>
-      0x6922,0x9E9A,      // <cjk>
-      0x6923,0x9EAE,      // <cjk>
-      0x6925,0x9EA7,      // <cjk>
-      0x6926,0x9E9B,      // <cjk>
-      0x6928,0x9EAB,      // <cjk>
-      0x692A,0x9EAC,      // <cjk>
-      0x6930,0x9EBD,      // <cjk>
-      0x6934,0x93CC,      // <cjk>
-      0x6936,0x9EA2,      // <cjk>
-      0x6939,0x9EB9,      // <cjk>
-      0x693D,0x9EBB,      // <cjk>
-      0x693F,0x92D6,      // <cjk>
-      0x694A,0x976B,      // <cjk>
-      0x6953,0x9596,      // <cjk>
-      0x6954,0x9EB6,      // <cjk>
-      0x6955,0x91C8,      // <cjk>
-      0x6959,0x9EBC,      // <cjk>
-      0x695A,0x915E,      // <cjk>
-      0x695C,0x9EB3,      // <cjk>
-      0x695D,0x9EC0,      // <cjk>
-      0x695E,0x9EBF,      // <cjk>
-      0x6960,0x93ED,      // <cjk>
-      0x6961,0x9EBE,      // <cjk>
-      0x6962,0x93E8,      // <cjk>
-      0x696A,0x9EC2,      // <cjk>
-      0x696B,0x9EB5,      // <cjk>
-      0x696D,0x8BC6,      // <cjk>
-      0x696E,0x9EB8,      // <cjk>
-      0x696F,0x8F7C,      // <cjk>
-      0x6973,0x9480,      // <cjk>
-      0x6974,0x9EBA,      // <cjk>
-      0x6975,0x8BC9,      // <cjk>
-      0x6977,0x9EB2,      // <cjk>
-      0x6978,0x9EB4,      // <cjk>
-      0x6979,0x9EB1,      // <cjk>
-      0x697C,0x984F,      // <cjk>
-      0x697D,0x8A79,      // <cjk>
-      0x697E,0x9EB7,      // <cjk>
-      0x6981,0x9EC1,      // <cjk>
-      0x6982,0x8A54,      // <cjk>
-      0x698A,0x8DE5,      // <cjk>
-      0x698E,0x897C,      // <cjk>
-      0x6991,0x9ED2,      // <cjk>
-      0x6994,0x9850,      // <cjk>
-      0x6995,0x9ED5,      // <cjk>
-      0x699B,0x9059,      // <cjk>
-      0x699C,0x9ED4,      // <cjk>
-      0x69A0,0x9ED3,      // <cjk>
-      0x69A7,0x9ED0,      // <cjk>
-      0x69AE,0x9EC4,      // <cjk>
-      0x69B1,0x9EE1,      // <cjk>
-      0x69B2,0x9EC3,      // <cjk>
-      0x69B4,0x9ED6,      // <cjk>
-      0x69BB,0x9ECE,      // <cjk>
-      0x69BE,0x9EC9,      // <cjk>
-      0x69BF,0x9EC6,      // <cjk>
-      0x69C1,0x9EC7,      // <cjk>
-      0x69C3,0x9ECF,      // <cjk>
-      0x69C7,0xEAA0,      // <cjk>
-      0x69CA,0x9ECC,      // <cjk>
-      0x69CB,0x8D5C,      // <cjk>
-      0x69CC,0x92C6,      // <cjk>
-      0x69CD,0x9184,      // <cjk>
-      0x69CE,0x9ECA,      // <cjk>
-      0x69D0,0x9EC5,      // <cjk>
-      0x69D3,0x9EC8,      // <cjk>
-      0x69D8,0x976C,      // <cjk>
-      0x69D9,0x968A,      // <cjk>
-      0x69DD,0x9ECD,      // <cjk>
-      0x69DE,0x9ED7,      // <cjk>
-      0x69E7,0x9EDF,      // <cjk>
-      0x69E8,0x9ED8,      // <cjk>
-      0x69EB,0x9EE5,      // <cjk>
-      0x69ED,0x9EE3,      // <cjk>
-      0x69F2,0x9EDE,      // <cjk>
-      0x69F9,0x9EDD,      // <cjk>
-      0x69FB,0x92CE,      // <cjk>
-      0x69FD,0x9185,      // <cjk>
-      0x69FF,0x9EDB,      // <cjk>
-      0x6A02,0x9ED9,      // <cjk>
-      0x6A05,0x9EE0,      // <cjk>
-      0x6A0A,0x9EE6,      // <cjk>
-      0x6A0B,0x94F3,      // <cjk>
-      0x6A0C,0x9EEC,      // <cjk>
-      0x6A12,0x9EE7,      // <cjk>
-      0x6A13,0x9EEA,      // <cjk>
-      0x6A14,0x9EE4,      // <cjk>
-      0x6A17,0x9294,      // <cjk>
-      0x6A19,0x9557,      // <cjk>
-      0x6A1B,0x9EDA,      // <cjk>
-      0x6A1E,0x9EE2,      // <cjk>
-      0x6A1F,0x8FBE,      // <cjk>
-      0x6A21,0x96CD,      // <cjk>
-      0x6A22,0x9EF6,      // <cjk>
-      0x6A23,0x9EE9,      // <cjk>
-      0x6A29,0x8CA0,      // <cjk>
-      0x6A2A,0x89A1,      // <cjk>
-      0x6A2B,0x8A7E,      // <cjk>
-      0x6A2E,0x9ED1,      // <cjk>
-      0x6A35,0x8FBF,      // <cjk>
-      0x6A36,0x9EEE,      // <cjk>
-      0x6A38,0x9EF5,      // <cjk>
-      0x6A39,0x8EF7,      // <cjk>
-      0x6A3A,0x8A92,      // <cjk>
-      0x6A3D,0x924D,      // <cjk>
-      0x6A44,0x9EEB,      // <cjk>
-      0x6A47,0x9EF0,      // <cjk>
-      0x6A48,0x9EF4,      // <cjk>
-      0x6A4B,0x8BB4,      // <cjk>
-      0x6A58,0x8B6B,      // <cjk>
-      0x6A59,0x9EF2,      // <cjk>
-      0x6A5F,0x8B40,      // <cjk>
-      0x6A61,0x93C9,      // <cjk>
-      0x6A62,0x9EF1,      // <cjk>
-      0x6A66,0x9EF3,      // <cjk>
-      0x6A72,0x9EED,      // <cjk>
-      0x6A78,0x9EEF,      // <cjk>
-      0x6A7F,0x8A80,      // <cjk>
-      0x6A80,0x9268,      // <cjk>
-      0x6A84,0x9EFA,      // <cjk>
-      0x6A8D,0x9EF8,      // <cjk>
-      0x6A8E,0x8CE7,      // <cjk>
-      0x6A90,0x9EF7,      // <cjk>
-      0x6A97,0x9F40,      // <cjk>
-      0x6A9C,0x9E77,      // <cjk>
-      0x6AA0,0x9EF9,      // <cjk>
-      0x6AA2,0x9EFB,      // <cjk>
-      0x6AA3,0x9EFC,      // <cjk>
-      0x6AAA,0x9F4B,      // <cjk>
-      0x6AAC,0x9F47,      // <cjk>
-      0x6AAE,0x9E8D,      // <cjk>
-      0x6AB3,0x9F46,      // <cjk>
-      0x6AB8,0x9F45,      // <cjk>
-      0x6ABB,0x9F42,      // <cjk>
-      0x6AC1,0x9EE8,      // <cjk>
-      0x6AC2,0x9F44,      // <cjk>
-      0x6AC3,0x9F43,      // <cjk>
-      0x6AD1,0x9F49,      // <cjk>
-      0x6AD3,0x9845,      // <cjk>
-      0x6ADA,0x9F4C,      // <cjk>
-      0x6ADB,0x8BF9,      // <cjk>
-      0x6ADE,0x9F48,      // <cjk>
-      0x6ADF,0x9F4A,      // <cjk>
-      0x6AE8,0x94A5,      // <cjk>
-      0x6AEA,0x9F4D,      // <cjk>
-      0x6AFA,0x9F51,      // <cjk>
-      0x6AFB,0x9F4E,      // <cjk>
-      0x6B04,0x9793,      // <cjk>
-      0x6B05,0x9F4F,      // <cjk>
-      0x6B0A,0x9EDC,      // <cjk>
-      0x6B12,0x9F52,      // <cjk>
-      0x6B16,0x9F53,      // <cjk>
-      0x6B1D,0x8954,      // <cjk>
-      0x6B1F,0x9F55,      // <cjk>
-      0x6B20,0x8C87,      // <cjk>
-      0x6B21,0x8E9F,      // <cjk>
-      0x6B23,0x8BD3,      // <cjk>
-      0x6B27,0x89A2,      // <cjk>
-      0x6B32,0x977E,      // <cjk>
-      0x6B37,0x9F57,      // <cjk>
-      0x6B38,0x9F56,      // <cjk>
-      0x6B39,0x9F59,      // <cjk>
-      0x6B3A,0x8B5C,      // <cjk>
-      0x6B3D,0x8BD4,      // <cjk>
-      0x6B3E,0x8ABC,      // <cjk>
-      0x6B43,0x9F5C,      // <cjk>
-      0x6B49,0x9F5D,      // <cjk>
-      0x6B4C,0x89CC,      // <cjk>
-      0x6B4E,0x9256,      // <cjk>
-      0x6B50,0x9F5E,      // <cjk>
-      0x6B53,0x8ABD,      // <cjk>
-      0x6B54,0x9F60,      // <cjk>
-      0x6B59,0x9F5F,      // <cjk>
-      0x6B5B,0x9F61,      // <cjk>
-      0x6B5F,0x9F62,      // <cjk>
-      0x6B61,0x9F63,      // <cjk>
-      0x6B62,0x8E7E,      // <cjk>
-      0x6B63,0x90B3,      // <cjk>
-      0x6B64,0x8D9F,      // <cjk>
-      0x6B66,0x9590,      // <cjk>
-      0x6B69,0x95E0,      // <cjk>
-      0x6B6A,0x9863,      // <cjk>
-      0x6B6F,0x8E95,      // <cjk>
-      0x6B73,0x8DCE,      // <cjk>
-      0x6B74,0x97F0,      // <cjk>
-      0x6B78,0x9F64,      // <cjk>
-      0x6B79,0x9F65,      // <cjk>
-      0x6B7B,0x8E80,      // <cjk>
-      0x6B7F,0x9F66,      // <cjk>
-      0x6B80,0x9F67,      // <cjk>
-      0x6B83,0x9F69,      // <cjk>
-      0x6B84,0x9F68,      // <cjk>
-      0x6B86,0x9677,      // <cjk>
-      0x6B89,0x8F7D,      // <cjk>
-      0x6B8A,0x8EEA,      // <cjk>
-      0x6B8B,0x8E63,      // <cjk>
-      0x6B8D,0x9F6A,      // <cjk>
-      0x6B95,0x9F6C,      // <cjk>
-      0x6B96,0x9042,      // <cjk>
-      0x6B98,0x9F6B,      // <cjk>
-      0x6B9E,0x9F6D,      // <cjk>
-      0x6BA4,0x9F6E,      // <cjk>
-      0x6BAA,0x9F6F,      // <cjk>
-      0x6BAB,0x9F70,      // <cjk>
-      0x6BAF,0x9F71,      // <cjk>
-      0x6BB1,0x9F73,      // <cjk>
-      0x6BB2,0x9F72,      // <cjk>
-      0x6BB3,0x9F74,      // <cjk>
-      0x6BB4,0x89A3,      // <cjk>
-      0x6BB5,0x9269,      // <cjk>
-      0x6BB7,0x9F75,      // <cjk>
-      0x6BBA,0x8E45,      // <cjk>
-      0x6BBB,0x8A6B,      // <cjk>
-      0x6BBC,0x9F76,      // <cjk>
-      0x6BBF,0x9361,      // <cjk>
-      0x6BC0,0x9ACA,      // <cjk>
-      0x6BC5,0x8B42,      // <cjk>
-      0x6BC6,0x9F77,      // <cjk>
-      0x6BCB,0x9F78,      // <cjk>
-      0x6BCD,0x95EA,      // <cjk>
-      0x6BCE,0x9688,      // <cjk>
-      0x6BD2,0x93C5,      // <cjk>
-      0x6BD3,0x9F79,      // <cjk>
-      0x6BD4,0x94E4,      // <cjk>
-      0x6BD8,0x94F9,      // <cjk>
-      0x6BDB,0x96D1,      // <cjk>
-      0x6BDF,0x9F7A,      // <cjk>
-      0x6BEB,0x9F7C,      // <cjk>
-      0x6BEC,0x9F7B,      // <cjk>
-      0x6BEF,0x9F7E,      // <cjk>
-      0x6BF3,0x9F7D,      // <cjk>
-      0x6C08,0x9F81,      // <cjk>
-      0x6C0F,0x8E81,      // <cjk>
-      0x6C11,0x96AF,      // <cjk>
-      0x6C13,0x9F82,      // <cjk>
-      0x6C14,0x9F83,      // <cjk>
-      0x6C17,0x8B43,      // <cjk>
-      0x6C1B,0x9F84,      // <cjk>
-      0x6C23,0x9F86,      // <cjk>
-      0x6C24,0x9F85,      // <cjk>
-      0x6C34,0x9085,      // <cjk>
-      0x6C37,0x9558,      // <cjk>
-      0x6C38,0x8969,      // <cjk>
-      0x6C3E,0x94C3,      // <cjk>
-      0x6C40,0x92F3,      // <cjk>
-      0x6C41,0x8F60,      // <cjk>
-      0x6C42,0x8B81,      // <cjk>
-      0x6C4E,0x94C4,      // <cjk>
-      0x6C50,0x8EAC,      // <cjk>
-      0x6C55,0x9F88,      // <cjk>
-      0x6C57,0x8ABE,      // <cjk>
-      0x6C5A,0x8998,      // <cjk>
-      0x6C5D,0x93F0,      // <cjk>
-      0x6C5E,0x9F87,      // <cjk>
-      0x6C5F,0x8D5D,      // <cjk>
-      0x6C60,0x9272,      // <cjk>
-      0x6C62,0x9F89,      // <cjk>
-      0x6C68,0x9F91,      // <cjk>
-      0x6C6A,0x9F8A,      // <cjk>
-      0x6C70,0x91BF,      // <cjk>
-      0x6C72,0x8B82,      // <cjk>
-      0x6C73,0x9F92,      // <cjk>
-      0x6C7A,0x8C88,      // <cjk>
-      0x6C7D,0x8B44,      // <cjk>
-      0x6C7E,0x9F90,      // <cjk>
-      0x6C81,0x9F8E,      // <cjk>
-      0x6C82,0x9F8B,      // <cjk>
-      0x6C83,0x9780,      // <cjk>
-      0x6C88,0x92BE,      // <cjk>
-      0x6C8C,0x93D7,      // <cjk>
-      0x6C8D,0x9F8C,      // <cjk>
-      0x6C90,0x9F94,      // <cjk>
-      0x6C92,0x9F93,      // <cjk>
-      0x6C93,0x8C42,      // <cjk>
-      0x6C96,0x89AB,      // <cjk>
-      0x6C99,0x8DB9,      // <cjk>
-      0x6C9A,0x9F8D,      // <cjk>
-      0x6C9B,0x9F8F,      // <cjk>
-      0x6CA1,0x9676,      // <cjk>
-      0x6CA2,0x91F2,      // <cjk>
-      0x6CAB,0x9697,      // <cjk>
-      0x6CAE,0x9F9C,      // <cjk>
-      0x6CB1,0x9F9D,      // <cjk>
-      0x6CB3,0x89CD,      // <cjk>
-      0x6CB8,0x95A6,      // <cjk>
-      0x6CB9,0x96FB,      // <cjk>
-      0x6CBA,0x9F9F,      // <cjk>
-      0x6CBB,0x8EA1,      // <cjk>
-      0x6CBC,0x8FC0,      // <cjk>
-      0x6CBD,0x9F98,      // <cjk>
-      0x6CBE,0x9F9E,      // <cjk>
-      0x6CBF,0x8988,      // <cjk>
-      0x6CC1,0x8BB5,      // <cjk>
-      0x6CC4,0x9F95,      // <cjk>
-      0x6CC5,0x9F9A,      // <cjk>
-      0x6CC9,0x90F2,      // <cjk>
-      0x6CCA,0x9491,      // <cjk>
-      0x6CCC,0x94E5,      // <cjk>
-      0x6CD3,0x9F97,      // <cjk>
-      0x6CD5,0x9640,      // <cjk>
-      0x6CD7,0x9F99,      // <cjk>
-      0x6CD9,0x9FA2,      // <cjk>
-      0x6CDB,0x9FA0,      // <cjk>
-      0x6CDD,0x9F9B,      // <cjk>
-      0x6CE1,0x9641,      // <cjk>
-      0x6CE2,0x9467,      // <cjk>
-      0x6CE3,0x8B83,      // <cjk>
-      0x6CE5,0x9344,      // <cjk>
-      0x6CE8,0x928D,      // <cjk>
-      0x6CEA,0x9FA3,      // <cjk>
-      0x6CEF,0x9FA1,      // <cjk>
-      0x6CF0,0x91D7,      // <cjk>
-      0x6CF1,0x9F96,      // <cjk>
-      0x6CF3,0x896A,      // <cjk>
-      0x6D0B,0x976D,      // <cjk>
-      0x6D0C,0x9FAE,      // <cjk>
-      0x6D12,0x9FAD,      // <cjk>
-      0x6D17,0x90F4,      // <cjk>
-      0x6D19,0x9FAA,      // <cjk>
-      0x6D1B,0x978C,      // <cjk>
-      0x6D1E,0x93B4,      // <cjk>
-      0x6D1F,0x9FA4,      // <cjk>
-      0x6D25,0x92C3,      // <cjk>
-      0x6D29,0x896B,      // <cjk>
-      0x6D2A,0x8D5E,      // <cjk>
-      0x6D2B,0x9FA7,      // <cjk>
-      0x6D32,0x8F46,      // <cjk>
-      0x6D33,0x9FAC,      // <cjk>
-      0x6D35,0x9FAB,      // <cjk>
-      0x6D36,0x9FA6,      // <cjk>
-      0x6D38,0x9FA9,      // <cjk>
-      0x6D3B,0x8A88,      // <cjk>
-      0x6D3D,0x9FA8,      // <cjk>
-      0x6D3E,0x9468,      // <cjk>
-      0x6D41,0x97AC,      // <cjk>
-      0x6D44,0x8FF2,      // <cjk>
-      0x6D45,0x90F3,      // <cjk>
-      0x6D59,0x9FB4,      // <cjk>
-      0x6D5A,0x9FB2,      // <cjk>
-      0x6D5C,0x956C,      // <cjk>
-      0x6D63,0x9FAF,      // <cjk>
-      0x6D64,0x9FB1,      // <cjk>
-      0x6D66,0x8959,      // <cjk>
-      0x6D69,0x8D5F,      // <cjk>
-      0x6D6A,0x9851,      // <cjk>
-      0x6D6C,0x8A5C,      // <cjk>
-      0x6D6E,0x9582,      // <cjk>
-      0x6D74,0x9781,      // <cjk>
-      0x6D77,0x8A43,      // <cjk>
-      0x6D78,0x905A,      // <cjk>
-      0x6D79,0x9FB3,      // <cjk>
-      0x6D85,0x9FB8,      // <cjk>
-      0x6D88,0x8FC1,      // <cjk>
-      0x6D8C,0x974F,      // <cjk>
-      0x6D8E,0x9FB5,      // <cjk>
-      0x6D93,0x9FB0,      // <cjk>
-      0x6D95,0x9FB6,      // <cjk>
-      0x6D99,0x97DC,      // <cjk>
-      0x6D9B,0x9393,      // <cjk>
-      0x6D9C,0x93C0,      // <cjk>
-      0x6DAF,0x8A55,      // <cjk>
-      0x6DB2,0x8974,      // <cjk>
-      0x6DB5,0x9FBC,      // <cjk>
-      0x6DB8,0x9FBF,      // <cjk>
-      0x6DBC,0x97C1,      // <cjk>
-      0x6DC0,0x9784,      // <cjk>
-      0x6DC5,0x9FC6,      // <cjk>
-      0x6DC6,0x9FC0,      // <cjk>
-      0x6DC7,0x9FBD,      // <cjk>
-      0x6DCB,0x97D2,      // <cjk>
-      0x6DCC,0x9FC3,      // <cjk>
-      0x6DD1,0x8F69,      // <cjk>
-      0x6DD2,0x9FC5,      // <cjk>
-      0x6DD5,0x9FCA,      // <cjk>
-      0x6DD8,0x9391,      // <cjk>
-      0x6DD9,0x9FC8,      // <cjk>
-      0x6DDE,0x9FC2,      // <cjk>
-      0x6DE1,0x9257,      // <cjk>
-      0x6DE4,0x9FC9,      // <cjk>
-      0x6DE6,0x9FBE,      // <cjk>
-      0x6DE8,0x9FC4,      // <cjk>
-      0x6DEA,0x9FCB,      // <cjk>
-      0x6DEB,0x88FA,      // <cjk>
-      0x6DEC,0x9FC1,      // <cjk>
-      0x6DEE,0x9FCC,      // <cjk>
-      0x6DF3,0x8F7E,      // <cjk>
-      0x6DF5,0x95A3,      // <cjk>
-      0x6DF7,0x8DAC,      // <cjk>
-      0x6DF9,0x9FB9,      // <cjk>
-      0x6DFA,0x9FC7,      // <cjk>
-      0x6DFB,0x9359,      // <cjk>
-      0x6E05,0x90B4,      // <cjk>
-      0x6E07,0x8A89,      // <cjk>
-      0x6E08,0x8DCF,      // <cjk>
-      0x6E09,0x8FC2,      // <cjk>
-      0x6E0A,0x9FBB,      // <cjk>
-      0x6E0B,0x8F61,      // <cjk>
-      0x6E13,0x8C6B,      // <cjk>
-      0x6E15,0x9FBA,      // <cjk>
-      0x6E19,0x9FD0,      // <cjk>
-      0x6E1A,0x8F8D,      // <cjk>
-      0x6E1B,0x8CB8,      // <cjk>
-      0x6E1D,0x9FDF,      // <cjk>
-      0x6E1F,0x9FD9,      // <cjk>
-      0x6E20,0x8B94,      // <cjk>
-      0x6E21,0x936E,      // <cjk>
-      0x6E23,0x9FD4,      // <cjk>
-      0x6E24,0x9FDD,      // <cjk>
-      0x6E25,0x88AD,      // <cjk>
-      0x6E26,0x8951,      // <cjk>
-      0x6E29,0x89B7,      // <cjk>
-      0x6E2B,0x9FD6,      // <cjk>
-      0x6E2C,0x91AA,      // <cjk>
-      0x6E2D,0x9FCD,      // <cjk>
-      0x6E2E,0x9FCF,      // <cjk>
-      0x6E2F,0x8D60,      // <cjk>
-      0x6E38,0x9FE0,      // <cjk>
-      0x6E3A,0x9FDB,      // <cjk>
-      0x6E3E,0x9FD3,      // <cjk>
-      0x6E43,0x9FDA,      // <cjk>
-      0x6E4A,0x96A9,      // <cjk>
-      0x6E4D,0x9FD8,      // <cjk>
-      0x6E4E,0x9FDC,      // <cjk>
-      0x6E56,0x8CCE,      // <cjk>
-      0x6E58,0x8FC3,      // <cjk>
-      0x6E5B,0x9258,      // <cjk>
-      0x6E5F,0x9FD2,      // <cjk>
-      0x6E67,0x974E,      // <cjk>
-      0x6E6B,0x9FD5,      // <cjk>
-      0x6E6E,0x9FCE,      // <cjk>
-      0x6E6F,0x9392,      // <cjk>
-      0x6E72,0x9FD1,      // <cjk>
-      0x6E76,0x9FD7,      // <cjk>
-      0x6E7E,0x9870,      // <cjk>
-      0x6E7F,0x8EBC,      // <cjk>
-      0x6E80,0x969E,      // <cjk>
-      0x6E82,0x9FE1,      // <cjk>
-      0x6E8C,0x94AC,      // <cjk>
-      0x6E8F,0x9FED,      // <cjk>
-      0x6E90,0x8CB9,      // <cjk>
-      0x6E96,0x8F80,      // <cjk>
-      0x6E98,0x9FE3,      // <cjk>
-      0x6E9C,0x97AD,      // <cjk>
-      0x6E9D,0x8D61,      // <cjk>
-      0x6E9F,0x9FF0,      // <cjk>
-      0x6EA2,0x88EC,      // <cjk>
-      0x6EA5,0x9FEE,      // <cjk>
-      0x6EAA,0x9FE2,      // <cjk>
-      0x6EAF,0x9FE8,      // <cjk>
-      0x6EB2,0x9FEA,      // <cjk>
-      0x6EB6,0x976E,      // <cjk>
-      0x6EB7,0x9FE5,      // <cjk>
-      0x6EBA,0x934D,      // <cjk>
-      0x6EBD,0x9FE7,      // <cjk>
-      0x6EC2,0x9FEF,      // <cjk>
-      0x6EC4,0x9FE9,      // <cjk>
-      0x6EC5,0x96C5,      // <cjk>
-      0x6EC9,0x9FE4,      // <cjk>
-      0x6ECB,0x8EA0,      // <cjk>
-      0x6ECC,0x9FFC,      // <cjk>
-      0x6ED1,0x8A8A,      // <cjk>
-      0x6ED3,0x9FE6,      // <cjk>
-      0x6ED4,0x9FEB,      // <cjk>
-      0x6ED5,0x9FEC,      // <cjk>
-      0x6EDD,0x91EA,      // <cjk>
-      0x6EDE,0x91D8,      // <cjk>
-      0x6EEC,0x9FF4,      // <cjk>
-      0x6EEF,0x9FFA,      // <cjk>
-      0x6EF2,0x9FF8,      // <cjk>
-      0x6EF4,0x9348,      // <cjk>
-      0x6EF7,0xE042,      // <cjk>
-      0x6EF8,0x9FF5,      // <cjk>
-      0x6EFE,0x9FF6,      // <cjk>
-      0x6EFF,0x9FDE,      // <cjk>
-      0x6F01,0x8B99,      // <cjk>
-      0x6F02,0x9559,      // <cjk>
-      0x6F06,0x8EBD,      // <cjk>
-      0x6F09,0x8D97,      // <cjk>
-      0x6F0F,0x9852,      // <cjk>
-      0x6F11,0x9FF2,      // <cjk>
-      0x6F13,0xE041,      // <cjk>
-      0x6F14,0x8989,      // <cjk>
-      0x6F15,0x9186,      // <cjk>
-      0x6F20,0x9499,      // <cjk>
-      0x6F22,0x8ABF,      // <cjk>
-      0x6F23,0x97F8,      // <cjk>
-      0x6F2B,0x969F,      // <cjk>
-      0x6F2C,0x92D0,      // <cjk>
-      0x6F31,0x9FF9,      // <cjk>
-      0x6F32,0x9FFB,      // <cjk>
-      0x6F38,0x9151,      // <cjk>
-      0x6F3E,0xE040,      // <cjk>
-      0x6F3F,0x9FF7,      // <cjk>
-      0x6F41,0x9FF1,      // <cjk>
-      0x6F45,0x8AC1,      // <cjk>
-      0x6F54,0x8C89,      // <cjk>
-      0x6F58,0xE04E,      // <cjk>
-      0x6F5B,0xE049,      // <cjk>
-      0x6F5C,0x90F6,      // <cjk>
-      0x6F5F,0x8A83,      // <cjk>
-      0x6F64,0x8F81,      // <cjk>
-      0x6F66,0xE052,      // <cjk>
-      0x6F6D,0xE04B,      // <cjk>
-      0x6F6E,0x92AA,      // <cjk>
-      0x6F6F,0xE048,      // <cjk>
-      0x6F70,0x92D7,      // <cjk>
-      0x6F74,0xE06B,      // <cjk>
-      0x6F78,0xE045,      // <cjk>
-      0x6F7A,0xE044,      // <cjk>
-      0x6F7C,0xE04D,      // <cjk>
-      0x6F80,0xE047,      // <cjk>
-      0x6F81,0xE046,      // <cjk>
-      0x6F82,0xE04C,      // <cjk>
-      0x6F84,0x909F,      // <cjk>
-      0x6F86,0xE043,      // <cjk>
-      0x6F8E,0xE04F,      // <cjk>
-      0x6F91,0xE050,      // <cjk>
-      0x6F97,0x8AC0,      // <cjk>
-      0x6FA1,0xE055,      // <cjk>
-      0x6FA3,0xE054,      // <cjk>
-      0x6FA4,0xE056,      // <cjk>
-      0x6FAA,0xE059,      // <cjk>
-      0x6FB1,0x9362,      // <cjk>
-      0x6FB3,0xE053,      // <cjk>
-      0x6FB9,0xE057,      // <cjk>
-      0x6FC0,0x8C83,      // <cjk>
-      0x6FC1,0x91F7,      // <cjk>
-      0x6FC2,0xE051,      // <cjk>
-      0x6FC3,0x945A,      // <cjk>
-      0x6FC6,0xE058,      // <cjk>
-      0x6FD4,0xE05D,      // <cjk>
-      0x6FD8,0xE05E,      // <cjk>
-      0x6FDB,0xE061,      // <cjk>
-      0x6FDF,0xE05A,      // <cjk>
-      0x6FE0,0x8D8A,      // <cjk>
-      0x6FE1,0x9447,      // <cjk>
-      0x6FE4,0x9FB7,      // <cjk>
-      0x6FEB,0x9794,      // <cjk>
-      0x6FEC,0xE05C,      // <cjk>
-      0x6FEE,0xE060,      // <cjk>
-      0x6FEF,0x91F3,      // <cjk>
-      0x6FF1,0xE05F,      // <cjk>
-      0x6FF3,0xE04A,      // <cjk>
-      0x6FF6,0xE889,      // <cjk>
-      0x6FFA,0xE064,      // <cjk>
-      0x6FFE,0xE068,      // <cjk>
-      0x7001,0xE066,      // <cjk>
-      0x7009,0xE062,      // <cjk>
-      0x700B,0xE063,      // <cjk>
-      0x700F,0xE067,      // <cjk>
-      0x7011,0xE065,      // <cjk>
-      0x7015,0x956D,      // <cjk>
-      0x7018,0xE06D,      // <cjk>
-      0x701A,0xE06A,      // <cjk>
-      0x701B,0xE069,      // <cjk>
-      0x701D,0xE06C,      // <cjk>
-      0x701E,0x93D2,      // <cjk>
-      0x701F,0xE06E,      // <cjk>
-      0x7026,0x9295,      // <cjk>
-      0x7027,0x91EB,      // <cjk>
-      0x702C,0x90A3,      // <cjk>
-      0x7030,0xE06F,      // <cjk>
-      0x7032,0xE071,      // <cjk>
-      0x703E,0xE070,      // <cjk>
-      0x704C,0x9FF3,      // <cjk>
-      0x7051,0xE072,      // <cjk>
-      0x7058,0x93E5,      // <cjk>
-      0x7063,0xE073,      // <cjk>
-      0x706B,0x89CE,      // <cjk>
-      0x706F,0x9394,      // <cjk>
-      0x7070,0x8A44,      // <cjk>
-      0x7078,0x8B84,      // <cjk>
-      0x707C,0x8EDC,      // <cjk>
-      0x707D,0x8DD0,      // <cjk>
-      0x7089,0x9846,      // <cjk>
-      0x708A,0x9086,      // <cjk>
-      0x708E,0x898A,      // <cjk>
-      0x7092,0xE075,      // <cjk>
-      0x7099,0xE074,      // <cjk>
-      0x70AC,0xE078,      // <cjk>
-      0x70AD,0x9259,      // <cjk>
-      0x70AE,0xE07B,      // <cjk>
-      0x70AF,0xE076,      // <cjk>
-      0x70B3,0xE07A,      // <cjk>
-      0x70B8,0xE079,      // <cjk>
-      0x70B9,0x935F,      // <cjk>
-      0x70BA,0x88D7,      // <cjk>
-      0x70C8,0x97F3,      // <cjk>
-      0x70CB,0xE07D,      // <cjk>
-      0x70CF,0x8947,      // <cjk>
-      0x70D9,0xE080,      // <cjk>
-      0x70DD,0xE07E,      // <cjk>
-      0x70DF,0xE07C,      // <cjk>
-      0x70F1,0xE077,      // <cjk>
-      0x70F9,0x9642,      // <cjk>
-      0x70FD,0xE082,      // <cjk>
-      0x7109,0xE081,      // <cjk>
-      0x7114,0x898B,      // <cjk>
-      0x7119,0xE084,      // <cjk>
-      0x711A,0x95B0,      // <cjk>
-      0x711C,0xE083,      // <cjk>
-      0x7121,0x96B3,      // <cjk>
-      0x7126,0x8FC5,      // <cjk>
-      0x7136,0x9152,      // <cjk>
-      0x713C,0x8FC4,      // <cjk>
-      0x7149,0x97F9,      // <cjk>
-      0x714C,0xE08A,      // <cjk>
-      0x714E,0x90F7,      // <cjk>
-      0x7155,0xE086,      // <cjk>
-      0x7156,0xE08B,      // <cjk>
-      0x7159,0x898C,      // <cjk>
-      0x7162,0xE089,      // <cjk>
-      0x7164,0x9481,      // <cjk>
-      0x7165,0xE085,      // <cjk>
-      0x7166,0xE088,      // <cjk>
-      0x7167,0x8FC6,      // <cjk>
-      0x7169,0x94CF,      // <cjk>
-      0x716C,0xE08C,      // <cjk>
-      0x716E,0x8ECF,      // <cjk>
-      0x717D,0x90F8,      // <cjk>
-      0x7184,0xE08F,      // <cjk>
-      0x7188,0xE087,      // <cjk>
-      0x718A,0x8C46,      // <cjk>
-      0x718F,0xE08D,      // <cjk>
-      0x7194,0x976F,      // <cjk>
-      0x7195,0xE090,      // <cjk>
-      0x7199,0xEAA4,      // <cjk>
-      0x719F,0x8F6E,      // <cjk>
-      0x71A8,0xE091,      // <cjk>
-      0x71AC,0xE092,      // <cjk>
-      0x71B1,0x944D,      // <cjk>
-      0x71B9,0xE094,      // <cjk>
-      0x71BE,0xE095,      // <cjk>
-      0x71C3,0x9452,      // <cjk>
-      0x71C8,0x9395,      // <cjk>
-      0x71C9,0xE097,      // <cjk>
-      0x71CE,0xE099,      // <cjk>
-      0x71D0,0x97D3,      // <cjk>
-      0x71D2,0xE096,      // <cjk>
-      0x71D4,0xE098,      // <cjk>
-      0x71D5,0x898D,      // <cjk>
-      0x71D7,0xE093,      // <cjk>
-      0x71DF,0x9A7A,      // <cjk>
-      0x71E0,0xE09A,      // <cjk>
-      0x71E5,0x9187,      // <cjk>
-      0x71E6,0x8E57,      // <cjk>
-      0x71E7,0xE09C,      // <cjk>
-      0x71EC,0xE09B,      // <cjk>
-      0x71ED,0x9043,      // <cjk>
-      0x71EE,0x99D7,      // <cjk>
-      0x71F5,0xE09D,      // <cjk>
-      0x71F9,0xE09F,      // <cjk>
-      0x71FB,0xE08E,      // <cjk>
-      0x71FC,0xE09E,      // <cjk>
-      0x71FF,0xE0A0,      // <cjk>
-      0x7206,0x949A,      // <cjk>
-      0x720D,0xE0A1,      // <cjk>
-      0x7210,0xE0A2,      // <cjk>
-      0x721B,0xE0A3,      // <cjk>
-      0x7228,0xE0A4,      // <cjk>
-      0x722A,0x92DC,      // <cjk>
-      0x722C,0xE0A6,      // <cjk>
-      0x722D,0xE0A5,      // <cjk>
-      0x7230,0xE0A7,      // <cjk>
-      0x7232,0xE0A8,      // <cjk>
-      0x7235,0x8EDD,      // <cjk>
-      0x7236,0x9583,      // <cjk>
-      0x723A,0x96EA,      // <cjk>
-      0x723B,0xE0A9,      // <cjk>
-      0x723C,0xE0AA,      // <cjk>
-      0x723D,0x9175,      // <cjk>
-      0x723E,0x8EA2,      // <cjk>
-      0x723F,0xE0AB,      // <cjk>
-      0x7240,0xE0AC,      // <cjk>
-      0x7246,0xE0AD,      // <cjk>
-      0x7247,0x95D0,      // <cjk>
-      0x7248,0x94C5,      // <cjk>
-      0x724B,0xE0AE,      // <cjk>
-      0x724C,0x9476,      // <cjk>
-      0x7252,0x92AB,      // <cjk>
-      0x7258,0xE0AF,      // <cjk>
-      0x7259,0x89E5,      // <cjk>
-      0x725B,0x8B8D,      // <cjk>
-      0x725D,0x96C4,      // <cjk>
-      0x725F,0x96B4,      // <cjk>
-      0x7261,0x89B2,      // <cjk>
-      0x7262,0x9853,      // <cjk>
-      0x7267,0x9671,      // <cjk>
-      0x7269,0x95A8,      // <cjk>
-      0x7272,0x90B5,      // <cjk>
-      0x7274,0xE0B0,      // <cjk>
-      0x7279,0x93C1,      // <cjk>
-      0x727D,0x8CA1,      // <cjk>
-      0x727E,0xE0B1,      // <cjk>
-      0x7280,0x8DD2,      // <cjk>
-      0x7281,0xE0B3,      // <cjk>
-      0x7282,0xE0B2,      // <cjk>
-      0x7287,0xE0B4,      // <cjk>
-      0x7292,0xE0B5,      // <cjk>
-      0x7296,0xE0B6,      // <cjk>
-      0x72A0,0x8B5D,      // <cjk>
-      0x72A2,0xE0B7,      // <cjk>
-      0x72A7,0xE0B8,      // <cjk>
-      0x72AC,0x8CA2,      // <cjk>
-      0x72AF,0x94C6,      // <cjk>
-      0x72B2,0xE0BA,      // <cjk>
-      0x72B6,0x8FF3,      // <cjk>
-      0x72B9,0xE0B9,      // <cjk>
-      0x72C2,0x8BB6,      // <cjk>
-      0x72C3,0xE0BB,      // <cjk>
-      0x72C4,0xE0BD,      // <cjk>
-      0x72C6,0xE0BC,      // <cjk>
-      0x72CE,0xE0BE,      // <cjk>
-      0x72D0,0x8CCF,      // <cjk>
-      0x72D2,0xE0BF,      // <cjk>
-      0x72D7,0x8BE7,      // <cjk>
-      0x72D9,0x915F,      // <cjk>
-      0x72DB,0x8D9D,      // <cjk>
-      0x72E0,0xE0C1,      // <cjk>
-      0x72E1,0xE0C2,      // <cjk>
-      0x72E2,0xE0C0,      // <cjk>
-      0x72E9,0x8EEB,      // <cjk>
-      0x72EC,0x93C6,      // <cjk>
-      0x72ED,0x8BB7,      // <cjk>
-      0x72F7,0xE0C4,      // <cjk>
-      0x72F8,0x924B,      // <cjk>
-      0x72F9,0xE0C3,      // <cjk>
-      0x72FC,0x9854,      // <cjk>
-      0x72FD,0x9482,      // <cjk>
-      0x730A,0xE0C7,      // <cjk>
-      0x7316,0xE0C9,      // <cjk>
-      0x7317,0xE0C6,      // <cjk>
-      0x731B,0x96D2,      // <cjk>
-      0x731C,0xE0C8,      // <cjk>
-      0x731D,0xE0CA,      // <cjk>
-      0x731F,0x97C2,      // <cjk>
-      0x7325,0xE0CE,      // <cjk>
-      0x7329,0xE0CD,      // <cjk>
-      0x732A,0x9296,      // <cjk>
-      0x732B,0x944C,      // <cjk>
-      0x732E,0x8CA3,      // <cjk>
-      0x732F,0xE0CC,      // <cjk>
-      0x7334,0xE0CB,      // <cjk>
-      0x7336,0x9750,      // <cjk>
-      0x7337,0x9751,      // <cjk>
-      0x733E,0xE0CF,      // <cjk>
-      0x733F,0x898E,      // <cjk>
-      0x7344,0x8D96,      // <cjk>
-      0x7345,0x8E82,      // <cjk>
-      0x734E,0xE0D0,      // <cjk>
-      0x734F,0xE0D1,      // <cjk>
-      0x7357,0xE0D3,      // <cjk>
-      0x7363,0x8F62,      // <cjk>
-      0x7368,0xE0D5,      // <cjk>
-      0x736A,0xE0D4,      // <cjk>
-      0x7370,0xE0D6,      // <cjk>
-      0x7372,0x8A6C,      // <cjk>
-      0x7375,0xE0D8,      // <cjk>
-      0x7378,0xE0D7,      // <cjk>
-      0x737A,0xE0DA,      // <cjk>
-      0x737B,0xE0D9,      // <cjk>
-      0x7384,0x8CBA,      // <cjk>
-      0x7387,0x97A6,      // <cjk>
-      0x7389,0x8BCA,      // <cjk>
-      0x738B,0x89A4,      // <cjk>
-      0x7396,0x8BE8,      // <cjk>
-      0x73A9,0x8ADF,      // <cjk>
-      0x73B2,0x97E6,      // <cjk>
-      0x73B3,0xE0DC,      // <cjk>
-      0x73BB,0xE0DE,      // <cjk>
-      0x73C0,0xE0DF,      // <cjk>
-      0x73C2,0x89CF,      // <cjk>
-      0x73C8,0xE0DB,      // <cjk>
-      0x73CA,0x8E58,      // <cjk>
-      0x73CD,0x92BF,      // <cjk>
-      0x73CE,0xE0DD,      // <cjk>
-      0x73DE,0xE0E2,      // <cjk>
-      0x73E0,0x8EEC,      // <cjk>
-      0x73E5,0xE0E0,      // <cjk>
-      0x73EA,0x8C5D,      // <cjk>
-      0x73ED,0x94C7,      // <cjk>
-      0x73EE,0xE0E1,      // <cjk>
-      0x73F1,0xE0FC,      // <cjk>
-      0x73F8,0xE0E7,      // <cjk>
-      0x73FE,0x8CBB,      // <cjk>
-      0x7403,0x8B85,      // <cjk>
-      0x7405,0xE0E4,      // <cjk>
-      0x7406,0x979D,      // <cjk>
-      0x7409,0x97AE,      // <cjk>
-      0x7422,0x91F4,      // <cjk>
-      0x7425,0xE0E6,      // <cjk>
-      0x7432,0xE0E8,      // <cjk>
-      0x7433,0x97D4,      // <cjk>
-      0x7434,0x8BD5,      // <cjk>
-      0x7435,0x94FA,      // <cjk>
-      0x7436,0x9469,      // <cjk>
-      0x743A,0xE0E9,      // <cjk>
-      0x743F,0xE0EB,      // <cjk>
-      0x7441,0xE0EE,      // <cjk>
-      0x7455,0xE0EA,      // <cjk>
-      0x7459,0xE0ED,      // <cjk>
-      0x745A,0x8CE8,      // <cjk>
-      0x745B,0x896C,      // <cjk>
-      0x745C,0xE0EF,      // <cjk>
-      0x745E,0x9090,      // <cjk>
-      0x745F,0xE0EC,      // <cjk>
-      0x7460,0x97DA,      // <cjk>
-      0x7463,0xE0F2,      // <cjk>
-      0x7464,0xEAA2,      // <cjk>
-      0x7469,0xE0F0,      // <cjk>
-      0x746A,0xE0F3,      // <cjk>
-      0x746F,0xE0E5,      // <cjk>
-      0x7470,0xE0F1,      // <cjk>
-      0x7473,0x8DBA,      // <cjk>
-      0x7476,0xE0F4,      // <cjk>
-      0x747E,0xE0F5,      // <cjk>
-      0x7483,0x979E,      // <cjk>
-      0x748B,0xE0F6,      // <cjk>
-      0x749E,0xE0F7,      // <cjk>
-      0x74A2,0xE0E3,      // <cjk>
-      0x74A7,0xE0F8,      // <cjk>
-      0x74B0,0x8AC2,      // <cjk>
-      0x74BD,0x8EA3,      // <cjk>
-      0x74CA,0xE0F9,      // <cjk>
-      0x74CF,0xE0FA,      // <cjk>
-      0x74D4,0xE0FB,      // <cjk>
-      0x74DC,0x895A,      // <cjk>
-      0x74E0,0xE140,      // <cjk>
-      0x74E2,0x955A,      // <cjk>
-      0x74E3,0xE141,      // <cjk>
-      0x74E6,0x8AA2,      // <cjk>
-      0x74E7,0xE142,      // <cjk>
-      0x74E9,0xE143,      // <cjk>
-      0x74EE,0xE144,      // <cjk>
-      0x74F0,0xE146,      // <cjk>
-      0x74F1,0xE147,      // <cjk>
-      0x74F2,0xE145,      // <cjk>
-      0x74F6,0x9572,      // <cjk>
-      0x74F7,0xE149,      // <cjk>
-      0x74F8,0xE148,      // <cjk>
-      0x7503,0xE14B,      // <cjk>
-      0x7504,0xE14A,      // <cjk>
-      0x7505,0xE14C,      // <cjk>
-      0x750C,0xE14D,      // <cjk>
-      0x750D,0xE14F,      // <cjk>
-      0x750E,0xE14E,      // <cjk>
-      0x7511,0x8D99,      // <cjk>
-      0x7513,0xE151,      // <cjk>
-      0x7515,0xE150,      // <cjk>
-      0x7518,0x8AC3,      // <cjk>
-      0x751A,0x9072,      // <cjk>
-      0x751E,0xE152,      // <cjk>
-      0x751F,0x90B6,      // <cjk>
-      0x7523,0x8E59,      // <cjk>
-      0x7525,0x8999,      // <cjk>
-      0x7526,0xE153,      // <cjk>
-      0x7528,0x9770,      // <cjk>
-      0x752B,0x95E1,      // <cjk>
-      0x752C,0xE154,      // <cjk>
-      0x7530,0x9363,      // <cjk>
-      0x7531,0x9752,      // <cjk>
-      0x7532,0x8D62,      // <cjk>
-      0x7533,0x905C,      // <cjk>
-      0x7537,0x926A,      // <cjk>
-      0x7538,0x99B2,      // <cjk>
-      0x753A,0x92AC,      // <cjk>
-      0x753B,0x89E6,      // <cjk>
-      0x753C,0xE155,      // <cjk>
-      0x7544,0xE156,      // <cjk>
-      0x7549,0xE159,      // <cjk>
-      0x754A,0xE158,      // <cjk>
-      0x754B,0x9DC0,      // <cjk>
-      0x754C,0x8A45,      // <cjk>
-      0x754D,0xE157,      // <cjk>
-      0x754F,0x88D8,      // <cjk>
-      0x7551,0x94A8,      // <cjk>
-      0x7554,0x94C8,      // <cjk>
-      0x7559,0x97AF,      // <cjk>
-      0x755A,0xE15C,      // <cjk>
-      0x755B,0xE15A,      // <cjk>
-      0x755C,0x927B,      // <cjk>
-      0x755D,0x90A4,      // <cjk>
-      0x7560,0x94A9,      // <cjk>
-      0x7562,0x954C,      // <cjk>
-      0x7564,0xE15E,      // <cjk>
-      0x7565,0x97AA,      // <cjk>
-      0x7566,0x8C6C,      // <cjk>
-      0x7567,0xE15F,      // <cjk>
-      0x7569,0xE15D,      // <cjk>
-      0x756A,0x94D4,      // <cjk>
-      0x756B,0xE160,      // <cjk>
-      0x756D,0xE161,      // <cjk>
-      0x7570,0x88D9,      // <cjk>
-      0x7573,0x8FF4,      // <cjk>
-      0x7574,0xE166,      // <cjk>
-      0x7576,0xE163,      // <cjk>
-      0x7577,0x93EB,      // <cjk>
-      0x7578,0xE162,      // <cjk>
-      0x757F,0x8B45,      // <cjk>
-      0x7582,0xE169,      // <cjk>
-      0x7586,0xE164,      // <cjk>
-      0x7587,0xE165,      // <cjk>
-      0x7589,0xE168,      // <cjk>
-      0x758A,0xE167,      // <cjk>
-      0x758B,0x9544,      // <cjk>
-      0x758E,0x9161,      // <cjk>
-      0x758F,0x9160,      // <cjk>
-      0x7591,0x8B5E,      // <cjk>
-      0x7594,0xE16A,      // <cjk>
-      0x759A,0xE16B,      // <cjk>
-      0x759D,0xE16C,      // <cjk>
-      0x75A3,0xE16E,      // <cjk>
-      0x75A5,0xE16D,      // <cjk>
-      0x75AB,0x8975,      // <cjk>
-      0x75B1,0xE176,      // <cjk>
-      0x75B2,0x94E6,      // <cjk>
-      0x75B3,0xE170,      // <cjk>
-      0x75B5,0xE172,      // <cjk>
-      0x75B8,0xE174,      // <cjk>
-      0x75B9,0x905D,      // <cjk>
-      0x75BC,0xE175,      // <cjk>
-      0x75BD,0xE173,      // <cjk>
-      0x75BE,0x8EBE,      // <cjk>
-      0x75C2,0xE16F,      // <cjk>
-      0x75C3,0xE171,      // <cjk>
-      0x75C5,0x9561,      // <cjk>
-      0x75C7,0x8FC7,      // <cjk>
-      0x75CA,0xE178,      // <cjk>
-      0x75CD,0xE177,      // <cjk>
-      0x75D2,0xE179,      // <cjk>
-      0x75D4,0x8EA4,      // <cjk>
-      0x75D5,0x8DAD,      // <cjk>
-      0x75D8,0x9397,      // <cjk>
-      0x75D9,0xE17A,      // <cjk>
-      0x75DB,0x92C9,      // <cjk>
-      0x75DE,0xE17C,      // <cjk>
-      0x75E2,0x979F,      // <cjk>
-      0x75E3,0xE17B,      // <cjk>
-      0x75E9,0x9189,      // <cjk>
-      0x75F0,0xE182,      // <cjk>
-      0x75F2,0xE184,      // <cjk>
-      0x75F3,0xE185,      // <cjk>
-      0x75F4,0x9273,      // <cjk>
-      0x75FA,0xE183,      // <cjk>
-      0x75FC,0xE180,      // <cjk>
-      0x75FE,0xE17D,      // <cjk>
-      0x75FF,0xE17E,      // <cjk>
-      0x7601,0xE181,      // <cjk>
-      0x7609,0xE188,      // <cjk>
-      0x760B,0xE186,      // <cjk>
-      0x760D,0xE187,      // <cjk>
-      0x761F,0xE189,      // <cjk>
-      0x7620,0xE18B,      // <cjk>
-      0x7621,0xE18C,      // <cjk>
-      0x7622,0xE18D,      // <cjk>
-      0x7624,0xE18E,      // <cjk>
-      0x7627,0xE18A,      // <cjk>
-      0x7630,0xE190,      // <cjk>
-      0x7634,0xE18F,      // <cjk>
-      0x763B,0xE191,      // <cjk>
-      0x7642,0x97C3,      // <cjk>
-      0x7646,0xE194,      // <cjk>
-      0x7647,0xE192,      // <cjk>
-      0x7648,0xE193,      // <cjk>
-      0x764C,0x8AE0,      // <cjk>
-      0x7652,0x96FC,      // <cjk>
-      0x7656,0x95C8,      // <cjk>
-      0x7658,0xE196,      // <cjk>
-      0x765C,0xE195,      // <cjk>
-      0x7661,0xE197,      // <cjk>
-      0x7662,0xE198,      // <cjk>
-      0x7667,0xE19C,      // <cjk>
-      0x7668,0xE199,      // <cjk>
-      0x7669,0xE19A,      // <cjk>
-      0x766A,0xE19B,      // <cjk>
-      0x766C,0xE19D,      // <cjk>
-      0x7670,0xE19E,      // <cjk>
-      0x7672,0xE19F,      // <cjk>
-      0x7676,0xE1A0,      // <cjk>
-      0x7678,0xE1A1,      // <cjk>
-      0x767A,0x94AD,      // <cjk>
-      0x767B,0x936F,      // <cjk>
-      0x767C,0xE1A2,      // <cjk>
-      0x767D,0x9492,      // <cjk>
-      0x767E,0x9553,      // <cjk>
-      0x7680,0xE1A3,      // <cjk>
-      0x7683,0xE1A4,      // <cjk>
-      0x7684,0x9349,      // <cjk>
-      0x7686,0x8A46,      // <cjk>
-      0x7687,0x8D63,      // <cjk>
-      0x7688,0xE1A5,      // <cjk>
-      0x768B,0xE1A6,      // <cjk>
-      0x768E,0xE1A7,      // <cjk>
-      0x7690,0x8E48,      // <cjk>
-      0x7693,0xE1A9,      // <cjk>
-      0x7696,0xE1A8,      // <cjk>
-      0x7699,0xE1AA,      // <cjk>
-      0x769A,0xE1AB,      // <cjk>
-      0x76AE,0x94E7,      // <cjk>
-      0x76B0,0xE1AC,      // <cjk>
-      0x76B4,0xE1AD,      // <cjk>
-      0x76B7,0xEA89,      // <cjk>
-      0x76B8,0xE1AE,      // <cjk>
-      0x76B9,0xE1AF,      // <cjk>
-      0x76BA,0xE1B0,      // <cjk>
-      0x76BF,0x8E4D,      // <cjk>
-      0x76C2,0xE1B1,      // <cjk>
-      0x76C3,0x9475,      // <cjk>
-      0x76C6,0x967E,      // <cjk>
-      0x76C8,0x896D,      // <cjk>
-      0x76CA,0x8976,      // <cjk>
-      0x76CD,0xE1B2,      // <cjk>
-      0x76D2,0xE1B4,      // <cjk>
-      0x76D6,0xE1B3,      // <cjk>
-      0x76D7,0x9390,      // <cjk>
-      0x76DB,0x90B7,      // <cjk>
-      0x76DC,0x9F58,      // <cjk>
-      0x76DE,0xE1B5,      // <cjk>
-      0x76DF,0x96BF,      // <cjk>
-      0x76E1,0xE1B6,      // <cjk>
-      0x76E3,0x8AC4,      // <cjk>
-      0x76E4,0x94D5,      // <cjk>
-      0x76E5,0xE1B7,      // <cjk>
-      0x76E7,0xE1B8,      // <cjk>
-      0x76EA,0xE1B9,      // <cjk>
-      0x76EE,0x96DA,      // <cjk>
-      0x76F2,0x96D3,      // <cjk>
-      0x76F4,0x92BC,      // <cjk>
-      0x76F8,0x918A,      // <cjk>
-      0x76FB,0xE1BB,      // <cjk>
-      0x76FE,0x8F82,      // <cjk>
-      0x7701,0x8FC8,      // <cjk>
-      0x7704,0xE1BE,      // <cjk>
-      0x7707,0xE1BD,      // <cjk>
-      0x7708,0xE1BC,      // <cjk>
-      0x7709,0x94FB,      // <cjk>
-      0x770B,0x8AC5,      // <cjk>
-      0x770C,0x8CA7,      // <cjk>
-      0x771B,0xE1C4,      // <cjk>
-      0x771E,0xE1C1,      // <cjk>
-      0x771F,0x905E,      // <cjk>
-      0x7720,0x96B0,      // <cjk>
-      0x7724,0xE1C0,      // <cjk>
-      0x7725,0xE1C2,      // <cjk>
-      0x7726,0xE1C3,      // <cjk>
-      0x7729,0xE1BF,      // <cjk>
-      0x7737,0xE1C5,      // <cjk>
-      0x7738,0xE1C6,      // <cjk>
-      0x773A,0x92AD,      // <cjk>
-      0x773C,0x8AE1,      // <cjk>
-      0x7740,0x9285,      // <cjk>
-      0x7747,0xE1C7,      // <cjk>
-      0x775A,0xE1C8,      // <cjk>
-      0x775B,0xE1CB,      // <cjk>
-      0x7761,0x9087,      // <cjk>
-      0x7763,0x93C2,      // <cjk>
-      0x7765,0xE1CC,      // <cjk>
-      0x7766,0x9672,      // <cjk>
-      0x7768,0xE1C9,      // <cjk>
-      0x776B,0xE1CA,      // <cjk>
-      0x7779,0xE1CF,      // <cjk>
-      0x777E,0xE1CE,      // <cjk>
-      0x777F,0xE1CD,      // <cjk>
-      0x778B,0xE1D1,      // <cjk>
-      0x778E,0xE1D0,      // <cjk>
-      0x7791,0xE1D2,      // <cjk>
-      0x779E,0xE1D4,      // <cjk>
-      0x77A0,0xE1D3,      // <cjk>
-      0x77A5,0x95CB,      // <cjk>
-      0x77AC,0x8F75,      // <cjk>
-      0x77AD,0x97C4,      // <cjk>
-      0x77B0,0xE1D5,      // <cjk>
-      0x77B3,0x93B5,      // <cjk>
-      0x77B6,0xE1D6,      // <cjk>
-      0x77B9,0xE1D7,      // <cjk>
-      0x77BB,0xE1DB,      // <cjk>
-      0x77BC,0xE1D9,      // <cjk>
-      0x77BD,0xE1DA,      // <cjk>
-      0x77BF,0xE1D8,      // <cjk>
-      0x77C7,0xE1DC,      // <cjk>
-      0x77CD,0xE1DD,      // <cjk>
-      0x77D7,0xE1DE,      // <cjk>
-      0x77DA,0xE1DF,      // <cjk>
-      0x77DB,0x96B5,      // <cjk>
-      0x77DC,0xE1E0,      // <cjk>
-      0x77E2,0x96EE,      // <cjk>
-      0x77E3,0xE1E1,      // <cjk>
-      0x77E5,0x926D,      // <cjk>
-      0x77E7,0x948A,      // <cjk>
-      0x77E9,0x8BE9,      // <cjk>
-      0x77ED,0x925A,      // <cjk>
-      0x77EE,0xE1E2,      // <cjk>
-      0x77EF,0x8BB8,      // <cjk>
-      0x77F3,0x90CE,      // <cjk>
-      0x77FC,0xE1E3,      // <cjk>
-      0x7802,0x8DBB,      // <cjk>
-      0x780C,0xE1E4,      // <cjk>
-      0x7812,0xE1E5,      // <cjk>
-      0x7814,0x8CA4,      // <cjk>
-      0x7815,0x8DD3,      // <cjk>
-      0x7820,0xE1E7,      // <cjk>
-      0x7825,0x9375,      // <cjk>
-      0x7826,0x8DD4,      // <cjk>
-      0x7827,0x8B6D,      // <cjk>
-      0x7832,0x9643,      // <cjk>
-      0x7834,0x946A,      // <cjk>
-      0x783A,0x9376,      // <cjk>
-      0x783F,0x8D7B,      // <cjk>
-      0x7845,0xE1E9,      // <cjk>
-      0x785D,0x8FC9,      // <cjk>
-      0x786B,0x97B0,      // <cjk>
-      0x786C,0x8D64,      // <cjk>
-      0x786F,0x8CA5,      // <cjk>
-      0x7872,0x94A1,      // <cjk>
-      0x7874,0xE1EB,      // <cjk>
-      0x787C,0xE1ED,      // <cjk>
-      0x7881,0x8CE9,      // <cjk>
-      0x7886,0xE1EC,      // <cjk>
-      0x7887,0x92F4,      // <cjk>
-      0x788C,0xE1EF,      // <cjk>
-      0x788D,0x8A56,      // <cjk>
-      0x788E,0xE1EA,      // <cjk>
-      0x7891,0x94E8,      // <cjk>
-      0x7893,0x894F,      // <cjk>
-      0x7895,0x8DEA,      // <cjk>
-      0x7897,0x9871,      // <cjk>
-      0x789A,0xE1EE,      // <cjk>
-      0x78A3,0xE1F0,      // <cjk>
-      0x78A7,0x95C9,      // <cjk>
-      0x78A9,0x90D7,      // <cjk>
-      0x78AA,0xE1F2,      // <cjk>
-      0x78AF,0xE1F3,      // <cjk>
-      0x78B5,0xE1F1,      // <cjk>
-      0x78BA,0x8A6D,      // <cjk>
-      0x78BC,0xE1F9,      // <cjk>
-      0x78BE,0xE1F8,      // <cjk>
-      0x78C1,0x8EA5,      // <cjk>
-      0x78C5,0xE1FA,      // <cjk>
-      0x78C6,0xE1F5,      // <cjk>
-      0x78CA,0xE1FB,      // <cjk>
-      0x78CB,0xE1F6,      // <cjk>
-      0x78D0,0x94D6,      // <cjk>
-      0x78D1,0xE1F4,      // <cjk>
-      0x78D4,0xE1F7,      // <cjk>
-      0x78DA,0xE241,      // <cjk>
-      0x78E7,0xE240,      // <cjk>
-      0x78E8,0x9681,      // <cjk>
-      0x78EC,0xE1FC,      // <cjk>
-      0x78EF,0x88E9,      // <cjk>
-      0x78F4,0xE243,      // <cjk>
-      0x78FD,0xE242,      // <cjk>
-      0x7901,0x8FCA,      // <cjk>
-      0x7907,0xE244,      // <cjk>
-      0x790E,0x9162,      // <cjk>
-      0x7911,0xE246,      // <cjk>
-      0x7912,0xE245,      // <cjk>
-      0x7919,0xE247,      // <cjk>
-      0x7926,0xE1E6,      // <cjk>
-      0x792A,0xE1E8,      // <cjk>
-      0x792B,0xE249,      // <cjk>
-      0x792C,0xE248,      // <cjk>
-      0x793A,0x8EA6,      // <cjk>
-      0x793C,0x97E7,      // <cjk>
-      0x793E,0x8ED0,      // <cjk>
-      0x7940,0xE24A,      // <cjk>
-      0x7941,0x8C56,      // <cjk>
-      0x7947,0x8B5F,      // <cjk>
-      0x7948,0x8B46,      // <cjk>
-      0x7949,0x8E83,      // <cjk>
-      0x7950,0x9753,      // <cjk>
-      0x7953,0xE250,      // <cjk>
-      0x7955,0xE24F,      // <cjk>
-      0x7956,0x9163,      // <cjk>
-      0x7957,0xE24C,      // <cjk>
-      0x795A,0xE24E,      // <cjk>
-      0x795D,0x8F6A,      // <cjk>
-      0x795E,0x905F,      // <cjk>
-      0x795F,0xE24D,      // <cjk>
-      0x7960,0xE24B,      // <cjk>
-      0x7962,0x9449,      // <cjk>
-      0x7965,0x8FCB,      // <cjk>
-      0x796D,0x8DD5,      // <cjk>
-      0x7977,0x9398,      // <cjk>
-      0x797A,0xE251,      // <cjk>
-      0x797F,0xE252,      // <cjk>
-      0x7980,0xE268,      // <cjk>
-      0x7981,0x8BD6,      // <cjk>
-      0x7984,0x985C,      // <cjk>
-      0x7985,0x9154,      // <cjk>
-      0x798A,0xE253,      // <cjk>
-      0x798D,0x89D0,      // <cjk>
-      0x798E,0x92F5,      // <cjk>
-      0x798F,0x959F,      // <cjk>
-      0x799D,0xE254,      // <cjk>
-      0x79A6,0x8B9A,      // <cjk>
-      0x79A7,0xE255,      // <cjk>
-      0x79AA,0xE257,      // <cjk>
-      0x79AE,0xE258,      // <cjk>
-      0x79B0,0x9448,      // <cjk>
-      0x79B3,0xE259,      // <cjk>
-      0x79B9,0xE25A,      // <cjk>
-      0x79BD,0x8BD7,      // <cjk>
-      0x79BE,0x89D1,      // <cjk>
-      0x79BF,0x93C3,      // <cjk>
-      0x79C0,0x8F47,      // <cjk>
-      0x79C1,0x8E84,      // <cjk>
-      0x79C9,0xE25C,      // <cjk>
-      0x79CB,0x8F48,      // <cjk>
-      0x79D1,0x89C8,      // <cjk>
-      0x79D2,0x9562,      // <cjk>
-      0x79D5,0xE25D,      // <cjk>
-      0x79D8,0x94E9,      // <cjk>
-      0x79DF,0x9164,      // <cjk>
-      0x79E1,0xE260,      // <cjk>
-      0x79E3,0xE261,      // <cjk>
-      0x79E4,0x9489,      // <cjk>
-      0x79E6,0x9060,      // <cjk>
-      0x79E7,0xE25E,      // <cjk>
-      0x79E9,0x9281,      // <cjk>
-      0x79EC,0xE25F,      // <cjk>
-      0x79F0,0x8FCC,      // <cjk>
-      0x79FB,0x88DA,      // <cjk>
-      0x7A00,0x8B48,      // <cjk>
-      0x7A08,0xE262,      // <cjk>
-      0x7A0B,0x92F6,      // <cjk>
-      0x7A0D,0xE263,      // <cjk>
-      0x7A0E,0x90C5,      // <cjk>
-      0x7A14,0x96AB,      // <cjk>
-      0x7A17,0x9542,      // <cjk>
-      0x7A18,0xE264,      // <cjk>
-      0x7A19,0xE265,      // <cjk>
-      0x7A1A,0x9274,      // <cjk>
-      0x7A1C,0x97C5,      // <cjk>
-      0x7A1F,0xE267,      // <cjk>
-      0x7A20,0xE266,      // <cjk>
-      0x7A2E,0x8EED,      // <cjk>
-      0x7A31,0xE269,      // <cjk>
-      0x7A32,0x88EE,      // <cjk>
-      0x7A37,0xE26C,      // <cjk>
-      0x7A3B,0xE26A,      // <cjk>
-      0x7A3C,0x89D2,      // <cjk>
-      0x7A3D,0x8C6D,      // <cjk>
-      0x7A3E,0xE26B,      // <cjk>
-      0x7A3F,0x8D65,      // <cjk>
-      0x7A40,0x8D92,      // <cjk>
-      0x7A42,0x95E4,      // <cjk>
-      0x7A43,0xE26D,      // <cjk>
-      0x7A46,0x9673,      // <cjk>
-      0x7A49,0xE26F,      // <cjk>
-      0x7A4D,0x90CF,      // <cjk>
-      0x7A4E,0x896E,      // <cjk>
-      0x7A4F,0x89B8,      // <cjk>
-      0x7A50,0x88AA,      // <cjk>
-      0x7A57,0xE26E,      // <cjk>
-      0x7A61,0xE270,      // <cjk>
-      0x7A62,0xE271,      // <cjk>
-      0x7A63,0x8FF5,      // <cjk>
-      0x7A69,0xE272,      // <cjk>
-      0x7A6B,0x8A6E,      // <cjk>
-      0x7A70,0xE274,      // <cjk>
-      0x7A74,0x8C8A,      // <cjk>
-      0x7A76,0x8B86,      // <cjk>
-      0x7A79,0xE275,      // <cjk>
-      0x7A7A,0x8BF3,      // <cjk>
-      0x7A7D,0xE276,      // <cjk>
-      0x7A7F,0x90FA,      // <cjk>
-      0x7A81,0x93CB,      // <cjk>
-      0x7A83,0x90DE,      // <cjk>
-      0x7A84,0x8DF3,      // <cjk>
-      0x7A88,0xE277,      // <cjk>
-      0x7A92,0x9282,      // <cjk>
-      0x7A93,0x918B,      // <cjk>
-      0x7A95,0xE279,      // <cjk>
-      0x7A96,0xE27B,      // <cjk>
-      0x7A97,0xE278,      // <cjk>
-      0x7A98,0xE27A,      // <cjk>
-      0x7A9F,0x8C41,      // <cjk>
-      0x7AA9,0xE27C,      // <cjk>
-      0x7AAA,0x8C45,      // <cjk>
-      0x7AAE,0x8B87,      // <cjk>
-      0x7AAF,0x9771,      // <cjk>
-      0x7AB0,0xE27E,      // <cjk>
-      0x7AB6,0xE280,      // <cjk>
-      0x7ABA,0x894D,      // <cjk>
-      0x7ABF,0xE283,      // <cjk>
-      0x7AC3,0x8A96,      // <cjk>
-      0x7AC4,0xE282,      // <cjk>
-      0x7AC5,0xE281,      // <cjk>
-      0x7AC7,0xE285,      // <cjk>
-      0x7AC8,0xE27D,      // <cjk>
-      0x7ACA,0xE286,      // <cjk>
-      0x7ACB,0x97A7,      // <cjk>
-      0x7ACD,0xE287,      // <cjk>
-      0x7ACF,0xE288,      // <cjk>
-      0x7AD2,0x9AF2,      // <cjk>
-      0x7AD3,0xE28A,      // <cjk>
-      0x7AD5,0xE289,      // <cjk>
-      0x7AD9,0xE28B,      // <cjk>
-      0x7ADA,0xE28C,      // <cjk>
-      0x7ADC,0x97B3,      // <cjk>
-      0x7ADD,0xE28D,      // <cjk>
-      0x7ADF,0xE8ED,      // <cjk>
-      0x7AE0,0x8FCD,      // <cjk>
-      0x7AE1,0xE28E,      // <cjk>
-      0x7AE2,0xE28F,      // <cjk>
-      0x7AE3,0x8F76,      // <cjk>
-      0x7AE5,0x93B6,      // <cjk>
-      0x7AE6,0xE290,      // <cjk>
-      0x7AEA,0x9247,      // <cjk>
-      0x7AED,0xE291,      // <cjk>
-      0x7AF0,0xE292,      // <cjk>
-      0x7AF6,0x8BA3,      // <cjk>
-      0x7AF8,0x995E,      // <cjk>
-      0x7AF9,0x927C,      // <cjk>
-      0x7AFA,0x8EB1,      // <cjk>
-      0x7AFF,0x8AC6,      // <cjk>
-      0x7B02,0xE293,      // <cjk>
-      0x7B04,0xE2A0,      // <cjk>
-      0x7B06,0xE296,      // <cjk>
-      0x7B08,0x8B88,      // <cjk>
-      0x7B0A,0xE295,      // <cjk>
-      0x7B0B,0xE2A2,      // <cjk>
-      0x7B0F,0xE294,      // <cjk>
-      0x7B11,0x8FCE,      // <cjk>
-      0x7B18,0xE298,      // <cjk>
-      0x7B19,0xE299,      // <cjk>
-      0x7B1B,0x934A,      // <cjk>
-      0x7B1E,0xE29A,      // <cjk>
-      0x7B20,0x8A7D,      // <cjk>
-      0x7B25,0x9079,      // <cjk>
-      0x7B26,0x9584,      // <cjk>
-      0x7B28,0xE29C,      // <cjk>
-      0x7B2C,0x91E6,      // <cjk>
-      0x7B33,0xE297,      // <cjk>
-      0x7B35,0xE29B,      // <cjk>
-      0x7B36,0xE29D,      // <cjk>
-      0x7B39,0x8DF9,      // <cjk>
-      0x7B45,0xE2A4,      // <cjk>
-      0x7B46,0x954D,      // <cjk>
-      0x7B48,0x94A4,      // <cjk>
-      0x7B49,0x9399,      // <cjk>
-      0x7B4B,0x8BD8,      // <cjk>
-      0x7B4C,0xE2A3,      // <cjk>
-      0x7B4D,0xE2A1,      // <cjk>
-      0x7B4F,0x94B3,      // <cjk>
-      0x7B50,0xE29E,      // <cjk>
-      0x7B51,0x927D,      // <cjk>
-      0x7B52,0x939B,      // <cjk>
-      0x7B54,0x939A,      // <cjk>
-      0x7B56,0x8DF4,      // <cjk>
-      0x7B5D,0xE2B6,      // <cjk>
-      0x7B65,0xE2A6,      // <cjk>
-      0x7B67,0xE2A8,      // <cjk>
-      0x7B6C,0xE2AB,      // <cjk>
-      0x7B6E,0xE2AC,      // <cjk>
-      0x7B70,0xE2A9,      // <cjk>
-      0x7B71,0xE2AA,      // <cjk>
-      0x7B74,0xE2A7,      // <cjk>
-      0x7B75,0xE2A5,      // <cjk>
-      0x7B7A,0xE29F,      // <cjk>
-      0x7B86,0x95CD,      // <cjk>
-      0x7B87,0x89D3,      // <cjk>
-      0x7B8B,0xE2B3,      // <cjk>
-      0x7B8D,0xE2B0,      // <cjk>
-      0x7B8F,0xE2B5,      // <cjk>
-      0x7B92,0xE2B4,      // <cjk>
-      0x7B94,0x9493,      // <cjk>
-      0x7B95,0x96A5,      // <cjk>
-      0x7B97,0x8E5A,      // <cjk>
-      0x7B98,0xE2AE,      // <cjk>
-      0x7B99,0xE2B7,      // <cjk>
-      0x7B9A,0xE2B2,      // <cjk>
-      0x7B9C,0xE2B1,      // <cjk>
-      0x7B9D,0xE2AD,      // <cjk>
-      0x7B9F,0xE2AF,      // <cjk>
-      0x7BA1,0x8AC7,      // <cjk>
-      0x7BAA,0x925C,      // <cjk>
-      0x7BAD,0x90FB,      // <cjk>
-      0x7BB1,0x94A0,      // <cjk>
-      0x7BB4,0xE2BC,      // <cjk>
-      0x7BB8,0x94A2,      // <cjk>
-      0x7BC0,0x90DF,      // <cjk>
-      0x7BC1,0xE2B9,      // <cjk>
-      0x7BC4,0x94CD,      // <cjk>
-      0x7BC6,0xE2BD,      // <cjk>
-      0x7BC7,0x95D1,      // <cjk>
-      0x7BC9,0x927A,      // <cjk>
-      0x7BCB,0xE2B8,      // <cjk>
-      0x7BCC,0xE2BA,      // <cjk>
-      0x7BCF,0xE2BB,      // <cjk>
-      0x7BDD,0xE2BE,      // <cjk>
-      0x7BE0,0x8EC2,      // <cjk>
-      0x7BE4,0x93C4,      // <cjk>
-      0x7BE5,0xE2C3,      // <cjk>
-      0x7BE6,0xE2C2,      // <cjk>
-      0x7BE9,0xE2BF,      // <cjk>
-      0x7BED,0x9855,      // <cjk>
-      0x7BF3,0xE2C8,      // <cjk>
-      0x7BF6,0xE2CC,      // <cjk>
-      0x7BF7,0xE2C9,      // <cjk>
-      0x7C00,0xE2C5,      // <cjk>
-      0x7C07,0xE2C6,      // <cjk>
-      0x7C0D,0xE2CB,      // <cjk>
-      0x7C11,0xE2C0,      // <cjk>
-      0x7C12,0x99D3,      // <cjk>
-      0x7C13,0xE2C7,      // <cjk>
-      0x7C14,0xE2C1,      // <cjk>
-      0x7C17,0xE2CA,      // <cjk>
-      0x7C1F,0xE2D0,      // <cjk>
-      0x7C21,0x8AC8,      // <cjk>
-      0x7C23,0xE2CD,      // <cjk>
-      0x7C27,0xE2CE,      // <cjk>
-      0x7C2A,0xE2CF,      // <cjk>
-      0x7C2B,0xE2D2,      // <cjk>
-      0x7C37,0xE2D1,      // <cjk>
-      0x7C38,0x94F4,      // <cjk>
-      0x7C3D,0xE2D3,      // <cjk>
-      0x7C3E,0x97FA,      // <cjk>
-      0x7C3F,0x95EB,      // <cjk>
-      0x7C40,0xE2D8,      // <cjk>
-      0x7C43,0xE2D5,      // <cjk>
-      0x7C4C,0xE2D4,      // <cjk>
-      0x7C4D,0x90D0,      // <cjk>
-      0x7C4F,0xE2D7,      // <cjk>
-      0x7C50,0xE2D9,      // <cjk>
-      0x7C54,0xE2D6,      // <cjk>
-      0x7C56,0xE2DD,      // <cjk>
-      0x7C58,0xE2DA,      // <cjk>
-      0x7C5F,0xE2DB,      // <cjk>
-      0x7C60,0xE2C4,      // <cjk>
-      0x7C64,0xE2DC,      // <cjk>
-      0x7C65,0xE2DE,      // <cjk>
-      0x7C6C,0xE2DF,      // <cjk>
-      0x7C73,0x95C4,      // <cjk>
-      0x7C75,0xE2E0,      // <cjk>
-      0x7C7E,0x96E0,      // <cjk>
-      0x7C81,0x8BCC,      // <cjk>
-      0x7C82,0x8C48,      // <cjk>
-      0x7C83,0xE2E1,      // <cjk>
-      0x7C89,0x95B2,      // <cjk>
-      0x7C8B,0x9088,      // <cjk>
-      0x7C8D,0x96AE,      // <cjk>
-      0x7C90,0xE2E2,      // <cjk>
-      0x7C92,0x97B1,      // <cjk>
-      0x7C95,0x9494,      // <cjk>
-      0x7C97,0x9165,      // <cjk>
-      0x7C98,0x9453,      // <cjk>
-      0x7C9B,0x8F6C,      // <cjk>
-      0x7C9F,0x88BE,      // <cjk>
-      0x7CA1,0xE2E7,      // <cjk>
-      0x7CA2,0xE2E5,      // <cjk>
-      0x7CA4,0xE2E3,      // <cjk>
-      0x7CA5,0x8A9F,      // <cjk>
-      0x7CA7,0x8FCF,      // <cjk>
-      0x7CA8,0xE2E8,      // <cjk>
-      0x7CAB,0xE2E6,      // <cjk>
-      0x7CAD,0xE2E4,      // <cjk>
-      0x7CAE,0xE2EC,      // <cjk>
-      0x7CB1,0xE2EB,      // <cjk>
-      0x7CB2,0xE2EA,      // <cjk>
-      0x7CB3,0xE2E9,      // <cjk>
-      0x7CB9,0xE2ED,      // <cjk>
-      0x7CBD,0xE2EE,      // <cjk>
-      0x7CBE,0x90B8,      // <cjk>
-      0x7CC0,0xE2EF,      // <cjk>
-      0x7CC2,0xE2F1,      // <cjk>
-      0x7CC5,0xE2F0,      // <cjk>
-      0x7CCA,0x8CD0,      // <cjk>
-      0x7CCE,0x9157,      // <cjk>
-      0x7CD2,0xE2F3,      // <cjk>
-      0x7CD6,0x939C,      // <cjk>
-      0x7CD8,0xE2F2,      // <cjk>
-      0x7CDC,0xE2F4,      // <cjk>
-      0x7CDE,0x95B3,      // <cjk>
-      0x7CDF,0x918C,      // <cjk>
-      0x7CE0,0x8D66,      // <cjk>
-      0x7CE2,0xE2F5,      // <cjk>
-      0x7CE7,0x97C6,      // <cjk>
-      0x7CEF,0xE2F7,      // <cjk>
-      0x7CF2,0xE2F8,      // <cjk>
-      0x7CF4,0xE2F9,      // <cjk>
-      0x7CF6,0xE2FA,      // <cjk>
-      0x7CF8,0x8E85,      // <cjk>
-      0x7CFA,0xE2FB,      // <cjk>
-      0x7CFB,0x8C6E,      // <cjk>
-      0x7CFE,0x8B8A,      // <cjk>
-      0x7D00,0x8B49,      // <cjk>
-      0x7D02,0xE340,      // <cjk>
-      0x7D04,0x96F1,      // <cjk>
-      0x7D05,0x8D67,      // <cjk>
-      0x7D06,0xE2FC,      // <cjk>
-      0x7D0A,0xE343,      // <cjk>
-      0x7D0B,0x96E4,      // <cjk>
-      0x7D10,0x9552,      // <cjk>
-      0x7D14,0x8F83,      // <cjk>
-      0x7D15,0xE342,      // <cjk>
-      0x7D17,0x8ED1,      // <cjk>
-      0x7D18,0x8D68,      // <cjk>
-      0x7D19,0x8E86,      // <cjk>
-      0x7D1A,0x8B89,      // <cjk>
-      0x7D1B,0x95B4,      // <cjk>
-      0x7D1C,0xE341,      // <cjk>
-      0x7D20,0x9166,      // <cjk>
-      0x7D21,0x9661,      // <cjk>
-      0x7D22,0x8DF5,      // <cjk>
-      0x7D2B,0x8E87,      // <cjk>
-      0x7D2C,0x92DB,      // <cjk>
-      0x7D2E,0xE346,      // <cjk>
-      0x7D2F,0x97DD,      // <cjk>
-      0x7D30,0x8DD7,      // <cjk>
-      0x7D32,0xE347,      // <cjk>
-      0x7D33,0x9061,      // <cjk>
-      0x7D35,0xE349,      // <cjk>
-      0x7D39,0x8FD0,      // <cjk>
-      0x7D3A,0x8DAE,      // <cjk>
-      0x7D3F,0xE348,      // <cjk>
-      0x7D42,0x8F49,      // <cjk>
-      0x7D43,0x8CBC,      // <cjk>
-      0x7D44,0x9167,      // <cjk>
-      0x7D45,0xE344,      // <cjk>
-      0x7D46,0xE34A,      // <cjk>
-      0x7D4B,0xE345,      // <cjk>
-      0x7D4C,0x8C6F,      // <cjk>
-      0x7D4E,0xE34D,      // <cjk>
-      0x7D4F,0xE351,      // <cjk>
-      0x7D50,0x8C8B,      // <cjk>
-      0x7D56,0xE34C,      // <cjk>
-      0x7D5B,0xE355,      // <cjk>
-      0x7D5E,0x8D69,      // <cjk>
-      0x7D61,0x978D,      // <cjk>
-      0x7D62,0x88BA,      // <cjk>
-      0x7D63,0xE352,      // <cjk>
-      0x7D66,0x8B8B,      // <cjk>
-      0x7D68,0xE34F,      // <cjk>
-      0x7D6E,0xE350,      // <cjk>
-      0x7D71,0x939D,      // <cjk>
-      0x7D72,0xE34E,      // <cjk>
-      0x7D73,0xE34B,      // <cjk>
-      0x7D75,0x8A47,      // <cjk>
-      0x7D76,0x90E2,      // <cjk>
-      0x7D79,0x8CA6,      // <cjk>
-      0x7D7D,0xE357,      // <cjk>
-      0x7D89,0xE354,      // <cjk>
-      0x7D8F,0xE356,      // <cjk>
-      0x7D93,0xE353,      // <cjk>
-      0x7D99,0x8C70,      // <cjk>
-      0x7D9A,0x91B1,      // <cjk>
-      0x7D9B,0xE358,      // <cjk>
-      0x7D9C,0x918E,      // <cjk>
-      0x7D9F,0xE365,      // <cjk>
-      0x7DA2,0xE361,      // <cjk>
-      0x7DAB,0xE35F,      // <cjk>
-      0x7DAC,0x8EF8,      // <cjk>
-      0x7DAD,0x88DB,      // <cjk>
-      0x7DAE,0xE35A,      // <cjk>
-      0x7DAF,0xE362,      // <cjk>
-      0x7DB0,0xE366,      // <cjk>
-      0x7DB1,0x8D6A,      // <cjk>
-      0x7DB2,0x96D4,      // <cjk>
-      0x7DB4,0x92D4,      // <cjk>
-      0x7DB5,0xE35C,      // <cjk>
-      0x7DB8,0xE364,      // <cjk>
-      0x7DBA,0xE359,      // <cjk>
-      0x7DBB,0x925D,      // <cjk>
-      0x7DBD,0xE35E,      // <cjk>
-      0x7DBE,0x88BB,      // <cjk>
-      0x7DBF,0x96C8,      // <cjk>
-      0x7DC7,0xE35D,      // <cjk>
-      0x7DCA,0x8BD9,      // <cjk>
-      0x7DCB,0x94EA,      // <cjk>
-      0x7DCF,0x918D,      // <cjk>
-      0x7DD1,0x97CE,      // <cjk>
-      0x7DD2,0x8F8F,      // <cjk>
-      0x7DD5,0xE38E,      // <cjk>
-      0x7DD8,0xE367,      // <cjk>
-      0x7DDA,0x90FC,      // <cjk>
-      0x7DDC,0xE363,      // <cjk>
-      0x7DDD,0xE368,      // <cjk>
-      0x7DDE,0xE36A,      // <cjk>
-      0x7DE0,0x92F7,      // <cjk>
-      0x7DE1,0xE36D,      // <cjk>
-      0x7DE4,0xE369,      // <cjk>
-      0x7DE8,0x95D2,      // <cjk>
-      0x7DE9,0x8AC9,      // <cjk>
-      0x7DEC,0x96C9,      // <cjk>
-      0x7DEF,0x88DC,      // <cjk>
-      0x7DF2,0xE36C,      // <cjk>
-      0x7DF4,0x97FB,      // <cjk>
-      0x7DFB,0xE36B,      // <cjk>
-      0x7E01,0x898F,      // <cjk>
-      0x7E04,0x93EA,      // <cjk>
-      0x7E05,0xE36E,      // <cjk>
-      0x7E09,0xE375,      // <cjk>
-      0x7E0A,0xE36F,      // <cjk>
-      0x7E0B,0xE376,      // <cjk>
-      0x7E12,0xE372,      // <cjk>
-      0x7E1B,0x949B,      // <cjk>
-      0x7E1E,0x8EC8,      // <cjk>
-      0x7E1F,0xE374,      // <cjk>
-      0x7E21,0xE371,      // <cjk>
-      0x7E22,0xE377,      // <cjk>
-      0x7E23,0xE370,      // <cjk>
-      0x7E26,0x8F63,      // <cjk>
-      0x7E2B,0x9644,      // <cjk>
-      0x7E2E,0x8F6B,      // <cjk>
-      0x7E31,0xE373,      // <cjk>
-      0x7E32,0xE380,      // <cjk>
-      0x7E35,0xE37B,      // <cjk>
-      0x7E37,0xE37E,      // <cjk>
-      0x7E39,0xE37C,      // <cjk>
-      0x7E3A,0xE381,      // <cjk>
-      0x7E3B,0xE37A,      // <cjk>
-      0x7E3D,0xE360,      // <cjk>
-      0x7E3E,0x90D1,      // <cjk>
-      0x7E41,0x94C9,      // <cjk>
-      0x7E43,0xE37D,      // <cjk>
-      0x7E46,0xE378,      // <cjk>
-      0x7E4A,0x9140,      // <cjk>
-      0x7E4B,0x8C71,      // <cjk>
-      0x7E4D,0x8F4A,      // <cjk>
-      0x7E54,0x9044,      // <cjk>
-      0x7E55,0x9155,      // <cjk>
-      0x7E56,0xE384,      // <cjk>
-      0x7E59,0xE386,      // <cjk>
-      0x7E5A,0xE387,      // <cjk>
-      0x7E5D,0xE383,      // <cjk>
-      0x7E5E,0xE385,      // <cjk>
-      0x7E66,0xE379,      // <cjk>
-      0x7E67,0xE382,      // <cjk>
-      0x7E69,0xE38A,      // <cjk>
-      0x7E6A,0xE389,      // <cjk>
-      0x7E6D,0x969A,      // <cjk>
-      0x7E70,0x8C4A,      // <cjk>
-      0x7E79,0xE388,      // <cjk>
-      0x7E7B,0xE38C,      // <cjk>
-      0x7E7C,0xE38B,      // <cjk>
-      0x7E7D,0xE38F,      // <cjk>
-      0x7E7F,0xE391,      // <cjk>
-      0x7E83,0xE38D,      // <cjk>
-      0x7E88,0xE392,      // <cjk>
-      0x7E89,0xE393,      // <cjk>
-      0x7E8C,0xE394,      // <cjk>
-      0x7E8E,0xE39A,      // <cjk>
-      0x7E8F,0x935A,      // <cjk>
-      0x7E90,0xE396,      // <cjk>
-      0x7E92,0xE395,      // <cjk>
-      0x7E93,0xE397,      // <cjk>
-      0x7E94,0xE398,      // <cjk>
-      0x7E96,0xE399,      // <cjk>
-      0x7E9B,0xE39B,      // <cjk>
-      0x7E9C,0xE39C,      // <cjk>
-      0x7F36,0x8ACA,      // <cjk>
-      0x7F38,0xE39D,      // <cjk>
-      0x7F3A,0xE39E,      // <cjk>
-      0x7F45,0xE39F,      // <cjk>
-      0x7F4C,0xE3A0,      // <cjk>
-      0x7F4D,0xE3A1,      // <cjk>
-      0x7F4E,0xE3A2,      // <cjk>
-      0x7F50,0xE3A3,      // <cjk>
-      0x7F51,0xE3A4,      // <cjk>
-      0x7F54,0xE3A6,      // <cjk>
-      0x7F55,0xE3A5,      // <cjk>
-      0x7F58,0xE3A7,      // <cjk>
-      0x7F5F,0xE3A8,      // <cjk>
-      0x7F60,0xE3A9,      // <cjk>
-      0x7F67,0xE3AC,      // <cjk>
-      0x7F68,0xE3AA,      // <cjk>
-      0x7F69,0xE3AB,      // <cjk>
-      0x7F6A,0x8DDF,      // <cjk>
-      0x7F6B,0x8C72,      // <cjk>
-      0x7F6E,0x9275,      // <cjk>
-      0x7F70,0x94B1,      // <cjk>
-      0x7F72,0x8F90,      // <cjk>
-      0x7F75,0x946C,      // <cjk>
-      0x7F77,0x94EB,      // <cjk>
-      0x7F78,0xE3AD,      // <cjk>
-      0x7F79,0x9CEB,      // <cjk>
-      0x7F82,0xE3AE,      // <cjk>
-      0x7F83,0xE3B0,      // <cjk>
-      0x7F85,0x9785,      // <cjk>
-      0x7F86,0xE3AF,      // <cjk>
-      0x7F87,0xE3B2,      // <cjk>
-      0x7F88,0xE3B1,      // <cjk>
-      0x7F8A,0x9772,      // <cjk>
-      0x7F8C,0xE3B3,      // <cjk>
-      0x7F8E,0x94FC,      // <cjk>
-      0x7F94,0xE3B4,      // <cjk>
-      0x7F9A,0xE3B7,      // <cjk>
-      0x7F9D,0xE3B6,      // <cjk>
-      0x7F9E,0xE3B5,      // <cjk>
-      0x7FA3,0xE3B8,      // <cjk>
-      0x7FA4,0x8C51,      // <cjk>
-      0x7FA8,0x9141,      // <cjk>
-      0x7FA9,0x8B60,      // <cjk>
-      0x7FAE,0xE3BC,      // <cjk>
-      0x7FAF,0xE3B9,      // <cjk>
-      0x7FB2,0xE3BA,      // <cjk>
-      0x7FB6,0xE3BD,      // <cjk>
-      0x7FB8,0xE3BE,      // <cjk>
-      0x7FB9,0xE3BB,      // <cjk>
-      0x7FBD,0x8948,      // <cjk>
-      0x7FC1,0x89A5,      // <cjk>
-      0x7FC5,0xE3C0,      // <cjk>
-      0x7FC6,0xE3C1,      // <cjk>
-      0x7FCA,0xE3C2,      // <cjk>
-      0x7FCC,0x9782,      // <cjk>
-      0x7FD2,0x8F4B,      // <cjk>
-      0x7FD4,0xE3C4,      // <cjk>
-      0x7FD5,0xE3C3,      // <cjk>
-      0x7FE0,0x9089,      // <cjk>
-      0x7FE1,0xE3C5,      // <cjk>
-      0x7FE6,0xE3C6,      // <cjk>
-      0x7FE9,0xE3C7,      // <cjk>
-      0x7FEB,0x8AE3,      // <cjk>
-      0x7FF0,0x8ACB,      // <cjk>
-      0x7FF3,0xE3C8,      // <cjk>
-      0x7FF9,0xE3C9,      // <cjk>
-      0x7FFB,0x967C,      // <cjk>
-      0x7FFC,0x9783,      // <cjk>
-      0x8000,0x9773,      // <cjk>
-      0x8001,0x9856,      // <cjk>
-      0x8003,0x8D6C,      // <cjk>
-      0x8004,0xE3CC,      // <cjk>
-      0x8005,0x8ED2,      // <cjk>
-      0x8006,0xE3CB,      // <cjk>
-      0x800B,0xE3CD,      // <cjk>
-      0x800C,0x8EA7,      // <cjk>
-      0x8010,0x91CF,      // <cjk>
-      0x8012,0xE3CE,      // <cjk>
-      0x8015,0x8D6B,      // <cjk>
-      0x8017,0x96D5,      // <cjk>
-      0x8018,0xE3CF,      // <cjk>
-      0x8019,0xE3D0,      // <cjk>
-      0x801C,0xE3D1,      // <cjk>
-      0x8021,0xE3D2,      // <cjk>
-      0x8028,0xE3D3,      // <cjk>
-      0x8033,0x8EA8,      // <cjk>
-      0x8036,0x96EB,      // <cjk>
-      0x803B,0xE3D5,      // <cjk>
-      0x803D,0x925E,      // <cjk>
-      0x803F,0xE3D4,      // <cjk>
-      0x8046,0xE3D7,      // <cjk>
-      0x804A,0xE3D6,      // <cjk>
-      0x8052,0xE3D8,      // <cjk>
-      0x8056,0x90B9,      // <cjk>
-      0x8058,0xE3D9,      // <cjk>
-      0x805A,0xE3DA,      // <cjk>
-      0x805E,0x95B7,      // <cjk>
-      0x805F,0xE3DB,      // <cjk>
-      0x8061,0x918F,      // <cjk>
-      0x8062,0xE3DC,      // <cjk>
-      0x8068,0xE3DD,      // <cjk>
-      0x806F,0x97FC,      // <cjk>
-      0x8070,0xE3E0,      // <cjk>
-      0x8072,0xE3DF,      // <cjk>
-      0x8073,0xE3DE,      // <cjk>
-      0x8074,0x92AE,      // <cjk>
-      0x8076,0xE3E1,      // <cjk>
-      0x8077,0x9045,      // <cjk>
-      0x8079,0xE3E2,      // <cjk>
-      0x807D,0xE3E3,      // <cjk>
-      0x807E,0x9857,      // <cjk>
-      0x807F,0xE3E4,      // <cjk>
-      0x8084,0xE3E5,      // <cjk>
-      0x8085,0xE3E7,      // <cjk>
-      0x8086,0xE3E6,      // <cjk>
-      0x8087,0x94A3,      // <cjk>
-      0x8089,0x93F7,      // <cjk>
-      0x808B,0x985D,      // <cjk>
-      0x808C,0x94A7,      // <cjk>
-      0x8093,0xE3E9,      // <cjk>
-      0x8096,0x8FD1,      // <cjk>
-      0x8098,0x9549,      // <cjk>
-      0x809A,0xE3EA,      // <cjk>
-      0x809B,0xE3E8,      // <cjk>
-      0x809D,0x8ACC,      // <cjk>
-      0x80A1,0x8CD2,      // <cjk>
-      0x80A2,0x8E88,      // <cjk>
-      0x80A5,0x94EC,      // <cjk>
-      0x80A9,0x8CA8,      // <cjk>
-      0x80AA,0x9662,      // <cjk>
-      0x80AC,0xE3ED,      // <cjk>
-      0x80AD,0xE3EB,      // <cjk>
-      0x80AF,0x8D6D,      // <cjk>
-      0x80B1,0x8D6E,      // <cjk>
-      0x80B2,0x88E7,      // <cjk>
-      0x80B4,0x8DE6,      // <cjk>
-      0x80BA,0x9478,      // <cjk>
-      0x80C3,0x88DD,      // <cjk>
-      0x80C4,0xE3F2,      // <cjk>
-      0x80C6,0x925F,      // <cjk>
-      0x80CC,0x9477,      // <cjk>
-      0x80CE,0x91D9,      // <cjk>
-      0x80D6,0xE3F4,      // <cjk>
-      0x80D9,0xE3F0,      // <cjk>
-      0x80DA,0xE3F3,      // <cjk>
-      0x80DB,0xE3EE,      // <cjk>
-      0x80DD,0xE3F1,      // <cjk>
-      0x80DE,0x9645,      // <cjk>
-      0x80E1,0x8CD3,      // <cjk>
-      0x80E4,0x88FB,      // <cjk>
-      0x80E5,0xE3EF,      // <cjk>
-      0x80EF,0xE3F6,      // <cjk>
-      0x80F1,0xE3F7,      // <cjk>
-      0x80F4,0x93B7,      // <cjk>
-      0x80F8,0x8BB9,      // <cjk>
-      0x80FC,0xE445,      // <cjk>
-      0x80FD,0x945C,      // <cjk>
-      0x8102,0x8E89,      // <cjk>
-      0x8105,0x8BBA,      // <cjk>
-      0x8106,0x90C6,      // <cjk>
-      0x8107,0x9865,      // <cjk>
-      0x8108,0x96AC,      // <cjk>
-      0x8109,0xE3F5,      // <cjk>
-      0x810A,0x90D2,      // <cjk>
-      0x811A,0x8B72,      // <cjk>
-      0x811B,0xE3F8,      // <cjk>
-      0x8123,0xE3FA,      // <cjk>
-      0x8129,0xE3F9,      // <cjk>
-      0x812F,0xE3FB,      // <cjk>
-      0x8131,0x9245,      // <cjk>
-      0x8133,0x945D,      // <cjk>
-      0x8139,0x92AF,      // <cjk>
-      0x813E,0xE442,      // <cjk>
-      0x8146,0xE441,      // <cjk>
-      0x814B,0xE3FC,      // <cjk>
-      0x814E,0x9074,      // <cjk>
-      0x8150,0x9585,      // <cjk>
-      0x8151,0xE444,      // <cjk>
-      0x8153,0xE443,      // <cjk>
-      0x8154,0x8D6F,      // <cjk>
-      0x8155,0x9872,      // <cjk>
-      0x815F,0xE454,      // <cjk>
-      0x8165,0xE448,      // <cjk>
-      0x8166,0xE449,      // <cjk>
-      0x816B,0x8EEE,      // <cjk>
-      0x816E,0xE447,      // <cjk>
-      0x8170,0x8D98,      // <cjk>
-      0x8171,0xE446,      // <cjk>
-      0x8174,0xE44A,      // <cjk>
-      0x8178,0x92B0,      // <cjk>
-      0x8179,0x95A0,      // <cjk>
-      0x817A,0x9142,      // <cjk>
-      0x817F,0x91DA,      // <cjk>
-      0x8180,0xE44E,      // <cjk>
-      0x8182,0xE44F,      // <cjk>
-      0x8183,0xE44B,      // <cjk>
-      0x8188,0xE44C,      // <cjk>
-      0x818A,0xE44D,      // <cjk>
-      0x818F,0x8D70,      // <cjk>
-      0x8193,0xE455,      // <cjk>
-      0x8195,0xE451,      // <cjk>
-      0x819A,0x9586,      // <cjk>
-      0x819C,0x968C,      // <cjk>
-      0x819D,0x9547,      // <cjk>
-      0x81A0,0xE450,      // <cjk>
-      0x81A3,0xE453,      // <cjk>
-      0x81A4,0xE452,      // <cjk>
-      0x81A8,0x9663,      // <cjk>
-      0x81A9,0xE456,      // <cjk>
-      0x81B0,0xE457,      // <cjk>
-      0x81B3,0x9156,      // <cjk>
-      0x81B5,0xE458,      // <cjk>
-      0x81B8,0xE45A,      // <cjk>
-      0x81BA,0xE45E,      // <cjk>
-      0x81BE,0xE459,      // <cjk>
-      0x81BF,0x945E,      // <cjk>
-      0x81C0,0xE45C,      // <cjk>
-      0x81C2,0xE45D,      // <cjk>
-      0x81C6,0x89B0,      // <cjk>
-      0x81C8,0xE464,      // <cjk>
-      0x81C9,0xE45F,      // <cjk>
-      0x81CD,0xE460,      // <cjk>
-      0x81D1,0xE461,      // <cjk>
-      0x81D3,0x919F,      // <cjk>
-      0x81D8,0xE463,      // <cjk>
-      0x81D9,0xE462,      // <cjk>
-      0x81DA,0xE465,      // <cjk>
-      0x81DF,0xE466,      // <cjk>
-      0x81E0,0xE467,      // <cjk>
-      0x81E3,0x9062,      // <cjk>
-      0x81E5,0x89E7,      // <cjk>
-      0x81E7,0xE468,      // <cjk>
-      0x81E8,0x97D5,      // <cjk>
-      0x81EA,0x8EA9,      // <cjk>
-      0x81ED,0x8F4C,      // <cjk>
-      0x81F3,0x8E8A,      // <cjk>
-      0x81F4,0x9276,      // <cjk>
-      0x81FA,0xE469,      // <cjk>
-      0x81FB,0xE46A,      // <cjk>
-      0x81FC,0x8950,      // <cjk>
-      0x81FE,0xE46B,      // <cjk>
-      0x8201,0xE46C,      // <cjk>
-      0x8202,0xE46D,      // <cjk>
-      0x8205,0xE46E,      // <cjk>
-      0x8207,0xE46F,      // <cjk>
-      0x8208,0x8BBB,      // <cjk>
-      0x8209,0x9DA8,      // <cjk>
-      0x820A,0xE470,      // <cjk>
-      0x820C,0x90E3,      // <cjk>
-      0x820D,0xE471,      // <cjk>
-      0x820E,0x8EC9,      // <cjk>
-      0x8210,0xE472,      // <cjk>
-      0x8212,0x98AE,      // <cjk>
-      0x8216,0xE473,      // <cjk>
-      0x8217,0x95DC,      // <cjk>
-      0x8218,0x8ADA,      // <cjk>
-      0x821B,0x9143,      // <cjk>
-      0x821C,0x8F77,      // <cjk>
-      0x821E,0x9591,      // <cjk>
-      0x821F,0x8F4D,      // <cjk>
-      0x8229,0xE474,      // <cjk>
-      0x822A,0x8D71,      // <cjk>
-      0x822B,0xE475,      // <cjk>
-      0x822C,0x94CA,      // <cjk>
-      0x822E,0xE484,      // <cjk>
-      0x8233,0xE477,      // <cjk>
-      0x8235,0x91C7,      // <cjk>
-      0x8236,0x9495,      // <cjk>
-      0x8237,0x8CBD,      // <cjk>
-      0x8238,0xE476,      // <cjk>
-      0x8239,0x9144,      // <cjk>
-      0x8240,0xE478,      // <cjk>
-      0x8247,0x92F8,      // <cjk>
-      0x8258,0xE47A,      // <cjk>
-      0x8259,0xE479,      // <cjk>
-      0x825A,0xE47C,      // <cjk>
-      0x825D,0xE47B,      // <cjk>
-      0x825F,0xE47D,      // <cjk>
-      0x8262,0xE480,      // <cjk>
-      0x8264,0xE47E,      // <cjk>
-      0x8266,0x8ACD,      // <cjk>
-      0x8268,0xE481,      // <cjk>
-      0x826A,0xE482,      // <cjk>
-      0x826B,0xE483,      // <cjk>
-      0x826E,0x8DAF,      // <cjk>
-      0x826F,0x97C7,      // <cjk>
-      0x8271,0xE485,      // <cjk>
-      0x8272,0x9046,      // <cjk>
-      0x8276,0x8990,      // <cjk>
-      0x8277,0xE486,      // <cjk>
-      0x8278,0xE487,      // <cjk>
-      0x827E,0xE488,      // <cjk>
-      0x828B,0x88F0,      // <cjk>
-      0x828D,0xE489,      // <cjk>
-      0x8292,0xE48A,      // <cjk>
-      0x8299,0x9587,      // <cjk>
-      0x829D,0x8EC5,      // <cjk>
-      0x829F,0xE48C,      // <cjk>
-      0x82A5,0x8A48,      // <cjk>
-      0x82A6,0x88B0,      // <cjk>
-      0x82AB,0xE48B,      // <cjk>
-      0x82AC,0xE48E,      // <cjk>
-      0x82AD,0x946D,      // <cjk>
-      0x82AF,0x9063,      // <cjk>
-      0x82B1,0x89D4,      // <cjk>
-      0x82B3,0x9646,      // <cjk>
-      0x82B8,0x8C7C,      // <cjk>
-      0x82B9,0x8BDA,      // <cjk>
-      0x82BB,0xE48D,      // <cjk>
-      0x82BD,0x89E8,      // <cjk>
-      0x82C5,0x8AA1,      // <cjk>
-      0x82D1,0x8991,      // <cjk>
-      0x82D2,0xE492,      // <cjk>
-      0x82D3,0x97E8,      // <cjk>
-      0x82D4,0x91DB,      // <cjk>
-      0x82D7,0x9563,      // <cjk>
-      0x82D9,0xE49E,      // <cjk>
-      0x82DB,0x89D5,      // <cjk>
-      0x82DC,0xE49C,      // <cjk>
-      0x82DE,0xE49A,      // <cjk>
-      0x82DF,0xE491,      // <cjk>
-      0x82E1,0xE48F,      // <cjk>
-      0x82E3,0xE490,      // <cjk>
-      0x82E5,0x8EE1,      // <cjk>
-      0x82E6,0x8BEA,      // <cjk>
-      0x82E7,0x9297,      // <cjk>
-      0x82EB,0x93CF,      // <cjk>
-      0x82F1,0x8970,      // <cjk>
-      0x82F3,0xE494,      // <cjk>
-      0x82F4,0xE493,      // <cjk>
-      0x82F9,0xE499,      // <cjk>
-      0x82FA,0xE495,      // <cjk>
-      0x82FB,0xE498,      // <cjk>
-      0x8302,0x96CE,      // <cjk>
-      0x8303,0xE497,      // <cjk>
-      0x8304,0x89D6,      // <cjk>
-      0x8305,0x8A9D,      // <cjk>
-      0x8306,0xE49B,      // <cjk>
-      0x8309,0xE49D,      // <cjk>
-      0x830E,0x8C73,      // <cjk>
-      0x8316,0xE4A1,      // <cjk>
-      0x8317,0xE4AA,      // <cjk>
-      0x8318,0xE4AB,      // <cjk>
-      0x831C,0x88A9,      // <cjk>
-      0x8323,0xE4B2,      // <cjk>
-      0x8328,0x88EF,      // <cjk>
-      0x832B,0xE4A9,      // <cjk>
-      0x832F,0xE4A8,      // <cjk>
-      0x8331,0xE4A3,      // <cjk>
-      0x8332,0xE4A2,      // <cjk>
-      0x8334,0xE4A0,      // <cjk>
-      0x8335,0xE49F,      // <cjk>
-      0x8336,0x9283,      // <cjk>
-      0x8338,0x91F9,      // <cjk>
-      0x8339,0xE4A5,      // <cjk>
-      0x8340,0xE4A4,      // <cjk>
-      0x8345,0xE4A7,      // <cjk>
-      0x8349,0x9190,      // <cjk>
-      0x834A,0x8C74,      // <cjk>
-      0x834F,0x8960,      // <cjk>
-      0x8350,0xE4A6,      // <cjk>
-      0x8352,0x8D72,      // <cjk>
-      0x8358,0x9191,      // <cjk>
-      0x8373,0xE4B8,      // <cjk>
-      0x8375,0xE4B9,      // <cjk>
-      0x8377,0x89D7,      // <cjk>
-      0x837B,0x89AC,      // <cjk>
-      0x837C,0xE4B6,      // <cjk>
-      0x8385,0xE4AC,      // <cjk>
-      0x8387,0xE4B4,      // <cjk>
-      0x8389,0xE4BB,      // <cjk>
-      0x838A,0xE4B5,      // <cjk>
-      0x838E,0xE4B3,      // <cjk>
-      0x8393,0xE496,      // <cjk>
-      0x8396,0xE4B1,      // <cjk>
-      0x839A,0xE4AD,      // <cjk>
-      0x839E,0x8ACE,      // <cjk>
-      0x839F,0xE4AF,      // <cjk>
-      0x83A0,0xE4BA,      // <cjk>
-      0x83A2,0xE4B0,      // <cjk>
-      0x83A8,0xE4BC,      // <cjk>
-      0x83AA,0xE4AE,      // <cjk>
-      0x83AB,0x949C,      // <cjk>
-      0x83B1,0x9789,      // <cjk>
-      0x83B5,0xE4B7,      // <cjk>
-      0x83BD,0xE4CD,      // <cjk>
-      0x83C1,0xE4C5,      // <cjk>
-      0x83C5,0x909B,      // <cjk>
-      0x83CA,0x8B65,      // <cjk>
-      0x83CC,0x8BDB,      // <cjk>
-      0x83CE,0xE4C0,      // <cjk>
-      0x83D3,0x89D9,      // <cjk>
-      0x83D6,0x8FD2,      // <cjk>
-      0x83D8,0xE4C3,      // <cjk>
-      0x83DC,0x8DD8,      // <cjk>
-      0x83DF,0x9370,      // <cjk>
-      0x83E0,0xE4C8,      // <cjk>
-      0x83E9,0x95EC,      // <cjk>
-      0x83EB,0xE4BF,      // <cjk>
-      0x83EF,0x89D8,      // <cjk>
-      0x83F0,0x8CD4,      // <cjk>
-      0x83F1,0x9548,      // <cjk>
-      0x83F2,0xE4C9,      // <cjk>
-      0x83F4,0xE4BD,      // <cjk>
-      0x83F7,0xE4C6,      // <cjk>
-      0x83FB,0xE4D0,      // <cjk>
-      0x83FD,0xE4C1,      // <cjk>
-      0x8403,0xE4C2,      // <cjk>
-      0x8404,0x93B8,      // <cjk>
-      0x8407,0xE4C7,      // <cjk>
-      0x840B,0xE4C4,      // <cjk>
-      0x840C,0x9647,      // <cjk>
-      0x840D,0xE4CA,      // <cjk>
-      0x840E,0x88DE,      // <cjk>
-      0x8413,0xE4BE,      // <cjk>
-      0x8420,0xE4CC,      // <cjk>
-      0x8422,0xE4CB,      // <cjk>
-      0x8429,0x948B,      // <cjk>
-      0x842A,0xE4D2,      // <cjk>
-      0x842C,0xE4DD,      // <cjk>
-      0x8431,0x8A9E,      // <cjk>
-      0x8435,0xE4E0,      // <cjk>
-      0x8438,0xE4CE,      // <cjk>
-      0x843C,0xE4D3,      // <cjk>
-      0x843D,0x978E,      // <cjk>
-      0x8446,0xE4DC,      // <cjk>
-      0x8449,0x9774,      // <cjk>
-      0x844E,0x97A8,      // <cjk>
-      0x8457,0x9298,      // <cjk>
-      0x845B,0x8A8B,      // <cjk>
-      0x8461,0x9592,      // <cjk>
-      0x8462,0xE4E2,      // <cjk>
-      0x8463,0x939F,      // <cjk>
-      0x8466,0x88AF,      // <cjk>
-      0x8469,0xE4DB,      // <cjk>
-      0x846B,0xE4D7,      // <cjk>
-      0x846C,0x9192,      // <cjk>
-      0x846D,0xE4D1,      // <cjk>
-      0x846E,0xE4D9,      // <cjk>
-      0x846F,0xE4DE,      // <cjk>
-      0x8471,0x944B,      // <cjk>
-      0x8475,0x88A8,      // <cjk>
-      0x8477,0xE4D6,      // <cjk>
-      0x8479,0xE4DF,      // <cjk>
-      0x847A,0x9598,      // <cjk>
-      0x8482,0xE4DA,      // <cjk>
-      0x8484,0xE4D5,      // <cjk>
-      0x848B,0x8FD3,      // <cjk>
-      0x8490,0x8F4E,      // <cjk>
-      0x8494,0x8EAA,      // <cjk>
-      0x8499,0x96D6,      // <cjk>
-      0x849C,0x9566,      // <cjk>
-      0x849F,0xE4E5,      // <cjk>
-      0x84A1,0xE4EE,      // <cjk>
-      0x84AD,0xE4D8,      // <cjk>
-      0x84B2,0x8A97,      // <cjk>
-      0x84B8,0x8FF6,      // <cjk>
-      0x84B9,0xE4E3,      // <cjk>
-      0x84BB,0xE4E8,      // <cjk>
-      0x84BC,0x9193,      // <cjk>
-      0x84BF,0xE4E4,      // <cjk>
-      0x84C1,0xE4EB,      // <cjk>
-      0x84C4,0x927E,      // <cjk>
-      0x84C6,0xE4EC,      // <cjk>
-      0x84C9,0x9775,      // <cjk>
-      0x84CA,0xE4E1,      // <cjk>
-      0x84CB,0x8A57,      // <cjk>
-      0x84CD,0xE4E7,      // <cjk>
-      0x84D0,0xE4EA,      // <cjk>
-      0x84D1,0x96AA,      // <cjk>
-      0x84D6,0xE4ED,      // <cjk>
-      0x84D9,0xE4E6,      // <cjk>
-      0x84DA,0xE4E9,      // <cjk>
-      0x84EC,0x9648,      // <cjk>
-      0x84EE,0x9840,      // <cjk>
-      0x84F4,0xE4F1,      // <cjk>
-      0x84FC,0xE4F8,      // <cjk>
-      0x84FF,0xE4F0,      // <cjk>
-      0x8500,0x8EC1,      // <cjk>
-      0x8506,0xE4CF,      // <cjk>
-      0x8511,0x95CC,      // <cjk>
-      0x8513,0x96A0,      // <cjk>
-      0x8514,0xE4F7,      // <cjk>
-      0x8515,0xE4F6,      // <cjk>
-      0x8517,0xE4F2,      // <cjk>
-      0x8518,0xE4F3,      // <cjk>
-      0x851A,0x8955,      // <cjk>
-      0x851F,0xE4F5,      // <cjk>
-      0x8521,0xE4EF,      // <cjk>
-      0x8526,0x92D3,      // <cjk>
-      0x852C,0xE4F4,      // <cjk>
-      0x852D,0x88FC,      // <cjk>
-      0x8535,0x91A0,      // <cjk>
-      0x853D,0x95C1,      // <cjk>
-      0x8540,0xE4F9,      // <cjk>
-      0x8541,0xE540,      // <cjk>
-      0x8543,0x94D7,      // <cjk>
-      0x8548,0xE4FC,      // <cjk>
-      0x8549,0x8FD4,      // <cjk>
-      0x854A,0x8EC7,      // <cjk>
-      0x854B,0xE542,      // <cjk>
-      0x854E,0x8BBC,      // <cjk>
-      0x8555,0xE543,      // <cjk>
-      0x8557,0x9599,      // <cjk>
-      0x8558,0xE4FB,      // <cjk>
-      0x855A,0xE4D4,      // <cjk>
-      0x8563,0xE4FA,      // <cjk>
-      0x8568,0x986E,      // <cjk>
-      0x8569,0x93A0,      // <cjk>
-      0x856A,0x9593,      // <cjk>
-      0x856D,0xE54A,      // <cjk>
-      0x8577,0xE550,      // <cjk>
-      0x857E,0xE551,      // <cjk>
-      0x8580,0xE544,      // <cjk>
-      0x8584,0x9496,      // <cjk>
-      0x8587,0xE54E,      // <cjk>
-      0x8588,0xE546,      // <cjk>
-      0x858A,0xE548,      // <cjk>
-      0x8590,0xE552,      // <cjk>
-      0x8591,0xE547,      // <cjk>
-      0x8594,0xE54B,      // <cjk>
-      0x8597,0x8992,      // <cjk>
-      0x8599,0x93E3,      // <cjk>
-      0x859B,0xE54C,      // <cjk>
-      0x859C,0xE54F,      // <cjk>
-      0x85A4,0xE545,      // <cjk>
-      0x85A6,0x9145,      // <cjk>
-      0x85A8,0xE549,      // <cjk>
-      0x85A9,0x8E46,      // <cjk>
-      0x85AA,0x9064,      // <cjk>
-      0x85AB,0x8C4F,      // <cjk>
-      0x85AC,0x96F2,      // <cjk>
-      0x85AE,0x96F7,      // <cjk>
-      0x85AF,0x8F92,      // <cjk>
-      0x85B9,0xE556,      // <cjk>
-      0x85BA,0xE554,      // <cjk>
-      0x85C1,0x986D,      // <cjk>
-      0x85C9,0xE553,      // <cjk>
-      0x85CD,0x9795,      // <cjk>
-      0x85CF,0xE555,      // <cjk>
-      0x85D0,0xE557,      // <cjk>
-      0x85D5,0xE558,      // <cjk>
-      0x85DD,0xE559,      // <cjk>
-      0x85E4,0x93A1,      // <cjk>
-      0x85E5,0xE55A,      // <cjk>
-      0x85E9,0x94CB,      // <cjk>
-      0x85EA,0xE54D,      // <cjk>
-      0x85F7,0x8F93,      // <cjk>
-      0x85F9,0xE55C,      // <cjk>
-      0x85FA,0xE561,      // <cjk>
-      0x85FB,0x9194,      // <cjk>
-      0x85FE,0xE560,      // <cjk>
-      0x8602,0xE541,      // <cjk>
-      0x8606,0xE562,      // <cjk>
-      0x8607,0x9168,      // <cjk>
-      0x860A,0xE55D,      // <cjk>
-      0x860B,0xE55F,      // <cjk>
-      0x8613,0xE55E,      // <cjk>
-      0x8616,0x9F50,      // <cjk>
-      0x8617,0x9F41,      // <cjk>
-      0x861A,0xE564,      // <cjk>
-      0x8622,0xE563,      // <cjk>
-      0x862D,0x9796,      // <cjk>
-      0x862F,0xE1BA,      // <cjk>
-      0x8630,0xE565,      // <cjk>
-      0x863F,0xE566,      // <cjk>
-      0x864D,0xE567,      // <cjk>
-      0x864E,0x8CD5,      // <cjk>
-      0x8650,0x8B73,      // <cjk>
-      0x8654,0xE569,      // <cjk>
-      0x8655,0x997C,      // <cjk>
-      0x865A,0x8B95,      // <cjk>
-      0x865C,0x97B8,      // <cjk>
-      0x865E,0x8BF1,      // <cjk>
-      0x865F,0xE56A,      // <cjk>
-      0x8667,0xE56B,      // <cjk>
-      0x866B,0x928E,      // <cjk>
-      0x8671,0xE56C,      // <cjk>
-      0x8679,0x93F8,      // <cjk>
-      0x867B,0x88B8,      // <cjk>
-      0x868A,0x89E1,      // <cjk>
-      0x868B,0xE571,      // <cjk>
-      0x868C,0xE572,      // <cjk>
-      0x8693,0xE56D,      // <cjk>
-      0x8695,0x8E5C,      // <cjk>
-      0x86A3,0xE56E,      // <cjk>
-      0x86A4,0x9461,      // <cjk>
-      0x86A9,0xE56F,      // <cjk>
-      0x86AA,0xE570,      // <cjk>
-      0x86AB,0xE57A,      // <cjk>
-      0x86AF,0xE574,      // <cjk>
-      0x86B0,0xE577,      // <cjk>
-      0x86B6,0xE573,      // <cjk>
-      0x86C4,0xE575,      // <cjk>
-      0x86C6,0xE576,      // <cjk>
-      0x86C7,0x8ED6,      // <cjk>
-      0x86C9,0xE578,      // <cjk>
-      0x86CB,0x9260,      // <cjk>
-      0x86CD,0x8C75,      // <cjk>
-      0x86CE,0x8A61,      // <cjk>
-      0x86D4,0xE57B,      // <cjk>
-      0x86D9,0x8A5E,      // <cjk>
-      0x86DB,0xE581,      // <cjk>
-      0x86DE,0xE57C,      // <cjk>
-      0x86DF,0xE580,      // <cjk>
-      0x86E4,0x94B8,      // <cjk>
-      0x86E9,0xE57D,      // <cjk>
-      0x86EC,0xE57E,      // <cjk>
-      0x86ED,0x9567,      // <cjk>
-      0x86EE,0x94D8,      // <cjk>
-      0x86EF,0xE582,      // <cjk>
-      0x86F8,0x91FB,      // <cjk>
-      0x86F9,0xE58C,      // <cjk>
-      0x86FB,0xE588,      // <cjk>
-      0x86FE,0x89E9,      // <cjk>
-      0x8700,0xE586,      // <cjk>
-      0x8702,0x9649,      // <cjk>
-      0x8703,0xE587,      // <cjk>
-      0x8706,0xE584,      // <cjk>
-      0x8708,0xE585,      // <cjk>
-      0x8709,0xE58A,      // <cjk>
-      0x870A,0xE58D,      // <cjk>
-      0x870D,0xE58B,      // <cjk>
-      0x8711,0xE589,      // <cjk>
-      0x8712,0xE583,      // <cjk>
-      0x8718,0x9277,      // <cjk>
-      0x871A,0xE594,      // <cjk>
-      0x871C,0x96A8,      // <cjk>
-      0x8725,0xE592,      // <cjk>
-      0x8729,0xE593,      // <cjk>
-      0x8734,0xE58E,      // <cjk>
-      0x8737,0xE590,      // <cjk>
-      0x873B,0xE591,      // <cjk>
-      0x873F,0xE58F,      // <cjk>
-      0x8749,0x90E4,      // <cjk>
-      0x874B,0x9858,      // <cjk>
-      0x874C,0xE598,      // <cjk>
-      0x874E,0xE599,      // <cjk>
-      0x8753,0xE59F,      // <cjk>
-      0x8755,0x9049,      // <cjk>
-      0x8757,0xE59B,      // <cjk>
-      0x8759,0xE59E,      // <cjk>
-      0x875F,0xE596,      // <cjk>
-      0x8760,0xE595,      // <cjk>
-      0x8763,0xE5A0,      // <cjk>
-      0x8766,0x89DA,      // <cjk>
-      0x8768,0xE59C,      // <cjk>
-      0x876A,0xE5A1,      // <cjk>
-      0x876E,0xE59D,      // <cjk>
-      0x8774,0xE59A,      // <cjk>
-      0x8776,0x92B1,      // <cjk>
-      0x8778,0xE597,      // <cjk>
-      0x877F,0x9488,      // <cjk>
-      0x8782,0xE5A5,      // <cjk>
-      0x878D,0x975A,      // <cjk>
-      0x879F,0xE5A4,      // <cjk>
-      0x87A2,0xE5A3,      // <cjk>
-      0x87AB,0xE5AC,      // <cjk>
-      0x87AF,0xE5A6,      // <cjk>
-      0x87B3,0xE5AE,      // <cjk>
-      0x87BA,0x9786,      // <cjk>
-      0x87BB,0xE5B1,      // <cjk>
-      0x87BD,0xE5A8,      // <cjk>
-      0x87C0,0xE5A9,      // <cjk>
-      0x87C4,0xE5AD,      // <cjk>
-      0x87C6,0xE5B0,      // <cjk>
-      0x87C7,0xE5AF,      // <cjk>
-      0x87CB,0xE5A7,      // <cjk>
-      0x87D0,0xE5AA,      // <cjk>
-      0x87D2,0xE5BB,      // <cjk>
-      0x87E0,0xE5B4,      // <cjk>
-      0x87EF,0xE5B2,      // <cjk>
-      0x87F2,0xE5B3,      // <cjk>
-      0x87F6,0xE5B8,      // <cjk>
-      0x87F7,0xE5B9,      // <cjk>
-      0x87F9,0x8A49,      // <cjk>
-      0x87FB,0x8B61,      // <cjk>
-      0x87FE,0xE5B7,      // <cjk>
-      0x8805,0xE5A2,      // <cjk>
-      0x880D,0xE5B6,      // <cjk>
-      0x880E,0xE5BA,      // <cjk>
-      0x880F,0xE5B5,      // <cjk>
-      0x8811,0xE5BC,      // <cjk>
-      0x8815,0xE5BE,      // <cjk>
-      0x8816,0xE5BD,      // <cjk>
-      0x8821,0xE5C0,      // <cjk>
-      0x8822,0xE5BF,      // <cjk>
-      0x8823,0xE579,      // <cjk>
-      0x8827,0xE5C4,      // <cjk>
-      0x8831,0xE5C1,      // <cjk>
-      0x8836,0xE5C2,      // <cjk>
-      0x8839,0xE5C3,      // <cjk>
-      0x883B,0xE5C5,      // <cjk>
-      0x8840,0x8C8C,      // <cjk>
-      0x8842,0xE5C7,      // <cjk>
-      0x8844,0xE5C6,      // <cjk>
-      0x8846,0x8F4F,      // <cjk>
-      0x884C,0x8D73,      // <cjk>
-      0x884D,0x9FA5,      // <cjk>
-      0x8852,0xE5C8,      // <cjk>
-      0x8853,0x8F70,      // <cjk>
-      0x8857,0x8A58,      // <cjk>
-      0x8859,0xE5C9,      // <cjk>
-      0x885B,0x8971,      // <cjk>
-      0x885D,0x8FD5,      // <cjk>
-      0x885E,0xE5CA,      // <cjk>
-      0x8861,0x8D74,      // <cjk>
-      0x8862,0xE5CB,      // <cjk>
-      0x8863,0x88DF,      // <cjk>
-      0x8868,0x955C,      // <cjk>
-      0x886B,0xE5CC,      // <cjk>
-      0x8870,0x908A,      // <cjk>
-      0x8872,0xE5D3,      // <cjk>
-      0x8875,0xE5D0,      // <cjk>
-      0x8877,0x928F,      // <cjk>
-      0x887D,0xE5D1,      // <cjk>
-      0x887E,0xE5CE,      // <cjk>
-      0x887F,0x8BDC,      // <cjk>
-      0x8881,0xE5CD,      // <cjk>
-      0x8882,0xE5D4,      // <cjk>
-      0x8888,0x8C55,      // <cjk>
-      0x888B,0x91DC,      // <cjk>
-      0x888D,0xE5DA,      // <cjk>
-      0x8892,0xE5D6,      // <cjk>
-      0x8896,0x91B3,      // <cjk>
-      0x8897,0xE5D5,      // <cjk>
-      0x8899,0xE5D8,      // <cjk>
-      0x889E,0xE5CF,      // <cjk>
-      0x88A2,0xE5D9,      // <cjk>
-      0x88A4,0xE5DB,      // <cjk>
-      0x88AB,0x94ED,      // <cjk>
-      0x88AE,0xE5D7,      // <cjk>
-      0x88B0,0xE5DC,      // <cjk>
-      0x88B1,0xE5DE,      // <cjk>
-      0x88B4,0x8CD1,      // <cjk>
-      0x88B5,0xE5D2,      // <cjk>
-      0x88B7,0x88BF,      // <cjk>
-      0x88BF,0xE5DD,      // <cjk>
-      0x88C1,0x8DD9,      // <cjk>
-      0x88C2,0x97F4,      // <cjk>
-      0x88C3,0xE5DF,      // <cjk>
-      0x88C4,0xE5E0,      // <cjk>
-      0x88C5,0x9195,      // <cjk>
-      0x88CF,0x97A0,      // <cjk>
-      0x88D4,0xE5E1,      // <cjk>
-      0x88D5,0x9754,      // <cjk>
-      0x88D8,0xE5E2,      // <cjk>
-      0x88D9,0xE5E3,      // <cjk>
-      0x88DC,0x95E2,      // <cjk>
-      0x88DD,0xE5E4,      // <cjk>
-      0x88DF,0x8DBE,      // <cjk>
-      0x88E1,0x97A1,      // <cjk>
-      0x88E8,0xE5E9,      // <cjk>
-      0x88F2,0xE5EA,      // <cjk>
-      0x88F3,0x8FD6,      // <cjk>
-      0x88F4,0xE5E8,      // <cjk>
-      0x88F8,0x9787,      // <cjk>
-      0x88F9,0xE5E5,      // <cjk>
-      0x88FC,0xE5E7,      // <cjk>
-      0x88FD,0x90BB,      // <cjk>
-      0x88FE,0x909E,      // <cjk>
-      0x8902,0xE5E6,      // <cjk>
-      0x8904,0xE5EB,      // <cjk>
-      0x8907,0x95A1,      // <cjk>
-      0x890A,0xE5ED,      // <cjk>
-      0x890C,0xE5EC,      // <cjk>
-      0x8910,0x8A8C,      // <cjk>
-      0x8912,0x964A,      // <cjk>
-      0x8913,0xE5EE,      // <cjk>
-      0x891D,0xE5FA,      // <cjk>
-      0x891E,0xE5F0,      // <cjk>
-      0x8925,0xE5F1,      // <cjk>
-      0x892A,0xE5F2,      // <cjk>
-      0x892B,0xE5F3,      // <cjk>
-      0x8936,0xE5F7,      // <cjk>
-      0x8938,0xE5F8,      // <cjk>
-      0x893B,0xE5F6,      // <cjk>
-      0x8941,0xE5F4,      // <cjk>
-      0x8943,0xE5EF,      // <cjk>
-      0x8944,0xE5F5,      // <cjk>
-      0x894C,0xE5F9,      // <cjk>
-      0x894D,0xE8B5,      // <cjk>
-      0x8956,0x89A6,      // <cjk>
-      0x895E,0xE5FC,      // <cjk>
-      0x895F,0x8BDD,      // <cjk>
-      0x8960,0xE5FB,      // <cjk>
-      0x8964,0xE641,      // <cjk>
-      0x8966,0xE640,      // <cjk>
-      0x896A,0xE643,      // <cjk>
-      0x896D,0xE642,      // <cjk>
-      0x896F,0xE644,      // <cjk>
-      0x8972,0x8F50,      // <cjk>
-      0x8974,0xE645,      // <cjk>
-      0x8977,0xE646,      // <cjk>
-      0x897E,0xE647,      // <cjk>
-      0x897F,0x90BC,      // <cjk>
-      0x8981,0x9776,      // <cjk>
-      0x8983,0xE648,      // <cjk>
-      0x8986,0x95A2,      // <cjk>
-      0x8987,0x9465,      // <cjk>
-      0x8988,0xE649,      // <cjk>
-      0x898A,0xE64A,      // <cjk>
-      0x898B,0x8CA9,      // <cjk>
-      0x898F,0x8B4B,      // <cjk>
-      0x8993,0xE64B,      // <cjk>
-      0x8996,0x8E8B,      // <cjk>
-      0x8997,0x9460,      // <cjk>
-      0x8998,0xE64C,      // <cjk>
-      0x899A,0x8A6F,      // <cjk>
-      0x89A1,0xE64D,      // <cjk>
-      0x89A6,0xE64F,      // <cjk>
-      0x89A7,0x9797,      // <cjk>
-      0x89A9,0xE64E,      // <cjk>
-      0x89AA,0x9065,      // <cjk>
-      0x89AC,0xE650,      // <cjk>
-      0x89AF,0xE651,      // <cjk>
-      0x89B2,0xE652,      // <cjk>
-      0x89B3,0x8ACF,      // <cjk>
-      0x89BA,0xE653,      // <cjk>
-      0x89BD,0xE654,      // <cjk>
-      0x89BF,0xE655,      // <cjk>
-      0x89C0,0xE656,      // <cjk>
-      0x89D2,0x8A70,      // <cjk>
-      0x89DA,0xE657,      // <cjk>
-      0x89DC,0xE658,      // <cjk>
-      0x89DD,0xE659,      // <cjk>
-      0x89E3,0x89F0,      // <cjk>
-      0x89E6,0x9047,      // <cjk>
-      0x89E7,0xE65A,      // <cjk>
-      0x89F8,0xE65C,      // <cjk>
-      0x8A00,0x8CBE,      // <cjk>
-      0x8A02,0x92F9,      // <cjk>
-      0x8A03,0xE65D,      // <cjk>
-      0x8A08,0x8C76,      // <cjk>
-      0x8A0A,0x9075,      // <cjk>
-      0x8A0C,0xE660,      // <cjk>
-      0x8A0E,0x93A2,      // <cjk>
-      0x8A10,0xE65F,      // <cjk>
-      0x8A13,0x8C50,      // <cjk>
-      0x8A16,0xE65E,      // <cjk>
-      0x8A17,0x91F5,      // <cjk>
-      0x8A18,0x8B4C,      // <cjk>
-      0x8A1B,0xE661,      // <cjk>
-      0x8A1D,0xE662,      // <cjk>
-      0x8A1F,0x8FD7,      // <cjk>
-      0x8A23,0x8C8D,      // <cjk>
-      0x8A25,0xE663,      // <cjk>
-      0x8A2A,0x964B,      // <cjk>
-      0x8A2D,0x90DD,      // <cjk>
-      0x8A31,0x8B96,      // <cjk>
-      0x8A33,0x96F3,      // <cjk>
-      0x8A34,0x9169,      // <cjk>
-      0x8A36,0xE664,      // <cjk>
-      0x8A3A,0x9066,      // <cjk>
-      0x8A3B,0x9290,      // <cjk>
-      0x8A3C,0x8FD8,      // <cjk>
-      0x8A41,0xE665,      // <cjk>
-      0x8A46,0xE668,      // <cjk>
-      0x8A48,0xE669,      // <cjk>
-      0x8A50,0x8DBC,      // <cjk>
-      0x8A51,0x91C0,      // <cjk>
-      0x8A52,0xE667,      // <cjk>
-      0x8A54,0x8FD9,      // <cjk>
-      0x8A55,0x955D,      // <cjk>
-      0x8A5B,0xE666,      // <cjk>
-      0x8A5E,0x8E8C,      // <cjk>
-      0x8A60,0x8972,      // <cjk>
-      0x8A62,0xE66D,      // <cjk>
-      0x8A63,0x8C77,      // <cjk>
-      0x8A66,0x8E8E,      // <cjk>
-      0x8A69,0x8E8D,      // <cjk>
-      0x8A6B,0x986C,      // <cjk>
-      0x8A6C,0xE66C,      // <cjk>
-      0x8A6D,0xE66B,      // <cjk>
-      0x8A6E,0x9146,      // <cjk>
-      0x8A70,0x8B6C,      // <cjk>
-      0x8A71,0x9862,      // <cjk>
-      0x8A72,0x8A59,      // <cjk>
-      0x8A73,0x8FDA,      // <cjk>
-      0x8A7C,0xE66A,      // <cjk>
-      0x8A82,0xE66F,      // <cjk>
-      0x8A84,0xE670,      // <cjk>
-      0x8A85,0xE66E,      // <cjk>
-      0x8A87,0x8CD6,      // <cjk>
-      0x8A89,0x975F,      // <cjk>
-      0x8A8C,0x8E8F,      // <cjk>
-      0x8A8D,0x9446,      // <cjk>
-      0x8A91,0xE673,      // <cjk>
-      0x8A93,0x90BE,      // <cjk>
-      0x8A95,0x9261,      // <cjk>
-      0x8A98,0x9755,      // <cjk>
-      0x8A9A,0xE676,      // <cjk>
-      0x8A9E,0x8CEA,      // <cjk>
-      0x8AA0,0x90BD,      // <cjk>
-      0x8AA1,0xE672,      // <cjk>
-      0x8AA3,0xE677,      // <cjk>
-      0x8AA4,0x8CEB,      // <cjk>
-      0x8AA5,0xE674,      // <cjk>
-      0x8AA6,0xE675,      // <cjk>
-      0x8AA8,0xE671,      // <cjk>
-      0x8AAC,0x90E0,      // <cjk>
-      0x8AAD,0x93C7,      // <cjk>
-      0x8AB0,0x924E,      // <cjk>
-      0x8AB2,0x89DB,      // <cjk>
-      0x8AB9,0x94EE,      // <cjk>
-      0x8ABC,0x8B62,      // <cjk>
-      0x8ABF,0x92B2,      // <cjk>
-      0x8AC2,0xE67A,      // <cjk>
-      0x8AC4,0xE678,      // <cjk>
-      0x8AC7,0x926B,      // <cjk>
-      0x8ACB,0x90BF,      // <cjk>
-      0x8ACC,0x8AD0,      // <cjk>
-      0x8ACD,0xE679,      // <cjk>
-      0x8ACF,0x907A,      // <cjk>
-      0x8AD2,0x97C8,      // <cjk>
-      0x8AD6,0x985F,      // <cjk>
-      0x8ADA,0xE67B,      // <cjk>
-      0x8ADB,0xE687,      // <cjk>
-      0x8ADC,0x92B3,      // <cjk>
-      0x8ADE,0xE686,      // <cjk>
-      0x8AE0,0xE683,      // <cjk>
-      0x8AE1,0xE68B,      // <cjk>
-      0x8AE2,0xE684,      // <cjk>
-      0x8AE4,0xE680,      // <cjk>
-      0x8AE6,0x92FA,      // <cjk>
-      0x8AE7,0xE67E,      // <cjk>
-      0x8AEB,0xE67C,      // <cjk>
-      0x8AED,0x9740,      // <cjk>
-      0x8AEE,0x8E90,      // <cjk>
-      0x8AF1,0xE681,      // <cjk>
-      0x8AF3,0xE67D,      // <cjk>
-      0x8AF7,0xE685,      // <cjk>
-      0x8AF8,0x8F94,      // <cjk>
-      0x8AFA,0x8CBF,      // <cjk>
-      0x8AFE,0x91F8,      // <cjk>
-      0x8B00,0x9664,      // <cjk>
-      0x8B01,0x8979,      // <cjk>
-      0x8B02,0x88E0,      // <cjk>
-      0x8B04,0x93A3,      // <cjk>
-      0x8B07,0xE689,      // <cjk>
-      0x8B0C,0xE688,      // <cjk>
-      0x8B0E,0x93E4,      // <cjk>
-      0x8B10,0xE68D,      // <cjk>
-      0x8B14,0xE682,      // <cjk>
-      0x8B16,0xE68C,      // <cjk>
-      0x8B17,0xE68E,      // <cjk>
-      0x8B19,0x8CAA,      // <cjk>
-      0x8B1A,0xE68A,      // <cjk>
-      0x8B1B,0x8D75,      // <cjk>
-      0x8B1D,0x8ED3,      // <cjk>
-      0x8B20,0xE68F,      // <cjk>
-      0x8B21,0x9777,      // <cjk>
-      0x8B26,0xE692,      // <cjk>
-      0x8B28,0xE695,      // <cjk>
-      0x8B2B,0xE693,      // <cjk>
-      0x8B2C,0x9554,      // <cjk>
-      0x8B33,0xE690,      // <cjk>
-      0x8B39,0x8BDE,      // <cjk>
-      0x8B3E,0xE694,      // <cjk>
-      0x8B41,0xE696,      // <cjk>
-      0x8B49,0xE69A,      // <cjk>
-      0x8B4C,0xE697,      // <cjk>
-      0x8B4E,0xE699,      // <cjk>
-      0x8B4F,0xE698,      // <cjk>
-      0x8B56,0xE69B,      // <cjk>
-      0x8B58,0x8EAF,      // <cjk>
-      0x8B5A,0xE69D,      // <cjk>
-      0x8B5B,0xE69C,      // <cjk>
-      0x8B5C,0x9588,      // <cjk>
-      0x8B5F,0xE69F,      // <cjk>
-      0x8B66,0x8C78,      // <cjk>
-      0x8B6B,0xE69E,      // <cjk>
-      0x8B6C,0xE6A0,      // <cjk>
-      0x8B6F,0xE6A1,      // <cjk>
-      0x8B70,0x8B63,      // <cjk>
-      0x8B71,0xE3BF,      // <cjk>
-      0x8B72,0x8FF7,      // <cjk>
-      0x8B74,0xE6A2,      // <cjk>
-      0x8B77,0x8CEC,      // <cjk>
-      0x8B7D,0xE6A3,      // <cjk>
-      0x8B80,0xE6A4,      // <cjk>
-      0x8B83,0x8E5D,      // <cjk>
-      0x8B8A,0x9DCC,      // <cjk>
-      0x8B8C,0xE6A5,      // <cjk>
-      0x8B8E,0xE6A6,      // <cjk>
-      0x8B90,0x8F51,      // <cjk>
-      0x8B92,0xE6A7,      // <cjk>
-      0x8B93,0xE6A8,      // <cjk>
-      0x8B96,0xE6A9,      // <cjk>
-      0x8B99,0xE6AA,      // <cjk>
-      0x8B9A,0xE6AB,      // <cjk>
-      0x8C37,0x924A,      // <cjk>
-      0x8C3A,0xE6AC,      // <cjk>
-      0x8C3F,0xE6AE,      // <cjk>
-      0x8C41,0xE6AD,      // <cjk>
-      0x8C46,0x93A4,      // <cjk>
-      0x8C48,0xE6AF,      // <cjk>
-      0x8C4A,0x964C,      // <cjk>
-      0x8C4C,0xE6B0,      // <cjk>
-      0x8C4E,0xE6B1,      // <cjk>
-      0x8C50,0xE6B2,      // <cjk>
-      0x8C55,0xE6B3,      // <cjk>
-      0x8C5A,0x93D8,      // <cjk>
-      0x8C61,0x8FDB,      // <cjk>
-      0x8C62,0xE6B4,      // <cjk>
-      0x8C6A,0x8D8B,      // <cjk>
-      0x8C6B,0x98AC,      // <cjk>
-      0x8C6C,0xE6B5,      // <cjk>
-      0x8C78,0xE6B6,      // <cjk>
-      0x8C79,0x955E,      // <cjk>
-      0x8C7A,0xE6B7,      // <cjk>
-      0x8C7C,0xE6BF,      // <cjk>
-      0x8C82,0xE6B8,      // <cjk>
-      0x8C85,0xE6BA,      // <cjk>
-      0x8C89,0xE6B9,      // <cjk>
-      0x8C8A,0xE6BB,      // <cjk>
-      0x8C8C,0x9665,      // <cjk>
-      0x8C8D,0xE6BC,      // <cjk>
-      0x8C8E,0xE6BD,      // <cjk>
-      0x8C94,0xE6BE,      // <cjk>
-      0x8C98,0xE6C0,      // <cjk>
-      0x8C9D,0x8A4C,      // <cjk>
-      0x8C9E,0x92E5,      // <cjk>
-      0x8CA0,0x9589,      // <cjk>
-      0x8CA1,0x8DE0,      // <cjk>
-      0x8CA2,0x8D76,      // <cjk>
-      0x8CA7,0x956E,      // <cjk>
-      0x8CA8,0x89DD,      // <cjk>
-      0x8CA9,0x94CC,      // <cjk>
-      0x8CAA,0xE6C3,      // <cjk>
-      0x8CAB,0x8AD1,      // <cjk>
-      0x8CAC,0x90D3,      // <cjk>
-      0x8CAD,0xE6C2,      // <cjk>
-      0x8CAE,0xE6C7,      // <cjk>
-      0x8CAF,0x9299,      // <cjk>
-      0x8CB0,0x96E1,      // <cjk>
-      0x8CB2,0xE6C5,      // <cjk>
-      0x8CB3,0xE6C6,      // <cjk>
-      0x8CB4,0x8B4D,      // <cjk>
-      0x8CB6,0xE6C8,      // <cjk>
-      0x8CB7,0x9483,      // <cjk>
-      0x8CB8,0x91DD,      // <cjk>
-      0x8CBB,0x94EF,      // <cjk>
-      0x8CBC,0x935C,      // <cjk>
-      0x8CBD,0xE6C4,      // <cjk>
-      0x8CBF,0x9666,      // <cjk>
-      0x8CC0,0x89EA,      // <cjk>
-      0x8CC1,0xE6CA,      // <cjk>
-      0x8CC2,0x9847,      // <cjk>
-      0x8CC3,0x92C0,      // <cjk>
-      0x8CC4,0x9864,      // <cjk>
-      0x8CC7,0x8E91,      // <cjk>
-      0x8CC8,0xE6C9,      // <cjk>
-      0x8CCA,0x91AF,      // <cjk>
-      0x8CCD,0xE6DA,      // <cjk>
-      0x8CCE,0x9147,      // <cjk>
-      0x8CD1,0x93F6,      // <cjk>
-      0x8CD3,0x956F,      // <cjk>
-      0x8CDA,0xE6CD,      // <cjk>
-      0x8CDB,0x8E5E,      // <cjk>
-      0x8CDC,0x8E92,      // <cjk>
-      0x8CDE,0x8FDC,      // <cjk>
-      0x8CE0,0x9485,      // <cjk>
-      0x8CE2,0x8CAB,      // <cjk>
-      0x8CE3,0xE6CC,      // <cjk>
-      0x8CE4,0xE6CB,      // <cjk>
-      0x8CE6,0x958A,      // <cjk>
-      0x8CEA,0x8EBF,      // <cjk>
-      0x8CED,0x9371,      // <cjk>
-      0x8CFA,0xE6CF,      // <cjk>
-      0x8CFB,0xE6D0,      // <cjk>
-      0x8CFC,0x8D77,      // <cjk>
-      0x8CFD,0xE6CE,      // <cjk>
-      0x8D04,0xE6D1,      // <cjk>
-      0x8D05,0xE6D2,      // <cjk>
-      0x8D07,0xE6D4,      // <cjk>
-      0x8D08,0x91A1,      // <cjk>
-      0x8D0A,0xE6D3,      // <cjk>
-      0x8D0B,0x8AE4,      // <cjk>
-      0x8D0D,0xE6D6,      // <cjk>
-      0x8D0F,0xE6D5,      // <cjk>
-      0x8D10,0xE6D7,      // <cjk>
-      0x8D13,0xE6D9,      // <cjk>
-      0x8D14,0xE6DB,      // <cjk>
-      0x8D16,0xE6DC,      // <cjk>
-      0x8D64,0x90D4,      // <cjk>
-      0x8D66,0x8ECD,      // <cjk>
-      0x8D67,0xE6DD,      // <cjk>
-      0x8D6B,0x8A71,      // <cjk>
-      0x8D6D,0xE6DE,      // <cjk>
-      0x8D70,0x9196,      // <cjk>
-      0x8D71,0xE6DF,      // <cjk>
-      0x8D73,0xE6E0,      // <cjk>
-      0x8D74,0x958B,      // <cjk>
-      0x8D77,0x8B4E,      // <cjk>
-      0x8D81,0xE6E1,      // <cjk>
-      0x8D85,0x92B4,      // <cjk>
-      0x8D8A,0x897A,      // <cjk>
-      0x8D99,0xE6E2,      // <cjk>
-      0x8DA3,0x8EEF,      // <cjk>
-      0x8DA8,0x9096,      // <cjk>
-      0x8DB3,0x91AB,      // <cjk>
-      0x8DBA,0xE6E5,      // <cjk>
-      0x8DBE,0xE6E4,      // <cjk>
-      0x8DC2,0xE6E3,      // <cjk>
-      0x8DCB,0xE6EB,      // <cjk>
-      0x8DCC,0xE6E9,      // <cjk>
-      0x8DCF,0xE6E6,      // <cjk>
-      0x8DD6,0xE6E8,      // <cjk>
-      0x8DDA,0xE6E7,      // <cjk>
-      0x8DDB,0xE6EA,      // <cjk>
-      0x8DDD,0x8B97,      // <cjk>
-      0x8DDF,0xE6EE,      // <cjk>
-      0x8DE1,0x90D5,      // <cjk>
-      0x8DE3,0xE6EF,      // <cjk>
-      0x8DE8,0x8CD7,      // <cjk>
-      0x8DEA,0xE6EC,      // <cjk>
-      0x8DEB,0xE6ED,      // <cjk>
-      0x8DEF,0x9848,      // <cjk>
-      0x8DF3,0x92B5,      // <cjk>
-      0x8DF5,0x9148,      // <cjk>
-      0x8DFC,0xE6F0,      // <cjk>
-      0x8DFF,0xE6F3,      // <cjk>
-      0x8E08,0xE6F1,      // <cjk>
-      0x8E09,0xE6F2,      // <cjk>
-      0x8E0A,0x9778,      // <cjk>
-      0x8E0F,0x93A5,      // <cjk>
-      0x8E10,0xE6F6,      // <cjk>
-      0x8E1D,0xE6F4,      // <cjk>
-      0x8E1E,0xE6F5,      // <cjk>
-      0x8E1F,0xE6F7,      // <cjk>
-      0x8E2A,0xE748,      // <cjk>
-      0x8E30,0xE6FA,      // <cjk>
-      0x8E34,0xE6FB,      // <cjk>
-      0x8E35,0xE6F9,      // <cjk>
-      0x8E42,0xE6F8,      // <cjk>
-      0x8E44,0x92FB,      // <cjk>
-      0x8E47,0xE740,      // <cjk>
-      0x8E48,0xE744,      // <cjk>
-      0x8E49,0xE741,      // <cjk>
-      0x8E4A,0xE6FC,      // <cjk>
-      0x8E4C,0xE742,      // <cjk>
-      0x8E50,0xE743,      // <cjk>
-      0x8E55,0xE74A,      // <cjk>
-      0x8E59,0xE745,      // <cjk>
-      0x8E5F,0x90D6,      // <cjk>
-      0x8E60,0xE747,      // <cjk>
-      0x8E63,0xE749,      // <cjk>
-      0x8E64,0xE746,      // <cjk>
-      0x8E72,0xE74C,      // <cjk>
-      0x8E74,0x8F52,      // <cjk>
-      0x8E76,0xE74B,      // <cjk>
-      0x8E7C,0xE74D,      // <cjk>
-      0x8E81,0xE74E,      // <cjk>
-      0x8E84,0xE751,      // <cjk>
-      0x8E85,0xE750,      // <cjk>
-      0x8E87,0xE74F,      // <cjk>
-      0x8E8A,0xE753,      // <cjk>
-      0x8E8B,0xE752,      // <cjk>
-      0x8E8D,0x96F4,      // <cjk>
-      0x8E91,0xE755,      // <cjk>
-      0x8E93,0xE754,      // <cjk>
-      0x8E94,0xE756,      // <cjk>
-      0x8E99,0xE757,      // <cjk>
-      0x8EA1,0xE759,      // <cjk>
-      0x8EAA,0xE758,      // <cjk>
-      0x8EAB,0x9067,      // <cjk>
-      0x8EAC,0xE75A,      // <cjk>
-      0x8EAF,0x8BEB,      // <cjk>
-      0x8EB1,0xE75D,      // <cjk>
-      0x8EBE,0xE75E,      // <cjk>
-      0x8EC5,0xE75F,      // <cjk>
-      0x8EC6,0xE75C,      // <cjk>
-      0x8EC8,0xE760,      // <cjk>
-      0x8ECA,0x8ED4,      // <cjk>
-      0x8ECB,0xE761,      // <cjk>
-      0x8ECC,0x8B4F,      // <cjk>
-      0x8ECD,0x8C52,      // <cjk>
-      0x8ED2,0x8CAC,      // <cjk>
-      0x8EDB,0xE762,      // <cjk>
-      0x8EDF,0x93EE,      // <cjk>
-      0x8EE2,0x935D,      // <cjk>
-      0x8EE3,0xE763,      // <cjk>
-      0x8EEB,0xE766,      // <cjk>
-      0x8EF8,0x8EB2,      // <cjk>
-      0x8EFB,0xE765,      // <cjk>
-      0x8EFC,0xE764,      // <cjk>
-      0x8EFD,0x8C79,      // <cjk>
-      0x8EFE,0xE767,      // <cjk>
-      0x8F03,0x8A72,      // <cjk>
-      0x8F05,0xE769,      // <cjk>
-      0x8F09,0x8DDA,      // <cjk>
-      0x8F0A,0xE768,      // <cjk>
-      0x8F0C,0xE771,      // <cjk>
-      0x8F12,0xE76B,      // <cjk>
-      0x8F13,0xE76D,      // <cjk>
-      0x8F14,0x95E3,      // <cjk>
-      0x8F15,0xE76A,      // <cjk>
-      0x8F19,0xE76C,      // <cjk>
-      0x8F1B,0xE770,      // <cjk>
-      0x8F1C,0xE76E,      // <cjk>
-      0x8F1D,0x8B50,      // <cjk>
-      0x8F1F,0xE76F,      // <cjk>
-      0x8F26,0xE772,      // <cjk>
-      0x8F29,0x9479,      // <cjk>
-      0x8F2A,0x97D6,      // <cjk>
-      0x8F2F,0x8F53,      // <cjk>
-      0x8F33,0xE773,      // <cjk>
-      0x8F38,0x9741,      // <cjk>
-      0x8F39,0xE775,      // <cjk>
-      0x8F3B,0xE774,      // <cjk>
-      0x8F3E,0xE778,      // <cjk>
-      0x8F3F,0x9760,      // <cjk>
-      0x8F42,0xE777,      // <cjk>
-      0x8F44,0x8A8D,      // <cjk>
-      0x8F45,0xE776,      // <cjk>
-      0x8F46,0xE77B,      // <cjk>
-      0x8F49,0xE77A,      // <cjk>
-      0x8F4C,0xE779,      // <cjk>
-      0x8F4D,0x9351,      // <cjk>
-      0x8F4E,0xE77C,      // <cjk>
-      0x8F57,0xE77D,      // <cjk>
-      0x8F5C,0xE77E,      // <cjk>
-      0x8F5F,0x8D8C,      // <cjk>
-      0x8F61,0x8C44,      // <cjk>
-      0x8F62,0xE780,      // <cjk>
-      0x8F63,0xE781,      // <cjk>
-      0x8F64,0xE782,      // <cjk>
-      0x8F9B,0x9068,      // <cjk>
-      0x8F9C,0xE783,      // <cjk>
-      0x8F9E,0x8EAB,      // <cjk>
-      0x8F9F,0xE784,      // <cjk>
-      0x8FA3,0xE785,      // <cjk>
-      0x8FA7,0x999F,      // <cjk>
-      0x8FA8,0x999E,      // <cjk>
-      0x8FAD,0xE786,      // <cjk>
-      0x8FAE,0xE390,      // <cjk>
-      0x8FAF,0xE787,      // <cjk>
-      0x8FB0,0x9243,      // <cjk>
-      0x8FB1,0x904A,      // <cjk>
-      0x8FB2,0x945F,      // <cjk>
-      0x8FB7,0xE788,      // <cjk>
-      0x8FBA,0x95D3,      // <cjk>
-      0x8FBB,0x92D2,      // <cjk>
-      0x8FBC,0x8D9E,      // <cjk>
-      0x8FBF,0x9248,      // <cjk>
-      0x8FC2,0x8949,      // <cjk>
-      0x8FC4,0x9698,      // <cjk>
-      0x8FC5,0x9076,      // <cjk>
-      0x8FCE,0x8C7D,      // <cjk>
-      0x8FD1,0x8BDF,      // <cjk>
-      0x8FD4,0x95D4,      // <cjk>
-      0x8FDA,0xE789,      // <cjk>
-      0x8FE2,0xE78B,      // <cjk>
-      0x8FE5,0xE78A,      // <cjk>
-      0x8FE6,0x89DE,      // <cjk>
-      0x8FE9,0x93F4,      // <cjk>
-      0x8FEA,0xE78C,      // <cjk>
-      0x8FEB,0x9497,      // <cjk>
-      0x8FED,0x9352,      // <cjk>
-      0x8FEF,0xE78D,      // <cjk>
-      0x8FF0,0x8F71,      // <cjk>
-      0x8FF4,0xE78F,      // <cjk>
-      0x8FF7,0x96C0,      // <cjk>
-      0x8FF8,0xE79E,      // <cjk>
-      0x8FF9,0xE791,      // <cjk>
-      0x8FFA,0xE792,      // <cjk>
-      0x8FFD,0x92C7,      // <cjk>
-      0x9000,0x91DE,      // <cjk>
-      0x9001,0x9197,      // <cjk>
-      0x9003,0x93A6,      // <cjk>
-      0x9005,0xE790,      // <cjk>
-      0x9006,0x8B74,      // <cjk>
-      0x900B,0xE799,      // <cjk>
-      0x900D,0xE796,      // <cjk>
-      0x900E,0xE7A3,      // <cjk>
-      0x900F,0x93A7,      // <cjk>
-      0x9010,0x9280,      // <cjk>
-      0x9011,0xE793,      // <cjk>
-      0x9013,0x92FC,      // <cjk>
-      0x9014,0x9372,      // <cjk>
-      0x9015,0xE794,      // <cjk>
-      0x9016,0xE798,      // <cjk>
-      0x9017,0x9080,      // <cjk>
-      0x9019,0x9487,      // <cjk>
-      0x901A,0x92CA,      // <cjk>
-      0x901D,0x90C0,      // <cjk>
-      0x901E,0xE797,      // <cjk>
-      0x901F,0x91AC,      // <cjk>
-      0x9020,0x91A2,      // <cjk>
-      0x9021,0xE795,      // <cjk>
-      0x9022,0x88A7,      // <cjk>
-      0x9023,0x9841,      // <cjk>
-      0x9027,0xE79A,      // <cjk>
-      0x902E,0x91DF,      // <cjk>
-      0x9031,0x8F54,      // <cjk>
-      0x9032,0x9069,      // <cjk>
-      0x9035,0xE79C,      // <cjk>
-      0x9036,0xE79B,      // <cjk>
-      0x9038,0x88ED,      // <cjk>
-      0x9039,0xE79D,      // <cjk>
-      0x903C,0x954E,      // <cjk>
-      0x903E,0xE7A5,      // <cjk>
-      0x9041,0x93D9,      // <cjk>
-      0x9042,0x908B,      // <cjk>
-      0x9045,0x9278,      // <cjk>
-      0x9047,0x8BF6,      // <cjk>
-      0x9049,0xE7A4,      // <cjk>
-      0x904A,0x9756,      // <cjk>
-      0x904B,0x895E,      // <cjk>
-      0x904D,0x95D5,      // <cjk>
-      0x904E,0x89DF,      // <cjk>
-      0x904F,0xE79F,      // <cjk>
-      0x9050,0xE7A0,      // <cjk>
-      0x9051,0xE7A1,      // <cjk>
-      0x9052,0xE7A2,      // <cjk>
-      0x9053,0x93B9,      // <cjk>
-      0x9054,0x9242,      // <cjk>
-      0x9055,0x88E1,      // <cjk>
-      0x9056,0xE7A6,      // <cjk>
-      0x9058,0xE7A7,      // <cjk>
-      0x9059,0xEAA1,      // <cjk>
-      0x905C,0x91BB,      // <cjk>
-      0x905E,0xE7A8,      // <cjk>
-      0x9060,0x8993,      // <cjk>
-      0x9061,0x916B,      // <cjk>
-      0x9063,0x8CAD,      // <cjk>
-      0x9065,0x9779,      // <cjk>
-      0x9068,0xE7A9,      // <cjk>
-      0x9069,0x934B,      // <cjk>
-      0x906D,0x9198,      // <cjk>
-      0x906E,0x8ED5,      // <cjk>
-      0x906F,0xE7AA,      // <cjk>
-      0x9072,0xE7AD,      // <cjk>
-      0x9075,0x8F85,      // <cjk>
-      0x9076,0xE7AB,      // <cjk>
-      0x9077,0x914A,      // <cjk>
-      0x9078,0x9149,      // <cjk>
-      0x907A,0x88E2,      // <cjk>
-      0x907C,0x97C9,      // <cjk>
-      0x907D,0xE7AF,      // <cjk>
-      0x907F,0x94F0,      // <cjk>
-      0x9080,0xE7B1,      // <cjk>
-      0x9081,0xE7B0,      // <cjk>
-      0x9082,0xE7AE,      // <cjk>
-      0x9083,0xE284,      // <cjk>
-      0x9084,0x8AD2,      // <cjk>
-      0x9087,0xE78E,      // <cjk>
-      0x9089,0xE7B3,      // <cjk>
-      0x908A,0xE7B2,      // <cjk>
-      0x908F,0xE7B4,      // <cjk>
-      0x9091,0x9757,      // <cjk>
-      0x90A3,0x93DF,      // <cjk>
-      0x90A6,0x964D,      // <cjk>
-      0x90A8,0xE7B5,      // <cjk>
-      0x90AA,0x8ED7,      // <cjk>
-      0x90AF,0xE7B6,      // <cjk>
-      0x90B1,0xE7B7,      // <cjk>
-      0x90B5,0xE7B8,      // <cjk>
-      0x90B8,0x9340,      // <cjk>
-      0x90C1,0x88E8,      // <cjk>
-      0x90CA,0x8D78,      // <cjk>
-      0x90CE,0x9859,      // <cjk>
-      0x90DB,0xE7BC,      // <cjk>
-      0x90E1,0x8C53,      // <cjk>
-      0x90E2,0xE7B9,      // <cjk>
-      0x90E4,0xE7BA,      // <cjk>
-      0x90E8,0x9594,      // <cjk>
-      0x90ED,0x8A73,      // <cjk>
-      0x90F5,0x9758,      // <cjk>
-      0x90F7,0x8BBD,      // <cjk>
-      0x90FD,0x9373,      // <cjk>
-      0x9102,0xE7BD,      // <cjk>
-      0x9112,0xE7BE,      // <cjk>
-      0x9119,0xE7BF,      // <cjk>
-      0x912D,0x9341,      // <cjk>
-      0x9130,0xE7C1,      // <cjk>
-      0x9132,0xE7C0,      // <cjk>
-      0x9149,0x93D1,      // <cjk>
-      0x914A,0xE7C2,      // <cjk>
-      0x914B,0x8F55,      // <cjk>
-      0x914C,0x8EDE,      // <cjk>
-      0x914D,0x947A,      // <cjk>
-      0x914E,0x9291,      // <cjk>
-      0x9152,0x8EF0,      // <cjk>
-      0x9154,0x908C,      // <cjk>
-      0x9156,0xE7C3,      // <cjk>
-      0x9158,0xE7C4,      // <cjk>
-      0x9162,0x907C,      // <cjk>
-      0x9163,0xE7C5,      // <cjk>
-      0x9165,0xE7C6,      // <cjk>
-      0x9169,0xE7C7,      // <cjk>
-      0x916A,0x978F,      // <cjk>
-      0x916C,0x8F56,      // <cjk>
-      0x9172,0xE7C9,      // <cjk>
-      0x9173,0xE7C8,      // <cjk>
-      0x9175,0x8D79,      // <cjk>
-      0x9177,0x8D93,      // <cjk>
-      0x9178,0x8E5F,      // <cjk>
-      0x9182,0xE7CC,      // <cjk>
-      0x9187,0x8F86,      // <cjk>
-      0x9189,0xE7CB,      // <cjk>
-      0x918B,0xE7CA,      // <cjk>
-      0x918D,0x91E7,      // <cjk>
-      0x9190,0x8CED,      // <cjk>
-      0x9192,0x90C1,      // <cjk>
-      0x9197,0x94AE,      // <cjk>
-      0x919C,0x8F58,      // <cjk>
-      0x91A2,0xE7CD,      // <cjk>
-      0x91A4,0x8FDD,      // <cjk>
-      0x91AA,0xE7D0,      // <cjk>
-      0x91AB,0xE7CE,      // <cjk>
-      0x91AF,0xE7CF,      // <cjk>
-      0x91B4,0xE7D2,      // <cjk>
-      0x91B5,0xE7D1,      // <cjk>
-      0x91B8,0x8FF8,      // <cjk>
-      0x91BA,0xE7D3,      // <cjk>
-      0x91C0,0xE7D4,      // <cjk>
-      0x91C1,0xE7D5,      // <cjk>
-      0x91C6,0x94CE,      // <cjk>
-      0x91C7,0x8DD1,      // <cjk>
-      0x91C8,0x8EDF,      // <cjk>
-      0x91C9,0xE7D6,      // <cjk>
-      0x91CB,0xE7D7,      // <cjk>
-      0x91CC,0x97A2,      // <cjk>
-      0x91CD,0x8F64,      // <cjk>
-      0x91CE,0x96EC,      // <cjk>
-      0x91CF,0x97CA,      // <cjk>
-      0x91D0,0xE7D8,      // <cjk>
-      0x91D1,0x8BE0,      // <cjk>
-      0x91D6,0xE7D9,      // <cjk>
-      0x91D8,0x9342,      // <cjk>
-      0x91DB,0xE7DC,      // <cjk>
-      0x91DC,0x8A98,      // <cjk>
-      0x91DD,0x906A,      // <cjk>
-      0x91DF,0xE7DA,      // <cjk>
-      0x91E1,0xE7DB,      // <cjk>
-      0x91E3,0x92DE,      // <cjk>
-      0x91E6,0x9674,      // <cjk>
-      0x91E7,0x8BFA,      // <cjk>
-      0x91F5,0xE7DE,      // <cjk>
-      0x91F6,0xE7DF,      // <cjk>
-      0x91FC,0xE7DD,      // <cjk>
-      0x91FF,0xE7E1,      // <cjk>
-      0x920D,0x93DD,      // <cjk>
-      0x920E,0x8A62,      // <cjk>
-      0x9211,0xE7E5,      // <cjk>
-      0x9214,0xE7E2,      // <cjk>
-      0x9215,0xE7E4,      // <cjk>
-      0x921E,0xE7E0,      // <cjk>
-      0x9229,0xE86E,      // <cjk>
-      0x922C,0xE7E3,      // <cjk>
-      0x9234,0x97E9,      // <cjk>
-      0x9237,0x8CD8,      // <cjk>
-      0x923F,0xE7ED,      // <cjk>
-      0x9244,0x9353,      // <cjk>
-      0x9245,0xE7E8,      // <cjk>
-      0x9248,0xE7EB,      // <cjk>
-      0x9249,0xE7E9,      // <cjk>
-      0x924B,0xE7EE,      // <cjk>
-      0x9250,0xE7EF,      // <cjk>
-      0x9257,0xE7E7,      // <cjk>
-      0x925A,0xE7F4,      // <cjk>
-      0x925B,0x8994,      // <cjk>
-      0x925E,0xE7E6,      // <cjk>
-      0x9262,0x94AB,      // <cjk>
-      0x9264,0xE7EA,      // <cjk>
-      0x9266,0x8FDE,      // <cjk>
-      0x9271,0x8D7A,      // <cjk>
-      0x927E,0x9667,      // <cjk>
-      0x9280,0x8BE2,      // <cjk>
-      0x9283,0x8F65,      // <cjk>
-      0x9285,0x93BA,      // <cjk>
-      0x9291,0x914C,      // <cjk>
-      0x9293,0xE7F2,      // <cjk>
-      0x9295,0xE7EC,      // <cjk>
-      0x9296,0xE7F1,      // <cjk>
-      0x9298,0x96C1,      // <cjk>
-      0x929A,0x92B6,      // <cjk>
-      0x929B,0xE7F3,      // <cjk>
-      0x929C,0xE7F0,      // <cjk>
-      0x92AD,0x914B,      // <cjk>
-      0x92B7,0xE7F7,      // <cjk>
-      0x92B9,0xE7F6,      // <cjk>
-      0x92CF,0xE7F5,      // <cjk>
-      0x92D2,0x964E,      // <cjk>
-      0x92E4,0x8F9B,      // <cjk>
-      0x92E9,0xE7F8,      // <cjk>
-      0x92EA,0x95DD,      // <cjk>
-      0x92ED,0x8973,      // <cjk>
-      0x92F2,0x9565,      // <cjk>
-      0x92F3,0x9292,      // <cjk>
-      0x92F8,0x8B98,      // <cjk>
-      0x92FA,0xE7FA,      // <cjk>
-      0x92FC,0x8D7C,      // <cjk>
-      0x9306,0x8E4B,      // <cjk>
-      0x930F,0xE7F9,      // <cjk>
-      0x9310,0x908D,      // <cjk>
-      0x9318,0x908E,      // <cjk>
-      0x9319,0xE840,      // <cjk>
-      0x931A,0xE842,      // <cjk>
-      0x9320,0x8FF9,      // <cjk>
-      0x9322,0xE841,      // <cjk>
-      0x9323,0xE843,      // <cjk>
-      0x9326,0x8BD1,      // <cjk>
-      0x9328,0x9564,      // <cjk>
-      0x932B,0x8EE0,      // <cjk>
-      0x932C,0x9842,      // <cjk>
-      0x932E,0xE7FC,      // <cjk>
-      0x932F,0x8DF6,      // <cjk>
-      0x9332,0x985E,      // <cjk>
-      0x9335,0xE845,      // <cjk>
-      0x933A,0xE844,      // <cjk>
-      0x933B,0xE846,      // <cjk>
-      0x9344,0xE7FB,      // <cjk>
-      0x934B,0x93E7,      // <cjk>
-      0x934D,0x9374,      // <cjk>
-      0x9354,0x92D5,      // <cjk>
-      0x9356,0xE84B,      // <cjk>
-      0x935B,0x9262,      // <cjk>
-      0x935C,0xE847,      // <cjk>
-      0x9360,0xE848,      // <cjk>
-      0x936C,0x8C4C,      // <cjk>
-      0x936E,0xE84A,      // <cjk>
-      0x9375,0x8CAE,      // <cjk>
-      0x937C,0xE849,      // <cjk>
-      0x937E,0x8FDF,      // <cjk>
-      0x938C,0x8A99,      // <cjk>
-      0x9394,0xE84F,      // <cjk>
-      0x9396,0x8DBD,      // <cjk>
-      0x9397,0x9199,      // <cjk>
-      0x939A,0x92C8,      // <cjk>
-      0x93A7,0x8A5A,      // <cjk>
-      0x93AC,0xE84D,      // <cjk>
-      0x93AD,0xE84E,      // <cjk>
-      0x93AE,0x92C1,      // <cjk>
-      0x93B0,0xE84C,      // <cjk>
-      0x93B9,0xE850,      // <cjk>
-      0x93C3,0xE856,      // <cjk>
-      0x93C8,0xE859,      // <cjk>
-      0x93D0,0xE858,      // <cjk>
-      0x93D1,0x934C,      // <cjk>
-      0x93D6,0xE851,      // <cjk>
-      0x93D7,0xE852,      // <cjk>
-      0x93D8,0xE855,      // <cjk>
-      0x93DD,0xE857,      // <cjk>
-      0x93E1,0x8BBE,      // <cjk>
-      0x93E4,0xE85A,      // <cjk>
-      0x93E5,0xE854,      // <cjk>
-      0x93E8,0xE853,      // <cjk>
-      0x9403,0xE85E,      // <cjk>
-      0x9407,0xE85F,      // <cjk>
-      0x9410,0xE860,      // <cjk>
-      0x9413,0xE85D,      // <cjk>
-      0x9414,0xE85C,      // <cjk>
-      0x9418,0x8FE0,      // <cjk>
-      0x9419,0x93A8,      // <cjk>
-      0x9421,0xE864,      // <cjk>
-      0x942B,0xE862,      // <cjk>
-      0x9435,0xE863,      // <cjk>
-      0x9436,0xE861,      // <cjk>
-      0x9438,0x91F6,      // <cjk>
-      0x943A,0xE865,      // <cjk>
-      0x9441,0xE866,      // <cjk>
-      0x9444,0xE868,      // <cjk>
-      0x9451,0x8AD3,      // <cjk>
-      0x9452,0xE867,      // <cjk>
-      0x9453,0x96F8,      // <cjk>
-      0x945A,0xE873,      // <cjk>
-      0x945B,0xE869,      // <cjk>
-      0x945E,0xE86C,      // <cjk>
-      0x9460,0xE86A,      // <cjk>
-      0x9462,0xE86B,      // <cjk>
-      0x946A,0xE86D,      // <cjk>
-      0x9470,0xE86F,      // <cjk>
-      0x9475,0xE870,      // <cjk>
-      0x9477,0xE871,      // <cjk>
-      0x947C,0xE874,      // <cjk>
-      0x947D,0xE872,      // <cjk>
-      0x947E,0xE875,      // <cjk>
-      0x947F,0xE877,      // <cjk>
-      0x9481,0xE876,      // <cjk>
-      0x9577,0x92B7,      // <cjk>
-      0x9580,0x96E5,      // <cjk>
-      0x9582,0xE878,      // <cjk>
-      0x9583,0x914D,      // <cjk>
-      0x9587,0xE879,      // <cjk>
-      0x9589,0x95C2,      // <cjk>
-      0x958A,0xE87A,      // <cjk>
-      0x958B,0x8A4A,      // <cjk>
-      0x9591,0x8AD5,      // <cjk>
-      0x9593,0x8AD4,      // <cjk>
-      0x9594,0xE87B,      // <cjk>
-      0x9596,0xE87C,      // <cjk>
-      0x9598,0xE87D,      // <cjk>
-      0x9599,0xE87E,      // <cjk>
-      0x95A0,0xE880,      // <cjk>
-      0x95A2,0x8AD6,      // <cjk>
-      0x95A3,0x8A74,      // <cjk>
-      0x95A4,0x8D7D,      // <cjk>
-      0x95A5,0x94B4,      // <cjk>
-      0x95A7,0xE882,      // <cjk>
-      0x95A8,0xE881,      // <cjk>
-      0x95AD,0xE883,      // <cjk>
-      0x95B2,0x897B,      // <cjk>
-      0x95B9,0xE886,      // <cjk>
-      0x95BB,0xE885,      // <cjk>
-      0x95BC,0xE884,      // <cjk>
-      0x95BE,0xE887,      // <cjk>
-      0x95C3,0xE88A,      // <cjk>
-      0x95C7,0x88C5,      // <cjk>
-      0x95CA,0xE888,      // <cjk>
-      0x95CC,0xE88C,      // <cjk>
-      0x95CD,0xE88B,      // <cjk>
-      0x95D4,0xE88E,      // <cjk>
-      0x95D5,0xE88D,      // <cjk>
-      0x95D6,0xE88F,      // <cjk>
-      0x95D8,0x93AC,      // <cjk>
-      0x95DC,0xE890,      // <cjk>
-      0x95E1,0xE891,      // <cjk>
-      0x95E2,0xE893,      // <cjk>
-      0x95E5,0xE892,      // <cjk>
-      0x961C,0x958C,      // <cjk>
-      0x9621,0xE894,      // <cjk>
-      0x9628,0xE895,      // <cjk>
-      0x962A,0x8DE3,      // <cjk>
-      0x962E,0xE896,      // <cjk>
-      0x962F,0xE897,      // <cjk>
-      0x9632,0x9668,      // <cjk>
-      0x963B,0x916A,      // <cjk>
-      0x963F,0x88A2,      // <cjk>
-      0x9640,0x91C9,      // <cjk>
-      0x9642,0xE898,      // <cjk>
-      0x9644,0x958D,      // <cjk>
-      0x964B,0xE89B,      // <cjk>
-      0x964C,0xE899,      // <cjk>
-      0x964D,0x8D7E,      // <cjk>
-      0x964F,0xE89A,      // <cjk>
-      0x9650,0x8CC0,      // <cjk>
-      0x965B,0x95C3,      // <cjk>
-      0x965C,0xE89D,      // <cjk>
-      0x965D,0xE89F,      // <cjk>
-      0x965E,0xE89E,      // <cjk>
-      0x965F,0xE8A0,      // <cjk>
-      0x9662,0x8940,      // <cjk>
-      0x9663,0x9077,      // <cjk>
-      0x9664,0x8F9C,      // <cjk>
-      0x9665,0x8AD7,      // <cjk>
-      0x9666,0xE8A1,      // <cjk>
-      0x966A,0x9486,      // <cjk>
-      0x966C,0xE8A3,      // <cjk>
-      0x9670,0x8941,      // <cjk>
-      0x9672,0xE8A2,      // <cjk>
-      0x9673,0x92C2,      // <cjk>
-      0x9675,0x97CB,      // <cjk>
-      0x9676,0x93A9,      // <cjk>
-      0x9677,0xE89C,      // <cjk>
-      0x9678,0x97A4,      // <cjk>
-      0x967A,0x8CAF,      // <cjk>
-      0x967D,0x977A,      // <cjk>
-      0x9685,0x8BF7,      // <cjk>
-      0x9686,0x97B2,      // <cjk>
-      0x9688,0x8C47,      // <cjk>
-      0x968A,0x91E0,      // <cjk>
-      0x968B,0xE440,      // <cjk>
-      0x968D,0xE8A4,      // <cjk>
-      0x968E,0x8A4B,      // <cjk>
-      0x968F,0x908F,      // <cjk>
-      0x9694,0x8A75,      // <cjk>
-      0x9695,0xE8A6,      // <cjk>
-      0x9697,0xE8A7,      // <cjk>
-      0x9698,0xE8A5,      // <cjk>
-      0x9699,0x8C84,      // <cjk>
-      0x969B,0x8DDB,      // <cjk>
-      0x969C,0x8FE1,      // <cjk>
-      0x96A0,0x8942,      // <cjk>
-      0x96A3,0x97D7,      // <cjk>
-      0x96A7,0xE8A9,      // <cjk>
-      0x96A8,0xE7AC,      // <cjk>
-      0x96AA,0xE8A8,      // <cjk>
-      0x96B0,0xE8AC,      // <cjk>
-      0x96B1,0xE8AA,      // <cjk>
-      0x96B2,0xE8AB,      // <cjk>
-      0x96B4,0xE8AD,      // <cjk>
-      0x96B6,0xE8AE,      // <cjk>
-      0x96B7,0x97EA,      // <cjk>
-      0x96B8,0xE8AF,      // <cjk>
-      0x96B9,0xE8B0,      // <cjk>
-      0x96BB,0x90C7,      // <cjk>
-      0x96BC,0x94B9,      // <cjk>
-      0x96C0,0x909D,      // <cjk>
-      0x96C1,0x8AE5,      // <cjk>
-      0x96C4,0x9759,      // <cjk>
-      0x96C5,0x89EB,      // <cjk>
-      0x96C6,0x8F57,      // <cjk>
-      0x96C7,0x8CD9,      // <cjk>
-      0x96C9,0xE8B3,      // <cjk>
-      0x96CB,0xE8B2,      // <cjk>
-      0x96CC,0x8E93,      // <cjk>
-      0x96CD,0xE8B4,      // <cjk>
-      0x96CE,0xE8B1,      // <cjk>
-      0x96D1,0x8E47,      // <cjk>
-      0x96D5,0xE8B8,      // <cjk>
-      0x96D6,0xE5AB,      // <cjk>
-      0x96D9,0x99D4,      // <cjk>
-      0x96DB,0x9097,      // <cjk>
-      0x96DC,0xE8B6,      // <cjk>
-      0x96E2,0x97A3,      // <cjk>
-      0x96E3,0x93EF,      // <cjk>
-      0x96E8,0x894A,      // <cjk>
-      0x96EA,0x90E1,      // <cjk>
-      0x96EB,0x8EB4,      // <cjk>
-      0x96F0,0x95B5,      // <cjk>
-      0x96F2,0x895F,      // <cjk>
-      0x96F6,0x97EB,      // <cjk>
-      0x96F7,0x978B,      // <cjk>
-      0x96F9,0xE8B9,      // <cjk>
-      0x96FB,0x9364,      // <cjk>
-      0x9700,0x8EF9,      // <cjk>
-      0x9704,0xE8BA,      // <cjk>
-      0x9706,0xE8BB,      // <cjk>
-      0x9707,0x906B,      // <cjk>
-      0x9708,0xE8BC,      // <cjk>
-      0x970A,0x97EC,      // <cjk>
-      0x970D,0xE8B7,      // <cjk>
-      0x970E,0xE8BE,      // <cjk>
-      0x970F,0xE8C0,      // <cjk>
-      0x9711,0xE8BF,      // <cjk>
-      0x9713,0xE8BD,      // <cjk>
-      0x9716,0xE8C1,      // <cjk>
-      0x9719,0xE8C2,      // <cjk>
-      0x971C,0x919A,      // <cjk>
-      0x971E,0x89E0,      // <cjk>
-      0x9724,0xE8C3,      // <cjk>
-      0x9727,0x96B6,      // <cjk>
-      0x972A,0xE8C4,      // <cjk>
-      0x9730,0xE8C5,      // <cjk>
-      0x9732,0x9849,      // <cjk>
-      0x9738,0x9E50,      // <cjk>
-      0x9739,0xE8C6,      // <cjk>
-      0x973D,0xE8C7,      // <cjk>
-      0x973E,0xE8C8,      // <cjk>
-      0x9742,0xE8CC,      // <cjk>
-      0x9744,0xE8C9,      // <cjk>
-      0x9746,0xE8CA,      // <cjk>
-      0x9748,0xE8CB,      // <cjk>
-      0x9749,0xE8CD,      // <cjk>
-      0x9752,0x90C2,      // <cjk>
-      0x9756,0x96F5,      // <cjk>
-      0x9759,0x90C3,      // <cjk>
-      0x975C,0xE8CE,      // <cjk>
-      0x975E,0x94F1,      // <cjk>
-      0x9760,0xE8CF,      // <cjk>
-      0x9761,0xEA72,      // <cjk>
-      0x9762,0x96CA,      // <cjk>
-      0x9764,0xE8D0,      // <cjk>
-      0x9766,0xE8D1,      // <cjk>
-      0x9768,0xE8D2,      // <cjk>
-      0x9769,0x8A76,      // <cjk>
-      0x976B,0xE8D4,      // <cjk>
-      0x976D,0x9078,      // <cjk>
-      0x9771,0xE8D5,      // <cjk>
-      0x9774,0x8C43,      // <cjk>
-      0x9779,0xE8D6,      // <cjk>
-      0x977A,0xE8DA,      // <cjk>
-      0x977C,0xE8D8,      // <cjk>
-      0x9781,0xE8D9,      // <cjk>
-      0x9784,0x8A93,      // <cjk>
-      0x9785,0xE8D7,      // <cjk>
-      0x9786,0xE8DB,      // <cjk>
-      0x978B,0xE8DC,      // <cjk>
-      0x978D,0x88C6,      // <cjk>
-      0x978F,0xE8DD,      // <cjk>
-      0x9790,0xE8DE,      // <cjk>
-      0x9798,0x8FE2,      // <cjk>
-      0x979C,0xE8DF,      // <cjk>
-      0x97A0,0x8B66,      // <cjk>
-      0x97A3,0xE8E2,      // <cjk>
-      0x97A6,0xE8E1,      // <cjk>
-      0x97A8,0xE8E0,      // <cjk>
-      0x97AB,0xE691,      // <cjk>
-      0x97AD,0x95DA,      // <cjk>
-      0x97B3,0xE8E3,      // <cjk>
-      0x97B4,0xE8E4,      // <cjk>
-      0x97C3,0xE8E5,      // <cjk>
-      0x97C6,0xE8E6,      // <cjk>
-      0x97C8,0xE8E7,      // <cjk>
-      0x97CB,0xE8E8,      // <cjk>
-      0x97D3,0x8AD8,      // <cjk>
-      0x97DC,0xE8E9,      // <cjk>
-      0x97ED,0xE8EA,      // <cjk>
-      0x97EE,0x9442,      // <cjk>
-      0x97F2,0xE8EC,      // <cjk>
-      0x97F3,0x89B9,      // <cjk>
-      0x97F5,0xE8EF,      // <cjk>
-      0x97F6,0xE8EE,      // <cjk>
-      0x97FB,0x8943,      // <cjk>
-      0x97FF,0x8BBF,      // <cjk>
-      0x9801,0x95C5,      // <cjk>
-      0x9802,0x92B8,      // <cjk>
-      0x9803,0x8DA0,      // <cjk>
-      0x9805,0x8D80,      // <cjk>
-      0x9806,0x8F87,      // <cjk>
-      0x9808,0x907B,      // <cjk>
-      0x980C,0xE8F1,      // <cjk>
-      0x980F,0xE8F0,      // <cjk>
-      0x9810,0x9761,      // <cjk>
-      0x9811,0x8AE6,      // <cjk>
-      0x9812,0x94D0,      // <cjk>
-      0x9813,0x93DA,      // <cjk>
-      0x9817,0x909C,      // <cjk>
-      0x9818,0x97CC,      // <cjk>
-      0x981A,0x8C7A,      // <cjk>
-      0x9821,0xE8F4,      // <cjk>
-      0x9824,0xE8F3,      // <cjk>
-      0x982C,0x966A,      // <cjk>
-      0x982D,0x93AA,      // <cjk>
-      0x9834,0x896F,      // <cjk>
-      0x9837,0xE8F5,      // <cjk>
-      0x9838,0xE8F2,      // <cjk>
-      0x983B,0x9570,      // <cjk>
-      0x983C,0x978A,      // <cjk>
-      0x983D,0xE8F6,      // <cjk>
-      0x9846,0xE8F7,      // <cjk>
-      0x984B,0xE8F9,      // <cjk>
-      0x984C,0x91E8,      // <cjk>
-      0x984D,0x8A7A,      // <cjk>
-      0x984E,0x8A7B,      // <cjk>
-      0x984F,0xE8F8,      // <cjk>
-      0x9854,0x8AE7,      // <cjk>
-      0x9855,0x8CB0,      // <cjk>
-      0x9858,0x8AE8,      // <cjk>
-      0x985B,0x935E,      // <cjk>
-      0x985E,0x97DE,      // <cjk>
-      0x9867,0x8CDA,      // <cjk>
-      0x986B,0xE8FA,      // <cjk>
-      0x986F,0xE8FB,      // <cjk>
-      0x9870,0xE8FC,      // <cjk>
-      0x9871,0xE940,      // <cjk>
-      0x9873,0xE942,      // <cjk>
-      0x9874,0xE941,      // <cjk>
-      0x98A8,0x9597,      // <cjk>
-      0x98AA,0xE943,      // <cjk>
-      0x98AF,0xE944,      // <cjk>
-      0x98B1,0xE945,      // <cjk>
-      0x98B6,0xE946,      // <cjk>
-      0x98C3,0xE948,      // <cjk>
-      0x98C4,0xE947,      // <cjk>
-      0x98C6,0xE949,      // <cjk>
-      0x98DB,0x94F2,      // <cjk>
-      0x98DC,0xE3CA,      // <cjk>
-      0x98DF,0x9048,      // <cjk>
-      0x98E2,0x8B51,      // <cjk>
-      0x98E9,0xE94A,      // <cjk>
-      0x98EB,0xE94B,      // <cjk>
-      0x98ED,0x99AA,      // <cjk>
-      0x98EE,0x9F5A,      // <cjk>
-      0x98EF,0x94D1,      // <cjk>
-      0x98F2,0x88F9,      // <cjk>
-      0x98F4,0x88B9,      // <cjk>
-      0x98FC,0x8E94,      // <cjk>
-      0x98FD,0x964F,      // <cjk>
-      0x98FE,0x8FFC,      // <cjk>
-      0x9903,0xE94C,      // <cjk>
-      0x9905,0x96DD,      // <cjk>
-      0x9909,0xE94D,      // <cjk>
-      0x990A,0x977B,      // <cjk>
-      0x990C,0x8961,      // <cjk>
-      0x9910,0x8E60,      // <cjk>
-      0x9912,0xE94E,      // <cjk>
-      0x9913,0x89EC,      // <cjk>
-      0x9914,0xE94F,      // <cjk>
-      0x9918,0xE950,      // <cjk>
-      0x991D,0xE952,      // <cjk>
-      0x991E,0xE953,      // <cjk>
-      0x9920,0xE955,      // <cjk>
-      0x9921,0xE951,      // <cjk>
-      0x9924,0xE954,      // <cjk>
-      0x9928,0x8AD9,      // <cjk>
-      0x992C,0xE956,      // <cjk>
-      0x992E,0xE957,      // <cjk>
-      0x993D,0xE958,      // <cjk>
-      0x993E,0xE959,      // <cjk>
-      0x9942,0xE95A,      // <cjk>
-      0x9945,0xE95C,      // <cjk>
-      0x994B,0xE95E,      // <cjk>
-      0x994C,0xE961,      // <cjk>
-      0x9950,0xE95D,      // <cjk>
-      0x9951,0xE95F,      // <cjk>
-      0x9952,0xE960,      // <cjk>
-      0x9955,0xE962,      // <cjk>
-      0x9957,0x8BC0,      // <cjk>
-      0x9996,0x8EF1,      // <cjk>
-      0x9997,0xE963,      // <cjk>
-      0x9998,0xE964,      // <cjk>
-      0x9999,0x8D81,      // <cjk>
-      0x99A5,0xE965,      // <cjk>
-      0x99A8,0x8A5D,      // <cjk>
-      0x99AC,0x946E,      // <cjk>
-      0x99AD,0xE966,      // <cjk>
-      0x99AE,0xE967,      // <cjk>
-      0x99B3,0x9279,      // <cjk>
-      0x99B4,0x93E9,      // <cjk>
-      0x99BC,0xE968,      // <cjk>
-      0x99C1,0x949D,      // <cjk>
-      0x99C4,0x91CA,      // <cjk>
-      0x99C5,0x8977,      // <cjk>
-      0x99C6,0x8BEC,      // <cjk>
-      0x99C8,0x8BED,      // <cjk>
-      0x99D0,0x9293,      // <cjk>
-      0x99D1,0xE96D,      // <cjk>
-      0x99D2,0x8BEE,      // <cjk>
-      0x99D5,0x89ED,      // <cjk>
-      0x99D8,0xE96C,      // <cjk>
-      0x99DB,0xE96A,      // <cjk>
-      0x99DD,0xE96B,      // <cjk>
-      0x99DF,0xE969,      // <cjk>
-      0x99E2,0xE977,      // <cjk>
-      0x99ED,0xE96E,      // <cjk>
-      0x99EE,0xE96F,      // <cjk>
-      0x99F1,0xE970,      // <cjk>
-      0x99F2,0xE971,      // <cjk>
-      0x99F8,0xE973,      // <cjk>
-      0x99FB,0xE972,      // <cjk>
-      0x99FF,0x8F78,      // <cjk>
-      0x9A01,0xE974,      // <cjk>
-      0x9A05,0xE976,      // <cjk>
-      0x9A0E,0x8B52,      // <cjk>
-      0x9A0F,0xE975,      // <cjk>
-      0x9A12,0x919B,      // <cjk>
-      0x9A13,0x8CB1,      // <cjk>
-      0x9A19,0xE978,      // <cjk>
-      0x9A28,0x91CB,      // <cjk>
-      0x9A2B,0xE979,      // <cjk>
-      0x9A30,0x93AB,      // <cjk>
-      0x9A37,0xE97A,      // <cjk>
-      0x9A3E,0xE980,      // <cjk>
-      0x9A40,0xE97D,      // <cjk>
-      0x9A42,0xE97C,      // <cjk>
-      0x9A43,0xE97E,      // <cjk>
-      0x9A45,0xE97B,      // <cjk>
-      0x9A4D,0xE982,      // <cjk>
-      0x9A55,0xE981,      // <cjk>
-      0x9A57,0xE984,      // <cjk>
-      0x9A5A,0x8BC1,      // <cjk>
-      0x9A5B,0xE983,      // <cjk>
-      0x9A5F,0xE985,      // <cjk>
-      0x9A62,0xE986,      // <cjk>
-      0x9A64,0xE988,      // <cjk>
-      0x9A65,0xE987,      // <cjk>
-      0x9A69,0xE989,      // <cjk>
-      0x9A6A,0xE98B,      // <cjk>
-      0x9A6B,0xE98A,      // <cjk>
-      0x9AA8,0x8D9C,      // <cjk>
-      0x9AAD,0xE98C,      // <cjk>
-      0x9AB0,0xE98D,      // <cjk>
-      0x9ABC,0xE98E,      // <cjk>
-      0x9AC0,0xE98F,      // <cjk>
-      0x9AC4,0x9091,      // <cjk>
-      0x9ACF,0xE990,      // <cjk>
-      0x9AD1,0xE991,      // <cjk>
-      0x9AD3,0xE992,      // <cjk>
-      0x9AD4,0xE993,      // <cjk>
-      0x9AD8,0x8D82,      // <cjk>
-      0x9ADE,0xE994,      // <cjk>
-      0x9ADF,0xE995,      // <cjk>
-      0x9AE2,0xE996,      // <cjk>
-      0x9AE3,0xE997,      // <cjk>
-      0x9AE6,0xE998,      // <cjk>
-      0x9AEA,0x94AF,      // <cjk>
-      0x9AEB,0xE99A,      // <cjk>
-      0x9AED,0x9545,      // <cjk>
-      0x9AEE,0xE99B,      // <cjk>
-      0x9AEF,0xE999,      // <cjk>
-      0x9AF1,0xE99D,      // <cjk>
-      0x9AF4,0xE99C,      // <cjk>
-      0x9AF7,0xE99E,      // <cjk>
-      0x9AFB,0xE99F,      // <cjk>
-      0x9B06,0xE9A0,      // <cjk>
-      0x9B18,0xE9A1,      // <cjk>
-      0x9B1A,0xE9A2,      // <cjk>
-      0x9B1F,0xE9A3,      // <cjk>
-      0x9B22,0xE9A4,      // <cjk>
-      0x9B23,0xE9A5,      // <cjk>
-      0x9B25,0xE9A6,      // <cjk>
-      0x9B27,0xE9A7,      // <cjk>
-      0x9B28,0xE9A8,      // <cjk>
-      0x9B29,0xE9A9,      // <cjk>
-      0x9B2A,0xE9AA,      // <cjk>
-      0x9B2E,0xE9AB,      // <cjk>
-      0x9B2F,0xE9AC,      // <cjk>
-      0x9B31,0x9F54,      // <cjk>
-      0x9B32,0xE9AD,      // <cjk>
-      0x9B3B,0xE2F6,      // <cjk>
-      0x9B3C,0x8B53,      // <cjk>
-      0x9B41,0x8A40,      // <cjk>
-      0x9B42,0x8DB0,      // <cjk>
-      0x9B43,0xE9AF,      // <cjk>
-      0x9B44,0xE9AE,      // <cjk>
-      0x9B45,0x96A3,      // <cjk>
-      0x9B4D,0xE9B1,      // <cjk>
-      0x9B4E,0xE9B2,      // <cjk>
-      0x9B4F,0xE9B0,      // <cjk>
-      0x9B51,0xE9B3,      // <cjk>
-      0x9B54,0x9682,      // <cjk>
-      0x9B58,0xE9B4,      // <cjk>
-      0x9B5A,0x8B9B,      // <cjk>
-      0x9B6F,0x9844,      // <cjk>
-      0x9B74,0xE9B5,      // <cjk>
-      0x9B83,0xE9B7,      // <cjk>
-      0x9B8E,0x88BC,      // <cjk>
-      0x9B91,0xE9B8,      // <cjk>
-      0x9B92,0x95A9,      // <cjk>
-      0x9B93,0xE9B6,      // <cjk>
-      0x9B96,0xE9B9,      // <cjk>
-      0x9B97,0xE9BA,      // <cjk>
-      0x9B9F,0xE9BB,      // <cjk>
-      0x9BA0,0xE9BC,      // <cjk>
-      0x9BA8,0xE9BD,      // <cjk>
-      0x9BAA,0x968E,      // <cjk>
-      0x9BAB,0x8E4C,      // <cjk>
-      0x9BAD,0x8DF8,      // <cjk>
-      0x9BAE,0x914E,      // <cjk>
-      0x9BB4,0xE9BE,      // <cjk>
-      0x9BB9,0xE9C1,      // <cjk>
-      0x9BC0,0xE9BF,      // <cjk>
-      0x9BC6,0xE9C2,      // <cjk>
-      0x9BC9,0x8CEF,      // <cjk>
-      0x9BCA,0xE9C0,      // <cjk>
-      0x9BCF,0xE9C3,      // <cjk>
-      0x9BD1,0xE9C4,      // <cjk>
-      0x9BD2,0xE9C5,      // <cjk>
-      0x9BD4,0xE9C9,      // <cjk>
-      0x9BD6,0x8E49,      // <cjk>
-      0x9BDB,0x91E2,      // <cjk>
-      0x9BE1,0xE9CA,      // <cjk>
-      0x9BE2,0xE9C7,      // <cjk>
-      0x9BE3,0xE9C6,      // <cjk>
-      0x9BE4,0xE9C8,      // <cjk>
-      0x9BE8,0x8C7E,      // <cjk>
-      0x9BF0,0xE9CE,      // <cjk>
-      0x9BF1,0xE9CD,      // <cjk>
-      0x9BF2,0xE9CC,      // <cjk>
-      0x9BF5,0x88B1,      // <cjk>
-      0x9C04,0xE9D8,      // <cjk>
-      0x9C06,0xE9D4,      // <cjk>
-      0x9C08,0xE9D5,      // <cjk>
-      0x9C09,0xE9D1,      // <cjk>
-      0x9C0A,0xE9D7,      // <cjk>
-      0x9C0C,0xE9D3,      // <cjk>
-      0x9C0D,0x8A82,      // <cjk>
-      0x9C10,0x986B,      // <cjk>
-      0x9C12,0xE9D6,      // <cjk>
-      0x9C13,0xE9D2,      // <cjk>
-      0x9C14,0xE9D0,      // <cjk>
-      0x9C15,0xE9CF,      // <cjk>
-      0x9C1B,0xE9DA,      // <cjk>
-      0x9C21,0xE9DD,      // <cjk>
-      0x9C24,0xE9DC,      // <cjk>
-      0x9C25,0xE9DB,      // <cjk>
-      0x9C2D,0x9568,      // <cjk>
-      0x9C2E,0xE9D9,      // <cjk>
-      0x9C2F,0x88F1,      // <cjk>
-      0x9C30,0xE9DE,      // <cjk>
-      0x9C32,0xE9E0,      // <cjk>
-      0x9C39,0x8A8F,      // <cjk>
-      0x9C3A,0xE9CB,      // <cjk>
-      0x9C3B,0x8956,      // <cjk>
-      0x9C3E,0xE9E2,      // <cjk>
-      0x9C46,0xE9E1,      // <cjk>
-      0x9C47,0xE9DF,      // <cjk>
-      0x9C48,0x924C,      // <cjk>
-      0x9C52,0x9690,      // <cjk>
-      0x9C57,0x97D8,      // <cjk>
-      0x9C5A,0xE9E3,      // <cjk>
-      0x9C60,0xE9E4,      // <cjk>
-      0x9C67,0xE9E5,      // <cjk>
-      0x9C76,0xE9E6,      // <cjk>
-      0x9C78,0xE9E7,      // <cjk>
-      0x9CE5,0x92B9,      // <cjk>
-      0x9CE7,0xE9E8,      // <cjk>
-      0x9CE9,0x94B5,      // <cjk>
-      0x9CEB,0xE9ED,      // <cjk>
-      0x9CEC,0xE9E9,      // <cjk>
-      0x9CF0,0xE9EA,      // <cjk>
-      0x9CF3,0x9650,      // <cjk>
-      0x9CF4,0x96C2,      // <cjk>
-      0x9CF6,0x93CE,      // <cjk>
-      0x9D03,0xE9EE,      // <cjk>
-      0x9D06,0xE9EF,      // <cjk>
-      0x9D07,0x93BC,      // <cjk>
-      0x9D08,0xE9EC,      // <cjk>
-      0x9D09,0xE9EB,      // <cjk>
-      0x9D0E,0x89A8,      // <cjk>
-      0x9D12,0xE9F7,      // <cjk>
-      0x9D15,0xE9F6,      // <cjk>
-      0x9D1B,0x8995,      // <cjk>
-      0x9D1F,0xE9F4,      // <cjk>
-      0x9D23,0xE9F3,      // <cjk>
-      0x9D26,0xE9F1,      // <cjk>
-      0x9D28,0x8A9B,      // <cjk>
-      0x9D2A,0xE9F0,      // <cjk>
-      0x9D2B,0x8EB0,      // <cjk>
-      0x9D2C,0x89A7,      // <cjk>
-      0x9D3B,0x8D83,      // <cjk>
-      0x9D3E,0xE9FA,      // <cjk>
-      0x9D3F,0xE9F9,      // <cjk>
-      0x9D41,0xE9F8,      // <cjk>
-      0x9D44,0xE9F5,      // <cjk>
-      0x9D46,0xE9FB,      // <cjk>
-      0x9D48,0xE9FC,      // <cjk>
-      0x9D50,0xEA44,      // <cjk>
-      0x9D51,0xEA43,      // <cjk>
-      0x9D59,0xEA45,      // <cjk>
-      0x9D5C,0x894C,      // <cjk>
-      0x9D5D,0xEA40,      // <cjk>
-      0x9D5E,0xEA41,      // <cjk>
-      0x9D60,0x8D94,      // <cjk>
-      0x9D61,0x96B7,      // <cjk>
-      0x9D64,0xEA42,      // <cjk>
-      0x9D6C,0x9651,      // <cjk>
-      0x9D6F,0xEA4A,      // <cjk>
-      0x9D72,0xEA46,      // <cjk>
-      0x9D7A,0xEA4B,      // <cjk>
-      0x9D87,0xEA48,      // <cjk>
-      0x9D89,0xEA47,      // <cjk>
-      0x9D8F,0x8C7B,      // <cjk>
-      0x9D9A,0xEA4C,      // <cjk>
-      0x9DA4,0xEA4D,      // <cjk>
-      0x9DA9,0xEA4E,      // <cjk>
-      0x9DAB,0xEA49,      // <cjk>
-      0x9DAF,0xE9F2,      // <cjk>
-      0x9DB2,0xEA4F,      // <cjk>
-      0x9DB4,0x92DF,      // <cjk>
-      0x9DB8,0xEA53,      // <cjk>
-      0x9DBA,0xEA54,      // <cjk>
-      0x9DBB,0xEA52,      // <cjk>
-      0x9DC1,0xEA51,      // <cjk>
-      0x9DC2,0xEA57,      // <cjk>
-      0x9DC4,0xEA50,      // <cjk>
-      0x9DC6,0xEA55,      // <cjk>
-      0x9DCF,0xEA56,      // <cjk>
-      0x9DD3,0xEA59,      // <cjk>
-      0x9DD9,0xEA58,      // <cjk>
-      0x9DED,0xEA5C,      // <cjk>
-      0x9DEF,0xEA5D,      // <cjk>
-      0x9DF2,0x9868,      // <cjk>
-      0x9DF8,0xEA5A,      // <cjk>
-      0x9DF9,0x91E9,      // <cjk>
-      0x9DFA,0x8DEB,      // <cjk>
-      0x9DFD,0xEA5E,      // <cjk>
-      0x9E1A,0xEA5F,      // <cjk>
-      0x9E1B,0xEA60,      // <cjk>
-      0x9E1E,0xEA61,      // <cjk>
-      0x9E75,0xEA62,      // <cjk>
-      0x9E78,0x8CB2,      // <cjk>
-      0x9E79,0xEA63,      // <cjk>
-      0x9E7D,0xEA64,      // <cjk>
-      0x9E7F,0x8EAD,      // <cjk>
-      0x9E81,0xEA65,      // <cjk>
-      0x9E88,0xEA66,      // <cjk>
-      0x9E8B,0xEA67,      // <cjk>
-      0x9E8C,0xEA68,      // <cjk>
-      0x9E91,0xEA6B,      // <cjk>
-      0x9E92,0xEA69,      // <cjk>
-      0x9E95,0xEA6A,      // <cjk>
-      0x9E97,0x97ED,      // <cjk>
-      0x9E9D,0xEA6C,      // <cjk>
-      0x9E9F,0x97D9,      // <cjk>
-      0x9EA5,0xEA6D,      // <cjk>
-      0x9EA6,0x949E,      // <cjk>
-      0x9EA9,0xEA6E,      // <cjk>
-      0x9EAA,0xEA70,      // <cjk>
-      0x9EAD,0xEA71,      // <cjk>
-      0x9EB8,0xEA6F,      // <cjk>
-      0x9EB9,0x8D8D,      // <cjk>
-      0x9EBA,0x96CB,      // <cjk>
-      0x9EBB,0x9683,      // <cjk>
-      0x9EBC,0x9BF5,      // <cjk>
-      0x9EBE,0x9F80,      // <cjk>
-      0x9EBF,0x969B,      // <cjk>
-      0x9EC4,0x89A9,      // <cjk>
-      0x9ECC,0xEA73,      // <cjk>
-      0x9ECD,0x8B6F,      // <cjk>
-      0x9ECE,0xEA74,      // <cjk>
-      0x9ECF,0xEA75,      // <cjk>
-      0x9ED0,0xEA76,      // <cjk>
-      0x9ED2,0x8D95,      // <cjk>
-      0x9ED4,0xEA77,      // <cjk>
-      0x9ED8,0xE0D2,      // <cjk>
-      0x9ED9,0x96D9,      // <cjk>
-      0x9EDB,0x91E1,      // <cjk>
-      0x9EDC,0xEA78,      // <cjk>
-      0x9EDD,0xEA7A,      // <cjk>
-      0x9EDE,0xEA79,      // <cjk>
-      0x9EE0,0xEA7B,      // <cjk>
-      0x9EE5,0xEA7C,      // <cjk>
-      0x9EE8,0xEA7D,      // <cjk>
-      0x9EEF,0xEA7E,      // <cjk>
-      0x9EF4,0xEA80,      // <cjk>
-      0x9EF6,0xEA81,      // <cjk>
-      0x9EF7,0xEA82,      // <cjk>
-      0x9EF9,0xEA83,      // <cjk>
-      0x9EFB,0xEA84,      // <cjk>
-      0x9EFC,0xEA85,      // <cjk>
-      0x9EFD,0xEA86,      // <cjk>
-      0x9F07,0xEA87,      // <cjk>
-      0x9F08,0xEA88,      // <cjk>
-      0x9F0E,0x9343,      // <cjk>
-      0x9F13,0x8CDB,      // <cjk>
-      0x9F15,0xEA8A,      // <cjk>
-      0x9F20,0x916C,      // <cjk>
-      0x9F21,0xEA8B,      // <cjk>
-      0x9F2C,0xEA8C,      // <cjk>
-      0x9F3B,0x9540,      // <cjk>
-      0x9F3E,0xEA8D,      // <cjk>
-      0x9F4A,0xEA8E,      // <cjk>
-      0x9F4B,0xE256,      // <cjk>
-      0x9F4E,0xE6D8,      // <cjk>
-      0x9F4F,0xE8EB,      // <cjk>
-      0x9F52,0xEA8F,      // <cjk>
-      0x9F54,0xEA90,      // <cjk>
-      0x9F5F,0xEA92,      // <cjk>
-      0x9F60,0xEA93,      // <cjk>
-      0x9F61,0xEA94,      // <cjk>
-      0x9F62,0x97EE,      // <cjk>
-      0x9F63,0xEA91,      // <cjk>
-      0x9F66,0xEA95,      // <cjk>
-      0x9F67,0xEA96,      // <cjk>
-      0x9F6A,0xEA98,      // <cjk>
-      0x9F6C,0xEA97,      // <cjk>
-      0x9F72,0xEA9A,      // <cjk>
-      0x9F76,0xEA9B,      // <cjk>
-      0x9F77,0xEA99,      // <cjk>
-      0x9F8D,0x97B4,      // <cjk>
-      0x9F95,0xEA9C,      // <cjk>
-      0x9F9C,0xEA9D,      // <cjk>
-      0x9F9D,0xE273,      // <cjk>
-      0x9FA0,0xEA9E,      // <cjk>
-      0xFF01,0x8149,      // FULLWIDTH EXCLAMATION MARK
-      0xFF03,0x8194,      // FULLWIDTH NUMBER SIGN
-      0xFF04,0x8190,      // FULLWIDTH DOLLAR SIGN
-      0xFF05,0x8193,      // FULLWIDTH PERCENT SIGN
-      0xFF06,0x8195,      // FULLWIDTH AMPERSAND
-      0xFF07,0x81AD,      // FULLWIDTH APOSTROPHE
-      0xFF08,0x8169,      // FULLWIDTH LEFT PARENTHESIS
-      0xFF09,0x816A,      // FULLWIDTH RIGHT PARENTHESIS
-      0xFF0A,0x8196,      // FULLWIDTH ASTERISK
-      0xFF0B,0x817B,      // FULLWIDTH PLUS SIGN
-      0xFF0C,0x8143,      // FULLWIDTH COMMA
-      0xFF0E,0x8144,      // FULLWIDTH FULL STOP
-      0xFF0F,0x815E,      // FULLWIDTH SOLIDUS
-      0xFF10,0x824F,      // FULLWIDTH DIGIT ZERO
-      0xFF11,0x8250,      // FULLWIDTH DIGIT ONE
-      0xFF12,0x8251,      // FULLWIDTH DIGIT TWO
-      0xFF13,0x8252,      // FULLWIDTH DIGIT THREE
-      0xFF14,0x8253,      // FULLWIDTH DIGIT FOUR
-      0xFF15,0x8254,      // FULLWIDTH DIGIT FIVE
-      0xFF16,0x8255,      // FULLWIDTH DIGIT SIX
-      0xFF17,0x8256,      // FULLWIDTH DIGIT SEVEN
-      0xFF18,0x8257,      // FULLWIDTH DIGIT EIGHT
-      0xFF19,0x8258,      // FULLWIDTH DIGIT NINE
-      0xFF1A,0x8146,      // FULLWIDTH COLON
-      0xFF1B,0x8147,      // FULLWIDTH SEMICOLON
-      0xFF1C,0x8183,      // FULLWIDTH LESS-THAN SIGN
-      0xFF1D,0x8181,      // FULLWIDTH EQUALS SIGN
-      0xFF1E,0x8184,      // FULLWIDTH GREATER-THAN SIGN
-      0xFF1F,0x8148,      // FULLWIDTH QUESTION MARK
-      0xFF20,0x8197,      // FULLWIDTH COMMERCIAL AT
-      0xFF21,0x8260,      // FULLWIDTH LATIN CAPITAL LETTER A
-      0xFF22,0x8261,      // FULLWIDTH LATIN CAPITAL LETTER B
-      0xFF23,0x8262,      // FULLWIDTH LATIN CAPITAL LETTER C
-      0xFF24,0x8263,      // FULLWIDTH LATIN CAPITAL LETTER D
-      0xFF25,0x8264,      // FULLWIDTH LATIN CAPITAL LETTER E
-      0xFF26,0x8265,      // FULLWIDTH LATIN CAPITAL LETTER F
-      0xFF27,0x8266,      // FULLWIDTH LATIN CAPITAL LETTER G
-      0xFF28,0x8267,      // FULLWIDTH LATIN CAPITAL LETTER H
-      0xFF29,0x8268,      // FULLWIDTH LATIN CAPITAL LETTER I
-      0xFF2A,0x8269,      // FULLWIDTH LATIN CAPITAL LETTER J
-      0xFF2B,0x826A,      // FULLWIDTH LATIN CAPITAL LETTER K
-      0xFF2C,0x826B,      // FULLWIDTH LATIN CAPITAL LETTER L
-      0xFF2D,0x826C,      // FULLWIDTH LATIN CAPITAL LETTER M
-      0xFF2E,0x826D,      // FULLWIDTH LATIN CAPITAL LETTER N
-      0xFF2F,0x826E,      // FULLWIDTH LATIN CAPITAL LETTER O
-      0xFF30,0x826F,      // FULLWIDTH LATIN CAPITAL LETTER P
-      0xFF31,0x8270,      // FULLWIDTH LATIN CAPITAL LETTER Q
-      0xFF32,0x8271,      // FULLWIDTH LATIN CAPITAL LETTER R
-      0xFF33,0x8272,      // FULLWIDTH LATIN CAPITAL LETTER S
-      0xFF34,0x8273,      // FULLWIDTH LATIN CAPITAL LETTER T
-      0xFF35,0x8274,      // FULLWIDTH LATIN CAPITAL LETTER U
-      0xFF36,0x8275,      // FULLWIDTH LATIN CAPITAL LETTER V
-      0xFF37,0x8276,      // FULLWIDTH LATIN CAPITAL LETTER W
-      0xFF38,0x8277,      // FULLWIDTH LATIN CAPITAL LETTER X
-      0xFF39,0x8278,      // FULLWIDTH LATIN CAPITAL LETTER Y
-      0xFF3A,0x8279,      // FULLWIDTH LATIN CAPITAL LETTER Z
-      0xFF3B,0x816D,      // FULLWIDTH LEFT SQUARE BRACKET
-      0xFF3D,0x816E,      // FULLWIDTH RIGHT SQUARE BRACKET
-      0xFF3E,0x814F,      // FULLWIDTH CIRCUMFLEX ACCENT
-      0xFF3F,0x8151,      // FULLWIDTH LOW LINE
-      0xFF40,0x814D,      // FULLWIDTH GRAVE ACCENT
-      0xFF41,0x8281,      // FULLWIDTH LATIN SMALL LETTER A
-      0xFF42,0x8282,      // FULLWIDTH LATIN SMALL LETTER B
-      0xFF43,0x8283,      // FULLWIDTH LATIN SMALL LETTER C
-      0xFF44,0x8284,      // FULLWIDTH LATIN SMALL LETTER D
-      0xFF45,0x8285,      // FULLWIDTH LATIN SMALL LETTER E
-      0xFF46,0x8286,      // FULLWIDTH LATIN SMALL LETTER F
-      0xFF47,0x8287,      // FULLWIDTH LATIN SMALL LETTER G
-      0xFF48,0x8288,      // FULLWIDTH LATIN SMALL LETTER H
-      0xFF49,0x8289,      // FULLWIDTH LATIN SMALL LETTER I
-      0xFF4A,0x828A,      // FULLWIDTH LATIN SMALL LETTER J
-      0xFF4B,0x828B,      // FULLWIDTH LATIN SMALL LETTER K
-      0xFF4C,0x828C,      // FULLWIDTH LATIN SMALL LETTER L
-      0xFF4D,0x828D,      // FULLWIDTH LATIN SMALL LETTER M
-      0xFF4E,0x828E,      // FULLWIDTH LATIN SMALL LETTER N
-      0xFF4F,0x828F,      // FULLWIDTH LATIN SMALL LETTER O
-      0xFF50,0x8290,      // FULLWIDTH LATIN SMALL LETTER P
-      0xFF51,0x8291,      // FULLWIDTH LATIN SMALL LETTER Q
-      0xFF52,0x8292,      // FULLWIDTH LATIN SMALL LETTER R
-      0xFF53,0x8293,      // FULLWIDTH LATIN SMALL LETTER S
-      0xFF54,0x8294,      // FULLWIDTH LATIN SMALL LETTER T
-      0xFF55,0x8295,      // FULLWIDTH LATIN SMALL LETTER U
-      0xFF56,0x8296,      // FULLWIDTH LATIN SMALL LETTER V
-      0xFF57,0x8297,      // FULLWIDTH LATIN SMALL LETTER W
-      0xFF58,0x8298,      // FULLWIDTH LATIN SMALL LETTER X
-      0xFF59,0x8299,      // FULLWIDTH LATIN SMALL LETTER Y
-      0xFF5A,0x829A,      // FULLWIDTH LATIN SMALL LETTER Z
-      0xFF5B,0x816F,      // FULLWIDTH LEFT CURLY BRACKET
-      0xFF5C,0x8162,      // FULLWIDTH VERTICAL LINE
-      0xFF5D,0x8170,      // FULLWIDTH RIGHT CURLY BRACKET
-      0xFFE3,0x8150,      // FULLWIDTH MACRON 
-      0xFFE5,0x818F       // FULLWIDTH YEN SIGN
-};
\ No newline at end of file
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+INTERNAL int sjis_wctomb_zint(unsigned int* r, unsigned int wc);
+INTERNAL int sjis_utf8tomb(struct zint_symbol *symbol, const unsigned char source[], size_t* p_length, unsigned int* jisdata);
+INTERNAL int sjis_utf8tosb(int eci, const unsigned char source[], size_t* p_length, unsigned int* jisdata, int full_multibyte);
+INTERNAL void sjis_cpy(const unsigned char source[], size_t* p_length, unsigned int* jisdata, int full_multibyte);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SJIS_H */
diff --git a/backend/stdint_msvc.h b/backend/stdint_msvc.h
new file mode 100644 (file)
index 0000000..2d7c82d
--- /dev/null
@@ -0,0 +1,54 @@
+/*  stdint_msvc.h - definitions for libzint
+
+    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 STDINT_MSVC_H
+#define STDINT_MSVC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef _MSC_VER
+
+typedef BYTE uint8_t;
+typedef WORD uint16_t;
+typedef DWORD uint32_t;
+typedef INT32 int32_t;
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* STDINT_MSVC_H */
+
+
diff --git a/backend/svg.c b/backend/svg.c
new file mode 100644 (file)
index 0000000..98cca3d
--- /dev/null
@@ -0,0 +1,248 @@
+/* svg.c - Scalable Vector Graphics */
+
+/*
+    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 <locale.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+
+#include "common.h"
+
+void pick_colour(int colour, char colour_code[]) {
+    switch(colour) {
+        case 0: // White
+            strcpy(colour_code, "ffffff");
+            break;
+        case 1: // Cyan
+            strcpy(colour_code, "00ffff");
+            break;
+        case 2: // Blue
+            strcpy(colour_code, "0000ff");
+            break;
+        case 3: // Magenta
+            strcpy(colour_code, "ff00ff");
+            break;
+        case 4: // Red
+            strcpy(colour_code, "ff0000");
+            break;
+        case 5: // Yellow
+            strcpy(colour_code, "ffff00");
+            break;
+        case 6: // Green
+            strcpy(colour_code, "00ff00");
+            break;
+        default: // Black
+            strcpy(colour_code, "000000");
+            break;
+    }
+}
+
+static void make_html_friendly(unsigned char * string, char * html_version) {
+    /* Converts text to use HTML entity codes */
+
+    int i, html_pos;
+
+    html_pos = 0;
+    html_version[html_pos] = '\0';
+
+    for (i = 0; i < (int) ustrlen(string); i++) {
+        switch(string[i]) {
+            case '>':
+                strcat(html_version, "&gt;");
+                html_pos += 4;
+                break;
+
+            case '<':
+                strcat(html_version, "&lt;");
+                html_pos += 4;
+                break;
+
+            case '&':
+                strcat(html_version, "&amp;");
+                html_pos += 5;
+                break;
+
+            case '"':
+                strcat(html_version, "&quot;");
+                html_pos += 6;
+                break;
+
+            case '\'':
+                strcat(html_version, "&apos;");
+                html_pos += 6;
+                break;
+
+            default:
+                html_version[html_pos] = string[i];
+                html_pos++;
+                html_version[html_pos] = '\0';
+                break;
+         }
+    }
+}
+
+INTERNAL int svg_plot(struct zint_symbol *symbol) {
+    FILE *fsvg;
+    int error_number = 0;
+    const char *locale = NULL;
+    float ax, ay, bx, by, cx, cy, dx, dy, ex, ey, fx, fy;
+    float radius;
+    int i;
+
+    struct zint_vector_rect *rect;
+    struct zint_vector_hexagon *hex;
+    struct zint_vector_circle *circle;
+    struct zint_vector_string *string;
+
+    char colour_code[7];
+
+#ifdef _MSC_VER
+    char* html_string;
+#endif
+
+    int html_len = strlen((char *)symbol->text) + 1;
+
+    for (i = 0; i < (int) strlen((char *)symbol->text); i++) {
+        switch(symbol->text[i]) {
+            case '>':
+            case '<':
+            case '"':
+            case '&':
+            case '\'':
+                html_len += 6;
+                break;
+        }
+    }
+
+#ifndef _MSC_VER
+    char html_string[html_len];
+#else
+    html_string = (char*) _alloca(html_len);
+#endif
+
+    /* Check for no created vector set */
+    /* E-Mail Christian Schmitz 2019-09-10: reason unknown  Ticket #164*/
+    if (symbol->vector == NULL) {
+        return ZINT_ERROR_INVALID_DATA;
+    }
+    if (symbol->output_options & BARCODE_STDOUT) {
+        fsvg = stdout;
+    } else {
+        fsvg = fopen(symbol->outfile, "w");
+    }
+    if (fsvg == NULL) {
+        strcpy(symbol->errtxt, "660: Could not open output file");
+        return ZINT_ERROR_FILE_ACCESS;
+    }
+
+    locale = setlocale(LC_ALL, "C");
+
+    /* Start writing the header */
+    fprintf(fsvg, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
+    fprintf(fsvg, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n");
+    fprintf(fsvg, "   \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+    fprintf(fsvg, "<svg width=\"%d\" height=\"%d\" version=\"1.1\"\n", (int) ceil(symbol->vector->width), (int) ceil(symbol->vector->height));
+    fprintf(fsvg, "   xmlns=\"http://www.w3.org/2000/svg\">\n");
+    fprintf(fsvg, "   <desc>Zint Generated Symbol\n");
+    fprintf(fsvg, "   </desc>\n");
+    fprintf(fsvg, "\n   <g id=\"barcode\" fill=\"#%s\">\n", symbol->fgcolour);
+
+    fprintf(fsvg, "      <rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" fill=\"#%s\" />\n", (int) ceil(symbol->vector->width), (int) ceil(symbol->vector->height), symbol->bgcolour);
+
+    rect = symbol->vector->rectangles;
+    while (rect) {
+        if (rect->colour == -1) {
+            fprintf(fsvg, "      <rect x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"%.2f\" />\n", rect->x, rect->y, rect->width, rect->height);
+        } else {
+            pick_colour(rect->colour, colour_code);
+            fprintf(fsvg, "      <rect x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"%.2f\" fill=\"#%s\" />\n", rect->x, rect->y, rect->width, rect->height, colour_code);
+        }
+        rect = rect->next;
+    }
+
+    hex = symbol->vector->hexagons;
+    while (hex) {
+        radius = hex->diameter / 2.0;
+        ay = hex->y + (1.0 * radius);
+        by = hex->y + (0.5 * radius);
+        cy = hex->y - (0.5 * radius);
+        dy = hex->y - (1.0 * radius);
+        ey = hex->y - (0.5 * radius);
+        fy = hex->y + (0.5 * radius);
+        ax = hex->x;
+        bx = hex->x + (0.86 * radius);
+        cx = hex->x + (0.86 * radius);
+        dx = hex->x;
+        ex = hex->x - (0.86 * radius);
+        fx = hex->x - (0.86 * radius);
+        fprintf(fsvg, "      <path d=\"M %.2f %.2f L %.2f %.2f L %.2f %.2f L %.2f %.2f L %.2f %.2f L %.2f %.2f Z\" />\n", ax, ay, bx, by, cx, cy, dx, dy, ex, ey, fx, fy);
+        hex = hex->next;
+    }
+
+    circle = symbol->vector->circles;
+    while (circle) {
+        if (circle->colour) {
+            fprintf(fsvg, "      <circle cx=\"%.2f\" cy=\"%.2f\" r=\"%.2f\" fill=\"#%s\" />\n", circle->x, circle->y, circle->diameter / 2.0, symbol->bgcolour);
+        } else {
+            fprintf(fsvg, "      <circle cx=\"%.2f\" cy=\"%.2f\" r=\"%.2f\" fill=\"#%s\" />\n", circle->x, circle->y, circle->diameter / 2.0, symbol->fgcolour);
+        }
+        circle = circle->next;
+    }
+
+    string = symbol->vector->strings;
+    while (string) {
+        fprintf(fsvg, "      <text x=\"%.2f\" y=\"%.2f\" text-anchor=\"middle\"\n", string->x, string->y);
+        fprintf(fsvg, "         font-family=\"Helvetica\" font-size=\"%.1f\" fill=\"#%s\" >\n", string->fsize, symbol->fgcolour);
+        make_html_friendly(string->text, html_string);
+        fprintf(fsvg, "         %s\n", html_string);
+        fprintf(fsvg, "      </text>\n");
+        string = string->next;
+    }
+
+    fprintf(fsvg, "   </g>\n");
+    fprintf(fsvg, "</svg>\n");
+
+    if (symbol->output_options & BARCODE_STDOUT) {
+        fflush(fsvg);
+    } else {
+        fclose(fsvg);
+    }
+
+    if (locale)
+        setlocale(LC_ALL, locale);
+
+    return error_number;
+}
diff --git a/backend/telepen.c b/backend/telepen.c
new file mode 100644 (file)
index 0000000..9db20b9
--- /dev/null
@@ -0,0 +1,168 @@
+/* telepen.c - Handles Telepen and Telepen numeric */
+
+/*
+    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 : */
+
+/* Telepen Barcode Symbology information and History (BSiH) https://telepen.co.uk/wp-content/uploads/2018/10/Barcode-Symbology-information-and-History.pdf */
+
+#define SODIUM  "0123456789X"
+
+#include <stdio.h>
+#include "common.h"
+
+static char *TeleTable[] = {
+    "31313131", "1131313111", "33313111", "1111313131", "3111313111", "11333131", "13133131", "111111313111",
+    "31333111", "1131113131", "33113131", "1111333111", "3111113131", "1113133111", "1311133111", "111111113131",
+    "3131113111", "11313331", "333331", "111131113111", "31113331", "1133113111", "1313113111", "1111113331",
+    "31131331", "113111113111", "3311113111", "1111131331", "311111113111", "1113111331", "1311111331", "11111111113111",
+    "31313311", "1131311131", "33311131", "1111313311", "3111311131", "11333311", "13133311", "111111311131",
+    "31331131", "1131113311", "33113311", "1111331131", "3111113311", "1113131131", "1311131131", "111111113311",
+    "3131111131", "1131131311", "33131311", "111131111131", "3111131311", "1133111131", "1313111131", "111111131311",
+    "3113111311", "113111111131", "3311111131", "111113111311", "311111111131", "111311111311", "131111111311", "11111111111131",
+    "3131311111", "11313133", "333133", "111131311111", "31113133", "1133311111", "1313311111", "1111113133",
+    "313333", "113111311111", "3311311111", "11113333", "311111311111", "11131333", "13111333", "11111111311111",
+    "31311133", "1131331111", "33331111", "1111311133", "3111331111", "11331133", "13131133", "111111331111",
+    "3113131111", "1131111133", "33111133", "111113131111", "3111111133", "111311131111", "131111131111", "111111111133",
+    "31311313", "113131111111", "3331111111", "1111311313", "311131111111", "11331313", "13131313", "11111131111111",
+    "3133111111", "1131111313", "33111313", "111133111111", "3111111313", "111313111111", "131113111111", "111111111313",
+    "313111111111", "1131131113", "33131113", "11113111111111", "3111131113", "113311111111", "131311111111", "111111131113",
+    "3113111113", "11311111111111", "331111111111", "111113111113", "31111111111111", "111311111113", "131111111113", "1111111111111111",
+};
+
+INTERNAL int telepen(struct zint_symbol *symbol, unsigned char source[], const size_t src_len) {
+    unsigned int i, count, check_digit;
+    int error_number;
+    char dest[521]; /* 12 (start) + 30 * 16 (max for DELs) + 16 (check digit) + 12 (stop) + 1 = 521 */
+
+    error_number = 0;
+
+    count = 0;
+
+    if (src_len > 30) {
+        strcpy(symbol->errtxt, "390: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    /* Start character */
+    strcpy(dest, TeleTable['_']);
+
+    for (i = 0; i < src_len; i++) {
+        if (source[i] > 127) {
+            /* Cannot encode extended ASCII */
+            strcpy(symbol->errtxt, "391: Invalid characters in input data");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+        strcat(dest, TeleTable[source[i]]);
+        count += source[i];
+    }
+
+    check_digit = 127 - (count % 127);
+    if (check_digit == 127) {
+        check_digit = 0;
+    }
+    strcat(dest, TeleTable[check_digit]);
+
+    /* Stop character */
+    strcat(dest, TeleTable['z']);
+
+    expand(symbol, dest);
+    for (i = 0; i < src_len; i++) {
+        if (source[i] == '\0') {
+            symbol->text[i] = ' ';
+        } else {
+            symbol->text[i] = source[i];
+        }
+    }
+    symbol->text[src_len] = '\0';
+    return error_number;
+}
+
+INTERNAL int telepen_num(struct zint_symbol *symbol, unsigned char source[], const size_t src_len) {
+    unsigned int count, check_digit, glyph;
+    int error_number;
+    size_t i, temp_length = src_len;
+    char dest[521]; /* 12 (start) + 30 * 16 (max for DELs) + 16 (check digit) + 12 (stop) + 1 = 521 */
+    unsigned char temp[64];
+
+    count = 0;
+
+    if (temp_length > 60) {
+        strcpy(symbol->errtxt, "392: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    ustrcpy(temp, source);
+    to_upper(temp);
+    error_number = is_sane(SODIUM, temp, temp_length);
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "393: Invalid characters in data");
+        return error_number;
+    }
+
+    /* Add a leading zero if required */
+    if (temp_length & 1) {
+        memmove(temp + 1, temp, temp_length);
+        temp[0] = '0';
+
+        temp[++temp_length] = '\0';
+    }
+
+    /* Start character */
+    strcpy(dest, TeleTable['_']);
+
+    for (i = 0; i < temp_length; i += 2) {
+        if (temp[i] == 'X') {
+            strcpy(symbol->errtxt, "394: Invalid position of X in Telepen data");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+
+        if (temp[i + 1] == 'X') {
+            glyph = ctoi(temp[i]) + 17;
+            count += glyph;
+        } else {
+            glyph = (10 * ctoi(temp[i])) + ctoi(temp[i + 1]);
+            glyph += 27;
+            count += glyph;
+        }
+        strcat(dest, TeleTable[glyph]);
+    }
+
+    check_digit = 127 - (count % 127);
+    if (check_digit == 127) {
+        check_digit = 0;
+    }
+    strcat(dest, TeleTable[check_digit]);
+
+    /* Stop character */
+    strcat(dest, TeleTable['z']);
+
+    expand(symbol, dest);
+    ustrcpy(symbol->text, temp);
+    return error_number;
+}
diff --git a/backend/tif.c b/backend/tif.c
new file mode 100644 (file)
index 0000000..0e29691
--- /dev/null
@@ -0,0 +1,346 @@
+/* tif.c - Aldus Tagged Image File Format support */
+/* TIFF Revision 6.0 https://www.adobe.io/content/dam/udp/en/open/standards/tiff/TIFF6.pdf */
+
+/*
+    libzint - the open source barcode library
+    Copyright (C) 2016 - 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 <math.h>
+#include <assert.h>
+#include "common.h"
+#include "tif.h"
+#ifdef _MSC_VER
+#include <io.h>
+#include <fcntl.h>
+#include <malloc.h>
+#endif
+
+INTERNAL int tif_pixel_plot(struct zint_symbol *symbol, char *pixelbuf) {
+    int fgred, fggrn, fgblu, bgred, bggrn, bgblu;
+    int i;
+    int rows_per_strip, strip_count;
+    unsigned int free_memory;
+    int row, column, strip;
+    unsigned int bytes_put;
+    FILE *tif_file;
+#ifdef _MSC_VER
+    uint32_t* strip_offset;
+    uint32_t* strip_bytes;
+#endif
+
+    tiff_header_t header;
+    tiff_ifd_t ifd;
+    uint16_t temp;
+    uint32_t temp32;
+
+    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]);
+
+    /* TIFF Rev 6 Section 7 p.27 "Set RowsPerStrip such that the size of each strip is about 8K bytes...
+     * Note that extremely wide high resolution images may have rows larger than 8K bytes; in this case,
+     * RowsPerStrip should be 1, and the strip will be larger than 8K." */
+    rows_per_strip = 8192 / (symbol->bitmap_width * 3);
+    if (rows_per_strip == 0) {
+        rows_per_strip = 1;
+    }
+
+    /* Suppresses clang-tidy clang-analyzer-core.VLASize warning */
+    assert(symbol->bitmap_height > 0);
+
+    strip_count = symbol->bitmap_height / rows_per_strip;
+    if ((symbol->bitmap_height % rows_per_strip) != 0) {
+        strip_count++;
+    }
+
+    if (rows_per_strip > symbol->bitmap_height) {
+        rows_per_strip = symbol->bitmap_height;
+    }
+
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("TIFF (%dx%d) Strip Count %d, Rows Per Strip %d\n", symbol->bitmap_width, symbol->bitmap_height, strip_count, rows_per_strip);
+    }
+
+#ifndef _MSC_VER
+    uint32_t strip_offset[strip_count];
+    uint32_t strip_bytes[strip_count];
+#else
+    strip_offset = (uint32_t*) _alloca(strip_count * sizeof(uint32_t));
+    strip_bytes = (uint32_t*) _alloca(strip_count * sizeof(uint32_t));
+#endif
+    free_memory = 8;
+
+    for(i = 0; i < strip_count; i++) {
+        strip_offset[i] = free_memory;
+        if (i != (strip_count - 1)) {
+            strip_bytes[i] = rows_per_strip * symbol->bitmap_width * 3;
+        } else {
+            if ((symbol->bitmap_height % rows_per_strip) != 0) {
+                strip_bytes[i] = (symbol->bitmap_height % rows_per_strip) * symbol->bitmap_width * 3;
+            } else {
+                strip_bytes[i] = rows_per_strip * symbol->bitmap_width * 3;
+            }
+        }
+        free_memory += strip_bytes[i];
+        if ((free_memory % 2) == 1) {
+            free_memory++;
+        }
+    }
+
+    if (free_memory > 0xffff0000) {
+        strcpy(symbol->errtxt, "670: Output file size too big");
+        return ZINT_ERROR_MEMORY;
+    }
+
+    /* Open output file in binary mode */
+    if (symbol->output_options & BARCODE_STDOUT) {
+#ifdef _MSC_VER
+        if (-1 == _setmode(_fileno(stdout), _O_BINARY)) {
+            strcpy(symbol->errtxt, "671: Can't open output file");
+            return ZINT_ERROR_FILE_ACCESS;
+        }
+#endif
+        tif_file = stdout;
+    } else {
+        if (!(tif_file = fopen(symbol->outfile, "wb"))) {
+            strcpy(symbol->errtxt, "672: Can't open output file");
+            return ZINT_ERROR_FILE_ACCESS;
+        }
+    }
+
+    /* Header */
+    header.byte_order = 0x4949;
+    header.identity = 42;
+    header.offset = free_memory;
+
+    fwrite(&header, sizeof(tiff_header_t), 1, tif_file);
+    free_memory += sizeof(tiff_ifd_t);
+
+    /* Pixel data */
+    strip = 0;
+    bytes_put = 0;
+    for (row = 0; row < symbol->bitmap_height; row++) {
+        for (column = 0; column < symbol->bitmap_width; column++) {
+            switch(pixelbuf[(row * symbol->bitmap_width) + column]) {
+                case 'W': // White
+                    putc(255, tif_file);
+                    putc(255, tif_file);
+                    putc(255, tif_file);
+                    break;
+                case 'C': // Cyan
+                    putc(0, tif_file);
+                    putc(255, tif_file);
+                    putc(255, tif_file);
+                    break;
+                case 'B': // Blue
+                    putc(0, tif_file);
+                    putc(0, tif_file);
+                    putc(255, tif_file);
+                    break;
+                case 'M': // Magenta
+                    putc(255, tif_file);
+                    putc(0, tif_file);
+                    putc(255, tif_file);
+                    break;
+                case 'R': // Red
+                    putc(255, tif_file);
+                    putc(0, tif_file);
+                    putc(0, tif_file);
+                    break;
+                case 'Y': // Yellow
+                    putc(255, tif_file);
+                    putc(255, tif_file);
+                    putc(0, tif_file);
+                    break;
+                case 'G': // Green
+                    putc(0, tif_file);
+                    putc(255, tif_file);
+                    putc(0, tif_file);
+                    break;
+                case 'K': // Black
+                    putc(0, tif_file);
+                    putc(0, tif_file);
+                    putc(0, tif_file);
+                    break;
+                case '1':
+                    putc(fgred, tif_file);
+                    putc(fggrn, tif_file);
+                    putc(fgblu, tif_file);
+                    break;
+                default:
+                    putc(bgred, tif_file);
+                    putc(bggrn, tif_file);
+                    putc(bgblu, tif_file);
+                    break;
+            }
+            bytes_put += 3;
+        }
+
+        if (strip < strip_count && (bytes_put + 3) >= strip_bytes[strip]) {
+            // End of strip, pad if strip length is odd
+            if (strip_bytes[strip] % 2 == 1) {
+                putc(0, tif_file);
+            }
+            strip++;
+            bytes_put = 0;
+        }
+    }
+
+    /* Image File Directory */
+    ifd.entries = 14;
+    ifd.offset = 0;
+
+    ifd.new_subset.tag = 0xfe;
+    ifd.new_subset.type = 4;
+    ifd.new_subset.count = 1;
+    ifd.new_subset.offset = 0;
+
+    ifd.image_width.tag = 0x0100;
+    ifd.image_width.type = 3; // SHORT
+    ifd.image_width.count = 1;
+    ifd.image_width.offset = symbol->bitmap_width;
+
+    ifd.image_length.tag = 0x0101;
+    ifd.image_length.type = 3; // SHORT
+    ifd.image_length.count = 1;
+    ifd.image_length.offset = symbol->bitmap_height;
+
+    ifd.bits_per_sample.tag = 0x0102;
+    ifd.bits_per_sample.type = 3; // SHORT
+    ifd.bits_per_sample.count = 3;
+    ifd.bits_per_sample.offset = free_memory;
+    free_memory += 6;
+
+    ifd.compression.tag = 0x0103;
+    ifd.compression.type = 3;
+    ifd.compression.count = 1;
+    ifd.compression.offset = 1; // Uncompressed
+
+    ifd.photometric.tag = 0x0106;
+    ifd.photometric.type = 3; // SHORT
+    ifd.photometric.count = 1;
+    ifd.photometric.offset = 2; // RGB Model
+
+    ifd.strip_offsets.tag = 0x0111;
+    ifd.strip_offsets.type = 4; // LONG
+    ifd.strip_offsets.count = strip_count;
+    if (strip_count == 1) {
+        ifd.strip_offsets.offset = strip_offset[0];
+    } else {
+        ifd.strip_offsets.offset = free_memory;
+        free_memory += strip_count * 4;
+    }
+
+    ifd.samples_per_pixel.tag = 0x0115;
+    ifd.samples_per_pixel.type = 3;
+    ifd.samples_per_pixel.count = 1;
+    ifd.samples_per_pixel.offset = 3;
+
+    ifd.rows_per_strip.tag = 0x0116;
+    ifd.rows_per_strip.type = 4;
+    ifd.rows_per_strip.count = 1;
+    ifd.rows_per_strip.offset = rows_per_strip;
+
+    ifd.strip_byte_counts.tag = 0x0117;
+    ifd.strip_byte_counts.type = 4;
+    ifd.strip_byte_counts.count = strip_count;
+    if (strip_count == 1) {
+        ifd.strip_byte_counts.offset = strip_bytes[0];
+    } else {
+        ifd.strip_byte_counts.offset = free_memory;
+        free_memory += strip_count * 4;
+    }
+
+    ifd.x_resolution.tag = 0x011a;
+    ifd.x_resolution.type = 5;
+    ifd.x_resolution.count = 1;
+    ifd.x_resolution.offset = free_memory;
+    free_memory += 8;
+
+    ifd.y_resolution.tag = 0x011b;
+    ifd.y_resolution.type = 5;
+    ifd.y_resolution.count = 1;
+    ifd.y_resolution.offset = free_memory;
+//    free_memory += 8;
+
+    ifd.planar_config.tag = 0x11c;
+    ifd.planar_config.type = 3;
+    ifd.planar_config.count = 1;
+    ifd.planar_config.offset = 1;
+
+    ifd.resolution_unit.tag = 0x0128;
+    ifd.resolution_unit.type = 3;
+    ifd.resolution_unit.count = 1;
+    ifd.resolution_unit.offset = 2; // Inches
+
+    fwrite(&ifd, sizeof(tiff_ifd_t), 1, tif_file);
+
+    /* Bits per sample */
+    temp = 8;
+    fwrite(&temp, 2, 1, tif_file); // Red Bytes
+    fwrite(&temp, 2, 1, tif_file); // Green Bytes
+    fwrite(&temp, 2, 1, tif_file); // Blue Bytes
+
+    if (strip_count != 1) {
+        /* Strip offsets */
+        for (i = 0; i < strip_count; i++) {
+            fwrite(&strip_offset[i], 4, 1, tif_file);
+        }
+
+        /* Strip byte lengths */
+        for (i = 0; i < strip_count; i++) {
+            fwrite(&strip_bytes[i], 4, 1, tif_file);
+        }
+    }
+
+    /* X Resolution */
+    temp32 = 72;
+    fwrite(&temp32, 4, 1, tif_file);
+    temp32 = 1;
+    fwrite(&temp32, 4, 1, tif_file);
+
+    /* Y Resolution */
+    temp32 = 72;
+    fwrite(&temp32, 4, 1, tif_file);
+    temp32 = 1;
+    fwrite(&temp32, 4, 1, tif_file);
+
+    if (symbol->output_options & BARCODE_STDOUT) {
+        fflush(tif_file);
+    } else {
+        fclose(tif_file);
+    }
+
+    return 0;
+}
diff --git a/backend/tif.h b/backend/tif.h
new file mode 100644 (file)
index 0000000..3e3c459
--- /dev/null
@@ -0,0 +1,88 @@
+/* tif.h - Aldus Tagged Image File Format */
+
+/*
+    libzint - the open source barcode library
+    Copyright (C) 2016-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 TIF_H
+#define        TIF_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 tiff_header {
+        uint16_t byte_order;
+        uint16_t identity;
+        uint32_t offset;
+    } tiff_header_t;
+
+    typedef struct tiff_tag {
+        uint16_t tag;
+        uint16_t type;
+        uint32_t count;
+        uint32_t offset;
+    } tiff_tag_t;
+
+    typedef struct tiff_ifd {
+        uint16_t entries;
+        tiff_tag_t new_subset;
+        tiff_tag_t image_width;
+        tiff_tag_t image_length;
+        tiff_tag_t bits_per_sample;
+        tiff_tag_t compression;
+        tiff_tag_t photometric;
+        tiff_tag_t strip_offsets;
+        tiff_tag_t samples_per_pixel;
+        tiff_tag_t rows_per_strip;
+        tiff_tag_t strip_byte_counts;
+        tiff_tag_t x_resolution;
+        tiff_tag_t y_resolution;
+        tiff_tag_t planar_config;
+        tiff_tag_t resolution_unit;
+        uint32_t offset;
+    } tiff_ifd_t;
+
+#pragma pack()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TIF_H */
+
+
diff --git a/backend/ultra.c b/backend/ultra.c
new file mode 100644 (file)
index 0000000..58d0da8
--- /dev/null
@@ -0,0 +1,1115 @@
+/*  ultra.c - Ultracode
+
+    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 : */
+
+ /* This version was developed using AIMD/TSC15032-43 v0.99c Edit 60, dated 4th Nov 2015 */
+
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include <stdio.h>
+#include "common.h"
+
+#define EIGHTBIT_MODE       10
+#define ASCII_MODE          20
+#define C43_MODE            30
+
+#define PREDICT_WINDOW      12
+
+#define GFMUL(i, j) ((((i) == 0)||((j) == 0)) ? 0 : gfPwr[(gfLog[i] + gfLog[j])])
+
+static const char fragment[27][14] = {"http://", "https://", "http://www.", "https://www.",
+        "ftp://", "www.", ".com", ".edu", ".gov", ".int", ".mil", ".net", ".org",
+        ".mobi", ".coop", ".biz", ".info", "mailto:", "tel:", ".cgi", ".asp",
+        ".aspx", ".php", ".htm", ".html", ".shtml", "file:"};
+
+static const char ultra_c43_set1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,%";
+static const char ultra_c43_set2[] = "abcdefghijklmnopqrstuvwxyz:/?#[]@=_~!.,-";
+static const char ultra_c43_set3[] = "{}`()\"+'<>|$;&\\^*";
+static const char ultra_digit[] = "0123456789,/";
+static const char ultra_colour[] = "WCBMRYGK";
+
+//static const int ultra_maxsize[] = {34, 78, 158, 282}; // According to Table 1
+static const int ultra_maxsize[] = {34, 81, 158, 282}; // Adjusted to allow 79-81 codeword range in 3-row symbols (only 1 secondary vertical clock track, not 2, so 3 extra)
+
+static const int ultra_mincols[] = {5, 13, 23, 30}; // # Total Tile Columns from Table 1
+
+static const int kec[] = {0, 1, 2, 4, 6, 8}; // Value K(EC) from Table 12
+
+static const int dccu[] = {
+    051363, 051563, 051653, 053153, 053163, 053513, 053563, 053613, //  0-7
+    053653, 056153, 056163, 056313, 056353, 056363, 056513, 056563, //  8-15
+    051316, 051356, 051536, 051616, 053156, 053516, 053536, 053616, // 16-23
+    053636, 053656, 056136, 056156, 056316, 056356, 056516, 056536  // 24-31
+};
+
+static const int dccl[] = {
+    061351, 061361, 061531, 061561, 061631, 061651, 063131, 063151, //  0-7
+    063161, 063531, 063561, 063631, 065131, 065161, 065351, 065631, //  8-15
+    031351, 031361, 031531, 031561, 031631, 031651, 035131, 035151, // 16-23
+    035161, 035361, 035631, 035651, 036131, 036151, 036351, 036531  // 24-31
+};
+
+static const int tiles[] = {
+    013135, 013136, 013153, 013156, 013163, 013165, 013513, 013515, 013516, 013531, //   0-9
+    013535, 013536, 013561, 013563, 013565, 013613, 013615, 013616, 013631, 013635, //  10-19
+    013636, 013651, 013653, 013656, 015135, 015136, 015153, 015163, 015165, 015313, //  20-29
+    015315, 015316, 015351, 015353, 015356, 015361, 015363, 015365, 015613, 015615, //  30-39
+    015616, 015631, 015635, 015636, 015651, 015653, 015656, 016135, 016136, 016153, //  40-49
+    016156, 016165, 016313, 016315, 016316, 016351, 016353, 016356, 016361, 016363, //  50-59
+    016365, 016513, 016515, 016516, 016531, 016535, 016536, 016561, 016563, 016565, //  60-69
+    031315, 031316, 031351, 031356, 031361, 031365, 031513, 031515, 031516, 031531, //  70-79
+    031535, 031536, 031561, 031563, 031565, 031613, 031615, 031631, 031635, 031636, //  80-89
+    031651, 031653, 031656, 035131, 035135, 035136, 035151, 035153, 035156, 035161, //  90-99
+    035163, 035165, 035315, 035316, 035351, 035356, 035361, 035365, 035613, 035615, // 100-109
+    035616, 035631, 035635, 035636, 035651, 035653, 035656, 036131, 036135, 036136, // 110-119
+    036151, 036153, 036156, 036163, 036165, 036315, 036316, 036351, 036356, 036361, // 120-129
+    036365, 036513, 036515, 036516, 036531, 036535, 036536, 036561, 036563, 036565, // 130-139
+    051313, 051315, 051316, 051351, 051353, 051356, 051361, 051363, 051365, 051513, // 140-149
+    051516, 051531, 051536, 051561, 051563, 051613, 051615, 051616, 051631, 051635, // 150-159
+    051636, 051651, 051653, 051656, 053131, 053135, 053136, 053151, 053153, 053156, // 160-169
+    053161, 053163, 053165, 053513, 053516, 053531, 053536, 053561, 053563, 053613, // 170-179
+    053615, 053616, 053631, 053635, 053636, 053651, 053653, 053656, 056131, 056135, // 180-189
+    056136, 056151, 056153, 056156, 056161, 056163, 056165, 056313, 056315, 056316, // 190-199
+    056351, 056353, 056356, 056361, 056363, 056365, 056513, 056516, 056531, 056536, // 200-209
+    056561, 056563, 061313, 061315, 061316, 061351, 061353, 061356, 061361, 061363, // 210-219
+    061365, 061513, 061515, 061516, 061531, 061535, 061536, 061561, 061563, 061565, // 220-229
+    061615, 061631, 061635, 061651, 061653, 063131, 063135, 063136, 063151, 063153, // 230-239
+    063156, 063161, 063163, 063165, 063513, 063515, 063516, 063531, 063535, 063536, // 240-249
+    063561, 063563, 063565, 063613, 063615, 063631, 063635, 063651, 063653, 065131, // 250-259
+    065135, 065136, 065151, 065153, 065156, 065161, 065163, 065165, 065313, 065315, // 260-269
+    065316, 065351, 065353, 065356, 065361, 065363, 065365, 065613, 065615, 065631, // 270-279
+    065635, 065651, 065653, 056565, 051515                                     // 280-284
+};
+
+/* The following adapted from ECC283.C "RSEC codeword generator"
+ * from Annex B of Ultracode draft
+ * originally written by Ted Williams of Symbol Vision Corp.
+ * Dated 2001-03-09
+ * Corrected thanks to input from Terry Burton */
+
+/* 
+ * NOTE: Included here is an attempt to allow code compression within Ultracode. Unfortunately
+ * the copy of the standard this was written from was an early draft which includes self
+ * contradictions, so this is a "best guess" implementation. Because it is not guaranteed
+ * to be correct this compression is not applied by default. To enable compression set
+ * 
+ * symbol->option_3 = ULTRA_COMPRESSION;
+ * 
+ * Code compression should be enabled by default when it has been implemented according to
+ * a more reliable version of the specification.
+ */
+
+/* Generate divisor polynomial gQ(x) for GF283() given the required ECC size, 3 to 101 */
+static void ultra_genPoly(short EccSize, unsigned short gPoly[], unsigned short gfPwr[], unsigned short gfLog[]) {
+    int i, j;
+
+    gPoly[0] = 1;
+    for (i = 1; i < (EccSize + 1); i++) gPoly[i] = 0;
+
+    for (i = 0; i < EccSize; i++) {
+        for (j = i; j >= 0; j--)
+            gPoly[j + 1] = (gPoly[j] + GFMUL(gPoly[j + 1], gfPwr[i + 1])) % 283;
+        gPoly[0] = GFMUL(gPoly[0], gfPwr[i + 1]);
+    }
+    for (i = EccSize - 1; i >= 0; i -= 2) gPoly[i] = 283 - gPoly[i];
+
+    /* gPoly[i] is > 0 so modulo operation not needed */
+}
+
+/* Generate the log and antilog tables for GF283() multiplication & division */
+static void ultra_initLogTables(unsigned short gfPwr[], unsigned short gfLog[]) {
+    int i, j;
+
+    for (j = 0; j < 283; j++) gfLog[j] = 0;
+    i = 1;
+    for (j = 0; j < 282; j++) {
+        /* j + 282 indicies save doing the modulo operation in GFMUL */
+        gfPwr[j + 282] = gfPwr[j] = (short) i;
+        gfLog[i] = (short) j;
+        i = (i * 3) % 283;
+    }
+}
+
+static void ultra_gf283(short DataSize, short EccSize, int Message[]) {
+    /* Input is complete message codewords in array Message[282]
+     * DataSize is number of message codewords
+     * EccSize is number of Reed-Solomon GF(283) check codewords to generate
+     *
+     * Upon exit, Message[282] contains complete 282 codeword Symbol Message
+     * including leading zeroes corresponding to each truncated codeword */
+
+    unsigned short gPoly[283], gfPwr[(282 * 2)], gfLog[283];
+    int i, j, n;
+    unsigned short t;
+
+    /* first build the log & antilog tables used in multiplication & division */
+    ultra_initLogTables(gfPwr, gfLog);
+
+    /* then generate the division polynomial of length EccSize */
+    ultra_genPoly(EccSize, gPoly, gfPwr, gfLog);
+
+    /* zero all EccSize codeword values */
+    for (j = 281; (j > (281 - EccSize)); j--) Message[j] = 0;
+
+    /* shift message codewords to the right, leave space for ECC checkwords */
+    for (i = DataSize - 1; (i >= 0); j--, i--) Message[j] = Message[i];
+
+    /* add zeroes to pad left end Message[] for truncated codewords */
+    j++;
+    for (i = 0; i < j; i++) Message[i] = 0;
+
+    /* generate (EccSize) Reed-Solomon checkwords */
+    for (n = j; n < (j + DataSize); n++) {
+        t = (Message[j + DataSize] + Message[n]) % 283;
+        for (i = 0; i < (EccSize - 1); i++) {
+            Message[j + DataSize + i] = (Message[j + DataSize + i + 1] + 283
+            - GFMUL(t, gPoly[EccSize - 1 - i])) % 283;
+        }
+        Message[j + DataSize + EccSize - 1] = (283 - GFMUL(t, gPoly[0])) % 283;
+    }
+    for (i = j + DataSize; i < (j + DataSize + EccSize); i++)
+        Message[i] = (283 - Message[i]) % 283;
+}
+
+/* End of Ted Williams code */
+
+static int ultra_find_fragment(const unsigned char source[], int source_length, int position) {
+    int retval = -1;
+    int j, k, latch, fraglen;
+
+    for (j = 0; j < 27; j++) {
+        latch = 0;
+        fraglen = strlen(fragment[j]);
+        if ((position + fraglen) <= source_length) {
+            latch = 1;
+            for (k = 0; k < fraglen; k++) {
+                if (source[position + k] != fragment[j][k]) {
+                    latch = 0;
+                    break;
+                }
+            }
+        }
+
+        if (latch) {
+            retval = j;
+        }
+    }
+
+    return retval;
+}
+
+/* Encode characters in 8-bit mode */
+static float look_ahead_eightbit(unsigned char source[], int in_length, int in_locn, char current_mode, int end_char, int cw[], int* cw_len, int gs1)
+{
+    int codeword_count = 0;
+    int i;
+    int letters_encoded = 0;
+
+    if (current_mode != EIGHTBIT_MODE) {
+        cw[codeword_count] = 282; // Unlatch
+        codeword_count += 1;
+    }
+
+    i = in_locn;
+    while ((i < in_length) && (i < end_char)) {
+        if ((source[i] == '[') && gs1) {
+            cw[codeword_count] = 268; // FNC1
+        } else {
+            cw[codeword_count] = source[i];
+        }
+        i++;
+        codeword_count++;
+    }
+
+    letters_encoded = i - in_locn;
+
+    *cw_len = codeword_count;
+
+    if (codeword_count == 0) {
+        return 0.0;
+    } else {
+        return (float)letters_encoded / (float)codeword_count;
+    }
+}
+
+/* Encode character in the ASCII mode/submode (including numeric compression) */
+static float look_ahead_ascii(unsigned char source[], int in_length, int in_locn, char current_mode, int symbol_mode, int end_char, int cw[], int* cw_len, int* encoded, int gs1) {
+    int codeword_count = 0;
+    int i;
+    int first_digit, second_digit, done;
+    int letters_encoded = 0;
+
+    if (current_mode == EIGHTBIT_MODE) {
+        cw[codeword_count] = 267; // Latch ASCII Submode
+        codeword_count++;
+    }
+
+    if (current_mode == C43_MODE) {
+        cw[codeword_count] = 282; // Unlatch
+        codeword_count++;
+        if (symbol_mode == EIGHTBIT_MODE) {
+            cw[codeword_count] = 267; // Latch ASCII Submode
+            codeword_count++;
+        }
+    }
+
+    i = in_locn;
+    do {
+        /* Check for double digits */
+        done = 0;
+        if (i + 1 < in_length) {
+            first_digit = posn(ultra_digit, source[i]);
+            second_digit = posn(ultra_digit, source[i + 1]);
+            if ((first_digit != -1) && (second_digit != -1)) {
+                /* Double digit can be encoded */
+                if ((first_digit >= 0) && (first_digit <= 9) && (second_digit >= 0) && (second_digit <= 9)) {
+                    /* Double digit numerics */
+                    cw[codeword_count] = (10 * first_digit) + second_digit + 128;
+                    codeword_count++;
+                    i += 2;
+                    done = 1;
+                } else if ((first_digit >= 0) && (first_digit <= 9) && (second_digit == 10)) {
+                    /* Single digit followed by selected decimal point character */
+                    cw[codeword_count] = first_digit + 228;
+                    codeword_count++;
+                    i += 2;
+                    done = 1;
+                } else if ((first_digit == 10) && (second_digit >= 0) && (second_digit <= 9)) {
+                    /* Selected decimal point character followed by single digit */
+                    cw[codeword_count] = second_digit + 238;
+                    codeword_count++;
+                    i += 2;
+                    done = 1;
+                } else if ((first_digit >= 0) && (first_digit <= 9) && (second_digit == 11)) {
+                    /* Single digit or decimal point followed by field deliminator */
+                    cw[codeword_count] = first_digit + 248;
+                    codeword_count++;
+                    i += 2;
+                    done = 1;
+                } else if ((first_digit == 11) && (second_digit >= 0) && (second_digit <= 9)) {
+                    /* Field deliminator followed by single digit or decimal point */
+                    cw[codeword_count] = second_digit + 259;
+                    codeword_count++;
+                    i += 2;
+                    done = 1;
+                }
+            }
+        }
+
+        if (!done && source[i] < 0x80) {
+            if ((source[i] == '[') && gs1) {
+                cw[codeword_count] = 272; // FNC1
+            } else {
+                cw[codeword_count] = source[i];
+            }
+            codeword_count++;
+            i++;
+        }
+    } while ((i < in_length) && (i < end_char) && (source[i] < 0x80));
+
+    letters_encoded = i - in_locn;
+    if (encoded != NULL) {
+        *encoded = letters_encoded;
+    }
+
+    *cw_len = codeword_count;
+
+    if (codeword_count == 0) {
+        return 0.0;
+    } else {
+        return (float)letters_encoded / (float)codeword_count;
+    }
+}
+
+/* Returns true if should latch to subset other than given `subset` */
+static int c43_should_latch_other(const unsigned char data[], const size_t length, const unsigned int locn, int subset, int gs1) {
+    unsigned int i, fraglen, predict_window;
+    int cnt, alt_cnt, fragno;
+    const char* set = subset == 1 ? ultra_c43_set1 : ultra_c43_set2;
+    const char* alt_set = subset == 2 ? ultra_c43_set1 : ultra_c43_set2;
+
+    if (locn + 3 > length) {
+        return 0;
+    }
+    predict_window = locn + 3;
+
+    for (i = locn, cnt = 0, alt_cnt = 0; i < predict_window; i++) {
+        if (data[i] <= 0x1F || data[i] >= 0x7F || (gs1 && data[i] == '[')) {
+            break;
+        }
+
+        fragno = ultra_find_fragment(data, length, i);
+        if (fragno != -1 && fragno != 26) {
+            fraglen = strlen(fragment[fragno]);
+            predict_window += fraglen;
+            if (predict_window > length) {
+                predict_window = length;
+            }
+            i += fraglen - 1;
+        } else {
+            if (strchr(set, data[i]) != NULL) {
+                cnt++;
+            }
+            if (strchr(alt_set, data[i]) != NULL) {
+                alt_cnt++;
+            }
+        }
+    }
+
+    return alt_cnt > cnt;
+}
+
+static int get_subset(unsigned char source[], int in_length, int in_locn, int current_subset) {
+    int fragno;
+    int subset = 0;
+
+    fragno = ultra_find_fragment(source, in_length, in_locn);
+    if ((fragno != -1) && (fragno != 26)) {
+        subset = 3;
+    } else if (current_subset == 2) {
+        if (posn(ultra_c43_set2, source[in_locn]) != -1) {
+            subset = 2;
+        } else if (posn(ultra_c43_set1, source[in_locn]) != -1) {
+            subset = 1;
+        }
+    } else {
+        if (posn(ultra_c43_set1, source[in_locn]) != -1) {
+            subset = 1;
+        } else if (posn(ultra_c43_set2, source[in_locn]) != -1) {
+            subset = 2;
+        }
+    }
+
+    if (subset == 0) {
+        if (posn(ultra_c43_set3, source[in_locn]) != -1) {
+            subset = 3;
+        }
+    }
+
+    return subset;
+}
+
+/* Encode characters in the C43 compaction submode */
+static float look_ahead_c43(unsigned char source[], int in_length, int in_locn, char current_mode, int end_char, int subset, int cw[], int* cw_len, int* encoded, int gs1, int debug) {
+    int codeword_count = 0;
+    int subcodeword_count = 0;
+    int i;
+    int fragno;
+    int sublocn = in_locn;
+    int new_subset;
+    int unshift_set;
+    int base43_value;
+    int letters_encoded = 0;
+    int pad;
+
+#ifndef _MSC_VER
+    int subcw[(in_length + 3) * 2];
+#else
+    int * subcw = (int *) _alloca((in_length + 3) * 2 * sizeof (int));
+#endif /* _MSC_VER */
+
+    if (current_mode == EIGHTBIT_MODE) {
+        /* Check for permissable URL C43 macro sequences, otherwise encode directly */
+        fragno = ultra_find_fragment(source, in_length, sublocn);
+
+        if ((fragno == 2) || (fragno == 3)) {
+            // http://www. > http://
+            // https://www. > https://
+            fragno -= 2;
+        }
+
+        switch(fragno) {
+            case 17: // mailto:
+                cw[codeword_count] = 276;
+                sublocn += strlen(fragment[fragno]);
+                codeword_count++;
+                break;
+            case 18: // tel:
+                cw[codeword_count] = 277;
+                sublocn += strlen(fragment[fragno]);
+                codeword_count++;
+                break;
+            case 26: // file:
+                cw[codeword_count] = 278;
+                sublocn += strlen(fragment[fragno]);
+                codeword_count++;
+                break;
+            case 0: // http://
+                cw[codeword_count] = 279;
+                sublocn += strlen(fragment[fragno]);
+                codeword_count++;
+                break;
+            case 1: // https://
+                cw[codeword_count] = 280;
+                sublocn += strlen(fragment[fragno]);
+                codeword_count++;
+                break;
+            case 4: // ftp://
+                cw[codeword_count] = 281;
+                sublocn += strlen(fragment[fragno]);
+                codeword_count++;
+                break;
+            default:
+                if (subset == 1) {
+                    cw[codeword_count] = 260; // C43 Compaction Submode C1
+                    codeword_count++;
+                }
+
+                if ((subset == 2) || (subset == 3)) {
+                    cw[codeword_count] = 266; // C43 Compaction Submode C2
+                    codeword_count++;
+                }
+                break;
+        }
+    }
+
+    if (current_mode == ASCII_MODE) {
+        if (subset == 1) {
+            cw[codeword_count] = 278; // C43 Compaction Submode C1
+            codeword_count++;
+        }
+
+        if ((subset == 2) || (subset == 3)) {
+            cw[codeword_count] = 280; // C43 Compaction Submode C2
+            codeword_count++;
+        }
+    }
+    unshift_set = subset;
+
+    while ((sublocn < in_length) && (sublocn < end_char)) {
+        /* Check for FNC1 */
+        if (gs1 && source[sublocn] == '[') {
+            break;
+        }
+
+        new_subset = get_subset(source, in_length, sublocn, subset);
+
+        if (new_subset == 0) {
+            break;
+        }
+
+        if ((new_subset != subset) && ((new_subset == 1) || (new_subset == 2))) {
+            if (c43_should_latch_other(source, in_length, sublocn, subset, gs1)) {
+                subcw[subcodeword_count] = 42; // Latch to other C43 set
+                subcodeword_count++;
+                unshift_set = new_subset;
+            } else {
+                subcw[subcodeword_count] = 40; // Shift to other C43 set for 1 char
+                subcodeword_count++;
+                subcw[subcodeword_count] = posn(new_subset == 1 ? ultra_c43_set1 : ultra_c43_set2, source[sublocn]);
+                subcodeword_count++;
+                sublocn++;
+                continue;
+            }
+        }
+
+        subset = new_subset;
+
+        if (subset == 1) {
+            subcw[subcodeword_count] = posn(ultra_c43_set1, source[sublocn]);
+            subcodeword_count++;
+            sublocn++;
+        }
+
+        if (subset == 2) {
+            subcw[subcodeword_count] = posn(ultra_c43_set2, source[sublocn]);
+            subcodeword_count++;
+            sublocn++;
+        }
+
+        if (subset == 3) {
+            subcw[subcodeword_count] = 41; // Shift to set 3
+            subcodeword_count++;
+
+            fragno = ultra_find_fragment(source, in_length, sublocn);
+            if (fragno == 26) {
+                fragno = -1;
+            }
+            if ((fragno >= 0) && (fragno <= 18)) {
+                subcw[subcodeword_count] = fragno; // C43 Set 3 codewords 0 to 18
+                subcodeword_count++;
+                sublocn += strlen(fragment[fragno]);
+            }
+            if ((fragno >= 19) && (fragno <= 25)) {
+                subcw[subcodeword_count] = fragno + 17; // C43 Set 3 codewords 36 to 42
+                subcodeword_count++;
+                sublocn += strlen(fragment[fragno]);
+            }
+            if (fragno == -1) {
+                subcw[subcodeword_count] = posn(ultra_c43_set3, source[sublocn]) + 19; // C43 Set 3 codewords 19 to 35
+                subcodeword_count++;
+                sublocn++;
+            }
+            subset = unshift_set;
+        }
+    }
+
+    pad = 3 - (subcodeword_count % 3);
+    if (pad == 3) {
+        pad = 0;
+    }
+
+    for (i = 0; i < pad; i++) {
+        subcw[subcodeword_count] = 42; // Latch to other C43 set used as pad
+        subcodeword_count++;
+    }
+
+    if (debug & ZINT_DEBUG_PRINT) {
+        printf("C43 codewords %.*s: (%d)", in_length, source + in_locn, subcodeword_count);
+        for (i = 0; i < subcodeword_count; i++) printf( " %d", subcw[i]);
+        printf("\n");
+    }
+
+    letters_encoded = sublocn - in_locn;
+    if (encoded != NULL) {
+        *encoded = letters_encoded;
+    }
+
+    for (i = 0; i < subcodeword_count; i += 3) {
+        base43_value = (43 * 43 * subcw[i]) + (43 * subcw[i + 1]) + subcw[i + 2];
+        cw[codeword_count] = base43_value / 282;
+        codeword_count++;
+        cw[codeword_count] = base43_value % 282;
+        codeword_count++;
+    }
+
+    *cw_len = codeword_count;
+
+    if (codeword_count == 0) {
+        return 0.0;
+    } else {
+        return (float)letters_encoded / (float)codeword_count;
+    }
+}
+
+/* Produces a set of codewords which are "somewhat" optimised - this could be improved on */
+static int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length, int codewords[]) {
+    int i;
+    int crop_length;
+    int codeword_count = 0;
+    int input_locn = 0;
+    char symbol_mode;
+    char current_mode;
+    int subset;
+    float eightbit_score;
+    float ascii_score;
+    float c43_score;
+    int end_char;
+    int block_length;
+    int fragment_length;
+    int fragno;
+    int gs1 = 0;
+    int ascii_encoded, c43_encoded;
+
+#ifndef _MSC_VER
+    unsigned char crop_source[in_length + 1];
+    char mode[in_length + 1];
+    int cw_fragment[in_length * 2 + 1];
+#else
+    unsigned char * crop_source = (unsigned char *) _alloca((in_length + 1) * sizeof (unsigned char));
+    char * mode = (char *) _alloca((in_length + 1) * sizeof (char));
+    int * cw_fragment = (int *) _alloca((in_length * 2 + 1) * sizeof (int));
+#endif /* _MSC_VER */
+
+    if ((symbol->input_mode & 0x07) == GS1_MODE) {
+        gs1 = 1;
+    }
+
+    // Decide start character codeword (from Table 5)
+    symbol_mode = ASCII_MODE;
+    for (i = 0; i < (int) in_length; i++) {
+        if (source[i] >= 0x80) {
+            symbol_mode = EIGHTBIT_MODE;
+            break;
+        }
+    }
+    
+    if (symbol->option_3 != ULTRA_COMPRESSION && !gs1) {
+        // Force eight-bit mode by default as other modes are poorly documented
+        symbol_mode = EIGHTBIT_MODE;
+    }
+
+    if (symbol->output_options & READER_INIT) {
+        /* Reader Initialisation mode */
+        if (symbol_mode == ASCII_MODE) {
+            codewords[0] = 272; // 7-bit ASCII mode
+            codewords[1] = 271; // FNC3
+        } else {
+            codewords[0] = 257; // 8859-1
+            codewords[1] = 269; // FNC3
+        }
+        codeword_count = 2;
+    } else {
+        /* Calculate start character codeword */
+        if (symbol_mode == ASCII_MODE) {
+            if (gs1) {
+                codewords[0] = 273;
+            } else {
+                codewords[0] = 272;
+            }
+        } else {
+            if ((symbol->eci >= 3) && (symbol->eci <= 18) && (symbol->eci != 14)) {
+                // ECI indicates use of character set within ISO/IEC 8859
+                codewords[0] = 257 + (symbol->eci - 3);
+                if (codewords[0] > 267) {
+                    // Avoids ECI 14 for non-existant ISO/IEC 8859-12
+                    codewords[0]--;
+                }
+            } else if ((symbol->eci > 18) && (symbol->eci <= 898)) {
+                // ECI indicates use of character set outside ISO/IEC 8859
+                codewords[0] = 275 + (symbol->eci / 256);
+                codewords[1] = symbol->eci % 256;
+                codeword_count++;
+            } else if (symbol->eci == 899) {
+                // Non-language byte data
+                codewords[0] = 280;
+            } else if ((symbol->eci > 899) && (symbol->eci <= 9999)) {
+                // ECI beyond 899 needs to use fixed length encodable ECI invocation (section 7.6.2)
+                // Encode as 3 codewords
+                codewords[0] = 257; // ISO/IEC 8859-1 used to enter 8-bit mode
+                codewords[1] = 274; // Encode ECI as 3 codewords
+                codewords[2] = (symbol->eci / 100) + 128;
+                codewords[3] = (symbol->eci % 100) + 128;
+                codeword_count += 3;
+            } else if (symbol->eci >= 10000) {
+                // Encode as 4 codewords
+                codewords[0] = 257; // ISO/IEC 8859-1 used to enter 8-bit mode
+                codewords[1] = 275; // Encode ECI as 4 codewords
+                codewords[2] = (symbol->eci / 10000) + 128;
+                codewords[3] = ((symbol->eci % 10000) / 100) + 128;
+                codewords[4] = (symbol->eci % 100) + 128;
+                codeword_count += 4;
+            } else {
+                codewords[0] = 257; // Default is assumed to be ISO/IEC 8859-1 (ECI 3)
+            }
+        }
+
+        if ((codewords[0] == 257) || (codewords[0] == 272)) {
+            fragno = ultra_find_fragment((unsigned char *)source, in_length, 0);
+
+            // Check for http:// at start of input
+            if ((fragno == 0) || (fragno == 2)) {
+                codewords[0] = 281;
+                input_locn = 7;
+                symbol_mode = EIGHTBIT_MODE;
+            }
+
+
+            // Check for https:// at start of input
+            if ((fragno == 1) || (fragno == 3)) {
+                codewords[0] = 282;
+                input_locn = 8;
+                symbol_mode = EIGHTBIT_MODE;
+            }
+        }
+    }
+
+    codeword_count++;
+
+    /* Check for 06 Macro Sequence and crop accordingly */
+    if (in_length >= 9
+            && source[0] == '[' && source[1] == ')' && source[2] == '>' && source[3] == '\x1e'
+            && source[4] == '0' && source[5] == '6' && source[6] == '\x1d'
+            && source[in_length - 2] == '\x1e' && source[in_length - 1] == '\x04') {
+
+            if (symbol_mode == EIGHTBIT_MODE) {
+                codewords[codeword_count] = 271; // 06 Macro
+            } else {
+                codewords[codeword_count] = 273; // 06 Macro
+            }
+            codeword_count++;
+
+            for (i = 7; i < ((int) in_length - 2); i++) {
+                crop_source[i - 7] = source[i];
+            }
+            crop_length = in_length - 9;
+            crop_source[crop_length] = '\0';
+   } else {
+        /* Make a cropped version of input data - removes http:// and https:// if needed */
+        for (i = input_locn; i < (int) in_length; i++) {
+            crop_source[i - input_locn] = source[i];
+        }
+        crop_length = in_length - input_locn;
+        crop_source[crop_length] = '\0';
+    }
+
+    /* Attempt encoding in all three modes to see which offers best compaction and store results */
+    if (symbol->option_3 == ULTRA_COMPRESSION || gs1) {
+        current_mode = symbol_mode;
+        input_locn = 0;
+        do {
+            end_char = input_locn + PREDICT_WINDOW;
+            eightbit_score = look_ahead_eightbit(crop_source, crop_length, input_locn, current_mode, end_char, cw_fragment, &fragment_length, gs1);
+            ascii_score = look_ahead_ascii(crop_source, crop_length, input_locn, current_mode, symbol_mode, end_char, cw_fragment, &fragment_length, &ascii_encoded, gs1);
+            subset = c43_should_latch_other(crop_source, crop_length, input_locn, 1 /*subset*/, gs1) ? 2 : 1;
+            c43_score = look_ahead_c43(crop_source, crop_length, input_locn, current_mode, end_char, subset, cw_fragment, &fragment_length, &c43_encoded, gs1, 0 /*debug*/);
+
+            mode[input_locn] = 'a';
+            current_mode = ASCII_MODE;
+
+            if ((c43_score > ascii_score) && (c43_score > eightbit_score)) {
+                mode[input_locn] = 'c';
+                current_mode = C43_MODE;
+            }
+
+            if ((eightbit_score > ascii_score) && (eightbit_score > c43_score)) {
+                mode[input_locn] = '8';
+                current_mode = EIGHTBIT_MODE;
+            }
+            if (mode[input_locn] == 'a') {
+                for (i = 0; i < ascii_encoded; i++) {
+                    mode[input_locn + i] = 'a';
+                }
+                input_locn += ascii_encoded;
+            } else if (mode[input_locn] == 'c') {
+                for (i = 0; i < c43_encoded; i++) {
+                    mode[input_locn + i] = 'c';
+                }
+                input_locn += c43_encoded;
+            } else {
+                input_locn++;
+            }
+        } while (input_locn < crop_length);
+    } else {
+        // Force eight-bit mode
+        for (input_locn = 0; input_locn < crop_length; input_locn++) {
+            mode[input_locn] = '8';
+        }
+    }
+    mode[crop_length] = '\0';
+
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("Mode: %s (%d)\n", mode, (int) strlen(mode));
+    }
+
+    /* Use results from test to perform actual mode switching */
+    current_mode = symbol_mode;
+    input_locn = 0;
+    do {
+        fragment_length = 0;
+        block_length = 0;
+        while (input_locn + block_length < crop_length && mode[input_locn + block_length] == mode[input_locn]) {
+            block_length++;
+        }
+
+        switch(mode[input_locn]) {
+            case 'a':
+                look_ahead_ascii(crop_source, crop_length, input_locn, current_mode, symbol_mode, input_locn + block_length, cw_fragment, &fragment_length, NULL, gs1);
+                current_mode = ASCII_MODE;
+                break;
+            case 'c':
+                subset = c43_should_latch_other(crop_source, crop_length, input_locn, 1 /*subset*/, gs1) ? 2 : 1;
+                look_ahead_c43(crop_source, crop_length, input_locn, current_mode, input_locn + block_length, subset, cw_fragment, &fragment_length, NULL, gs1, symbol->debug);
+
+                /* Substitute temporary latch if possible */
+                if ((current_mode == EIGHTBIT_MODE) && (cw_fragment[0] == 260) && (fragment_length >= 5) && (fragment_length <= 11)) {
+                    /* Temporary latch to submode 1 from Table 11 */
+                    cw_fragment[0] = 256 + ((fragment_length - 5) / 2);
+                } else if ((current_mode == EIGHTBIT_MODE) && (cw_fragment[0] == 266) && (fragment_length >= 5) && (fragment_length <= 11)) {
+                    /* Temporary latch to submode 2 from Table 11 */
+                    cw_fragment[0] = 262 + ((fragment_length - 5) / 2);
+                } else if ((current_mode == ASCII_MODE) && (cw_fragment[0] == 278) && (fragment_length >= 5) && (fragment_length <= 11)) {
+                    /* Temporary latch to submode 1 from Table 9 */
+                    cw_fragment[0] = 274 + ((fragment_length - 5) / 2);
+                } else {
+                    current_mode = C43_MODE;
+                }
+                break;
+            case '8':
+                look_ahead_eightbit(crop_source, crop_length, input_locn, current_mode, input_locn + block_length, cw_fragment, &fragment_length, gs1);
+                current_mode = EIGHTBIT_MODE;
+                break;
+        }
+
+        for (i = 0; i < fragment_length; i++) {
+            codewords[codeword_count + i] = cw_fragment[i];
+        }
+        codeword_count += fragment_length;
+
+        input_locn += block_length;
+    } while (input_locn < crop_length);
+
+    return codeword_count;
+}
+
+INTERNAL int ultracode(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) {
+    int data_cw_count = 0;
+    int acc, qcc;
+    int ecc_level;
+    int rows, columns;
+    int total_cws;
+    int pads;
+    int cw_memalloc;
+    int codeword[282 + 3]; // Allow for 3 pads in final 57th (60th incl. clock tracks) column of 5-row symbol (57 * 5 == 285)
+    int i, j, locn;
+    int total_height, total_width;
+    char tilepat[6];
+    int tilex, tiley;
+    int dcc;
+#ifdef _MSC_VER
+    int* data_codewords;
+    char* pattern;
+#endif /* _MSC_VER */
+
+    cw_memalloc = in_length * 2;
+    if (cw_memalloc < 283) {
+        cw_memalloc = 283;
+    }
+
+    if (symbol->eci > 811799) {
+        strcpy(symbol->errtxt, "590: ECI value not supported by Ultracode");
+        return ZINT_ERROR_INVALID_OPTION;
+    }
+
+#ifndef _MSC_VER
+    int data_codewords[cw_memalloc];
+#else
+    data_codewords = (int *) _alloca(cw_memalloc * sizeof (int));
+#endif /* _MSC_VER */
+
+    data_cw_count = ultra_generate_codewords(symbol, source, in_length, data_codewords);
+
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("Codewords returned = %d\n", data_cw_count);
+    }
+#ifdef ZINT_TEST
+    if (symbol->debug & ZINT_DEBUG_TEST) {
+        debug_test_codeword_dump_int(symbol, data_codewords, data_cw_count);
+    }
+#endif
+
+    data_cw_count += 2; // 2 == MCC + ACC (data codeword count includes start char)
+
+    /* Default ECC level is EC2 */
+    if ((symbol->option_1 <= 0) || (symbol->option_1 > 6)) {
+        ecc_level = 2;
+    } else {
+        ecc_level = symbol->option_1 - 1;
+    }
+
+    /* ECC calculation from section 7.7.2 */
+    if (ecc_level == 0) {
+        qcc = 3;
+    } else {
+        if ((data_cw_count % 25) == 0) {
+            qcc = (kec[ecc_level] * (data_cw_count / 25)) + 3 + 2;
+        } else {
+            qcc = (kec[ecc_level] * ((data_cw_count / 25) + 1)) + 3 + 2;
+        }
+
+    }
+    acc = qcc - 3;
+
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("ECC codewords: %d\n", qcc);
+    }
+
+    /* Maximum capacity is 282 codewords */
+    total_cws = data_cw_count + qcc + 3; // 3 == TCC pattern + RSEC pattern + QCC pattern
+    if (total_cws > 282) {
+        strcpy(symbol->errtxt, "591: Data too long for selected error correction capacity");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    rows = 5;
+    for (i = 2; i >= 0; i--) {
+        if (total_cws - 6 <= ultra_maxsize[i]) { // Total codewords less 6 overhead (Start + MCC + ACC + 3 TCC/RSEC/QCC patterns)
+            rows--;
+        }
+    }
+
+    if ((total_cws % rows) == 0) {
+        pads = 0;
+        columns = total_cws / rows;
+    } else {
+        pads = rows - (total_cws % rows);
+        columns = (total_cws / rows) + 1;
+    }
+    columns += columns / 15; // Secondary vertical clock tracks
+
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("Calculated size is %d rows by %d columns\n", rows, columns);
+    }
+
+    /* Insert MCC and ACC into data codewords */
+    for (i = 282; i > 2; i--) {
+        data_codewords[i] = data_codewords[i - 2];
+    }
+    data_codewords[1] = data_cw_count; // MCC
+    data_codewords[2] = acc; // ACC
+
+    locn = 0;
+    /* Calculate error correction codewords (RSEC) */
+    ultra_gf283((short) data_cw_count, (short) qcc, data_codewords);
+
+    /* Rearrange to make final codeword sequence */
+    codeword[locn++] = data_codewords[282 - (data_cw_count + qcc)]; // Start Character
+    codeword[locn++] = data_cw_count; // MCC
+    for (i = 0; i < qcc; i++) {
+        codeword[locn++] = data_codewords[(282 - qcc) + i]; // RSEC Region
+    }
+    codeword[locn++] = data_cw_count + qcc; // TCC = C + Q - section 6.11.4
+    codeword[locn++] = 283; // Separator
+    codeword[locn++] = acc; // ACC
+    for (i = 0; i < (data_cw_count - 3); i++) {
+        codeword[locn++] = data_codewords[(282 - ((data_cw_count - 3) + qcc)) + i]; // Data Region
+    }
+    for (i = 0; i < pads; i++) {
+        codeword[locn++] = 284; // Pad pattern
+    }
+    codeword[locn++] = qcc; // QCC
+
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("Rearranged codewords with ECC:\n");
+        for (i = 0; i < locn; i++) {
+            printf("%d ", codeword[i]);
+        }
+        printf("\n");
+    }
+
+    total_height = (rows * 6) + 1;
+    total_width = columns + 6;
+
+    /* Build symbol */
+#ifndef _MSC_VER
+    char pattern[total_height * total_width];
+#else
+    pattern = (char *) _alloca(total_height * total_width * sizeof (char));
+#endif /* _MSC_VER */
+
+    for (i = 0; i < (total_height * total_width); i++) {
+        pattern[i] = 'W';
+    }
+
+    /* Border */
+    for (i = 0; i < total_width; i++) {
+        pattern[i] = 'K'; // Top
+        pattern[(total_height * total_width) - i - 1] = 'K'; // Bottom
+    }
+    for (i = 0; i < total_height; i++) {
+        pattern[total_width * i] = 'K'; // Left
+        pattern[(total_width * i) + 3] = 'K';
+        pattern[(total_width * i) + (total_width - 1)] = 'K'; // Right
+    }
+
+    /* Clock tracks */
+    for (i = 0; i < total_height; i += 2) {
+        pattern[(total_width * i) + 1] = 'K'; // Primary vertical clock track
+        if (total_width > 20) {
+            pattern[(total_width * i) + 19] = 'K'; // Secondary vertical clock track
+        }
+        if (total_width > 36) {
+            pattern[(total_width * i) + 35] = 'K'; // Secondary vertical clock track
+        }
+        if (total_width > 52) {
+            pattern[(total_width * i) + 51] = 'K'; // Secondary vertical clock track
+        }
+    }
+    for (i = 6; i < total_height; i += 6) {
+        for (j = 5; j < total_width; j += 2) {
+            pattern[(total_width * i) + j] = 'K'; // Horizontal clock track
+        }
+    }
+
+    /* Place tiles */
+    tilepat[5] = '\0';
+    tilex = 0;
+    tiley = 0;
+    for (i = 0; i < locn; i++) {
+        for (j = 0; j < 5; j++) {
+            tilepat[4 - j] = ultra_colour[(tiles[codeword[i]] >> (3 * j)) & 0x07];
+        }
+        if ((tiley + 1) >= total_height) {
+            tiley = 0;
+            tilex++;
+
+            if (tilex == 14) {
+                tilex++;
+            }
+            if (tilex == 30) {
+                tilex++;
+            }
+            if (tilex == 46) {
+                tilex++;
+            }
+        }
+
+        for (j = 0; j < 5; j++) {
+            pattern[((tiley + j + 1) * total_width) + (tilex + 5)] = tilepat[j];
+        }
+        tiley += 6;
+    }
+
+    /* Add data column count */
+    dcc = columns - ultra_mincols[rows - 2];
+    tilex = 2;
+    tiley = (total_height - 11) / 2;
+    /* DCCU */
+    for (j = 0; j < 5; j++) {
+        tilepat[4 - j] = ultra_colour[(dccu[dcc] >> (3 * j)) & 0x07];
+    }
+    for (j = 0; j < 5; j++) {
+        pattern[((tiley + j) * total_width) + tilex] = tilepat[j];
+    }
+    /* DCCL */
+    tiley += 6;
+    for (j = 0; j < 5; j++) {
+        tilepat[4 - j] = ultra_colour[(dccl[dcc] >> (3 * j)) & 0x07];
+    }
+    for (j = 0; j < 5; j++) {
+        pattern[((tiley + j) * total_width) + tilex] = tilepat[j];
+    }
+
+    if (symbol->debug & ZINT_DEBUG_PRINT) {
+        printf("DCC: %d\n", dcc);
+
+        for (i = 0; i < (total_height * total_width); i++) {
+            printf("%c", pattern[i]);
+            if ((i + 1) % total_width == 0) {
+                printf("\n");
+            }
+        }
+    }
+
+    /* Put pattern into symbol */
+    symbol->rows = total_height;
+    symbol->width = total_width;
+
+    for (i = 0; i < total_height; i++) {
+        symbol->row_height[i] = 1;
+        for(j = 0; j < total_width; j++) {
+            set_module_colour(symbol, i, j, posn(ultra_colour, pattern[(i * total_width) + j]));
+        }
+    }
+
+    return 0;
+}
index c99091b..15fac07 100644 (file)
@@ -1,7 +1,7 @@
 /*  upcean.c - Handles UPC, EAN and ISBN
 
     libzint - the open source barcode library
-    Copyright (C) 2008 Robin Stuart <robin@zint.org.uk>
+    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
@@ -27,7 +27,8 @@
     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     SUCH DAMAGE.
-*/
+ */
+/* vim: set ts=4 sw=4 et : */
 
 #define SODIUM "0123456789+"
 #define EAN2   102
 
 /* UPC and EAN tables checked against EN 797:1996 */
 
-static const char *UPCParity0[10] = {"BBBAAA", "BBABAA", "BBAABA", "BBAAAB", "BABBAA", "BAABBA", "BAAABB",
-       "BABABA", "BABAAB", "BAABAB"}; /* Number set for UPC-E symbol (EN Table 4) */
-static const char *UPCParity1[10] = {"AAABBB", "AABABB", "AABBAB", "AABBBA", "ABAABB", "ABBAAB", "ABBBAA",
-       "ABABAB", "ABABBA", "ABBABA"}; /* Not covered by BS EN 797:1995 */
-static const char *EAN2Parity[4] = {"AA", "AB", "BA", "BB"}; /* Number sets for 2-digit add-on (EN Table 6) */
-static const char *EAN5Parity[10] = {"BBAAA", "BABAA", "BAABA", "BAAAB", "ABBAA", "AABBA", "AAABB", "ABABA",
-       "ABAAB", "AABAB"}; /* Number set for 5-digit add-on (EN Table 7) */
-static const char *EAN13Parity[10] = {"AAAAA", "ABABB", "ABBAB", "ABBBA", "BAABB", "BBAAB", "BBBAA", "BABAB",
-       "BABBA", "BBABA"}; /* Left hand of the EAN-13 symbol (EN Table 3) */
-static const char *EANsetA[10] = {"3211", "2221", "2122", "1411", "1132", "1231", "1114", "1312", "1213",
-       "3112"}; /* Representation set A and C (EN Table 1) */
-static const char *EANsetB[10] = {"1123", "1222", "2212", "1141", "2311", "1321", "4111", "2131", "3121",
-       "2113"}; /* Representation set B (EN Table 1) */
-
-char upc_check(char source[])
-{ /* Calculate the correct check digit for a UPC barcode */
-       unsigned int i, count, check_digit;
-
-       count = 0;
-
-       for (i = 0; i < strlen(source); 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; }
-       return itoc(check_digit);
+static const char *UPCParity0[10] = {
+    /* Number set for UPC-E symbol (EN Table 4) */
+    "BBBAAA", "BBABAA", "BBAABA", "BBAAAB", "BABBAA", "BAABBA", "BAAABB",
+    "BABABA", "BABAAB", "BAABAB"
+};
+
+static const char *UPCParity1[10] = {
+    /* Not covered by BS EN 797:1995 */
+    "AAABBB", "AABABB", "AABBAB", "AABBBA", "ABAABB", "ABBAAB", "ABBBAA",
+    "ABABAB", "ABABBA", "ABBABA"
+};
+
+static const char *EAN2Parity[4] = {
+    /* Number sets for 2-digit add-on (EN Table 6) */
+    "AA", "AB", "BA", "BB"
+};
+
+static const char *EAN5Parity[10] = {
+    /* Number set for 5-digit add-on (EN Table 7) */
+    "BBAAA", "BABAA", "BAABA", "BAAAB", "ABBAA", "AABBA", "AAABB", "ABABA",
+    "ABAAB", "AABAB"
+};
+
+static const char *EAN13Parity[10] = {
+    /* Left hand of the EAN-13 symbol (EN Table 3) */
+    "AAAAA", "ABABB", "ABBAB", "ABBBA", "BAABB", "BBAAB", "BBBAA", "BABAB",
+    "BABBA", "BBABA"
+};
+
+static const char *EANsetA[10] = {
+    /* Representation set A and C (EN Table 1) */
+    "3211", "2221", "2122", "1411", "1132", "1231", "1114", "1312", "1213", "3112"
+};
+
+static const char *EANsetB[10] = {
+    /* Representation set B (EN Table 1) */
+    "1123", "1222", "2212", "1141", "2311", "1321", "4111", "2131", "3121", "2113"
+};
+
+/* Calculate the correct check digit for a UPC barcode */
+static char upc_check(char source[]) {
+    unsigned int i, count, check_digit;
+
+    count = 0;
+
+    for (i = 0; i < strlen(source); 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;
+    }
+    return itoc(check_digit);
 }
 
-void upca_draw(char source[], char dest[])
-{ /* UPC A is usually used for 12 digit numbers, but this function takes a source of any length */
-       unsigned int i, half_way;
+/* UPC A is usually used for 12 digit numbers, but this function takes a source of any length */
+static void upca_draw(char source[], char dest[]) {
+    unsigned int i, half_way;
 
-       half_way = strlen(source) / 2;
+    half_way = strlen(source) / 2;
 
-       /* start character */
-       concat (dest, "111");
+    /* start character */
+    strcat(dest, "111");
 
-       for(i = 0; i <= strlen(source); i++)
-       {
-               if (i == half_way)
-               {
-                       /* middle character - separates manufacturer no. from product no. */
-                       /* also inverts right hand characters */
-                       concat(dest, "11111");
-               }
+    for (i = 0; i <= strlen(source); i++) {
+        if (i == half_way) {
+            /* middle character - separates manufacturer no. from product no. */
+            /* also inverts right hand characters */
+            strcat(dest, "11111");
+        }
 
-               lookup(NEON, EANsetA, source[i], dest);
-       }
+        lookup(NEON, EANsetA, source[i], dest);
+    }
 
-       /* stop character */
-       concat (dest, "111");
+    /* stop character */
+    strcat(dest, "111");
 }
 
-void upca(struct zint_symbol *symbol, unsigned char source[], char dest[])
-{ /* Make a UPC A barcode when we haven't been given the check digit */
-       int length;
-       char gtin[15];
-
-       strcpy(gtin, (char*)source);
-       length = strlen(gtin);
-       gtin[length] = upc_check(gtin);
-       gtin[length + 1] = '\0';
-       upca_draw(gtin, dest);
-       ustrcpy(symbol->text, (unsigned char*)gtin);
+/* Make a UPC A barcode when we haven't been given the check digit */
+static int upca(struct zint_symbol *symbol, unsigned char source[], char dest[]) {
+    int length;
+    char gtin[15];
+
+    strcpy(gtin, (char*) source);
+    length = strlen(gtin);
+
+    if (length == 11) {
+        gtin[length] = upc_check(gtin);
+        gtin[length + 1] = '\0';
+    } else {
+        gtin[length - 1] = '\0';
+        if (source[length - 1] != upc_check(gtin)) {
+            strcpy(symbol->errtxt, "270: Invalid check digit");
+            return ZINT_ERROR_INVALID_CHECK;
+        }
+        gtin[length - 1] = upc_check(gtin);
+    }
+    upca_draw(gtin, dest);
+    ustrcpy(symbol->text, (unsigned char*) gtin);
+    return 0;
 }
 
-void upce(struct zint_symbol *symbol, unsigned char source[], char dest[])
-{ /* UPC E is a zero-compressed version of UPC A */
-       unsigned int i, num_system;
-       char emode, equivalent[12], check_digit, parity[8], temp[8];
-       char hrt[9];
-
-       /* Two number systems can be used - system 0 and system 1 */
-       if(ustrlen(source) == 7) {
-               switch(source[0]) {
-                       case '0': num_system = 0; break;
-                       case '1': num_system = 1; break;
-                       default: num_system = 0; source[0] = '0'; break;
-               }
-               strcpy(temp, (char*)source);
-               strcpy(hrt, (char*)source);
-               for(i = 1; i <= 7; i++) {
-                       source[i - 1] = temp[i];
-               }
-       }
-       else {
-               num_system = 0;
-               hrt[0] = '0';
-               hrt[1] = '\0';
-               concat(hrt, (char*)source);
-       }
-
-       /* Expand the zero-compressed UPCE code to make a UPCA equivalent (EN Table 5) */
-       emode = source[5];
-       for(i = 0; i < 11; i++) {
-               equivalent[i] = '0';
-       }
-       if(num_system == 1) { equivalent[0] = temp[0]; }
-       equivalent[1] = source[0];
-       equivalent[2] = source[1];
-       equivalent[11] = '\0';
-
-       switch(emode)
-       {
-               case '0':
-               case '1':
-               case '2':
-                       equivalent[3] = emode;
-                       equivalent[8] = source[2];
-                       equivalent[9] = source[3];
-                       equivalent[10] = source[4];
-                       break;
-               case '3':
-                       equivalent[3] = source[2];
-                       equivalent[9] = source[3];
-                       equivalent[10] = source[4];
-                       if(((source[2] == '0') || (source[2] == '1')) || (source[2] == '2')) {
-                               /* Note 1 - "X3 shall not be equal to 0, 1 or 2" */
-                               strcpy(symbol->errtxt, "Invalid UPC-E data");
-                       }
-                       break;
-               case '4':
-                       equivalent[3] = source[2];
-                       equivalent[4] = source[3];
-                       equivalent[10] = source[4];
-                       if(source[3] == '0') {
-                               /* Note 2 - "X4 shall not be equal to 0" */
-                               strcpy(symbol->errtxt, "Invalid UPC-E data");
-                       }
-                       break;
-               case '5':
-               case '6':
-               case '7':
-               case '8':
-               case '9':
-                       equivalent[3] = source[2];
-                       equivalent[4] = source[3];
-                       equivalent[5] = source[4];
-                       equivalent[10] = emode;
-                       if(source[4] == '0') {
-                               /* Note 3 - "X5 shall not be equal to 0" */
-                               strcpy(symbol->errtxt, "Invalid UPC-E data");
-                       }
-                       break;
-       }
-
-       /* Get the check digit from the expanded UPCA code */
-
-       check_digit = upc_check(equivalent);
-
-       /* Use the number system and check digit information to choose a parity scheme */
-       if(num_system == 1) {
-               strcpy(parity, UPCParity1[ctoi(check_digit)]);
-       } else {
-               strcpy(parity, UPCParity0[ctoi(check_digit)]);
-       }
-
-       /* Take all this information and make the barcode pattern */
-
-       /* start character */
-       concat (dest, "111");
-
-       for(i = 0; i <= ustrlen(source); i++) {
-               switch(parity[i]) {
-                       case 'A': lookup(NEON, EANsetA, source[i], dest); break;
-                       case 'B': lookup(NEON, EANsetB, source[i], dest); break;
-               }
-       }
-
-       /* stop character */
-       concat (dest, "111111");
-       
-       hrt[7] = check_digit;
-       hrt[8] = '\0';
-       ustrcpy(symbol->text, (unsigned char*)hrt);
+/* UPC E is a zero-compressed version of UPC A */
+static int upce(struct zint_symbol *symbol, unsigned char source[], char dest[]) {
+    unsigned int i, num_system;
+    char emode, equivalent[12], check_digit, parity[8], temp[9];
+    char hrt[9];
+
+    /* Two number systems can be used - system 0 and system 1 */
+    if (symbol->symbology != BARCODE_UPCE_CHK) {
+        /* No check digit in input data */
+        if (ustrlen(source) == 7) {
+            switch (source[0]) {
+                case '0': num_system = 0;
+                    break;
+                case '1': num_system = 1;
+                    break;
+                default: num_system = 0;
+                    source[0] = '0';
+                    break;
+            }
+            strcpy(temp, (char*) source);
+            strcpy(hrt, (char*) source);
+            for (i = 1; i <= 7; i++) {
+                source[i - 1] = temp[i];
+            }
+        } else {
+            num_system = 0;
+            hrt[0] = '0';
+            hrt[1] = '\0';
+            strcat(hrt, (char*) source);
+        }
+    } else {
+        /* Check digit is included in input data */
+        if (ustrlen(source) == 8) {
+            switch (source[0]) {
+                case '0': num_system = 0;
+                    break;
+                case '1': num_system = 1;
+                    break;
+                default: num_system = 0;
+                    source[0] = '0';
+                    break;
+            }
+            strcpy(temp, (char*) source);
+            strcpy(hrt, (char*) source);
+            for (i = 1; i <= 8; i++) {
+                source[i - 1] = temp[i];
+            }
+        } else {
+            num_system = 0;
+            hrt[0] = '0';
+            hrt[1] = '\0';
+            strcat(hrt, (char*) source);
+        }
+    }
+
+    /* Expand the zero-compressed UPCE code to make a UPCA equivalent (EN Table 5) */
+    emode = source[5];
+    for (i = 0; i < 11; i++) {
+        equivalent[i] = '0';
+    }
+    if (num_system == 1) {
+        equivalent[0] = temp[0];
+    }
+    equivalent[1] = source[0];
+    equivalent[2] = source[1];
+    equivalent[11] = '\0';
+
+    switch (emode) {
+        case '0':
+        case '1':
+        case '2':
+            equivalent[3] = emode;
+            equivalent[8] = source[2];
+            equivalent[9] = source[3];
+            equivalent[10] = source[4];
+            break;
+        case '3':
+            equivalent[3] = source[2];
+            equivalent[9] = source[3];
+            equivalent[10] = source[4];
+            if (((source[2] == '0') || (source[2] == '1')) || (source[2] == '2')) {
+                /* Note 1 - "X3 shall not be equal to 0, 1 or 2" */
+                strcpy(symbol->errtxt, "271: Invalid UPC-E data");
+                return ZINT_ERROR_INVALID_DATA;
+            }
+            break;
+        case '4':
+            equivalent[3] = source[2];
+            equivalent[4] = source[3];
+            equivalent[10] = source[4];
+            if (source[3] == '0') {
+                /* Note 2 - "X4 shall not be equal to 0" */
+                strcpy(symbol->errtxt, "272: Invalid UPC-E data");
+                return ZINT_ERROR_INVALID_DATA;
+            }
+            break;
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+            equivalent[3] = source[2];
+            equivalent[4] = source[3];
+            equivalent[5] = source[4];
+            equivalent[10] = emode;
+            if (source[4] == '0') {
+                /* Note 3 - "X5 shall not be equal to 0" */
+                strcpy(symbol->errtxt, "273: Invalid UPC-E data");
+                return ZINT_ERROR_INVALID_DATA;
+            }
+            break;
+    }
+
+    /* Get the check digit from the expanded UPCA code */
+
+    check_digit = upc_check(equivalent);
+
+    /* Use the number system and check digit information to choose a parity scheme */
+    if (num_system == 1) {
+        strcpy(parity, UPCParity1[ctoi(check_digit)]);
+    } else {
+        strcpy(parity, UPCParity0[ctoi(check_digit)]);
+    }
+
+    /* Take all this information and make the barcode pattern */
+
+    /* start character */
+    strcat(dest, "111");
+
+    for (i = 0; i <= ustrlen(source); i++) {
+        switch (parity[i]) {
+            case 'A': lookup(NEON, EANsetA, source[i], dest);
+                break;
+            case 'B': lookup(NEON, EANsetB, source[i], dest);
+                break;
+        }
+    }
+
+    /* stop character */
+    strcat(dest, "111111");
+
+    if (symbol->symbology != BARCODE_UPCE_CHK) {
+        hrt[7] = check_digit;
+        hrt[8] = '\0';
+    } else {
+        if (hrt[7] != check_digit) {
+            strcpy(symbol->errtxt, "274: Invalid check digit");
+            return ZINT_ERROR_INVALID_CHECK;
+        }
+    }
+    ustrcpy(symbol->text, (unsigned char*) hrt);
+    return 0;
 }
 
-
-void add_on(unsigned char source[], char dest[], int mode)
-{ /* EAN-2 and EAN-5 add-on codes */
-       char parity[6];
-       unsigned int i, code_type;
-
-       /* If an add-on then append with space */
-       if (mode != 0)
-       {
-               concat(dest, "9");
-       }
-
-       /* Start character */
-       concat (dest, "112");
-
-       /* Determine EAN2 or EAN5 add-on */
-       if(ustrlen(source) == 2)
-       {
-               code_type = EAN2;
-       }
-       else
-       {
-               code_type = EAN5;
-       }
-
-       /* Calculate parity for EAN2 */
-       if(code_type == EAN2)
-       {
-               int code_value, parity_bit;
-
-               code_value = (10 * ctoi(source[0])) + ctoi(source[1]);
-               parity_bit = code_value%4;
-               strcpy(parity, EAN2Parity[parity_bit]);
-       }
-
-       if(code_type == EAN5)
-       {
-               int values[6], parity_sum, parity_bit;
-
-               for(i = 0; i < 6; i++)
-               {
-                       values[i] = ctoi(source[i]);
-               }
-
-               parity_sum = (3 * (values[0] + values[2] + values[4]));
-               parity_sum += (9 * (values[1] + values[3]));
-
-               parity_bit = parity_sum%10;
-               strcpy(parity, EAN5Parity[parity_bit]);
-       }
-
-       for(i = 0; i < ustrlen(source); i++)
-       {
-               switch(parity[i]) {
-                       case 'A': lookup(NEON, EANsetA, source[i], dest); break;
-                       case 'B': lookup(NEON, EANsetB, source[i], dest); break;
-               }
-
-               /* Glyph separator */
-               if(i != (ustrlen(source) - 1))
-               {
-                       concat (dest, "11");
-               }
-       }
+/* EAN-2 and EAN-5 add-on codes */
+static void add_on(unsigned char source[], char dest[], int mode) {
+    char parity[6];
+    unsigned int i, code_type;
+
+    /* If an add-on then append with space */
+    if (mode != 0) {
+        strcat(dest, "9");
+    }
+
+    /* Start character */
+    strcat(dest, "112");
+
+    /* Determine EAN2 or EAN5 add-on */
+    if (ustrlen(source) == 2) {
+        code_type = EAN2;
+    } else {
+        code_type = EAN5;
+    }
+
+    /* Calculate parity for EAN2 */
+    if (code_type == EAN2) {
+        int code_value, parity_bit;
+
+        code_value = (10 * ctoi(source[0])) + ctoi(source[1]);
+        parity_bit = code_value % 4;
+        strcpy(parity, EAN2Parity[parity_bit]);
+    }
+
+    if (code_type == EAN5) {
+        int values[6], parity_sum, parity_bit;
+
+        for (i = 0; i < 6; i++) {
+            values[i] = ctoi(source[i]);
+        }
+
+        parity_sum = (3 * (values[0] + values[2] + values[4]));
+        parity_sum += (9 * (values[1] + values[3]));
+
+        parity_bit = parity_sum % 10;
+        strcpy(parity, EAN5Parity[parity_bit]);
+    }
+
+    for (i = 0; i < ustrlen(source); i++) {
+        switch (parity[i]) {
+            case 'A': lookup(NEON, EANsetA, source[i], dest);
+                break;
+            case 'B': lookup(NEON, EANsetB, source[i], dest);
+                break;
+        }
+
+        /* Glyph separator */
+        if (i != (ustrlen(source) - 1)) {
+            strcat(dest, "11");
+        }
+    }
 }
 
-
 /* ************************ EAN-13 ****************** */
 
-char ean_check(char source[])
-{ /* Calculate the correct check digit for a EAN-13 barcode */
-       int i;
-       unsigned int h, count, check_digit;
-
-       count = 0;
-
-       h = strlen(source);
-       for (i = h - 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; }
-       return itoc(check_digit);
+/* Calculate the correct check digit for a EAN-13 barcode */
+static char ean_check(char source[]) {
+    int i;
+    unsigned int h, count, check_digit;
+
+    count = 0;
+
+    h = strlen(source);
+    for (i = h - 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;
+    }
+    return itoc(check_digit);
 }
 
-void ean13(struct zint_symbol *symbol, unsigned char source[], char dest[])
-{
-       unsigned int length, i, half_way;
-       char parity[6];
-       char gtin[15];
-
-       strcpy(parity, "");
-       strcpy(gtin, (char*)source);
-       
-       /* Add the appropriate check digit */
-       length = strlen(gtin);
-       gtin[length] = ean_check(gtin);
-       gtin[length + 1] = '\0';
-
-       /* Get parity for first half of the symbol */
-       lookup(SODIUM, EAN13Parity, gtin[0], parity);
-
-       /* Now get on with the cipher */
-       half_way = 7;
-
-       /* start character */
-       concat (dest, "111");
-       length = strlen(gtin);
-       for(i = 1; i <= length; i++)
-       {
-               if (i == half_way)
-               {
-                       /* middle character - separates manufacturer no. from product no. */
-                       /* also inverses right hand characters */
-                       concat (dest, "11111");
-               }
-
-               if(((i > 1) && (i < 7)) && (parity[i - 2] == 'B'))
-               {
-                       lookup(NEON, EANsetB, gtin[i], dest);
-               }
-               else
-               {
-                       lookup(NEON, EANsetA, gtin[i], dest);
-               }
-       }
-
-       /* stop character */
-       concat (dest, "111");
-       
-       ustrcpy(symbol->text, (unsigned char*)gtin);
+static int ean13(struct zint_symbol *symbol, unsigned char source[], char dest[]) {
+    unsigned int length, i, half_way;
+    char parity[6];
+    char gtin[15];
+
+    strcpy(parity, "");
+    strcpy(gtin, (char*) source);
+
+    /* Add the appropriate check digit */
+    length = strlen(gtin);
+
+    if (length == 12) {
+        gtin[length] = ean_check(gtin);
+        gtin[length + 1] = '\0';
+    } else {
+        gtin[length - 1] = '\0';
+        if (source[length - 1] != ean_check(gtin)) {
+            strcpy(symbol->errtxt, "275: Invalid check digit");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+        gtin[length - 1] = ean_check(gtin);
+    }
+
+    /* Get parity for first half of the symbol */
+    lookup(SODIUM, EAN13Parity, gtin[0], parity);
+
+    /* Now get on with the cipher */
+    half_way = 7;
+
+    /* start character */
+    strcat(dest, "111");
+    length = strlen(gtin);
+    for (i = 1; i <= length; i++) {
+        if (i == half_way) {
+            /* middle character - separates manufacturer no. from product no. */
+            /* also inverses right hand characters */
+            strcat(dest, "11111");
+        }
+
+        if (((i > 1) && (i < 7)) && (parity[i - 2] == 'B')) {
+            lookup(NEON, EANsetB, gtin[i], dest);
+        } else {
+            lookup(NEON, EANsetA, gtin[i], dest);
+        }
+    }
+
+    /* stop character */
+    strcat(dest, "111");
+
+    ustrcpy(symbol->text, (unsigned char*) gtin);
+    return 0;
 }
 
-void ean8(struct zint_symbol *symbol, unsigned char source[], char dest[])
-{ /* Make an EAN-8 barcode when we haven't been given the check digit */
-  /* EAN-8 is basically the same as UPC-A but with fewer digits */
-       int length;
-       char gtin[10];
-
-       strcpy(gtin, (char*)source);
-       length = strlen(gtin);
-       gtin[length] = upc_check(gtin);
-       gtin[length + 1] = '\0';
-       upca_draw(gtin, dest);
-       ustrcpy(symbol->text, (unsigned char*)gtin);
+/* Make an EAN-8 barcode when we haven't been given the check digit */
+static int ean8(struct zint_symbol *symbol, unsigned char source[], char dest[]) {
+    /* EAN-8 is basically the same as UPC-A but with fewer digits */
+    int length;
+    char gtin[10];
+
+    strcpy(gtin, (char*) source);
+    length = strlen(gtin);
+
+    if (length == 7) {
+        gtin[length] = upc_check(gtin);
+        gtin[length + 1] = '\0';
+    } else {
+        gtin[length - 1] = '\0';
+        if (source[length - 1] != upc_check(gtin)) {
+            strcpy(symbol->errtxt, "276: Invalid check digit");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+        gtin[length - 1] = upc_check(gtin);
+    }
+    upca_draw(gtin, dest);
+    ustrcpy(symbol->text, (unsigned char*) gtin);
+
+    return 0;
 }
 
-char isbn13_check(unsigned char source[]) /* For ISBN(13) only */
-{
-       unsigned int i, weight, sum, check, h;
+/* For ISBN(13) only */
+static char isbn13_check(unsigned char source[]) {
+    unsigned int i, weight, sum, check, h;
 
-       sum = 0;
-       weight = 1;
-       h = ustrlen(source) - 1;
+    sum = 0;
+    weight = 1;
+    h = ustrlen(source) - 1;
 
-       for(i = 0; i < h; i++)
-       {
-               sum += ctoi(source[i]) * weight;
-               if(weight == 1) weight = 3; else weight = 1;
-       }
+    for (i = 0; i < h; i++) {
+        sum += ctoi(source[i]) * weight;
+        if (weight == 1) weight = 3;
+        else weight = 1;
+    }
 
-       check = sum % 10;
-       check = 10 - check;
-       if(check == 10) check = 0;
-       return itoc(check);
+    check = sum % 10;
+    check = 10 - check;
+    if (check == 10) check = 0;
+    return itoc(check);
 }
 
-char isbn_check(unsigned char source[]) /* For ISBN(10) and SBN only */
-{
-       unsigned int i, weight, sum, check, h;
-       char check_char;
-
-       sum = 0;
-       weight = 1;
-       h = ustrlen(source) - 1;
-
-       for(i = 0; i < h; i++)
-       {
-               sum += ctoi(source[i]) * weight;
-               weight++;
-       }
-
-       check = sum % 11;
-       check_char = itoc(check);
-       if(check == 10) { check_char = 'X'; }
-       return check_char;
+/* For ISBN(10) and SBN only */
+static char isbn_check(unsigned char source[]) {
+    unsigned int i, weight, sum, check, h;
+    char check_char;
+
+    sum = 0;
+    weight = 1;
+    h = ustrlen(source) - 1;
+
+    for (i = 0; i < h; i++) {
+        sum += ctoi(source[i]) * weight;
+        weight++;
+    }
+
+    check = sum % 11;
+    check_char = itoc(check);
+    if (check == 10) {
+        check_char = 'X';
+    }
+    return check_char;
 }
 
-int isbn(struct zint_symbol *symbol, unsigned char source[], const unsigned int src_len, char dest[]) /* Make an EAN-13 barcode from an SBN or ISBN */
-{
-       int i, error_number;
-       char check_digit;
-       
-       to_upper(source);
-       error_number = is_sane("0123456789X", source, src_len);
-       if(error_number == ERROR_INVALID_DATA) {
-               strcpy(symbol->errtxt, "Invalid characters in input");
-               return error_number;
-       }
-
-       /* Input must be 9, 10 or 13 characters */
-       if(((src_len < 9) || (src_len > 13)) || ((src_len > 10) && (src_len < 13)))
-       {
-               strcpy(symbol->errtxt, "Input wrong length");
-               return ERROR_TOO_LONG;
-       }
-
-       if(src_len == 13) /* Using 13 character ISBN */
-       {
-               if(!(((source[0] == '9') && (source[1] == '7')) &&
-                                    ((source[2] == '8') || (source[2] == '9'))))
-               {
-                       strcpy(symbol->errtxt, "Invalid ISBN");
-                       return ERROR_INVALID_DATA;
-               }
-
-               check_digit = isbn13_check(source);
-               if (source[src_len - 1] != check_digit)
-               {
-                       strcpy(symbol->errtxt, "Incorrect ISBN check");
-                       return ERROR_INVALID_CHECK;
-               }
-               source[12] = '\0';
-
-               ean13(symbol, source, dest);
-       }
-
-       if(src_len == 10) /* Using 10 digit ISBN */
-       {
-               check_digit = isbn_check(source);
-               if(check_digit != source[src_len - 1])
-               {
-                       strcpy(symbol->errtxt, "Incorrect ISBN check");
-                       return ERROR_INVALID_CHECK;
-               }
-               for(i = 13; i > 0; i--)
-               {
-                       source[i] = source[i - 3];
-               }
-               source[0] = '9';
-               source[1] = '7';
-               source[2] = '8';
-               source[12] = '\0';
-
-               ean13(symbol, source, dest);
-       }
-
-       if(src_len == 9) /* Using 9 digit SBN */
-       {
-               /* Add leading zero */
-               for(i = 10; i > 0; i--)
-               {
-                       source[i] = source[i - 1];
-               }
-               source[0] = '0';
-
-               /* Verify check digit */
-               check_digit = isbn_check(source);
-               if(check_digit != source[ustrlen(source) - 1])
-               {
-                       strcpy(symbol->errtxt, "Incorrect SBN check");
-                       return ERROR_INVALID_CHECK;
-               }
-
-               /* Convert to EAN-13 number */
-               for(i = 13; i > 0; i--)
-               {
-                       source[i] = source[i - 3];
-               }
-               source[0] = '9';
-               source[1] = '7';
-               source[2] = '8';
-               source[12] = '\0';
-
-               ean13(symbol, source, dest);
-       }
-       
-       return 0;
+/* Make an EAN-13 barcode from an SBN or ISBN */
+static int isbn(struct zint_symbol *symbol, unsigned char source[], const size_t src_len, char dest[]) {
+    int i, error_number;
+    char check_digit;
+
+    to_upper(source);
+    error_number = is_sane("0123456789X", source, src_len);
+    if (error_number == ZINT_ERROR_INVALID_DATA) {
+        strcpy(symbol->errtxt, "277: Invalid characters in input");
+        return error_number;
+    }
+
+    /* Input must be 9, 10 or 13 characters */
+    if (src_len != 9 && src_len != 10 && src_len != 13) {
+        strcpy(symbol->errtxt, "278: Input wrong length");
+        return ZINT_ERROR_TOO_LONG;
+    }
+
+    if (src_len == 13) /* Using 13 character ISBN */ {
+        if (!(((source[0] == '9') && (source[1] == '7')) &&
+                ((source[2] == '8') || (source[2] == '9')))) {
+            strcpy(symbol->errtxt, "279: Invalid ISBN");
+            return ZINT_ERROR_INVALID_DATA;
+        }
+
+        check_digit = isbn13_check(source);
+        if (source[src_len - 1] != check_digit) {
+            strcpy(symbol->errtxt, "280: Incorrect ISBN check");
+            return ZINT_ERROR_INVALID_CHECK;
+        }
+        source[12] = '\0';
+    }
+
+    if (src_len == 9) /* Using 9 digit SBN */ {
+        /* Add leading zero */
+        for (i = 10; i > 0; i--) {
+            source[i] = source[i - 1];
+        }
+        source[0] = '0';
+    }
+
+    if (src_len == 9 || src_len == 10) /* Using 10 digit ISBN or 9 digit SBN padded with leading zero */ {
+        check_digit = isbn_check(source);
+        if (check_digit != source[ustrlen(source) - 1]) {
+            strcpy(symbol->errtxt, src_len == 9 ? "281: Incorrect SBN check" : "281: Incorrect ISBN check");
+            return ZINT_ERROR_INVALID_CHECK;
+        }
+        for (i = 11; i > 2; i--) {
+            source[i] = source[i - 3];
+        }
+        source[0] = '9';
+        source[1] = '7';
+        source[2] = '8';
+        source[12] = '\0';
+    }
+
+    return ean13(symbol, source, dest);
 }
 
-void ean_leading_zeroes(struct zint_symbol *symbol, unsigned char source[], unsigned char local_source[]) {
-       /* Add leading zeroes to EAN and UPC strings */
-       unsigned char first_part[20], second_part[20], zfirst_part[20], zsecond_part[20];
-       int with_addon = 0;
-       int first_len = 0, second_len = 0, zfirst_len = 0, zsecond_len = 0, i, h;
-       
-       h = ustrlen(source);
-       for(i = 0; i < h; i++) {
-               if(source[i] == '+') {
-                       with_addon = 1;
-               } else {
-                       if(with_addon == 0) {
-                               first_len++;
-                       } else {
-                               second_len++;
-                       }
-               }
-       }
-       
-       ustrcpy(first_part, (unsigned char *)"");
-       ustrcpy(second_part, (unsigned char *)"");
-       ustrcpy(zfirst_part, (unsigned char *)"");
-       ustrcpy(zsecond_part, (unsigned char *)"");
-       
-       /* Split input into two strings */
-       for(i = 0; i < first_len; i++) {
-               first_part[i] = source[i];
-               first_part[i + 1] = '\0';
-       }
-       
-       for(i = 0; i < second_len; i++) {
-               second_part[i] = source[i + first_len + 1];
-               second_part[i + 1] = '\0';
-       }
-       
-       /* Calculate target lengths */
-       if(second_len <= 5) { zsecond_len = 5; }
-       if(second_len <= 2) { zsecond_len = 2; }
-       if(second_len == 0) { zsecond_len = 0; }
-       switch(symbol->symbology) {
-               case BARCODE_EANX:
-               case BARCODE_EANX_CC:
-                       if(first_len <= 12) { zfirst_len = 12; }
-                       if(first_len <= 7) { zfirst_len = 7; }
-                       if(second_len == 0) {
-                               if(first_len <= 5) { zfirst_len = 5; }
-                               if(first_len <= 2) { zfirst_len = 2; }
-                       }
-                       break;
-               case BARCODE_UPCA:
-               case BARCODE_UPCA_CC:
-                       zfirst_len = 11;
-                       break;
-               case BARCODE_UPCE:
-               case BARCODE_UPCE_CC:
-                       if(first_len == 7) { zfirst_len = 7; }
-                       if(first_len <= 6) { zfirst_len = 6; }
-                       break;
-               case BARCODE_ISBNX:
-                       if(first_len <= 9) { zfirst_len = 9; }
-                       break;
-       }
-
-       
-       /* Add leading zeroes */
-       for(i = 0; i < (zfirst_len - first_len); i++) {
-               uconcat(zfirst_part, (unsigned char *)"0");
-       }
-       uconcat(zfirst_part, first_part);
-       for(i = 0; i < (zsecond_len - second_len); i++) {
-               uconcat(zsecond_part, (unsigned char *)"0");
-       }
-       uconcat(zsecond_part, second_part);
-       
-       /* Copy adjusted data back to local_source */
-       uconcat(local_source, zfirst_part);
-       if(zsecond_len != 0) {
-               uconcat(local_source, (unsigned char *)"+");
-               uconcat(local_source, zsecond_part);
-       }
+/* Add leading zeroes to EAN and UPC strings */
+INTERNAL void ean_leading_zeroes(struct zint_symbol *symbol, unsigned char source[], unsigned char local_source[]) {
+    unsigned char first_part[20], second_part[20], zfirst_part[20], zsecond_part[20];
+    int with_addon = 0;
+    int first_len = 0, second_len = 0, zfirst_len = 0, zsecond_len = 0, i, h;
+
+    h = ustrlen(source);
+    for (i = 0; i < h; i++) {
+        if (source[i] == '+') {
+            with_addon = 1;
+        } else {
+            if (with_addon == 0) {
+                first_len++;
+            } else {
+                second_len++;
+            }
+        }
+    }
+
+    ustrcpy(first_part, (unsigned char *) "");
+    ustrcpy(second_part, (unsigned char *) "");
+    ustrcpy(zfirst_part, (unsigned char *) "");
+    ustrcpy(zsecond_part, (unsigned char *) "");
+
+    /* Split input into two strings */
+    for (i = 0; i < first_len; i++) {
+        first_part[i] = source[i];
+        first_part[i + 1] = '\0';
+    }
+
+    if (second_len >= 6) { /* Allow 6 (actual max 5) so as to trigger too long error */
+        second_len = 6;
+    }
+    for (i = 0; i < second_len; i++) {
+        second_part[i] = source[i + first_len + 1];
+        second_part[i + 1] = '\0';
+    }
+
+    /* Calculate target lengths */
+    if (second_len <= 5) {
+        zsecond_len = 5;
+    }
+    if (second_len <= 2) {
+        zsecond_len = 2;
+    }
+    if (second_len == 0) {
+        zsecond_len = 0;
+    }
+    switch (symbol->symbology) {
+        case BARCODE_EANX:
+        case BARCODE_EANX_CC:
+            if (first_len <= 12) {
+                zfirst_len = 12;
+            }
+            if (first_len <= 7) {
+                zfirst_len = 7;
+            }
+            if (second_len == 0 && symbol->symbology == BARCODE_EANX) { /* No composite EAN-2/5 */
+                if (first_len <= 5) {
+                    zfirst_len = 5;
+                }
+                if (first_len <= 2) {
+                    zfirst_len = 2;
+                }
+            }
+            break;
+        case BARCODE_EANX_CHK:
+            if (first_len <= 13) {
+                zfirst_len = 13;
+            }
+            if (first_len <= 8) {
+                zfirst_len = 8;
+            }
+            if (second_len == 0) {
+                if (first_len <= 5) {
+                    zfirst_len = 5;
+                }
+                if (first_len <= 2) {
+                    zfirst_len = 2;
+                }
+            }
+            break;
+        case BARCODE_UPCA:
+        case BARCODE_UPCA_CC:
+            zfirst_len = 11;
+            break;
+        case BARCODE_UPCA_CHK:
+            zfirst_len = 12;
+            break;
+        case BARCODE_UPCE:
+        case BARCODE_UPCE_CC:
+            if (first_len == 7) {
+                zfirst_len = 7;
+            }
+            if (first_len <= 6) {
+                zfirst_len = 6;
+            }
+            break;
+        case BARCODE_UPCE_CHK:
+            if (first_len == 8) {
+                zfirst_len = 8;
+            }
+            if (first_len <= 7) {
+                zfirst_len = 7;
+            }
+            break;
+        case BARCODE_ISBNX:
+            if (first_len <= 9) {
+                zfirst_len = 9;
+            }
+            break;
+    }
+
+
+    /* Add leading zeroes */
+    for (i = 0; i < (zfirst_len - first_len); i++) {
+        strcat((char*) zfirst_part, "0");
+    }
+    strcat((char*) zfirst_part, (char*) first_part);
+    for (i = 0; i < (zsecond_len - second_len); i++) {
+        strcat((char*) zsecond_part, "0");
+    }
+    strcat((char*) zsecond_part, (char*) second_part);
+
+    /* Copy adjusted data back to local_source */
+    strcat((char*) local_source, (char*) zfirst_part);
+    if (ustrlen(zsecond_part)) {
+        strcat((char*) local_source, "+");
+        strcat((char*) local_source, (char*) zsecond_part);
+    }
 }
 
-int eanx(struct zint_symbol *symbol, unsigned char source[], int src_len)
-{
-       /* splits string to parts before and after '+' parts */
-       unsigned char first_part[20] = { 0 }, second_part[20] = { 0 }, dest[1000] = { 0 };
-       unsigned char local_source[20] = { 0 };
-       unsigned int latch, reader, writer, with_addon;
-       int error_number, i;
-       
-
-       with_addon = FALSE;
-       latch = FALSE;
-       writer = 0;
-
-       if(src_len > 19) {
-               strcpy(symbol->errtxt, "Input too long");
-               return ERROR_TOO_LONG;
-       }
-       if(symbol->symbology != BARCODE_ISBNX) {
-               /* ISBN has it's own checking routine */
-               error_number = is_sane("0123456789+", source, src_len);
-               if(error_number == ERROR_INVALID_DATA) {
-                       strcpy(symbol->errtxt, "Invalid characters in data");
-                       return error_number;
-               }
-       } else {
-               error_number = is_sane("0123456789Xx", source, src_len);
-               if(error_number == ERROR_INVALID_DATA) {
-                       strcpy(symbol->errtxt, "Invalid characters in input");
-                       return error_number;
-               }
-       }
-
-
-       /* Add leading zeroes */
-       ustrcpy(local_source, (unsigned char *)"");
-       if(symbol->symbology == BARCODE_ISBNX) {
-               to_upper(local_source);
-       }
-       
-       ean_leading_zeroes(symbol, source, local_source);
-       
-       for(reader = 0; reader <= ustrlen(local_source); reader++)
-       {
-               if(source[reader] == '+') { with_addon = TRUE; }
-       }
-
-       reader = 0;
-       if(with_addon) {
-               do {
-                       if(local_source[reader] == '+') {
-                               first_part[writer] = '\0';
-                               latch = TRUE;
-                               reader++;
-                               writer = 0;
-                       }
-
-                       if(latch) {
-                               second_part[writer] = local_source[reader];
-                               reader++;
-                               writer++;
-                       } else {
-                               first_part[writer] = local_source[reader];
-                               reader++;
-                               writer++;
-                       }
-               } while (reader <= ustrlen(local_source));
-       } else {
-               strcpy((char*)first_part, (char*)local_source);
-       }
-
-
-       switch(symbol->symbology)
-       {
-               case BARCODE_EANX:
-                       switch(ustrlen(first_part))
-                       {
-                               case 2: add_on(first_part, (char*)dest, 0); ustrcpy(symbol->text, first_part); break;
-                               case 5: add_on(first_part, (char*)dest, 0); ustrcpy(symbol->text, first_part); break;
-                               case 7: ean8(symbol, first_part, (char*)dest); break;
-                               case 12: ean13(symbol, first_part, (char*)dest); break;
-                               default: strcpy(symbol->errtxt, "Invalid length input"); return ERROR_TOO_LONG; break;
-                       }
-                       break;
-               case BARCODE_EANX_CC:
-                       switch(ustrlen(first_part))
-                       { /* Adds vertical separator bars according to ISO/IEC 24723 section 11.4 */
-                               case 7: set_module(symbol, symbol->rows, 1);
-                                       set_module(symbol, symbol->rows, 67);
-                                       set_module(symbol, symbol->rows + 1, 0);
-                                       set_module(symbol, symbol->rows + 1, 68);
-                                       set_module(symbol, symbol->rows + 2, 1);
-                                       set_module(symbol, symbol->rows + 1, 67);
-                                       symbol->row_height[symbol->rows] = 2;
-                                       symbol->row_height[symbol->rows + 1] = 2;
-                                       symbol->row_height[symbol->rows + 2] = 2;
-                                       symbol->rows += 3;
-                                       ean8(symbol, first_part, (char*)dest); break;
-                               case 12:set_module(symbol, symbol->rows, 1);
-                                       set_module(symbol, symbol->rows, 95);
-                                       set_module(symbol, symbol->rows + 1, 0);
-                                       set_module(symbol, symbol->rows + 1, 96);
-                                       set_module(symbol, symbol->rows + 2, 1);
-                                       set_module(symbol, symbol->rows + 2, 95);
-                                       symbol->row_height[symbol->rows] = 2;
-                                       symbol->row_height[symbol->rows + 1] = 2;
-                                       symbol->row_height[symbol->rows + 2] = 2;
-                                       symbol->rows += 3;
-                                       ean13(symbol, first_part, (char*)dest); break;
-                                       default: strcpy(symbol->errtxt, "Invalid length EAN input"); return ERROR_TOO_LONG; break;
-                       }
-                       break;
-               case BARCODE_UPCA:
-                       if(ustrlen(first_part) == 11) {
-                               upca(symbol, first_part, (char*)dest);
-                       } else {
-                               strcpy(symbol->errtxt, "Input wrong length");
-                               return ERROR_TOO_LONG;
-                       }
-                       break;
-               case BARCODE_UPCA_CC:
-                       if(ustrlen(first_part) == 11) {
-                               set_module(symbol, symbol->rows, 1);
-                               set_module(symbol, symbol->rows, 95);
-                               set_module(symbol, symbol->rows + 1, 0);
-                               set_module(symbol, symbol->rows + 1, 96);
-                               set_module(symbol, symbol->rows + 2, 1);
-                               set_module(symbol, symbol->rows + 2, 95);
-                               symbol->row_height[symbol->rows] = 2;
-                               symbol->row_height[symbol->rows + 1] = 2;
-                               symbol->row_height[symbol->rows + 2] = 2;
-                               symbol->rows += 3;
-                               upca(symbol, first_part, (char*)dest);
-                       } else {
-                               strcpy(symbol->errtxt, "UPCA input wrong length");
-                               return ERROR_TOO_LONG;
-                       }
-                       break;
-               case BARCODE_UPCE:
-                       if((ustrlen(first_part) >= 6) && (ustrlen(first_part) <= 7)) {
-                               upce(symbol, first_part, (char*)dest);
-                       } else {
-                               strcpy(symbol->errtxt, "Input wrong length");
-                               return ERROR_TOO_LONG;
-                       }
-                       break;
-               case BARCODE_UPCE_CC:
-                       if((ustrlen(first_part) >= 6) && (ustrlen(first_part) <= 7)) {
-                               set_module(symbol, symbol->rows, 1);
-                               set_module(symbol, symbol->rows, 51);
-                               set_module(symbol, symbol->rows + 1, 0);
-                               set_module(symbol, symbol->rows + 1, 52);
-                               set_module(symbol, symbol->rows + 2, 1);
-                               set_module(symbol, symbol->rows + 2, 51);
-                               symbol->row_height[symbol->rows] = 2;
-                               symbol->row_height[symbol->rows + 1] = 2;
-                               symbol->row_height[symbol->rows + 2] = 2;
-                               symbol->rows += 3;
-                               upce(symbol, first_part, (char*)dest);
-                       } else {
-                               strcpy(symbol->errtxt, "UPCE input wrong length");
-                               return ERROR_TOO_LONG;
-                       }
-                       break;
-               case BARCODE_ISBNX:
-                       error_number = isbn(symbol, first_part, ustrlen(first_part), (char*)dest);
-                       if(error_number > 4) {
-                               return error_number;
-                       }
-                       break;
-       }
-       switch(ustrlen(second_part))
-       {
-               case 0: break;
-               case 2:
-                       add_on(second_part, (char*)dest, 1);
-                       uconcat(symbol->text, (unsigned char*)"+");
-                       uconcat(symbol->text, second_part);
-                       break;
-               case 5:
-                       add_on(second_part, (char*)dest, 1);
-                       uconcat(symbol->text, (unsigned char*)"+");
-                       uconcat(symbol->text, second_part);
-                       break;
-               default:
-                       strcpy(symbol->errtxt, "Invalid length input");
-                       return ERROR_TOO_LONG;
-                       break;
-       }
-       
-       expand(symbol, (char*)dest);
-
-       switch(symbol->symbology) {
-               case BARCODE_EANX_CC:
-               case BARCODE_UPCA_CC:
-               case BARCODE_UPCE_CC:
-                       /* shift the symbol to the right one space to allow for separator bars */
-                       for(i = (symbol->width + 1); i >= 1; i--) {
-                               if(module_is_set(symbol, symbol->rows - 1, i - 1)) {
-                                       set_module(symbol, symbol->rows - 1, i);
-                               } else {
-                                       unset_module(symbol, symbol->rows - 1, i);
-                               }
-                       }
-                       unset_module(symbol, symbol->rows - 1, 0);
-                       symbol->width += 2;
-                       break;
-       }
-
-       
-       if((symbol->errtxt[0] == 'w') && (error_number == 0)) {
-               error_number = 1; /* flag UPC-E warnings */
-       }
-       return error_number;
+/* splits string to parts before and after '+' parts */
+INTERNAL int eanx(struct zint_symbol *symbol, unsigned char source[], int src_len) {
+    unsigned char first_part[20] = {0}, second_part[7] = {0}, dest[1000] = {0};
+    unsigned char local_source[20] = {0};
+    unsigned int latch, reader, writer, with_addon;
+    int error_number, i, plus_count;
+
+    with_addon = FALSE;
+    latch = FALSE;
+    writer = 0;
+
+    if (src_len > 19) {
+        strcpy(symbol->errtxt, "283: Input too long");
+        return ZINT_ERROR_TOO_LONG;
+    }
+    if (symbol->symbology != BARCODE_ISBNX) {
+        /* ISBN has it's own checking routine */
+        error_number = is_sane("0123456789+", source, src_len);
+        if (error_number == ZINT_ERROR_INVALID_DATA) {
+            strcpy(symbol->errtxt, "284: Invalid characters in data");
+            return error_number;
+        }
+    } else {
+        error_number = is_sane("0123456789Xx+", source, src_len);
+        if (error_number == ZINT_ERROR_INVALID_DATA) {
+            strcpy(symbol->errtxt, "285: Invalid characters in input");
+            return error_number;
+        }
+    }
+    
+    /* Check for multiple '+' characters */
+    plus_count = 0;
+    for (i = 0; i < src_len; i++) {
+        if (source[i] == '+') {
+            plus_count++;
+        }
+    }
+    if (plus_count > 1) {
+        strcpy(symbol->errtxt, "293: Invalid add-on data");
+        return ZINT_ERROR_INVALID_DATA;
+    }
+
+    /* Add leading zeroes */
+    ustrcpy(local_source, (unsigned char *) "");
+    if (symbol->symbology == BARCODE_ISBNX) {
+        to_upper(local_source);
+    }
+
+    ean_leading_zeroes(symbol, source, local_source);
+
+    for (reader = 0; reader < ustrlen(local_source); reader++) {
+        if (local_source[reader] == '+') {
+            with_addon = TRUE;
+        }
+    }
+
+    reader = 0;
+    if (with_addon) {
+        do {
+            if (local_source[reader] == '+') {
+                first_part[writer] = '\0';
+                latch = TRUE;
+                reader++;
+                writer = 0;
+            }
+
+            if (latch) {
+                second_part[writer] = local_source[reader];
+                reader++;
+                writer++;
+            } else {
+                first_part[writer] = local_source[reader];
+                reader++;
+                writer++;
+            }
+        } while (reader <= ustrlen(local_source));
+    } else {
+        strcpy((char*) first_part, (char*) local_source);
+    }
+
+    switch (symbol->symbology) {
+        case BARCODE_EANX:
+        case BARCODE_EANX_CHK:
+            switch (ustrlen(first_part)) {
+                case 2: add_on(first_part, (char*) dest, 0);
+                    ustrcpy(symbol->text, first_part);
+                    break;
+                case 5: add_on(first_part, (char*) dest, 0);
+                    ustrcpy(symbol->text, first_part);
+                    break;
+                case 7:
+                case 8: error_number = ean8(symbol, first_part, (char*) dest);
+                    break;
+                case 12:
+                case 13: error_number = ean13(symbol, first_part, (char*) dest);
+                    break;
+                default: strcpy(symbol->errtxt, "286: Invalid length input");
+                    return ZINT_ERROR_TOO_LONG;
+            }
+            break;
+        case BARCODE_EANX_CC:
+            switch (ustrlen(first_part)) { /* Adds vertical separator bars according to ISO/IEC 24723 section 11.4 */
+                case 7: set_module(symbol, symbol->rows, 1);
+                    set_module(symbol, symbol->rows, 67);
+                    set_module(symbol, symbol->rows + 1, 0);
+                    set_module(symbol, symbol->rows + 1, 68);
+                    set_module(symbol, symbol->rows + 2, 1);
+                    set_module(symbol, symbol->rows + 2, 67);
+                    symbol->row_height[symbol->rows] = 2;
+                    symbol->row_height[symbol->rows + 1] = 2;
+                    symbol->row_height[symbol->rows + 2] = 2;
+                    symbol->rows += 3;
+                    error_number = ean8(symbol, first_part, (char*) dest);
+                    break;
+                case 12:set_module(symbol, symbol->rows, 1);
+                    set_module(symbol, symbol->rows, 95);
+                    set_module(symbol, symbol->rows + 1, 0);
+                    set_module(symbol, symbol->rows + 1, 96);
+                    set_module(symbol, symbol->rows + 2, 1);
+                    set_module(symbol, symbol->rows + 2, 95);
+                    symbol->row_height[symbol->rows] = 2;
+                    symbol->row_height[symbol->rows + 1] = 2;
+                    symbol->row_height[symbol->rows + 2] = 2;
+                    symbol->rows += 3;
+                    error_number = ean13(symbol, first_part, (char*) dest);
+                    break;
+                default: strcpy(symbol->errtxt, "287: Invalid length EAN input");
+                    return ZINT_ERROR_TOO_LONG;
+            }
+            break;
+        case BARCODE_UPCA:
+        case BARCODE_UPCA_CHK:
+            if ((ustrlen(first_part) == 11) || (ustrlen(first_part) == 12)) {
+                error_number = upca(symbol, first_part, (char*) dest);
+            } else {
+                strcpy(symbol->errtxt, "288: Input wrong length (C6I)");
+                return ZINT_ERROR_TOO_LONG;
+            }
+            break;
+        case BARCODE_UPCA_CC:
+            if (ustrlen(first_part) == 11) {
+                set_module(symbol, symbol->rows, 1);
+                set_module(symbol, symbol->rows, 95);
+                set_module(symbol, symbol->rows + 1, 0);
+                set_module(symbol, symbol->rows + 1, 96);
+                set_module(symbol, symbol->rows + 2, 1);
+                set_module(symbol, symbol->rows + 2, 95);
+                symbol->row_height[symbol->rows] = 2;
+                symbol->row_height[symbol->rows + 1] = 2;
+                symbol->row_height[symbol->rows + 2] = 2;
+                symbol->rows += 3;
+                error_number = upca(symbol, first_part, (char*) dest);
+            } else {
+                strcpy(symbol->errtxt, "289: UPCA input wrong length");
+                return ZINT_ERROR_TOO_LONG;
+            }
+            break;
+        case BARCODE_UPCE:
+        case BARCODE_UPCE_CHK:
+            if ((ustrlen(first_part) >= 6) && (ustrlen(first_part) <= (symbol->symbology == BARCODE_UPCE ? 7 : 8))) {
+                error_number = upce(symbol, first_part, (char*) dest);
+            } else {
+                strcpy(symbol->errtxt, "290: Input wrong length");
+                return ZINT_ERROR_TOO_LONG;
+            }
+            break;
+        case BARCODE_UPCE_CC:
+            if ((ustrlen(first_part) >= 6) && (ustrlen(first_part) <= 7)) {
+                set_module(symbol, symbol->rows, 1);
+                set_module(symbol, symbol->rows, 51);
+                set_module(symbol, symbol->rows + 1, 0);
+                set_module(symbol, symbol->rows + 1, 52);
+                set_module(symbol, symbol->rows + 2, 1);
+                set_module(symbol, symbol->rows + 2, 51);
+                symbol->row_height[symbol->rows] = 2;
+                symbol->row_height[symbol->rows + 1] = 2;
+                symbol->row_height[symbol->rows + 2] = 2;
+                symbol->rows += 3;
+                error_number = upce(symbol, first_part, (char*) dest);
+            } else {
+                strcpy(symbol->errtxt, "291: UPCE input wrong length");
+                return ZINT_ERROR_TOO_LONG;
+            }
+            break;
+        case BARCODE_ISBNX:
+            error_number = isbn(symbol, first_part, ustrlen(first_part), (char*) dest);
+            break;
+    }
+
+    if (error_number > 4) {
+        return error_number;
+    }
+
+    switch (ustrlen(second_part)) {
+        case 0: break;
+        case 2:
+            add_on(second_part, (char*) dest, 1);
+            strcat((char*) symbol->text, "+");
+            strcat((char*) symbol->text, (char*) second_part);
+            break;
+        case 5:
+            add_on(second_part, (char*) dest, 1);
+            strcat((char*) symbol->text, "+");
+            strcat((char*) symbol->text, (char*) second_part);
+            break;
+        default:
+            strcpy(symbol->errtxt, "292: Invalid length input");
+            return ZINT_ERROR_TOO_LONG;
+    }
+
+    expand(symbol, (char*) dest);
+
+    switch (symbol->symbology) {
+        case BARCODE_EANX_CC:
+        case BARCODE_UPCA_CC:
+        case BARCODE_UPCE_CC:
+            /* shift the symbol to the right one space to allow for separator bars */
+            for (i = (symbol->width + 1); i >= 1; i--) {
+                if (module_is_set(symbol, symbol->rows - 1, i - 1)) {
+                    set_module(symbol, symbol->rows - 1, i);
+                } else {
+                    unset_module(symbol, symbol->rows - 1, i);
+                }
+            }
+            unset_module(symbol, symbol->rows - 1, 0);
+            symbol->width += 2;
+            break;
+    }
+
+    return 0;
 }
-
-
-
-
diff --git a/backend/vector.c b/backend/vector.c
new file mode 100644 (file)
index 0000000..5313b60
--- /dev/null
@@ -0,0 +1,823 @@
+/*  vector.c - Creates vector image objects
+
+    libzint - the open source barcode library
+    Copyright (C) 2018 - 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>
+#include <math.h>
+
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+
+#include "common.h"
+#include "output.h"
+
+INTERNAL int ps_plot(struct zint_symbol *symbol);
+INTERNAL int svg_plot(struct zint_symbol *symbol);
+INTERNAL int emf_plot(struct zint_symbol *symbol);
+
+static struct zint_vector_rect *vector_plot_create_rect(float x, float y, float width, float height) {
+    struct zint_vector_rect *rect;
+
+    rect = (struct zint_vector_rect*) malloc(sizeof (struct zint_vector_rect));
+    if (!rect) return NULL;
+
+    rect->next = NULL;
+    rect->x = x;
+    rect->y = y;
+    rect->width = width;
+    rect->height = height;
+    rect->colour = -1; // Default colour
+
+    return rect;
+}
+
+static int vector_plot_add_rect(struct zint_symbol *symbol, struct zint_vector_rect *rect, struct zint_vector_rect **last_rect) {
+    if (!rect) return ZINT_ERROR_MEMORY;
+    if (*last_rect)
+        (*last_rect)->next = rect;
+    else
+        symbol->vector->rectangles = rect; // first rectangle
+
+    *last_rect = rect;
+    return 1;
+}
+
+static struct zint_vector_hexagon *vector_plot_create_hexagon(float x, float y, float diameter) {
+    struct zint_vector_hexagon *hexagon;
+
+    hexagon = (struct zint_vector_hexagon*) malloc(sizeof (struct zint_vector_hexagon));
+    if (!hexagon) return NULL;
+    hexagon->next = NULL;
+    hexagon->x = x;
+    hexagon->y = y;
+    hexagon->diameter = (float)((diameter * 5.0) / 4.0); // Ugly kludge for legacy support
+
+    return hexagon;
+}
+
+static int vector_plot_add_hexagon(struct zint_symbol *symbol, struct zint_vector_hexagon *hexagon, struct zint_vector_hexagon **last_hexagon) {
+    if (!hexagon) return ZINT_ERROR_MEMORY;
+    if (*last_hexagon)
+        (*last_hexagon)->next = hexagon;
+    else
+        symbol->vector->hexagons = hexagon; // first hexagon
+
+    *last_hexagon = hexagon;
+    return 1;
+}
+
+static struct zint_vector_circle *vector_plot_create_circle(float x, float y, float diameter, int colour) {
+    struct zint_vector_circle *circle;
+
+    circle = (struct zint_vector_circle *) malloc(sizeof (struct zint_vector_circle));
+    if (!circle) return NULL;
+    circle->next = NULL;
+    circle->x = x;
+    circle->y = y;
+    circle->diameter = diameter;
+    circle->colour = colour;
+
+    return circle;
+}
+
+static int vector_plot_add_circle(struct zint_symbol *symbol, struct zint_vector_circle *circle, struct zint_vector_circle **last_circle) {
+    if (!circle) return ZINT_ERROR_MEMORY;
+    if (*last_circle)
+        (*last_circle)->next = circle;
+    else
+        symbol->vector->circles = circle; // first circle
+
+    *last_circle = circle;
+    return 1;
+}
+
+static int vector_plot_add_string(struct zint_symbol *symbol,
+        unsigned char *text, float x, float y, float fsize, float width,
+        struct zint_vector_string **last_string) {
+    struct zint_vector_string *string;
+
+    string = (struct zint_vector_string*) malloc(sizeof (struct zint_vector_string));
+    string->next = NULL;
+    string->x = x;
+    string->y = y;
+    string->width = width;
+    string->fsize = fsize;
+    string->length = ustrlen(text);
+    string->text = (unsigned char*) malloc(sizeof (unsigned char) * (ustrlen(text) + 1));
+    ustrcpy(string->text, text);
+
+    if (*last_string)
+        (*last_string)->next = string;
+    else
+        symbol->vector->strings = string; // First text portion
+    *last_string = string;
+
+    return 1;
+}
+
+INTERNAL void vector_free(struct zint_symbol *symbol) {
+    if (symbol->vector != NULL) {
+        struct zint_vector_rect *rect;
+        struct zint_vector_hexagon *hex;
+        struct zint_vector_circle *circle;
+        struct zint_vector_string *string;
+
+        // Free Rectangles
+        rect = symbol->vector->rectangles;
+        while (rect) {
+            struct zint_vector_rect *r = rect;
+            rect = rect->next;
+            free(r);
+        }
+
+        // Free Hexagons
+        hex = symbol->vector->hexagons;
+        while (hex) {
+            struct zint_vector_hexagon *h = hex;
+            hex = hex->next;
+            free(h);
+        }
+
+        // Free Circles
+        circle = symbol->vector->circles;
+        while (circle) {
+            struct zint_vector_circle *c = circle;
+            circle = circle->next;
+            free(c);
+        }
+
+        // Free Strings
+        string = symbol->vector->strings;
+        while (string) {
+            struct zint_vector_string *s = string;
+            string = string->next;
+            free(s->text);
+            free(s);
+        }
+
+        // Free vector
+        free(symbol->vector);
+        symbol->vector = NULL;
+    }
+}
+
+static void vector_scale(struct zint_symbol *symbol, int file_type) {
+    struct zint_vector_rect *rect;
+    struct zint_vector_hexagon *hex;
+    struct zint_vector_circle *circle;
+    struct zint_vector_string *string;
+    float scale = symbol->scale * 2.0f;
+
+    if ((file_type == OUT_EMF_FILE) && (symbol->symbology == BARCODE_MAXICODE)) {
+        // Increase size to overcome limitations in EMF file format
+        scale *= 20;
+    }
+    
+    symbol->vector->width *= scale;
+    symbol->vector->height *= scale;
+
+    rect = symbol->vector->rectangles;
+    while (rect) {
+        rect->x *= scale;
+        rect->y *= scale;
+        rect->height *= scale;
+        rect->width *= scale;
+        rect = rect->next;
+    }
+
+    hex = symbol->vector->hexagons;
+    while (hex) {
+        hex->x *= scale;
+        hex->y *= scale;
+        hex->diameter *= scale;
+        hex = hex->next;
+    }
+
+    circle = symbol->vector->circles;
+    while (circle) {
+        circle->x *= scale;
+        circle->y *= scale;
+        circle->diameter *= scale;
+        circle = circle->next;
+    }
+
+    string = symbol->vector->strings;
+    while (string) {
+        string->x *= scale;
+        string->y *= scale;
+        string->width *= scale;
+        string->fsize *= scale;
+        string = string->next;
+    }
+    return;
+}
+
+static void vector_reduce_rectangles(struct zint_symbol *symbol) {
+    // Looks for vertically aligned rectangles and merges them together
+    struct zint_vector_rect *rect, *target, *prev;
+
+    rect = symbol->vector->rectangles;
+    while (rect) {
+        prev = rect;
+        target = prev->next;
+
+        while (target) {
+            if ((rect->x == target->x) && (rect->width == target->width) && ((rect->y + rect->height) == target->y) && (rect->colour == target->colour)) {
+                rect->height += target->height;
+                prev->next = target->next;
+                free(target);
+            } else {
+                prev = target;
+            }
+            target = prev->next;
+        }
+
+        rect = rect->next;
+    }
+
+    return;
+}
+
+INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) {
+    int error_number;
+    struct zint_vector *vector;
+    struct zint_vector_rect *rectangle, *rect, *last_rectangle = NULL;
+    struct zint_vector_hexagon *last_hexagon = NULL;
+    struct zint_vector_string *last_string = NULL;
+    struct zint_vector_circle *last_circle = NULL;
+
+    int i, r, latch;
+    float textpos, large_bar_height, preset_height, row_height, row_posn = 0.0;
+    float text_offset, text_height;
+    int xoffset, yoffset, textdone, main_symbol_width_x;
+    int roffset, boffset;
+    char addon[6];
+    int large_bar_count, symbol_lead_in;
+    float addon_text_posn;
+    float default_text_posn;
+    int hide_text = 0;
+    int upceanflag = 0;
+    int rect_count, last_row_start;
+    int this_row;
+    int addon_latch = 0;
+    struct zint_vector_string *string;
+
+    (void)rotate_angle; /* Not currently implemented */
+
+    // Sanity check colours
+    error_number = check_colour_options(symbol);
+    if (error_number != 0) {
+        return error_number;
+    }
+
+    // Free any previous rendering structures
+    vector_free(symbol);
+
+    // Allocate memory
+    vector = symbol->vector = (struct zint_vector *) malloc(sizeof (struct zint_vector));
+    if (!vector) return ZINT_ERROR_MEMORY;
+    vector->rectangles = NULL;
+    vector->hexagons = NULL;
+    vector->circles = NULL;
+    vector->strings = NULL;
+
+    row_height = 0;
+    textdone = 0;
+    main_symbol_width_x = symbol->width;
+    strcpy(addon, "");
+    symbol_lead_in = 0;
+    addon_text_posn = 0.0;
+    rect_count = 0;
+    last_row_start = 0;
+
+    /*
+     * Determine if there will be any addon texts and text height
+     */
+    latch = 0;
+    r = 0;
+    /* Isolate add-on text */
+    if (is_extendable(symbol->symbology)) {
+        for (i = 0; i < (int) ustrlen(symbol->text); i++) {
+            if (latch == 1) {
+                addon[r] = symbol->text[i];
+                r++;
+            }
+            if (symbol->text[i] == '+') {
+                latch = 1;
+            }
+        }
+    }
+    addon[r] = '\0';
+
+
+    /*
+     * Calculate the width of the barcode, especially if there are any extra
+     * borders or white space to add.
+     */
+
+    if (is_composite(symbol->symbology)) {
+        while (!(module_is_set(symbol, symbol->rows - 1, symbol_lead_in))) {
+            symbol_lead_in++;
+        }
+    }
+
+    /* Certain symbols need whitespace otherwise characters get chopped off the sides */
+    if ((symbol->symbology == BARCODE_EANX) || (symbol->symbology == BARCODE_EANX_CHK)
+            || (symbol->symbology == BARCODE_EANX_CC) || (symbol->symbology == BARCODE_ISBNX)) {
+        switch (ustrlen(symbol->text)) {
+            case 13: /* EAN 13 */
+            case 16:
+            case 19:
+                if (symbol->whitespace_width == 0) {
+                    symbol->whitespace_width = 10;
+                }
+                main_symbol_width_x = 96 + symbol_lead_in;
+                upceanflag = 13;
+                break;
+            case 2:
+                main_symbol_width_x = 22 + symbol_lead_in;
+                upceanflag = 2;
+                break;
+            case 5:
+                main_symbol_width_x = 49 + symbol_lead_in;
+                upceanflag = 5;
+                break;
+            default:
+                main_symbol_width_x = 68 + symbol_lead_in;
+                upceanflag = 8;
+        }
+    } else if ((symbol->symbology == BARCODE_UPCA) || (symbol->symbology == BARCODE_UPCA_CHK)
+            || (symbol->symbology == BARCODE_UPCA_CC)) {
+        upceanflag = 12;
+        if (symbol->whitespace_width == 0) {
+            symbol->whitespace_width = 10;
+        }
+        main_symbol_width_x = 96 + symbol_lead_in;
+    } else if ((symbol->symbology == BARCODE_UPCE) || (symbol->symbology == BARCODE_UPCE_CHK)
+            || (symbol->symbology == BARCODE_UPCE_CC)) {
+        upceanflag = 6;
+        if (symbol->whitespace_width == 0) {
+            symbol->whitespace_width = 10;
+        }
+        main_symbol_width_x = 51 + symbol_lead_in;
+    }
+
+    if ((!symbol->show_hrt) || (ustrlen(symbol->text) == 0)) {
+        hide_text = 1;
+        text_height = 0.0;
+        text_offset = upceanflag ? 9.0f : 0.0f;
+    } else {
+        text_height = upceanflag ? 11.0f : 9.0f;
+        text_offset = 9.0;
+    }
+    if (symbol->output_options & SMALL_TEXT)
+        text_height *= 0.8f;
+
+    set_whitespace_offsets(symbol, &xoffset, &yoffset, &roffset, &boffset);
+
+    // Determine if height should be overridden
+    large_bar_count = 0;
+    preset_height = 0.0;
+    for (i = 0; i < symbol->rows; i++) {
+        preset_height += symbol->row_height[i];
+        if (symbol->row_height[i] == 0) {
+            large_bar_count++;
+        }
+    }
+
+    vector->width = (float)ceil(symbol->width + (xoffset + roffset));
+    vector->height = (float)ceil(symbol->height + text_offset + (yoffset + boffset));
+
+    large_bar_height = large_bar_count ? (symbol->height - preset_height) / large_bar_count : 0 /*Not used if large_bar_count zero*/;
+
+    if ((symbol->output_options & BARCODE_BOX) || (symbol->output_options & BARCODE_BIND)) {
+        default_text_posn = symbol->height + text_offset + symbol->border_width + symbol->border_width;
+    } else {
+        default_text_posn = symbol->height + text_offset;
+    }
+
+    // Plot rectangles - most symbols created here
+    if ((symbol->symbology != BARCODE_MAXICODE) && ((symbol->output_options & BARCODE_DOTTY_MODE) == 0)) {
+        for (r = 0; r < symbol->rows; r++) {
+            this_row = r;
+            last_row_start = rect_count;
+            if (symbol->row_height[this_row] == 0) {
+                row_height = large_bar_height;
+            } else {
+                row_height = (float)symbol->row_height[this_row];
+            }
+            row_posn = 0;
+            for (i = 0; i < r; i++) {
+                if (symbol->row_height[i] == 0) {
+                    row_posn += large_bar_height;
+                } else {
+                    row_posn += symbol->row_height[i];
+                }
+            }
+            row_posn += yoffset;
+
+            i = 0;
+
+            do {
+                int block_width = 0;
+                do {
+                    block_width++;
+                } while (i + block_width < symbol->width && module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i));
+                if ((addon_latch == 0) && (r == (symbol->rows - 1)) && (i > main_symbol_width_x)) {
+                    addon_text_posn = row_posn + 8.0f;
+                    addon_latch = 1;
+                }
+                if (module_is_set(symbol, this_row, i)) {
+                    /* a bar or colour block */
+                    if (addon_latch == 0) {
+                        rectangle = vector_plot_create_rect((float)(i + xoffset), row_posn, (float)block_width, row_height);
+                        if (symbol->symbology == BARCODE_ULTRA) {
+                            rectangle->colour = module_is_set(symbol, this_row, i);
+                        }
+                    } else {
+                        rectangle = vector_plot_create_rect((float)(i + xoffset), row_posn + 10.0f, (float)block_width, row_height - 5.0f);
+                    }
+                    vector_plot_add_rect(symbol, rectangle, &last_rectangle);
+                    rect_count++;
+                }
+                i += block_width;
+
+            } while (i < symbol->width);
+        }
+    }
+
+    // Plot Maxicode symbols
+    if (symbol->symbology == BARCODE_MAXICODE) {
+        struct zint_vector_circle *circle;
+        vector->width = 37.0f + (xoffset + roffset);
+        vector->height = 36.0f + (yoffset + boffset);
+
+        // Bullseye
+        circle = vector_plot_create_circle(17.88f + xoffset, 17.8f + yoffset, 10.85f, 0);
+        vector_plot_add_circle(symbol, circle, &last_circle);
+        circle = vector_plot_create_circle(17.88f + xoffset, 17.8f + yoffset, 8.97f, 1);
+        vector_plot_add_circle(symbol, circle, &last_circle);
+        circle = vector_plot_create_circle(17.88f + xoffset, 17.8f + yoffset, 7.10f, 0);
+        vector_plot_add_circle(symbol, circle, &last_circle);
+        circle = vector_plot_create_circle(17.88f + xoffset, 17.8f + yoffset, 5.22f, 1);
+        vector_plot_add_circle(symbol, circle, &last_circle);
+        circle = vector_plot_create_circle(17.88f + xoffset, 17.8f + yoffset, 3.31f, 0);
+        vector_plot_add_circle(symbol, circle, &last_circle);
+        circle = vector_plot_create_circle(17.88f + xoffset, 17.8f + yoffset, 1.43f, 1);
+        vector_plot_add_circle(symbol, circle, &last_circle);
+
+        /* Hexagons */
+        for (r = 0; r < symbol->rows; r++) {
+            for (i = 0; i < symbol->width; i++) {
+                if (module_is_set(symbol, r, i)) {
+                    //struct zint_vector_hexagon *hexagon = vector_plot_create_hexagon(((i * 0.88) + ((r & 1) ? 1.76 : 1.32)), ((r * 0.76) + 0.76), symbol->dot_size);
+                    struct zint_vector_hexagon *hexagon = vector_plot_create_hexagon(((i * 1.23f) + 0.615f + ((r & 1) ? 0.615f : 0.0f)) + xoffset,
+                                                                                     ((r * 1.067f) + 0.715f) + yoffset, symbol->dot_size);
+                    vector_plot_add_hexagon(symbol, hexagon, &last_hexagon);
+                }
+            }
+        }
+    }
+
+    // Dotty mode
+    if ((symbol->symbology != BARCODE_MAXICODE) && (symbol->output_options & BARCODE_DOTTY_MODE)) {
+        for (r = 0; r < symbol->rows; r++) {
+            for (i = 0; i < symbol->width; i++) {
+                if (module_is_set(symbol, r, i)) {
+                    struct zint_vector_circle *circle = vector_plot_create_circle(i + 0.5f + xoffset, r + 0.5f + yoffset, 1.0f, 0);
+                    vector_plot_add_circle(symbol, circle, &last_circle);
+                }
+            }
+        }
+    }
+
+    /* Guard bar extension */
+    if (upceanflag == 6) {
+        i = 0;
+        for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) {
+            switch (i - last_row_start) {
+                case 0:
+                case 1:
+                case 14:
+                case 15:
+                case 16:
+                    rect->height += 5.0;
+                    break;
+            }
+            i++;
+        }
+    }
+
+    if (upceanflag == 8) {
+        i = 0;
+        for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) {
+            switch (i - last_row_start) {
+                case 0:
+                case 1:
+                case 10:
+                case 11:
+                case 20:
+                case 21:
+                    rect->height += 5.0;
+                    break;
+            }
+            i++;
+        }
+    }
+
+    if (upceanflag == 12) {
+        i = 0;
+        for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) {
+            switch (i - last_row_start) {
+                case 0:
+                case 1:
+                case 2:
+                case 3:
+                case 14:
+                case 15:
+                case 26:
+                case 27:
+                case 28:
+                case 29:
+                    rect->height += 5.0;
+                    break;
+            }
+            i++;
+        }
+    }
+
+    if (upceanflag == 13) {
+        i = 0;
+        for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) {
+            switch (i - last_row_start) {
+                case 0:
+                case 1:
+                case 14:
+                case 15:
+                case 28:
+                case 29:
+                    rect->height += 5.0;
+                    break;
+            }
+            i++;
+        }
+    }
+
+    /* Add the text */
+
+    if (!hide_text) {
+        char textpart[10];
+        float textwidth;
+
+        xoffset += symbol_lead_in;
+
+        if (upceanflag == 8) {
+            for (i = 0; i < 4; i++) {
+                textpart[i] = symbol->text[i];
+            }
+            textpart[4] = '\0';
+            textpos = 17;
+            textwidth = 4.0 * 8.5;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn, text_height, textwidth, &last_string);
+            for (i = 0; i < 4; i++) {
+                textpart[i] = symbol->text[i + 4];
+            }
+            textpart[4] = '\0';
+            textpos = 50;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, (textpos + xoffset), default_text_posn, text_height, textwidth, &last_string);
+            textdone = 1;
+            switch (strlen(addon)) {
+                case 2:
+                    textpos = (float)(xoffset + 86);
+                    textwidth = 2.0f * 8.5f;
+                    vector_plot_add_string(symbol, (unsigned char *) addon, textpos, addon_text_posn, text_height, textwidth, &last_string);
+                    break;
+                case 5:
+                    textpos = (float)(xoffset + 100);
+                    textwidth = 5.0f * 8.5f;
+                    vector_plot_add_string(symbol, (unsigned char *) addon, textpos, addon_text_posn, text_height, textwidth, &last_string);
+                    break;
+            }
+
+        }
+
+        if (upceanflag == 13) {
+            textpart[0] = symbol->text[0];
+            textpart[1] = '\0';
+            textpos = -5; // 7
+            textwidth = 8.5;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn, text_height, textwidth, &last_string);
+
+            for (i = 0; i < 6; i++) {
+                textpart[i] = symbol->text[i + 1];
+            }
+            textpart[6] = '\0';
+            textpos = 25;
+            textwidth = 6.0 * 8.5;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn, text_height, textwidth, &last_string);
+            for (i = 0; i < 6; i++) {
+                textpart[i] = symbol->text[i + 7];
+            }
+            textpart[6] = '\0';
+            textpos = 72;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn, text_height, textwidth, &last_string);
+            textdone = 1;
+            switch (strlen(addon)) {
+                case 2:
+                    textpos = (float)(xoffset + 114);
+                    textwidth = 2.0f * 8.5f;
+                    vector_plot_add_string(symbol, (unsigned char *) addon, textpos, addon_text_posn, text_height, textwidth, &last_string);
+                    break;
+                case 5:
+                    textpos = (float)(xoffset + 128);
+                    textwidth = 5.0f * 8.5f;
+                    vector_plot_add_string(symbol, (unsigned char *) addon, textpos, addon_text_posn, text_height, textwidth, &last_string);
+                    break;
+            }
+        }
+
+        if (upceanflag == 12) {
+            textpart[0] = symbol->text[0];
+            textpart[1] = '\0';
+            textpos = -5;
+            textwidth = 6.2f;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn - 2.0f, text_height * (8.0f / 11.0f), textwidth, &last_string);
+            for (i = 0; i < 5; i++) {
+                textpart[i] = symbol->text[i + 1];
+            }
+            textpart[5] = '\0';
+            textpos = 27;
+            textwidth = 5.0f * 8.5f;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn, text_height, textwidth, &last_string);
+            for (i = 0; i < 5; i++) {
+                textpart[i] = symbol->text[i + 6];
+            }
+            textpos = 68;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn, text_height, textwidth, &last_string);
+            textpart[0] = symbol->text[11];
+            textpart[1] = '\0';
+            textpos = 100;
+            textwidth = 6.2f;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn - 2.0f, text_height * (8.0f / 11.0f), textwidth, &last_string);
+            textdone = 1;
+            switch (strlen(addon)) {
+                case 2:
+                    textpos = (float)(xoffset + 116);
+                    textwidth = 2.0f * 8.5f;
+                    vector_plot_add_string(symbol, (unsigned char *) addon, textpos, addon_text_posn, text_height, textwidth, &last_string);
+                    break;
+                case 5:
+                    textpos = (float)(xoffset + 130);
+                    textwidth = 5.0f * 8.5f;
+                    vector_plot_add_string(symbol, (unsigned char *) addon, textpos, addon_text_posn, text_height, textwidth, &last_string);
+                    break;
+            }
+        }
+
+        if (upceanflag == 6) {
+            textpart[0] = symbol->text[0];
+            textpart[1] = '\0';
+            textpos = -5;
+            textwidth = 6.2f;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn - 2.0f, text_height * (8.0f / 11.0f), textwidth, &last_string);
+            for (i = 0; i < 6; i++) {
+                textpart[i] = symbol->text[i + 1];
+            }
+            textpart[6] = '\0';
+            textpos = 24;
+            textwidth = 6.0 * 8.5;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn, text_height, textwidth, &last_string);
+            textpart[0] = symbol->text[7];
+            textpart[1] = '\0';
+            textpos = 55;
+            textwidth = 6.2f;
+            vector_plot_add_string(symbol, (unsigned char *) textpart, textpos + xoffset, default_text_posn - 2.0f, text_height * (8.0f / 11.0f), textwidth, &last_string);
+            textdone = 1;
+            switch (strlen(addon)) {
+                case 2:
+                    textpos = (float)(xoffset + 70);
+                    textwidth = 2.0f * 8.5f;
+                    vector_plot_add_string(symbol, (unsigned char *) addon, textpos, addon_text_posn, text_height, textwidth, &last_string);
+                    break;
+                case 5:
+                    textpos = (float)(xoffset + 84);
+                    textwidth = 5.0f * 8.5f;
+                    vector_plot_add_string(symbol, (unsigned char *) addon, textpos, addon_text_posn, text_height, textwidth, &last_string);
+                    break;
+            }
+        }
+
+        /* Put normal human readable text at the bottom (and centered) */
+        if (textdone == 0) {
+            // caculate start xoffset to center text
+            vector_plot_add_string(symbol, symbol->text, (symbol->width / 2.0f) + xoffset, default_text_posn, text_height, (float)symbol->width, &last_string);
+        }
+
+        xoffset -= symbol_lead_in; // Restore xoffset
+    }
+
+    //Remove control characters from readable text
+    // This only applies to Code 128
+    string = symbol->vector->strings;
+    if (string) {
+        for (i = 0; i < string->length; i++) {
+            if (string->text[i] < ' ') {
+                string->text[i] = ' ';
+            }
+        }
+    }
+
+    // Binding and boxes
+    if ((symbol->output_options & BARCODE_BIND) != 0) {
+        if ((symbol->rows > 1) && (is_stackable(symbol->symbology) == 1)) {
+            double sep_height = 1;
+            if (symbol->option_3 > 0 && symbol->option_3 <= 4) {
+                sep_height = symbol->option_3;
+            }
+            /* row binding */
+            for (r = 1; r < symbol->rows; r++) {
+                if (symbol->symbology != BARCODE_CODABLOCKF && symbol->symbology != BARCODE_HIBC_BLOCKF) {
+                    rectangle = vector_plot_create_rect((float)xoffset, (r * row_height) + yoffset - sep_height / 2, (float)symbol->width, sep_height);
+                    vector_plot_add_rect(symbol, rectangle, &last_rectangle);
+                } else {
+                    /* Avoid 11-module start and 13-module stop chars */
+                    rectangle = vector_plot_create_rect(xoffset + 11, (r * row_height) + yoffset - sep_height / 2, symbol->width - 24, sep_height);
+                    vector_plot_add_rect(symbol, rectangle, &last_rectangle);
+                }
+            }
+        }
+    }
+    if ((symbol->output_options & BARCODE_BOX) || (symbol->output_options & BARCODE_BIND)) {
+        // Top
+        rectangle = vector_plot_create_rect(0.0f, 0.0f, vector->width, (float)symbol->border_width);
+        if (!(symbol->output_options & BARCODE_BOX) && (symbol->symbology == BARCODE_CODABLOCKF || symbol->symbology == BARCODE_HIBC_BLOCKF)) {
+            rectangle->x = (float)xoffset;
+            rectangle->width -= (2.0f * xoffset);
+        }
+        vector_plot_add_rect(symbol, rectangle, &last_rectangle);
+        // Bottom
+        rectangle = vector_plot_create_rect(0.0f, vector->height - symbol->border_width - text_offset, vector->width, (float)symbol->border_width);
+        if (!(symbol->output_options & BARCODE_BOX) && (symbol->symbology == BARCODE_CODABLOCKF || symbol->symbology == BARCODE_HIBC_BLOCKF)) {
+            rectangle->x = (float)xoffset;
+            rectangle->width -= (2.0f * xoffset);
+        }
+        vector_plot_add_rect(symbol, rectangle, &last_rectangle);
+    }
+    if (symbol->output_options & BARCODE_BOX) {
+        // Left
+        rectangle = vector_plot_create_rect(0.0f, 0.0f, (float)symbol->border_width, vector->height - text_offset);
+        vector_plot_add_rect(symbol, rectangle, &last_rectangle);
+        // Right
+        rectangle = vector_plot_create_rect(vector->width - symbol->border_width, 0.0f, (float)symbol->border_width, vector->height - text_offset);
+        vector_plot_add_rect(symbol, rectangle, &last_rectangle);
+    }
+
+    vector_reduce_rectangles(symbol);
+
+    vector_scale(symbol, file_type);
+
+    switch (file_type) {
+        case OUT_EPS_FILE:
+            error_number = ps_plot(symbol);
+            break;
+        case OUT_SVG_FILE:
+            error_number = svg_plot(symbol);
+            break;
+        case OUT_EMF_FILE:
+            error_number = emf_plot(symbol);
+            break;
+        /* case OUT_BUFFER: No more work needed */
+    }
+
+    return error_number;
+}
diff --git a/backend/zint.def b/backend/zint.def
deleted file mode 100644 (file)
index 262390f..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-;------------------------------------------
-; LIBZINT module definition file for Windows
-;------------------------------------------
-
-LIBRARY
-
-EXPORTS
-;Version 2.4.3
-DllGetVersion
-
-ZBarcode_Create
-ZBarcode_Clear
-ZBarcode_Delete
-
-ZBarcode_Encode
-ZBarcode_Encode_File
-ZBarcode_Print
-ZBarcode_Encode_and_Print
-ZBarcode_Encode_File_and_Print
-
-ZBarcode_Render
-
-ZBarcode_Buffer
-ZBarcode_Encode_and_Buffer
-ZBarcode_Encode_File_and_Buffer
-
-ZBarcode_ValidID
\ No newline at end of file
index 1efb96e..4d28369 100644 (file)
@@ -1,7 +1,7 @@
 /*  zint.h - definitions for libzint
 
     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
@@ -27,7 +27,8 @@
     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     SUCH DAMAGE.
-*/
+ */
+/* vim: set ts=4 sw=4 et : */
 
 #ifndef ZINT_H
 #define ZINT_H
 extern "C" {
 #endif /* __cplusplus */
 
-#include <stdio.h>
-
-struct zint_render_line {
-       float x, y, length, width;
-       struct zint_render_line *next;      /* Pointer to next line */
-};
-
-struct zint_render_string {
-       float x, y, fsize;
-       float width;                        /* Suggested string width, may be 0 if none recommended */
-       int length;
-       unsigned char *text;
-       struct zint_render_string *next;    /* Pointer to next character */
-};
-
-struct zint_render_ring {
-       float x, y, radius, line_width;
-       struct zint_render_ring *next;      /* Pointer to next ring */
-};
-
-struct zint_render_hexagon {
-       float x, y;
-       struct zint_render_hexagon *next;   /* Pointer to next hexagon */
-};
-
-struct zint_render {
-       float width, height;
-       struct zint_render_line *lines;         /* Pointer to first line */
-       struct zint_render_string *strings;     /* Pointer to first string */
-       struct zint_render_ring *rings;         /* Pointer to first ring */
-       struct zint_render_hexagon *hexagons;   /* Pointer to first hexagon */
-};
-
-struct zint_symbol {
-       int symbology;
-       int height;
-       int whitespace_width;
-       int border_width;
-       int output_options;
-#define ZINT_COLOUR_SIZE 10
-       char fgcolour[ZINT_COLOUR_SIZE];
-       char bgcolour[ZINT_COLOUR_SIZE];
-       char outfile[FILENAME_MAX];
-       float scale;
-       int option_1;
-       int option_2;
-       int option_3;
-       int show_hrt;
-       int input_mode;
-#define ZINT_TEXT_SIZE  128
-       unsigned char text[ZINT_TEXT_SIZE];
-       int rows;
-       int width;
-#define ZINT_PRIMARY_SIZE  128
-       char primary[ZINT_PRIMARY_SIZE];
-#define ZINT_ROWS_MAX  178
-#define ZINT_COLS_MAX  178
-       unsigned char encoded_data[ZINT_ROWS_MAX][ZINT_COLS_MAX];
-       int row_height[ZINT_ROWS_MAX]; /* Largest symbol is 177x177 QR Code */
-#define ZINT_ERR_SIZE   100
-       char errtxt[ZINT_ERR_SIZE];
-       char *bitmap;
-       int bitmap_width;
-       int bitmap_height;
-       struct zint_render *rendered;
-};
-
-
-/* Tbarcode 7 codes */
-#define BARCODE_CODE11         1
-#define BARCODE_C25MATRIX      2
-#define BARCODE_C25INTER       3
-#define BARCODE_C25IATA                4
-#define BARCODE_C25LOGIC       6
-#define BARCODE_C25IND         7
-#define BARCODE_CODE39         8
-#define BARCODE_EXCODE39       9
-#define BARCODE_EANX           13
-#define BARCODE_EAN128         16
-#define BARCODE_CODABAR                18
-#define BARCODE_CODE128                20
-#define BARCODE_DPLEIT         21
-#define BARCODE_DPIDENT                22
-#define BARCODE_CODE16K                23
-#define BARCODE_CODE49         24
-#define BARCODE_CODE93         25
-#define BARCODE_FLAT           28
-#define BARCODE_RSS14          29
-#define BARCODE_RSS_LTD                30
-#define BARCODE_RSS_EXP                31
-#define BARCODE_TELEPEN                32
-#define BARCODE_UPCA           34
-#define BARCODE_UPCE           37
-#define BARCODE_POSTNET                40
-#define BARCODE_MSI_PLESSEY    47
-#define BARCODE_FIM                49
-#define BARCODE_LOGMARS                50
-#define BARCODE_PHARMA         51
-#define BARCODE_PZN                52
-#define BARCODE_PHARMA_TWO     53
-#define BARCODE_PDF417         55
-#define BARCODE_PDF417TRUNC    56
-#define BARCODE_MAXICODE       57
-#define BARCODE_QRCODE         58
-#define BARCODE_CODE128B       60
-#define BARCODE_AUSPOST                63
-#define BARCODE_AUSREPLY       66
-#define BARCODE_AUSROUTE       67
-#define BARCODE_AUSREDIRECT    68
-#define BARCODE_ISBNX          69
-#define BARCODE_RM4SCC         70
-#define BARCODE_DATAMATRIX     71
-#define BARCODE_EAN14          72
-#define BARCODE_CODABLOCKF     74
-#define BARCODE_NVE18          75
-#define BARCODE_JAPANPOST      76
-#define BARCODE_KOREAPOST      77
-#define BARCODE_RSS14STACK     79
-#define BARCODE_RSS14STACK_OMNI        80
-#define BARCODE_RSS_EXPSTACK   81
-#define BARCODE_PLANET         82
-#define BARCODE_MICROPDF417    84
-#define BARCODE_ONECODE                85
-#define BARCODE_PLESSEY                86
-
-/* Tbarcode 8 codes */
-#define BARCODE_TELEPEN_NUM    87
-#define BARCODE_ITF14          89
-#define BARCODE_KIX                90
-#define BARCODE_AZTEC          92
-#define BARCODE_DAFT           93
-#define BARCODE_MICROQR                97
-
-/* Tbarcode 9 codes */
-#define BARCODE_HIBC_128       98
-#define BARCODE_HIBC_39                99
-#define BARCODE_HIBC_DM                102
-#define BARCODE_HIBC_QR                104
-#define BARCODE_HIBC_PDF       106
-#define BARCODE_HIBC_MICPDF    108
-#define BARCODE_HIBC_BLOCKF    110
-#define BARCODE_HIBC_AZTEC     112
-
-/* Zint specific */
-#define BARCODE_AZRUNE         128
-#define BARCODE_CODE32         129
-#define BARCODE_EANX_CC                130
-#define BARCODE_EAN128_CC      131
-#define BARCODE_RSS14_CC       132
-#define BARCODE_RSS_LTD_CC     133
-#define BARCODE_RSS_EXP_CC     134
-#define BARCODE_UPCA_CC                135
-#define BARCODE_UPCE_CC                136
-#define BARCODE_RSS14STACK_CC  137
-#define BARCODE_RSS14_OMNI_CC  138
-#define BARCODE_RSS_EXPSTACK_CC        139
-#define BARCODE_CHANNEL                140
-#define BARCODE_CODEONE                141
-#define BARCODE_GRIDMATRIX     142
-
-#define BARCODE_NO_ASCII       1
-#define BARCODE_BIND           2
-#define BARCODE_BOX                4
-#define BARCODE_STDOUT         8
-#define READER_INIT            16
-#define SMALL_TEXT             32
-
-#define DATA_MODE          0
-#define UNICODE_MODE   1
-#define GS1_MODE           2
-#define KANJI_MODE         3
-#define SJIS_MODE          4
-
-#define DM_SQUARE          100
-
-#define WARN_INVALID_OPTION    2
-#define ERROR_TOO_LONG         5
-#define ERROR_INVALID_DATA     6
-#define ERROR_INVALID_CHECK    7
-#define ERROR_INVALID_OPTION   8
-#define ERROR_ENCODING_PROBLEM 9
-#define ERROR_FILE_ACCESS      10
-#define ERROR_MEMORY           11
+    struct zint_render_line {
+        float x, y, length, width;
+        struct zint_render_line *next; /* Pointer to next line */
+    };
+
+    struct zint_vector_rect {
+        float x, y, height, width;
+        int colour;
+        struct zint_vector_rect *next;
+    };
+
+    struct zint_render_string {
+        float x, y, fsize;
+        float width; /* Suggested string width, may be 0 if none recommended */
+        int length;
+        unsigned char *text;
+        struct zint_render_string *next; /* Pointer to next character */
+    };
+
+    struct zint_vector_string {
+        float x, y, fsize;
+        float width; /* Suggested string width, may be 0 if none recommended */
+        int length;
+        unsigned char *text;
+        struct zint_vector_string *next; /* Pointer to next character */
+    };
+
+    struct zint_render_ring {
+        float x, y, radius, line_width;
+        struct zint_render_ring *next; /* Pointer to next ring */
+    };
+
+    struct zint_vector_circle {
+        float x, y, diameter;
+        int colour;
+        struct zint_vector_circle *next; /* Pointer to next circle */
+    };
+
+    struct zint_render_hexagon {
+        float x, y, height;
+        struct zint_render_hexagon *next; /* Pointer to next hexagon */
+    };
+
+    struct zint_vector_hexagon {
+        float x, y, diameter;
+        struct zint_vector_hexagon *next; /* Pointer to next hexagon */
+    };
+
+    struct zint_render {
+        float width, height;
+        struct zint_render_line *lines; /* Pointer to first line */
+        struct zint_render_string *strings; /* Pointer to first string */
+        struct zint_render_ring *rings; /* Pointer to first ring */
+        struct zint_render_hexagon *hexagons; /* Pointer to first hexagon */
+    };
+
+    struct zint_vector {
+        float width, height;
+        struct zint_vector_rect *rectangles; /* Pointer to first rectangle */
+        struct zint_vector_hexagon *hexagons; /* Pointer to first hexagon */
+        struct zint_vector_string *strings; /* Points to first string */
+        struct zint_vector_circle *circles; /* Points to first circle */
+    };
+
+    struct zint_symbol {
+        int symbology;
+        int height;
+        int whitespace_width;
+        int border_width;
+        int output_options;
+        char fgcolour[10];
+        char bgcolour[10];
+        char outfile[256];
+        float scale;
+        int option_1;
+        int option_2;
+        int option_3;
+        int show_hrt;
+        int fontsize;
+        int input_mode;
+        int eci;
+        unsigned char text[128];
+        int rows;
+        int width;
+        char primary[128];
+        unsigned char encoded_data[200][143];
+        int row_height[200]; /* Largest symbol is 189 x 189 Han Xin */
+        char errtxt[100];
+        unsigned char *bitmap;
+        int bitmap_width;
+        int bitmap_height;
+        unsigned int bitmap_byte_length;
+        float dot_size;
+        struct zint_vector *vector;
+        struct zint_render *rendered;
+        int debug;
+    };
+
+#define ZINT_VERSION_MAJOR      2
+#define ZINT_VERSION_MINOR      8
+#define ZINT_VERSION_RELEASE    0
+
+    /* Tbarcode 7 codes */
+#define BARCODE_CODE11          1
+#define BARCODE_C25MATRIX       2
+#define BARCODE_C25INTER        3
+#define BARCODE_C25IATA         4
+#define BARCODE_C25LOGIC        6
+#define BARCODE_C25IND          7
+#define BARCODE_CODE39          8
+#define BARCODE_EXCODE39        9
+#define BARCODE_EANX            13
+#define BARCODE_EANX_CHK        14
+#define BARCODE_EAN128          16
+#define BARCODE_CODABAR         18
+#define BARCODE_CODE128         20
+#define BARCODE_DPLEIT          21
+#define BARCODE_DPIDENT         22
+#define BARCODE_CODE16K         23
+#define BARCODE_CODE49          24
+#define BARCODE_CODE93          25
+#define BARCODE_FLAT            28
+#define BARCODE_RSS14           29
+#define BARCODE_RSS_LTD         30
+#define BARCODE_RSS_EXP         31
+#define BARCODE_TELEPEN         32
+#define BARCODE_UPCA            34
+#define BARCODE_UPCA_CHK        35
+#define BARCODE_UPCE            37
+#define BARCODE_UPCE_CHK        38
+#define BARCODE_POSTNET         40
+#define BARCODE_MSI_PLESSEY     47
+#define BARCODE_FIM             49
+#define BARCODE_LOGMARS         50
+#define BARCODE_PHARMA          51
+#define BARCODE_PZN             52
+#define BARCODE_PHARMA_TWO      53
+#define BARCODE_PDF417          55
+#define BARCODE_PDF417TRUNC     56
+#define BARCODE_MAXICODE        57
+#define BARCODE_QRCODE          58
+#define BARCODE_CODE128B        60
+#define BARCODE_AUSPOST         63
+#define BARCODE_AUSREPLY        66
+#define BARCODE_AUSROUTE        67
+#define BARCODE_AUSREDIRECT     68
+#define BARCODE_ISBNX           69
+#define BARCODE_RM4SCC          70
+#define BARCODE_DATAMATRIX      71
+#define BARCODE_EAN14           72
+#define BARCODE_VIN             73
+#define BARCODE_CODABLOCKF      74
+#define BARCODE_NVE18           75
+#define BARCODE_JAPANPOST       76
+#define BARCODE_KOREAPOST       77
+#define BARCODE_RSS14STACK      79
+#define BARCODE_RSS14STACK_OMNI 80
+#define BARCODE_RSS_EXPSTACK    81
+#define BARCODE_PLANET          82
+#define BARCODE_MICROPDF417     84
+#define BARCODE_ONECODE         85
+#define BARCODE_PLESSEY         86
+
+    /* Tbarcode 8 codes */
+#define BARCODE_TELEPEN_NUM     87
+#define BARCODE_ITF14           89
+#define BARCODE_KIX             90
+#define BARCODE_AZTEC           92
+#define BARCODE_DAFT            93
+#define BARCODE_MICROQR         97
+
+    /* Tbarcode 9 codes */
+#define BARCODE_HIBC_128        98
+#define BARCODE_HIBC_39         99
+#define BARCODE_HIBC_DM         102
+#define BARCODE_HIBC_QR         104
+#define BARCODE_HIBC_PDF        106
+#define BARCODE_HIBC_MICPDF     108
+#define BARCODE_HIBC_BLOCKF     110
+#define BARCODE_HIBC_AZTEC      112
+
+    /* Tbarcode 10 codes */
+#define BARCODE_DOTCODE         115
+#define BARCODE_HANXIN          116
+
+    /*Tbarcode 11 codes*/
+#define BARCODE_MAILMARK        121
+
+    /* Zint specific */
+#define BARCODE_AZRUNE          128
+#define BARCODE_CODE32          129
+#define BARCODE_EANX_CC         130
+#define BARCODE_EAN128_CC       131
+#define BARCODE_RSS14_CC        132
+#define BARCODE_RSS_LTD_CC      133
+#define BARCODE_RSS_EXP_CC      134
+#define BARCODE_UPCA_CC         135
+#define BARCODE_UPCE_CC         136
+#define BARCODE_RSS14STACK_CC   137
+#define BARCODE_RSS14_OMNI_CC   138
+#define BARCODE_RSS_EXPSTACK_CC 139
+#define BARCODE_CHANNEL         140
+#define BARCODE_CODEONE         141
+#define BARCODE_GRIDMATRIX      142
+#define BARCODE_UPNQR           143
+#define BARCODE_ULTRA           144
+#define BARCODE_RMQR            145
+
+// Output options
+#define BARCODE_NO_ASCII        1
+#define BARCODE_BIND            2
+#define BARCODE_BOX             4
+#define BARCODE_STDOUT          8
+#define READER_INIT             16
+#define SMALL_TEXT              32
+#define BOLD_TEXT               64
+#define CMYK_COLOUR             128
+#define BARCODE_DOTTY_MODE      256
+#define GS1_GS_SEPARATOR        512
+
+// Input data types
+#define DATA_MODE               0
+#define UNICODE_MODE            1
+#define GS1_MODE                2
+#define ESCAPE_MODE             8
+
+// Data Matrix specific options (option_3)
+#define DM_SQUARE               100
+#define DM_DMRE                 101
+
+// QR, Han Xin, Grid Matrix specific options (option_3)
+#define ZINT_FULL_MULTIBYTE     200
+
+// Ultracode specific option (option_3)
+#define ULTRA_COMPRESSION       128
+
+// Warning and error conditions
+#define ZINT_WARN_INVALID_OPTION        2
+#define ZINT_WARN_USES_ECI              3
+#define ZINT_ERROR_TOO_LONG             5
+#define ZINT_ERROR_INVALID_DATA                6
+#define ZINT_ERROR_INVALID_CHECK        7
+#define ZINT_ERROR_INVALID_OPTION       8
+#define ZINT_ERROR_ENCODING_PROBLEM     9
+#define ZINT_ERROR_FILE_ACCESS          10
+#define ZINT_ERROR_MEMORY               11
+
+// Raster file types
+#define OUT_BUFFER              0
+#define OUT_SVG_FILE            10
+#define OUT_EPS_FILE            20
+#define OUT_EMF_FILE            30
+#define OUT_PNG_FILE            100
+#define OUT_BMP_FILE            120
+#define OUT_GIF_FILE            140
+#define OUT_PCX_FILE            160
+#define OUT_JPG_FILE            180
+#define OUT_TIF_FILE            200
+
+// Debug flags
+#define ZINT_DEBUG_PRINT    1
+#define ZINT_DEBUG_TEST     2
 
 #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(_MSC_VER)
-#  if defined (DLL_EXPORT) || defined(PIC) || defined(_USRDLL)
-#       define ZINT_EXTERN __declspec(dllexport)
-#  elif defined(ZINT_DLL)
-#       define ZINT_EXTERN __declspec(dllimport)
-#  else
-#    define ZINT_EXTERN extern
-#  endif
+#if defined (DLL_EXPORT) || defined(PIC) || defined(_USRDLL)
+#define ZINT_EXTERN __declspec(dllexport)
+#elif defined(ZINT_DLL)
+#define ZINT_EXTERN __declspec(dllimport)
 #else
-#  define ZINT_EXTERN extern   
+#define ZINT_EXTERN extern
+#endif
+#else
+#define ZINT_EXTERN extern
 #endif
 
-ZINT_EXTERN struct zint_symbol* ZBarcode_Create(void);
-ZINT_EXTERN void ZBarcode_Clear(struct zint_symbol *symbol);
-ZINT_EXTERN void ZBarcode_Delete(struct zint_symbol *symbol);
-
-ZINT_EXTERN int ZBarcode_Encode(struct zint_symbol *symbol, unsigned char *input, int length);
-ZINT_EXTERN int ZBarcode_Encode_File(struct zint_symbol *symbol, char *filename);
-ZINT_EXTERN int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle);
-ZINT_EXTERN int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
-ZINT_EXTERN int ZBarcode_Encode_File_and_Print(struct zint_symbol *symbol, char *filename, int rotate_angle);
+    ZINT_EXTERN struct zint_symbol *ZBarcode_Create(void);
+    ZINT_EXTERN void ZBarcode_Clear(struct zint_symbol *symbol);
+    ZINT_EXTERN void ZBarcode_Delete(struct zint_symbol *symbol);
 
-ZINT_EXTERN int ZBarcode_Render(struct zint_symbol *symbol, float width, float height);
+    ZINT_EXTERN int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int in_length);
+    ZINT_EXTERN int ZBarcode_Encode_File(struct zint_symbol *symbol, char *filename);
+    ZINT_EXTERN int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle);
+    ZINT_EXTERN int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
+    ZINT_EXTERN int ZBarcode_Encode_File_and_Print(struct zint_symbol *symbol, char *filename, int rotate_angle);
 
-ZINT_EXTERN int ZBarcode_Buffer(struct zint_symbol *symbol, int rotate_angle);
-ZINT_EXTERN int ZBarcode_Encode_and_Buffer(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
-ZINT_EXTERN int ZBarcode_Encode_File_and_Buffer(struct zint_symbol *symbol, char *filename, int rotate_angle);
+    ZINT_EXTERN int ZBarcode_Buffer(struct zint_symbol *symbol, int rotate_angle);
+    ZINT_EXTERN int ZBarcode_Buffer_Vector(struct zint_symbol *symbol, int rotate_angle);
+    ZINT_EXTERN int ZBarcode_Encode_and_Buffer(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
+    ZINT_EXTERN int ZBarcode_Encode_and_Buffer_Vector(struct zint_symbol *symbol, unsigned char *input, int length, int rotate_angle);
+    ZINT_EXTERN int ZBarcode_Encode_File_and_Buffer(struct zint_symbol *symbol, char *filename, int rotate_angle);
+    ZINT_EXTERN int ZBarcode_Encode_File_and_Buffer_Vector(struct zint_symbol *symbol, char *filename, int rotate_angle);
 
-ZINT_EXTERN int ZBarcode_ValidID(int symbol_id);
+    ZINT_EXTERN int ZBarcode_ValidID(int symbol_id);
+    ZINT_EXTERN int ZBarcode_Version();
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 
 #endif /* ZINT_H */
+
index 7ff387b..73f0b58 100644 (file)
@@ -1,6 +1,6 @@
 Name:      zint
-Version:   2.4.3
-Release:   14
+Version:   2.7.1
+Release:   1
 Summary:   Barcode generator library
 License:   BSD-3-Clause
 URL:       http://www.zint.org.uk
@@ -22,7 +22,7 @@ Features of the library:
   FNC1 characters.
 - Support for encoding binary data including NULL (ASCII 0) characters.
 - Health Industry Barcode (HIBC) encoding capabilities.
-- Output in PNG, EPS and SVG formats with user adjustable sizes and colors.
+- Output in the following file formats: PNG, GIF, EPS, WMF, BMP, TIF, SVG.
 - Verification stage for SBN, ISBN and ISBN-13 data.