diff --git a/ChangeLog b/ChangeLog index 282910e2..7062e66a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -112,21 +112,23 @@ Bugs - GUI: fix not enabling font combo "Small Bold (vector only)" by default - CODEONE: fix S/T quiet zone 1X bottom (props BWIPP issue #245 doc) - EAN-2/EAN-5: fix `BARCODE_BIND_TOP/BIND/BOX` output -- PDF417: fix out-of-bounds crash in `pdf_text_submode_length()`, ticket #300, - props Andre Maute +- library: fix 21-bit Unicode conversion in `escape_char_process()`; fix + restricting escaped data length by using de-escaped length to check - AZTEC: fix out-of-bounds crash when user-specified size given, ticket #300, props Andre Maute; fix 4-layer compact block max (76 -> 64); fix encoding of byte-blocks > 11-bit limit -- library: fix 21-bit Unicode conversion in `escape_char_process()`; fix - restricting escaped data length by using de-escaped length to check -- CODEONE: fix out-of-bounds crash in `c1_c40text_cnt()` and looping on latch - crash in `c1_encode()`, ticket #300, props Andre Maute - CODABLOCKF: fix crash due to `columns` overflow, ticket #300, props Andre Maute -- EANX_CC/UPCA_CC: fix crash in `dbar_date()` on not checking length, ticket - #300, props Andre Maute -- PDF417: fix out-of-bounds crash on overrunning string and codeword buffers, - ticket #300, props Andre Maute +- CODEONE: fix out-of-bounds crash in `c1_c40text_cnt()` and looping on latch + crash in `c1_encode()` and too small buffer for Version T, ticket #300, props + Andre Maute +- EANX_CC/UPCA_CC: fix crash in `dbar_date()` on not checking length and crash + in `gs1_verify()` on not checking length, ticket #300, props Andre Maute +- GS1_128_CC: fix divide-by-zero crash in `calc_padding_ccc()`, ticket #300, + props Andre Maute +- PDF417: fix out-of-bounds crash in `pdf_text_submode_length()` and + out-of-bounds crash on overrunning string and codeword buffers, ticket #300, + props Andre Maute Version 2.12.0 (2022-12-12) diff --git a/backend/code1.c b/backend/code1.c index 27f3d4dd..75cbe5e3 100644 --- a/backend/code1.c +++ b/backend/code1.c @@ -37,6 +37,9 @@ #include "reedsol.h" #include "large.h" +#define C1_MAX_CWS 1480 /* Max data codewords for Version H */ +#define C1_MAX_ECCS 560 /* Max ECC codewords for Version H */ + #define C1_ASCII 1 #define C1_C40 2 #define C1_DECIMAL 3 @@ -851,7 +854,7 @@ static int c1_encode(struct zint_symbol *symbol, unsigned char source[], int len } } - if (tp > 1480) { + if (tp > C1_MAX_CWS) { if (debug_print) fputc('\n', stdout); /* Data is too large for symbol */ return 0; @@ -953,7 +956,7 @@ static int c1_encode(struct zint_symbol *symbol, unsigned char source[], int len } /* Re-check length of data */ - if (tp > 1480) { + if (tp > C1_MAX_CWS) { /* Data is too large for symbol */ return 0; } @@ -1135,7 +1138,7 @@ INTERNAL int codeone(struct zint_symbol *symbol, struct zint_seg segs[], const i } else if (symbol->option_2 == 10) { /* Version T */ - unsigned int target[90 + 2]; /* Allow for 90 BYTE mode (+ latch and byte count) */ + unsigned int target[C1_MAX_CWS + C1_MAX_ECCS]; /* Use same buffer size as A to H to avail of loop checks */ unsigned int ecc[22]; int data_length; int data_cw, ecc_cw, block_width; @@ -1221,7 +1224,7 @@ INTERNAL int codeone(struct zint_symbol *symbol, struct zint_seg segs[], const i } else { /* Versions A to H */ - unsigned int target[1480 + 560]; + unsigned int target[C1_MAX_CWS + C1_MAX_ECCS]; unsigned int sub_data[185], sub_ecc[70]; int data_length; int data_cw; diff --git a/backend/composite.c b/backend/composite.c index 7d39b0f3..7d23f35d 100644 --- a/backend/composite.c +++ b/backend/composite.c @@ -778,7 +778,7 @@ static int calc_padding_ccb(const int binary_length, const int cc_width) { return target_bitsize; } -static int calc_padding_ccc(const int binary_length, int *cc_width, const int linear_width, int *ecc) { +static int calc_padding_ccc(const int binary_length, int *p_cc_width, const int linear_width, int *p_ecc_level) { int target_bitsize = 0; int byte_length, codewords_used, ecc_level, ecc_codewords, rows; int codewords_total, target_codewords, target_bytesize; @@ -806,22 +806,25 @@ static int calc_padding_ccc(const int binary_length, int *cc_width, const int li } else { return 0; } - *(ecc) = ecc_level; + *p_ecc_level = ecc_level; ecc_codewords = 1 << (ecc_level + 1); codewords_used += ecc_codewords; codewords_used += 3; + /* Minimum possible linear width (with GS1_NO_CHECK) is 11*5 (start, FNC1, linkage, data, check) + 13 stop */ + assert(linear_width >= 68); /* -52 = 7 left shift (section 12.3 f) + 10 right quiet zone - 17 start + 2x17 row indicators + 18 stop */ - *(cc_width) = (linear_width - 52) / 17; - if (*(cc_width) > 30) { - *(cc_width) = 30; + *p_cc_width = linear_width == 68 ? 1 : (linear_width - 52) / 17; /* Ensure > 0 */ + if (*p_cc_width > 30) { + *p_cc_width = 30; } - rows = (int) ceil((double) codewords_used / *(cc_width)); + assert(*p_cc_width > 0); + rows = (int) ceil((double) codewords_used / *p_cc_width); /* stop the symbol from becoming too high */ - while (rows > 30 && *(cc_width) < 30) { - *(cc_width) = *(cc_width) + 1; - rows = (int) ceil((double) codewords_used / *(cc_width)); + while (rows > 30 && *p_cc_width < 30) { + (*p_cc_width)++; + rows = (int) ceil((double) codewords_used / *p_cc_width); } if (rows > 30) { /* Should never happen given `codewords_used` check above (865 / 30 ~ 28.83) */ @@ -831,7 +834,7 @@ static int calc_padding_ccc(const int binary_length, int *cc_width, const int li rows = 3; } - codewords_total = *(cc_width) * rows; + codewords_total = *p_cc_width * rows; target_codewords = codewords_total - ecc_codewords; target_codewords -= 3; @@ -846,7 +849,7 @@ static int calc_padding_ccc(const int binary_length, int *cc_width, const int li /* Handles all data encodation from section 5 of ISO/IEC 24723 */ static int cc_binary_string(struct zint_symbol *symbol, const unsigned char source[], const int length, - char binary_string[], const int cc_mode, int *cc_width, int *ecc, const int linear_width) { + char binary_string[], const int cc_mode, int *p_cc_width, int *p_ecc_level, const int linear_width) { int encoding_method, read_posn, alpha_pad; int i, j, ai_crop, ai_crop_posn, fnc1_latch; int ai90_mode, remainder; @@ -863,7 +866,7 @@ static int cc_binary_string(struct zint_symbol *symbol, const unsigned char sour ai_crop_posn = -1; fnc1_latch = 0; alpha_pad = 0; - *ecc = 0; + *p_ecc_level = 0; target_bitsize = 0; mode = NUMERIC; @@ -1133,13 +1136,13 @@ static int cc_binary_string(struct zint_symbol *symbol, const unsigned char sour switch (cc_mode) { case 1: - target_bitsize = calc_padding_cca(bp, *(cc_width)); + target_bitsize = calc_padding_cca(bp, *p_cc_width); break; case 2: - target_bitsize = calc_padding_ccb(bp, *(cc_width)); + target_bitsize = calc_padding_ccb(bp, *p_cc_width); break; case 3: - target_bitsize = calc_padding_ccc(bp, cc_width, linear_width, ecc); + target_bitsize = calc_padding_ccc(bp, p_cc_width, linear_width, p_ecc_level); break; } @@ -1170,13 +1173,13 @@ static int cc_binary_string(struct zint_symbol *symbol, const unsigned char sour switch (cc_mode) { case 1: - target_bitsize = calc_padding_cca(bp, *(cc_width)); + target_bitsize = calc_padding_cca(bp, *p_cc_width); break; case 2: - target_bitsize = calc_padding_ccb(bp, *(cc_width)); + target_bitsize = calc_padding_ccb(bp, *p_cc_width); break; case 3: - target_bitsize = calc_padding_ccc(bp, cc_width, linear_width, ecc); + target_bitsize = calc_padding_ccc(bp, p_cc_width, linear_width, p_ecc_level); break; } @@ -1203,7 +1206,7 @@ static int cc_binary_string(struct zint_symbol *symbol, const unsigned char sour binary_string[target_bitsize] = '\0'; if (debug_print) { - printf("ECC: %d, CC width %d\n", *ecc, *cc_width); + printf("ECC: %d, CC width %d\n", *p_ecc_level, *p_cc_width); printf("Binary: %s (%d)\n", binary_string, target_bitsize); } diff --git a/backend/gs1.c b/backend/gs1.c index 78382ac5..776a24df 100644 --- a/backend/gs1.c +++ b/backend/gs1.c @@ -1332,7 +1332,7 @@ static int hyphen(const unsigned char *data, int data_len, int offset, int min, #include "gs1_lint.h" /* Verify a GS1 input string */ -INTERNAL int gs1_verify(struct zint_symbol *symbol, const unsigned char source[], const int src_len, +INTERNAL int gs1_verify(struct zint_symbol *symbol, const unsigned char source[], const int length, unsigned char reduced[]) { int i, j, last_ai, ai_latch; int bracket_level, max_bracket_level, ai_length, max_ai_length, min_ai_length; @@ -1341,14 +1341,14 @@ INTERNAL int gs1_verify(struct zint_symbol *symbol, const unsigned char source[] int error_value = 0; char obracket = symbol->input_mode & GS1PARENS_MODE ? '(' : '['; char cbracket = symbol->input_mode & GS1PARENS_MODE ? ')' : ']'; - int ai_max = chr_cnt(source, src_len, obracket) + 1; /* Plus 1 so non-zero */ + int ai_max = chr_cnt(source, length, obracket) + 1; /* Plus 1 so non-zero */ int *ai_value = (int *) z_alloca(sizeof(int) * ai_max); int *ai_location = (int *) z_alloca(sizeof(int) * ai_max); int *data_location = (int *) z_alloca(sizeof(int) * ai_max); int *data_length = (int *) z_alloca(sizeof(int) * ai_max); /* Detect extended ASCII characters */ - for (i = 0; i < src_len; i++) { + for (i = 0; i < length; i++) { if (source[i] >= 128) { strcpy(symbol->errtxt, "250: Extended ASCII characters are not supported by GS1"); return ZINT_ERROR_INVALID_DATA; @@ -1379,7 +1379,7 @@ INTERNAL int gs1_verify(struct zint_symbol *symbol, const unsigned char source[] max_ai_length = 0; min_ai_length = 5; ai_latch = 0; - for (i = 0; i < src_len; i++) { + for (i = 0; i < length; i++) { if (source[i] == obracket) { bracket_level++; if (bracket_level > max_bracket_level) { @@ -1395,7 +1395,7 @@ INTERNAL int gs1_verify(struct zint_symbol *symbol, const unsigned char source[] min_ai_length = ai_length; } /* Check zero-length AI has data */ - if (ai_length == 0 && (i + 1 == src_len || source[i + 1] == obracket)) { + if (ai_length == 0 && (i + 1 == length || source[i + 1] == obracket)) { ai_zero_len_no_data = 1; } else if (ai_length == 1) { ai_single_digit = 1; @@ -1446,7 +1446,7 @@ INTERNAL int gs1_verify(struct zint_symbol *symbol, const unsigned char source[] if (!(symbol->input_mode & GS1NOCHECK_MODE)) { ai_count = 0; - for (i = 1; i < src_len; i++) { + for (i = 1; i < length; i++) { if (source[i - 1] == obracket) { ai_location[ai_count] = i; for (j = 1; source[i + j] != cbracket; j++); @@ -1465,7 +1465,7 @@ INTERNAL int gs1_verify(struct zint_symbol *symbol, const unsigned char source[] data_location[i] = ai_location[i] + 3; } data_length[i] = 0; - while ((data_location[i] + data_length[i] < src_len) + while ((data_location[i] + data_length[i] < length) && (source[data_location[i] + data_length[i]] != obracket)) { data_length[i]++; } @@ -1501,7 +1501,7 @@ INTERNAL int gs1_verify(struct zint_symbol *symbol, const unsigned char source[] /* Resolve AI data - put resulting string in 'reduced' */ j = 0; ai_latch = 1; - for (i = 0; i < src_len; i++) { + for (i = 0; i < length; i++) { if ((source[i] != obracket) && (source[i] != cbracket)) { reduced[j++] = source[i]; } @@ -1510,20 +1510,22 @@ INTERNAL int gs1_verify(struct zint_symbol *symbol, const unsigned char source[] if (ai_latch == 0) { reduced[j++] = '['; } - last_ai = to_int(source + i + 1, 2); - ai_latch = 0; - /* The following values from "GS1 General Specifications Release 21.0.1" - Figure 7.8.4-2 "Element strings with predefined length using GS1 Application Identifiers" */ - if ( - ((last_ai >= 0) && (last_ai <= 4)) - || ((last_ai >= 11) && (last_ai <= 20)) - /* NOTE: as noted by Terry Burton the following complies with ISO/IEC 24724:2011 Table D.1, - but clashes with TPX AI [235], introduced May 2019; awaiting feedback from GS1 */ - || (last_ai == 23) /* legacy support */ /* TODO: probably remove */ - || ((last_ai >= 31) && (last_ai <= 36)) - || (last_ai == 41) - ) { - ai_latch = 1; + if (i + 1 != length) { + last_ai = to_int(source + i + 1, 2); + ai_latch = 0; + /* The following values from "GS1 General Specifications Release 21.0.1" + Figure 7.8.4-2 "Element strings with predefined length using GS1 Application Identifiers" */ + if ( + ((last_ai >= 0) && (last_ai <= 4)) + || ((last_ai >= 11) && (last_ai <= 20)) + /* NOTE: as noted by Terry Burton the following complies with ISO/IEC 24724:2011 Table D.1, + but clashes with TPX AI [235], introduced May 2019; awaiting feedback from GS1 */ + || (last_ai == 23) /* legacy support */ /* TODO: probably remove */ + || ((last_ai >= 31) && (last_ai <= 36)) + || (last_ai == 41) + ) { + ai_latch = 1; + } } } /* The ']' character is simply dropped from the input */ diff --git a/backend/library.c b/backend/library.c index a7ff0d02..80d5f825 100644 --- a/backend/library.c +++ b/backend/library.c @@ -1031,6 +1031,7 @@ int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[ symbol->option_3, symbol->scale, symbol->output_options, symbol->fgcolour, symbol->bgcolour, seg_count, len > 30 ? "first 30 " : "", seg_count > 1 ? "[0]" : "", len, source, primary_len > 30 ? "first 30 " : "", primary_len, primary); + fflush(stdout); } if (total_len > ZINT_MAX_DATA_LEN) { diff --git a/backend/pdf417.c b/backend/pdf417.c index ce8f4f9a..5e832b8d 100644 --- a/backend/pdf417.c +++ b/backend/pdf417.c @@ -219,7 +219,7 @@ static int pdf_textprocess_switch(const int curtable, const int newtable, unsign } /* Check consecutive segments for text/num and return the length */ -static int pdf_text_num_length(int liste[3][PDF_MAX_LEN], const int indexliste, const int start) { +static int pdf_text_num_length(short liste[3][PDF_MAX_LEN], const int indexliste, const int start) { int i, len = 0; for (i = start; i < indexliste; i++) { if (liste[1][i] == PDF_BYT) @@ -289,7 +289,7 @@ static int pdf_text_submode_length(const unsigned char chaine[], const int start } /* Whether to stay in numeric mode or not */ -static int pdf_num_stay(const unsigned char *chaine, const int indexliste, int liste[3][PDF_MAX_LEN], const int i) { +static int pdf_num_stay(const unsigned char *chaine, const int indexliste, short liste[3][PDF_MAX_LEN], const int i) { int curtable, not_tex, last_len, last_ml, next_len, num_cws, tex_cws; if (liste[0][i] >= 13 || (indexliste == 1 && liste[0][i] > 5)) { @@ -320,7 +320,7 @@ static int pdf_num_stay(const unsigned char *chaine, const int indexliste, int l } /* Pack segments using the method described in Appendix D of the AIM specification (ISO/IEC 15438:2015 Annex N) */ -static void pdf_appendix_d_encode(const unsigned char *chaine, int liste[3][PDF_MAX_LEN], int *p_indexliste, +static void pdf_appendix_d_encode(const unsigned char *chaine, short liste[3][PDF_MAX_LEN], int *p_indexliste, const int debug_print) { const int indexliste = *p_indexliste; int i = 0, next, last = 0, stayintext = 0; @@ -496,7 +496,7 @@ static void pdf_textprocess(short *chainemc, int *p_mclength, const unsigned cha /* Minimal text compaction */ static void pdf_textprocess_minimal(short *chainemc, int *p_mclength, const unsigned char chaine[], - int liste[3][PDF_MAX_LEN], const int indexliste, const int lastmode, const int is_last_seg, + short liste[3][PDF_MAX_LEN], const int indexliste, const int lastmode, const int is_last_seg, int *p_curtable, int *p_tex_padded, int *p_i) { const int real_lastmode = PDF_REAL_MODE(lastmode); int i, j, k; @@ -913,7 +913,7 @@ static void pdf_addEdges(const unsigned char source[], const int length, const i } /* Calculate optimized encoding modes */ -static int pdf_define_mode(int liste[3][PDF_MAX_LEN], int *p_indexliste, const unsigned char source[], +static int pdf_define_mode(short liste[3][PDF_MAX_LEN], int *p_indexliste, const unsigned char source[], const int length, const int lastmode, const int debug_print) { int i, j, v_i; @@ -980,9 +980,9 @@ static int pdf_define_mode(int liste[3][PDF_MAX_LEN], int *p_indexliste, const u } *p_indexliste = length - mode_start; if (mode_start) { - memmove(liste[0], liste[0] + mode_start, sizeof(int) * (*p_indexliste)); - memmove(liste[1], liste[1] + mode_start, sizeof(int) * (*p_indexliste)); - memmove(liste[2], liste[2] + mode_start, sizeof(int) * (*p_indexliste)); + memmove(liste[0], liste[0] + mode_start, sizeof(short) * (*p_indexliste)); + memmove(liste[1], liste[1] + mode_start, sizeof(short) * (*p_indexliste)); + memmove(liste[2], liste[2] + mode_start, sizeof(short) * (*p_indexliste)); } if (debug_print) { printf("modes (%d):", *p_indexliste); @@ -1000,7 +1000,7 @@ static int pdf_initial(struct zint_symbol *symbol, const unsigned char chaine[], const int is_micro, const int is_last_seg, int *p_lastmode, int *p_curtable, int *p_tex_padded, short chainemc[PDF_MAX_STREAM_LEN], int *p_mclength) { int i, indexchaine = 0, indexliste = 0; - int liste[3][PDF_MAX_LEN] = {{0}}; + short liste[3][PDF_MAX_LEN] = {{0}}; int mclength; const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; const int fast_encode = symbol->input_mode & FAST_MODE; diff --git a/backend/tests/test_code1.c b/backend/tests/test_code1.c index 28e2b0b2..fddbf70a 100644 --- a/backend/tests/test_code1.c +++ b/backend/tests/test_code1.c @@ -183,18 +183,20 @@ static void test_large(const testCtx *const p_ctx) { /*133*/ { -1, 10, { 0, 0, "" }, "\\", 39, ZINT_ERROR_TOO_LONG, -1, -1 }, /*134*/ { -1, 10, { 0, 0, "" }, "\200", 36, 0, 16, 49 }, /*135*/ { -1, 10, { 0, 0, "" }, "\200", 37, ZINT_ERROR_TOO_LONG, -1, -1 }, - /*136*/ { 3, 10, { 0, 0, "" }, "A", 46, 0, 16, 49 }, /* Version T-48 with ECI (9 less as PAD escape char + "\123456") */ - /*137*/ { 3, 10, { 0, 0, "" }, "A", 47, ZINT_ERROR_TOO_LONG, -1, -1 }, - /*138*/ { 3, 10, { 0, 0, "" }, "\001", 32, 0, 16, 49 }, - /*139*/ { 3, 10, { 0, 0, "" }, "\001", 33, ZINT_ERROR_TOO_LONG, -1, -1 }, + /*136*/ { -1, 10, { 0, 0, "" }, "AAA\200", 31, 0, 16, 49 }, /* ASCII + BYTE (ASCII UpSh - worse than BYTE) */ + /*137*/ { -1, 10, { 0, 0, "" }, "AAA\200", 32, ZINT_ERROR_TOO_LONG, -1, -1 }, + /*138*/ { 3, 10, { 0, 0, "" }, "A", 46, 0, 16, 49 }, /* Version T-48 with ECI (9 less as PAD escape char + "\123456") */ + /*139*/ { 3, 10, { 0, 0, "" }, "A", 47, ZINT_ERROR_TOO_LONG, -1, -1 }, + /*140*/ { 3, 10, { 0, 0, "" }, "\001", 32, 0, 16, 49 }, + /*141*/ { 3, 10, { 0, 0, "" }, "\001", 33, ZINT_ERROR_TOO_LONG, -1, -1 }, }; int data_size = ARRAY_SIZE(data); int i, length, ret; - struct zint_symbol *symbol; + struct zint_symbol *symbol = NULL; char data_buf[4096]; - testStart("test_large"); + testStartSymbol("test_large", &symbol); for (i = 0; i < data_size; i++) { @@ -282,9 +284,9 @@ static void test_input(const testCtx *const p_ctx) { }; int data_size = ARRAY_SIZE(data); int i, length, ret; - struct zint_symbol *symbol; + struct zint_symbol *symbol = NULL; - testStart("test_input"); + testStartSymbol("test_input", &symbol); for (i = 0; i < data_size; i++) { @@ -2879,7 +2881,7 @@ static void test_encode(const testCtx *const p_ctx) { }; int data_size = ARRAY_SIZE(data); int i, length, ret; - struct zint_symbol *symbol; + struct zint_symbol *symbol = NULL; char escaped[8192]; char bwipp_buf[32768]; @@ -2887,7 +2889,7 @@ static void test_encode(const testCtx *const p_ctx) { int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ - testStart("test_encode"); + testStartSymbol("test_encode", &symbol); for (i = 0; i < data_size; i++) { @@ -3268,7 +3270,7 @@ static void test_encode_segs(const testCtx *const p_ctx) { }; int data_size = ARRAY_SIZE(data); int i, j, seg_count, ret; - struct zint_symbol *symbol; + struct zint_symbol *symbol = NULL; char escaped[8192]; char bwipp_buf[32768]; @@ -3276,7 +3278,7 @@ static void test_encode_segs(const testCtx *const p_ctx) { int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ - testStart("test_encode_segs"); + testStartSymbol("test_encode_segs", &symbol); for (i = 0; i < data_size; i++) { @@ -3364,9 +3366,10 @@ static void test_fuzz(const testCtx *const p_ctx) { struct item data[] = { /* 0*/ { -1, "3333P33B\035333V3333333333333\0363", -1, 0, 1, "" }, /* #181 Nico Gunkel, OSS-Fuzz */ /* 1*/ { -1, "{{-06\024755712162106130000000829203983\377", -1, 0, 1, "" }, /* #232 Jan Schrewe, CI-Fuzz, out-of-bounds in is_last_single_ascii() sp + 1 */ - /* 2*/ { -1, "\000\000\000\367\000\000\000\000\000\103\040\000\000\244\137\140\140\000\000\000\000\000\000\000\000\000\005\000\000\000\000\000\165\060\060\060\060\061\060\060\114\114\060\010\102\102\102\102\102\102\102\102\057\102\100\102\057\233\100\102", 60, 0, 1, "" }, /* #300 (#4) Andre Maute */ - /* 3*/ { 10, "\153\153\153\060\001\000\134\153\153\015\015\353\362\015\015\015\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\362\362\000", 65, ZINT_ERROR_TOO_LONG, 1, "" }, /* #300 (#8) Andre Maute */ + /* 2*/ { -1, "\000\000\000\367\000\000\000\000\000\103\040\000\000\244\137\140\140\000\000\000\000\000\000\000\000\000\005\000\000\000\000\000\165\060\060\060\060\061\060\060\114\114\060\010\102\102\102\102\102\102\102\102\057\102\100\102\057\233\100\102", 60, 0, 1, "" }, /* #300 (#4) Andre Maute (`c1_c40text_cnt()` not accounting for extended ASCII shifts) */ + /* 3*/ { 10, "\153\153\153\060\001\000\134\153\153\015\015\353\362\015\015\015\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\362\362\000", 65, ZINT_ERROR_TOO_LONG, 1, "" }, /* #300 (#8) Andre Maute (`c1_encode()` looping on latch) */ /* 4*/ { 10, "\015\015\353\362\015\015\015\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\110\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\362\362\000", 39, 0, 1, "" }, /* #300 (#8 shortened) Andre Maute */ + /* 5*/ { 10, "\153\153\153\153\153\060\001\000\000\134\153\153\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\153\153\153\153\153\153\043\000\000\307\000\147\000\000\000\043\113\153\162\162\215\220", 90, ZINT_ERROR_TOO_LONG, 1, "" }, /* #300 (#12) Andre Maute (too small buffer for Version T) */ }; int data_size = ARRAY_SIZE(data); int i, length, ret; diff --git a/backend/tests/test_composite.c b/backend/tests/test_composite.c index fd4a28d9..d048c333 100644 --- a/backend/tests/test_composite.c +++ b/backend/tests/test_composite.c @@ -3464,25 +3464,37 @@ static void test_fuzz(const testCtx *const p_ctx) { struct item { int symbology; int input_mode; + int option_1; char *data; int length; char *composite; int ret; + int bwipp_cmp; + char *comment; }; /* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */ struct item data[] = { - /* 0*/ { BARCODE_EANX_CC, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG }, - /* 1*/ { BARCODE_UPCA_CC, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG }, - /* 2*/ { BARCODE_UPCE_CC, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG }, - /* 3*/ { BARCODE_EANX_CC, -1, "+12345", -1, "[21]A12345678", 0 }, - /* 4*/ { BARCODE_EANX_CC, -1, "+123456", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG }, - /* 5*/ { BARCODE_EANX_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, "kks", -1, "()111%", ZINT_ERROR_INVALID_DATA }, /* #300 (#5), Andre Maute */ - /* 6*/ { BARCODE_UPCA_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\153\153\153\153\153\153\153\153\163", -1, "()90", ZINT_ERROR_TOO_LONG }, /* #300 (#6), Andre Maute */ + /* 0*/ { BARCODE_EANX_CC, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "" }, + /* 1*/ { BARCODE_UPCA_CC, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG , 1, ""}, + /* 2*/ { BARCODE_UPCE_CC, -1, -1, "+123456789012345678", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG , 1, ""}, + /* 3*/ { BARCODE_EANX_CC, -1, -1, "+12345", -1, "[21]A12345678", 0 , 0, "BWIPP checks for proper EAN data"}, + /* 4*/ { BARCODE_EANX_CC, -1, -1, "+123456", -1, "[21]A12345678", ZINT_ERROR_TOO_LONG, 1, "" }, + /* 5*/ { BARCODE_EANX_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, "kks", -1, "()111%", ZINT_ERROR_INVALID_DATA, 1, "" }, /* #300 (#5), Andre Maute (`dbar_date()` not checking length + other non-checks) */ + /* 6*/ { BARCODE_UPCA_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\153\153\153\153\153\153\153\153\163", -1, "()90", ZINT_ERROR_TOO_LONG, 1, "" }, /* #300 (#6), Andre Maute (`dbar_date()` not checking length + other non-checks) */ + /* 7*/ { BARCODE_UPCA_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\377\002\000\000\153\153\153\153\163\000\000\000\153\153\153\153\153\153\153\060\047\047\043\047\057\153\153\153\153\153\000\000\000\000\153\153\153\161\153\153\153\153\153\153\153\153\153\153\153\153\153\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\001\100\000\000\000\000\000\000\000\167\167\167\167\167\167\167\167\167\167\167\167\167\167", 127, "()904OOOOO)CK0336680OOOOOOOOOOOOOO29[0kkkk%%%%(", ZINT_ERROR_TOO_LONG, 1, "" }, /* #300 (#11), Andre Maute (`gs1_verify()` not checking length on resolve AI data loop) */ + /* 8*/ { BARCODE_EANX_CC, GS1PARENS_MODE | GS1NOCHECK_MODE, -1, "\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\153\225\215\153\153\153\153\153\153\263\153\153\377\002\000\000\153\153\153\153\163\000\000\000\153\153\153\153\153\153\153\060\047\047\043\047\057\153\153\153\153\153\000\000\000\000\153\153\153\161\153\153\153\153\153\153\153\153\153\153\153\153\153\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\167\001\100\000\000\000\000\000\000\000\167\167\167\167\167\167\167\167\167\167\167\167\167\167", 127, "()904OOOOO)CK0336680OOOOOOOOOOOOOO29[0kkkk%%%%(", ZINT_ERROR_TOO_LONG, 1, "" }, /* #300 (#11 with EANX_CC) */ + /* 9*/ { BARCODE_GS1_128_CC, GS1NOCHECK_MODE, 3, "[]28", -1, "[]RRR___________________KKKRRR0000", 0, 1, "" }, /* #300 (#13), Andre Maute (`calc_padding_ccc()` dividing by zero when linear width == 68) */ + /*10*/ { BARCODE_GS1_128_CC, GS1NOCHECK_MODE, 3, "[]2", -1, "[]RRR___________________KKKRRR0000", 0, 1, "" }, /* #300 (#13 shortened to min linear input (but same linear width 68)) */ }; int data_size = ARRAY_SIZE(data); int i, length, composite_length, ret; struct zint_symbol *symbol = NULL; + char bwipp_buf[32768]; + char bwipp_msg[1024]; + + int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */ + testStartSymbol("test_fuzz", &symbol); for (i = 0; i < data_size; i++) { @@ -3492,7 +3504,7 @@ static void test_fuzz(const testCtx *const p_ctx) { symbol = ZBarcode_Create(); assert_nonnull(symbol, "Symbol not created\n"); - length = testUtilSetSymbol(symbol, data[i].symbology, data[i].input_mode, -1 /*eci*/, -1 /*option_1*/, -1, -1, -1 /*output_options*/, data[i].data, -1, debug); + length = testUtilSetSymbol(symbol, data[i].symbology, data[i].input_mode, -1 /*eci*/, data[i].option_1, -1, -1, -1 /*output_options*/, data[i].data, -1, debug); assert_zero(length >= 128, "i:%d length %d >= 128\n", i, length); strcpy(symbol->primary, data[i].data); @@ -3501,6 +3513,23 @@ static void test_fuzz(const testCtx *const p_ctx) { ret = ZBarcode_Encode(symbol, (const unsigned char *) data[i].composite, composite_length); assert_equal(ret, data[i].ret, "i:%d ZBarcode_Encode ret %d != %d (%s)\n", i, ret, data[i].ret, symbol->errtxt); + if (ret < ZINT_ERROR) { + if (do_bwipp && testUtilCanBwipp(i, symbol, data[i].option_1, -1, -1, debug)) { + if (!data[i].bwipp_cmp) { + if (debug & ZINT_DEBUG_TEST_PRINT) printf("i:%d %s not BWIPP compatible (%s)\n", i, testUtilBarcodeName(symbol->symbology), data[i].comment); + } else { + char modules_dump[32768]; + assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1, "i:%d testUtilModulesDump == -1\n", i); + ret = testUtilBwipp(i, symbol, data[i].option_1, -1, -1, data[i].composite, composite_length, symbol->primary, 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, modules_dump); + 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, modules_dump); + } + } + } + ZBarcode_Delete(symbol); } diff --git a/backend/tests/test_pdf417.c b/backend/tests/test_pdf417.c index d1119e85..bd6532b9 100644 --- a/backend/tests/test_pdf417.c +++ b/backend/tests/test_pdf417.c @@ -5356,7 +5356,7 @@ static void test_fuzz(const testCtx *const p_ctx) { "\000\000\000\000\000\000\000\000\323\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" "\000\000\000\000\000\000\000\000", 1048, 0, 0, "BWIPP different encodation" - }, /* #300 (#1) Andre Maute */ + }, /* #300 (#1) Andre Maute (`pdf_text_submode_length()` not checking if previous/next BYT) */ /* 29*/ { BARCODE_PDF417, DATA_MODE | FAST_MODE, -1, -1, "\060\060\060\060\060\060\060\060\060\060\060\162\162\162\162\162\162\162\162\162\162\047\122\162\000\000\167\211\206\001\000\047\153\153\153\153\153\067\066\164" "\060\060\060\060\060\060\060\060\060\060\060\162\162\162\162\162\162\162\162\162\162\047\122\162\000\000\167\211\206\001\000\047\153\153\153\153\153\153\153\164" diff --git a/backend/tests/tools/bwipp_dump.ps.tar.xz b/backend/tests/tools/bwipp_dump.ps.tar.xz index b79b646d..ca852e56 100644 Binary files a/backend/tests/tools/bwipp_dump.ps.tar.xz and b/backend/tests/tools/bwipp_dump.ps.tar.xz differ diff --git a/backend/tools/gen_gs1_lint.php b/backend/tools/gen_gs1_lint.php index ed71bb7e..47dfccde 100644 --- a/backend/tools/gen_gs1_lint.php +++ b/backend/tools/gen_gs1_lint.php @@ -55,13 +55,13 @@ foreach ($lines as $line) { if ($line === '' || $line[0] === '#') { continue; } - if (!preg_match('/^([0-9]+(?:-[0-9]+)?) +([ *] )([NXYZ][0-9.][ NXYZ0-9.,a-z=|\[\]]*)(?:# (.+))?$/', $line, $matches)) { + if (!preg_match('/^([0-9]+(?:-[0-9]+)?) +([ *] )([NXYZ][0-9.][ NXYZ0-9.,a-z=|+\[\]]*)(?:# (.+))?$/', $line, $matches)) { print $line . PHP_EOL; exit("$basename:" . __LINE__ . " ERROR: Could not parse line $line_no" . PHP_EOL); } $ai = $matches[1]; $fixed = trim($matches[2]); - $spec = preg_replace('/ +req=[0-9,n]*/', '', trim($matches[3])); // Strip mandatory association info + $spec = preg_replace('/ +req=[0-9,n+]*/', '', trim($matches[3])); // Strip mandatory association info $spec = preg_replace('/ +ex=[0-9,n]*/', '', $spec); // Strip invalid pairings info $spec = preg_replace('/ +dlpkey[=0-9,|]*/', '', $spec); // Strip Digital Link primary key info $comment = isset($matches[4]) ? trim($matches[4]) : '';