diff --git a/ChangeLog b/ChangeLog index 943b50fe..74b1a673 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ Version 2.13.0.9 (dev) not released yet - New `memfile` & `memfile_size` fields in `symbol` for use with new output option `BARCODE_MEMORY_FILE` - Invalid `input_mode` now returns warning +- New CODE128-only special extra escape `\^1` for manually inserting FNC1s Changes ------- @@ -21,6 +22,8 @@ Changes iso4217: new ISO 4217 currency code 924 - AZTEC: workaround MSVC 2022 optimizer bug in `az_populate_map()` loops, ticket #317, props Andre Maute +- CODE128: Add new extra escape `\^1` for manual insertion of FNC1s, ticket + #324, props Jim Shank Bugs ---- diff --git a/README.clang-tidy b/README.clang-tidy index 1d16ecec..55be6fc9 100644 --- a/README.clang-tidy +++ b/README.clang-tidy @@ -1,16 +1,16 @@ -% README.clang-tidy 2024-03-03 -% Current as of latest clang-tidy-19 from Ubuntu 22.04 apt package +% README.clang-tidy 2024-09-03 +% Current as of latest clang-tidy-20 from Ubuntu 22.04 apt package Requires cmake in "build" sub-directory with -DCMAKE_EXPORT_COMPILE_COMMANDS=ON (for "build/compile_commands.json") and -DCMAKE_BUILD_TYPE=Debug (so `assert()`s defined), and then make (for Qt generated includes). In project root directory (warning, slow): -clang-tidy-19 backend/*.c frontend/*.c backend_qt/*.cpp frontend_qt/*.cpp -p build/compile_commands.json +clang-tidy-20 backend/*.c frontend/*.c backend_qt/*.cpp frontend_qt/*.cpp -p build/compile_commands.json For "backend_tcl", which has no "compile_commands.json", specify the tcl include directory, e.g. -clang-tidy-19 backend_tcl/*.c -- -I/usr/include/tcl8.6 +clang-tidy-20 backend_tcl/*.c -- -I/usr/include/tcl8.6 Options are in ".clang-tidy" (in the project root directory). The excluded checks are `clang-analyzer-security.insecureAPI.strcpy` (for `strcpy()`, `strcat()` etc), and @@ -18,5 +18,5 @@ Options are in ".clang-tidy" (in the project root directory). The excluded check The test suite (cmake given -DZINT_TEST=ON) can also be analysed with an additional check disabled: -clang-tidy-19 backend/tests/*.c frontend/tests/*.c backend_qt/tests/*.cpp \ +clang-tidy-20 backend/tests/*.c frontend/tests/*.c backend_qt/tests/*.cpp \ -checks='-clang-analyzer-optin.performance.Padding' -p build/compile_commands.json diff --git a/backend/code128.c b/backend/code128.c index f2c9027d..1a18249f 100644 --- a/backend/code128.c +++ b/backend/code128.c @@ -76,11 +76,11 @@ INTERNAL_DATA const char C128Table[107][6] = { /* Used by CODABLOCKF and CODE16K }; /* Determine appropriate mode for a given character */ -INTERNAL int c128_parunmodd(const unsigned char llyth) { +INTERNAL int c128_parunmodd(const unsigned char llyth, const int check_fnc1) { int modd; if (llyth <= 31) { - modd = C128_SHIFTA; + modd = check_fnc1 && llyth == '\x1D' ? C128_ABORC : C128_SHIFTA; } else if ((llyth >= 48) && (llyth <= 57)) { modd = C128_ABORC; } else if (llyth <= 95) { @@ -244,7 +244,7 @@ INTERNAL void c128_dxsmooth(int list[2][C128_MAX], int *p_indexliste, const char */ INTERNAL void c128_set_a(const unsigned char source, int values[], int *bar_chars) { - if (source > 127) { + if (source >= 128) { if (source < 160) { values[(*bar_chars)] = (source - 128) + 64; } else { @@ -290,7 +290,7 @@ INTERNAL void c128_set_c(const unsigned char source_a, const unsigned char sourc (*bar_chars)++; } -/* Put set data into set[]. If source given (GS1_MODE) then resolves odd C blocks */ +/* Put set data into set[]. If source given (GS1_MODE or manual FNC1s) then resolves odd C blocks */ INTERNAL void c128_put_in_set(int list[2][C128_MAX], const int indexliste, char set[C128_MAX], const unsigned char *source) { int read = 0; @@ -303,12 +303,13 @@ INTERNAL void c128_put_in_set(int list[2][C128_MAX], const int indexliste, char } if (source) { /* Watch out for odd-length Mode C blocks */ - int c_count = 0; + int c_count = 0, have_nonc = 0; for (i = 0; i < read; i++) { if (set[i] == 'C') { if (source[i] == '\x1D') { if (c_count & 1) { - if ((i - c_count) != 0) { + have_nonc = 1; + if (i > c_count) { set[i - c_count] = 'B'; } else { set[i - 1] = 'B'; @@ -319,8 +320,9 @@ INTERNAL void c128_put_in_set(int list[2][C128_MAX], const int indexliste, char c_count++; } } else { + have_nonc = 1; if (c_count & 1) { - if ((i - c_count) != 0) { + if (i > c_count) { set[i - c_count] = 'B'; } else { set[i - 1] = 'B'; @@ -330,17 +332,26 @@ INTERNAL void c128_put_in_set(int list[2][C128_MAX], const int indexliste, char } } if (c_count & 1) { - if ((i - c_count) != 0) { + if (i > c_count && have_nonc) { set[i - c_count] = 'B'; + if (c_count < 4) { + /* Rule 1b */ + for (j = i - c_count + 1; j < i; j++) { + set[j] = 'B'; + } + } } else { set[i - 1] = 'B'; } } for (i = 1; i < read - 1; i++) { - if ((set[i] == 'C') && ((set[i - 1] == 'B') && (set[i + 1] == 'B'))) { - set[i] = 'B'; + if (set[i] == 'C' && set[i - 1] != 'C' && set[i + 1] != 'C') { + set[i] = set[i + 1]; } } + if (read > 1 && set[read - 1] == 'C' && set[read - 2] != 'C') { + set[read - 1] = set[read - 2]; + } } } @@ -351,8 +362,10 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len unsigned char src_buf[C128_MAX + 1]; unsigned char *src = source; char manual_set[C128_MAX] = {0}; + unsigned char fncs[C128_MAX] = {0}; /* Manual FNC1 positions */ int list[2][C128_MAX] = {{0}}; char set[C128_MAX] = {0}, fset[C128_MAX], mode, last_set, current_set = ' '; + int have_fnc1 = 0; /* Whether have at least 1 manual FNC1 */ int glyph_count = 0; /* Codeword estimate times 2 */ char dest[1000]; char *d = dest; @@ -373,16 +386,22 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len j = 0; for (i = 0; i < length; i++) { if (source[i] == '\\' && i + 2 < length && source[i + 1] == '^' - && ((source[i + 2] >= 'A' && source[i + 2] <= 'C') || source[i + 2] == '^')) { - if (source[i + 2] != '^') { - i += 2; - manual_ch = source[i]; - } else { /* Escape sequence '\^^' */ + && ((source[i + 2] >= 'A' && source[i + 2] <= 'C') || source[i + 2] == '1' + || source[i + 2] == '^')) { + if (source[i + 2] == '^') { /* Escape sequence '\^^' */ manual_set[j] = manual_ch; src_buf[j++] = source[i++]; manual_set[j] = manual_ch; src_buf[j++] = source[i++]; /* Drop second '^' */ + } else if (source[i + 2] == '1') { /* FNC1 */ + i += 2; + fncs[j] = have_fnc1 = 1; + manual_set[j] = manual_ch; + src_buf[j++] = '\x1D'; /* Manual FNC1 dummy */ + } else { /* Manual mode A/B/C */ + i += 2; + manual_ch = source[i]; } } else { manual_set[j] = manual_ch; @@ -456,10 +475,10 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len indexliste = 0; indexchaine = 0; - mode = c128_parunmodd(src[indexchaine]); + mode = c128_parunmodd(src[indexchaine], fncs[indexchaine]); if (mode == C128_ABORC && (symbol->symbology == BARCODE_CODE128AB - || (manual_set[indexchaine] == 'A' || manual_set[indexchaine] == 'B'))) { + || manual_set[indexchaine] == 'A' || manual_set[indexchaine] == 'B')) { mode = C128_AORB; } @@ -471,10 +490,10 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len if (indexchaine == length) { break; } - mode = c128_parunmodd(src[indexchaine]); + mode = c128_parunmodd(src[indexchaine], fncs[indexchaine]); if (mode == C128_ABORC && (symbol->symbology == BARCODE_CODE128AB - || (manual_set[indexchaine] == 'A' || manual_set[indexchaine] == 'B'))) { + || manual_set[indexchaine] == 'A' || manual_set[indexchaine] == 'B')) { mode = C128_AORB; } if (manual_set[indexchaine] != manual_set[indexchaine - 1]) { @@ -494,29 +513,32 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len } c128_dxsmooth(list, &indexliste, src == src_buf ? manual_set : NULL); - /* 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] = C128_LATCHB; - indexliste = 2; + if (!have_fnc1) { + /* 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] = C128_LATCHB; + indexliste = 2; + } } - } - if (indexliste > 1) { - for (i = 1; i < indexliste; i++) { - if ((list[1][i] == C128_LATCHC) && (list[0][i] & 1)) { - /* Rule 3b */ - list[0][i - 1]++; - list[0][i]--; + if (indexliste > 1) { + for (i = 1; i < indexliste; i++) { + if ((list[1][i] == C128_LATCHC) && (list[0][i] & 1)) { + /* Rule 3b */ + list[0][i - 1]++; + list[0][i]--; + } } } } - /* 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*/); + /* Put set data into set[]. Give NULL as source if no manual FNC1s as used to resolve odd C blocks + which has been done above */ + c128_put_in_set(list, indexliste, set, have_fnc1 ? src : NULL); if (symbol->debug & ZINT_DEBUG_PRINT) { printf("Data: %.*s (%d)\n", length, src, length); @@ -547,13 +569,12 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len } else { if ((fset[i] == 'F') && (fset[i - 1] != 'F')) { glyph_count += 4; - } - if ((fset[i] != 'F') && (fset[i - 1] == 'F')) { + } else if ((fset[i] != 'F') && (fset[i - 1] == 'F')) { glyph_count += 4; } } - if (set[i] == 'C') { + if (set[i] == 'C' && !fncs[i]) { glyph_count += 1; /* Half a codeword */ } else { glyph_count += 2; @@ -622,25 +643,25 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len read = 0; do { - if ((read != 0) && (set[read] != current_set)) { - /* Latch different code set */ - switch (set[read]) { - case 'A': - values[bar_characters++] = 101; - current_set = 'A'; - break; - case 'B': - values[bar_characters++] = 100; - current_set = 'B'; - break; - case 'C': - values[bar_characters++] = 99; - current_set = 'C'; - break; - } - } - if (read != 0) { + if (set[read] != current_set) { + /* Latch different code set */ + switch (set[read]) { + case 'A': + values[bar_characters++] = 101; + current_set = 'A'; + break; + case 'B': + values[bar_characters++] = 100; + current_set = 'B'; + break; + case 'C': + values[bar_characters++] = 99; + current_set = 'C'; + break; + } + } + if ((fset[read] == 'F') && (f_state == 0)) { /* Latch beginning of extended mode */ switch (current_set) { @@ -690,18 +711,24 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len values[bar_characters++] = 98; } - switch (set[read]) { /* Encode data characters */ - case 'a': - case 'A': c128_set_a(src[read], values, &bar_characters); - read++; - break; - case 'b': - case 'B': (void) c128_set_b(src[read], values, &bar_characters); - read++; - break; - case 'C': c128_set_c(src[read], src[read + 1], values, &bar_characters); - read += 2; - break; + if (!fncs[read]) { + switch (set[read]) { /* Encode data characters */ + case 'a': + case 'A': + c128_set_a(src[read++], values, &bar_characters); + break; + case 'b': + case 'B': + (void) c128_set_b(src[read++], values, &bar_characters); + break; + case 'C': + c128_set_c(src[read], src[read + 1], values, &bar_characters); + read += 2; + break; + } + } else { + values[bar_characters++] = 102; /* FNC1 in all modes */ + read++; } } while (read < length); @@ -744,6 +771,16 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len /* ISO/IEC 15417:2007 leaves dimensions/height as application specification */ + /* HRT */ + if (have_fnc1) { + /* Remove any manual FNC1 dummies ('\x1D') */ + for (i = 0, j = 0; i < length; i++) { + if (!fncs[i]) { + src[j++] = src[i]; + } + } + length = j; + } error_number = hrt_cpy_iso8859_1(symbol, src, length); return error_number; @@ -788,7 +825,7 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int indexliste = 0; indexchaine = 0; - mode = c128_parunmodd(reduced[indexchaine]); + mode = c128_parunmodd(reduced[indexchaine], 1 /*check_fnc1*/); do { list[1][indexliste] = mode; @@ -798,10 +835,7 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int if (indexchaine == reduced_length) { break; } - mode = c128_parunmodd(reduced[indexchaine]); - if (reduced[indexchaine] == '\x1D') { - mode = C128_ABORC; - } + mode = c128_parunmodd(reduced[indexchaine], 1 /*check_fnc1*/); } indexliste++; } while (indexchaine < reduced_length); @@ -853,7 +887,7 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int break; } - values[bar_characters++] = 102; + values[bar_characters++] = 102; /* FNC1 */ /* Encode the data */ read = 0; @@ -882,13 +916,11 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int switch (set[read]) { /* Encode data characters */ case 'A': case 'a': - c128_set_a(reduced[read], values, &bar_characters); /* Not reached */ - read++; + c128_set_a(reduced[read++], values, &bar_characters); /* Not reached */ break; case 'B': case 'b': - (void) c128_set_b(reduced[read], values, &bar_characters); - read++; + (void) c128_set_b(reduced[read++], values, &bar_characters); break; case 'C': c128_set_c(reduced[read], reduced[read + 1], values, &bar_characters); @@ -896,7 +928,7 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int break; } } else { - values[bar_characters++] = 102; + values[bar_characters++] = 102; /* FNC1 in all modes */ read++; } } while (read < reduced_length); @@ -1194,8 +1226,7 @@ INTERNAL int dpd(struct zint_symbol *symbol, unsigned char source[], int length) case 21: case 24: case 27: - symbol->text[p] = ' '; - p++; + symbol->text[p++] = ' '; break; } } diff --git a/backend/code128.h b/backend/code128.h index 4b1c573c..3102eb60 100644 --- a/backend/code128.h +++ b/backend/code128.h @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2020-2023 Robin Stuart + Copyright (C) 2020-2024 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -49,7 +49,7 @@ extern "C" { INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int length); -INTERNAL int c128_parunmodd(const unsigned char llyth); +INTERNAL int c128_parunmodd(const unsigned char llyth, const int check_fnc1); INTERNAL void c128_dxsmooth(int list[2][C128_MAX], int *indexliste, const char *manual_set); 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); diff --git a/backend/code16k.c b/backend/code16k.c index 4f122b8e..bd757955 100644 --- a/backend/code16k.c +++ b/backend/code16k.c @@ -90,7 +90,7 @@ INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int len indexliste = 0; indexchaine = 0; - mode = c128_parunmodd(source[indexchaine]); + mode = c128_parunmodd(source[indexchaine], gs1 /*check_fnc1*/); do { list[1][indexliste] = mode; @@ -100,10 +100,7 @@ INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int len if (indexchaine == length) { break; } - mode = c128_parunmodd(source[indexchaine]); - if (gs1 && source[indexchaine] == '\x1D') { - mode = C128_ABORC; - } /* FNC1 */ + mode = c128_parunmodd(source[indexchaine], gs1 /*check_fnc1*/); } indexliste++; } while (indexchaine < length); diff --git a/backend/raster.c b/backend/raster.c index 4eebe26c..5e3a62d8 100644 --- a/backend/raster.c +++ b/backend/raster.c @@ -68,7 +68,7 @@ static void *raster_malloc(size_t size, size_t size2) { /* Check for large image `malloc`s, which produce very large files most systems can't handle anyway */ /* Also `malloc()` on Linux will (usually) succeed regardless of request, and then get untrappably killed on access by OOM killer if too much, so this is a crude mitigation */ - if (size + size2 > 0x40000000) { /* 1GB */ + if (size + size2 < size /*Overflow check*/ || size + size2 > 0x40000000 /*1GB*/) { return NULL; } return malloc(size); @@ -112,7 +112,7 @@ static int buffer_plot(struct zint_symbol *symbol, const unsigned char *pixelbuf symbol->alphamap = NULL; } - symbol->bitmap = (unsigned char *) raster_malloc(bm_bitmap_size, 0); + symbol->bitmap = (unsigned char *) raster_malloc(bm_bitmap_size, 0 /*size2*/); if (symbol->bitmap == NULL) { strcpy(symbol->errtxt, "661: Insufficient memory for bitmap buffer"); return ZINT_ERROR_MEMORY; @@ -783,7 +783,7 @@ static int plot_raster_maxicode(struct zint_symbol *symbol, const int rotate_ang assert(image_width && image_height); image_size = (size_t) image_width * image_height; - if (!(pixelbuf = (unsigned char *) raster_malloc(image_size, 0 /*size*/))) { + if (!(pixelbuf = (unsigned char *) raster_malloc(image_size, 0 /*size2*/))) { strcpy(symbol->errtxt, "655: Insufficient memory for pixel buffer"); return ZINT_ERROR_MEMORY; } diff --git a/backend/tests/test_code128.c b/backend/tests/test_code128.c index a31d62c0..da78c1d5 100644 --- a/backend/tests/test_code128.c +++ b/backend/tests/test_code128.c @@ -370,6 +370,19 @@ static void test_input(const testCtx *const p_ctx) { /* 78*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "A\\^", -1, 0, 68, 1, "(6) 104 33 60 62 31 106", "StartC 12 34 CodeB A B C CodeC 12 CodeA LF" }, /* 79*/ { UNICODE_MODE, "A\0121234A12\012", -1, 0, 145, 1, "(13) 103 33 74 99 12 34 101 33 17 18 74 99 106", "StartA A CodeC 12 34 CodeA A 1 2 ; Okapi c128/improved-lookahead-mode-a.png" }, /* 80*/ { UNICODE_MODE, "21*\015\012M0", -1, 0, 112, 1, "(10) 103 18 17 10 77 74 45 16 9 106", "StartA 2 1 * M 0; Okapi c128/improved-lookahead-rule-1c.png" }, + /* 81*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "\\^1SN123456789012", -1, 0, 145, 1, "(13) 104 102 51 46 99 12 34 56 78 90 12 65 106", "StartB FNC1 S N CodeC 12 34 56 78 90 12" }, + /* 82*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "\\^B\\^1SN123456789012", -1, 0, 200, 0, "(18) 104 102 51 46 17 18 19 20 21 22 23 24 25 16 17 18 56 106", "StartB FNC1 S N 1 2 3 4 5 6 7 8 9 0 1 2; BWIPP no manual mode" }, + /* 83*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "A\\^1BC\\^1DEF\\^1", -1, 0, 134, 1, "(12) 104 33 102 34 35 102 36 37 38 102 9 106", "StartB A FNC1 B C FNC1 D E F FNC1" }, + /* 84*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "\\^C12\\^1", -1, 0, 57, 0, "(5) 105 12 102 12 106", "StartC 12 FNC1; BWIPP no manual mode" }, + /* 85*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "12\\^13", -1, 0, 79, 1, "(7) 105 12 102 100 19 79 106", "StartC 12 FNC1 CodeB 3" }, + /* 86*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "12\\^13\\^1", -1, 0, 90, 1, "(8) 105 12 102 100 19 102 74 106", "StartC 12 FNC1 CodeB 3 FNC1" }, + /* 87*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "1\\^123", -1, 0, 79, 0, "(7) 104 17 99 102 23 99 106", "StartB 1 CodeC FNC1 23; BWIPP different encodation (same codeword count)" }, + /* 88*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "12\\^134", -1, 0, 68, 1, "(6) 105 12 102 34 11 106", "StartC 12 FNC1 34" }, + /* 89*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "12\\^134\\^1", -1, 0, 79, 1, "(7) 105 12 102 34 102 7 106", "StartC 12 FNC1 34 FNC1" }, + /* 90*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "123\\^145\\^1", -1, 0, 112, 0, "(10) 105 12 100 19 99 102 45 102 101 106", "StartC 12 CodeB 3 CodeC FNC1 45 FNC1; BWIPP different encodation (BWIPP 1 shorter)" }, + /* 91*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "12\\^1345\\^1", -1, 0, 112, 0, "(10) 105 12 102 100 19 99 45 102 13 106", "StartC 12 FNC1 CodeB 3 CodeC 45 FNC1; BWIPP different encodation (BWIPP 1 shorter)" }, + /* 92*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "1234\\^156\\^1", -1, 0, 90, 1, "(8) 105 12 34 102 56 102 92 106", "StartC 12 34 FNC1 56 FNC1" }, + /* 93*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "1234\\^156789\\^101\\^11\\^1", -1, 0, 189, 0, "(17) 105 12 34 102 100 21 99 67 89 102 1 102 100 17 102 48 106", "StartC 12 34 FNC1 56 78 CodeB 9 CodeC FNC1 01 FNC1 CodeB 1 FNC1; BWIPP different encodation (BWIPP 1 shorter)" }, }; int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -449,45 +462,51 @@ static void test_gs1_128_input(const testCtx *const p_ctx) { char *data; int ret; int expected_width; + int bwipp_cmp; char *expected; char *comment; }; struct item data[] = { - /* 0*/ { GS1_MODE, "[90]1[90]1", 0, 123, "(11) 105 102 90 100 17 102 25 99 1 56 106", "StartC FNC1 90 CodeB 1 FNC1 9" }, - /* 1*/ { GS1_MODE | GS1PARENS_MODE, "(90)1(90)1", 0, 123, "(11) 105 102 90 100 17 102 25 99 1 56 106", "StartC FNC1 90 CodeB 1 FNC1 9" }, - /* 2*/ { GS1_MODE, "[90]1[90]12", 0, 123, "(11) 105 102 90 100 17 99 102 90 12 13 106", "StartC FNC1 90 CodeB 1 CodeC FNC1 90 12" }, - /* 3*/ { GS1_MODE, "[90]1[90]123", 0, 134, "(12) 105 102 90 100 17 102 25 99 1 23 57 106", "StartC FNC1 90 CodeB 1 FNC1 9 CodeC 01 23" }, - /* 4*/ { GS1_MODE, "[90]12[90]1", 0, 123, "(11) 105 102 90 12 102 100 25 99 1 19 106", "StartC FNC1 90 12 FNC1 CodeB 9 CodeC 01" }, - /* 5*/ { GS1_MODE, "[90]12[90]12", 0, 101, "(9) 105 102 90 12 102 90 12 14 106", "StartC FNC1 90 12 FNC1 90 12" }, - /* 6*/ { GS1_MODE, "[90]12[90]123", 0, 134, "(12) 105 102 90 12 102 100 25 99 1 23 20 106", "StartC FNC1 90 12 FNC1 CodeB 9 CodeC 01 23" }, - /* 7*/ { GS1_MODE, "[90]123[90]1", 0, 134, "(12) 105 102 90 12 100 19 102 25 99 1 34 106", "StartC FNC1 90 12 CodeB 3 FNC1 9 CodeC 01" }, - /* 8*/ { GS1_MODE, "[90]123[90]1234", 0, 145, "(13) 105 102 90 12 100 19 99 102 90 12 34 98 106", "StartC FNC1 90 12 CodeB 3 CodeC FNC1 90 12 34" }, - /* 9*/ { GS1_MODE, "[90]1[90]1[90]1", 0, 178, "(16) 105 102 90 100 17 102 25 99 1 102 100 25 99 1 51 106", "StartC FNC1 90 CodeB 1 FNC1 9 CodeC 01 FNC1 CodeB 9 CodeC 01" }, - /* 10*/ { GS1_MODE, "[90]1[90]12[90]1", 0, 178, "(16) 105 102 90 100 17 99 102 90 12 102 100 25 99 1 8 106", "StartC FNC1 90 CodeB 1 CodeC FNC1 90 12 FNC1 CodeB 9 CodeC 01" }, - /* 11*/ { GS1_MODE, "[90]1[90]123[90]1", 0, 189, "(17) 105 102 90 100 17 102 25 99 1 23 102 100 25 99 1 70 106", "StartC FNC1 90 CodeB 1 FNC1 9 CodeC 01 23 FNC1 CodeB 9 CodeC 01" }, - /* 12*/ { GS1_MODE, "[90]12[90]123[90]1", 0, 189, "(17) 105 102 90 12 102 100 25 99 1 23 102 100 25 99 1 33 106", "StartC FNC1 90 12 FNC1 CodeB 9 CodeC 01 23 FNC1 CodeB 9 CodeC 01" }, - /* 13*/ { GS1_MODE, "[90]12[90]123[90]12", 0, 167, "(15) 105 102 90 12 102 100 25 99 1 23 102 90 12 11 106", "StartC FNC1 90 12 FNC1 CodeB 9 CodeC 01 23 FNC1 90 12" }, - /* 14*/ { GS1_MODE, "[90]123[90]1[90]1", 0, 189, "(17) 105 102 90 12 100 19 102 25 99 1 102 100 25 99 1 47 106", "StartC FNC1 90 12 CodeB 3 FNC1 9 CodeC 01 FNC1 CodeB 9 CodeC 01" }, - /* 15*/ { GS1_MODE, "[90]123[90]12[90]1", 0, 189, "(17) 105 102 90 12 100 19 99 102 90 12 102 100 25 99 1 80 106", "StartC FNC1 90 12 CodeB 3 CodeC FNC1 90 12 FNC1 CodeB 9 CodeC 01" }, - /* 16*/ { GS1_MODE, "[90]123[90]123[90]12", 0, 178, "(16) 105 102 90 12 100 19 102 25 99 1 23 102 90 12 47 106", "StartC FNC1 90 12 CodeB 3 FNC1 9 CodeC 01 23 FNC1 90 12" }, - /* 17*/ { GS1_MODE, "[90]123[90]1234[90]1", 0, 200, "(18) 105 102 90 12 100 19 99 102 90 12 34 102 100 25 99 1 26 106", "StartC FNC1 90 12 CodeB 3 CodeC FNC1 90 12 34 FNC1 CodeB 9 CodeC 01" }, - /* 18*/ { GS1_MODE, "[90]123[90]1234[90]123", 0, 211, "(19) 105 102 90 12 100 19 99 102 90 12 34 102 100 25 99 1 23 85 106", "StartC FNC1 90 12 CodeB 3 CodeC FNC1 90 12 34 FNC1 CodeB 9 CodeC 01 23" }, - /* 19*/ { GS1_MODE, "[90]12345[90]1234[90]1", 0, 211, "(19) 105 102 90 12 34 100 21 99 102 90 12 34 102 100 25 99 1 30 106", "StartC FNC1 90 12 34 CodeB 5 CodeC FNC1 90 12 34 FNC1 CodeB 9 CodeC 01" }, - /* 20*/ { GS1_MODE, "[90]1A[90]1", 0, 134, "(12) 104 102 25 16 17 33 102 25 99 1 65 106", "StartB FNC1 9 0 1 A FNC1 9 CodeC 01" }, - /* 21*/ { GS1_MODE, "[90]12A[90]123", 0, 145, "(13) 105 102 90 12 100 33 102 25 99 1 23 25 106", "StartC FNC1 90 12 CodeB A FNC1 9 CodeC 01 23" }, - /* 22*/ { GS1_MODE, "[90]123[90]A234[90]123", 0, 244, "(22) 105 102 90 12 100 19 99 102 90 100 33 18 99 34 102 100 25 99 1 23 37 106", "StartC FNC1 90 12 CodeB 3 CodeC FNC1 90 CodeB A 2 CodeC 34 FNC1 CodeB 9 CodeC 01 23" }, - /* 23*/ { GS1_MODE, "[90]12345A12345A", 0, 178, "(16) 105 102 90 12 34 100 21 33 17 99 23 45 100 33 59 106", "StartC FNC1 90 12 34 CodeB 5 A 1 CodeC 23 45 CodeB A [" }, - /* 24*/ { GS1_MODE, "[01]12345678901231[90]12345678901234567890123456789", 0, 321, "(29) 105 102 1 12 34 56 78 90 12 31 90 12 34 56 78 90 12 34 56 78 90 12 34 56 78 100 25 59", "Max length" }, - /* 25*/ { GS1_MODE, "[01]12345678901231[90]123456789012345678901234567890[91]1", ZINT_WARN_NONCOMPLIANT, 365, "Warning 843: GS1-128 input too long (48 character maximum)", "Over length" }, - /* 26*/ { GS1_MODE, "[90]123456789012345678901234567890[91]1234567890123456789012345678901234567890123456789012345678901234567890[92]12345678901234567890123456789012345678901234567890123456789012345678901234567890[93]1234", ZINT_WARN_HRT_TRUNCATED, 1135, "Warning 844: Human Readable Text truncated", "Max input" }, - /* 27*/ { GS1_MODE, "[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[3100]567890[20]34[20]78", ZINT_WARN_HRT_TRUNCATED, 1135, "Warning 844: Human Readable Text truncated", "HRT truncation warning trumps non-compliant (3100) warning" }, - /* 28*/ { GS1_MODE, "[90]123456789012345678901234567890[91]1234567890123456789012345678901234567890123456789012345678901234567890[92]12345678901234567890123456789012345678901234567890123456789012345678901234567890[93]12345", ZINT_ERROR_TOO_LONG, 0, "Error 344: Input too long (99 symbol character maximum)", "" }, + /* 0*/ { GS1_MODE, "[90]1[90]1", 0, 123, 1, "(11) 105 102 90 100 17 102 25 16 17 15 106", "StartC FNC1 90 CodeB 1 FNC1 9 0 1" }, + /* 1*/ { GS1_MODE | GS1PARENS_MODE, "(90)1(90)1", 0, 123, 1, "(11) 105 102 90 100 17 102 25 16 17 15 106", "StartC FNC1 90 CodeB 1 FNC1 9 0 1" }, + /* 2*/ { GS1_MODE, "[90]1[90]12", 0, 123, 0, "(11) 105 102 90 100 17 99 102 90 12 13 106", "StartC FNC1 90 CodeB 1 CodeC FNC1 90 12; BWIPP different encodation (same codeword count)" }, + /* 3*/ { GS1_MODE, "[90]1[90]123", 0, 134, 1, "(12) 105 102 90 100 17 102 25 99 1 23 57 106", "StartC FNC1 90 CodeB 1 FNC1 9 CodeC 01 23" }, + /* 4*/ { GS1_MODE, "[90]12[90]1", 0, 112, 1, "(10) 105 102 90 12 102 90 100 17 43 106", "StartC FNC1 90 12 FNC1 90 CodeB 1" }, + /* 5*/ { GS1_MODE, "[90]12[90]12", 0, 101, 1, "(9) 105 102 90 12 102 90 12 14 106", "StartC FNC1 90 12 FNC1 90 12" }, + /* 6*/ { GS1_MODE, "[90]12[90]123", 0, 123, 1, "(11) 105 102 90 12 102 90 12 100 19 42 106", "StartC FNC1 90 12 FNC1 CodeB 9 CodeC 01 23" }, + /* 7*/ { GS1_MODE, "[90]123[90]1", 0, 134, 1, "(12) 105 102 90 12 100 19 102 25 16 17 29 106", "StartC FNC1 90 12 CodeB 3 FNC1 9 0 1" }, + /* 8*/ { GS1_MODE, "[90]123[90]1234", 0, 145, 0, "(13) 105 102 90 12 100 19 99 102 90 12 34 98 106", "StartC FNC1 90 12 CodeB 3 CodeC FNC1 90 12 34; BWIPP different encodation (same codeword count)" }, + /* 9*/ { GS1_MODE, "[90]1[90]1[90]1", 0, 178, 0, "(16) 105 102 90 100 17 102 25 99 1 102 100 25 16 17 87 106", "StartC FNC1 90 CodeB 1 FNC1 9 CodeC 01 FNC1 CodeB 9 0 1; BWIPP different encodation (BWIPP 1 shorter)" }, + /* 10*/ { GS1_MODE, "[90]1[90]12[90]1", 0, 178, 0, "(16) 105 102 90 100 17 99 102 90 12 102 100 25 16 17 44 106", "StartC FNC1 90 CodeB 1 CodeC FNC1 90 12 FNC1 CodeB 9 0 1; BWIPP different encodation (same codeword count)" }, + /* 11*/ { GS1_MODE, "[90]1[90]123[90]1", 0, 189, 0, "(17) 105 102 90 100 17 102 25 99 1 23 102 100 25 16 17 39 106", "StartC FNC1 90 CodeB 1 FNC1 9 CodeC 01 23 FNC1 CodeB 9 0 1; BWIPP different encodation (BWIPP 1 shorter)" }, + /* 12*/ { GS1_MODE, "[90]12[90]123[90]1", 0, 189, 0, "(17) 105 102 90 12 102 100 25 99 1 23 102 100 25 16 17 2 106", "StartC FNC1 90 12 FNC1 CodeB 9 CodeC 01 23 FNC1 CodeB 9 0 1; BWIPP different encodation (BWIPP 2 shorter)" }, + /* 13*/ { GS1_MODE, "[90]12[90]123[90]12", 0, 167, 0, "(15) 105 102 90 12 102 100 25 99 1 23 102 90 12 11 106", "StartC FNC1 90 12 FNC1 CodeB 9 CodeC 01 23 FNC1 90 12; BWIPP different encodation (same codeword count)" }, + /* 14*/ { GS1_MODE, "[90]123[90]1[90]1", 0, 189, 0, "(17) 105 102 90 12 100 19 102 25 99 1 102 100 25 16 17 16 106", "StartC FNC1 90 12 CodeB 3 FNC1 9 CodeC 01 FNC1 CodeB 9 0 1; BWIPP different encodation (BWIPP 1 shorter)" }, + /* 15*/ { GS1_MODE, "[90]123[90]12[90]1", 0, 189, 0, "(17) 105 102 90 12 100 19 99 102 90 12 102 100 25 16 17 49 106", "StartC FNC1 90 12 CodeB 3 CodeC FNC1 90 12 FNC1 CodeB 9 CodeC 01; BWIPP different encodation (same codeword count)" }, + /* 16*/ { GS1_MODE, "[90]123[90]123[90]12", 0, 178, 1, "(16) 105 102 90 12 100 19 102 25 99 1 23 102 90 12 47 106", "StartC FNC1 90 12 CodeB 3 FNC1 9 CodeC 01 23 FNC1 90 12" }, + /* 17*/ { GS1_MODE, "[90]123[90]1234[90]1", 0, 200, 0, "(18) 105 102 90 12 100 19 99 102 90 12 34 102 100 25 16 17 31 106", "StartC FNC1 90 12 CodeB 3 CodeC FNC1 90 12 34 FNC1 CodeB 9 CodeC 01; BWIPP different encodation (BWIPP 1 longer)" }, + /* 18*/ { GS1_MODE, "[90]123[90]1234[90]123", 0, 211, 0, "(19) 105 102 90 12 100 19 99 102 90 12 34 102 100 25 99 1 23 85 106", "StartC FNC1 90 12 CodeB 3 CodeC FNC1 90 12 34 FNC1 CodeB 9 CodeC 01 23; BWIPP different encodation (BWIPP 1 longer)" }, + /* 19*/ { GS1_MODE, "[90]12345[90]1234[90]1", 0, 211, 0, "(19) 105 102 90 12 34 100 21 99 102 90 12 34 102 100 25 16 17 71 106", "StartC FNC1 90 12 34 CodeB 5 CodeC FNC1 90 12 34 FNC1 CodeB 9 CodeC 01; BWIPP different encodation (BWIPP 1 longer)" }, + /* 20*/ { GS1_MODE, "[90]1A[90]1", 0, 134, 0, "(12) 104 102 25 16 17 33 102 25 16 17 60 106", "StartB FNC1 9 0 1 A FNC1 9 CodeC 01; BWIPP different encodation (same codeword count)" }, + /* 21*/ { GS1_MODE, "[90]12A[90]123", 0, 145, 1, "(13) 105 102 90 12 100 33 102 25 99 1 23 25 106", "StartC FNC1 90 12 CodeB A FNC1 9 CodeC 01 23" }, + /* 22*/ { GS1_MODE, "[90]123[90]A234[90]123", 0, 244, 0, "(22) 105 102 90 12 100 19 99 102 90 100 33 18 99 34 102 100 25 99 1 23 37 106", "StartC FNC1 90 12 CodeB 3 CodeC FNC1 90 CodeB A 2 CodeC 34 FNC1 CodeB 9 CodeC 01 23; BWIPP different encodation (BWIPP 2 shorter)" }, + /* 23*/ { GS1_MODE, "[90]12345A12345A", 0, 178, 1, "(16) 105 102 90 12 34 100 21 33 17 99 23 45 100 33 59 106", "StartC FNC1 90 12 34 CodeB 5 A 1 CodeC 23 45 CodeB A" }, + /* 24*/ { GS1_MODE, "[01]12345678901231[90]12345678901234567890123456789", 0, 321, 1, "(29) 105 102 1 12 34 56 78 90 12 31 90 12 34 56 78 90 12 34 56 78 90 12 34 56 78 100 25 59", "Max length" }, + /* 25*/ { GS1_MODE, "[01]12345678901231[90]123456789012345678901234567890[91]1", ZINT_WARN_NONCOMPLIANT, 354, 1, "Warning 843: GS1-128 input too long (48 character maximum)", "Over length" }, + /* 26*/ { GS1_MODE, "[90]123456789012345678901234567890[91]1234567890123456789012345678901234567890123456789012345678901234567890[92]12345678901234567890123456789012345678901234567890123456789012345678901234567890[93]1234", ZINT_WARN_HRT_TRUNCATED, 1135, 1, "Warning 844: Human Readable Text truncated", "Max input" }, + /* 27*/ { GS1_MODE, "[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[00]345678901234567890[3100]567890[20]34[20]78", ZINT_WARN_HRT_TRUNCATED, 1135, 1, "Warning 844: Human Readable Text truncated", "HRT truncation warning trumps non-compliant (3100) warning" }, + /* 28*/ { GS1_MODE, "[90]123456789012345678901234567890[91]1234567890123456789012345678901234567890123456789012345678901234567890[92]12345678901234567890123456789012345678901234567890123456789012345678901234567890[93]12345", ZINT_ERROR_TOO_LONG, 0, 1, "Error 344: Input too long (99 symbol character maximum)", "" }, }; int data_size = ARRAY_SIZE(data); int i, length, ret; struct zint_symbol *symbol = NULL; char escaped[1024]; + char cmp_buf[8192]; + char cmp_msg[1024]; + + int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ + int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder(); /* Only do ZXing-C++ test if asked, too slow otherwise */ testStartSymbol("test_gs1_128_input", &symbol); @@ -505,13 +524,14 @@ static void test_gs1_128_input(const testCtx *const p_ctx) { length = testUtilSetSymbol(symbol, BARCODE_GS1_128, data[i].input_mode, -1 /*eci*/, -1 /*option_1*/, -1, -1, -1 /*output_options*/, data[i].data, -1, debug); ret = ZBarcode_Encode(symbol, (unsigned char *) data[i].data, length); - assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); if (p_ctx->generate) { - printf(" /*%3d*/ { %s, \"%s\", %s, %d, \"%s\", \"%s\" },\n", + printf(" /*%3d*/ { %s, \"%s\", %s, %d, %d, \"%s\", \"%s\" },\n", i, testUtilInputModeName(data[i].input_mode), testUtilEscape(data[i].data, length, escaped, sizeof(escaped)), - testUtilErrorName(data[i].ret), symbol->width, symbol->errtxt, data[i].comment); + testUtilErrorName(data[i].ret), symbol->width, data[i].bwipp_cmp, symbol->errtxt, data[i].comment); } else { + assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + assert_zero(strcmp(symbol->errtxt, data[i].expected), "i:%d strcmp(%s, %s) != 0 (width %d)\n", i, symbol->errtxt, data[i].expected, symbol->width); if (ret < ZINT_ERROR) { assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", i, symbol->width, data[i].expected_width, data[i].data); if (ret == ZINT_WARN_HRT_TRUNCATED) { @@ -521,8 +541,33 @@ static void test_gs1_128_input(const testCtx *const p_ctx) { assert_equal((int) ustrlen(symbol->text), (int) strlen(data[i].data), "i:%d len symbol->text(%s) %d != %d (%s, %s) (%s)\n", i, symbol->text, (int) ustrlen(symbol->text), (int) strlen(data[i].data), testUtilErrorName(ret), data[i].data, symbol->errtxt); } + + if (do_bwipp && testUtilCanBwipp(i, symbol, -1, -1, -1, debug)) { + if (!data[i].bwipp_cmp) { + if (debug & ZINT_DEBUG_TEST_PRINT) printf("i:%d %s not BWIPP compatible (%s)\n", i, testUtilBarcodeName(symbol->symbology), data[i].comment); + } else { + char modules_dump[4096]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilBwipp(i, symbol, -1, -1, -1, data[i].data, length, NULL, cmp_buf, sizeof(cmp_buf), NULL); + assert_zero(ret, "i:%d %s testUtilBwipp ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilBwippCmp(symbol, cmp_msg, cmp_buf, modules_dump); + assert_zero(ret, "i:%d %s testUtilBwippCmp %d != 0 %s\n actual: %s\nexpected: %s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_buf, modules_dump); + } + } + if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data[i].data, length, debug)) { + int cmp_len, ret_len; + char modules_dump[4096]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, cmp_buf, sizeof(cmp_buf), &cmp_len); + assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length, NULL /*primary*/, escaped, &ret_len); + assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len, escaped); + } } - assert_zero(strcmp(symbol->errtxt, data[i].expected), "i:%d strcmp(%s, %s) != 0\n", i, symbol->errtxt, data[i].expected); } ZBarcode_Delete(symbol); @@ -556,6 +601,11 @@ static void test_hibc_input(const testCtx *const p_ctx) { struct zint_symbol *symbol = NULL; char escaped[1024]; + char cmp_buf[8192]; + char cmp_msg[1024]; + + int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ + int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder(); /* Only do ZXing-C++ test if asked, too slow otherwise */ testStartSymbol("test_hibc_input", &symbol); @@ -578,10 +628,32 @@ static void test_hibc_input(const testCtx *const p_ctx) { i, testUtilEscape(data[i].data, length, escaped, sizeof(escaped)), testUtilErrorName(data[i].ret), symbol->width, symbol->errtxt, data[i].comment); } else { + assert_zero(strcmp(symbol->errtxt, data[i].expected), "i:%d strcmp(%s, %s) != 0 (width %d)\n", i, symbol->errtxt, data[i].expected, symbol->width); if (ret < ZINT_ERROR) { assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", i, symbol->width, data[i].expected_width, data[i].data); + + if (do_bwipp && testUtilCanBwipp(i, symbol, -1, -1, -1, debug)) { + char modules_dump[4096]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilBwipp(i, symbol, -1, -1, -1, data[i].data, length, NULL, cmp_buf, sizeof(cmp_buf), NULL); + assert_zero(ret, "i:%d %s testUtilBwipp ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilBwippCmp(symbol, cmp_msg, cmp_buf, modules_dump); + assert_zero(ret, "i:%d %s testUtilBwippCmp %d != 0 %s\n actual: %s\nexpected: %s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_buf, modules_dump); + } + if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data[i].data, length, debug)) { + int cmp_len, ret_len; + char modules_dump[4096]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, cmp_buf, sizeof(cmp_buf), &cmp_len); + assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + + ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length, NULL /*primary*/, escaped, &ret_len); + assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n", + i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len, escaped); + } } - assert_zero(strcmp(symbol->errtxt, data[i].expected), "i:%d strcmp(%s, %s) != 0\n", i, symbol->errtxt, data[i].expected); } ZBarcode_Delete(symbol); diff --git a/backend/tests/testcommon.c b/backend/tests/testcommon.c index 0ca34ef2..a7bf55e1 100644 --- a/backend/tests/testcommon.c +++ b/backend/tests/testcommon.c @@ -2505,8 +2505,17 @@ static char *testUtilBwippEscape(char *bwipp_data, int bwipp_data_size, const ch sprintf(b, "^%03d", val); b += 4; } else { - if (d + 1 < de && *(d + 1) >= 'A' && *(d + 1) <= 'C') { + if (d + 1 < de && ((*(d + 1) >= 'A' && *(d + 1) <= 'C') || *(d + 1) == '1')) { d++; + if (*d == '1') { + if (b + 5 >= be) { + fprintf(stderr, "testUtilBwippEscape: FNC1 bwipp_data buffer full (%d)\n", bwipp_data_size); + return NULL; + } + strcpy(b, "^FNC1"); + b += 5; + *parsefnc = 1; + } } else { if (b + 8 >= be) { fprintf(stderr, "testUtilBwippEscape: loop bwipp_data buffer full (%d)\n", bwipp_data_size); @@ -3960,9 +3969,18 @@ int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, in int j = 0; for (i = 0; i < expected_len; i++) { if (escaped[i] == '\\' && i + 2 < expected_len && escaped[i + 1] == '^' - && ((escaped[i + 2] >= 'A' && escaped[i + 2] <= 'C') || escaped[i + 2] == '^')) { + && ((escaped[i + 2] >= 'A' && escaped[i + 2] <= 'C') || escaped[i + 2] == '1' + || escaped[i + 2] == '^')) { if (escaped[i + 2] != '^') { i += 2; + if (escaped[i] == '1') { + /* FNC1 in 1st position treated as GS1 and in 2nd position AIM, neither transmitted */ + if (j > 2 || (j == 1 && !(z_isupper(escaped[0]) || z_islower(escaped[0]))) + /* TODO: following exception only valid if in Code Set C */ + || (j == 2 && !(z_isdigit(escaped[0]) && z_isdigit(escaped[1])))) { + escaped[j++] = 29; /* GS */ + } + } } else { escaped[j++] = escaped[i++]; escaped[j++] = escaped[i++]; diff --git a/backend/tests/tools/bwipp_dump.ps.tar.xz b/backend/tests/tools/bwipp_dump.ps.tar.xz index 7d163eb6..37dde529 100644 Binary files a/backend/tests/tools/bwipp_dump.ps.tar.xz and b/backend/tests/tools/bwipp_dump.ps.tar.xz differ diff --git a/backend/tests/tools/run_bwipp_tests.sh b/backend/tests/tools/run_bwipp_tests.sh index 421fef6e..0bae754f 100755 --- a/backend/tests/tools/run_bwipp_tests.sh +++ b/backend/tests/tools/run_bwipp_tests.sh @@ -1,5 +1,6 @@ #!/bin/bash -# Copyright (C) 2020 - 2021 Robin Stuart +# Copyright (C) 2021-2024 Robin Stuart +# SPDX-License-Identifier: BSD-3-Clause # vim: set ts=4 sw=4 et : set -e @@ -28,6 +29,8 @@ run_bwipp_test "test_code1" "encode" run_bwipp_test "test_code1" "encode_segs" run_bwipp_test "test_code1" "fuzz" run_bwipp_test "test_code128" "input" +run_bwipp_test "test_code128" "gs1_128_input" +run_bwipp_test "test_code128" "hibc_input" run_bwipp_test "test_code128" "encode" run_bwipp_test "test_code16k" "input" run_bwipp_test "test_code16k" "encode" diff --git a/backend/tests/tools/run_zxingcpp_tests.sh b/backend/tests/tools/run_zxingcpp_tests.sh index be1a2049..73bb1e5f 100755 --- a/backend/tests/tools/run_zxingcpp_tests.sh +++ b/backend/tests/tools/run_zxingcpp_tests.sh @@ -1,5 +1,6 @@ #!/bin/bash -# Copyright (C) 2021-2022 Robin Stuart +# Copyright (C) 2021-2024 Robin Stuart +# SPDX-License-Identifier: BSD-3-Clause # vim: set ts=4 sw=4 et : set -e @@ -23,6 +24,8 @@ run_zxingcpp_test "test_codablock" "encode" run_zxingcpp_test "test_codablock" "fuzz" run_zxingcpp_test "test_code" "encode" run_zxingcpp_test "test_code128" "input" +run_zxingcpp_test "test_code128" "gs1_128_input" +run_zxingcpp_test "test_code128" "hibc_input" run_zxingcpp_test "test_code128" "encode" run_zxingcpp_test "test_code16k" "input" run_zxingcpp_test "test_code16k" "encode" diff --git a/backend/vector.c b/backend/vector.c index b95f4d54..2ac51cf2 100644 --- a/backend/vector.c +++ b/backend/vector.c @@ -1,7 +1,7 @@ /* vector.c - Creates vector image objects */ /* libzint - the open source barcode library - Copyright (C) 2018-2023 Robin Stuart + Copyright (C) 2018-2024 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -42,8 +42,7 @@ static int vector_add_rect(struct zint_symbol *symbol, const float x, const floa const float height, struct zint_vector_rect **last_rect) { struct zint_vector_rect *rect; - rect = (struct zint_vector_rect *) malloc(sizeof(struct zint_vector_rect)); - if (!rect) { + if (!(rect = (struct zint_vector_rect *) malloc(sizeof(struct zint_vector_rect)))) { strcpy(symbol->errtxt, "691: Insufficient memory for vector rectangle"); return 0; } @@ -69,8 +68,7 @@ static int vector_add_hexagon(struct zint_symbol *symbol, const float x, const f const float diameter, struct zint_vector_hexagon **last_hexagon) { struct zint_vector_hexagon *hexagon; - hexagon = (struct zint_vector_hexagon *) malloc(sizeof(struct zint_vector_hexagon)); - if (!hexagon) { + if (!(hexagon = (struct zint_vector_hexagon *) malloc(sizeof(struct zint_vector_hexagon)))) { strcpy(symbol->errtxt, "692: Insufficient memory for vector hexagon"); return 0; } @@ -94,8 +92,7 @@ static int vector_add_circle(struct zint_symbol *symbol, const float x, const fl const float width, const int colour, struct zint_vector_circle **last_circle) { struct zint_vector_circle *circle; - circle = (struct zint_vector_circle *) malloc(sizeof(struct zint_vector_circle)); - if (!circle) { + if (!(circle = (struct zint_vector_circle *) malloc(sizeof(struct zint_vector_circle)))) { strcpy(symbol->errtxt, "693: Insufficient memory for vector circle"); return 0; } @@ -121,8 +118,7 @@ static int vector_add_string(struct zint_symbol *symbol, const unsigned char *te struct zint_vector_string **last_string) { struct zint_vector_string *string; - string = (struct zint_vector_string *) malloc(sizeof(struct zint_vector_string)); - if (!string) { + if (!(string = (struct zint_vector_string *) malloc(sizeof(struct zint_vector_string)))) { strcpy(symbol->errtxt, "694: Insufficient memory for vector string"); return 0; } @@ -134,8 +130,7 @@ static int vector_add_string(struct zint_symbol *symbol, const unsigned char *te string->length = length == -1 ? (int) ustrlen(text) : length; string->rotation = 0; string->halign = halign; - string->text = (unsigned char *) malloc(string->length + 1); - if (!string->text) { + if (!(string->text = (unsigned char *) malloc(string->length + 1))) { free(string); strcpy(symbol->errtxt, "695: Insufficient memory for vector string text"); return 0; @@ -449,8 +444,7 @@ INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_ } /* Allocate memory */ - vector = symbol->vector = (struct zint_vector *) malloc(sizeof(struct zint_vector)); - if (!vector) { + if (!(vector = symbol->vector = (struct zint_vector *) malloc(sizeof(struct zint_vector)))) { strcpy(symbol->errtxt, "696: Insufficient memory for vector header"); return ZINT_ERROR_MEMORY; } diff --git a/docs/README b/docs/README index 9bf3b7be..37c3afac 100644 --- a/docs/README +++ b/docs/README @@ -1,11 +1,11 @@ -% docs/README 2024-06-27 +% docs/README 2024-09-03 For generation of "docs/manual.pdf" and "docs/manual.txt" from "manual.pmd" using a recent version of pandoc On Ubuntu/Debian (tested on Ubuntu 22.04) - wget https://github.com/jgm/pandoc/releases/download/3.2.1/pandoc-3.2.1-1-amd64.deb - sudo dpkg -i pandoc-3.2.1-1-amd64.deb + wget https://github.com/jgm/pandoc/releases/download/3.3/pandoc-3.3-1-amd64.deb + sudo dpkg -i pandoc-3.3-1-amd64.deb sudo apt install python3-pip pip install pandoc-tablenos --user export PATH=~/.local/bin:"$PATH" @@ -20,9 +20,9 @@ On Ubuntu/Debian (tested on Ubuntu 22.04) On Fedora (tested on Fedora Linux 38 (Workstation Edition)) - wget https://github.com/jgm/pandoc/releases/download/3.2.1/pandoc-3.2.1-linux-amd64.tar.gz - tar xf pandoc-3.2.1-linux-amd64.tar.gz - sudo mv -i pandoc-3.2.1/bin/pandoc /usr/local/bin + wget https://github.com/jgm/pandoc/releases/download/3.3/pandoc-3.3-linux-amd64.tar.gz + tar xf pandoc-3.3-linux-amd64.tar.gz + sudo mv -i pandoc-3.3/bin/pandoc /usr/local/bin sudo dnf install python3-pip pip install pandoc-tablenos --user export PATH=~/.local/bin:"$PATH" diff --git a/docs/manual.html b/docs/manual.html index b1c25918..68ab1f43 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -332,7 +332,7 @@

Zint Barcode Generator and Zint Barcode Studio User Manual

Version 2.13.0.9

-

June 2024

+

September 2024