diff --git a/ChangeLog b/ChangeLog index f64680b8..49e5f59b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -Version 2.13.0.9 (dev) not released yet (2024-11-23) +Version 2.13.0.9 (dev) not released yet (2025-01-18) ==================================================== **Incompatible changes** @@ -51,6 +51,7 @@ Changes touch add-on TODO: revisit when standard clarified - manual: make explicit that AI "(00)" and "(01)" prefixes added by Zint are HRT-only; clarify Codablock-F length maximum & add examples +- add DXFILMEDGE (MR #159, props Antoine Mérino) Bugs ---- @@ -70,6 +71,9 @@ Bugs - CODE128: fix extended char latching when exactly 3 extended chars at end - library: need to check for valid UTF-8 after de-escaping - MAXICODE: maintain current set between segments +- MSYS2: fix stdout output on Windows under MSYS2 (mailing list, props Frank) +- DATAMATRIX: fix mis-encodation by only doing special end-of-data processing + on last segment Version 2.13.0 (2023-12-18) diff --git a/README b/README index f5e30e7c..033782e1 100644 --- a/README +++ b/README @@ -38,12 +38,13 @@ Deutsche Post Leitcode Telepen DotCode Telepen Numeric DPD Code UK Plessey Dutch Post KIX Ultracode -EAN (EAN-2, EAN-5, EAN-8 and EAN-13) UPC-A -EAN-14 UPC-E -FIM (Facing Identification Mark) UPNQR -Flattermarken UPU S10 -Grid Matrix USPS Intelligent Mail (OneCode) -GS1 Composite (EAN/UPC/DataBar/GS-128) VIN (Vehicle Identification Number) +DX Film Edge Barcode UPC-A +EAN (EAN-2, EAN-5, EAN-8 and EAN-13) UPC-E +EAN-14 UPNQR +FIM (Facing Identification Mark) UPU S10 +Flattermarken USPS Intelligent Mail (OneCode) +Grid Matrix VIN (Vehicle Identification Number) +GS1 Composite (EAN/UPC/DataBar/GS-128) Output can be saved as BMP, EMF, EPS, GIF, PCX, PNG, SVG or TIF. diff --git a/README.bsd b/README.bsd index b0465948..48cb6ea8 100644 --- a/README.bsd +++ b/README.bsd @@ -1,5 +1,5 @@ -% README.bsd 2024-01-17 -% Tested on FreeBSD 14.0-RELEASE (with X11 + GNOME installed), OpenBSD 7.4 (with X11) and NetBSD 9.3 (with X11) +% README.bsd 2025-01-18 +% Tested on FreeBSD 14.2-RELEASE (with X11 + GNOME installed), OpenBSD 7.6 (with X11) and NetBSD 10.0 (with X11) 1. Prerequisites for building zint ================================== @@ -74,7 +74,20 @@ and on NetBSD instead. -3. CMake options +4. Run +====== + +On FreeBSD and OpenBSD, the CLI zint and GUI zint-qt should run without issue from the command line. + +On NetBSD you may have to set LD_LIBRARY_PATH if using the default ksh. For zint ("libzint.so" and "libpng16.so") and +zint-qt (Qt5 libraries and "libGL.so"): + + setenv LD_LIBRARY_PATH /usr/local/lib:/usr/pkg/lib:/usr/pkg/qt5/lib:/usr/X11R7/lib + +Place in "~/.cshrc" to make permanent. + + +5. CMake options ================ See "README.linux". Note for running the test suite on FreeBSD, if using the default csh, to set LD_LIBRARY_PATH use: diff --git a/backend/2of5.c b/backend/2of5.c index 2f062559..8706eb0d 100644 --- a/backend/2of5.c +++ b/backend/2of5.c @@ -1,7 +1,7 @@ -/* 2of5.c - Handles Code 2 of 5 barcodes */ +/* 2of5.c - Handles non-interleaved Code 2 of 5 barcodes */ /* libzint - the open source barcode library - Copyright (C) 2008-2024 Robin Stuart + Copyright (C) 2008-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -34,7 +34,6 @@ #include "common.h" #include "gs1.h" -/* First 5 of each entry Interleaved also */ static const char C25MatrixTable[10][6] = { {'1','1','3','3','1','1'}, {'3','1','1','1','3','1'}, {'1','3','1','1','3','1'}, {'3','3','1','1','1','1'}, {'1','1','3','1','3','1'}, {'3','1','3','1','1','1'}, {'1','3','3','1','1','1'}, {'1','1','1','3','3','1'}, @@ -138,248 +137,4 @@ INTERNAL int c25logic(struct zint_symbol *symbol, unsigned char source[], int le return c25_common(symbol, source, length, 113, 1 /*is_matrix*/, C25IataLogicStartStop, 4, 307); } -/* Common to Interleaved, ITF-14, DP Leitcode, DP Identcode */ -static int c25_inter_common(struct zint_symbol *symbol, unsigned char source[], int length, - const int checkdigit_option, const int dont_set_height) { - int i, j, error_number = 0; - char dest[638]; /* 4 + (125 + 1) * 5 + 3 + 1 = 638 */ - char *d = dest; - unsigned char temp[125 + 1 + 1]; - const int have_checkdigit = checkdigit_option == 1 || checkdigit_option == 2; - - if (length > 125) { /* 4 + (125 + 1) * 9 + 5 = 1143 */ - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 309, "Input length %d too long (maximum 125)", length); - } - if ((i = not_sane(NEON_F, source, length))) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 310, - "Invalid character at position %d in input (digits only)", i); - } - - /* Input must be an even number of characters for Interlaced 2 of 5 to work: - if an odd number of characters has been entered and no check digit or an even number and have check digit - then add a leading zero */ - if (have_checkdigit == !(length & 1)) { - temp[0] = '0'; - memcpy(temp + 1, source, length++); - } else { - memcpy(temp, source, length); - } - temp[length] = '\0'; - - if (have_checkdigit) { - /* Add standard GS1 check digit */ - temp[length] = gs1_check_digit(temp, length); - temp[++length] = '\0'; - } - - /* Start character */ - memcpy(d, "1111", 4); - d += 4; - - for (i = 0; i < length; i += 2) { - /* Look up the bars and the spaces */ - const char *const bars = C25MatrixTable[temp[i] - '0']; - const char *const spaces = C25MatrixTable[temp[i + 1] - '0']; - - /* Then merge (interlace) the strings together */ - for (j = 0; j < 5; j++) { - *d++ = bars[j]; - *d++ = spaces[j]; - } - } - - /* Stop character */ - memcpy(d, "311", 3); - d += 3; - - expand(symbol, dest, d - dest); - - ustrcpy(symbol->text, temp); - if (checkdigit_option == 2) { - /* Remove check digit from HRT */ - symbol->text[length - 1] = '\0'; - } - - if (!dont_set_height) { - if (symbol->output_options & COMPLIANT_HEIGHT) { - /* ISO/IEC 16390:2007 Section 4.4 min height 5mm or 15% of symbol width whichever greater where - (P = character pairs, N = wide/narrow ratio = 3) - width = (P(4N + 6) + N + 6)X = (length / 2) * 18 + 9 */ - /* Taking min X = 0.330mm from Annex D.3.1 (application specification) */ - const float min_height_min = 15.151515f; /* 5.0 / 0.33 */ - float min_height = stripf((18.0f * (length / 2) + 9.0f) * 0.15f); - if (min_height < min_height_min) { - min_height = min_height_min; - } - /* Using 50 as default as none recommended */ - error_number = set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, - 0 /*no_errtxt*/); - } else { - (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); - } - } - - return error_number; -} - -/* Code 2 of 5 Interleaved ISO/IEC 16390:2007 */ -INTERNAL int c25inter(struct zint_symbol *symbol, unsigned char source[], int length) { - return c25_inter_common(symbol, source, length, symbol->option_2 /*checkdigit_option*/, 0 /*dont_set_height*/); -} - -/* Interleaved 2-of-5 (ITF-14) */ -INTERNAL int itf14(struct zint_symbol *symbol, unsigned char source[], int length) { - int i, error_number, zeroes; - unsigned char localstr[16] = {0}; - - if (length > 13) { - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 311, "Input length %d too long (maximum 13)", length); - } - - if ((i = not_sane(NEON_F, source, length))) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 312, - "Invalid character at position %d in input (digits only)", i); - } - - /* 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 */ - localstr[13] = gs1_check_digit(localstr, 13); - localstr[14] = '\0'; - error_number = c25_inter_common(symbol, localstr, 14, 0 /*checkdigit_option*/, 1 /*dont_set_height*/); - ustrcpy(symbol->text, localstr); - - if (error_number < ZINT_ERROR) { - if (!(symbol->output_options & (BARCODE_BOX | BARCODE_BIND | BARCODE_BIND_TOP))) { - /* If no option has been selected then uses default box option */ - symbol->output_options |= BARCODE_BOX; - if (symbol->border_width == 0) { /* Allow override if non-zero */ - /* GS1 General Specifications 21.0.1 Sections 5.3.2.4 & 5.3.6 (4.83 / 1.016 ~ 4.75) */ - symbol->border_width = 5; /* Note change from previous value 8 */ - } - } - - if (symbol->output_options & COMPLIANT_HEIGHT) { - /* GS1 General Specifications 21.0.1 5.12.3.2 table 2, including footnote (**): (note bind/box additional - to symbol->height), same as GS1-128: "in case of further space constraints" - height 5.8mm / 1.016mm (X max) ~ 5.7; default 31.75mm / 0.495mm ~ 64.14 */ - const float min_height = 5.70866156f; /* 5.8 / 1.016 */ - const float default_height = 64.1414108f; /* 31.75 / 0.495 */ - error_number = set_height(symbol, min_height, default_height, 0.0f, 0 /*no_errtxt*/); - } else { - (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); - } - } - - return error_number; -} - -/* Deutsche Post check digit */ -static char c25_dp_check_digit(const unsigned int count) { - return itoc((10 - (count % 10)) % 10); -} - -/* Deutsche Post Leitcode */ -/* Documentation (of a very incomplete and non-technical type): -https://www.deutschepost.de/content/dam/dpag/images/D_d/dialogpost-schwer/dp-dialogpost-schwer-broschuere-072021.pdf -*/ -INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int length) { - int i, j, error_number; - unsigned int count; - int factor; - unsigned char localstr[16] = {0}; - int zeroes; - - count = 0; - if (length > 13) { - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 313, "Input length %d too long (maximum 13)", length); - } - if ((i = not_sane(NEON_F, source, length))) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 314, - "Invalid character at position %d in input (digits only)", i); - } - - zeroes = 13 - length; - for (i = 0; i < zeroes; i++) - localstr[i] = '0'; - ustrcpy(localstr + zeroes, source); - - factor = 4; - for (i = 12; i >= 0; i--) { - count += factor * ctoi(localstr[i]); - factor ^= 0x0D; /* Toggles 4 and 9 */ - } - localstr[13] = c25_dp_check_digit(count); - localstr[14] = '\0'; - error_number = c25_inter_common(symbol, localstr, 14, 0 /*checkdigit_option*/, 1 /*dont_set_height*/); - - /* HRT formatting as per DIALOGPOST SCHWER brochure but TEC-IT differs as do examples at - https://www.philaseiten.de/cgi-bin/index.pl?ST=8615&CP=0&F=1#M147 */ - for (i = 0, j = 0; i <= 14; i++) { - symbol->text[j++] = localstr[i]; - if (i == 4 || i == 7 || i == 10) { - symbol->text[j++] = '.'; - } - } - - /* TODO: Find documentation on BARCODE_DPLEIT dimensions/height */ - /* Based on eyeballing DIALOGPOST SCHWER, using 72X as default */ - (void) set_height(symbol, 0.0f, 72.0f, 0.0f, 1 /*no_errtxt*/); - - return error_number; -} - -/* Deutsche Post Identcode */ -/* See dpleit() for (sort of) documentation reference */ -INTERNAL int dpident(struct zint_symbol *symbol, unsigned char source[], int length) { - int i, j, error_number, zeroes; - unsigned int count; - int factor; - unsigned char localstr[16] = {0}; - - count = 0; - if (length > 11) { - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 315, "Input length %d too long (maximum 11)", length); - } - if ((i = not_sane(NEON_F, source, length))) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 316, - "Invalid character at position %d in input (digits only)", i); - } - - zeroes = 11 - length; - for (i = 0; i < zeroes; i++) - localstr[i] = '0'; - ustrcpy(localstr + zeroes, source); - - factor = 4; - for (i = 10; i >= 0; i--) { - count += factor * ctoi(localstr[i]); - factor ^= 0x0D; /* Toggles 4 and 9 */ - } - localstr[11] = c25_dp_check_digit(count); - localstr[12] = '\0'; - error_number = c25_inter_common(symbol, localstr, 12, 0 /*checkdigit_option*/, 1 /*dont_set_height*/); - - /* HRT formatting as per DIALOGPOST SCHWER brochure but TEC-IT differs as do other examples (see above) */ - for (i = 0, j = 0; i <= 12; i++) { - symbol->text[j++] = localstr[i]; - if (i == 1 || i == 4 || i == 7) { - symbol->text[j++] = '.'; - } else if (i == 3 || i == 10) { - symbol->text[j++] = ' '; - } - } - - /* TODO: Find documentation on BARCODE_DPIDENT dimensions/height */ - /* Based on eyeballing DIALOGPOST SCHWER, using 72X as default */ - (void) set_height(symbol, 0.0f, 72.0f, 0.0f, 1 /*no_errtxt*/); - - return error_number; -} - /* vim: set ts=4 sw=4 et : */ diff --git a/backend/2of5inter.c b/backend/2of5inter.c new file mode 100644 index 00000000..94cf7a19 --- /dev/null +++ b/backend/2of5inter.c @@ -0,0 +1,134 @@ +/* 2of5inter.c - Handles Code 2 of 5 Interleaved */ +/* + libzint - the open source barcode library + Copyright (C) 2008-2025 Robin 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* Was in "2of5.c" */ + +#include +#include "common.h" +#include "gs1.h" + +static const char C25InterTable[10][5] = { + {'1','1','3','3','1'}, {'3','1','1','1','3'}, {'1','3','1','1','3'}, {'3','3','1','1','1'}, + {'1','1','3','1','3'}, {'3','1','3','1','1'}, {'1','3','3','1','1'}, {'1','1','1','3','3'}, + {'3','1','1','3','1'}, {'1','3','1','3','1'} +}; + +/* Common to Interleaved, and to ITF-14, DP Leitcode, DP Identcode */ +INTERNAL int c25_inter_common(struct zint_symbol *symbol, unsigned char source[], int length, + const int checkdigit_option, const int dont_set_height) { + int i, j, error_number = 0; + char dest[638]; /* 4 + (125 + 1) * 5 + 3 + 1 = 638 */ + char *d = dest; + unsigned char temp[125 + 1 + 1]; + const int have_checkdigit = checkdigit_option == 1 || checkdigit_option == 2; + + if (length > 125) { /* 4 + (125 + 1) * 9 + 5 = 1143 */ + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 309, "Input length %d too long (maximum 125)", length); + } + if ((i = not_sane(NEON_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 310, + "Invalid character at position %d in input (digits only)", i); + } + + /* Input must be an even number of characters for Interlaced 2 of 5 to work: + if an odd number of characters has been entered and no check digit or an even number and have check digit + then add a leading zero */ + if (have_checkdigit == !(length & 1)) { + temp[0] = '0'; + memcpy(temp + 1, source, length++); + } else { + memcpy(temp, source, length); + } + temp[length] = '\0'; + + if (have_checkdigit) { + /* Add standard GS1 check digit */ + temp[length] = gs1_check_digit(temp, length); + temp[++length] = '\0'; + } + + /* Start character */ + memcpy(d, "1111", 4); + d += 4; + + for (i = 0; i < length; i += 2) { + /* Look up the bars and the spaces */ + const char *const bars = C25InterTable[temp[i] - '0']; + const char *const spaces = C25InterTable[temp[i + 1] - '0']; + + /* Then merge (interlace) the strings together */ + for (j = 0; j < 5; j++) { + *d++ = bars[j]; + *d++ = spaces[j]; + } + } + + /* Stop character */ + memcpy(d, "311", 3); + d += 3; + + expand(symbol, dest, d - dest); + + ustrcpy(symbol->text, temp); + if (checkdigit_option == 2) { + /* Remove check digit from HRT */ + symbol->text[length - 1] = '\0'; + } + + if (!dont_set_height) { + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* ISO/IEC 16390:2007 Section 4.4 min height 5mm or 15% of symbol width whichever greater where + (P = character pairs, N = wide/narrow ratio = 3) + width = (P(4N + 6) + N + 6)X = (length / 2) * 18 + 9 */ + /* Taking min X = 0.330mm from Annex D.3.1 (application specification) */ + const float min_height_min = 15.151515f; /* 5.0 / 0.33 */ + float min_height = stripf((18.0f * (length / 2) + 9.0f) * 0.15f); + if (min_height < min_height_min) { + min_height = min_height_min; + } + /* Using 50 as default as none recommended */ + error_number = set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, + 0 /*no_errtxt*/); + } else { + (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); + } + } + + return error_number; +} + +/* Code 2 of 5 Interleaved ISO/IEC 16390:2007 */ +INTERNAL int c25inter(struct zint_symbol *symbol, unsigned char source[], int length) { + return c25_inter_common(symbol, source, length, symbol->option_2 /*checkdigit_option*/, 0 /*dont_set_height*/); +} + +/* vim: set ts=4 sw=4 et : */ diff --git a/backend/2of5inter_based.c b/backend/2of5inter_based.c new file mode 100644 index 00000000..18b0e767 --- /dev/null +++ b/backend/2of5inter_based.c @@ -0,0 +1,197 @@ +/* 2of5_based.c - Handles Code 2 of 5 Interleaved derivatives ITF-14, DP Leitcode and DP Identcode */ +/* + libzint - the open source barcode library + Copyright (C) 2008-2025 Robin 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* Was in "2of5.c" */ + +#include +#include "common.h" +#include "gs1.h" + +INTERNAL int c25_inter_common(struct zint_symbol *symbol, unsigned char source[], int length, + const int checkdigit_option, const int dont_set_height); + +/* Interleaved 2-of-5 (ITF-14) */ +INTERNAL int itf14(struct zint_symbol *symbol, unsigned char source[], int length) { + int i, error_number, zeroes; + unsigned char localstr[16] = {0}; + + if (length > 13) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 311, "Input length %d too long (maximum 13)", length); + } + + if ((i = not_sane(NEON_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 312, + "Invalid character at position %d in input (digits only)", i); + } + + /* 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 */ + localstr[13] = gs1_check_digit(localstr, 13); + localstr[14] = '\0'; + error_number = c25_inter_common(symbol, localstr, 14, 0 /*checkdigit_option*/, 1 /*dont_set_height*/); + ustrcpy(symbol->text, localstr); + + if (error_number < ZINT_ERROR) { + if (!(symbol->output_options & (BARCODE_BOX | BARCODE_BIND | BARCODE_BIND_TOP))) { + /* If no option has been selected then uses default box option */ + symbol->output_options |= BARCODE_BOX; + if (symbol->border_width == 0) { /* Allow override if non-zero */ + /* GS1 General Specifications 21.0.1 Sections 5.3.2.4 & 5.3.6 (4.83 / 1.016 ~ 4.75) */ + symbol->border_width = 5; /* Note change from previous value 8 */ + } + } + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* GS1 General Specifications 21.0.1 5.12.3.2 table 2, including footnote (**): (note bind/box additional + to symbol->height), same as GS1-128: "in case of further space constraints" + height 5.8mm / 1.016mm (X max) ~ 5.7; default 31.75mm / 0.495mm ~ 64.14 */ + const float min_height = 5.70866156f; /* 5.8 / 1.016 */ + const float default_height = 64.1414108f; /* 31.75 / 0.495 */ + error_number = set_height(symbol, min_height, default_height, 0.0f, 0 /*no_errtxt*/); + } else { + (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); + } + } + + return error_number; +} + +/* Deutsche Post check digit */ +static char c25_dp_check_digit(const unsigned int count) { + return itoc((10 - (count % 10)) % 10); +} + +/* Deutsche Post Leitcode */ +/* Documentation (of a very incomplete and non-technical type): +https://www.deutschepost.de/content/dam/dpag/images/D_d/dialogpost-schwer/dp-dialogpost-schwer-broschuere-072021.pdf +*/ +INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int length) { + int i, j, error_number; + unsigned int count; + int factor; + unsigned char localstr[16] = {0}; + int zeroes; + + count = 0; + if (length > 13) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 313, "Input length %d too long (maximum 13)", length); + } + if ((i = not_sane(NEON_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 314, + "Invalid character at position %d in input (digits only)", i); + } + + zeroes = 13 - length; + for (i = 0; i < zeroes; i++) + localstr[i] = '0'; + ustrcpy(localstr + zeroes, source); + + factor = 4; + for (i = 12; i >= 0; i--) { + count += factor * ctoi(localstr[i]); + factor ^= 0x0D; /* Toggles 4 and 9 */ + } + localstr[13] = c25_dp_check_digit(count); + localstr[14] = '\0'; + error_number = c25_inter_common(symbol, localstr, 14, 0 /*checkdigit_option*/, 1 /*dont_set_height*/); + + /* HRT formatting as per DIALOGPOST SCHWER brochure but TEC-IT differs as do examples at + https://www.philaseiten.de/cgi-bin/index.pl?ST=8615&CP=0&F=1#M147 */ + for (i = 0, j = 0; i <= 14; i++) { + symbol->text[j++] = localstr[i]; + if (i == 4 || i == 7 || i == 10) { + symbol->text[j++] = '.'; + } + } + + /* TODO: Find documentation on BARCODE_DPLEIT dimensions/height */ + /* Based on eyeballing DIALOGPOST SCHWER, using 72X as default */ + (void) set_height(symbol, 0.0f, 72.0f, 0.0f, 1 /*no_errtxt*/); + + return error_number; +} + +/* Deutsche Post Identcode */ +/* See dpleit() for (sort of) documentation reference */ +INTERNAL int dpident(struct zint_symbol *symbol, unsigned char source[], int length) { + int i, j, error_number, zeroes; + unsigned int count; + int factor; + unsigned char localstr[16] = {0}; + + count = 0; + if (length > 11) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 315, "Input length %d too long (maximum 11)", length); + } + if ((i = not_sane(NEON_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 316, + "Invalid character at position %d in input (digits only)", i); + } + + zeroes = 11 - length; + for (i = 0; i < zeroes; i++) + localstr[i] = '0'; + ustrcpy(localstr + zeroes, source); + + factor = 4; + for (i = 10; i >= 0; i--) { + count += factor * ctoi(localstr[i]); + factor ^= 0x0D; /* Toggles 4 and 9 */ + } + localstr[11] = c25_dp_check_digit(count); + localstr[12] = '\0'; + error_number = c25_inter_common(symbol, localstr, 12, 0 /*checkdigit_option*/, 1 /*dont_set_height*/); + + /* HRT formatting as per DIALOGPOST SCHWER brochure but TEC-IT differs as do other examples (see above) */ + for (i = 0, j = 0; i <= 12; i++) { + symbol->text[j++] = localstr[i]; + if (i == 1 || i == 4 || i == 7) { + symbol->text[j++] = '.'; + } else if (i == 3 || i == 10) { + symbol->text[j++] = ' '; + } + } + + /* TODO: Find documentation on BARCODE_DPIDENT dimensions/height */ + /* Based on eyeballing DIALOGPOST SCHWER, using 72X as default */ + (void) set_height(symbol, 0.0f, 72.0f, 0.0f, 1 /*no_errtxt*/); + + return error_number; +} + +/* vim: set ts=4 sw=4 et : */ diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index d1cf5f68..eb75db18 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -1,5 +1,5 @@ # Copyright (C) 2008 by BogDan Vatra < bogdan@licentia.eu > -# Copyright (C) 2009-2024 Robin Stuart +# Copyright (C) 2009-2025 Robin Stuart # vim: set ts=4 sw=4 et : cmake_minimum_required(VERSION 3.10) @@ -9,14 +9,16 @@ if(ZINT_USE_PNG) find_package(PNG) endif() -set(zint_COMMON_SRCS common.c library.c large.c reedsol.c gs1.c eci.c filemem.c general_field.c) -set(zint_ONEDIM_SRCS bc412.c 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_COMMON_SRCS common.c eci.c filemem.c general_field.c gs1.c large.c library.c reedsol.c) +set(zint_ONEDIM_SRCS 2of5.c 2of5inter.c 2of5inter_based.c bc412.c channel.c codabar.c code.c code11.c code128.c + code128_based.c dxfilmedge.c medical.c plessey.c rss.c telepen.c upcean.c) +set(zint_POSTAL_SRCS auspost.c imail.c mailmark.c postal.c) +set(zint_TWODIM_SRCS aztec.c codablock.c code1.c code16k.c code49.c composite.c dmatrix.c dotcode.c gridmtx.c + hanxin.c maxicode.c pdf417.c qr.c ultra.c) if(ZINT_USE_PNG AND PNG_FOUND) - 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_OUTPUT_SRCS bmp.c emf.c gif.c output.c pcx.c png.c ps.c raster.c svg.c tif.c vector.c) else() - set(zint_OUTPUT_SRCS vector.c ps.c svg.c emf.c bmp.c pcx.c gif.c tif.c raster.c output.c) + set(zint_OUTPUT_SRCS bmp.c emf.c gif.c output.c pcx.c ps.c raster.c svg.c tif.c vector.c) endif() set(zint_SRCS ${zint_OUTPUT_SRCS} ${zint_COMMON_SRCS} ${zint_ONEDIM_SRCS} ${zint_POSTAL_SRCS} ${zint_TWODIM_SRCS}) diff --git a/backend/channel.c b/backend/channel.c new file mode 100644 index 00000000..d3e8e382 --- /dev/null +++ b/backend/channel.c @@ -0,0 +1,259 @@ +/* channel.c - Handles Channel */ +/* + libzint - the open source barcode library + Copyright (C) 2008-2025 Robin 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* Was in "code.c" */ + +#include +#include "common.h" + +typedef const struct s_channel_precalc { + int value; unsigned char B[8]; unsigned char S[8]; unsigned char bmax[7]; unsigned char smax[7]; +} channel_precalc; + +#if 0 +#define CHANNEL_GENERATE_PRECALCS +#endif + +#ifdef CHANNEL_GENERATE_PRECALCS +/* To generate precalc tables uncomment CHANNEL_GENERATE_PRECALCS define and run + "backend/tests/test_channel -f generate -g" and place result in "channel_precalcs.h" */ +static void channel_generate_precalc(int channels, int 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]); fputs(" },", stdout); + fputs(" {", stdout); for (i = 0; i < 8; i++) printf(" %d,", S[i]); fputs(" },", stdout); + fputs(" {", stdout); for (i = 0; i < 7; i++) printf(" %d,", bmax[i]); fputs(" },", stdout); + fputs(" {", stdout); for (i = 0; i < 7; i++) printf(" %d,", smax[i]); fputs(" }, },\n", stdout); + if (value == last) fputs("};\n", stdout); +} +#else +#include "channel_precalcs.h" +#endif + +static int channel_copy_precalc(channel_precalc *const 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, int 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]; + int 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 + /* 115338 == (576688 + 2) / 5 */ + if (channels == 7 && value && value % 115338 == 0) { + channel_generate_precalc(channels, value, 115338, + 115338 * (5 - 1), B, S, bmax, smax); + /* 119121 == (7742862 + 3) / 65 */ + } else if (channels == 8 && value && value % 119121 == 0) { + 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(struct zint_symbol *symbol, unsigned char source[], int length) { + static const int max_ranges[] = { -1, -1, -1, 26, 292, 3493, 44072, 576688, 7742862 }; + int S[8] = {0}, B[8] = {0}; + int target_value; + char dest[30]; + char *d = dest; + int channels, i; + int error_number = 0, zeroes; + + if (length > 7) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 333, "Input length %d too long (maximum 7)", length); + } + if ((i = not_sane(NEON_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 334, + "Invalid character at position %d in input (digits only)", i); + } + target_value = to_int(source, length); + + if ((symbol->option_2 < 3) || (symbol->option_2 > 8)) { + channels = 0; + } else { + channels = symbol->option_2; + } + + 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; + } + + if (target_value > max_ranges[channels]) { + if (channels == 8) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 318, "Input value \"%1$d\" out of range (0 to %2$d)", + target_value, max_ranges[channels]); + } + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 335, + "Input value \"%1$d\" out of range (0 to %2$d for %3$d channels)", + target_value, max_ranges[channels], channels); + } + + CHNCHR(channels, target_value, B, S); + + memcpy(d, "111111111", 9); /* Finder pattern */ + d += 9; + for (i = 8 - channels; i < 8; i++) { + *d++ = itoc(S[i]); + *d++ = itoc(B[i]); + } + + zeroes = channels - 1 - length; + if (zeroes < 0) { + zeroes = 0; + } else if (zeroes) { + memset(symbol->text, '0', zeroes); + } + ustrcpy(symbol->text + zeroes, source); + + expand(symbol, dest, d - dest); + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* ANSI/AIM BC12-1998 gives min height as 5mm or 15% of length; X left as application specification so use + length = 1X (left qz) + (9 (finder) + 4 * 8 - 2) * X + 2X (right qz); + use 20 as default based on figures in spec */ + const float min_height = stripf((1 + 9 + 4 * channels - 2 + 2) * 0.15f); + error_number = set_height(symbol, min_height, 20.0f, 0.0f, 0 /*no_errtxt*/); + } else { + (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); + } + + return error_number; +} + +/* vim: set ts=4 sw=4 et : */ diff --git a/backend/codabar.c b/backend/codabar.c new file mode 100644 index 00000000..be9cfc91 --- /dev/null +++ b/backend/codabar.c @@ -0,0 +1,146 @@ +/* codabar.c - Handles Codabar */ +/* + libzint - the open source barcode library + Copyright (C) 2008-2025 Robin 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* Was in "medical.c" */ + +#include +#include "common.h" + +static const char CALCIUM[] = "0123456789-$:/.+ABCD"; +#define CALCIUM_INNER_F (IS_NUM_F | IS_MNS_F | IS_CLI_F | IS_PLS_F) /* CALCIUM_INNER "0123456789-$:/.+" */ + +/* Codabar table checked against EN 798:1995 */ +static const char CodaTable[20][8] = { + {'1','1','1','1','1','2','2','1'}, {'1','1','1','1','2','2','1','1'}, {'1','1','1','2','1','1','2','1'}, + {'2','2','1','1','1','1','1','1'}, {'1','1','2','1','1','2','1','1'}, {'2','1','1','1','1','2','1','1'}, + {'1','2','1','1','1','1','2','1'}, {'1','2','1','1','2','1','1','1'}, {'1','2','2','1','1','1','1','1'}, + {'2','1','1','2','1','1','1','1'}, {'1','1','1','2','2','1','1','1'}, {'1','1','2','2','1','1','1','1'}, + {'2','1','1','1','2','1','2','1'}, {'2','1','2','1','1','1','2','1'}, {'2','1','2','1','2','1','1','1'}, + {'1','1','2','1','2','1','2','1'}, {'1','1','2','2','1','2','1','1'}, {'1','2','1','2','1','1','2','1'}, + {'1','1','1','2','1','2','2','1'}, {'1','1','1','2','2','2','1','1'} +}; + +/* The Codabar system consisting of simple substitution */ +INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int length) { + + int i, error_number = 0; + int posns[103]; + char dest[833]; /* (103 + 1) * 8 + 1 == 833 */ + char *d = dest; + int add_checksum, count = 0, checksum = 0; + int d_chars = 0; + + if (length > 103) { /* No stack smashing please (103 + 1) * 11 = 1144 */ + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 356, "Input length %d too long (maximum 103)", length); + } + /* 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) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 362, "Input length %d too short (minimum 3)", length); + } + to_upper(source, length); + + /* 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')) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 358, "Does not begin with \"A\", \"B\", \"C\" or \"D\""); + } + if ((source[length - 1] != 'A') && (source[length - 1] != 'B') && + (source[length - 1] != 'C') && (source[length - 1] != 'D')) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 359, "Does not end with \"A\", \"B\", \"C\" or \"D\""); + } + if ((i = not_sane_lookup(CALCIUM, sizeof(CALCIUM) - 1, source, length, posns))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 357, + "Invalid character at position %1$d in input (\"%2$s\" only)", i, CALCIUM); + } + /* And must not use A, B, C or D otherwise (BS EN 798:1995 4.3.2) */ + if ((i = not_sane(CALCIUM_INNER_F, source + 1, length - 2))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 363, + "Invalid character at position %d in input (cannot contain \"A\", \"B\", \"C\" or \"D\")", i); + } + + /* Add check character: 1 don't show to HRT, 2 do show to HRT + (unfortunately to maintain back-compatibility, this is reverse of C25) */ + add_checksum = symbol->option_2 == 1 || symbol->option_2 == 2; + + for (i = 0; i < length; i++, d += 8) { + if (add_checksum) { + /* BS EN 798:1995 A.3 suggests using ISO 7064 algorithm but leaves it application defined. + Following BWIPP and TEC-IT, use this simple mod-16 algorithm (not in ISO 7064) */ + count += posns[i]; + 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 (%c)\n", source, count, checksum, CALCIUM[checksum]); + } + memcpy(d, CodaTable[checksum], 8); + d += 8; + } + } + memcpy(d, CodaTable[posns[i]], 8); + if (source[i] == '/' || source[i] == ':' || source[i] == '.' || source[i] == '+') { /* Wide data characters */ + d_chars++; + } + } + + expand(symbol, dest, d - dest); + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* BS EN 798:1995 4.4.1 (d) max of 5mm / 0.43mm (X max) ~ 11.628 or 15% of width where (taking N = + narrow/wide ratio as 2 and I = X) width = ((2 * N + 5) * C + (N – 1) * (D + 2)) * X + I * (C – 1) + 2Q + = ((4 + 5) * C + (D + 2) + C - 1 + 2 * 10) * X = (10 * C + D + 21) * X + Length (C) includes start/stop chars */ + const float min_height_min = 11.6279068f; /* 5.0 / 0.43 */ + float min_height = stripf((10.0f * ((add_checksum ? length + 1 : length) + 2.0f) + d_chars + 21.0f) * 0.15f); + if (min_height < min_height_min) { + min_height = min_height_min; + } + /* Using 50 as default as none recommended */ + error_number = set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, 0 /*no_errtxt*/); + } else { + (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); + } + + ustrcpy(symbol->text, source); + if (symbol->option_2 == 2) { + symbol->text[length - 1] = CALCIUM[checksum]; /* Place before final A/B/C/D character (BS EN 798:1995 A.3) */ + symbol->text[length] = source[length - 1]; + symbol->text[length + 1] = '\0'; + } + + return error_number; +} + +/* vim: set ts=4 sw=4 et : */ diff --git a/backend/code.c b/backend/code.c index 8b999890..a029d37e 100644 --- a/backend/code.c +++ b/backend/code.c @@ -1,7 +1,7 @@ -/* code.c - Handles Code 11, 39, 39+, 93, PZN, Channel and VIN */ +/* code.c - Handles Code 39, 39+, 93 and VIN */ /* libzint - the open source barcode library - Copyright (C) 2008-2024 Robin Stuart + Copyright (C) 2008-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -36,20 +36,11 @@ #include #include "common.h" -#define SODIUM_MNS_F (IS_NUM_F | IS_MNS_F) /* SODIUM "0123456789-" */ - /* Same as TECHNETIUM (HIBC) with "abcd" added for CODE93 */ static const char SILVER[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd"; #define ARSENIC_F (IS_NUM_F | IS_ARS_F) /* ARSENIC "0123456789ABCDEFGHJKLMNPRSTUVWXYZ" */ -static const char C11Table[11 + 1][6] = { - {'1','1','1','1','2','1'}, {'2','1','1','1','2','1'}, {'1','2','1','1','2','1'}, {'2','2','1','1','1','1'}, - {'1','1','2','1','2','1'}, {'2','1','2','1','1','1'}, {'1','2','2','1','1','1'}, {'1','1','1','2','2','1'}, - {'2','1','1','2','1','1'}, {'2','1','1','1','1','1'}, {'1','1','2','1','1','1'}, - {'1','1','2','2','1','1'} /* Start character (full 6), Stop character (first 5) */ -}; - /* Code 39 character assignments (ISO/IEC 16388:2007 Table 1 and Table A.1) */ static const char C39Table[43 + 1][10] = { {'1','1','1','2','2','1','2','1','1','1'}, {'2','1','1','2','1','1','1','1','2','1'}, @@ -127,115 +118,6 @@ static const char C93Table[47][6] = { {'3','1','2','1','1','1'}, {'3','1','1','1','2','1'}, {'1','2','2','2','1','1'} }; -/* Code 11 */ -INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int length) { - - int i; - int h, c_digit, c_weight, c_count, k_digit, k_weight, k_count; - int weight[141]; /* 140 + 1 extra for 1st check */ - char dest[864]; /* 6 + 140 * 6 + 2 * 6 + 5 + 1 = 864 */ - int error_number = 0; - char *d = dest; - int num_check_digits; - char checkstr[3] = {0}; - static const char checkchrs[11] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-' }; - - /* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warning */ - assert(length > 0); - - if (length > 140) { /* 8 (Start) + 140 * 8 + 2 * 8 (Check) + 7 (Stop) = 1151 */ - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 320, "Input length %d too long (maximum 140)", length); - } - if ((i = not_sane(SODIUM_MNS_F, source, length))) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 321, - "Invalid character at position %d in input (digits and \"-\" only)", i); - } - - if (symbol->option_2 < 0 || symbol->option_2 > 2) { - return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 339, "Invalid check digit version '%d' (1 or 2 only)", - symbol->option_2); - } - 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 */ - memcpy(d, C11Table[11], 6); - d += 6; - - /* Draw main body of barcode */ - for (i = 0; i < length; i++, d += 6) { - if (source[i] == '-') - weight[i] = 10; - else - weight[i] = ctoi(source[i]); - memcpy(d, C11Table[weight[i]], 6); - } - - 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; - - checkstr[0] = checkchrs[c_digit]; - memcpy(d, C11Table[c_digit], 6); - d += 6; - - if (num_check_digits == 2) { - 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[1] = checkchrs[k_digit]; - memcpy(d, C11Table[k_digit], 6); - d += 6; - } - } - - if (symbol->debug & ZINT_DEBUG_PRINT) { - printf("Check digit (%d): %s\n", num_check_digits, num_check_digits ? checkstr : ""); - } - - /* Stop character */ - memcpy(d, C11Table[11], 5); - d += 5; - - expand(symbol, dest, d - dest); - - /* TODO: Find documentation on BARCODE_CODE11 dimensions/height */ - - ustrcpy(symbol->text, source); - if (num_check_digits) { - ustrcat(symbol->text, checkstr); - } - return error_number; -} - /* Code 39 */ INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int length) { int i; @@ -353,91 +235,6 @@ INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int leng return error_number; } -/* Pharmazentralnummer (PZN) */ -/* 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 */ -INTERNAL int pzn(struct zint_symbol *symbol, unsigned char source[], int length) { - - int i, error_number, zeroes; - int count, check_digit; - unsigned char have_check_digit = '\0'; - char localstr[1 + 8 + 1]; /* '-' prefix + 8 digits + NUL */ - const int pzn7 = symbol->option_2 == 1; - - if (length > 8 - pzn7) { - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 325, "Input length %1$d too long (maximum %2$d)", length, - 8 - pzn7); - } - if (length == 8 - pzn7) { - have_check_digit = source[7 - pzn7]; - length--; - } - if ((i = not_sane(NEON_F, source, length))) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 326, - "Invalid character at position %d in input (digits only)", i); - } - - localstr[0] = '-'; - zeroes = 7 - pzn7 - length + 1; - for (i = 1; i < zeroes; i++) - localstr[i] = '0'; - ustrcpy(localstr + zeroes, source); - - count = 0; - for (i = 1; i < 8 - pzn7; i++) { - count += (i + pzn7) * ctoi(localstr[i]); - } - - check_digit = count % 11; - - if (symbol->debug & ZINT_DEBUG_PRINT) { - printf("PZN: %s, check digit %d\n", localstr, (int) check_digit); - } - - if (check_digit == 10) { - return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 327, "Invalid PZN, check digit is '10'"); - } - if (have_check_digit && ctoi(have_check_digit) != check_digit) { - return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 890, "Invalid check digit '%1$c', expecting '%2$c'", - have_check_digit, itoc(check_digit)); - } - - localstr[8 - pzn7] = itoc(check_digit); - localstr[9 - pzn7] = '\0'; - - if (pzn7) { - symbol->option_2 = 0; /* Need to overwrite this so `code39()` doesn't add a check digit itself */ - } - - error_number = code39(symbol, (unsigned char *) localstr, 9 - pzn7); - - if (pzn7) { - symbol->option_2 = 1; /* Restore */ - } - - ustrcpy(symbol->text, "PZN - "); /* Note changed to put space after hyphen */ - ustrcat(symbol->text, localstr + 1); - - if (symbol->output_options & COMPLIANT_HEIGHT) { - /* Technical Information regarding PZN Coding V 2.1 (25 Feb 2019) Code size - https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/IFA_Info_Code_39_EN.pdf - "normal" X 0.25mm (0.187mm - 0.45mm), height 8mm - 20mm for 0.25mm X, 10mm mentioned so use that - as default, 10mm / 0.25mm = 40 */ - if (error_number < ZINT_ERROR) { - const float min_height = 17.7777786f; /* 8.0 / 0.45 */ - const float max_height = 106.951874f; /* 20.0 / 0.187 */ - error_number = set_height(symbol, min_height, 40.0f, max_height, 0 /*no_errtxt*/); - } - } else { - if (error_number < ZINT_ERROR) { - (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); - } - } - - return error_number; -} - /* Extended Code 39 - ISO/IEC 16388:2007 Annex A */ INTERNAL int excode39(struct zint_symbol *symbol, unsigned char source[], int length) { @@ -599,227 +396,6 @@ INTERNAL int code93(struct zint_symbol *symbol, unsigned char source[], int leng return error_number; } -typedef const struct s_channel_precalc { - int value; unsigned char B[8]; unsigned char S[8]; unsigned char bmax[7]; unsigned char smax[7]; -} channel_precalc; - -#if 0 -#define CHANNEL_GENERATE_PRECALCS -#endif - -#ifdef CHANNEL_GENERATE_PRECALCS -/* To generate precalc tables uncomment CHANNEL_GENERATE_PRECALCS define and run - "backend/tests/test_channel -f generate -g" and place result in "channel_precalcs.h" */ -static void channel_generate_precalc(int channels, int 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]); fputs(" },", stdout); - fputs(" {", stdout); for (i = 0; i < 8; i++) printf(" %d,", S[i]); fputs(" },", stdout); - fputs(" {", stdout); for (i = 0; i < 7; i++) printf(" %d,", bmax[i]); fputs(" },", stdout); - fputs(" {", stdout); for (i = 0; i < 7; i++) printf(" %d,", smax[i]); fputs(" }, },\n", stdout); - if (value == last) fputs("};\n", stdout); -} -#else -#include "channel_precalcs.h" -#endif - -static int channel_copy_precalc(channel_precalc *const 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, int 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]; - int 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 - /* 115338 == (576688 + 2) / 5 */ - if (channels == 7 && value && value % 115338 == 0) { - channel_generate_precalc(channels, value, 115338, - 115338 * (5 - 1), B, S, bmax, smax); - /* 119121 == (7742862 + 3) / 65 */ - } else if (channels == 8 && value && value % 119121 == 0) { - 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(struct zint_symbol *symbol, unsigned char source[], int length) { - static const int max_ranges[] = { -1, -1, -1, 26, 292, 3493, 44072, 576688, 7742862 }; - int S[8] = {0}, B[8] = {0}; - int target_value; - char dest[30]; - char *d = dest; - int channels, i; - int error_number = 0, zeroes; - - if (length > 7) { - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 333, "Input length %d too long (maximum 7)", length); - } - if ((i = not_sane(NEON_F, source, length))) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 334, - "Invalid character at position %d in input (digits only)", i); - } - target_value = to_int(source, length); - - if ((symbol->option_2 < 3) || (symbol->option_2 > 8)) { - channels = 0; - } else { - channels = symbol->option_2; - } - - 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; - } - - if (target_value > max_ranges[channels]) { - if (channels == 8) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 318, "Input value \"%1$d\" out of range (0 to %2$d)", - target_value, max_ranges[channels]); - } - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 335, - "Input value \"%1$d\" out of range (0 to %2$d for %3$d channels)", - target_value, max_ranges[channels], channels); - } - - CHNCHR(channels, target_value, B, S); - - memcpy(d, "111111111", 9); /* Finder pattern */ - d += 9; - for (i = 8 - channels; i < 8; i++) { - *d++ = itoc(S[i]); - *d++ = itoc(B[i]); - } - - zeroes = channels - 1 - length; - if (zeroes < 0) { - zeroes = 0; - } else if (zeroes) { - memset(symbol->text, '0', zeroes); - } - ustrcpy(symbol->text + zeroes, source); - - expand(symbol, dest, d - dest); - - if (symbol->output_options & COMPLIANT_HEIGHT) { - /* ANSI/AIM BC12-1998 gives min height as 5mm or 15% of length; X left as application specification so use - length = 1X (left qz) + (9 (finder) + 4 * 8 - 2) * X + 2X (right qz); - use 20 as default based on figures in spec */ - const float min_height = stripf((1 + 9 + 4 * channels - 2 + 2) * 0.15f); - error_number = set_height(symbol, min_height, 20.0f, 0.0f, 0 /*no_errtxt*/); - } else { - (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); - } - - return error_number; -} - /* Vehicle Identification Number (VIN) */ INTERNAL int vin(struct zint_symbol *symbol, unsigned char source[], int length) { diff --git a/backend/code11.c b/backend/code11.c new file mode 100644 index 00000000..e103ba12 --- /dev/null +++ b/backend/code11.c @@ -0,0 +1,155 @@ +/* code11.c - Handles Code 11 */ +/* + libzint - the open source barcode library + Copyright (C) 2008-2025 Robin 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* Was in "code.c" */ + +#include +#include +#include "common.h" + +#define SODIUM_MNS_F (IS_NUM_F | IS_MNS_F) /* SODIUM "0123456789-" */ + +static const char C11Table[11 + 1][6] = { + {'1','1','1','1','2','1'}, {'2','1','1','1','2','1'}, {'1','2','1','1','2','1'}, {'2','2','1','1','1','1'}, + {'1','1','2','1','2','1'}, {'2','1','2','1','1','1'}, {'1','2','2','1','1','1'}, {'1','1','1','2','2','1'}, + {'2','1','1','2','1','1'}, {'2','1','1','1','1','1'}, {'1','1','2','1','1','1'}, + {'1','1','2','2','1','1'} /* Start character (full 6), Stop character (first 5) */ +}; + +/* Code 11 */ +INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int length) { + + int i; + int h; + int weight[141]; /* 140 + 1 extra for 1st check */ + char dest[864]; /* 6 + 140 * 6 + 2 * 6 + 5 + 1 = 864 */ + int error_number = 0; + char *d = dest; + int num_check_digits; + char checkstr[3] = {0}; + static const char checkchrs[11] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-' }; + + /* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warning */ + assert(length > 0); + + if (length > 140) { /* 8 (Start) + 140 * 8 + 2 * 8 (Check) + 7 (Stop) = 1151 */ + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 320, "Input length %d too long (maximum 140)", length); + } + if ((i = not_sane(SODIUM_MNS_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 321, + "Invalid character at position %d in input (digits and \"-\" only)", i); + } + + if (symbol->option_2 < 0 || symbol->option_2 > 2) { + return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 339, "Invalid check digit version '%d' (1 or 2 only)", + symbol->option_2); + } + if (symbol->option_2 == 2) { + num_check_digits = 0; + } else if (symbol->option_2 == 1) { + num_check_digits = 1; + } else { + num_check_digits = 2; + } + + + /* start character */ + memcpy(d, C11Table[11], 6); + d += 6; + + /* Draw main body of barcode */ + for (i = 0; i < length; i++, d += 6) { + if (source[i] == '-') + weight[i] = 10; + else + weight[i] = ctoi(source[i]); + memcpy(d, C11Table[weight[i]], 6); + } + + if (num_check_digits) { + int c_weight = 1, c_count = 0, c_digit; + /* 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; + + checkstr[0] = checkchrs[c_digit]; + memcpy(d, C11Table[c_digit], 6); + d += 6; + + if (num_check_digits == 2) { + int k_weight = 1, k_count = 0, k_digit; + 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[1] = checkchrs[k_digit]; + memcpy(d, C11Table[k_digit], 6); + d += 6; + } + } + + if (symbol->debug & ZINT_DEBUG_PRINT) { + printf("Check digit (%d): %s\n", num_check_digits, num_check_digits ? checkstr : ""); + } + + /* Stop character */ + memcpy(d, C11Table[11], 5); + d += 5; + + expand(symbol, dest, d - dest); + + /* TODO: Find documentation on BARCODE_CODE11 dimensions/height */ + + ustrcpy(symbol->text, source); + if (num_check_digits) { + ustrcat(symbol->text, checkstr); + } + return error_number; +} + +/* vim: set ts=4 sw=4 et : */ diff --git a/backend/code128.c b/backend/code128.c index 55d63c04..f9d5590c 100644 --- a/backend/code128.c +++ b/backend/code128.c @@ -1,7 +1,7 @@ -/* code128.c - Handles Code 128 and derivatives */ +/* code128.c - Handles Code 128 and GS1-128 */ /* libzint - the open source barcode library - Copyright (C) 2008-2024 Robin Stuart + Copyright (C) 2008-2025 Robin Stuart Bugfixes thanks to Christian Sakowski and BogDan Vatra Redistribution and use in source and binary forms, with or without @@ -663,277 +663,4 @@ INTERNAL int gs1_128(struct zint_symbol *symbol, unsigned char source[], int len return gs1_128_cc(symbol, source, length, 0 /*cc_mode*/, 0 /*cc_rows*/); } -/* Helper to do NVE18 or EAN14 */ -static int nve18_or_ean14(struct zint_symbol *symbol, unsigned char source[], const int length, const int data_len) { - static const char prefix[2][2][5] = { - { "(01)", "[01]" }, /* EAN14 */ - { "(00)", "[00]" }, /* NVE18 */ - }; - unsigned char ean128_equiv[23]; - int error_number, zeroes; - int i; - - if (length > data_len) { - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 345, "Input length %1$d too long (maximum %2$d)", length, - data_len); - } - - if ((i = not_sane(NEON_F, source, length))) { - /* Note: for all "at position" error messages, escape sequences not accounted for */ - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 346, - "Invalid character at position %d in input (digits only)", i); - } - - zeroes = data_len - length; - ustrcpy(ean128_equiv, prefix[data_len == 17][!(symbol->input_mode & GS1PARENS_MODE)]); - memset(ean128_equiv + 4, '0', zeroes); - ustrcpy(ean128_equiv + 4 + zeroes, source); - - ean128_equiv[data_len + 4] = gs1_check_digit(ean128_equiv + 4, data_len); - ean128_equiv[data_len + 5] = '\0'; - - error_number = gs1_128(symbol, ean128_equiv, data_len + 5); - - return error_number; -} - - -/* Add check digit if encoding an NVE18 symbol */ -INTERNAL int nve18(struct zint_symbol *symbol, unsigned char source[], int length) { - return nve18_or_ean14(symbol, source, length, 17 /*data_len*/); -} - -/* EAN-14 - A version of EAN-128 */ -INTERNAL int ean14(struct zint_symbol *symbol, unsigned char source[], int length) { - return nve18_or_ean14(symbol, source, length, 13 /*data_len*/); -} - -static const char KRSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; -#define KRSET_F (IS_NUM_F | IS_UPR_F) - -/* DPD (Deutscher Paketdienst) Code */ -/* Specification at https://esolutions.dpd.com/dokumente/DPD_Parcel_Label_Specification_2.4.1_EN.pdf - * and identification tag info (Barcode ID) at https://esolutions.dpd.com/dokumente/DPD_Routing_Database_1.3_EN.pdf */ -INTERNAL int dpd(struct zint_symbol *symbol, unsigned char source[], int length) { - int error_number = 0; - int i, p; - unsigned char ident_tag; - unsigned char local_source_buf[29]; - unsigned char *local_source; - const int mod = 36; - const int relabel = symbol->option_2 == 1; /* A "relabel" has no identification tag */ - int cd; /* Check digit */ - - if ((length != 27 && length != 28) || (length == 28 && relabel)) { - if (relabel) { - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 830, "DPD relabel input length %d wrong (27 only)", length); - } - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 349, "DPD input length %d wrong (27 or 28 only)", length); - } - - if (length == 27 && !relabel) { - local_source_buf[0] = '%'; - ustrcpy(local_source_buf + 1, source); - local_source = local_source_buf; - length++; - } else { - local_source = source; - } - - ident_tag = local_source[0]; - - to_upper(local_source + !relabel, length - !relabel); - if ((i = not_sane(KRSET_F, local_source + !relabel, length - !relabel))) { - if (local_source == local_source_buf || relabel) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 300, - "Invalid character at position %d in input (alphanumerics only)", i); - } - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 299, - "Invalid character at position %d in input (alphanumerics only after first)", i); - } - - if ((ident_tag < 32) || (ident_tag > 127)) { - return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 343, - "Invalid DPD identification tag (first character), ASCII values 32 to 127 only"); - } - - (void) code128(symbol, local_source, length); /* Only error returned is for large text which can't happen */ - - if (!(symbol->output_options & (BARCODE_BOX | BARCODE_BIND | BARCODE_BIND_TOP))) { - /* If no option has been selected then uses default bind top option */ - symbol->output_options |= BARCODE_BIND_TOP; /* Note won't extend over quiet zones for DPD */ - if (symbol->border_width == 0) { /* Allow override if non-zero */ - symbol->border_width = 3; /* From examples, not mentioned in spec */ - } - } - - if (symbol->output_options & COMPLIANT_HEIGHT) { - /* DPD Parcel Label Specification Version 2.4.1 (19.01.2021) Section 4.6.1.2 - 25mm / 0.4mm (X max) = 62.5 min, 25mm / 0.375 (X) ~ 66.66 default */ - if (relabel) { /* If relabel then half-size */ - const float default_height = 33.3333321f; /* 12.5 / 0.375 */ - error_number = set_height(symbol, 31.25f, default_height, 0.0f, 0 /*no_errtxt*/); - } else { - const float default_height = 66.6666641f; /* 25.0 / 0.375 */ - error_number = set_height(symbol, 62.5f, default_height, 0.0f, 0 /*no_errtxt*/); - } - } else { - (void) set_height(symbol, 0.0f, relabel ? 25.0f : 50.0f, 0.0f, 1 /*no_errtxt*/); - } - - cd = mod; - - p = 0; - for (i = !relabel; i < length; i++) { - symbol->text[p] = local_source[i]; - p++; - - cd += posn(KRSET, local_source[i]); - if (cd > mod) cd -= mod; - cd *= 2; - if (cd >= (mod + 1)) cd -= mod + 1; - - switch (i + relabel) { - case 4: - case 7: - case 11: - case 15: - case 19: - case 21: - case 24: - case 27: - symbol->text[p++] = ' '; - break; - } - } - - cd = mod + 1 - cd; - if (cd == mod) cd = 0; - - if (cd < 10) { - symbol->text[p] = cd + '0'; - } else { - symbol->text[p] = (cd - 10) + 'A'; - } - p++; - - symbol->text[p] = '\0'; - - /* Some compliance checks */ - if (not_sane(NEON_F, local_source + length - 16, 16)) { - if (not_sane(NEON_F, local_source + length - 3, 3)) { /* 3-digit Country Code (ISO 3166-1) */ - errtxt(0, symbol, 831, "Destination Country Code (last 3 characters) should be numeric"); - } else if (not_sane(NEON_F, local_source + length - 6, 3)) { /* 3-digit Service Code */ - errtxt(0, symbol, 832, "Service Code (characters 6-4 from end) should be numeric"); - } else { /* Last 10 characters of Tracking No. */ - errtxt(0, symbol, 833, - "Last 10 characters of Tracking Number (characters 16-7 from end) should be numeric"); - } - error_number = ZINT_WARN_NONCOMPLIANT; - } - - return error_number; -} - -/* Universal Postal Union S10 */ -/* https://www.upu.int/UPU/media/upu/files/postalSolutions/programmesAndServices/standards/S10-12.pdf */ -INTERNAL int upu_s10(struct zint_symbol *symbol, unsigned char source[], int length) { - int i, j; - unsigned char local_source[13 + 1]; - unsigned char have_check_digit = '\0'; - int check_digit; - static const char weights[8] = { 8, 6, 4, 2, 3, 5, 9, 7 }; - int error_number = 0; - - if (length != 12 && length != 13) { - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 834, "Input length %d wrong (12 or 13 only)", length); - } - if (length == 13) { /* Includes check digit - remove for now */ - have_check_digit = source[10]; - memcpy(local_source, source, 10); - ustrcpy(local_source + 10, source + 11); - } else { - ustrcpy(local_source, source); - } - to_upper(local_source, length); - - if (!z_isupper(local_source[0]) || !z_isupper(local_source[1])) { - return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 835, - "Invalid character in Service Indictor (first 2 characters) (alphabetic only)"); - } - if (not_sane(NEON_F, local_source + 2, 12 - 4) || (have_check_digit && !z_isdigit(have_check_digit))) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 836, - "Invalid character in Serial Number (middle %d characters) (digits only)", - have_check_digit ? 9 : 8); - } - if (!z_isupper(local_source[10]) || !z_isupper(local_source[11])) { - return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 837, - "Invalid character in Country Code (last 2 characters) (alphabetic only)"); - } - - check_digit = 0; - for (i = 2; i < 10; i++) { /* Serial Number only */ - check_digit += ctoi(local_source[i]) * weights[i - 2]; - } - check_digit %= 11; - check_digit = 11 - check_digit; - if (check_digit == 10) { - check_digit = 0; - } else if (check_digit == 11) { - check_digit = 5; - } - if (have_check_digit && ctoi(have_check_digit) != check_digit) { - return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 838, "Invalid check digit '%1$c', expecting '%2$c'", - have_check_digit, itoc(check_digit)); - } - /* Add in (back) check digit */ - local_source[12] = local_source[11]; - local_source[11] = local_source[10]; - local_source[10] = itoc(check_digit); - local_source[13] = '\0'; - - /* Do some checks on the Service Indicator (first char only) and Country Code */ - if (strchr("JKSTW", local_source[0]) != NULL) { /* These are reserved & cannot be assigned */ - error_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 839, - "Invalid Service Indicator (first character should not be any of \"JKSTW\")"); - } else if (strchr("FHIOXY", local_source[0]) != NULL) { /* These aren't allocated as of spec Oct 2017 */ - error_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 840, - "Non-standard Service Indicator (first 2 characters)"); - } else if (!gs1_iso3166_alpha2(local_source + 11)) { - error_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 841, - "Country code (last two characters) is not ISO 3166-1"); - } - - (void) code128(symbol, local_source, 13); /* Only error returned is for large text which can't happen */ - - j = 0; - for (i = 0; i < 13; i++) { - if (i == 2 || i == 5 || i == 8 || i == 11) { - symbol->text[j++] = ' '; - } - symbol->text[j++] = local_source[i]; - } - symbol->text[j] = '\0'; - - if (symbol->output_options & COMPLIANT_HEIGHT) { - /* Universal Postal Union S10 Section 8, using max X 0.51mm & minimum height 12.5mm or 15% of width */ - const float min_height_min = 24.5098038f; /* 12.5 / 0.51 */ - float min_height = stripf(symbol->width * 0.15f); - if (min_height < min_height_min) { - min_height = min_height_min; - } - /* Using 50 as default as none recommended */ - if (error_number == 0) { - error_number = set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, - 0 /*no_errtxt*/); - } else { - (void) set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, 1 /*no_errtxt*/); - } - } else { - (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); - } - - return error_number; -} - /* vim: set ts=4 sw=4 et : */ diff --git a/backend/code128_based.c b/backend/code128_based.c new file mode 100644 index 00000000..db498119 --- /dev/null +++ b/backend/code128_based.c @@ -0,0 +1,316 @@ +/* code128_based.c - Handles Code 128 derivatives NVE-18, EAN-14, DPD and Universal Postal Union S10 */ +/* + libzint - the open source barcode library + Copyright (C) 2008-2025 Robin Stuart + Bugfixes thanks to Christian Sakowski and BogDan Vatra + + 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include +#include "common.h" +#include "code128.h" +#include "gs1.h" + +/* Was in "code128.c" */ + +INTERNAL int gs1_128(struct zint_symbol *symbol, unsigned char source[], int length); + +/* Helper to do NVE18 or EAN14 */ +static int nve18_or_ean14(struct zint_symbol *symbol, unsigned char source[], const int length, const int data_len) { + static const char prefix[2][2][5] = { + { "(01)", "[01]" }, /* EAN14 */ + { "(00)", "[00]" }, /* NVE18 */ + }; + unsigned char ean128_equiv[23]; + int error_number, zeroes; + int i; + + if (length > data_len) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 345, "Input length %1$d too long (maximum %2$d)", length, + data_len); + } + + if ((i = not_sane(NEON_F, source, length))) { + /* Note: for all "at position" error messages, escape sequences not accounted for */ + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 346, + "Invalid character at position %d in input (digits only)", i); + } + + zeroes = data_len - length; + ustrcpy(ean128_equiv, prefix[data_len == 17][!(symbol->input_mode & GS1PARENS_MODE)]); + memset(ean128_equiv + 4, '0', zeroes); + ustrcpy(ean128_equiv + 4 + zeroes, source); + + ean128_equiv[data_len + 4] = gs1_check_digit(ean128_equiv + 4, data_len); + ean128_equiv[data_len + 5] = '\0'; + + error_number = gs1_128(symbol, ean128_equiv, data_len + 5); + + return error_number; +} + + +/* Add check digit if encoding an NVE18 symbol */ +INTERNAL int nve18(struct zint_symbol *symbol, unsigned char source[], int length) { + return nve18_or_ean14(symbol, source, length, 17 /*data_len*/); +} + +/* EAN-14 - A version of EAN-128 */ +INTERNAL int ean14(struct zint_symbol *symbol, unsigned char source[], int length) { + return nve18_or_ean14(symbol, source, length, 13 /*data_len*/); +} + +static const char KRSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#define KRSET_F (IS_NUM_F | IS_UPR_F) + +/* DPD (Deutscher Paketdienst) Code */ +/* Specification at https://esolutions.dpd.com/dokumente/DPD_Parcel_Label_Specification_2.4.1_EN.pdf + * and identification tag info (Barcode ID) at https://esolutions.dpd.com/dokumente/DPD_Routing_Database_1.3_EN.pdf */ +INTERNAL int dpd(struct zint_symbol *symbol, unsigned char source[], int length) { + int error_number = 0; + int i, p; + unsigned char ident_tag; + unsigned char local_source_buf[29]; + unsigned char *local_source; + const int mod = 36; + const int relabel = symbol->option_2 == 1; /* A "relabel" has no identification tag */ + int cd; /* Check digit */ + + if ((length != 27 && length != 28) || (length == 28 && relabel)) { + if (relabel) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 830, "DPD relabel input length %d wrong (27 only)", length); + } + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 349, "DPD input length %d wrong (27 or 28 only)", length); + } + + if (length == 27 && !relabel) { + local_source_buf[0] = '%'; + ustrcpy(local_source_buf + 1, source); + local_source = local_source_buf; + length++; + } else { + local_source = source; + } + + ident_tag = local_source[0]; + + to_upper(local_source + !relabel, length - !relabel); + if ((i = not_sane(KRSET_F, local_source + !relabel, length - !relabel))) { + if (local_source == local_source_buf || relabel) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 300, + "Invalid character at position %d in input (alphanumerics only)", i); + } + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 299, + "Invalid character at position %d in input (alphanumerics only after first)", i); + } + + if ((ident_tag < 32) || (ident_tag > 127)) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 343, + "Invalid DPD identification tag (first character), ASCII values 32 to 127 only"); + } + + (void) code128(symbol, local_source, length); /* Only error returned is for large text which can't happen */ + + if (!(symbol->output_options & (BARCODE_BOX | BARCODE_BIND | BARCODE_BIND_TOP))) { + /* If no option has been selected then uses default bind top option */ + symbol->output_options |= BARCODE_BIND_TOP; /* Note won't extend over quiet zones for DPD */ + if (symbol->border_width == 0) { /* Allow override if non-zero */ + symbol->border_width = 3; /* From examples, not mentioned in spec */ + } + } + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* DPD Parcel Label Specification Version 2.4.1 (19.01.2021) Section 4.6.1.2 + 25mm / 0.4mm (X max) = 62.5 min, 25mm / 0.375 (X) ~ 66.66 default */ + if (relabel) { /* If relabel then half-size */ + const float default_height = 33.3333321f; /* 12.5 / 0.375 */ + error_number = set_height(symbol, 31.25f, default_height, 0.0f, 0 /*no_errtxt*/); + } else { + const float default_height = 66.6666641f; /* 25.0 / 0.375 */ + error_number = set_height(symbol, 62.5f, default_height, 0.0f, 0 /*no_errtxt*/); + } + } else { + (void) set_height(symbol, 0.0f, relabel ? 25.0f : 50.0f, 0.0f, 1 /*no_errtxt*/); + } + + cd = mod; + + p = 0; + for (i = !relabel; i < length; i++) { + symbol->text[p] = local_source[i]; + p++; + + cd += posn(KRSET, local_source[i]); + if (cd > mod) cd -= mod; + cd *= 2; + if (cd >= (mod + 1)) cd -= mod + 1; + + switch (i + relabel) { + case 4: + case 7: + case 11: + case 15: + case 19: + case 21: + case 24: + case 27: + symbol->text[p++] = ' '; + break; + } + } + + cd = mod + 1 - cd; + if (cd == mod) cd = 0; + + if (cd < 10) { + symbol->text[p] = cd + '0'; + } else { + symbol->text[p] = (cd - 10) + 'A'; + } + p++; + + symbol->text[p] = '\0'; + + /* Some compliance checks */ + if (not_sane(NEON_F, local_source + length - 16, 16)) { + if (not_sane(NEON_F, local_source + length - 3, 3)) { /* 3-digit Country Code (ISO 3166-1) */ + errtxt(0, symbol, 831, "Destination Country Code (last 3 characters) should be numeric"); + } else if (not_sane(NEON_F, local_source + length - 6, 3)) { /* 3-digit Service Code */ + errtxt(0, symbol, 832, "Service Code (characters 6-4 from end) should be numeric"); + } else { /* Last 10 characters of Tracking No. */ + errtxt(0, symbol, 833, + "Last 10 characters of Tracking Number (characters 16-7 from end) should be numeric"); + } + error_number = ZINT_WARN_NONCOMPLIANT; + } + + return error_number; +} + +/* Universal Postal Union S10 */ +/* https://www.upu.int/UPU/media/upu/files/postalSolutions/programmesAndServices/standards/S10-12.pdf */ +INTERNAL int upu_s10(struct zint_symbol *symbol, unsigned char source[], int length) { + int i, j; + unsigned char local_source[13 + 1]; + unsigned char have_check_digit = '\0'; + int check_digit; + static const char weights[8] = { 8, 6, 4, 2, 3, 5, 9, 7 }; + int error_number = 0; + + if (length != 12 && length != 13) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 834, "Input length %d wrong (12 or 13 only)", length); + } + if (length == 13) { /* Includes check digit - remove for now */ + have_check_digit = source[10]; + memcpy(local_source, source, 10); + ustrcpy(local_source + 10, source + 11); + } else { + ustrcpy(local_source, source); + } + to_upper(local_source, length); + + if (!z_isupper(local_source[0]) || !z_isupper(local_source[1])) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 835, + "Invalid character in Service Indictor (first 2 characters) (alphabetic only)"); + } + if (not_sane(NEON_F, local_source + 2, 12 - 4) || (have_check_digit && !z_isdigit(have_check_digit))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 836, + "Invalid character in Serial Number (middle %d characters) (digits only)", + have_check_digit ? 9 : 8); + } + if (!z_isupper(local_source[10]) || !z_isupper(local_source[11])) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 837, + "Invalid character in Country Code (last 2 characters) (alphabetic only)"); + } + + check_digit = 0; + for (i = 2; i < 10; i++) { /* Serial Number only */ + check_digit += ctoi(local_source[i]) * weights[i - 2]; + } + check_digit %= 11; + check_digit = 11 - check_digit; + if (check_digit == 10) { + check_digit = 0; + } else if (check_digit == 11) { + check_digit = 5; + } + if (have_check_digit && ctoi(have_check_digit) != check_digit) { + return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 838, "Invalid check digit '%1$c', expecting '%2$c'", + have_check_digit, itoc(check_digit)); + } + /* Add in (back) check digit */ + local_source[12] = local_source[11]; + local_source[11] = local_source[10]; + local_source[10] = itoc(check_digit); + local_source[13] = '\0'; + + /* Do some checks on the Service Indicator (first char only) and Country Code */ + if (strchr("JKSTW", local_source[0]) != NULL) { /* These are reserved & cannot be assigned */ + error_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 839, + "Invalid Service Indicator (first character should not be any of \"JKSTW\")"); + } else if (strchr("FHIOXY", local_source[0]) != NULL) { /* These aren't allocated as of spec Oct 2017 */ + error_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 840, + "Non-standard Service Indicator (first 2 characters)"); + } else if (!gs1_iso3166_alpha2(local_source + 11)) { + error_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 841, + "Country code (last two characters) is not ISO 3166-1"); + } + + (void) code128(symbol, local_source, 13); /* Only error returned is for large text which can't happen */ + + j = 0; + for (i = 0; i < 13; i++) { + if (i == 2 || i == 5 || i == 8 || i == 11) { + symbol->text[j++] = ' '; + } + symbol->text[j++] = local_source[i]; + } + symbol->text[j] = '\0'; + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* Universal Postal Union S10 Section 8, using max X 0.51mm & minimum height 12.5mm or 15% of width */ + const float min_height_min = 24.5098038f; /* 12.5 / 0.51 */ + float min_height = stripf(symbol->width * 0.15f); + if (min_height < min_height_min) { + min_height = min_height_min; + } + /* Using 50 as default as none recommended */ + if (error_number == 0) { + error_number = set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, + 0 /*no_errtxt*/); + } else { + (void) set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, 1 /*no_errtxt*/); + } + } else { + (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); + } + + return error_number; +} + +/* vim: set ts=4 sw=4 et : */ diff --git a/backend/common.c b/backend/common.c index ceb6f560..7b2f6d0d 100644 --- a/backend/common.c +++ b/backend/common.c @@ -1,7 +1,7 @@ /* common.c - Contains functions needed for a number of barcodes */ /* libzint - the open source barcode library - Copyright (C) 2008-2024 Robin Stuart + Copyright (C) 2008-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -503,15 +503,15 @@ INTERNAL int errtxt_adj(const int error_number, struct zint_symbol *symbol, cons err_buf[0] = '\0'; -/* Suppress gcc 14 warning output may be truncated */ -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 14 +/* Suppress gcc 8+ warning output may be truncated */ +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-truncation" #endif strncat(err_buf, symbol->errtxt, sizeof(symbol->errtxt) - 1); -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 14 +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 8 #pragma GCC diagnostic pop #endif diff --git a/backend/common.h b/backend/common.h index 6017dbb2..092f452f 100644 --- a/backend/common.h +++ b/backend/common.h @@ -1,7 +1,7 @@ /* common.h - Header for all common functions in common.c */ /* libzint - the open source barcode library - Copyright (C) 2009-2024 Robin Stuart + Copyright (C) 2009-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -84,6 +84,8 @@ typedef unsigned __int64 uint64_t; # if _MSC_VER > 1200 /* VC6 */ # pragma warning(disable: 4996) /* function or variable may be unsafe */ # endif +#elif defined(__MINGW64__) && defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 3 +# pragma GCC diagnostic ignored "-Wlong-long" #endif #if defined(__GNUC__) && __GNUC__ >= 3 diff --git a/backend/dmatrix.c b/backend/dmatrix.c index 997d24ea..5ea4d303 100644 --- a/backend/dmatrix.c +++ b/backend/dmatrix.c @@ -1,7 +1,7 @@ /* dmatrix.c Handles Data Matrix ECC 200 symbols */ /* libzint - the open source barcode library - Copyright (C) 2009-2024 Robin Stuart + Copyright (C) 2009-2025 Robin Stuart developed from and including some functions from: IEC16022 bar code generation @@ -323,7 +323,7 @@ static int dm_look_ahead_test(const unsigned char source[], const int length, co const unsigned char c = source[sp]; const int is_extended = c & 0x80; - /* ascii ... step (l) */ + /* ASCII ... step (l) */ if (z_isdigit(c)) { ascii_count += DM_MULT_1_DIV_2; /* (l)(1) */ } else { @@ -334,7 +334,7 @@ static int dm_look_ahead_test(const unsigned char source[], const int length, co } } - /* c40 ... step (m) */ + /* C40 ... step (m) */ if (dm_isc40(c)) { c40_count += DM_MULT_2_DIV_3; /* (m)(1) */ } else { @@ -345,7 +345,7 @@ static int dm_look_ahead_test(const unsigned char source[], const int length, co } } - /* text ... step (n) */ + /* TEXT ... step (n) */ if (dm_istext(c)) { text_count += DM_MULT_2_DIV_3; /* (n)(1) */ } else { @@ -356,7 +356,7 @@ static int dm_look_ahead_test(const unsigned char source[], const int length, co } } - /* x12 ... step (o) */ + /* X12 ... step (o) */ if (dm_isX12(c)) { x12_count += DM_MULT_2_DIV_3; /* (o)(1) */ } else { @@ -367,7 +367,7 @@ static int dm_look_ahead_test(const unsigned char source[], const int length, co } } - /* edifact ... step (p) */ + /* EDIFACT ... step (p) */ if (dm_isedifact(c)) { edf_count += DM_MULT_3_DIV_4; /* (p)(1) */ } else { @@ -378,7 +378,7 @@ static int dm_look_ahead_test(const unsigned char source[], const int length, co } } - /* base 256 ... step (q) */ + /* Base 256 ... step (q) */ if (gs1 == 1 && c == '\x1D') { /* FNC1 separator */ b256_count += DM_MULT_4; /* (q)(1) */ @@ -740,19 +740,20 @@ static int dm_last_ascii(const unsigned char source[], const int length, const i /* Treat EDIFACT edges specially, returning DM_ASCII mode if not full (i.e. encoding < 4 chars), or if full and at EOD where 1 or 2 ASCII chars can be encoded */ -static int dm_getEndMode(struct zint_symbol *symbol, const unsigned char *source, const int length, const int mode, - const int from, const int len, const int size) { +static int dm_getEndMode(struct zint_symbol *symbol, const unsigned char *source, const int length, + const int last_seg, const int mode, const int from, const int len, const int size) { if (mode == DM_EDIFACT) { - int last_ascii; if (len < 4) { return DM_ASCII; } - last_ascii = dm_last_ascii(source, length, from + len); - if (last_ascii) { /* At EOD with remaining chars ASCII-encodable in 1 or 2 codewords */ - const int symbols_left = dm_codewords_remaining(symbol, size + last_ascii, 0); - /* If no codewords left and 1 or 2 ASCII-encodables or 1 codeword left and 1 ASCII-encodable */ - if (symbols_left <= 2 - last_ascii) { - return DM_ASCII; + if (last_seg) { + const int last_ascii = dm_last_ascii(source, length, from + len); + if (last_ascii) { /* At EOD with remaining chars ASCII-encodable in 1 or 2 codewords */ + const int symbols_left = dm_codewords_remaining(symbol, size + last_ascii, 0); + /* If no codewords left and 1 or 2 ASCII-encodables or 1 codeword left and 1 ASCII-encodable */ + if (symbols_left <= 2 - last_ascii) { + return DM_ASCII; + } } } } @@ -796,12 +797,11 @@ static int dm_getNumberOfC40Words(const unsigned char *source, const int length, } /* Initialize a new edge. Returns endMode */ -static int dm_new_Edge(struct zint_symbol *symbol, const unsigned char *source, const int length, +static int dm_new_Edge(struct zint_symbol *symbol, const unsigned char *source, const int length, const int last_seg, struct dm_edge *edges, const int mode, const int from, const int len, struct dm_edge *previous, struct dm_edge *edge, const int cwds) { int previousMode; int size; - int last_ascii, symbols_left; edge->mode = mode; edge->endMode = mode; @@ -859,9 +859,9 @@ static int dm_new_Edge(struct zint_symbol *symbol, const unsigned char *source, size++; /* Unlatch to ASCII */ } } - if (from + len + 2 >= length) { /* If less than batch of 3 away from EOD */ - last_ascii = dm_last_ascii(source, length, from + len); - symbols_left = dm_codewords_remaining(symbol, size + last_ascii, 0); + if (last_seg && from + len + 2 >= length) { /* If less than batch of 3 away from EOD */ + const int last_ascii = dm_last_ascii(source, length, from + len); + const int symbols_left = dm_codewords_remaining(symbol, size + last_ascii, 0); if (symbols_left > 0) { size++; /* We need an extra unlatch at the end */ } @@ -877,12 +877,12 @@ static int dm_new_Edge(struct zint_symbol *symbol, const unsigned char *source, size++; /* Unlatch to ASCII */ } } - if (from + len + 2 >= length) { /* If less than batch of 3 away from EOD */ - last_ascii = dm_last_ascii(source, length, from + len); + if (last_seg && from + len + 2 >= length) { /* If less than batch of 3 away from EOD */ + const int last_ascii = dm_last_ascii(source, length, from + len); if (last_ascii == 2) { /* Only 1 ASCII-encodable allowed at EOD for X12, unlike C40/TEXT */ size++; /* We need an extra unlatch at the end */ } else { - symbols_left = dm_codewords_remaining(symbol, size + last_ascii, 0); + const int symbols_left = dm_codewords_remaining(symbol, size + last_ascii, 0); if (symbols_left > 0) { size++; /* We need an extra unlatch at the end */ } @@ -898,7 +898,7 @@ static int dm_new_Edge(struct zint_symbol *symbol, const unsigned char *source, size++; /* Unlatch to ASCII */ } } - edge->endMode = dm_getEndMode(symbol, source, length, mode, from, len, size); + edge->endMode = dm_getEndMode(symbol, source, length, last_seg, mode, from, len, size); break; } edge->size = size; @@ -907,11 +907,11 @@ static int dm_new_Edge(struct zint_symbol *symbol, const unsigned char *source, } /* Add an edge for a mode at a vertex if no existing edge or if more optimal than existing edge */ -static void dm_addEdge(struct zint_symbol *symbol, const unsigned char *source, const int length, +static void dm_addEdge(struct zint_symbol *symbol, const unsigned char *source, const int length, const int last_seg, struct dm_edge *edges, const int mode, const int from, const int len, struct dm_edge *previous, const int cwds) { struct dm_edge edge; - const int endMode = dm_new_Edge(symbol, source, length, edges, mode, from, len, previous, &edge, cwds); + const int endMode = dm_new_Edge(symbol, source, length, last_seg, edges, mode, from, len, previous, &edge, cwds); const int vertexIndex = from + len; const int v_ij = vertexIndex * DM_NUM_MODES + endMode - 1; @@ -925,7 +925,7 @@ static void dm_addEdge(struct zint_symbol *symbol, const unsigned char *source, /* Add edges for the various modes at a vertex */ static void dm_addEdges(struct zint_symbol *symbol, const unsigned char source[], const int length, - struct dm_edge *edges, const int from, struct dm_edge *previous, const int gs1) { + const int last_seg, struct dm_edge *edges, const int from, struct dm_edge *previous, const int gs1) { int i, pos; /* Not possible to unlatch a full EDF edge to something else */ @@ -934,29 +934,29 @@ static void dm_addEdges(struct zint_symbol *symbol, const unsigned char source[] static const char c40text_modes[] = { DM_C40, DM_TEXT }; if (z_isdigit(source[from]) && from + 1 < length && z_isdigit(source[from + 1])) { - dm_addEdge(symbol, source, length, edges, DM_ASCII, from, 2, previous, 0); + dm_addEdge(symbol, source, length, last_seg, edges, DM_ASCII, from, 2, previous, 0); /* If ASCII vertex, don't bother adding other edges as this will be optimal; suggested by Alex Geller */ if (previous && previous->mode == DM_ASCII) { return; } } else { - dm_addEdge(symbol, source, length, edges, DM_ASCII, from, 1, previous, 0); + dm_addEdge(symbol, source, length, last_seg, edges, DM_ASCII, from, 1, previous, 0); } for (i = 0; i < ARRAY_SIZE(c40text_modes); i++) { int len; int cwds = dm_getNumberOfC40Words(source, length, from, c40text_modes[i], &len); if (cwds) { - dm_addEdge(symbol, source, length, edges, c40text_modes[i], from, len, previous, cwds); + dm_addEdge(symbol, source, length, last_seg, edges, c40text_modes[i], from, len, previous, cwds); } } if (from + 2 < length && dm_isX12(source[from]) && dm_isX12(source[from + 1]) && dm_isX12(source[from + 2])) { - dm_addEdge(symbol, source, length, edges, DM_X12, from, 3, previous, 0); + dm_addEdge(symbol, source, length, last_seg, edges, DM_X12, from, 3, previous, 0); } if (gs1 != 1 || source[from] != '\x1D') { - dm_addEdge(symbol, source, length, edges, DM_BASE256, from, 1, previous, 0); + dm_addEdge(symbol, source, length, last_seg, edges, DM_BASE256, from, 1, previous, 0); } } @@ -964,14 +964,14 @@ static void dm_addEdges(struct zint_symbol *symbol, const unsigned char source[] /* We create 3 EDF edges, 2, 3 or 4 characters length. The 4-char normally doesn't have a latch to ASCII unless it is 2 characters away from the end of the input. */ for (i = 1, pos = from + i; i < 4 && pos < length && dm_isedifact(source[pos]); i++, pos++) { - dm_addEdge(symbol, source, length, edges, DM_EDIFACT, from, i + 1, previous, 0); + dm_addEdge(symbol, source, length, last_seg, edges, DM_EDIFACT, from, i + 1, previous, 0); } } } /* Calculate optimized encoding modes */ static int dm_define_mode(struct zint_symbol *symbol, char modes[], const unsigned char source[], const int length, - const int gs1, const int debug_print) { + const int last_seg, const int gs1, const int debug_print) { int i, j, v_i; int minimalJ, minimalSize; @@ -983,7 +983,7 @@ static int dm_define_mode(struct zint_symbol *symbol, char modes[], const unsign if (!edges) { return 0; } - dm_addEdges(symbol, source, length, edges, 0, NULL, gs1); + dm_addEdges(symbol, source, length, last_seg, edges, 0, NULL, gs1); DM_TRACE_Edges("DEBUG Initial situation\n", source, length, edges, 0); @@ -991,7 +991,7 @@ static int dm_define_mode(struct zint_symbol *symbol, char modes[], const unsign v_i = i * DM_NUM_MODES; for (j = 0; j < DM_NUM_MODES; j++) { if (edges[v_i + j].mode) { - dm_addEdges(symbol, source, length, edges, i, edges + v_i + j, gs1); + dm_addEdges(symbol, source, length, last_seg, edges, i, edges + v_i + j, gs1); } } DM_TRACE_Edges("DEBUG situation after adding edges to vertices at position %d\n", source, length, edges, i); @@ -1046,20 +1046,19 @@ static int dm_define_mode(struct zint_symbol *symbol, char modes[], const unsign } /* Do default minimal encodation */ -static int dm_minimalenc(struct zint_symbol *symbol, const unsigned char source[], const int length, int *p_sp, - unsigned char target[], int *p_tp, int process_buffer[8], int *p_process_p, int *p_b256_start, - int *p_current_mode, const int gs1, const int debug_print) { +static int dm_minimalenc(struct zint_symbol *symbol, const unsigned char source[], const int length, + const int last_seg, int *p_sp, unsigned char target[], int *p_tp, int process_buffer[8], int *p_process_p, + int *p_b256_start, int *p_current_mode, const int gs1, const int debug_print) { int sp = *p_sp; int tp = *p_tp; int process_p = *p_process_p; int current_mode = *p_current_mode; - int last_ascii, symbols_left; int i; char *modes = (char *) z_alloca(length); assert(length <= 10921); /* Can only handle (10921 + 1) * 6 = 65532 < 65536 (2*16) due to sizeof(previous) */ - if (!dm_define_mode(symbol, modes, source, length, gs1, debug_print)) { + if (!dm_define_mode(symbol, modes, source, length, last_seg, gs1, debug_print)) { return errtxt(ZINT_ERROR_MEMORY, symbol, 728, "Insufficient memory for mode buffers"); } @@ -1074,17 +1073,19 @@ static int dm_minimalenc(struct zint_symbol *symbol, const unsigned char source[ target[tp++] = 254; /* Unlatch */ break; case DM_EDIFACT: - last_ascii = dm_last_ascii(source, length, sp); - if (!last_ascii) { - process_buffer[process_p++] = 31; /* Unlatch */ - } else { - symbols_left = dm_codewords_remaining(symbol, tp + last_ascii, process_p); - if (debug_print) { - printf("process_p %d, last_ascii %d, symbols_left %d\n", - process_p, last_ascii, symbols_left); - } - if (symbols_left > 2 - last_ascii) { + if (last_seg) { + const int last_ascii = dm_last_ascii(source, length, sp); + if (!last_ascii) { process_buffer[process_p++] = 31; /* Unlatch */ + } else { + const int symbols_left = dm_codewords_remaining(symbol, tp + last_ascii, process_p); + if (debug_print) { + printf("process_p %d, last_ascii %d, symbols_left %d, last_seg %d\n", + process_p, last_ascii, symbols_left, last_seg); + } + if (symbols_left > 2 - last_ascii) { + process_buffer[process_p++] = 31; /* Unlatch */ + } } } process_p = dm_edi_buffer_xfer(process_buffer, process_p, target, &tp, 1 /*empty*/, debug_print); @@ -1251,7 +1252,7 @@ static int dm_isoenc(struct zint_symbol *symbol, const unsigned char source[], c next_mode = DM_C40; tp = dm_switch_mode(next_mode, target, tp, p_b256_start, debug_print); while (sp < 45) { - assert(!(sp & 0x80)); + assert(dm_isc40(source[sp])); process_buffer[process_p++] = dm_c40_value[source[sp]]; if (process_p >= 3) { @@ -1488,7 +1489,7 @@ static int dm_isoenc(struct zint_symbol *symbol, const unsigned char source[], c /* Encodes data using ASCII, C40, Text, X12, EDIFACT or Base 256 modes as appropriate Supports encoding FNC1 in supporting systems */ static int dm_encode(struct zint_symbol *symbol, const unsigned char source[], const int length, const int eci, - const int gs1, unsigned char target[], int *p_tp) { + const int last_seg, const int gs1, unsigned char target[], int *p_tp) { int sp = 0; int tp = *p_tp; int current_mode = DM_ASCII; @@ -1521,23 +1522,23 @@ static int dm_encode(struct zint_symbol *symbol, const unsigned char source[], c error_number = dm_isoenc(symbol, source, length, &sp, target, &tp, process_buffer, &process_p, &b256_start, ¤t_mode, gs1, debug_print); } else { /* Do default minimal encodation */ - error_number = dm_minimalenc(symbol, source, length, &sp, target, &tp, process_buffer, &process_p, + error_number = dm_minimalenc(symbol, source, length, last_seg, &sp, target, &tp, process_buffer, &process_p, &b256_start, ¤t_mode, gs1, debug_print); } if (error_number != 0) { return error_number; } - symbols_left = dm_codewords_remaining(symbol, tp, process_p); + symbols_left = last_seg ? dm_codewords_remaining(symbol, tp, process_p) : 3; - if (debug_print) printf("\nsymbols_left %d, tp %d, process_p %d ", symbols_left, tp, process_p); + if (debug_print) printf("\nsymbols_left %d, tp %d, process_p %d, last_seg %d, ", symbols_left, tp, process_p, last_seg); if (current_mode == DM_C40 || current_mode == DM_TEXT) { /* NOTE: changed to follow spec exactly here, only using Shift 1 padded triplets when 2 symbol chars remain. - This matches the behaviour of BWIPP but not tec-it, nor figures 4.15.1-1 and 4.15-1-2 in GS1 General + This matches the behaviour of BWIPP but not TEC-IT, nor figures 4.15.1-1 and 4.15-1-2 in GS1 General Specifications 21.0.1. */ - if (debug_print) printf("%s ", current_mode == DM_C40 ? "C40" : "TEX"); + if (debug_print) fputs(current_mode == DM_C40 ? "C40 " : "TEX ", stdout); if (process_p == 0) { if (symbols_left > 0) { target[tp++] = 254; /* Unlatch */ @@ -1553,7 +1554,7 @@ static int dm_encode(struct zint_symbol *symbol, const unsigned char source[], c /* 5.2.5.2 (c)/(d) */ if (symbols_left > 1) { /* 5.2.5.2 (c) */ - target[tp++] = 254; /* Unlatch and encode remaining data in ascii. */ + target[tp++] = 254; /* Unlatch and encode remaining data in ASCII. */ if (debug_print) fputs("ASC ", stdout); } target[tp++] = source[length - 1] + 1; @@ -1568,7 +1569,6 @@ static int dm_encode(struct zint_symbol *symbol, const unsigned char source[], c total_cnt += cnt; process_p -= cnt; } - if (debug_print) printf("Mode %d, backtracked %d\n", current_mode, (total_cnt / 3) * 2); tp -= (total_cnt / 3) * 2; target[tp++] = 254; /* Unlatch */ @@ -1632,7 +1632,7 @@ static int dm_encode(struct zint_symbol *symbol, const unsigned char source[], c if (debug_print) printf("A%02X A%02X ", target[tp - 2] - 1, target[tp - 1] - 1); } } else { - /* Append edifact unlatch value (31) and empty buffer */ + /* Append EDIFACT unlatch value (31) and empty buffer */ if (process_p <= 3) { process_buffer[process_p++] = 31; } @@ -1665,8 +1665,8 @@ static int dm_encode(struct zint_symbol *symbol, const unsigned char source[], c #ifdef ZINT_TEST /* Wrapper for direct testing */ INTERNAL int dm_encode_test(struct zint_symbol *symbol, const unsigned char source[], const int length, const int eci, - const int gs1, unsigned char target[], int *p_tp) { - return dm_encode(symbol, source, length, eci, gs1, target, p_tp); + const int last_seg, const int gs1, unsigned char target[], int *p_tp) { + return dm_encode(symbol, source, length, eci, last_seg, gs1, target, p_tp); } #endif @@ -1803,8 +1803,8 @@ static int dm_encode_segs(struct zint_symbol *symbol, struct zint_seg segs[], co len_dec += 2; /* Remove RS + EOT from end */ } } - error_number = dm_encode(symbol, segs[i].source + src_inc, segs[i].length - len_dec, segs[i].eci, gs1, - target, &tp); + error_number = dm_encode(symbol, segs[i].source + src_inc, segs[i].length - len_dec, segs[i].eci, + i + 1 == seg_count, gs1, target, &tp); if (error_number != 0) { return error_number; } @@ -1874,7 +1874,7 @@ static int dm_ecc200(struct zint_symbol *symbol, struct zint_seg segs[], const i dm_add_tail(binary, binlen, taillength); } if (debug_print) { - printf("Pads (%d): ", taillength); + printf("HxW: %dx%d\nPads (%d): ", H, W, taillength); for (i = binlen; i < binlen + taillength; i++) printf("%d ", binary[i]); fputc('\n', stdout); } diff --git a/backend/dxfilmedge.c b/backend/dxfilmedge.c new file mode 100644 index 00000000..868d6f89 --- /dev/null +++ b/backend/dxfilmedge.c @@ -0,0 +1,344 @@ +/* dxfilmedge.c - Handles DX Film Edge symbology */ +/* + libzint - the open source barcode library + Copyright (C) 2024-2025 Antoine Merino + + 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* DX Film Edge Barcode is used on 35mm and APS films: + * https://en.wikipedia.org/wiki/DX_encoding + * + * A little information about decoding this symbology can be found at + * https://www.merinorus.com/blog/identifying-manufacturer-35-mm-films/ + * + * Partial specification and history can be found on this Kodak patent: + * https://patents.google.com/patent/US4965628A/en + */ + +#include +#include +#include "common.h" + +#define DX_DEBUG_STR_LEN 20 +/* Max length of the DX info part. Eg: "018500", "150-10" */ +#define DX_MAX_DX_INFO_LENGTH 6 +#define DX_MAX_DX_INFO_MAX_STR "6" /* String version of above */ +/* Max length of the frame info part. Eg: "00A", "23A" */ +#define DX_MAX_FRAME_INFO_LENGTH 3 +#define DX_MAX_FRAME_INFO_MAX_STR "3" /* String version of above */ + +static void dx_int_to_binary(const int value, const int width, char *output) { + int i; + for (i = 0; i < width; i++) { + output[width - 1 - i] = (value & (1 << i)) ? '1' : '0'; + } + output[width] = '\0'; +} + +static int dx_parse_code(struct zint_symbol *symbol, const unsigned char *source, const int length, + char *binary_output, int *output_length, int *has_frame_info) { + int i; + int parity_bit = 0; + int dx_extract = -1, dx_code_1 = -1, dx_code_2 = -1, frame_number = -1; + char binary_dx_code_1[8], binary_dx_code_2[5], binary_frame_number[7]; + char half_frame_flag = '\0'; + char dx_info[DX_MAX_DX_INFO_LENGTH + 1] = "\0"; + char frame_info[DX_MAX_FRAME_INFO_LENGTH + 1] = "\0"; + int dx_length; + const char *frame_start; + const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; + + *has_frame_info = 0; + + /* All codes should start with a digit*/ + if (!z_isdigit(source[0])) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 970, + "Invalid first character \"%c\", DX code should start with a number", source[0]); + } + + /* Check if there is the '/' separator, which indicates the frame number is present. */ + dx_length = posn((const char *) source, '/'); + if (dx_length != -1) { + /* Split the DX information from the frame number */ + int frame_info_len; + if (dx_length > DX_MAX_DX_INFO_LENGTH) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 971, + "DX information length %d too long (maximum " DX_MAX_DX_INFO_MAX_STR ")", dx_length); + } + ustrncat(dx_info, source, dx_length); + dx_info[dx_length] = '\0'; + frame_start = (const char *) source + dx_length + 1; + frame_info_len = (int) strlen(frame_start); + if (frame_info_len > DX_MAX_FRAME_INFO_LENGTH) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 972, + "Frame number part length %d too long (maximum " DX_MAX_FRAME_INFO_MAX_STR ")", frame_info_len); + } + ustrcpy(frame_info, frame_start); + *has_frame_info = 1; + to_upper((unsigned char *) frame_info, frame_info_len); + if (not_sane(IS_UPR_F | IS_NUM_F | IS_MNS_F, (const unsigned char *) frame_info, frame_info_len)) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 973, + "Frame number \"%s\" is invalid (expected digits, optionally followed by a single \"A\")", + frame_info); + } + } else { + /* No "/" found, store the entire input in dx_info */ + dx_length = length; + if (dx_length > DX_MAX_DX_INFO_LENGTH) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 974, + "DX information length %d too long (maximum " DX_MAX_DX_INFO_MAX_STR ")", dx_length); + } + ustrcpy(dx_info, source); + } + + if ((i = not_sane(IS_NUM_F | IS_MNS_F, (const unsigned char *) dx_info, dx_length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 975, + "Invalid character at position %d in DX info (digits and \"-\" character only)", i); + } + + if (debug_print) printf("\nDX info part: \"%s\", Frame info part: \"%s\"\n", dx_info, frame_info); + /* Parse the DX information */ + if (strchr(dx_info, '-')) { + /* DX code parts 1 and 2 are given directly, separated by a '-'. Eg: "79-7" */ + if (debug_print) printf("DX code 1 and 2 are separated by a dash \"-\"\n"); + if (chr_cnt((const unsigned char *) dx_info, dx_length, '-') > 1) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 976, + "The \"-\" is used to separate DX parts 1 and 2, and should be used no more than once"); + } + if (sscanf(dx_info, "%d-%d", &dx_code_1, &dx_code_2) < 2) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 977, + "Wrong format for DX parts 1 and 2 (expected format: NNN-NN, digits)"); + } + if (dx_code_1 <= 0 || dx_code_1 > 127) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 978, "DX part 1 \"%d\" out of range (1 to 127)", + dx_code_1); + } + if (dx_code_2 < 0 || dx_code_2 > 15) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 979, "DX part 2 \"%d\" out of range (0 to 15)", + dx_code_2); + } + } else { + /* DX format is either 4 digits (DX Extract, eg: 1271) or 6 digits (DX Full, eg: 012710) */ + if (debug_print) printf("No \"-\" separator, computing from DX Extract (4 digits) or DX Full (6 digits)\n"); + if (dx_length == 5 || dx_length > 6) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 980, + "DX number \"%s\" is incorrect; expected 4 digits (DX extract) or 6 digits (DX full)", dx_info); + } + if (dx_length == 6) { + if (debug_print) { + printf("DX full format detected: %s. Removing the first and the last characters.\n", dx_info); + } + /* Convert DX Full to DX Extract (remove first and last character) */ + for (i = 0; i <= 3; ++i) { + dx_info[i] = dx_info[i + 1]; + } + dx_info[4] = '\0'; + dx_length = 4; + } + /* Compute the DX parts 1 and 2 from the DX extract */ + dx_extract = to_int((const unsigned char *) dx_info, dx_length); + assert(dx_extract != -1); + if (dx_extract < 16 || dx_extract > 2047) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 981, "DX extract \"%d\" out of range (16 to 2047)", + dx_extract); + } + if (debug_print) printf("Computed DX extract: %04d\n", dx_extract); + dx_code_1 = dx_extract / 16; + dx_code_2 = dx_extract % 16; + } + + /* Convert components to binary strings */ + dx_int_to_binary(dx_code_1, 7, binary_dx_code_1); + dx_int_to_binary(dx_code_2, 4, binary_dx_code_2); + + if (debug_print) { + printf("%-*s%d\t-> %s\n", DX_DEBUG_STR_LEN, "DX code 1:", dx_code_1, binary_dx_code_1); + printf("%-*s%d\t-> %s\n", DX_DEBUG_STR_LEN, "DX code 2:", dx_code_2, binary_dx_code_2); + } + + if (*has_frame_info) { + int ret_sscanf, n; + if (strlen(frame_info) < 1) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 982, + "Frame number indicator \"/\" at position %d, but frame number is empty", + dx_length + 1); + } + /* Some frame numbers are special values, convert them their equivalent number */ + if (strcmp(frame_info, "S") == 0 || strcmp(frame_info, "X") == 0) { + strcpy(frame_info, "62"); + } else if (strcmp(frame_info, "SA") == 0 || strcmp(frame_info, "XA") == 0) { + strcpy(frame_info, "62A"); + } else if (strcmp(frame_info, "K") == 0 || strcmp(frame_info, "00") == 0) { + strcpy(frame_info, "63"); + } else if (strcmp(frame_info, "KA") == 0 || strcmp(frame_info, "00A") == 0) { + strcpy(frame_info, "63A"); + } else if (strcmp(frame_info, "F") == 0) { + strcpy(frame_info, "0"); + } else if (strcmp(frame_info, "FA") == 0) { + strcpy(frame_info, "0A"); + } + + ret_sscanf = sscanf(frame_info, "%d%c%n", &frame_number, &half_frame_flag, &n); + if (ret_sscanf < 1 || (ret_sscanf == 2 && frame_info[n] != '\0')) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 983, + "Frame number \"%s\" is invalid (expected digits, optionally followed by a single \"A\")", + frame_info); + } + if (frame_number < 0 || frame_number > 63) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 984, "Frame number \"%d\" out of range (0 to 63)", + frame_number); + } + dx_int_to_binary(frame_number, 6, binary_frame_number); + if (debug_print) { + printf("%-*s%d\t-> %s\n", DX_DEBUG_STR_LEN, "Frame number:", frame_number, binary_frame_number); + } + } + + /* Build the binary output */ + strcpy(binary_output, "101010"); /* Start pattern */ + strcat(binary_output, binary_dx_code_1); + strcat(binary_output, "0"); /* Separator between DX part 1 and DX part 2 */ + strcat(binary_output, binary_dx_code_2); + if (*has_frame_info) { + strcat(binary_output, binary_frame_number); + to_upper((unsigned char *) &half_frame_flag, 1); + if (half_frame_flag == 'A') { + if (debug_print) printf("%-*s'%c'\t-> 1\n", DX_DEBUG_STR_LEN, "Half frame flag:", half_frame_flag); + strcat(binary_output, "1"); /* Half-frame is set */ + } else { + if (half_frame_flag) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 985, + "Frame number \"%s\" is invalid (expected digits, optionally followed by a single \"A\")", + frame_info); + } + if (debug_print) printf("%-*s'%c'\t-> 0\n", DX_DEBUG_STR_LEN, "Half frame flag:", half_frame_flag); + strcat(binary_output, "0"); /* Half-frame is NOT set */ + } + strcat(binary_output, "0"); /* Separator between half frame flag and parity bit*/ + } + + /* Parity bit */ + for (i = 6; binary_output[i] != '\0'; i++) { + if (binary_output[i] == '1') { + parity_bit++; + } + } + parity_bit %= 2; + if (debug_print) { + printf("%-*s%s\t-> %d\n", DX_DEBUG_STR_LEN, "Parity bit:", parity_bit ? "yes" : "no", parity_bit); + } + if (parity_bit) { + strcat(binary_output, "1"); + } else { + strcat(binary_output, "0"); + } + + strcat(binary_output, "0101"); /* Stop pattern */ + + *output_length = (int) strlen(binary_output); + return 0; +} + +INTERNAL int dxfilmedge(struct zint_symbol *symbol, unsigned char source[], int length) { + int i; + int writer = 0; + int error_number = 0; + + char char_data[32]; + int data_length; + int has_frame_info; + + const char long_clock_pattern[] = "1111101010101010101010101010111"; + const char short_clock_pattern[] = "11111010101010101010111"; + const char *clock_pattern; + int clock_length; + int parse_result = -1; + const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; + + if (length > 10) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 986, "Input length %d too long (maximum 10)", length); + } + + parse_result = dx_parse_code(symbol, source, length, char_data, &data_length, &has_frame_info); + if (parse_result != 0) { + if (debug_print) printf("Error %s\n\n", symbol->errtxt); + return parse_result; + } + + /* Clock signal is longer if the frame number is provided */ + if (has_frame_info) { + clock_pattern = long_clock_pattern; + clock_length = sizeof(long_clock_pattern) -1; + } else { + clock_pattern = short_clock_pattern; + clock_length = sizeof(short_clock_pattern) -1; + } + + /* First row: clock pattern */ + for (i = 0; i < clock_length; i++) { + if (clock_pattern[i] == '1') { + set_module(symbol, 0, writer); + } else if (clock_pattern[i] == '0') { + unset_module(symbol, 0, writer); + } + writer++; + } + + /* Reset writer X position for the second row */ + writer = 0; + + /* Second row: data signal */ + for (i = 0; i < clock_length; i++) { + if (char_data[i] == '1') { + set_module(symbol, 1, writer); + } else if (char_data[i] == '0') { + unset_module(symbol, 1, writer); + } + writer++; + } + symbol->rows = 2; + symbol->width = clock_length; + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* Measured ratio on 35mm films. Depending on the brands, one symbol height is about 3 * the X-dim.*/ + const float default_height = 6.0f; + + /* AFAIK There is no standard on minimum and maximum height, so we stay close to the measurements */ + const float min_row_height = 2.2f; + const float max_height = 7.5f; + error_number = set_height(symbol, min_row_height, default_height, max_height, 0 /*no_errtxt*/); + } else { + /* Using compliant height as default as no backwards compatibility to consider */ + const float default_height = 6.0f; + (void) set_height(symbol, 0.0f, default_height, 0.0f, 1 /*no_errtxt*/); + } + + return error_number; +} + +/* vim: set ts=4 sw=4 et : */ diff --git a/backend/filemem.c b/backend/filemem.c index 0ea982f1..7b752cb6 100644 --- a/backend/filemem.c +++ b/backend/filemem.c @@ -1,7 +1,7 @@ /* filemem.c - write to file/memory abstraction */ /* libzint - the open source barcode library - Copyright (C) 2023-2024 Robin Stuart + Copyright (C) 2023-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -34,7 +34,7 @@ #include #include #include -#ifdef _MSC_VER +#ifdef _WIN32 #include #include #endif @@ -117,7 +117,7 @@ INTERNAL int fm_open(struct filemem *restrict const fmp, struct zint_symbol *sym return 1; } if (fmp->flags & BARCODE_STDOUT) { -#ifdef _MSC_VER +#ifdef _WIN32 if (strchr(mode, 'b') != NULL && _setmode(_fileno(stdout), _O_BINARY) == -1) { return fm_seterr(fmp, errno); } diff --git a/backend/library.c b/backend/library.c index de0bc1ff..e9bdb057 100644 --- a/backend/library.c +++ b/backend/library.c @@ -235,6 +235,7 @@ INTERNAL int ultra(struct zint_symbol *symbol, struct zint_seg segs[], const int INTERNAL int rmqr(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* rMQR */ INTERNAL int dpd(struct zint_symbol *symbol, unsigned char source[], int length); /* DPD Code */ INTERNAL int bc412(struct zint_symbol *symbol, unsigned char source[], int length); /* BC412 */ +INTERNAL int dxfilmedge(struct zint_symbol *symbol, unsigned char source[], int length); /* DX Film Edge Barcode */ /* Output handlers */ /* Plot to BMP/GIF/PCX/PNG/TIF */ @@ -512,6 +513,7 @@ static int has_hrt(const int symbology) { case BARCODE_FIM: case BARCODE_PHARMA: case BARCODE_PHARMA_TWO: + case BARCODE_DXFILMEDGE: case BARCODE_CEPNET: case BARCODE_PDF417: case BARCODE_PDF417COMP: @@ -580,7 +582,7 @@ static const barcode_src_func_t barcode_src_funcs[BARCODE_LAST + 1] = { composite, composite, composite, composite, composite, /*130-134*/ composite, composite, composite, composite, composite, /*135-139*/ channel, NULL, NULL, upnqr, NULL, /*140-144*/ - NULL, bc412, /*145-146*/ + NULL, bc412, dxfilmedge, /*145-147*/ }; #define LIB_SEG_FUNCS_START 55 @@ -1640,7 +1642,7 @@ int ZBarcode_BarcodeName(int symbol_id, char name[32]) { "EANX_CC", "GS1_128_CC", "DBAR_OMN_CC", "DBAR_LTD_CC", "DBAR_EXP_CC", /*130-134*/ "UPCA_CC", "UPCE_CC", "DBAR_STK_CC", "DBAR_OMNSTK_CC", "DBAR_EXPSTK_CC", /*135-139*/ "CHANNEL", "CODEONE", "GRIDMATRIX", "UPNQR", "ULTRA", /*140-144*/ - "RMQR", "BC412", /*145-146*/ + "RMQR", "BC412", "DXFILMEDGE", /*145-147*/ }; name[0] = '\0'; @@ -1867,7 +1869,10 @@ float ZBarcode_Default_Xdim(int symbol_id) { case BARCODE_DBAR_EXPSTK_CC: x_dim_mm = 0.33f; /* GS1 General Standards 22.0 Section 5.12.3 Table 1 except DBAR_LTD Table 4 */ break; - + case BARCODE_DXFILMEDGE: + /* Measured on Kodak 35mm film, a DX Film Edge with frame number with 31 symbols is 12,51 mm long */ + x_dim_mm = 0.403548f; + break; /* Specific */ case BARCODE_BC412: x_dim_mm = 0.12f; /* SEMI T1-95 Table 1 */ diff --git a/backend/medical.c b/backend/medical.c index 8f375c00..ebe5776c 100644 --- a/backend/medical.c +++ b/backend/medical.c @@ -1,7 +1,7 @@ -/* medical.c - Handles 1 track and 2 track pharmacode and Codabar */ +/* medical.c - Handles Pharmacode One-Track, Pharmacode Two-Track, Italian Pharmacode and PZN */ /* libzint - the open source barcode library - Copyright (C) 2008-2024 Robin Stuart + Copyright (C) 2008-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -35,20 +35,7 @@ INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int length); -static const char CALCIUM[] = "0123456789-$:/.+ABCD"; -#define CALCIUM_INNER_F (IS_NUM_F | IS_MNS_F | IS_CLI_F | IS_PLS_F) /* CALCIUM_INNER "0123456789-$:/.+" */ - -/* Codabar table checked against EN 798:1995 */ -static const char CodaTable[20][8] = { - {'1','1','1','1','1','2','2','1'}, {'1','1','1','1','2','2','1','1'}, {'1','1','1','2','1','1','2','1'}, - {'2','2','1','1','1','1','1','1'}, {'1','1','2','1','1','2','1','1'}, {'2','1','1','1','1','2','1','1'}, - {'1','2','1','1','1','1','2','1'}, {'1','2','1','1','2','1','1','1'}, {'1','2','2','1','1','1','1','1'}, - {'2','1','1','2','1','1','1','1'}, {'1','1','1','2','2','1','1','1'}, {'1','1','2','2','1','1','1','1'}, - {'2','1','1','1','2','1','2','1'}, {'2','1','2','1','1','1','2','1'}, {'2','1','2','1','2','1','1','1'}, - {'1','1','2','1','2','1','2','1'}, {'1','1','2','2','1','2','1','1'}, {'1','2','1','2','1','1','2','1'}, - {'1','1','1','2','1','2','2','1'}, {'1','1','1','2','2','2','1','1'} -}; - +/* Pharmacode One-Track */ INTERNAL int pharma(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 @@ -149,6 +136,7 @@ static int pharma_two_calc(int tester, char *d) { return h; } +/* Pharmacode Two-Track */ INTERNAL int pharma_two(struct zint_symbol *symbol, unsigned char source[], int length) { /* Draws the patterns for two track pharmacode */ int i; @@ -197,100 +185,6 @@ INTERNAL int pharma_two(struct zint_symbol *symbol, unsigned char source[], int 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 = 0; - int posns[103]; - char dest[833]; /* (103 + 1) * 8 + 1 == 833 */ - char *d = dest; - int add_checksum, count = 0, checksum = 0; - int d_chars = 0; - - if (length > 103) { /* No stack smashing please (103 + 1) * 11 = 1144 */ - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 356, "Input length %d too long (maximum 103)", length); - } - /* 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) { - return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 362, "Input length %d too short (minimum 3)", length); - } - to_upper(source, length); - - /* 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')) { - return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 358, "Does not begin with \"A\", \"B\", \"C\" or \"D\""); - } - if ((source[length - 1] != 'A') && (source[length - 1] != 'B') && - (source[length - 1] != 'C') && (source[length - 1] != 'D')) { - return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 359, "Does not end with \"A\", \"B\", \"C\" or \"D\""); - } - if ((i = not_sane_lookup(CALCIUM, sizeof(CALCIUM) - 1, source, length, posns))) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 357, - "Invalid character at position %1$d in input (\"%2$s\" only)", i, CALCIUM); - } - /* And must not use A, B, C or D otherwise (BS EN 798:1995 4.3.2) */ - if ((i = not_sane(CALCIUM_INNER_F, source + 1, length - 2))) { - return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 363, - "Invalid character at position %d in input (cannot contain \"A\", \"B\", \"C\" or \"D\")", i); - } - - /* Add check character: 1 don't show to HRT, 2 do show to HRT - (unfortunately to maintain back-compatibility, this is reverse of C25) */ - add_checksum = symbol->option_2 == 1 || symbol->option_2 == 2; - - for (i = 0; i < length; i++, d += 8) { - if (add_checksum) { - /* BS EN 798:1995 A.3 suggests using ISO 7064 algorithm but leaves it application defined. - Following BWIPP and TEC-IT, use this simple mod-16 algorithm (not in ISO 7064) */ - count += posns[i]; - 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 (%c)\n", source, count, checksum, CALCIUM[checksum]); - } - memcpy(d, CodaTable[checksum], 8); - d += 8; - } - } - memcpy(d, CodaTable[posns[i]], 8); - if (source[i] == '/' || source[i] == ':' || source[i] == '.' || source[i] == '+') { /* Wide data characters */ - d_chars++; - } - } - - expand(symbol, dest, d - dest); - - if (symbol->output_options & COMPLIANT_HEIGHT) { - /* BS EN 798:1995 4.4.1 (d) max of 5mm / 0.43mm (X max) ~ 11.628 or 15% of width where (taking N = - narrow/wide ratio as 2 and I = X) width = ((2 * N + 5) * C + (N – 1) * (D + 2)) * X + I * (C – 1) + 2Q - = ((4 + 5) * C + (D + 2) + C - 1 + 2 * 10) * X = (10 * C + D + 21) * X - Length (C) includes start/stop chars */ - const float min_height_min = 11.6279068f; /* 5.0 / 0.43 */ - float min_height = stripf((10.0f * ((add_checksum ? length + 1 : length) + 2.0f) + d_chars + 21.0f) * 0.15f); - if (min_height < min_height_min) { - min_height = min_height_min; - } - /* Using 50 as default as none recommended */ - error_number = set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, 0 /*no_errtxt*/); - } else { - (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); - } - - ustrcpy(symbol->text, source); - if (symbol->option_2 == 2) { - symbol->text[length - 1] = CALCIUM[checksum]; /* Place before final A/B/C/D character (BS EN 798:1995 A.3) */ - symbol->text[length] = source[length - 1]; - symbol->text[length + 1] = '\0'; - } - - return error_number; -} - /* Italian Pharmacode */ INTERNAL int code32(struct zint_symbol *symbol, unsigned char source[], int length) { static const char TABELLA[] = "0123456789BCDFGHJKLMNPQRSTUVWXYZ"; @@ -374,4 +268,89 @@ INTERNAL int code32(struct zint_symbol *symbol, unsigned char source[], int leng return error_number; } +/* Pharmazentralnummer (PZN) */ +/* 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 */ +INTERNAL int pzn(struct zint_symbol *symbol, unsigned char source[], int length) { + + int i, error_number, zeroes; + int count, check_digit; + unsigned char have_check_digit = '\0'; + char localstr[1 + 8 + 1]; /* '-' prefix + 8 digits + NUL */ + const int pzn7 = symbol->option_2 == 1; + + if (length > 8 - pzn7) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 325, "Input length %1$d too long (maximum %2$d)", length, + 8 - pzn7); + } + if (length == 8 - pzn7) { + have_check_digit = source[7 - pzn7]; + length--; + } + if ((i = not_sane(NEON_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 326, + "Invalid character at position %d in input (digits only)", i); + } + + localstr[0] = '-'; + zeroes = 7 - pzn7 - length + 1; + for (i = 1; i < zeroes; i++) + localstr[i] = '0'; + ustrcpy(localstr + zeroes, source); + + count = 0; + for (i = 1; i < 8 - pzn7; i++) { + count += (i + pzn7) * ctoi(localstr[i]); + } + + check_digit = count % 11; + + if (symbol->debug & ZINT_DEBUG_PRINT) { + printf("PZN: %s, check digit %d\n", localstr, (int) check_digit); + } + + if (check_digit == 10) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 327, "Invalid PZN, check digit is '10'"); + } + if (have_check_digit && ctoi(have_check_digit) != check_digit) { + return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 890, "Invalid check digit '%1$c', expecting '%2$c'", + have_check_digit, itoc(check_digit)); + } + + localstr[8 - pzn7] = itoc(check_digit); + localstr[9 - pzn7] = '\0'; + + if (pzn7) { + symbol->option_2 = 0; /* Need to overwrite this so `code39()` doesn't add a check digit itself */ + } + + error_number = code39(symbol, (unsigned char *) localstr, 9 - pzn7); + + if (pzn7) { + symbol->option_2 = 1; /* Restore */ + } + + ustrcpy(symbol->text, "PZN - "); /* Note changed to put space after hyphen */ + ustrcat(symbol->text, localstr + 1); + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* Technical Information regarding PZN Coding V 2.1 (25 Feb 2019) Code size + https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/IFA_Info_Code_39_EN.pdf + "normal" X 0.25mm (0.187mm - 0.45mm), height 8mm - 20mm for 0.25mm X, 10mm mentioned so use that + as default, 10mm / 0.25mm = 40 */ + if (error_number < ZINT_ERROR) { + const float min_height = 17.7777786f; /* 8.0 / 0.45 */ + const float max_height = 106.951874f; /* 20.0 / 0.187 */ + error_number = set_height(symbol, min_height, 40.0f, max_height, 0 /*no_errtxt*/); + } + } else { + if (error_number < ZINT_ERROR) { + (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); + } + } + + return error_number; +} + /* vim: set ts=4 sw=4 et : */ diff --git a/backend/output.c b/backend/output.c index e6f5ed9a..03ec7eda 100644 --- a/backend/output.c +++ b/backend/output.c @@ -360,6 +360,12 @@ static int out_quiet_zones(const struct zint_symbol *symbol, const int hide_text *left = *right = 10.0f; done = 1; break; + + case BARCODE_DXFILMEDGE: + /* No known standard. Add a little horizontal space to make the detection easier. Tested with Zxing-CPP */ + *left = *right = 1.8f; + done = 1; + break; case BARCODE_C25INTER: /* ISO/IEC 16390:2007 Section 4.4 10X */ diff --git a/backend/tests/CMakeLists.txt b/backend/tests/CMakeLists.txt index 7a165f72..42a8ba62 100644 --- a/backend/tests/CMakeLists.txt +++ b/backend/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2009-2024 Robin Stuart +# Copyright (C) 2009-2025 Robin Stuart # Adapted from qrencode/tests/CMakeLists.txt # Copyright (C) 2006-2017 Kentaro Fukuchi # vim: set ts=4 sw=4 et : @@ -46,9 +46,11 @@ zint_add_test(bc412 test_bc412) zint_add_test(big5 test_big5) zint_add_test(bmp test_bmp) zint_add_test(channel test_channel) +zint_add_test(codabar test_codabar) zint_add_test(codablock test_codablock) zint_add_test(code test_code) zint_add_test(code1 test_code1) +zint_add_test(code11 test_code11) zint_add_test(code128 test_code128) zint_add_test(code16k test_code16k) zint_add_test(code49 test_code49) @@ -56,6 +58,7 @@ zint_add_test(common test_common) zint_add_test(composite test_composite) zint_add_test(dmatrix test_dmatrix) zint_add_test(dotcode test_dotcode) +zint_add_test(dxfilmedge test_dxfilmedge) zint_add_test(eci test_eci) zint_add_test(emf test_emf) zint_add_test(filemem test_filemem) diff --git a/backend/tests/test_codabar.c b/backend/tests/test_codabar.c new file mode 100644 index 00000000..4db07cf0 --- /dev/null +++ b/backend/tests/test_codabar.c @@ -0,0 +1,326 @@ +/* + libzint - the open source barcode library + Copyright (C) 2020-2025 Robin 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* Was in "test_medical.c */ + +#include "testcommon.h" + +static void test_large(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + int option_2; + char *pattern; + int length; + int ret; + int expected_rows; + int expected_width; + }; + /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ + static const struct item data[] = { + /* 0*/ { BARCODE_CODABAR, -1, "A+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++B", 103, 0, 1, 1133 }, + /* 1*/ { BARCODE_CODABAR, -1, "A++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++B", 104, ZINT_ERROR_TOO_LONG, -1, -1 }, + /* 2*/ { BARCODE_CODABAR, 1, "A+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++B", 103, 0, 1, 1143 }, + /* 3*/ { BARCODE_CODABAR, 1, "A++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++B", 104, ZINT_ERROR_TOO_LONG, -1, -1 }, + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol = NULL; + + char data_buf[128]; + + testStartSymbol("test_large", &symbol); + + for (i = 0; i < data_size; i++) { + + if (testContinue(p_ctx, i)) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + testUtilStrCpyRepeat(data_buf, data[i].pattern, data[i].length); + assert_equal(data[i].length, (int) strlen(data_buf), "i:%d length %d != strlen(data_buf) %d\n", i, data[i].length, (int) strlen(data_buf)); + + length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, data[i].option_2, -1, -1 /*output_options*/, data_buf, data[i].length, debug); + + ret = ZBarcode_Encode(symbol, (unsigned char *) data_buf, length); + assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + + if (ret < ZINT_ERROR) { + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d\n", i, symbol->rows, data[i].expected_rows); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d\n", i, symbol->width, data[i].expected_width); + } + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +static void test_hrt(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + int option_2; + char *data; + + char *expected; + }; + /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ + static const struct item data[] = { + /* 0*/ { BARCODE_CODABAR, -1, "A1234B", "A1234B" }, + /* 1*/ { BARCODE_CODABAR, -1, "a1234c", "A1234C" }, /* Converts to upper */ + /* 2*/ { BARCODE_CODABAR, 1, "A1234B", "A1234B" }, /* Check not included */ + /* 3*/ { BARCODE_CODABAR, 2, "A1234B", "A12345B" }, /* Check included */ + /* 4*/ { BARCODE_CODABAR, 1, "A123456A", "A123456A" }, /* Check not included */ + /* 5*/ { BARCODE_CODABAR, 2, "A123456A", "A123456$A" }, /* Check included */ + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol = NULL; + + testStartSymbol("test_hrt", &symbol); + + for (i = 0; i < data_size; i++) { + + if (testContinue(p_ctx, i)) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, data[i].option_2, -1, -1 /*output_options*/, data[i].data, -1, debug); + + ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); + assert_zero(ret, "i:%d ZBarcode_Encode ret %d != 0 %s\n", i, ret, symbol->errtxt); + + assert_zero(strcmp((char *) symbol->text, data[i].expected), "i:%d strcmp(%s, %s) != 0\n", i, symbol->text, data[i].expected); + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +static void test_input(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + char *data; + int ret; + int expected_rows; + int expected_width; + const char *expected_errtxt; + int bwipp_cmp; + const char *comment; + }; + /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ + static const struct item data[] = { + /* 0*/ { BARCODE_CODABAR, "A1234B", 0, 1, 62, "", 1, "" }, + /* 1*/ { BARCODE_CODABAR, "1234B", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 358: Does not begin with \"A\", \"B\", \"C\" or \"D\"", 1, "" }, + /* 2*/ { BARCODE_CODABAR, "A1234", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 359: Does not end with \"A\", \"B\", \"C\" or \"D\"", 1, "" }, + /* 3*/ { BARCODE_CODABAR, "A1234E", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 359: Does not end with \"A\", \"B\", \"C\" or \"D\"", 1, "" }, + /* 4*/ { BARCODE_CODABAR, "C123.D", 0, 1, 63, "", 1, "" }, + /* 5*/ { BARCODE_CODABAR, "C123,D", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 357: Invalid character at position 5 in input (\"0123456789-$:/.+ABCD\" only)", 1, "" }, + /* 6*/ { BARCODE_CODABAR, "D:C", 0, 1, 33, "", 1, "" }, + /* 7*/ { BARCODE_CODABAR, "DCC", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 363: Invalid character at position 1 in input (cannot contain \"A\", \"B\", \"C\" or \"D\")", 1, "" }, + /* 8*/ { BARCODE_CODABAR, "A234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123B", ZINT_ERROR_TOO_LONG, -1, -1, "Error 356: Input length 104 too long (maximum 103)", 1, "" }, + /* 9*/ { BARCODE_CODABAR, "AB", ZINT_ERROR_TOO_LONG, -1, -1, "Error 362: Input length 2 too short (minimum 3)", 1, "" }, + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol = NULL; + + char cmp_buf[8192]; + char cmp_msg[1024]; + + int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ + + testStartSymbol("test_input", &symbol); + + for (i = 0; i < data_size; i++) { + + if (testContinue(p_ctx, i)) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, -1, -1, -1 /*output_options*/, data[i].data, -1, debug); + + ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); + assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + assert_zero(strcmp(symbol->errtxt, data[i].expected_errtxt), "i:%d symbol->errtxt %s != %s\n", i, symbol->errtxt, data[i].expected_errtxt); + + if (ret < ZINT_ERROR) { + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d\n", i, symbol->rows, data[i].expected_rows); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d\n", i, symbol->width, data[i].expected_width); + + if (do_bwipp && testUtilCanBwipp(i, symbol, -1, -1, -1, debug)) { + if (!data[i].bwipp_cmp) { + if (debug & ZINT_DEBUG_TEST_PRINT) printf("i:%d %s not BWIPP compatible (%s)\n", i, testUtilBarcodeName(symbol->symbology), data[i].comment); + } else { + char modules_dump[4096]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilBwipp(i, symbol, -1, -1, -1, data[i].data, length, NULL, cmp_buf, sizeof(cmp_buf), NULL); + assert_zero(ret, "i:%d %s testUtilBwipp ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilBwippCmp(symbol, cmp_msg, cmp_buf, modules_dump); + assert_zero(ret, "i:%d %s testUtilBwippCmp %d != 0 %s\n actual: %s\nexpected: %s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_buf, modules_dump); + } + } + } + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +static void test_encode(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + int option_2; + char *data; + int ret; + + int expected_rows; + int expected_width; + char *comment; + char *expected; + }; + static const struct item data[] = { + /* 0*/ { BARCODE_CODABAR, -1, "A37859B", 0, 1, 72, "BS EN 798:1995 Figure 1", + "101100100101100101010100101101010011010101101010010110100101010010010110" + }, + /* 1*/ { BARCODE_CODABAR, -1, "A0123456789-$:/.+D", 0, 1, 186, "Verified manually against tec-it", + "101100100101010100110101011001010100101101100101010101101001011010100101001010110100101101010011010101101001010101001101010110010101101011011011011010110110110110101011011011010100110010" + }, + /* 2*/ { BARCODE_CODABAR, 1, "A1B", 0, 1, 43, "Verified manually against tec-it", + "1011001001010101100101101101101010010010110" + }, + /* 3*/ { BARCODE_CODABAR, 1, "A+B", 0, 1, 43, "Verified manually against tec-it", + "1011001001010110110110101010011010010010110" + }, + /* 4*/ { BARCODE_CODABAR, 1, "B0123456789-$:/.+B", 0, 1, 196, "Verified manually against tec-it", + "1001001011010101001101010110010101001011011001010101011010010110101001010010101101001011010100110101011010010101010011010101100101011010110110110110101101101101101010110110110100101011010010010110" + }, + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol = NULL; + + char escaped[1024]; + char cmp_buf[8192]; + char cmp_msg[1024]; + + int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ + int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder(); /* Only do ZXing-C++ test if asked, too slow otherwise */ + + testStartSymbol("test_encode", &symbol); + + for (i = 0; i < data_size; i++) { + + if (testContinue(p_ctx, i)) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, data[i].option_2, -1, -1 /*output_options*/, data[i].data, -1, debug); + + ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); + assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + + if (p_ctx->generate) { + printf(" /*%3d*/ { %s, %d, \"%s\", %s, %d, %d, \"%s\",\n", + i, testUtilBarcodeName(data[i].symbology), data[i].option_2, testUtilEscape(data[i].data, length, escaped, sizeof(escaped)), + testUtilErrorName(data[i].ret), symbol->rows, symbol->width, data[i].comment); + testUtilModulesPrint(symbol, " ", "\n"); + printf(" },\n"); + } else { + if (ret < ZINT_ERROR) { + int width, row; + + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d (%s)\n", i, symbol->rows, data[i].expected_rows, data[i].data); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", i, symbol->width, data[i].expected_width, data[i].data); + + ret = testUtilModulesCmp(symbol, data[i].expected, &width, &row); + assert_zero(ret, "i:%d testUtilModulesCmp ret %d != 0 width %d row %d (%s)\n", i, ret, width, row, data[i].data); + + if (do_bwipp && testUtilCanBwipp(i, symbol, -1, data[i].option_2, -1, debug)) { + ret = testUtilBwipp(i, symbol, -1, data[i].option_2, -1, data[i].data, length, NULL, cmp_buf, sizeof(cmp_buf), NULL); + assert_zero(ret, "i:%d %s testUtilBwipp ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilBwippCmp(symbol, cmp_msg, cmp_buf, data[i].expected); + assert_zero(ret, "i:%d %s testUtilBwippCmp %d != 0 %s\n actual: %s\nexpected: %s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_buf, data[i].expected); + } + if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data[i].data, length, debug)) { + int cmp_len, ret_len; + char modules_dump[8192 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, cmp_buf, sizeof(cmp_buf), &cmp_len); + assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length, NULL /*primary*/, escaped, &ret_len); + assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len, escaped); + } + } + } + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +int main(int argc, char *argv[]) { + + testFunction funcs[] = { /* name, func */ + { "test_large", test_large }, + { "test_hrt", test_hrt }, + { "test_input", test_input }, + { "test_encode", test_encode }, + }; + + testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); + + testReport(); + + return 0; +} + +/* vim: set ts=4 sw=4 et : */ diff --git a/backend/tests/test_codablock.c b/backend/tests/test_codablock.c index 6fe1be09..06464e0a 100644 --- a/backend/tests/test_codablock.c +++ b/backend/tests/test_codablock.c @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2019-2024 Robin Stuart + Copyright (C) 2019-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -332,8 +332,14 @@ static void test_input(const testCtx *const p_ctx) { /* 42*/ { BARCODE_CODABLOCKF, UNICODE_MODE, -1, -1, "ÿ12345678\012à12345678abcdef\0121\01223456\012\0127890àAàBCDEFà\012\012à", -1, 0, 8, 134, 0, "(96) 67 64 46 64 5F 63 0C 22 38 4E 5E 6A 67 62 0B 4A 64 64 40 63 0C 22 2B 6A 67 63 2C 38", "BWIPP different encoding (CodeB before FNC4 instead of after)" }, /* 43*/ { BARCODE_CODABLOCKF, UNICODE_MODE, -1, -1, "123456789012345ABCDEFGHI\012123456ÿ12345678\012à12345678abcdef\012\012123456\012\0127890àABCDEFà\012\012ààGHIJKàLMNOPQabc\012defà1234567ghijk\012\012à901234\012\012\012\012567890àààààààABCDEFGààà\012\012\012HIJK\012\012\012\012à\012à\012à\01212345à\012à\012à67890ààÄ9012ÄÄ56789Ä12Ä3\0124\0125\0126A\012a\012A\012A\012a\012a\012BCD1A2B3C4a5b6c7d8e9\0120\0121\0122\0123Ä4Ä5Ä6A7a8A9a0\012Ä12345678ÄÄÄÄÄÄÄÄÄÄÄ2ÄÄÄÄÄÄÄÄ4ÄÄÄÄÄÄAÄÄÄÄÄÄaÄÄÄÄÄÄé1é2é34é56Ä78é9éAéBéCéééééaébécé123456789012345ABCDEFGHI\012123456ÿ12345678\012à12345678abcdef\012\012123456\012\0127890àABCDEFà\012\012ààGHIJKàLMNOPQabc\012defà1234567ghijk\012\012à901234\012\012\012\012567890àààààààABCDEFGààà\012\012\012HIJK\012\012\012\012à\012à\012à\01212345à\012à\012à67890ààÄ9012ÄÄ56789Ä12Ä3\0124\0125\0126A\012a\012A\012A\012a\012a\012BCD1A2B3C4a5b6c7d8e9\0120\0121\0122\0123Ä4Ä5Ä6A7a8A9a0\012Ä12345678ÄÄÄÄÄÄÄÄÄÄÄ2ÄÄÄÄÄÄÄÄ4ÄÄÄÄÄÄAÄÄÄÄÄÄaÄÄÄÄÄÄé1é2é34é56Ä78é9éAéBéCéééééaébécé12345123456789012345ABCDEFGHI\012123456ÿ12345678\012à12345678abcdef\012\012123456\012\0127890àABCDEFà\012\012ààGHIJKàLMNOPQabc\012defà1234567ghijk\012\012à901234\012\012\012\012567890àààààààABCDEFGààà\012\012\012HIJK\012\012\012\012à\012à\012à\01212345à\012à\012à67890ààÄ9012ÄÄ56789Ä12Ä3\0124\0125\0126A\012a\012A\012A\012a\012a\012BCD1A2B3C4a5b6c7d8e9\0120\0121\0122\0123Ä4Ä5Ä6A7a8A9a0\012Ä12345678ÄÄÄÄÄÄÄÄÄÄÄ2ÄÄÄÄÄÄÄÄ4ÄÄÄÄÄÄAÄÄÄÄÄÄaÄÄÄÄÄÄé1é2é34é56Ä78é9éAéBéCéééééaébécé123456789012345ABCDEFGHI\012123456ÿ12345678\012à12345678abcdef\012\012123456\012\0127890àABCDEFà\012\012ààGHIJKàLMNOPQabc\012defà1234567ghijk\012\012à901234\012\012\012\012567890àààààààABCDEFGààà\012\012\012HIJK\012\012\012\012à\012à\012à\01212345à\012à\012à67890ààÄ9012ÄÄ56789Ä12Ä3\0124\0125\0126A\012a\012A\012A\012a\012a\012BCD1A2" "B3C4a5b6c7d8e9\0120\0121\0122\0123Ä4Ä5Ä6A7a8A9a0\012Ä12345678ÄÄÄÄÄÄÄÄÄÄÄ2ÄÄÄÄÄÄÄÄ4ÄÄÄÄÄÄAÄÄÄÄÄÄaÄÄÄÄÄÄé1é2é34é56Ä78é9éAéBéCéééééaébécé6789012345ABCDEFGHI\012123456ÿ12345678\012à12345678abcdef\012\012123456\012\0127890àABCDEFà\012\012ààGHIJKàLMNOPQabc\012defà1234567ghijk\012\012à901234\012\012\012\012567890àààààààABCDEFGààà\012\012\012HIJK\012\012\012\012à\012à\012à\01212345à\012à\012à67890ààÄ9012ÄÄ56789Ä12Ä3\0124\0125\0126A\012a\012A\012A\012a\012a\012BCD1A2B3C4a5b6c7d8e9\0120\0121\0122\0123Ä4Ä5Ä6A7a8A9a0\012Ä12345678ÄÄÄÄÄÄÄÄÄÄÄ2ÄÄÄÄÄÄÄÄ4ÄÄÄÄÄÄAÄÄÄÄÄÄaÄÄÄÄÄÄé1é2é34é56Ä78é9éAéBéCéééééaébécé123456789012345ABCDEFGHI\012123456ÿ12345678\012à12345678abcdef\012\012123456\012\0127890àABCDEFà\012\012ààGHIJKàLMNOPQabc\012defà1234567ghijk\012\012à901234\012\012\012\012567890àààààààABCDEFGààà\012\012\012HIJK\012\012\012\012à\012à\012à\012123456à\012à\012à\0123Ä4Ä5Ä6AÄ56789Ä12Ä3\0124\0125\0126A\012a\012A\012A\012a\012a\012BCD1A2B3C4a5b6c7d8e9\0120\0121\0122\0123Ä4Ä5Ä6A7a8A9a0\012Ä12345678ÄÄÄÄÄé1é2é34é56Ä78é9éAéBéCéééééaébécéÄÄÄÄÄÄ2ÄÄÄÄÄÄÄÄ4ÄÄÄé1é2é34é56Ä78é9éAéBéCéééééaébécéÄÄÄAÄÄÄÄÄÄaÄÄÄÄÄÄé1é2é34é56Ä78é9éAéBéCéééééaébécé", -1, 0, 44, 739, 0, "(2948) 67 63 2A 0C 22 38 4E 5A 0C 22 65 15 21 22 23 24 25 26 27 28 29 4A 63 0C 22 38 64", "BWIPP gs command too long" }, /* 44*/ { BARCODE_CODABLOCKF, UNICODE_MODE, -1, -1, "ÿ12345678\012à12345678abcdef\012\012123456\012\0127890àABCDEFà\012\012ààGHIJKàLMNOPQabc\012defà1234567ghijk\012\012à901234\012\012\012\012567890ààààABCDEFGààà\012\012\012HIJK\012\012\012\012à\012à\012à\01212345à\012à\012à67890ààÄ9012ÄÄ56789Ä12Ä3\0124\0125\0126A\012a\012A\012A\012a\012a\012BCD1A2B3C4a5b6c7d8e9\0120\0121\0122\0123Ä4Ä5Ä6A7a8A9a0\012Ä12345678ÄÄÄÄÄÄ2ÄÄÄÄÄÄ4ÄÄÄÄÄÄaÄÄÄÄé1é2é34é56Ä78é9éAéBéCéééééaébécé123456789012345ABCDEFGHI\012123456ÿ12345678\012à12345678abcdef\012123456\012\0127890àABCDEFà\012\012ààGHIJKàLMNOPQabc\012defà1234567ghijk\012\012à901234\0122567890àààààABCDEFGààà\012\012\012HIJK\012\012\0122à\012à\012à\01212345à\012à\012à67890ààÄ9012ÄÄ56789Ä12Ä3\0124\0125\0126A\012a\012A\012A\012a\012a\012BCD1A2B3C4a5b6c7d8e9\0120\0121\0122\0123Ä4Ä5Ä6A7a8A9a0\012Ä12345678ÄÄ2Ä4ÄaÄé1é2é34é56Ä78é9éAéBéCééaébécé123456789012345ABCDEF\012123456ÿ123456\012à12345678abcdef\012\0121234\012\0127890àABCDà\012\012ààGHIJKàLMabc\012defà1234567ghijk\012\012à901234\012\012\012\012567890ààABCDEFGààà\012\012\012HIJK\012\012\012\012à\012à\012à\01212345à\012à\012à67890ààÄ9012ÄÄ56789Ä12Ä3\0124\0125\0126A\012a\012A\012A\012a\012a\012BCD1A2", -1, 0, 33, 387, 0, "(1155) 67 64 5F 64 5F 63 0C 22 38 4E 65 4A 64 64 40 63 0C 22 38 4E 64 41 42 43 44 45 46", "BWIPP different encodation" }, - /* 45*/ { BARCODE_HIBC_BLOCKF, UNICODE_MODE, -1, -1, "A99912345/$$52001510X3", -1, 0, 6, 101, 1, "(54) 67 64 44 0B 21 19 19 3A 6A 67 63 2B 5B 17 2D 64 24 6A 67 64 0C 0F 04 04 15 16 6A 67", "" }, - /* 46*/ { BARCODE_HIBC_BLOCKF, UNICODE_MODE, -1, -1, "A99912345/$$520:1510X3", -1, ZINT_ERROR_INVALID_DATA, -1, -1, 1, "Error 203: Invalid character at position 16 in input (alphanumerics, space and \"-.$/+%\" only)", "" }, + /* 45*/ { BARCODE_CODABLOCKF, DATA_MODE | ESCAPE_MODE, -1, -1, "\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09", -1, 0, 3, 101, 1, "67 62 41 41 42 43 44 5B 6A 67 62 0B 45 46 47 48 37 6A 67 62 0C 49 63 1B 44 2C 6A", "Okapi control-chars-1.png" }, + /* 46*/ { BARCODE_CODABLOCKF, DATA_MODE | ESCAPE_MODE, 4, -1, "\\x80\\x81\\x82\\x83\\x9E\\x9F\\xA0", -1, 0, 4, 101, 1, "(36) 67 62 42 65 40 65 41 24 6A 67 62 0B 65 42 65 43 31 6A 67 62 0C 65 5E 65 5F 16 6A 67", "Okapi control-chars-2.png" }, + /* 47*/ { BARCODE_CODABLOCKF, DATA_MODE | ESCAPE_MODE, -1, -1, "\\x00z", -1, 0, 2, 101, 0, "67 62 40 40 62 5A 63 00 6A 67 64 0B 63 64 32 04 3F 6A", "Okapi data-null-z.png; BWIPP different encodation" }, + /* 48*/ { BARCODE_CODABLOCKF, UNICODE_MODE | ESCAPE_MODE, -1, -1, "2610\\u00F2", -1, 0, 2, 101, 1, "67 63 00 1A 0A 64 63 4B 6A 67 64 0B 64 52 33 26 64 6A", "Okapi data-fuzz-19.png" }, + /* 49*/ { BARCODE_CODABLOCKF, DATA_MODE | ESCAPE_MODE, 7, -1, "*\\r\\xF2\\x82\\x82(\\x982\\x82\\x82*\\r\\xF2\\x82\\xA8\\x82\\x82\\x82\\x82", -1, 0, 7, 123, 0, "(77) 67 62 45 0A 4D 64 64 52 63 35 6A 67 62 0B 65 42 65 42 08 63 43 6A 67 62 0C 65 58 12", "Okapi data-fuzz-20.png; BWIPP different encodation" }, + /* 50*/ { BARCODE_CODABLOCKF, UNICODE_MODE | ESCAPE_MODE, -1, -1, "\\u0018\\u00F2", -1, 0, 2, 101, 0, "67 62 40 58 65 62 52 16 6A 67 64 0B 63 64 38 30 30 6A", "Okapi data-fuzz-21.png; BWIPP different encodation" }, + /* 51*/ { BARCODE_HIBC_BLOCKF, UNICODE_MODE, -1, -1, "A99912345/$$52001510X3", -1, 0, 6, 101, 1, "(54) 67 64 44 0B 21 19 19 3A 6A 67 63 2B 5B 17 2D 64 24 6A 67 64 0C 0F 04 04 15 16 6A 67", "" }, + /* 52*/ { BARCODE_HIBC_BLOCKF, UNICODE_MODE, -1, -1, "A99912345/$$520:1510X3", -1, ZINT_ERROR_INVALID_DATA, -1, -1, 1, "Error 203: Invalid character at position 16 in input (alphanumerics, space and \"-.$/+%\" only)", "" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; diff --git a/backend/tests/test_code.c b/backend/tests/test_code.c index 3f3f4655..09af49a5 100644 --- a/backend/tests/test_code.c +++ b/backend/tests/test_code.c @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2020-2024 Robin Stuart + Copyright (C) 2020-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -46,34 +46,28 @@ static void test_large(const testCtx *const p_ctx) { }; /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ static const struct item data[] = { - /* 0*/ { BARCODE_CODE11, -1, "13", 140, 0, 1, 1151, "" }, /* 8 (Start) + 140*8 + 2*8 (Checks) + 7 (Stop) == 1151 */ - /* 1*/ { BARCODE_CODE11, -1, "13", 141, ZINT_ERROR_TOO_LONG, -1, -1, "Error 320: Input length 141 too long (maximum 140)" }, - /* 2*/ { BARCODE_CODE39, -1, "1", 86, 0, 1, 1143, "" }, /* 13 (Start) + 86*13 + 12 (Stop) == 1143 */ - /* 3*/ { BARCODE_CODE39, -1, "1", 87, ZINT_ERROR_TOO_LONG, -1, -1, "Error 323: Input length 87 too long (maximum 86)" }, - /* 4*/ { BARCODE_EXCODE39, -1, "1", 86, 0, 1, 1143, "" }, - /* 5*/ { BARCODE_EXCODE39, -1, "1", 87, ZINT_ERROR_TOO_LONG, -1, -1, "Error 328: Input length 87 too long (maximum 86)" }, - /* 6*/ { BARCODE_EXCODE39, -1, "a", 43, 0, 1, 1143, "" }, /* Takes 2 encoding chars per char */ - /* 7*/ { BARCODE_EXCODE39, -1, "a", 44, ZINT_ERROR_TOO_LONG, -1, -1, "Error 317: Input too long, requires 88 symbol characters (maximum 86)" }, - /* 8*/ { BARCODE_EXCODE39, -1, "a", 86, ZINT_ERROR_TOO_LONG, -1, -1, "Error 317: Input too long, requires 172 symbol characters (maximum 86)" }, - /* 9*/ { BARCODE_LOGMARS, -1, "1", 30, 0, 1, 511, "" }, /* 16 (Start) + 30*16 + 15 (Stop) == 511 */ - /* 10*/ { BARCODE_LOGMARS, -1, "1", 31, ZINT_ERROR_TOO_LONG, -1, -1, "Error 322: Input length 31 too long (maximum 30)" }, - /* 11*/ { BARCODE_CODE93, -1, "1", 123, 0, 1, 1144, "" }, /* 9 (Start) + 123*9 + 2*9 (Checks) + 10 (Stop) == 1144 */ - /* 12*/ { BARCODE_CODE93, -1, "1", 124, ZINT_ERROR_TOO_LONG, -1, -1, "Error 330: Input length 124 too long (maximum 123)" }, - /* 13*/ { BARCODE_CODE93, -1, "a", 61, 0, 1, 1135, "" }, /* Takes 2 encoding chars per char */ - /* 14*/ { BARCODE_CODE93, -1, "a", 62, ZINT_ERROR_TOO_LONG, -1, -1, "Error 332: Input too long, requires 124 symbol characters (maximum 123)" }, - /* 15*/ { BARCODE_CODE93, -1, "a", 124, ZINT_ERROR_TOO_LONG, -1, -1, "Error 330: Input length 124 too long (maximum 123)" }, - /* 16*/ { BARCODE_CODE93, -1, "a1", 82, 0, 1, 1144, "" }, /* Takes 1.5 encoding chars (1.5*82 == 123) */ - /* 17*/ { BARCODE_CODE93, -1, "a1", 83, ZINT_ERROR_TOO_LONG, -1, -1, "Error 332: Input too long, requires 125 symbol characters (maximum 123)" }, - /* 18*/ { BARCODE_PZN, -1, "1", 7, 0, 1, 142, "" }, /* Takes 8 with correct check digit */ - /* 19*/ { BARCODE_PZN, -1, "1", 9, ZINT_ERROR_TOO_LONG, -1, -1, "Error 325: Input length 9 too long (maximum 8)" }, - /* 20*/ { BARCODE_PZN, 1, "1", 6, 0, 1, 129, "" }, /* PZN7 takes 7 with correct check digit */ - /* 21*/ { BARCODE_PZN, 1, "1", 8, ZINT_ERROR_TOO_LONG, -1, -1, "Error 325: Input length 8 too long (maximum 7)" }, - /* 22*/ { BARCODE_VIN, -1, "1", 17, 0, 1, 246, "" }, - /* 23*/ { BARCODE_VIN, -1, "1", 18, ZINT_ERROR_TOO_LONG, -1, -1, "Error 336: Input length 18 wrong (17 only)" }, - /* 24*/ { BARCODE_VIN, -1, "1", 16, ZINT_ERROR_TOO_LONG, -1, -1, "Error 336: Input length 16 wrong (17 only)" }, - /* 25*/ { BARCODE_VIN, 1, "1", 17, 0, 1, 259, "" }, - /* 26*/ { BARCODE_HIBC_39, -1, "1", 68, 0, 1, 1151, "" }, /* 70 - 2 ('+' and check digit) */ - /* 27*/ { BARCODE_HIBC_39, -1, "1", 69, ZINT_ERROR_TOO_LONG, -1, -1, "Error 319: Input length 69 too long (maximum 68)" }, + /* 0*/ { BARCODE_CODE39, -1, "1", 86, 0, 1, 1143, "" }, /* 13 (Start) + 86*13 + 12 (Stop) == 1143 */ + /* 1*/ { BARCODE_CODE39, -1, "1", 87, ZINT_ERROR_TOO_LONG, -1, -1, "Error 323: Input length 87 too long (maximum 86)" }, + /* 2*/ { BARCODE_EXCODE39, -1, "1", 86, 0, 1, 1143, "" }, + /* 3*/ { BARCODE_EXCODE39, -1, "1", 87, ZINT_ERROR_TOO_LONG, -1, -1, "Error 328: Input length 87 too long (maximum 86)" }, + /* 4*/ { BARCODE_EXCODE39, -1, "a", 43, 0, 1, 1143, "" }, /* Takes 2 encoding chars per char */ + /* 5*/ { BARCODE_EXCODE39, -1, "a", 44, ZINT_ERROR_TOO_LONG, -1, -1, "Error 317: Input too long, requires 88 symbol characters (maximum 86)" }, + /* 6*/ { BARCODE_EXCODE39, -1, "a", 86, ZINT_ERROR_TOO_LONG, -1, -1, "Error 317: Input too long, requires 172 symbol characters (maximum 86)" }, + /* 7*/ { BARCODE_LOGMARS, -1, "1", 30, 0, 1, 511, "" }, /* 16 (Start) + 30*16 + 15 (Stop) == 511 */ + /* 8*/ { BARCODE_LOGMARS, -1, "1", 31, ZINT_ERROR_TOO_LONG, -1, -1, "Error 322: Input length 31 too long (maximum 30)" }, + /* 9*/ { BARCODE_CODE93, -1, "1", 123, 0, 1, 1144, "" }, /* 9 (Start) + 123*9 + 2*9 (Checks) + 10 (Stop) == 1144 */ + /* 10*/ { BARCODE_CODE93, -1, "1", 124, ZINT_ERROR_TOO_LONG, -1, -1, "Error 330: Input length 124 too long (maximum 123)" }, + /* 11*/ { BARCODE_CODE93, -1, "a", 61, 0, 1, 1135, "" }, /* Takes 2 encoding chars per char */ + /* 12*/ { BARCODE_CODE93, -1, "a", 62, ZINT_ERROR_TOO_LONG, -1, -1, "Error 332: Input too long, requires 124 symbol characters (maximum 123)" }, + /* 13*/ { BARCODE_CODE93, -1, "a", 124, ZINT_ERROR_TOO_LONG, -1, -1, "Error 330: Input length 124 too long (maximum 123)" }, + /* 14*/ { BARCODE_CODE93, -1, "a1", 82, 0, 1, 1144, "" }, /* Takes 1.5 encoding chars (1.5*82 == 123) */ + /* 15*/ { BARCODE_CODE93, -1, "a1", 83, ZINT_ERROR_TOO_LONG, -1, -1, "Error 332: Input too long, requires 125 symbol characters (maximum 123)" }, + /* 16*/ { BARCODE_VIN, -1, "1", 17, 0, 1, 246, "" }, + /* 17*/ { BARCODE_VIN, -1, "1", 18, ZINT_ERROR_TOO_LONG, -1, -1, "Error 336: Input length 18 wrong (17 only)" }, + /* 18*/ { BARCODE_VIN, -1, "1", 16, ZINT_ERROR_TOO_LONG, -1, -1, "Error 336: Input length 16 wrong (17 only)" }, + /* 19*/ { BARCODE_VIN, 1, "1", 17, 0, 1, 259, "" }, + /* 20*/ { BARCODE_HIBC_39, -1, "1", 68, 0, 1, 1151, "" }, /* 70 - 2 ('+' and check digit) */ + /* 21*/ { BARCODE_HIBC_39, -1, "1", 69, ZINT_ERROR_TOO_LONG, -1, -1, "Error 319: Input length 69 too long (maximum 68)" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -124,48 +118,36 @@ static void test_hrt(const testCtx *const p_ctx) { }; /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ static const struct item data[] = { - /* 0*/ { BARCODE_CODE11, -1, "123-45", -1, "123-4552" }, /* 2 checksums */ - /* 1*/ { BARCODE_CODE11, 1, "123-45", -1, "123-455" }, /* 1 check digit */ - /* 2*/ { BARCODE_CODE11, 2, "123-45", -1, "123-45" }, /* No checksums */ - /* 3*/ { BARCODE_CODE11, -1, "123456789012", -1, "123456789012-8" }, /* First check digit 10 (A) goes to hyphen */ - /* 4*/ { BARCODE_CODE39, -1, "ABC1234", -1, "*ABC1234*" }, - /* 5*/ { BARCODE_CODE39, 1, "ABC1234", -1, "*ABC12340*" }, /* With visible check digit */ - /* 6*/ { BARCODE_CODE39, -1, "abc1234", -1, "*ABC1234*" }, /* Converts to upper */ - /* 7*/ { BARCODE_CODE39, 1, "abc1234", -1, "*ABC12340*" }, /* Converts to upper */ - /* 8*/ { BARCODE_CODE39, -1, "123456789", -1, "*123456789*" }, - /* 9*/ { BARCODE_CODE39, 1, "123456789", -1, "*1234567892*" }, /* With visible check digit */ - /* 10*/ { BARCODE_CODE39, 2, "123456789", -1, "*123456789*" }, /* With hidden check digit */ - /* 11*/ { BARCODE_EXCODE39, -1, "ABC1234", -1, "ABC1234" }, - /* 12*/ { BARCODE_EXCODE39, 1, "ABC1234", -1, "ABC12340" }, /* With visible check digit */ - /* 13*/ { BARCODE_EXCODE39, -1, "abc1234", -1, "abc1234" }, - /* 14*/ { BARCODE_EXCODE39, 1, "abc1234", -1, "abc1234." }, /* With visible check digit (previously was hidden) */ - /* 15*/ { BARCODE_EXCODE39, 2, "abc1234", -1, "abc1234" }, /* With hidden check digit */ - /* 16*/ { BARCODE_EXCODE39, -1, "a%\000\001$\177z\033\037!+/\\@A~", 16, "a% $ z !+/\\@A~" }, /* NUL, ctrls and DEL replaced with spaces */ - /* 17*/ { BARCODE_EXCODE39, 1, "a%\000\001$\177z\033\037!+/\\@A~", 16, "a% $ z !+/\\@A~L" }, /* With visible check digit */ - /* 18*/ { BARCODE_EXCODE39, 2, "a%\000\001$\177z\033\037!+/\\@A~", 16, "a% $ z !+/\\@A~" }, /* With hidden check digit */ - /* 19*/ { BARCODE_LOGMARS, -1, "ABC1234", -1, "ABC1234" }, - /* 20*/ { BARCODE_LOGMARS, -1, "abc1234", -1, "ABC1234" }, /* Converts to upper */ - /* 21*/ { BARCODE_LOGMARS, 1, "abc1234", -1, "ABC12340" }, /* With check digit */ - /* 22*/ { BARCODE_LOGMARS, 1, "12345/ABCDE", -1, "12345/ABCDET" }, /* With visible check digit */ - /* 23*/ { BARCODE_LOGMARS, 2, "12345/ABCDE", -1, "12345/ABCDE" }, /* With hidden check digit */ - /* 24*/ { BARCODE_CODE93, -1, "ABC1234", -1, "ABC1234" }, /* No longer shows 2 check chars added (same as BWIPP and TEC-IT) */ - /* 25*/ { BARCODE_CODE93, 1, "ABC1234", -1, "ABC1234S5" }, /* Unless requested */ - /* 26*/ { BARCODE_CODE93, -1, "abc1234", -1, "abc1234" }, - /* 27*/ { BARCODE_CODE93, 1, "abc1234", -1, "abc1234ZG" }, - /* 28*/ { BARCODE_CODE93, -1, "A\001a\000b\177d\037e", 9, "A a b d e" }, /* NUL, ctrls and DEL replaced with spaces */ - /* 29*/ { BARCODE_PZN, -1, "12345", -1, "PZN - 00123458" }, /* Pads with zeroes if length < 7 */ - /* 30*/ { BARCODE_PZN, -1, "123456", -1, "PZN - 01234562" }, - /* 31*/ { BARCODE_PZN, -1, "1234567", -1, "PZN - 12345678" }, - /* 32*/ { BARCODE_PZN, -1, "12345678", -1, "PZN - 12345678" }, - /* 33*/ { BARCODE_PZN, 1, "1234", -1, "PZN - 0012345" }, /* PZN7, pads with zeroes if length < 6 */ - /* 34*/ { BARCODE_PZN, 1, "12345", -1, "PZN - 0123458" }, - /* 35*/ { BARCODE_PZN, 1, "123456", -1, "PZN - 1234562" }, - /* 36*/ { BARCODE_PZN, 1, "1234562", -1, "PZN - 1234562" }, - /* 37*/ { BARCODE_VIN, -1, "1FTCR10UXTPA78180", -1, "1FTCR10UXTPA78180" }, - /* 38*/ { BARCODE_VIN, 1, "2FTPX28L0XCA15511", -1, "2FTPX28L0XCA15511" }, /* Include Import char - no change */ - /* 39*/ { BARCODE_HIBC_39, -1, "ABC1234", -1, "*+ABC1234+*" }, - /* 40*/ { BARCODE_HIBC_39, -1, "abc1234", -1, "*+ABC1234+*" }, /* Converts to upper */ - /* 41*/ { BARCODE_HIBC_39, -1, "123456789", -1, "*+1234567890*" }, + /* 0*/ { BARCODE_CODE39, -1, "ABC1234", -1, "*ABC1234*" }, + /* 1*/ { BARCODE_CODE39, 1, "ABC1234", -1, "*ABC12340*" }, /* With visible check digit */ + /* 2*/ { BARCODE_CODE39, -1, "abc1234", -1, "*ABC1234*" }, /* Converts to upper */ + /* 3*/ { BARCODE_CODE39, 1, "abc1234", -1, "*ABC12340*" }, /* Converts to upper */ + /* 4*/ { BARCODE_CODE39, -1, "123456789", -1, "*123456789*" }, + /* 5*/ { BARCODE_CODE39, 1, "123456789", -1, "*1234567892*" }, /* With visible check digit */ + /* 6*/ { BARCODE_CODE39, 2, "123456789", -1, "*123456789*" }, /* With hidden check digit */ + /* 7*/ { BARCODE_EXCODE39, -1, "ABC1234", -1, "ABC1234" }, + /* 8*/ { BARCODE_EXCODE39, 1, "ABC1234", -1, "ABC12340" }, /* With visible check digit */ + /* 9*/ { BARCODE_EXCODE39, -1, "abc1234", -1, "abc1234" }, + /* 10*/ { BARCODE_EXCODE39, 1, "abc1234", -1, "abc1234." }, /* With visible check digit (previously was hidden) */ + /* 11*/ { BARCODE_EXCODE39, 2, "abc1234", -1, "abc1234" }, /* With hidden check digit */ + /* 12*/ { BARCODE_EXCODE39, -1, "a%\000\001$\177z\033\037!+/\\@A~", 16, "a% $ z !+/\\@A~" }, /* NUL, ctrls and DEL replaced with spaces */ + /* 13*/ { BARCODE_EXCODE39, 1, "a%\000\001$\177z\033\037!+/\\@A~", 16, "a% $ z !+/\\@A~L" }, /* With visible check digit */ + /* 14*/ { BARCODE_EXCODE39, 2, "a%\000\001$\177z\033\037!+/\\@A~", 16, "a% $ z !+/\\@A~" }, /* With hidden check digit */ + /* 15*/ { BARCODE_LOGMARS, -1, "ABC1234", -1, "ABC1234" }, + /* 16*/ { BARCODE_LOGMARS, -1, "abc1234", -1, "ABC1234" }, /* Converts to upper */ + /* 17*/ { BARCODE_LOGMARS, 1, "abc1234", -1, "ABC12340" }, /* With check digit */ + /* 18*/ { BARCODE_LOGMARS, 1, "12345/ABCDE", -1, "12345/ABCDET" }, /* With visible check digit */ + /* 19*/ { BARCODE_LOGMARS, 2, "12345/ABCDE", -1, "12345/ABCDE" }, /* With hidden check digit */ + /* 20*/ { BARCODE_CODE93, -1, "ABC1234", -1, "ABC1234" }, /* No longer shows 2 check chars added (same as BWIPP and TEC-IT) */ + /* 21*/ { BARCODE_CODE93, 1, "ABC1234", -1, "ABC1234S5" }, /* Unless requested */ + /* 22*/ { BARCODE_CODE93, -1, "abc1234", -1, "abc1234" }, + /* 23*/ { BARCODE_CODE93, 1, "abc1234", -1, "abc1234ZG" }, + /* 24*/ { BARCODE_CODE93, -1, "A\001a\000b\177d\037e", 9, "A a b d e" }, /* NUL, ctrls and DEL replaced with spaces */ + /* 25*/ { BARCODE_VIN, -1, "1FTCR10UXTPA78180", -1, "1FTCR10UXTPA78180" }, + /* 26*/ { BARCODE_VIN, 1, "2FTPX28L0XCA15511", -1, "2FTPX28L0XCA15511" }, /* Include Import char - no change */ + /* 27*/ { BARCODE_HIBC_39, -1, "ABC1234", -1, "*+ABC1234+*" }, + /* 28*/ { BARCODE_HIBC_39, -1, "abc1234", -1, "*+ABC1234+*" }, /* Converts to upper */ + /* 29*/ { BARCODE_HIBC_39, -1, "123456789", -1, "*+1234567890*" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -209,74 +191,59 @@ static void test_input(const testCtx *const p_ctx) { }; /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ static const struct item data[] = { - /* 0*/ { BARCODE_CODE11, -1, -1, "-", -1, 0, 1, 37, "" }, - /* 1*/ { BARCODE_CODE11, -1, -1, "0123456789-", -1, 0, 1, 115, "" }, - /* 2*/ { BARCODE_CODE11, -1, -1, "A", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 1 in input (digits and \"-\" only)" }, - /* 3*/ { BARCODE_CODE11, -1, -1, "12+", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 3 in input (digits and \"-\" only)" }, - /* 4*/ { BARCODE_CODE11, -1, -1, "1.2", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 2 in input (digits and \"-\" only)" }, - /* 5*/ { BARCODE_CODE11, -1, -1, "12!", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 3 in input (digits and \"-\" only)" }, - /* 6*/ { BARCODE_CODE11, -1, -1, " ", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 1 in input (digits and \"-\" only)" }, - /* 7*/ { BARCODE_CODE11, ESCAPE_MODE, -1, "\\d048 ", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 2 in input (digits and \"-\" only)" }, /* Note position doesn't account for escape sequences */ - /* 8*/ { BARCODE_CODE11, -1, 3, "1", -1, ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 339: Invalid check digit version '3' (1 or 2 only)" }, - /* 9*/ { BARCODE_CODE39, -1, -1, "a", -1, 0, 1, 38, "" }, /* Converts to upper */ - /* 10*/ { BARCODE_CODE39, -1, -1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%", -1, 0, 1, 584, "" }, - /* 11*/ { BARCODE_CODE39, -1, -1, "AB!", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 3 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 12*/ { BARCODE_CODE39, -1, -1, "A\"B", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 2 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 13*/ { BARCODE_CODE39, -1, -1, "#AB", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 14*/ { BARCODE_CODE39, -1, -1, "&", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 15*/ { BARCODE_CODE39, -1, -1, "'", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 16*/ { BARCODE_CODE39, -1, -1, "(", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 17*/ { BARCODE_CODE39, -1, -1, ")", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 18*/ { BARCODE_CODE39, -1, -1, "*", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 19*/ { BARCODE_CODE39, -1, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 20*/ { BARCODE_CODE39, -1, -1, ":", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 21*/ { BARCODE_CODE39, -1, -1, "@", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 22*/ { BARCODE_CODE39, -1, -1, "[", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 23*/ { BARCODE_CODE39, -1, -1, "`", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 24*/ { BARCODE_CODE39, -1, -1, "{", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 25*/ { BARCODE_CODE39, -1, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 26*/ { BARCODE_CODE39, -1, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 27*/ { BARCODE_CODE39, -1, 0, "1", -1, 0, 1, 38, "" }, - /* 28*/ { BARCODE_CODE39, -1, 1, "1", -1, 0, 1, 51, "" }, /* Check digit */ - /* 29*/ { BARCODE_CODE39, -1, 2, "1", -1, 0, 1, 51, "" }, /* Hidden check digit */ - /* 30*/ { BARCODE_CODE39, -1, 3, "1", -1, 0, 1, 38, "" }, /* option_2 > 2 ignored */ - /* 31*/ { BARCODE_EXCODE39, -1, -1, "A", -1, 0, 1, 38, "" }, - /* 32*/ { BARCODE_EXCODE39, -1, 3, "A", -1, 0, 1, 38, "" }, /* option_2 > 2 ignored */ - /* 33*/ { BARCODE_EXCODE39, -1, -1, "a", -1, 0, 1, 51, "" }, - /* 34*/ { BARCODE_EXCODE39, -1, -1, ",", -1, 0, 1, 51, "" }, - /* 35*/ { BARCODE_EXCODE39, -1, -1, "\000", 1, 0, 1, 51, "" }, - /* 36*/ { BARCODE_EXCODE39, -1, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 329: Invalid character at position 1 in input, extended ASCII not allowed" }, - /* 37*/ { BARCODE_EXCODE39, -1, -1, "ABCDé", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 329: Invalid character at position 5 in input, extended ASCII not allowed" }, - /* 38*/ { BARCODE_LOGMARS, -1, -1, "A", -1, 0, 1, 47, "" }, - /* 39*/ { BARCODE_LOGMARS, -1, -1, "a", -1, 0, 1, 47, "" }, - /* 40*/ { BARCODE_LOGMARS, -1, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 41*/ { BARCODE_LOGMARS, -1, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 42*/ { BARCODE_LOGMARS, -1, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 43*/ { BARCODE_LOGMARS, -1, 3, "A", -1, 0, 1, 47, "" }, /* option_2 > 2 ignored */ - /* 44*/ { BARCODE_CODE93, -1, -1, "A", -1, 0, 1, 46, "" }, - /* 45*/ { BARCODE_CODE93, -1, -1, "a", -1, 0, 1, 55, "" }, - /* 46*/ { BARCODE_CODE93, -1, -1, ",", -1, 0, 1, 55, "" }, - /* 47*/ { BARCODE_CODE93, -1, -1, "\000", 1, 0, 1, 55, "" }, - /* 48*/ { BARCODE_CODE93, -1, -1, "12\3004", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 331: Invalid character at position 3 in input, extended ASCII not allowed" }, - /* 49*/ { BARCODE_CODE93, -1, -1, "é", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 331: Invalid character at position 1 in input, extended ASCII not allowed" }, - /* 50*/ { BARCODE_PZN, -1, -1, "1", -1, 0, 1, 142, "" }, - /* 51*/ { BARCODE_PZN, -1, -1, "A", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 326: Invalid character at position 1 in input (digits only)" }, - /* 52*/ { BARCODE_PZN, -1, -1, "1000006", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 327: Invalid PZN, check digit is '10'" }, /* Check digit == 10 so can't be used */ - /* 53*/ { BARCODE_PZN, -1, -1, "00000011", -1, ZINT_ERROR_INVALID_CHECK, -1, -1, "Error 890: Invalid check digit '1', expecting '7'" }, - /* 54*/ { BARCODE_PZN, -1, 1, "100009", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 327: Invalid PZN, check digit is '10'" }, /* Check digit == 10 so can't be used */ - /* 55*/ { BARCODE_PZN, -1, 1, "0000011", -1, ZINT_ERROR_INVALID_CHECK, -1, -1, "Error 890: Invalid check digit '1', expecting '7'" }, - /* 56*/ { BARCODE_VIN, -1, -1, "5GZCZ43D13S812715", -1, 0, 1, 246, "" }, - /* 57*/ { BARCODE_VIN, -1, -1, "5GZCZ43D23S812715", -1, ZINT_ERROR_INVALID_CHECK, -1, -1, "Error 338: Invalid check digit '2' (position 9), expecting '1'" }, /* North American with invalid check character */ - /* 58*/ { BARCODE_VIN, -1, -1, "WP0ZZZ99ZTS392124", -1, 0, 1, 246, "" }, /* Not North American so no check */ - /* 59*/ { BARCODE_VIN, -1, -1, "WP0ZZZ99ZTS392I24", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 337: Invalid character at position 15 in input (alphanumerics only, excluding \"IOQ\")" }, /* I not allowed */ - /* 60*/ { BARCODE_VIN, -1, -1, "WPOZZZ99ZTS392124", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 337: Invalid character at position 3 in input (alphanumerics only, excluding \"IOQ\")" }, /* O not allowed */ - /* 61*/ { BARCODE_VIN, -1, -1, "WPQZZZ99ZTS392124", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 337: Invalid character at position 3 in input (alphanumerics only, excluding \"IOQ\")" }, /* Q not allowed */ - /* 62*/ { BARCODE_HIBC_39, -1, -1, "a", -1, 0, 1, 79, "" }, /* Converts to upper */ - /* 63*/ { BARCODE_HIBC_39, -1, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 203: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 64*/ { BARCODE_HIBC_39, -1, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 203: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 65*/ { BARCODE_HIBC_39, -1, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 203: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, - /* 66*/ { BARCODE_HIBC_39, -1, 1, "a", -1, 0, 1, 79, "" }, /* option_2 ignored */ - /* 67*/ { BARCODE_HIBC_39, -1, 2, "a", -1, 0, 1, 79, "" }, /* option_2 ignored */ + /* 0*/ { BARCODE_CODE39, -1, -1, "a", -1, 0, 1, 38, "" }, /* Converts to upper */ + /* 1*/ { BARCODE_CODE39, -1, -1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%", -1, 0, 1, 584, "" }, + /* 2*/ { BARCODE_CODE39, -1, -1, "AB!", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 3 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 3*/ { BARCODE_CODE39, -1, -1, "A\"B", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 2 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 4*/ { BARCODE_CODE39, -1, -1, "#AB", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 5*/ { BARCODE_CODE39, -1, -1, "&", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 6*/ { BARCODE_CODE39, -1, -1, "'", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 7*/ { BARCODE_CODE39, -1, -1, "(", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 8*/ { BARCODE_CODE39, -1, -1, ")", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 9*/ { BARCODE_CODE39, -1, -1, "*", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 10*/ { BARCODE_CODE39, -1, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 11*/ { BARCODE_CODE39, -1, -1, ":", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 12*/ { BARCODE_CODE39, -1, -1, "@", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 13*/ { BARCODE_CODE39, -1, -1, "[", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 14*/ { BARCODE_CODE39, -1, -1, "`", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 15*/ { BARCODE_CODE39, -1, -1, "{", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 16*/ { BARCODE_CODE39, -1, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 17*/ { BARCODE_CODE39, -1, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 18*/ { BARCODE_CODE39, -1, 0, "1", -1, 0, 1, 38, "" }, + /* 19*/ { BARCODE_CODE39, -1, 1, "1", -1, 0, 1, 51, "" }, /* Check digit */ + /* 20*/ { BARCODE_CODE39, -1, 2, "1", -1, 0, 1, 51, "" }, /* Hidden check digit */ + /* 21*/ { BARCODE_CODE39, -1, 3, "1", -1, 0, 1, 38, "" }, /* option_2 > 2 ignored */ + /* 22*/ { BARCODE_EXCODE39, -1, -1, "A", -1, 0, 1, 38, "" }, + /* 23*/ { BARCODE_EXCODE39, -1, 3, "A", -1, 0, 1, 38, "" }, /* option_2 > 2 ignored */ + /* 24*/ { BARCODE_EXCODE39, -1, -1, "a", -1, 0, 1, 51, "" }, + /* 25*/ { BARCODE_EXCODE39, -1, -1, ",", -1, 0, 1, 51, "" }, + /* 26*/ { BARCODE_EXCODE39, -1, -1, "\000", 1, 0, 1, 51, "" }, + /* 27*/ { BARCODE_EXCODE39, -1, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 329: Invalid character at position 1 in input, extended ASCII not allowed" }, + /* 28*/ { BARCODE_EXCODE39, -1, -1, "ABCDé", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 329: Invalid character at position 5 in input, extended ASCII not allowed" }, + /* 29*/ { BARCODE_LOGMARS, -1, -1, "A", -1, 0, 1, 47, "" }, + /* 30*/ { BARCODE_LOGMARS, -1, -1, "a", -1, 0, 1, 47, "" }, + /* 31*/ { BARCODE_LOGMARS, -1, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 32*/ { BARCODE_LOGMARS, -1, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 33*/ { BARCODE_LOGMARS, -1, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 324: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 34*/ { BARCODE_LOGMARS, -1, 3, "A", -1, 0, 1, 47, "" }, /* option_2 > 2 ignored */ + /* 35*/ { BARCODE_CODE93, -1, -1, "A", -1, 0, 1, 46, "" }, + /* 36*/ { BARCODE_CODE93, -1, -1, "a", -1, 0, 1, 55, "" }, + /* 37*/ { BARCODE_CODE93, -1, -1, ",", -1, 0, 1, 55, "" }, + /* 38*/ { BARCODE_CODE93, -1, -1, "\000", 1, 0, 1, 55, "" }, + /* 39*/ { BARCODE_CODE93, -1, -1, "12\3004", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 331: Invalid character at position 3 in input, extended ASCII not allowed" }, + /* 40*/ { BARCODE_CODE93, -1, -1, "é", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 331: Invalid character at position 1 in input, extended ASCII not allowed" }, + /* 41*/ { BARCODE_VIN, -1, -1, "5GZCZ43D13S812715", -1, 0, 1, 246, "" }, + /* 42*/ { BARCODE_VIN, -1, -1, "5GZCZ43D23S812715", -1, ZINT_ERROR_INVALID_CHECK, -1, -1, "Error 338: Invalid check digit '2' (position 9), expecting '1'" }, /* North American with invalid check character */ + /* 43*/ { BARCODE_VIN, -1, -1, "WP0ZZZ99ZTS392124", -1, 0, 1, 246, "" }, /* Not North American so no check */ + /* 44*/ { BARCODE_VIN, -1, -1, "WP0ZZZ99ZTS392I24", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 337: Invalid character at position 15 in input (alphanumerics only, excluding \"IOQ\")" }, /* I not allowed */ + /* 45*/ { BARCODE_VIN, -1, -1, "WPOZZZ99ZTS392124", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 337: Invalid character at position 3 in input (alphanumerics only, excluding \"IOQ\")" }, /* O not allowed */ + /* 46*/ { BARCODE_VIN, -1, -1, "WPQZZZ99ZTS392124", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 337: Invalid character at position 3 in input (alphanumerics only, excluding \"IOQ\")" }, /* Q not allowed */ + /* 47*/ { BARCODE_HIBC_39, -1, -1, "a", -1, 0, 1, 79, "" }, /* Converts to upper */ + /* 48*/ { BARCODE_HIBC_39, -1, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 203: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 49*/ { BARCODE_HIBC_39, -1, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 203: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 50*/ { BARCODE_HIBC_39, -1, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 203: Invalid character at position 1 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 51*/ { BARCODE_HIBC_39, -1, 1, "a", -1, 0, 1, 79, "" }, /* option_2 ignored */ + /* 52*/ { BARCODE_HIBC_39, -1, 2, "a", -1, 0, 1, 79, "" }, /* option_2 ignored */ }; const int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -325,133 +292,106 @@ static void test_encode(const testCtx *const p_ctx) { char *expected; }; static const struct item data[] = { - /* 0*/ { BARCODE_CODE11, -1, "123-45", -1, 0, 1, 78, "2 check digits (52); verified manually against TEC-IT", - "101100101101011010010110110010101011010101101101101101011011010100101101011001" - }, - /* 1*/ { BARCODE_CODE11, -1, "93", -1, 0, 1, 44, "2 check digits (--); verified manually against TEC-IT", - "10110010110101011001010101101010110101011001" - }, - /* 2*/ { BARCODE_CODE11, 1, "123-455", -1, 0, 1, 78, "1 check digit (2); verified manually against TEC-IT", - "101100101101011010010110110010101011010101101101101101011011010100101101011001" - }, - /* 3*/ { BARCODE_CODE11, 2, "123-4552", -1, 0, 1, 78, "0 check digits; verified manually against TEC-IT", - "101100101101011010010110110010101011010101101101101101011011010100101101011001" - }, - /* 4*/ { BARCODE_CODE11, 1, "123-45", -1, 0, 1, 70, "1 check digit; verified manually against TEC-IT", - "1011001011010110100101101100101010110101011011011011010110110101011001" - }, - /* 5*/ { BARCODE_CODE11, 2, "123-45", -1, 0, 1, 62, "0 check digits; verified manually against TEC-IT", - "10110010110101101001011011001010101101010110110110110101011001" - }, - /* 6*/ { BARCODE_CODE39, -1, "1A", -1, 0, 1, 51, "ISO/IEC 16388:2007 Figure 1", + /* 0*/ { BARCODE_CODE39, -1, "1A", -1, 0, 1, 51, "ISO/IEC 16388:2007 Figure 1", "100101101101011010010101101101010010110100101101101" }, - /* 7*/ { BARCODE_CODE39, 1, "1A", -1, 0, 1, 64, "With check digit (B)", + /* 1*/ { BARCODE_CODE39, 1, "1A", -1, 0, 1, 64, "With check digit (B)", "1001011011010110100101011011010100101101011010010110100101101101" }, - /* 8*/ { BARCODE_CODE39, 1, "Z1", -1, 0, 1, 64, "Check digit '-'", + /* 2*/ { BARCODE_CODE39, 1, "Z1", -1, 0, 1, 64, "Check digit '-'", "1001011011010100110110101011010010101101001010110110100101101101" }, - /* 9*/ { BARCODE_CODE39, 1, "Z2", -1, 0, 1, 64, "Check digit '.'", + /* 3*/ { BARCODE_CODE39, 1, "Z2", -1, 0, 1, 64, "Check digit '.'", "1001011011010100110110101010110010101101100101011010100101101101" }, - /* 10*/ { BARCODE_CODE39, 1, "Z3", -1, 0, 1, 64, "Check digit space, displayed as underscore", + /* 4*/ { BARCODE_CODE39, 1, "Z3", -1, 0, 1, 64, "Check digit space, displayed as underscore", "1001011011010100110110101011011001010101001101011010100101101101" }, - /* 11*/ { BARCODE_CODE39, 1, "Z4", -1, 0, 1, 64, "Check digit '$'", + /* 5*/ { BARCODE_CODE39, 1, "Z4", -1, 0, 1, 64, "Check digit '$'", "1001011011010100110110101010100110101101001001001010100101101101" }, - /* 12*/ { BARCODE_CODE39, 1, "Z5", -1, 0, 1, 64, "Check digit '/'", + /* 6*/ { BARCODE_CODE39, 1, "Z5", -1, 0, 1, 64, "Check digit '/'", "1001011011010100110110101011010011010101001001010010100101101101" }, - /* 13*/ { BARCODE_CODE39, 1, "Z6", -1, 0, 1, 64, "Check digit '+'", + /* 7*/ { BARCODE_CODE39, 1, "Z6", -1, 0, 1, 64, "Check digit '+'", "1001011011010100110110101010110011010101001010010010100101101101" }, - /* 14*/ { BARCODE_CODE39, 1, "Z7", -1, 0, 1, 64, "Check digit '%'", + /* 8*/ { BARCODE_CODE39, 1, "Z7", -1, 0, 1, 64, "Check digit '%'", "1001011011010100110110101010100101101101010010010010100101101101" }, - /* 15*/ { BARCODE_CODE39, -1, "+A/E%U$A/D%T+Z", -1, 0, 1, 207, "Same as BARCODE_EXCODE39 'a%\000\001$\177z' below", + /* 9*/ { BARCODE_CODE39, -1, "+A/E%U$A/D%T+Z", -1, 0, 1, 207, "Same as BARCODE_EXCODE39 'a%\000\001$\177z' below", "100101101101010010100100101101010010110100100101001011010110010101010010010010110010101011010010010010101101010010110100100101001010101100101101010010010010101011011001010010100100101001101101010100101101101" }, - /* 16*/ { BARCODE_CODE39, -1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%", -1, 0, 1, 584, "Full CODE39 set", + /* 10*/ { BARCODE_CODE39, -1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%", -1, 0, 1, 584, "Full CODE39 set", "10010110110101010011011010110100101011010110010101101101100101010101001101011011010011010101011001101010101001011011011010010110101011001011010110101001011010110100101101101101001010101011001011011010110010101011011001010101010011011011010100110101011010011010101011001101011010101001101011010100110110110101001010101101001101101011010010101101101001010101011001101101010110010101101011001010101101100101100101010110100110101011011001101010101001011010110110010110101010011011010101001010110110110010101101010011010110101001001001010100100101001010010100100101010010010010100101101101" }, - /* 17*/ { BARCODE_EXCODE39, -1, "1A", -1, 0, 1, 51, "ISO/IEC 16388:2007 Figure 1", + /* 11*/ { BARCODE_EXCODE39, -1, "1A", -1, 0, 1, 51, "ISO/IEC 16388:2007 Figure 1", "100101101101011010010101101101010010110100101101101" }, - /* 18*/ { BARCODE_EXCODE39, 1, "1A", -1, 0, 1, 64, "With check digit", + /* 12*/ { BARCODE_EXCODE39, 1, "1A", -1, 0, 1, 64, "With check digit", "1001011011010110100101011011010100101101011010010110100101101101" }, - /* 19*/ { BARCODE_EXCODE39, 1, "Z4", -1, 0, 1, 64, "Check digit $", + /* 13*/ { BARCODE_EXCODE39, 1, "Z4", -1, 0, 1, 64, "Check digit $", "1001011011010100110110101010100110101101001001001010100101101101" }, - /* 20*/ { BARCODE_EXCODE39, -1, "a%\000\001$\177z", 7, 0, 1, 207, "Verified manually against TEC-IT", + /* 14*/ { BARCODE_EXCODE39, -1, "a%\000\001$\177z", 7, 0, 1, 207, "Verified manually against TEC-IT", "100101101101010010100100101101010010110100100101001011010110010101010010010010110010101011010010010010101101010010110100100101001010101100101101010010010010101011011001010010100100101001101101010100101101101" }, - /* 21*/ { BARCODE_EXCODE39, -1, "\033\037!+/\\@A~", -1, 0, 1, 246, "Verified manually against TEC-IT", + /* 15*/ { BARCODE_EXCODE39, -1, "\033\037!+/\\@A~", -1, 0, 1, 246, "Verified manually against TEC-IT", "100101101101010100100100101101010010110101001001001011010110010101001001010010110101001011010010010100101101010100110100100101001011010110100101010010010010101101010011010100100100101001101010110110101001011010100100100101011010110010100101101101" }, - /* 22*/ { BARCODE_EXCODE39, -1, " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]", -1, 0, 1, 1130, "Visible ASCII 1st 85 symbol chars", + /* 16*/ { BARCODE_EXCODE39, -1, " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]", -1, 0, 1, 1130, "Visible ASCII 1st 85 symbol chars", "10010110110101001101011010100100101001011010100101101001001010010101101001011010010010100101101101001010100100101001010101100101101001001010010110101100101010010010100101011011001010100100101001010101001101101001001010010110101001101010010010100101011010011010100100101001010101100110101001001010010110101010011010010010100101011010100110100101011011011001010110101001001010010110101101001010100110110101101001010110101100101011011011001010101010011010110110100110101010110011010101010010110110110100101101010110010110101001001010010100110110101010100100100101011011001010101001001001010101001101101010010010010110101001101010100100100101011010011010101001001001010101100110101010010010010100110101011011010100101101011010010110110110100101010101100101101101011001010101101100101010101001101101101010011010101101001101010101100110101101010100110101101010011011011010100101010110100110110101101001010110110100101010101100110110101011001010110101100101010110110010110010101011010011010101101100110101010100101101011011001011010101001101101010101001001001011010101001101010010010010101101010011010100100100101101101010010100101101101" }, - /* 23*/ { BARCODE_EXCODE39, -1, "^_`abcdefghijklmnopqrstuvwxyz{|}~", -1, 0, 1, 883, "Visible ASCII last part", + /* 17*/ { BARCODE_EXCODE39, -1, "^_`abcdefghijklmnopqrstuvwxyz{|}~", -1, 0, 1, 883, "Visible ASCII last part", "1001011011010101001001001010101101001101010010010010110101101001010100100100101100110101010100101001001011010100101101001010010010101101001011010010100100101101101001010100101001001010101100101101001010010010110101100101010010100100101011011001010100101001001010101001101101001010010010110101001101010010100100101011010011010100101001001010101100110101001010010010110101010011010010100100101011010100110100101001001011011010100101001010010010101011010011010010100100101101011010010100101001001010110110100101001010010010101010110011010010100100101101010110010100101001001010110101100101001010010010101011011001010010100100101100101010110100101001001010011010101101001010010010110011010101010010100100101001011010110100101001001011001011010101001010010010100110110101010100100100101011011010010101001001001010101011001101010010010010110101011001010100100100101011010110010100101101101" }, - /* 24*/ { BARCODE_LOGMARS, -1, "1A", -1, 0, 1, 63, "Verified manually against TEC-IT", + /* 18*/ { BARCODE_LOGMARS, -1, "1A", -1, 0, 1, 63, "Verified manually against TEC-IT", "100010111011101011101000101011101110101000101110100010111011101" }, - /* 25*/ { BARCODE_LOGMARS, 1, "1A", -1, 0, 1, 79, "With check digit; verified manually against TEC-IT", + /* 19*/ { BARCODE_LOGMARS, 1, "1A", -1, 0, 1, 79, "With check digit; verified manually against TEC-IT", "1000101110111010111010001010111011101010001011101011101000101110100010111011101" }, - /* 26*/ { BARCODE_LOGMARS, -1, "ABC", -1, 0, 1, 79, "MIL-STD-1189 Rev. B Figure 1", + /* 20*/ { BARCODE_LOGMARS, -1, "ABC", -1, 0, 1, 79, "MIL-STD-1189 Rev. B Figure 1", "1000101110111010111010100010111010111010001011101110111010001010100010111011101" }, - /* 27*/ { BARCODE_LOGMARS, -1, "SAMPLE 1", -1, 0, 1, 159, "MIL-STD-1189 Rev. B Figure 2 top", + /* 21*/ { BARCODE_LOGMARS, -1, "SAMPLE 1", -1, 0, 1, 159, "MIL-STD-1189 Rev. B Figure 2 top", "100010111011101010111010111000101110101000101110111011101010001010111011101000101011101010001110111010111000101010001110101110101110100010101110100010111011101" }, - /* 28*/ { BARCODE_LOGMARS, 1, "12345/ABCDE", -1, 0, 1, 223, "MIL-STD-1189 Rev. B Section 6.2.1 check character example; verified manually against TEC-IT", + /* 22*/ { BARCODE_LOGMARS, 1, "12345/ABCDE", -1, 0, 1, 223, "MIL-STD-1189 Rev. B Section 6.2.1 check character example; verified manually against TEC-IT", "1000101110111010111010001010111010111000101011101110111000101010101000111010111011101000111010101000100010100010111010100010111010111010001011101110111010001010101011100010111011101011100010101010111011100010100010111011101" }, - /* 29*/ { BARCODE_CODE93, -1, "C93", -1, 0, 1, 64, "ANSI/AIM BC5-1995 Figure 1; verified manually against TEC-IT", + /* 23*/ { BARCODE_CODE93, -1, "C93", -1, 0, 1, 64, "ANSI/AIM BC5-1995 Figure 1; verified manually against TEC-IT", "1010111101101000101000010101010000101101010001110110101010111101" }, - /* 30*/ { BARCODE_CODE93, -1, "CODE\01593", -1, 0, 1, 109, "ANSI/AIM BC5-1995 Figure B1; verified manually against TEC-IT", + /* 24*/ { BARCODE_CODE93, -1, "CODE\01593", -1, 0, 1, 109, "ANSI/AIM BC5-1995 Figure B1; verified manually against TEC-IT", "1010111101101000101001011001100101001100100101001001101010011001000010101010000101100101001000101101010111101" }, - /* 31*/ { BARCODE_CODE93, -1, "1A", -1, 0, 1, 55, "Verified manually against TEC-IT", + /* 25*/ { BARCODE_CODE93, -1, "1A", -1, 0, 1, 55, "Verified manually against TEC-IT", "1010111101010010001101010001101000101001110101010111101" }, - /* 32*/ { BARCODE_CODE93, -1, "TEST93", -1, 0, 1, 91, "Verified manually against TEC-IT", + /* 26*/ { BARCODE_CODE93, -1, "TEST93", -1, 0, 1, 91, "Verified manually against TEC-IT", "1010111101101001101100100101101011001101001101000010101010000101011101101001000101010111101" }, - /* 33*/ { BARCODE_CODE93, -1, "\000a\177", 3, 0, 1, 91, "Verified manually against TEC-IT", + /* 27*/ { BARCODE_CODE93, -1, "\000a\177", 3, 0, 1, 91, "Verified manually against TEC-IT", "1010111101110110101100101101001100101101010001110110101101001101011011101010010001010111101" }, - /* 34*/ { BARCODE_CODE93, -1, " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghij", -1, 0, 1, 1000, "Visible ASCII 1st 107 symbol chars", + /* 28*/ { BARCODE_CODE93, -1, " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghij", -1, 0, 1, 1000, "Visible ASCII 1st 107 symbol chars", "1010111101110100101110101101101010001110101101101001001110101101101000101110010101101011101110101101100010101110101101011010001110101101011001001110101101011000101110101101001101001011101101110101101010110001001011101110101001011011101000101001010010001010001001010000101001010001001001001001000101010100001000100101000010101110101101001110101110110101100010101110110101011010001110110101011001001110110101011000101110110101001101001110110101100110101101010001101001001101000101100101001100100101100010101011010001011001001011000101001101001000110101010110001010011001010001101001011001000101101101101001101100101101011001101001101100101101100110101011011001011001101001101101001110101110110101000110101110110101010110001110110101010011001110110101010001101110110101001011001110110101011011001001100101101010001001100101101001001001100101101000101001100101100101001001100101100100101001100101100010101001100101011010001001100101011001001001100101011000101001100101001101001010001101101001101010111101" }, - /* 35*/ { BARCODE_CODE93, -1, "klmnopqrstuvwxyz{|}~", -1, 0, 1, 397, "Visible ASCII last part", + /* 29*/ { BARCODE_CODE93, -1, "klmnopqrstuvwxyz{|}~", -1, 0, 1, 397, "Visible ASCII last part", "1010111101001100101000110101001100101010110001001100101010011001001100101010001101001100101001011001001100101000101101001100101101101001001100101101100101001100101101011001001100101101001101001100101100101101001100101100110101001100101011011001001100101011001101001100101001101101001100101001110101110110101000101101110110101101101001110110101101100101110110101101011001101001001101100101010111101" }, - /* 36*/ { BARCODE_PZN, -1, "1234567", -1, 0, 1, 142, "Example from IFA Info Code 39 EN V2.1; verified manually against TEC-IT", - "1001011011010100101011011011010010101101011001010110110110010101010100110101101101001101010101100110101010100101101101101001011010100101101101" - }, - /* 37*/ { BARCODE_PZN, -1, "2758089", -1, 0, 1, 142, "Example from IFA Info Check Digit Calculations EN 15 July 2019; verified manually against TEC-IT", - "1001011011010100101011011010110010101101010010110110110100110101011010010110101010011011010110100101101010110010110101011001011010100101101101" - }, - /* 38*/ { BARCODE_PZN, 1, "123456", -1, 0, 1, 129, "Example from BWIPP; verified manually against TEC-IT", - "100101101101010010101101101101001010110101100101011011011001010101010011010110110100110101010110011010101011001010110100101101101" - }, - /* 39*/ { BARCODE_VIN, -1, "1FTCR10UXTPA78180", -1, 0, 1, 246, "https://www.vinquery.com/img/vinbarcode/vinbarcode4.jpg", + /* 30*/ { BARCODE_VIN, -1, "1FTCR10UXTPA78180", -1, 0, 1, 246, "https://www.vinquery.com/img/vinbarcode/vinbarcode4.jpg", "100101101101011010010101101011011001010101011011001011011010010101101010110010110100101011010100110110101100101010110100101101011010101101100101011011010010110101001011010100101101101101001011010110100101011011010010110101010011011010100101101101" }, - /* 40*/ { BARCODE_VIN, 1, "2FTPX28L0XCA15511", -1, 0, 1, 259, "With Import 'I' prefix; https://www.vinquery.com/img/vinbarcode/vinbarcode1.jpg", + /* 31*/ { BARCODE_VIN, 1, "2FTPX28L0XCA15511", -1, 0, 1, 259, "With Import 'I' prefix; https://www.vinquery.com/img/vinbarcode/vinbarcode1.jpg", "1001011011010101101001101010110010101101011011001010101011011001010110110100101001011010110101100101011011010010110101011010100110101001101101010010110101101101101001010110101001011011010010101101101001101010110100110101011010010101101101001010110100101101101" }, - /* 41*/ { BARCODE_HIBC_39, -1, "A123BJC5D6E71", -1, 0, 1, 271, "ANSI/HIBC 2.6 - 2016 Figure 2, same", + /* 32*/ { BARCODE_HIBC_39, -1, "A123BJC5D6E71", -1, 0, 1, 271, "ANSI/HIBC 2.6 - 2016 Figure 2, same", "1000101110111010100010100010001011101010001011101110100010101110101110001010111011101110001010101011101000101110101011100011101011101110100010101110100011101010101011100010111010111000111010101110101110001010101000101110111011101000101011101010100011101110100010111011101" }, - /* 42*/ { BARCODE_HIBC_39, -1, "$$52001510X3G", -1, 0, 1, 271, "ANSI/HIBC 2.6 - 2016 Figure 6, same", + /* 33*/ { BARCODE_HIBC_39, -1, "$$52001510X3G", -1, 0, 1, 271, "ANSI/HIBC 2.6 - 2016 Figure 6, same", "1000101110111010100010100010001010001000100010101000100010001010111010001110101010111000101011101010001110111010101000111011101011101000101011101110100011101010111010001010111010100011101110101000101110101110111011100010101010101000111011101010111000101110100010111011101" }, }; @@ -551,8 +491,6 @@ static void test_perf(const testCtx *const p_ctx) { "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !\"#$%&'()*+,-./0123456789ABCDEFGHIJ", 0, 1, 1000, "CODE93 107 symbol chars" }, /* 3*/ { BARCODE_CODE93, -1, "123456ABCD", 0, 1, 127, "CODE93 10" }, - /* 4*/ { BARCODE_CODE11, -1, "1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-", 0, 1, 966, "CODE11 121" }, - /* 5*/ { BARCODE_CODE11, -1, "1234567890-", 0, 1, 116, "CODE11 5" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; diff --git a/backend/tests/test_code11.c b/backend/tests/test_code11.c new file mode 100644 index 00000000..fa92f95f --- /dev/null +++ b/backend/tests/test_code11.c @@ -0,0 +1,412 @@ +/* + libzint - the open source barcode library + Copyright (C) 2020-2025 Robin 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* Was in "test_code.c" */ + +#include "testcommon.h" + +static void test_large(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + int option_2; + char *pattern; + int length; + int ret; + int expected_rows; + int expected_width; + char *expected_errtxt; + }; + /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ + static const struct item data[] = { + /* 0*/ { BARCODE_CODE11, -1, "13", 140, 0, 1, 1151, "" }, /* 8 (Start) + 140*8 + 2*8 (Checks) + 7 (Stop) == 1151 */ + /* 1*/ { BARCODE_CODE11, -1, "13", 141, ZINT_ERROR_TOO_LONG, -1, -1, "Error 320: Input length 141 too long (maximum 140)" }, + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol = NULL; + + char data_buf[4096]; + + testStartSymbol("test_large", &symbol); + + for (i = 0; i < data_size; i++) { + + if (testContinue(p_ctx, i)) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + testUtilStrCpyRepeat(data_buf, data[i].pattern, data[i].length); + assert_equal(data[i].length, (int) strlen(data_buf), "i:%d length %d != strlen(data_buf) %d\n", i, data[i].length, (int) strlen(data_buf)); + + length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, data[i].option_2, -1, -1 /*output_options*/, data_buf, data[i].length, debug); + + ret = ZBarcode_Encode(symbol, (unsigned char *) data_buf, length); + assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + assert_equal(symbol->errtxt[0] == '\0', ret == 0, "i:%d symbol->errtxt not %s (%s)\n", i, ret ? "set" : "empty", symbol->errtxt); + assert_zero(strcmp(symbol->errtxt, data[i].expected_errtxt), "i:%d strcmp(%s, %s) != 0\n", i, symbol->errtxt, data[i].expected_errtxt); + + if (ret < ZINT_ERROR) { + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d\n", i, symbol->rows, data[i].expected_rows); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d\n", i, symbol->width, data[i].expected_width); + } + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +static void test_hrt(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + int option_2; + char *data; + int length; + + char *expected; + }; + /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ + static const struct item data[] = { + /* 0*/ { BARCODE_CODE11, -1, "123-45", -1, "123-4552" }, /* 2 checksums */ + /* 1*/ { BARCODE_CODE11, 1, "123-45", -1, "123-455" }, /* 1 check digit */ + /* 2*/ { BARCODE_CODE11, 2, "123-45", -1, "123-45" }, /* No checksums */ + /* 3*/ { BARCODE_CODE11, -1, "123456789012", -1, "123456789012-8" }, /* First check digit 10 (A) goes to hyphen */ + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol = NULL; + + testStartSymbol("test_hrt", &symbol); + + for (i = 0; i < data_size; i++) { + + if (testContinue(p_ctx, i)) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, data[i].option_2, -1, -1 /*output_options*/, data[i].data, data[i].length, debug); + + ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); + assert_zero(ret, "i:%d ZBarcode_Encode ret %d != 0 %s\n", i, ret, symbol->errtxt); + + assert_zero(strcmp((char *) symbol->text, data[i].expected), "i:%d strcmp(%s, %s) != 0\n", i, symbol->text, data[i].expected); + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +static void test_input(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + int input_mode; + int option_2; + char *data; + int length; + int ret; + int expected_rows; + int expected_width; + char *expected_errtxt; + }; + /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ + static const struct item data[] = { + /* 0*/ { BARCODE_CODE11, -1, -1, "-", -1, 0, 1, 37, "" }, + /* 1*/ { BARCODE_CODE11, -1, -1, "0123456789-", -1, 0, 1, 115, "" }, + /* 2*/ { BARCODE_CODE11, -1, -1, "A", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 1 in input (digits and \"-\" only)" }, + /* 3*/ { BARCODE_CODE11, -1, -1, "12+", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 3 in input (digits and \"-\" only)" }, + /* 4*/ { BARCODE_CODE11, -1, -1, "1.2", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 2 in input (digits and \"-\" only)" }, + /* 5*/ { BARCODE_CODE11, -1, -1, "12!", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 3 in input (digits and \"-\" only)" }, + /* 6*/ { BARCODE_CODE11, -1, -1, " ", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 1 in input (digits and \"-\" only)" }, + /* 7*/ { BARCODE_CODE11, ESCAPE_MODE, -1, "\\d048 ", -1, ZINT_ERROR_INVALID_DATA, -1, -1, "Error 321: Invalid character at position 2 in input (digits and \"-\" only)" }, /* Note position doesn't account for escape sequences */ + /* 8*/ { BARCODE_CODE11, -1, 3, "1", -1, ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 339: Invalid check digit version '3' (1 or 2 only)" }, + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol = NULL; + + testStartSymbol("test_input", &symbol); + + for (i = 0; i < data_size; i++) { + + if (testContinue(p_ctx, i)) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + length = testUtilSetSymbol(symbol, data[i].symbology, data[i].input_mode, -1 /*eci*/, -1 /*option_1*/, data[i].option_2, -1, -1 /*output_options*/, data[i].data, data[i].length, debug); + + ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); + assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + assert_equal(symbol->errtxt[0] == '\0', ret == 0, "i:%d symbol->errtxt not %s (%s)\n", i, ret ? "set" : "empty", symbol->errtxt); + assert_zero(strcmp(symbol->errtxt, data[i].expected_errtxt), "i:%d strcmp(%s, %s) != 0\n", i, symbol->errtxt, data[i].expected_errtxt); + + if (ret < ZINT_ERROR) { + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d\n", i, symbol->rows, data[i].expected_rows); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d\n", i, symbol->width, data[i].expected_width); + } + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +static void test_encode(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + int option_2; + char *data; + int length; + int ret; + + int expected_rows; + int expected_width; + char *comment; + char *expected; + }; + static const struct item data[] = { + /* 0*/ { BARCODE_CODE11, -1, "123-45", -1, 0, 1, 78, "2 check digits (52); verified manually against TEC-IT", + "101100101101011010010110110010101011010101101101101101011011010100101101011001" + }, + /* 1*/ { BARCODE_CODE11, -1, "93", -1, 0, 1, 44, "2 check digits (--); verified manually against TEC-IT", + "10110010110101011001010101101010110101011001" + }, + /* 2*/ { BARCODE_CODE11, 1, "123-455", -1, 0, 1, 78, "1 check digit (2); verified manually against TEC-IT", + "101100101101011010010110110010101011010101101101101101011011010100101101011001" + }, + /* 3*/ { BARCODE_CODE11, 2, "123-4552", -1, 0, 1, 78, "0 check digits; verified manually against TEC-IT", + "101100101101011010010110110010101011010101101101101101011011010100101101011001" + }, + /* 4*/ { BARCODE_CODE11, 1, "123-45", -1, 0, 1, 70, "1 check digit; verified manually against TEC-IT", + "1011001011010110100101101100101010110101011011011011010110110101011001" + }, + /* 5*/ { BARCODE_CODE11, 2, "123-45", -1, 0, 1, 62, "0 check digits; verified manually against TEC-IT", + "10110010110101101001011011001010101101010110110110110101011001" + }, + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol = NULL; + + char escaped[1024]; + char cmp_buf[8192]; + char cmp_msg[1024]; + + int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ + int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder(); /* Only do ZXing-C++ test if asked, too slow otherwise */ + + testStartSymbol("test_encode", &symbol); + + for (i = 0; i < data_size; i++) { + + if (testContinue(p_ctx, i)) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, data[i].option_2, -1, -1 /*output_options*/, data[i].data, data[i].length, debug); + + ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); + assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + + if (p_ctx->generate) { + printf(" /*%3d*/ { %s, %d, \"%s\", %d, %s, %d, %d, \"%s\",\n", + i, testUtilBarcodeName(data[i].symbology), data[i].option_2, testUtilEscape(data[i].data, length, escaped, sizeof(escaped)), data[i].length, + testUtilErrorName(data[i].ret), symbol->rows, symbol->width, data[i].comment); + testUtilModulesPrint(symbol, " ", "\n"); + printf(" },\n"); + } else { + if (ret < ZINT_ERROR) { + int width, row; + + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d (%s)\n", i, symbol->rows, data[i].expected_rows, data[i].data); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", i, symbol->width, data[i].expected_width, data[i].data); + + ret = testUtilModulesCmp(symbol, data[i].expected, &width, &row); + assert_zero(ret, "i:%d testUtilModulesCmp ret %d != 0 width %d row %d (%s)\n", i, ret, width, row, data[i].data); + + if (do_bwipp && testUtilCanBwipp(i, symbol, -1, data[i].option_2, -1, debug)) { + ret = testUtilBwipp(i, symbol, -1, data[i].option_2, -1, data[i].data, length, NULL, cmp_buf, sizeof(cmp_buf), NULL); + assert_zero(ret, "i:%d %s testUtilBwipp ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilBwippCmp(symbol, cmp_msg, cmp_buf, data[i].expected); + assert_zero(ret, "i:%d %s testUtilBwippCmp %d != 0 %s\n actual: %s\nexpected: %s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_buf, data[i].expected); + } + if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data[i].data, length, debug)) { + int cmp_len, ret_len; + char modules_dump[8192 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, cmp_buf, sizeof(cmp_buf), &cmp_len); + assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length, NULL /*primary*/, escaped, &ret_len); + assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len, escaped); + } + } + } + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +#include + +#define TEST_PERF_ITER_MILLES 5 +#define TEST_PERF_ITERATIONS (TEST_PERF_ITER_MILLES * 1000) +#define TEST_PERF_TIME(arg) ((arg) * 1000.0 / CLOCKS_PER_SEC) + +/* Not a real test, just performance indicator */ +static void test_perf(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + int option_2; + char *data; + int ret; + + int expected_rows; + int expected_width; + char *comment; + }; + static const struct item data[] = { + /* 0*/ { BARCODE_CODE11, -1, "1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-", 0, 1, 966, "CODE11 121" }, + /* 1*/ { BARCODE_CODE11, -1, "1234567890-", 0, 1, 116, "CODE11 5" }, + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol; + + clock_t start; + clock_t total_create = 0, total_encode = 0, total_buffer = 0, total_buf_inter = 0, total_print = 0; + clock_t diff_create, diff_encode, diff_buffer, diff_buf_inter, diff_print; + int comment_max = 0; + + if (!(debug & ZINT_DEBUG_TEST_PERFORMANCE)) { /* -d 256 */ + return; + } + + for (i = 0; i < data_size; i++) if ((int) strlen(data[i].comment) > comment_max) comment_max = (int) strlen(data[i].comment); + + printf("Iterations %d\n", TEST_PERF_ITERATIONS); + + for (i = 0; i < data_size; i++) { + int j; + + if (testContinue(p_ctx, i)) continue; + + diff_create = diff_encode = diff_buffer = diff_buf_inter = diff_print = 0; + + for (j = 0; j < TEST_PERF_ITERATIONS; j++) { + start = clock(); + symbol = ZBarcode_Create(); + diff_create += clock() - start; + assert_nonnull(symbol, "Symbol not created\n"); + + length = testUtilSetSymbol(symbol, data[i].symbology, DATA_MODE, -1 /*eci*/, -1 /*option_1*/, data[i].option_2, -1, -1 /*output_options*/, data[i].data, -1, debug); + + start = clock(); + ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); + diff_encode += clock() - start; + assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d (%s)\n", i, symbol->rows, data[i].expected_rows, data[i].data); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", i, symbol->width, data[i].expected_width, data[i].data); + + start = clock(); + ret = ZBarcode_Buffer(symbol, 0 /*rotate_angle*/); + diff_buffer += clock() - start; + assert_zero(ret, "i:%d ZBarcode_Buffer ret %d != 0 (%s)\n", i, ret, symbol->errtxt); + + symbol->output_options |= OUT_BUFFER_INTERMEDIATE; + start = clock(); + ret = ZBarcode_Buffer(symbol, 0 /*rotate_angle*/); + diff_buf_inter += clock() - start; + assert_zero(ret, "i:%d ZBarcode_Buffer OUT_BUFFER_INTERMEDIATE ret %d != 0 (%s)\n", i, ret, symbol->errtxt); + symbol->output_options &= ~OUT_BUFFER_INTERMEDIATE; /* Undo */ + + start = clock(); + ret = ZBarcode_Print(symbol, 0 /*rotate_angle*/); + diff_print += clock() - start; + assert_zero(ret, "i:%d ZBarcode_Print ret %d != 0 (%s)\n", i, ret, symbol->errtxt); + assert_zero(testUtilRemove(symbol->outfile), "i:%d testUtilRemove(%s) != 0\n", i, symbol->outfile); + + ZBarcode_Delete(symbol); + } + + printf("%*s: encode % 8gms, buffer % 8gms, buf_inter % 8gms, print % 8gms, create % 8gms\n", comment_max, data[i].comment, + TEST_PERF_TIME(diff_encode), TEST_PERF_TIME(diff_buffer), TEST_PERF_TIME(diff_buf_inter), TEST_PERF_TIME(diff_print), TEST_PERF_TIME(diff_create)); + + total_create += diff_create; + total_encode += diff_encode; + total_buffer += diff_buffer; + total_buf_inter += diff_buf_inter; + total_print += diff_print; + } + if (p_ctx->index == -1) { + printf("%*s: encode % 8gms, buffer % 8gms, buf_inter % 8gms, print % 8gms, create % 8gms\n", comment_max, "totals", + TEST_PERF_TIME(total_encode), TEST_PERF_TIME(total_buffer), TEST_PERF_TIME(total_buf_inter), TEST_PERF_TIME(total_print), TEST_PERF_TIME(total_create)); + } +} + +int main(int argc, char *argv[]) { + + testFunction funcs[] = { /* name, func */ + { "test_large", test_large }, + { "test_hrt", test_hrt }, + { "test_input", test_input }, + { "test_encode", test_encode }, + { "test_perf", test_perf }, + }; + + testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); + + testReport(); + + return 0; +} + +/* vim: set ts=4 sw=4 et : */ diff --git a/backend/tests/test_dmatrix.c b/backend/tests/test_dmatrix.c index 3970b62c..5d8a7f0b 100644 --- a/backend/tests/test_dmatrix.c +++ b/backend/tests/test_dmatrix.c @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2019-2024 Robin Stuart + Copyright (C) 2019-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -358,7 +358,12 @@ static void test_large(const testCtx *const p_ctx) { struct zint_symbol *symbol = NULL; char data_buf[ZINT_MAX_DATA_LEN]; - char escaped[64]; + + char escaped[8192]; + char cmp_buf[32768]; + char cmp_msg[1024]; + + int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder(); /* Only do ZXing-C++ test if asked, too slow otherwise */ testStartSymbol("test_large", &symbol); @@ -387,6 +392,7 @@ static void test_large(const testCtx *const p_ctx) { data[i].structapp.index, data[i].structapp.count, data[i].structapp.id, testUtilEscape(data[i].pattern, (int) strlen(data[i].pattern), escaped, sizeof(escaped)), data[i].length, testUtilErrorName(ret), symbol->rows, symbol->width, errtxt); + ZBarcode_Clear(symbol); symbol->input_mode |= FAST_MODE; (void) ZBarcode_Encode(symbol, (unsigned char *) data_buf, length); printf(" \"%s\", \"%s\" },\n", strcmp(errtxt, symbol->errtxt) != 0 ? symbol->errtxt : "", data[i].comment); @@ -398,8 +404,20 @@ static void test_large(const testCtx *const p_ctx) { if (ret < ZINT_ERROR) { assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d\n", i, symbol->rows, data[i].expected_rows); assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d\n", i, symbol->width, data[i].expected_width); + if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data_buf, length, debug)) { + int cmp_len, ret_len; + char modules_dump[144 * 144 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilZXingCPP(i, symbol, data_buf, length, modules_dump, cmp_buf, sizeof(cmp_buf), &cmp_len); + assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data_buf, length, NULL /*primary*/, escaped, &ret_len); + assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len, escaped); + } } + ZBarcode_Clear(symbol); symbol->input_mode |= FAST_MODE; ret = ZBarcode_Encode(symbol, (unsigned char *) data_buf, length); assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); @@ -408,6 +426,17 @@ static void test_large(const testCtx *const p_ctx) { if (ret < ZINT_ERROR) { assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d\n", i, symbol->rows, data[i].expected_rows); assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d\n", i, symbol->width, data[i].expected_width); + if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data_buf, length, debug)) { + int cmp_len, ret_len; + char modules_dump[144 * 144 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilZXingCPP(i, symbol, data_buf, length, modules_dump, cmp_buf, sizeof(cmp_buf), &cmp_len); + assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data_buf, length, NULL /*primary*/, escaped, &ret_len); + assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len, escaped); + } } else { if (data[i].expected_errtxt2[0]) { assert_zero(strcmp(symbol->errtxt, data[i].expected_errtxt2), "i:%d strcmp(%s, %s) != 0\n", i, symbol->errtxt, data[i].expected_errtxt2); @@ -433,17 +462,25 @@ static void test_buffer(const testCtx *const p_ctx) { int output_options; char *data; int ret; + int bwipp_cmp; char *comment; }; /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ static const struct item data[] = { - /* 0*/ { 16383, UNICODE_MODE, READER_INIT, "1", 0, "" }, - /* 1*/ { 3, UNICODE_MODE, 0, "000106j 05 Galeria A Nação0000000000", 0, "From Okapi, consecutive use of upper shift; #176" }, + /* 0*/ { 16383, UNICODE_MODE, READER_INIT, "1", 0, 1, "" }, + /* 1*/ { 3, UNICODE_MODE, 0, "000106j 05 Galeria A Nação0000000000", 0, 0, "From Okapi, consecutive use of upper shift; #176; BWIPP different encodation" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; struct zint_symbol *symbol = NULL; + char escaped[8192]; + char cmp_buf[32768]; + char cmp_msg[1024]; + + int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ + int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder(); /* Only do ZXing-C++ test if asked, too slow otherwise */ + testStartSymbol("test_buffer", &symbol); for (i = 0; i < data_size; i++) { @@ -457,6 +494,31 @@ static void test_buffer(const testCtx *const p_ctx) { ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d\n", i, ret, data[i].ret); + if (do_bwipp && testUtilCanBwipp(i, symbol, -1, -1, -1, debug)) { + if (!data[i].bwipp_cmp) { + if (debug & ZINT_DEBUG_TEST_PRINT) printf("i:%d %s not BWIPP compatible (%s)\n", i, testUtilBarcodeName(symbol->symbology), data[i].comment); + } else { + char modules_dump[144 * 144 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilBwipp(i, symbol, -1, -1, -1, data[i].data, length, NULL, cmp_buf, sizeof(cmp_buf), NULL); + assert_zero(ret, "i:%d %s testUtilBwipp ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilBwippCmp(symbol, cmp_msg, cmp_buf, modules_dump); + assert_zero(ret, "i:%d %s testUtilBwippCmp %d != 0 %s\n actual: %s\nexpected: %s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_buf, modules_dump); + } + } + if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data[i].data, length, debug)) { + int cmp_len, ret_len; + char modules_dump[144 * 144 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, cmp_buf, sizeof(cmp_buf), &cmp_len); + assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length, NULL /*primary*/, escaped, &ret_len); + assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len, escaped); + } ZBarcode_Delete(symbol); } @@ -481,114 +543,123 @@ static void test_options(const testCtx *const p_ctx) { int expected_rows; int expected_width; const char *expected_errtxt; + int bwipp_cmp; + const char *comment; }; /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ static const struct item data[] = { - /* 0*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "1", 0, 10, 10, "" }, - /* 1*/ { BARCODE_DATAMATRIX, -1, 2, -1, -1, -1, { 0, 0, "" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 524: Older Data Matrix standards are no longer supported" }, - /* 2*/ { BARCODE_DATAMATRIX, -1, -1, 1, -1, -1, { 0, 0, "" }, "1", 0, 10, 10, "" }, - /* 3*/ { BARCODE_DATAMATRIX, -1, -1, 2, -1, -1, { 0, 0, "" }, "1", 0, 12, 12, "" }, - /* 4*/ { BARCODE_DATAMATRIX, -1, -1, 48, -1, -1, { 0, 0, "" }, "1", 0, 26, 64, "" }, - /* 5*/ { BARCODE_DATAMATRIX, -1, -1, 49, -1, -1, { 0, 0, "" }, "1", 0, 10, 10, "" }, /* Ignored */ - /* 6*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "____", 0, 12, 12, "" }, /* 4 data */ - /* 7*/ { BARCODE_DATAMATRIX, -1, -1, 1, -1, -1, { 0, 0, "" }, "____", ZINT_ERROR_TOO_LONG, -1, -1, "Error 522: Input too long for Version 1, requires 4 codewords (maximum 3)" }, - /* 8*/ { BARCODE_DATAMATRIX, -1, -1, 25, -1, -1, { 0, 0, "" }, "____", 0, 8, 18, "" }, - /* 9*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "__________", 0, 8, 32, "" }, /* 10 data */ - /* 10*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "__________", 0, 8, 32, "" }, - /* 11*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE | DM_ISO_144, -1, { 0, 0, "" }, "__________", 0, 8, 32, "" }, - /* 12*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "__________", 0, 16, 16, "" }, - /* 13*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE | DM_ISO_144, -1, { 0, 0, "" }, "__________", 0, 16, 16, "" }, - /* 14*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________", 0, 12, 26, "" }, /* 15 data */ - /* 15*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________", 0, 12, 26, "" }, - /* 16*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________", 0, 18, 18, "" }, - /* 17*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "__________________", 0, 18, 18, "" }, /* 18 data */ - /* 18*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "___________________", 0, 20, 20, "" }, /* 19 data */ - /* 19*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_____________________", 0, 20, 20, "" }, /* 21 data */ - /* 20*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________________", 0, 22, 22, "" }, /* 23 data */ - /* 21*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________________", 0, 8, 64, "" }, - /* 22*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________________", 0, 22, 22, "" }, - /* 23*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________________________", 0, 16, 36, "" }, /* 31 data */ - /* 24*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________________________", 0, 16, 36, "" }, - /* 25*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________________________", 0, 24, 24, "" }, - /* 26*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_____________________________________", 0, 26, 26, "" }, /* 37 data */ - /* 27*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_____________________________________", 0, 8, 96, "" }, - /* 28*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_____________________________________", 0, 26, 26, "" }, - /* 29*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________________________________", 0, 26, 26, "" }, /* 39 data */ - /* 30*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________________________________", 0, 12, 64, "" }, - /* 31*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________________________________", 0, 26, 26, "" }, - /* 32*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "___________________________________________", 0, 26, 26, "" }, /* 43 data */ - /* 33*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "___________________________________________", 0, 12, 64, "" }, - /* 34*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "___________________________________________", 0, 26, 26, "" }, - /* 35*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "____________________________________________", 0, 26, 26, "" }, /* 44 data */ - /* 36*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_____________________________________________", 0, 16, 48, "" }, /* 45 data */ - /* 37*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_____________________________________________", 0, 16, 48, "" }, - /* 38*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_____________________________________________", 0, 32, 32, "" }, - /* 39*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_________________________________________________", 0, 16, 48, "" }, /* 49 data */ - /* 40*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_________________________________________________", 0, 16, 48, "" }, - /* 41*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_________________________________________________", 0, 32, 32, "" }, - /* 42*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "__________________________________________________", 0, 32, 32, "" }, /* 50 data */ - /* 43*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "__________________________________________________", 0, 20, 44, "" }, - /* 44*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "__________________________________________________", 0, 32, 32, "" }, - /* 45*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU", 0, 32, 32, "" }, /* 51 data */ - /* 46*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU", 0, 20, 44, "" }, - /* 47*/ { BARCODE_DATAMATRIX, -1, -1, -1, 9999, -1, { 0, 0, "" }, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU", 0, 32, 32, "" }, /* Ignored */ - /* 48*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_____________________________________________________________", 0, 32, 32, "" }, /* 61 data */ - /* 49*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "______________________________________________________________", 0, 32, 32, "" }, /* 62 data */ - /* 50*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________________________________________________________", 0, 36, 36, "" }, /* 63 data */ - /* 51*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________________________________________________________", 0, 8, 144, "" }, - /* 52*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________________________________________________________", 0, 36, 36, "" }, - /* 53*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "________________________________________________________________", 0, 36, 36, "" }, /* 64 data */ - /* 54*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "________________________________________________________________", 0, 12, 88, "" }, - /* 55*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "________________________________________________________________", 0, 36, 36, "" }, - /* 56*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_________________________________________________________________", 0, 36, 36, "" }, /* 65 data */ - /* 57*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_________________________________________________________________", 0, 26, 40, "" }, - /* 58*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_________________________________________________________________", 0, 36, 36, "" }, - /* 59*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "______________________________________________________________________", 0, 36, 36, "" }, /* 70 data */ - /* 60*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "______________________________________________________________________", 0, 26, 40, "" }, - /* 61*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "______________________________________________________________________", 0, 36, 36, "" }, - /* 62*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________________________________________________________________", 0, 36, 36, "" }, /* 71 data */ - /* 63*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________________________________________________________________", 0, 22, 48, "" }, - /* 64*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________________________________________________________________", 0, 36, 36, "" }, - /* 65*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "________________________________________________________________________________", 0, 36, 36, "" }, /* 80 data */ - /* 66*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "________________________________________________________________________________", 0, 24, 48, "" }, - /* 67*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "________________________________________________________________________________", 0, 36, 36, "" }, - /* 68*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "____________________________________________________________________________________", 0, 36, 36, "" }, /* 84 data */ - /* 69*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "____________________________________________________________________________________", 0, 20, 64, "" }, - /* 70*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "____________________________________________________________________________________", 0, 36, 36, "" }, - /* 71*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "__________________________________________________________________________________________", 0, 40, 40, "" }, /* 90 data */ - /* 72*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "__________________________________________________________________________________________", 0, 26, 48, "" }, - /* 73*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "__________________________________________________________________________________________", 0, 40, 40, "" }, - /* 74*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "___________________________________________________________________________________________", 0, 40, 40, "" }, /* 91 data */ - /* 75*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "___________________________________________________________________________________________", 0, 24, 64, "" }, - /* 76*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "___________________________________________________________________________________________", 0, 40, 40, "" }, - /* 77*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "______________________________________________________________________________________________________________________", 0, 44, 44, "" }, /* 118 data */ - /* 78*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "______________________________________________________________________________________________________________________", 0, 26, 64, "" }, /* 118 data */ - /* 79*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "______________________________________________________________________________________________________________________", 0, 44, 44, "" }, /* 118 data */ - /* 80*/ { BARCODE_DATAMATRIX, GS1_MODE, -1, -1, -1, -1, { 0, 0, "" }, "[90]12", 0, 10, 10, "" }, - /* 81*/ { BARCODE_DATAMATRIX, GS1_MODE | GS1PARENS_MODE, -1, -1, -1, -1, { 0, 0, "" }, "(90)12", 0, 10, 10, "" }, - /* 82*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 1, 2, "" }, "1", 0, 12, 12, "" }, - /* 83*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 16, 16, "" }, "1", 0, 12, 12, "" }, - /* 84*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 1, 1, "" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 720: Structured Append count '1' out of range (2 to 16)" }, - /* 85*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 1, 17, "" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 720: Structured Append count '17' out of range (2 to 16)" }, - /* 86*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 16, "" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 721: Structured Append index '0' out of range (1 to count 16)" }, - /* 87*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 17, 16, "" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 721: Structured Append index '17' out of range (1 to count 16)" }, - /* 88*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "1001" }, "1", 0, 12, 12, "" }, - /* 89*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "A" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 723: Invalid Structured Append ID (digits only)" }, - /* 90*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "0" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 724: Structured Append ID1 '000' and ID2 '000' out of range (001 to 254) (ID \"000000\")" }, - /* 91*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "1" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 725: Structured Append ID1 '000' out of range (001 to 254) (ID \"000001\")" }, - /* 92*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "1000" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 726: Structured Append ID2 '000' out of range (001 to 254) (ID \"001000\")" }, - /* 93*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "001255" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 726: Structured Append ID2 '255' out of range (001 to 254) (ID \"001255\")" }, - /* 94*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "255001" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 725: Structured Append ID1 '255' out of range (001 to 254) (ID \"255001\")" }, - /* 95*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "255255" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 724: Structured Append ID1 '255' and ID2 '255' out of range (001 to 254) (ID \"255255\")" }, - /* 96*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "1234567" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 722: Structured Append ID length 7 too long (6 digit maximum)" }, - /* 97*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, READER_INIT, { 2, 3, "1001" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 727: Cannot have Structured Append and Reader Initialisation at the same time" }, - /* 98*/ { BARCODE_DATAMATRIX, ESCAPE_MODE, -1, -1, -1, -1, { 2, 3, "1001" }, "[)>\\R05\\GA\\R\\E", 0, 12, 26, "" }, /* Macro05/06 ignored if have Structured Append TODO: error/warning */ - /* 99*/ { BARCODE_HIBC_DM, -1, -1, -1, -1, -1, { 0, 0, "" }, "1234,67", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 203: Invalid character at position 5 in input (alphanumerics, space and \"-.$/+%\" only)" }, + /* 0*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "1", 0, 10, 10, "", 1, "" }, + /* 1*/ { BARCODE_DATAMATRIX, -1, 2, -1, -1, -1, { 0, 0, "" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 524: Older Data Matrix standards are no longer supported", 1, "" }, + /* 2*/ { BARCODE_DATAMATRIX, -1, -1, 1, -1, -1, { 0, 0, "" }, "1", 0, 10, 10, "", 1, "" }, + /* 3*/ { BARCODE_DATAMATRIX, -1, -1, 2, -1, -1, { 0, 0, "" }, "1", 0, 12, 12, "", 1, "" }, + /* 4*/ { BARCODE_DATAMATRIX, -1, -1, 48, -1, -1, { 0, 0, "" }, "1", 0, 26, 64, "", 1, "" }, + /* 5*/ { BARCODE_DATAMATRIX, -1, -1, 49, -1, -1, { 0, 0, "" }, "1", 0, 10, 10, "", 0, "Ignored; BWIPP no options set" }, + /* 6*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "____", 0, 12, 12, "", 1, "4 data" }, + /* 7*/ { BARCODE_DATAMATRIX, -1, -1, 1, -1, -1, { 0, 0, "" }, "____", ZINT_ERROR_TOO_LONG, -1, -1, "Error 522: Input too long for Version 1, requires 4 codewords (maximum 3)", 1, "" }, + /* 8*/ { BARCODE_DATAMATRIX, -1, -1, 25, -1, -1, { 0, 0, "" }, "____", 0, 8, 18, "", 1, "" }, + /* 9*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "__________", 0, 8, 32, "", 1, "10 data" }, + /* 10*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "__________", 0, 8, 32, "", 1, "" }, + /* 11*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE | DM_ISO_144, -1, { 0, 0, "" }, "__________", 0, 8, 32, "", 1, "" }, + /* 12*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "__________", 0, 16, 16, "", 1, "" }, + /* 13*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE | DM_ISO_144, -1, { 0, 0, "" }, "__________", 0, 16, 16, "", 1, "" }, + /* 14*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________", 0, 12, 26, "", 1, "15 data" }, + /* 15*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________", 0, 12, 26, "", 1, "" }, + /* 16*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________", 0, 18, 18, "", 1, "" }, + /* 17*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "__________________", 0, 18, 18, "", 1, "18 data" }, + /* 18*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "___________________", 0, 20, 20, "", 1, "19 data" }, + /* 19*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_____________________", 0, 20, 20, "", 1, "21 data" }, + /* 20*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________________", 0, 22, 22, "", 1, "23 data" }, + /* 21*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________________", 0, 8, 64, "", 1, "" }, + /* 22*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________________", 0, 22, 22, "", 1, "" }, + /* 23*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________________________", 0, 16, 36, "", 1, "31 data" }, + /* 24*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________________________", 0, 16, 36, "", 0, "BWIPP DMRE requires dimensions" }, + /* 25*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________________________", 0, 24, 24, "", 1, "" }, + /* 26*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_____________________________________", 0, 26, 26, "", 1, "37 data" }, + /* 27*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_____________________________________", 0, 8, 96, "", 1, "" }, + /* 28*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_____________________________________", 0, 26, 26, "", 1, "" }, + /* 29*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________________________________", 0, 26, 26, "", 1, "39 data" }, + /* 30*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________________________________", 0, 12, 64, "", 1, "" }, + /* 31*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________________________________", 0, 26, 26, "", 1, "" }, + /* 32*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "___________________________________________", 0, 26, 26, "", 1, "43 data" }, + /* 33*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "___________________________________________", 0, 12, 64, "", 1, "" }, + /* 34*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "___________________________________________", 0, 26, 26, "", 1, "" }, + /* 35*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "____________________________________________", 0, 26, 26, "", 1, "44 data" }, + /* 36*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_____________________________________________", 0, 16, 48, "", 1, "45 data" }, + /* 37*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_____________________________________________", 0, 16, 48, "", 0, "BWIPP DMRE requires dimensions" }, + /* 38*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_____________________________________________", 0, 32, 32, "", 1, "" }, + /* 39*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_________________________________________________", 0, 16, 48, "", 1, "49 data" }, + /* 40*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_________________________________________________", 0, 16, 48, "", 0, "BWIPP DMRE requires dimensions" }, + /* 41*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_________________________________________________", 0, 32, 32, "", 1, "" }, + /* 42*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "__________________________________________________", 0, 32, 32, "", 1, "50 data" }, + /* 43*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "__________________________________________________", 0, 20, 44, "", 1, "" }, + /* 44*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "__________________________________________________", 0, 32, 32, "", 1, "" }, + /* 45*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU", 0, 32, 32, "", 0, "51 data; BWIPP different encodation" }, + /* 46*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU", 0, 20, 44, "", 0, "BWIPP DMRE requires dimensions" }, + /* 47*/ { BARCODE_DATAMATRIX, -1, -1, -1, 9999, -1, { 0, 0, "" }, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTU", 0, 32, 32, "", 0, "Ignored; BWIPP different encodation" }, + /* 48*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_____________________________________________________________", 0, 32, 32, "", 1, "61 data" }, + /* 49*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "______________________________________________________________", 0, 32, 32, "", 1, "62 data" }, + /* 50*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________________________________________________________", 0, 36, 36, "", 1, "63 data" }, + /* 51*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________________________________________________________", 0, 8, 144, "", 1, "" }, + /* 52*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________________________________________________________", 0, 36, 36, "", 1, "" }, + /* 53*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "________________________________________________________________", 0, 36, 36, "", 1, "64 data" }, + /* 54*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "________________________________________________________________", 0, 12, 88, "", 1, "" }, + /* 55*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "________________________________________________________________", 0, 36, 36, "", 1, "" }, + /* 56*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_________________________________________________________________", 0, 36, 36, "", 1, "65 data" }, + /* 57*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_________________________________________________________________", 0, 26, 40, "", 1, "" }, + /* 58*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_________________________________________________________________", 0, 36, 36, "", 1, "" }, + /* 59*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "______________________________________________________________________", 0, 36, 36, "", 1, "70 data" }, + /* 60*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "______________________________________________________________________", 0, 26, 40, "", 1, "" }, + /* 61*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "______________________________________________________________________", 0, 36, 36, "", 1, "" }, + /* 62*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "_______________________________________________________________________", 0, 36, 36, "", 1, "71 data" }, + /* 63*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "_______________________________________________________________________", 0, 22, 48, "", 1, "" }, + /* 64*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "_______________________________________________________________________", 0, 36, 36, "", 1, "" }, + /* 65*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "________________________________________________________________________________", 0, 36, 36, "", 1, "80 data" }, + /* 66*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "________________________________________________________________________________", 0, 24, 48, "", 1, "" }, + /* 67*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "________________________________________________________________________________", 0, 36, 36, "", 1, "" }, + /* 68*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "____________________________________________________________________________________", 0, 36, 36, "", 1, "84 data" }, + /* 69*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "____________________________________________________________________________________", 0, 20, 64, "", 1, "" }, + /* 70*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "____________________________________________________________________________________", 0, 36, 36, "", 1, "" }, + /* 71*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "__________________________________________________________________________________________", 0, 40, 40, "", 1, "90 data" }, + /* 72*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "__________________________________________________________________________________________", 0, 26, 48, "", 1, "" }, + /* 73*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "__________________________________________________________________________________________", 0, 40, 40, "", 1, "" }, + /* 74*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "___________________________________________________________________________________________", 0, 40, 40, "", 1, "91 data" }, + /* 75*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "___________________________________________________________________________________________", 0, 24, 64, "", 1, "" }, + /* 76*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "___________________________________________________________________________________________", 0, 40, 40, "", 1, "" }, + /* 77*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 0, "" }, "______________________________________________________________________________________________________________________", 0, 44, 44, "", 1, "118 data" }, + /* 78*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_DMRE, -1, { 0, 0, "" }, "______________________________________________________________________________________________________________________", 0, 26, 64, "", 1, "118 data" }, + /* 79*/ { BARCODE_DATAMATRIX, -1, -1, -1, DM_SQUARE, -1, { 0, 0, "" }, "______________________________________________________________________________________________________________________", 0, 44, 44, "", 1, "118 data" }, + /* 80*/ { BARCODE_DATAMATRIX, GS1_MODE, -1, -1, -1, -1, { 0, 0, "" }, "[90]12", 0, 10, 10, "", 1, "" }, + /* 81*/ { BARCODE_DATAMATRIX, GS1_MODE | GS1PARENS_MODE, -1, -1, -1, -1, { 0, 0, "" }, "(90)12", 0, 10, 10, "", 1, "" }, + /* 82*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 1, 2, "" }, "1", 0, 12, 12, "", 1, "" }, + /* 83*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 16, 16, "" }, "1", 0, 12, 12, "", 1, "" }, + /* 84*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 1, 1, "" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 720: Structured Append count '1' out of range (2 to 16)", 1, "" }, + /* 85*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 1, 17, "" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 720: Structured Append count '17' out of range (2 to 16)", 1, "" }, + /* 86*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 0, 16, "" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 721: Structured Append index '0' out of range (1 to count 16)", 1, "" }, + /* 87*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 17, 16, "" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 721: Structured Append index '17' out of range (1 to count 16)", 1, "" }, + /* 88*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "1001" }, "1", 0, 12, 12, "", 1, "" }, + /* 89*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "A" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 723: Invalid Structured Append ID (digits only)", 1, "" }, + /* 90*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "0" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 724: Structured Append ID1 '000' and ID2 '000' out of range (001 to 254) (ID \"000000\")", 1, "" }, + /* 91*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "1" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 725: Structured Append ID1 '000' out of range (001 to 254) (ID \"000001\")", 1, "" }, + /* 92*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "1000" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 726: Structured Append ID2 '000' out of range (001 to 254) (ID \"001000\")", 1, "" }, + /* 93*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "001255" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 726: Structured Append ID2 '255' out of range (001 to 254) (ID \"001255\")", 1, "" }, + /* 94*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "255001" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 725: Structured Append ID1 '255' out of range (001 to 254) (ID \"255001\")", 1, "" }, + /* 95*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "255255" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 724: Structured Append ID1 '255' and ID2 '255' out of range (001 to 254) (ID \"255255\")", 1, "" }, + /* 96*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, -1, { 2, 3, "1234567" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 722: Structured Append ID length 7 too long (6 digit maximum)", 1, "" }, + /* 97*/ { BARCODE_DATAMATRIX, -1, -1, -1, -1, READER_INIT, { 2, 3, "1001" }, "1", ZINT_ERROR_INVALID_OPTION, -1, -1, "Error 727: Cannot have Structured Append and Reader Initialisation at the same time", 1, "" }, + /* 98*/ { BARCODE_DATAMATRIX, ESCAPE_MODE, -1, -1, -1, -1, { 2, 3, "1001" }, "[)>\\R05\\GA\\R\\E", 0, 12, 26, "", 1, "Macro05/06 ignored if have Structured Append TODO: error/warning " }, + /* 99*/ { BARCODE_HIBC_DM, -1, -1, -1, -1, -1, { 0, 0, "" }, "1234,67", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 203: Invalid character at position 5 in input (alphanumerics, space and \"-.$/+%\" only)", 1, "" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; struct zint_symbol *symbol = NULL; + char escaped[8192]; + char cmp_buf[32768]; + char cmp_msg[1024]; + + int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ + int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder(); /* Only do ZXing-C++ test if asked, too slow otherwise */ + testStartSymbol("test_options", &symbol); for (i = 0; i < data_size; i++) { @@ -608,8 +679,35 @@ static void test_options(const testCtx *const p_ctx) { assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); if (ret < ZINT_ERROR) { - assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d (%s)\n", i, symbol->rows, data[i].expected_rows, symbol->errtxt); - assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", i, symbol->width, data[i].expected_width, symbol->errtxt); + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d (width %d) (%s)\n", + i, symbol->rows, data[i].expected_rows, symbol->width, symbol->errtxt); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", + i, symbol->width, data[i].expected_width, symbol->errtxt); + if (do_bwipp && testUtilCanBwipp(i, symbol, -1, data[i].option_2, data[i].option_3, debug)) { + if (!data[i].bwipp_cmp) { + if (debug & ZINT_DEBUG_TEST_PRINT) printf("i:%d %s not BWIPP compatible (%s)\n", i, testUtilBarcodeName(symbol->symbology), data[i].comment); + } else { + char modules_dump[144 * 144 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilBwipp(i, symbol, -1, data[i].option_2, data[i].option_3, data[i].data, length, NULL, cmp_buf, sizeof(cmp_buf), NULL); + assert_zero(ret, "i:%d %s testUtilBwipp ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilBwippCmp(symbol, cmp_msg, cmp_buf, modules_dump); + assert_zero(ret, "i:%d %s testUtilBwippCmp %d != 0 %s\n actual: %s\nexpected: %s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_buf, modules_dump); + } + } + if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data[i].data, length, debug)) { + int cmp_len, ret_len; + char modules_dump[144 * 144 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, cmp_buf, sizeof(cmp_buf), &cmp_len); + assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length, NULL /*primary*/, escaped, &ret_len); + assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len, escaped); + } } assert_zero(strcmp(symbol->errtxt, data[i].expected_errtxt), "i:%d symbol->errtxt %s != %s\n", i, symbol->errtxt, data[i].expected_errtxt); @@ -644,14 +742,19 @@ static void test_reader_init(const testCtx *const p_ctx) { char *comment; }; static const struct item data[] = { - /* 0*/ { BARCODE_DATAMATRIX, UNICODE_MODE, READER_INIT, "A", 0, 10, 10, "EA 42 81 19 A4 53 21 DF", "TODO: Check this" }, + /* 0*/ { BARCODE_DATAMATRIX, UNICODE_MODE, READER_INIT, "A", 0, 10, 10, "EA 42 81 19 A4 53 21 DF", "" }, /* 1*/ { BARCODE_DATAMATRIX, GS1_MODE, READER_INIT, "[91]A", ZINT_ERROR_INVALID_OPTION, 0, 0, "Error 521: Cannot use Reader Initialisation in GS1 mode", "" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; struct zint_symbol *symbol = NULL; - char escaped[1024]; + char escaped[8192]; + char cmp_buf[32768]; + char cmp_msg[1024]; + + int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ + int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder(); /* Only do ZXing-C++ test if asked, too slow otherwise */ testStartSymbol("test_reader_init", &symbol); @@ -678,6 +781,27 @@ static void test_reader_init(const testCtx *const p_ctx) { if (ret < ZINT_ERROR) { assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d (%s)\n", i, symbol->rows, data[i].expected_rows, data[i].data); assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", i, symbol->width, data[i].expected_width, data[i].data); + if (do_bwipp && testUtilCanBwipp(i, symbol, -1, -1, -1, debug)) { + char modules_dump[144 * 144 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilBwipp(i, symbol, -1, -1, -1, data[i].data, length, NULL, cmp_buf, sizeof(cmp_buf), NULL); + assert_zero(ret, "i:%d %s testUtilBwipp ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilBwippCmp(symbol, cmp_msg, cmp_buf, modules_dump); + assert_zero(ret, "i:%d %s testUtilBwippCmp %d != 0 %s\n actual: %s\nexpected: %s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_buf, modules_dump); + } + if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data[i].data, length, debug)) { + int cmp_len, ret_len; + char modules_dump[144 * 144 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, cmp_buf, sizeof(cmp_buf), &cmp_len); + assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length, NULL /*primary*/, escaped, &ret_len); + assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len, escaped); + } } assert_zero(strcmp(symbol->errtxt, data[i].expected), "i:%d strcmp(%s, %s) != 0\n", i, symbol->errtxt, data[i].expected); } @@ -691,7 +815,7 @@ static void test_reader_init(const testCtx *const p_ctx) { #define ZINT_TEST_ENCODING #ifdef ZINT_TEST_ENCODING INTERNAL int dm_encode_test(struct zint_symbol *symbol, const unsigned char source[], const int length, const int eci, - const int gs1, unsigned char target[], int *p_tp); + const int last_seg, const int gs1, unsigned char target[], int *p_tp); #endif static void test_input(const testCtx *const p_ctx) { @@ -1044,6 +1168,7 @@ static void test_input(const testCtx *const p_ctx) { int binlens[2] = {0}; unsigned char reduced[1000]; unsigned char *text; + const int last_seg = 1; assert_equal(data[i].expected_rows * data[i].expected_width <= data[i - 1].expected_rows * data[i - 1].expected_width, 1, "i:%d data[i].expected_rows * data[i].expected_width %d > data[i - 1].expected_rows * data[i - 1].expected_width %d\n", i, @@ -1060,7 +1185,7 @@ static void test_input(const testCtx *const p_ctx) { binlen = 0; symbol->input_mode = data[i - 1].input_mode; gs1 = (symbol->input_mode & 0x07) != GS1_MODE ? 0 : (symbol->output_options & GS1_GS_SEPARATOR) ? 2 : 1; - ret = dm_encode_test(symbol, text, length, symbol->eci, gs1, binary[0], &binlen); + ret = dm_encode_test(symbol, text, length, symbol->eci, last_seg, gs1, binary[0], &binlen); assert_zero(ret, "i:%d dm_encode() FAST_MODE ret %d != 0 (%s)\n", i, ret, symbol->errtxt); binlens[0] = binlen; @@ -1068,7 +1193,7 @@ static void test_input(const testCtx *const p_ctx) { binlen = 0; symbol->input_mode = data[i].input_mode; gs1 = (symbol->input_mode & 0x07) != GS1_MODE ? 0 : (symbol->output_options & GS1_GS_SEPARATOR) ? 2 : 1; - ret = dm_encode_test(symbol, text, length, symbol->eci, gs1, binary[1], &binlen); + ret = dm_encode_test(symbol, text, length, symbol->eci, last_seg, gs1, binary[1], &binlen); assert_zero(ret, "i:%d dm_encode() minimal ret %d != 0 (%s)\n", i, ret, symbol->errtxt); binlens[1] = binlen; @@ -5611,6 +5736,7 @@ static void test_encode(const testCtx *const p_ctx) { int gs1; int binlen; int binlens[2] = {0}; + const int last_seg = 1; assert_equal(data[i].expected_rows * data[i].expected_width <= data[i - 1].expected_rows * data[i - 1].expected_width, 1, "i:%d data[i].expected_rows * data[i].expected_width %d > data[i - 1].expected_rows * data[i - 1].expected_width %d\n", i, @@ -5619,7 +5745,8 @@ static void test_encode(const testCtx *const p_ctx) { binlen = 0; symbol->input_mode = data[i - 1].input_mode; gs1 = (symbol->input_mode & 0x07) != GS1_MODE ? 0 : (symbol->output_options & GS1_GS_SEPARATOR) ? 2 : 1; - ret = dm_encode_test(symbol, (unsigned char *) data[i].data, length, symbol->eci, gs1, binary[0], &binlen); + ret = dm_encode_test(symbol, (unsigned char *) data[i].data, length, symbol->eci, last_seg, gs1, + binary[0], &binlen); assert_zero(ret, "i:%d dm_encode() FAST_MODE ret %d != 0 (%s)\n", i, ret, symbol->errtxt); binlens[0] = binlen; @@ -5627,13 +5754,15 @@ static void test_encode(const testCtx *const p_ctx) { binlen = 0; symbol->input_mode = data[i].input_mode; gs1 = (symbol->input_mode & 0x07) != GS1_MODE ? 0 : (symbol->output_options & GS1_GS_SEPARATOR) ? 2 : 1; - ret = dm_encode_test(symbol, (unsigned char *) data[i].data, length, symbol->eci, gs1, binary[1], &binlen); + ret = dm_encode_test(symbol, (unsigned char *) data[i].data, length, symbol->eci, last_seg, gs1, + binary[1], &binlen); assert_zero(ret, "i:%d dm_encode() minimal ret %d != 0 (%s)\n", i, ret, symbol->errtxt); binlens[1] = binlen; assert_equal(binlens[1] <= binlens[0], 1, "i:%d binlens[1] %d > binlens[0] %d\n", i, binlens[1], binlens[0]); - assert_equal(binlens[0], binlens[1] + data[i].expected_diff, "i:%d binlens[0] %d != %d binlens[1] (%d) + expected_diff (%d)\n", + assert_equal(binlens[0], binlens[1] + data[i].expected_diff, + "i:%d binlens[0] %d != %d binlens[1] (%d) + expected_diff (%d)\n", i, binlens[0], binlens[1] + data[i].expected_diff, binlens[1], data[i].expected_diff); } #endif @@ -5826,6 +5955,154 @@ static void test_encode_segs(const testCtx *const p_ctx) { "10000011000001110111011000" "11111111111111111111111111" }, + /* 8*/ { BARCODE_DATAMATRIX, UNICODE_MODE | FAST_MODE, -1, -1, -1, { 0, 0, "" }, { { TU("ABCDEFGHIJ"), -1, 3 }, { TU("KL"), -1, 4 }, { TU("MN"), -1, 5 } }, 0, 20, 20, 1, "", + "10101010101010101010" + "10011001100100001111" + "10001100100011101110" + "11001011110111000001" + "10010011100000100100" + "11101010010000010111" + "10101001011101010110" + "10011011001101010011" + "10011101110000001000" + "10111000111110110101" + "10111011100000111000" + "11110000010011100001" + "10110010001100101000" + "10011111100011011111" + "11111011010011010110" + "11011001001000110111" + "11011111100110000110" + "11100100101111100101" + "11000101100101000010" + "11111111111111111111" + }, + /* 9*/ { BARCODE_DATAMATRIX, UNICODE_MODE, -1, -1, -1, { 0, 0, "" }, { { TU("ABCDEFGHIJ"), -1, 3 }, { TU("KL"), -1, 4 }, { TU("MN"), -1, 5 } }, 0, 20, 20, 0, "BWIPP same as FAST_MODE", + "10101010101010101010" + "10001010000100001111" + "10000111000011101110" + "11001001110111010001" + "10010001100000110000" + "11010110010000000011" + "11010111011100110100" + "11011110001001010001" + "11100101110110011000" + "11000000110000110101" + "10001011110001000000" + "11100000110100010101" + "11110011100101111100" + "11011101111010001111" + "11111111010110100110" + "11001110001101010001" + "11010010011000100110" + "10101000101010011101" + "10001111100101101010" + "11111111111111111111" + }, + /* 10*/ { BARCODE_DATAMATRIX, UNICODE_MODE, -1, -1, -1, { 0, 0, "" }, { { TU("AB"), -1, 3 }, { TU("CD"), -1, 4 }, { TU("EF"), -1, 5 } }, 0, 16, 16, 1, "", + "1010101010101010" + "1000100001000101" + "1000110110110010" + "1100110010100101" + "1000001000010010" + "1100001111000111" + "1110100000011110" + "1000011010111001" + "1000001001110100" + "1111101101001001" + "1110111111101010" + "1001000000010011" + "1010010110100000" + "1101001100010101" + "1000000001011010" + "1111111111111111" + }, + /* 11*/ { BARCODE_DATAMATRIX, UNICODE_MODE, -1, -1, -1, { 0, 0, "" }, { { TU("ABC"), -1, 3 }, { TU("DEF"), -1, 4 }, { TU("GHI"), -1, 5 } }, 0, 12, 26, 0, "BWIPP different encodation (1st seg C40)", + "10101010101010101010101010" + "10001000011110001111000011" + "10000101111001000011010000" + "11000000100100110111100111" + "10111000000100111110100110" + "11110011110011010010011001" + "10001000100100010000010000" + "10001110000110000110000001" + "10100001001011000111000110" + "10110110100111010011101111" + "10000100100001011001101100" + "11111111111111111111111111" + }, + /* 12*/ { BARCODE_DATAMATRIX, UNICODE_MODE, -1, -1, -1, { 0, 0, "" }, { { TU("ABCDEF"), -1, 3 }, { TU("GHIJKL"), -1, 4 }, { TU("MNOPQR"), -1, 5 } }, 0, 22, 22, 1, "", + "1010101010101010101010" + "1001100110101101111101" + "1000110010111101010100" + "1100101101111111100001" + "1001001000111100001000" + "1110111000110001011111" + "1010110000001101001100" + "1000011000010101000111" + "1000001111001011101110" + "1111011001111000001001" + "1110101101110111011100" + "1001100011100000011111" + "1111110101001010000010" + "1001011000001100101111" + "1010101010111010100000" + "1111000100011100001111" + "1100000111000010111110" + "1110010000110010010111" + "1111110010101010101010" + "1110001110011001010111" + "1000000100010110101000" + "1111111111111111111111" + }, + /* 13*/ { BARCODE_DATAMATRIX, UNICODE_MODE, -1, -1, -1, { 0, 0, "" }, { { TU("abcdef"), -1, 3 }, { TU("\015*>\015*>"), -1, 4 }, { TU("ghijkl"), -1, 5 } }, 0, 22, 22, 0, "BWIPP different encodation", + "1010101010101010101010" + "1001110110000010100111" + "1000110011011101100100" + "1100101000111110100011" + "1001001000111101111100" + "1110111000110000000001" + "1010110100001101010000" + "1000011000010101000111" + "1000001111001000001110" + "1111011011111010011001" + "1110101111111110100000" + "1001000011101000001011" + "1101000101110001010010" + "1001111000110101010011" + "1011101011101101011000" + "1101000101100000010111" + "1110000101000010110110" + "1110010001101000010111" + "1111110000100110110110" + "1110000111110100001101" + "1100010101011000000000" + "1111111111111111111111" + }, + /* 14*/ { BARCODE_DATAMATRIX, UNICODE_MODE, -1, -1, -1, { 0, 0, "" }, { { TU("abcdefg"), -1, 3 }, { TU("\015*>\015*>\015*"), -1, 4 }, { TU("hijklm"), -1, 5 } }, 0, 22, 22, 0, "BWIPP different encodation", + "1010101010101010101010" + "1000101010011000110001" + "1000011111011010010010" + "1100100000110000111111" + "1001000001000101010000" + "1101000110001000000111" + "1101000010100101101110" + "1101110100010101110111" + "1111101101001000000110" + "1110011111011010101001" + "1111111100001100010000" + "1110110110010010111011" + "1100001111100110011000" + "1100000110000111101101" + "1111000000000101000000" + "1011001101101100000101" + "1110110011011010000000" + "1110100011010111001101" + "1001011100101100101010" + "1000000010001111101111" + "1100011100111001010010" + "1111111111111111111111" + }, }; const int data_size = ARRAY_SIZE(data); int i, j, seg_count, ret; @@ -5889,7 +6166,7 @@ static void test_encode_segs(const testCtx *const p_ctx) { if (!data[i].bwipp_cmp) { if (debug & ZINT_DEBUG_TEST_PRINT) printf("i:%d %s not BWIPP compatible (%s)\n", i, testUtilBarcodeName(symbol->symbology), data[i].comment); } else { - ret = testUtilBwippSegs(i, symbol, -1, data[i].option_2, -1, data[i].segs, seg_count, NULL, cmp_buf, sizeof(cmp_buf)); + ret = testUtilBwippSegs(i, symbol, -1, data[i].option_2, data[i].option_3, data[i].segs, seg_count, NULL, cmp_buf, sizeof(cmp_buf)); assert_zero(ret, "i:%d %s testUtilBwippSegs ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); ret = testUtilBwippCmp(symbol, cmp_msg, cmp_buf, data[i].expected); @@ -6970,6 +7247,7 @@ static void test_minimalenc(const testCtx *const p_ctx) { int gs1; int binlen; int binlens[2] = {0}; + const int last_seg = 1; testStartSymbol("test_minimalenc", &symbol); @@ -6985,7 +7263,7 @@ static void test_minimalenc(const testCtx *const p_ctx) { binlen = 0; symbol->input_mode |= FAST_MODE; gs1 = (symbol->input_mode & 0x07) != GS1_MODE ? 0 : (symbol->output_options & GS1_GS_SEPARATOR) ? 2 : 1; - ret = dm_encode_test(symbol, (unsigned char *) data[i].data, length, symbol->eci, gs1, binary[0], &binlen); + ret = dm_encode_test(symbol, (unsigned char *) data[i].data, length, symbol->eci, last_seg, gs1, binary[0], &binlen); assert_equal(ret, data[i].ret, "i:%d dm_encode() FAST_MODE ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); binlens[0] = binlen; @@ -6993,7 +7271,7 @@ static void test_minimalenc(const testCtx *const p_ctx) { binlen = 0; symbol->input_mode &= ~FAST_MODE; gs1 = (symbol->input_mode & 0x07) != GS1_MODE ? 0 : (symbol->output_options & GS1_GS_SEPARATOR) ? 2 : 1; - ret = dm_encode_test(symbol, (unsigned char *) data[i].data, length, symbol->eci, gs1, binary[1], &binlen); + ret = dm_encode_test(symbol, (unsigned char *) data[i].data, length, symbol->eci, last_seg, gs1, binary[1], &binlen); assert_equal(ret, data[i].ret, "i:%d dm_encode() minimal ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); binlens[1] = binlen; diff --git a/backend/tests/test_dxfilmedge.c b/backend/tests/test_dxfilmedge.c new file mode 100644 index 00000000..9a8cdbaa --- /dev/null +++ b/backend/tests/test_dxfilmedge.c @@ -0,0 +1,293 @@ +/* + libzint - the open source barcode library + Copyright (C) 2024-2025 Antoine Merino + + 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. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include "testcommon.h" + +static void test_encode(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + int option_2; + char *data; + int ret; + + int expected_rows; + int expected_width; + char *comment; + char *expected; + }; + static const struct item data[] = { + /* 0*/ { BARCODE_DXFILMEDGE, -1, "79-7", 0, 2, 23, "DX code 1: 79, DX code 2: 7. DX Extract = 1271. DX Full: X1271X (X is any digit)", + "1111101010101010101011110101010011110011100101" + }, + /* 1*/ { BARCODE_DXFILMEDGE, -1, "1271", 0, 2, 23, "", + "1111101010101010101011110101010011110011100101" + }, + /* 2*/ { BARCODE_DXFILMEDGE, -1, "012710", 0, 2, 23, "", + "1111101010101010101011110101010011110011100101" + }, + /* 3*/ { BARCODE_DXFILMEDGE, -1, "112712", 0, 2, 23, "", + "1111101010101010101011110101010011110011100101" + }, + /* 4*/ { BARCODE_DXFILMEDGE, -1, "1-0", 0, 2, 23, "Lower limit: DX part 1 = 1, DX part 2 = 0", + "1111101010101010101011110101000000010000010101" + }, + /* 5*/ { BARCODE_DXFILMEDGE, -1, "000160", 0, 2, 23, "", + "1111101010101010101011110101000000010000010101" + }, + /* 6*/ { BARCODE_DXFILMEDGE, -1, "16", 0, 2, 23, "", + "1111101010101010101011110101000000010000010101" + }, + /* 7*/ { BARCODE_DXFILMEDGE, -1, "920479/63A", 0, 2, 31, "Upper limit: DX part 1 = 127, DX part 2 = 15", + "11111010101010101010101010101111010101111111011111111111000101" + }, + /* 8*/ { BARCODE_DXFILMEDGE, -1, "127-15/00A", 0, 2, 31, "", + "11111010101010101010101010101111010101111111011111111111000101" + }, + /* 9*/ { BARCODE_DXFILMEDGE, -1, "79-7/1", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001110000010010101" + }, + /* 10*/ { BARCODE_DXFILMEDGE, -1, "0079-7/001", 0, 2, 31, "Optional behaviour: leading zeros are accepted", + "11111010101010101010101010101111010101001111001110000010010101" + }, + /* 11*/ { BARCODE_DXFILMEDGE, -1, "79-7/1", 0, 2, 31, "Frame number", + "11111010101010101010101010101111010101001111001110000010010101" + }, + /* 12*/ { BARCODE_DXFILMEDGE, -1, "1271/1", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001110000010010101" + }, + /* 13*/ { BARCODE_DXFILMEDGE, -1, "912718/1", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001110000010010101" + }, + /* 14*/ { BARCODE_DXFILMEDGE, -1, "79-7/1A", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001110000011000101" + }, + /* 15*/ { BARCODE_DXFILMEDGE, -1, "1271/1a", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001110000011000101" + }, + /* 16*/ { BARCODE_DXFILMEDGE, -1, "212715/1A", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001110000011000101" + }, + /* 17*/ { BARCODE_DXFILMEDGE, -1, "79-7/62", 0, 2, 31, "Special frame numbers", + "11111010101010101010101010101111010101001111001111111100010101" + }, + /* 18*/ { BARCODE_DXFILMEDGE, -1, "79-7/S", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111100010101" + }, + /* 19*/ { BARCODE_DXFILMEDGE, -1, "79-7/x", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111100010101" + }, + /* 20*/ { BARCODE_DXFILMEDGE, -1, "79-7/62a", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111101000101" + }, + /* 21*/ { BARCODE_DXFILMEDGE, -1, "79-7/sA", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111101000101" + }, + /* 22*/ { BARCODE_DXFILMEDGE, -1, "79-7/Xa", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111101000101" + }, + /* 23*/ { BARCODE_DXFILMEDGE, -1, "79-7/63", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111110000101" + }, + /* 24*/ { BARCODE_DXFILMEDGE, -1, "79-7/k", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111110000101" + }, + /* 25*/ { BARCODE_DXFILMEDGE, -1, "79-7/00", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111110000101" + }, + /* 26*/ { BARCODE_DXFILMEDGE, -1, "79-7/63a", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111111010101" + }, + /* 27*/ { BARCODE_DXFILMEDGE, -1, "79-7/kA", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111111010101" + }, + /* 28*/ { BARCODE_DXFILMEDGE, -1, "79-7/00a", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001111111111010101" + }, + /* 29*/ { BARCODE_DXFILMEDGE, -1, "79-7/0", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001110000000000101" + }, + /* 30*/ { BARCODE_DXFILMEDGE, -1, "79-7/F", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001110000000000101" + }, + /* 31*/ { BARCODE_DXFILMEDGE, -1, "79-7/0a", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001110000001010101" + }, + /* 32*/ { BARCODE_DXFILMEDGE, -1, "79-7/fA", 0, 2, 31, "", + "11111010101010101010101010101111010101001111001110000001010101" + }, + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol = NULL; + + char escaped[1024]; + char cmp_buf[4096]; + char cmp_msg[1024]; + + int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder(); /* Only do ZXing-C++ test if asked, too slow otherwise */ + + testStartSymbol("test_encode", &symbol); + + for (i = 0; i < data_size; i++) { + + if (testContinue(p_ctx, i)) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, data[i].option_2, -1, -1 /*output_options*/, data[i].data, -1, debug); + + ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); + assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + + if (p_ctx->generate) { + printf(" /*%3d*/ { %s, %d, \"%s\", %s, %d, %d, \"%s\",\n", + i, testUtilBarcodeName(data[i].symbology), data[i].option_2, testUtilEscape(data[i].data, length, escaped, sizeof(escaped)), + testUtilErrorName(data[i].ret), symbol->rows, symbol->width, data[i].comment); + testUtilModulesPrint(symbol, " ", "\n"); + printf(" },\n"); + } else { + if (ret < ZINT_ERROR) { + int width, row; + + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d (%s)\n", i, symbol->rows, data[i].expected_rows, data[i].data); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", i, symbol->width, data[i].expected_width, data[i].data); + + ret = testUtilModulesCmp(symbol, data[i].expected, &width, &row); + assert_zero(ret, "i:%d testUtilModulesCmp ret %d != 0 width %d row %d (%s)\n", i, ret, width, row, data[i].data); + + if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data[i].data, length, debug)) { + int cmp_len, ret_len; + char modules_dump[8192 + 1]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, cmp_buf, sizeof(cmp_buf), &cmp_len); + assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length, NULL /*primary*/, escaped, &ret_len); + assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len, escaped); + } + } + } + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +static void test_input(const testCtx *const p_ctx) { + int debug = p_ctx->debug; + + struct item { + int symbology; + int input_mode; + char *data; + int ret; + int expected_rows; + int expected_width; + char *expected_errtxt; + }; + /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ + static const struct item data[] = { + /* 0*/ { BARCODE_DXFILMEDGE, -1, "79-1/123A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 972: Frame number part length 4 too long (maximum 3)" }, + /* 1*/ { BARCODE_DXFILMEDGE, -1, "79-1/1@A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 973: Frame number \"1@A\" is invalid (expected digits, optionally followed by a single \"A\")" }, + /* 2*/ { BARCODE_DXFILMEDGE, -1, "012312365", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 974: DX information length 9 too long (maximum 6)" }, + /* 3*/ { BARCODE_DXFILMEDGE, -1, "12-", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 977: Wrong format for DX parts 1 and 2 (expected format: NNN-NN, digits)" }, + /* 4*/ { BARCODE_DXFILMEDGE, -1, "01234/00A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 980: DX number \"01234\" is incorrect; expected 4 digits (DX extract) or 6 digits (DX full)" }, + /* 5*/ { BARCODE_DXFILMEDGE, -1, "0123/0AA", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 983: Frame number \"0AA\" is invalid (expected digits, optionally followed by a single \"A\")" }, + /* 6*/ { BARCODE_DXFILMEDGE, -1, "128-0/24", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 978: DX part 1 \"128\" out of range (1 to 127)" }, + /* 7*/ { BARCODE_DXFILMEDGE, -1, "127-16", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 979: DX part 2 \"16\" out of range (0 to 15)" }, + /* 8*/ { BARCODE_DXFILMEDGE, -1, "79-2/A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 983: Frame number \"A\" is invalid (expected digits, optionally followed by a single \"A\")" }, + /* 9*/ { BARCODE_DXFILMEDGE, -1, "79-2/-1", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 984: Frame number \"-1\" out of range (0 to 63)" }, + /* 10*/ { BARCODE_DXFILMEDGE, -1, "79-2/64", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 984: Frame number \"64\" out of range (0 to 63)" }, + /* 11*/ { BARCODE_DXFILMEDGE, -1, "79-2-1", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 976: The \"-\" is used to separate DX parts 1 and 2, and should be used no more than once" }, + /* 12*/ { BARCODE_DXFILMEDGE, -1, "110-2/2B", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 985: Frame number \"2B\" is invalid (expected digits, optionally followed by a single \"A\")" }, + /* 13*/ { BARCODE_DXFILMEDGE, -1, "099990/123A", ZINT_ERROR_TOO_LONG, -1, -1, "Error 986: Input length 11 too long (maximum 10)" }, + /* 14*/ { BARCODE_DXFILMEDGE, -1, "0123123/1", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 971: DX information length 7 too long (maximum 6)" }, + /* 15*/ { BARCODE_DXFILMEDGE, -1, "120481", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 981: DX extract \"2048\" out of range (16 to 2047)" }, + /* 16*/ { BARCODE_DXFILMEDGE, -1, "100151", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 981: DX extract \"15\" out of range (16 to 2047)" }, + /* 17*/ { BARCODE_DXFILMEDGE, -1, "15", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 981: DX extract \"15\" out of range (16 to 2047)" }, + /* 18*/ { BARCODE_DXFILMEDGE, -1, "12-12A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 975: Invalid character at position 6 in DX info (digits and \"-\" character only)" }, + /* 19*/ { BARCODE_DXFILMEDGE, -1, "012X", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 975: Invalid character at position 4 in DX info (digits and \"-\" character only)" }, + /* 20*/ { BARCODE_DXFILMEDGE, -1, "110-2/", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 982: Frame number indicator \"/\" at position 6, but frame number is empty" }, + /* 21*/ { BARCODE_DXFILMEDGE, -1, "/", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 970: Invalid first character \"/\", DX code should start with a number" }, + /* 22*/ { BARCODE_DXFILMEDGE, -1, "-12", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 970: Invalid first character \"-\", DX code should start with a number" }, + /* 23*/ { BARCODE_DXFILMEDGE, -1, "X1234X", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 970: Invalid first character \"X\", DX code should start with a number" }, + }; + const int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol = NULL; + + testStartSymbol("test_input", &symbol); + + for (i = 0; i < data_size; i++) { + + if (testContinue(p_ctx, i)) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + length = testUtilSetSymbol(symbol, data[i].symbology, data[i].input_mode, -1 /*eci*/, -1 /*option_1*/, -1 /*option_2*/, -1, -1 /*output_options*/, data[i].data, -1, debug); + + ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); + assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + assert_equal(symbol->errtxt[0] == '\0', ret == 0, "i:%d symbol->errtxt not %s (%s)\n", i, ret ? "set" : "empty", symbol->errtxt); + assert_zero(strcmp(symbol->errtxt, data[i].expected_errtxt), "i:%d strcmp(%s, %s) != 0\n", i, symbol->errtxt, data[i].expected_errtxt); + + if (ret < ZINT_ERROR) { + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d\n", i, symbol->rows, data[i].expected_rows); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d\n", i, symbol->width, data[i].expected_width); + } + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + +int main(int argc, char *argv[]) { + + testFunction funcs[] = { /* name, func */ + { "test_input", test_input }, + { "test_encode", test_encode }, + }; + + testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); + + testReport(); + + return 0; +} + +/* vim: set ts=4 sw=4 et : */ diff --git a/backend/tests/test_large.c b/backend/tests/test_large.c index 5deb77d7..472d5000 100644 --- a/backend/tests/test_large.c +++ b/backend/tests/test_large.c @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2020-2024 Robin Stuart + Copyright (C) 2020-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -34,7 +34,7 @@ #include "testcommon.h" #include "../large.h" -#if defined(__MINGW32__) +#if defined(__MINGW32__) && !defined(__MINGW64__) # if __WORDSIZE == 32 # define LX_FMT "I32" # else diff --git a/backend/tests/test_library.c b/backend/tests/test_library.c index 276fa2a9..eb41ff03 100644 --- a/backend/tests/test_library.c +++ b/backend/tests/test_library.c @@ -191,8 +191,8 @@ static void test_checks(const testCtx *const p_ctx) { /*127*/ { 126, -1, "1", -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_INVALID_OPTION, "Error 206: Symbology out of range", -1 }, /*128*/ { 127, -1, "1", -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_WARN_INVALID_OPTION, "Warning 206: Symbology out of range", BARCODE_CODE128 }, /*129*/ { 127, -1, "1", -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_INVALID_OPTION, "Error 206: Symbology out of range", -1 }, - /*130*/ { 147, -1, "1", -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_WARN_INVALID_OPTION, "Warning 206: Symbology out of range", BARCODE_CODE128 }, - /*131*/ { 147, -1, "1", -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_INVALID_OPTION, "Error 206: Symbology out of range", -1 }, + /*130*/ { 148, -1, "1", -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_WARN_INVALID_OPTION, "Warning 206: Symbology out of range", BARCODE_CODE128 }, + /*131*/ { 148, -1, "1", -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_INVALID_OPTION, "Error 206: Symbology out of range", -1 }, /*132*/ { BARCODE_LAST + 1, -1, "1", -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_WARN_INVALID_OPTION, "Warning 206: Symbology out of range", BARCODE_CODE128 }, /*133*/ { BARCODE_LAST + 1, -1, "1", -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_INVALID_OPTION, "Error 206: Symbology out of range", -1 }, /*134*/ { BARCODE_CODE128, -1, "\200", -1, UNICODE_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_ERROR_INVALID_DATA, "Error 245: Invalid UTF-8 in input", -1 }, @@ -964,9 +964,12 @@ static void test_cap_compliant_height(const testCtx *const p_ctx) { case BARCODE_DBAR_EXPSTK_CC: case BARCODE_CHANNEL: case BARCODE_BC412: + case BARCODE_DXFILMEDGE: + /* Make sure ZINT_CAP_COMPLIANT_HEIGHT set for those that have it */ assert_equal(uret, ZINT_CAP_COMPLIANT_HEIGHT, "symbol_id %d (%s) uret 0x%X != ZINT_CAP_COMPLIANT_HEIGHT\n", symbol_id, testUtilBarcodeName(symbol_id), uret); break; default: + /* And not set for those that don't */ assert_zero(uret, "symbol_id %d (%s) uret 0x%X non-zero\n", symbol_id, testUtilBarcodeName(symbol_id), uret); break; } @@ -1549,6 +1552,7 @@ static int test_prev_ZBarcode_BarcodeName(int symbol_id, char name[32]) { { "BARCODE_ULTRA", BARCODE_ULTRA, 144 }, { "BARCODE_RMQR", BARCODE_RMQR, 145 }, { "BARCODE_BC412", BARCODE_BC412, 146 }, + { "BARCODE_DXFILMEDGE", BARCODE_DXFILMEDGE, 147 }, }; name[0] = '\0'; diff --git a/backend/tests/test_medical.c b/backend/tests/test_medical.c index 261575af..d166b3b1 100644 --- a/backend/tests/test_medical.c +++ b/backend/tests/test_medical.c @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2020-2024 Robin Stuart + Copyright (C) 2020-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -42,19 +42,20 @@ static void test_large(const testCtx *const p_ctx) { int ret; int expected_rows; int expected_width; + char *expected_errtxt; }; /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ static const struct item data[] = { - /* 0*/ { BARCODE_CODABAR, -1, "A+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++B", 103, 0, 1, 1133 }, - /* 1*/ { BARCODE_CODABAR, -1, "A++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++B", 104, ZINT_ERROR_TOO_LONG, -1, -1 }, - /* 2*/ { BARCODE_CODABAR, 1, "A+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++B", 103, 0, 1, 1143 }, - /* 3*/ { BARCODE_CODABAR, 1, "A++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++B", 104, ZINT_ERROR_TOO_LONG, -1, -1 }, - /* 4*/ { BARCODE_PHARMA, -1, "131070", 6, 0, 1, 78 }, - /* 5*/ { BARCODE_PHARMA, -1, "1", 7, ZINT_ERROR_TOO_LONG, -1, -1 }, - /* 6*/ { BARCODE_PHARMA_TWO, -1, "64570080", 8, 0, 2, 31 }, - /* 7*/ { BARCODE_PHARMA_TWO, -1, "1", 9, ZINT_ERROR_TOO_LONG, -1, -1 }, - /* 8*/ { BARCODE_CODE32, -1, "1", 8, 0, 1, 103 }, - /* 9*/ { BARCODE_CODE32, -1, "1", 9, ZINT_ERROR_TOO_LONG, -1, -1 }, + /* 0*/ { BARCODE_PHARMA, -1, "131070", 6, 0, 1, 78, "", }, + /* 1*/ { BARCODE_PHARMA, -1, "1", 7, ZINT_ERROR_TOO_LONG, -1, -1, "Error 350: Input length 7 too long (maximum 6)" }, + /* 2*/ { BARCODE_PHARMA_TWO, -1, "64570080", 8, 0, 2, 31, "", }, + /* 3*/ { BARCODE_PHARMA_TWO, -1, "1", 9, ZINT_ERROR_TOO_LONG, -1, -1, "Error 354: Input length 9 too long (maximum 8)" }, + /* 4*/ { BARCODE_CODE32, -1, "1", 8, 0, 1, 103, "", }, + /* 5*/ { BARCODE_CODE32, -1, "1", 9, ZINT_ERROR_TOO_LONG, -1, -1, "Error 360: Input length 9 too long (maximum 8)" }, + /* 6*/ { BARCODE_PZN, -1, "1", 7, 0, 1, 142, "" }, /* Takes 8 with correct check digit */ + /* 7*/ { BARCODE_PZN, -1, "1", 9, ZINT_ERROR_TOO_LONG, -1, -1, "Error 325: Input length 9 too long (maximum 8)" }, + /* 8*/ { BARCODE_PZN, 1, "1", 6, 0, 1, 129, "" }, /* PZN7 takes 7 with correct check digit */ + /* 9*/ { BARCODE_PZN, 1, "1", 8, ZINT_ERROR_TOO_LONG, -1, -1, "Error 325: Input length 8 too long (maximum 7)" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -78,6 +79,8 @@ static void test_large(const testCtx *const p_ctx) { ret = ZBarcode_Encode(symbol, (unsigned char *) data_buf, length); assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + assert_equal(symbol->errtxt[0] == '\0', ret == 0, "i:%d symbol->errtxt not %s (%s)\n", i, ret ? "set" : "empty", symbol->errtxt); + assert_zero(strcmp(symbol->errtxt, data[i].expected_errtxt), "i:%d strcmp(%s, %s) != 0\n", i, symbol->errtxt, data[i].expected_errtxt); if (ret < ZINT_ERROR) { assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d\n", i, symbol->rows, data[i].expected_rows); @@ -102,16 +105,18 @@ static void test_hrt(const testCtx *const p_ctx) { }; /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ static const struct item data[] = { - /* 0*/ { BARCODE_CODABAR, -1, "A1234B", "A1234B" }, - /* 1*/ { BARCODE_CODABAR, -1, "a1234c", "A1234C" }, /* Converts to upper */ - /* 2*/ { BARCODE_CODABAR, 1, "A1234B", "A1234B" }, /* Check not included */ - /* 3*/ { BARCODE_CODABAR, 2, "A1234B", "A12345B" }, /* Check included */ - /* 4*/ { BARCODE_CODABAR, 1, "A123456A", "A123456A" }, /* Check not included */ - /* 5*/ { BARCODE_CODABAR, 2, "A123456A", "A123456$A" }, /* Check included */ - /* 6*/ { BARCODE_PHARMA, -1, "123456", "" }, /* None */ - /* 7*/ { BARCODE_PHARMA_TWO, -1, "123456", "" }, /* None */ - /* 8*/ { BARCODE_CODE32, -1, "123456", "A001234564" }, - /* 9*/ { BARCODE_CODE32, -1, "12345678", "A123456788" }, + /* 0*/ { BARCODE_PHARMA, -1, "123456", "" }, /* None */ + /* 1*/ { BARCODE_PHARMA_TWO, -1, "123456", "" }, /* None */ + /* 2*/ { BARCODE_CODE32, -1, "123456", "A001234564" }, + /* 3*/ { BARCODE_CODE32, -1, "12345678", "A123456788" }, + /* 4*/ { BARCODE_PZN, -1, "12345", "PZN - 00123458" }, /* Pads with zeroes if length < 7 */ + /* 5*/ { BARCODE_PZN, -1, "123456", "PZN - 01234562" }, + /* 6*/ { BARCODE_PZN, -1, "1234567", "PZN - 12345678" }, + /* 7*/ { BARCODE_PZN, -1, "12345678", "PZN - 12345678" }, + /* 8*/ { BARCODE_PZN, 1, "1234", "PZN - 0012345" }, /* PZN7, pads with zeroes if length < 6 */ + /* 9*/ { BARCODE_PZN, 1, "12345", "PZN - 0123458" }, + /* 10*/ { BARCODE_PZN, 1, "123456", "PZN - 1234562" }, + /* 11*/ { BARCODE_PZN, 1, "1234562", "PZN - 1234562" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -144,6 +149,7 @@ static void test_input(const testCtx *const p_ctx) { struct item { int symbology; + int option_2; char *data; int ret; int expected_rows; @@ -154,37 +160,33 @@ static void test_input(const testCtx *const p_ctx) { }; /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ static const struct item data[] = { - /* 0*/ { BARCODE_CODABAR, "A1234B", 0, 1, 62, "", 1, "" }, - /* 1*/ { BARCODE_CODABAR, "1234B", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 358: Does not begin with \"A\", \"B\", \"C\" or \"D\"", 1, "" }, - /* 2*/ { BARCODE_CODABAR, "A1234", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 359: Does not end with \"A\", \"B\", \"C\" or \"D\"", 1, "" }, - /* 3*/ { BARCODE_CODABAR, "A1234E", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 359: Does not end with \"A\", \"B\", \"C\" or \"D\"", 1, "" }, - /* 4*/ { BARCODE_CODABAR, "C123.D", 0, 1, 63, "", 1, "" }, - /* 5*/ { BARCODE_CODABAR, "C123,D", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 357: Invalid character at position 5 in input (\"0123456789-$:/.+ABCD\" only)", 1, "" }, - /* 6*/ { BARCODE_CODABAR, "D:C", 0, 1, 33, "", 1, "" }, - /* 7*/ { BARCODE_CODABAR, "DCC", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 363: Invalid character at position 1 in input (cannot contain \"A\", \"B\", \"C\" or \"D\")", 1, "" }, - /* 8*/ { BARCODE_CODABAR, "A234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123B", ZINT_ERROR_TOO_LONG, -1, -1, "Error 356: Input length 104 too long (maximum 103)", 1, "" }, - /* 9*/ { BARCODE_CODABAR, "AB", ZINT_ERROR_TOO_LONG, -1, -1, "Error 362: Input length 2 too short (minimum 3)", 1, "" }, - /* 10*/ { BARCODE_PHARMA, "131070", 0, 1, 78, "", 1, "" }, - /* 11*/ { BARCODE_PHARMA, "1310700", ZINT_ERROR_TOO_LONG, -1, -1, "Error 350: Input length 7 too long (maximum 6)", 1, "" }, - /* 12*/ { BARCODE_PHARMA, "131071", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 352: Input value '131071' out of range (3 to 131070)", 1, "" }, - /* 13*/ { BARCODE_PHARMA, "3", 0, 1, 4, "", 1, "" }, - /* 14*/ { BARCODE_PHARMA, "2", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 352: Input value '2' out of range (3 to 131070)", 1, "" }, - /* 15*/ { BARCODE_PHARMA, "1", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 352: Input value '1' out of range (3 to 131070)", 1, "" }, - /* 16*/ { BARCODE_PHARMA, "12A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 351: Invalid character at position 3 in input (digits only)", 1, "" }, - /* 17*/ { BARCODE_PHARMA_TWO, "64570080", 0, 2, 31, "", 1, "" }, - /* 18*/ { BARCODE_PHARMA_TWO, "64570081", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 353: Input value '64570081' out of range (4 to 64570080)", 1, "" }, - /* 19*/ { BARCODE_PHARMA_TWO, "064570080", ZINT_ERROR_TOO_LONG, -1, -1, "Error 354: Input length 9 too long (maximum 8)", 1, "" }, - /* 20*/ { BARCODE_PHARMA_TWO, "4", 0, 2, 3, "", 1, "" }, - /* 21*/ { BARCODE_PHARMA_TWO, "3", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 353: Input value '3' out of range (4 to 64570080)", 1, "" }, - /* 22*/ { BARCODE_PHARMA_TWO, "2", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 353: Input value '2' out of range (4 to 64570080)", 1, "" }, - /* 23*/ { BARCODE_PHARMA_TWO, "1", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 353: Input value '1' out of range (4 to 64570080)", 1, "" }, - /* 24*/ { BARCODE_PHARMA_TWO, "123A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 355: Invalid character at position 4 in input (digits only)", 1, "" }, - /* 25*/ { BARCODE_CODE32, "12345678", 0, 1, 103, "", 1, "" }, - /* 26*/ { BARCODE_CODE32, "9", 0, 1, 103, "", 0, "BWIPP requires length 8 or 9" }, - /* 27*/ { BARCODE_CODE32, "0", 0, 1, 103, "", 0, "BWIPP requires length 8 or 9" }, - /* 28*/ { BARCODE_CODE32, "123456789", ZINT_ERROR_TOO_LONG, -1, -1, "Error 360: Input length 9 too long (maximum 8)", 1, "" }, - /* 29*/ { BARCODE_CODE32, "A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 361: Invalid character at position 1 in input (digits only)", 1, "" }, - /* 30*/ { BARCODE_CODE32, "99999999", 0, 1, 103, "", 1, "" }, + /* 0*/ { BARCODE_PHARMA, -1, "131070", 0, 1, 78, "", 1, "" }, + /* 1*/ { BARCODE_PHARMA, -1, "1310700", ZINT_ERROR_TOO_LONG, -1, -1, "Error 350: Input length 7 too long (maximum 6)", 1, "" }, + /* 2*/ { BARCODE_PHARMA, -1, "131071", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 352: Input value '131071' out of range (3 to 131070)", 1, "" }, + /* 3*/ { BARCODE_PHARMA, -1, "3", 0, 1, 4, "", 1, "" }, + /* 4*/ { BARCODE_PHARMA, -1, "2", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 352: Input value '2' out of range (3 to 131070)", 1, "" }, + /* 5*/ { BARCODE_PHARMA, -1, "1", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 352: Input value '1' out of range (3 to 131070)", 1, "" }, + /* 6*/ { BARCODE_PHARMA, -1, "12A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 351: Invalid character at position 3 in input (digits only)", 1, "" }, + /* 7*/ { BARCODE_PHARMA_TWO, -1, "64570080", 0, 2, 31, "", 1, "" }, + /* 8*/ { BARCODE_PHARMA_TWO, -1, "64570081", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 353: Input value '64570081' out of range (4 to 64570080)", 1, "" }, + /* 9*/ { BARCODE_PHARMA_TWO, -1, "064570080", ZINT_ERROR_TOO_LONG, -1, -1, "Error 354: Input length 9 too long (maximum 8)", 1, "" }, + /* 10*/ { BARCODE_PHARMA_TWO, -1, "4", 0, 2, 3, "", 1, "" }, + /* 11*/ { BARCODE_PHARMA_TWO, -1, "3", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 353: Input value '3' out of range (4 to 64570080)", 1, "" }, + /* 12*/ { BARCODE_PHARMA_TWO, -1, "2", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 353: Input value '2' out of range (4 to 64570080)", 1, "" }, + /* 13*/ { BARCODE_PHARMA_TWO, -1, "1", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 353: Input value '1' out of range (4 to 64570080)", 1, "" }, + /* 14*/ { BARCODE_PHARMA_TWO, -1, "123A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 355: Invalid character at position 4 in input (digits only)", 1, "" }, + /* 15*/ { BARCODE_CODE32, -1, "12345678", 0, 1, 103, "", 1, "" }, + /* 16*/ { BARCODE_CODE32, -1, "9", 0, 1, 103, "", 0, "BWIPP requires length 8 or 9" }, + /* 17*/ { BARCODE_CODE32, -1, "0", 0, 1, 103, "", 0, "BWIPP requires length 8 or 9" }, + /* 18*/ { BARCODE_CODE32, -1, "123456789", ZINT_ERROR_TOO_LONG, -1, -1, "Error 360: Input length 9 too long (maximum 8)", 1, "" }, + /* 19*/ { BARCODE_CODE32, -1, "A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 361: Invalid character at position 1 in input (digits only)", 1, "" }, + /* 20*/ { BARCODE_CODE32, -1, "99999999", 0, 1, 103, "", 1, "" }, + /* 21*/ { BARCODE_PZN, -1, "1", 0, 1, 142, "", 0, "BWIPP requires 7 or 8 digits" }, + /* 22*/ { BARCODE_PZN, -1, "A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 326: Invalid character at position 1 in input (digits only)", 1, "" }, + /* 23*/ { BARCODE_PZN, -1, "1000006", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 327: Invalid PZN, check digit is '10'", 1, "" }, /* Check digit == 10 so can't be used */ + /* 24*/ { BARCODE_PZN, -1, "00000011", ZINT_ERROR_INVALID_CHECK, -1, -1, "Error 890: Invalid check digit '1', expecting '7'", 1, "" }, + /* 25*/ { BARCODE_PZN, 1, "100009", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 327: Invalid PZN, check digit is '10'", 1, "" }, /* Check digit == 10 so can't be used */ + /* 26*/ { BARCODE_PZN, 1, "0000011", ZINT_ERROR_INVALID_CHECK, -1, -1, "Error 890: Invalid check digit '1', expecting '7'", 1, "" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -204,7 +206,7 @@ static void test_input(const testCtx *const p_ctx) { symbol = ZBarcode_Create(); assert_nonnull(symbol, "Symbol not created\n"); - length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, -1, -1, -1 /*output_options*/, data[i].data, -1, debug); + length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, data[i].option_2, -1, -1 /*output_options*/, data[i].data, -1, debug); ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); @@ -251,38 +253,32 @@ static void test_encode(const testCtx *const p_ctx) { char *expected; }; static const struct item data[] = { - /* 0*/ { BARCODE_CODABAR, -1, "A37859B", 0, 1, 72, "BS EN 798:1995 Figure 1", - "101100100101100101010100101101010011010101101010010110100101010010010110" - }, - /* 1*/ { BARCODE_CODABAR, -1, "A0123456789-$:/.+D", 0, 1, 186, "Verified manually against tec-it", - "101100100101010100110101011001010100101101100101010101101001011010100101001010110100101101010011010101101001010101001101010110010101101011011011011010110110110110101011011011010100110010" - }, - /* 2*/ { BARCODE_CODABAR, 1, "A1B", 0, 1, 43, "Verified manually against tec-it", - "1011001001010101100101101101101010010010110" - }, - /* 3*/ { BARCODE_CODABAR, 1, "A+B", 0, 1, 43, "Verified manually against tec-it", - "1011001001010110110110101010011010010010110" - }, - /* 4*/ { BARCODE_CODABAR, 1, "B0123456789-$:/.+B", 0, 1, 196, "Verified manually against tec-it", - "1001001011010101001101010110010101001011011001010101011010010110101001010010101101001011010100110101011010010101010011010101100101011010110110110110101101101101101010110110110100101011010010010110" - }, - /* 5*/ { BARCODE_PHARMA, -1, "131070", 0, 1, 78, "", + /* 0*/ { BARCODE_PHARMA, -1, "131070", 0, 1, 78, "", "111001110011100111001110011100111001110011100111001110011100111001110011100111" }, - /* 6*/ { BARCODE_PHARMA, -1, "123456", 0, 1, 58, "", + /* 1*/ { BARCODE_PHARMA, -1, "123456", 0, 1, 58, "", "1110011100111001001001001110010010011100100100100100100111" }, - /* 7*/ { BARCODE_PHARMA_TWO, -1, "64570080", 0, 2, 31, "Verified manually against tec-it", + /* 2*/ { BARCODE_PHARMA_TWO, -1, "64570080", 0, 2, 31, "Verified manually against TEC-IT", "1010101010101010101010101010101" "1010101010101010101010101010101" }, - /* 8*/ { BARCODE_PHARMA_TWO, -1, "29876543", 0, 2, 31, "Verified manually against tec-it", + /* 3*/ { BARCODE_PHARMA_TWO, -1, "29876543", 0, 2, 31, "Verified manually against TEC-IT", "0010100010001010001010001000101" "1000101010100000100000101010000" }, - /* 9*/ { BARCODE_CODE32, -1, "34567890", 0, 1, 103, "Verified manually against tec-it", + /* 4*/ { BARCODE_CODE32, -1, "34567890", 0, 1, 103, "Verified manually against TEC-IT", "1001011011010101101001011010110010110101011011010010101100101101011010010101101010101100110100101101101" }, + /* 5*/ { BARCODE_PZN, -1, "1234567", 0, 1, 142, "Example from IFA Info Code 39 EN V2.1; verified manually against TEC-IT", + "1001011011010100101011011011010010101101011001010110110110010101010100110101101101001101010101100110101010100101101101101001011010100101101101" + }, + /* 6*/ { BARCODE_PZN, -1, "2758089", 0, 1, 142, "Example from IFA Info Check Digit Calculations EN 15 July 2019; verified manually against TEC-IT", + "1001011011010100101011011010110010101101010010110110110100110101011010010110101010011011010110100101101010110010110101011001011010100101101101" + }, + /* 7*/ { BARCODE_PZN, 1, "123456", 0, 1, 129, "Example from BWIPP; verified manually against TEC-IT", + "100101101101010010101101101101001010110101100101011011011001010101010011010110110100110101010110011010101011001010110100101101101" + }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; diff --git a/backend/tests/testcommon.c b/backend/tests/testcommon.c index 2e57f099..a6baf0b0 100644 --- a/backend/tests/testcommon.c +++ b/backend/tests/testcommon.c @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2019-2024 Robin Stuart + Copyright (C) 2019-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -601,22 +601,26 @@ const char *testUtilOption3Name(int symbology, int option_3) { const unsigned int high_byte = option_3 == -1 ? 0 : (option_3 >> 8) & 0xFF; if (symbology == BARCODE_DATAMATRIX || symbology == BARCODE_HIBC_DM) { - if ((option_3 & 0x7F) == DM_SQUARE) { - if ((option_3 & DM_ISO_144) == DM_ISO_144) { - name = "DM_SQUARE | DM_ISO_144"; + if (option_3 > 0) { + if ((option_3 & 0x7F) == DM_SQUARE) { + if ((option_3 & DM_ISO_144) == DM_ISO_144) { + name = "DM_SQUARE | DM_ISO_144"; + } else { + name = "DM_SQUARE"; + } + } else if ((option_3 & 0x7F) == DM_DMRE) { + if ((option_3 & DM_ISO_144) == DM_ISO_144) { + name = "DM_DMRE | DM_ISO_144"; + } else { + name = "DM_DMRE"; + } + } else if ((option_3 & DM_ISO_144) == DM_ISO_144) { + name = "DM_ISO_144"; } else { - name = "DM_SQUARE"; + name = (option_3 & 0xFF) ? "-1" : "0"; } - } else if ((option_3 & 0x7F) == DM_DMRE) { - if ((option_3 & DM_ISO_144) == DM_ISO_144) { - name = "DM_DMRE | DM_ISO_144"; - } else { - name = "DM_DMRE"; - } - } else if ((option_3 & DM_ISO_144) == DM_ISO_144) { - name = "DM_ISO_144"; } else { - name = (option_3 & 0xFF) ? "-1" : "0"; + name = option_3 ? "-1" : "0"; } } else if (symbology == BARCODE_QRCODE || symbology == BARCODE_HIBC_QR || symbology == BARCODE_MICROQR || symbology == BARCODE_RMQR || symbology == BARCODE_GRIDMATRIX || symbology == BARCODE_HANXIN) { @@ -2357,7 +2361,7 @@ static const char *testUtilBwippName(int index, const struct zint_symbol *symbol { "", -1, 124, 0, 0, 0, 0, 0, }, { "", -1, 125, 0, 0, 0, 0, 0, }, { "", -1, 126, 0, 0, 0, 0, 0, }, - { "", -1, 127, 0, 0, 0, 0, 0, }, + { "", BARCODE_DXFILMEDGE, 127, 0, 0, 0, 0, 0, }, { "aztecrune", BARCODE_AZRUNE, 128, 0, 0, 0, 0, 0, }, { "code32", BARCODE_CODE32, 129, 0, 0, 0, 0, 0, }, { "ean13composite", BARCODE_EANX_CC, 130, 1, 1, 0, 72 /*linear_row_height*/, 1 /*gs1_cvt*/, }, @@ -2572,7 +2576,7 @@ static char *testUtilBwippEscape(char *bwipp_data, int bwipp_data_size, const ch case 'R': val = 0x1e; /* Record Separator */ break; case 'x': val = d + 2 < de && z_isxdigit(d[1]) && z_isxdigit(d[2]) ? (ctoi(d[1]) << 4) | ctoi(d[2]) : -1; - if (val != -1) d+= 2; + if (val != -1) d += 2; break; case 'd': val = d + 3 < de ? to_int(d + 1, 3) : -1; @@ -2586,7 +2590,14 @@ static char *testUtilBwippEscape(char *bwipp_data, int bwipp_data_size, const ch if (val != -1) d += 3; break; case '\\': val = '\\'; break; - /*case 'u': val = 0; TODO: implement break; */ + case 'u': /* For convenience, only handles ISO/IEC 8859-1 */ + val = d + 4 < de && z_isxdigit(d[1]) && z_isxdigit(d[2]) && z_isxdigit(d[3]) && z_isxdigit(d[4]) + ? (ctoi(d[1]) << 4) | ctoi(d[2]) : -1; + if (val == 0) { /* Only handling Latin-1 so must be zero */ + val = (ctoi(d[3]) << 4) | ctoi(d[4]); + d += 4; + } + break; /*case 'U': val = 0; TODO: implement break; */ case '^': val = -1; break; /* Code 128 special escapes */ default: fprintf(stderr, "testUtilBwippEscape: unknown escape %c\n", *d); return NULL; break; @@ -3274,6 +3285,16 @@ int testUtilBwipp(int index, const struct zint_symbol *symbol, int option_1, int if (option_3 != -1) { bwipp_opts = bwipp_opts_buf; } + if (symbol->output_options & READER_INIT) { + memmove(bwipp_data + 5, bwipp_data, strlen(bwipp_data) + 1); + memcpy(bwipp_data, "^PROG", 5); + if (!parsefnc) { + sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparsefnc", + strlen(bwipp_opts_buf) ? " " : ""); + bwipp_opts = bwipp_opts_buf; + parse = 1; + } + } } else if (symbology == BARCODE_DOTCODE) { if (option_2 > 0) { sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scolumns=%d", @@ -3513,6 +3534,7 @@ int testUtilBwipp(int index, const struct zint_symbol *symbol, int option_1, int return 0; } +/* Append multiple segments together and then call `testUtilBwipp()` */ int testUtilBwippSegs(int index, struct zint_symbol *symbol, int option_1, int option_2, int option_3, const struct zint_seg segs[], const int seg_count, const char *primary, char *buffer, int buffer_size) { const int symbology = symbol->symbology; @@ -3679,6 +3701,7 @@ int testUtilHaveZXingCPPDecoder(void) { return system("zxingcppdecoder " DEV_NULL_STDERR) == 0; } +/* Helper to test whether have non-ASCII */ static int testUtilHasNonASCII(const char *source, const int length) { int i; for (i = 0; i < length; i++) { @@ -3826,7 +3849,7 @@ static const char *testUtilZXingCPPName(int index, const struct zint_symbol *sym { "", -1, 125, }, { "", -1, 126, }, { "", -1, 127, }, - { "", BARCODE_AZRUNE, 128, }, + { "Aztec", BARCODE_AZRUNE, 128, }, { "", BARCODE_CODE32, 129, }, /* Code39 based */ { "", BARCODE_EANX_CC, 130, }, { "", BARCODE_GS1_128_CC, 131, }, @@ -3844,6 +3867,8 @@ static const char *testUtilZXingCPPName(int index, const struct zint_symbol *sym { "QRCode", BARCODE_UPNQR, 143, }, { "", BARCODE_ULTRA, 144, }, { "RMQRCode", BARCODE_RMQR, 145, }, + { "", BARCODE_BC412, 146, }, + { "DXFilmEdge", BARCODE_DXFILMEDGE, 147, }, }; const int data_size = ARRAY_SIZE(data); @@ -3906,6 +3931,7 @@ int testUtilCanZXingCPP(int index, const struct zint_symbol *symbol, const char return testUtilZXingCPPName(index, symbol, source, length, debug) != NULL; } +/* Run "zxingcppdecoder", returning result in `buffer` */ int testUtilZXingCPP(int index, struct zint_symbol *symbol, const char *source, const int length, char *bits, char *buffer, const int buffer_size, int *p_cmp_len) { static const char cmd_fmt[] = "zxingcppdecoder -textonly -format %s -width %d -bits '%s'"; @@ -4038,6 +4064,37 @@ INTERNAL int escape_char_process_test(struct zint_symbol *symbol, const unsigned static const char TECHNETIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; /* Same as SILVER (CODE39) */ +/* Helper to strip leading zeroes (as long as have at least one non-zero digit) */ +static const char *testUtilZXingCPPLeadingZeroes(const char *expected) { + const char *stripped = expected; + while (*stripped == '0') stripped++; + return z_isdigit(*stripped) ? stripped : expected; +} + +/* Helper to convert DX number from "NNNN"/"NNNNNN" format to "NNN-NN" format */ +static int textUtilZXingCPPDX(const char *expected, const int expected_len, const char *cmp_buf, char *out) { + if (strchr(cmp_buf, '-')) { + const char *stripped; + if (strchr(expected, '-') == NULL) { + if (expected_len == 6) { + const int dx = to_int((const unsigned char *) expected + 1, expected_len - 2); + sprintf(out, "%d-%d", dx / 16, dx % 16); + } else { + const int dx = to_int((const unsigned char *) expected, expected_len); + sprintf(out, "%d-%d", dx / 16, dx % 16); + } + return 1; + } + if ((stripped = testUtilZXingCPPLeadingZeroes(expected)) != expected) { + memcpy(out, stripped, expected_len - (stripped - expected)); + out[expected_len - (stripped - expected)] = '\0'; + return 1; + } + } + return 0; +} + +/* Massage result from "zxingcppdecoder" so as can compare to Zint input */ int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, int cmp_len, const char *expected, int expected_len, const char *primary, char *ret_buf, int *p_ret_len) { const int symbology = symbol->symbology; @@ -4068,6 +4125,8 @@ int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, in ? (char *) z_alloca(expected_len + 3 + 19 + 1) : NULL; char *dpd = need_dpd_prefix ? (char *) z_alloca(28 + 1) : NULL; char *pzn = symbology == BARCODE_PZN ? (char *) z_alloca(expected_len + 1 + 1) : NULL; + char *dxfe = symbology == BARCODE_DXFILMEDGE ? (char *) z_alloca(expected_len * 2 + 1) : NULL; + char azrune[4]; int ret; int ret_memcmp; @@ -4226,7 +4285,6 @@ int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, in expected_len++; } c25inter[expected_len] = '\0'; - printf("c25inter %s\n", c25inter); expected = c25inter; } } else if (symbology == BARCODE_DPLEIT || symbology == BARCODE_DPIDENT) { @@ -4397,6 +4455,55 @@ int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, in } expected = pzn; expected_len++; + + } else if (symbology == BARCODE_DXFILMEDGE) { + const int dx_info_len = posn(expected, '/'); + if (dx_info_len != -1) { + char frame_info[20]; + assert(strlen(expected + dx_info_len + 1) < sizeof(frame_info)); + strcpy(frame_info, expected + dx_info_len + 1); + to_upper((unsigned char *) frame_info, (int) strlen(frame_info)); + if (!textUtilZXingCPPDX(expected, dx_info_len, cmp_buf, dxfe)) { + memcpy(dxfe, expected, dx_info_len); + dxfe[dx_info_len] = '\0'; + } + if (strcmp(frame_info, "S") == 0 || strcmp(frame_info, "X") == 0) { + strcat(dxfe, "/62"); + } else if (strcmp(frame_info, "SA") == 0 || strcmp(frame_info, "XA") == 0) { + strcat(dxfe, "/62A"); + } else if (strcmp(frame_info, "K") == 0 || strcmp(frame_info, "00") == 0) { + strcat(dxfe, "/63"); + } else if (strcmp(frame_info, "KA") == 0 || strcmp(frame_info, "00A") == 0) { + strcat(dxfe, "/63A"); + } else if (strcmp(frame_info, "F") == 0) { + strcat(dxfe, "/0"); + } else if (strcmp(frame_info, "FA") == 0) { + strcat(dxfe, "/0A"); + } else { + const char *stripped; + if ((stripped = testUtilZXingCPPLeadingZeroes(frame_info)) != frame_info) { + strcat(dxfe, "/"); + strcat(dxfe, stripped); + } else { + strcat(dxfe, expected + dx_info_len); + } + } + expected = dxfe; + expected_len = (int) strlen(expected); + to_upper((unsigned char *) expected, expected_len); + } else { + if (textUtilZXingCPPDX(expected, expected_len, cmp_buf, dxfe)) { + expected = dxfe; + expected_len = (int) strlen(expected); + } + } + + } else if (symbology == BARCODE_AZRUNE) { + if (expected_len != 3) { + sprintf(azrune, "%03d", to_int((const unsigned char *) expected, expected_len)); + expected = azrune; + expected_len = 3; + } } if (ret_buf) { diff --git a/backend/tests/testcommon.h b/backend/tests/testcommon.h index 83653f13..bf6652a9 100644 --- a/backend/tests/testcommon.h +++ b/backend/tests/testcommon.h @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2019-2024 Robin Stuart + Copyright (C) 2019-2025 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -57,8 +57,10 @@ extern "C" { #define testutil_pclose(stream) _pclose(stream) #else #include +# ifndef _WIN32 extern FILE *popen(const char *command, const char *type); extern int pclose(FILE *stream); +# endif #define testutil_popen(command, mode) popen(command, mode) #define testutil_pclose(stream) pclose(stream) #endif diff --git a/backend/tests/tools/run_bwipp_tests.sh b/backend/tests/tools/run_bwipp_tests.sh index 3e4d3d96..30321fd4 100755 --- a/backend/tests/tools/run_bwipp_tests.sh +++ b/backend/tests/tools/run_bwipp_tests.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (C) 2021-2024 Robin Stuart +# Copyright (C) 2021-2025 Robin Stuart # SPDX-License-Identifier: BSD-3-Clause # vim: set ts=4 sw=4 et : set -e @@ -34,6 +34,9 @@ run_bwipp_test "test_code16k" "encode" run_bwipp_test "test_code49" "input" run_bwipp_test "test_code49" "encode" run_bwipp_test "test_composite" +run_bwipp_test "test_dmatrix" "buffer" +run_bwipp_test "test_dmatrix" "options" +run_bwipp_test "test_dmatrix" "reader_init" run_bwipp_test "test_dmatrix" "input" run_bwipp_test "test_dmatrix" "encode" run_bwipp_test "test_dmatrix" "encode_segs" diff --git a/backend/tests/tools/run_zxingcpp_tests.sh b/backend/tests/tools/run_zxingcpp_tests.sh index 9d459d13..8d1faa09 100755 --- a/backend/tests/tools/run_zxingcpp_tests.sh +++ b/backend/tests/tools/run_zxingcpp_tests.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (C) 2021-2024 Robin Stuart +# Copyright (C) 2021-2025 Robin Stuart # SPDX-License-Identifier: BSD-3-Clause # vim: set ts=4 sw=4 et : set -e @@ -26,9 +26,14 @@ run_zxingcpp_test "test_code" "encode" run_zxingcpp_test "test_code128" run_zxingcpp_test "test_code16k" "input" run_zxingcpp_test "test_code16k" "encode" +run_zxingcpp_test "test_dmatrix" "large" +run_zxingcpp_test "test_dmatrix" "buffer" +run_zxingcpp_test "test_dmatrix" "options" +run_zxingcpp_test "test_dmatrix" "reader_init" run_zxingcpp_test "test_dmatrix" "input" run_zxingcpp_test "test_dmatrix" "encode" run_zxingcpp_test "test_dmatrix" "encode_segs" +run_zxingcpp_test "test_dxfilmedge" "encode" run_zxingcpp_test "test_dotcode" "input" run_zxingcpp_test "test_dotcode" "encode" run_zxingcpp_test "test_dotcode" "encode_segs" diff --git a/backend/zint.h b/backend/zint.h index c507a0e5..44d4c389 100644 --- a/backend/zint.h +++ b/backend/zint.h @@ -274,7 +274,8 @@ extern "C" { #define BARCODE_ULTRA 144 /* Ultracode */ #define BARCODE_RMQR 145 /* Rectangular Micro QR Code (rMQR) */ #define BARCODE_BC412 146 /* IBM BC412 (SEMI T1-95) */ -#define BARCODE_LAST 146 /* Max barcode number marker, not barcode */ +#define BARCODE_DXFILMEDGE 147 /* DX Film Edge Barcode on 35mm and APS films */ +#define BARCODE_LAST 147 /* Max barcode number marker, not barcode */ /* Output options (`symbol->output_options`) */ #define BARCODE_BIND_TOP 0x00001 /* Boundary bar above the symbol only (not below), does not affect stacking */ diff --git a/backend_qt/backend_qt.pro b/backend_qt/backend_qt.pro index c6578491..382595c4 100644 --- a/backend_qt/backend_qt.pro +++ b/backend_qt/backend_qt.pro @@ -71,20 +71,27 @@ HEADERS += ../backend/aztec.h \ qzint.h SOURCES += ../backend/2of5.c \ + ../backend/2of5inter.c \ + ../backend/2of5inter_based.c \ ../backend/auspost.c \ ../backend/aztec.c \ ../backend/bc412.c \ ../backend/bmp.c \ + ../backend/channel.c \ + ../backend/codabar.c \ ../backend/codablock.c \ ../backend/code.c \ ../backend/code1.c \ + ../backend/code11.c \ ../backend/code128.c \ + ../backend/code128_based.c \ ../backend/code16k.c \ ../backend/code49.c \ ../backend/common.c \ ../backend/composite.c \ ../backend/dmatrix.c \ ../backend/dotcode.c \ + ../backend/dxfilmedge.c \ ../backend/eci.c \ ../backend/emf.c \ ../backend/filemem.c \ diff --git a/backend_qt/backend_vc8.pro b/backend_qt/backend_vc8.pro index 36180d04..f5c3e86b 100644 --- a/backend_qt/backend_vc8.pro +++ b/backend_qt/backend_vc8.pro @@ -54,20 +54,27 @@ HEADERS += ../backend/aztec.h \ qzint.h SOURCES += ../backend/2of5.c \ + ../backend/2of5inter.c \ + ../backend/2of5inter_based.c \ ../backend/auspost.c \ ../backend/aztec.c \ ../backend/bc412.c \ ../backend/bmp.c \ + ../backend/channel.c \ + ../backend/codabar.c \ ../backend/codablock.c \ ../backend/code.c \ ../backend/code1.c \ + ../backend/code11.c \ ../backend/code128.c \ + ../backend/code128_based.c \ ../backend/code16k.c \ ../backend/code49.c \ ../backend/common.c \ ../backend/composite.c \ ../backend/dmatrix.c \ ../backend/dotcode.c \ + ../backend/dxfilmedge.c \ ../backend/eci.c \ ../backend/emf.c \ ../backend/gridmtx.c \ diff --git a/backend_tcl/configure b/backend_tcl/configure index 8c3c2891..070ccdc1 100755 --- a/backend_tcl/configure +++ b/backend_tcl/configure @@ -643,6 +643,7 @@ TCLSH_PROG VC_MANIFEST_EMBED_EXE VC_MANIFEST_EMBED_DLL RANLIB_STUB +PKG_STUB_LIB_FILE MAKE_STUB_LIB MAKE_STATIC_LIB MAKE_SHARED_LIB @@ -706,7 +707,6 @@ PKG_HEADERS PKG_TCL_SOURCES PKG_STUB_OBJECTS PKG_STUB_SOURCES -PKG_STUB_LIB_FILE PKG_LIB_FILE9 PKG_LIB_FILE8 PKG_LIB_FILE @@ -2580,8 +2580,6 @@ printf "%s\n" "$as_me: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&6;} - # Substitute STUB_LIB_FILE in case package creates a stub library too. - # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... @@ -2770,10 +2768,16 @@ printf "%s\n" "$as_me: WARNING: --with-tcl argument should refer to directory co `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ + `ls -d /usr/lib/tcl9.0 2>/dev/null` \ + `ls -d /usr/lib/tcl8.7 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl9.0 2>/dev/null` \ + `ls -d /usr/local/lib/tcl8.7 2>/dev/null` \ `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tcl9.0 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tcl8.7 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \ ; do @@ -3849,11 +3853,11 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu printf %s "checking for existence of ${TCL_BIN_DIR}/tclConfig.sh... " >&6; } if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: loading" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: loading" >&5 printf "%s\n" "loading" >&6; } . "${TCL_BIN_DIR}/tclConfig.sh" else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5 printf "%s\n" "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi @@ -3864,9 +3868,9 @@ printf "%s\n" "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; } # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then - TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" - TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" - TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" + TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" + TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" + TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works @@ -5175,10 +5179,14 @@ printf "%s\n" "$tcl_cv_cc_pipe" >&6; } fi fi + if test "${TCL_MAJOR_VERSION}" -lt 9 -a "${TCL_MINOR_VERSION}" -lt 7; then + +printf "%s\n" "#define Tcl_Size int" >>confdefs.h + + fi + #-------------------------------------------------------------------- # Common compiler flag setup - # ####GL Suppress "warning: AC_C_BIGENDIAN should be used with AC_CONFIG_HEADERS", taken from - # ####GL https://git.ruby-lang.org/ruby.git/commit/?id=ca3cc677b31897e7306ac3b4565a0dd928168b08 #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 @@ -5412,8 +5420,7 @@ printf "%s\n" "$ac_cv_c_bigendian" >&6; } no) ;; #( universal) - printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h - + # ;; #( *) as_fn_error $? "unknown endianness @@ -5435,21 +5442,28 @@ printf "%s\n" "$ac_cv_c_bigendian" >&6; } vars=" ../backend/2of5.c + ../backend/2of5inter.c + ../backend/2of5inter_based.c ../backend/auspost.c ../backend/aztec.c ../backend/bc412.c ../backend/bmp.c + ../backend/channel.c + ../backend/codabar.c ../backend/codablock.c - ../backend/code128.c - ../backend/code16k.c - ../backend/code1.c - ../backend/code49.c ../backend/code.c + ../backend/code1.c + ../backend/code11.c + ../backend/code128.c + ../backend/code128_based.c + ../backend/code16k.c + ../backend/code49.c ../backend/common.c ../backend/composite.c ../backend/dllversion.c ../backend/dmatrix.c ../backend/dotcode.c + ../backend/dxfilmedge.c ../backend/eci.c ../backend/emf.c ../backend/filemem.c @@ -6131,7 +6145,7 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: shared" >&5 printf "%s\n" "shared" >&6; } SHARED_BUILD=1 - STUBS_BUILD=1 + STUBS_BUILD=1 else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: static" >&5 printf "%s\n" "static" >&6; } @@ -6139,11 +6153,11 @@ printf "%s\n" "static" >&6; } printf "%s\n" "#define STATIC_BUILD 1" >>confdefs.h - if test "$stubs_ok" = "yes" ; then - STUBS_BUILD=1 - else - STUBS_BUILD=0 - fi + if test "$stubs_ok" = "yes" ; then + STUBS_BUILD=1 + else + STUBS_BUILD=0 + fi fi if test "${STUBS_BUILD}" = "1" ; then @@ -6582,14 +6596,14 @@ fi fi if test "$GCC" != "yes" ; then - if test "${SHARED_BUILD}" = "0" ; then + if test "${SHARED_BUILD}" = "0" ; then runtime=-MT - else + else runtime=-MD - fi - case "x`echo \${VisualStudioVersion}`" in - x1[4-9]*) - lflags="${lflags} -nodefaultlib:libucrt.lib" + fi + case "x`echo \${VisualStudioVersion}`" in + x1[4-9]*) + lflags="${lflags} -nodefaultlib:libucrt.lib" vars="ucrt.lib" for i in $vars; do @@ -6601,12 +6615,12 @@ fi done - ;; - *) - ;; - esac + ;; + *) + ;; + esac - if test "$do64bit" != "no" ; then + if test "$do64bit" != "no" ; then CC="cl.exe" RC="rc.exe" lflags="${lflags} -nologo -MACHINE:${MACHINE} " @@ -6829,7 +6843,7 @@ printf "%s\n" "$ac_cv_cross" >&6; } SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots - ;; + ;; AIX-*) if test "$GCC" != "yes" then : @@ -6841,7 +6855,7 @@ then : ;; *) # Make sure only first arg gets _r - CC=`echo "$CC" | sed -e 's/^\([^ ]*\)/\1_r/'` + CC=`echo "$CC" | sed -e 's/^\([^ ]*\)/\1_r/'` ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using $CC for compiling with threads" >&5 @@ -7323,19 +7337,19 @@ fi if test "$do64bit" = yes then : - if test "$GCC" = yes + if test "$GCC" = yes then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported by gcc" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported by gcc" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported by gcc" >&2;} else case e in #( e) - do64bit_ok=yes - SHLIB_LD="ld -64 -shared -rdata_shared" - CFLAGS="$CFLAGS -64" - LDFLAGS_ARCH="-64" - ;; + do64bit_ok=yes + SHLIB_LD="ld -64 -shared -rdata_shared" + CFLAGS="$CFLAGS -64" + LDFLAGS_ARCH="-64" + ;; esac fi @@ -7363,7 +7377,7 @@ then : LDFLAGS="$LDFLAGS $PTHREAD_LIBS" fi ;; - esac + esac if test $doRpath = yes then : @@ -7611,46 +7625,6 @@ esac fi # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ld accepts -single_module flag" >&5 -printf %s "checking if ld accepts -single_module flag... " >&6; } -if test ${tcl_cv_ld_single_module+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) - hold_ldflags=$LDFLAGS - LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -int i; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - tcl_cv_ld_single_module=yes -else case e in #( - e) tcl_cv_ld_single_module=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$hold_ldflags ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_single_module" >&5 -printf "%s\n" "$tcl_cv_ld_single_module" >&6; } - if test $tcl_cv_ld_single_module = yes -then : - - SHLIB_LD="${SHLIB_LD} -Wl,-single_module" - -fi # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([0-9]\{1,5\}\)\(\(\.[0-9]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" @@ -7827,11 +7801,11 @@ printf "%s\n" "#define _OE_SOCKETS 1" >>confdefs.h if test "$SHARED_BUILD" = 1 then : - SHLIB_LD='ld -shared -expect_unresolved "*"' + SHLIB_LD='ld -shared -expect_unresolved "*"' else case e in #( e) - SHLIB_LD='ld -non_shared -expect_unresolved "*"' + SHLIB_LD='ld -non_shared -expect_unresolved "*"' ;; esac fi @@ -8120,7 +8094,7 @@ esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$hold_ldflags ;; + LDFLAGS=$hold_ldflags ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_Bexport" >&5 @@ -8468,8 +8442,9 @@ printf "%s\n" "#define _ISOC99_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _ISOC99_SOURCE" fi + if test "${TCL_MAJOR_VERSION}" -ne 8 ; then - if test ${tcl_cv_flag__largefile64_source+y} + if test ${tcl_cv_flag__file_offset_bits+y} then : printf %s "(cached) " >&6 else case e in #( @@ -8479,32 +8454,32 @@ else case e in #( int main (void) { -struct stat64 buf; int i = stat64("/", &buf); +switch (0) { case 0: case (sizeof(off_t)==sizeof(long long)): ; } ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : - tcl_cv_flag__largefile64_source=no + tcl_cv_flag__file_offset_bits=no else case e in #( e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#define _LARGEFILE64_SOURCE 1 +#define _FILE_OFFSET_BITS 64 #include int main (void) { -struct stat64 buf; int i = stat64("/", &buf); +switch (0) { case 0: case (sizeof(off_t)==sizeof(long long)): ; } ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : - tcl_cv_flag__largefile64_source=yes + tcl_cv_flag__file_offset_bits=yes else case e in #( - e) tcl_cv_flag__largefile64_source=no ;; + e) tcl_cv_flag__file_offset_bits=no ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -8514,66 +8489,14 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi - if test "x${tcl_cv_flag__largefile64_source}" = "xyes" ; then + if test "x${tcl_cv_flag__file_offset_bits}" = "xyes" ; then -printf "%s\n" "#define _LARGEFILE64_SOURCE 1" >>confdefs.h +printf "%s\n" "#define _FILE_OFFSET_BITS 64" >>confdefs.h - tcl_flags="$tcl_flags _LARGEFILE64_SOURCE" + tcl_flags="$tcl_flags _FILE_OFFSET_BITS" fi - - if test ${tcl_cv_flag__largefile_source64+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -char *p = (char *)open64; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - tcl_cv_flag__largefile_source64=no -else case e in #( - e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#define _LARGEFILE_SOURCE64 1 -#include -int -main (void) -{ -char *p = (char *)open64; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - tcl_cv_flag__largefile_source64=yes -else case e in #( - e) tcl_cv_flag__largefile_source64=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; -esac -fi - - if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then - -printf "%s\n" "#define _LARGEFILE_SOURCE64 1" >>confdefs.h - - tcl_flags="$tcl_flags _LARGEFILE_SOURCE64" fi - if test "x${tcl_flags}" = "x" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 printf "%s\n" "none" >&6; } @@ -8614,15 +8537,15 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # See if we could use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { switch (0) { - case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; - } + case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; + } ; return 0; } @@ -8655,6 +8578,79 @@ printf "%s\n" "#define TCL_WIDE_INT_TYPE ${tcl_cv_type_64bit}" >>confdefs.h printf "%s\n" "${tcl_cv_type_64bit}" >&6; } # Now check for auxiliary declarations + if test "${TCL_MAJOR_VERSION}" -ne 8 ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit time_t" >&5 +printf %s "checking for 64-bit time_t... " >&6; } +if test ${tcl_cv_time_t_64+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ +switch (0) {case 0: case (sizeof(time_t)==sizeof(long long)): ;} + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + tcl_cv_time_t_64=yes +else case e in #( + e) tcl_cv_time_t_64=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_time_t_64" >&5 +printf "%s\n" "$tcl_cv_time_t_64" >&6; } + if test "x${tcl_cv_time_t_64}" = "xno" ; then + # Note that _TIME_BITS=64 requires _FILE_OFFSET_BITS=64 + # which SC_TCL_EARLY_FLAGS has defined if necessary. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if _TIME_BITS=64 enables 64-bit time_t" >&5 +printf %s "checking if _TIME_BITS=64 enables 64-bit time_t... " >&6; } +if test ${tcl_cv__time_bits+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _TIME_BITS 64 +#include +int +main (void) +{ +switch (0) {case 0: case (sizeof(time_t)==sizeof(long long)): ;} + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + tcl_cv__time_bits=yes +else case e in #( + e) tcl_cv__time_bits=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv__time_bits" >&5 +printf "%s\n" "$tcl_cv__time_bits" >&6; } + if test "x${tcl_cv__time_bits}" = "xyes" ; then + +printf "%s\n" "#define _TIME_BITS 64" >>confdefs.h + + fi + fi + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct dirent64" >&5 printf %s "checking for struct dirent64... " >&6; } if test ${tcl_cv_struct_dirent64+y} @@ -8707,7 +8703,7 @@ int main (void) { struct dirent64 *p; DIR64 d = opendir64("."); - p = readdir64(d); rewinddir64(d); closedir64(d); + p = readdir64(d); rewinddir64(d); closedir64(d); ; return 0; } @@ -8811,8 +8807,8 @@ esac fi if test "x${tcl_cv_type_off64_t}" = "xyes" && \ - test "x${ac_cv_func_lseek64}" = "xyes" && \ - test "x${ac_cv_func_open64}" = "xyes" ; then + test "x${ac_cv_func_lseek64}" = "xyes" && \ + test "x${ac_cv_func_open64}" = "xyes" ; then printf "%s\n" "#define HAVE_TYPE_OFF64_T 1" >>confdefs.h @@ -9068,13 +9064,18 @@ rm -rf conftest* PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" - if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" == x; then + if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" else PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" printf "%s\n" "#define TCL_MAJOR_VERSION 8" >>confdefs.h + fi + if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tk8}" != x; then + +printf "%s\n" "#define TK_MAJOR_VERSION 8" >>confdefs.h + fi if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then @@ -9099,7 +9100,11 @@ printf "%s\n" "#define TCL_MAJOR_VERSION 8" >>confdefs.h eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries - eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then + eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub.a" + else + eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + fi if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi @@ -9118,12 +9123,16 @@ printf "%s\n" "#define TCL_MAJOR_VERSION 8" >>confdefs.h eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else - eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" - eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries - eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then + eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub.a" + else + eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" + fi fi # These are escaped so that only CFLAGS is picked up at configure time. @@ -9137,6 +9146,8 @@ printf "%s\n" "#define TCL_MAJOR_VERSION 8" >>confdefs.h + # Substitute STUB_LIB_FILE in case package creates a stub library too. + @@ -9154,37 +9165,37 @@ printf "%s\n" "#define TCL_MAJOR_VERSION 8" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5 printf %s "checking for tclsh... " >&6; } if test -f "${TCL_BIN_DIR}/Makefile" ; then - # tclConfig.sh is in Tcl build directory - if test "${TEA_PLATFORM}" = "windows"; then - if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then - TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" - elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then - TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" - elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then - TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" - elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then - TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" - fi - else - TCLSH_PROG="${TCL_BIN_DIR}/tclsh" - fi + # tclConfig.sh is in Tcl build directory + if test "${TEA_PLATFORM}" = "windows"; then + if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" + fi + else + TCLSH_PROG="${TCL_BIN_DIR}/tclsh" + fi else - # tclConfig.sh is in install location - if test "${TEA_PLATFORM}" = "windows"; then - TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" - else - TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" - fi - list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ - `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ - `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" - for i in $list ; do - if test -f "$i/${TCLSH_PROG}" ; then - REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" - break - fi - done - TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" + # tclConfig.sh is in install location + if test "${TEA_PLATFORM}" = "windows"; then + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" + else + TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" + fi + list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ + `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ + `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" + for i in $list ; do + if test -f "$i/${TCLSH_PROG}" ; then + REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" + break + fi + done + TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${TCLSH_PROG}" >&5 printf "%s\n" "${TCLSH_PROG}" >&6; } diff --git a/backend_tcl/configure.ac b/backend_tcl/configure.ac index cb973b94..4e6aa8a5 100644 --- a/backend_tcl/configure.ac +++ b/backend_tcl/configure.ac @@ -73,21 +73,28 @@ TEA_SETUP_COMPILER TEA_ADD_SOURCES([ ../backend/2of5.c + ../backend/2of5inter.c + ../backend/2of5inter_based.c ../backend/auspost.c ../backend/aztec.c ../backend/bc412.c ../backend/bmp.c + ../backend/channel.c + ../backend/codabar.c ../backend/codablock.c - ../backend/code128.c - ../backend/code16k.c - ../backend/code1.c - ../backend/code49.c ../backend/code.c + ../backend/code1.c + ../backend/code11.c + ../backend/code128.c + ../backend/code128_based.c + ../backend/code16k.c + ../backend/code49.c ../backend/common.c ../backend/composite.c ../backend/dllversion.c ../backend/dmatrix.c ../backend/dotcode.c + ../backend/dxfilmedge.c ../backend/eci.c ../backend/emf.c ../backend/filemem.c diff --git a/backend_tcl/win/makefile.vc b/backend_tcl/win/makefile.vc index be2db55f..8b2c7442 100644 --- a/backend_tcl/win/makefile.vc +++ b/backend_tcl/win/makefile.vc @@ -51,6 +51,7 @@ PRJ_OBJS = \ $(TMP_DIR)\dllversion.obj \ $(TMP_DIR)\dmatrix.obj \ $(TMP_DIR)\dotcode.obj \ + $(TMP_DIR)\dxfilmedge.obj \ $(TMP_DIR)\eci.obj \ $(TMP_DIR)\emf.obj \ $(TMP_DIR)\filemem.obj \ diff --git a/backend_tcl/zint.c b/backend_tcl/zint.c index dd5fd9c4..276f6ddd 100644 --- a/backend_tcl/zint.c +++ b/backend_tcl/zint.c @@ -1,7 +1,7 @@ /* zint_tcl.c TCL binding for zint */ /* zint - the open source tcl binding to the zint barcode library - Copyright (C) 2014-2023 Harald Oehlmann + Copyright (C) 2014-2024 Harald Oehlmann Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -176,6 +176,8 @@ - TCL 9 compatibility - support TCL buildinfo - remove the zint command on dll unload +2024-12-23 GL +- Added DXFILMEDGE */ #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) @@ -330,6 +332,7 @@ static const char *s_code_list[] = { "MailMark-2D", "UPU-S10", "MailMark-4S", + "DXFilmEdge", "AztecRunes", "Code32", "EAN-CC", @@ -432,6 +435,7 @@ static const int s_code_number[] = { BARCODE_MAILMARK_2D, BARCODE_UPU_S10, BARCODE_MAILMARK_4S, + BARCODE_DXFILMEDGE, BARCODE_AZRUNE, BARCODE_CODE32, BARCODE_EANX_CC, diff --git a/docs/README b/docs/README index aafad60b..a011d5e7 100644 --- a/docs/README +++ b/docs/README @@ -1,11 +1,11 @@ -% docs/README 2024-10-27 +% docs/README 2025-01-18 For generation of "docs/manual.pdf" and "docs/manual.txt" from "manual.pmd" using a recent version of pandoc On Ubuntu/Debian (tested on Ubuntu 22.04 and Ubuntu 24.04) - wget https://github.com/jgm/pandoc/releases/download/3.5/pandoc-3.5-1-amd64.deb - sudo dpkg -i pandoc-3.5-1-amd64.deb + wget https://github.com/jgm/pandoc/releases/download/3.6.2/pandoc-3.6.2-1-amd64.deb + sudo dpkg -i pandoc-3.6.2-1-amd64.deb For Ubuntu 22.04 (python < 3.12) sudo apt install python3-pip pip install pandoc-tablenos --user @@ -27,9 +27,9 @@ Then On Fedora (tested on Fedora Linux 38 (Workstation Edition) and Fedora Linux 40 (Workstation Edition)) - wget https://github.com/jgm/pandoc/releases/download/3.5/pandoc-3.5-linux-amd64.tar.gz - tar xf pandoc-3.5-linux-amd64.tar.gz - sudo mv -i pandoc-3.5/bin/pandoc /usr/local/bin + wget https://github.com/jgm/pandoc/releases/download/3.6.2/pandoc-3.6.2-linux-amd64.tar.gz + tar xf pandoc-3.6.2-linux-amd64.tar.gz + sudo mv -i pandoc-3.6.2/bin/pandoc /usr/local/bin sudo dnf install python3-pip pip install pandoc-tablenos --user export PATH=~/.local/bin:"$PATH" diff --git a/docs/images/dxfilmedge.svg b/docs/images/dxfilmedge.svg new file mode 100644 index 00000000..da2b3fe3 --- /dev/null +++ b/docs/images/dxfilmedge.svg @@ -0,0 +1,9 @@ + + + + Zint Generated Symbol + + + + + diff --git a/docs/manual.html b/docs/manual.html index b4a3a853..bd496eea 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -260,8 +260,9 @@ } .display.math{display: block; text-align: center; margin: 0.5rem auto;} /* CSS for syntax highlighting */ + html { -webkit-text-size-adjust: 100%; } pre > code.sourceCode { white-space: pre; position: relative; } - pre > code.sourceCode > span { line-height: 1.25; } + pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } pre > code.sourceCode > span:empty { height: 1.2em; } .sourceCode { overflow: visible; } code.sourceCode > span { color: inherit; text-decoration: inherit; } @@ -272,7 +273,7 @@ } @media print { pre > code.sourceCode { white-space: pre-wrap; } - pre > code.sourceCode > span { display: inline-block; text-indent: -5em; padding-left: 5em; } + pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } } pre.numberSource code { counter-reset: source-line 0; } @@ -332,7 +333,7 @@

Zint Barcode Generator and Zint Barcode Studio User Manual

Version 2.13.0.9

-

November 2024

+

January 2025