diff options
author | Tae-Young Chung <ty83.chung@samsung.com> | 2020-06-22 11:16:33 +0900 |
---|---|---|
committer | Tae-Young Chung <ty83.chung@samsung.com> | 2020-06-22 13:32:26 +0900 |
commit | 0428f8a17e78dae97a8774a0ec42f48f85abcb88 (patch) | |
tree | 100c5b5a6d1d6f996294ead7474f31703a456339 /backend/dmatrix.c | |
parent | f18ddd9e3e6afc1edf5d030dd32647b3eac5462b (diff) | |
download | libzint-0428f8a17e78dae97a8774a0ec42f48f85abcb88.tar.gz libzint-0428f8a17e78dae97a8774a0ec42f48f85abcb88.tar.bz2 libzint-0428f8a17e78dae97a8774a0ec42f48f85abcb88.zip |
Bump to version 2.7.1submit/tizen/20200708.035054submit/tizen/20200706.003724submit/tizen/20200702.015201submit/tizen/20200701.041707accepted/tizen/unified/20200708.125323
zint is originally GPL v3 for an whole package
but backend can be used as BSD-3 as
The backed part of zint-code is updated to version 2.7.1
https://sourceforge.net/p/zint/code/ci/master/tree/
Change-Id: I779a9f70f93f0202affe41a7644d9e4bfb810123
Signed-off-by: Tae-Young Chung <ty83.chung@samsung.com>
Diffstat (limited to 'backend/dmatrix.c')
-rw-r--r-- | backend/dmatrix.c | 1342 |
1 files changed, 1342 insertions, 0 deletions
diff --git a/backend/dmatrix.c b/backend/dmatrix.c new file mode 100644 index 0000000..212eb6d --- /dev/null +++ b/backend/dmatrix.c @@ -0,0 +1,1342 @@ +/* dmatrix.c Handles Data Matrix ECC 200 symbols */ + +/* + libzint - the open source barcode library + Copyright (C) 2009-2017 Robin Stuart <rstuart114@gmail.com> + + developed from and including some functions from: + IEC16022 bar code generation + Adrian Kennard, Andrews & Arnold Ltd + with help from Cliff Hones on the RS coding + + (c) 2004 Adrian Kennard, Andrews & Arnold Ltd + (c) 2006 Stefan Schmidt <stefan@datenfreihafen.org> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ +/* vim: set ts=4 sw=4 et : */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <math.h> +#ifdef _MSC_VER +#include <malloc.h> +/* ceilf (C99) not before MSVC++2013 (C++ 12.0) */ +#if _MSC_VER < 1800 +#define ceilf ceil +#endif +#endif +#include "common.h" +#include "reedsol.h" +#include "dmatrix.h" + +/* Annex M placement alorithm low level */ +static void ecc200placementbit(int *array, const int NR, const int NC, int r, int c, const int p, const char b) { + if (r < 0) { + r += NR; + c += 4 - ((NR + 4) % 8); + } + if (c < 0) { + c += NC; + r += 4 - ((NC + 4) % 8); + } + // Necessary for 26x32,26x40,26x48,36x120,36x144,72x120,72x144 + if (r >= NR) { +#ifdef DEBUG + fprintf(stderr, "r >= NR:%i,%i at r=%i->", p, b, r); +#endif + r -= NR; +#ifdef DEBUG + fprintf(stderr, "%i,c=%i\n", r, c); +#endif + } +#ifdef DEBUG + if (0 != array[r * NC + c]) { + int a = array[r * NC + c]; + fprintf(stderr, "Double:%i,%i->%i,%i at r=%i,c=%i\n", a >> 3, a & 7, p, b, r, c); + return; + } +#endif + // Check index limits + assert(r < NR); + assert(c < NC); + // Check double-assignment + assert(0 == array[r * NC + c]); + array[r * NC + c] = (p << 3) + b; +} + +static void ecc200placementblock(int *array, const int NR, const int NC, const int r, + const int c, const int p) { + ecc200placementbit(array, NR, NC, r - 2, c - 2, p, 7); + ecc200placementbit(array, NR, NC, r - 2, c - 1, p, 6); + ecc200placementbit(array, NR, NC, r - 1, c - 2, p, 5); + ecc200placementbit(array, NR, NC, r - 1, c - 1, p, 4); + ecc200placementbit(array, NR, NC, r - 1, c - 0, p, 3); + ecc200placementbit(array, NR, NC, r - 0, c - 2, p, 2); + ecc200placementbit(array, NR, NC, r - 0, c - 1, p, 1); + ecc200placementbit(array, NR, NC, r - 0, c - 0, p, 0); +} + +static void ecc200placementcornerA(int *array, const int NR, const int NC, const int p) { + ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7); + ecc200placementbit(array, NR, NC, NR - 1, 1, p, 6); + ecc200placementbit(array, NR, NC, NR - 1, 2, p, 5); + ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); + ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); + ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2); + ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1); + ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0); +} + +static void ecc200placementcornerB(int *array, const int NR, const int NC, const int p) { + ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7); + ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6); + ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5); + ecc200placementbit(array, NR, NC, 0, NC - 4, p, 4); + ecc200placementbit(array, NR, NC, 0, NC - 3, p, 3); + ecc200placementbit(array, NR, NC, 0, NC - 2, p, 2); + ecc200placementbit(array, NR, NC, 0, NC - 1, p, 1); + ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0); +} + +static void ecc200placementcornerC(int *array, const int NR, const int NC, const int p) { + ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7); + ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6); + ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5); + ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); + ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); + ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2); + ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1); + ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0); +} + +static void ecc200placementcornerD(int *array, const int NR, const int NC, const int p) { + ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7); + ecc200placementbit(array, NR, NC, NR - 1, NC - 1, p, 6); + ecc200placementbit(array, NR, NC, 0, NC - 3, p, 5); + ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4); + ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3); + ecc200placementbit(array, NR, NC, 1, NC - 3, p, 2); + ecc200placementbit(array, NR, NC, 1, NC - 2, p, 1); + ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0); +} + +/* Annex M placement alorithm main function */ +static void ecc200placement(int *array, const int NR, const int NC) { + int r, c, p; + // invalidate + for (r = 0; r < NR; r++) + for (c = 0; c < NC; c++) + array[r * NC + c] = 0; + // start + p = 1; + r = 4; + c = 0; + do { + // check corner + if (r == NR && !c) + ecc200placementcornerA(array, NR, NC, p++); + if (r == NR - 2 && !c && NC % 4) + ecc200placementcornerB(array, NR, NC, p++); + if (r == NR - 2 && !c && (NC % 8) == 4) + ecc200placementcornerC(array, NR, NC, p++); + if (r == NR + 4 && c == 2 && !(NC % 8)) + ecc200placementcornerD(array, NR, NC, p++); + // up/right + do { + if (r < NR && c >= 0 && !array[r * NC + c]) + ecc200placementblock(array, NR, NC, r, c, p++); + r -= 2; + c += 2; + } while (r >= 0 && c < NC); + r++; + c += 3; + // down/left + do { + if (r >= 0 && c < NC && !array[r * NC + c]) + ecc200placementblock(array, NR, NC, r, c, p++); + r += 2; + c -= 2; + } while (r < NR && c >= 0); + r += 3; + c++; + } while (r < NR || c < NC); + // unfilled corner + if (!array[NR * NC - 1]) + array[NR * NC - 1] = array[NR * NC - NC - 2] = 1; +} + +/* calculate and append ecc code, and if necessary interleave */ +static void ecc200(unsigned char *binary, const int bytes, const int datablock, const int rsblock, const int skew) { + int blocks = (bytes + 2) / datablock, b; + int n; + rs_init_gf(0x12d); + rs_init_code(rsblock, 1); + for (b = 0; b < blocks; b++) { + unsigned char buf[256], ecc[256]; + int p = 0; + for (n = b; n < bytes; n += blocks) + buf[p++] = binary[n]; + rs_encode(p, buf, ecc); + p = rsblock - 1; // comes back reversed + for (n = b; n < rsblock * blocks; n += blocks) { + if (skew) { + /* Rotate ecc data to make 144x144 size symbols acceptable */ + /* See http://groups.google.com/group/postscriptbarcode/msg/5ae8fda7757477da */ + if (b < 8) { + binary[bytes + n + 2] = ecc[p--]; + } else { + binary[bytes + n - 8] = ecc[p--]; + } + } else { + binary[bytes + n] = ecc[p--]; + } + } + } + rs_free(); +} + +/* Return true (1) if a character is valid in X12 set */ +static int isX12(const int source) { + + switch(source) { + case 13: // CR + case 42: // * + case 62: // > + case 32: // space + return 1; + } + + if ((source >= '0') && (source <= '9')) { + return 1; + } + if ((source >= 'A') && (source <= 'Z')) { + return 1; + } + + return 0; +} + +/* Insert a character into the middle of a string at position posn */ +static void dminsert(char binary_string[], const int posn, const char newbit) { + int i, end; + + end = (int) strlen(binary_string); + for (i = end + 1; i > posn; i--) { + binary_string[i] = binary_string[i - 1]; + } + binary_string[posn] = newbit; +} + +static void insert_value(unsigned char binary_stream[], const int posn, const int streamlen, const int newbit) { + int i; + + for(i = (int)streamlen; i > posn; i--) { + binary_stream[i] = binary_stream[i - 1]; + } + binary_stream[posn] = (unsigned char) newbit; +} + +static int p_r_6_2_1(const unsigned char inputData[], const size_t position, const size_t sourcelen) { + /* Annex P section (r)(6)(ii)(I) + "If one of the three X12 terminator/separator characters first + occurs in the yet to be processed data before a non-X12 character..." + */ + + size_t i; + size_t nonX12Position = 0; + size_t specialX12Position = 0; + int retval = 0; + + for (i = position; i < sourcelen; i++) { + if (nonX12Position == 0) { + if (isX12(inputData[i]) != 1) { + nonX12Position = i; + } + } + + if (specialX12Position == 0) { + if ((inputData[i] == (char) 13) || + (inputData[i] == '*') || + (inputData[i] == '>')) { + specialX12Position = i; + } + } + } + + if ((nonX12Position != 0) && (specialX12Position != 0)) { + if (specialX12Position < nonX12Position) { + retval = 1; + } + } + + return retval; +} + +/* 'look ahead test' from Annex P */ +static int look_ahead_test(const unsigned char inputData[], const size_t sourcelen, const size_t position, const int current_mode, const int gs1) { + float ascii_count, c40_count, text_count, x12_count, edf_count, b256_count, best_count; + const float stiction = (1.0F / 24.0F); // smallest change to act on, to get around floating point inaccuracies + int best_scheme; + size_t sp; + + best_scheme = DM_NULL; + + /* step (j) */ + if (current_mode == DM_ASCII) { + ascii_count = 0.0F; + c40_count = 1.0F; + text_count = 1.0F; + x12_count = 1.0F; + edf_count = 1.0F; + b256_count = 1.25F; + } else { + ascii_count = 1.0F; + c40_count = 2.0F; + text_count = 2.0F; + x12_count = 2.0F; + edf_count = 2.0F; + b256_count = 2.25F; + } + + switch (current_mode) { + case DM_C40: c40_count = 0.0F; + break; + case DM_TEXT: text_count = 0.0F; + break; + case DM_X12: x12_count = 0.0F; + break; + case DM_EDIFACT: edf_count = 0.0F; + break; + case DM_BASE256: b256_count = 0.0F; + break; + } + + sp = position; + + do { + if (sp == sourcelen) { + /* At the end of data ... step (k) */ + ascii_count = ceilf(ascii_count); + b256_count = ceilf(b256_count); + edf_count = ceilf(edf_count); + text_count = ceilf(text_count); + x12_count = ceilf(x12_count); + c40_count = ceilf(c40_count); + + best_count = c40_count; + best_scheme = DM_C40; // (k)(7) + + if (x12_count < (best_count - stiction)) { + best_count = x12_count; + best_scheme = DM_X12; // (k)(6) + } + + if (text_count < (best_count - stiction)) { + best_count = text_count; + best_scheme = DM_TEXT; // (k)(5) + } + + if (edf_count < (best_count - stiction)) { + best_count = edf_count; + best_scheme = DM_EDIFACT; // (k)(4) + } + + if (b256_count < (best_count - stiction)) { + best_count = b256_count; + best_scheme = DM_BASE256; // (k)(3) + } + + if (ascii_count <= (best_count + stiction)) { + best_scheme = DM_ASCII; // (k)(2) + } + } else { + + /* ascii ... step (l) */ + if ((inputData[sp] >= '0') && (inputData[sp] <= '9')) { + ascii_count += 0.5F; // (l)(1) + } else { + if (inputData[sp] > 127) { + ascii_count = ceilf(ascii_count) + 2.0F; // (l)(2) + } else { + ascii_count = ceilf(ascii_count) + 1.0F; // (l)(3) + } + } + + /* c40 ... step (m) */ + if ((inputData[sp] == ' ') || + (((inputData[sp] >= '0') && (inputData[sp] <= '9')) || + ((inputData[sp] >= 'A') && (inputData[sp] <= 'Z')))) { + c40_count += (2.0F / 3.0F); // (m)(1) + } else { + if (inputData[sp] > 127) { + c40_count += (8.0F / 3.0F); // (m)(2) + } else { + c40_count += (4.0F / 3.0F); // (m)(3) + } + } + + /* text ... step (n) */ + if ((inputData[sp] == ' ') || + (((inputData[sp] >= '0') && (inputData[sp] <= '9')) || + ((inputData[sp] >= 'a') && (inputData[sp] <= 'z')))) { + text_count += (2.0F / 3.0F); // (n)(1) + } else { + if (inputData[sp] > 127) { + text_count += (8.0F / 3.0F); // (n)(2) + } else { + text_count += (4.0F / 3.0F); // (n)(3) + } + } + + /* x12 ... step (o) */ + if (isX12(inputData[sp])) { + x12_count += (2.0F / 3.0F); // (o)(1) + } else { + if (inputData[sp] > 127) { + x12_count += (13.0F / 3.0F); // (o)(2) + } else { + x12_count += (10.0F / 3.0F); // (o)(3) + } + } + + /* edifact ... step (p) */ + if ((inputData[sp] >= ' ') && (inputData[sp] <= '^')) { + edf_count += (3.0F / 4.0F); // (p)(1) + } else { + if (inputData[sp] > 127) { + edf_count += 17.0F; // (p)(2) > Value changed from ISO + } else { + edf_count += 13.0F; // (p)(3) > Value changed from ISO + } + } + if (gs1 && (inputData[sp] == '[')) { + /* fnc1 and gs have the same weight of 13.0f */ + edf_count += 13.0F; // > Value changed from ISO + } + + /* base 256 ... step (q) */ + if ((gs1 == 1) && (inputData[sp] == '[')) { + /* FNC1 separator */ + b256_count += 4.0F; // (q)(1) + } else { + b256_count += 1.0F; // (q)(2) + } + } + + + if (sp > (position + 3)) { + /* 4 data characters processed ... step (r) */ + + /* step (r)(6) */ + if (((c40_count + 1.0F) < (ascii_count - stiction)) && + ((c40_count + 1.0F) < (b256_count - stiction)) && + ((c40_count + 1.0F) < (edf_count - stiction)) && + ((c40_count + 1.0F) < (text_count - stiction))) { + + if (c40_count < (x12_count - stiction)) { + best_scheme = DM_C40; + } + + if ((c40_count >= (x12_count - stiction)) + && (c40_count <= (x12_count + stiction))) { + if (p_r_6_2_1(inputData, sp, sourcelen) == 1) { + // Test (r)(6)(ii)(i) + best_scheme = DM_X12; + } else { + best_scheme = DM_C40; + } + } + } + + /* step (r)(5) */ + if (((x12_count + 1.0F) < (ascii_count - stiction)) && + ((x12_count + 1.0F) < (b256_count - stiction)) && + ((x12_count + 1.0F) < (edf_count - stiction)) && + ((x12_count + 1.0F) < (text_count - stiction)) && + ((x12_count + 1.0F) < (c40_count - stiction))) { + best_scheme = DM_X12; + } + + /* step (r)(4) */ + if (((text_count + 1.0F) < (ascii_count - stiction)) && + ((text_count + 1.0F) < (b256_count - stiction)) && + ((text_count + 1.0F) < (edf_count - stiction)) && + ((text_count + 1.0F) < (x12_count - stiction)) && + ((text_count + 1.0F) < (c40_count - stiction))) { + best_scheme = DM_TEXT; + } + + /* step (r)(3) */ + if (((edf_count + 1.0F) < (ascii_count - stiction)) && + ((edf_count + 1.0F) < (b256_count - stiction)) && + ((edf_count + 1.0F) < (text_count - stiction)) && + ((edf_count + 1.0F) < (x12_count - stiction)) && + ((edf_count + 1.0F) < (c40_count - stiction))) { + best_scheme = DM_EDIFACT; + } + + /* step (r)(2) */ + if (((b256_count + 1.0F) <= (ascii_count + stiction)) || + (((b256_count + 1.0F) < (edf_count - stiction)) && + ((b256_count + 1.0F) < (text_count - stiction)) && + ((b256_count + 1.0F) < (x12_count - stiction)) && + ((b256_count + 1.0F) < (c40_count - stiction)))) { + best_scheme = DM_BASE256; + } + + /* step (r)(1) */ + if (((ascii_count + 1.0F) <= (b256_count + stiction)) && + ((ascii_count + 1.0F) <= (edf_count + stiction)) && + ((ascii_count + 1.0F) <= (text_count + stiction)) && + ((ascii_count + 1.0F) <= (x12_count + stiction)) && + ((ascii_count + 1.0F) <= (c40_count + stiction))) { + best_scheme = DM_ASCII; + } + } + + sp++; + } while (best_scheme == DM_NULL); // step (s) + + return best_scheme; +} + +/* Encodes data using ASCII, C40, Text, X12, EDIFACT or Base 256 modes as appropriate + Supports encoding FNC1 in supporting systems */ +static int dm200encode(struct zint_symbol *symbol, const unsigned char source[], unsigned char target[], int *last_mode, size_t *length_p, int process_buffer[], int *process_p, int *binlen_p) { + + size_t sp; + int tp, i, gs1; + int current_mode, next_mode; + size_t inputlen = *length_p; + int debug = symbol->debug; +#ifndef _MSC_VER + char binary[2 * inputlen + 1 + 4 + 1]; /* Allow for GS1/READER_INIT, ECI and nul chars overhead */ +#else + char* binary = (char*) _alloca(2 * inputlen + 1 + 4 + 1); +#endif + + sp = 0; + tp = 0; + memset(process_buffer, 0, 8); + *process_p = 0; + strcpy(binary, ""); + + /* step (a) */ + current_mode = DM_ASCII; + next_mode = DM_ASCII; + + /* gs1 flag values: 0: no gs1, 1: gs1 with FNC1 serparator, 2: GS separator */ + if ((symbol->input_mode & 0x07) == GS1_MODE) { + if (symbol->output_options & GS1_GS_SEPARATOR) { + gs1 = 2; + } else { + gs1 = 1; + } + } else { + gs1 = 0; + } + + if (gs1) { + target[tp] = 232; + tp++; + strcat(binary, " "); + if (debug) printf("FN1 "); + } /* FNC1 */ + + if (symbol->output_options & READER_INIT) { + if (gs1) { + strcpy(symbol->errtxt, "521: Cannot encode in GS1 mode and Reader Initialisation at the same time"); + return ZINT_ERROR_INVALID_OPTION; + } else { + target[tp] = 234; + tp++; /* Reader Programming */ + strcat(binary, " "); + if (debug) printf("RP "); + } + } + + if (symbol->eci > 0) { + /* Encode ECI numbers according to Table 6 */ + target[tp] = 241; /* ECI Character */ + tp++; + if (symbol->eci <= 126) { + target[tp] = (unsigned char) symbol->eci + 1; + tp++; + strcat(binary, " "); + } + if ((symbol->eci >= 127) && (symbol->eci <= 16382)) { + target[tp] = (unsigned char) ((symbol->eci - 127) / 254) + 128; + tp++; + target[tp] = (unsigned char) ((symbol->eci - 127) % 254) + 1; + tp++; + strcat(binary, " "); + } + if (symbol->eci >= 16383) { + target[tp] = (unsigned char) ((symbol->eci - 16383) / 64516) + 192; + tp++; + target[tp] = (unsigned char) (((symbol->eci - 16383) / 254) % 254) + 1; + tp++; + target[tp] = (unsigned char) ((symbol->eci - 16383) % 254) + 1; + tp++; + strcat(binary, " "); + } + if (debug) printf("ECI %d ", symbol->eci + 1); + } + + /* Check for Macro05/Macro06 */ + /* "[)>[RS]05[GS]...[RS][EOT]" -> CW 236 */ + /* "[)>[RS]06[GS]...[RS][EOT]" -> CW 237 */ + if (tp == 0 && sp == 0 && inputlen >= 9 + && source[0] == '[' && source[1] == ')' && source[2] == '>' + && source[3] == '\x1e' && source[4] == '0' + && (source[5] == '5' || source[5] == '6') + && source[6] == '\x1d' + && source[inputlen - 2] == '\x1e' && source[inputlen - 1] == '\x04') { + /* Output macro Codeword */ + if (source[5] == '5') { + target[tp] = 236; + if (debug) printf("Macro05 "); + } else { + target[tp] = 237; + if (debug) printf("Macro06 "); + } + tp++; + strcat(binary, " "); + /* Remove macro characters from input string */ + sp = 7; + inputlen -= 2; + *length_p -= 2; + } + + + while (sp < inputlen) { + + current_mode = next_mode; + + /* step (b) - ASCII encodation */ + if (current_mode == DM_ASCII) { + next_mode = DM_ASCII; + + if (istwodigits(source, inputlen, sp)) { + target[tp] = (unsigned char) ((10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130); + if (debug) printf("N%d ", target[tp] - 130); + tp++; + strcat(binary, " "); + sp += 2; + } else { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + + if (next_mode != DM_ASCII) { + switch (next_mode) { + case DM_C40: target[tp] = 230; + tp++; + strcat(binary, " "); + if (debug) printf("C40 "); + break; + case DM_TEXT: target[tp] = 239; + tp++; + strcat(binary, " "); + if (debug) printf("TEX "); + break; + case DM_X12: target[tp] = 238; + tp++; + strcat(binary, " "); + if (debug) printf("X12 "); + break; + case DM_EDIFACT: target[tp] = 240; + tp++; + strcat(binary, " "); + if (debug) printf("EDI "); + break; + case DM_BASE256: target[tp] = 231; + tp++; + strcat(binary, " "); + if (debug) printf("BAS "); + break; + } + } else { + if (source[sp] > 127) { + target[tp] = 235; /* FNC4 */ + if (debug) printf("FN4 "); + tp++; + target[tp] = (source[sp] - 128) + 1; + if (debug) printf("A%02X ", target[tp] - 1); + tp++; + strcat(binary, " "); + } else { + if (gs1 && (source[sp] == '[')) { + if (gs1==2) { + target[tp] = 29+1; /* GS */ + if (debug) printf("GS "); + } else { + target[tp] = 232; /* FNC1 */ + if (debug) printf("FN1 "); + } + } else { + target[tp] = source[sp] + 1; + if (debug) printf("A%02X ", target[tp] - 1); + } + tp++; + strcat(binary, " "); + } + sp++; + } + } + + } + + /* step (c) C40 encodation */ + if (current_mode == DM_C40) { + + next_mode = DM_C40; + if (*process_p == 0) { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + } + + if (next_mode != DM_C40) { + target[tp] = 254; + tp++; + strcat(binary, " "); /* Unlatch */ + next_mode = DM_ASCII; + if (debug) printf("ASC "); + } else { + int shift_set, value; + if (source[sp] > 127) { + process_buffer[*process_p] = 1; + (*process_p)++; + process_buffer[*process_p] = 30; + (*process_p)++; /* Upper Shift */ + shift_set = c40_shift[source[sp] - 128]; + value = c40_value[source[sp] - 128]; + } else { + shift_set = c40_shift[source[sp]]; + value = c40_value[source[sp]]; + } + + if (gs1 && (source[sp] == '[')) { + if (gs1 == 2) { + shift_set = c40_shift[29]; + value = c40_value[29]; /* GS */ + } else { + shift_set = 2; + value = 27; /* FNC1 */ + } + } + + if (shift_set != 0) { + process_buffer[*process_p] = shift_set - 1; + (*process_p)++; + } + process_buffer[*process_p] = value; + (*process_p)++; + + while (*process_p >= 3) { + int iv; + + iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1; + target[tp] = (unsigned char) (iv / 256); + tp++; + target[tp] = iv % 256; + tp++; + strcat(binary, " "); + if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]); + + process_buffer[0] = process_buffer[3]; + process_buffer[1] = process_buffer[4]; + process_buffer[2] = process_buffer[5]; + process_buffer[3] = 0; + process_buffer[4] = 0; + process_buffer[5] = 0; + *process_p -= 3; + } + sp++; + } + } + + /* step (d) Text encodation */ + if (current_mode == DM_TEXT) { + + next_mode = DM_TEXT; + if (*process_p == 0) { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + } + + if (next_mode != DM_TEXT) { + target[tp] = 254; + tp++; + strcat(binary, " "); /* Unlatch */ + next_mode = DM_ASCII; + if (debug) printf("ASC "); + } else { + int shift_set, value; + if (source[sp] > 127) { + process_buffer[*process_p] = 1; + (*process_p)++; + process_buffer[*process_p] = 30; + (*process_p)++; /* Upper Shift */ + shift_set = text_shift[source[sp] - 128]; + value = text_value[source[sp] - 128]; + } else { + shift_set = text_shift[source[sp]]; + value = text_value[source[sp]]; + } + + if (gs1 && (source[sp] == '[')) { + if (gs1 == 2) { + shift_set = text_shift[29]; + value = text_value[29]; /* GS */ + } else { + shift_set = 2; + value = 27; /* FNC1 */ + } + } + + if (shift_set != 0) { + process_buffer[*process_p] = shift_set - 1; + (*process_p)++; + } + process_buffer[*process_p] = value; + (*process_p)++; + + while (*process_p >= 3) { + int iv; + + iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1; + target[tp] = (unsigned char) (iv / 256); + tp++; + target[tp] = iv % 256; + tp++; + strcat(binary, " "); + if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]); + + process_buffer[0] = process_buffer[3]; + process_buffer[1] = process_buffer[4]; + process_buffer[2] = process_buffer[5]; + process_buffer[3] = 0; + process_buffer[4] = 0; + process_buffer[5] = 0; + *process_p -= 3; + } + sp++; + } + } + + /* step (e) X12 encodation */ + if (current_mode == DM_X12) { + + next_mode = DM_X12; + if (*process_p == 0) { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + } + + if (next_mode != DM_X12) { + target[tp] = 254; + tp++; + strcat(binary, " "); /* Unlatch */ + next_mode = DM_ASCII; + if (debug) printf("ASC "); + } else { + int value = 0; + if (source[sp] == 13) { + value = 0; + } + if (source[sp] == '*') { + value = 1; + } + if (source[sp] == '>') { + value = 2; + } + if (source[sp] == ' ') { + value = 3; + } + if ((source[sp] >= '0') && (source[sp] <= '9')) { + value = (source[sp] - '0') + 4; + } + if ((source[sp] >= 'A') && (source[sp] <= 'Z')) { + value = (source[sp] - 'A') + 14; + } + + process_buffer[*process_p] = value; + (*process_p)++; + + while (*process_p >= 3) { + int iv; + + iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1; + target[tp] = (unsigned char) (iv / 256); + tp++; + target[tp] = iv % 256; + tp++; + strcat(binary, " "); + if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]); + + process_buffer[0] = process_buffer[3]; + process_buffer[1] = process_buffer[4]; + process_buffer[2] = process_buffer[5]; + process_buffer[3] = 0; + process_buffer[4] = 0; + process_buffer[5] = 0; + *process_p -= 3; + } + sp++; + } + } + + /* step (f) EDIFACT encodation */ + if (current_mode == DM_EDIFACT) { + + next_mode = DM_EDIFACT; + if (*process_p == 3) { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + } + + if (next_mode != DM_EDIFACT) { + process_buffer[*process_p] = 31; + (*process_p)++; + next_mode = DM_ASCII; + } else { + int value = source[sp]; + + if (source[sp] >= 64) { // '@' + value -= 64; + } + + process_buffer[*process_p] = value; + (*process_p)++; + sp++; + } + + while (*process_p >= 4) { + target[tp] = (unsigned char) ((process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4)); + tp++; + target[tp] = ((process_buffer[1] & 0x0f) << 4) + ((process_buffer[2] & 0x3c) >> 2); + tp++; + target[tp] = (unsigned char) (((process_buffer[2] & 0x03) << 6) + process_buffer[3]); + tp++; + strcat(binary, " "); + if (debug) printf("[%d %d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2], process_buffer[3]); + + process_buffer[0] = process_buffer[4]; + process_buffer[1] = process_buffer[5]; + process_buffer[2] = process_buffer[6]; + process_buffer[3] = process_buffer[7]; + process_buffer[4] = 0; + process_buffer[5] = 0; + process_buffer[6] = 0; + process_buffer[7] = 0; + *process_p -= 4; + } + } + + /* step (g) Base 256 encodation */ + if (current_mode == DM_BASE256) { + next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1); + + if (next_mode == DM_BASE256) { + target[tp] = source[sp]; + if (debug) printf("B%02X ", target[tp]); + tp++; + sp++; + strcat(binary, "b"); + } else { + next_mode = DM_ASCII; + if (debug) printf("ASC "); + } + } + + if (tp > 1558) { + strcpy(symbol->errtxt, "520: Data too long to fit in symbol"); + return ZINT_ERROR_TOO_LONG; + } + + } /* while */ + + /* Add length and randomising algorithm to b256 */ + i = 0; + while (i < tp) { + if (binary[i] == 'b') { + if ((i == 0) || (binary[i - 1] != 'b')) { + /* start of binary data */ + int binary_count; /* length of b256 data */ + + for (binary_count = 0; binary_count + i < tp && binary[binary_count + i] == 'b'; binary_count++); + + if (binary_count <= 249) { + dminsert(binary, i, 'b'); + insert_value(target, i, tp, binary_count); + tp++; + } else { + dminsert(binary, i, 'b'); + dminsert(binary, i + 1, 'b'); + insert_value(target, i, tp, (binary_count / 250) + 249); + tp++; + insert_value(target, i + 1, tp, binary_count % 250); + tp++; + } + } + } + i++; + } + + for (i = 0; i < tp; i++) { + if (binary[i] == 'b') { + int prn, temp; + + prn = ((149 * (i + 1)) % 255) + 1; + temp = target[i] + prn; + if (temp <= 255) { + target[i] = (unsigned char) (temp); + } else { + target[i] = (unsigned char) (temp - 256); + } + } + } + + *(last_mode) = current_mode; + *binlen_p = tp; + return 0; +} + +static int dm200encode_remainder(unsigned char target[], int target_length, const unsigned char source[], const size_t inputlen, const int last_mode, const int process_buffer[], const int process_p, const int symbols_left) { + int debug = 0; + + switch (last_mode) { + case DM_C40: + case DM_TEXT: + if (process_p == 1) // 1 data character left to encode. + { + if (symbols_left > 1) { + target[target_length] = 254; + target_length++; // Unlatch and encode remaining data in ascii. + } + target[target_length] = source[inputlen - 1] + 1; + target_length++; + } else if (process_p == 2) // 2 data characters left to encode. + { + // Pad with shift 1 value (0) and encode as double. + int intValue = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + 1; // ie (0 + 1). + target[target_length] = (unsigned char) (intValue / 256); + target_length++; + target[target_length] = (unsigned char) (intValue % 256); + target_length++; + if (symbols_left > 2) { + target[target_length] = 254; // Unlatch + target_length++; + } + } else { + if (symbols_left > 0) { + target[target_length] = 254; // Unlatch + target_length++; + } + } + break; + + case DM_X12: + if ((symbols_left == process_p) && (process_p == 1)) { + // Unlatch not required! + target[target_length] = source[inputlen - 1] + 1; + target_length++; + } else { + target[target_length] = (254); + target_length++; // Unlatch. + + if (process_p == 1) { + target[target_length] = source[inputlen - 1] + 1; + target_length++; + } + + if (process_p == 2) { + target[target_length] = source[inputlen - 2] + 1; + target_length++; + target[target_length] = source[inputlen - 1] + 1; + target_length++; + } + } + break; + + case DM_EDIFACT: + if (symbols_left <= 2) // Unlatch not required! + { + if (process_p == 1) { + target[target_length] = source[inputlen - 1] + 1; + target_length++; + } + + if (process_p == 2) { + target[target_length] = source[inputlen - 2] + 1; + target_length++; + target[target_length] = source[inputlen - 1] + 1; + target_length++; + } + } else { + // Append edifact unlatch value (31) and empty buffer + if (process_p == 0) { + target[target_length] = (unsigned char) (31 << 2); + target_length++; + } + + if (process_p == 1) { + target[target_length] = (unsigned char) ((process_buffer[0] << 2) + ((31 & 0x30) >> 4)); + target_length++; + target[target_length] = (unsigned char) ((31 & 0x0f) << 4); + target_length++; + } + + if (process_p == 2) { + target[target_length] = (unsigned char) ((process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4)); + target_length++; + target[target_length] = (unsigned char) (((process_buffer[1] & 0x0f) << 4) + ((31 & 0x3c) >> 2)); + target_length++; + target[target_length] = (unsigned char) (((31 & 0x03) << 6)); + target_length++; + } + + if (process_p == 3) { + target[target_length] = (unsigned char) ((process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4)); + target_length++; + target[target_length] = (unsigned char) (((process_buffer[1] & 0x0f) << 4) + ((process_buffer[2] & 0x3c) >> 2)); + target_length++; + target[target_length] = (unsigned char) (((process_buffer[2] & 0x03) << 6) + 31); + target_length++; + } + } + break; + } + + if (debug) { + int i; + printf("\n\n"); + for (i = 0; i < target_length; i++) + printf("%03d ", target[i]); + + printf("\n"); + } + + return target_length; +} + +/* add pad bits */ +static void add_tail(unsigned char target[], int tp, const int tail_length) { + int i, prn, temp; + + for (i = tail_length; i > 0; i--) { + if (i == tail_length) { + target[tp] = 129; + tp++; /* Pad */ + } else { + prn = ((149 * (tp + 1)) % 253) + 1; + temp = 129 + prn; + if (temp <= 254) { + target[tp] = (unsigned char) (temp); + tp++; + } else { + target[tp] = (unsigned char) (temp - 254); + tp++; + } + } + } +} + +static int data_matrix_200(struct zint_symbol *symbol,const unsigned char source[], const size_t in_length) { + int i, skew = 0; + size_t inputlen = in_length; + unsigned char binary[2200]; + int binlen; + int process_buffer[8]; /* holds remaining data to finalised */ + int process_p; /* number of characters left to finalise */ + int symbolsize, optionsize, calcsize; + int taillength, error_number = 0; + int H, W, FH, FW, datablock, bytes, rsblock; + int last_mode = DM_ASCII; + int symbols_left; + + /* inputlen may be decremented by 2 if macro character is used */ + error_number = dm200encode(symbol, source, binary, &last_mode, &inputlen, process_buffer, &process_p, &binlen); + if (error_number != 0) { + return error_number; + } + + if ((symbol->option_2 >= 1) && (symbol->option_2 <= DMSIZESCOUNT)) { + optionsize = intsymbol[symbol->option_2 - 1]; + } else { + optionsize = -1; + } + + calcsize = DMSIZESCOUNT - 1; + for (i = DMSIZESCOUNT - 1; i > -1; i--) { + if (matrixbytes[i] >= (binlen + process_p)) { + // Allow for the remaining data characters + calcsize = i; + } + } + + if (optionsize == -1) { + // We are in automatic size mode as the exact symbol size was not given + // Now check the detailed search options square only or no dmre + if (symbol->option_3 == DM_SQUARE) { + /* Skip rectangular symbols in square only mode */ + while (matrixH[calcsize] != matrixW[calcsize]) { + calcsize++; + } + } else if (symbol->option_3 != DM_DMRE) { + /* Skip DMRE symbols in no dmre mode */ + while (isDMRE[calcsize]) { + calcsize++; + } + } + symbolsize = calcsize; + } else { + // The symbol size was given by --ver (option_2) + // Thus check if the data fits into this symbol size and use this size + if (calcsize > optionsize) { + strcpy(symbol->errtxt, "522: Input too long for selected symbol size"); + return ZINT_ERROR_TOO_LONG; + } + symbolsize = optionsize; + } + + // Now we know the symbol size we can handle the remaining data in the process buffer. + symbols_left = matrixbytes[symbolsize] - binlen; + binlen = dm200encode_remainder(binary, binlen, source, inputlen, last_mode, process_buffer, process_p, symbols_left); + + if (binlen > matrixbytes[symbolsize]) { + strcpy(symbol->errtxt, "523: Data too long to fit in symbol"); + return ZINT_ERROR_TOO_LONG; + } + + H = matrixH[symbolsize]; + W = matrixW[symbolsize]; + FH = matrixFH[symbolsize]; + FW = matrixFW[symbolsize]; + bytes = matrixbytes[symbolsize]; + datablock = matrixdatablock[symbolsize]; + rsblock = matrixrsblock[symbolsize]; + + taillength = bytes - binlen; + + if (taillength != 0) { + add_tail(binary, binlen, taillength); + } + + // ecc code + if (symbolsize == INTSYMBOL144) { + skew = 1; + } + ecc200(binary, bytes, datablock, rsblock, skew); + // Print Codewords +#ifdef DEBUG + { + int CWCount; + int posCur; + if (skew) + CWCount = 1558 + 620; + else + CWCount = bytes + rsblock * (bytes / datablock); + printf("Codewords (%i):", CWCount); + for (posCur = 0; posCur < CWCount; posCur++) + printf(" %3i", binary[posCur]); + puts("\n"); + } +#endif + { // placement + int x, y, NC, NR, *places; + unsigned char *grid; + NC = W - 2 * (W / FW); + NR = H - 2 * (H / FH); + places = (int*) malloc(NC * NR * sizeof (int)); + ecc200placement(places, NR, NC); + grid = (unsigned char*) malloc(W * H); + memset(grid, 0, W * H); + for (y = 0; y < H; y += FH) { + for (x = 0; x < W; x++) + grid[y * W + x] = 1; + for (x = 0; x < W; x += 2) + grid[(y + FH - 1) * W + x] = 1; + } + for (x = 0; x < W; x += FW) { + for (y = 0; y < H; y++) + grid[y * W + x] = 1; + for (y = 0; y < H; y += 2) + grid[y * W + x + FW - 1] = 1; + } +#ifdef DEBUG + // Print position matrix as in standard + for (y = NR - 1; y >= 0; y--) { + for (x = 0; x < NC; x++) { + int v; + if (x != 0) + fprintf(stderr, "|"); + v = places[(NR - y - 1) * NC + x]; + fprintf(stderr, "%3d.%2d", (v >> 3), 8 - (v & 7)); + } + fprintf(stderr, "\n"); + } +#endif + for (y = 0; y < NR; y++) { + for (x = 0; x < NC; x++) { + int v = places[(NR - y - 1) * NC + x]; + //fprintf (stderr, "%4d", v); + if (v == 1 || (v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7))))) + grid[(1 + y + 2 * (y / (FH - 2))) * W + 1 + x + 2 * (x / (FW - 2))] = 1; + } + //fprintf (stderr, "\n"); + } + for (y = H - 1; y >= 0; y--) { + int x; + for (x = 0; x < W; x++) { + if (grid[W * y + x]) { + set_module(symbol, (H - y) - 1, x); + } + } + symbol->row_height[(H - y) - 1] = 1; + } + free(grid); + free(places); + } + + symbol->rows = H; + symbol->width = W; + + return error_number; +} + +INTERNAL int dmatrix(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) { + int error_number; + + if (symbol->option_1 <= 1) { + /* ECC 200 */ + error_number = data_matrix_200(symbol, source, in_length); + } else { + /* ECC 000 - 140 */ + strcpy(symbol->errtxt, "524: Older Data Matrix standards are no longer supported"); + error_number = ZINT_ERROR_INVALID_OPTION; + } + + return error_number; +} |