diff --git a/ChangeLog b/ChangeLog index 94f1d9c1..75fae057 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -Version 2.16.0.9 (dev) not released yet (2026-04-18) +Version 2.16.0.9 (dev) not released yet (2026-04-22) ==================================================== **Incompatible changes** @@ -35,6 +35,7 @@ Changes (`option_3 = DM_C40_START`) to allow forcing of initial encodation for given no. (`option_1`) of initial characters, with 0 meaning all - DATAMATRIX: add manual FNC1 support +- AUSPOST: support Null FCC (DPID all zeroes) Bugs ---- diff --git a/backend/2of5.c b/backend/2of5.c index dd629c2c..8c9e9f1e 100644 --- a/backend/2of5.c +++ b/backend/2of5.c @@ -90,10 +90,12 @@ static int c25_common(struct zint_symbol *symbol, const unsigned char source[], d += start_length; if (is_matrix) { + /* Standard, Data Logic */ for (i = 0; i < length; i++, d += 6) { memcpy(d, C25MatrixTable[local_source[i] - '0'], 6); } } else { + /* IATA, Industrial */ for (i = 0; i < length; i++, d += 10) { memcpy(d, C25IndustTable[local_source[i] - '0'], 10); } diff --git a/backend/2of5inter.c b/backend/2of5inter.c index 7873197c..55398b53 100644 --- a/backend/2of5inter.c +++ b/backend/2of5inter.c @@ -36,15 +36,15 @@ #include "common.h" #include "gs1.h" -static const char C25InterTable[10][5] = { - {'1','1','3','3','1'}, {'3','1','1','1','3'}, {'1','3','1','1','3'}, {'3','3','1','1','1'}, - {'1','1','3','1','3'}, {'3','1','3','1','1'}, {'1','3','3','1','1'}, {'1','1','1','3','3'}, - {'3','1','1','3','1'}, {'1','3','1','3','1'} -}; - /* Common to Interleaved, and to ITF-14, DP Leitcode, DP Identcode */ INTERNAL int zint_c25_inter_common(struct zint_symbol *symbol, unsigned char source[], int length, const int checkdigit_option, const int dont_set_height) { + 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 const char stop_start[5] = { '3','1','1','1','1' }; /* 1st 3 stop, last 4 start */ int i, j, error_number = 0; char dest[638]; /* 4 + (125 + 1) * 5 + 3 + 1 = 638 */ char *d = dest; @@ -77,7 +77,7 @@ INTERNAL int zint_c25_inter_common(struct zint_symbol *symbol, unsigned char sou } /* Start character */ - memcpy(d, "1111", 4); + memcpy(d, stop_start + 1, 4); d += 4; for (i = 0; i < length; i += 2) { @@ -93,7 +93,7 @@ INTERNAL int zint_c25_inter_common(struct zint_symbol *symbol, unsigned char sou } /* Stop character */ - memcpy(d, "311", 3); + memcpy(d, stop_start, 3); d += 3; z_expand(symbol, dest, (int) (d - dest)); diff --git a/backend/auspost.c b/backend/auspost.c index 2d2b562d..fb679ddb 100644 --- a/backend/auspost.c +++ b/backend/auspost.c @@ -33,36 +33,45 @@ static const char AusGDSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz #"; #define AUS_GDSET_F (IS_NUM_F | IS_UPR_F | IS_LWR_F | IS_SPC_F | IS_HSH_F) +/* The contents of data_pattern conform to the following standard: + 0 = Tracker, Ascender and Descender + 1 = Tracker and Ascender + 2 = Tracker and Descender + 3 = Tracker only */ + +/* N Encoding Table (numeric) */ 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'} + { 0,0 }, { 0,1 }, { 0,2 }, { 1,0 }, { 1,1 }, { 1,2 }, { 2,0 }, { 2,1 }, { 2,2 }, { 3,0 } }; +/* C Encoding Table (GDSET) */ 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'} + { 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 } }; +/* Bar to Decimal Conversion Table (Reed-Solomon) */ 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'} + { 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 @@ -71,7 +80,7 @@ static const char AusBarTable[64][3] = { #include "reedsol.h" static unsigned char aus_convert_pattern(const char data, const int shift) { - return (data - '0') << shift; + return data << shift; } /* Adds Reed-Solomon error correction to auspost */ @@ -104,15 +113,15 @@ INTERNAL int zint_daft_set_height(struct zint_symbol *symbol, const float min_he /* Handles Australia Posts's 4 State Codes */ INTERNAL int zint_auspost(struct zint_symbol *symbol, unsigned char source[], int length) { - /* Customer Standard Barcode, Barcode 2 or Barcode 3 system determined automatically - (i.e. the FCC doesn't need to be specified by the user) dependent + /* Standard Customer Barcode, Customer Barcode 2 or Customer Barcode 3 system determined automatically + (i.e. the Format Control Code (FCC) doesn't need to be specified by the user) dependent on the length of the input string */ + static const unsigned char fccs[7][2] = { + /* Null Standard Barcode 2 Barcode 3 Reply Route Redirect */ + { '0','0' }, { '1','1' }, { '5','9' }, { '6','2' }, { '4','5' }, { '8','7' }, { '9','2' } + }; + static const char start_stop[2] = { 1,3 }; - /* The contents of data_pattern conform to the following standard: - 0 = Tracker, Ascender and Descender - 1 = Tracker and Ascender - 2 = Tracker and Descender - 3 = Tracker only */ int i; int error_number; int writer; @@ -121,7 +130,7 @@ INTERNAL int zint_auspost(struct zint_symbol *symbol, unsigned char source[], in char data_pattern[200]; char *d = data_pattern; - unsigned char fcc[2] = {0}; /* Suppress clang-tidy warning clang-analyzer-core.UndefinedBinaryOperatorResult */ + int fcc_idx; /* Index into `fccs[]` */ unsigned char local_source[30]; int zeroes = 0; const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS; @@ -150,13 +159,13 @@ INTERNAL int zint_auspost(struct zint_symbol *symbol, unsigned char source[], in /* Format control code (FCC) */ switch (length) { case 8: - memcpy(fcc, "11", 2); + fcc_idx = 1; /* FCC 11 Standard Customer */ break; case 13: - memcpy(fcc, "59", 2); + fcc_idx = 2; /* FCC 59 Customer 2 */ break; case 16: - memcpy(fcc, "59", 2); + fcc_idx = 2; /* FCC 59 Customer 2 */ if ((i = z_not_sane(NEON_F, source, length))) { return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 402, "Invalid character at position %d in input (digits only for FCC 59 length 16)", @@ -164,10 +173,10 @@ INTERNAL int zint_auspost(struct zint_symbol *symbol, unsigned char source[], in } break; case 18: - memcpy(fcc, "62", 2); + fcc_idx = 3; /* FCC 62 Customer 3 */ break; case 23: - memcpy(fcc, "62", 2); + fcc_idx = 3; /* FCC 62 Customer 3 */ if ((i = z_not_sane(NEON_F, source, length))) { return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 406, "Invalid character at position %d in input (digits only for FCC 62 length 23)", @@ -175,12 +184,13 @@ INTERNAL int zint_auspost(struct zint_symbol *symbol, unsigned char source[], in } break; } - } else { - switch (symbol->symbology) { - case BARCODE_AUSREPLY: memcpy(fcc, "45", 2); break; - case BARCODE_AUSROUTE: memcpy(fcc, "87", 2); break; - case BARCODE_AUSREDIRECT: memcpy(fcc, "92", 2); break; + /* Check if DPID all zeros (Null) */ + for (i = 0; i < 8 && source[i] == '0'; i++); + if (i == 8) { + fcc_idx = 0; /* Null */ } + } else { + fcc_idx = symbol->symbology - BARCODE_AUSREPLY + 4; /* 4 (FCC 45), 5 (FCC 87) or 6 (FCC 92) */ /* Add leading zeros as required */ zeroes = 8 - length; @@ -188,7 +198,7 @@ INTERNAL int zint_auspost(struct zint_symbol *symbol, unsigned char source[], in } if (symbol->debug & ZINT_DEBUG_PRINT) { - printf("AUSPOST FCC: %.2s\n", fcc); + printf("AUSPOST FCC: %.2s\n", fccs[fcc_idx]); } memcpy(local_source + zeroes, source, length); @@ -201,12 +211,12 @@ INTERNAL int zint_auspost(struct zint_symbol *symbol, unsigned char source[], in } /* Start character */ - memcpy(d, "13", 2); + memcpy(d, start_stop, 2); d += 2; /* Encode the FCC */ for (reader = 0; reader < 2; reader++, d += 2) { - memcpy(d, AusNTable[fcc[reader] - '0'], 2); + memcpy(d, AusNTable[fccs[fcc_idx][reader] - '0'], 2); } /* Delivery Point Identifier (DPID) */ @@ -233,7 +243,7 @@ INTERNAL int zint_auspost(struct zint_symbol *symbol, unsigned char source[], in case 22: case 37: case 52: - *d++ = '3'; + *d++ = 3; break; default: break; @@ -243,22 +253,22 @@ INTERNAL int zint_auspost(struct zint_symbol *symbol, unsigned char source[], in d = aus_rs_error(data_pattern, d); /* Stop character */ - memcpy(d, "13", 2); + memcpy(d, start_stop, 2); d += 2; /* Turn the symbol into a bar pattern ready for plotting */ - writer = 0; h = (int) (d - data_pattern); - for (loopey = 0; loopey < h; loopey++) { - if (data_pattern[loopey] == '1' || data_pattern[loopey] == '0') { + for (loopey = 0, writer = 0; loopey < h; loopey++, writer += 2) { + if (data_pattern[loopey] == 1 || data_pattern[loopey] == 0) { z_set_module(symbol, 0, writer); } z_set_module(symbol, 1, writer); - if (data_pattern[loopey] == '2' || data_pattern[loopey] == '0') { + if (data_pattern[loopey] == 2 || data_pattern[loopey] == 0) { z_set_module(symbol, 2, writer); } - writer += 2; } + symbol->rows = 3; /* Not stackable */ + symbol->width = writer - 1; if (symbol->output_options & COMPLIANT_HEIGHT) { /* Australia Post Customer Barcoding Technical Specifications (Revised Aug 2012) Dimensions, placement and @@ -278,10 +288,8 @@ INTERNAL int zint_auspost(struct zint_symbol *symbol, unsigned char source[], in symbol->row_height[1] = 2.0f; error_number = zint_daft_set_height(symbol, 0.0f, 0.0f); } - symbol->rows = 3; /* Not stackable */ - symbol->width = writer - 1; - if (content_segs && z_ct_cpy_cat(symbol, fcc, 2, '\xFF' /*separator (none)*/, local_source, length)) { + if (content_segs && z_ct_cpy_cat(symbol, fccs[fcc_idx], 2, '\xFF' /*separator (none)*/, local_source, length)) { return ZINT_ERROR_MEMORY; /* `z_ct_cpy_cat()` only fails with OOM */ } diff --git a/backend/bc412.c b/backend/bc412.c index 1e3c8e36..2265c8ef 100644 --- a/backend/bc412.c +++ b/backend/bc412.c @@ -66,6 +66,7 @@ static const char BC412Table[35][8] = { }; INTERNAL int zint_bc412(struct zint_symbol *symbol, unsigned char source[], int length) { /* IBM BC412 */ + static const char stop_start[4] = { '1','1','1','2' }; /* 1st 3 stop, last 2 start */ unsigned char padded_source[20]; int posns[35]; int i, counter_odd = 0, counter_even = 0, check_sum = 0; @@ -119,7 +120,7 @@ INTERNAL int zint_bc412(struct zint_symbol *symbol, unsigned char source[], int posns[1] = check_sum; /* Start character */ - memcpy(d, "12", 2); + memcpy(d, stop_start + 2, 2); d += 2; for (i = 0; i <= length; i++, d += 8) { @@ -127,7 +128,7 @@ INTERNAL int zint_bc412(struct zint_symbol *symbol, unsigned char source[], int } /* Stop character */ - memcpy(d, "111", 3); + memcpy(d, stop_start, 3); d += 3; z_expand(symbol, dest, (int) (d - dest)); diff --git a/backend/channel.c b/backend/channel.c index 0e3995e7..62560ccf 100644 --- a/backend/channel.c +++ b/backend/channel.c @@ -175,7 +175,8 @@ nb0: if (++B[0] <= bmax[0]) goto lb0; /* Channel Code - According to ANSI/AIM BC12-1998 */ INTERNAL int zint_channel(struct zint_symbol *symbol, unsigned char source[], int length) { static const int max_ranges[] = { -1, -1, -1, 26, 292, 3493, 44072, 576688, 7742862 }; - static const unsigned char zeroes_str[] = "0000000"; /* 7 zeroes */ + static const unsigned char zeroes_str[7] = { '0','0','0','0','0','0','0' }; + static const char finder_pattern[9] = { '1','1','1','1','1','1','1','1','1' }; int S[8] = {0}, B[8] = {0}; int target_value; char dest[30]; @@ -233,7 +234,7 @@ INTERNAL int zint_channel(struct zint_symbol *symbol, unsigned char source[], in CHNCHR(channels, target_value, B, S); - memcpy(d, "111111111", 9); /* Finder pattern */ + memcpy(d, finder_pattern, 9); /* Finder pattern */ d += 9; for (i = 8 - channels; i < 8; i++) { *d++ = z_itoc(S[i]); diff --git a/backend/codablock.c b/backend/codablock.c index ff7fe429..43beae8f 100644 --- a/backend/codablock.c +++ b/backend/codablock.c @@ -535,6 +535,7 @@ static void SumASCII(uchar **ppOutPos, const int Sum, const int CharacterSet) { /* Main function called by zint framework */ INTERNAL int zint_codablockf(struct zint_symbol *symbol, unsigned char source[], int length) { + static const char stop[7] = { '2','3','3','1','1','1','2' }; /* Stop character */ int charCur, dataLength; int error_number; int rows, columns, useColumns; @@ -859,7 +860,7 @@ INTERNAL int zint_codablockf(struct zint_symbol *symbol, unsigned char source[], for (c = 0; c < columns - 1; c++, d += 6) { memcpy(d, zint_C128Table[pOutput[rc + c]], 6); } - memcpy(d, "2331112", 7); /* Stop character (106, not in `zint_C128Table[]`) */ + memcpy(d, stop, 7); /* Stop character (106, not in `zint_C128Table[]`) */ d += 7; z_expand(symbol, dest, (int) (d - dest)); } diff --git a/backend/code.c b/backend/code.c index af46fff3..46ae849b 100644 --- a/backend/code.c +++ b/backend/code.c @@ -1,4 +1,4 @@ -/* code.c - Handles Code 39, 39+, 93 and VIN */ +/* code.c - Handles Code 39 (incl. LOGMARS & HIBC), Extended Code 39 (39+), Code 93 and VIN */ /* libzint - the open source barcode library Copyright (C) 2008-2026 Robin Stuart @@ -68,56 +68,6 @@ static const char C39Table[43 + 1][10] = { {'1','2','1','1','2','1','2','1','1','1'} /* Start character (full 10), Stop character (first 9) */ }; -/* Encoding the full ASCII character set in Code 39 (ISO/IEC 16388:2007 Table A.2) */ -static const char EC39Ctrl[128][2] = { - {'%','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'} -}; - -/* Code 93 ANSI/AIM BC5-1995 Table 3 */ -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'} -}; - -/* Code 93 ANSI/AIM BC5-1995 Table 2 */ -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 39 */ INTERNAL int zint_code39(struct zint_symbol *symbol, unsigned char source[], int length) { int i; @@ -239,6 +189,22 @@ INTERNAL int zint_code39(struct zint_symbol *symbol, unsigned char source[], int /* Extended Code 39 - ISO/IEC 16388:2007 Annex A */ INTERNAL int zint_excode39(struct zint_symbol *symbol, unsigned char source[], int length) { + /* Encoding the full ASCII character set in Code 39 (ISO/IEC 16388:2007 Table A.2) */ + static const char EC39Ctrl[128][2] = { + {'%','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'} + }; int i; unsigned char buffer[86 * 2 + 1] = {0}; unsigned char *b = buffer; @@ -308,11 +274,42 @@ INTERNAL int zint_excode39(struct zint_symbol *symbol, unsigned char source[], i /* Code 93 is an advancement on Code 39 and the definition is a lot tighter */ INTERNAL int zint_code93(struct zint_symbol *symbol, unsigned char source[], int length) { + /* Code 93 ANSI/AIM BC5-1995 Table 2 */ + 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 93 ANSI/AIM BC5-1995 Table 3 */ + 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 start_stop[7] = { '1','1','1','1','4','1','1' }; /* 1st 6 start, all 7 stop */ /* SILVER includes the extra characters a, b, c and d to represent Code 93 specific shift characters 1, 2, 3 and 4 respectively. These characters are never used by `zint_code39()` and `excode39()` */ - int i; int h, weight, c, k, error_number = 0; int values[125]; /* 123 + 2 (Checks) */ @@ -383,7 +380,7 @@ INTERNAL int zint_code93(struct zint_symbol *symbol, unsigned char source[], int } /* Start character */ - memcpy(d, "111141", 6); + memcpy(d, start_stop, 6); d += 6; for (i = 0; i < h; i++, d += 6) { @@ -391,7 +388,7 @@ INTERNAL int zint_code93(struct zint_symbol *symbol, unsigned char source[], int } /* Stop character */ - memcpy(d, "1111411", 7); + memcpy(d, start_stop, 7); d += 7; z_expand(symbol, dest, (int) (d - dest)); diff --git a/backend/code128.c b/backend/code128.c index 18df937c..b9229380 100644 --- a/backend/code128.c +++ b/backend/code128.c @@ -158,7 +158,8 @@ static int c128_cost(const unsigned char source[], const int length, const int i const unsigned char ch = source[i]; const char *const latch_len = prior_cset == 0 ? c128_start_latch_len[start_idx] : c128_latch_len[prior_cset]; const int is_fnc1 = ch == '\x1D' && fncs[i]; - const int can_c = is_fnc1 || (z_isdigit(ch) && z_isdigit(source[i + 1])); /* Assumes source NUL-terminated */ + const int can_c = is_fnc1 ? i != 1 || !z_isalpha(source[0]) /* Don't use C if FNC1 in 2nd position after alpha */ + : (z_isdigit(ch) && z_isdigit(source[i + 1])); /* Assumes source NUL-terminated */ const int manual_c_fail = !can_c && manuals[i] == C128_C0; /* C requested but not doable */ int min_cost = 999999; /* Max possible cost less than 2 * 256 */ int min_mode = 0; @@ -247,14 +248,6 @@ static int c128_set_values(const unsigned char source[], const int length, const *p_first_cset = modes[0][0]; } - /* Make sure FNC1 in 2nd position after single alpha does not switch modes before FNC1 */ - if (length > 1 && !fncs[0] && fncs[1] && z_isalpha(source[0])) { - const int mode = modes[0][0]; - if (mode == (mode & 0x0F) && mode != modes[1][mode]) { - modes[1][mode] = mode; - } - } - /* Output codewords into `values` */ for (i = 0; i < length; i++) { const unsigned char ch = source[i]; @@ -309,6 +302,7 @@ static int c128_set_values(const unsigned char source[], const int length, const /* Helper to write out symbol, calculating check digit */ static void c128_expand(struct zint_symbol *symbol, int values[C128_VALUES_MAX], int glyph_count) { + static const char stop[7] = { '2','3','3','1','1','1','2' }; char dest[640]; /* (102 + 1 (check digit)) * 6 + 7 (Stop) = 625 */ char *d = dest; int total_sum; @@ -329,7 +323,7 @@ static void c128_expand(struct zint_symbol *symbol, int values[C128_VALUES_MAX], values[glyph_count++] = total_sum; /* For debug/test */ /* Stop character */ - memcpy(d, "2331112", 7); + memcpy(d, stop, 7); d += 7; values[glyph_count++] = 106; /* For debug/test */ diff --git a/backend/dxfilmedge.c b/backend/dxfilmedge.c index 1b4de78e..ad3e2844 100644 --- a/backend/dxfilmedge.c +++ b/backend/dxfilmedge.c @@ -1,7 +1,7 @@ /* dxfilmedge.c - Handles DX Film Edge symbology */ /* libzint - the open source barcode library - Copyright (C) 2024-2025 Antoine Merino + Copyright (C) 2024-2026 Antoine Merino Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -54,6 +54,7 @@ static int dx_parse_code(struct zint_symbol *symbol, const unsigned char *source, const int length, char *binary_output, int *output_length, int *has_frame_info) { + static const char start_stop[6] = { '1','0','1','0','1','0' }; /* All 6 start, middle 4 stop */ int i; int parity_bit = 0; int dx_code_1 = -1, dx_code_2 = -1, frame_number = -1; @@ -209,7 +210,7 @@ static int dx_parse_code(struct zint_symbol *symbol, const unsigned char *source } /* Build the binary output */ - memcpy(binary_output, "101010", 6); /* Start pattern */ + memcpy(binary_output, start_stop, 6); /* Start pattern */ bp = z_bin_append_posn(dx_code_1, 7, binary_output, 6); binary_output[bp++] = '0'; /* Separator between DX part 1 and DX part 2 */ bp = z_bin_append_posn(dx_code_2, 4, binary_output, bp); @@ -242,7 +243,7 @@ static int dx_parse_code(struct zint_symbol *symbol, const unsigned char *source } binary_output[bp++] = parity_bit ? '1' : '0'; - memcpy(binary_output + bp, "0101", 4); /* Stop pattern */ + memcpy(binary_output + bp, start_stop + 1, 4); /* Stop pattern */ bp += 4; *output_length = bp; diff --git a/backend/gs1.c b/backend/gs1.c index 685b378a..d77136f0 100644 --- a/backend/gs1.c +++ b/backend/gs1.c @@ -1671,9 +1671,14 @@ static void gs1se_gs_caret_sub(const unsigned char *src, const int length, unsig /* Use GS1 Syntax Engine to verify */ static int gs1se_verify(struct zint_symbol *symbol, const unsigned char source[], const int length, unsigned char reduced[], int *p_reduced_length) { + static const char linear_dummies[3][19] = { + { '[','0','1',']','1','2','3','4','5','6','7','8','9','0','1','2','3','1','|' }, /* Normal */ + { '(','0','1',')','1','2','3','4','5','6','7','8','9','0','1','2','3','1','|' }, /* Parens */ + { '^','0','1','1','2','3','4','5','6','7','8','9','0','1','2','3','1','|','^' }, /* Raw/caret */ + }; int i, j; const int primary_len = z_is_composite(symbol->symbology) ? (int) strlen(symbol->primary) : 0; - const int gs1parens_mode = symbol->input_mode & GS1PARENS_MODE; + const int gs1parens_mode = !!(symbol->input_mode & GS1PARENS_MODE); const int gs1raw_mode = !!(symbol->input_mode & GS1RAW_MODE); const int gs1_caret = source[0] == '^'; const int is_digital_link = !primary_len && !gs1_caret && gs1_is_digital_link(source, length); @@ -1742,7 +1747,7 @@ static int gs1se_verify(struct zint_symbol *symbol, const unsigned char source[] } else { /* Just use dummy "01" linear */ if (gs1_caret || gs1raw_mode) { - memcpy(local_source_buf, "^0112345678901231|^", 18 + gs1raw_mode); + memcpy(local_source_buf, linear_dummies[2], 18 + gs1raw_mode); if (gs1_caret) { memcpy(local_source_buf + 18, source, length + 1); /* Include terminating NUL */ } else { @@ -1750,7 +1755,7 @@ static int gs1se_verify(struct zint_symbol *symbol, const unsigned char source[] } local_length += 18 + gs1raw_mode; } else { - memcpy(local_source_buf, gs1parens_mode ? "(01)12345678901231|" : "[01]12345678901231|", 19); + memcpy(local_source_buf, linear_dummies[gs1parens_mode], 19); memcpy(local_source_buf + 19, source, length + 1); /* Include terminating NUL */ local_length += 19; } diff --git a/backend/library.c b/backend/library.c index c8626e8b..48feefb1 100644 --- a/backend/library.c +++ b/backend/library.c @@ -213,13 +213,11 @@ INTERNAL LIB_DECL_FUNC_SRC(zint_codablockf); /* Codablock */ INTERNAL LIB_DECL_FUNC_SRC(zint_nve18); /* NVE-18 */ INTERNAL LIB_DECL_FUNC_SRC(zint_japanpost); /* Japanese Post */ INTERNAL LIB_DECL_FUNC_SRC(zint_koreapost); /* Korea Post */ -INTERNAL LIB_DECL_FUNC_SRC(zint_planet); /* PLANET */ INTERNAL LIB_DECL_FUNC_SEG(zint_micropdf417); /* Micro PDF417 */ INTERNAL LIB_DECL_FUNC_SRC(zint_usps_imail); /* Intelligent Mail (aka USPS OneCode) */ INTERNAL LIB_DECL_FUNC_SRC(zint_plessey); /* Plessey Code */ INTERNAL LIB_DECL_FUNC_SRC(zint_telepen_num); /* Telepen Numeric */ INTERNAL LIB_DECL_FUNC_SRC(zint_itf14); /* ITF-14 */ -INTERNAL LIB_DECL_FUNC_SRC(zint_kix); /* TNT KIX Code */ INTERNAL LIB_DECL_FUNC_SEG(zint_aztec); /* Aztec Code */ INTERNAL LIB_DECL_FUNC_SRC(zint_daft); /* DAFT Code */ INTERNAL LIB_DECL_FUNC_SRC(zint_dpd); /* DPD Code */ @@ -531,9 +529,9 @@ static const barcode_src_func_t barcode_src_funcs[BARCODE_LAST + 1] = { NULL, zint_auspost, zint_auspost, zint_auspost, zint_eanx, /*65-69*/ zint_rm4scc, NULL, zint_ean14, zint_vin, zint_codablockf, /*70-74*/ zint_nve18, zint_japanpost, zint_koreapost, NULL, zint_dbar_omn, /*75-79*/ - zint_dbar_omn, zint_dbar_exp, zint_planet, NULL, NULL, /*80-84*/ + zint_dbar_omn, zint_dbar_exp, zint_postnet, NULL, NULL, /*80-84*/ zint_usps_imail, zint_plessey, zint_telepen_num, NULL, zint_itf14, /*85-89*/ - zint_kix, NULL, NULL, zint_daft, NULL, /*90-94*/ + zint_rm4scc, NULL, NULL, zint_daft, NULL, /*90-94*/ NULL, zint_dpd, zint_microqr, NULL, NULL, /*95-99*/ NULL, NULL, NULL, NULL, NULL, /*100-104*/ NULL, NULL, NULL, NULL, NULL, /*105-109*/ @@ -1746,6 +1744,7 @@ int ZBarcode_BarcodeName(int symbol_id, char name[32]) { "CHANNEL", "CODEONE", "GRIDMATRIX", "UPNQR", "ULTRA", /*140-144*/ "RMQR", "BC412", "DXFILMEDGE", "EAN8_CC", "EAN13_CC", /*145-149*/ }; + static const char barcode_prefix[8] = { 'B','A','R','C','O','D','E','_' }; name[0] = '\0'; @@ -1754,7 +1753,7 @@ int ZBarcode_BarcodeName(int symbol_id, char name[32]) { } assert(symbol_id >= 0 && symbol_id < ARRAY_SIZE(names) && names[symbol_id][0]); - memcpy(name, "BARCODE_", 8); + memcpy(name, barcode_prefix, 8); memcpy(name + 8, names[symbol_id], strlen(names[symbol_id]) + 1); /* Include terminating NUL */ return 0; diff --git a/backend/mailmark.c b/backend/mailmark.c index cc91a4e3..b6cb420d 100644 --- a/backend/mailmark.c +++ b/backend/mailmark.c @@ -514,6 +514,7 @@ INTERNAL int zint_datamatrix(struct zint_symbol *symbol, struct zint_seg segs[], /* https://www.royalmailtechnical.com/rmt_docs/User_Guides_2021/Mailmark_Barcode_definition_document_20210215.pdf */ INTERNAL int zint_mailmark_2d(struct zint_symbol *symbol, unsigned char source[], int length) { static const char spaces[9] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; + static const char jgb_prefix[4] = { 'J','G','B',' ' }; unsigned char local_source[90 + 1]; char postcode[10]; int i; @@ -531,11 +532,11 @@ INTERNAL int zint_mailmark_2d(struct zint_symbol *symbol, unsigned char source[] /* Add prefix if missing */ memcpy(local_source, source, 4); z_to_upper(local_source, 3); - if (memcmp(local_source, "JGB ", 4) != 0) { + if (memcmp(local_source, jgb_prefix, 4) != 0) { if (length > 86) { return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 861, "Input length %d too long (maximum 86)", length); } - memcpy(local_source, "JGB ", 4); + memcpy(local_source, jgb_prefix, 4); memcpy(local_source + 4, source, length); length += 4; } else { diff --git a/backend/plessey.c b/backend/plessey.c index 9b411ba9..8fa5f75f 100644 --- a/backend/plessey.c +++ b/backend/plessey.c @@ -54,10 +54,13 @@ static const char MSITable[10][8] = { /* Not MSI/Plessey but the older Plessey standard */ INTERNAL int zint_plessey(struct zint_symbol *symbol, unsigned char source[], int length) { + static const char grid[9] = { 1, 1, 1, 1, 0, 1, 0, 0, 1 }; + static const char start[8] = { '3','1','3','1','1','3','3','1' }; + static const char stop[9] = { '3','3','1','3','1','1','3','1','3' }; + static const char checks[3] = { '1','3','1' }; /* Case 0 1st 2, case 1 2nd 2 */ int i; unsigned char checkptr[67 * 4 + 8] = {0}; - static const char grid[9] = {1, 1, 1, 1, 0, 1, 0, 0, 1}; char dest[570]; /* 8 + 67 * 8 + 2 * 8 + 9 + 1 = 570 */ char *d = dest; unsigned int check_digits = 0; @@ -74,7 +77,7 @@ INTERNAL int zint_plessey(struct zint_symbol *symbol, unsigned char source[], in } /* Start character */ - memcpy(d, "31311331", 8); + memcpy(d, start, 8); d += 8; /* Data area */ @@ -101,11 +104,11 @@ INTERNAL int zint_plessey(struct zint_symbol *symbol, unsigned char source[], in for (i = 0; i < 8; i++) { switch (checkptr[length * 4 + i]) { case 0: - memcpy(d, "13", 2); + memcpy(d, checks, 2); d += 2; break; case 1: - memcpy(d, "31", 2); + memcpy(d, checks + 1, 2); d += 2; check_digits |= (1 << i); break; @@ -113,7 +116,7 @@ INTERNAL int zint_plessey(struct zint_symbol *symbol, unsigned char source[], in } /* Stop character */ - memcpy(d, "331311313", 9); + memcpy(d, stop, 9); d += 9; z_expand(symbol, dest, (int) (d - dest)); @@ -327,6 +330,7 @@ static char *msi_plessey_mod1110(struct zint_symbol *symbol, const unsigned char } INTERNAL int zint_msi_plessey(struct zint_symbol *symbol, unsigned char source[], int length) { + static const char stop_start[3] = { '1','2','1' }; /* All 3 stop, last 2 start */ int error_number = 0; int i; char dest[766]; /* 2 + 92 * 8 + 3 * 8 + 3 + 1 = 766 */ @@ -354,7 +358,7 @@ INTERNAL int zint_msi_plessey(struct zint_symbol *symbol, unsigned char source[] } /* Start character */ - memcpy(d, "21", 2); + memcpy(d, stop_start + 1, 2); d += 2; switch (check_option) { @@ -372,7 +376,7 @@ INTERNAL int zint_msi_plessey(struct zint_symbol *symbol, unsigned char source[] } /* Stop character */ - memcpy(d, "121", 3); + memcpy(d, stop_start, 3); d += 3; z_expand(symbol, dest, (int) (d - dest)); diff --git a/backend/postal.c b/backend/postal.c index 4fd0361b..5962428b 100644 --- a/backend/postal.c +++ b/backend/postal.c @@ -40,54 +40,6 @@ 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][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][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][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][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][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][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][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/CEPNet codes, maintaining ratio */ static int usps_set_height(struct zint_symbol *symbol, const int no_errtxt) { /* USPS Domestic Mail Manual (USPS DMM 300) Jan 8, 2006 (updated 2011) 708.4.2.5 POSTNET Barcode Dimensions and @@ -133,14 +85,26 @@ static int usps_set_height(struct zint_symbol *symbol, const int no_errtxt) { return error_number; } -/* Handles the POSTNET system used for Zip codes in the US */ -/* Also handles Brazilian CEPNet - more information CEPNet e Código Bidimensional Datamatrix 2D (26/05/2021) at +/* Handles the POSTNET system for delivering mail by ZIP codes in the US */ +/* Also handles PLANET, used to tag outgoing/return mail & identify sender */ +/* Also handles Brazilian CEPNet (ZIP-like) - more info CEPNet e Código Bidimensional Datamatrix 2D (26/05/2021) at https://www.correios.com.br/enviar/correspondencia/arquivos/nacional/ guia-tecnico-cepnet-e-2d-triagem-enderecamento-27-04-2021.pdf/view */ -static int postnet_enc(struct zint_symbol *symbol, const unsigned char source[], char *d, const int length) { +INTERNAL int zint_postnet(struct zint_symbol *symbol, unsigned char source[], int length) { + /* For POSTNET/CEPNet 1 is ascender and 0 is tracker, vice versa for PLANET */ + static const char POSTNET_PLANET[10][5] = { + { 1,1,0,0,0 }, { 0,0,0,1,1 }, { 0,0,1,0,1 }, { 0,0,1,1,0 }, { 0,1,0,0,1 }, + { 0,1,0,1,0 }, { 0,1,1,0,0 }, { 1,0,0,0,1 }, { 1,0,0,1,0 }, { 1,0,1,0,0 } + }; + /* Suppress clang-tidy-20 garbage value false positive by initializing (see "vector.c" `vection_add_rect()`) */ + char dest[256] = {0}; /* 5 + 38 * 5 + 5 + 5 + 1 = 206 */ + char *d = dest; + unsigned int loopey, h; + int writer; + int error_number = 0, warn_number; int i, sum, check_digit; - int error_number = 0; + const int ascender = symbol->symbology != BARCODE_PLANET; /* PLANET uses 0 for ascender, 1 for tracker */ const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS; if (length > 38) { @@ -148,11 +112,19 @@ static int postnet_enc(struct zint_symbol *symbol, const unsigned char source[], } if (symbol->symbology == BARCODE_CEPNET) { + /* 5 (area) + 3 (+location within area) */ if (length != 8) { error_number = z_errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 780, "Input length %d wrong (should be 8 digits)", length); } + } else if (symbol->symbology == BARCODE_PLANET) { + /* 2 (delivery/return) + 9 or 11 (identification) */ + if (length != 11 && length != 13) { + error_number = z_errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 478, + "Input length %d is not standard (should be 11 or 13 digits)", length); + } } else { + /* 5 ZIP (area), 9 ZIP+4 (+location within area), 11 ZIP+6 (+delivery point barcode) */ if (length != 5 && length != 9 && length != 11) { error_number = z_errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 479, "Input length %d is not standard (should be 5, 9 or 11 digits)", length); @@ -162,137 +134,53 @@ static int postnet_enc(struct zint_symbol *symbol, const unsigned char source[], return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 481, "Invalid character at position %d in input (digits only)", i); } - sum = 0; /* Start character */ - *d++ = 'L'; + *d++ = ascender; + sum = 0; for (i = 0; i < length; i++, d += 5) { const int val = source[i] - '0'; - memcpy(d, PNTable[val], 5); + memcpy(d, POSTNET_PLANET[val], 5); sum += val; } check_digit = (10 - (sum % 10)) % 10; - memcpy(d, PNTable[check_digit], 5); + memcpy(d, POSTNET_PLANET[check_digit], 5); d += 5; if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit); /* Stop character */ - memcpy(d, "L", 2); /* Include terminating NUL */ + *d++ = ascender; - if (content_segs && z_ct_cpy_cat(symbol, source, length, (char) z_itoc(check_digit), NULL /*cat*/, 0)) { - return ZINT_ERROR_MEMORY; /* `z_ct_cpy_cat()` only fails with OOM */ - } - - return error_number; -} - -/* Puts POSTNET barcodes into the pattern matrix */ -INTERNAL int zint_postnet(struct zint_symbol *symbol, unsigned char source[], int length) { - /* Suppress clang-tidy-20 garbage value false positive by initializing (see "vector.c" `vection_add_rect()`) */ - char height_pattern[256] = {0}; /* 5 + 38 * 5 + 5 + 5 + 1 = 206 */ - unsigned int loopey, h; - int writer; - int error_number, warn_number; - - error_number = postnet_enc(symbol, source, height_pattern, length); - if (error_number >= ZINT_ERROR) { - return error_number; - } - - writer = 0; - h = (int) strlen(height_pattern); - for (loopey = 0; loopey < h; loopey++) { - if (height_pattern[loopey] == 'L') { + h = d - dest; + for (loopey = 0, writer = 0; loopey < h; loopey++, writer += 2) { + if (dest[loopey] == ascender) { z_set_module(symbol, 0, writer); } - z_set_module(symbol, 1, writer); - writer += 2; + z_set_module(symbol, 1, writer); /* Tracker */ } warn_number = usps_set_height(symbol, error_number /*no_errtxt*/); symbol->rows = 2; symbol->width = writer - 1; - return error_number ? error_number : warn_number; -} - -/* Handles the PLANET system used for item tracking in the US */ -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; - const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS; - - if (length > 38) { - return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 482, "Input length %d too long (maximum 38)", length); - } - if (length != 11 && length != 13) { - error_number = z_errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 478, - "Input length %d is not standard (should be 11 or 13 digits)", length); - } - if ((i = z_not_sane(NEON_F, source, length))) { - return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 483, - "Invalid character at position %d in input (digits only)", i); - } - sum = 0; - - /* Start character */ - *d++ = 'L'; - - 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; - memcpy(d, PLTable[check_digit], 5); - d += 5; - - if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit); - - /* Stop character */ - memcpy(d, "L", 2); /* Include terminating NUL */ - if (content_segs && z_ct_cpy_cat(symbol, source, length, (char) z_itoc(check_digit), NULL /*cat*/, 0)) { return ZINT_ERROR_MEMORY; /* `z_ct_cpy_cat()` only fails with OOM */ } - return error_number; -} - -/* Puts PLANET barcodes into the pattern matrix */ -INTERNAL int zint_planet(struct zint_symbol *symbol, unsigned char source[], int length) { - /* Suppress clang-tidy-20 garbage value false positive by initializing (see "vector.c" `vection_add_rect()`) */ - char height_pattern[256] = {0}; /* 5 + 38 * 5 + 5 + 5 + 1 = 206 */ - unsigned int loopey, h; - int writer; - int error_number, warn_number; - - error_number = planet_enc(symbol, source, height_pattern, length); - if (error_number >= ZINT_ERROR) { - return error_number; - } - - writer = 0; - h = (int) strlen(height_pattern); - for (loopey = 0; loopey < h; loopey++) { - if (height_pattern[loopey] == 'L') { - z_set_module(symbol, 0, writer); - } - z_set_module(symbol, 1, writer); - writer += 2; - } - warn_number = usps_set_height(symbol, error_number /*no_errtxt*/); - symbol->rows = 2; - symbol->width = writer - 1; - return error_number ? error_number : warn_number; } /* Korean Postal Authority */ INTERNAL int zint_koreapost(struct zint_symbol *symbol, unsigned char source[], int length) { + 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" } + }; int total, i, check, zeroes, error_number = 0; unsigned char local_source[8]; char dest[80]; @@ -346,6 +234,11 @@ INTERNAL int zint_koreapost(struct zint_symbol *symbol, unsigned char source[], /* The simplest barcode symbology ever! Supported by MS Word, so here it is! glyphs from http://en.wikipedia.org/wiki/Facing_Identification_Mark */ INTERNAL int zint_fim(struct zint_symbol *symbol, unsigned char source[], int length) { + static const char a[9] = { '1','1','1','5','1','5','1','1','1' }; + static const char b[11] = { '1','3','1','1','1','3','1','1','1','3','1' }; + static const char c[11] = { '1','1','1','3','1','3','1','3','1','1','1' }; + static const char d[13] = { '1','1','1','1','1','3','1','3','1','1','1','1','1' }; + static const char e[7] = { '1','3','1','7','1','3','1' }; int error_number = 0; const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS; @@ -357,19 +250,19 @@ INTERNAL int zint_fim(struct zint_symbol *symbol, unsigned char source[], int le switch ((char) source[0]) { case 'A': - z_expand(symbol, "111515111", 9); + z_expand(symbol, a, 9); break; case 'B': - z_expand(symbol, "13111311131", 11); + z_expand(symbol, b, 11); break; case 'C': - z_expand(symbol, "11131313111", 11); + z_expand(symbol, c, 11); break; case 'D': - z_expand(symbol, "1111131311111", 13); + z_expand(symbol, d, 13); break; case 'E': - z_expand(symbol, "1317131", 7); + z_expand(symbol, e, 7); break; default: return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 487, @@ -428,22 +321,57 @@ INTERNAL int zint_daft_set_height(struct zint_symbol *symbol, const float min_he return error_number; } -/* Handles the 4 State barcodes used in the UK by Royal Mail. Returns check_character */ -static int rm4scc_enc(struct zint_symbol *symbol, const int *posns, char *d, const int length) { +/* Helper to expand 4-states into 3 rows, where 0 = Full, 1 = Ascender, 2 = Descender, 3 Tracker (always) */ +static void post_4state(struct zint_symbol *symbol, char *dest, const int length) { + int loopey, writer; + + for (loopey = 0, writer = 0; loopey < length; loopey++, writer += 2) { + if (dest[loopey] == 1 || dest[loopey] == 0) { /* Ascender/full */ + z_set_module(symbol, 0, writer); + } + z_set_module(symbol, 1, writer); /* Tracker */ + if (dest[loopey] == 2 || dest[loopey] == 0) { /* Descender/full */ + z_set_module(symbol, 2, writer); + } + } + symbol->rows = 3; + symbol->width = writer - 1; +} + +/* Used by Royal Mail 4-state (& KIX) - 0 = Full, 1 = Ascender, 2 = Descender, 3 = Tracker */ +static const char RM4KIX[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 } +}; + +/* Handles the 4-state barcodes used in the UK by Royal Mail. Returns check_character */ +static int rm4scc_enc(struct zint_symbol *symbol, const int *const posns, char *const dest, const int length, + int *p_dest_len) { + static const char CheckCharTopBottom[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 } + }; int i; int top, bottom, row, column, check_digit; + char *d = dest; top = 0; bottom = 0; /* Start character */ - *d++ = '1'; + *d++ = 1; /* Ascender */ 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]; + memcpy(d, RM4KIX[p], 4); + top += CheckCharTopBottom[p][0]; + bottom += CheckCharTopBottom[p][1]; } /* Calculate the check digit */ @@ -456,30 +384,40 @@ static int rm4scc_enc(struct zint_symbol *symbol, const int *posns, char *d, con column = 5; } check_digit = (6 * row) + column; - memcpy(d, RoyalTable[check_digit], 4); + memcpy(d, RM4KIX[check_digit], 4); d += 4; if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit); /* Stop character */ - memcpy(d, "0", 2); /* Include terminating NUL */ + *d++ = 0; /* Full */ + + *p_dest_len = d - dest; return KRSET[check_digit]; } -/* Puts RM4SCC into the data matrix */ +/* Royal Mail 4-State Customer Code (RM4SCC) */ +/* Also handles Dutch Post TNT KIX symbols + 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 zint_rm4scc(struct zint_symbol *symbol, unsigned char source[], int length) { int i; - char height_pattern[210]; + char dest[210]; int posns[50]; - int loopey, h; - int writer; + int h; char check_digit; int error_number = 0; const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS; - if (length > 50) { - return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 488, "Input length %d too long (maximum 50)", length); + if (symbol->symbology == BARCODE_KIX) { + if (length > 18) { + return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 490, "Input length %d too long (maximum 18)", length); + } + } else { + if (length > 50) { + return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 488, "Input length %d too long (maximum 50)", length); + } } z_to_upper(source, length); if ((i = z_not_sane_lookup(KRSET, 36, source, length, posns))) { @@ -487,21 +425,20 @@ INTERNAL int zint_rm4scc(struct zint_symbol *symbol, unsigned char source[], int "Invalid character at position %d in input (alphanumerics only)", i); } - check_digit = rm4scc_enc(symbol, posns, height_pattern, length); - - writer = 0; - h = (int) strlen(height_pattern); - for (loopey = 0; loopey < h; loopey++) { - if (height_pattern[loopey] == '1' || height_pattern[loopey] == '0') { - z_set_module(symbol, 0, writer); + /* Encode data */ + if (symbol->symbology == BARCODE_KIX) { + char *d = dest; + for (i = 0; i < length; i++, d += 4) { + memcpy(d, RM4KIX[posns[i]], 4); } - z_set_module(symbol, 1, writer); - if (height_pattern[loopey] == '2' || height_pattern[loopey] == '0') { - z_set_module(symbol, 2, writer); - } - writer += 2; + h = (int) (d - dest); + check_digit = '\xFF'; /* None */ + } else { + check_digit = rm4scc_enc(symbol, posns, dest, length, &h); } + post_4state(symbol, dest, h); + if (symbol->output_options & COMPLIANT_HEIGHT) { /* Royal Mail Know How User's Manual Appendix C: using CBC (https://web.archive.org/web/20120120060743/ @@ -509,6 +446,7 @@ INTERNAL int zint_rm4scc(struct zint_symbol *symbol, unsigned char source[], int Bar pitch and min/maxes same as Mailmark, so using recommendations from Royal Mail Mailmark Barcode Definition Document (15 Sept 2015) Section 3.5.1 */ + /* KIX same */ const float min_height = 6.47952747f; /* (4.22 * 39) / 25.4 */ const float max_height = 10.8062992f; /* (5.84 * 47) / 25.4 */ symbol->row_height[0] = 3.16417313f; /* (1.9 * 42.3) / 25.4 */ @@ -520,8 +458,6 @@ INTERNAL int zint_rm4scc(struct zint_symbol *symbol, unsigned char source[], int symbol->row_height[1] = 2.0f; (void) zint_daft_set_height(symbol, 0.0f, 0.0f); } - symbol->rows = 3; - symbol->width = writer - 1; if (content_segs && z_ct_cpy_cat(symbol, source, length, check_digit, NULL /*cat*/, 0)) { return ZINT_ERROR_MEMORY; /* `z_ct_cpy_cat()` only fails with OOM */ @@ -530,67 +466,6 @@ INTERNAL int zint_rm4scc(struct zint_symbol *symbol, unsigned char source[], int return error_number; } -/* Handles Dutch Post TNT KIX symbols - 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 zint_kix(struct zint_symbol *symbol, unsigned char source[], int length) { - char height_pattern[75]; - char *d = height_pattern; - int posns[18]; - int loopey; - int writer, i, h; - int error_number = 0; - const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS; - - if (length > 18) { - return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 490, "Input length %d too long (maximum 18)", length); - } - z_to_upper(source, length); - if ((i = z_not_sane_lookup(KRSET, 36, source, length, posns))) { - return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 491, - "Invalid character at position %d in input (alphanumerics only)", i); - } - - /* Encode data */ - for (i = 0; i < length; i++, d += 4) { - memcpy(d, RoyalTable[posns[i]], 4); - } - - writer = 0; - h = (int) (d - height_pattern); - for (loopey = 0; loopey < h; loopey++) { - if (height_pattern[loopey] == '1' || height_pattern[loopey] == '0') { - z_set_module(symbol, 0, writer); - } - z_set_module(symbol, 1, writer); - if (height_pattern[loopey] == '2' || height_pattern[loopey] == '0') { - z_set_module(symbol, 2, writer); - } - writer += 2; - } - - if (symbol->output_options & COMPLIANT_HEIGHT) { - /* Dimensions same as RM4SCC */ - const float min_height = 6.47952747f; /* (4.22 * 39) / 25.4 */ - const float max_height = 10.8062992f; /* (5.84 * 47) / 25.4 */ - symbol->row_height[0] = 3.16417313f; /* (1.9 * 42.3) / 25.4 */ - symbol->row_height[1] = 2.16496062f; /* (1.3 * 42.3) / 25.4 */ - /* Note using max X for minimum and min X for maximum */ - error_number = zint_daft_set_height(symbol, min_height, max_height); - } else { - symbol->row_height[0] = 3.0f; - symbol->row_height[1] = 2.0f; - (void) zint_daft_set_height(symbol, 0.0f, 0.0f); - } - symbol->rows = 3; - symbol->width = writer - 1; - - if (content_segs && z_ct_cpy(symbol, source, length)) { - return ZINT_ERROR_MEMORY; /* `z_ct_cpy()` only fails with OOM */ - } - - return error_number; -} /* Handles DAFT Code symbols */ INTERNAL int zint_daft(struct zint_symbol *symbol, unsigned char source[], int length) { @@ -610,17 +485,17 @@ INTERNAL int zint_daft(struct zint_symbol *symbol, unsigned char source[], int l "Invalid character at position %d in input (\"D\", \"A\", \"F\" and \"T\" only)", i); } - writer = 0; - for (loopey = 0; loopey < length; loopey++) { - if (posns[loopey] == 1 || posns[loopey] == 0) { + for (loopey = 0, writer = 0; loopey < length; loopey++, writer += 2) { + if (posns[loopey] == 1 || posns[loopey] == 0) { /* Ascender/full */ z_set_module(symbol, 0, writer); } - z_set_module(symbol, 1, writer); - if (posns[loopey] == 2 || posns[loopey] == 0) { + z_set_module(symbol, 1, writer); /* Tracker */ + if (posns[loopey] == 2 || posns[loopey] == 0) { /* Descender/full */ z_set_module(symbol, 2, writer); } - writer += 2; } + symbol->rows = 3; + symbol->width = writer - 1; /* Allow ratio of tracker to be specified in thousandths */ if (symbol->option_2 >= 50 && symbol->option_2 <= 900) { @@ -637,8 +512,6 @@ INTERNAL int zint_daft(struct zint_symbol *symbol, unsigned char source[], int l /* DAFT generic barcode so no dimensions/height specification */ (void) zint_daft_set_height(symbol, 0.0f, 0.0f); - symbol->rows = 3; - symbol->width = writer - 1; if (content_segs && z_ct_cpy(symbol, source, length)) { return ZINT_ERROR_MEMORY; /* `z_ct_cpy()` only fails with OOM */ @@ -649,6 +522,10 @@ INTERNAL int zint_daft(struct zint_symbol *symbol, unsigned char source[], int l /* Flattermarken - Not really a barcode symbology! */ INTERNAL int zint_flat(struct zint_symbol *symbol, unsigned char source[], int length) { + 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'} + }; int i, error_number = 0; char dest[512]; /* 128 * 4 = 512 */ char *d = dest; @@ -681,10 +558,17 @@ INTERNAL int zint_flat(struct zint_symbol *symbol, unsigned char source[], int l /* Japanese Postal Code (Kasutama Barcode) */ INTERNAL int zint_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; + static const char JapanTable[19][3] = { + { 0,0,3 }, { 0,2,1 }, { 2,0,1 }, { 0,1,2 }, { 0,3,0 }, + { 2,1,0 }, { 1,0,2 }, { 1,2,0 }, { 3,0,0 }, { 0,3,3 }, + { 3,0,3 }, { 2,1,3 }, { 2,3,1 }, { 1,2,3 }, { 3,2,1 }, + { 1,3,2 }, { 3,1,2 }, { 3,3,0 }, { 0,0,0 } + }; + static const char start_stop[3] = { 0,2,0 }; /* 1st 2 chars start, last 2 chars stop */ + int error_number = 0; + char dest[69]; + char *d = dest; + int inter_posn, i, sum, check; char check_char; unsigned char inter[20 + 1]; const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS; @@ -729,7 +613,7 @@ INTERNAL int zint_japanpost(struct zint_symbol *symbol, unsigned char source[], "Input too long, requires too many symbol characters (maximum 20)"); } - memcpy(d, "13", 2); /* Start */ + memcpy(d, start_stop, 2); /* Start */ d += 2; sum = 0; @@ -755,25 +639,11 @@ INTERNAL int zint_japanpost(struct zint_symbol *symbol, unsigned char source[], if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check: %d, char: %c\n", check, check_char); - memcpy(d, "31", 2); /* Stop */ + memcpy(d, start_stop + 1, 2); /* Stop */ d += 2; /* Resolve pattern to 4-state symbols */ - writer = 0; - h = (int) (d - pattern); - for (loopey = 0; loopey < h; loopey++) { - if (pattern[loopey] == '2' || pattern[loopey] == '1') { - z_set_module(symbol, 0, writer); - } - z_set_module(symbol, 1, writer); - if (pattern[loopey] == '3' || pattern[loopey] == '1') { - z_set_module(symbol, 2, writer); - } - writer += 2; - } - - symbol->rows = 3; - symbol->width = writer - 1; + post_4state(symbol, dest, (int) (d - dest)); if (symbol->output_options & COMPLIANT_HEIGHT) { /* Japan Post Zip/Barcode Manual pp.11-12 https://www.post.japanpost.jp/zipcode/zipmanual/p11.html diff --git a/backend/svg.c b/backend/svg.c index 4a36228f..d27c6024 100644 --- a/backend/svg.c +++ b/backend/svg.c @@ -1,7 +1,7 @@ /* svg.c - Scalable Vector Graphics */ /* libzint - the open source barcode library - Copyright (C) 2009-2025 Robin Stuart + Copyright (C) 2009-2026 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -58,33 +58,37 @@ static void svg_pick_colour(const int colour, char colour_code[7]) { /* Convert text to use HTML entity codes */ static void svg_make_html_friendly(const unsigned char *string, char *html_version) { - + static const char gt[4] = { '&','g','t',';' }; + static const char lt[4] = { '&','l','t',';' }; + static const char amp[5] = { '&','a','m','p',';' }; + static const char quot[6] = { '&','q','u','o','t',';' }; + static const char apos[6] = { '&','a','p','o','s',';' }; /* `NOLINT` required due to disconnect between `symbol->text` and vector `string`s which are always <= */ /* NOLINTBEGIN(clang-analyzer-security.ArrayBound) clang-tidy-21 false positive */ for (; *string; string++) { switch (*string) { case '>': - memcpy(html_version, ">", 4); + memcpy(html_version, gt, 4); html_version += 4; break; case '<': - memcpy(html_version, "<", 4); + memcpy(html_version, lt, 4); html_version += 4; break; case '&': - memcpy(html_version, "&", 5); + memcpy(html_version, amp, 5); html_version += 5; break; case '"': - memcpy(html_version, """, 6); + memcpy(html_version, quot, 6); html_version += 6; break; case '\'': - memcpy(html_version, "'", 6); + memcpy(html_version, apos, 6); html_version += 6; break; diff --git a/backend/tests/test_auspost.c b/backend/tests/test_auspost.c index af63bc85..957a3e79 100644 --- a/backend/tests/test_auspost.c +++ b/backend/tests/test_auspost.c @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2020-2025 Robin Stuart + Copyright (C) 2020-2026 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -148,8 +148,8 @@ static void test_hrt(const testCtx *const p_ctx) { assert_nonnull(symbol, "Symbol not created\n"); length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, - -1 /*option_1*/, -1 /*option_2*/, -1 /*option_3*/, data[i].output_options, - data[i].data, -1, debug); + -1 /*option_1*/, -1 /*option_2*/, -1 /*option_3*/, data[i].output_options, + data[i].data, -1, debug); expected_length = (int) strlen(data[i].expected); expected_content_length = (int) strlen(data[i].expected_content); @@ -195,25 +195,29 @@ static void test_input(const testCtx *const p_ctx) { static const struct item data[] = { /* 0*/ { BARCODE_AUSPOST, "12345678", 0, 3, 73, "" }, /* 1*/ { BARCODE_AUSPOST, "1234567A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 405: Invalid character at position 8 in DPID (first 8 characters) (digits only)" }, - /* 2*/ { BARCODE_AUSPOST, "12345678ABcd#", 0, 3, 103, "" }, - /* 3*/ { BARCODE_AUSPOST, "12345678ABcd!", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 404: Invalid character at position 13 in input (alphanumerics, space and \"#\" only)" }, - /* 4*/ { BARCODE_AUSPOST, "12345678ABcd#", 0, 3, 103, "" }, - /* 5*/ { BARCODE_AUSPOST, "1234567890123456", 0, 3, 103, "" }, - /* 6*/ { BARCODE_AUSPOST, "123456789012345A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 402: Invalid character at position 16 in input (digits only for FCC 59 length 16)" }, - /* 7*/ { BARCODE_AUSPOST, "12345678ABCDefgh #", 0, 3, 133, "" }, /* Length 18 */ - /* 8*/ { BARCODE_AUSPOST, "12345678901234567890123", 0, 3, 133, "" }, - /* 9*/ { BARCODE_AUSPOST, "1234567890123456789012A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 406: Invalid character at position 23 in input (digits only for FCC 62 length 23)" }, - /* 10*/ { BARCODE_AUSPOST, "1234567", ZINT_ERROR_TOO_LONG, -1, -1, "Error 401: Input length 7 wrong (8, 13, 16, 18 or 23 characters required)" }, /* No leading zeroes added */ - /* 11*/ { BARCODE_AUSREPLY, "12345678", 0, 3, 73, "" }, - /* 12*/ { BARCODE_AUSREPLY, "1234567", 0, 3, 73, "" }, /* Leading zeroes added */ - /* 13*/ { BARCODE_AUSREPLY, "123456789", ZINT_ERROR_TOO_LONG, -1, -1, "Error 403: Input length 9 too long (maximum 8)" }, - /* 14*/ { BARCODE_AUSROUTE, "123456", 0, 3, 73, "" }, - /* 15*/ { BARCODE_AUSROUTE, "12345", 0, 3, 73, "" }, - /* 16*/ { BARCODE_AUSROUTE, "123456789", ZINT_ERROR_TOO_LONG, -1, -1, "Error 403: Input length 9 too long (maximum 8)" }, - /* 17*/ { BARCODE_AUSREDIRECT, "1234", 0, 3, 73, "" }, - /* 18*/ { BARCODE_AUSREDIRECT, "123", 0, 3, 73, "" }, - /* 19*/ { BARCODE_AUSREDIRECT, "0", 0, 3, 73, "" }, - /* 20*/ { BARCODE_AUSREDIRECT, "123456789", ZINT_ERROR_TOO_LONG, -1, -1, "Error 403: Input length 9 too long (maximum 8)" }, + /* 2*/ { BARCODE_AUSPOST, "0000000A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 405: Invalid character at position 8 in DPID (first 8 characters) (digits only)" }, + /* 3*/ { BARCODE_AUSPOST, "12345678ABcd#", 0, 3, 103, "" }, + /* 4*/ { BARCODE_AUSPOST, "12345678ABcd!", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 404: Invalid character at position 13 in input (alphanumerics, space and \"#\" only)" }, + /* 5*/ { BARCODE_AUSPOST, "00000000ABcd!", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 404: Invalid character at position 13 in input (alphanumerics, space and \"#\" only)" }, + /* 6*/ { BARCODE_AUSPOST, "12345678ABcd#", 0, 3, 103, "" }, + /* 7*/ { BARCODE_AUSPOST, "1234567890123456", 0, 3, 103, "" }, + /* 8*/ { BARCODE_AUSPOST, "123456789012345A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 402: Invalid character at position 16 in input (digits only for FCC 59 length 16)" }, + /* 9*/ { BARCODE_AUSPOST, "000000009012345A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 402: Invalid character at position 16 in input (digits only for FCC 59 length 16)" }, + /* 10*/ { BARCODE_AUSPOST, "12345678ABCDefgh #", 0, 3, 133, "" }, /* Length 18 */ + /* 11*/ { BARCODE_AUSPOST, "12345678901234567890123", 0, 3, 133, "" }, + /* 12*/ { BARCODE_AUSPOST, "1234567890123456789012A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 406: Invalid character at position 23 in input (digits only for FCC 62 length 23)" }, + /* 13*/ { BARCODE_AUSPOST, "0000000090123456789012A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 406: Invalid character at position 23 in input (digits only for FCC 62 length 23)" }, + /* 14*/ { BARCODE_AUSPOST, "1234567", ZINT_ERROR_TOO_LONG, -1, -1, "Error 401: Input length 7 wrong (8, 13, 16, 18 or 23 characters required)" }, /* No leading zeroes added */ + /* 15*/ { BARCODE_AUSREPLY, "12345678", 0, 3, 73, "" }, + /* 16*/ { BARCODE_AUSREPLY, "1234567", 0, 3, 73, "" }, /* Leading zeroes added */ + /* 17*/ { BARCODE_AUSREPLY, "123456789", ZINT_ERROR_TOO_LONG, -1, -1, "Error 403: Input length 9 too long (maximum 8)" }, + /* 18*/ { BARCODE_AUSROUTE, "123456", 0, 3, 73, "" }, + /* 19*/ { BARCODE_AUSROUTE, "12345", 0, 3, 73, "" }, + /* 20*/ { BARCODE_AUSROUTE, "123456789", ZINT_ERROR_TOO_LONG, -1, -1, "Error 403: Input length 9 too long (maximum 8)" }, + /* 21*/ { BARCODE_AUSREDIRECT, "1234", 0, 3, 73, "" }, + /* 22*/ { BARCODE_AUSREDIRECT, "123", 0, 3, 73, "" }, + /* 23*/ { BARCODE_AUSREDIRECT, "0", 0, 3, 73, "" }, + /* 24*/ { BARCODE_AUSREDIRECT, "123456789", ZINT_ERROR_TOO_LONG, -1, -1, "Error 403: Input length 9 too long (maximum 8)" }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; @@ -277,81 +281,108 @@ static void test_encode(const testCtx *const p_ctx) { int expected_rows; int expected_width; + int bwipp_cmp; const char *comment; const char *expected; }; + /* s/\v(\/\*)[ 0-9]*(\*\/)/\=printf("%s%3d%s", submatch(1), (@z+setreg('z',@z+1)), submatch(2))/ | let @z=0: */ static const struct item data[] = { - /* 0*/ { BARCODE_AUSPOST, "96184209", 0, 3, 73, "AusPost Tech Specs Diagram 1; verified manually against TEC-IT", + /* 0*/ { BARCODE_AUSPOST, "96184209", 0, 3, 73, 1, "AusPost Tech Specs Diagram 1; verified manually against TEC-IT", "1000101010100010001010100000101010001010001000001010000010001000001000100" "1010101010101010101010101010101010101010101010101010101010101010101010101" "0000100010000010101010001010000010101010001000101010001000100010000010000" }, - /* 1*/ { BARCODE_AUSPOST, "39549554", 0, 3, 73, "AusPost Guide Figure 3, same; verified manually against TEC-IT", + /* 1*/ { BARCODE_AUSPOST, "39549554", 0, 3, 73, 1, "AusPost Guide Figure 3, same; verified manually against TEC-IT", "1000101010101010001010001010001010001000101000001000101010001010000000100" "1010101010101010101010101010101010101010101010101010101010101010101010101" "0000100010000010001000100000001000100010000000000010001000000000001010000" }, - /* 2*/ { BARCODE_AUSPOST, "56439111ABA 9", 0, 3, 103, "AusPost Guide Figure 4, same; verified manually against TEC-IT", + /* 2*/ { BARCODE_AUSPOST, "56439111ABA 9", 0, 3, 103, 1, "AusPost Guide Figure 4, same; verified manually against TEC-IT", "1000100000101000001010101010001010101010101010101010101010101010100000000000001010100010101010000010100" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000001000100010101000000010001010001000100010101010100010101010100000101000000010001000101010000000000" }, - /* 3*/ { BARCODE_AUSPOST, "3221132412345678", 0, 3, 103, "59 Custom 2 N encoding", + /* 3*/ { BARCODE_AUSPOST, "3221132412345678", 0, 3, 103, 1, "59 Custom 2 N encoding", "1000100000101010100010001010101010101000101010101000101010101000001000100000101000000000001000000000100" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000001000100010101010101000100000101010000010001010001000000010101010001010000010001010101000100000000" }, - /* 4*/ { BARCODE_AUSPOST, "32211324Ab #2", 0, 3, 103, "59 Custom 2 C encoding", + /* 4*/ { BARCODE_AUSPOST, "32211324Ab #2", 0, 3, 103, 1, "59 Custom 2 C encoding", "1000100000101010100010001010101010101000101010101010001010100010100000101000100000000010100000100010100" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000001000100010101010101000100000101010000010101010001010100010000000100000001000101010000010000000000" }, - /* 5*/ { BARCODE_AUSPOST, "32211324123456789012345", 0, 3, 133, "62 Custom 3 N encoding", + /* 5*/ { BARCODE_AUSPOST, "32211324123456789012345", 0, 3, 133, 1, "62 Custom 3 N encoding", "1000001010001010100010001010101010101000101010101000101010101000001000100000001010101010100010101010100000100000100010101010100010100" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000101010100010101010101000100000101010000010001010001000000010101010001010001010101000101000100000001000001010000010001010100010000" }, - /* 6*/ { BARCODE_AUSPOST, "32211324aBCd#F hIz", 0, 3, 133, "62 Custom 3 C encoding", + /* 6*/ { BARCODE_AUSPOST, "32211324aBCd#F hIz", 0, 3, 133, 1, "62 Custom 3 C encoding", "1000001010001010100010001010101010101000101010000010101010100010000010100010100010100010000010000000000000100010100010101010000000100" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000101010100010101010101000100000101010000010100010100010101010001010000010001010100000100010101000000000101000001010100000000010000" }, - /* 7*/ { BARCODE_AUSPOST, "12345678DEGHJKLMNO", 0, 3, 133, "62 Custom 3 C encoding GDSET 1st part", + /* 7*/ { BARCODE_AUSPOST, "12345678DEGHJKLMNO", 0, 3, 133, 1, "62 Custom 3 C encoding GDSET 1st part", "1000001010001010100010101010100000100010000010101010101010001010001010101010101010100010101010101010100000001010000010000000000010100" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000101010101000101000100000001010101000101010001010000010101010100000101000100000101000001000000000001000001010000010001010001010000" }, - /* 8*/ { BARCODE_AUSPOST, "23456789PQRSTUVWXY", 0, 3, 133, "62 Custom 3 C encoding GDSET 2nd part", + /* 8*/ { BARCODE_AUSPOST, "23456789PQRSTUVWXY", 0, 3, 133, 1, "62 Custom 3 C encoding GDSET 2nd part", "1000001010001000101010101000001000100000001010001010001010000000101000101000100000101000101000100000001000101000101010101000101010100" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000101010101010001000000010101010001010001000101000100000101010101010100010101010001010000010001010101000000010001000001010101000000" }, - /* 9*/ { BARCODE_AUSPOST, "34567890Zcefgijklm", 0, 3, 133, "62 Custom 3 C encoding GDSET 3rd part", + /* 9*/ { BARCODE_AUSPOST, "34567890Zcefgijklm", 0, 3, 133, 1, "62 Custom 3 C encoding GDSET 3rd part", "1000001010001010101010000010001000000010101000001010001010000010100010100010001010001010000010000000100000101000100000001010001010100" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000101010100010000000101010100010100010101010100010000010000000100000000000001000000000001000000010100000101000000010101010100010000" }, - /* 10*/ { BARCODE_AUSPOST, "12345678lnopqrstuv", 0, 3, 133, "62 Custom 3 C encoding GDSET 4th part", + /* 10*/ { BARCODE_AUSPOST, "12345678lnopqrstuv", 0, 3, 133, 1, "62 Custom 3 C encoding GDSET 4th part", "1000001010001010100010101010100000100010000010000000100000000000001000001000000000000000100000100000000000001010001010101000000010100" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000101010101000101000100000001010101000101000000010000010100010001010000010001010000000100000000000100000100000001010001000100000000" }, - /* 11*/ { BARCODE_AUSPOST, "09876543wxy# ", 0, 3, 103, "59 Custom 2 C encoding GDSET 5th part", + /* 11*/ { BARCODE_AUSPOST, "09876543wxy# ", 0, 3, 103, 1, "59 Custom 2 C encoding GDSET 5th part", "1000100000101010001000000010001010001010101000001000001000000010100010100000100010000000000010100010100" "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" "0000001000101010001010101000101000100000001000001000000000001010000010100000001010001000001000100000000" }, - /* 12*/ { BARCODE_AUSREPLY, "12345678", 0, 3, 73, "Verified manually against tec-it", + /* 12*/ { BARCODE_AUSPOST, "00000000", 0, 3, 73, 0, "Null (DPID all-zeros) length 8; BWIPP: not supported yet", + "1000101010101010101010101010101010101010101000001000001000001000101000100" + "1010101010101010101010101010101010101010101010101010101010101010101010101" + "0000101010101010101010101010101010101010101000101010100000001000001000000" + }, + /* 13*/ { BARCODE_AUSPOST, "00000000ABC 9", 0, 3, 103, 0, "Null length 13; BWIPP: not supported yet", + "1000101010101010101010101010101010101010101010101010101010100010100000000000100000001000101000000000100" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "0000101010101010101010101010101010101010101010101010100010101010100000101000101010001010001000000000000" + }, + /* 14*/ { BARCODE_AUSPOST, "0000000012345678", 0, 3, 103, 0, "Null length 16; BWIPP: not supported yet", + "1000101010101010101010101010101010101010101010101000101010101000001000100000001000101000001010100000100" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "0000101010101010101010101010101010101010101010001010001000000010101010001010001010101010101010101010000" + }, + /* 15*/ { BARCODE_AUSPOST, "00000000aBCd#F hIz", 0, 3, 133, 0, "Null length 18; BWIPP: not supported yet", + "1000101010101010101010101010101010101010101010000010101010100010000010100010100010100010000010000000000000001010100000000000000000100" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "0000101010101010101010101010101010101010101010100010100010101010001010000010001010100000100010101000000000001000001000000000000000000" + }, + /* 16*/ { BARCODE_AUSPOST, "00000000123456789012345", 0, 3, 133, 0, "Null length 23; BWIPP: not supported yet", + "1000101010101010101010101010101010101010101010101000101010101000001000100000001010101010100010101010100000001000100000000000100010100" + "1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101" + "0000101010101010101010101010101010101010101010001010001000000010101010001010001010101000101000100000001000101010000000101010100000000" + }, + /* 17*/ { BARCODE_AUSREPLY, "12345678", 0, 3, 73, 1, "Verified manually against TEC-IT", "1000101010001010100010101010100000100010000000001000001000000000100010100" "1010101010101010101010101010101010101010101010101010101010101010101010101" "0000000000101000101000100000001010101000101000000000100010101000101000000" }, - /* 13*/ { BARCODE_AUSROUTE, "34567890", 0, 3, 73, "Verified manually against tec-it", + /* 18*/ { BARCODE_AUSROUTE, "34567890", 0, 3, 73, 1, "Verified manually against TEC-IT", "1000000000101010101010000010001000000010101000100010101010000000101000100" "1010101010101010101010101010101010101010101010101010101010101010101010101" "0000101010000010000000101010100010100010101000100010101010001010001000000" }, - /* 14*/ { BARCODE_AUSREDIRECT, "98765432", 0, 3, 73, "Verified manually against tec-it", + /* 19*/ { BARCODE_AUSREDIRECT, "98765432", 0, 3, 73, 1, "Verified manually against TEC-IT", "1000001010000010000000100010100010101010100000101010101000100010100010100" "1010101010101010101010101010101010101010101010101010101010101010101010101" "0000001010100010101010001010001000000010101000000000001010101000001010000" @@ -376,34 +407,51 @@ static void test_encode(const testCtx *const p_ctx) { symbol = ZBarcode_Create(); assert_nonnull(symbol, "Symbol not created\n"); - length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, -1 /*option_1*/, -1, -1, -1 /*output_options*/, data[i].data, -1, debug); + length = testUtilSetSymbol(symbol, data[i].symbology, -1 /*input_mode*/, -1 /*eci*/, + -1 /*option_1*/, -1, -1, -1 /*output_options*/, + data[i].data, -1, debug); ret = ZBarcode_Encode(symbol, TCU(data[i].data), length); - assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + assert_equal(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, %d, \"%s\",\n", - i, testUtilBarcodeName(data[i].symbology), testUtilEscape(data[i].data, length, escaped, sizeof(escaped)), - testUtilErrorName(data[i].ret), symbol->rows, symbol->width, data[i].comment); + printf(" /*%3d*/ { %s, \"%s\", %s, %d, %d, %d, \"%s\",\n", + i, testUtilBarcodeName(data[i].symbology), + testUtilEscape(data[i].data, length, escaped, sizeof(escaped)), + testUtilErrorName(data[i].ret), symbol->rows, symbol->width, data[i].bwipp_cmp, data[i].comment); testUtilModulesPrint(symbol, " ", "\n"); printf(" },\n"); } else { if (ret < ZINT_ERROR) { int width, row; - assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d (%s)\n", i, symbol->rows, data[i].expected_rows, data[i].data); - assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", i, symbol->width, data[i].expected_width, data[i].data); + assert_equal(symbol->rows, data[i].expected_rows, "i:%d symbol->rows %d != %d (%s)\n", + i, symbol->rows, data[i].expected_rows, data[i].data); + assert_equal(symbol->width, data[i].expected_width, "i:%d symbol->width %d != %d (%s)\n", + i, symbol->width, data[i].expected_width, data[i].data); ret = testUtilModulesCmp(symbol, data[i].expected, &width, &row); - assert_zero(ret, "i:%d testUtilModulesCmp ret %d != 0 width %d row %d (%s)\n", i, ret, width, row, data[i].data); + assert_zero(ret, "i:%d testUtilModulesCmp ret %d != 0 width %d row %d (%s)\n", + i, ret, width, row, data[i].data); if (do_bwipp && testUtilCanBwipp(i, symbol, -1, -1, -1, debug)) { - ret = testUtilBwipp(i, symbol, -1, -1, -1, data[i].data, length, NULL, bwipp_buf, sizeof(bwipp_buf), NULL); - assert_zero(ret, "i:%d %s testUtilBwipp ret %d != 0\n", i, testUtilBarcodeName(symbol->symbology), ret); + if (!data[i].bwipp_cmp) { + if (debug & ZINT_DEBUG_TEST_PRINT) { + printf("i:%d %s not BWIPP compatible (%s)\n", + i, testUtilBarcodeName(symbol->symbology), data[i].comment); + } + } else { + ret = testUtilBwipp(i, symbol, -1, -1, -1, data[i].data, length, NULL, bwipp_buf, + sizeof(bwipp_buf), NULL); + assert_zero(ret, "i:%d %s testUtilBwipp ret %d != 0\n", + i, testUtilBarcodeName(symbol->symbology), ret); - ret = testUtilBwippCmp(symbol, bwipp_msg, bwipp_buf, data[i].expected); - assert_zero(ret, "i:%d %s testUtilBwippCmp %d != 0 %s\n actual: %s\nexpected: %s\n", - i, testUtilBarcodeName(symbol->symbology), ret, bwipp_msg, bwipp_buf, data[i].expected); + ret = testUtilBwippCmp(symbol, bwipp_msg, bwipp_buf, data[i].expected); + assert_zero(ret, "i:%d %s testUtilBwippCmp %d != 0 %s\n actual: %s\nexpected: %s\n", + i, testUtilBarcodeName(symbol->symbology), ret, bwipp_msg, bwipp_buf, + data[i].expected); + } } } } diff --git a/backend/tests/test_code128.c b/backend/tests/test_code128.c index 2b820a50..da1f3a56 100644 --- a/backend/tests/test_code128.c +++ b/backend/tests/test_code128.c @@ -1752,6 +1752,7 @@ static void test_fuzz(const testCtx *const p_ctx) { "\136\136", 162, ZINT_ERROR_TOO_LONG, "Error 341: Input too long, requires 167 symbol characters (maximum 102)", 3 }, /* fuzz_data (2nd, 2026-01-12) */ + /* 1*/ { BARCODE_CODE128, DATA_MODE | EXTRA_ESCAPE_MODE, -1, -1, "\\^CC\\^177#", -1, 0, "", 3 }, }; const int data_size = ARRAY_SIZE(data); int i, length, ret; diff --git a/backend/tests/test_postal.c b/backend/tests/test_postal.c index 66677490..66696b83 100644 --- a/backend/tests/test_postal.c +++ b/backend/tests/test_postal.c @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2019-2025 Robin Stuart + Copyright (C) 2019-2026 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -72,7 +72,7 @@ static void test_large(const testCtx *const p_ctx) { /* 20*/ { BARCODE_PLANET, "1", 13, 0, 2, 143, "" }, /* 21*/ { BARCODE_PLANET, "1", 14, ZINT_WARN_NONCOMPLIANT, 2, 153, "Warning 478: Input length 14 is not standard (should be 11 or 13 digits)" }, /* 22*/ { BARCODE_PLANET, "1", 38, ZINT_WARN_NONCOMPLIANT, 2, 393, "Warning 478: Input length 38 is not standard (should be 11 or 13 digits)" }, - /* 23*/ { BARCODE_PLANET, "1", 39, ZINT_ERROR_TOO_LONG, -1, -1, "Error 482: Input length 39 too long (maximum 38)" }, + /* 23*/ { BARCODE_PLANET, "1", 39, ZINT_ERROR_TOO_LONG, -1, -1, "Error 480: Input length 39 too long (maximum 38)" }, /* 24*/ { BARCODE_KIX, "1", 18, 0, 3, 143, "" }, /* 25*/ { BARCODE_KIX, "1", 19, ZINT_ERROR_TOO_LONG, -1, -1, "Error 490: Input length 19 too long (maximum 18)" }, /* 26*/ { BARCODE_DAFT, "D", 576, 0, 3, 1151, "" }, @@ -352,10 +352,10 @@ static void test_input(const testCtx *const p_ctx) { /* 34*/ { BARCODE_PLANET, -1, 0, "1234567890", ZINT_WARN_NONCOMPLIANT, 2, 113, 12, "Warning 478: Input length 10 is not standard (should be 11 or 13 digits)", 0, "BWIPP requires standard lengths" }, /* 35*/ { BARCODE_PLANET, -1, 0, "123456789012", ZINT_WARN_NONCOMPLIANT, 2, 133, 12, "Warning 478: Input length 12 is not standard (should be 11 or 13 digits)", 0, "BWIPP requires standard lengths" }, /* 36*/ { BARCODE_PLANET, -1, 0, "12345678901234", ZINT_WARN_NONCOMPLIANT, 2, 153, 12, "Warning 478: Input length 14 is not standard (should be 11 or 13 digits)", 0, "BWIPP requires standard lengths" }, - /* 37*/ { BARCODE_PLANET, -1, 0, "1234567890A", ZINT_ERROR_INVALID_DATA, -1, -1, -1, "Error 483: Invalid character at position 11 in input (digits only)", 1, "" }, + /* 37*/ { BARCODE_PLANET, -1, 0, "1234567890A", ZINT_ERROR_INVALID_DATA, -1, -1, -1, "Error 481: Invalid character at position 11 in input (digits only)", 1, "" }, /* 38*/ { BARCODE_KIX, -1, 0, "0123456789ABCDEFGH", 0, 3, 143, 8, "", 1, "" }, /* 39*/ { BARCODE_KIX, -1, 0, "a", 0, 3, 7, 8, "", 1, "" }, /* Converts to upper */ - /* 40*/ { BARCODE_KIX, -1, 0, ",", ZINT_ERROR_INVALID_DATA, -1, -1, -1, "Error 491: Invalid character at position 1 in input (alphanumerics only)", 1, "" }, + /* 40*/ { BARCODE_KIX, -1, 0, ",", ZINT_ERROR_INVALID_DATA, -1, -1, -1, "Error 489: Invalid character at position 1 in input (alphanumerics only)", 1, "" }, /* 41*/ { BARCODE_DAFT, -1, 0, "DAFT", 0, 3, 7, 8, "", 1, "" }, /* 42*/ { BARCODE_DAFT, -1, 0, "a", 0, 3, 1, 8, "", 1, "" }, /* Converts to upper */ /* 43*/ { BARCODE_DAFT, -1, 0, "B", ZINT_ERROR_INVALID_DATA, -1, -1, -1, "Error 493: Invalid character at position 1 in input (\"D\", \"A\", \"F\" and \"T\" only)", 1, "" }, diff --git a/backend/tests/testcommon.c b/backend/tests/testcommon.c index cf285470..aec5ffc3 100644 --- a/backend/tests/testcommon.c +++ b/backend/tests/testcommon.c @@ -3262,6 +3262,11 @@ int testUtilBwipp(int index, const struct zint_symbol *symbol, int option_1, int bwipp_opts = bwipp_opts_buf; } } + /* Check for Null - for when supported by BWIPP */ + for (i = 0; i < 8 && data[i] == '0'; i++); + if (i == 8) { + prefix = "00"; + } memmove(bwipp_data + 2, bwipp_data, data_len + 1); memmove(bwipp_data, prefix, 2); } diff --git a/backend/upcean.c b/backend/upcean.c index 292fb6b6..b0d6930f 100644 --- a/backend/upcean.c +++ b/backend/upcean.c @@ -1,7 +1,7 @@ /* upcean.c - Handles UPC, EAN and ISBN */ /* libzint - the open source barcode library - Copyright (C) 2008-2025 Robin Stuart + Copyright (C) 2008-2026 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -85,6 +85,8 @@ static const char EANsetB[10][4] = { {'1','3','2','1'}, {'4','1','1','1'}, {'2','1','3','1'}, {'3','1','2','1'}, {'2','1','1','3'} }; +static const char EANones[6] = { '1','1','1','1','1','1' }; /* Various lengths used for start/stop/separators */ + /* Write UPC-A or EAN-8 encodation to destination `d` */ static void upca_set_dest(const unsigned char source[], const int length, char *d) { int i, half_way; @@ -92,13 +94,13 @@ static void upca_set_dest(const unsigned char source[], const int length, char * half_way = length / 2; /* Start character */ - memcpy(d, "111", 3); + memcpy(d, EANones, 3); d += 3; 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 */ - memcpy(d, "11111", 5); + memcpy(d, EANones, 5); d += 5; } @@ -106,7 +108,9 @@ static void upca_set_dest(const unsigned char source[], const int length, char * } /* Stop character */ - memcpy(d, "111", 4); /* Include terminating NUL */ + memcpy(d, EANones, 3); + d += 3; + *d = '\0'; /* Need to NUL-terminate */ } /* Make a UPC-A barcode, allowing for composite if `cc_rows` set */ @@ -278,7 +282,7 @@ static int upce_cc(struct zint_symbol *symbol, unsigned char source[], int lengt /* Take all this information and make the barcode pattern */ /* Start character */ - memcpy(d, "111", 3); + memcpy(d, EANones, 3); d += 3; for (i = 0; i < length; i++, d += 4) { @@ -293,7 +297,9 @@ static int upce_cc(struct zint_symbol *symbol, unsigned char source[], int lengt } /* Stop character */ - memcpy(d, "111111", 7); /* Include terminating NUL */ + memcpy(d, EANones, 6); + d += 6; + *d = '\0'; /* Need to NUL-terminate */ z_hrt_cat_chr_nochk(symbol, check_digit); @@ -333,6 +339,7 @@ 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) { + static const char start[3] = { '1','1','2' }; const char *parity; int i; char *d = dest + strlen(dest); @@ -343,7 +350,7 @@ static void ean_add_on(const unsigned char source[], const int length, char dest } /* Start character */ - memcpy(d, "112", 3); + memcpy(d, start, 3); d += 3; /* Calculate parity */ @@ -381,7 +388,7 @@ static void ean_add_on(const unsigned char source[], const int length, char dest /* Glyph separator */ if (i != (length - 1)) { - memcpy(d, "11", 2); + memcpy(d, EANones, 2); d += 2; } } @@ -422,13 +429,13 @@ static int ean13_cc(struct zint_symbol *symbol, const unsigned char source[], in half_way = 7; /* Start character */ - memcpy(d, "111", 3); + memcpy(d, EANones, 3); d += 3; for (i = 1; i < symbol->text_length; i++, d += 4) { if (i == half_way) { /* Middle character - separates manufacturer no. from product no. - also inverts right hand characters */ - memcpy(d, "11111", 5); + memcpy(d, EANones, 5); d += 5; } @@ -440,7 +447,9 @@ static int ean13_cc(struct zint_symbol *symbol, const unsigned char source[], in } /* Stop character */ - memcpy(d, "111", 4); /* Include terminating NUL */ + memcpy(d, EANones, 3); + d += 3; + *d = '\0'; /* Need to NUL-terminate */ if (symbol->output_options & COMPLIANT_HEIGHT) { /* ISO/IEC 15420:2009 4.3.3 Bar height EAN-13 22.85mm / 0.33mm (X) ~ 69.24, diff --git a/docs/manual.html b/docs/manual.html index fe93be60..9996b2de 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -6086,7 +6086,8 @@ alt="zint -b AUSPOST --compliantheight -d "96184209"" /> Control Code (FCC) is added by Zint and should not be included in the input data. Reed-Solomon error correction data is generated by Zint. Encoding behaviour is determined by the length of the input data -according to the formula shown in the following table.

+according to the formula shown in the following table. The first 8 +digits is the DPID.

@@ -6103,7 +6104,7 @@ Formats - + @@ -6112,38 +6113,41 @@ Formats - + - + - + - + - +
Table 23: Australia Post Input Formats
Required Input Format Symbol Length FCCEncoding TableEncoding Table(s)
99999999 37-bar 11NoneN
13 99999999AAAAA 52-bar 59CN and C
16 9999999999999999 52-bar 59NN
18 99999999AAAAAAAAAA 67-bar 62CN and C
23 99999999999999999999999 67-bar 62NN
+

The special Null FCC 00, non-machine readable and intended for +customer use only, is used (all input lengths) if the DPID is all +zeroes.

6.5.1.2 Reply Paid Barcode

A Reply Paid version of the Australia Post 4-State Barcode (FCC 45) which requires an 8-digit DPID input.

diff --git a/docs/manual.pmd b/docs/manual.pmd index 36f0f105..c209524c 100644 --- a/docs/manual.pmd +++ b/docs/manual.pmd @@ -4142,25 +4142,28 @@ Valid data characters are 0-9, A-Z, a-z, space and hash (#). A Format Control Code (FCC) is added by Zint and should not be included in the input data. Reed-Solomon error correction data is generated by Zint. Encoding behaviour is determined by the length of the input data according to the formula shown in the -following table. +following table. The first 8 digits is the DPID. ------------------------------------------------------------- Input Required Input Format Symbol FCC Encoding -Length Length Table +Length Length Table(s) ------ ------------------------- ------ --- -------- -8 `99999999` 37-bar 11 None +8 `99999999` 37-bar 11 N -13 `99999999AAAAA` 52-bar 59 C +13 `99999999AAAAA` 52-bar 59 N and C 16 `9999999999999999` 52-bar 59 N -18 `99999999AAAAAAAAAA` 67-bar 62 C +18 `99999999AAAAAAAAAA` 67-bar 62 N and C 23 `99999999999999999999999` 67-bar 62 N ------------------------------------------------------------- Table: Australia Post Input Formats {#tbl:auspost_input_formats} +The special Null FCC 00, non-machine readable and intended for customer use +only, is used (all input lengths) if the DPID is all zeroes. + #### 6.5.1.2 Reply Paid Barcode A Reply Paid version of the Australia Post 4-State Barcode (FCC 45) which diff --git a/docs/manual.txt b/docs/manual.txt index 3832b4bc..c12cc136 100644 --- a/docs/manual.txt +++ b/docs/manual.txt @@ -3949,25 +3949,28 @@ Valid data characters are 0-9, A-Z, a-z, space and hash (#). A Format Control Code (FCC) is added by Zint and should not be included in the input data. Reed-Solomon error correction data is generated by Zint. Encoding behaviour is determined by the length of the input data according to the formula shown in the -following table. +following table. The first 8 digits is the DPID. --------------------------------------------------------------- Input Required Input Format Symbol FCC Encoding - Length Length Table + Length Length Table(s) --------- --------------------------- -------- ----- ---------- - 8 99999999 37-bar 11 None + 8 99999999 37-bar 11 N - 13 99999999AAAAA 52-bar 59 C + 13 99999999AAAAA 52-bar 59 N and C 16 9999999999999999 52-bar 59 N - 18 99999999AAAAAAAAAA 67-bar 62 C + 18 99999999AAAAAAAAAA 67-bar 62 N and C 23 99999999999999999999999 67-bar 62 N --------------------------------------------------------------- Table 23: Australia Post Input Formats +The special Null FCC 00, non-machine readable and intended for customer use +only, is used (all input lengths) if the DPID is all zeroes. + 6.5.1.2 Reply Paid Barcode A Reply Paid version of the Australia Post 4-State Barcode (FCC 45) which