From fab7435fac1cb441e8543d3df588001d417bf845 Mon Sep 17 00:00:00 2001 From: gitlost Date: Wed, 20 Oct 2021 23:05:30 +0100 Subject: [PATCH] Performance improvements for linear encoding and raster output - use fixed-length string tables (mostly) instead of (char *) pointer ones (saves ~40K) - re-use C128Table for CODABLOCKF and CODE16K (required removal of Stop character and extra CODE16K-only entry) - use pointer to destination and copy (memcpy/strcpy(), bin_append_posn()) instead of concatenating (strcat()) (mostly) - replace last remaining bin_append()s with bin_append_posn(); bin_append() removed - add length arg to toupper() and expand() (avoids strlen()) - change is_sane() to use table-based flags (avoids an iteration) - rename lookup() to is_sane_lookup() and change to check and return posns and use in pointer to destination loops (avoids strcat()s) - remove special case PHARMA in expand() (dealt with in pharma()) - make #define SILVER/CALCIUM/TECHNETIUM/KRSET etc static strings - replace strchr() -> posn() - CODE128: populate destination once in checksum loop; re-use and export some more routines (c128_set_a/b/c(), c128_put_in_set()) for sharing; prefix defines (SHIFTA -> C128_SHIFTA etc) and existing exported routines - use factor XOR toggle trick in checksum calcs (avoids branch) - raster.c: fill out single 1-pixel row and copy using new draw_bar_line(), copy_bar_line() routines; similarly in buffer_plot compare previous line & copy if same (same technique as used to improve non-half-integer scaling, significant performance increase, (c) codemonkey82); also done for PNG (BMP/GIF/PCX/TIFF not done) - raster/vector/output.c: shorten "output_" prefix -> "out_"; sync vector to other raster changes to try to keep source files similar - 2of5.c: prefix "c25_" JAPANPOST: return error if input data truncated (backward incompatible) DAFT: max chars 50 -> 100 common.c: istwodigit() -> is_twodigit() common.c/emf.c/output.c: use some further stripf()s (MSVC6 float variations) library.c: new check_output_args() helper zint.h: add BARCODE_LAST marker and use in library.c QRCODE: remove a NOLINT (requires clang-tidy-13), one remaining CMake: separate no-optimize from ZINT_DEBUG into new ZINT_NOOPT option --- CMakeLists.txt | 41 +- ChangeLog | 6 +- backend/2of5.c | 138 ++--- backend/auspost.c | 130 +++-- backend/aztec.c | 5 +- backend/codablock.c | 31 +- backend/code.c | 340 +++++++------ backend/code1.c | 10 +- backend/code1.h | 15 +- backend/code128.c | 561 ++++++++++---------- backend/code128.h | 29 +- backend/code16k.c | 153 +----- backend/code49.c | 42 +- backend/code49.h | 33 +- backend/common.c | 122 +++-- backend/common.h | 44 +- backend/composite.c | 7 +- backend/dllversion.c | 50 +- backend/dmatrix.c | 4 +- backend/dotcode.c | 2 +- backend/emf.c | 46 +- backend/emf.h | 11 +- backend/font.h | 3 +- backend/general_field.c | 5 +- backend/gridmtx.c | 16 +- backend/gridmtx.h | 6 +- backend/gs1.c | 18 +- backend/hanxin.c | 8 +- backend/imail.c | 11 +- backend/large.c | 2 +- backend/library.c | 131 ++--- backend/mailmark.c | 42 +- backend/maxicode.c | 2 +- backend/medical.c | 136 +++-- backend/output.c | 48 +- backend/output.h | 10 +- backend/plessey.c | 140 ++--- backend/png.c | 34 +- backend/postal.c | 288 ++++++----- backend/qr.c | 207 ++++---- backend/raster.c | 329 ++++++------ backend/reedsol.c | 16 +- backend/rss.c | 20 +- backend/svg.c | 4 +- backend/telepen.c | 114 +++-- backend/tests/test_2of5.c | 146 +++++- backend/tests/test_auspost.c | 31 +- backend/tests/test_channel.c | 60 +++ backend/tests/test_codablock.c | 17 +- backend/tests/test_code.c | 253 +++++++-- backend/tests/test_code128.c | 100 ++++ backend/tests/test_common.c | 267 ++++++++-- backend/tests/test_emf.c | 2 +- backend/tests/test_imail.c | 2 +- backend/tests/test_library.c | 2 +- backend/tests/test_output.c | 6 +- backend/tests/test_plessey.c | 102 ++++ backend/tests/test_png.c | 28 + backend/tests/test_postal.c | 230 +++++++-- backend/tests/test_raster.c | 50 +- backend/tests/test_reedsol.c | 26 +- backend/tests/test_telepen.c | 57 +++ backend/tests/test_tif.c | 2 +- backend/tests/test_upcean.c | 623 ++++++++++++++--------- backend/tests/testcommon.c | 21 +- backend/tests/testcommon.h | 12 +- backend/tests/tools/bwipp_dump.ps.tar.xz | Bin 123856 -> 123868 bytes backend/ultra.c | 16 +- backend/upcean.c | 251 ++++----- backend/vector.c | 164 +++--- backend/zint.h | 1 + frontend_qt/mainwindow.cpp | 2 +- 72 files changed, 3501 insertions(+), 2380 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ad8e2980..c598c6b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ add_definitions(-DZINT_VERSION=\"${ZINT_VERSION}\") set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") option(ZINT_DEBUG "Set debug compile flags" OFF) +option(ZINT_NOOPT "Set no optimize compile flags" OFF) option(ZINT_SANITIZE "Set sanitize compile/link flags" OFF) option(ZINT_TEST "Set test compile flag" OFF) option(ZINT_COVERAGE "Set code coverage flags" OFF) @@ -52,32 +53,15 @@ if(ZINT_DEBUG) if(CXX_COMPILER_FLAG_G) add_compile_options("-g") endif() +endif() +if(ZINT_NOOPT) check_cxx_compiler_flag("-O0" CXX_COMPILER_FLAG_O0) if(CXX_COMPILER_FLAG_O0) add_compile_options("-O0") endif() endif() -if(ZINT_TEST) - enable_testing() -endif() - -if(ZINT_COVERAGE) - set(CMAKE_REQUIRED_LIBRARIES -fprofile-arcs) - check_cxx_compiler_flag(--coverage CXX_COMPILER_FLAG_COVERAGE) - unset(CMAKE_REQUIRED_LIBRARIES) - if(CXX_COMPILER_FLAG_COVERAGE) - add_compile_options(--coverage) - link_libraries(-fprofile-arcs) - - check_cxx_compiler_flag(-O0 CXX_COMPILER_FLAG_O0) - if(CXX_COMPILER_FLAG_O0) - add_compile_options(-O0) - endif() - endif() -endif() - if(ZINT_SANITIZE) if(MSVC) if(MSVC_VERSION GREATER_EQUAL 1920) @@ -105,6 +89,25 @@ if(ZINT_SANITIZE) endif() endif() +if(ZINT_TEST) + enable_testing() +endif() + +if(ZINT_COVERAGE) + set(CMAKE_REQUIRED_LIBRARIES -fprofile-arcs) + check_cxx_compiler_flag(--coverage CXX_COMPILER_FLAG_COVERAGE) + unset(CMAKE_REQUIRED_LIBRARIES) + if(CXX_COMPILER_FLAG_COVERAGE) + add_compile_options(--coverage) + link_libraries(-fprofile-arcs) + + check_cxx_compiler_flag(-O0 CXX_COMPILER_FLAG_O0) + if(CXX_COMPILER_FLAG_O0) + add_compile_options(-O0) + endif() + endif() +endif() + if(APPLE) if(UNIVERSAL) # TODO: make universal binary if(NOT ZINT_HAS_BEEN_RUN_BEFORE) diff --git a/ChangeLog b/ChangeLog index a060384b..77d00c34 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,8 @@ Version 2.10.0.9 (dev) not released yet NOTE: will return error if values outside ranges - raster.c: Bug fix for heap-buffer-overflow (#204 ARM-Cortex) NOTE: may cause single-pixel changes to height depending on height/scale used +- JAPANPOST: return error if input data would be truncated + NOTE: previously was silently truncated Changes ------- @@ -31,6 +33,8 @@ Changes - GUI: add Menu, copy to clipboard EMF/GIF/PNG/TIF, errtxt bar and status bar, icons (feathericons) - CODABAR: add show check digit option +- DAFT: max chars 50 -> 100 +- CMake: separate no-optimize from ZINT_DEBUG into new ZINT_NOOPT option Bugs ---- @@ -43,7 +47,7 @@ Bugs also ceilf(large_bar_height * si); also avoid distributive multiplication with floats to lessen chances of platform variation (#204 ARM-Cortex crash) -- raster/vector.c: use new stripf() func to workaround gcc 32-bit +- common/emf/output/raster/vector.c: use new stripf() func to workaround float variations - raster.c: Don't add height offset for text if scale < 1.0 (as won't print) - ISBNX: fix not returning error number (warning) correctly diff --git a/backend/2of5.c b/backend/2of5.c index 64d6aa84..2873038d 100644 --- a/backend/2of5.c +++ b/backend/2of5.c @@ -35,38 +35,42 @@ #include "common.h" #include "gs1.h" -static const char *C25MatrixTable[10] = { - "113311", "311131", "131131", "331111", "113131", - "313111", "133111", "111331", "311311", "131311" +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'}, + {'3','1','1','3','1','1'}, {'1','3','1','3','1','1'} }; +static const char C25IndustTable[10][10] = { + {'1','1','1','1','3','1','3','1','1','1'}, {'3','1','1','1','1','1','1','1','3','1'}, + {'1','1','3','1','1','1','1','1','3','1'}, {'3','1','3','1','1','1','1','1','1','1'}, + {'1','1','1','1','3','1','1','1','3','1'}, {'3','1','1','1','3','1','1','1','1','1'}, + {'1','1','3','1','3','1','1','1','1','1'}, {'1','1','1','1','1','1','3','1','3','1'}, + {'3','1','1','1','1','1','3','1','1','1'}, {'1','1','3','1','1','1','3','1','1','1'} +}; + +/* Note `c25_common()` assumes Stop string length one less than Start */ static const char *C25MatrixStartStop[2] = { "411111", "41111" }; - -static const char *C25IndustTable[10] = { - "1111313111", "3111111131", "1131111131", "3131111111", "1111311131", - "3111311111", "1131311111", "1111113131", "3111113111", "1131113111" -}; - static const char *C25IndustStartStop[2] = { "313111", "31113" }; - static const char *C25IataLogicStartStop[2] = { "1111", "311" }; -static const char *C25InterTable[10] = { - "11331", "31113", "13113", "33111", "11313", - "31311", "13311", "11133", "31131", "13131" +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'} }; -static char check_digit(const unsigned int count) { +static char c25_check_digit(const unsigned int count) { return itoc((10 - (count % 10)) % 10); } /* Common to Standard (Matrix), Industrial, IATA, and Data Logic */ static int c25_common(struct zint_symbol *symbol, const unsigned char source[], int length, const int max, - const char *table[10], const char *start_stop[2], const int error_base) { + const int is_matrix, const char *start_stop[2], const int start_length, const int error_base) { int i; - char dest[512]; /* Largest destination 6 + (80 + 1) * 6 + 5 + 1 = 498 */ - unsigned char temp[80 + 1 + 1]; /* Largest maximum 80 */ + char dest[500]; /* Largest destination 6 + (80 + 1) * 6 + 5 + 1 = 498 */ + char *d = dest; + unsigned char temp[80 + 1 + 1]; /* Largest maximum 80 + optional check digit */ int have_checkdigit = symbol->option_2 == 1 || symbol->option_2 == 2; if (length > max) { @@ -74,7 +78,7 @@ static int c25_common(struct zint_symbol *symbol, const unsigned char source[], sprintf(symbol->errtxt, "%d: Input too long (%d character maximum)", error_base, max); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { /* errtxt 302: 304: 306: 308: */ sprintf(symbol->errtxt, "%d: Invalid character in data (digits only)", error_base + 1); return ZINT_ERROR_INVALID_DATA; @@ -88,17 +92,25 @@ static int c25_common(struct zint_symbol *symbol, const unsigned char source[], temp[++length] = '\0'; } - /* start character */ - strcpy(dest, start_stop[0]); + /* Start character */ + memcpy(d, start_stop[0], start_length); + d += start_length; - for (i = 0; i < length; i++) { - lookup(NEON, table, temp[i], dest); + if (is_matrix) { + for (i = 0; i < length; i++, d += 6) { + memcpy(d, C25MatrixTable[temp[i] - '0'], 6); + } + } else { + for (i = 0; i < length; i++, d += 10) { + memcpy(d, C25IndustTable[temp[i] - '0'], 10); + } } /* Stop character */ - strcat(dest, start_stop[1]); + memcpy(d, start_stop[1], start_length - 1); + d += start_length - 1; - expand(symbol, dest); + expand(symbol, dest, d - dest); ustrcpy(symbol->text, temp); if (symbol->option_2 == 2) { @@ -111,29 +123,30 @@ static int c25_common(struct zint_symbol *symbol, const unsigned char source[], /* Code 2 of 5 Standard (Code 2 of 5 Matrix) */ INTERNAL int c25standard(struct zint_symbol *symbol, unsigned char source[], int length) { - return c25_common(symbol, source, length, 80, C25MatrixTable, C25MatrixStartStop, 301); + return c25_common(symbol, source, length, 80, 1 /*is_matrix*/, C25MatrixStartStop, 6, 301); } /* Code 2 of 5 Industrial */ INTERNAL int c25ind(struct zint_symbol *symbol, unsigned char source[], int length) { - return c25_common(symbol, source, length, 45, C25IndustTable, C25IndustStartStop, 303); + return c25_common(symbol, source, length, 45, 0 /*is_matrix*/, C25IndustStartStop, 6, 303); } /* Code 2 of 5 IATA */ INTERNAL int c25iata(struct zint_symbol *symbol, unsigned char source[], int length) { - return c25_common(symbol, source, length, 45, C25IndustTable, C25IataLogicStartStop, 305); + return c25_common(symbol, source, length, 45, 0 /*is_matrix*/, C25IataLogicStartStop, 4, 305); } /* Code 2 of 5 Data Logic */ INTERNAL int c25logic(struct zint_symbol *symbol, unsigned char source[], int length) { - return c25_common(symbol, source, length, 80, C25MatrixTable, C25IataLogicStartStop, 307); + return c25_common(symbol, source, length, 80, 1 /*is_matrix*/, C25IataLogicStartStop, 4, 307); } /* Common to Interleaved, ITF-14, DP Leitcode, DP Identcode */ -static int c25inter_common(struct zint_symbol *symbol, unsigned char source[], int length, +static int c25_inter_common(struct zint_symbol *symbol, unsigned char source[], int length, const int dont_set_height) { int i, j, error_number = 0; - char bars[7], spaces[7], mixed[14], dest[512]; /* 4 + (90 + 2) * 5 + 3 + 1 = 468 */ + char dest[468]; /* 4 + (90 + 2) * 5 + 3 + 1 = 468 */ + char *d = dest; unsigned char temp[90 + 2 + 1]; int have_checkdigit = symbol->option_2 == 1 || symbol->option_2 == 2; @@ -141,7 +154,7 @@ static int c25inter_common(struct zint_symbol *symbol, unsigned char source[], i strcpy(symbol->errtxt, "309: Input too long (90 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "310: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -163,31 +176,26 @@ static int c25inter_common(struct zint_symbol *symbol, unsigned char source[], i } /* start character */ - strcpy(dest, "1111"); + memcpy(d, "1111", 4); + d += 4; for (i = 0; i < length; i += 2) { - int k = 0; - /* look up the bars and the spaces and put them in two strings */ - bars[0] = '\0'; - lookup(NEON, C25InterTable, temp[i], bars); - spaces[0] = '\0'; - lookup(NEON, C25InterTable, temp[i + 1], spaces); + /* 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 <= 4; j++) { - mixed[k] = bars[j]; - k++; - mixed[k] = spaces[j]; - k++; + for (j = 0; j < 5; j++) { + *d++ = bars[j]; + *d++ = spaces[j]; } - mixed[k] = '\0'; - strcat(dest, mixed); } /* Stop character */ - strcat(dest, "311"); + memcpy(d, "311", 3); + d += 3; - expand(symbol, dest); + expand(symbol, dest, d - dest); ustrcpy(symbol->text, temp); if (symbol->option_2 == 2) { @@ -219,7 +227,7 @@ static int c25inter_common(struct zint_symbol *symbol, unsigned char source[], i /* Code 2 of 5 Interleaved ISO/IEC 16390:2007 */ INTERNAL int c25inter(struct zint_symbol *symbol, unsigned char source[], int length) { - return c25inter_common(symbol, source, length, 0 /*dont_set_height*/); + return c25_inter_common(symbol, source, length, 0 /*dont_set_height*/); } /* Interleaved 2-of-5 (ITF-14) */ @@ -232,7 +240,7 @@ INTERNAL int itf14(struct zint_symbol *symbol, unsigned char source[], int lengt return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "312: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -247,7 +255,7 @@ INTERNAL int itf14(struct zint_symbol *symbol, unsigned char source[], int lengt /* Calculate the check digit - the same method used for EAN-13 */ localstr[13] = gs1_check_digit(localstr, 13); localstr[14] = '\0'; - error_number = c25inter_common(symbol, localstr, 14, 1 /*dont_set_height*/); + error_number = c25_inter_common(symbol, localstr, 14, 1 /*dont_set_height*/); ustrcpy(symbol->text, localstr); if (!((symbol->output_options & BARCODE_BOX) || (symbol->output_options & BARCODE_BIND))) { @@ -277,6 +285,7 @@ INTERNAL int itf14(struct zint_symbol *symbol, unsigned char source[], int lengt INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int length) { int i, error_number; unsigned int count; + int factor; unsigned char localstr[16] = {0}; int zeroes; @@ -285,7 +294,7 @@ INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int leng strcpy(symbol->errtxt, "313: Input wrong length (13 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "314: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -295,16 +304,14 @@ INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int leng localstr[i] = '0'; ustrcpy(localstr + zeroes, source); + factor = 4; for (i = 12; i >= 0; i--) { - count += 4 * ctoi(localstr[i]); - - if (i & 1) { - count += 5 * ctoi(localstr[i]); - } + count += factor * ctoi(localstr[i]); + factor ^= 0x0D; /* Toggles 4 and 9 */ } - localstr[13] = check_digit(count); + localstr[13] = c25_check_digit(count); localstr[14] = '\0'; - error_number = c25inter_common(symbol, localstr, 14, 1 /*dont_set_height*/); + error_number = c25_inter_common(symbol, localstr, 14, 1 /*dont_set_height*/); ustrcpy(symbol->text, localstr); // TODO: Find documentation on BARCODE_DPLEIT dimensions/height @@ -316,6 +323,7 @@ INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int leng INTERNAL int dpident(struct zint_symbol *symbol, unsigned char source[], int length) { int i, error_number, zeroes; unsigned int count; + int factor; unsigned char localstr[16] = {0}; count = 0; @@ -323,7 +331,7 @@ INTERNAL int dpident(struct zint_symbol *symbol, unsigned char source[], int len strcpy(symbol->errtxt, "315: Input wrong length (11 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "316: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -333,16 +341,14 @@ INTERNAL int dpident(struct zint_symbol *symbol, unsigned char source[], int len localstr[i] = '0'; ustrcpy(localstr + zeroes, source); + factor = 4; for (i = 10; i >= 0; i--) { - count += 4 * ctoi(localstr[i]); - - if (i & 1) { - count += 5 * ctoi(localstr[i]); - } + count += factor * ctoi(localstr[i]); + factor ^= 0x0D; /* Toggles 4 and 9 */ } - localstr[11] = check_digit(count); + localstr[11] = c25_check_digit(count); localstr[12] = '\0'; - error_number = c25inter_common(symbol, localstr, 12, 1 /*dont_set_height*/); + error_number = c25_inter_common(symbol, localstr, 12, 1 /*dont_set_height*/); ustrcpy(symbol->text, localstr); // TODO: Find documentation on BARCODE_DPIDENT dimensions/height diff --git a/backend/auspost.c b/backend/auspost.c index f9a52d3f..b3225686 100644 --- a/backend/auspost.c +++ b/backend/auspost.c @@ -31,61 +31,74 @@ */ /* vim: set ts=4 sw=4 et : */ -#define GDSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz #" +static const char GDSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz #"; +#define GDSET_F (IS_NUM_F | IS_UPR_F | IS_LWR_F | IS_SPC_F | IS_HSH_F) -static const char *AusNTable[10] = { - "00", "01", "02", "10", "11", "12", "20", "21", "22", "30" +static const char AusNTable[10][2] = { + {'0','0'}, {'0','1'}, {'0','2'}, {'1','0'}, {'1','1'}, {'1','2'}, {'2','0'}, {'2','1'}, {'2','2'}, {'3','0'} }; -static const char *AusCTable[64] = { - "222", "300", "301", "302", "310", "311", "312", "320", "321", "322", - "000", "001", "002", "010", "011", "012", "020", "021", "022", "100", "101", "102", "110", - "111", "112", "120", "121", "122", "200", "201", "202", "210", "211", "212", "220", "221", - "023", "030", "031", "032", "033", "103", "113", "123", "130", "131", "132", "133", "203", - "213", "223", "230", "231", "232", "233", "303", "313", "323", "330", "331", "332", "333", - "003", "013" +static const char AusCTable[64][3] = { + {'2','2','2'}, {'3','0','0'}, {'3','0','1'}, {'3','0','2'}, {'3','1','0'}, {'3','1','1'}, + {'3','1','2'}, {'3','2','0'}, {'3','2','1'}, {'3','2','2'}, {'0','0','0'}, {'0','0','1'}, + {'0','0','2'}, {'0','1','0'}, {'0','1','1'}, {'0','1','2'}, {'0','2','0'}, {'0','2','1'}, + {'0','2','2'}, {'1','0','0'}, {'1','0','1'}, {'1','0','2'}, {'1','1','0'}, {'1','1','1'}, + {'1','1','2'}, {'1','2','0'}, {'1','2','1'}, {'1','2','2'}, {'2','0','0'}, {'2','0','1'}, + {'2','0','2'}, {'2','1','0'}, {'2','1','1'}, {'2','1','2'}, {'2','2','0'}, {'2','2','1'}, + {'0','2','3'}, {'0','3','0'}, {'0','3','1'}, {'0','3','2'}, {'0','3','3'}, {'1','0','3'}, + {'1','1','3'}, {'1','2','3'}, {'1','3','0'}, {'1','3','1'}, {'1','3','2'}, {'1','3','3'}, + {'2','0','3'}, {'2','1','3'}, {'2','2','3'}, {'2','3','0'}, {'2','3','1'}, {'2','3','2'}, + {'2','3','3'}, {'3','0','3'}, {'3','1','3'}, {'3','2','3'}, {'3','3','0'}, {'3','3','1'}, + {'3','3','2'}, {'3','3','3'}, {'0','0','3'}, {'0','1','3'} }; -static const char *AusBarTable[64] = { - "000", "001", "002", "003", "010", "011", "012", "013", "020", "021", - "022", "023", "030", "031", "032", "033", "100", "101", "102", "103", "110", "111", "112", - "113", "120", "121", "122", "123", "130", "131", "132", "133", "200", "201", "202", "203", - "210", "211", "212", "213", "220", "221", "222", "223", "230", "231", "232", "233", "300", - "301", "302", "303", "310", "311", "312", "313", "320", "321", "322", "323", "330", "331", - "332", "333" +static const char AusBarTable[64][3] = { + {'0','0','0'}, {'0','0','1'}, {'0','0','2'}, {'0','0','3'}, {'0','1','0'}, {'0','1','1'}, + {'0','1','2'}, {'0','1','3'}, {'0','2','0'}, {'0','2','1'}, {'0','2','2'}, {'0','2','3'}, + {'0','3','0'}, {'0','3','1'}, {'0','3','2'}, {'0','3','3'}, {'1','0','0'}, {'1','0','1'}, + {'1','0','2'}, {'1','0','3'}, {'1','1','0'}, {'1','1','1'}, {'1','1','2'}, {'1','1','3'}, + {'1','2','0'}, {'1','2','1'}, {'1','2','2'}, {'1','2','3'}, {'1','3','0'}, {'1','3','1'}, + {'1','3','2'}, {'1','3','3'}, {'2','0','0'}, {'2','0','1'}, {'2','0','2'}, {'2','0','3'}, + {'2','1','0'}, {'2','1','1'}, {'2','1','2'}, {'2','1','3'}, {'2','2','0'}, {'2','2','1'}, + {'2','2','2'}, {'2','2','3'}, {'2','3','0'}, {'2','3','1'}, {'2','3','2'}, {'2','3','3'}, + {'3','0','0'}, {'3','0','1'}, {'3','0','2'}, {'3','0','3'}, {'3','1','0'}, {'3','1','1'}, + {'3','1','2'}, {'3','1','3'}, {'3','2','0'}, {'3','2','1'}, {'3','2','2'}, {'3','2','3'}, + {'3','3','0'}, {'3','3','1'}, {'3','3','2'}, {'3','3','3'} }; #include #include "common.h" #include "reedsol.h" -static char convert_pattern(char data, int shift) { +static char aus_convert_pattern(char data, int shift) { return (data - '0') << shift; } /* Adds Reed-Solomon error correction to auspost */ -static void rs_error(char data_pattern[]) { - int reader, len, triple_writer = 0; +static char *aus_rs_error(char data_pattern[], char *d) { + int reader, length, triple_writer = 0; unsigned char triple[31]; unsigned char result[5]; rs_t rs; - for (reader = 2, len = (int) strlen(data_pattern); reader < len; reader += 3, triple_writer++) { - triple[triple_writer] = convert_pattern(data_pattern[reader], 4) - + convert_pattern(data_pattern[reader + 1], 2) - + convert_pattern(data_pattern[reader + 2], 0); + for (reader = 2, length = d - data_pattern; reader < length; reader += 3, triple_writer++) { + triple[triple_writer] = aus_convert_pattern(data_pattern[reader], 4) + + aus_convert_pattern(data_pattern[reader + 1], 2) + + aus_convert_pattern(data_pattern[reader + 2], 0); } rs_init_gf(&rs, 0x43); rs_init_code(&rs, 4, 1); rs_encode(&rs, triple_writer, triple, result); - for (reader = 4; reader > 0; reader--) { - strcat(data_pattern, AusBarTable[(int) result[reader - 1]]); + for (reader = 4; reader > 0; reader--, d += 3) { + memcpy(d, AusBarTable[(int) result[reader - 1]], 3); } + + return d; } -INTERNAL int daft_set_height(struct zint_symbol *symbol, float min_height, float max_height); +INTERNAL int daft_set_height(struct zint_symbol *symbol, const float min_height, const float max_height); /* Handles Australia Posts's 4 State Codes */ INTERNAL int auspost(struct zint_symbol *symbol, unsigned char source[], int length) { @@ -104,17 +117,29 @@ INTERNAL int auspost(struct zint_symbol *symbol, unsigned char source[], int len int h; char data_pattern[200]; - char fcc[3] = {0, 0, 0}, dpid[10]; + char *d = data_pattern; + char fcc[3] = {0}, dpid[10]; char localstr[30]; + /* Do all of the length checking first to avoid stack smashing */ + if (symbol->symbology == BARCODE_AUSPOST) { + if (length != 8 && length != 13 && length != 16 && length != 18 && length != 23) { + strcpy(symbol->errtxt, "401: Auspost input is wrong length (8, 13, 16, 18 or 23 characters only)"); + return ZINT_ERROR_TOO_LONG; + } + } else if (length > 8) { + strcpy(symbol->errtxt, "403: Auspost input is too long (8 character maximum)"); + return ZINT_ERROR_TOO_LONG; + } + /* Check input immediately to catch nuls */ - if (is_sane(GDSET, source, length) != 0) { + if (!is_sane(GDSET_F, source, length)) { strcpy(symbol->errtxt, "404: Invalid character in data (alphanumerics, space and \"#\" only)"); return ZINT_ERROR_INVALID_DATA; } - strcpy(localstr, ""); - /* Do all of the length checking first to avoid stack smashing */ + localstr[0] = '\0'; + if (symbol->symbology == BARCODE_AUSPOST) { /* Format control code (FCC) */ switch (length) { @@ -126,7 +151,7 @@ INTERNAL int auspost(struct zint_symbol *symbol, unsigned char source[], int len break; case 16: strcpy(fcc, "59"); - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "402: Invalid character in data (digits only for length 16)"); return ZINT_ERROR_INVALID_DATA; } @@ -136,21 +161,14 @@ INTERNAL int auspost(struct zint_symbol *symbol, unsigned char source[], int len break; case 23: strcpy(fcc, "62"); - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "406: Invalid character in data (digits only for length 23)"); return ZINT_ERROR_INVALID_DATA; } break; - default: - strcpy(symbol->errtxt, "401: Auspost input is wrong length (8, 13, 16, 18 or 23 characters only)"); - return ZINT_ERROR_TOO_LONG; } } else { int zeroes; - if (length > 8) { - strcpy(symbol->errtxt, "403: Auspost input is too long (8 character maximum)"); - return ZINT_ERROR_TOO_LONG; - } switch (symbol->symbology) { case BARCODE_AUSREPLY: strcpy(fcc, "45"); break; @@ -175,58 +193,60 @@ INTERNAL int auspost(struct zint_symbol *symbol, unsigned char source[], int len /* Verify that the first 8 characters are numbers */ memcpy(dpid, localstr, 8); dpid[8] = '\0'; - if (is_sane(NEON, (unsigned char *) dpid, 8) != 0) { + if (!is_sane(NEON_F, (unsigned char *) dpid, 8)) { strcpy(symbol->errtxt, "405: Invalid character in DPID (first 8 characters) (digits only)"); return ZINT_ERROR_INVALID_DATA; } /* Start character */ - strcpy(data_pattern, "13"); + memcpy(d, "13", 2); + d += 2; /* Encode the FCC */ - for (reader = 0; reader < 2; reader++) { - lookup(NEON, AusNTable, fcc[reader], data_pattern); + for (reader = 0; reader < 2; reader++, d += 2) { + memcpy(d, AusNTable[fcc[reader] - '0'], 2); } /* Delivery Point Identifier (DPID) */ - for (reader = 0; reader < 8; reader++) { - lookup(NEON, AusNTable, dpid[reader], data_pattern); + for (reader = 0; reader < 8; reader++, d += 2) { + memcpy(d, AusNTable[dpid[reader] - '0'], 2); } /* Customer Information */ if (h > 8) { if ((h == 13) || (h == 18)) { - for (reader = 8; reader < h; reader++) { - lookup(GDSET, AusCTable, localstr[reader], data_pattern); + for (reader = 8; reader < h; reader++, d += 3) { + memcpy(d, AusCTable[posn(GDSET, localstr[reader])], 3); } } else if ((h == 16) || (h == 23)) { - for (reader = 8; reader < h; reader++) { - lookup(NEON, AusNTable, localstr[reader], data_pattern); + for (reader = 8; reader < h; reader++, d += 2) { + memcpy(d, AusNTable[localstr[reader] - '0'], 2); } } } /* Filler bar */ - h = (int) strlen(data_pattern); + h = d - data_pattern; switch (h) { case 22: case 37: case 52: - strcat(data_pattern, "3"); + *d++ = '3'; break; default: break; } /* Reed Solomon error correction */ - rs_error(data_pattern); + d = aus_rs_error(data_pattern, d); /* Stop character */ - strcat(data_pattern, "13"); + memcpy(d, "13", 2); + d += 2; /* Turn the symbol into a bar pattern ready for plotting */ writer = 0; - h = (int) strlen(data_pattern); + h = d - data_pattern; for (loopey = 0; loopey < h; loopey++) { if ((data_pattern[loopey] == '1') || (data_pattern[loopey] == '0')) { set_module(symbol, 0, writer); diff --git a/backend/aztec.c b/backend/aztec.c index 9bfdd244..7161864f 100644 --- a/backend/aztec.c +++ b/backend/aztec.c @@ -1447,7 +1447,7 @@ INTERNAL int aztec(struct zint_symbol *symbol, unsigned char source[], int lengt /* Encodes Aztec runes as specified in ISO/IEC 24778:2008 Annex A */ INTERNAL int azrune(struct zint_symbol *symbol, unsigned char source[], int length) { unsigned int input_value; - int error_number, i, y, x, r; + int i, y, x, r; char binary_string[28]; unsigned char data_codewords[3], ecc_codewords[6]; int bp = 0; @@ -1459,8 +1459,7 @@ INTERNAL int azrune(struct zint_symbol *symbol, unsigned char source[], int leng strcpy(symbol->errtxt, "507: Input too large (3 character maximum)"); return ZINT_ERROR_TOO_LONG; } - error_number = is_sane(NEON, source, length); - if (error_number != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "508: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } diff --git a/backend/codablock.c b/backend/codablock.c index f16c1d27..940b52c4 100644 --- a/backend/codablock.c +++ b/backend/codablock.c @@ -38,8 +38,7 @@ #endif #include #include "common.h" - -INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int length); +#include "code128.h" #define uchar unsigned char @@ -65,23 +64,6 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len #define aCodeC (uchar)(134) #define aShift (uchar)(135) -static const char *C128Table[107] = { - /* Code 128 character encodation - Table 1 */ - "212222", "222122", "222221", "121223", "121322", "131222", "122213", - "122312", "132212", "221213", "221312", "231212", "112232", "122132", "122231", "113222", - "123122", "123221", "223211", "221132", "221231", "213212", "223112", "312131", "311222", - "321122", "321221", "312212", "322112", "322211", "212123", "212321", "232121", "111323", - "131123", "131321", "112313", "132113", "132311", "211313", "231113", "231311", "112133", - "112331", "132131", "113123", "113321", "133121", "313121", "211331", "231131", "213113", - "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111", "314111", - "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214", - "112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112", - "134111", "111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112", - "421211", "212141", "214121", "412121", "111143", "111341", "131141", "114113", "114311", - "411113", "411311", "113141", "114131", "311141", "411131", "211412", "211214", "211232", - "2331112" -}; - /* Code F Analysing-Chart */ typedef struct sCharacterSetTable { @@ -953,11 +935,14 @@ INTERNAL int codablockf(struct zint_symbol *symbol, unsigned char source[], int /* Paint the C128 patterns */ for (r = 0; r < rows; r++) { - strcpy(dest, ""); - for(c = 0; c < columns; c++) { - strcat(dest, C128Table[pOutput[r * columns + c]]); + const int rc = r * columns; + char *d = dest; + for (c = 0; c < columns - 1; c++, d += 6) { + memcpy(d, C128Table[pOutput[rc + c]], 6); } - expand(symbol, dest); + memcpy(d, "2331112", 7); /* Stop character (106, not in C128Table) */ + d += 7; + expand(symbol, dest, d - dest); } if (symbol->output_options & COMPLIANT_HEIGHT) { diff --git a/backend/code.c b/backend/code.c index f05cf163..26157419 100644 --- a/backend/code.c +++ b/backend/code.c @@ -1,8 +1,4 @@ /* code.c - Handles Code 11, 39, 39+, 93, PZN, Channel and VIN */ -/* LOGMARS MIL-STD-1189 Rev. B https://apps.dtic.mil/dtic/tr/fulltext/u2/a473534.pdf */ -/* PZN https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/IFA_Info_Code_39_EN.pdf */ -/* PZN https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/ - IFA-Info_Check_Digit_Calculations_PZN_PPN_UDI_EN.pdf */ /* libzint - the open source barcode library @@ -41,61 +37,95 @@ #include #include "common.h" -#define SODIUM "0123456789-" -#define SILVER "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd" -#define ARSENIC "0123456789ABCDEFGHJKLMNPRSTUVWXYZ" +#define SODIUM_MNS_F (IS_NUM_F | IS_MNS_F) /* SODIUM "0123456789-" */ -static const char *C11Table[11] = { - "111121", "211121", "121121", "221111", "112121", "212111", "122111", - "111221", "211211", "211111", "112111" +/* 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][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'} }; /* Code 39 tables checked against ISO/IEC 16388:2007 */ /* Incorporates Table A1 */ -static const char *C39Table[43] = { +static const char C39Table[43][10] = { /* Code 39 character assignments (Table 1) */ - "1112212111", "2112111121", "1122111121", "2122111111", "1112211121", - "2112211111", "1122211111", "1112112121", "2112112111", "1122112111", "2111121121", - "1121121121", "2121121111", "1111221121", "2111221111", "1121221111", "1111122121", - "2111122111", "1121122111", "1111222111", "2111111221", "1121111221", "2121111211", - "1111211221", "2111211211", "1121211211", "1111112221", "2111112211", "1121112211", - "1111212211", "2211111121", "1221111121", "2221111111", "1211211121", "2211211111", - "1221211111", "1211112121", "2211112111", "1221112111", "1212121111", "1212111211", - "1211121211", "1112121211" + {'1','1','1','2','2','1','2','1','1','1'}, {'2','1','1','2','1','1','1','1','2','1'}, + {'1','1','2','2','1','1','1','1','2','1'}, {'2','1','2','2','1','1','1','1','1','1'}, + {'1','1','1','2','2','1','1','1','2','1'}, {'2','1','1','2','2','1','1','1','1','1'}, + {'1','1','2','2','2','1','1','1','1','1'}, {'1','1','1','2','1','1','2','1','2','1'}, + {'2','1','1','2','1','1','2','1','1','1'}, {'1','1','2','2','1','1','2','1','1','1'}, + {'2','1','1','1','1','2','1','1','2','1'}, {'1','1','2','1','1','2','1','1','2','1'}, + {'2','1','2','1','1','2','1','1','1','1'}, {'1','1','1','1','2','2','1','1','2','1'}, + {'2','1','1','1','2','2','1','1','1','1'}, {'1','1','2','1','2','2','1','1','1','1'}, + {'1','1','1','1','1','2','2','1','2','1'}, {'2','1','1','1','1','2','2','1','1','1'}, + {'1','1','2','1','1','2','2','1','1','1'}, {'1','1','1','1','2','2','2','1','1','1'}, + {'2','1','1','1','1','1','1','2','2','1'}, {'1','1','2','1','1','1','1','2','2','1'}, + {'2','1','2','1','1','1','1','2','1','1'}, {'1','1','1','1','2','1','1','2','2','1'}, + {'2','1','1','1','2','1','1','2','1','1'}, {'1','1','2','1','2','1','1','2','1','1'}, + {'1','1','1','1','1','1','2','2','2','1'}, {'2','1','1','1','1','1','2','2','1','1'}, + {'1','1','2','1','1','1','2','2','1','1'}, {'1','1','1','1','2','1','2','2','1','1'}, + {'2','2','1','1','1','1','1','1','2','1'}, {'1','2','2','1','1','1','1','1','2','1'}, + {'2','2','2','1','1','1','1','1','1','1'}, {'1','2','1','1','2','1','1','1','2','1'}, + {'2','2','1','1','2','1','1','1','1','1'}, {'1','2','2','1','2','1','1','1','1','1'}, + {'1','2','1','1','1','1','2','1','2','1'}, {'2','2','1','1','1','1','2','1','1','1'}, + {'1','2','2','1','1','1','2','1','1','1'}, {'1','2','1','2','1','2','1','1','1','1'}, + {'1','2','1','2','1','1','1','2','1','1'}, {'1','2','1','1','1','2','1','2','1','1'}, + {'1','1','1','2','1','2','1','2','1','1'} }; -static const char *EC39Ctrl[128] = { +static const char EC39Ctrl[128][2] = { /* Encoding the full ASCII character set in Code 39 (Table A2) */ - "%U", "$A", "$B", "$C", "$D", "$E", "$F", "$G", "$H", "$I", "$J", "$K", - "$L", "$M", "$N", "$O", "$P", "$Q", "$R", "$S", "$T", "$U", "$V", "$W", "$X", "$Y", "$Z", - "%A", "%B", "%C", "%D", "%E", " ", "/A", "/B", "/C", "/D", "/E", "/F", "/G", "/H", "/I", "/J", - "/K", "/L", "-", ".", "/O", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "/Z", "%F", - "%G", "%H", "%I", "%J", "%V", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", - "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "%K", "%L", "%M", "%N", "%O", - "%W", "+A", "+B", "+C", "+D", "+E", "+F", "+G", "+H", "+I", "+J", "+K", "+L", "+M", "+N", "+O", - "+P", "+Q", "+R", "+S", "+T", "+U", "+V", "+W", "+X", "+Y", "+Z", "%P", "%Q", "%R", "%S", "%T" + {'%','U'}, {'$','A'}, {'$','B'}, {'$','C'}, {'$','D'}, {'$','E'}, {'$','F'}, {'$','G'}, {'$','H'}, {'$','I'}, + {'$','J'}, {'$','K'}, {'$','L'}, {'$','M'}, {'$','N'}, {'$','O'}, {'$','P'}, {'$','Q'}, {'$','R'}, {'$','S'}, + {'$','T'}, {'$','U'}, {'$','V'}, {'$','W'}, {'$','X'}, {'$','Y'}, {'$','Z'}, {'%','A'}, {'%','B'}, {'%','C'}, + {'%','D'}, {'%','E'}, { " " }, {'/','A'}, {'/','B'}, {'/','C'}, {'/','D'}, {'/','E'}, {'/','F'}, {'/','G'}, + {'/','H'}, {'/','I'}, {'/','J'}, {'/','K'}, {'/','L'}, { "-" }, { "." }, {'/','O'}, { "0" }, { "1" }, + { "2" }, { "3" }, { "4" }, { "5" }, { "6" }, { "7" }, { "8" }, { "9" }, {'/','Z'}, {'%','F'}, + {'%','G'}, {'%','H'}, {'%','I'}, {'%','J'}, {'%','V'}, { "A" }, { "B" }, { "C" }, { "D" }, { "E" }, + { "F" }, { "G" }, { "H" }, { "I" }, { "J" }, { "K" }, { "L" }, { "M" }, { "N" }, { "O" }, + { "P" }, { "Q" }, { "R" }, { "S" }, { "T" }, { "U" }, { "V" }, { "W" }, { "X" }, { "Y" }, + { "Z" }, {'%','K'}, {'%','L'}, {'%','M'}, {'%','N'}, {'%','O'}, {'%','W'}, {'+','A'}, {'+','B'}, {'+','C'}, + {'+','D'}, {'+','E'}, {'+','F'}, {'+','G'}, {'+','H'}, {'+','I'}, {'+','J'}, {'+','K'}, {'+','L'}, {'+','M'}, + {'+','N'}, {'+','O'}, {'+','P'}, {'+','Q'}, {'+','R'}, {'+','S'}, {'+','T'}, {'+','U'}, {'+','V'}, {'+','W'}, + {'+','X'}, {'+','Y'}, {'+','Z'}, {'%','P'}, {'%','Q'}, {'%','R'}, {'%','S'}, {'%','T'} }; -static const char *C93Ctrl[128] = { - "bU", "aA", "aB", "aC", "aD", "aE", "aF", "aG", "aH", "aI", "aJ", "aK", - "aL", "aM", "aN", "aO", "aP", "aQ", "aR", "aS", "aT", "aU", "aV", "aW", "aX", "aY", "aZ", - "bA", "bB", "bC", "bD", "bE", " ", "cA", "cB", "cC", "$", "%", "cF", "cG", "cH", "cI", "cJ", - "+", "cL", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "cZ", "bF", - "bG", "bH", "bI", "bJ", "bV", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", - "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bK", "bL", "bM", "bN", "bO", - "bW", "dA", "dB", "dC", "dD", "dE", "dF", "dG", "dH", "dI", "dJ", "dK", "dL", "dM", "dN", "dO", - "dP", "dQ", "dR", "dS", "dT", "dU", "dV", "dW", "dX", "dY", "dZ", "bP", "bQ", "bR", "bS", "bT" +static const char C93Ctrl[128][2] = { + {'b','U'}, {'a','A'}, {'a','B'}, {'a','C'}, {'a','D'}, {'a','E'}, {'a','F'}, {'a','G'}, {'a','H'}, {'a','I'}, + {'a','J'}, {'a','K'}, {'a','L'}, {'a','M'}, {'a','N'}, {'a','O'}, {'a','P'}, {'a','Q'}, {'a','R'}, {'a','S'}, + {'a','T'}, {'a','U'}, {'a','V'}, {'a','W'}, {'a','X'}, {'a','Y'}, {'a','Z'}, {'b','A'}, {'b','B'}, {'b','C'}, + {'b','D'}, {'b','E'}, { " " }, {'c','A'}, {'c','B'}, {'c','C'}, { "$" }, { "%" }, {'c','F'}, {'c','G'}, + {'c','H'}, {'c','I'}, {'c','J'}, { "+" }, {'c','L'}, { "-" }, { "." }, { "/" }, { "0" }, { "1" }, + { "2" }, { "3" }, { "4" }, { "5" }, { "6" }, { "7" }, { "8" }, { "9" }, {'c','Z'}, {'b','F'}, + {'b','G'}, {'b','H'}, {'b','I'}, {'b','J'}, {'b','V'}, { "A" }, { "B" }, { "C" }, { "D" }, { "E" }, + { "F" }, { "G" }, { "H" }, { "I" }, { "J" }, { "K" }, { "L" }, { "M" }, { "N" }, { "O" }, + { "P" }, { "Q" }, { "R" }, { "S" }, { "T" }, { "U" }, { "V" }, { "W" }, { "X" }, { "Y" }, + { "Z" }, {'b','K'}, {'b','L'}, {'b','M'}, {'b','N'}, {'b','O'}, {'b','W'}, {'d','A'}, {'d','B'}, {'d','C'}, + {'d','D'}, {'d','E'}, {'d','F'}, {'d','G'}, {'d','H'}, {'d','I'}, {'d','J'}, {'d','K'}, {'d','L'}, {'d','M'}, + {'d','N'}, {'d','O'}, {'d','P'}, {'d','Q'}, {'d','R'}, {'d','S'}, {'d','T'}, {'d','U'}, {'d','V'}, {'d','W'}, + {'d','X'}, {'d','Y'}, {'d','Z'}, {'b','P'}, {'b','Q'}, {'b','R'}, {'b','S'}, {'b','T'} }; -static const char *C93Table[47] = { - "131112", "111213", "111312", "111411", "121113", "121212", "121311", - "111114", "131211", "141111", "211113", "211212", "211311", "221112", "221211", "231111", - "112113", "112212", "112311", "122112", "132111", "111123", "111222", "111321", "121122", - "131121", "212112", "212211", "211122", "211221", "221121", "222111", "112122", "112221", - "122121", "123111", "121131", "311112", "311211", "321111", "112131", "113121", "211131", - "121221", "312111", "311121", "122211" +static const char C93Table[47][6] = { + {'1','3','1','1','1','2'}, {'1','1','1','2','1','3'}, {'1','1','1','3','1','2'}, {'1','1','1','4','1','1'}, + {'1','2','1','1','1','3'}, {'1','2','1','2','1','2'}, {'1','2','1','3','1','1'}, {'1','1','1','1','1','4'}, + {'1','3','1','2','1','1'}, {'1','4','1','1','1','1'}, {'2','1','1','1','1','3'}, {'2','1','1','2','1','2'}, + {'2','1','1','3','1','1'}, {'2','2','1','1','1','2'}, {'2','2','1','2','1','1'}, {'2','3','1','1','1','1'}, + {'1','1','2','1','1','3'}, {'1','1','2','2','1','2'}, {'1','1','2','3','1','1'}, {'1','2','2','1','1','2'}, + {'1','3','2','1','1','1'}, {'1','1','1','1','2','3'}, {'1','1','1','2','2','2'}, {'1','1','1','3','2','1'}, + {'1','2','1','1','2','2'}, {'1','3','1','1','2','1'}, {'2','1','2','1','1','2'}, {'2','1','2','2','1','1'}, + {'2','1','1','1','2','2'}, {'2','1','1','2','2','1'}, {'2','2','1','1','2','1'}, {'2','2','2','1','1','1'}, + {'1','1','2','1','2','2'}, {'1','1','2','2','2','1'}, {'1','2','2','1','2','1'}, {'1','2','3','1','1','1'}, + {'1','2','1','1','3','1'}, {'3','1','1','1','1','2'}, {'3','1','1','2','1','1'}, {'3','2','1','1','1','1'}, + {'1','1','2','1','3','1'}, {'1','1','3','1','2','1'}, {'2','1','1','1','3','1'}, {'1','2','1','2','2','1'}, + {'3','1','2','1','1','1'}, {'3','1','1','1','2','1'}, {'1','2','2','2','1','1'} }; /* *********************** CODE 11 ******************** */ @@ -105,8 +135,10 @@ INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int leng int h, c_digit, c_weight, c_count, k_digit, k_weight, k_count; int weight[122], error_number = 0; char dest[750]; /* 6 + 121 * 6 + 2 * 6 + 5 + 1 == 750 */ - char checkstr[3]; + char *d = dest; int num_check_digits; + char checkstr[3] = {0}; + static char checkchrs[11] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-' }; /* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warning */ assert(length > 0); @@ -115,7 +147,7 @@ INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int leng strcpy(symbol->errtxt, "320: Input too long (121 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(SODIUM, source, length) != 0) { + if (!is_sane(SODIUM_MNS_F, source, length)) { strcpy(symbol->errtxt, "321: Invalid character in data (digits and \"-\" only)"); return ZINT_ERROR_INVALID_DATA; } @@ -138,15 +170,16 @@ INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int leng k_count = 0; /* start character */ - strcpy(dest, "112211"); + memcpy(d, "112211", 6); + d += 6; /* Draw main body of barcode */ - for (i = 0; i < length; i++) { - lookup(SODIUM, C11Table, source[i], dest); + 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) { @@ -161,14 +194,11 @@ INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int leng } c_digit = c_count % 11; - if (num_check_digits == 1) { - checkstr[0] = itoc(c_digit); - if (checkstr[0] == 'A') { - checkstr[0] = '-'; - } - checkstr[1] = '\0'; - lookup(SODIUM, C11Table, checkstr[0], dest); - } else { + 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 */ @@ -182,17 +212,9 @@ INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int leng } k_digit = k_count % 11; - checkstr[0] = itoc(c_digit); - checkstr[1] = itoc(k_digit); - if (checkstr[0] == 'A') { - checkstr[0] = '-'; - } - if (checkstr[1] == 'A') { - checkstr[1] = '-'; - } - checkstr[2] = '\0'; - lookup(SODIUM, C11Table, checkstr[0], dest); - lookup(SODIUM, C11Table, checkstr[1], dest); + checkstr[1] = checkchrs[k_digit]; + memcpy(d, C11Table[k_digit], 6); + d += 6; } } @@ -201,9 +223,10 @@ INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int leng } /* Stop character */ - strcat(dest, "11221"); + memcpy(d, "11221", 5); + d += 5; - expand(symbol, dest); + expand(symbol, dest, d - dest); // TODO: Find documentation on BARCODE_CODE11 dimensions/height @@ -219,7 +242,9 @@ INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int leng int i; int counter; int error_number = 0; + int posns[85]; char dest[880]; /* 10 (Start) + 85 * 10 + 10 (Check) + 9 (Stop) + 1 = 880 */ + char *d = dest; char localstr[2] = {0}; counter = 0; @@ -228,6 +253,7 @@ INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int leng symbol->option_2 = 0; } + /* LOGMARS MIL-STD-1189 Rev. B https://apps.dtic.mil/dtic/tr/fulltext/u2/a473534.pdf */ if ((symbol->symbology == BARCODE_LOGMARS) && (length > 30)) { /* MIL-STD-1189 Rev. B Section 5.2.6.2 */ strcpy(symbol->errtxt, "322: Input too long (30 character maximum)"); return ZINT_ERROR_TOO_LONG; @@ -240,18 +266,20 @@ INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int leng strcpy(symbol->errtxt, "323: Input too long (85 character maximum)"); return ZINT_ERROR_TOO_LONG; } - to_upper(source); - if (is_sane(SILVER, source, length) != 0) { + + to_upper(source, length); + if (!is_sane_lookup(SILVER, 43, source, length, posns)) { strcpy(symbol->errtxt, "324: Invalid character in data (alphanumerics, space and \"-.$/+%\" only)"); return ZINT_ERROR_INVALID_DATA; } /* Start character */ - strcpy(dest, "1211212111"); + memcpy(d, "1211212111", 10); + d += 10; - for (i = 0; i < length; i++) { - lookup(SILVER, C39Table, source[i], dest); - counter += posn(SILVER, source[i]); + for (i = 0; i < length; i++, d += 10) { + memcpy(d, C39Table[posns[i]], 10); + counter += posns[i]; } if (symbol->option_2 == 1) { @@ -259,7 +287,8 @@ INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int leng char check_digit; counter %= 43; check_digit = SILVER[counter]; - lookup(SILVER, C39Table, check_digit, dest); + memcpy(d, C39Table[counter], 10); + d += 10; /* Display a space check digit as _, otherwise it looks like an error */ if (check_digit == ' ') { @@ -271,11 +300,12 @@ INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int leng } /* Stop character */ - strcat(dest, "121121211"); + memcpy(d, "121121211", 9); + d += 9; if ((symbol->symbology == BARCODE_LOGMARS) || (symbol->symbology == BARCODE_HIBC_39)) { /* LOGMARS uses wider 'wide' bars than normal Code 39 */ - counter = (int) strlen(dest); + counter = d - dest; for (i = 0; i < counter; i++) { if (dest[i] == '2') { dest[i] = '3'; @@ -283,11 +313,11 @@ INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int leng } } - if (symbol->debug & ZINT_DEBUG_PRINT) { - printf("Barspaces: %s\n", dest); - } + if (symbol->debug & ZINT_DEBUG_PRINT) { + printf("Barspaces: %.*s\n", (int) (d - dest), dest); + } - expand(symbol, dest); + expand(symbol, dest, d - dest); if (symbol->output_options & COMPLIANT_HEIGHT) { if (symbol->symbology == BARCODE_LOGMARS) { @@ -324,6 +354,9 @@ INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int leng } /* Pharmazentral Nummer (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; @@ -334,7 +367,7 @@ INTERNAL int pzn(struct zint_symbol *symbol, unsigned char source[], int length) strcpy(symbol->errtxt, "325: Input wrong length (7 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "326: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -387,6 +420,7 @@ INTERNAL int pzn(struct zint_symbol *symbol, unsigned char source[], int length) INTERNAL int excode39(struct zint_symbol *symbol, unsigned char source[], int length) { unsigned char buffer[85 * 2 + 1] = {0}; + unsigned char *b = buffer; int i; int error_number; @@ -402,11 +436,17 @@ INTERNAL int excode39(struct zint_symbol *symbol, unsigned char source[], int le strcpy(symbol->errtxt, "329: Invalid character in data, extended ASCII not allowed"); return ZINT_ERROR_INVALID_DATA; } - ustrcat(buffer, EC39Ctrl[source[i]]); + memcpy(b, EC39Ctrl[source[i]], 2); + b += EC39Ctrl[source[i]][1] ? 2 : 1; } + if (b - buffer > 85) { + strcpy(symbol->errtxt, "317: Expanded input too long (85 symbol character maximum)"); + return ZINT_ERROR_TOO_LONG; + } + *b = '\0'; /* Then sends the buffer to the C39 function */ - error_number = code39(symbol, buffer, (int) ustrlen(buffer)); + error_number = code39(symbol, buffer, b - buffer); for (i = 0; i < length; i++) symbol->text[i] = source[i] >= ' ' && source[i] != 0x7F ? source[i] : ' '; @@ -424,10 +464,11 @@ INTERNAL int code93(struct zint_symbol *symbol, unsigned char source[], int leng int i; int h, weight, c, k, error_number = 0; - int values[108]; /* 107 + 1 (1st check) */ + int values[110]; /* 107 + 2 (Checks) */ char buffer[216]; /* 107*2 (107 full ASCII) + 1 = 215 */ + char *b = buffer; char dest[668]; /* 6 (Start) + 107*6 + 2*6 (Checks) + 7 (Stop) + 1 (NUL) = 668 */ - char set_copy[] = SILVER; + char *d = dest; /* Suppresses clang-tidy clang-analyzer-core.CallAndMessage warning */ assert(length > 0); @@ -437,8 +478,6 @@ INTERNAL int code93(struct zint_symbol *symbol, unsigned char source[], int leng return ZINT_ERROR_TOO_LONG; } - *buffer = '\0'; - /* Message Content */ for (i = 0; i < length; i++) { if (source[i] > 127) { @@ -446,14 +485,15 @@ INTERNAL int code93(struct zint_symbol *symbol, unsigned char source[], int leng strcpy(symbol->errtxt, "331: Invalid character in data, extended ASCII not allowed"); return ZINT_ERROR_INVALID_DATA; } - strcat(buffer, C93Ctrl[source[i]]); + memcpy(b, C93Ctrl[source[i]], 2); + b += C93Ctrl[source[i]][1] ? 2 : 1; symbol->text[i] = source[i] >= ' ' && source[i] != 0x7F ? source[i] : ' '; } /* Now we can check the true length of the barcode */ - h = (int) strlen(buffer); + h = b - buffer; if (h > 107) { - strcpy(symbol->errtxt, "332: Input too long (107 symbol character maximum)"); + strcpy(symbol->errtxt, "332: Expanded input too long (107 symbol character maximum)"); return ZINT_ERROR_TOO_LONG; } @@ -474,7 +514,6 @@ INTERNAL int code93(struct zint_symbol *symbol, unsigned char source[], int leng } c = c % 47; values[h] = c; - buffer[h] = set_copy[c]; /* Check digit K */ k = 0; @@ -486,19 +525,26 @@ INTERNAL int code93(struct zint_symbol *symbol, unsigned char source[], int leng weight = 1; } k = k % 47; - buffer[++h] = set_copy[k]; - buffer[++h] = '\0'; + values[h + 1] = k; + h += 2; + + if (symbol->debug & ZINT_DEBUG_PRINT) { + printf("Check digit c: %d, k: %d\n", c, k); + } /* Start character */ - strcpy(dest, "111141"); + memcpy(d, "111141", 6); + d += 6; - for (i = 0; i < h; i++) { - lookup(SILVER, C93Table, buffer[i], dest); + for (i = 0; i < h; i++, d += 6) { + memcpy(d, C93Table[values[i]], 6); } /* Stop character */ - strcat(dest, "1111411"); - expand(symbol, dest); + memcpy(d, "1111411", 7); + d += 7; + + expand(symbol, dest, d - dest); if (symbol->output_options & COMPLIANT_HEIGHT) { /* ANSI/AIM BC5-1995 Section 2.6 minimum height 0.2" or 15% of symbol length, whichever is greater @@ -511,8 +557,8 @@ INTERNAL int code93(struct zint_symbol *symbol, unsigned char source[], int leng } if (symbol->option_2 == 1) { - symbol->text[length] = set_copy[c]; - symbol->text[length + 1] = set_copy[k]; + symbol->text[length] = SILVER[c]; + symbol->text[length + 1] = SILVER[k]; symbol->text[length + 2] = '\0'; } @@ -658,16 +704,16 @@ INTERNAL int channel(struct zint_symbol *symbol, unsigned char source[], int len static int max_ranges[] = { -1, -1, -1, 26, 292, 3493, 44072, 576688, 7742862 }; int S[8] = {0}, B[8] = {0}; long target_value = 0; - char pattern[30]; + char dest[30]; + char *d = dest; int channels, i; int error_number = 0, zeroes; - char hrt[9]; if (length > 7) { strcpy(symbol->errtxt, "333: Input too long (7 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "334: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -713,24 +759,23 @@ INTERNAL int channel(struct zint_symbol *symbol, unsigned char source[], int len CHNCHR(channels, target_value, B, S); - strcpy(pattern, "111111111"); /* Finder pattern */ + memcpy(d, "111111111", 9); /* Finder pattern */ + d += 9; for (i = 8 - channels; i < 8; i++) { - char part[3]; - part[0] = itoc(S[i]); - part[1] = itoc(B[i]); - part[2] = '\0'; - strcat(pattern, part); + *d++ = itoc(S[i]); + *d++ = itoc(B[i]); } zeroes = channels - 1 - length; if (zeroes < 0) { zeroes = 0; } - memset(hrt, '0', zeroes); - ustrcpy(hrt + zeroes, source); - ustrcpy(symbol->text, hrt); + if (zeroes) { + memset(symbol->text, '0', zeroes); + } + ustrcpy(symbol->text + zeroes, source); - expand(symbol, pattern); + 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 @@ -750,11 +795,10 @@ INTERNAL int vin(struct zint_symbol *symbol, unsigned char source[], int length) /* This code verifies the check digit present in North American VIN codes */ - char local_source[18]; char dest[200]; /* 10 + 10 + 17 * 10 + 9 + 1 = 200 */ + char *d = dest; char input_check; char output_check; - int value[17]; int weight[17] = {8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2}; int sum; int i; @@ -766,34 +810,30 @@ INTERNAL int vin(struct zint_symbol *symbol, unsigned char source[], int length) } // Check input characters, I, O and Q are not allowed - if (is_sane(ARSENIC, source, length) != 0) { - sprintf(symbol->errtxt, "337: Invalid character in data (\"%s\" only)", ARSENIC); + if (!is_sane(ARSENIC_F, source, length)) { + strcpy(symbol->errtxt, "337: Invalid character in data (alphanumerics only, excluding \"I\", \"O\" and \"Q\")"); return ZINT_ERROR_INVALID_DATA; } - ustrcpy(local_source, source); - - to_upper((unsigned char *) local_source); + to_upper(source, length); // Check digit only valid for North America - if (local_source[0] >= '1' && local_source[0] <= '5') { - input_check = local_source[8]; - - for (i = 0; i < 17; i++) { - if ((local_source[i] >= '0') && (local_source[i] <= '9')) { - value[i] = local_source[i] - '0'; - } else if ((local_source[i] >= 'A') && (local_source[i] <= 'I')) { - value[i] = (local_source[i] - 'A') + 1; - } else if ((local_source[i] >= 'J') && (local_source[i] <= 'R')) { - value[i] = (local_source[i] - 'J') + 1; - } else if ((local_source[i] >= 'S') && (local_source[i] <= 'Z')) { - value[i] = (local_source[i] - 'S') + 2; - } - } + if (source[0] >= '1' && source[0] <= '5') { + input_check = source[8]; sum = 0; for (i = 0; i < 17; i++) { - sum += value[i] * weight[i]; + int value; + if (source[i] <= '9') { + value = source[i] - '0'; + } else if (source[i] <= 'H') { + value = (source[i] - 'A') + 1; + } else if (source[i] <= 'R') { + value = (source[i] - 'J') + 1; + } else { /* (source[i] >= 'S') && (source[i] <= 'Z') */ + value = (source[i] - 'S') + 2; + } + sum += value * weight[i]; } output_check = '0' + (sum % 11); @@ -804,33 +844,39 @@ INTERNAL int vin(struct zint_symbol *symbol, unsigned char source[], int length) } if (symbol->debug & ZINT_DEBUG_PRINT) { - printf("Producing VIN code: %s\n", local_source); + printf("Producing VIN code: %s\n", source); printf("Input check was %c, calculated check is %c\n", input_check, output_check); } if (input_check != output_check) { - sprintf(symbol->errtxt, "338: Invalid check digit '%c', expecting '%c'", input_check, output_check); + sprintf(symbol->errtxt, "338: Invalid check digit '%c' (position 9), expecting '%c'", + input_check, output_check); return ZINT_ERROR_INVALID_CHECK; } } /* Start character */ - strcpy(dest, "1211212111"); + memcpy(d, "1211212111", 10); + d += 10; /* Import character 'I' prefix? */ if (symbol->option_2 & 1) { - strcat(dest, "1121122111"); + memcpy(d, C39Table[18], 10); + d += 10; } // Copy glyphs to symbol - for (i = 0; i < 17; i++) { - lookup(SILVER, C39Table, local_source[i], dest); + for (i = 0; i < 17; i++, d += 10) { + memcpy(d, C39Table[posn(SILVER, source[i])], 10); } - strcat(dest, "121121211"); + /* Stop character */ + memcpy(d, "121121211", 9); + d += 9; - ustrcpy(symbol->text, local_source); - expand(symbol, dest); + expand(symbol, dest, d - dest); + + ustrcpy(symbol->text, source); /* Specification of dimensions/height for BARCODE_VIN unlikely */ diff --git a/backend/code1.c b/backend/code1.c index f0f1cf74..0bf3882b 100644 --- a/backend/code1.c +++ b/backend/code1.c @@ -319,7 +319,7 @@ static int is_last_single_ascii(const unsigned char string[], const int length, if (length - sp == 1 && string[sp] <= 127) { return 1; } - if (length - sp == 2 && istwodigits(string, length, sp)) { + if (length - sp == 2 && is_twodigits(string, length, sp)) { return 1; } return 0; @@ -591,7 +591,7 @@ static int c1_encode(struct zint_symbol *symbol, unsigned char source[], unsigne } if (next_mode == C1_ASCII) { - if (istwodigits(source, length, sp)) { + if (is_twodigits(source, length, sp)) { if (debug_print) printf("ASCII double-digits "); /* Step B3 */ @@ -753,7 +753,7 @@ static int c1_encode(struct zint_symbol *symbol, unsigned char source[], unsigne if (codewords_remaining(symbol, tp) == 1 && (can_ascii || (num_digits[sp] == 1 && bits_left >= 4))) { if (can_ascii) { /* Encode last character or last 2 digits as ASCII */ - if (istwodigits(source, length, sp)) { + if (is_twodigits(source, length, sp)) { target[tp++] = (10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130; sp += 2; } else { @@ -864,7 +864,7 @@ static int c1_encode(struct zint_symbol *symbol, unsigned char source[], unsigne target[tp++] = 255; /* Unlatch */ for (; sp < length; sp++) { - if (istwodigits(source, length, sp)) { + if (is_twodigits(source, length, sp)) { target[tp++] = (10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130; sp++; } else if (source[sp] & 0x80) { @@ -1005,7 +1005,7 @@ INTERNAL int codeone(struct zint_symbol *symbol, unsigned char source[], int len strcpy(symbol->errtxt, "514: Input data too long for Version S"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "515: Invalid input data (Version S encodes numeric input only)"); return ZINT_ERROR_INVALID_DATA; } diff --git a/backend/code1.h b/backend/code1.h index aaf48984..99ade65d 100644 --- a/backend/code1.h +++ b/backend/code1.h @@ -2,7 +2,7 @@ /* libzint - the open source barcode library - Copyright (C) 2009-2017 Robin Stuart + Copyright (C) 2009-2021 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -29,6 +29,7 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* vim: set ts=4 sw=4 et : */ static const char c40_shift[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -94,9 +95,9 @@ static const unsigned short int c1_grid_height[] = { 5, 7, 10, 15, 21, 30, 46, 68 }; -#define C1_ASCII 1 -#define C1_C40 2 -#define C1_DECIMAL 3 -#define C1_TEXT 4 -#define C1_EDI 5 -#define C1_BYTE 6 +#define C1_ASCII 1 +#define C1_C40 2 +#define C1_DECIMAL 3 +#define C1_TEXT 4 +#define C1_EDI 5 +#define C1_BYTE 6 diff --git a/backend/code128.c b/backend/code128.c index 147f10da..71346329 100644 --- a/backend/code128.c +++ b/backend/code128.c @@ -41,42 +41,60 @@ #include "code128.h" #include "gs1.h" +static const char KRSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#define KRSET_F (IS_NUM_F | IS_UPR_F) + /* Code 128 tables checked against ISO/IEC 15417:2007 */ -static const char *C128Table[107] = { - /* Code 128 character encodation - Table 1 */ - /* 0 1 2 3 4 5 6 7 8 9 */ - "212222", "222122", "222221", "121223", "121322", "131222", "122213", "122312", "132212", "221213", /* 0 */ - "221312", "231212", "112232", "122132", "122231", "113222", "123122", "123221", "223211", "221132", /* 10 */ - "221231", "213212", "223112", "312131", "311222", "321122", "321221", "312212", "322112", "322211", /* 20 */ - "212123", "212321", "232121", "111323", "131123", "131321", "112313", "132113", "132311", "211313", /* 30 */ - "231113", "231311", "112133", "112331", "132131", "113123", "113321", "133121", "313121", "211331", /* 40 */ - "231131", "213113", "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111", /* 50 */ - "314111", "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214", /* 60 */ - "112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112", "134111", /* 70 */ - "111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112", "421211", "212141", /* 80 */ - "214121", "412121", "111143", "111341", "131141", "114113", "114311", "411113", "411311", "113141", /* 90 */ - "114131", "311141", "411131", "211412", "211214", "211232", "2331112" /*100 */ +INTERNAL_DATA const char C128Table[107][6] = { /* Used by CODABLOCKF and CODE16K also */ + /* Code 128 character encodation - Table 1 (with final CODE16K-only character in place of Stop character) */ + {'2','1','2','2','2','2'}, {'2','2','2','1','2','2'}, {'2','2','2','2','2','1'}, {'1','2','1','2','2','3'}, + {'1','2','1','3','2','2'}, {'1','3','1','2','2','2'}, {'1','2','2','2','1','3'}, {'1','2','2','3','1','2'}, + {'1','3','2','2','1','2'}, {'2','2','1','2','1','3'}, {'2','2','1','3','1','2'}, {'2','3','1','2','1','2'}, + {'1','1','2','2','3','2'}, {'1','2','2','1','3','2'}, {'1','2','2','2','3','1'}, {'1','1','3','2','2','2'}, + {'1','2','3','1','2','2'}, {'1','2','3','2','2','1'}, {'2','2','3','2','1','1'}, {'2','2','1','1','3','2'}, + {'2','2','1','2','3','1'}, {'2','1','3','2','1','2'}, {'2','2','3','1','1','2'}, {'3','1','2','1','3','1'}, + {'3','1','1','2','2','2'}, {'3','2','1','1','2','2'}, {'3','2','1','2','2','1'}, {'3','1','2','2','1','2'}, + {'3','2','2','1','1','2'}, {'3','2','2','2','1','1'}, {'2','1','2','1','2','3'}, {'2','1','2','3','2','1'}, + {'2','3','2','1','2','1'}, {'1','1','1','3','2','3'}, {'1','3','1','1','2','3'}, {'1','3','1','3','2','1'}, + {'1','1','2','3','1','3'}, {'1','3','2','1','1','3'}, {'1','3','2','3','1','1'}, {'2','1','1','3','1','3'}, + {'2','3','1','1','1','3'}, {'2','3','1','3','1','1'}, {'1','1','2','1','3','3'}, {'1','1','2','3','3','1'}, + {'1','3','2','1','3','1'}, {'1','1','3','1','2','3'}, {'1','1','3','3','2','1'}, {'1','3','3','1','2','1'}, + {'3','1','3','1','2','1'}, {'2','1','1','3','3','1'}, {'2','3','1','1','3','1'}, {'2','1','3','1','1','3'}, + {'2','1','3','3','1','1'}, {'2','1','3','1','3','1'}, {'3','1','1','1','2','3'}, {'3','1','1','3','2','1'}, + {'3','3','1','1','2','1'}, {'3','1','2','1','1','3'}, {'3','1','2','3','1','1'}, {'3','3','2','1','1','1'}, + {'3','1','4','1','1','1'}, {'2','2','1','4','1','1'}, {'4','3','1','1','1','1'}, {'1','1','1','2','2','4'}, + {'1','1','1','4','2','2'}, {'1','2','1','1','2','4'}, {'1','2','1','4','2','1'}, {'1','4','1','1','2','2'}, + {'1','4','1','2','2','1'}, {'1','1','2','2','1','4'}, {'1','1','2','4','1','2'}, {'1','2','2','1','1','4'}, + {'1','2','2','4','1','1'}, {'1','4','2','1','1','2'}, {'1','4','2','2','1','1'}, {'2','4','1','2','1','1'}, + {'2','2','1','1','1','4'}, {'4','1','3','1','1','1'}, {'2','4','1','1','1','2'}, {'1','3','4','1','1','1'}, + {'1','1','1','2','4','2'}, {'1','2','1','1','4','2'}, {'1','2','1','2','4','1'}, {'1','1','4','2','1','2'}, + {'1','2','4','1','1','2'}, {'1','2','4','2','1','1'}, {'4','1','1','2','1','2'}, {'4','2','1','1','1','2'}, + {'4','2','1','2','1','1'}, {'2','1','2','1','4','1'}, {'2','1','4','1','2','1'}, {'4','1','2','1','2','1'}, + {'1','1','1','1','4','3'}, {'1','1','1','3','4','1'}, {'1','3','1','1','4','1'}, {'1','1','4','1','1','3'}, + {'1','1','4','3','1','1'}, {'4','1','1','1','1','3'}, {'4','1','1','3','1','1'}, {'1','1','3','1','4','1'}, + {'1','1','4','1','3','1'}, {'3','1','1','1','4','1'}, {'4','1','1','1','3','1'}, {'2','1','1','4','1','2'}, + {'2','1','1','2','1','4'}, {'2','1','1','2','3','2'}, {/* Only used by CODE16K */ '2','1','1','1','3','3'} }; /* Determine appropriate mode for a given character */ -INTERNAL int parunmodd(const unsigned char llyth) { +INTERNAL int c128_parunmodd(const unsigned char llyth) { int modd; if (llyth <= 31) { - modd = SHIFTA; + modd = C128_SHIFTA; } else if ((llyth >= 48) && (llyth <= 57)) { - modd = ABORC; + modd = C128_ABORC; } else if (llyth <= 95) { - modd = AORB; + modd = C128_AORB; } else if (llyth <= 127) { - modd = SHIFTB; + modd = C128_SHIFTB; } else if (llyth <= 159) { - modd = SHIFTA; + modd = C128_SHIFTA; } else if (llyth <= 223) { - modd = AORB; + modd = C128_AORB; } else { - modd = SHIFTB; + modd = C128_SHIFTB; } return modd; @@ -114,11 +132,11 @@ static void grwp(int list[2][C128_MAX], int *indexliste) { /** * Implements rules from ISO 15417 Annex E */ -INTERNAL void dxsmooth(int list[2][C128_MAX], int *indexliste) { +INTERNAL void c128_dxsmooth(int list[2][C128_MAX], int *indexliste) { int i, last, next; for (i = 0; i < *(indexliste); i++) { - int current = list[1][i]; /* Either ABORC, AORB, SHIFTA or SHIFTB */ + int current = list[1][i]; /* Either C128_ABORC, C128_AORB, C128_SHIFTA or C128_SHIFTB */ int length = list[0][i]; if (i != 0) { last = list[1][i - 1]; @@ -132,71 +150,71 @@ INTERNAL void dxsmooth(int list[2][C128_MAX], int *indexliste) { } if (i == 0) { /* first block */ - if (current == ABORC) { + if (current == C128_ABORC) { if ((*(indexliste) == 1) && (length == 2)) { /* Rule 1a */ - list[1][i] = LATCHC; - current = LATCHC; + list[1][i] = C128_LATCHC; + current = C128_LATCHC; } else if (length >= 4) { /* Rule 1b */ - list[1][i] = LATCHC; - current = LATCHC; + list[1][i] = C128_LATCHC; + current = C128_LATCHC; } else { - current = AORB; /* Determine below */ + current = C128_AORB; /* Determine below */ } } - if (current == AORB) { - if (next == SHIFTA) { + if (current == C128_AORB) { + if (next == C128_SHIFTA) { /* Rule 1c */ - list[1][i] = LATCHA; + list[1][i] = C128_LATCHA; } else { /* Rule 1d */ - list[1][i] = LATCHB; + list[1][i] = C128_LATCHB; } - } else if (current == SHIFTA) { + } else if (current == C128_SHIFTA) { /* Rule 1c */ - list[1][i] = LATCHA; - } else if (current == SHIFTB) { /* Unless LATCHC set above, can only be SHIFTB */ + list[1][i] = C128_LATCHA; + } else if (current == C128_SHIFTB) { /* Unless C128_LATCHC set above, can only be C128_SHIFTB */ /* Rule 1d */ - list[1][i] = LATCHB; + list[1][i] = C128_LATCHB; } } else { - if (current == ABORC) { + if (current == C128_ABORC) { if (length >= 4) { /* Rule 3 */ - list[1][i] = LATCHC; - current = LATCHC; + list[1][i] = C128_LATCHC; + current = C128_LATCHC; } else { - current = AORB; /* Determine below */ + current = C128_AORB; /* Determine below */ } } - if (current == AORB) { - if (last == LATCHA || last == SHIFTB) { /* Maintain state */ - list[1][i] = LATCHA; - } else if (last == LATCHB || last == SHIFTA) { /* Maintain state */ - list[1][i] = LATCHB; - } else if (next == SHIFTA) { - list[1][i] = LATCHA; + if (current == C128_AORB) { + if (last == C128_LATCHA || last == C128_SHIFTB) { /* Maintain state */ + list[1][i] = C128_LATCHA; + } else if (last == C128_LATCHB || last == C128_SHIFTA) { /* Maintain state */ + list[1][i] = C128_LATCHB; + } else if (next == C128_SHIFTA) { + list[1][i] = C128_LATCHA; } else { - list[1][i] = LATCHB; + list[1][i] = C128_LATCHB; } - } else if (current == SHIFTA) { + } else if (current == C128_SHIFTA) { if (length > 1) { /* Rule 4 */ - list[1][i] = LATCHA; - } else if (last == LATCHA || last == SHIFTB) { /* Maintain state */ - list[1][i] = LATCHA; - } else if (last == LATCHC) { - list[1][i] = LATCHA; + list[1][i] = C128_LATCHA; + } else if (last == C128_LATCHA || last == C128_SHIFTB) { /* Maintain state */ + list[1][i] = C128_LATCHA; + } else if (last == C128_LATCHC) { + list[1][i] = C128_LATCHA; } - } else if (current == SHIFTB) { /* Unless LATCHC set above, can only be SHIFTB */ + } else if (current == C128_SHIFTB) { /* Unless C128_LATCHC set above, can only be C128_SHIFTB */ if (length > 1) { /* Rule 5 */ - list[1][i] = LATCHB; - } else if (last == LATCHB || last == SHIFTA) { /* Maintain state */ - list[1][i] = LATCHB; - } else if (last == LATCHC) { - list[1][i] = LATCHB; + list[1][i] = C128_LATCHB; + } else if (last == C128_LATCHB || last == C128_SHIFTA) { /* Maintain state */ + list[1][i] = C128_LATCHB; + } else if (last == C128_LATCHC) { + list[1][i] = C128_LATCHB; } } } /* Rule 2 is implemented elsewhere, Rule 6 is implied */ @@ -209,22 +227,18 @@ INTERNAL void dxsmooth(int list[2][C128_MAX], int *indexliste) { * Translate Code 128 Set A characters into barcodes. * This set handles all control characters NUL to US. */ -static void c128_set_a(const unsigned char source, char dest[], int values[], int *bar_chars) { +INTERNAL void c128_set_a(const unsigned char source, int values[], int *bar_chars) { if (source > 127) { if (source < 160) { - strcat(dest, C128Table[(source - 128) + 64]); values[(*bar_chars)] = (source - 128) + 64; } else { - strcat(dest, C128Table[(source - 128) - 32]); values[(*bar_chars)] = (source - 128) - 32; } } else { if (source < 32) { - strcat(dest, C128Table[source + 64]); values[(*bar_chars)] = source + 64; } else { - strcat(dest, C128Table[source - 32]); values[(*bar_chars)] = source - 32; } } @@ -236,14 +250,12 @@ static void c128_set_a(const unsigned char source, char dest[], int values[], in * This set handles all characters which are not part of long numbers and not * control characters. */ -static int c128_set_b(const unsigned char source, char dest[], int values[], int *bar_chars) { +INTERNAL int c128_set_b(const unsigned char source, int values[], int *bar_chars) { if (source >= 128 + 32) { - strcat(dest, C128Table[source - 32 - 128]); values[(*bar_chars)] = source - 32 - 128; } else if (source >= 128) { /* Should never happen */ return 0; /* Not reached */ } else if (source >= 32) { - strcat(dest, C128Table[source - 32]); values[(*bar_chars)] = source - 32; } else { /* Should never happen */ return 0; /* Not reached */ @@ -255,16 +267,80 @@ static int c128_set_b(const unsigned char source, char dest[], int values[], int /* Translate Code 128 Set C characters into barcodes * This set handles numbers in a compressed form */ -static void c128_set_c(const unsigned char source_a, const unsigned char source_b, char dest[], int values[], - int *bar_chars) { +INTERNAL void c128_set_c(const unsigned char source_a, const unsigned char source_b, int values[], int *bar_chars) { int weight; weight = (10 * ctoi(source_a)) + ctoi(source_b); - strcat(dest, C128Table[weight]); values[(*bar_chars)] = weight; (*bar_chars)++; } +/* Put set data into set[]. If source given (GS1_MODE) then resolves odd C blocks */ +INTERNAL void c128_put_in_set(int list[2][C128_MAX], const int indexliste, char set[C128_MAX], + unsigned char *source) { + int read = 0; + int i, j; + + for (i = 0; i < indexliste; i++) { + for (j = 0; j < list[0][i]; j++) { + switch (list[1][i]) { + case C128_SHIFTA: set[read] = 'a'; + break; + case C128_LATCHA: set[read] = 'A'; + break; + case C128_SHIFTB: set[read] = 'b'; + break; + case C128_LATCHB: set[read] = 'B'; + break; + case C128_LATCHC: set[read] = 'C'; + break; + } + read++; + } + } + if (source) { + /* Watch out for odd-length Mode C blocks */ + int c_count = 0; + for (i = 0; i < read; i++) { + if (set[i] == 'C') { + if (source[i] == '[') { + if (c_count & 1) { + if ((i - c_count) != 0) { + set[i - c_count] = 'B'; + } else { + set[i - 1] = 'B'; + } + } + c_count = 0; + } else { + c_count++; + } + } else { + if (c_count & 1) { + if ((i - c_count) != 0) { + set[i - c_count] = 'B'; + } else { + set[i - 1] = 'B'; + } + } + c_count = 0; + } + } + if (c_count & 1) { + if ((i - c_count) != 0) { + set[i - c_count] = 'B'; + } else { + set[i - 1] = 'B'; + } + } + for (i = 1; i < read - 1; i++) { + if ((set[i] == 'C') && ((set[i - 1] == 'B') && (set[i + 1] == 'B'))) { + set[i] = 'B'; + } + } + } +} + /* Treats source as ISO 8859-1 and copies into symbol->text, converting to UTF-8. Returns length of symbol->text */ STATIC_UNLESS_ZINT_TEST int hrt_cpy_iso8859_1(struct zint_symbol *symbol, const unsigned char *source, const int source_len) { @@ -308,12 +384,12 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len char set[C128_MAX] = {0}, fset[C128_MAX], mode, last_set, current_set = ' '; float glyph_count; char dest[1000]; + char *d = dest; /* Suppresses clang-analyzer-core.UndefinedBinaryOperatorResult warning on fset which is fully set */ assert(length > 0); error_number = 0; - strcpy(dest, ""); sourcelen = length; @@ -378,9 +454,9 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len indexliste = 0; indexchaine = 0; - mode = parunmodd(source[indexchaine]); - if ((symbol->symbology == BARCODE_CODE128B) && (mode == ABORC)) { - mode = AORB; + mode = c128_parunmodd(source[indexchaine]); + if ((symbol->symbology == BARCODE_CODE128B) && (mode == C128_ABORC)) { + mode = C128_AORB; } do { @@ -391,30 +467,30 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len if (indexchaine == sourcelen) { break; } - mode = parunmodd(source[indexchaine]); - if ((symbol->symbology == BARCODE_CODE128B) && (mode == ABORC)) { - mode = AORB; + mode = c128_parunmodd(source[indexchaine]); + if ((symbol->symbology == BARCODE_CODE128B) && (mode == C128_ABORC)) { + mode = C128_AORB; } } indexliste++; } while (indexchaine < sourcelen); - dxsmooth(list, &indexliste); + c128_dxsmooth(list, &indexliste); - /* Resolve odd length LATCHC blocks */ - if ((list[1][0] == LATCHC) && (list[0][0] & 1)) { + /* Resolve odd length C128_LATCHC blocks */ + if ((list[1][0] == C128_LATCHC) && (list[0][0] & 1)) { /* Rule 2 */ list[0][1]++; list[0][0]--; if (indexliste == 1) { list[0][1] = 1; - list[1][1] = LATCHB; + list[1][1] = C128_LATCHB; indexliste = 2; } } if (indexliste > 1) { for (i = 1; i < indexliste; i++) { - if ((list[1][i] == LATCHC) && (list[0][i] & 1)) { + if ((list[1][i] == C128_LATCHC) && (list[0][i] & 1)) { /* Rule 3b */ list[0][i - 1]++; list[0][i]--; @@ -422,26 +498,8 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len } } - /* Put set data into set[] */ - - read = 0; - for (i = 0; i < indexliste; i++) { - for (j = 0; j < list[0][i]; j++) { - switch (list[1][i]) { - case SHIFTA: set[read] = 'a'; - break; - case LATCHA: set[read] = 'A'; - break; - case SHIFTB: set[read] = 'b'; - break; - case LATCHB: set[read] = 'B'; - break; - case LATCHC: set[read] = 'C'; - break; - } - read++; - } - } + /* Put set data into set[]. Giving NULL as source as used to resolve odd C blocks which has been done above */ + c128_put_in_set(list, indexliste, set, NULL /*source*/); if (symbol->debug & ZINT_DEBUG_PRINT) { printf("Data: %.*s (%d)\n", sourcelen, source, sourcelen); @@ -495,29 +553,19 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len /* Reader Initialisation mode */ switch (set[0]) { case 'A': /* Start A */ - strcat(dest, C128Table[103]); - values[0] = 103; + values[bar_characters++] = 103; current_set = 'A'; - strcat(dest, C128Table[96]); /* FNC3 */ - values[1] = 96; - bar_characters++; + values[bar_characters++] = 96; /* FNC3 */ break; case 'B': /* Start B */ - strcat(dest, C128Table[104]); - values[0] = 104; + values[bar_characters++] = 104; current_set = 'B'; - strcat(dest, C128Table[96]); /* FNC3 */ - values[1] = 96; - bar_characters++; + values[bar_characters++] = 96; /* FNC3 */ break; case 'C': /* Start C */ - strcat(dest, C128Table[104]); /* Start B */ - values[0] = 104; - strcat(dest, C128Table[96]); /* FNC3 */ - values[1] = 96; - strcat(dest, C128Table[99]); /* Code C */ - values[2] = 99; - bar_characters += 2; + values[bar_characters++] = 104; /* Start B */ + values[bar_characters++] = 96; /* FNC3 */ + values[bar_characters++] = 99; /* Code C */ current_set = 'C'; break; } @@ -525,40 +573,31 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len /* Normal mode */ switch (set[0]) { case 'A': /* Start A */ - strcat(dest, C128Table[103]); - values[0] = 103; + values[bar_characters++] = 103; current_set = 'A'; break; case 'B': /* Start B */ - strcat(dest, C128Table[104]); - values[0] = 104; + values[bar_characters++] = 104; current_set = 'B'; break; case 'C': /* Start C */ - strcat(dest, C128Table[105]); - values[0] = 105; + values[bar_characters++] = 105; current_set = 'C'; break; } } - bar_characters++; if (fset[0] == 'F') { switch (current_set) { case 'A': - strcat(dest, C128Table[101]); - strcat(dest, C128Table[101]); - values[bar_characters] = 101; - values[bar_characters + 1] = 101; + values[bar_characters++] = 101; + values[bar_characters++] = 101; break; case 'B': - strcat(dest, C128Table[100]); - strcat(dest, C128Table[100]); - values[bar_characters] = 100; - values[bar_characters + 1] = 100; + values[bar_characters++] = 100; + values[bar_characters++] = 100; break; } - bar_characters += 2; f_state = 1; } @@ -569,19 +608,16 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len if ((read != 0) && (set[read] != current_set)) { /* Latch different code set */ switch (set[read]) { - case 'A': strcat(dest, C128Table[101]); - values[bar_characters] = 101; - bar_characters++; + case 'A': + values[bar_characters++] = 101; current_set = 'A'; break; - case 'B': strcat(dest, C128Table[100]); - values[bar_characters] = 100; - bar_characters++; + case 'B': + values[bar_characters++] = 100; current_set = 'B'; break; - case 'C': strcat(dest, C128Table[99]); - values[bar_characters] = 99; - bar_characters++; + case 'C': + values[bar_characters++] = 99; current_set = 'C'; break; } @@ -592,38 +628,28 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len /* Latch beginning of extended mode */ switch (current_set) { case 'A': - strcat(dest, C128Table[101]); - strcat(dest, C128Table[101]); - values[bar_characters] = 101; - values[bar_characters + 1] = 101; + values[bar_characters++] = 101; + values[bar_characters++] = 101; break; case 'B': - strcat(dest, C128Table[100]); - strcat(dest, C128Table[100]); - values[bar_characters] = 100; - values[bar_characters + 1] = 100; + values[bar_characters++] = 100; + values[bar_characters++] = 100; break; } - bar_characters += 2; f_state = 1; } if ((fset[read] == ' ') && (f_state == 1)) { /* Latch end of extended mode */ switch (current_set) { case 'A': - strcat(dest, C128Table[101]); - strcat(dest, C128Table[101]); - values[bar_characters] = 101; - values[bar_characters + 1] = 101; + values[bar_characters++] = 101; + values[bar_characters++] = 101; break; case 'B': - strcat(dest, C128Table[100]); - strcat(dest, C128Table[100]); - values[bar_characters] = 100; - values[bar_characters + 1] = 100; + values[bar_characters++] = 100; + values[bar_characters++] = 100; break; } - bar_characters += 2; f_state = 0; } } @@ -632,54 +658,53 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len /* Shift to or from extended mode */ switch (current_set) { case 'A': - strcat(dest, C128Table[101]); /* FNC 4 */ - values[bar_characters] = 101; + values[bar_characters++] = 101; /* FNC 4 */ break; case 'B': - strcat(dest, C128Table[100]); /* FNC 4 */ - values[bar_characters] = 100; + values[bar_characters++] = 100; /* FNC 4 */ break; } - bar_characters++; } if ((set[read] == 'a') || (set[read] == 'b')) { /* Insert shift character */ - strcat(dest, C128Table[98]); - values[bar_characters] = 98; - bar_characters++; + values[bar_characters++] = 98; } switch (set[read]) { /* Encode data characters */ case 'a': - case 'A': c128_set_a(source[read], dest, values, &bar_characters); + case 'A': c128_set_a(source[read], values, &bar_characters); read++; break; case 'b': - case 'B': (void) c128_set_b(source[read], dest, values, &bar_characters); + case 'B': (void) c128_set_b(source[read], values, &bar_characters); read++; break; - case 'C': c128_set_c(source[read], source[read + 1], dest, values, &bar_characters); + case 'C': c128_set_c(source[read], source[read + 1], values, &bar_characters); read += 2; break; } } while (read < sourcelen); - /* check digit calculation */ - total_sum = values[0] % 103; /* Mod as we go along to avoid overflow */ + /* Destination setting and check digit calculation */ + memcpy(d, C128Table[values[0]], 6); + d += 6; + total_sum = values[0]; - for (i = 1; i < bar_characters; i++) { - total_sum = (total_sum + values[i] * i) % 103; + for (i = 1; i < bar_characters; i++, d += 6) { + memcpy(d, C128Table[values[i]], 6); + total_sum += values[i] * i; /* Note can't overflow as 106 * 60 * 60 = 381600 */ } - strcat(dest, C128Table[total_sum]); - values[bar_characters] = total_sum; - bar_characters++; + total_sum %= 103; + memcpy(d, C128Table[total_sum], 6); + d += 6; + values[bar_characters++] = total_sum; /* Stop character */ - strcat(dest, C128Table[106]); - values[bar_characters] = 106; - bar_characters++; + memcpy(d, "2331112", 7); + d += 7; + values[bar_characters++] = 106; if (symbol->debug & ZINT_DEBUG_PRINT) { printf("Codewords:"); @@ -695,7 +720,7 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len } #endif - expand(symbol, dest); + expand(symbol, dest, d - dest); /* ISO/IEC 15417:2007 leaves dimensions/height as application specification */ @@ -707,13 +732,14 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len /* Handle EAN-128 (Now known as GS1-128), and composite version if `cc_mode` set */ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_mode, const int cc_rows) { - int i, j, values[C128_MAX] = {0}, bar_characters, read, total_sum; + int i, values[C128_MAX] = {0}, bar_characters, read, total_sum; int error_number, warn_number = 0, indexchaine, indexliste; int list[2][C128_MAX] = {{0}}; char set[C128_MAX] = {0}, mode, last_set; float glyph_count; char dest[1000]; - int separator_row, linkage_flag, c_count; + char *d = dest; + int separator_row, linkage_flag; int reduced_length; #ifndef _MSC_VER unsigned char reduced[length + 1]; @@ -721,7 +747,6 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int unsigned char *reduced = (unsigned char *) _alloca(length + 1); #endif - strcpy(dest, ""); linkage_flag = 0; bar_characters = 0; @@ -752,7 +777,7 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int indexliste = 0; indexchaine = 0; - mode = parunmodd(reduced[indexchaine]); + mode = c128_parunmodd(reduced[indexchaine]); do { list[1][indexliste] = mode; @@ -762,76 +787,18 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int if (indexchaine == reduced_length) { break; } - mode = parunmodd(reduced[indexchaine]); + mode = c128_parunmodd(reduced[indexchaine]); if (reduced[indexchaine] == '[') { - mode = ABORC; + mode = C128_ABORC; } } indexliste++; } while (indexchaine < reduced_length); - dxsmooth(list, &indexliste); + c128_dxsmooth(list, &indexliste); - /* Put set data into set[] */ - /* Note as control chars not permitted in GS1, no reason to ever be in Set A, but cases left in anyway */ - read = 0; - for (i = 0; i < indexliste; i++) { - for (j = 0; j < list[0][i]; j++) { - switch (list[1][i]) { - case SHIFTA: set[read] = 'a'; /* Not reached */ - break; - case LATCHA: set[read] = 'A'; /* Not reached */ - break; - case SHIFTB: set[read] = 'b'; /* Not reached */ - break; - case LATCHB: set[read] = 'B'; - break; - case LATCHC: set[read] = 'C'; - break; - } - read++; - } - } - - /* Watch out for odd-length Mode C blocks */ - c_count = 0; - for (i = 0; i < read; i++) { - if (set[i] == 'C') { - if (reduced[i] == '[') { - if (c_count & 1) { - if ((i - c_count) != 0) { - set[i - c_count] = 'B'; - } else { - set[i - 1] = 'B'; - } - } - c_count = 0; - } else { - c_count++; - } - } else { - if (c_count & 1) { - if ((i - c_count) != 0) { - set[i - c_count] = 'B'; - } else { - set[i - 1] = 'B'; - } - } - c_count = 0; - } - } - if (c_count & 1) { - if ((i - c_count) != 0) { - set[i - c_count] = 'B'; - } else { - set[i - 1] = 'B'; - } - } - for (i = 1; i < read - 1; i++) { - if ((set[i] == 'C') && ((set[i - 1] == 'B') && (set[i + 1] == 'B'))) { - set[i] = 'B'; - } - } + /* Put set data into set[], resolving odd C blocks */ + c128_put_in_set(list, indexliste, set, reduced); if (symbol->debug & ZINT_DEBUG_PRINT) { printf("Data: %s (%d)\n", reduced, reduced_length); @@ -866,23 +833,17 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int /* So now we know what start character to use - we can get on with it! */ switch (set[0]) { case 'A': /* Start A */ - strcat(dest, C128Table[103]); /* Not reached */ - values[0] = 103; + values[bar_characters++] = 103; /* Not reached */ break; case 'B': /* Start B */ - strcat(dest, C128Table[104]); - values[0] = 104; + values[bar_characters++] = 104; break; case 'C': /* Start C */ - strcat(dest, C128Table[105]); - values[0] = 105; + values[bar_characters++] = 105; break; } - bar_characters++; - strcat(dest, C128Table[102]); - values[1] = 102; - bar_characters++; + values[bar_characters++] = 102; /* Encode the data */ read = 0; @@ -890,49 +851,42 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int if ((read != 0) && (set[read] != set[read - 1])) { /* Latch different code set */ switch (set[read]) { - case 'A': strcat(dest, C128Table[101]); /* Not reached */ - values[bar_characters] = 101; - bar_characters++; + case 'A': + values[bar_characters++] = 101; /* Not reached */ break; - case 'B': strcat(dest, C128Table[100]); - values[bar_characters] = 100; - bar_characters++; + case 'B': + values[bar_characters++] = 100; break; - case 'C': strcat(dest, C128Table[99]); - values[bar_characters] = 99; - bar_characters++; + case 'C': + values[bar_characters++] = 99; break; } } if ((set[read] == 'a') || (set[read] == 'b')) { /* Insert shift character */ - strcat(dest, C128Table[98]); /* Not reached */ - values[bar_characters] = 98; - bar_characters++; + values[bar_characters++] = 98; /* Not reached */ } if (reduced[read] != '[') { switch (set[read]) { /* Encode data characters */ case 'A': case 'a': - c128_set_a(reduced[read], dest, values, &bar_characters); /* Not reached */ + c128_set_a(reduced[read], values, &bar_characters); /* Not reached */ read++; break; case 'B': case 'b': - (void) c128_set_b(reduced[read], dest, values, &bar_characters); + (void) c128_set_b(reduced[read], values, &bar_characters); read++; break; case 'C': - c128_set_c(reduced[read], reduced[read + 1], dest, values, &bar_characters); + c128_set_c(reduced[read], reduced[read + 1], values, &bar_characters); read += 2; break; } } else { - strcat(dest, C128Table[102]); - values[bar_characters] = 102; - bar_characters++; + values[bar_characters++] = 102; read++; } } while (read < reduced_length); @@ -969,25 +923,27 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int } if (linkage_flag != 0) { - strcat(dest, C128Table[linkage_flag]); - values[bar_characters] = linkage_flag; - bar_characters++; + values[bar_characters++] = linkage_flag; } - /* check digit calculation */ - total_sum = values[0] % 103; /* Mod as we go along to avoid overflow */ + /* Destination setting and check digit calculation */ + memcpy(d, C128Table[values[0]], 6); + d += 6; + total_sum = values[0]; - for (i = 1; i < bar_characters; i++) { - total_sum = (total_sum + values[i] * i) % 103; + for (i = 1; i < bar_characters; i++, d += 6) { + memcpy(d, C128Table[values[i]], 6); + total_sum += values[i] * i; /* Note can't overflow as 106 * 60 * 60 = 381600 */ } - strcat(dest, C128Table[total_sum]); - values[bar_characters] = total_sum; - bar_characters++; + total_sum %= 103; + memcpy(d, C128Table[total_sum], 6); + d += 6; + values[bar_characters++] = total_sum; /* Stop character */ - strcat(dest, C128Table[106]); - values[bar_characters] = 106; - bar_characters++; + memcpy(d, "2331112", 7); + d += 7; + values[bar_characters++] = 106; if (symbol->debug & ZINT_DEBUG_PRINT) { printf("Codewords:"); @@ -1003,7 +959,7 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int } #endif - expand(symbol, dest); + expand(symbol, dest, d - dest); /* Add the separator pattern for composite symbols */ if (symbol->symbology == BARCODE_GS1_128_CC) { @@ -1057,6 +1013,7 @@ INTERNAL int gs1_128(struct zint_symbol *symbol, unsigned char source[], int len INTERNAL int nve18(struct zint_symbol *symbol, unsigned char source[], int length) { int i, count, check_digit; int error_number, zeroes; + int factor; unsigned char ean128_equiv[23]; if (length > 17) { @@ -1064,7 +1021,7 @@ INTERNAL int nve18(struct zint_symbol *symbol, unsigned char source[], int lengt return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "346: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -1075,8 +1032,10 @@ INTERNAL int nve18(struct zint_symbol *symbol, unsigned char source[], int lengt ustrcpy(ean128_equiv + 4 + zeroes, source); count = 0; + factor = 3; for (i = 20; i >= 4; i--) { - count += i & 1 ? ctoi(ean128_equiv[i]) : 3 * ctoi(ean128_equiv[i]); + count += ctoi(ean128_equiv[i]) * factor; + factor ^= 2; /* Toggles 1 and 3 */ } check_digit = 10 - count % 10; if (check_digit == 10) { @@ -1101,7 +1060,7 @@ INTERNAL int ean14(struct zint_symbol *symbol, unsigned char source[], int lengt return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "348: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -1144,8 +1103,8 @@ INTERNAL int dpd(struct zint_symbol *symbol, unsigned char source[], int length) identifier = source[0]; - to_upper(source + 1); - if (is_sane(KRSET, source + 1, length - 1) != 0) { + to_upper(source + 1, length - 1); + if (!is_sane(KRSET_F, source + 1, length - 1)) { strcpy(symbol->errtxt, "300: Invalid character in DPD data (alphanumerics only)"); return ZINT_ERROR_INVALID_DATA; } diff --git a/backend/code128.h b/backend/code128.h index 3d553e53..93336241 100644 --- a/backend/code128.h +++ b/backend/code128.h @@ -38,19 +38,26 @@ extern "C" { #define C128_MAX 160 -#define SHIFTA 90 -#define LATCHA 91 -#define SHIFTB 92 -#define LATCHB 93 -#define SHIFTC 94 -#define LATCHC 95 -#define AORB 96 -#define ABORC 97 +#define C128_SHIFTA 90 +#define C128_LATCHA 91 +#define C128_SHIFTB 92 +#define C128_LATCHB 93 +#define C128_SHIFTC 94 +#define C128_LATCHC 95 +#define C128_AORB 96 +#define C128_ABORC 97 -#define KRSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" +INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int length); -INTERNAL int parunmodd(const unsigned char llyth); -INTERNAL void dxsmooth(int list[2][C128_MAX], int *indexliste); +INTERNAL int c128_parunmodd(const unsigned char llyth); +INTERNAL void c128_dxsmooth(int list[2][C128_MAX], int *indexliste); +INTERNAL void c128_set_a(const unsigned char source, int values[], int *bar_chars); +INTERNAL int c128_set_b(const unsigned char source, int values[], int *bar_chars); +INTERNAL void c128_set_c(const unsigned char source_a, const unsigned char source_b, int values[], int *bar_chars); +INTERNAL void c128_put_in_set(int list[2][C128_MAX], const int indexliste, char set[C128_MAX], + unsigned char *source); + +INTERNAL_DATA_EXTERN const char C128Table[107][6]; #ifdef __cplusplus } diff --git a/backend/code16k.c b/backend/code16k.c index a4de2bbe..fbcf6d0e 100644 --- a/backend/code16k.c +++ b/backend/code16k.c @@ -40,27 +40,12 @@ #include "common.h" #include "code128.h" -static const char *C16KTable[107] = { - /* EN 12323 Table 1 - "Code 16K" character encodations */ - "212222", "222122", "222221", "121223", "121322", "131222", "122213", - "122312", "132212", "221213", "221312", "231212", "112232", "122132", "122231", "113222", - "123122", "123221", "223211", "221132", "221231", "213212", "223112", "312131", "311222", - "321122", "321221", "312212", "322112", "322211", "212123", "212321", "232121", "111323", - "131123", "131321", "112313", "132113", "132311", "211313", "231113", "231311", "112133", - "112331", "132131", "113123", "113321", "133121", "313121", "211331", "231131", "213113", - "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111", "314111", - "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214", - "112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112", - "134111", "111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112", - "421211", "212141", "214121", "412121", "111143", "111341", "131141", "114113", "114311", - "411113", "411311", "113141", "114131", "311141", "411131", "211412", "211214", "211232", - "211133" -}; +/* Note using C128Table with extra entry at 106 (Triple Shift) for C16KTable */ - -static const char *C16KStartStop[8] = { +static const char C16KStartStop[8][4] = { /* EN 12323 Table 3 and Table 4 - Start patterns and stop patterns */ - "3211", "2221", "2122", "1411", "1132", "1231", "1114", "3112" + {'3','2','1','1'}, {'2','2','2','1'}, {'2','1','2','2'}, {'1','4','1','1'}, + {'1','1','3','2'}, {'1','2','3','1'}, {'1','1','1','4'}, {'3','1','1','2'} }; /* EN 12323 Table 5 - Start and stop values defining row numbers */ @@ -72,58 +57,23 @@ static const int C16KStopValues[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 0, 1, 2, 3 }; -static void c16k_set_a(const unsigned char source, int values[], int *bar_chars) { - if (source > 127) { - if (source < 160) { - values[(*bar_chars)] = source + 64 - 128; - } else { - values[(*bar_chars)] = source - 32 - 128; - } - } else { - if (source < 32) { - values[(*bar_chars)] = source + 64; - } else { - values[(*bar_chars)] = source - 32; - } - } - (*bar_chars)++; -} - -static void c16k_set_b(const unsigned char source, int values[], int *bar_chars) { - if (source > 127) { - values[(*bar_chars)] = source - 32 - 128; - } else { - values[(*bar_chars)] = source - 32; - } - (*bar_chars)++; -} - -static void c16k_set_c(const unsigned char source_a, unsigned char source_b, int values[], int *bar_chars) { - int weight; - - weight = (10 * ctoi(source_a)) + ctoi(source_b); - values[(*bar_chars)] = weight; - (*bar_chars)++; -} - INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int length) { char width_pattern[100]; int current_row, rows, looper, first_check, second_check; int indexchaine; int list[2][C128_MAX] = {{0}}; char set[C128_MAX] = {0}, fset[C128_MAX], mode, last_set, current_set; - int pads_needed, indexliste, i, j, m, read, mx_reader; + int pads_needed, indexliste, i, m, read, mx_reader; int values[C128_MAX] = {0}; int bar_characters; float glyph_count; int error_number = 0, first_sum, second_sum; int input_length; - int gs1, c_count; + int gs1; /* Suppresses clang-analyzer-core.UndefinedBinaryOperatorResult warning on fset which is fully set */ assert(length > 0); - strcpy(width_pattern, ""); input_length = length; if ((symbol->input_mode & 0x07) == GS1_MODE) { @@ -149,7 +99,7 @@ INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int len indexliste = 0; indexchaine = 0; - mode = parunmodd(source[indexchaine]); + mode = c128_parunmodd(source[indexchaine]); do { list[1][indexliste] = mode; @@ -159,75 +109,18 @@ INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int len if (indexchaine == input_length) { break; } - mode = parunmodd(source[indexchaine]); + mode = c128_parunmodd(source[indexchaine]); if ((gs1) && (source[indexchaine] == '[')) { - mode = ABORC; + mode = C128_ABORC; } /* FNC1 */ } indexliste++; } while (indexchaine < input_length); - dxsmooth(list, &indexliste); + c128_dxsmooth(list, &indexliste); - /* Put set data into set[] */ - read = 0; - for (i = 0; i < indexliste; i++) { - for (j = 0; j < list[0][i]; j++) { - switch (list[1][i]) { - case SHIFTA: set[read] = 'a'; - break; - case LATCHA: set[read] = 'A'; - break; - case SHIFTB: set[read] = 'b'; - break; - case LATCHB: set[read] = 'B'; - break; - case LATCHC: set[read] = 'C'; - break; - } - read++; - } - } - - /* Watch out for odd-length Mode C blocks */ - c_count = 0; - for (i = 0; i < read; i++) { - if (set[i] == 'C') { - if (source[i] == '[') { - if (c_count & 1) { - if ((i - c_count) != 0) { - set[i - c_count] = 'B'; - } else { - set[i - 1] = 'B'; - } - } - c_count = 0; - } else { - c_count++; - } - } else { - if (c_count & 1) { - if ((i - c_count) != 0) { - set[i - c_count] = 'B'; - } else { - set[i - 1] = 'B'; - } - } - c_count = 0; - } - } - if (c_count & 1) { - if ((i - c_count) != 0) { - set[i - c_count] = 'B'; - } else { - set[i - 1] = 'B'; - } - } - for (i = 1; i < read - 1; i++) { - if ((set[i] == 'C') && ((set[i - 1] == 'B') && (set[i + 1] == 'B'))) { - set[i] = 'B'; - } - } + /* Put set data into set[], resolving odd C blocks */ + c128_put_in_set(list, indexliste, set, source); if (symbol->debug & ZINT_DEBUG_PRINT) { printf("Data: %.*s\n", input_length, source); @@ -394,15 +287,15 @@ INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int len switch (set[read]) { /* Encode data characters */ case 'A': case 'a': - c16k_set_a(source[read], values, &bar_characters); + c128_set_a(source[read], values, &bar_characters); read++; break; case 'B': case 'b': - c16k_set_b(source[read], values, &bar_characters); + c128_set_b(source[read], values, &bar_characters); read++; break; - case 'C': c16k_set_c(source[read], source[read + 1], values, &bar_characters); + case 'C': c128_set_c(source[read], source[read + 1], values, &bar_characters); read += 2; break; } @@ -456,19 +349,21 @@ INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int len int writer; int flip_flop; int len; + char *d = width_pattern; - strcpy(width_pattern, ""); - strcat(width_pattern, C16KStartStop[C16KStartValues[current_row]]); - strcat(width_pattern, "1"); - for (i = 0; i < 5; i++) { - strcat(width_pattern, C16KTable[values[(current_row * 5) + i]]); + memcpy(d, C16KStartStop[C16KStartValues[current_row]], 4); + d += 4; + *d++ = '1'; + for (i = 0; i < 5; i++, d += 6) { + memcpy(d, C128Table[values[(current_row * 5) + i]], 6); } - strcat(width_pattern, C16KStartStop[C16KStopValues[current_row]]); + memcpy(d, C16KStartStop[C16KStopValues[current_row]], 4); + d += 4; /* Write the information into the symbol */ writer = 0; flip_flop = 1; - for (mx_reader = 0, len = (int) strlen(width_pattern); mx_reader < len; mx_reader++) { + for (mx_reader = 0, len = d - width_pattern; mx_reader < len; mx_reader++) { for (looper = 0; looper < ctoi(width_pattern[mx_reader]); looper++) { if (flip_flop == 1) { set_module(symbol, current_row, writer); diff --git a/backend/code49.c b/backend/code49.c index 50f69aaf..64bcf80c 100644 --- a/backend/code49.c +++ b/backend/code49.c @@ -35,20 +35,22 @@ #include "common.h" #include "code49.h" -#define INSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%!&*" +static const char C49_INSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%!&*"; /* "!" represents Shift 1 and "&" represents Shift 2, "*" represents FNC1 */ INTERNAL int code49(struct zint_symbol *symbol, unsigned char source[], int length) { int i, j, rows, M, x_count, y_count, z_count, posn_val, local_value; char intermediate[170] = ""; + char *d = intermediate; int codewords[170], codeword_count; int c_grid[8][8]; /* Refers to table 3 */ int w_grid[8][4]; /* Refets to table 2 */ int pad_count = 0; char pattern[80]; + int bp; int gs1; - int h, len; + int h; int error_number = 0; if (length > 81) { @@ -57,7 +59,7 @@ INTERNAL int code49(struct zint_symbol *symbol, unsigned char source[], int leng } if ((symbol->input_mode & 0x07) == GS1_MODE) { gs1 = 1; - strcpy(intermediate, "*"); /* FNC1 */ + *d++ = '*'; /* FNC1 */ } else { gs1 = 0; } @@ -67,15 +69,18 @@ INTERNAL int code49(struct zint_symbol *symbol, unsigned char source[], int leng strcpy(symbol->errtxt, "431: Invalid character in input data, extended ASCII not allowed"); return ZINT_ERROR_INVALID_DATA; } - if (gs1 && (source[i] == '[')) - strcat(intermediate, "*"); /* FNC1 */ - else - strcat(intermediate, c49_table7[source[i]]); + if (gs1 && (source[i] == '[')) { + *d++ = '*'; /* FNC1 */ + } else { + const char *const entry = c49_table7[source[i]]; + memcpy(d, entry, 2); + d += entry[1] ? 2 : 1; + } } codeword_count = 0; i = 0; - h = (int) strlen(intermediate); + h = d - intermediate; do { if ((intermediate[i] >= '0') && (intermediate[i] <= '9')) { /* Numeric data */ @@ -142,7 +147,7 @@ INTERNAL int code49(struct zint_symbol *symbol, unsigned char source[], int leng switch (block_remain) { case 1: /* Rule (a) */ - codewords[codeword_count] = posn(INSET, intermediate[i]); + codewords[codeword_count] = posn(C49_INSET, intermediate[i]); codeword_count++; i++; break; @@ -184,12 +189,12 @@ INTERNAL int code49(struct zint_symbol *symbol, unsigned char source[], int leng codeword_count++; } } else { - codewords[codeword_count] = posn(INSET, intermediate[i]); + codewords[codeword_count] = posn(C49_INSET, intermediate[i]); codeword_count++; i++; } } else { - codewords[codeword_count] = posn(INSET, intermediate[i]); + codewords[codeword_count] = posn(C49_INSET, intermediate[i]); codeword_count++; i++; } @@ -321,25 +326,26 @@ INTERNAL int code49(struct zint_symbol *symbol, unsigned char source[], int leng } for (i = 0; i < rows; i++) { - strcpy(pattern, "10"); /* Start character */ + bp = 0; + bp = bin_append_posn(2, 2, pattern, bp); /* Start character "10" */ for (j = 0; j < 4; j++) { if (i != (rows - 1)) { if (c49_table4[i][j] == 'E') { /* Even Parity */ - bin_append(c49_even_bitpattern[w_grid[i][j]], 16, pattern); + bp = bin_append_posn(c49_even_bitpattern[w_grid[i][j]], 16, pattern, bp); } else { /* Odd Parity */ - bin_append(c49_odd_bitpattern[w_grid[i][j]], 16, pattern); + bp = bin_append_posn(c49_odd_bitpattern[w_grid[i][j]], 16, pattern, bp); } } else { /* Last row uses all even parity */ - bin_append(c49_even_bitpattern[w_grid[i][j]], 16, pattern); + bp = bin_append_posn(c49_even_bitpattern[w_grid[i][j]], 16, pattern, bp); } } - strcat(pattern, "1111"); /* Stop character */ + bp = bin_append_posn(15, 4, pattern, bp); /* Stop character "1111" */ /* Expand into symbol */ - for (j = 0, len = (int) strlen(pattern); j < len; j++) { + for (j = 0; j < bp; j++) { if (pattern[j] == '1') { set_module(symbol, i, j); } @@ -347,7 +353,7 @@ INTERNAL int code49(struct zint_symbol *symbol, unsigned char source[], int leng } symbol->rows = rows; - symbol->width = (int) strlen(pattern); + symbol->width = bp; if (symbol->output_options & COMPLIANT_HEIGHT) { /* ANSI/AIM BC6-2000 Section 2.6 minimum 8X; use 10X as default diff --git a/backend/code49.h b/backend/code49.h index 01dec462..f781a9e7 100644 --- a/backend/code49.h +++ b/backend/code49.h @@ -2,7 +2,7 @@ /* libzint - the open source barcode library - Copyright (C) 2009-2017 Robin Stuart + Copyright (C) 2009-2021 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -29,21 +29,25 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* vim: set ts=4 sw=4 et : */ /* This data set taken from ANSI/AIM-BC6-2000, 4th April 2000 */ -static const char *c49_table7[128] = { +static const char c49_table7[128][2] = { /* Table 7: Code 49 ASCII Chart */ - "! ", "!A", "!B", "!C", "!D", "!E", "!F", "!G", "!H", "!I", "!J", "!K", "!L", - "!M", "!N", "!O", "!P", "!Q", "!R", "!S", "!T", "!U", "!V", "!W", "!X", "!Y", - "!Z", "!1", "!2", "!3", "!4", "!5", " ", "!6", "!7", "!8", "$", "%", "!9", "!0", - "!-", "!.", "!$", "+", "!/", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", - "7", "8", "9", "!+", "&1", "&2", "&3", "&4", "&5", "&6", "A", "B", "C", "D", "E", - "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", - "V", "W", "X", "Y", "Z", "&7", "&8", "&9", "&0", "&-", "&.", "&A", "&B", "&C", - "&D", "&E", "&F", "&G", "&H", "&I", "&J", "&K", "&L", "&M", "&N", "&O", "&P", - "&Q", "&R", "&S", "&T", "&U", "&V", "&W", "&X", "&Y", "&Z", "&$", "&/", "&+", - "&%", "& " + {'!',' '}, {'!','A'}, {'!','B'}, {'!','C'}, {'!','D'}, {'!','E'}, {'!','F'}, {'!','G'}, {'!','H'}, {'!','I'}, + {'!','J'}, {'!','K'}, {'!','L'}, {'!','M'}, {'!','N'}, {'!','O'}, {'!','P'}, {'!','Q'}, {'!','R'}, {'!','S'}, + {'!','T'}, {'!','U'}, {'!','V'}, {'!','W'}, {'!','X'}, {'!','Y'}, {'!','Z'}, {'!','1'}, {'!','2'}, {'!','3'}, + {'!','4'}, {'!','5'}, { " " }, {'!','6'}, {'!','7'}, {'!','8'}, { "$" }, { "%" }, {'!','9'}, {'!','0'}, + {'!','-'}, {'!','.'}, {'!','$'}, { "+" }, {'!','/'}, { "-" }, { "." }, { "/" }, { "0" }, { "1" }, + { "2" }, { "3" }, { "4" }, { "5" }, { "6" }, { "7" }, { "8" }, { "9" }, {'!','+'}, {'&','1'}, + {'&','2'}, {'&','3'}, {'&','4'}, {'&','5'}, {'&','6'}, { "A" }, { "B" }, { "C" }, { "D" }, { "E" }, + { "F" }, { "G" }, { "H" }, { "I" }, { "J" }, { "K" }, { "L" }, { "M" }, { "N" }, { "O" }, + { "P" }, { "Q" }, { "R" }, { "S" }, { "T" }, { "U" }, { "V" }, { "W" }, { "X" }, { "Y" }, + { "Z" }, {'&','7'}, {'&','8'}, {'&','9'}, {'&','0'}, {'&','-'}, {'&','.'}, {'&','A'}, {'&','B'}, {'&','C'}, + {'&','D'}, {'&','E'}, {'&','F'}, {'&','G'}, {'&','H'}, {'&','I'}, {'&','J'}, {'&','K'}, {'&','L'}, {'&','M'}, + {'&','N'}, {'&','O'}, {'&','P'}, {'&','Q'}, {'&','R'}, {'&','S'}, {'&','T'}, {'&','U'}, {'&','V'}, {'&','W'}, + {'&','X'}, {'&','Y'}, {'&','Z'}, {'&','$'}, {'&','/'}, {'&','+'}, {'&','%'}, {'&',' '} }; /* Table 5: Check Character Weighting Values */ @@ -62,9 +66,10 @@ static const char c49_z_weight[] = { 13, 5, 41, 33, 36, 8, 4, 32, 3, 19, 40, 25, 29, 10, 24, 30 }; -static const char *c49_table4[8] = { +static const char c49_table4[8][4] = { /* Table 4: Row Parity Pattern for Code 49 Symbols */ - "OEEO", "EOEO", "OOEE", "EEOO", "OEOE", "EOOE", "OOOO", "EEEE" + {'O','E','E','O'}, {'E','O','E','O'}, {'O','O','E','E'}, {'E','E','O','O'}, + {'O','E','O','E'}, {'E','O','O','E'}, {'O','O','O','O'}, {'E','E','E','E'} }; static const unsigned short int c49_even_bitpattern[] = { diff --git a/backend/common.c b/backend/common.c index dc45dd01..7b4bbf8d 100644 --- a/backend/common.c +++ b/backend/common.c @@ -75,10 +75,10 @@ INTERNAL int to_int(const unsigned char source[], const int length) { } /* Converts lower case characters to upper case in a string source[] */ -INTERNAL void to_upper(unsigned char source[]) { - int i, src_len = (int) ustrlen(source); +INTERNAL void to_upper(unsigned char source[], const int length) { + int i; - for (i = 0; i < src_len; i++) { + for (i = 0; i < length; i++) { if ((source[i] >= 'a') && (source[i] <= 'z')) { source[i] = (source[i] - 'a') + 'A'; } @@ -98,59 +98,80 @@ INTERNAL int chr_cnt(const unsigned char string[], const int length, const unsig } /* Verifies that a string only uses valid characters */ -INTERNAL int is_sane(const char test_string[], const unsigned char source[], const int length) { - int i, j, lt = (int) strlen(test_string); +INTERNAL int is_sane(const unsigned int flg, const unsigned char source[], const int length) { + #define IS_CLS_F (IS_CLI_F | IS_SIL_F) + static unsigned short flgs[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*00-1F*/ + IS_SPC_F, IS_C82_F, IS_C82_F, IS_HSH_F, /*20-23*/ /* !"# */ + IS_CLS_F, IS_SIL_F | IS_C82_F, IS_C82_F, IS_C82_F, /*24-27*/ /* $%&' */ + IS_C82_F, IS_C82_F, IS_C82_F, IS_PLS_F, /*28-2B*/ /* ()*+ */ + IS_C82_F, IS_MNS_F, IS_CLS_F | IS_C82_F, IS_CLS_F | IS_C82_F, /*2B-2F*/ /* ,-./ */ + IS_NUM_F, IS_NUM_F, IS_NUM_F, IS_NUM_F, /*30-33*/ /* 0123 */ + IS_NUM_F, IS_NUM_F, IS_NUM_F, IS_NUM_F, /*34-37*/ /* 4567 */ + IS_NUM_F, IS_NUM_F, IS_CLI_F | IS_C82_F, IS_C82_F, /*38-3B*/ /* 89:; */ + IS_C82_F, IS_C82_F, IS_C82_F, IS_C82_F, /*3B-3F*/ /* <=>? */ + 0, IS_UHX_F | IS_ARS_F, IS_UHX_F | IS_ARS_F, IS_UHX_F | IS_ARS_F, /*40-43*/ /* @ABC */ + IS_UHX_F | IS_ARS_F, IS_UHX_F | IS_ARS_F, IS_UHX_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, /*44-47*/ /* DEFG */ + IS_UPO_F | IS_ARS_F, IS_UPO_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, /*48-4B*/ /* HIJK */ + IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, IS_UPO_F, /*4B-4F*/ /* LMNO */ + IS_UPO_F | IS_ARS_F, IS_UPO_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, /*50-53*/ /* PQRS */ + IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, /*53-57*/ /* TUVW */ + IS_UX__F | IS_ARS_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, 0, /*58-5B*/ /* XYZ[ */ + 0, 0, 0, IS_C82_F, /*5B-5F*/ /* \]^_ */ + 0, IS_LHX_F, IS_LHX_F, IS_LHX_F, /*60-63*/ /* `abc */ + IS_LHX_F, IS_LHX_F, IS_LHX_F, IS_LWO_F, /*64-67*/ /* defg */ + IS_LWO_F, IS_LWO_F, IS_LWO_F, IS_LWO_F, /*68-6B*/ /* hijk */ + IS_LWO_F, IS_LWO_F, IS_LWO_F, IS_LWO_F, /*6B-6F*/ /* lmno */ + IS_LWO_F, IS_LWO_F, IS_LWO_F, IS_LWO_F, /*70-73*/ /* pqrs */ + IS_LWO_F, IS_LWO_F, IS_LWO_F, IS_LWO_F, /*74-77*/ /* tuvw */ + IS_LX__F, IS_LWO_F, IS_LWO_F, 0, /*78-7B*/ /* xyz{ */ + 0, 0, 0, 0, /*7B-7F*/ /* |}~D */ + }; + int i; for (i = 0; i < length; i++) { - unsigned int latch = FALSE; - for (j = 0; j < lt; j++) { - if (source[i] == test_string[j]) { - latch = TRUE; - break; - } - } - if (!(latch)) { - return ZINT_ERROR_INVALID_DATA; + if (!(flgs[source[i]] & flg)) { + return 0; } } - - return 0; + return 1; } /* Replaces huge switch statements for looking up in tables */ -INTERNAL void lookup(const char set_string[], const char *table[], const char data, char dest[]) { - int i, n = (int) strlen(set_string); +/* Verifies that a string only uses valid characters, and returns `test_string` position of each in `posns` array */ +INTERNAL int is_sane_lookup(const char test_string[], const int test_length, const unsigned char source[], + const int length, int *posns) { + int i, j; - for (i = 0; i < n; i++) { - if (data == set_string[i]) { - strcat(dest, table[i]); - break; + for (i = 0; i < length; i++) { + posns[i] = -1; + for (j = 0; j < test_length; j++) { + if (source[i] == test_string[j]) { + posns[i] = j; + break; + } + } + if (posns[i] == -1) { + return 0; } } + + return 1; } /* Returns the position of data in set_string */ INTERNAL int posn(const char set_string[], const char data) { - int i, n = (int) strlen(set_string); + const char *s; - for (i = 0; i < n; i++) { - if (data == set_string[i]) { - return i; + for (s = set_string; *s; s++) { + if (data == *s) { + return s - set_string; } } return -1; } -/* Convert an integer value to a string representing its binary equivalent */ -INTERNAL void bin_append(const int arg, const int length, char *binary) { - int bin_posn = (int) strlen(binary); - - bin_append_posn(arg, length, binary, bin_posn); - - binary[bin_posn + length] = '\0'; -} - -/* Convert an integer value to a string representing its binary equivalent at a set position */ +/* Convert an integer value to a string representing its binary equivalent and place at a given position */ INTERNAL int bin_append_posn(const int arg, const int length, char *binary, const int bin_posn) { int i; int start; @@ -195,20 +216,23 @@ INTERNAL void unset_module(struct zint_symbol *symbol, const int y_coord, const } /* Expands from a width pattern to a bit pattern */ -INTERNAL void expand(struct zint_symbol *symbol, const char data[]) { +INTERNAL void expand(struct zint_symbol *symbol, const char data[], const int length) { - int reader, n = (int) strlen(data); + int reader; int writer, i; int latch, num; + int row = symbol->rows; + + symbol->rows++; writer = 0; latch = 1; - for (reader = 0; reader < n; reader++) { + for (reader = 0; reader < length; reader++) { num = ctoi(data[reader]); for (i = 0; i < num; i++) { if (latch) { - set_module(symbol, symbol->rows, writer); + set_module(symbol, row, writer); } writer++; } @@ -216,17 +240,9 @@ INTERNAL void expand(struct zint_symbol *symbol, const char data[]) { latch = !latch; } - if (symbol->symbology != BARCODE_PHARMA) { - if (writer > symbol->width) { - symbol->width = writer; - } - } else { - /* Pharmacode One ends with a space - adjust for this */ - if (writer > symbol->width + 2) { - symbol->width = writer - 2; - } + if (writer > symbol->width) { + symbol->width = writer; } - symbol->rows = symbol->rows + 1; } /* Indicates which symbologies can have row binding */ @@ -281,7 +297,7 @@ INTERNAL int is_composite(const int symbology) { } /* Whether next two characters are digits */ -INTERNAL int istwodigits(const unsigned char source[], const int length, const int position) { +INTERNAL int is_twodigits(const unsigned char source[], const int length, const int position) { if ((position + 1 < length) && (source[position] >= '0') && (source[position] <= '9') && (source[position + 1] >= '0') && (source[position + 1] <= '9')) { return 1; @@ -415,7 +431,7 @@ INTERNAL int set_height(struct zint_symbol *symbol, const float min_row_height, if (row_height < 0.5f) { /* Absolute minimum */ row_height = 0.5f; } - if (min_row_height && row_height < min_row_height) { + if (min_row_height && stripf(row_height) < stripf(min_row_height)) { error_number = ZINT_WARN_NONCOMPLIANT; if (!no_errtxt) { strcpy(symbol->errtxt, "247: Height not compliant with standards"); @@ -425,7 +441,7 @@ INTERNAL int set_height(struct zint_symbol *symbol, const float min_row_height, } else { symbol->height = stripf(fixed_height); /* Ignore any given height */ } - if (max_height && symbol->height > max_height) { + if (max_height && stripf(symbol->height) > stripf(max_height)) { error_number = ZINT_WARN_NONCOMPLIANT; if (!no_errtxt) { strcpy(symbol->errtxt, "248: Height not compliant with standards"); diff --git a/backend/common.h b/backend/common.h index a7a98405..84af5798 100644 --- a/backend/common.h +++ b/backend/common.h @@ -42,8 +42,28 @@ #define TRUE 1 #endif +/* `is_sane()` flags */ +#define IS_SPC_F 0x0001 /* Space */ +#define IS_HSH_F 0x0002 /* Hash sign # */ +#define IS_PLS_F 0x0004 /* Plus sign + */ +#define IS_MNS_F 0x0008 /* Minus sign - */ +#define IS_NUM_F 0x0010 /* Number 0-9 */ +#define IS_UPO_F 0x0020 /* Uppercase letter, apart from A-F and X */ +#define IS_UHX_F 0x0040 /* Uppercase hex A-F */ +#define IS_UX__F 0x0080 /* Uppercase X */ +#define IS_LWO_F 0x0100 /* Lowercase letter, apart from a-f and x */ +#define IS_LHX_F 0x0200 /* Lowercase hex a-f */ +#define IS_LX__F 0x0400 /* Lowercase x */ +#define IS_C82_F 0x0800 /* CSET82 punctuation (apart from - and +) */ +#define IS_SIL_F 0x1000 /* SILVER/TECHNETIUM punctuation .$/% (apart from space, - and +) */ +#define IS_CLI_F 0x2000 /* CALCIUM INNER punctuation $:/. (apart from - and +) (Codabar) */ +#define IS_ARS_F 0x4000 /* ARSENIC uppercase subset (VIN) */ + +#define IS_UPR_F (IS_UPO_F | IS_UHX_F | IS_UX__F) /* Uppercase letters */ +#define IS_LWR_F (IS_LWO_F | IS_LHX_F | IS_LX__F) /* Lowercase letters */ + /* The most commonly used set */ -#define NEON "0123456789" +#define NEON_F IS_NUM_F /* NEON "0123456789" */ #include "zint.h" #include "zintconfig.h" @@ -83,6 +103,14 @@ # define INTERNAL #endif +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__MINGW32__) +# define INTERNAL_DATA_EXTERN __attribute__ ((visibility ("hidden"))) extern +# define INTERNAL_DATA __attribute__ ((visibility ("hidden"))) +#else +# define INTERNAL_DATA_EXTERN extern +# define INTERNAL_DATA +#endif + #ifdef ZINT_TEST #define STATIC_UNLESS_ZINT_TEST INTERNAL #else @@ -112,14 +140,14 @@ extern "C" { INTERNAL int ctoi(const char source); INTERNAL char itoc(const int source); INTERNAL int to_int(const unsigned char source[], const int length); - INTERNAL void to_upper(unsigned char source[]); + INTERNAL void to_upper(unsigned char source[], const int length); INTERNAL int chr_cnt(const unsigned char string[], const int length, const unsigned char c); - INTERNAL int is_sane(const char test_string[], const unsigned char source[], const int length); - INTERNAL void lookup(const char set_string[], const char *table[], const char data, char dest[]); + INTERNAL int is_sane(const unsigned int flg, const unsigned char source[], const int length); + INTERNAL int is_sane_lookup(const char test_string[], const int test_length, const unsigned char source[], + const int length, int *posns); INTERNAL int posn(const char set_string[], const char data); - INTERNAL void bin_append(const int arg, const int length, char *binary); INTERNAL int bin_append_posn(const int arg, const int length, char *binary, const int bin_posn); #ifndef COMMON_INLINE @@ -130,12 +158,14 @@ extern "C" { const int colour); #endif INTERNAL void unset_module(struct zint_symbol *symbol, const int y_coord, const int x_coord); - INTERNAL void expand(struct zint_symbol *symbol, const char data[]); + + INTERNAL void expand(struct zint_symbol *symbol, const char data[], const int length); INTERNAL int is_stackable(const int symbology); INTERNAL int is_extendable(const int symbology); INTERNAL int is_composite(const int symbology); - INTERNAL int istwodigits(const unsigned char source[], const int length, const int position); + + INTERNAL int is_twodigits(const unsigned char source[], const int length, const int position); INTERNAL unsigned int decode_utf8(unsigned int *state, unsigned int *codep, const unsigned char byte); INTERNAL int is_valid_utf8(const unsigned char source[], const int length); diff --git a/backend/composite.c b/backend/composite.c index 2febeedf..980b9d2f 100644 --- a/backend/composite.c +++ b/backend/composite.c @@ -68,7 +68,8 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int INTERNAL int eanx_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows); INTERNAL int ean_leading_zeroes(struct zint_symbol *symbol, const unsigned char source[], - unsigned char local_source[], int *p_with_addon); + unsigned char local_source[], int *p_with_addon, unsigned char *zfirst_part, + unsigned char *zsecond_part); INTERNAL int dbar_omnstk_set_height(struct zint_symbol *symbol, const int first_row); INTERNAL int dbar_omn_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows); @@ -1331,8 +1332,8 @@ INTERNAL int composite(struct zint_symbol *symbol, unsigned char source[], int l int padded_pri_len; int with_addon; unsigned char padded_pri[21]; - padded_pri[0] = '\0'; - if (!ean_leading_zeroes(symbol, (unsigned char *) symbol->primary, padded_pri, &with_addon)) { + if (!ean_leading_zeroes(symbol, (unsigned char *) symbol->primary, padded_pri, &with_addon, NULL, + NULL)) { sprintf(symbol->errtxt, "448: Input too long (%s) in linear component", with_addon ? "5 character maximum for add-on" : "13 character maximum"); return ZINT_ERROR_TOO_LONG; diff --git a/backend/dllversion.c b/backend/dllversion.c index d5cca9d0..62b02698 100644 --- a/backend/dllversion.c +++ b/backend/dllversion.c @@ -1,4 +1,35 @@ /* Sed: http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/versions.asp */ + +/* + libzint - the open source barcode library + Copyright (C) 2008 - 2021 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. + */ +/* vim: set ts=4 sw=4 et : */ #if defined (_WIN32) && (defined(_USRDLL) || defined(DLL_EXPORT) || defined(PIC)) #include #include @@ -17,17 +48,18 @@ __declspec(dllexport) HRESULT DllGetVersion (DLLVERSIONINFO2* pdvi); HRESULT DllGetVersion (DLLVERSIONINFO2* pdvi) { - if (!pdvi || (sizeof(*pdvi) != pdvi->info1.cbSize)) - return (E_INVALIDARG); + if (!pdvi || (sizeof(*pdvi) != pdvi->info1.cbSize)) + return (E_INVALIDARG); - pdvi->info1.dwMajorVersion = ZINT_VERSION_MAJOR; - pdvi->info1.dwMinorVersion = ZINT_VERSION_MINOR; - pdvi->info1.dwBuildNumber = ZINT_VERSION_RELEASE; - pdvi->info1.dwPlatformID = DLLVER_PLATFORM_WINDOWS; - if (sizeof(DLLVERSIONINFO2) == pdvi->info1.cbSize) - pdvi->ullVersion = MAKEDLLVERULL(ZINT_VERSION_MAJOR, ZINT_VERSION_MINOR, ZINT_VERSION_RELEASE, ZINT_VERSION_BUILD); + pdvi->info1.dwMajorVersion = ZINT_VERSION_MAJOR; + pdvi->info1.dwMinorVersion = ZINT_VERSION_MINOR; + pdvi->info1.dwBuildNumber = ZINT_VERSION_RELEASE; + pdvi->info1.dwPlatformID = DLLVER_PLATFORM_WINDOWS; + if (sizeof(DLLVERSIONINFO2) == pdvi->info1.cbSize) + pdvi->ullVersion = MAKEDLLVERULL(ZINT_VERSION_MAJOR, ZINT_VERSION_MINOR, ZINT_VERSION_RELEASE, + ZINT_VERSION_BUILD); - return S_OK; + return S_OK; } #else /* https://stackoverflow.com/a/26541331 Suppresses gcc warning ISO C forbids an empty translation unit */ diff --git a/backend/dmatrix.c b/backend/dmatrix.c index 44680a5f..927cbb10 100644 --- a/backend/dmatrix.c +++ b/backend/dmatrix.c @@ -779,7 +779,7 @@ static int dm200encode(struct zint_symbol *symbol, const unsigned char source[], if (current_mode == DM_ASCII) { next_mode = DM_ASCII; - if (istwodigits(source, inputlen, sp)) { + if (is_twodigits(source, inputlen, sp)) { target[tp] = (unsigned char) ((10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130); if (debug) printf("N%02d ", target[tp] - 130); tp++; @@ -1029,7 +1029,7 @@ static int dm200encode(struct zint_symbol *symbol, const unsigned char source[], target[tp++] = 254; // Unlatch if (debug) printf("ASC "); for (; sp < inputlen; sp++) { - if (istwodigits(source, inputlen, sp)) { + if (is_twodigits(source, inputlen, sp)) { target[tp++] = (unsigned char) ((10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130); if (debug) printf("N%02d ", target[tp - 1] - 130); sp++; diff --git a/backend/dotcode.c b/backend/dotcode.c index 67658d36..957367da 100644 --- a/backend/dotcode.c +++ b/backend/dotcode.c @@ -584,7 +584,7 @@ static int dotcode_encode_message(struct zint_symbol *symbol, const unsigned cha } // Prevent encodation as a macro if a special character is in first position - if (strchr(lead_specials, source[input_position]) != NULL) { + if (posn(lead_specials, source[input_position]) != -1) { codeword_array[array_length] = 101; // Latch A array_length++; codeword_array[array_length] = source[input_position] + 64; diff --git a/backend/emf.c b/backend/emf.c index c1738788..775db073 100644 --- a/backend/emf.c +++ b/backend/emf.c @@ -46,7 +46,7 @@ #include "emf.h" /* Multiply truncating to 3 decimal places (avoids rounding differences on various platforms) */ -#define mul3dpf(m, arg) (roundf(m * arg * 1000.0) / 1000.0f) +#define mul3dpf(m, arg) stripf(roundf(m * arg * 1000.0) / 1000.0f) static int count_rectangles(struct zint_symbol *symbol) { int rectangles = 0; @@ -453,9 +453,9 @@ INTERNAL int emf_plot(struct zint_symbol *symbol, int rotate_angle) { rectangle[this_rectangle].type = 0x0000002b; // EMR_RECTANGLE rectangle[this_rectangle].size = 24; rectangle[this_rectangle].box.top = (int32_t) rect->y; - rectangle[this_rectangle].box.bottom = (int32_t) (rect->y + rect->height); + rectangle[this_rectangle].box.bottom = (int32_t) stripf(rect->y + rect->height); rectangle[this_rectangle].box.left = (int32_t) rect->x; - rectangle[this_rectangle].box.right = (int32_t) (rect->x + rect->width); + rectangle[this_rectangle].box.right = (int32_t) stripf(rect->x + rect->width); this_rectangle++; bytecount += 24; recordcount++; @@ -475,10 +475,10 @@ INTERNAL int emf_plot(struct zint_symbol *symbol, int rotate_angle) { } circle[this_circle].type = 0x0000002a; // EMR_ELLIPSE circle[this_circle].size = 24; - circle[this_circle].box.top = (int32_t) (circ->y - radius); - circle[this_circle].box.bottom = (int32_t) (circ->y + radius); - circle[this_circle].box.left = (int32_t) (circ->x - radius); - circle[this_circle].box.right = (int32_t) (circ->x + radius); + circle[this_circle].box.top = (int32_t) stripf(circ->y - radius); + circle[this_circle].box.bottom = (int32_t) stripf(circ->y + radius); + circle[this_circle].box.left = (int32_t) stripf(circ->x - radius); + circle[this_circle].box.right = (int32_t) stripf(circ->x + radius); this_circle++; bytecount += 24; recordcount++; @@ -487,10 +487,10 @@ INTERNAL int emf_plot(struct zint_symbol *symbol, int rotate_angle) { float inner_radius = radius - circ->width; circle[this_circle].type = 0x0000002a; // EMR_ELLIPSE circle[this_circle].size = 24; - circle[this_circle].box.top = (int32_t) (circ->y - inner_radius); - circle[this_circle].box.bottom = (int32_t) (circ->y + inner_radius); - circle[this_circle].box.left = (int32_t) (circ->x - inner_radius); - circle[this_circle].box.right = (int32_t) (circ->x + inner_radius); + circle[this_circle].box.top = (int32_t) stripf(circ->y - inner_radius); + circle[this_circle].box.bottom = (int32_t) stripf(circ->y + inner_radius); + circle[this_circle].box.left = (int32_t) stripf(circ->x - inner_radius); + circle[this_circle].box.right = (int32_t) stripf(circ->x + inner_radius); this_circle++; bytecount += 24; recordcount++; @@ -516,18 +516,18 @@ INTERNAL int emf_plot(struct zint_symbol *symbol, int rotate_angle) { } /* Note rotation done via world transform */ - hexagon[this_hexagon].a_points_a.x = (int32_t) (hex->x); - hexagon[this_hexagon].a_points_a.y = (int32_t) (hex->y + radius); - hexagon[this_hexagon].a_points_b.x = (int32_t) (hex->x + half_sqrt3_radius); - hexagon[this_hexagon].a_points_b.y = (int32_t) (hex->y + half_radius); - hexagon[this_hexagon].a_points_c.x = (int32_t) (hex->x + half_sqrt3_radius); - hexagon[this_hexagon].a_points_c.y = (int32_t) (hex->y - half_radius); - hexagon[this_hexagon].a_points_d.x = (int32_t) (hex->x); - hexagon[this_hexagon].a_points_d.y = (int32_t) (hex->y - radius); - hexagon[this_hexagon].a_points_e.x = (int32_t) (hex->x - half_sqrt3_radius); - hexagon[this_hexagon].a_points_e.y = (int32_t) (hex->y - half_radius); - hexagon[this_hexagon].a_points_f.x = (int32_t) (hex->x - half_sqrt3_radius); - hexagon[this_hexagon].a_points_f.y = (int32_t) (hex->y + half_radius); + hexagon[this_hexagon].a_points_a.x = (int32_t) hex->x; + hexagon[this_hexagon].a_points_a.y = (int32_t) stripf(hex->y + radius); + hexagon[this_hexagon].a_points_b.x = (int32_t) stripf(hex->x + half_sqrt3_radius); + hexagon[this_hexagon].a_points_b.y = (int32_t) stripf(hex->y + half_radius); + hexagon[this_hexagon].a_points_c.x = (int32_t) stripf(hex->x + half_sqrt3_radius); + hexagon[this_hexagon].a_points_c.y = (int32_t) stripf(hex->y - half_radius); + hexagon[this_hexagon].a_points_d.x = (int32_t) hex->x; + hexagon[this_hexagon].a_points_d.y = (int32_t) stripf(hex->y - radius); + hexagon[this_hexagon].a_points_e.x = (int32_t) stripf(hex->x - half_sqrt3_radius); + hexagon[this_hexagon].a_points_e.y = (int32_t) stripf(hex->y - half_radius); + hexagon[this_hexagon].a_points_f.x = (int32_t) stripf(hex->x - half_sqrt3_radius); + hexagon[this_hexagon].a_points_f.y = (int32_t) stripf(hex->y + half_radius); hexagon[this_hexagon].bounds.top = hexagon[this_hexagon].a_points_d.y; hexagon[this_hexagon].bounds.bottom = hexagon[this_hexagon].a_points_a.y; diff --git a/backend/emf.h b/backend/emf.h index a10aa629..cb073887 100644 --- a/backend/emf.h +++ b/backend/emf.h @@ -28,11 +28,12 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* vim: set ts=4 sw=4 et : */ #ifndef EMF_H -#define EMF_H +#define EMF_H -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -243,10 +244,8 @@ extern "C" { #pragma pack() -#ifdef __cplusplus +#ifdef __cplusplus } #endif -#endif /* EMF_H */ - - +#endif /* EMF_H */ diff --git a/backend/font.h b/backend/font.h index a01abaf7..e7126e26 100644 --- a/backend/font.h +++ b/backend/font.h @@ -448,7 +448,8 @@ static font_item small_font[] = { * release of ocr-b only granted rights for non-commercial use; that * restriction is now lifted." * - * Used OCRB.otf with FontForge to create OCRB-18.bdf (normal) and OCRB-16.bdf (small) and then touched up using gbdfed + * Used OCRB.otf with FontForge to create OCRB-18.bdf (normal) and OCRB-16.bdf (small) and then touched up + * using gbdfed * Note there's no bold version of OCR-B. */ diff --git a/backend/general_field.c b/backend/general_field.c index 7c450c60..d8a85069 100644 --- a/backend/general_field.c +++ b/backend/general_field.c @@ -36,16 +36,17 @@ static const char alphanum_puncs[] = "*,-./"; static const char isoiec_puncs[] = "!\"%&'()*+,-./:;<=>?_ "; /* Note contains space, not in cset82 */ +#define IS_ISOIEC_F (IS_LWR_F | IS_C82_F | IS_PLS_F | IS_MNS_F | IS_SPC_F) /* Returns type of char at `i`. FNC1 counted as NUMERIC. Returns 0 if invalid char */ static int general_field_type(const char *general_field, const int i) { if (general_field[i] == '[' || (general_field[i] >= '0' && general_field[i] <= '9')) { return NUMERIC; } - if ((general_field[i] >= 'A' && general_field[i] <= 'Z') || strchr(alphanum_puncs, general_field[i])) { + if ((general_field[i] >= 'A' && general_field[i] <= 'Z') || posn(alphanum_puncs, general_field[i]) != -1) { return ALPHANUMERIC; } - if ((general_field[i] >= 'a' && general_field[i] <= 'z') || strchr(isoiec_puncs, general_field[i])) { + if (is_sane(IS_ISOIEC_F, (const unsigned char *) general_field + i, 1)) { return ISOIEC; } return 0; diff --git a/backend/gridmtx.c b/backend/gridmtx.c index 1f78960a..efc4b6f8 100644 --- a/backend/gridmtx.c +++ b/backend/gridmtx.c @@ -43,6 +43,10 @@ #include "gb2312.h" #include "eci.h" +static const char EUROPIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz "; +static const char EUROPIUM_UPR[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ "; +static const char EUROPIUM_LWR[] = "abcdefghijklmnopqrstuvwxyz "; + /* define_mode() stuff */ /* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */ @@ -68,7 +72,7 @@ static int in_numeral(const unsigned int gbdata[], const int length, const int i i++) { if (gbdata[i] >= '0' && gbdata[i] <= '9') { digit_cnt++; - } else if (strchr(numeral_nondigits, gbdata[i])) { + } else if (posn(numeral_nondigits, (const char) gbdata[i]) != -1) { if (nondigit) { break; } @@ -282,7 +286,7 @@ static void define_mode(char *mode, const unsigned int gbdata[], const int lengt /* Get optimal mode for each code point by tracing backwards */ for (i = length - 1, cm_i = i * GM_NUM_MODES; i >= 0; i--, cm_i -= GM_NUM_MODES) { - j = strchr(mode_types, cur_mode) - mode_types; + j = posn(mode_types, cur_mode); cur_mode = char_modes[cm_i + j]; mode[i] = cur_mode; } @@ -308,7 +312,7 @@ static int add_shift_char(char binary[], int bp, int shifty, int debug) { glyph = shifty; } else { for (i = 32; i < 64; i++) { - if (shift_set[i] == shifty) { + if (gm_shift_set[i] == shifty) { glyph = i; break; } @@ -577,7 +581,7 @@ static int gm_encode(unsigned int gbdata[], const int length, char binary[], con if ((gbdata[sp] >= '0') && (gbdata[sp] <= '9')) { numbuf[p] = gbdata[sp]; p++; - } else if (strchr(numeral_nondigits, gbdata[sp])) { + } else if (posn(numeral_nondigits, (const char) gbdata[sp]) != -1) { if (ppos != -1) { break; } @@ -701,7 +705,7 @@ static int gm_encode(unsigned int gbdata[], const int length, char binary[], con if (shift == 0) { /* Upper Case character */ - glyph = posn("ABCDEFGHIJKLMNOPQRSTUVWXYZ ", (const char) gbdata[sp]); + glyph = posn(EUROPIUM_UPR, (const char) gbdata[sp]); if (debug & ZINT_DEBUG_PRINT) { printf("[%d] ", (int) glyph); } @@ -726,7 +730,7 @@ static int gm_encode(unsigned int gbdata[], const int length, char binary[], con if (shift == 0) { /* Lower Case character */ - glyph = posn("abcdefghijklmnopqrstuvwxyz ", (const char) gbdata[sp]); + glyph = posn(EUROPIUM_LWR, (const char) gbdata[sp]); if (debug & ZINT_DEBUG_PRINT) { printf("[%d] ", (int) glyph); } diff --git a/backend/gridmtx.h b/backend/gridmtx.h index f0d58c8b..65b99a48 100644 --- a/backend/gridmtx.h +++ b/backend/gridmtx.h @@ -1,7 +1,7 @@ /* gridmtx.h - definitions for Grid Matrix libzint - the open source barcode library - Copyright (C) 2009-2017 Robin Stuart + Copyright (C) 2009-2021 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -30,9 +30,7 @@ */ /* vim: set ts=4 sw=4 et : */ -#define EUROPIUM "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz " - -static const char shift_set[] = { +static const char gm_shift_set[] = { /* From Table 7 - Encoding of control characters */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* NULL -> SI */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* DLE -> US */ diff --git a/backend/gs1.c b/backend/gs1.c index 17a18738..93eb4f54 100644 --- a/backend/gs1.c +++ b/backend/gs1.c @@ -52,7 +52,7 @@ static int numeric(const unsigned char *data, int data_len, int offset, int min, if (data_len) { const unsigned char *d = data + offset; - const unsigned char *de = d + (data_len > max ? max : data_len); + const unsigned char *const de = d + (data_len > max ? max : data_len); for (; d < de; d++) { if (*d < '0' || *d > '9') { @@ -90,7 +90,7 @@ static int cset82(const unsigned char *data, int data_len, int offset, int min, if (data_len) { const unsigned char *d = data + offset; - const unsigned char *de = d + (data_len > max ? max : data_len); + const unsigned char *const de = d + (data_len > max ? max : data_len); for (; d < de; d++) { if (*d < '!' || *d > 'z' || c82[*d - '!'] == 82) { @@ -117,7 +117,7 @@ static int cset39(const unsigned char *data, int data_len, int offset, int min, if (data_len) { const unsigned char *d = data + offset; - const unsigned char *de = d + (data_len > max ? max : data_len); + const unsigned char *const de = d + (data_len > max ? max : data_len); for (; d < de; d++) { /* 0-9, A-Z and "#", "-", "/" */ @@ -145,13 +145,13 @@ static int csum(const unsigned char *data, int data_len, int offset, int min, in if (!length_only && data_len) { const unsigned char *d = data + offset; - const unsigned char *de = d + (data_len > max ? max : data_len) - 1; /* Note less last character */ + const unsigned char *const de = d + (data_len > max ? max : data_len) - 1; /* Note less last character */ int checksum = 0; int factor = (min & 1) ? 1 : 3; for (; d < de; d++) { checksum += (*d - '0') * factor; - factor = factor == 3 ? 1 : 3; + factor ^= 2; /* Toggles 1 and 3 */ } checksum = 10 - checksum % 10; if (checksum == 10) { @@ -189,7 +189,7 @@ static int csumalpha(const unsigned char *data, int data_len, int offset, int mi 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83 }; const unsigned char *d = data + offset; - const unsigned char *de = d + (data_len > max ? max : data_len) - 2; /* Note less last 2 characters */ + const unsigned char *const de = d + (data_len > max ? max : data_len) - 2; /* Note less last 2 characters */ int checksum = 0, c1, c2; for (; d < de; d++) { @@ -549,7 +549,7 @@ static int pcenc(const unsigned char *data, int data_len, int offset, int min, i if (!length_only && data_len) { const unsigned char *d = data + offset; - const unsigned char *de = d + (data_len > max ? max : data_len); + const unsigned char *const de = d + (data_len > max ? max : data_len); for (; d < de; d++) { if (*d == '%') { @@ -746,7 +746,7 @@ static int iban(const unsigned char *data, int data_len, int offset, int min, in if (!length_only && data_len) { const unsigned char *d = data + offset; - const unsigned char *de = d + (data_len > max ? max : data_len); + const unsigned char *const de = d + (data_len > max ? max : data_len); int checksum = 0; int given_checksum; @@ -1394,7 +1394,7 @@ INTERNAL char gs1_check_digit(const unsigned char source[], const int length) { for (i = 0; i < length; i++) { count += factor * ctoi(source[i]); - factor = factor == 1 ? 3 : 1; + factor ^= 2; /* Toggles 1 and 3 */ } return itoc((10 - (count % 10)) % 10); diff --git a/backend/hanxin.c b/backend/hanxin.c index 3b7f6c25..c0adc0fb 100644 --- a/backend/hanxin.c +++ b/backend/hanxin.c @@ -474,7 +474,7 @@ static void hx_define_mode(char *mode, const unsigned int gbdata[], const int le /* Get optimal mode for each code point by tracing backwards */ for (i = length - 1, cm_i = i * HX_NUM_MODES; i >= 0; i--, cm_i -= HX_NUM_MODES) { - j = strchr(mode_types, cur_mode) - mode_types; + j = posn(mode_types, cur_mode); cur_mode = char_modes[cm_i + j]; mode[i] = cur_mode; } @@ -535,17 +535,17 @@ static void calculate_binary(char binary[], const char mode[], unsigned int sour while (i < block_length) { int first = 0; - first = posn(NEON, (char) source[position + i]); + first = ctoi((const char) source[position + i]); count = 1; encoding_value = first; if (i + 1 < block_length && mode[position + i + 1] == 'n') { - int second = posn(NEON, (char) source[position + i + 1]); + int second = ctoi((const char) source[position + i + 1]); count = 2; encoding_value = (encoding_value * 10) + second; if (i + 2 < block_length && mode[position + i + 2] == 'n') { - int third = posn(NEON, (char) source[position + i + 2]); + int third = ctoi((const char) source[position + i + 2]); count = 3; encoding_value = (encoding_value * 10) + third; } diff --git a/backend/imail.c b/backend/imail.c index be2db805..7e234614 100644 --- a/backend/imail.c +++ b/backend/imail.c @@ -38,7 +38,7 @@ #include "common.h" #include "large.h" -#define SODIUM "0123456789-" +#define SODIUM_MNS_F (IS_NUM_F | IS_MNS_F) /* SODIUM "0123456789-" */ /* The following lookup tables were generated using the code in Appendix C */ @@ -242,11 +242,11 @@ static unsigned short USPS_MSB_Math_CRC11GenerateFrameCheckSequence(unsigned cha return FrameCheckSequence; } -INTERNAL int daft_set_height(struct zint_symbol *symbol, float min_height, float max_height); +INTERNAL int daft_set_height(struct zint_symbol *symbol, const float min_height, const float max_height); INTERNAL int usps_imail(struct zint_symbol *symbol, unsigned char source[], int length) { char data_pattern[200]; - int error_number; + int error_number = 0; int i, j, read; char zip[35], tracker[35], temp[2]; large_int accum; @@ -262,10 +262,9 @@ INTERNAL int usps_imail(struct zint_symbol *symbol, unsigned char source[], int strcpy(symbol->errtxt, "450: Input too long (32 character maximum)"); return ZINT_ERROR_TOO_LONG; } - error_number = is_sane(SODIUM, source, length); - if (error_number == ZINT_ERROR_INVALID_DATA) { + if (!is_sane(SODIUM_MNS_F, source, length)) { strcpy(symbol->errtxt, "451: Invalid character in data (digits and \"-\" only)"); - return error_number; + return ZINT_ERROR_INVALID_DATA; } strcpy(zip, ""); diff --git a/backend/large.c b/backend/large.c index 9df5a1be..127dca12 100644 --- a/backend/large.c +++ b/backend/large.c @@ -57,7 +57,7 @@ /* Convert decimal string `s` of (at most) length `length` to 64-bit and place in 128-bit `t` */ INTERNAL void large_load_str_u64(large_int *t, const unsigned char *s, const int length) { uint64_t val = 0; - const unsigned char *se = s + length; + const unsigned char *const se = s + length; for (; s < se && *s >= '0' && *s <= '9'; s++) { val *= 10; val += *s - '0'; diff --git a/backend/library.c b/backend/library.c index e17bb209..e18131ea 100644 --- a/backend/library.c +++ b/backend/library.c @@ -41,8 +41,6 @@ #include "gs1.h" #include "zfiletypes.h" -#define TECHNETIUM "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%" - /* It's assumed that int is at least 32 bits, the following will compile-time fail if not * https://stackoverflow.com/a/1980056 */ typedef int static_assert_int_at_least_32bits[CHAR_BIT != 8 || sizeof(int) < 4 ? -1 : 1]; @@ -51,11 +49,9 @@ typedef int static_assert_int_at_least_32bits[CHAR_BIT != 8 || sizeof(int) < 4 ? struct zint_symbol *ZBarcode_Create() { struct zint_symbol *symbol; - symbol = (struct zint_symbol *) malloc(sizeof(*symbol)); + symbol = (struct zint_symbol *) calloc(1, sizeof(*symbol)); if (!symbol) return NULL; - memset(symbol, 0, sizeof(*symbol)); - symbol->symbology = BARCODE_CODE128; symbol->scale = 1.0f; strcpy(symbol->fgcolour, "000000"); @@ -86,14 +82,12 @@ INTERNAL void vector_free(struct zint_symbol *symbol); /* Free vector structures /* Free any output buffers that may have been created and initialize output fields */ void ZBarcode_Clear(struct zint_symbol *symbol) { - int i, j; + int i; if (!symbol) return; for (i = 0; i < symbol->rows; i++) { - for (j = 0; j < symbol->width; j++) { - unset_module(symbol, i, j); - } + memset(symbol->encoded_data[i], 0, sizeof(symbol->encoded_data[0])); } symbol->rows = 0; symbol->width = 0; @@ -209,8 +203,8 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ STATIC_UNLESS_ZINT_TEST int error_tag(struct zint_symbol *symbol, int error_number, const char *error_string) { if (error_number != 0) { - static const char *error_fmt = "Error %.93s"; /* Truncate if too long */ - static const char *warn_fmt = "Warning %.91s"; /* Truncate if too long */ + static const char error_fmt[] = "Error %.93s"; /* Truncate if too long */ + static const char warn_fmt[] = "Warning %.91s"; /* Truncate if too long */ const char *fmt = error_number >= ZINT_ERROR ? error_fmt : warn_fmt; char error_buffer[100]; @@ -291,61 +285,36 @@ static int dump_plot(struct zint_symbol *symbol) { return 0; } +static const char TECHNETIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; /* Same as SILVER (CODE39) */ + /* Process health industry bar code data */ static int hibc(struct zint_symbol *symbol, unsigned char source[], int length) { int i; int counter, error_number = 0; - char to_process[113], check_digit; + char to_process[110 + 2 + 1]; + int posns[110]; /* without "+" and check: max 110 characters in HIBC 2.6 */ if (length > 110) { strcpy(symbol->errtxt, "202: Data too long for HIBC LIC (110 character maximum)"); return ZINT_ERROR_TOO_LONG; } - to_upper(source); - if (is_sane(TECHNETIUM, source, length) != 0) { + to_upper(source, length); + if (!is_sane_lookup(TECHNETIUM, sizeof(TECHNETIUM) - 1, source, length, posns)) { strcpy(symbol->errtxt, "203: Invalid character in data (alphanumerics, space and \"-.$/+%\" only)"); return ZINT_ERROR_INVALID_DATA; } counter = 41; for (i = 0; i < length; i++) { - counter += posn(TECHNETIUM, source[i]); + counter += posns[i]; } counter = counter % 43; - if (counter < 10) { - check_digit = itoc(counter); - } else { - if (counter < 36) { - check_digit = (counter - 10) + 'A'; - } else { - switch (counter) { - case 36: check_digit = '-'; - break; - case 37: check_digit = '.'; - break; - case 38: check_digit = ' '; - break; - case 39: check_digit = '$'; - break; - case 40: check_digit = '/'; - break; - case 41: check_digit = '+'; - break; - case 42: check_digit = '%'; - break; - default: check_digit = ' '; - break; /* Keep compiler happy */ - } - } - } - to_process[0] = '+'; memcpy(to_process + 1, source, length); - to_process[length + 1] = check_digit; - length += 2; - to_process[length] = '\0'; + to_process[++length] = TECHNETIUM[counter]; + to_process[++length] = '\0'; switch (symbol->symbology) { case BARCODE_HIBC_128: @@ -538,7 +507,7 @@ static int has_hrt(const int symbology) { /* Used for dispatching barcodes and for whether symbol id valid */ typedef int (*barcode_func_t)(struct zint_symbol *, unsigned char *, int); -static const barcode_func_t barcode_funcs[146] = { +static const barcode_func_t barcode_funcs[BARCODE_LAST + 1] = { NULL, code11, c25standard, c25inter, c25iata, /*0-4*/ NULL, c25logic, c25ind, code39, excode39, /*5-9*/ NULL, NULL, NULL, eanx, eanx, /*10-14*/ @@ -895,7 +864,7 @@ int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int symbol->symbology = BARCODE_CODE128; } /* Everything from 128 up is Zint-specific */ - } else if (symbol->symbology > 145) { + } else if (symbol->symbology > BARCODE_LAST) { warn_number = error_tag(symbol, ZINT_WARN_INVALID_OPTION, "216: Symbology out of range"); if (warn_number >= ZINT_ERROR) { return warn_number; @@ -1033,10 +1002,8 @@ int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int return error_number; } -/* Output a previously encoded symbol to file `symbol->outfile` */ -int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) { - int error_number; - int len; +/* Helper for output routines to check `rotate_angle` and dottiness */ +static int check_output_args(struct zint_symbol *symbol, int rotate_angle) { if (!symbol) return ZINT_ERROR_INVALID_DATA; @@ -1051,10 +1018,20 @@ int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) { break; } - if (symbol->output_options & BARCODE_DOTTY_MODE) { - if (!(is_dotty(symbol->symbology))) { - return error_tag(symbol, ZINT_ERROR_INVALID_OPTION, "224: Selected symbology cannot be rendered as dots"); - } + if ((symbol->output_options & BARCODE_DOTTY_MODE) && !(is_dotty(symbol->symbology))) { + return error_tag(symbol, ZINT_ERROR_INVALID_OPTION, "224: Selected symbology cannot be rendered as dots"); + } + + return 0; +} + +/* Output a previously encoded symbol to file `symbol->outfile` */ +int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) { + int error_number; + int len; + + if ((error_number = check_output_args(symbol, rotate_angle))) { /* >= ZINT_ERROR only */ + return error_number; /* Already tagged */ } len = (int) strlen(symbol->outfile); @@ -1064,7 +1041,7 @@ int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) { output[1] = symbol->outfile[len - 2]; output[2] = symbol->outfile[len - 1]; output[3] = '\0'; - to_upper((unsigned char *) output); + to_upper((unsigned char *) output, 3); if (!(strcmp(output, "PNG"))) { error_number = plot_raster(symbol, rotate_angle, OUT_PNG_FILE); @@ -1107,23 +1084,8 @@ int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) { int ZBarcode_Buffer(struct zint_symbol *symbol, int rotate_angle) { int error_number; - if (!symbol) return ZINT_ERROR_INVALID_DATA; - - switch (rotate_angle) { - case 0: - case 90: - case 180: - case 270: - break; - default: - return error_tag(symbol, ZINT_ERROR_INVALID_OPTION, "228: Invalid rotation angle"); - break; - } - - if (symbol->output_options & BARCODE_DOTTY_MODE) { - if (!(is_dotty(symbol->symbology))) { - return error_tag(symbol, ZINT_ERROR_INVALID_OPTION, "237: Selected symbology cannot be rendered as dots"); - } + if ((error_number = check_output_args(symbol, rotate_angle))) { /* >= ZINT_ERROR only */ + return error_number; /* Already tagged */ } error_number = plot_raster(symbol, rotate_angle, OUT_BUFFER); @@ -1134,23 +1096,8 @@ int ZBarcode_Buffer(struct zint_symbol *symbol, int rotate_angle) { int ZBarcode_Buffer_Vector(struct zint_symbol *symbol, int rotate_angle) { int error_number; - if (!symbol) return ZINT_ERROR_INVALID_DATA; - - switch (rotate_angle) { - case 0: - case 90: - case 180: - case 270: - break; - default: - return error_tag(symbol, ZINT_ERROR_INVALID_OPTION, "219: Invalid rotation angle"); - break; - } - - if (symbol->output_options & BARCODE_DOTTY_MODE) { - if (!(is_dotty(symbol->symbology))) { - return error_tag(symbol, ZINT_ERROR_INVALID_OPTION, "238: Selected symbology cannot be rendered as dots"); - } + if ((error_number = check_output_args(symbol, rotate_angle))) { /* >= ZINT_ERROR only */ + return error_number; /* Already tagged */ } error_number = plot_vector(symbol, rotate_angle, OUT_BUFFER); @@ -1350,7 +1297,7 @@ int ZBarcode_Encode_File_and_Buffer_Vector(struct zint_symbol *symbol, const cha /* Checks whether a symbology is supported */ int ZBarcode_ValidID(int symbol_id) { - if (symbol_id <= 0 || symbol_id > 145) { + if (symbol_id <= 0 || symbol_id > BARCODE_LAST) { return 0; } @@ -1387,7 +1334,7 @@ unsigned int ZBarcode_Cap(int symbol_id, unsigned int cap_flag) { result |= ZINT_CAP_DOTTY; } if (cap_flag & ZINT_CAP_QUIET_ZONES) { - switch (symbol_id) { /* See `quiet_zones()` in "output.c" */ + switch (symbol_id) { /* See `out_quiet_zones()` in "output.c" */ case BARCODE_CODE16K: case BARCODE_CODE49: case BARCODE_CODABLOCKF: diff --git a/backend/mailmark.c b/backend/mailmark.c index 79a92610..f80fb1e1 100644 --- a/backend/mailmark.c +++ b/backend/mailmark.c @@ -49,7 +49,7 @@ #include "large.h" #include "reedsol.h" -#define RUBIDIUM "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ " +#define RUBIDIUM_F (IS_NUM_F | IS_UPR_F | IS_SPC_F) /* RUBIDIUM "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ " */ // Allowed character values from Table 3 #define SET_F "ABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -57,8 +57,10 @@ #define SET_N "0123456789" #define SET_S " " -static const char *postcode_format[6] = { - "FNFNLLNLS", "FFNNLLNLS", "FFNNNLLNL", "FFNFNLLNL", "FNNLLNLSS", "FNNNLLNLS" +static const char postcode_format[6][9] = { + {'F','N','F','N','L','L','N','L','S'}, {'F','F','N','N','L','L','N','L','S'}, + {'F','F','N','N','N','L','L','N','L'}, {'F','F','N','F','N','L','L','N','L'}, + {'F','N','N','L','L','N','L','S','S'}, {'F','N','N','N','L','L','N','L','S'} }; // Data/Check Symbols from Table 5 @@ -109,9 +111,7 @@ static int verify_character(char input, char type) { static int verify_postcode(char *postcode, int type) { int i; - char pattern[11]; - - strcpy(pattern, postcode_format[type - 1]); + const char *const pattern = postcode_format[type - 1]; for (i = 0; i < 9; i++) { if (!(verify_character(postcode[i], pattern[i]))) { @@ -122,7 +122,7 @@ static int verify_postcode(char *postcode, int type) { return 0; } -INTERNAL int daft_set_height(struct zint_symbol *symbol, float min_height, float max_height); +INTERNAL int daft_set_height(struct zint_symbol *symbol, const float min_height, const float max_height); /* Royal Mail Mailmark */ INTERNAL int mailmark(struct zint_symbol *symbol, unsigned char source[], int length) { @@ -135,7 +135,7 @@ INTERNAL int mailmark(struct zint_symbol *symbol, unsigned char source[], int le unsigned int item_id; char postcode[10]; int postcode_type; - char pattern[10]; + const char *pattern; large_int destination_postcode; large_int b; large_int cdv; @@ -144,6 +144,7 @@ INTERNAL int mailmark(struct zint_symbol *symbol, unsigned char source[], int le unsigned char check[7]; unsigned int extender[27]; char bar[80]; + char *d = bar; int check_count; int i, j, len; rs_t rs; @@ -170,13 +171,13 @@ INTERNAL int mailmark(struct zint_symbol *symbol, unsigned char source[], int le length = 26; } - to_upper((unsigned char *) local_source); + to_upper((unsigned char *) local_source, length); if (symbol->debug & ZINT_DEBUG_PRINT) { printf("Producing Mailmark %s\n", local_source); } - if (is_sane(RUBIDIUM, (unsigned char *) local_source, length) != 0) { + if (!is_sane(RUBIDIUM_F, (unsigned char *) local_source, length)) { strcpy(symbol->errtxt, "581: Invalid character in data (alphanumerics and space only)"); return ZINT_ERROR_INVALID_DATA; } @@ -285,7 +286,7 @@ INTERNAL int mailmark(struct zint_symbol *symbol, unsigned char source[], int le large_load_u64(&destination_postcode, 0); if (postcode_type != 7) { - strcpy(pattern, postcode_format[postcode_type - 1]); + pattern = postcode_format[postcode_type - 1]; large_load_u64(&b, 0); @@ -440,45 +441,42 @@ INTERNAL int mailmark(struct zint_symbol *symbol, unsigned char source[], int le } // Conversion from Extender Groups to Bar Identifiers - strcpy(bar, ""); for (i = 0; i < length; i++) { for (j = 0; j < 3; j++) { switch (extender[i] & 0x24) { case 0x24: - strcat(bar, "F"); + *d++ = 'F'; break; case 0x20: if (i % 2) { - strcat(bar, "D"); + *d++ = 'D'; } else { - strcat(bar, "A"); + *d++ = 'A'; } break; case 0x04: if (i % 2) { - strcat(bar, "A"); + *d++ = 'A'; } else { - strcat(bar, "D"); + *d++ = 'D'; } break; default: - strcat(bar, "T"); + *d++ = 'T'; break; } extender[i] = extender[i] << 1; } } - bar[(length * 3)] = '\0'; - if (symbol->debug & ZINT_DEBUG_PRINT) { - printf("Bar pattern: %s\n", bar); + printf("Bar pattern: %.*s\n", (int) (d - bar), bar); } /* Translate 4-state data pattern to symbol */ j = 0; - for (i = 0, len = (int) strlen(bar); i < len; i++) { + for (i = 0, len = d - bar; i < len; i++) { if ((bar[i] == 'F') || (bar[i] == 'A')) { set_module(symbol, 0, j); } diff --git a/backend/maxicode.c b/backend/maxicode.c index 5e4a28a7..94034278 100644 --- a/backend/maxicode.c +++ b/backend/maxicode.c @@ -612,7 +612,7 @@ INTERNAL int maxicode(struct zint_symbol *symbol, unsigned char source[], int le postcode[i] = ' '; } /* Upper-case and check for Code Set A characters only */ - to_upper(postcode); + to_upper(postcode, postcode_len); for (i = 0; i < 6; i++) { /* Don't allow Code Set A control characters CR, RS, GS and RS */ if (postcode[i] < ' ' || maxiCodeSet[postcode[i]] > 1) { diff --git a/backend/medical.c b/backend/medical.c index a488c7d6..b2477ba9 100644 --- a/backend/medical.c +++ b/backend/medical.c @@ -36,15 +36,18 @@ 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 */ - -#define CALCIUM "0123456789-$:/.+ABCD" -#define CALCIUM_INNER "0123456789-$:/.+" - -static const char *CodaTable[20] = { - "11111221", "11112211", "11121121", "22111111", "11211211", "21111211", - "12111121", "12112111", "12211111", "21121111", "11122111", "11221111", "21112121", "21211121", - "21212111", "11212121", "11221211", "12121121", "11121221", "11122211" +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'} }; INTERNAL int pharma(struct zint_symbol *symbol, unsigned char source[], int length) { @@ -61,22 +64,23 @@ INTERNAL int pharma(struct zint_symbol *symbol, unsigned char source[], int leng the specification at http://www.laetus.com/laetus.php?request=file&id=69 (http://www.gomaro.ch/ftproot/Laetus_PHARMA-CODE.pdf) */ - unsigned long int tester; + int tester; int counter, error_number = 0, h; char inter[18] = {0}; /* 131070 -> 17 bits */ + char *in = inter; char dest[64]; /* 17 * 2 + 1 */ + char *d = dest; if (length > 6) { strcpy(symbol->errtxt, "350: Input too long (6 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + tester = to_int(source, length); + if (tester == -1) { strcpy(symbol->errtxt, "351: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } - tester = atoi((char *) source); - if ((tester < 3) || (tester > 131070)) { strcpy(symbol->errtxt, "352: Data out of range (3 to 131070)"); return ZINT_ERROR_INVALID_DATA; @@ -84,25 +88,22 @@ INTERNAL int pharma(struct zint_symbol *symbol, unsigned char source[], int leng do { if (!(tester & 1)) { - strcat(inter, "W"); + *in++ = 'W'; tester = (tester - 2) / 2; } else { - strcat(inter, "N"); + *in++ = 'N'; tester = (tester - 1) / 2; } } while (tester != 0); - h = (int) strlen(inter) - 1; - *dest = '\0'; - for (counter = h; counter >= 0; counter--) { - if (inter[counter] == 'W') { - strcat(dest, "32"); - } else { - strcat(dest, "12"); - } + h = in - inter; + for (counter = h - 1; counter >= 0; counter--) { + *d++ = inter[counter] == 'W' ? '3' : '1'; + *d++ = '2'; } + *--d = '\0'; /* Chop off final bar */ - expand(symbol, dest); + expand(symbol, dest, d - dest); if (symbol->output_options & COMPLIANT_HEIGHT) { /* Laetus Pharmacode Guide 1.2 Standard one-track height 8mm / 0.5mm (X) */ @@ -114,75 +115,66 @@ INTERNAL int pharma(struct zint_symbol *symbol, unsigned char source[], int leng return error_number; } -static int pharma_two_calc(struct zint_symbol *symbol, unsigned char source[], char dest[]) { +static int pharma_two_calc(int tester, char *d) { /* This code uses the Two Track Pharamacode defined in the document at http://www.laetus.com/laetus.php?request=file&id=69 and using a modified algorithm from the One Track system. This standard accepts integet values from 4 to 64570080. */ - unsigned long int tester; int counter, h; char inter[17]; - int error_number; + char *in = inter; - tester = atoi((char *) source); - - if ((tester < 4) || (tester > 64570080)) { - strcpy(symbol->errtxt, "353: Data out of range (4 to 64570080)"); - return ZINT_ERROR_INVALID_DATA; - } - error_number = 0; - strcpy(inter, ""); do { switch (tester % 3) { case 0: - strcat(inter, "3"); + *in++ = '3'; tester = (tester - 3) / 3; break; case 1: - strcat(inter, "1"); + *in++ = '1'; tester = (tester - 1) / 3; break; case 2: - strcat(inter, "2"); + *in++ = '2'; tester = (tester - 2) / 3; break; } } while (tester != 0); - h = (int) strlen(inter) - 1; - for (counter = h; counter >= 0; counter--) { - dest[h - counter] = inter[counter]; + h = in - inter; + for (counter = h - 1; counter >= 0; counter--) { + *d++ = inter[counter]; } - dest[h + 1] = '\0'; + *d = '\0'; - return error_number; + return h; } INTERNAL int pharma_two(struct zint_symbol *symbol, unsigned char source[], int length) { /* Draws the patterns for two track pharmacode */ + int tester; char height_pattern[200]; unsigned int loopey, h; int writer; - int error_number; - - strcpy(height_pattern, ""); + int error_number = 0; if (length > 8) { strcpy(symbol->errtxt, "354: Input too long (8 character maximum"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + tester = to_int(source, length); + if (tester == -1) { strcpy(symbol->errtxt, "355: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } - error_number = pharma_two_calc(symbol, source, height_pattern); - if (error_number != 0) { - return error_number; + if ((tester < 4) || (tester > 64570080)) { + strcpy(symbol->errtxt, "353: Data out of range (4 to 64570080)"); + return ZINT_ERROR_INVALID_DATA; } + h = pharma_two_calc(tester, height_pattern); writer = 0; - h = (int) strlen(height_pattern); for (loopey = 0; loopey < h; loopey++) { if ((height_pattern[loopey] == '2') || (height_pattern[loopey] == '3')) { set_module(symbol, 0, writer); @@ -209,14 +201,13 @@ INTERNAL int pharma_two(struct zint_symbol *symbol, unsigned char source[], int /* The Codabar system consisting of simple substitution */ INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int length) { - static const char calcium[] = CALCIUM; int i, error_number = 0; + int posns[60]; char dest[512]; + char *d = dest; int add_checksum, count = 0, checksum = 0; int d_chars = 0; - strcpy(dest, ""); - if (length > 60) { /* No stack smashing please */ strcpy(symbol->errtxt, "356: Input too long (60 character maximum)"); return ZINT_ERROR_TOO_LONG; @@ -227,7 +218,7 @@ INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int len strcpy(symbol->errtxt, "362: Input too short (3 character minimum)"); return ZINT_ERROR_TOO_LONG; } - to_upper(source); + 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') @@ -240,14 +231,13 @@ INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int len strcpy(symbol->errtxt, "359: Does not end with \"A\", \"B\", \"C\" or \"D\""); return ZINT_ERROR_INVALID_DATA; } - + if (!is_sane_lookup(CALCIUM, sizeof(CALCIUM) - 1, source, length, posns)) { + sprintf(symbol->errtxt, "357: Invalid character in data (\"%s\" only)", CALCIUM); + return ZINT_ERROR_INVALID_DATA; + } /* And must not use A, B, C or D otherwise (BS EN 798:1995 4.3.2) */ - if (is_sane(CALCIUM_INNER, source + 1, length - 2) != 0) { - if (is_sane(calcium, source + 1, length - 2) == 0) { - strcpy(symbol->errtxt, "363: Cannot contain \"A\", \"B\", \"C\" or \"D\""); - } else { - sprintf(symbol->errtxt, "357: Invalid character in data (\"%s\" only)", calcium); - } + if (!is_sane(CALCIUM_INNER_F, source + 1, length - 2)) { + strcpy(symbol->errtxt, "363: Cannot contain \"A\", \"B\", \"C\" or \"D\""); return ZINT_ERROR_INVALID_DATA; } @@ -255,29 +245,30 @@ INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int len (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++) { + 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 += strchr(calcium, source[i]) - calcium; + 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]); + printf("Codabar: %s, count %d, checksum %d (%c)\n", source, count, checksum, CALCIUM[checksum]); } - strcat(dest, CodaTable[checksum]); + memcpy(d, CodaTable[checksum], 8); + d += 8; } } - lookup(calcium, CodaTable, source[i], dest); + memcpy(d, CodaTable[posns[i]], 8); if (source[i] == '/' || source[i] == ':' || source[i] == '.' || source[i] == '+') { /* Wide data characters */ d_chars++; } } - expand(symbol, dest); + expand(symbol, dest, d - dest); if (symbol->output_options & COMPLIANT_HEIGHT) { /* BS EN 798:1995 4.4.1 (d) max of 5mm / 0.191mm (X) ~ 26.178 or 15% of width where (taking N = narrow/wide @@ -297,7 +288,7 @@ INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int len 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 - 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'; } @@ -307,18 +298,18 @@ INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int len /* Italian Pharmacode */ INTERNAL int code32(struct zint_symbol *symbol, unsigned char source[], int length) { + static const char TABELLA[] = "0123456789BCDFGHJKLMNPQRSTUVWXYZ"; int i, zeroes, error_number = 0, checksum, checkpart, checkdigit; char localstr[10], risultante[7]; long int pharmacode, devisor; int codeword[6]; - char tabella[34]; /* Validate the input */ if (length > 8) { strcpy(symbol->errtxt, "360: Input too long (8 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "361: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -360,13 +351,12 @@ INTERNAL int code32(struct zint_symbol *symbol, unsigned char source[], int leng } /* Look up values in 'Tabella di conversione' */ - strcpy(tabella, "0123456789BCDFGHJKLMNPQRSTUVWXYZ"); for (i = 5; i >= 0; i--) { - risultante[5 - i] = tabella[codeword[i]]; + risultante[5 - i] = TABELLA[codeword[i]]; } risultante[6] = '\0'; /* Plot the barcode using Code 39 */ - error_number = code39(symbol, (unsigned char *) risultante, (int) strlen(risultante)); + error_number = code39(symbol, (unsigned char *) risultante, 6); if (error_number != 0) { /* Should never happen */ return error_number; /* Not reached */ } diff --git a/backend/output.c b/backend/output.c index b0a563cb..19e8922f 100644 --- a/backend/output.c +++ b/backend/output.c @@ -35,32 +35,31 @@ #include "output.h" #include "font.h" -#define SSET "0123456789ABCDEF" +#define SSET_F (IS_NUM_F | IS_UHX_F) /* SSET "0123456789ABCDEF" */ /* Check colour options are good. Note: using raster.c error nos 651-654 */ -INTERNAL int output_check_colour_options(struct zint_symbol *symbol) { - int error_number; +INTERNAL int out_check_colour_options(struct zint_symbol *symbol) { + int fg_len = (int) strlen(symbol->fgcolour); + int bg_len = (int) strlen(symbol->bgcolour); - if ((strlen(symbol->fgcolour) != 6) && (strlen(symbol->fgcolour) != 8)) { + if ((fg_len != 6) && (fg_len != 8)) { strcpy(symbol->errtxt, "651: Malformed foreground colour target"); return ZINT_ERROR_INVALID_OPTION; } - if ((strlen(symbol->bgcolour) != 6) && (strlen(symbol->bgcolour) != 8)) { + if ((bg_len != 6) && (bg_len != 8)) { strcpy(symbol->errtxt, "652: Malformed background colour target"); return ZINT_ERROR_INVALID_OPTION; } - to_upper((unsigned char *) symbol->fgcolour); - to_upper((unsigned char *) symbol->bgcolour); + to_upper((unsigned char *) symbol->fgcolour, fg_len); + to_upper((unsigned char *) symbol->bgcolour, bg_len); - error_number = is_sane(SSET, (unsigned char *) symbol->fgcolour, (int) strlen(symbol->fgcolour)); - if (error_number == ZINT_ERROR_INVALID_DATA) { + if (!is_sane(SSET_F, (unsigned char *) symbol->fgcolour, fg_len)) { strcpy(symbol->errtxt, "653: Malformed foreground colour target"); return ZINT_ERROR_INVALID_OPTION; } - error_number = is_sane(SSET, (unsigned char *) symbol->bgcolour, (int) strlen(symbol->bgcolour)); - if (error_number == ZINT_ERROR_INVALID_DATA) { + if (!is_sane(SSET_F, (unsigned char *) symbol->bgcolour, bg_len)) { strcpy(symbol->errtxt, "654: Malformed background colour target"); return ZINT_ERROR_INVALID_OPTION; } @@ -69,7 +68,7 @@ INTERNAL int output_check_colour_options(struct zint_symbol *symbol) { } /* Return minimum quiet zones for each symbology */ -STATIC_UNLESS_ZINT_TEST int quiet_zones(const struct zint_symbol *symbol, const int hide_text, +STATIC_UNLESS_ZINT_TEST int out_quiet_zones(const struct zint_symbol *symbol, const int hide_text, float *left, float *right, float *top, float *bottom) { int done = 0; @@ -192,7 +191,7 @@ STATIC_UNLESS_ZINT_TEST int quiet_zones(const struct zint_symbol *symbol, const /* Only do others if flag set */ if (!(symbol->output_options & BARCODE_QUIET_ZONES) || (symbol->output_options & BARCODE_NO_QUIET_ZONES)) { - return done; + return 0; } switch (symbol->symbology) { @@ -471,12 +470,12 @@ STATIC_UNLESS_ZINT_TEST int quiet_zones(const struct zint_symbol *symbol, const } /* Set left (x), top (y), right and bottom offsets for whitespace */ -INTERNAL void output_set_whitespace_offsets(const struct zint_symbol *symbol, const int hide_text, +INTERNAL void out_set_whitespace_offsets(const struct zint_symbol *symbol, const int hide_text, float *xoffset, float *yoffset, float *roffset, float *boffset, const float scaler, int *xoffset_si, int *yoffset_si, int *roffset_si, int *boffset_si) { float qz_left, qz_right, qz_top, qz_bottom; - quiet_zones(symbol, hide_text, &qz_left, &qz_right, &qz_top, &qz_bottom); + out_quiet_zones(symbol, hide_text, &qz_left, &qz_right, &qz_top, &qz_bottom); *xoffset = symbol->whitespace_width + qz_left; *roffset = symbol->whitespace_width + qz_right; @@ -510,7 +509,7 @@ INTERNAL void output_set_whitespace_offsets(const struct zint_symbol *symbol, co /* Set composite offset and main width excluding addon (for start of addon calc) and addon text, returning UPC/EAN type */ -INTERNAL int output_process_upcean(const struct zint_symbol *symbol, int *p_main_width, int *p_comp_xoffset, +INTERNAL int out_process_upcean(const struct zint_symbol *symbol, int *p_main_width, int *p_comp_xoffset, unsigned char addon[6], int *p_addon_gap) { int main_width; /* Width of main linear symbol, excluding addon */ int comp_xoffset; /* Whitespace offset (if any) of main linear symbol due to having composite */ @@ -588,9 +587,9 @@ INTERNAL int output_process_upcean(const struct zint_symbol *symbol, int *p_main } /* Calculate large bar height i.e. linear bars with zero row height that respond to the symbol height. - If scaler `si` non-zero (raster), then large_bar_height if non-zero or else row heights will be rounded to nearest - pixel and symbol height adjusted */ -INTERNAL float output_large_bar_height(struct zint_symbol *symbol, int si) { + If scaler `si` non-zero (raster), then large_bar_height if non-zero or else row heights will be rounded + to nearest pixel and symbol height adjusted */ +INTERNAL float out_large_bar_height(struct zint_symbol *symbol, int si) { float fixed_height = 0.0f; int zero_count = 0; int round_rows = 0; @@ -609,15 +608,14 @@ INTERNAL float output_large_bar_height(struct zint_symbol *symbol, int si) { } if (zero_count) { - large_bar_height = (symbol->height - fixed_height) / zero_count; + large_bar_height = stripf((symbol->height - fixed_height) / zero_count); if (large_bar_height <= 0.0f) { /* Shouldn't happen but protect against memory access violations */ large_bar_height = 0.0078125f; /* Token positive value (exact float 2**-6) */ - symbol->height = large_bar_height * zero_count + fixed_height; } if (si && !isfintf(large_bar_height * si)) { - large_bar_height = roundf(large_bar_height * si) / si; - symbol->height = large_bar_height * zero_count + fixed_height; + large_bar_height = stripf(roundf(large_bar_height * si) / si); } + symbol->height = stripf(large_bar_height * zero_count + fixed_height); /* Note should never happen that have both zero_count and round_rows */ } else { large_bar_height = 0.0f; /* Not used if zero_count zero */ @@ -629,7 +627,7 @@ INTERNAL float output_large_bar_height(struct zint_symbol *symbol, int si) { } fixed_height += symbol->row_height[i]; } - symbol->height = fixed_height; + symbol->height = stripf(fixed_height); } } @@ -637,7 +635,7 @@ INTERNAL float output_large_bar_height(struct zint_symbol *symbol, int si) { } /* Split UPC/EAN add-on text into various constituents */ -INTERNAL void output_upcean_split_text(int upceanflag, unsigned char text[], +INTERNAL void out_upcean_split_text(int upceanflag, unsigned char text[], unsigned char textpart1[5], unsigned char textpart2[7], unsigned char textpart3[7], unsigned char textpart4[2]) { int i; diff --git a/backend/output.h b/backend/output.h index fadaf1d2..99da9e5f 100644 --- a/backend/output.h +++ b/backend/output.h @@ -37,14 +37,14 @@ extern "C" { #endif /* __cplusplus */ -INTERNAL int output_check_colour_options(struct zint_symbol *symbol); -INTERNAL void output_set_whitespace_offsets(const struct zint_symbol *symbol, const int hide_text, +INTERNAL int out_check_colour_options(struct zint_symbol *symbol); +INTERNAL void out_set_whitespace_offsets(const struct zint_symbol *symbol, const int hide_text, float *xoffset, float *yoffset, float *roffset, float *boffset, const float scaler, int *xoffset_si, int *yoffset_si, int *roffset_si, int *boffset_si); -INTERNAL int output_process_upcean(const struct zint_symbol *symbol, int *p_main_width, int *p_comp_xoffset, +INTERNAL int out_process_upcean(const struct zint_symbol *symbol, int *p_main_width, int *p_comp_xoffset, unsigned char addon[6], int *p_addon_gap); -INTERNAL float output_large_bar_height(struct zint_symbol *symbol, int si); -INTERNAL void output_upcean_split_text(int upceanflag, unsigned char text[], +INTERNAL float out_large_bar_height(struct zint_symbol *symbol, int si); +INTERNAL void out_upcean_split_text(int upceanflag, unsigned char text[], unsigned char textpart1[5], unsigned char textpart2[7], unsigned char textpart3[7], unsigned char textpart4[2]); diff --git a/backend/plessey.c b/backend/plessey.c index 70322c8d..4471ea0e 100644 --- a/backend/plessey.c +++ b/backend/plessey.c @@ -34,50 +34,51 @@ #include #include "common.h" -#define SSET "0123456789ABCDEF" +#define SSET_F (IS_NUM_F | IS_UHX_F) /* SSET "0123456789ABCDEF" */ -static const char *PlessTable[16] = { - "13131313", "31131313", "13311313", "31311313", - "13133113", "31133113", "13313113", "31313113", - "13131331", "31131331", "13311331", "31311331", - "13133131", "31133131", "13313131", "31313131" +static const char PlessTable[16][8] = { + {'1','3','1','3','1','3','1','3'}, {'3','1','1','3','1','3','1','3'}, {'1','3','3','1','1','3','1','3'}, + {'3','1','3','1','1','3','1','3'}, {'1','3','1','3','3','1','1','3'}, {'3','1','1','3','3','1','1','3'}, + {'1','3','3','1','3','1','1','3'}, {'3','1','3','1','3','1','1','3'}, {'1','3','1','3','1','3','3','1'}, + {'3','1','1','3','1','3','3','1'}, {'1','3','3','1','1','3','3','1'}, {'3','1','3','1','1','3','3','1'}, + {'1','3','1','3','3','1','3','1'}, {'3','1','1','3','3','1','3','1'}, {'1','3','3','1','3','1','3','1'}, + {'3','1','3','1','3','1','3','1'} }; -static const char *MSITable[10] = { - "12121212", "12121221", "12122112", "12122121", "12211212", - "12211221", "12212112", "12212121", "21121212", "21121221" +static const char MSITable[10][8] = { + {'1','2','1','2','1','2','1','2'}, {'1','2','1','2','1','2','2','1'}, {'1','2','1','2','2','1','1','2'}, + {'1','2','1','2','2','1','2','1'}, {'1','2','2','1','1','2','1','2'}, {'1','2','2','1','1','2','2','1'}, + {'1','2','2','1','2','1','1','2'}, {'1','2','2','1','2','1','2','1'}, {'2','1','1','2','1','2','1','2'}, + {'2','1','1','2','1','2','2','1'} }; /* Not MSI/Plessey but the older Plessey standard */ INTERNAL int plessey(struct zint_symbol *symbol, unsigned char source[], int length) { int i; - unsigned char *checkptr; + unsigned char checkptr[65 * 4 + 8] = {0}; static const char grid[9] = {1, 1, 1, 1, 0, 1, 0, 0, 1}; char dest[554]; /* 8 + 65 * 8 + 8 * 2 + 9 + 1 = 554 */ + char *d = dest; int error_number = 0; if (length > 65) { strcpy(symbol->errtxt, "370: Input too long (65 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(SSET, source, length) != 0) { + if (!is_sane(SSET_F, source, length)) { strcpy(symbol->errtxt, "371: Invalid character in data (digits and \"ABCDEF\" only)"); return ZINT_ERROR_INVALID_DATA; } - if (!(checkptr = (unsigned char *) calloc(1, length * 4 + 8))) { - strcpy(symbol->errtxt, "373: Insufficient memory for check digit CRC buffer"); - return ZINT_ERROR_MEMORY; - } - /* Start character */ - strcpy(dest, "31311331"); + memcpy(d, "31311331", 8); + d += 8; /* Data area */ - for (i = 0; i < length; i++) { - unsigned int check = posn(SSET, source[i]); - lookup(SSET, PlessTable, source[i], dest); + for (i = 0; i < length; i++, d += 8) { + unsigned int check = source[i] - '0' - (source[i] >> 6) * 7; + memcpy(d, PlessTable[check], 8); checkptr[4 * i] = check & 1; checkptr[4 * i + 1] = (check >> 1) & 1; checkptr[4 * i + 2] = (check >> 2) & 1; @@ -97,24 +98,26 @@ INTERNAL int plessey(struct zint_symbol *symbol, unsigned char source[], int len for (i = 0; i < 8; i++) { switch (checkptr[length * 4 + i]) { - case 0: strcat(dest, "13"); + case 0: memcpy(d, "13", 2); + d += 2; break; - case 1: strcat(dest, "31"); + case 1: memcpy(d, "31", 2); + d += 2; break; } } /* Stop character */ - strcat(dest, "331311313"); + memcpy(d, "331311313", 9); + d += 9; - expand(symbol, dest); + expand(symbol, dest, d - dest); // TODO: Find documentation on BARCODE_PLESSEY dimensions/height symbol->text[0] = '\0'; ustrncat(symbol->text, source, length); - free(checkptr); return error_number; } @@ -154,35 +157,38 @@ static char msi_check_digit_mod11(const unsigned char source[], const int length } /* Plain MSI Plessey - does not calculate any check character */ -static void msi_plessey_nomod(struct zint_symbol *symbol, const unsigned char source[], const int length, - char dest[]) { +static char *msi_plessey_nomod(struct zint_symbol *symbol, const unsigned char source[], const int length, + char *d) { int i; - for (i = 0; i < length; i++) { - lookup(NEON, MSITable, source[i], dest); + for (i = 0; i < length; i++, d += 8) { + memcpy(d, MSITable[source[i] - '0'], 8); } symbol->text[0] = '\0'; ustrncat(symbol->text, source, length); + + return d; } /* MSI Plessey with Modulo 10 check digit */ -static void msi_plessey_mod10(struct zint_symbol *symbol, const unsigned char source[], const int length, - const int no_checktext, char dest[]) { +static char *msi_plessey_mod10(struct zint_symbol *symbol, const unsigned char source[], const int length, + const int no_checktext, char *d) { int i; char check_digit; /* draw data section */ - for (i = 0; i < length; i++) { - lookup(NEON, MSITable, source[i], dest); + for (i = 0; i < length; i++, d += 8) { + memcpy(d, MSITable[source[i] - '0'], 8); } /* calculate check digit */ check_digit = msi_check_digit_mod10(source, length); /* draw check digit */ - lookup(NEON, MSITable, check_digit, dest); + memcpy(d, MSITable[check_digit - '0'], 8); + d += 8; symbol->text[0] = '\0'; ustrncat(symbol->text, source, length); @@ -190,11 +196,13 @@ static void msi_plessey_mod10(struct zint_symbol *symbol, const unsigned char so symbol->text[length] = check_digit; symbol->text[length + 1] = '\0'; } + + return d; } /* MSI Plessey with two Modulo 10 check digits */ -static void msi_plessey_mod1010(struct zint_symbol *symbol, const unsigned char source[], const int length, - const int no_checktext, char dest[]) { +static char *msi_plessey_mod1010(struct zint_symbol *symbol, const unsigned char source[], const int length, + const int no_checktext, char *d) { int i; unsigned char temp[65 + 2 + 1]; @@ -207,8 +215,8 @@ static void msi_plessey_mod1010(struct zint_symbol *symbol, const unsigned char temp[length + 2] = '\0'; /* draw data section */ - for (i = 0; i < length + 2; i++) { - lookup(NEON, MSITable, temp[i], dest); + for (i = 0; i < length + 2; i++, d += 8) { + memcpy(d, MSITable[temp[i] - '0'], 8); } if (no_checktext) { @@ -217,27 +225,32 @@ static void msi_plessey_mod1010(struct zint_symbol *symbol, const unsigned char } else { ustrcpy(symbol->text, temp); } + + return d; } /* MSI Plessey with Modulo 11 check digit */ -static void msi_plessey_mod11(struct zint_symbol *symbol, const unsigned char source[], const int length, - const int no_checktext, const int wrap, char dest[]) { +static char *msi_plessey_mod11(struct zint_symbol *symbol, const unsigned char source[], const int length, + const int no_checktext, const int wrap, char *d) { /* Uses the IBM weight system if wrap = 7, and the NCR system if wrap = 9 */ int i; char check_digit; /* draw data section */ - for (i = 0; i < length; i++) { - lookup(NEON, MSITable, source[i], dest); + for (i = 0; i < length; i++, d += 8) { + memcpy(d, MSITable[source[i] - '0'], 8); } /* Append check digit */ check_digit = msi_check_digit_mod11(source, length, wrap); if (check_digit == 'A') { - lookup(NEON, MSITable, '1', dest); - lookup(NEON, MSITable, '0', dest); + memcpy(d, MSITable[1], 8); + d += 8; + memcpy(d, MSITable[0], 8); + d += 8; } else { - lookup(NEON, MSITable, check_digit, dest); + memcpy(d, MSITable[check_digit - '0'], 8); + d += 8; } symbol->text[0] = '\0'; @@ -250,11 +263,13 @@ static void msi_plessey_mod11(struct zint_symbol *symbol, const unsigned char so symbol->text[length + 1] = '\0'; } } + + return d; } /* MSI Plessey with Modulo 11 check digit and Modulo 10 check digit */ -static void msi_plessey_mod1110(struct zint_symbol *symbol, const unsigned char source[], const int length, - const int no_checktext, const int wrap, char dest[]) { +static char *msi_plessey_mod1110(struct zint_symbol *symbol, const unsigned char source[], const int length, + const int no_checktext, const int wrap, char *d) { /* Uses the IBM weight system if wrap = 7, and the NCR system if wrap = 9 */ int i; char check_digit; @@ -278,8 +293,8 @@ static void msi_plessey_mod1110(struct zint_symbol *symbol, const unsigned char temp[++temp_len] = '\0'; /* draw data section */ - for (i = 0; i < temp_len; i++) { - lookup(NEON, MSITable, temp[i], dest); + for (i = 0; i < temp_len; i++, d += 8) { + memcpy(d, MSITable[temp[i] - '0'], 8); } if (no_checktext) { @@ -288,11 +303,14 @@ static void msi_plessey_mod1110(struct zint_symbol *symbol, const unsigned char } else { ustrcpy(symbol->text, temp); } + + return d; } INTERNAL int msi_plessey(struct zint_symbol *symbol, unsigned char source[], int length) { int error_number = 0; char dest[550]; /* 2 + 65 * 8 + 3 * 8 + 3 + 1 = 550 */ + char *d = dest; int check_option = symbol->option_2; int no_checktext = 0; @@ -300,7 +318,7 @@ INTERNAL int msi_plessey(struct zint_symbol *symbol, unsigned char source[], int strcpy(symbol->errtxt, "372: Input too long (65 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "377: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -314,29 +332,31 @@ INTERNAL int msi_plessey(struct zint_symbol *symbol, unsigned char source[], int } /* Start character */ - strcpy(dest, "21"); + memcpy(d, "21", 2); + d += 2; switch (check_option) { - case 0: msi_plessey_nomod(symbol, source, length, dest); + case 0: d = msi_plessey_nomod(symbol, source, length, d); break; - case 1: msi_plessey_mod10(symbol, source, length, no_checktext, dest); + case 1: d = msi_plessey_mod10(symbol, source, length, no_checktext, d); break; - case 2: msi_plessey_mod1010(symbol, source, length, no_checktext, dest); + case 2: d = msi_plessey_mod1010(symbol, source, length, no_checktext, d); break; - case 3: msi_plessey_mod11(symbol, source, length, no_checktext, 7 /*IBM wrap*/, dest); + case 3: d = msi_plessey_mod11(symbol, source, length, no_checktext, 7 /*IBM wrap*/, d); break; - case 4: msi_plessey_mod1110(symbol, source, length, no_checktext, 7 /*IBM wrap*/, dest); + case 4: d = msi_plessey_mod1110(symbol, source, length, no_checktext, 7 /*IBM wrap*/, d); break; - case 5: msi_plessey_mod11(symbol, source, length, no_checktext, 9 /*NCR wrap*/, dest); + case 5: d = msi_plessey_mod11(symbol, source, length, no_checktext, 9 /*NCR wrap*/, d); break; - case 6: msi_plessey_mod1110(symbol, source, length, no_checktext, 9 /*NCR wrap*/, dest); + case 6: d = msi_plessey_mod1110(symbol, source, length, no_checktext, 9 /*NCR wrap*/, d); break; } /* Stop character */ - strcat(dest, "121"); + memcpy(d, "121", 3); + d += 3; - expand(symbol, dest); + expand(symbol, dest, d - dest); // TODO: Find documentation on BARCODE_MSI_PLESSEY dimensions/height diff --git a/backend/png.c b/backend/png.c index 0ebfa752..65a51f86 100644 --- a/backend/png.c +++ b/backend/png.c @@ -46,8 +46,6 @@ #include #include -#define SSET "0123456789ABCDEF" - /* Note if change this need to change "backend/tests/test_png.c" definition also */ struct wpng_error_type { struct zint_symbol *symbol; @@ -300,26 +298,34 @@ INTERNAL int png_pixel_plot(struct zint_symbol *symbol, unsigned char *pixelbuf) pb = pixelbuf; if (bit_depth == 1) { for (row = 0; row < symbol->bitmap_height; row++) { - unsigned char *image_data = outdata; - for (column = 0; column < symbol->bitmap_width; column += 8, image_data++) { - unsigned char byte = 0; - for (i = 0; i < 8 && column + i < symbol->bitmap_width; i++, pb++) { - byte |= map[*pb] << (7 - i); + if (row && memcmp(pb, pb - symbol->bitmap_width, symbol->bitmap_width) == 0) { + pb += symbol->bitmap_width; + } else { + unsigned char *image_data = outdata; + for (column = 0; column < symbol->bitmap_width; column += 8, image_data++) { + unsigned char byte = 0; + for (i = 0; i < 8 && column + i < symbol->bitmap_width; i++, pb++) { + byte |= map[*pb] << (7 - i); + } + *image_data = byte; } - *image_data = byte; } /* write row contents to file */ png_write_row(png_ptr, outdata); } } else { /* Bit depth 4 */ for (row = 0; row < symbol->bitmap_height; row++) { - unsigned char *image_data = outdata; - for (column = 0; column < symbol->bitmap_width; column += 2, image_data++) { - unsigned char byte = map[*pb++] << 4; - if (column + 1 < symbol->bitmap_width) { - byte |= map[*pb++]; + if (row && memcmp(pb, pb - symbol->bitmap_width, symbol->bitmap_width) == 0) { + pb += symbol->bitmap_width; + } else { + unsigned char *image_data = outdata; + for (column = 0; column < symbol->bitmap_width; column += 2, image_data++) { + unsigned char byte = map[*pb++] << 4; + if (column + 1 < symbol->bitmap_width) { + byte |= map[*pb++]; + } + *image_data = byte; } - *image_data = byte; } /* write row contents to file */ png_write_row(png_ptr, outdata); diff --git a/backend/postal.c b/backend/postal.c index 7204b531..9a75d4ab 100644 --- a/backend/postal.c +++ b/backend/postal.c @@ -38,49 +38,58 @@ #endif #include "common.h" -#define DAFTSET "DAFT" -#define KRSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" -#define KASUTSET "1234567890-abcdefgh" -#define CHKASUTSET "0123456789-abcdefgh" -#define SHKASUTSET "1234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ" +static const char DAFTSET[] = "FADT"; +static const char KRSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static const char KASUTSET[] = "1234567890-abcdefgh"; +static const char CHKASUTSET[] = "0123456789-abcdefgh"; +#define SHKASUTSET_F (IS_NUM_F | IS_MNS_F | IS_UPR_F) /* SHKASUTSET "1234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ" */ /* PostNet number encoding table - In this table L is long as S is short */ -static const char *PNTable[10] = { - "LLSSS", "SSSLL", "SSLSL", "SSLLS", "SLSSL", "SLSLS", "SLLSS", "LSSSL", - "LSSLS", "LSLSS" +static const char PNTable[10][5] = { + {'L','L','S','S','S'}, {'S','S','S','L','L'}, {'S','S','L','S','L'}, {'S','S','L','L','S'}, {'S','L','S','S','L'}, + {'S','L','S','L','S'}, {'S','L','L','S','S'}, {'L','S','S','S','L'}, {'L','S','S','L','S'}, {'L','S','L','S','S'} }; -static const char *PLTable[10] = { - "SSLLL", "LLLSS", "LLSLS", "LLSSL", "LSLLS", "LSLSL", "LSSLL", "SLLLS", - "SLLSL", "SLSLL" +static const char PLTable[10][5] = { + {'S','S','L','L','L'}, {'L','L','L','S','S'}, {'L','L','S','L','S'}, {'L','L','S','S','L'}, {'L','S','L','L','S'}, + {'L','S','L','S','L'}, {'L','S','S','L','L'}, {'S','L','L','L','S'}, {'S','L','L','S','L'}, {'S','L','S','L','L'} }; -static const char *RoyalValues[36] = { - "11", "12", "13", "14", "15", "10", "21", "22", "23", "24", "25", - "20", "31", "32", "33", "34", "35", "30", "41", "42", "43", "44", "45", "40", "51", "52", - "53", "54", "55", "50", "01", "02", "03", "04", "05", "00" +static const char RoyalValues[36][2] = { + { 1, 1 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 1, 5 }, { 1, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 }, { 2, 4 }, + { 2, 5 }, { 2, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 }, { 3, 4 }, { 3, 5 }, { 3, 0 }, { 4, 1 }, { 4, 2 }, + { 4, 3 }, { 4, 4 }, { 4, 5 }, { 4, 0 }, { 5, 1 }, { 5, 2 }, { 5, 3 }, { 5, 4 }, { 5, 5 }, { 5, 0 }, + { 0, 1 }, { 0, 2 }, { 0, 3 }, { 0, 4 }, { 0, 5 }, { 0, 0 } }; /* 0 = Full, 1 = Ascender, 2 = Descender, 3 = Tracker */ -static const char *RoyalTable[36] = { - "3300", "3210", "3201", "2310", "2301", "2211", "3120", "3030", "3021", - "2130", "2121", "2031", "3102", "3012", "3003", "2112", "2103", "2013", "1320", "1230", - "1221", "0330", "0321", "0231", "1302", "1212", "1203", "0312", "0303", "0213", "1122", - "1032", "1023", "0132", "0123", "0033" +static const char RoyalTable[36][4] = { + {'3','3','0','0'}, {'3','2','1','0'}, {'3','2','0','1'}, {'2','3','1','0'}, {'2','3','0','1'}, {'2','2','1','1'}, + {'3','1','2','0'}, {'3','0','3','0'}, {'3','0','2','1'}, {'2','1','3','0'}, {'2','1','2','1'}, {'2','0','3','1'}, + {'3','1','0','2'}, {'3','0','1','2'}, {'3','0','0','3'}, {'2','1','1','2'}, {'2','1','0','3'}, {'2','0','1','3'}, + {'1','3','2','0'}, {'1','2','3','0'}, {'1','2','2','1'}, {'0','3','3','0'}, {'0','3','2','1'}, {'0','2','3','1'}, + {'1','3','0','2'}, {'1','2','1','2'}, {'1','2','0','3'}, {'0','3','1','2'}, {'0','3','0','3'}, {'0','2','1','3'}, + {'1','1','2','2'}, {'1','0','3','2'}, {'1','0','2','3'}, {'0','1','3','2'}, {'0','1','2','3'}, {'0','0','3','3'} }; -static const char *FlatTable[10] = { - "0504", "18", "0117", "0216", "0315", "0414", "0513", "0612", "0711", "0810" +static const char FlatTable[10][4] = { + {'0','5','0','4'}, { "18" }, {'0','1','1','7'}, {'0','2','1','6'}, {'0','3','1','5'}, + {'0','4','1','4'}, {'0','5','1','3'}, {'0','6','1','2'}, {'0','7','1','1'}, {'0','8','1','0'} }; -static const char *KoreaTable[10] = { - "1313150613", "0713131313", "0417131313", "1506131313", - "0413171313", "17171313", "1315061313", "0413131713", "17131713", "13171713" +static const char KoreaTable[10][10] = { + {'1','3','1','3','1','5','0','6','1','3'}, {'0','7','1','3','1','3','1','3','1','3'}, + {'0','4','1','7','1','3','1','3','1','3'}, {'1','5','0','6','1','3','1','3','1','3'}, + {'0','4','1','3','1','7','1','3','1','3'}, { "17171313" }, + {'1','3','1','5','0','6','1','3','1','3'}, {'0','4','1','3','1','3','1','7','1','3'}, + { "17131713" }, { "13171713" } }; -static const char *JapanTable[19] = { - "114", "132", "312", "123", "141", "321", "213", "231", "411", "144", - "414", "324", "342", "234", "432", "243", "423", "441", "111" +static const char JapanTable[19][3] = { + {'1','1','4'}, {'1','3','2'}, {'3','1','2'}, {'1','2','3'}, {'1','4','1'}, + {'3','2','1'}, {'2','1','3'}, {'2','3','1'}, {'4','1','1'}, {'1','4','4'}, + {'4','1','4'}, {'3','2','4'}, {'3','4','2'}, {'2','3','4'}, {'4','3','2'}, + {'2','4','3'}, {'4','2','3'}, {'4','4','1'}, {'1','1','1'} }; /* Set height for POSTNET/PLANET codes, maintaining ratio */ @@ -127,7 +136,7 @@ static int usps_set_height(struct zint_symbol *symbol, const int no_errtxt) { } /* Handles the PostNet system used for Zip codes in the US */ -static int postnet_enc(struct zint_symbol *symbol, unsigned char source[], char dest[], int length) { +static int postnet_enc(struct zint_symbol *symbol, const unsigned char source[], char *d, const int length) { int i, sum, check_digit; int error_number = 0; @@ -139,25 +148,27 @@ static int postnet_enc(struct zint_symbol *symbol, unsigned char source[], char strcpy(symbol->errtxt, "479: Input length is not standard (5, 9 or 11 characters)"); error_number = ZINT_WARN_NONCOMPLIANT; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "481: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } sum = 0; /* start character */ - strcpy(dest, "L"); + *d++ = 'L'; - for (i = 0; i < length; i++) { - lookup(NEON, PNTable, source[i], dest); - sum += ctoi(source[i]); + for (i = 0; i < length; i++, d += 5) { + const int val = source[i] - '0'; + memcpy(d, PNTable[val], 5); + sum += val; } check_digit = (10 - (sum % 10)) % 10; - strcat(dest, PNTable[check_digit]); + memcpy(d, PNTable[check_digit], 5); + d += 5; /* stop character */ - strcat(dest, "L"); + strcpy(d, "L"); return error_number; } @@ -191,7 +202,7 @@ INTERNAL int postnet(struct zint_symbol *symbol, unsigned char source[], int len } /* Handles the PLANET system used for item tracking in the US */ -static int planet_enc(struct zint_symbol *symbol, unsigned char source[], char dest[], int length) { +static int planet_enc(struct zint_symbol *symbol, const unsigned char source[], char *d, const int length) { int i, sum, check_digit; int error_number = 0; @@ -203,25 +214,27 @@ static int planet_enc(struct zint_symbol *symbol, unsigned char source[], char d strcpy(symbol->errtxt, "478: Input length is not standard (11 or 13 characters)"); error_number = ZINT_WARN_NONCOMPLIANT; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "483: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } sum = 0; /* start character */ - strcpy(dest, "L"); + *d++ = 'L'; - for (i = 0; i < length; i++) { - lookup(NEON, PLTable, source[i], dest); - sum += ctoi(source[i]); + for (i = 0; i < length; i++, d += 5) { + const int val = source[i] - '0'; + memcpy(d, PLTable[val], 5); + sum += val; } check_digit = (10 - (sum % 10)) % 10; - strcat(dest, PLTable[check_digit]); + memcpy(d, PLTable[check_digit], 5); + d += 5; /* stop character */ - strcat(dest, "L"); + strcpy(d, "L"); return error_number; } @@ -258,12 +271,14 @@ INTERNAL int planet(struct zint_symbol *symbol, unsigned char source[], int leng INTERNAL int koreapost(struct zint_symbol *symbol, unsigned char source[], int length) { int total, loop, check, zeroes, error_number = 0; char localstr[8], dest[80]; + char *d = dest; + int posns[6]; if (length > 6) { strcpy(symbol->errtxt, "484: Input too long (6 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "485: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -273,7 +288,8 @@ INTERNAL int koreapost(struct zint_symbol *symbol, unsigned char source[], int l total = 0; for (loop = 0; loop < 6; loop++) { - total += ctoi(localstr[loop]); + posns[loop] = ctoi(localstr[loop]); + total += posns[loop]; } check = 10 - (total % 10); if (check == 10) { @@ -281,12 +297,17 @@ INTERNAL int koreapost(struct zint_symbol *symbol, unsigned char source[], int l } localstr[6] = itoc(check); localstr[7] = '\0'; - *dest = '\0'; + for (loop = 5; loop >= 0; loop--) { - lookup(NEON, KoreaTable, localstr[loop], dest); + const char *const entry = KoreaTable[posns[loop]]; + memcpy(d, entry, 10); + d += entry[8] ? 10 : 8; } - lookup(NEON, KoreaTable, localstr[6], dest); - expand(symbol, dest); + memcpy(d, KoreaTable[check], 10); + d += KoreaTable[check][8] ? 10 : 8; + + expand(symbol, dest, d - dest); + ustrcpy(symbol->text, localstr); // TODO: Find documentation on BARCODE_KOREAPOST dimensions/height @@ -298,7 +319,6 @@ INTERNAL int koreapost(struct zint_symbol *symbol, unsigned char source[], int l glyphs from http://en.wikipedia.org/wiki/Facing_Identification_Mark */ INTERNAL int fim(struct zint_symbol *symbol, unsigned char source[], int length) { int error_number = 0; - char dest[16] = {0}; if (length > 1) { strcpy(symbol->errtxt, "486: Input too long (1 character maximum)"); @@ -308,19 +328,19 @@ INTERNAL int fim(struct zint_symbol *symbol, unsigned char source[], int length) switch ((char) source[0]) { case 'a': case 'A': - strcpy(dest, "111515111"); + expand(symbol, "111515111", 9); break; case 'b': case 'B': - strcpy(dest, "13111311131"); + expand(symbol, "13111311131", 11); break; case 'c': case 'C': - strcpy(dest, "11131313111"); + expand(symbol, "11131313111", 11); break; case 'd': case 'D': - strcpy(dest, "1111131311111"); + expand(symbol, "1111131311111", 13); break; default: strcpy(symbol->errtxt, "487: Invalid character in data (\"A\", \"B\", \"C\" or \"D\" only)"); @@ -328,8 +348,6 @@ INTERNAL int fim(struct zint_symbol *symbol, unsigned char source[], int length) break; } - expand(symbol, dest); - if (symbol->output_options & COMPLIANT_HEIGHT) { /* USPS Domestic Mail Manual (USPS DMM 300) Jan 8, 2006 (updated 2011) 708.9.3 X 0.03125" (1/32) +- 0.008" so X max 0.03925", height 0.625" (5/8) +- 0.125" (1/8) */ @@ -344,7 +362,7 @@ INTERNAL int fim(struct zint_symbol *symbol, unsigned char source[], int length) /* Set height for DAFT-type codes, maintaining ratio. Expects row_height[0] & row_height[1] to be set */ /* Used by auspost.c also */ -INTERNAL int daft_set_height(struct zint_symbol *symbol, float min_height, float max_height) { +INTERNAL int daft_set_height(struct zint_symbol *symbol, const float min_height, const float max_height) { int error_number = 0; float t_ratio; /* Tracker ratio */ @@ -376,22 +394,21 @@ INTERNAL int daft_set_height(struct zint_symbol *symbol, float min_height, float } /* Handles the 4 State barcodes used in the UK by Royal Mail */ -static char rm4scc_enc(unsigned char source[], char dest[], int length) { +static void rm4scc_enc(const int *posns, char *d, const int length) { int i; int top, bottom, row, column, check_digit; - char values[3], set_copy[] = KRSET; top = 0; bottom = 0; /* start character */ - strcpy(dest, "1"); + *d++ = '1'; - for (i = 0; i < length; i++) { - lookup(KRSET, RoyalTable, source[i], dest); - strcpy(values, RoyalValues[posn(KRSET, source[i])]); - top += ctoi(values[0]); - bottom += ctoi(values[1]); + for (i = 0; i < length; i++, d += 4) { + const int p = posns[i]; + memcpy(d, RoyalTable[p], 4); + top += RoyalValues[p][0]; + bottom += RoyalValues[p][1]; } /* Calculate the check digit */ @@ -404,32 +421,31 @@ static char rm4scc_enc(unsigned char source[], char dest[], int length) { column = 5; } check_digit = (6 * row) + column; - strcat(dest, RoyalTable[check_digit]); + memcpy(d, RoyalTable[check_digit], 4); + d += 4; /* stop character */ - strcat(dest, "0"); - - return set_copy[check_digit]; + strcpy(d, "0"); } /* Puts RM4SCC into the data matrix */ INTERNAL int rm4scc(struct zint_symbol *symbol, unsigned char source[], int length) { char height_pattern[210]; + int posns[50]; int loopey, h; int writer; int error_number = 0; - strcpy(height_pattern, ""); if (length > 50) { strcpy(symbol->errtxt, "488: Input too long (50 character maximum)"); return ZINT_ERROR_TOO_LONG; } - to_upper(source); - if (is_sane(KRSET, source, length) != 0) { + to_upper(source, length); + if (!is_sane_lookup(KRSET, 36, source, length, posns)) { strcpy(symbol->errtxt, "489: Invalid character in data (alphanumerics only)"); return ZINT_ERROR_INVALID_DATA; } - /*check = */rm4scc_enc(source, height_pattern, length); + rm4scc_enc(posns, height_pattern, length); writer = 0; h = (int) strlen(height_pattern); @@ -467,34 +483,33 @@ INTERNAL int rm4scc(struct zint_symbol *symbol, unsigned char source[], int leng } /* Handles Dutch Post TNT KIX symbols - The same as RM4SCC but without check digit + The same as RM4SCC but without check digit or stop/start chars Specification at http://www.tntpost.nl/zakelijk/klantenservice/downloads/kIX_code/download.aspx */ INTERNAL int kix(struct zint_symbol *symbol, unsigned char source[], int length) { - char height_pattern[75], localstr[20]; + char height_pattern[75]; + char *d = height_pattern; + int posns[18]; int loopey; int writer, i, h; int error_number = 0; - strcpy(height_pattern, ""); if (length > 18) { strcpy(symbol->errtxt, "490: Input too long (18 character maximum)"); return ZINT_ERROR_TOO_LONG; } - to_upper(source); - if (is_sane(KRSET, source, length) != 0) { + to_upper(source, length); + if (!is_sane_lookup(KRSET, 36, source, length, posns)) { strcpy(symbol->errtxt, "491: Invalid character in data (alphanumerics only)"); return ZINT_ERROR_INVALID_DATA; } - ustrcpy(localstr, source); - /* Encode data */ - for (i = 0; i < length; i++) { - lookup(KRSET, RoyalTable, localstr[i], height_pattern); + for (i = 0; i < length; i++, d += 4) { + memcpy(d, RoyalTable[posns[i]], 4); } writer = 0; - h = (int) strlen(height_pattern); + h = d - height_pattern; for (loopey = 0; loopey < h; loopey++) { if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '0')) { set_module(symbol, 0, writer); @@ -525,45 +540,28 @@ INTERNAL int kix(struct zint_symbol *symbol, unsigned char source[], int length) /* Handles DAFT Code symbols */ INTERNAL int daft(struct zint_symbol *symbol, unsigned char source[], int length) { - char height_pattern[100]; - unsigned int loopey, h; - int writer, i; - strcpy(height_pattern, ""); + int posns[100]; + int loopey; + int writer; - if (length > 50) { - strcpy(symbol->errtxt, "492: Input too long (50 character maximum)"); + if (length > 100) { + strcpy(symbol->errtxt, "492: Input too long (100 character maximum)"); return ZINT_ERROR_TOO_LONG; } - to_upper(source); + to_upper(source, length); - if (is_sane(DAFTSET, source, length) != 0) { + if (!is_sane_lookup(DAFTSET, 4, source, length, posns)) { strcpy(symbol->errtxt, "493: Invalid character in data (\"D\", \"A\", \"F\" and \"T\" only)"); return ZINT_ERROR_INVALID_DATA; } - for (i = 0; i < length; i++) { - if (source[i] == 'D') { - strcat(height_pattern, "2"); - } - if (source[i] == 'A') { - strcat(height_pattern, "1"); - } - if (source[i] == 'F') { - strcat(height_pattern, "0"); - } - if (source[i] == 'T') { - strcat(height_pattern, "3"); - } - } - writer = 0; - h = (int) strlen(height_pattern); - for (loopey = 0; loopey < h; loopey++) { - if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '0')) { + for (loopey = 0; loopey < length; loopey++) { + if ((posns[loopey] == 1) || (posns[loopey] == 0)) { set_module(symbol, 0, writer); } set_module(symbol, 1, writer); - if ((height_pattern[loopey] == '2') || (height_pattern[loopey] == '0')) { + if ((posns[loopey] == 2) || (posns[loopey] == 0)) { set_module(symbol, 2, writer); } writer += 2; @@ -594,21 +592,24 @@ INTERNAL int daft(struct zint_symbol *symbol, unsigned char source[], int length INTERNAL int flat(struct zint_symbol *symbol, unsigned char source[], int length) { int loop, error_number = 0; char dest[512]; /* 90 * 4 + 1 ~ */ + char *d = dest; if (length > 90) { strcpy(symbol->errtxt, "494: Input too long (90 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, length) != 0) { + if (!is_sane(NEON_F, source, length)) { strcpy(symbol->errtxt, "495: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } - *dest = '\0'; + for (loop = 0; loop < length; loop++) { - lookup(NEON, FlatTable, source[loop], dest); + const char *const entry = FlatTable[source[loop] - '0']; + memcpy(d, entry, 4); + d += entry[2] ? 4 : 2; } - expand(symbol, dest); + expand(symbol, dest, d - dest); // TODO: Find documentation on BARCODE_FLAT dimensions/height @@ -619,25 +620,19 @@ INTERNAL int flat(struct zint_symbol *symbol, unsigned char source[], int length INTERNAL int japanpost(struct zint_symbol *symbol, unsigned char source[], int length) { int error_number = 0, h; char pattern[69]; + char *d = pattern; int writer, loopey, inter_posn, i, sum, check; char check_char; - char inter[23]; - -#ifndef _MSC_VER - unsigned char local_source[length + 1]; -#else - unsigned char *local_source = (unsigned char *) _alloca(length + 1); -#endif + char inter[20 + 1]; if (length > 20) { strcpy(symbol->errtxt, "496: Input too long (20 character maximum)"); return ZINT_ERROR_TOO_LONG; } - ustrcpy(local_source, source); - to_upper(local_source); + to_upper(source, length); - if (is_sane(SHKASUTSET, local_source, length) != 0) { + if (!is_sane(SHKASUTSET_F, source, length)) { strcpy(symbol->errtxt, "497: Invalid character in data (alphanumerics and \"-\" only)"); return ZINT_ERROR_INVALID_DATA; } @@ -647,35 +642,36 @@ INTERNAL int japanpost(struct zint_symbol *symbol, unsigned char source[], int l i = 0; inter_posn = 0; do { - if (((local_source[i] >= '0') && (local_source[i] <= '9')) || (local_source[i] == '-')) { - inter[inter_posn] = local_source[i]; + if (((source[i] >= '0') && (source[i] <= '9')) || (source[i] == '-')) { + inter[inter_posn] = source[i]; inter_posn++; } else { - if ((local_source[i] >= 'A') && (local_source[i] <= 'J')) { + if (source[i] <= 'J') { inter[inter_posn] = 'a'; - inter[inter_posn + 1] = local_source[i] - 'A' + '0'; - inter_posn += 2; - } - if ((local_source[i] >= 'K') && (local_source[i] <= 'T')) { + inter[inter_posn + 1] = source[i] - 'A' + '0'; + } else if (source[i] <= 'T') { inter[inter_posn] = 'b'; - inter[inter_posn + 1] = local_source[i] - 'K' + '0'; - inter_posn += 2; - } - if ((local_source[i] >= 'U') && (local_source[i] <= 'Z')) { + inter[inter_posn + 1] = source[i] - 'K' + '0'; + } else { /* (source[i] >= 'U') && (source[i] <= 'Z') */ inter[inter_posn] = 'c'; - inter[inter_posn + 1] = local_source[i] - 'U' + '0'; - inter_posn += 2; + inter[inter_posn + 1] = source[i] - 'U' + '0'; } + inter_posn += 2; } i++; } while ((i < length) && (inter_posn < 20)); - inter[20] = '\0'; - strcpy(pattern, "13"); /* Start */ + if (i != length || inter[20] != '\0') { + strcpy(symbol->errtxt, "477: Input too long (20 symbol character maximum)"); + return ZINT_ERROR_TOO_LONG; + } + + memcpy(d, "13", 2); /* Start */ + d += 2; sum = 0; - for (i = 0; i < 20; i++) { - strcat(pattern, JapanTable[posn(KASUTSET, inter[i])]); + for (i = 0; i < 20; i++, d += 3) { + memcpy(d, JapanTable[posn(KASUTSET, inter[i])], 3); sum += posn(CHKASUTSET, inter[i]); } @@ -691,15 +687,17 @@ INTERNAL int japanpost(struct zint_symbol *symbol, unsigned char source[], int l } else { check_char = (check - 11) + 'a'; } - strcat(pattern, JapanTable[posn(KASUTSET, check_char)]); + memcpy(d, JapanTable[posn(KASUTSET, check_char)], 3); + d += 3; if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check: %d, char: %c\n", check, check_char); - strcat(pattern, "31"); /* Stop */ + memcpy(d, "31", 2); /* Stop */ + d += 2; /* Resolve pattern to 4-state symbols */ writer = 0; - h = (int) strlen(pattern); + h = d - pattern; for (loopey = 0; loopey < h; loopey++) { if ((pattern[loopey] == '2') || (pattern[loopey] == '1')) { set_module(symbol, 0, writer); diff --git a/backend/qr.c b/backend/qr.c index 65ec479f..4af59b72 100644 --- a/backend/qr.c +++ b/backend/qr.c @@ -305,7 +305,7 @@ static void qr_define_mode(char mode[], const unsigned int jisdata[], const int /* Get optimal mode for each code point by tracing backwards */ for (i = length - 1, cm_i = i * QR_NUM_MODES; i >= 0; i--, cm_i -= QR_NUM_MODES) { - j = strchr(mode_types, cur_mode) - mode_types; + j = posn(mode_types, cur_mode); cur_mode = char_modes[cm_i + j]; mode[i] = cur_mode; } @@ -327,7 +327,7 @@ static int mode_indicator(const int version, const int mode) { { 0, 1, 2, 3, }, }; - int mode_index = strchr(mode_types, mode) - mode_types; + int mode_index = posn(mode_types, (const char) mode); if (version < RMQR_VERSION) { return mode_indicators[0][mode_index]; /* QRCODE */ @@ -364,7 +364,7 @@ static int cci_bits(const int version, const int mode) { static const unsigned short int *rmqr_ccis[QR_NUM_MODES] = { rmqr_numeric_cci, rmqr_alphanum_cci, rmqr_byte_cci, rmqr_kanji_cci, }; - int mode_index = strchr(mode_types, mode) - mode_types; + int mode_index = posn(mode_types, (const char) mode); if (version < RMQR_VERSION) { /* QRCODE */ if (version < 10) { @@ -393,7 +393,7 @@ static int terminator_bits(const int version) { } /* Convert input data to a binary stream and add padding */ -static void qr_binary(unsigned char datastream[], const int version, const int target_codewords, const char mode[], +static int qr_binary(unsigned char datastream[], const int version, const int target_codewords, const char mode[], const unsigned int jisdata[], const int length, const struct zint_structapp *p_structapp, const int gs1, const int eci, const int est_binlen, const int debug_print) { int position = 0; @@ -406,8 +406,9 @@ static void qr_binary(unsigned char datastream[], const int version, const int t #ifndef _MSC_VER char binary[est_binlen + 12]; #else - char *binary = (char *) _alloca(est_binlen + 12); + char *binary= (char *) _alloca(est_binlen + 12); #endif + *binary = '\0'; bp = 0; @@ -641,17 +642,17 @@ static void qr_binary(unsigned char datastream[], const int version, const int t int count; int first = 0, prod; - first = posn(NEON, (char) jisdata[position + i]); + first = ctoi((const char) jisdata[position + i]); count = 1; prod = first; if (i + 1 < short_data_block_length && mode[position + i + 1] == 'N') { - int second = posn(NEON, (char) jisdata[position + i + 1]); + int second = ctoi((const char) jisdata[position + i + 1]); count = 2; prod = (prod * 10) + second; if (i + 2 < short_data_block_length && mode[position + i + 2] == 'N') { - int third = posn(NEON, (char) jisdata[position + i + 2]); + int third = ctoi((const char) jisdata[position + i + 2]); count = 3; prod = (prod * 10) + third; } @@ -678,9 +679,8 @@ static void qr_binary(unsigned char datastream[], const int version, const int t if (version >= MICROQR_VERSION && version < MICROQR_VERSION + 4) { /* MICROQR does its own terminating/padding */ - binary[bp] = '\0'; - ustrcpy(datastream, binary); - return; + memcpy(datastream, binary, bp); + return bp; } /* Terminator */ @@ -738,6 +738,8 @@ static void qr_binary(unsigned char datastream[], const int version, const int t } printf("\n"); } + + return 0; /* Not used */ } /* Split data into blocks, add error correction and then interleave the blocks and error correction data */ @@ -769,7 +771,7 @@ static void add_ecc(unsigned char fullstream[], const unsigned char datastream[] ecc_block_length = ecc_cw / blocks; /* Suppress some clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult/uninitialized.Assign warnings */ - assert(short_data_block_length >= 0); + assert(short_data_block_length > 0); assert(ecc_block_length * blocks == ecc_cw); #ifndef _MSC_VER @@ -842,7 +844,6 @@ static void add_ecc(unsigned char fullstream[], const unsigned char datastream[] fullstream[j] = interleaved_data[j]; } for (j = 0; j < ecc_cw; j++) { - // NOLINTNEXTLINE suppress clang-tidy warning: interleaved_ecc[ecc_cw] fully set fullstream[j + data_cw] = interleaved_ecc[j]; } @@ -1788,8 +1789,8 @@ INTERNAL int qrcode(struct zint_symbol *symbol, unsigned char source[], int leng fullstream = (unsigned char *) _alloca(qr_total_codewords[version - 1] + 1); #endif - qr_binary(datastream, version, target_codewords, mode, jisdata, length, p_structapp, gs1, symbol->eci, - est_binlen, debug_print); + (void) qr_binary(datastream, version, target_codewords, mode, jisdata, length, p_structapp, gs1, symbol->eci, + est_binlen, debug_print); #ifdef ZINT_TEST if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords); #endif @@ -1833,7 +1834,7 @@ INTERNAL int qrcode(struct zint_symbol *symbol, unsigned char source[], int leng return 0; } -static void micro_qr_m1(struct zint_symbol *symbol, char binary_data[]) { +static int micro_qr_m1(struct zint_symbol *symbol, char binary_data[], int bp) { int i, j, latch; int bits_total, bits_left; int data_codewords, ecc_codewords; @@ -1844,26 +1845,26 @@ static void micro_qr_m1(struct zint_symbol *symbol, char binary_data[]) { latch = 0; /* Add terminator */ - bits_left = bits_total - (int) strlen(binary_data); + bits_left = bits_total - bp; if (bits_left <= 3) { - for (i = 0; i < bits_left; i++) { - strcat(binary_data, "0"); + if (bits_left) { + bp = bin_append_posn(0, bits_left, binary_data, bp); } latch = 1; } else { - strcat(binary_data, "000"); + bp = bin_append_posn(0, 3, binary_data, bp); } if (symbol->debug & ZINT_DEBUG_PRINT) { - printf("M1 Terminated binary (%d): %s (bits_left %d)\n", (int) strlen(binary_data), binary_data, bits_left); + printf("M1 Terminated binary (%d): %s (bits_left %d)\n", bp, binary_data, bits_left); } if (latch == 0) { /* Manage last (4-bit) block */ - bits_left = bits_total - (int) strlen(binary_data); + bits_left = bits_total - bp; if (bits_left <= 4) { - for (i = 0; i < bits_left; i++) { - strcat(binary_data, "0"); + if (bits_left) { + bp = bin_append_posn(0, bits_left, binary_data, bp); } latch = 1; } @@ -1871,23 +1872,20 @@ static void micro_qr_m1(struct zint_symbol *symbol, char binary_data[]) { if (latch == 0) { /* Complete current byte */ - int remainder = 8 - (strlen(binary_data) % 8); - if (remainder == 8) { - remainder = 0; - } - for (i = 0; i < remainder; i++) { - strcat(binary_data, "0"); + int remainder = 8 - (bp % 8); + if (remainder != 8) { + bp = bin_append_posn(0, remainder, binary_data, bp); } /* Add padding */ - bits_left = bits_total - (int) strlen(binary_data); + bits_left = bits_total - bp; if (bits_left > 4) { remainder = (bits_left - 4) / 8; for (i = 0; i < remainder; i++) { - strcat(binary_data, (i & 1) ? "00010001" : "11101100"); + bp = bin_append_posn(i & 1 ? 0x11 : 0xEC, 8, binary_data, bp); } } - bin_append(0, 4, binary_data); + bp = bin_append_posn(0, 4, binary_data, bp); } data_codewords = 3; @@ -1919,14 +1917,16 @@ static void micro_qr_m1(struct zint_symbol *symbol, char binary_data[]) { /* Add Reed-Solomon codewords to binary data */ for (i = 0; i < ecc_codewords; i++) { - bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data); + bp = bin_append_posn(ecc_blocks[ecc_codewords - i - 1], 8, binary_data, bp); } + + return bp; } -static void micro_qr_m2(struct zint_symbol *symbol, char binary_data[], const int ecc_mode) { +static int micro_qr_m2(struct zint_symbol *symbol, char binary_data[], int bp, const int ecc_mode) { int i, j, latch; - int bits_total=0, bits_left; - int data_codewords=0, ecc_codewords=0; + int bits_total = 0, bits_left; + int data_codewords = 0, ecc_codewords = 0; unsigned char data_blocks[6], ecc_blocks[7]; rs_t rs; @@ -1941,35 +1941,32 @@ static void micro_qr_m2(struct zint_symbol *symbol, char binary_data[], const in else assert(0); /* Add terminator */ - bits_left = bits_total - (int) strlen(binary_data); + bits_left = bits_total - bp; if (bits_left <= 5) { - for (i = 0; i < bits_left; i++) { - strcat(binary_data, "0"); + if (bits_left) { + bp = bin_append_posn(0, bits_left, binary_data, bp); } latch = 1; } else { - bin_append(0, 5, binary_data); + bp = bin_append_posn(0, 5, binary_data, bp); } if (symbol->debug & ZINT_DEBUG_PRINT) { - printf("M2 Terminated binary (%d): %s (bits_left %d)\n", (int) strlen(binary_data), binary_data, bits_left); + printf("M2 Terminated binary (%d): %s (bits_left %d)\n", bp, binary_data, bits_left); } if (latch == 0) { /* Complete current byte */ - int remainder = 8 - (strlen(binary_data) % 8); - if (remainder == 8) { - remainder = 0; - } - for (i = 0; i < remainder; i++) { - strcat(binary_data, "0"); + int remainder = 8 - (bp % 8); + if (remainder != 8) { + bp = bin_append_posn(0, remainder, binary_data, bp); } /* Add padding */ - bits_left = bits_total - (int) strlen(binary_data); + bits_left = bits_total - bp; remainder = bits_left / 8; for (i = 0; i < remainder; i++) { - strcat(binary_data, (i & 1) ? "00010001" : "11101100"); + bp = bin_append_posn(i & 1 ? 0x11 : 0xEC, 8, binary_data, bp); } } @@ -2004,16 +2001,16 @@ static void micro_qr_m2(struct zint_symbol *symbol, char binary_data[], const in /* Add Reed-Solomon codewords to binary data */ for (i = 0; i < ecc_codewords; i++) { - bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data); + bp = bin_append_posn(ecc_blocks[ecc_codewords - i - 1], 8, binary_data, bp); } - return; + return bp; } -static void micro_qr_m3(struct zint_symbol *symbol, char binary_data[], const int ecc_mode) { +static int micro_qr_m3(struct zint_symbol *symbol, char binary_data[], int bp, const int ecc_mode) { int i, j, latch; - int bits_total=0, bits_left; - int data_codewords=0, ecc_codewords=0; + int bits_total = 0, bits_left; + int data_codewords = 0, ecc_codewords = 0; unsigned char data_blocks[12], ecc_blocks[9]; rs_t rs; @@ -2028,26 +2025,26 @@ static void micro_qr_m3(struct zint_symbol *symbol, char binary_data[], const in else assert(0); /* Add terminator */ - bits_left = bits_total - (int) strlen(binary_data); + bits_left = bits_total - bp; if (bits_left <= 7) { - for (i = 0; i < bits_left; i++) { - strcat(binary_data, "0"); + if (bits_left) { + bp = bin_append_posn(0, bits_left, binary_data, bp); } latch = 1; } else { - bin_append(0, 7, binary_data); + bp = bin_append_posn(0, 7, binary_data, bp); } if (symbol->debug & ZINT_DEBUG_PRINT) { - printf("M3 Terminated binary (%d): %s (bits_left %d)\n", (int) strlen(binary_data), binary_data, bits_left); + printf("M3 Terminated binary (%d): %s (bits_left %d)\n", bp, binary_data, bits_left); } if (latch == 0) { /* Manage last (4-bit) block */ - bits_left = bits_total - (int) strlen(binary_data); + bits_left = bits_total - bp; if (bits_left <= 4) { - for (i = 0; i < bits_left; i++) { - strcat(binary_data, "0"); + if (bits_left) { + bp = bin_append_posn(0, bits_left, binary_data, bp); } latch = 1; } @@ -2055,23 +2052,20 @@ static void micro_qr_m3(struct zint_symbol *symbol, char binary_data[], const in if (latch == 0) { /* Complete current byte */ - int remainder = 8 - (strlen(binary_data) % 8); - if (remainder == 8) { - remainder = 0; - } - for (i = 0; i < remainder; i++) { - strcat(binary_data, "0"); + int remainder = 8 - (bp % 8); + if (remainder != 8) { + bp = bin_append_posn(0, remainder, binary_data, bp); } /* Add padding */ - bits_left = bits_total - (int) strlen(binary_data); + bits_left = bits_total - bp; if (bits_left > 4) { remainder = (bits_left - 4) / 8; for (i = 0; i < remainder; i++) { - strcat(binary_data, (i & 1) ? "00010001" : "11101100"); + bp = bin_append_posn(i & 1 ? 0x11 : 0xEC, 8, binary_data, bp); } } - bin_append(0, 4, binary_data); + bp = bin_append_posn(0, 4, binary_data, bp); } if (ecc_mode == LEVEL_L) { @@ -2123,16 +2117,16 @@ static void micro_qr_m3(struct zint_symbol *symbol, char binary_data[], const in /* Add Reed-Solomon codewords to binary data */ for (i = 0; i < ecc_codewords; i++) { - bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data); + bp = bin_append_posn(ecc_blocks[ecc_codewords - i - 1], 8, binary_data, bp); } - return; + return bp; } -static void micro_qr_m4(struct zint_symbol *symbol, char binary_data[], const int ecc_mode) { +static int micro_qr_m4(struct zint_symbol *symbol, char binary_data[], int bp, const int ecc_mode) { int i, j, latch; - int bits_total=0, bits_left; - int data_codewords=0, ecc_codewords=0; + int bits_total = 0, bits_left; + int data_codewords = 0, ecc_codewords = 0; unsigned char data_blocks[17], ecc_blocks[15]; rs_t rs; @@ -2150,14 +2144,14 @@ static void micro_qr_m4(struct zint_symbol *symbol, char binary_data[], const in else assert(0); /* Add terminator */ - bits_left = bits_total - (int) strlen(binary_data); + bits_left = bits_total - bp; if (bits_left <= 9) { - for (i = 0; i < bits_left; i++) { - strcat(binary_data, "0"); + if (bits_left) { + bp = bin_append_posn(0, bits_left, binary_data, bp); } latch = 1; } else { - bin_append(0, 9, binary_data); + bp = bin_append_posn(0, 9, binary_data, bp); } if (symbol->debug & ZINT_DEBUG_PRINT) { @@ -2166,19 +2160,16 @@ static void micro_qr_m4(struct zint_symbol *symbol, char binary_data[], const in if (latch == 0) { /* Complete current byte */ - int remainder = 8 - (strlen(binary_data) % 8); - if (remainder == 8) { - remainder = 0; - } - for (i = 0; i < remainder; i++) { - strcat(binary_data, "0"); + int remainder = 8 - (bp % 8); + if (remainder != 8) { + bp = bin_append_posn(0, remainder, binary_data, bp); } /* Add padding */ - bits_left = bits_total - (int) strlen(binary_data); + bits_left = bits_total - bp; remainder = bits_left / 8; for (i = 0; i < remainder; i++) { - strcat(binary_data, (i & 1) ? "00010001" : "11101100"); + bp = bin_append_posn(i & 1 ? 0x11 : 0xEC, 8, binary_data, bp); } } @@ -2217,8 +2208,10 @@ static void micro_qr_m4(struct zint_symbol *symbol, char binary_data[], const in /* Add Reed-Solomon codewords to binary data */ for (i = 0; i < ecc_codewords; i++) { - bin_append(ecc_blocks[ecc_codewords - i - 1], 8, binary_data); + bp = bin_append_posn(ecc_blocks[ecc_codewords - i - 1], 8, binary_data, bp); } + + return bp; } static void micro_setup_grid(unsigned char *grid, const int size) { @@ -2256,13 +2249,12 @@ static void micro_setup_grid(unsigned char *grid, const int size) { grid[(8 * size) + 8] |= 20; } -static void micro_populate_grid(unsigned char *grid, const int size, const char full_stream[]) { +static void micro_populate_grid(unsigned char *grid, const int size, const char full_stream[], int bp) { int direction = 1; /* up */ int row = 0; /* right hand side */ - int n, i; + int i; int y; - n = (int) strlen(full_stream); y = size - 1; i = 0; do { @@ -2277,7 +2269,7 @@ static void micro_populate_grid(unsigned char *grid, const int size, const char i++; } - if (i < n) { + if (i < bp) { if (!(grid[(y * size) + x] & 0xf0)) { if (full_stream[i] == '1') { grid[(y * size) + x] = 0x01; @@ -2305,7 +2297,7 @@ static void micro_populate_grid(unsigned char *grid, const int size, const char y = size - 1; direction = 1; } - } while (i < n); + } while (i < bp); } static int micro_evaluate(const unsigned char *grid, const int size, const int pattern) { @@ -2432,6 +2424,7 @@ static int micro_apply_bitmask(unsigned char *grid, const int size, const int us INTERNAL int microqr(struct zint_symbol *symbol, unsigned char source[], int length) { int i, size, j; char full_stream[200]; + int bp; int full_multibyte; int user_mask; @@ -2614,19 +2607,19 @@ INTERNAL int microqr(struct zint_symbol *symbol, unsigned char source[], int len qr_define_mode(mode, jisdata, length, 0 /*gs1*/, MICROQR_VERSION + version, debug_print); - qr_binary((unsigned char *) full_stream, MICROQR_VERSION + version, 0 /*target_codewords*/, mode, jisdata, length, - NULL /*p_structapp*/, 0 /*gs1*/, 0 /*eci*/, binary_count[version], debug_print); + bp = qr_binary((unsigned char *) full_stream, MICROQR_VERSION + version, 0 /*target_codewords*/, mode, jisdata, + length, NULL /*p_structapp*/, 0 /*gs1*/, 0 /*eci*/, binary_count[version], debug_print); - if (debug_print) printf("Binary (%d): %s\n", (int) strlen(full_stream), full_stream); + if (debug_print) printf("Binary (%d): %s\n", bp, full_stream); switch (version) { - case 0: micro_qr_m1(symbol, full_stream); + case 0: bp = micro_qr_m1(symbol, full_stream, bp); break; - case 1: micro_qr_m2(symbol, full_stream, ecc_level); + case 1: bp = micro_qr_m2(symbol, full_stream, bp, ecc_level); break; - case 2: micro_qr_m3(symbol, full_stream, ecc_level); + case 2: bp = micro_qr_m3(symbol, full_stream, bp, ecc_level); break; - case 3: micro_qr_m4(symbol, full_stream, ecc_level); + case 3: bp = micro_qr_m4(symbol, full_stream, bp, ecc_level); break; } @@ -2641,7 +2634,7 @@ INTERNAL int microqr(struct zint_symbol *symbol, unsigned char source[], int len memset(grid, 0, size_squared); micro_setup_grid(grid, size); - micro_populate_grid(grid, size, full_stream); + micro_populate_grid(grid, size, full_stream, bp); bitmask = micro_apply_bitmask(grid, size, user_mask, debug_print); /* Add format data */ @@ -2814,8 +2807,8 @@ INTERNAL int upnqr(struct zint_symbol *symbol, unsigned char source[], int lengt fullstream = (unsigned char *) _alloca(qr_total_codewords[version - 1] + 1); #endif - qr_binary(datastream, version, target_codewords, mode, jisdata, length, NULL /*p_structapp*/, 0 /*gs1*/, - symbol->eci, est_binlen, debug_print); + (void) qr_binary(datastream, version, target_codewords, mode, jisdata, length, NULL /*p_structapp*/, 0 /*gs1*/, + symbol->eci, est_binlen, debug_print); #ifdef ZINT_TEST if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords); #endif @@ -3145,8 +3138,8 @@ INTERNAL int rmqr(struct zint_symbol *symbol, unsigned char source[], int length fullstream = (unsigned char *) _alloca(rmqr_total_codewords[version] + 1); #endif - qr_binary(datastream, RMQR_VERSION + version, target_codewords, mode, jisdata, length, NULL /*p_structapp*/, gs1, - symbol->eci, est_binlen, debug_print); + (void) qr_binary(datastream, RMQR_VERSION + version, target_codewords, mode, jisdata, length, + NULL /*p_structapp*/, gs1, symbol->eci, est_binlen, debug_print); #ifdef ZINT_TEST if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords); #endif diff --git a/backend/raster.c b/backend/raster.c index 14869343..da3582d2 100644 --- a/backend/raster.c +++ b/backend/raster.c @@ -77,7 +77,7 @@ static int buffer_plot(struct zint_symbol *symbol, const unsigned char *pixelbuf }; int row; int plot_alpha = 0; - unsigned char *bitmap; + const size_t bm_bitmap_width = (size_t) symbol->bitmap_width * 3; map[DEFAULT_INK][0] = (16 * ctoi(symbol->fgcolour[0])) + ctoi(symbol->fgcolour[1]); map[DEFAULT_INK][1] = (16 * ctoi(symbol->fgcolour[2])) + ctoi(symbol->fgcolour[3]); @@ -110,7 +110,7 @@ static int buffer_plot(struct zint_symbol *symbol, const unsigned char *pixelbuf symbol->alphamap = NULL; } - symbol->bitmap = (unsigned char *) malloc((size_t) symbol->bitmap_width * symbol->bitmap_height * 3); + symbol->bitmap = (unsigned char *) malloc(bm_bitmap_width * symbol->bitmap_height); if (symbol->bitmap == NULL) { strcpy(symbol->errtxt, "661: Insufficient memory for bitmap buffer"); return ZINT_ERROR_MEMORY; @@ -124,21 +124,31 @@ static int buffer_plot(struct zint_symbol *symbol, const unsigned char *pixelbuf } for (row = 0; row < symbol->bitmap_height; row++) { int p = row * symbol->bitmap_width; - const int pe = p + symbol->bitmap_width; - bitmap = symbol->bitmap + p * 3; - for (; p < pe; p++, bitmap += 3) { - memcpy(bitmap, map[pixelbuf[p]], 3); - symbol->alphamap[p] = pixelbuf[p] == DEFAULT_PAPER ? bgalpha : fgalpha; + const unsigned char *pb = pixelbuf + p; + unsigned char *bitmap = symbol->bitmap + p * 3; + if (row && memcmp(pb, pb - symbol->bitmap_width, symbol->bitmap_width) == 0) { + memcpy(bitmap, bitmap - bm_bitmap_width, bm_bitmap_width); + memcpy(symbol->alphamap + p, symbol->alphamap + p - symbol->bitmap_width, symbol->bitmap_width); + } else { + const int pe = p + symbol->bitmap_width; + for (; p < pe; p++, bitmap += 3) { + memcpy(bitmap, map[pixelbuf[p]], 3); + symbol->alphamap[p] = pixelbuf[p] == DEFAULT_PAPER ? bgalpha : fgalpha; + } } } } else { for (row = 0; row < symbol->bitmap_height; row++) { const int r = row * symbol->bitmap_width; const unsigned char *pb = pixelbuf + r; - const unsigned char *const pe = pb + symbol->bitmap_width; - bitmap = symbol->bitmap + r * 3; - for (; pb < pe; pb++, bitmap += 3) { - memcpy(bitmap, map[*pb], 3); + unsigned char *bitmap = symbol->bitmap + r * 3; + if (row && memcmp(pb, pb - symbol->bitmap_width, symbol->bitmap_width) == 0) { + memcpy(bitmap, bitmap - bm_bitmap_width, bm_bitmap_width); + } else { + const unsigned char *const pbe = pb + symbol->bitmap_width; + for (; pb < pbe; pb++, bitmap += 3) { + memcpy(bitmap, map[*pb], 3); + } } } } @@ -262,15 +272,39 @@ static void draw_pt(unsigned char *buf, const int buf_width, const int buf_heigh } } +/* Draw the first line of a bar, to be completed by `copy_bar_line()`; more performant than multiple `draw_bar()`s */ +static void draw_bar_line(unsigned char *pixelbuf, const int xpos, const int xlen, const int ypos, + const int image_width, const char fill) { + unsigned char *pb = pixelbuf + ((size_t) image_width * ypos) + xpos; + + memset(pb, fill, xlen); +} + +/* Fill out a bar code row by copying the first line (called after multiple `draw_bar_line()`s) */ +static void copy_bar_line(unsigned char *pixelbuf, const int xpos, const int xlen, const int ypos, const int ylen, + const int image_width, const int image_height) { + int y; + const int ye = ypos + ylen > image_height ? image_height : ypos + ylen; /* Defensive, should never happen */ + unsigned char *pb = pixelbuf + ((size_t) image_width * ypos) + xpos; + + assert(ypos + ylen <= image_height); // Trigger assert if "should never happen" happens + + for (y = ypos + 1; y < ye; y++) { + memcpy(pixelbuf + ((size_t) image_width * y) + xpos, pb, xlen); + } +} + /* Draw a rectangle */ static void draw_bar(unsigned char *pixelbuf, const int xpos, const int xlen, const int ypos, const int ylen, const int image_width, const int image_height, const char fill) { int y; const int ye = ypos + ylen > image_height ? image_height : ypos + ylen; /* Defensive, should never happen */ - assert(ypos + ylen <= image_height); // Trigger assert if happens + unsigned char *pb = pixelbuf + ((size_t) image_width * ypos) + xpos; - for (y = ypos; y < ye; y++) { - memset(pixelbuf + ((size_t) image_width * y) + xpos, fill, xlen); + assert(ypos + ylen <= image_height); // Trigger assert if "should never happen" happens + + for (y = ypos; y < ye; y++, pb += image_width) { + memset(pb, fill, xlen); } } @@ -682,7 +716,7 @@ static int plot_raster_maxicode(struct zint_symbol *symbol, const int rotate_ang } scaler *= 10.0f; - output_set_whitespace_offsets(symbol, 0 /*hide_text*/, &xoffset, &yoffset, &roffset, &boffset, scaler, + out_set_whitespace_offsets(symbol, 0 /*hide_text*/, &xoffset, &yoffset, &roffset, &boffset, scaler, &xoffset_si, &yoffset_si, &roffset_si, &boffset_si); hex_width = (int) roundf(scaler); /* Short diameter, X in ISO/IEC 16023:2000 Figure 8 (same as W) */ @@ -779,7 +813,7 @@ static int plot_raster_dotty(struct zint_symbol *symbol, const int rotate_angle, dot_radius_s = (symbol->dot_size * scaler) / 2.0f; dot_radius_si = (int) dot_radius_s; - output_set_whitespace_offsets(symbol, 0 /*hide_text*/, &xoffset, &yoffset, &roffset, &boffset, scaler, + out_set_whitespace_offsets(symbol, 0 /*hide_text*/, &xoffset, &yoffset, &roffset, &boffset, scaler, &xoffset_si, &yoffset_si, &roffset_si, &boffset_si); /* TODO: Revisit this overspill stuff, it's hacky */ @@ -884,6 +918,7 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl unsigned char textpart1[5], textpart2[7], textpart3[7], textpart4[2]; int hide_text; int i, r; + int block_width = 0; int text_height; /* Font pixel size (so whole integers) */ float text_gap; /* Gap between barcode and text */ float guard_descent; @@ -910,20 +945,22 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl si = 2; } - large_bar_height = output_large_bar_height(symbol, si /*Round to scale*/); + large_bar_height = out_large_bar_height(symbol, si /*Round to scale*/); symbol_height_si = (int) ceilf(symbol->height * si); main_width = symbol->width; if (is_extendable(symbol->symbology)) { - upceanflag = output_process_upcean(symbol, &main_width, &comp_xoffset, addon, &addon_gap); + upceanflag = out_process_upcean(symbol, &main_width, &comp_xoffset, addon, &addon_gap); } hide_text = ((!symbol->show_hrt) || (ustrlen(symbol->text) == 0) || scaler < 1.0f); - output_set_whitespace_offsets(symbol, hide_text, &xoffset, &yoffset, &roffset, &boffset, si, + out_set_whitespace_offsets(symbol, hide_text, &xoffset, &yoffset, &roffset, &boffset, si, &xoffset_si, &yoffset_si, &roffset_si, &boffset_si); + comp_xoffset_si = xoffset_si + comp_xoffset * si; + /* Note font sizes halved as in pixels */ if (upceanflag) { textflags = UPCEAN_TEXT | (symbol->output_options & SMALL_TEXT); /* Bold not available for UPC/EAN */ @@ -960,40 +997,41 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl yposn = yoffset; /* Plot the body of the symbol to the pixel buffer */ - for (r = 0; r < symbol->rows; r++) { - int yposn_si = yposn * si; - float row_height = symbol->row_height[r] ? symbol->row_height[r] : large_bar_height; - int row_height_si = (int) ceilf(row_height * si); + if (symbol->symbology == BARCODE_ULTRA) { + for (r = 0; r < symbol->rows; r++) { + int yposn_si = yposn * si; + float row_height = symbol->row_height[r]; + int row_height_si = (int) ceilf(row_height * si); - i = 0; - - if (symbol->symbology == BARCODE_ULTRA) { - do { - int module_fill = module_colour_is_set(symbol, r, i); - int block_width = 0; - do { - block_width++; - } while ((i + block_width < symbol->width) - && module_colour_is_set(symbol, r, i + block_width) == module_fill); - if (module_fill) { + for (i = 0; i < symbol->width; i += block_width) { + int fill = module_colour_is_set(symbol, r, i); + for (block_width = 1; (i + block_width < symbol->width) + && module_colour_is_set(symbol, r, i + block_width) == fill; block_width++); + if (fill) { /* a colour block */ - draw_bar(pixelbuf, i * si + xoffset_si, block_width * si, yposn_si, row_height_si, - image_width, image_height, ultra_colour[module_fill]); + draw_bar_line(pixelbuf, i * si + xoffset_si, block_width * si, yposn_si, image_width, + ultra_colour[fill]); } - i += block_width; + } + copy_bar_line(pixelbuf, xoffset_si, image_width - xoffset_si - roffset_si, yposn_si, row_height_si, + image_width, image_height); + yposn += row_height; + } - } while (i < symbol->width); - } else { - do { - float addon_row_height; - int module_fill = module_is_set(symbol, r, i); - int block_width = 0; - do { - block_width++; - } while ((i + block_width < symbol->width) - && module_is_set(symbol, r, i + block_width) == module_fill); + } else if (upceanflag >= 6) { /* UPC-E, EAN-8, UPC-A, EAN-13 */ + for (r = 0; r < symbol->rows; r++) { + int yposn_si = yposn * si; + float row_height = symbol->row_height[r] ? symbol->row_height[r] : large_bar_height; + int row_height_si = (int) ceilf(row_height * si); - if (upceanflag && (addon_latch == 0) && (r == (symbol->rows - 1)) && (i > main_width)) { + for (i = 0; i < symbol->width; i += block_width) { + int fill = module_is_set(symbol, r, i); + for (block_width = 1; (i + block_width < symbol->width) + && module_is_set(symbol, r, i + block_width) == fill; block_width++); + if ((r == (symbol->rows - 1)) && (i > main_width) && (addon_latch == 0)) { + float addon_row_height; + copy_bar_line(pixelbuf, xoffset_si, main_width * si, yposn_si, row_height_si, image_width, + image_height); yposn_si += (text_height + text_gap) * si; addon_text_yposn = yposn * si; addon_row_height = row_height - (text_height + text_gap); @@ -1006,127 +1044,110 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl row_height_si = addon_row_height * si; addon_latch = 1; } - if (module_fill) { + if (fill) { /* a bar */ - draw_bar(pixelbuf, i * si + xoffset_si, block_width * si, yposn_si, row_height_si, image_width, - image_height, DEFAULT_INK); + draw_bar_line(pixelbuf, i * si + xoffset_si, block_width * si, yposn_si, image_width, + DEFAULT_INK); } - i += block_width; - - } while (i < symbol->width); + } + if (addon_latch) { + copy_bar_line(pixelbuf, xoffset_si + main_width * si, + image_width - main_width * si - xoffset_si - roffset_si, yposn_si, row_height_si, + image_width, image_height); + } else { + copy_bar_line(pixelbuf, xoffset_si, image_width - xoffset_si - roffset_si, yposn_si, row_height_si, + image_width, image_height); + } + yposn += row_height; + } + + } else { + for (r = 0; r < symbol->rows; r++) { + int yposn_si = yposn * si; + float row_height = symbol->row_height[r] ? symbol->row_height[r] : large_bar_height; + int row_height_si = (int) ceilf(row_height * si); + + for (i = 0; i < symbol->width; i += block_width) { + int fill = module_is_set(symbol, r, i); + for (block_width = 1; (i + block_width < symbol->width) + && module_is_set(symbol, r, i + block_width) == fill; block_width++); + if (fill) { + /* a bar */ + draw_bar_line(pixelbuf, i * si + xoffset_si, block_width * si, yposn_si, image_width, + DEFAULT_INK); + } + } + copy_bar_line(pixelbuf, xoffset_si, image_width - xoffset_si - roffset_si, yposn_si, row_height_si, + image_width, image_height); + yposn += row_height; } - yposn += row_height; } - comp_xoffset_si = xoffset_si + comp_xoffset * si; - - if (upceanflag) { + if (guard_descent && upceanflag >= 6) { /* UPC-E, EAN-8, UPC-A, EAN-13 */ /* Guard bar extension */ int guard_yoffset_si = yoffset_si + symbol_height_si; int guard_descent_si = guard_descent * si; if (upceanflag == 6) { /* UPC-E */ - draw_bar(pixelbuf, 0 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 2 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 46 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 48 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 50 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); + draw_bar_line(pixelbuf, 0 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 2 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 46 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 48 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 50 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); } else if (upceanflag == 8) { /* EAN-8 */ - draw_bar(pixelbuf, 0 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 2 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 32 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 34 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 64 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 66 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); + draw_bar_line(pixelbuf, 0 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 2 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 32 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 34 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 64 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 66 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); } else if (upceanflag == 12) { /* UPC-A */ - int latch = 1; - - i = 0 + comp_xoffset; - do { - int module_fill = module_is_set(symbol, symbol->rows - 1, i); - int block_width = 0; - do { - block_width++; - } while ((i + block_width < symbol->width) - && module_is_set(symbol, symbol->rows - 1, i + block_width) == module_fill); - if (latch == 1) { - /* a bar */ - draw_bar(pixelbuf, i * si + xoffset_si, block_width * si, - guard_yoffset_si, guard_descent_si, image_width, image_height, DEFAULT_INK); - latch = 0; - } else { - /* a space */ - latch = 1; + for (i = 0 + comp_xoffset; i < 11 + comp_xoffset; i += block_width) { + int fill = module_is_set(symbol, symbol->rows - 1, i); + for (block_width = 1; (i + block_width < symbol->width) + && module_is_set(symbol, symbol->rows - 1, i + block_width) == fill; + block_width++); + if (fill) { + draw_bar_line(pixelbuf, i * si + xoffset_si, block_width * si, guard_yoffset_si, image_width, + DEFAULT_INK); } - i += block_width; - } while (i < 11 + comp_xoffset); - draw_bar(pixelbuf, 46 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 48 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - latch = 1; - i = 85 + comp_xoffset; - do { - int module_fill = module_is_set(symbol, symbol->rows - 1, i); - int block_width = 0; - do { - block_width++; - } while ((i + block_width < symbol->width) - && module_is_set(symbol, symbol->rows - 1, i + block_width) == module_fill); - if (latch == 1) { - /* a bar */ - draw_bar(pixelbuf, i * si + xoffset_si, block_width * si, - guard_yoffset_si, guard_descent_si, image_width, image_height, DEFAULT_INK); - latch = 0; - } else { - /* a space */ - latch = 1; + } + draw_bar_line(pixelbuf, 46 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 48 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + for (i = 85 + comp_xoffset; i < 96 + comp_xoffset; i += block_width) { + int fill = module_is_set(symbol, symbol->rows - 1, i); + for (block_width = 1; (i + block_width < symbol->width) + && module_is_set(symbol, symbol->rows - 1, i + block_width) == fill; + block_width++); + if (fill) { + draw_bar_line(pixelbuf, i * si + xoffset_si, block_width * si, guard_yoffset_si, image_width, + DEFAULT_INK); } - i += block_width; - } while (i < 96 + comp_xoffset); + } - } else if (upceanflag == 13) { /* EAN-13 */ - draw_bar(pixelbuf, 0 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 2 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 46 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 48 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 92 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); - draw_bar(pixelbuf, 94 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, guard_descent_si, - image_width, image_height, DEFAULT_INK); + } else { /* EAN-13 */ + draw_bar_line(pixelbuf, 0 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 2 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 46 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 48 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 92 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); + draw_bar_line(pixelbuf, 94 * si + comp_xoffset_si, 1 * si, guard_yoffset_si, image_width, DEFAULT_INK); } + copy_bar_line(pixelbuf, comp_xoffset_si, image_width - comp_xoffset_si - roffset_si, guard_yoffset_si, + guard_descent_si, image_width, image_height); } /* Add the text */ if (!hide_text) { - int textdone = 0; - int text_xposn; - int text_yposn; - - text_yposn = yoffset_si + symbol_height_si + (int) (text_gap * si); /* Calculated to top of text */ + int text_yposn = yoffset_si + symbol_height_si + (int) (text_gap * si); /* Calculated to top of text */ if (symbol->border_width > 0 && (symbol->output_options & (BARCODE_BOX | BARCODE_BIND))) { text_yposn += symbol->border_width * si; } - if (upceanflag) { + if (upceanflag >= 6) { /* UPC-E, EAN-8, UPC-A, EAN-13 */ /* Note font sizes halved as in pixels */ @@ -1136,10 +1157,10 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl /* Halved again to get middle position that draw_string() expects */ int ean_width_adj = (UPCEAN_FONT_WIDTH + 3) / 4; - output_upcean_split_text(upceanflag, symbol->text, textpart1, textpart2, textpart3, textpart4); + out_upcean_split_text(upceanflag, symbol->text, textpart1, textpart2, textpart3, textpart4); if (upceanflag == 6) { /* UPC-E */ - text_xposn = -(5 + upcea_width_adj) * si + comp_xoffset_si; + int text_xposn = -(5 + upcea_width_adj) * si + comp_xoffset_si; draw_string(pixelbuf, textpart1, text_xposn, text_yposn + upcea_height_adj, textflags | SMALL_TEXT, image_width, image_height, si); text_xposn = 24 * si + comp_xoffset_si; @@ -1147,7 +1168,6 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl text_xposn = (51 + 3 + upcea_width_adj) * si + comp_xoffset_si; draw_string(pixelbuf, textpart3, text_xposn, text_yposn + upcea_height_adj, textflags | SMALL_TEXT, image_width, image_height, si); - textdone = 1; switch (ustrlen(addon)) { case 2: text_xposn = (61 + addon_gap) * si + comp_xoffset_si; @@ -1162,11 +1182,10 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl } } else if (upceanflag == 8) { /* EAN-8 */ - text_xposn = 17 * si + comp_xoffset_si; + int text_xposn = 17 * si + comp_xoffset_si; draw_string(pixelbuf, textpart1, text_xposn, text_yposn, textflags, image_width, image_height, si); text_xposn = 50 * si + comp_xoffset_si; draw_string(pixelbuf, textpart2, text_xposn, text_yposn, textflags, image_width, image_height, si); - textdone = 1; switch (ustrlen(addon)) { case 2: text_xposn = (77 + addon_gap) * si + comp_xoffset_si; @@ -1181,7 +1200,7 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl } } else if (upceanflag == 12) { /* UPC-A */ - text_xposn = (-(5 + upcea_width_adj)) * si + comp_xoffset_si; + int text_xposn = (-(5 + upcea_width_adj)) * si + comp_xoffset_si; draw_string(pixelbuf, textpart1, text_xposn, text_yposn + upcea_height_adj, textflags | SMALL_TEXT, image_width, image_height, si); text_xposn = 27 * si + comp_xoffset_si; @@ -1191,7 +1210,6 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl text_xposn = (95 + 5 + upcea_width_adj) * si + comp_xoffset_si; draw_string(pixelbuf, textpart4, text_xposn, text_yposn + upcea_height_adj, textflags | SMALL_TEXT, image_width, image_height, si); - textdone = 1; switch (ustrlen(addon)) { case 2: text_xposn = (105 + addon_gap) * si + comp_xoffset_si; @@ -1205,14 +1223,13 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl break; } - } else if (upceanflag == 13) { /* EAN-13 */ - text_xposn = (-(5 + ean_width_adj)) * si + comp_xoffset_si; + } else { /* EAN-13 */ + int text_xposn = (-(5 + ean_width_adj)) * si + comp_xoffset_si; draw_string(pixelbuf, textpart1, text_xposn, text_yposn, textflags, image_width, image_height, si); text_xposn = 24 * si + comp_xoffset_si; draw_string(pixelbuf, textpart2, text_xposn, text_yposn, textflags, image_width, image_height, si); text_xposn = 71 * si + comp_xoffset_si; draw_string(pixelbuf, textpart3, text_xposn, text_yposn, textflags, image_width, image_height, si); - textdone = 1; switch (ustrlen(addon)) { case 2: text_xposn = (105 + addon_gap) * si + comp_xoffset_si; @@ -1226,14 +1243,12 @@ static int plot_raster_default(struct zint_symbol *symbol, const int rotate_angl break; } } - } - - if (!textdone) { + } else { + int text_xposn = (main_width / 2) * si + comp_xoffset_si; /* Suppress clang-analyzer-core.CallAndMessage warning */ unsigned char local_text[sizeof(symbol->text)] = {0}; to_iso8859_1(symbol->text, local_text); /* Put the human readable text at the bottom */ - text_xposn = (main_width / 2) * si + comp_xoffset_si; draw_string(pixelbuf, local_text, text_xposn, text_yposn, textflags, image_width, image_height, si); } } @@ -1319,7 +1334,7 @@ INTERNAL int plot_raster(struct zint_symbol *symbol, int rotate_angle, int file_ } #endif /* NO_PNG */ - error = output_check_colour_options(symbol); + error = out_check_colour_options(symbol); if (error != 0) { return error; } diff --git a/backend/reedsol.c b/backend/reedsol.c index 53aea312..d54d2ad5 100644 --- a/backend/reedsol.c +++ b/backend/reedsol.c @@ -106,8 +106,8 @@ INTERNAL void rs_init_gf(rs_t *rs, const unsigned int prime_poly) { INTERNAL void rs_init_code(rs_t *rs, const int nsym, int index) { int i, k; - const unsigned char *logt = rs->logt; - const unsigned char *alog = rs->alog; + const unsigned char *const logt = rs->logt; + const unsigned char *const alog = rs->alog; unsigned char *rspoly = rs->rspoly; rs->nsym = nsym; @@ -129,9 +129,9 @@ INTERNAL void rs_init_code(rs_t *rs, const int nsym, int index) { * and places them in reverse order in res */ INTERNAL void rs_encode(const rs_t *rs, const int datalen, const unsigned char *data, unsigned char *res) { int i, k; - const unsigned char *logt = rs->logt; - const unsigned char *alog = rs->alog; - const unsigned char *rspoly = rs->rspoly; + const unsigned char *const logt = rs->logt; + const unsigned char *const alog = rs->alog; + const unsigned char *const rspoly = rs->rspoly; const int nsym = rs->nsym; memset(res, 0, nsym); @@ -157,9 +157,9 @@ INTERNAL void rs_encode(const rs_t *rs, const int datalen, const unsigned char * INTERNAL void rs_encode_uint(const rs_t *rs, const int datalen, const unsigned int *data, unsigned int *res) { int i, k; - const unsigned char *logt = rs->logt; - const unsigned char *alog = rs->alog; - const unsigned char *rspoly = rs->rspoly; + const unsigned char *const logt = rs->logt; + const unsigned char *const alog = rs->alog; + const unsigned char *const rspoly = rs->rspoly; const int nsym = rs->nsym; memset(res, 0, sizeof(unsigned int) * nsym); diff --git a/backend/rss.c b/backend/rss.c index cac8d13b..3199727c 100644 --- a/backend/rss.c +++ b/backend/rss.c @@ -177,18 +177,20 @@ static void dbar_set_gtin14_hrt(struct zint_symbol *symbol, const unsigned char /* Expand from a width pattern to a bit pattern */ static int dbar_expand(struct zint_symbol *symbol, int writer, int *p_latch, const int width) { int j; - int latch = *p_latch; - for (j = 0; j < width; j++) { - if (latch) { + if (*p_latch) { + for (j = 0; j < width; j++) { set_module(symbol, symbol->rows, writer); - } else { - unset_module(symbol, symbol->rows, writer); + writer++; + } + } else { + for (j = 0; j < width; j++) { + unset_module(symbol, symbol->rows, writer); + writer++; } - writer++; } - *p_latch = !latch; + *p_latch = !*p_latch; return writer; } @@ -304,7 +306,7 @@ INTERNAL int dbar_omn_cc(struct zint_symbol *symbol, unsigned char source[], int strcpy(symbol->errtxt, "380: Input too long (14 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, src_len) != 0) { + if (!is_sane(NEON_F, source, src_len)) { strcpy(symbol->errtxt, "381: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -641,7 +643,7 @@ INTERNAL int dbar_ltd_cc(struct zint_symbol *symbol, unsigned char source[], int strcpy(symbol->errtxt, "382: Input too long (14 character maximum)"); return ZINT_ERROR_TOO_LONG; } - if (is_sane(NEON, source, src_len) != 0) { + if (!is_sane(NEON_F, source, src_len)) { strcpy(symbol->errtxt, "383: Invalid character in data (digits only)"); return ZINT_ERROR_INVALID_DATA; } diff --git a/backend/svg.c b/backend/svg.c index 5df16051..ee22d8fe 100644 --- a/backend/svg.c +++ b/backend/svg.c @@ -128,7 +128,7 @@ INTERNAL int svg_plot(struct zint_symbol *symbol) { int bg_alpha = 0xff; int fg_alpha = 0xff; float fg_alpha_opacity = 0.0f, bg_alpha_opacity = 0.0f; - const char *font_family = "Helvetica, sans-serif"; + const char font_family[] = "Helvetica, sans-serif"; int bold; struct zint_vector_rect *rect; @@ -317,7 +317,7 @@ INTERNAL int svg_plot(struct zint_symbol *symbol) { && (!is_extendable(symbol->symbology) || (symbol->output_options & SMALL_TEXT)); string = symbol->vector->strings; while (string) { - const char *halign = string->halign == 2 ? "end" : string->halign == 1 ? "start" : "middle"; + const char *const halign = string->halign == 2 ? "end" : string->halign == 1 ? "start" : "middle"; fprintf(fsvg, " x, string->y, halign); fprintf(fsvg, " font-family=\"%s\" font-size=\"%.1f\"", font_family, string->fsize); if (bold) { diff --git a/backend/telepen.c b/backend/telepen.c index 00895d0b..24c8f3f4 100644 --- a/backend/telepen.c +++ b/backend/telepen.c @@ -34,50 +34,63 @@ /* Telepen Barcode Symbology information and History (BSiH) https://telepen.co.uk/wp-content/uploads/2018/10/Barcode-Symbology-information-and-History.pdf */ -#define SODIUM "0123456789X" +#define SODIUM_X_F (IS_NUM_F | IS_UX__F) /* SODIUM "0123456789X" */ #include #include "common.h" -static char *TeleTable[] = { - "31313131", "1131313111", "33313111", "1111313131", - "3111313111", "11333131", "13133131", "111111313111", - "31333111", "1131113131", "33113131", "1111333111", - "3111113131", "1113133111", "1311133111", "111111113131", - "3131113111", "11313331", "333331", "111131113111", - "31113331", "1133113111", "1313113111", "1111113331", - "31131331", "113111113111", "3311113111", "1111131331", - "311111113111", "1113111331", "1311111331", "11111111113111", - "31313311", "1131311131", "33311131", "1111313311", - "3111311131", "11333311", "13133311", "111111311131", - "31331131", "1131113311", "33113311", "1111331131", - "3111113311", "1113131131", "1311131131", "111111113311", - "3131111131", "1131131311", "33131311", "111131111131", - "3111131311", "1133111131", "1313111131", "111111131311", - "3113111311", "113111111131", "3311111131", "111113111311", - "311111111131", "111311111311", "131111111311", "11111111111131", - "3131311111", "11313133", "333133", "111131311111", - "31113133", "1133311111", "1313311111", "1111113133", - "313333", "113111311111", "3311311111", "11113333", - "311111311111", "11131333", "13111333", "11111111311111", - "31311133", "1131331111", "33331111", "1111311133", - "3111331111", "11331133", "13131133", "111111331111", - "3113131111", "1131111133", "33111133", "111113131111", - "3111111133", "111311131111", "131111131111", "111111111133", - "31311313", "113131111111", "3331111111", "1111311313", - "311131111111", "11331313", "13131313", "11111131111111", - "3133111111", "1131111313", "33111313", "111133111111", - "3111111313", "111313111111", "131113111111", "111111111313", - "313111111111", "1131131113", "33131113", "11113111111111", - "3111131113", "113311111111", "131311111111", "111111131113", - "3113111113", "11311111111111", "331111111111", "111113111113", - "31111111111111", "111311111113", "131111111113", "1111111111111111", +static char TeleTable[128][16] = { + { "31313131" }, { "1131313111" }, { "33313111" }, { "1111313131" }, + { "3111313111" }, { "11333131" }, { "13133131" }, { "111111313111" }, + { "31333111" }, { "1131113131" }, { "33113131" }, { "1111333111" }, + { "3111113131" }, { "1113133111" }, { "1311133111" }, { "111111113131" }, + { "3131113111" }, { "11313331" }, { "333331" }, { "111131113111" }, + { "31113331" }, { "1133113111" }, { "1313113111" }, { "1111113331" }, + { "31131331" }, { "113111113111" }, { "3311113111" }, { "1111131331" }, + { "311111113111" }, { "1113111331" }, { "1311111331" }, { "11111111113111" }, + { "31313311" }, { "1131311131" }, { "33311131" }, { "1111313311" }, + { "3111311131" }, { "11333311" }, { "13133311" }, { "111111311131" }, + { "31331131" }, { "1131113311" }, { "33113311" }, { "1111331131" }, + { "3111113311" }, { "1113131131" }, { "1311131131" }, { "111111113311" }, + { "3131111131" }, { "1131131311" }, { "33131311" }, { "111131111131" }, + { "3111131311" }, { "1133111131" }, { "1313111131" }, { "111111131311" }, + { "3113111311" }, { "113111111131" }, { "3311111131" }, { "111113111311" }, + { "311111111131" }, { "111311111311" }, { "131111111311" }, { "11111111111131" }, + { "3131311111" }, { "11313133" }, { "333133" }, { "111131311111" }, + { "31113133" }, { "1133311111" }, { "1313311111" }, { "1111113133" }, + { "313333" }, { "113111311111" }, { "3311311111" }, { "11113333" }, + { "311111311111" }, { "11131333" }, { "13111333" }, { "11111111311111" }, + { "31311133" }, { "1131331111" }, { "33331111" }, { "1111311133" }, + { "3111331111" }, { "11331133" }, { "13131133" }, { "111111331111" }, + { "3113131111" }, { "1131111133" }, { "33111133" }, { "111113131111" }, + { "3111111133" }, { "111311131111" }, { "131111131111" }, { "111111111133" }, + { "31311313" }, { "113131111111" }, { "3331111111" }, { "1111311313" }, + { "311131111111" }, { "11331313" }, { "13131313" }, { "11111131111111" }, + { "3133111111" }, { "1131111313" }, { "33111313" }, { "111133111111" }, + { "3111111313" }, { "111313111111" }, { "131113111111" }, { "111111111313" }, + { "313111111111" }, { "1131131113" }, { "33131113" }, { "11113111111111" }, + { "3111131113" }, { "113311111111" }, { "131311111111" }, { "111111131113" }, + { "3113111113" }, { "11311111111111" }, { "331111111111" }, { "111113111113" }, + { "31111111111111" }, { "111311111113" }, { "131111111113" }, + {'1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'}, +}; +/* Generated by "backend/tests/test_telepen -f generate_lens -g" */ +static const char TeleLens[128] = { + 8, 10, 8, 10, 10, 8, 8, 12, 8, 10, 8, 10, 10, 10, 10, 12, + 10, 8, 6, 12, 8, 10, 10, 10, 8, 12, 10, 10, 12, 10, 10, 14, + 8, 10, 8, 10, 10, 8, 8, 12, 8, 10, 8, 10, 10, 10, 10, 12, + 10, 10, 8, 12, 10, 10, 10, 12, 10, 12, 10, 12, 12, 12, 12, 14, + 10, 8, 6, 12, 8, 10, 10, 10, 6, 12, 10, 8, 12, 8, 8, 14, + 8, 10, 8, 10, 10, 8, 8, 12, 10, 10, 8, 12, 10, 12, 12, 12, + 8, 12, 10, 10, 12, 8, 8, 14, 10, 10, 8, 12, 10, 12, 12, 12, + 12, 10, 8, 14, 10, 12, 12, 12, 10, 14, 12, 12, 14, 12, 12, 16 }; INTERNAL int telepen(struct zint_symbol *symbol, unsigned char source[], int src_len) { int i, count, check_digit; int error_number; char dest[521]; /* 12 (start) + 30 * 16 (max for DELs) + 16 (check digit) + 12 (stop) + 1 = 521 */ + char *d = dest; error_number = 0; @@ -88,7 +101,8 @@ INTERNAL int telepen(struct zint_symbol *symbol, unsigned char source[], int src return ZINT_ERROR_TOO_LONG; } /* Start character */ - strcpy(dest, TeleTable['_']); + memcpy(d, TeleTable['_'], 12); + d += 12; for (i = 0; i < src_len; i++) { if (source[i] > 127) { @@ -96,7 +110,8 @@ INTERNAL int telepen(struct zint_symbol *symbol, unsigned char source[], int src strcpy(symbol->errtxt, "391: Invalid character in input data, extended ASCII not allowed"); return ZINT_ERROR_INVALID_DATA; } - strcat(dest, TeleTable[source[i]]); + memcpy(d, TeleTable[source[i]], TeleLens[source[i]]); + d += TeleLens[source[i]]; count += source[i]; } @@ -104,14 +119,16 @@ INTERNAL int telepen(struct zint_symbol *symbol, unsigned char source[], int src if (check_digit == 127) { check_digit = 0; } - strcat(dest, TeleTable[check_digit]); + memcpy(d, TeleTable[check_digit], TeleLens[check_digit]); + d += TeleLens[check_digit]; if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit); /* Stop character */ - strcat(dest, TeleTable['z']); + memcpy(d, TeleTable['z'], 14); + d += 14; - expand(symbol, dest); + expand(symbol, dest, d - dest); if (symbol->output_options & COMPLIANT_HEIGHT) { /* Default height from various Telepen docs is based on default 26pt at X 0.01125" @@ -137,6 +154,7 @@ INTERNAL int telepen_num(struct zint_symbol *symbol, unsigned char source[], int int error_number = 0; int i; char dest[521]; /* 12 (start) + 30 * 16 (max for DELs) + 16 (check digit) + 12 (stop) + 1 = 521 */ + char *d = dest; unsigned char temp[64]; count = 0; @@ -146,8 +164,8 @@ INTERNAL int telepen_num(struct zint_symbol *symbol, unsigned char source[], int return ZINT_ERROR_TOO_LONG; } ustrcpy(temp, source); - to_upper(temp); - if (is_sane(SODIUM, temp, src_len) != 0) { + to_upper(temp, src_len); + if (!is_sane(SODIUM_X_F, temp, src_len)) { strcpy(symbol->errtxt, "393: Invalid character in data (digits and \"X\" only)"); return ZINT_ERROR_INVALID_DATA; } @@ -161,7 +179,8 @@ INTERNAL int telepen_num(struct zint_symbol *symbol, unsigned char source[], int } /* Start character */ - strcpy(dest, TeleTable['_']); + memcpy(d, TeleTable['_'], 12); + d += 12; for (i = 0; i < src_len; i += 2) { if (temp[i] == 'X') { @@ -177,21 +196,24 @@ INTERNAL int telepen_num(struct zint_symbol *symbol, unsigned char source[], int glyph += 27; count += glyph; } - strcat(dest, TeleTable[glyph]); + memcpy(d, TeleTable[glyph], TeleLens[glyph]); + d += TeleLens[glyph]; } check_digit = 127 - (count % 127); if (check_digit == 127) { check_digit = 0; } - strcat(dest, TeleTable[check_digit]); + memcpy(d, TeleTable[check_digit], TeleLens[check_digit]); + d += TeleLens[check_digit]; if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit); /* Stop character */ - strcat(dest, TeleTable['z']); + memcpy(d, TeleTable['z'], 14); + d += 14; - expand(symbol, dest); + expand(symbol, dest, d - dest); if (symbol->output_options & COMPLIANT_HEIGHT) { (void) set_height(symbol, 0.0f, 32.0f, 0, 1 /*no_errtxt*/); /* Same as alphanumeric Telepen */ diff --git a/backend/tests/test_2of5.c b/backend/tests/test_2of5.c index 1b56a437..d5a1161a 100644 --- a/backend/tests/test_2of5.c +++ b/backend/tests/test_2of5.c @@ -236,61 +236,67 @@ static void test_encode(int index, int generate, int debug) { /* 1*/ { BARCODE_C25STANDARD, 1, "87654321", 0, 1, 107, "With check digit", "11110101011101000101010001110100011101011101110101011101110111000101010001011101110101110100010111011110101" }, - /* 2*/ { BARCODE_C25INTER, -1, "87654321", 0, 1, 81, "Interleaved Code 2 of 5, even; verified manually against tec-it", + /* 2*/ { BARCODE_C25STANDARD, -1, "1234567890", 0, 1, 117, "", + "111101010111010111010001011101110001010101110111011101110101000111010101000111011101000101000100010101110001011110101" + }, + /* 3*/ { BARCODE_C25INTER, -1, "87654321", 0, 1, 81, "Interleaved Code 2 of 5, even; verified manually against tec-it", "101011101010111000100010001110111000101010001000111010111010001110101011100011101" }, - /* 3*/ { BARCODE_C25INTER, 1, "87654321", 0, 1, 99, "With check digit", + /* 4*/ { BARCODE_C25INTER, 1, "87654321", 0, 1, 99, "With check digit", "101010001011101110001010100010001110111011101011100010100011101110001010100011101000101011100011101" }, - /* 4*/ { BARCODE_C25INTER, -1, "7654321", 0, 1, 81, "Interleaved Code 2 of 5, odd", + /* 5*/ { BARCODE_C25INTER, -1, "7654321", 0, 1, 81, "Interleaved Code 2 of 5, odd", "101010101110111000100010001110111000101010001000111010111010001110101011100011101" }, - /* 5*/ { BARCODE_C25INTER, 1, "7654321", 0, 1, 81, "With check digit", + /* 6*/ { BARCODE_C25INTER, 1, "7654321", 0, 1, 81, "With check digit", "101010100010001110111011101011100010100011101110001010100011101010001000111011101" }, - /* 6*/ { BARCODE_C25INTER, -1, "602003", 0, 1, 63, "DX cartridge barcode https://en.wikipedia.org/wiki/Interleaved_2_of_5 example", + /* 7*/ { BARCODE_C25INTER, -1, "602003", 0, 1, 63, "DX cartridge barcode https://en.wikipedia.org/wiki/Interleaved_2_of_5 example", "101010111011100010001010111010001000111010001000111011101011101" }, - /* 7*/ { BARCODE_C25IATA, -1, "87654321", 0, 1, 121, "IATA Code 2 of 5; verified manually against tec-it", + /* 8*/ { BARCODE_C25IATA, -1, "87654321", 0, 1, 121, "IATA Code 2 of 5; verified manually against tec-it", "1010111010101110101010101110111010111011101010111010111010101010111010111011101110101010101110101011101110101010111011101" }, - /* 8*/ { BARCODE_C25IATA, 1, "87654321", 0, 1, 135, "With check digit", + /* 9*/ { BARCODE_C25IATA, 1, "87654321", 0, 1, 135, "With check digit", "101011101010111010101010111011101011101110101011101011101010101011101011101110111010101010111010101110111010101011101011101010111011101" }, - /* 9*/ { BARCODE_C25LOGIC, -1, "87654321", 0, 1, 89, "Code 2 of 5 Data Logic; verified manually against tec-it", + /* 10*/ { BARCODE_C25LOGIC, -1, "87654321", 0, 1, 89, "Code 2 of 5 Data Logic; verified manually against tec-it", "10101110100010101000111010001110101110111010101110111011100010101000101110111010111011101" }, - /* 10*/ { BARCODE_C25LOGIC, 1, "87654321", 0, 1, 99, "With check digit", + /* 11*/ { BARCODE_C25LOGIC, 1, "87654321", 0, 1, 99, "With check digit", "101011101000101010001110100011101011101110101011101110111000101010001011101110101110100010111011101" }, - /* 11*/ { BARCODE_C25IND, -1, "87654321", 0, 1, 131, "Industrial Code 2 of 5; verified manually against tec-it", + /* 12*/ { BARCODE_C25IND, -1, "87654321", 0, 1, 131, "Industrial Code 2 of 5; verified manually against tec-it", "11101110101110101011101010101011101110101110111010101110101110101010101110101110111011101010101011101010111011101010101110111010111" }, - /* 12*/ { BARCODE_C25IND, 1, "87654321", 0, 1, 145, "With check digit", + /* 13*/ { BARCODE_C25IND, 1, "87654321", 0, 1, 145, "With check digit", "1110111010111010101110101010101110111010111011101010111010111010101010111010111011101110101010101110101011101110101010111010111010101110111010111" }, - /* 13*/ { BARCODE_DPLEIT, -1, "0000087654321", 0, 1, 135, "Deutsche Post Leitcode; verified manually against tec-it", + /* 14*/ { BARCODE_C25IND, -1, "1234567890", 0, 1, 159, "", + "111011101011101010101110101110101011101110111010101010101110101110111010111010101011101110101010101011101110111010101110101011101011101010101110111010111010111" + }, + /* 15*/ { BARCODE_DPLEIT, -1, "0000087654321", 0, 1, 135, "Deutsche Post Leitcode; verified manually against tec-it", "101010101110001110001010101110001110001010001011101110001010100010001110111011101011100010100011101110001010100011101000100010111011101" }, - /* 14*/ { BARCODE_DPLEIT, -1, "5082300702800", 0, 1, 135, "Deutsche Post Leitcode https://de.wikipedia.org/wiki/Leitcode example", + /* 16*/ { BARCODE_DPLEIT, -1, "5082300702800", 0, 1, 135, "Deutsche Post Leitcode https://de.wikipedia.org/wiki/Leitcode example", "101011101011100010001011101000101110100011101110100010001010101110111000100010100011101110100011101010001110001010001011100011101011101" }, - /* 15*/ { BARCODE_DPIDENT, -1, "00087654321", 0, 1, 117, "Deutsche Post Identcode; verified manually against tec-it", + /* 17*/ { BARCODE_DPIDENT, -1, "00087654321", 0, 1, 117, "Deutsche Post Identcode; verified manually against tec-it", "101010101110001110001010001011101110001010100010001110111011101011100010100011101110001010100011101000100010111011101" }, - /* 16*/ { BARCODE_DPIDENT, -1, "39601313414", 0, 1, 117, "Deutsche Post Identcode https://de.wikipedia.org/wiki/Leitcode example", + /* 18*/ { BARCODE_DPIDENT, -1, "39601313414", 0, 1, 117, "Deutsche Post Identcode https://de.wikipedia.org/wiki/Leitcode example", "101011101110001010001010111011100010001011100010001010111011100010001010111010001011101011100010101110001000111011101" }, - /* 17*/ { BARCODE_ITF14, -1, "0000087654321", 0, 1, 135, "ITF-14; verified manually against tec-it", + /* 19*/ { BARCODE_ITF14, -1, "0000087654321", 0, 1, 135, "ITF-14; verified manually against tec-it", "101010101110001110001010101110001110001010001011101110001010100010001110111011101011100010100011101110001010100011101000101011100011101" }, - /* 18*/ { BARCODE_ITF14, -1, "0950110153000", 0, 1, 135, "GS1 General Specifications Figure 5.1-2", + /* 20*/ { BARCODE_ITF14, -1, "0950110153000", 0, 1, 135, "GS1 General Specifications Figure 5.1-2", "101010100011101110001011101011100010001011100010101011100010001011101110100011100010001110101010101110001110001010001000111011101011101" }, - /* 19*/ { BARCODE_ITF14, -1, "1540014128876", 0, 1, 135, "GS1 General Specifications Figure 5.3.2.4-1", + /* 21*/ { BARCODE_ITF14, -1, "1540014128876", 0, 1, 135, "GS1 General Specifications Figure 5.3.2.4-1", "101011100010100010111010101110001000111010001011101110100010001011101011100010001110101000111011101010111000100010001110001110101011101" }, - /* 20*/ { BARCODE_ITF14, -1, "0950110153001", 0, 1, 135, "GS1 General Specifications Figure 5.3.6-1", + /* 22*/ { BARCODE_ITF14, -1, "0950110153001", 0, 1, 135, "GS1 General Specifications Figure 5.3.6-1", "101010100011101110001011101011100010001011100010101011100010001011101110100011100010001110101010101110001110001011101010001000111011101" }, }; @@ -351,6 +357,107 @@ static void test_encode(int index, int generate, int debug) { 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(int index, int debug) { + + struct item { + int symbology; + int option_2; + char *data; + int ret; + + int expected_rows; + int expected_width; + char *comment; + }; + struct item data[] = { + /* 0*/ { BARCODE_C25INTER, -1, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", 0, 1, 819, "C25INTER 90" }, + /* 1*/ { BARCODE_C25INTER, -1, "1234567890", 0, 1, 99, "C25INTER 10" }, + /* 2*/ { BARCODE_C25STANDARD, -1, "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 0, 1, 817, "C25STANDARD 80" }, + /* 3*/ { BARCODE_C25STANDARD, -1, "1234567890", 0, 1, 117, "C25STANDARD 10" }, + }; + 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 (index != -1 && i != index) 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(remove(symbol->outfile), "i:%d remove(%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 (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, has_index, has_generate, has_debug */ @@ -358,6 +465,7 @@ int main(int argc, char *argv[]) { { "test_hrt", test_hrt, 1, 0, 1 }, { "test_input", test_input, 1, 0, 1 }, { "test_encode", test_encode, 1, 1, 1 }, + { "test_perf", test_perf, 1, 0, 1 }, }; testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); diff --git a/backend/tests/test_auspost.c b/backend/tests/test_auspost.c index f9c6b2c0..e0674aa1 100644 --- a/backend/tests/test_auspost.c +++ b/backend/tests/test_auspost.c @@ -236,17 +236,42 @@ static void test_encode(int index, int generate, int debug) { "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000101010100010101010101000100000101010000010100010100010101010001010000010001010100000100010101000000000101000001010100000000010000" }, - /* 5*/ { BARCODE_AUSREPLY, "12345678", 0, 3, 73, "Verified manually against tec-it", + /* 5*/ { BARCODE_AUSPOST, "12345678DEGHJKLMNO", 0, 3, 133, "62 Custom 3 C encoding GDSET 1st part", + "1000001010001010100010101010100000100010000010101010101010001010001010101010101010100010101010101010100000001010000010000000000010100" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "0000101010101000101000100000001010101000101010001010000010101010100000101000100000101000001000000000001000001010000010001010001010000" + }, + /* 6*/ { BARCODE_AUSPOST, "23456789PQRSTUVWXY", 0, 3, 133, "62 Custom 3 C encoding GDSET 2nd part", + "1000001010001000101010101000001000100000001010001010001010000000101000101000100000101000101000100000001000101000101010101000101010100" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "0000101010101010001000000010101010001010001000101000100000101010101010100010101010001010000010001010101000000010001000001010101000000" + }, + /* 7*/ { BARCODE_AUSPOST, "34567890Zcefgijklm", 0, 3, 133, "62 Custom 3 C encoding GDSET 3rd part", + "1000001010001010101010000010001000000010101000001010001010000010100010100010001010001010000010000000100000101000100000001010001010100" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "0000101010100010000000101010100010100010101010100010000010000000100000000000001000000000001000000010100000101000000010101010100010000" + }, + /* 8*/ { BARCODE_AUSPOST, "12345678lnopqrstuv", 0, 3, 133, "62 Custom 3 C encoding GDSET 4th part", + "1000001010001010100010101010100000100010000010000000100000000000001000001000000000000000100000100000000000001010001010101000000010100" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "0000101010101000101000100000001010101000101000000010000010100010001010000010001010000000100000000000100000100000001010001000100000000" + }, + /* 9*/ { BARCODE_AUSPOST, "09876543wxy# ", 0, 3, 103, "59 Custom 2 C encoding GDSET 5th part", + "1000100000101010001000000010001010001010101000001000001000000010100010100000100010000000000010100010100" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "0000001000101010001010101000101000100000001000001000000000001010000010100000001010001000001000100000000" + }, + /* 10*/ { BARCODE_AUSREPLY, "12345678", 0, 3, 73, "Verified manually against tec-it", "1000101010001010100010101010100000100010000000001000001000000000100010100" "1010101010101010101010101010101010101010101010101010101010101010101010101" "0000000000101000101000100000001010101000101000000000100010101000101000000" }, - /* 6*/ { BARCODE_AUSROUTE, "34567890", 0, 3, 73, "Verified manually against tec-it", + /* 11*/ { BARCODE_AUSROUTE, "34567890", 0, 3, 73, "Verified manually against tec-it", "1000000000101010101010000010001000000010101000100010101010000000101000100" "1010101010101010101010101010101010101010101010101010101010101010101010101" "0000101010000010000000101010100010100010101000100010101010001010001000000" }, - /* 7*/ { BARCODE_AUSREDIRECT, "98765432", 0, 3, 73, "Verified manually against tec-it", + /* 12*/ { BARCODE_AUSREDIRECT, "98765432", 0, 3, 73, "Verified manually against tec-it", "1000001010000010000000100010100010101010100000101010101000100010100010100" "1010101010101010101010101010101010101010101010101010101010101010101010101" "0000001010100010101010001010001000000010101000000000001010101000001010000" diff --git a/backend/tests/test_channel.c b/backend/tests/test_channel.c index 3e1bc881..917abc85 100644 --- a/backend/tests/test_channel.c +++ b/backend/tests/test_channel.c @@ -31,6 +31,65 @@ #include "testcommon.h" +static void test_hrt(int index, int debug) { + + struct item { + int option_2; + char *data; + int length; + + char *expected; + }; + // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) + struct item data[] = { + /* 0*/ { -1, "1", -1, "01" }, + /* 1*/ { 3, "1", -1, "01" }, + /* 2*/ { 3, "12", -1, "12" }, + /* 3*/ { 4, "123", -1, "123" }, + /* 4*/ { 5, "123", -1, "0123" }, + /* 5*/ { 5, "12", -1, "0012" }, + /* 6*/ { 5, "1", -1, "0001" }, + /* 7*/ { 5, "1234", -1, "1234" }, + /* 8*/ { 6, "1234", -1, "01234" }, + /* 9*/ { 6, "123", -1, "00123" }, + /* 10*/ { 6, "12", -1, "00012" }, + /* 11*/ { 6, "1", -1, "00001" }, + /* 12*/ { 7, "1234", -1, "001234" }, + /* 13*/ { 7, "12345", -1, "012345" }, + /* 14*/ { 7, "123456", -1, "123456" }, + /* 15*/ { 7, "1", -1, "000001" }, + /* 16*/ { 8, "12345", -1, "0012345" }, + /* 17*/ { 8, "123456", -1, "0123456" }, + /* 18*/ { 8, "1234567", -1, "1234567" }, + /* 19*/ { 8, "12", -1, "0000012" }, + /* 20*/ { 8, "1", -1, "0000001" }, + }; + int data_size = ARRAY_SIZE(data); + int i, length, ret; + struct zint_symbol *symbol; + + testStart("test_hrt"); + + for (i = 0; i < data_size; i++) { + + if (index != -1 && i != index) continue; + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + length = testUtilSetSymbol(symbol, BARCODE_CHANNEL, -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(int index, int debug) { struct item { @@ -436,6 +495,7 @@ static void test_generate(int generate) { int main(int argc, char *argv[]) { testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */ + { "test_hrt", test_hrt, 1, 0, 1 }, { "test_input", test_input, 1, 0, 1 }, { "test_encode", test_encode, 1, 1, 1 }, { "test_generate", test_generate, 0, 1, 0 }, diff --git a/backend/tests/test_codablock.c b/backend/tests/test_codablock.c index 5ee3b65e..2cf653ee 100644 --- a/backend/tests/test_codablock.c +++ b/backend/tests/test_codablock.c @@ -428,12 +428,25 @@ static void test_encode(int index, int generate, int debug) { "1101000010010111101110110001001001011000111011011001100100011000101101100110011011101000110110111101111011101010010000110100100111101100011101011" "1101000010010111101110101100111001000111101011001010000100011110101001101000011011011110101110111101000011001011011101110101001111001100011101011" }, - /* 11*/ { BARCODE_HIBC_BLOCKF, 3, -1, "A123BJC5D6E71", 0, 3, 123, 0, "Verified manually against tec-it; differs from BWIPP (columns=6) which uses Code C for final 71 (same no. of codewords)", + /* 11*/ { BARCODE_CODABLOCKF, -1, -1, " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 0, 11, 156, 1, "Visible ASCII", + "110100001001011110111010000110100110110011001100110110011001100110100100110001001000110010001001100100110010001001100010010001100100101100011101100011101011" + "110100001001011110111011000100100110010010001100100010011000100100101100111001001101110010011001110101110011001001110110010011100110100001100101100011101011" + "110100001001011101111010001101110111011011101011101100010000101100110110111101011110111011100100110111011001001110011010011100110010100001001101100011101011" + "110100001001011110111010011011100110110110001101100011011000110110101000110001000101100010001000110101100010001000110100010001100010111100010101100011101011" + "110100001001011110111010011001110110100010001100010100011000100010101101110001011000111010001101110101110110001011100011010001110110100110111001100011101011" + "110100001001011110111010111001100111011101101101000111011000101110110111010001101110001011011101110111010110001110100011011100010110100001011001100011101011" + "110100001001011110111011100100110111011010001110110001011100011010111011110101100100001011110001010101001100001010000110010010110000100011000101100011101011" + "110100001001011110111011101100100100100001101000010110010000100110101100100001011000010010011010000100110000101000011010010000110010101011110001100011101011" + "110100001001011110111011100110100110000100101100101000011110111010110000101001000111101010100111100100101111001001001111010111100100101100011101100011101011" + "110100001001011110111011100110010100111101001001111001011110100100111100101001111001001011011011110110111101101111011011010101111000111101010001100011101011" + "110100001001011110111011011011000101000111101000101111010111011110101111011101011101111010111101110101110111101011100011011101101110101001100001100011101011" + }, + /* 12*/ { BARCODE_HIBC_BLOCKF, 3, -1, "A123BJC5D6E71", 0, 3, 123, 0, "Verified manually against tec-it; differs from BWIPP (columns=6) which uses Code C for final 71 (same no. of codewords)", "110100001001011110111010010110000110001001001010001100010011100110110011100101100101110010001011000100100001101100011101011" "110100001001011110111011000100100101101110001000100011011011100100101100010001100111010010001101000111001001101100011101011" "110100001001011110111010110011100111011011101001110011011010001000101110111101011100011011001110100100100110001100011101011" }, - /* 12*/ { BARCODE_HIBC_BLOCKF, -1, -1, "$$52001510X3G", 0, 4, 101, 1, "tec-it differs as adds unnecessary Code C at end of 1st line", + /* 13*/ { BARCODE_HIBC_BLOCKF, -1, -1, "$$52001510X3G", 0, 4, 101, 1, "tec-it differs as adds unnecessary Code C at end of 1st line", "11010000100101111011101001000011011000100100100100011001001000110011011100100101110011001100011101011" "11010000100101110111101011000111011001001110110011011001101110100010111101110100001100101100011101011" "11010000100101111011101011001110010011101100111000101101100101110011010001000100100011001100011101011" diff --git a/backend/tests/test_code.c b/backend/tests/test_code.c index a6d8163f..e6a2835e 100644 --- a/backend/tests/test_code.c +++ b/backend/tests/test_code.c @@ -185,38 +185,64 @@ static void test_input(int index, int debug) { // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) struct item data[] = { /* 0*/ { BARCODE_CODE11, -1, "-", -1, 0, 1, 37 }, - /* 1*/ { BARCODE_CODE11, -1, "A", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, - /* 2*/ { BARCODE_CODE11, 3, "1", -1, ZINT_ERROR_INVALID_OPTION, -1, -1 }, - /* 3*/ { BARCODE_CODE39, -1, "a", -1, 0, 1, 38 }, // Converts to upper - /* 4*/ { BARCODE_CODE39, -1, ",", 1, ZINT_ERROR_INVALID_DATA, -1, -1 }, - /* 5*/ { BARCODE_CODE39, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1 }, - /* 6*/ { BARCODE_CODE39, 0, "1", -1, 0, 1, 38 }, - /* 7*/ { BARCODE_CODE39, 1, "1", -1, 0, 1, 51 }, // Check digit - /* 8*/ { BARCODE_CODE39, 2, "1", -1, 0, 1, 38 }, // option_2 > 1 gnored - /* 9*/ { BARCODE_EXCODE39, -1, "A", -1, 0, 1, 38 }, - /* 10*/ { BARCODE_EXCODE39, -1, "a", -1, 0, 1, 51 }, - /* 11*/ { BARCODE_EXCODE39, -1, ",", -1, 0, 1, 51 }, - /* 12*/ { BARCODE_EXCODE39, -1, "\000", 1, 0, 1, 51 }, - /* 13*/ { BARCODE_EXCODE39, -1, "é", -1, ZINT_ERROR_INVALID_DATA, -1, -1, }, - /* 14*/ { BARCODE_LOGMARS, -1, "A", -1, 0, 1, 47 }, - /* 15*/ { BARCODE_LOGMARS, -1, "a", -1, 0, 1, 47 }, - /* 16*/ { BARCODE_LOGMARS, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1, }, - /* 17*/ { BARCODE_LOGMARS, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1, }, - /* 18*/ { BARCODE_CODE93, -1, "A", -1, 0, 1, 46 }, - /* 19*/ { BARCODE_CODE93, -1, "a", -1, 0, 1, 55 }, - /* 20*/ { BARCODE_CODE93, -1, ",", -1, 0, 1, 55 }, - /* 21*/ { BARCODE_CODE93, -1, "\000", 1, 0, 1, 55 }, - /* 22*/ { BARCODE_CODE93, -1, "é", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, - /* 23*/ { BARCODE_PZN, -1, "1", -1, 0, 1, 142 }, - /* 24*/ { BARCODE_PZN, -1, "A", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, - /* 25*/ { BARCODE_PZN, -1, "1000006", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, // Check digit == 10 so can't be used - /* 26*/ { BARCODE_VIN, -1, "5GZCZ43D13S812715", -1, 0, 1, 246 }, - /* 27*/ { BARCODE_VIN, -1, "5GZCZ43D23S812715", -1, ZINT_ERROR_INVALID_CHECK, -1, -1 }, // North American with invalid check character - /* 28*/ { BARCODE_VIN, -1, "WP0ZZZ99ZTS392124", -1, 0, 1, 246 }, // Not North American so no check - /* 29*/ { BARCODE_VIN, -1, "WPOZZZ99ZTS392124", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, // O not allowed - /* 30*/ { BARCODE_HIBC_39, -1, "a", -1, 0, 1, 79 }, // Converts to upper - /* 31*/ { BARCODE_HIBC_39, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, - /* 32*/ { BARCODE_HIBC_39, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 1*/ { BARCODE_CODE11, -1, "0123456789-", -1, 0, 1, 115 }, + /* 2*/ { BARCODE_CODE11, -1, "A", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 3*/ { BARCODE_CODE11, -1, "12+", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 4*/ { BARCODE_CODE11, -1, "1.2", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 5*/ { BARCODE_CODE11, -1, "12!", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 6*/ { BARCODE_CODE11, -1, " ", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 7*/ { BARCODE_CODE11, 3, "1", -1, ZINT_ERROR_INVALID_OPTION, -1, -1 }, + /* 8*/ { BARCODE_CODE39, -1, "a", -1, 0, 1, 38 }, // Converts to upper + /* 9*/ { BARCODE_CODE39, -1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%", -1, 0, 1, 584 }, + /* 10*/ { BARCODE_CODE39, -1, "AB!", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 11*/ { BARCODE_CODE39, -1, "A\"B", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 12*/ { BARCODE_CODE39, -1, "#AB", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 13*/ { BARCODE_CODE39, -1, "&", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 14*/ { BARCODE_CODE39, -1, "'", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 15*/ { BARCODE_CODE39, -1, "(", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 16*/ { BARCODE_CODE39, -1, ")", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 17*/ { BARCODE_CODE39, -1, "*", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 18*/ { BARCODE_CODE39, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 19*/ { BARCODE_CODE39, -1, ":", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 20*/ { BARCODE_CODE39, -1, "@", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 21*/ { BARCODE_CODE39, -1, "[", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 22*/ { BARCODE_CODE39, -1, "`", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 23*/ { BARCODE_CODE39, -1, "{", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 24*/ { BARCODE_CODE39, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 25*/ { BARCODE_CODE39, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 26*/ { BARCODE_CODE39, 0, "1", -1, 0, 1, 38 }, + /* 27*/ { BARCODE_CODE39, 1, "1", -1, 0, 1, 51 }, // Check digit + /* 28*/ { BARCODE_CODE39, 2, "1", -1, 0, 1, 38 }, // option_2 > 1 gnored + /* 29*/ { BARCODE_EXCODE39, -1, "A", -1, 0, 1, 38 }, + /* 30*/ { BARCODE_EXCODE39, -1, "a", -1, 0, 1, 51 }, + /* 31*/ { BARCODE_EXCODE39, -1, ",", -1, 0, 1, 51 }, + /* 32*/ { BARCODE_EXCODE39, -1, "\000", 1, 0, 1, 51 }, + /* 33*/ { BARCODE_EXCODE39, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 34*/ { BARCODE_EXCODE39, -1, "é", -1, ZINT_ERROR_INVALID_DATA, -1, -1, }, + /* 35*/ { BARCODE_LOGMARS, -1, "A", -1, 0, 1, 47 }, + /* 36*/ { BARCODE_LOGMARS, -1, "a", -1, 0, 1, 47 }, + /* 37*/ { BARCODE_LOGMARS, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1, }, + /* 38*/ { BARCODE_LOGMARS, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1, }, + /* 39*/ { BARCODE_LOGMARS, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1, }, + /* 40*/ { BARCODE_CODE93, -1, "A", -1, 0, 1, 46 }, + /* 41*/ { BARCODE_CODE93, -1, "a", -1, 0, 1, 55 }, + /* 42*/ { BARCODE_CODE93, -1, ",", -1, 0, 1, 55 }, + /* 43*/ { BARCODE_CODE93, -1, "\000", 1, 0, 1, 55 }, + /* 44*/ { BARCODE_CODE93, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 45*/ { BARCODE_CODE93, -1, "é", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 46*/ { BARCODE_PZN, -1, "1", -1, 0, 1, 142 }, + /* 47*/ { BARCODE_PZN, -1, "A", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 48*/ { BARCODE_PZN, -1, "1000006", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, // Check digit == 10 so can't be used + /* 49*/ { BARCODE_VIN, -1, "5GZCZ43D13S812715", -1, 0, 1, 246 }, + /* 50*/ { BARCODE_VIN, -1, "5GZCZ43D23S812715", -1, ZINT_ERROR_INVALID_CHECK, -1, -1 }, // North American with invalid check character + /* 51*/ { BARCODE_VIN, -1, "WP0ZZZ99ZTS392124", -1, 0, 1, 246 }, // Not North American so no check + /* 52*/ { BARCODE_VIN, -1, "WP0ZZZ99ZTS392I24", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, // I not allowed + /* 53*/ { BARCODE_VIN, -1, "WPOZZZ99ZTS392124", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, // O not allowed + /* 54*/ { BARCODE_VIN, -1, "WPQZZZ99ZTS392124", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, // Q not allowed + /* 55*/ { BARCODE_HIBC_39, -1, "a", -1, 0, 1, 79 }, // Converts to upper + /* 56*/ { BARCODE_HIBC_39, -1, ",", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 57*/ { BARCODE_HIBC_39, -1, "\000", 1, ZINT_ERROR_INVALID_DATA, -1, -1 }, + /* 58*/ { BARCODE_HIBC_39, -1, "\300", -1, ZINT_ERROR_INVALID_DATA, -1, -1 }, }; int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -310,67 +336,82 @@ static void test_encode(int index, int generate, int debug) { /* 15*/ { 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_EXCODE39, -1, "1A", -1, 0, 1, 51, "ISO/IEC 16388:2007 Figure 1", + /* 16*/ { 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", "100101101101011010010101101101010010110100101101101" }, - /* 17*/ { BARCODE_EXCODE39, 1, "1A", -1, 0, 1, 64, "With check digit", + /* 18*/ { BARCODE_EXCODE39, 1, "1A", -1, 0, 1, 64, "With check digit", "1001011011010110100101011011010100101101011010010110100101101101" }, - /* 18*/ { BARCODE_EXCODE39, 1, "Z4", -1, 0, 1, 64, "Check digit $", + /* 19*/ { BARCODE_EXCODE39, 1, "Z4", -1, 0, 1, 64, "Check digit $", "1001011011010100110110101010100110101101001001001010100101101101" }, - /* 19*/ { BARCODE_EXCODE39, -1, "a%\000\001$\177z", 7, 0, 1, 207, "Verified manually against tec-it", + /* 20*/ { BARCODE_EXCODE39, -1, "a%\000\001$\177z", 7, 0, 1, 207, "Verified manually against tec-it", "100101101101010010100100101101010010110100100101001011010110010101010010010010110010101011010010010010101101010010110100100101001010101100101101010010010010101011011001010010100100101001101101010100101101101" }, - /* 20*/ { BARCODE_EXCODE39, -1, "\033\037!+/\\@A~", -1, 0, 1, 246, "Verified manually against tec-it", + /* 21*/ { BARCODE_EXCODE39, -1, "\033\037!+/\\@A~", -1, 0, 1, 246, "Verified manually against tec-it", "100101101101010100100100101101010010110101001001001011010110010101001001010010110101001011010010010100101101010100110100100101001011010110100101010010010010101101010011010100100100101001101010110110101001011010100100100101011010110010100101101101" }, - /* 21*/ { BARCODE_LOGMARS, -1, "1A", -1, 0, 1, 63, "Verified manually against tec-it", + /* 22*/ { 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", + "1001011011010101001001001010101101001101010010010010110101101001010100100100101100110101010100101001001011010100101101001010010010101101001011010010100100101101101001010100101001001010101100101101001010010010110101100101010010100100101011011001010100101001001010101001101101001010010010110101001101010010100100101011010011010100101001001010101100110101001010010010110101010011010010100100101011010100110100101001001011011010100101001010010010101011010011010010100100101101011010010100101001001010110110100101001010010010101010110011010010100100101101010110010100101001001010110101100101001010010010101011011001010010100100101100101010110100101001001010011010101101001010010010110011010101010010100100101001011010110100101001001011001011010101001010010010100110110101010100100100101011011010010101001001001010101011001101010010010010110101011001010100100100101011010110010100101101101" + }, + /* 24*/ { BARCODE_LOGMARS, -1, "1A", -1, 0, 1, 63, "Verified manually against tec-it", "100010111011101011101000101011101110101000101110100010111011101" }, - /* 22*/ { BARCODE_LOGMARS, 1, "1A", -1, 0, 1, 79, "With check digit; verified manually against tec-it", + /* 25*/ { BARCODE_LOGMARS, 1, "1A", -1, 0, 1, 79, "With check digit; verified manually against tec-it", "1000101110111010111010001010111011101010001011101011101000101110100010111011101" }, - /* 23*/ { BARCODE_LOGMARS, -1, "ABC", -1, 0, 1, 79, "MIL-STD-1189 Rev. B Figure 1", + /* 26*/ { BARCODE_LOGMARS, -1, "ABC", -1, 0, 1, 79, "MIL-STD-1189 Rev. B Figure 1", "1000101110111010111010100010111010111010001011101110111010001010100010111011101" }, - /* 24*/ { BARCODE_LOGMARS, -1, "SAMPLE 1", -1, 0, 1, 159, "MIL-STD-1189 Rev. B Figure 2 top", + /* 27*/ { BARCODE_LOGMARS, -1, "SAMPLE 1", -1, 0, 1, 159, "MIL-STD-1189 Rev. B Figure 2 top", "100010111011101010111010111000101110101000101110111011101010001010111011101000101011101010001110111010111000101010001110101110101110100010101110100010111011101" }, - /* 25*/ { 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", + /* 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", "1000101110111010111010001010111010111000101011101110111000101010101000111010111011101000111010101000100010100010111010100010111010111010001011101110111010001010101011100010111011101011100010101010111011100010100010111011101" }, - /* 26*/ { BARCODE_CODE93, -1, "C93", -1, 0, 1, 64, "ANSI/AIM BC5-1995 Figure 1; verified manually against tec-it", + /* 29*/ { BARCODE_CODE93, -1, "C93", -1, 0, 1, 64, "ANSI/AIM BC5-1995 Figure 1; verified manually against tec-it", "1010111101101000101000010101010000101101010001110110101010111101" }, - /* 27*/ { BARCODE_CODE93, -1, "CODE\01593", -1, 0, 1, 109, "ANSI/AIM BC5-1995 Figure B1; verified manually against tec-it", + /* 30*/ { BARCODE_CODE93, -1, "CODE\01593", -1, 0, 1, 109, "ANSI/AIM BC5-1995 Figure B1; verified manually against tec-it", "1010111101101000101001011001100101001100100101001001101010011001000010101010000101100101001000101101010111101" }, - /* 28*/ { BARCODE_CODE93, -1, "1A", -1, 0, 1, 55, "Verified manually against tec-it", + /* 31*/ { BARCODE_CODE93, -1, "1A", -1, 0, 1, 55, "Verified manually against tec-it", "1010111101010010001101010001101000101001110101010111101" }, - /* 29*/ { BARCODE_CODE93, -1, "TEST93", -1, 0, 1, 91, "Verified manually against tec-it", + /* 32*/ { BARCODE_CODE93, -1, "TEST93", -1, 0, 1, 91, "Verified manually against tec-it", "1010111101101001101100100101101011001101001101000010101010000101011101101001000101010111101" }, - /* 30*/ { BARCODE_CODE93, -1, "\000a\177", 3, 0, 1, 91, "Verified manually against tec-it", + /* 33*/ { BARCODE_CODE93, -1, "\000a\177", 3, 0, 1, 91, "Verified manually against tec-it", "1010111101110110101100101101001100101101010001110110101101001101011011101010010001010111101" }, - /* 31*/ { BARCODE_PZN, -1, "1234567", -1, 0, 1, 142, "Example from IFA Info Code 39 EN V2.1; verified manually against tec-it", + /* 34*/ { 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", + "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" }, - /* 32*/ { BARCODE_PZN, -1, "2758089", -1, 0, 1, 142, "Example from IFA Info Check Digit Calculations EN 15 July 2019; verified manually against tec-it", + /* 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" }, - /* 33*/ { BARCODE_VIN, -1, "1FTCR10UXTPA78180", -1, 0, 1, 246, "https://www.vinquery.com/img/vinbarcode/vinbarcode4.jpg", + /* 38*/ { BARCODE_VIN, -1, "1FTCR10UXTPA78180", -1, 0, 1, 246, "https://www.vinquery.com/img/vinbarcode/vinbarcode4.jpg", "100101101101011010010101101011011001010101011011001011011010010101101010110010110100101011010100110110101100101010110100101101011010101101100101011011010010110101001011010100101101101101001011010110100101011011010010110101010011011010100101101101" }, - /* 34*/ { BARCODE_VIN, 1, "2FTPX28L0XCA15511", -1, 0, 1, 259, "With Import 'I' prefix; https://www.vinquery.com/img/vinbarcode/vinbarcode1.jpg", + /* 39*/ { BARCODE_VIN, 1, "2FTPX28L0XCA15511", -1, 0, 1, 259, "With Import 'I' prefix; https://www.vinquery.com/img/vinbarcode/vinbarcode1.jpg", "1001011011010101101001101010110010101101011011001010101011011001010110110100101001011010110101100101011011010010110101011010100110101001101101010010110101101101101001010110101001011011010010101101101001101010110100110101011010010101101101001010110100101101101" }, - /* 35*/ { BARCODE_HIBC_39, -1, "A123BJC5D6E71", -1, 0, 1, 271, "ANSI/HIBC 2.6 - 2016 Figure 2, same", + /* 40*/ { BARCODE_HIBC_39, -1, "A123BJC5D6E71", -1, 0, 1, 271, "ANSI/HIBC 2.6 - 2016 Figure 2, same", "1000101110111010100010100010001011101010001011101110100010101110101110001010111011101110001010101011101000101110101011100011101011101110100010101110100011101010101011100010111010111000111010101110101110001010101000101110111011101000101011101010100011101110100010111011101" }, - /* 36*/ { BARCODE_HIBC_39, -1, "$$52001510X3G", -1, 0, 1, 271, "ANSI/HIBC 2.6 - 2016 Figure 6, same", + /* 41*/ { BARCODE_HIBC_39, -1, "$$52001510X3G", -1, 0, 1, 271, "ANSI/HIBC 2.6 - 2016 Figure 6, same", "1000101110111010100010100010001010001000100010101000100010001010111010001110101010111000101011101010001110111010101000111011101011101000101011101110100011101010111010001010111010100011101110101000101110101110111011100010101010101000111011101010111000101110100010111011101" }, }; @@ -431,6 +472,111 @@ static void test_encode(int index, int generate, int debug) { 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(int index, int debug) { + + struct item { + int symbology; + int option_2; + char *data; + int ret; + + int expected_rows; + int expected_width; + char *comment; + }; + struct item data[] = { + /* 0*/ { BARCODE_CODE39, -1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+", 0, 1, 1130, "CODE39 85" }, + /* 1*/ { BARCODE_CODE39, -1, "123456ABCD", 0, 1, 155, "CODE39 10" }, + /* 2*/ { BARCODE_CODE93, -1, + "\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" }, + }; + 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 (index != -1 && i != index) 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(remove(symbol->outfile), "i:%d remove(%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 (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, has_index, has_generate, has_debug */ @@ -438,6 +584,7 @@ int main(int argc, char *argv[]) { { "test_hrt", test_hrt, 1, 0, 1 }, { "test_input", test_input, 1, 0, 1 }, { "test_encode", test_encode, 1, 1, 1 }, + { "test_perf", test_perf, 1, 0, 1 }, }; testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); diff --git a/backend/tests/test_code128.c b/backend/tests/test_code128.c index 03624dd5..f48d0092 100644 --- a/backend/tests/test_code128.c +++ b/backend/tests/test_code128.c @@ -839,6 +839,105 @@ static void test_encode(int index, int generate, int debug) { testFinish(); } +#include + +#define TEST_PERF_ITER_MILLES 10 +#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(int index, int debug) { + + struct item { + int symbology; + char *data; + int ret; + + int expected_rows; + int expected_width; + char *comment; + }; + struct item data[] = { + /* 0*/ { BARCODE_CODE128, "123456ABCD123456ABCD123456ABCD123456ABCD123456ABCD123456ABCD", 0, 1, 618, "CODE128 60" }, + /* 1*/ { BARCODE_CODE128, "123456ABCD", 0, 1, 123, "CODE128 10" }, + /* 2*/ { BARCODE_GS1_128, "[01]09501101530003", 0, 1, 134, "GS1_128 (01)" }, + }; + 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 (index != -1 && i != index) 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*/, -1, -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(remove(symbol->outfile), "i:%d remove(%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 (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, has_index, has_generate, has_debug */ @@ -852,6 +951,7 @@ int main(int argc, char *argv[]) { { "test_ean14_input", test_ean14_input, 1, 1, 1 }, { "test_dpd_input", test_dpd_input, 1, 1, 1 }, { "test_encode", test_encode, 1, 1, 1 }, + { "test_perf", test_perf, 1, 0, 1 }, }; testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); diff --git a/backend/tests/test_common.c b/backend/tests/test_common.c index f23ec65f..e874d49e 100644 --- a/backend/tests/test_common.c +++ b/backend/tests/test_common.c @@ -31,6 +31,230 @@ #include "testcommon.h" +/* Original */ +static int is_sane_orig(const char test_string[], const unsigned char source[], const int length) { + int i, j, lt = (int) strlen(test_string); + + for (i = 0; i < length; i++) { + unsigned int latch = FALSE; + for (j = 0; j < lt; j++) { + if (source[i] == test_string[j]) { + latch = TRUE; + break; + } + } + if (!(latch)) { + return ZINT_ERROR_INVALID_DATA; + } + } + + return 0; +} + +static void test_is_sane(int index) { + + struct item { + unsigned int flg; + char *data; + int length; + int ret; + + char *orig_test; + }; + // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) + struct item data[] = { + /* 0*/ { IS_SPC_F, " ", -1, 1, " " }, + /* 1*/ { IS_SPC_F, "\000", 1, 0, " " }, + /* 2*/ { IS_HSH_F, "#", -1, 1, "#" }, + /* 3*/ { IS_HSH_F, " ", -1, 0, "#" }, + /* 4*/ { IS_PLS_F, "+", -1, 1, "+" }, + /* 5*/ { IS_PLS_F, " ", -1, 0, "+" }, + /* 6*/ { IS_MNS_F, "-", -1, 1, "-" }, + /* 7*/ { IS_MNS_F, " ", -1, 0, "-" }, + /* 8*/ { IS_NUM_F, "0123456789", -1, 1, "0123456789" }, // NEON + /* 9*/ { IS_NUM_F, "0123456789 ", -1, 0, "0123456789" }, + /* 10*/ { IS_NUM_F, "012345678A9", -1, 0, "0123456789" }, + /* 11*/ { IS_UPO_F, "GHIJKLMNOPQRSTUVWYZ", -1, 1, "GHIJKLMNOPQRSTUVWYZ" }, + /* 12*/ { IS_UPO_F, "FGHIJKLMNOPQRSTUVWYZ", -1, 0, "GHIJKLMNOPQRSTUVWYZ" }, + /* 13*/ { IS_LWO_F, "ghijklmnopqrstuvwyz", -1, 1, "ghijklmnopqrstuvwyz" }, + /* 14*/ { IS_LWO_F, "fghijklmnopqrstuvwyz", -1, 0, "ghijklmnopqrstuvwyz" }, + /* 15*/ { IS_UHX_F, "ABCDEF", -1, 1, "ABCDEF" }, + /* 16*/ { IS_UHX_F, "ABCDEf", -1, 0, "ABCDEF" }, + /* 17*/ { IS_LHX_F, "abcdef", -1, 1, "abcdef" }, + /* 18*/ { IS_LHX_F, "abcdeF", -1, 0, "abcdef" }, + /* 19*/ { IS_UPR_F, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", -1, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" }, + /* 20*/ { IS_UPR_F, "ABCDEFGHIJKLMNOPQRSTUVWXYZ ", -1, 0, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" }, + /* 21*/ { IS_UPR_F, "X", -1, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" }, + /* 22*/ { IS_UPR_F, "x", -1, 0, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" }, + /* 23*/ { IS_LWR_F, "abcdefghijklmnopqrstuvwxyz", -1, 1, "abcdefghijklmnopqrstuvwxyz" }, + /* 24*/ { IS_LWR_F, "abcdefghijklmnopqrstuvwxyz ", -1, 0, "abcdefghijklmnopqrstuvwxyz" }, + /* 25*/ { IS_LWR_F, "x", -1, 1, "abcdefghijklmnopqrstuvwxyz" }, + /* 26*/ { IS_LWR_F, "X", -1, 0, "abcdefghijklmnopqrstuvwxyz" }, + /* 27*/ { IS_UX__F, "X", -1, 1, "X" }, + /* 28*/ { IS_UX__F, "x", -1, 0, "X" }, + /* 29*/ { IS_LX__F, "x", -1, 1, "x" }, + /* 30*/ { IS_LX__F, "X", -1, 0, "x" }, + /* 31*/ { IS_C82_F, "!\"%&'()*,./:;<=>?_", -1, 1, "!\"%&'()*,./:;<=>?_" }, // CSET82 punctuation less "-+" + /* 32*/ { IS_C82_F, "!\"%&'()*,./:;<=>?_ ", -1, 0, "!\"%&'()*,./:;<=>?_" }, + /* 33*/ { IS_C82_F, "-", -1, 0, "!\"%&'()*,./:;<=>?_" }, + /* 34*/ { IS_C82_F, "$", -1, 0, "!\"%&'()*,./:;<=>?_" }, + /* 35*/ { IS_SIL_F, ".$/%", -1, 1, ".$/%" }, // SILVER punctuation less " -+" + /* 36*/ { IS_SIL_F, ".$/% " , -1, 0, ".$/%" }, + /* 37*/ { IS_SIL_F, "-", -1, 0, ".$/%" }, + /* 38*/ { IS_CLI_F, "$:/.", -1, 1, "$:/." }, // CALCIUM INNER punctuation less "-+" + /* 39*/ { IS_CLI_F, "$:/. ", -1, 0, "$:/." }, + /* 40*/ { IS_CLI_F, "+", -1, 0, "$:/." }, + /* 41*/ { IS_ARS_F, "ABCDEFGHJKLMNPRSTUVWXYZ", -1, 1, "ABCDEFGHJKLMNPRSTUVWXYZ" }, // ARSENIC uppercase + /* 42*/ { IS_ARS_F, "ABCDEFGHJKLMNPRSTUVWXYZ ", -1, 0, "ABCDEFGHJKLMNPRSTUVWXYZ" }, + /* 43*/ { IS_ARS_F, "I", -1, 0, "ABCDEFGHJKLMNPRSTUVWXYZ" }, + /* 44*/ { IS_ARS_F, "O", -1, 0, "ABCDEFGHJKLMNPRSTUVWXYZ" }, + /* 45*/ { IS_NUM_F | IS_UHX_F, "0123456789ABCDEF", -1, 1, "0123456789ABCDEF" }, // SSET + /* 46*/ { IS_NUM_F | IS_UHX_F, "0123456789ABCDEf", -1, 0, "0123456789ABCDEF" }, + /* 47*/ { IS_NUM_F | IS_PLS_F, "0123456789+", -1, 1, "0123456789+" }, // SODIUM_PLS + /* 48*/ { IS_NUM_F | IS_PLS_F, "0123456789+-", -1, 0, "0123456789+" }, + /* 49*/ { IS_NUM_F | IS_UX__F, "0123456789X", -1, 1, "0123456789X" }, // ISBNX_SANE + /* 50*/ { IS_NUM_F | IS_UX__F, "0123456789x", -1, 0, "0123456789X" }, + /* 51*/ { IS_NUM_F | IS_UX__F | IS_LX__F | IS_PLS_F, "0123456789Xx+", -1, 1, "0123456789Xx+" }, // ISBNX_ADDON_SANE + /* 52*/ { IS_NUM_F | IS_UX__F | IS_LX__F | IS_PLS_F, "0123456789Xx+Y", -1, 0, "0123456789Xx+" }, + /* 53*/ { IS_NUM_F | IS_MNS_F, "0123456789-", -1, 1, "0123456789-" }, // SODIUM_MNS + /* 54*/ { IS_NUM_F | IS_MNS_F, "0123456789-+", -1, 0, "0123456789-" }, + /* 55*/ { IS_C82_F | IS_MNS_F | IS_PLS_F | IS_NUM_F | IS_UPR_F | IS_LWR_F, "!\"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz", -1, 1, "!\"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" }, // CSET82 + /* 56*/ { IS_C82_F | IS_MNS_F | IS_PLS_F | IS_NUM_F | IS_UPR_F | IS_LWR_F, " ", -1, 0, "!\"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" }, + /* 57*/ { IS_C82_F | IS_MNS_F | IS_PLS_F | IS_NUM_F | IS_UPR_F | IS_LWR_F, "#", -1, 0, "!\"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" }, + /* 58*/ { IS_C82_F | IS_MNS_F | IS_PLS_F | IS_NUM_F | IS_UPR_F | IS_LWR_F, "$", -1, 0, "!\"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" }, + /* 59*/ { IS_C82_F | IS_MNS_F | IS_PLS_F | IS_NUM_F | IS_UPR_F | IS_LWR_F, "@", -1, 0, "!\"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" }, + /* 60*/ { IS_LWR_F | IS_C82_F | IS_PLS_F | IS_MNS_F | IS_SPC_F, "abcdefghijklmnopqrstuvwxyz!\"%&'()*+,-./:;<=>?_ ", -1, 1, "abcdefghijklmnopqrstuvwxyz!\"%&'()*+,-./:;<=>?_ " }, // IS_ISOIEC_F + /* 61*/ { IS_LWR_F | IS_C82_F | IS_PLS_F | IS_MNS_F | IS_SPC_F, "abcdefghijklmnopqrstuvwxyz!\"%&'()*+,-./:;<=>?_ #", -1, 0, "abcdefghijklmnopqrstuvwxyz!\"%&'()*+,-./:;<=>?_ " }, + /* 62*/ { IS_LWR_F | IS_C82_F | IS_PLS_F | IS_MNS_F | IS_SPC_F, "$", -1, 0, "abcdefghijklmnopqrstuvwxyz!\"%&'()*+,-./:;<=>?_ " }, + /* 63*/ { IS_MNS_F | IS_SIL_F | IS_SPC_F | IS_PLS_F, "-. $/+%", -1, 1, "" }, + /* 64*/ { IS_MNS_F | IS_SIL_F | IS_SPC_F | IS_PLS_F, "-. $/!+%", -1, 0, "" }, + /* 65*/ { IS_NUM_F | IS_UPR_F | IS_MNS_F | IS_SIL_F | IS_SPC_F | IS_PLS_F, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%", -1, 1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%" }, // SILVER + /* 66*/ { IS_NUM_F | IS_UPR_F | IS_MNS_F | IS_SIL_F | IS_SPC_F | IS_PLS_F, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%a", -1, 0, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%" }, + /* 67*/ { IS_NUM_F | IS_ARS_F, "0123456789ABCDEFGHJKLMNPRSTUVWXYZ", -1, 1, "0123456789ABCDEFGHJKLMNPRSTUVWXYZ" }, // ARSENIC + /* 68*/ { IS_NUM_F | IS_ARS_F, "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ", -1, 0, "0123456789ABCDEFGHJKLMNPRSTUVWXYZ" }, + /* 69*/ { IS_NUM_F | IS_ARS_F, "0123456789ABCDEFGHJKLMNPRSTUVWXYz", -1, 0, "0123456789ABCDEFGHJKLMNPRSTUVWXYZ" }, + /* 70*/ { IS_NUM_F | IS_UPR_F | IS_LWR_F | IS_SPC_F | IS_HSH_F, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz #", -1, 1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz #" }, // GDSET + /* 71*/ { IS_NUM_F | IS_UPR_F | IS_LWR_F | IS_SPC_F | IS_HSH_F, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz #!", -1, 0, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz #" }, + /* 72*/ { IS_NUM_F | IS_MNS_F | IS_CLI_F | IS_PLS_F, "0123456789-$:/.+", -1, 1, "0123456789-$:/.+" }, // CALCIUM_INNER + /* 73*/ { IS_NUM_F | IS_MNS_F | IS_CLI_F | IS_PLS_F, "0123456789-$:/.+ ", -1, 0, "0123456789-$:/.+" }, + /* 74*/ { IS_NUM_F | IS_MNS_F | IS_CLI_F | IS_PLS_F, "0123456789-$:/.+!", -1, 0, "0123456789-$:/.+" }, + /* 75*/ { IS_NUM_F | IS_UPR_F, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", -1, 1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" }, // KRSET + /* 76*/ { IS_NUM_F | IS_UPR_F, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYz", -1, 0, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" }, + /* 77*/ { IS_NUM_F | IS_UPR_F | IS_SPC_F, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ ", -1, 1, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ " }, // RUBIDIUM + /* 78*/ { IS_NUM_F | IS_UPR_F | IS_SPC_F, "0123456789aBCDEFGHIJKLMNOPQRSTUVWXYZ ", -1, 0, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ " }, + /* 79*/ { IS_NUM_F | IS_MNS_F | IS_UPR_F, "1234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ", -1, 1, "1234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ" }, // SHKASUTSET + /* 80*/ { IS_NUM_F | IS_MNS_F | IS_UPR_F, "1234567890-ABCDEFGHIJKLMNOPQRSTUVWXYz", -1, 0, "1234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ" }, + }; + int data_size = ARRAY_SIZE(data); + int i, length, ret; + + testStart("test_is_sane"); + + for (i = 0; i < data_size; i++) { + + if (index != -1 && i != index) continue; + + length = data[i].length == -1 ? (int) strlen(data[i].data) : data[i].length; + + ret = is_sane(data[i].flg, (const unsigned char *) data[i].data, length); + assert_equal(ret, data[i].ret, "i:%d ret %d != %d\n", i, ret, data[i].ret); + + if (data[i].orig_test[0]) { + int orig_ret = is_sane_orig(data[i].orig_test, (const unsigned char *) data[i].data, length); + if (orig_ret == 0) { + assert_nonzero(ret, "i:%d orig_ret %d, ret %d == 0\n", i, orig_ret, ret); + } else { + assert_zero(ret, "i:%d orig_ret %d, ret %d != 0\n", i, orig_ret, ret); + } + } + } + + testFinish(); +} + +static void test_is_sane_lookup(int index) { + + struct item { + char *test_string; + int test_length; + char *data; + int length; + int ret; + + int posns[32]; + }; + // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) + struct item data[] = { + /* 0*/ { "1234567", -1, "7654321357", -1, 1, { 6, 5, 4, 3, 2, 1, 0, 2, 4, 6 } }, + /* 1*/ { "1234567", -1, "76543213578", -1, 0, {0} }, + }; + int data_size = ARRAY_SIZE(data); + int i, length, ret; + int test_length; + int posns[32]; + + testStart("test_is_sane_lookup"); + + for (i = 0; i < data_size; i++) { + + if (index != -1 && i != index) continue; + + test_length = data[i].test_length == -1 ? (int) strlen(data[i].test_string) : data[i].test_length; + length = data[i].length == -1 ? (int) strlen(data[i].data) : data[i].length; + + ret = is_sane_lookup(data[i].test_string, test_length, (const unsigned char *) data[i].data, length, posns); + assert_equal(ret, data[i].ret, "i:%d ret %d != %d\n", i, ret, data[i].ret); + + if (ret) { + int j; + for (j = 0; j < length; j++) { + assert_equal(posns[j], data[i].posns[j], "i:%d posns[%d] %d != expected posns[%d] %d\n", i, j, posns[j], j, data[i].posns[j]); + } + } + } + + testFinish(); +} + +static void test_is_valid_utf8(int index) { + + struct item { + char *data; + int length; + int ret; + char *comment; + }; + // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) + struct item data[] = { + /* 0*/ { "", -1, 1, "" }, + /* 1*/ { "abcdefghijklmnopqrstuvwxyz", -1, 1, "" }, + /* 2*/ { "éa", -1, 1, "" }, + /* 3*/ { "a\000b", 3, 1, "Embedded nul" }, + /* 4*/ { "\357\273\277a", -1, 1, "Bom" }, + + /* 5*/ { "a\xC2", -1, 0, "Missing 2nd byte" }, + /* 6*/ { "a\200b", -1, 0, "Orphan continuation 0x80" }, + /* 7*/ { "\300\201", -1, 0, "Overlong 0xC081" }, + /* 8*/ { "\355\240\200", -1, 0, "Surrogate 0xEDA080" }, + }; + int data_size = ARRAY_SIZE(data); + int i, length, ret; + + testStart("test_is_valid_utf8"); + + for (i = 0; i < data_size; i++) { + + if (index != -1 && i != index) continue; + + length = data[i].length == -1 ? (int) strlen(data[i].data) : data[i].length; + + ret = is_valid_utf8((const unsigned char *) data[i].data, length); + assert_equal(ret, data[i].ret, "i:%d ret %d != %d\n", i, ret, data[i].ret); + } + + testFinish(); +} + static void test_utf8_to_unicode(int index, int debug) { struct item { @@ -142,45 +366,6 @@ static void test_set_height(int index, int debug) { testFinish(); } -static void test_is_valid_utf8(int index) { - - struct item { - char *data; - int length; - int ret; - char *comment; - }; - // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) - struct item data[] = { - /* 0*/ { "", -1, 1, "" }, - /* 1*/ { "abcdefghijklmnopqrstuvwxyz", -1, 1, "" }, - /* 2*/ { "éa", -1, 1, "" }, - /* 3*/ { "a\000b", 3, 1, "Embedded nul" }, - /* 4*/ { "\357\273\277a", -1, 1, "Bom" }, - - /* 5*/ { "a\xC2", -1, 0, "Missing 2nd byte" }, - /* 6*/ { "a\200b", -1, 0, "Orphan continuation 0x80" }, - /* 7*/ { "\300\201", -1, 0, "Overlong 0xC081" }, - /* 8*/ { "\355\240\200", -1, 0, "Surrogate 0xEDA080" }, - }; - int data_size = ARRAY_SIZE(data); - int i, length, ret; - - testStart("test_is_valid_utf8"); - - for (i = 0; i < data_size; i++) { - - if (index != -1 && i != index) continue; - - length = data[i].length == -1 ? (int) strlen(data[i].data) : data[i].length; - - ret = is_valid_utf8((const unsigned char *) data[i].data, length); - assert_equal(ret, data[i].ret, "i:%d ret %d != %d\n", i, ret, data[i].ret); - } - - testFinish(); -} - static void test_debug_test_codeword_dump_int(int index, int debug) { struct item { @@ -217,9 +402,11 @@ static void test_debug_test_codeword_dump_int(int index, int debug) { int main(int argc, char *argv[]) { testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */ + { "test_is_sane", test_is_sane, 1, 0, 0 }, + { "test_is_sane_lookup", test_is_sane_lookup, 1, 0, 0 }, + { "test_is_valid_utf8", test_is_valid_utf8, 1, 0, 0 }, { "test_utf8_to_unicode", test_utf8_to_unicode, 1, 0, 1 }, { "test_set_height", test_set_height, 1, 0, 1 }, - { "test_is_valid_utf8", test_is_valid_utf8, 1, 0, 0 }, { "test_debug_test_codeword_dump_int", test_debug_test_codeword_dump_int, 1, 0, 1 }, }; diff --git a/backend/tests/test_emf.c b/backend/tests/test_emf.c index 041380d2..25105887 100644 --- a/backend/tests/test_emf.c +++ b/backend/tests/test_emf.c @@ -146,7 +146,7 @@ static void test_print(int index, int generate, int debug) { ret = testUtilCmpBins(symbol->outfile, expected_file); assert_zero(ret, "i:%d %s testUtilCmpBins(%s, %s) %d != 0\n", i, testUtilBarcodeName(data[i].symbology), symbol->outfile, expected_file, ret); - assert_zero(remove(symbol->outfile), "i:%d remove(%s) != 0\n", i, symbol->outfile); + if (index == -1) assert_zero(remove(symbol->outfile), "i:%d remove(%s) != 0\n", i, symbol->outfile); } ZBarcode_Delete(symbol); diff --git a/backend/tests/test_imail.c b/backend/tests/test_imail.c index 52e5b636..b23c26b8 100644 --- a/backend/tests/test_imail.c +++ b/backend/tests/test_imail.c @@ -62,7 +62,7 @@ static void test_csv(int index, int debug) { assert_nonnull(fd, "fopen(%s) == NULL", csvfile); while (fgets(buffer, sizeof(buffer), fd) != NULL) { - char *b; + const char *b; struct zint_symbol *symbol; lc++; diff --git a/backend/tests/test_library.c b/backend/tests/test_library.c index 6cf47806..ea4e9de4 100644 --- a/backend/tests/test_library.c +++ b/backend/tests/test_library.c @@ -501,7 +501,7 @@ static void test_cap_compliant_height() { testStart("test_cap_compliant_height"); - for (symbol_id = 1; symbol_id <= BARCODE_RMQR; symbol_id++) { + for (symbol_id = 1; symbol_id <= BARCODE_LAST; symbol_id++) { if (!ZBarcode_ValidID(symbol_id)) continue; ret = ZBarcode_Cap(symbol_id, ZINT_CAP_COMPLIANT_HEIGHT); diff --git a/backend/tests/test_output.c b/backend/tests/test_output.c index e9709c02..2b5466d2 100644 --- a/backend/tests/test_output.c +++ b/backend/tests/test_output.c @@ -31,7 +31,7 @@ #include "testcommon.h" -STATIC_UNLESS_ZINT_TEST int quiet_zones(const struct zint_symbol *symbol, const int hide_text, +STATIC_UNLESS_ZINT_TEST int out_quiet_zones(const struct zint_symbol *symbol, const int hide_text, float *left, float *right, float *top, float *bottom); static void test_quiet_zones(void) { @@ -42,11 +42,11 @@ static void test_quiet_zones(void) { testStart("test_quiet_zones"); - for (i = BARCODE_CODE11; i <= BARCODE_RMQR; i++) { + for (i = 1; i <= BARCODE_LAST; i++) { if (!ZBarcode_ValidID(i)) continue; symbol.symbology = i; symbol.output_options = BARCODE_QUIET_ZONES; - ret = quiet_zones(&symbol, hide_text, &left, &right, &top, &bottom); + ret = out_quiet_zones(&symbol, hide_text, &left, &right, &top, &bottom); if (i != BARCODE_FLAT) { // Only one which isn't marked as done assert_nonzero(ret, "i:%d %s not done\n", i, testUtilBarcodeName(i)); } diff --git a/backend/tests/test_plessey.c b/backend/tests/test_plessey.c index 264e49e4..3b88b0a3 100644 --- a/backend/tests/test_plessey.c +++ b/backend/tests/test_plessey.c @@ -319,6 +319,107 @@ static void test_encode(int index, int generate, int debug) { 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(int index, int debug) { + + struct item { + int symbology; + int option_2; + char *data; + int ret; + + int expected_rows; + int expected_width; + char *comment; + }; + struct item data[] = { + /* 0*/ { BARCODE_PLESSEY, -1, "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1", 0, 1, 1107, "PLESSEY 65" }, + /* 1*/ { BARCODE_PLESSEY, -1, "123456ABCD", 0, 1, 227, "PLESSEY 10" }, + /* 2*/ { BARCODE_MSI_PLESSEY, -1, "12345678901234567890123456789012345678901234567890123456789012345", 0, 1, 787, "MSI_PLESSEY 65" }, + /* 3*/ { BARCODE_MSI_PLESSEY, -1, "1234567890", 0, 1, 127, "MSI_PLESSEY 10" }, + }; + 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 (index != -1 && i != index) 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(remove(symbol->outfile), "i:%d remove(%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 (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, has_index, has_generate, has_debug */ @@ -326,6 +427,7 @@ int main(int argc, char *argv[]) { { "test_hrt", test_hrt, 1, 0, 1 }, { "test_input", test_input, 1, 0, 1 }, { "test_encode", test_encode, 1, 1, 1 }, + { "test_perf", test_perf, 1, 0, 1 }, }; testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); diff --git a/backend/tests/test_png.c b/backend/tests/test_png.c index 5399168f..1fbd58b0 100644 --- a/backend/tests/test_png.c +++ b/backend/tests/test_png.c @@ -385,6 +385,33 @@ static void test_wpng_error_handler(void) { testFinish(); } +// Check compliant height printable for max CODABLOCKF with 44 rows * ((62 cols) * 0.55 + 3)) = 1632.4 +static void test_large_compliant_height(void) { + int ret; + struct zint_symbol *symbol = NULL; + const char pattern[] = { "1" }; + const int codablockf_max = 2726; + char data_buf[2726 + 1]; + + testStart("test_large_compliant_height"); + + symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + symbol->symbology = BARCODE_CODABLOCKF; + symbol->output_options |= COMPLIANT_HEIGHT; + testUtilStrCpyRepeat(data_buf, pattern, codablockf_max); + assert_equal(codablockf_max, (int) strlen(data_buf), "length %d != strlen(data_buf) %d\n", codablockf_max, (int) strlen(data_buf)); + + ret = ZBarcode_Encode_and_Print(symbol, (const unsigned char *) data_buf, codablockf_max, 0); + assert_zero(ret, "ZBarcode_Encode_and_Print ret %d != 0 (%s)\n", ret, symbol->errtxt); + assert_zero(remove(symbol->outfile), "remove(%s) != 0\n", symbol->outfile); + + ZBarcode_Delete(symbol); + + testFinish(); +} + int main(int argc, char *argv[]) { testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */ @@ -392,6 +419,7 @@ int main(int argc, char *argv[]) { { "test_print", test_print, 1, 1, 1 }, { "test_outfile", test_outfile, 0, 0, 0 }, { "test_wpng_error_handler", test_wpng_error_handler, 0, 0, 0 }, + { "test_large_compliant_height", test_large_compliant_height, 0, 0, 0 }, }; testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); diff --git a/backend/tests/test_postal.c b/backend/tests/test_postal.c index 92dfd49f..0a7d8adc 100644 --- a/backend/tests/test_postal.c +++ b/backend/tests/test_postal.c @@ -59,16 +59,18 @@ static void test_large(int index, int debug) { /* 9*/ { BARCODE_RM4SCC, "1", 51, ZINT_ERROR_TOO_LONG, -1, -1 }, /* 10*/ { BARCODE_JAPANPOST, "1", 20, 0, 3, 133 }, /* 11*/ { BARCODE_JAPANPOST, "1", 21, ZINT_ERROR_TOO_LONG, -1, -1 }, - /* 12*/ { BARCODE_KOREAPOST, "1", 6, 0, 1, 162 }, - /* 13*/ { BARCODE_KOREAPOST, "1", 7, ZINT_ERROR_TOO_LONG, -1, -1 }, - /* 14*/ { BARCODE_PLANET, "1", 13, 0, 2, 143 }, - /* 15*/ { BARCODE_PLANET, "1", 14, ZINT_WARN_NONCOMPLIANT, 2, 153 }, - /* 16*/ { BARCODE_PLANET, "1", 38, ZINT_WARN_NONCOMPLIANT, 2, 393 }, - /* 17*/ { BARCODE_PLANET, "1", 39, ZINT_ERROR_TOO_LONG, -1, -1 }, - /* 18*/ { BARCODE_KIX, "1", 18, 0, 3, 143 }, - /* 19*/ { BARCODE_KIX, "1", 19, ZINT_ERROR_TOO_LONG, -1, -1 }, - /* 20*/ { BARCODE_DAFT, "D", 50, 0, 3, 99 }, - /* 21*/ { BARCODE_DAFT, "D", 51, ZINT_ERROR_TOO_LONG, -1, -1 }, + /* 12*/ { BARCODE_JAPANPOST, "A", 10, 0, 3, 133 }, + /* 13*/ { BARCODE_JAPANPOST, "A", 11, ZINT_ERROR_TOO_LONG, -1, -1 }, + /* 14*/ { BARCODE_KOREAPOST, "1", 6, 0, 1, 162 }, + /* 15*/ { BARCODE_KOREAPOST, "1", 7, ZINT_ERROR_TOO_LONG, -1, -1 }, + /* 16*/ { BARCODE_PLANET, "1", 13, 0, 2, 143 }, + /* 17*/ { BARCODE_PLANET, "1", 14, ZINT_WARN_NONCOMPLIANT, 2, 153 }, + /* 18*/ { BARCODE_PLANET, "1", 38, ZINT_WARN_NONCOMPLIANT, 2, 393 }, + /* 19*/ { BARCODE_PLANET, "1", 39, ZINT_ERROR_TOO_LONG, -1, -1 }, + /* 20*/ { BARCODE_KIX, "1", 18, 0, 3, 143 }, + /* 21*/ { BARCODE_KIX, "1", 19, ZINT_ERROR_TOO_LONG, -1, -1 }, + /* 22*/ { BARCODE_DAFT, "D", 100, 0, 3, 199 }, + /* 23*/ { BARCODE_DAFT, "D", 101, ZINT_ERROR_TOO_LONG, -1, -1 }, }; int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -237,27 +239,31 @@ static void test_input(int index, int debug) { /* 17*/ { BARCODE_RM4SCC, -1, 0, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0, 3, 299, 8 }, /* 18*/ { BARCODE_RM4SCC, -1, 0, "a", 0, 3, 19, 8 }, // Converts to upper /* 19*/ { BARCODE_RM4SCC, -1, 0, ",", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, - /* 20*/ { BARCODE_JAPANPOST, -1, 0, "1234567890-ABCDEFGH", 0, 3, 133, 8 }, - /* 21*/ { BARCODE_JAPANPOST, -1, 0, "a", 0, 3, 133, 8 }, // Converts to upper - /* 22*/ { BARCODE_JAPANPOST, -1, 0, ",", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, - /* 23*/ { BARCODE_KOREAPOST, -1, 0, "123456", 0, 1, 167, 50 }, - /* 24*/ { BARCODE_KOREAPOST, -1, 0, "A", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, - /* 25*/ { BARCODE_PLANET, -1, 0, "12345678901", 0, 2, 123, 12 }, - /* 26*/ { BARCODE_PLANET, -1, 0, "1234567890123", 0, 2, 143, 12 }, - /* 27*/ { BARCODE_PLANET, -1, 0, "0", ZINT_WARN_NONCOMPLIANT, 2, 23, 12 }, - /* 28*/ { BARCODE_PLANET, -1, 0, "1234567890", ZINT_WARN_NONCOMPLIANT, 2, 113, 12 }, - /* 29*/ { BARCODE_PLANET, -1, 0, "123456789012", ZINT_WARN_NONCOMPLIANT, 2, 133, 12 }, - /* 30*/ { BARCODE_PLANET, -1, 0, "12345678901234", ZINT_WARN_NONCOMPLIANT, 2, 153, 12 }, - /* 31*/ { BARCODE_PLANET, -1, 0, "1234567890A", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, - /* 32*/ { BARCODE_KIX, -1, 0, "0123456789ABCDEFGH", 0, 3, 143, 8 }, - /* 33*/ { BARCODE_KIX, -1, 0, "a", 0, 3, 7, 8 }, // Converts to upper - /* 34*/ { BARCODE_KIX, -1, 0, ",", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, - /* 35*/ { BARCODE_DAFT, -1, 0, "DAFT", 0, 3, 7, 8 }, - /* 36*/ { BARCODE_DAFT, -1, 0, "a", 0, 3, 1, 8 }, // Converts to upper - /* 37*/ { BARCODE_DAFT, -1, 0, "B", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, - /* 38*/ { BARCODE_DAFT, -1, 1.9, "DAFT", 0, 3, 7, 2 }, - /* 39*/ { BARCODE_DAFT, 500, 0.9, "DAFT", 0, 3, 7, 2 }, // 50% ratio - /* 40*/ { BARCODE_DAFT, 500, 0.4, "DAFT", 0, 3, 7, 8 }, // 50% ratio + /* 20*/ { BARCODE_JAPANPOST, -1, 0, "1234567890-ABCD", 0, 3, 133, 8 }, // 19 symbol chars + /* 21*/ { BARCODE_JAPANPOST, -1, 0, "1234567890-ABCD1", 0, 3, 133, 8 }, // 20 symbol chars + /* 22*/ { BARCODE_JAPANPOST, -1, 0, "1234567890-ABCDE", ZINT_ERROR_TOO_LONG, -1, -1, -1 }, // 21 symbol chars + /* 23*/ { BARCODE_JAPANPOST, -1, 0, "1234567890-ABCD12", ZINT_ERROR_TOO_LONG, -1, -1, -1 }, // 21 symbol chars + /* 24*/ { BARCODE_JAPANPOST, -1, 0, "1234567890ABCDE", 0, 3, 133, 8 }, // 20 symbol chars + /* 25*/ { BARCODE_JAPANPOST, -1, 0, "a", 0, 3, 133, 8 }, // Converts to upper + /* 26*/ { BARCODE_JAPANPOST, -1, 0, ",", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, + /* 27*/ { BARCODE_KOREAPOST, -1, 0, "123456", 0, 1, 167, 50 }, + /* 28*/ { BARCODE_KOREAPOST, -1, 0, "A", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, + /* 29*/ { BARCODE_PLANET, -1, 0, "12345678901", 0, 2, 123, 12 }, + /* 30*/ { BARCODE_PLANET, -1, 0, "1234567890123", 0, 2, 143, 12 }, + /* 31*/ { BARCODE_PLANET, -1, 0, "0", ZINT_WARN_NONCOMPLIANT, 2, 23, 12 }, + /* 32*/ { BARCODE_PLANET, -1, 0, "1234567890", ZINT_WARN_NONCOMPLIANT, 2, 113, 12 }, + /* 33*/ { BARCODE_PLANET, -1, 0, "123456789012", ZINT_WARN_NONCOMPLIANT, 2, 133, 12 }, + /* 34*/ { BARCODE_PLANET, -1, 0, "12345678901234", ZINT_WARN_NONCOMPLIANT, 2, 153, 12 }, + /* 35*/ { BARCODE_PLANET, -1, 0, "1234567890A", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, + /* 36*/ { BARCODE_KIX, -1, 0, "0123456789ABCDEFGH", 0, 3, 143, 8 }, + /* 37*/ { BARCODE_KIX, -1, 0, "a", 0, 3, 7, 8 }, // Converts to upper + /* 38*/ { BARCODE_KIX, -1, 0, ",", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, + /* 39*/ { BARCODE_DAFT, -1, 0, "DAFT", 0, 3, 7, 8 }, + /* 40*/ { BARCODE_DAFT, -1, 0, "a", 0, 3, 1, 8 }, // Converts to upper + /* 41*/ { BARCODE_DAFT, -1, 0, "B", ZINT_ERROR_INVALID_DATA, -1, -1, -1 }, + /* 42*/ { BARCODE_DAFT, -1, 1.9, "DAFT", 0, 3, 7, 2 }, + /* 43*/ { BARCODE_DAFT, 500, 0.9, "DAFT", 0, 3, 7, 2 }, // 50% ratio + /* 44*/ { BARCODE_DAFT, 500, 0.4, "DAFT", 0, 3, 7, 8 }, // 50% ratio }; int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -329,60 +335,95 @@ static void test_encode(int index, int generate, int debug) { "101010101010101010101010101010101010101010101010101010101010101010101010101" "000010100000100010001000100000101010100000100000100000101000100010001010001" }, - /* 6*/ { BARCODE_JAPANPOST, "15400233-16-4-205", 0, 3, 133, "Zip/Barcode Manual p.6 1st example; verified manually against tec-it", + /* 6*/ { BARCODE_RM4SCC, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0, 3, 299, "Verified manually against tec-it", + "10000010100000101000001010000010100000101000001010001000100010001000100010001000100010001000100010001010000010100000101000001010000010100000101000100000101000001010000010100000101000001010000010100010001000100010001000100010001000100010001000101000001010000010100000101000001010000010100000101000001" + "10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "00000010100010001000101000100000101000100010100000000010100010001000101000100000101000100010100000000010100010001000101000100000101000100010100000000010100010001000101000100000101000100010100000000010100010001000101000100000101000100010100000000010100010001000101000100000101000100010100000101000001" + }, + /* 7*/ { BARCODE_JAPANPOST, "15400233-16-4-205", 0, 3, 133, "Zip/Barcode Manual p.6 1st example; verified manually against tec-it", "1000101000100010101000100000100000100010001010001010001000101000001010001000101000001000100010100000100010000010000010000010001010001" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "1010101000100010100010100000100000101000101000101000001000101000100010001000100010001000101000100000100010001000001000001000100010101" }, - /* 7*/ { BARCODE_JAPANPOST, "350110622-1A308", 0, 3, 133, "Zip/Barcode Manual p.6 2nd example; verified manually against tec-it", + /* 8*/ { BARCODE_JAPANPOST, "350110622-1A308", 0, 3, 133, "Zip/Barcode Manual p.6 2nd example; verified manually against tec-it", "1000001010100010100000101000101000100000001010100010100010001000101000001000100000001010100000100010000010000010000010000010100010001" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "1010101000100010100000101000101000100000100010101000101000001000101000100000100000101000100000001010001000001000001000001000100010101" }, - /* 8*/ { BARCODE_JAPANPOST, "12345671-2-3", 0, 3, 133, "Verified manually against tec-it", + /* 9*/ { BARCODE_JAPANPOST, "12345671-2-3", 0, 3, 133, "Verified manually against tec-it", "1000101000100010001010101000100010001010101000101000001000100010001000001010000010000010000010000010000010000010000010000010100010001" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "1010101000101000101000100010100010100010001010101000001000101000001000101000001000001000001000001000001000001000001000001000100010101" }, - /* 9*/ { BARCODE_KOREAPOST, "010230", 0, 1, 167, "Verified manually against tec-it", + /* 10*/ { BARCODE_JAPANPOST, "1234567BCDEFG", 0, 3, 133, "Verified manually against tec-it", + "1000101000100010001010101000100010001010101000001000101000001000100010001000001010001000101000001000100010001000001010000010101000001" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "1010101000101000101000100010100010100010001010100000101000100000101000100000101000100000100010100000100010100000100010001000100010101" + }, + /* 11*/ { BARCODE_JAPANPOST, "8901234HIJKLM", 0, 3, 133, "Verified manually against tec-it", + "1000100010001010100000101000100010001010101000001000101000001000100010001000001010000010100000000010101000000010100010000010100000001" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "1010001010001010100000101000101000101000100010100000001010100000001010100000001010100000100000100000101000100000101000001000000010101" + }, + /* 12*/ { BARCODE_JAPANPOST, "0987654NOPQRS", 0, 3, 133, "Verified manually against tec-it", + "1000100000001010100010101000001010100010101000000010001010000010101000000010100010000010001010000010101000000010100010000010100000001" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "1010100000001010001010001010100010100010100010100000101000100000100010100000100010100000100010100000001010100000001010001000001000101" + }, + /* 13*/ { BARCODE_JAPANPOST, "3210987TUVWXY", 0, 3, 133, "Verified manually against tec-it", + "1000001010100010101000100000001010100010101000000010001010100000100000100000101000100000100010100000001010100000101000000010000010001" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "1010101000101000101000100000001010001010001010100000001010001000100000001000101000001000101000001000101000001000100010001000100000101" + }, + /* 14*/ { BARCODE_KOREAPOST, "010230", 0, 1, 167, "Verified manually against tec-it", "10001000100000000000100010000000000010001000100000001000000010001000100010001000100000000000100000000001000100010001000100010001000000000001000000010001000000010001000" }, - /* 10*/ { BARCODE_KOREAPOST, "923457", 0, 1, 168, "Verified manually against tec-it", + /* 15*/ { BARCODE_KOREAPOST, "923457", 0, 1, 168, "Verified manually against tec-it", "000010001000100000001000100000001000000010001000000010001000000010001000100000000000100010001000000010000000100010001000100010000000100000001000100010001000000000001000" }, - /* 11*/ { BARCODE_PLANET, "4012345235636", 0, 2, 143, "USPS Publication 197 (2004) Exhibit 4; verified manually against tec-it", + /* 16*/ { BARCODE_PLANET, "4012345235636", 0, 2, 143, "USPS Publication 197 (2004) Exhibit 4; verified manually against tec-it", "10100010100000001010101010100000101000100010100000101000101000100010001010100010001010000010100010001010000010101010000010100000101010000010101" "10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" }, - /* 12*/ { BARCODE_PLANET, "40123452356", 0, 2, 123, "Verified manually against tec-it", + /* 17*/ { BARCODE_PLANET, "40123452356", 0, 2, 123, "Verified manually against tec-it", "101000101000000010101010101000001010001000101000001010001010001000100010101000100010100000101000100010100000101010001000101" "101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" }, - /* 13*/ { BARCODE_PLANET, "5020140235635", 0, 2, 143, "USPS Publication 197 (2004) Exhibit 6; verified manually against tec-it", + /* 18*/ { BARCODE_PLANET, "5020140235635", 0, 2, 143, "USPS Publication 197 (2004) Exhibit 6; verified manually against tec-it", "10100010001000001010101010001000000010101010101000001000101000000010101010100010001010000010100010001010000010101010000010100010001010001010001" "10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" }, - /* 14*/ { BARCODE_KIX, "2500GG30250", 0, 3, 87, "PostNL Handleiding KIX code Section 2.1 Example 1", + /* 19*/ { BARCODE_KIX, "2500GG30250", 0, 3, 87, "PostNL Handleiding KIX code Section 2.1 Example 1", "000010100000101000001010000010100010100000101000000010100000101000001010000010100000101" "101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "001010001010000000001010000010101000100010001000100000100000101000101000101000000000101" }, - /* 15*/ { BARCODE_KIX, "2130VA80430", 0, 3, 87, "PostNL Handleiding KIX code Section 2.1 Example 2", + /* 20*/ { BARCODE_KIX, "2130VA80430", 0, 3, 87, "PostNL Handleiding KIX code Section 2.1 Example 2", "000010100000101000001010000010101010000000100010001000100000101000001010000010100000101" "101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "001010000010001010000010000010100010001010001000001010000000101010001000100000100000101" }, - /* 16*/ { BARCODE_KIX, "1231GF156X2", 0, 3, 87, "PostNL Handleiding KIX code Section 2.1 Example 3", + /* 21*/ { BARCODE_KIX, "1231GF156X2", 0, 3, 87, "PostNL Handleiding KIX code Section 2.1 Example 3", "000010100000101000001010000010100010100000101000000010100000101000100010101000000000101" "101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "001000100010100010000010001000101000100010000010001000101010000000001010100000100010100" }, - /* 17*/ { BARCODE_KIX, "1231FZ13Xhs", 0, 3, 87, "PostNL Handleiding KIX code Section 2.1 Example 4", + /* 22*/ { BARCODE_KIX, "1231FZ13Xhs", 0, 3, 87, "PostNL Handleiding KIX code Section 2.1 Example 4", "000010100000101000001010000010100010100010100000000010100000101010100000001010001000100" "101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "001000100010100010000010001000101000001010100000001000101000001010000010101000001000100" }, - /* 18*/ { BARCODE_DAFT, "DAFTTFADFATDTATFT", 0, 3, 33, "Verified manually against tec-it", + /* 23*/ { BARCODE_KIX, "1234567890ABCDEFGH", 0, 3, 143, "Verified manually against tec-it", + "00001010000010100000101000001010000010100010001000100010001000100010001000001010001000100010001000101000001010000010100000101000001010000010100" + "10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "00100010001010001000001010001000101000000000101000100010001010001000001000001010100010001010000000001010001000100010100010000010100010001010000" + }, + /* 24*/ { BARCODE_KIX, "IJKLMNOPQRSTUVWXYZ", 0, 3, 143, "Verified manually against tec-it", + "10000010100000101000001010000010100000101000001010001000100010001000100010001000100010001000100010100000101000001010000010100000101000001010000" + "10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "00001010001000100010100010000010100010001010000000001010001000100010100010000010100010001010000000001010001000100010100010000010100010001010000" + }, + /* 25*/ { BARCODE_DAFT, "DAFTTFADFATDTATFT", 0, 3, 33, "Verified manually against tec-it", "001010000010100010100000001000100" "101010101010101010101010101010101" "100010000010001010000010000000100" @@ -445,6 +486,106 @@ static void test_encode(int index, int generate, int debug) { testFinish(); } +#include + +#define TEST_PERF_ITER_MILLES 10 +#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(int index, int debug) { + + struct item { + int symbology; + int option_2; + char *data; + int ret; + + int expected_rows; + int expected_width; + char *comment; + }; + struct item data[] = { + /* 0*/ { BARCODE_POSTNET, -1, "12345678901", 0, 2, 123, "POSTNET 11" }, + /* 1*/ { BARCODE_PLANET, -1, "1234567890123", 0, 2, 143, "PLANET 13" }, + /* 2*/ { BARCODE_KOREAPOST, -1, "123456", 0, 1, 167, "KOREAPOST 6" }, + }; + 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 (index != -1 && i != index) 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(remove(symbol->outfile), "i:%d remove(%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 (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, has_index, has_generate, has_debug */ @@ -453,6 +594,7 @@ int main(int argc, char *argv[]) { { "test_japanpost", test_japanpost, 1, 0, 1 }, { "test_input", test_input, 1, 0, 1 }, { "test_encode", test_encode, 1, 1, 1 }, + { "test_perf", test_perf, 1, 0, 1 }, }; testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); diff --git a/backend/tests/test_raster.c b/backend/tests/test_raster.c index 059f90ee..29298903 100644 --- a/backend/tests/test_raster.c +++ b/backend/tests/test_raster.c @@ -2518,7 +2518,9 @@ static void test_height(int index, int generate, int debug) { #include -#define TEST_PERF_ITERATIONS 1000 +#define TEST_PERF_ITER_MILLES 1 +#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 for scaling static void test_perf_scale(int index, int debug) { @@ -2547,28 +2549,38 @@ static void test_perf_scale(int index, int debug) { "HIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345678901234567" "890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcde" "fghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO", - 0, 40, 307, "960 chars, text/numeric" }, - /* 1*/ { BARCODE_POSTNET, -1, -1, BARCODE_QUIET_ZONES, -1, -1, 0, 1.1, "12345", 0, 2, 63, "" }, - /* 2*/ { BARCODE_ITF14, -1, 4, BARCODE_BIND, -1, -1, 61.8, 3.1, "12345", 0, 1, 135, "" }, + 0, 40, 307, "PDF417 960 chars, text/numeric, 1.3" }, + /* 1*/ { BARCODE_POSTNET, -1, -1, BARCODE_QUIET_ZONES, -1, -1, 0, 1.1, "12345", 0, 2, 63, "POSTNET 5 chars, quiet zones, 1.1" }, + /* 2*/ { BARCODE_ITF14, -1, 4, BARCODE_BIND, -1, -1, 61.8, 3.1, "12345", 0, 1, 135, "ITF14 bind 4, height 61.8, 3.1" }, }; int data_size = ARRAY_SIZE(data); int i, length, ret; + struct zint_symbol *symbol; - clock_t start, total_encode = 0, total_buffer = 0, diff_encode, diff_buffer; + 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 (index != -1 && i != index) continue; - diff_encode = diff_buffer = 0; + diff_create = diff_encode = diff_buffer = diff_buf_inter = diff_print = 0; for (j = 0; j < TEST_PERF_ITERATIONS; j++) { - struct zint_symbol *symbol = ZBarcode_Create(); + start = clock(); + symbol = ZBarcode_Create(); + diff_create += clock() - start; assert_nonnull(symbol, "Symbol not created\n"); length = testUtilSetSymbol(symbol, data[i].symbology, data[i].input_mode, -1 /*eci*/, data[i].option_1, data[i].option_2, -1, data[i].output_options, data[i].data, -1, debug); @@ -2592,16 +2604,34 @@ static void test_perf_scale(int index, int debug) { 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(remove(symbol->outfile), "i:%d remove(%s) != 0\n", i, symbol->outfile); + ZBarcode_Delete(symbol); } - printf("%s: diff_encode %gms, diff_buffer %gms\n", data[i].comment, diff_encode * 1000.0 / CLOCKS_PER_SEC, diff_buffer * 1000.0 / CLOCKS_PER_SEC); + 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 (index != -1) { - printf("totals: encode %gms, buffer %gms\n", total_encode * 1000.0 / CLOCKS_PER_SEC, total_buffer * 1000.0 / CLOCKS_PER_SEC); + if (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)); } } diff --git a/backend/tests/test_reedsol.c b/backend/tests/test_reedsol.c index d0ef01fa..8dff481a 100644 --- a/backend/tests/test_reedsol.c +++ b/backend/tests/test_reedsol.c @@ -34,28 +34,28 @@ // Print out the log/alog tables for "backend/reedsol_logs.h" static void print_logs(const char *name, int logmod, unsigned int *logt, unsigned int *alog, int u16, int last) { - int i; + int i; const char *type = u16 ? "short" : "char"; const char *format = u16 ? " 0x%04X," : " 0x%02X,"; - printf("static const unsigned %s logt_%s[%d] = {", type, name, logmod + 1); - for (i = 0; i < logmod + 1; i++) { - if (i % 16 == 0) printf("\n "); - printf(format, i ? logt[i] : 0); - } - printf("\n};\n"); + printf("static const unsigned %s logt_%s[%d] = {", type, name, logmod + 1); + for (i = 0; i < logmod + 1; i++) { + if (i % 16 == 0) printf("\n "); + printf(format, i ? logt[i] : 0); + } + printf("\n};\n"); - printf("static const unsigned %s alog_%s[%d] = {", type, name, logmod * 2); - for (i = 0; i < logmod; i++) { - if (i % 16 == 0) printf("\n "); - printf(format, alog[i]); - } + printf("static const unsigned %s alog_%s[%d] = {", type, name, logmod * 2); + for (i = 0; i < logmod; i++) { + if (i % 16 == 0) printf("\n "); + printf(format, alog[i]); + } // Double antilog table for (i = 0; i < logmod; i++) { if (i % 16 == 0) printf("\n "); printf(format, alog[i]); } - printf("\n};\n"); + printf("\n};\n"); if (!last) { printf("\n"); } diff --git a/backend/tests/test_telepen.c b/backend/tests/test_telepen.c index a55fe7fa..dea2c358 100644 --- a/backend/tests/test_telepen.c +++ b/backend/tests/test_telepen.c @@ -330,6 +330,62 @@ static void test_fuzz(int index, int debug) { testFinish(); } +static char TeleTable[128][16] = { + { "31313131" }, { "1131313111" }, { "33313111" }, { "1111313131" }, + { "3111313111" }, { "11333131" }, { "13133131" }, { "111111313111" }, + { "31333111" }, { "1131113131" }, { "33113131" }, { "1111333111" }, + { "3111113131" }, { "1113133111" }, { "1311133111" }, { "111111113131" }, + { "3131113111" }, { "11313331" }, { "333331" }, { "111131113111" }, + { "31113331" }, { "1133113111" }, { "1313113111" }, { "1111113331" }, + { "31131331" }, { "113111113111" }, { "3311113111" }, { "1111131331" }, + { "311111113111" }, { "1113111331" }, { "1311111331" }, { "11111111113111" }, + { "31313311" }, { "1131311131" }, { "33311131" }, { "1111313311" }, + { "3111311131" }, { "11333311" }, { "13133311" }, { "111111311131" }, + { "31331131" }, { "1131113311" }, { "33113311" }, { "1111331131" }, + { "3111113311" }, { "1113131131" }, { "1311131131" }, { "111111113311" }, + { "3131111131" }, { "1131131311" }, { "33131311" }, { "111131111131" }, + { "3111131311" }, { "1133111131" }, { "1313111131" }, { "111111131311" }, + { "3113111311" }, { "113111111131" }, { "3311111131" }, { "111113111311" }, + { "311111111131" }, { "111311111311" }, { "131111111311" }, { "11111111111131" }, + { "3131311111" }, { "11313133" }, { "333133" }, { "111131311111" }, + { "31113133" }, { "1133311111" }, { "1313311111" }, { "1111113133" }, + { "313333" }, { "113111311111" }, { "3311311111" }, { "11113333" }, + { "311111311111" }, { "11131333" }, { "13111333" }, { "11111111311111" }, + { "31311133" }, { "1131331111" }, { "33331111" }, { "1111311133" }, + { "3111331111" }, { "11331133" }, { "13131133" }, { "111111331111" }, + { "3113131111" }, { "1131111133" }, { "33111133" }, { "111113131111" }, + { "3111111133" }, { "111311131111" }, { "131111131111" }, { "111111111133" }, + { "31311313" }, { "113131111111" }, { "3331111111" }, { "1111311313" }, + { "311131111111" }, { "11331313" }, { "13131313" }, { "11111131111111" }, + { "3133111111" }, { "1131111313" }, { "33111313" }, { "111133111111" }, + { "3111111313" }, { "111313111111" }, { "131113111111" }, { "111111111313" }, + { "313111111111" }, { "1131131113" }, { "33131113" }, { "11113111111111" }, + { "3111131113" }, { "113311111111" }, { "131311111111" }, { "111111131113" }, + { "3113111113" }, { "11311111111111" }, { "331111111111" }, { "111113111113" }, + { "31111111111111" }, { "111311111113" }, { "131111111113" }, + {'1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'}, +}; + +// Dummy to generate lengths table +static void test_generate_lens(int generate) { + + int i; + + if (!generate) { + return; + } + + printf("static const char TeleLens[128] = {"); + for (i = 0; i < 127; i++) { + if ((i % 16) == 0) { + printf("\n %2d,", (int) strlen(TeleTable[i])); + } else { + printf(" %2d,", (int) strlen(TeleTable[i])); + } + } + printf(" 16\n};\n"); +} + int main(int argc, char *argv[]) { testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */ @@ -338,6 +394,7 @@ int main(int argc, char *argv[]) { { "test_input", test_input, 1, 0, 1 }, { "test_encode", test_encode, 1, 1, 1 }, { "test_fuzz", test_fuzz, 1, 0, 1 }, + { "test_generate_lens", test_generate_lens, 0, 1, 0 }, }; testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); diff --git a/backend/tests/test_tif.c b/backend/tests/test_tif.c index 4058e340..2f1cedf9 100644 --- a/backend/tests/test_tif.c +++ b/backend/tests/test_tif.c @@ -92,7 +92,7 @@ static void test_pixel_plot(int index, int debug) { char *tif = "out.tif"; - char data_buf[65536]; + char data_buf[ZINT_MAX_DATA_LEN * 2 + 1]; int have_tiffinfo = testUtilHaveTiffInfo(); int have_identify = testUtilHaveIdentify(); diff --git a/backend/tests/test_upcean.c b/backend/tests/test_upcean.c index 957a4f53..f98bc64f 100644 --- a/backend/tests/test_upcean.c +++ b/backend/tests/test_upcean.c @@ -266,150 +266,154 @@ static void test_upca_input(int index, int debug) { testFinish(); } -static void test_eanx_input(int index, int debug) { +static void test_eanx_input(int index, int generate, int debug) { struct item { int symbology; char *data; int ret; + char *ret_errtxt; + char *comment; }; // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) struct item data[] = { - /* 0*/ { BARCODE_EANX, "123456789012", 0 }, - /* 1*/ { BARCODE_EANX, "12345678901A", ZINT_ERROR_INVALID_DATA }, - /* 2*/ { BARCODE_EANX, "12345678901", 0 }, - /* 3*/ { BARCODE_EANX, "1234567890128", 0 }, // EANX accepts CHK (treated as such if no leading zeroes required) - /* 4*/ { BARCODE_EANX, "1234567890120", ZINT_ERROR_INVALID_CHECK }, - /* 5*/ { BARCODE_EANX, "123456789012+1", 0 }, - /* 6*/ { BARCODE_EANX, "1234567890128+1", 0 }, - /* 7*/ { BARCODE_EANX, "1234567890121+1", ZINT_ERROR_INVALID_CHECK }, - /* 8*/ { BARCODE_EANX, "123456789012+12", 0 }, - /* 9*/ { BARCODE_EANX, "1234567890128+12", 0 }, - /* 10*/ { BARCODE_EANX, "1234567890122+12", ZINT_ERROR_INVALID_CHECK }, - /* 11*/ { BARCODE_EANX, "12345678901234+12", ZINT_ERROR_TOO_LONG }, - /* 12*/ { BARCODE_EANX, "123456789012345+12", ZINT_ERROR_TOO_LONG }, - /* 13*/ { BARCODE_EANX, "1234567890123456+12", ZINT_ERROR_TOO_LONG }, - /* 14*/ { BARCODE_EANX, "123456789012+123", 0 }, - /* 15*/ { BARCODE_EANX, "1234567890128+123", 0 }, - /* 16*/ { BARCODE_EANX, "1234567890123+123", ZINT_ERROR_INVALID_CHECK }, - /* 17*/ { BARCODE_EANX, "12345678901234+123", ZINT_ERROR_TOO_LONG }, - /* 18*/ { BARCODE_EANX, "123456789012345+123", ZINT_ERROR_TOO_LONG }, - /* 19*/ { BARCODE_EANX, "123456789012+1234", 0 }, - /* 20*/ { BARCODE_EANX, "1234567890128+1234", 0 }, - /* 21*/ { BARCODE_EANX, "1234567890124+1234", ZINT_ERROR_INVALID_CHECK }, - /* 22*/ { BARCODE_EANX, "12345678901234+1234", ZINT_ERROR_TOO_LONG }, - /* 23*/ { BARCODE_EANX, "123456789012+12345", 0 }, - /* 24*/ { BARCODE_EANX, "1234567890128+12345", 0 }, - /* 25*/ { BARCODE_EANX, "12345678901234+12345", ZINT_ERROR_TOO_LONG }, - /* 26*/ { BARCODE_EANX, "1234567890125+12345", ZINT_ERROR_INVALID_CHECK }, - /* 27*/ { BARCODE_EANX, "123456789012+123456", ZINT_ERROR_TOO_LONG }, - /* 28*/ { BARCODE_EANX, "1234567890128+123456", ZINT_ERROR_TOO_LONG }, - /* 29*/ { BARCODE_EANX, "12345678901+123456", ZINT_ERROR_TOO_LONG }, - /* 30*/ { BARCODE_EANX, "12345678901+1234567", ZINT_ERROR_TOO_LONG }, - /* 31*/ { BARCODE_EANX, "1234567890+123456", ZINT_ERROR_TOO_LONG }, - /* 32*/ { BARCODE_EANX, "1234567890+1234567", ZINT_ERROR_TOO_LONG }, - /* 33*/ { BARCODE_EANX, "123456789+123456", ZINT_ERROR_TOO_LONG }, - /* 34*/ { BARCODE_EANX, "123456789+1234567", ZINT_ERROR_TOO_LONG }, - /* 35*/ { BARCODE_EANX, "12345678+123456", ZINT_ERROR_TOO_LONG }, - /* 36*/ { BARCODE_EANX, "1234567+123456", ZINT_ERROR_TOO_LONG }, // EAN-8 - /* 37*/ { BARCODE_EANX, "123456+123456", ZINT_ERROR_TOO_LONG }, - /* 38*/ { BARCODE_EANX, "12345+123456", ZINT_ERROR_TOO_LONG }, - /* 39*/ { BARCODE_EANX, "1234+123456", ZINT_ERROR_TOO_LONG }, - /* 40*/ { BARCODE_EANX, "123+123456", ZINT_ERROR_TOO_LONG }, - /* 41*/ { BARCODE_EANX, "12+123456", ZINT_ERROR_TOO_LONG }, - /* 42*/ { BARCODE_EANX, "1+123456", ZINT_ERROR_TOO_LONG }, - /* 43*/ { BARCODE_EANX, "1+12345678901234", ZINT_ERROR_TOO_LONG }, - /* 44*/ { BARCODE_EANX, "1+12345", 0 }, - /* 45*/ { BARCODE_EANX, "1+", 0 }, // EAN-2 - /* 46*/ { BARCODE_EANX, "+1", 0 }, // EAN-8 - /* 47*/ { BARCODE_EANX, "+", 0 }, // EAN-2 - /* 48*/ { BARCODE_EANX, "1", 0 }, // EAN-2 - /* 49*/ { BARCODE_EANX, "12", 0 }, // EAN-2 - /* 50*/ { BARCODE_EANX, "123", 0 }, // EAN-5 - /* 51*/ { BARCODE_EANX, "12345678901234", ZINT_ERROR_TOO_LONG }, - /* 52*/ { BARCODE_EANX, "1234567890123A", ZINT_ERROR_INVALID_DATA }, - /* 53*/ { BARCODE_EANX, "123456789012345", ZINT_ERROR_TOO_LONG }, - /* 54*/ { BARCODE_EANX, "12345678901234A", ZINT_ERROR_INVALID_DATA }, - /* 55*/ { BARCODE_EANX, "1234567890123456", ZINT_ERROR_TOO_LONG }, - /* 56*/ { BARCODE_EANX, "12345678901234567", ZINT_ERROR_TOO_LONG }, - /* 57*/ { BARCODE_EANX, "123456789012345678", ZINT_ERROR_TOO_LONG }, - /* 58*/ { BARCODE_EANX, "1234567890123456789", ZINT_ERROR_TOO_LONG }, - /* 59*/ { BARCODE_EANX_CHK, "1234567890128", 0 }, - /* 60*/ { BARCODE_EANX_CHK, "1234567890126", ZINT_ERROR_INVALID_CHECK }, - /* 61*/ { BARCODE_EANX_CHK, "123456789012A", ZINT_ERROR_INVALID_DATA }, - /* 62*/ { BARCODE_EANX_CHK, "123456789012", 0 }, // Note: this is "0123456789012" with '2' happening to be the correct check digit - /* 63*/ { BARCODE_EANX_CHK, "123456789013", ZINT_ERROR_INVALID_CHECK }, - /* 64*/ { BARCODE_EANX_CHK, "12345678901", ZINT_ERROR_INVALID_CHECK }, - /* 65*/ { BARCODE_EANX_CHK, "12345678905", 0 }, - /* 66*/ { BARCODE_EANX_CHK, "1234567890", ZINT_ERROR_INVALID_CHECK }, - /* 67*/ { BARCODE_EANX_CHK, "123456789", ZINT_ERROR_INVALID_CHECK }, - /* 68*/ { BARCODE_EANX_CHK, "12345678", ZINT_ERROR_INVALID_CHECK }, // EAN-8 - /* 69*/ { BARCODE_EANX_CHK, "1234567", ZINT_ERROR_INVALID_CHECK }, - /* 70*/ { BARCODE_EANX_CHK, "123456", ZINT_ERROR_INVALID_CHECK }, - /* 71*/ { BARCODE_EANX_CHK, "12345", 0 }, // EAN-5 - /* 72*/ { BARCODE_EANX_CHK, "1234", 0 }, - /* 73*/ { BARCODE_EANX_CHK, "123", 0 }, - /* 74*/ { BARCODE_EANX_CHK, "12", 0 }, // EAN-2 - /* 75*/ { BARCODE_EANX_CHK, "1", 0 }, - /* 76*/ { BARCODE_EANX_CHK, "123456789012+1", 0 }, - /* 77*/ { BARCODE_EANX_CHK, "1234567890128+1", 0 }, - /* 78*/ { BARCODE_EANX_CHK, "1234567890127+1", ZINT_ERROR_INVALID_CHECK }, - /* 79*/ { BARCODE_EANX_CHK, "123456789012+12", 0 }, - /* 80*/ { BARCODE_EANX_CHK, "1234567890128+12", 0 }, - /* 81*/ { BARCODE_EANX_CHK, "1234567890129+12", ZINT_ERROR_INVALID_CHECK }, - /* 82*/ { BARCODE_EANX_CHK, "123456789012+123", 0 }, - /* 83*/ { BARCODE_EANX_CHK, "1234567890128+123", 0 }, - /* 84*/ { BARCODE_EANX_CHK, "1234567890120+1234", ZINT_ERROR_INVALID_CHECK }, - /* 85*/ { BARCODE_EANX_CHK, "123456789012+1234", 0 }, - /* 86*/ { BARCODE_EANX_CHK, "1234567890128+1234", 0 }, - /* 87*/ { BARCODE_EANX_CHK, "1234567890121+1234", ZINT_ERROR_INVALID_CHECK }, - /* 88*/ { BARCODE_EANX_CHK, "123456789012+12345", 0 }, - /* 89*/ { BARCODE_EANX_CHK, "1234567890128+12345", 0 }, - /* 90*/ { BARCODE_EANX_CHK, "1234567890122+12345", ZINT_ERROR_INVALID_CHECK }, - /* 91*/ { BARCODE_EANX_CHK, "1234567890122+1234A", ZINT_ERROR_INVALID_DATA }, - /* 92*/ { BARCODE_EANX_CHK, "123456789012+123456", ZINT_ERROR_TOO_LONG }, - /* 93*/ { BARCODE_EANX_CHK, "123456789012+12345A", ZINT_ERROR_INVALID_DATA }, - /* 94*/ { BARCODE_EANX_CHK, "1234567890128+123456", ZINT_ERROR_TOO_LONG }, - /* 95*/ { BARCODE_EANX_CHK, "12345678901+123456", ZINT_ERROR_TOO_LONG }, - /* 96*/ { BARCODE_EANX_CHK, "12345678901+1234567", ZINT_ERROR_TOO_LONG }, - /* 97*/ { BARCODE_EANX_CHK, "12345678901+12345", ZINT_ERROR_INVALID_CHECK }, - /* 98*/ { BARCODE_EANX_CHK, "1234567890+12345", ZINT_ERROR_INVALID_CHECK }, - /* 99*/ { BARCODE_EANX_CHK, "1234567890+123456", ZINT_ERROR_TOO_LONG }, - /*100*/ { BARCODE_EANX_CHK, "123456789+12345", ZINT_ERROR_INVALID_CHECK }, - /*101*/ { BARCODE_EANX_CHK, "12345678+12345", ZINT_ERROR_INVALID_CHECK }, // EAN-8 - /*102*/ { BARCODE_EANX_CHK, "12345670+12345", 0 }, - /*103*/ { BARCODE_EANX_CHK, "1234567+12345", ZINT_ERROR_INVALID_CHECK }, - /*104*/ { BARCODE_EANX_CHK, "1234565+12345", 0 }, - /*105*/ { BARCODE_EANX_CHK, "123456+12345", ZINT_ERROR_INVALID_CHECK }, - /*106*/ { BARCODE_EANX_CHK, "123457+12345", 0 }, - /*107*/ { BARCODE_EANX_CHK, "12345+12345", ZINT_ERROR_INVALID_CHECK }, - /*108*/ { BARCODE_EANX_CHK, "12348+12345", 0 }, - /*109*/ { BARCODE_EANX_CHK, "1234+12345", ZINT_ERROR_INVALID_CHECK }, - /*110*/ { BARCODE_EANX_CHK, "1236+12345", 0 }, - /*111*/ { BARCODE_EANX_CHK, "123+12345", 0 }, // 3 happens to be correct check digit - /*112*/ { BARCODE_EANX_CHK, "124+12345", ZINT_ERROR_INVALID_CHECK }, - /*113*/ { BARCODE_EANX_CHK, "12+12345", ZINT_ERROR_INVALID_CHECK }, - /*114*/ { BARCODE_EANX_CHK, "17+12345", 0 }, - /*115*/ { BARCODE_EANX_CHK, "1+12345", ZINT_ERROR_INVALID_CHECK }, - /*116*/ { BARCODE_EANX_CHK, "0+12345", 0 }, - /*117*/ { BARCODE_EANX_CHK, "0+123456", ZINT_ERROR_TOO_LONG }, - /*118*/ { BARCODE_EANX_CHK, "1+12345678901234", ZINT_ERROR_TOO_LONG }, - /*119*/ { BARCODE_EANX_CHK, "0+12345678901234", ZINT_ERROR_TOO_LONG }, - /*120*/ { BARCODE_EANX_CHK, "1+", 0 }, // EAN-2 - /*121*/ { BARCODE_EANX_CHK, "+1", 0 }, // EAN-8 - /*122*/ { BARCODE_EANX_CHK, "+", 0 }, // EAN-2 - /*123*/ { BARCODE_EANX_CHK, "12345678901234", ZINT_ERROR_TOO_LONG }, - /*124*/ { BARCODE_EANX_CHK, "1234567890123A", ZINT_ERROR_INVALID_DATA }, - /*125*/ { BARCODE_EANX_CHK, "123456789012345", ZINT_ERROR_TOO_LONG }, - /*126*/ { BARCODE_EANX_CHK, "1234567890123456", ZINT_ERROR_TOO_LONG }, - /*127*/ { BARCODE_EANX_CHK, "12345678901234567", ZINT_ERROR_TOO_LONG }, - /*128*/ { BARCODE_EANX_CHK, "123456789012345678", ZINT_ERROR_TOO_LONG }, - /*129*/ { BARCODE_EANX_CHK, "1234567890123456789", ZINT_ERROR_TOO_LONG }, + /* 0*/ { BARCODE_EANX, "123456789012", 0, "", "" }, + /* 1*/ { BARCODE_EANX, "12345678901A", ZINT_ERROR_INVALID_DATA, "Error 284: Invalid character in data (digits and \"+\" only)", "" }, + /* 2*/ { BARCODE_EANX, "12345678901", 0, "", "" }, + /* 3*/ { BARCODE_EANX, "1234567890128", 0, "", "EANX accepts CHK (treated as such if no leading zeroes required)" }, + /* 4*/ { BARCODE_EANX, "1234567890120", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '0', expecting '8'", "" }, + /* 5*/ { BARCODE_EANX, "123456789012+1", 0, "", "" }, + /* 6*/ { BARCODE_EANX, "1234567890128+1", 0, "", "" }, + /* 7*/ { BARCODE_EANX, "1234567890121+1", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '1', expecting '8'", "" }, + /* 8*/ { BARCODE_EANX, "123456789012+12", 0, "", "" }, + /* 9*/ { BARCODE_EANX, "1234567890128+12", 0, "", "" }, + /* 10*/ { BARCODE_EANX, "1234567890122+12", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '2', expecting '8'", "" }, + /* 11*/ { BARCODE_EANX, "12345678901234+12", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 12*/ { BARCODE_EANX, "123456789012345+12", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 13*/ { BARCODE_EANX, "1234567890123456+12", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 14*/ { BARCODE_EANX, "123456789012+123", 0, "", "" }, + /* 15*/ { BARCODE_EANX, "1234567890128+123", 0, "", "" }, + /* 16*/ { BARCODE_EANX, "1234567890123+123", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '3', expecting '8'", "" }, + /* 17*/ { BARCODE_EANX, "12345678901234+123", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 18*/ { BARCODE_EANX, "123456789012345+123", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 19*/ { BARCODE_EANX, "123456789012+1234", 0, "", "" }, + /* 20*/ { BARCODE_EANX, "1234567890128+1234", 0, "", "" }, + /* 21*/ { BARCODE_EANX, "1234567890124+1234", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '4', expecting '8'", "" }, + /* 22*/ { BARCODE_EANX, "12345678901234+1234", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 23*/ { BARCODE_EANX, "123456789012+12345", 0, "", "" }, + /* 24*/ { BARCODE_EANX, "1234567890128+12345", 0, "", "" }, + /* 25*/ { BARCODE_EANX, "12345678901234+12345", ZINT_ERROR_TOO_LONG, "Error 283: Input too long (19 character maximum)", "" }, + /* 26*/ { BARCODE_EANX, "1234567890125+12345", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '5', expecting '8'", "" }, + /* 27*/ { BARCODE_EANX, "123456789012+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 28*/ { BARCODE_EANX, "1234567890128+123456", ZINT_ERROR_TOO_LONG, "Error 283: Input too long (19 character maximum)", "" }, + /* 29*/ { BARCODE_EANX, "12345678901+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 30*/ { BARCODE_EANX, "12345678901+1234567", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 31*/ { BARCODE_EANX, "1234567890+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 32*/ { BARCODE_EANX, "1234567890+1234567", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 33*/ { BARCODE_EANX, "123456789+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 34*/ { BARCODE_EANX, "123456789+1234567", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 35*/ { BARCODE_EANX, "12345678+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 36*/ { BARCODE_EANX, "1234567+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "EAN-8" }, + /* 37*/ { BARCODE_EANX, "123456+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 38*/ { BARCODE_EANX, "12345+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 39*/ { BARCODE_EANX, "1234+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 40*/ { BARCODE_EANX, "123+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 41*/ { BARCODE_EANX, "12+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 42*/ { BARCODE_EANX, "1+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 43*/ { BARCODE_EANX, "1+12345678901234", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 44*/ { BARCODE_EANX, "1+12345", 0, "", "" }, + /* 45*/ { BARCODE_EANX, "1+", 0, "", "EAN-2" }, + /* 46*/ { BARCODE_EANX, "+1", 0, "", "EAN-8" }, + /* 47*/ { BARCODE_EANX, "+", 0, "", "EAN-2" }, + /* 48*/ { BARCODE_EANX, "1", 0, "", "EAN-2" }, + /* 49*/ { BARCODE_EANX, "12", 0, "", "EAN-2" }, + /* 50*/ { BARCODE_EANX, "123", 0, "", "EAN-5" }, + /* 51*/ { BARCODE_EANX, "12345678901234", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 52*/ { BARCODE_EANX, "1234567890123A", ZINT_ERROR_INVALID_DATA, "Error 284: Invalid character in data (digits and \"+\" only)", "" }, + /* 53*/ { BARCODE_EANX, "123456789012345", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 54*/ { BARCODE_EANX, "12345678901234A", ZINT_ERROR_INVALID_DATA, "Error 284: Invalid character in data (digits and \"+\" only)", "" }, + /* 55*/ { BARCODE_EANX, "1234567890123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 56*/ { BARCODE_EANX, "12345678901234567", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 57*/ { BARCODE_EANX, "123456789012345678", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 58*/ { BARCODE_EANX, "1234567890123456789", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /* 59*/ { BARCODE_EANX_CHK, "1234567890128", 0, "", "" }, + /* 60*/ { BARCODE_EANX_CHK, "1234567890126", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '6', expecting '8'", "" }, + /* 61*/ { BARCODE_EANX_CHK, "123456789012A", ZINT_ERROR_INVALID_DATA, "Error 284: Invalid character in data (digits and \"+\" only)", "" }, + /* 62*/ { BARCODE_EANX_CHK, "123456789012", 0, "", "Note: this is '0123456789012' with '2' happening to be the correct check digit" }, + /* 63*/ { BARCODE_EANX_CHK, "123456789013", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '3', expecting '2'", "" }, + /* 64*/ { BARCODE_EANX_CHK, "12345678901", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '1', expecting '5'", "" }, + /* 65*/ { BARCODE_EANX_CHK, "12345678905", 0, "", "" }, + /* 66*/ { BARCODE_EANX_CHK, "1234567890", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '0', expecting '5'", "" }, + /* 67*/ { BARCODE_EANX_CHK, "123456789", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '9', expecting '4'", "" }, + /* 68*/ { BARCODE_EANX_CHK, "12345678", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '8', expecting '0'", "EAN-8" }, + /* 69*/ { BARCODE_EANX_CHK, "1234567", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '7', expecting '5'", "" }, + /* 70*/ { BARCODE_EANX_CHK, "123456", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '6', expecting '7'", "" }, + /* 71*/ { BARCODE_EANX_CHK, "12345", 0, "", "EAN-5" }, + /* 72*/ { BARCODE_EANX_CHK, "1234", 0, "", "" }, + /* 73*/ { BARCODE_EANX_CHK, "123", 0, "", "" }, + /* 74*/ { BARCODE_EANX_CHK, "12", 0, "", "EAN-2" }, + /* 75*/ { BARCODE_EANX_CHK, "1", 0, "", "" }, + /* 76*/ { BARCODE_EANX_CHK, "123456789012+1", 0, "", "" }, + /* 77*/ { BARCODE_EANX_CHK, "1234567890128+1", 0, "", "" }, + /* 78*/ { BARCODE_EANX_CHK, "1234567890127+1", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '7', expecting '8'", "" }, + /* 79*/ { BARCODE_EANX_CHK, "123456789012+12", 0, "", "" }, + /* 80*/ { BARCODE_EANX_CHK, "1234567890128+12", 0, "", "" }, + /* 81*/ { BARCODE_EANX_CHK, "1234567890129+12", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '9', expecting '8'", "" }, + /* 82*/ { BARCODE_EANX_CHK, "123456789012+123", 0, "", "" }, + /* 83*/ { BARCODE_EANX_CHK, "1234567890128+123", 0, "", "" }, + /* 84*/ { BARCODE_EANX_CHK, "1234567890120+1234", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '0', expecting '8'", "" }, + /* 85*/ { BARCODE_EANX_CHK, "123456789012+1234", 0, "", "" }, + /* 86*/ { BARCODE_EANX_CHK, "1234567890128+1234", 0, "", "" }, + /* 87*/ { BARCODE_EANX_CHK, "1234567890121+1234", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '1', expecting '8'", "" }, + /* 88*/ { BARCODE_EANX_CHK, "123456789012+12345", 0, "", "" }, + /* 89*/ { BARCODE_EANX_CHK, "1234567890128+12345", 0, "", "" }, + /* 90*/ { BARCODE_EANX_CHK, "1234567890122+12345", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '2', expecting '8'", "" }, + /* 91*/ { BARCODE_EANX_CHK, "1234567890122+1234A", ZINT_ERROR_INVALID_DATA, "Error 284: Invalid character in data (digits and \"+\" only)", "" }, + /* 92*/ { BARCODE_EANX_CHK, "123456789012+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 93*/ { BARCODE_EANX_CHK, "123456789012+12345A", ZINT_ERROR_INVALID_DATA, "Error 284: Invalid character in data (digits and \"+\" only)", "" }, + /* 94*/ { BARCODE_EANX_CHK, "1234567890128+123456", ZINT_ERROR_TOO_LONG, "Error 283: Input too long (19 character maximum)", "" }, + /* 95*/ { BARCODE_EANX_CHK, "12345678901+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 96*/ { BARCODE_EANX_CHK, "12345678901+1234567", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 97*/ { BARCODE_EANX_CHK, "12345678901+12345", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '1', expecting '5'", "" }, + /* 98*/ { BARCODE_EANX_CHK, "1234567890+12345", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '0', expecting '5'", "" }, + /* 99*/ { BARCODE_EANX_CHK, "1234567890+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /*100*/ { BARCODE_EANX_CHK, "123456789+12345", ZINT_ERROR_INVALID_CHECK, "Error 275: Invalid check digit '9', expecting '4'", "" }, + /*101*/ { BARCODE_EANX_CHK, "12345678+12345", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '8', expecting '0'", "EAN-8" }, + /*102*/ { BARCODE_EANX_CHK, "12345670+12345", 0, "", "" }, + /*103*/ { BARCODE_EANX_CHK, "1234567+12345", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '7', expecting '5'", "" }, + /*104*/ { BARCODE_EANX_CHK, "1234565+12345", 0, "", "" }, + /*105*/ { BARCODE_EANX_CHK, "123456+12345", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '6', expecting '7'", "" }, + /*106*/ { BARCODE_EANX_CHK, "123457+12345", 0, "", "" }, + /*107*/ { BARCODE_EANX_CHK, "12345+12345", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '5', expecting '8'", "" }, + /*108*/ { BARCODE_EANX_CHK, "12348+12345", 0, "", "" }, + /*109*/ { BARCODE_EANX_CHK, "1234+12345", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '4', expecting '6'", "" }, + /*110*/ { BARCODE_EANX_CHK, "1236+12345", 0, "", "" }, + /*111*/ { BARCODE_EANX_CHK, "123+12345", 0, "", "3 happens to be correct check digit" }, + /*112*/ { BARCODE_EANX_CHK, "124+12345", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '4', expecting '3'", "" }, + /*113*/ { BARCODE_EANX_CHK, "12+12345", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '2', expecting '7'", "" }, + /*114*/ { BARCODE_EANX_CHK, "17+12345", 0, "", "" }, + /*115*/ { BARCODE_EANX_CHK, "1+12345", ZINT_ERROR_INVALID_CHECK, "Error 276: Invalid check digit '1', expecting '0'", "" }, + /*116*/ { BARCODE_EANX_CHK, "0+12345", 0, "", "" }, + /*117*/ { BARCODE_EANX_CHK, "0+123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /*118*/ { BARCODE_EANX_CHK, "1+12345678901234", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /*119*/ { BARCODE_EANX_CHK, "0+12345678901234", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /*120*/ { BARCODE_EANX_CHK, "1+", 0, "", "EAN-2" }, + /*121*/ { BARCODE_EANX_CHK, "+1", 0, "", "EAN-8" }, + /*122*/ { BARCODE_EANX_CHK, "+", 0, "", "EAN-2" }, + /*123*/ { BARCODE_EANX_CHK, "12345678901234", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /*124*/ { BARCODE_EANX_CHK, "1234567890123A", ZINT_ERROR_INVALID_DATA, "Error 284: Invalid character in data (digits and \"+\" only)", "" }, + /*125*/ { BARCODE_EANX_CHK, "123456789012345", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /*126*/ { BARCODE_EANX_CHK, "1234567890123456", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /*127*/ { BARCODE_EANX_CHK, "12345678901234567", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /*128*/ { BARCODE_EANX_CHK, "123456789012345678", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, + /*129*/ { BARCODE_EANX_CHK, "1234567890123456789", ZINT_ERROR_TOO_LONG, "Error 294: Input too long (13 character maximum)", "" }, }; int data_size = ARRAY_SIZE(data); int i, length, ret; struct zint_symbol *symbol; + char errtxt_escaped[256]; + testStart("test_eanx_input"); for (i = 0; i < data_size; i++) { @@ -422,7 +426,16 @@ static void test_eanx_input(int index, int debug) { 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 ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + + if (generate) { + printf(" /*%3d*/ { %s, \"%s\", %s, \"%s\", \"%s\" },\n", + i, testUtilBarcodeName(data[i].symbology), data[i].data, testUtilErrorName(data[i].ret), + testUtilEscape(symbol->errtxt, (int) strlen(symbol->errtxt), errtxt_escaped, sizeof(errtxt_escaped)), + data[i].comment); + } else { + assert_equal(ret, data[i].ret, "i:%d ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + assert_zero(strcmp(symbol->errtxt, data[i].ret_errtxt), "i:%d errtxt %s != %s\n", i, symbol->errtxt, data[i].ret_errtxt); + } ZBarcode_Delete(symbol); } @@ -430,125 +443,129 @@ static void test_eanx_input(int index, int debug) { testFinish(); } -static void test_isbn_input(int index, int debug) { +static void test_isbn_input(int index, int generate, int debug) { struct item { char *data; int ret_encode; int ret_vector; + char *ret_errtxt; + char *comment; }; // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) struct item data[] = { - /* 0*/ { "0", 0, 0 }, // Left zero-padded if < 10 chars - /* 1*/ { "1", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 2*/ { "X", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 3*/ { "12", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 4*/ { "19", 0, 0, }, - /* 5*/ { "X9", ZINT_ERROR_INVALID_DATA, -1 }, - /* 6*/ { "123", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 7*/ { "124", 0, 0, }, - /* 8*/ { "1X4", ZINT_ERROR_INVALID_DATA, -1 }, - /* 9*/ { "1234", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 10*/ { "1236", 0, 0, }, - /* 11*/ { "12X6", ZINT_ERROR_INVALID_DATA, -1 }, - /* 12*/ { "12345", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 13*/ { "12343", 0, 0, }, - /* 14*/ { "123X3", ZINT_ERROR_INVALID_DATA, -1 }, - /* 15*/ { "123456", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 16*/ { "123455", 0, 0, }, - /* 17*/ { "1234X5", ZINT_ERROR_INVALID_DATA, -1 }, - /* 18*/ { "1234567", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 19*/ { "1234560", 0, 0, }, - /* 20*/ { "12345X0", ZINT_ERROR_INVALID_DATA, -1 }, - /* 21*/ { "12345678", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 22*/ { "12345679", 0, 0 }, // 9 is correct check digit - /* 23*/ { "98765434", 0, 0 }, // 4 is correct check digit - /* 24*/ { "123456X9", ZINT_ERROR_INVALID_DATA, -1 }, - /* 25*/ { "123456789", 0, 0 }, - /* 26*/ { "340013817", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 27*/ { "340013818", 0, 0 }, // 8 is correct check digit - /* 28*/ { "902888455", 0, 0 }, // 5 is correct check digit - /* 29*/ { "9028884X5", ZINT_ERROR_INVALID_DATA, -1 }, - /* 30*/ { "0123456789", 0, 0 }, - /* 31*/ { "1234567890", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 32*/ { "123456789X", 0, 0 }, // X is correct check digit - /* 33*/ { "123456789x", 0, 0 }, // x is correct check digit - /* 34*/ { "8175257660", 0, 0 }, // 0 is correct check digit - /* 35*/ { "0590764845", 0, 0 }, // 5 is correct check digit - /* 36*/ { "0906495741", 0, 0 }, // 1 is correct check digit - /* 37*/ { "0140430016", 0, 0 }, // 6 is correct check digit - /* 38*/ { "0571086187", 0, 0 }, // 7 is correct check digit - /* 39*/ { "0486600882", 0, 0 }, // 2 is correct check digit - /* 40*/ { "04866008X2", ZINT_ERROR_INVALID_DATA, -1 }, - /* 41*/ { "123456789A", ZINT_ERROR_INVALID_DATA, -1 }, - /* 42*/ { "12345678901", ZINT_ERROR_TOO_LONG, -1 }, - /* 43*/ { "1234567890A", ZINT_ERROR_INVALID_DATA, -1 }, - /* 44*/ { "123456789012", ZINT_ERROR_TOO_LONG, -1 }, - /* 45*/ { "12345678901", ZINT_ERROR_TOO_LONG, -1 }, - /* 46*/ { "123456789012", ZINT_ERROR_TOO_LONG, -1 }, - /* 47*/ { "1234567890123", ZINT_ERROR_INVALID_DATA, -1 }, - /* 48*/ { "9784567890123", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 49*/ { "9784567890120", 0, 0 }, // 0 is correct check digit - /* 50*/ { "9783161484100", 0, 0 }, // 0 is correct check digit - /* 51*/ { "9781846688225", 0, 0 }, // 5 is correct check digit - /* 52*/ { "9781847657954", 0, 0 }, // 4 is correct check digit - /* 53*/ { "9781846688188", 0, 0 }, // 8 is correct check digit - /* 54*/ { "9781847659293", 0, 0 }, // 3 is correct check digit - /* 55*/ { "97845678901201", ZINT_ERROR_TOO_LONG, -1 }, - /* 56*/ { "978456789012012", ZINT_ERROR_TOO_LONG, -1 }, - /* 57*/ { "3954994+12", 0, 0 }, - /* 58*/ { "3954994+1X", ZINT_ERROR_INVALID_DATA, -1 }, - /* 59*/ { "39549X4+12", ZINT_ERROR_INVALID_DATA, -1 }, - /* 60*/ { "3954994+12345", 0, 0 }, - /* 61*/ { "3954994+1234X", ZINT_ERROR_INVALID_DATA, -1 }, - /* 62*/ { "39549X4+12345", ZINT_ERROR_INVALID_DATA, -1 }, - /* 63*/ { "3954994+123456", ZINT_ERROR_TOO_LONG, -1 }, - /* 64*/ { "3954994+", 0, 0 }, - /* 65*/ { "3954X94+", ZINT_ERROR_INVALID_DATA, -1 }, - /* 66*/ { "61954993+1", 0, 0 }, - /* 67*/ { "61954993+X", ZINT_ERROR_INVALID_DATA, -1 }, - /* 68*/ { "619549X3+1", ZINT_ERROR_INVALID_DATA, -1 }, - /* 69*/ { "61954992+123", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 70*/ { "61954993+123", 0, 0 }, - /* 71*/ { "61954993+12X", ZINT_ERROR_INVALID_DATA, -1 }, - /* 72*/ { "619549X3+123", ZINT_ERROR_INVALID_DATA, -1 }, - /* 73*/ { "361954990+12", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 74*/ { "361954999+12", 0, 0 }, - /* 75*/ { "361954999+1X", ZINT_ERROR_INVALID_DATA, -1 }, - /* 76*/ { "3619549X9+12", ZINT_ERROR_INVALID_DATA, -1 }, - /* 77*/ { "361954999+1234", 0, 0 }, - /* 78*/ { "361954999+123X", ZINT_ERROR_INVALID_DATA, -1 }, - /* 79*/ { "3619549X9+1234", ZINT_ERROR_INVALID_DATA, -1 }, - /* 80*/ { "1999000030+12", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 81*/ { "199900003X+12", 0, 0 }, - /* 82*/ { "199900003x+12", 0, 0 }, - /* 83*/ { "19990000XX+12", ZINT_ERROR_INVALID_DATA, -1 }, - /* 84*/ { "199900003X+1X", ZINT_ERROR_INVALID_DATA, -1 }, - /* 85*/ { "1999000031+12345", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 86*/ { "199900003X+12345", 0, 0 }, - /* 87*/ { "199900003x+12345", 0, 0 }, - /* 88*/ { "199900003X+1234X", ZINT_ERROR_INVALID_DATA, -1 }, - /* 89*/ { "19990000XX+12345", ZINT_ERROR_INVALID_DATA, -1 }, - /* 90*/ { "199900003X+1234A", ZINT_ERROR_INVALID_DATA, -1 }, - /* 91*/ { "9791234567895+12", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 92*/ { "9791234567896+12", 0, 0 }, - /* 93*/ { "9791234567896+1X", ZINT_ERROR_INVALID_DATA, -1 }, - /* 94*/ { "97912345678X6+12", ZINT_ERROR_INVALID_DATA, -1 }, - /* 95*/ { "9791234567897+12345", ZINT_ERROR_INVALID_CHECK, -1 }, - /* 96*/ { "9791234567896+12345", 0, 0 }, - /* 97*/ { "9791234567896+1234X", ZINT_ERROR_INVALID_DATA, -1 }, - /* 98*/ { "979123456X896+12345", ZINT_ERROR_INVALID_DATA, -1 }, - /* 99*/ { "9791234567892+", ZINT_ERROR_INVALID_CHECK, -1 }, - /*100*/ { "9791234567896+", 0, 0 }, - /*101*/ { "97912345678X6+", ZINT_ERROR_INVALID_DATA, -1 }, - /*102*/ { "97912345678961+", ZINT_ERROR_TOO_LONG, -1 }, - /*103*/ { "97912345678961+12345", ZINT_ERROR_TOO_LONG, -1 }, - /*104*/ { "9791234567896+123456", ZINT_ERROR_TOO_LONG, -1 }, + /* 0*/ { "0", 0, 0, "", "Left zero-padded if < 10 chars" }, + /* 1*/ { "1", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '1', expecting '0'", "" }, + /* 2*/ { "X", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit 'X', expecting '0'", "" }, + /* 3*/ { "12", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '2', expecting '9'", "" }, + /* 4*/ { "19", 0, 0, "", "" }, + /* 5*/ { "X9", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 6*/ { "123", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '3', expecting '4'", "" }, + /* 7*/ { "124", 0, 0, "", "" }, + /* 8*/ { "1X4", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 9*/ { "1234", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '4', expecting '6'", "" }, + /* 10*/ { "1236", 0, 0, "", "" }, + /* 11*/ { "12X6", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 12*/ { "12345", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '5', expecting '3'", "" }, + /* 13*/ { "12343", 0, 0, "", "" }, + /* 14*/ { "123X3", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 15*/ { "123456", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '6', expecting '5'", "" }, + /* 16*/ { "123455", 0, 0, "", "" }, + /* 17*/ { "1234X5", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 18*/ { "1234567", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '7', expecting '0'", "" }, + /* 19*/ { "1234560", 0, 0, "", "" }, + /* 20*/ { "12345X0", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 21*/ { "12345678", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '8', expecting '9'", "" }, + /* 22*/ { "12345679", 0, 0, "", "9 is correct check digit" }, + /* 23*/ { "98765434", 0, 0, "", "4 is correct check digit" }, + /* 24*/ { "123456X9", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 25*/ { "123456789", 0, 0, "", "" }, + /* 26*/ { "340013817", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '7', expecting '8'", "" }, + /* 27*/ { "340013818", 0, 0, "", "8 is correct check digit" }, + /* 28*/ { "902888455", 0, 0, "", "5 is correct check digit" }, + /* 29*/ { "9028884X5", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 30*/ { "0123456789", 0, 0, "", "" }, + /* 31*/ { "1234567890", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid ISBN check digit '0', expecting 'X'", "" }, + /* 32*/ { "123456789X", 0, 0, "", "X is correct check digit" }, + /* 33*/ { "123456789x", 0, 0, "", "x is correct check digit" }, + /* 34*/ { "8175257660", 0, 0, "", "0 is correct check digit" }, + /* 35*/ { "0590764845", 0, 0, "", "5 is correct check digit" }, + /* 36*/ { "0906495741", 0, 0, "", "1 is correct check digit" }, + /* 37*/ { "0140430016", 0, 0, "", "6 is correct check digit" }, + /* 38*/ { "0571086187", 0, 0, "", "7 is correct check digit" }, + /* 39*/ { "0486600882", 0, 0, "", "2 is correct check digit" }, + /* 40*/ { "04866008X2", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 41*/ { "123456789A", ZINT_ERROR_INVALID_DATA, -1, "Error 285: Invalid character in data (digits, \"X\" and \"+\" only)", "" }, + /* 42*/ { "12345678901", ZINT_ERROR_TOO_LONG, -1, "Error 278: Input wrong length (9, 10, or 13 characters only)", "" }, + /* 43*/ { "1234567890A", ZINT_ERROR_INVALID_DATA, -1, "Error 285: Invalid character in data (digits, \"X\" and \"+\" only)", "" }, + /* 44*/ { "123456789012", ZINT_ERROR_TOO_LONG, -1, "Error 278: Input wrong length (9, 10, or 13 characters only)", "" }, + /* 45*/ { "12345678901", ZINT_ERROR_TOO_LONG, -1, "Error 278: Input wrong length (9, 10, or 13 characters only)", "" }, + /* 46*/ { "123456789012", ZINT_ERROR_TOO_LONG, -1, "Error 278: Input wrong length (9, 10, or 13 characters only)", "" }, + /* 47*/ { "1234567890123", ZINT_ERROR_INVALID_DATA, -1, "Error 279: Invalid ISBN (must begin with \"978\" or \"979\")", "" }, + /* 48*/ { "9784567890123", ZINT_ERROR_INVALID_CHECK, -1, "Error 280: Invalid ISBN check digit '3', expecting '0'", "" }, + /* 49*/ { "9784567890120", 0, 0, "", "0 is correct check digit" }, + /* 50*/ { "9783161484100", 0, 0, "", "0 is correct check digit" }, + /* 51*/ { "9781846688225", 0, 0, "", "5 is correct check digit" }, + /* 52*/ { "9781847657954", 0, 0, "", "4 is correct check digit" }, + /* 53*/ { "9781846688188", 0, 0, "", "8 is correct check digit" }, + /* 54*/ { "9781847659293", 0, 0, "", "3 is correct check digit" }, + /* 55*/ { "97845678901201", ZINT_ERROR_TOO_LONG, -1, "Error 294: Input too long (13 character maximum)", "" }, + /* 56*/ { "978456789012012", ZINT_ERROR_TOO_LONG, -1, "Error 294: Input too long (13 character maximum)", "" }, + /* 57*/ { "3954994+12", 0, 0, "", "" }, + /* 58*/ { "3954994+1X", ZINT_ERROR_INVALID_DATA, -1, "Error 295: Invalid add-on data (digits only)", "" }, + /* 59*/ { "39549X4+12", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 60*/ { "3954994+12345", 0, 0, "", "" }, + /* 61*/ { "3954994+1234X", ZINT_ERROR_INVALID_DATA, -1, "Error 295: Invalid add-on data (digits only)", "" }, + /* 62*/ { "39549X4+12345", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 63*/ { "3954994+123456", ZINT_ERROR_TOO_LONG, -1, "Error 294: Input too long (5 character maximum for add-on)", "" }, + /* 64*/ { "3954994+", 0, 0, "", "" }, + /* 65*/ { "3954X94+", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 66*/ { "61954993+1", 0, 0, "", "" }, + /* 67*/ { "61954993+X", ZINT_ERROR_INVALID_DATA, -1, "Error 295: Invalid add-on data (digits only)", "" }, + /* 68*/ { "619549X3+1", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 69*/ { "61954992+123", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '2', expecting '3'", "" }, + /* 70*/ { "61954993+123", 0, 0, "", "" }, + /* 71*/ { "61954993+12X", ZINT_ERROR_INVALID_DATA, -1, "Error 295: Invalid add-on data (digits only)", "" }, + /* 72*/ { "619549X3+123", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 73*/ { "361954990+12", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid SBN check digit '0', expecting '9'", "" }, + /* 74*/ { "361954999+12", 0, 0, "", "" }, + /* 75*/ { "361954999+1X", ZINT_ERROR_INVALID_DATA, -1, "Error 295: Invalid add-on data (digits only)", "" }, + /* 76*/ { "3619549X9+12", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 77*/ { "361954999+1234", 0, 0, "", "" }, + /* 78*/ { "361954999+123X", ZINT_ERROR_INVALID_DATA, -1, "Error 295: Invalid add-on data (digits only)", "" }, + /* 79*/ { "3619549X9+1234", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 80*/ { "1999000030+12", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid ISBN check digit '0', expecting 'X'", "" }, + /* 81*/ { "199900003X+12", 0, 0, "", "" }, + /* 82*/ { "199900003x+12", 0, 0, "", "" }, + /* 83*/ { "19990000XX+12", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 84*/ { "199900003X+1X", ZINT_ERROR_INVALID_DATA, -1, "Error 295: Invalid add-on data (digits only)", "" }, + /* 85*/ { "1999000031+12345", ZINT_ERROR_INVALID_CHECK, -1, "Error 281: Invalid ISBN check digit '1', expecting 'X'", "" }, + /* 86*/ { "199900003X+12345", 0, 0, "", "" }, + /* 87*/ { "199900003x+12345", 0, 0, "", "" }, + /* 88*/ { "199900003X+1234X", ZINT_ERROR_INVALID_DATA, -1, "Error 295: Invalid add-on data (digits only)", "" }, + /* 89*/ { "19990000XX+12345", ZINT_ERROR_INVALID_DATA, -1, "Error 296: Invalid character in data, \"X\" allowed in last position only", "" }, + /* 90*/ { "199900003X+1234A", ZINT_ERROR_INVALID_DATA, -1, "Error 285: Invalid character in data (digits, \"X\" and \"+\" only)", "" }, + /* 91*/ { "9791234567895+12", ZINT_ERROR_INVALID_CHECK, -1, "Error 280: Invalid ISBN check digit '5', expecting '6'", "" }, + /* 92*/ { "9791234567896+12", 0, 0, "", "" }, + /* 93*/ { "9791234567896+1X", ZINT_ERROR_INVALID_DATA, -1, "Error 295: Invalid add-on data (digits only)", "" }, + /* 94*/ { "97912345678X6+12", ZINT_ERROR_INVALID_DATA, -1, "Error 282: Invalid character in data, \"X\" not allowed in ISBN-13", "" }, + /* 95*/ { "9791234567897+12345", ZINT_ERROR_INVALID_CHECK, -1, "Error 280: Invalid ISBN check digit '7', expecting '6'", "" }, + /* 96*/ { "9791234567896+12345", 0, 0, "", "" }, + /* 97*/ { "9791234567896+1234X", ZINT_ERROR_INVALID_DATA, -1, "Error 295: Invalid add-on data (digits only)", "" }, + /* 98*/ { "979123456X896+12345", ZINT_ERROR_INVALID_DATA, -1, "Error 282: Invalid character in data, \"X\" not allowed in ISBN-13", "" }, + /* 99*/ { "9791234567892+", ZINT_ERROR_INVALID_CHECK, -1, "Error 280: Invalid ISBN check digit '2', expecting '6'", "" }, + /*100*/ { "9791234567896+", 0, 0, "", "" }, + /*101*/ { "97912345678X6+", ZINT_ERROR_INVALID_DATA, -1, "Error 282: Invalid character in data, \"X\" not allowed in ISBN-13", "" }, + /*102*/ { "97912345678961+", ZINT_ERROR_TOO_LONG, -1, "Error 294: Input too long (13 character maximum)", "" }, + /*103*/ { "97912345678961+12345", ZINT_ERROR_TOO_LONG, -1, "Error 283: Input too long (19 character maximum)", "" }, + /*104*/ { "9791234567896+123456", ZINT_ERROR_TOO_LONG, -1, "Error 283: Input too long (19 character maximum)", "" }, }; int data_size = ARRAY_SIZE(data); int i, length, ret; struct zint_symbol *symbol; + char errtxt_escaped[256]; + testStart("test_isbn_input"); for (i = 0; i < data_size; i++) { @@ -562,11 +579,20 @@ static void test_isbn_input(int index, int debug) { length = testUtilSetSymbol(symbol, BARCODE_ISBNX, -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_encode, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret_encode, symbol->errtxt); - if (data[i].ret_vector != -1) { - ret = ZBarcode_Buffer_Vector(symbol, 0); - assert_equal(ret, data[i].ret_vector, "i:%d ZBarcode_Buffer_Vector ret %d != %d (%s)\n", i, ret, data[i].ret_vector, symbol->errtxt); + if (generate) { + printf(" /*%3d*/ { \"%s\", %s, %d, \"%s\", \"%s\" },\n", + i, data[i].data, testUtilErrorName(data[i].ret_encode), data[i].ret_vector, + testUtilEscape(symbol->errtxt, (int) strlen(symbol->errtxt), errtxt_escaped, sizeof(errtxt_escaped)), + data[i].comment); + } else { + assert_equal(ret, data[i].ret_encode, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret_encode, symbol->errtxt); + assert_zero(strcmp(symbol->errtxt, data[i].ret_errtxt), "i:%d errtxt %s != %s\n", i, symbol->errtxt, data[i].ret_errtxt); + + if (data[i].ret_vector != -1) { + ret = ZBarcode_Buffer_Vector(symbol, 0); + assert_equal(ret, data[i].ret_vector, "i:%d ZBarcode_Buffer_Vector ret %d != %d (%s)\n", i, ret, data[i].ret_vector, symbol->errtxt); + } } ZBarcode_Delete(symbol); @@ -955,18 +981,127 @@ static void test_fuzz(int index, int debug) { testFinish(); } +#include + +#define TEST_PERF_ITER_MILLES 10 +#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(int index, int debug) { + + struct item { + int symbology; + int option_2; + char *data; + int ret; + + int expected_rows; + int expected_width; + char *comment; + }; + // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) + struct item data[] = { + /* 0*/ { BARCODE_EANX, -1, "123456789012+12345", 0, 1, 149, "EAN-13 add-on 5" }, + /* 1*/ { BARCODE_EANX, -1, "123456789012", 0, 1, 95, "EAN-13 no add-on" }, + /* 2*/ { BARCODE_UPCA, -1, "12345678901+12345", 0, 1, 151, "UPC-A add-on 5" }, + /* 3*/ { BARCODE_UPCA, -1, "12345678901", 0, 1, 95, "UPC-A no add-on" }, + /* 4*/ { BARCODE_EANX, -1, "1234567+12345", 0, 1, 121, "EAN-8 add-on 5" }, + /* 5*/ { BARCODE_EANX, -1, "1234567", 0, 1, 67, "EAN-8 no add-on" }, + /* 6*/ { BARCODE_UPCE, -1, "1234567+12", 0, 1, 78, "UPC-E add-on 2" }, + /* 7*/ { BARCODE_UPCE, -1, "1234567", 0, 1, 51, "UPC-E no add-on" }, + /* 8*/ { BARCODE_EANX, -1, "12345", 0, 1, 47, "EAN-5" }, + /* 9*/ { BARCODE_EANX, -1, "12", 0, 1, 20, "EAN-2" }, + }; + 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 (index != -1 && i != index) 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(remove(symbol->outfile), "i:%d remove(%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 (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, has_index, has_generate, has_debug */ { "test_upce_input", test_upce_input, 1, 0, 1 }, { "test_upca_print", test_upca_print, 1, 0, 1 }, { "test_upca_input", test_upca_input, 1, 0, 1 }, - { "test_eanx_input", test_eanx_input, 1, 0, 1 }, - { "test_isbn_input", test_isbn_input, 1, 0, 1 }, + { "test_eanx_input", test_eanx_input, 1, 1, 1 }, + { "test_isbn_input", test_isbn_input, 1, 1, 1 }, { "test_hrt", test_hrt, 1, 0, 1 }, { "test_vector_same", test_vector_same, 1, 0, 1 }, { "test_encode", test_encode, 1, 1, 1 }, { "test_fuzz", test_fuzz, 1, 0, 1 }, + { "test_perf", test_perf, 1, 0, 1 }, }; testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); diff --git a/backend/tests/testcommon.c b/backend/tests/testcommon.c index a53d0d44..6b630db7 100644 --- a/backend/tests/testcommon.c +++ b/backend/tests/testcommon.c @@ -84,13 +84,13 @@ void assert_nonzero(int exp, const char *fmt, ...) { va_list args; assertionFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish(); } } -void assert_null(void *exp, const char *fmt, ...) { +void assert_null(const void *exp, const char *fmt, ...) { assertionNum++; if (exp != NULL) { va_list args; assertionFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish(); } } -void assert_nonnull(void *exp, const char *fmt, ...) { +void assert_nonnull(const void *exp, const char *fmt, ...) { assertionNum++; if (exp == NULL) { va_list args; assertionFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish(); @@ -683,7 +683,7 @@ const char *testUtilOutputOptionsName(int output_options) { } /* Convert modules spanning 3 rows to DAFT equivalents */ -int testUtilDAFTConvert(const struct zint_symbol *symbol, char *buffer, int buffer_size) { +int testUtilDAFTConvert(const struct zint_symbol *symbol, char *buffer, const int buffer_size) { int i; char *b = buffer; *b = '\0'; @@ -720,7 +720,7 @@ int testUtilIsValidUTF8(const unsigned char str[], const int length) { } /* Escape data for printing on generate test. Has a number of issues, e.g. need to use octal escapes */ -char *testUtilEscape(char *buffer, int length, char *escaped, int escaped_size) { +char *testUtilEscape(const char *buffer, const int length, char *escaped, const int escaped_size) { int i; unsigned char *b = (unsigned char *) buffer; unsigned char *be = b + length; @@ -767,9 +767,9 @@ char *testUtilEscape(char *buffer, int length, char *escaped, int escaped_size) } /* Helper to read a CSV field */ -char *testUtilReadCSVField(char *buffer, char *field, int field_size) { +const char *testUtilReadCSVField(const char *buffer, char *field, const int field_size) { int i; - char *b = buffer; + const char *b = buffer; for (i = 0; i < field_size && *b && *b != ',' && *b != '\n' && *b != '\r'; i++) { field[i] = *b++; } @@ -781,7 +781,7 @@ char *testUtilReadCSVField(char *buffer, char *field, int field_size) { } /* Helper to fill a buffer (for "large" tests) - single-byte filler only */ -void testUtilStrCpyRepeat(char *buffer, char *repeat, int size) { +void testUtilStrCpyRepeat(char *buffer, const char *repeat, const int size) { int i; int len = (int) strlen(repeat); int max = size - len; @@ -2046,7 +2046,7 @@ static const char *testUtilBwippName(int index, const struct zint_symbol *symbol { "identcode", BARCODE_DPIDENT, 22, 0, 0, 0, 0, 0, }, { "code16k", BARCODE_CODE16K, 23, 0, 0, 0, 8 /*linear_row_height*/, 0, }, { "code49", BARCODE_CODE49, 24, 0, 0, 0, 8 /*linear_row_height*/, 0, }, - { "code93", BARCODE_CODE93, 25, 0, 0, 0, 0, 0, }, + { "code93ext", BARCODE_CODE93, 25, 0, 0, 0, 0, 0, }, { "", -1, 26, 0, 0, 0, 0, 0, }, { "", -1, 27, 0, 0, 0, 0, 0, }, { "flattermarken", BARCODE_FLAT, 28, 0, 0, 0, 0, 0, }, @@ -2598,9 +2598,6 @@ int testUtilBwipp(int index, const struct zint_symbol *symbol, int option_1, int } else if (symbology == BARCODE_CODE93) { sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck", strlen(bwipp_opts_buf) ? " " : ""); - if (parse) { - bwipp_barcode = "code93ext"; - } bwipp_opts = bwipp_opts_buf; } else if (symbology == BARCODE_PZN) { sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%spzn8", strlen(bwipp_opts_buf) ? " " : ""); @@ -2681,7 +2678,7 @@ int testUtilBwipp(int index, const struct zint_symbol *symbol, int option_1, int || symbology == BARCODE_PHARMA_TWO) { for (r = 0; r < symbol->rows; r++) bwipp_row_height[r] = 1; /* Zap */ if (symbology == BARCODE_KIX) { - to_upper((unsigned char *) bwipp_data); + to_upper((unsigned char *) bwipp_data, (int) strlen(bwipp_data)); } else if (symbology == BARCODE_USPS_IMAIL) { char *dash = strchr(bwipp_data, '-'); if (dash) { diff --git a/backend/tests/testcommon.h b/backend/tests/testcommon.h index 5ea4ac0a..41be147d 100644 --- a/backend/tests/testcommon.h +++ b/backend/tests/testcommon.h @@ -96,8 +96,8 @@ void testRun(int argc, char *argv[], testFunction funcs[], int funcs_size); #include "../ms_stdint.h" void assert_zero(int exp, const char *fmt, ...); void assert_nonzero(int exp, const char *fmt, ...); -void assert_null(void *exp, const char *fmt, ...); -void assert_nonnull(void *exp, const char *fmt, ...); +void assert_null(const void *exp, const char *fmt, ...); +void assert_nonnull(const void *exp, const char *fmt, ...); void assert_equal(int e1, int e2, const char *fmt, ...); void assert_equalu64(uint64_t e1, uint64_t e2, const char *fmt, ...); void assert_notequal(int e1, int e2, ...); @@ -126,11 +126,11 @@ const char *testUtilInputModeName(int input_mode); const char *testUtilOption3Name(int option_3); const char *testUtilOutputOptionsName(int output_options); -int testUtilDAFTConvert(const struct zint_symbol *symbol, char *buffer, int buffer_size); +int testUtilDAFTConvert(const struct zint_symbol *symbol, char *buffer, const int buffer_size); int testUtilIsValidUTF8(const unsigned char str[], const int length); -char *testUtilEscape(char *buffer, int length, char *escaped, int escaped_size); -char *testUtilReadCSVField(char *buffer, char *field, int field_size); -void testUtilStrCpyRepeat(char *buffer, char *repeat, int size); +char *testUtilEscape(const char *buffer, const int length, char *escaped, const int escaped_size); +const char *testUtilReadCSVField(const char *buffer, char *field, const int field_size); +void testUtilStrCpyRepeat(char *buffer, const char *repeat, const int size); int testUtilSymbolCmp(const struct zint_symbol *a, const struct zint_symbol *b); struct zint_vector *testUtilVectorCpy(const struct zint_vector *in); diff --git a/backend/tests/tools/bwipp_dump.ps.tar.xz b/backend/tests/tools/bwipp_dump.ps.tar.xz index f2bec6ef8bc7f2ef5af16ae875a96c39fa84e8bf..fe3f8d2727a71d5288cb21d7c958a5a40cb570b6 100644 GIT binary patch literal 123868 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�o=e1gx84{*& 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 literal 123856 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 BLgn<1)#%Ms4Dj`*%lbNX{t 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 diff --git a/backend/ultra.c b/backend/ultra.c index 77dca6aa..4fbc23c9 100644 --- a/backend/ultra.c +++ b/backend/ultra.c @@ -46,7 +46,7 @@ #define GFMUL(i, j) ((((i) == 0)||((j) == 0)) ? 0 : gfPwr[(gfLog[i] + gfLog[j])]) -static const char fragment[27][14] = {"http://", "https://", "http://www.", "https://www.", +static const char fragment[27][13] = {"http://", "https://", "http://www.", "https://www.", "ftp://", "www.", ".com", ".edu", ".gov", ".int", ".mil", ".net", ".org", ".mobi", ".coop", ".biz", ".info", "mailto:", "tel:", ".cgi", ".asp", ".aspx", ".php", ".htm", ".html", ".shtml", "file:"}; @@ -273,7 +273,7 @@ static float look_ahead_eightbit(unsigned char source[], int in_length, int in_l *cw_len = codeword_count; if (codeword_count == 0) { - return 0.0; + return 0.0f; } return (float) letters_encoded / (float) codeword_count; } @@ -362,7 +362,7 @@ static float look_ahead_ascii(unsigned char source[], int in_length, int in_locn *cw_len = codeword_count; if (codeword_count == 0) { - return 0.0; + return 0.0f; } return (float) letters_encoded / (float) codeword_count; } @@ -372,8 +372,8 @@ static int c43_should_latch_other(const unsigned char data[], const int length, const int gs1) { int i, fraglen, predict_window; int cnt, alt_cnt, fragno; - const char *set = subset == 1 ? ultra_c43_set1 : ultra_c43_set2; - const char *alt_set = subset == 2 ? ultra_c43_set1 : ultra_c43_set2; + const char *const set = subset == 1 ? ultra_c43_set1 : ultra_c43_set2; + const char *const alt_set = subset == 2 ? ultra_c43_set1 : ultra_c43_set2; if (locn + 3 > length) { return 0; @@ -394,10 +394,10 @@ static int c43_should_latch_other(const unsigned char data[], const int length, } i += fraglen - 1; } else { - if (strchr(set, data[i]) != NULL) { + if (posn(set, data[i]) != -1) { cnt++; } - if (strchr(alt_set, data[i]) != NULL) { + if (posn(alt_set, data[i]) != -1) { alt_cnt++; } } @@ -612,7 +612,7 @@ static float look_ahead_c43(unsigned char source[], int in_length, int in_locn, *cw_len = codeword_count; if (codeword_count == 0) { - return 0.0; + return 0.0f; } return (float) letters_encoded / (float) codeword_count; } diff --git a/backend/upcean.c b/backend/upcean.c index cbc6d410..3fbe2e90 100644 --- a/backend/upcean.c +++ b/backend/upcean.c @@ -30,12 +30,9 @@ */ /* vim: set ts=4 sw=4 et : */ -#define SODIUM "0123456789+" -#define ISBNX_SANE "0123456789X" -#define ISBNX_ADDON_SANE "0123456789Xx+" - -#define EAN2 102 -#define EAN5 105 +#define SODIUM_PLS_F (IS_NUM_F | IS_PLS_F) /* SODIUM "0123456789+" */ +#define ISBNX_SANE_F (IS_NUM_F | IS_UX__F) /* ISBNX_SANE "0123456789X" */ +#define ISBNX_ADDON_SANE_F (IS_NUM_F | IS_UX__F | IS_LX__F | IS_PLS_F) /* ISBNX_ADDON_SANE "0123456789Xx+" */ #include #include "common.h" @@ -43,66 +40,72 @@ /* UPC and EAN tables checked against EN 797:1996 */ -static const char *UPCParity0[10] = { +static const char UPCParity0[10][6] = { /* Number set for UPC-E symbol (EN Table 4) */ - "BBBAAA", "BBABAA", "BBAABA", "BBAAAB", "BABBAA", "BAABBA", "BAAABB", - "BABABA", "BABAAB", "BAABAB" + {'B','B','B','A','A','A'}, {'B','B','A','B','A','A'}, {'B','B','A','A','B','A'}, {'B','B','A','A','A','B'}, + {'B','A','B','B','A','A'}, {'B','A','A','B','B','A'}, {'B','A','A','A','B','B'}, {'B','A','B','A','B','A'}, + {'B','A','B','A','A','B'}, {'B','A','A','B','A','B'} }; -static const char *UPCParity1[10] = { +static const char UPCParity1[10][6] = { /* Not covered by BS EN 797:1995 */ - "AAABBB", "AABABB", "AABBAB", "AABBBA", "ABAABB", "ABBAAB", "ABBBAA", - "ABABAB", "ABABBA", "ABBABA" + {'A','A','A','B','B','B'}, {'A','A','B','A','B','B'}, {'A','A','B','B','A','B'}, {'A','A','B','B','B','A'}, + {'A','B','A','A','B','B'}, {'A','B','B','A','A','B'}, {'A','B','B','B','A','A'}, {'A','B','A','B','A','B'}, + {'A','B','A','B','B','A'}, {'A','B','B','A','B','A'} }; -static const char *EAN2Parity[4] = { +static const char EAN2Parity[4][2] = { /* Number sets for 2-digit add-on (EN Table 6) */ - "AA", "AB", "BA", "BB" + {'A','A'}, {'A','B'}, {'B','A'}, {'B','B'} }; -static const char *EAN5Parity[10] = { +static const char EAN5Parity[10][5] = { /* Number set for 5-digit add-on (EN Table 7) */ - "BBAAA", "BABAA", "BAABA", "BAAAB", "ABBAA", "AABBA", "AAABB", "ABABA", - "ABAAB", "AABAB" + {'B','B','A','A','A'}, {'B','A','B','A','A'}, {'B','A','A','B','A'}, {'B','A','A','A','B'}, {'A','B','B','A','A'}, + {'A','A','B','B','A'}, {'A','A','A','B','B'}, {'A','B','A','B','A'}, {'A','B','A','A','B'}, {'A','A','B','A','B'} }; -static const char *EAN13Parity[10] = { +static const char EAN13Parity[10][5] = { /* Left hand of the EAN-13 symbol (EN Table 3) */ - "AAAAA", "ABABB", "ABBAB", "ABBBA", "BAABB", "BBAAB", "BBBAA", "BABAB", - "BABBA", "BBABA" + {'A','A','A','A','A'}, {'A','B','A','B','B'}, {'A','B','B','A','B'}, {'A','B','B','B','A'}, {'B','A','A','B','B'}, + {'B','B','A','A','B'}, {'B','B','B','A','A'}, {'B','A','B','A','B'}, {'B','A','B','B','A'}, {'B','B','A','B','A'} }; -static const char *EANsetA[10] = { +static const char EANsetA[10][4] = { /* Representation set A and C (EN Table 1) */ - "3211", "2221", "2122", "1411", "1132", "1231", "1114", "1312", "1213", "3112" + {'3','2','1','1'}, {'2','2','2','1'}, {'2','1','2','2'}, {'1','4','1','1'}, {'1','1','3','2'}, + {'1','2','3','1'}, {'1','1','1','4'}, {'1','3','1','2'}, {'1','2','1','3'}, {'3','1','1','2'} }; -static const char *EANsetB[10] = { +static const char EANsetB[10][4] = { /* Representation set B (EN Table 1) */ - "1123", "1222", "2212", "1141", "2311", "1321", "4111", "2131", "3121", "2113" + {'1','1','2','3'}, {'1','2','2','2'}, {'2','2','1','2'}, {'1','1','4','1'}, {'2','3','1','1'}, + {'1','3','2','1'}, {'4','1','1','1'}, {'2','1','3','1'}, {'3','1','2','1'}, {'2','1','1','3'} }; /* UPC A is usually used for 12 digit numbers, but this function takes a source of any length */ -static void upca_draw(const unsigned char source[], const int length, char dest[]) { +static void upca_draw(const unsigned char source[], const int length, char *d) { int i, half_way; half_way = length / 2; /* start character */ - strcat(dest, "111"); + memcpy(d, "111", 3); + d += 3; - for (i = 0; i < length; i++) { + for (i = 0; i < length; i++, d += 4) { if (i == half_way) { /* middle character - separates manufacturer no. from product no. */ /* also inverts right hand characters */ - strcat(dest, "11111"); + memcpy(d, "11111", 5); + d += 5; } - lookup(NEON, EANsetA, source[i], dest); + memcpy(d, EANsetA[source[i] - '0'], 4); } /* stop character */ - strcat(dest, "111"); + strcpy(d, "111"); } /* Make a UPC-A barcode, allowing for composite if `cc_rows` set */ @@ -156,9 +159,10 @@ static int upca(struct zint_symbol *symbol, const unsigned char source[], int le } /* UPC-E, allowing for composite if `cc_rows` set */ -static int upce_cc(struct zint_symbol *symbol, unsigned char source[], int length, char dest[], int cc_rows) { +static int upce_cc(struct zint_symbol *symbol, unsigned char source[], int length, char *d, int cc_rows) { int i, num_system; - char emode, check_digit, parity[8]; + char emode, check_digit; + const char *parity; char src_check_digit = '\0'; unsigned char equivalent[12]; unsigned char *hrt = symbol->text; @@ -266,27 +270,28 @@ static int upce_cc(struct zint_symbol *symbol, unsigned char source[], int lengt /* Use the number system and check digit information to choose a parity scheme */ if (num_system == 1) { - strcpy(parity, UPCParity1[ctoi(check_digit)]); + parity = UPCParity1[ctoi(check_digit)]; } else { - strcpy(parity, UPCParity0[ctoi(check_digit)]); + parity = UPCParity0[ctoi(check_digit)]; } /* Take all this information and make the barcode pattern */ /* start character */ - strcat(dest, "111"); + memcpy(d, "111", 3); + d += 3; - for (i = 0; i < length; i++) { + for (i = 0; i < length; i++, d += 4) { switch (parity[i]) { - case 'A': lookup(NEON, EANsetA, source[i], dest); + case 'A': memcpy(d, EANsetA[source[i] - '0'], 4); break; - case 'B': lookup(NEON, EANsetB, source[i], dest); + case 'B': memcpy(d, EANsetB[source[i] - '0'], 4); break; } } /* stop character */ - strcat(dest, "111111"); + strcpy(d, "111111"); hrt[7] = check_digit; hrt[8] = '\0'; @@ -323,36 +328,27 @@ static int upce(struct zint_symbol *symbol, unsigned char source[], int length, /* EAN-2 and EAN-5 add-on codes */ static void ean_add_on(const unsigned char source[], const int length, char dest[], const int addon_gap) { - char parity[6]; - int i, code_type; + const char *parity; + int i; + char *d = dest + strlen(dest); /* If an add-on then append with space */ if (addon_gap != 0) { - i = (int) strlen(dest); - dest[i] = itoc(addon_gap); - dest[i + 1] = '\0'; + *d++ = itoc(addon_gap); } /* Start character */ - strcat(dest, "112"); + memcpy(d, "112", 3); + d += 3; - /* Determine EAN2 or EAN5 add-on */ - if (length == 2) { - code_type = EAN2; - } else { - code_type = EAN5; - } - - /* Calculate parity for EAN2 */ - if (code_type == EAN2) { + /* Calculate parity */ + if (length == 2) { /* EAN-2 */ int code_value, parity_bit; code_value = (10 * ctoi(source[0])) + ctoi(source[1]); parity_bit = code_value % 4; - strcpy(parity, EAN2Parity[parity_bit]); - } - - if (code_type == EAN5) { + parity = EAN2Parity[parity_bit]; + } else { /* EAN-5 */ int values[6], parity_sum, parity_bit; for (i = 0; i < 6; i++) { @@ -363,34 +359,37 @@ static void ean_add_on(const unsigned char source[], const int length, char dest parity_sum += (9 * (values[1] + values[3])); parity_bit = parity_sum % 10; - strcpy(parity, EAN5Parity[parity_bit]); + parity = EAN5Parity[parity_bit]; } for (i = 0; i < length; i++) { switch (parity[i]) { - case 'A': lookup(NEON, EANsetA, source[i], dest); + case 'A': memcpy(d, EANsetA[source[i] - '0'], 4); + d += 4; break; - case 'B': lookup(NEON, EANsetB, source[i], dest); + case 'B': memcpy(d, EANsetB[source[i] - '0'], 4); + d += 4; break; } /* Glyph separator */ if (i != (length - 1)) { - strcat(dest, "11"); + memcpy(d, "11", 2); + d += 2; } } + *d = '\0'; } /* ************************ EAN-13 ****************** */ -static int ean13_cc(struct zint_symbol *symbol, const unsigned char source[], int length, char dest[], +static int ean13_cc(struct zint_symbol *symbol, const unsigned char source[], int length, char *d, int cc_rows) { int i, half_way; - char parity[6]; + const char *parity; unsigned char *gtin = symbol->text; int error_number = 0; - parity[0] = '\0'; ustrcpy(gtin, source); /* Add the appropriate check digit */ @@ -410,29 +409,32 @@ static int ean13_cc(struct zint_symbol *symbol, const unsigned char source[], in } /* Get parity for first half of the symbol */ - lookup(SODIUM, EAN13Parity, gtin[0], parity); + parity = EAN13Parity[gtin[0] - '0']; /* Now get on with the cipher */ half_way = 7; /* start character */ - strcat(dest, "111"); - for (i = 1; i < length; i++) { + memcpy(d, "111", 3); + d += 3; + + for (i = 1; i < length; i++, d += 4) { if (i == half_way) { /* middle character - separates manufacturer no. from product no. */ /* also inverses right hand characters */ - strcat(dest, "11111"); + memcpy(d, "11111", 5); + d += 5; } if (((i > 1) && (i < 7)) && (parity[i - 2] == 'B')) { - lookup(NEON, EANsetB, gtin[i], dest); + memcpy(d, EANsetB[gtin[i] - '0'], 4); } else { - lookup(NEON, EANsetA, gtin[i], dest); + memcpy(d, EANsetA[gtin[i] - '0'], 4); } } /* stop character */ - strcat(dest, "111"); + strcpy(d, "111"); if (symbol->output_options & COMPLIANT_HEIGHT) { /* BS EN 797:1996 4.5.1 Nominal dimensions 22.85mm / 0.33mm (X) ~ 69.24, @@ -535,8 +537,8 @@ static int isbnx(struct zint_symbol *symbol, unsigned char source[], const int s int i; char check_digit; - to_upper(source); - if (is_sane(ISBNX_SANE, source, src_len) != 0) { + to_upper(source, src_len); + if (!is_sane(ISBNX_SANE_F, source, src_len)) { strcpy(symbol->errtxt, "277: Invalid character in data (digits and \"X\" only)"); return ZINT_ERROR_INVALID_DATA; } @@ -554,16 +556,15 @@ static int isbnx(struct zint_symbol *symbol, unsigned char source[], const int s return ZINT_ERROR_INVALID_DATA; } - /* "X" can only occur in last position */ - if (is_sane(NEON, source, 12) != 0) { - strcpy(symbol->errtxt, "282: Invalid character in data, \"X\" allowed in last position only"); + /* "X" cannot occur */ + if (!is_sane(NEON_F, source, 13)) { + strcpy(symbol->errtxt, "282: Invalid character in data, \"X\" not allowed in ISBN-13"); return ZINT_ERROR_INVALID_DATA; } check_digit = gs1_check_digit(source, 12); - if (source[src_len - 1] != check_digit) { - sprintf(symbol->errtxt, "280: Invalid ISBN check digit '%c', expecting '%c'", - source[src_len - 1], check_digit); + if (source[12] != check_digit) { + sprintf(symbol->errtxt, "280: Invalid ISBN check digit '%c', expecting '%c'", source[12], check_digit); return ZINT_ERROR_INVALID_CHECK; } source[12] = '\0'; @@ -578,7 +579,7 @@ static int isbnx(struct zint_symbol *symbol, unsigned char source[], const int s } /* "X" can only occur in last position */ - if (is_sane(NEON, source, 9) != 0) { + if (!is_sane(NEON_F, source, 9)) { strcpy(symbol->errtxt, "296: Invalid character in data, \"X\" allowed in last position only"); return ZINT_ERROR_INVALID_DATA; } @@ -589,7 +590,7 @@ static int isbnx(struct zint_symbol *symbol, unsigned char source[], const int s source[9], check_digit); return ZINT_ERROR_INVALID_CHECK; } - for (i = 11; i > 2; i--) { + for (i = 11; i > 2; i--) { /* This drops the check digit */ source[i] = source[i - 3]; } source[0] = '9'; @@ -603,8 +604,9 @@ static int isbnx(struct zint_symbol *symbol, unsigned char source[], const int s /* Add leading zeroes to EAN and UPC strings */ INTERNAL int ean_leading_zeroes(struct zint_symbol *symbol, const unsigned char source[], - unsigned char local_source[], int *p_with_addon) { - unsigned char first_part[14], second_part[6], zfirst_part[14], zsecond_part[6]; + unsigned char local_source[], int *p_with_addon, unsigned char *zfirst_part, + unsigned char *zsecond_part) { + unsigned char first_part[14], second_part[6]; int with_addon = 0; int first_len = 0, second_len = 0, zfirst_len = 0, zsecond_len = 0, i, h; @@ -641,14 +643,10 @@ INTERNAL int ean_leading_zeroes(struct zint_symbol *symbol, const unsigned char /* Calculate target lengths */ if (second_len == 0) { zsecond_len = 0; + } else if (second_len <= 2) { + zsecond_len = 2; } else { - if (second_len <= 5) { - if (second_len <= 2) { - zsecond_len = 2; - } else { - zsecond_len = 5; - } - } + zsecond_len = 5; } switch (symbol->symbology) { case BARCODE_EANX: @@ -717,25 +715,29 @@ INTERNAL int ean_leading_zeroes(struct zint_symbol *symbol, const unsigned char break; } + /* Copy adjusted data back to local_source */ /* Add leading zeroes */ - zfirst_part[0] = '\0'; for (i = 0; i < (zfirst_len - first_len); i++) { - ustrcat(zfirst_part, "0"); + local_source[i] = '0'; } - ustrcat(zfirst_part, first_part); - - zsecond_part[0] = '\0'; - for (i = 0; i < (zsecond_len - second_len); i++) { - ustrcat(zsecond_part, "0"); + ustrcpy(local_source + i, first_part); + if (zfirst_part) { + ustrcpy(zfirst_part, local_source); } - ustrcat(zsecond_part, second_part); - /* Copy adjusted data back to local_source */ - ustrcat(local_source, zfirst_part); - if (*zsecond_part) { - ustrcat(local_source, "+"); - ustrcat(local_source, zsecond_part); + if (with_addon) { + h = (int) ustrlen(local_source); + local_source[h++] = '+'; + for (i = 0; i < (zsecond_len - second_len); i++) { + local_source[h + i] = '0'; + } + ustrcpy(local_source + h + i, second_part); + if (zsecond_part) { + ustrcpy(zsecond_part, local_source + h); + } + } else if (zsecond_part) { + *zsecond_part = '\0'; } if (p_with_addon) { @@ -746,30 +748,26 @@ INTERNAL int ean_leading_zeroes(struct zint_symbol *symbol, const unsigned char } INTERNAL int eanx_cc(struct zint_symbol *symbol, unsigned char source[], int src_len, int cc_rows) { - unsigned char first_part[14] = {0}, second_part[6] = {0}; - unsigned char local_source[20] = {0}; /* Allow 13 + "+" + 5 + 1 */ + unsigned char first_part[14], second_part[6]; + unsigned char local_source[20]; /* Allow 13 + "+" + 5 + 1 */ char dest[1000] = {0}; - int latch, reader, writer; int with_addon; int error_number = 0, i, plus_count; int addon_gap = 0; int first_part_len, second_part_len; - latch = FALSE; - writer = 0; - if (src_len > 19) { strcpy(symbol->errtxt, "283: Input too long (19 character maximum)"); return ZINT_ERROR_TOO_LONG; } if (symbol->symbology != BARCODE_ISBNX) { /* ISBN has its own sanity routine */ - if (is_sane(SODIUM, source, src_len) != 0) { + if (!is_sane(SODIUM_PLS_F, source, src_len)) { strcpy(symbol->errtxt, "284: Invalid character in data (digits and \"+\" only)"); return ZINT_ERROR_INVALID_DATA; } } else { - if (is_sane(ISBNX_ADDON_SANE, source, src_len) != 0) { + if (!is_sane(ISBNX_ADDON_SANE_F, source, src_len)) { strcpy(symbol->errtxt, "285: Invalid character in data (digits, \"X\" and \"+\" only)"); return ZINT_ERROR_INVALID_DATA; } @@ -789,42 +787,19 @@ INTERNAL int eanx_cc(struct zint_symbol *symbol, unsigned char source[], int src } /* Add leading zeroes, checking max lengths of parts */ - if (!ean_leading_zeroes(symbol, source, local_source, &with_addon)) { + if (!ean_leading_zeroes(symbol, source, local_source, &with_addon, first_part, second_part)) { sprintf(symbol->errtxt, "294: Input too long (%s)", with_addon ? "5 character maximum for add-on" : "13 character maximum"); return ZINT_ERROR_TOO_LONG; } - reader = 0; if (with_addon) { - int local_length = (int) ustrlen(local_source); - do { - if (local_source[reader] == '+') { - first_part[writer] = '\0'; - latch = TRUE; - reader++; - writer = 0; - } - - if (latch) { - second_part[writer] = local_source[reader]; - reader++; - writer++; - } else { - first_part[writer] = local_source[reader]; - reader++; - writer++; - } - } while (reader <= local_length); - if (symbol->symbology == BARCODE_UPCA || symbol->symbology == BARCODE_UPCA_CHK || symbol->symbology == BARCODE_UPCA_CC) { addon_gap = symbol->option_2 >= 9 && symbol->option_2 <= 12 ? symbol->option_2 : 9; } else { addon_gap = symbol->option_2 >= 7 && symbol->option_2 <= 12 ? symbol->option_2 : 7; } - } else { - ustrcpy(first_part, local_source); } first_part_len = (int) ustrlen(first_part); @@ -960,7 +935,7 @@ INTERNAL int eanx_cc(struct zint_symbol *symbol, unsigned char source[], int src second_part_len = (int) ustrlen(second_part); if (symbol->symbology == BARCODE_ISBNX) { /* Need to further check that add-on numeric only */ - if (is_sane(NEON, second_part, second_part_len) != 0) { + if (!is_sane(NEON_F, second_part, second_part_len)) { strcpy(symbol->errtxt, "295: Invalid add-on data (digits only)"); return ZINT_ERROR_INVALID_DATA; } @@ -983,7 +958,7 @@ INTERNAL int eanx_cc(struct zint_symbol *symbol, unsigned char source[], int src return ZINT_ERROR_TOO_LONG; } - expand(symbol, (const char *) dest); + expand(symbol, dest, (int) strlen(dest)); switch (symbol->symbology) { case BARCODE_EANX_CC: diff --git a/backend/vector.c b/backend/vector.c index ec4426b1..296043ec 100644 --- a/backend/vector.c +++ b/backend/vector.c @@ -407,6 +407,7 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ unsigned char textpart1[5], textpart2[7], textpart3[7], textpart4[2]; int hide_text; int i, r; + int block_width = 0; int text_height; /* Font pixel size (so whole integers) */ float text_gap; /* Gap between barcode and text */ float guard_descent; @@ -415,7 +416,7 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ float digit_ascent_factor = 0.25f; /* Assuming digit ascent roughly 25% less than font size */ float dot_overspill = 0.0f; float dot_offset = 0.0f; - int rect_count, last_row_start = 0; + int rect_count = 0, last_row_start = 0; struct zint_vector *vector; struct zint_vector_rect *rect, *last_rectangle = NULL; @@ -427,7 +428,7 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ vector_free(symbol); // Sanity check colours - error_number = output_check_colour_options(symbol); + error_number = out_check_colour_options(symbol); if (error_number != 0) { return error_number; } @@ -443,17 +444,17 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ vector->circles = NULL; vector->strings = NULL; - large_bar_height = output_large_bar_height(symbol, 0 /*No rounding to scale*/); + large_bar_height = out_large_bar_height(symbol, 0 /*No rounding to scale*/); main_width = symbol->width; if (is_extendable(symbol->symbology)) { - upceanflag = output_process_upcean(symbol, &main_width, &comp_xoffset, addon, &addon_gap); + upceanflag = out_process_upcean(symbol, &main_width, &comp_xoffset, addon, &addon_gap); } hide_text = ((!symbol->show_hrt) || (ustrlen(symbol->text) == 0)); - output_set_whitespace_offsets(symbol, hide_text, &xoffset, &yoffset, &roffset, &boffset, 0 /*scaler*/, + out_set_whitespace_offsets(symbol, hide_text, &xoffset, &yoffset, &roffset, &boffset, 0 /*scaler*/, NULL, NULL, NULL, NULL); /* Note font sizes scaled by 2 so really twice these values */ @@ -540,12 +541,12 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ /* Hexagons */ for (r = 0; r < symbol->rows; r++) { const int odd_row = r & 1; /* Odd (reduced) row, even (full) row */ - const float yposn = r * yposn_offset + hex_yradius + yoffset; + const float hex_yposn = r * yposn_offset + hex_yradius + yoffset; const float xposn_offset = (odd_row ? hex_diameter : hex_radius) + xoffset; for (i = 0; i < symbol->width - odd_row; i++) { if (module_is_set(symbol, r, i)) { - const float xposn = i * hex_diameter + xposn_offset; - hexagon = vector_plot_create_hexagon(symbol, xposn, yposn, hex_diameter); + const float hex_xposn = i * hex_diameter + xposn_offset; + hexagon = vector_plot_create_hexagon(symbol, hex_xposn, hex_yposn, hex_diameter); if (!hexagon) return ZINT_ERROR_MEMORY; vector_plot_add_hexagon(symbol, hexagon, &last_hexagon); } @@ -564,79 +565,93 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ } } // Plot rectangles - most symbols created here - } else { - rect_count = 0; + } else if (symbol->symbology == BARCODE_ULTRA) { + yposn = yoffset; + for (r = 0; r < symbol->rows; r++) { + float row_height = symbol->row_height[r]; + last_row_start = rect_count; + + for (i = 0; i < symbol->width; i += block_width) { + int fill = module_colour_is_set(symbol, r, i); + for (block_width = 1; (i + block_width < symbol->width) + && module_colour_is_set(symbol, r, i + block_width) == fill; block_width++); + if (fill) { + /* a colour block */ + rect = vector_plot_create_rect(symbol, i + xoffset, yposn, block_width, row_height); + if (!rect) return ZINT_ERROR_MEMORY; + rect->colour = module_colour_is_set(symbol, r, i); + vector_plot_add_rect(symbol, rect, &last_rectangle); + rect_count++; + } + } + yposn += row_height; + } + + } else if (upceanflag >= 6) { /* UPC-E, EAN-8, UPC-A, EAN-13 */ yposn = yoffset; for (r = 0; r < symbol->rows; r++) { float row_height = symbol->row_height[r] ? symbol->row_height[r] : large_bar_height; last_row_start = rect_count; - i = 0; + for (i = 0; i < symbol->width; i += block_width) { + float addon_row_height; + int fill = module_is_set(symbol, r, i); + for (block_width = 1; (i + block_width < symbol->width) + && module_is_set(symbol, r, i + block_width) == fill; block_width++); - if (symbol->symbology == BARCODE_ULTRA) { - do { - int module_fill = module_colour_is_set(symbol, r, i); - int block_width = 0; - do { - block_width++; - } while (i + block_width < symbol->width - && module_colour_is_set(symbol, r, i + block_width) == module_fill); - if (module_fill) { - /* a colour block */ + if ((r == (symbol->rows - 1)) && (i > main_width) && (addon_latch == 0)) { + addon_text_yposn = yposn + text_height - text_height * digit_ascent_factor; + if (addon_text_yposn < 0.0f) { + addon_text_yposn = 0.0f; + } + addon_row_height = row_height - (addon_text_yposn - yposn) + text_gap; + if (upceanflag != 12 && upceanflag != 6) { /* UPC-A/E add-ons don't descend */ + addon_row_height += guard_descent; + } + if (addon_row_height < 0.5f) { + addon_row_height = 0.5f; + } + addon_latch = 1; + } + if (fill) { + /* a bar */ + if (addon_latch) { + rect = vector_plot_create_rect(symbol, i + xoffset, addon_text_yposn - text_gap, + block_width, addon_row_height); + } else { rect = vector_plot_create_rect(symbol, i + xoffset, yposn, block_width, row_height); - if (!rect) return ZINT_ERROR_MEMORY; - rect->colour = module_colour_is_set(symbol, r, i); - vector_plot_add_rect(symbol, rect, &last_rectangle); - rect_count++; } - i += block_width; + if (!rect) return ZINT_ERROR_MEMORY; + vector_plot_add_rect(symbol, rect, &last_rectangle); + rect_count++; + } + } + yposn += row_height; + } - } while (i < symbol->width); - } else { - do { - float addon_row_height; - int module_fill = module_is_set(symbol, r, i); - int block_width = 0; - do { - block_width++; - } while (i + block_width < symbol->width - && module_is_set(symbol, r, i + block_width) == module_fill); + } else { + yposn = yoffset; + for (r = 0; r < symbol->rows; r++) { + float row_height = symbol->row_height[r] ? symbol->row_height[r] : large_bar_height; + last_row_start = rect_count; - if (upceanflag && (addon_latch == 0) && (r == (symbol->rows - 1)) && (i > main_width)) { - addon_text_yposn = yposn + text_height - text_height * digit_ascent_factor; - if (addon_text_yposn < 0.0f) { - addon_text_yposn = 0.0f; - } - addon_row_height = row_height - (addon_text_yposn - yposn) + text_gap; - if (upceanflag != 12 && upceanflag != 6) { /* UPC-A/E add-ons don't descend */ - addon_row_height += guard_descent; - } - if (addon_row_height < 0.5f) { - addon_row_height = 0.5f; - } - addon_latch = 1; - } - if (module_fill) { - /* a bar */ - if (addon_latch == 0) { - rect = vector_plot_create_rect(symbol, i + xoffset, yposn, block_width, row_height); - } else { - rect = vector_plot_create_rect(symbol, i + xoffset, addon_text_yposn - text_gap, - block_width, addon_row_height); - } - if (!rect) return ZINT_ERROR_MEMORY; - vector_plot_add_rect(symbol, rect, &last_rectangle); - rect_count++; - } - i += block_width; - - } while (i < symbol->width); + for (i = 0; i < symbol->width; i += block_width) { + int fill = module_is_set(symbol, r, i); + for (block_width = 1; (i + block_width < symbol->width) + && module_is_set(symbol, r, i + block_width) == fill; block_width++); + if (fill) { + /* a bar */ + rect = vector_plot_create_rect(symbol, i + xoffset, yposn, block_width, row_height); + if (!rect) return ZINT_ERROR_MEMORY; + vector_plot_add_rect(symbol, rect, &last_rectangle); + rect_count++; + } } yposn += row_height; } } - if (upceanflag) { + if (guard_descent && upceanflag >= 6) { /* UPC-E, EAN-8, UPC-A, EAN-13 */ /* Guard bar extension */ if (upceanflag == 6) { /* UPC-E */ i = 0; @@ -686,7 +701,7 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ } i++; } - } else if (upceanflag == 13) { /* EAN-13 */ + } else { /* EAN-13 */ i = 0; for (rect = symbol->vector->rectangles; rect != NULL; rect = rect->next) { switch (i - last_row_start) { @@ -707,7 +722,6 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ /* Add the text */ if (!hide_text) { - int textdone = 0; float text_xposn; float text_yposn; @@ -718,10 +732,10 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ text_yposn += symbol->border_width; } - if (upceanflag) { + if (upceanflag >= 6) { /* UPC-E, EAN-8, UPC-A, EAN-13 */ float textwidth; - output_upcean_split_text(upceanflag, symbol->text, textpart1, textpart2, textpart3, textpart4); + out_upcean_split_text(upceanflag, symbol->text, textpart1, textpart2, textpart3, textpart4); if (upceanflag == 6) { /* UPC-E */ text_xposn = -5.0f + xoffset; @@ -736,7 +750,6 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ textwidth = 6.2f; if (!vector_plot_add_string(symbol, textpart3, text_xposn, text_yposn, upcae_outside_text_height, textwidth, 1 /*left align*/, &last_string)) return ZINT_ERROR_MEMORY; - textdone = 1; switch (ustrlen(addon)) { case 2: text_xposn = 61.0f + xoffset + addon_gap; @@ -760,7 +773,6 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ text_xposn = 50.0f + xoffset; if (!vector_plot_add_string(symbol, textpart2, text_xposn, text_yposn, text_height, textwidth, 0, &last_string)) return ZINT_ERROR_MEMORY; - textdone = 1; switch (ustrlen(addon)) { case 2: text_xposn = 77.0f + xoffset + addon_gap; @@ -792,7 +804,6 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ textwidth = 6.2f; if (!vector_plot_add_string(symbol, textpart4, text_xposn, text_yposn, upcae_outside_text_height, textwidth, 1 /*left align*/, &last_string)) return ZINT_ERROR_MEMORY; - textdone = 1; switch (ustrlen(addon)) { case 2: text_xposn = 105.0f + xoffset + addon_gap; @@ -808,7 +819,7 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ break; } - } else if (upceanflag == 13) { /* EAN-13 */ + } else { /* EAN-13 */ text_xposn = -5.0f + xoffset; textwidth = 8.5f; if (!vector_plot_add_string(symbol, textpart1, text_xposn, text_yposn, @@ -820,7 +831,6 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ text_xposn = 71.0f + xoffset; if (!vector_plot_add_string(symbol, textpart3, text_xposn, text_yposn, text_height, textwidth, 0, &last_string)) return ZINT_ERROR_MEMORY; - textdone = 1; switch (ustrlen(addon)) { case 2: text_xposn = 105.0f + xoffset + addon_gap; @@ -836,9 +846,7 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ break; } } - } - - if (!textdone) { + } else { /* Put normal human readable text at the bottom (and centered) */ // calculate start xoffset to center text text_xposn = main_width / 2.0f + xoffset; diff --git a/backend/zint.h b/backend/zint.h index b278f22e..1cb6e3b3 100644 --- a/backend/zint.h +++ b/backend/zint.h @@ -253,6 +253,7 @@ extern "C" { #define BARCODE_UPNQR 143 /* UPNQR (Univerzalnega Plačilnega Naloga QR) */ #define BARCODE_ULTRA 144 /* Ultracode */ #define BARCODE_RMQR 145 /* Rectangular Micro QR Code (rMQR) */ +#define BARCODE_LAST 145 /* Max barcode number marker, not barcode */ /* Output options (`symbol->output_options`) */ #define BARCODE_NO_ASCII 0x0001 /* Legacy (no-op) */ diff --git a/frontend_qt/mainwindow.cpp b/frontend_qt/mainwindow.cpp index 97f20aea..0c9d776d 100644 --- a/frontend_qt/mainwindow.cpp +++ b/frontend_qt/mainwindow.cpp @@ -111,7 +111,7 @@ static const struct bstyle_item bstyle_items[] = { { QSL("POSTNET"), BARCODE_POSTNET }, { QSL("QR Code (ISO 18004) (and HIBC)"), BARCODE_QRCODE }, { QSL("Rectangular Micro QR (rMQR)"), BARCODE_RMQR }, - { QSL("Royal Mail 4-state Barcode"), BARCODE_RM4SCC }, + { QSL("Royal Mail 4-state Barcode (RM4SCC)"), BARCODE_RM4SCC }, { QSL("Royal Mail 4-state Mailmark"), BARCODE_MAILMARK }, { QSL("Telepen"), BARCODE_TELEPEN }, { QSL("Telepen Numeric"), BARCODE_TELEPEN_NUM },