1
0
mirror of https://git.code.sf.net/p/zint/code synced 2026-01-16 08:26:03 +00:00

CODE128: fix not handling FNC1 at end of data when in manual

switching mode or any FNC1 after manual C mode selected and no
  other non-C data - found by fuzz test "fuzz_data" - 2nd ever
  trophy!
qr.h: fix typo (props https://github.com/crate-ci/typos)
This commit is contained in:
gitlost
2026-01-12 20:38:15 +00:00
parent a718c79237
commit 6e533c7a0a
8 changed files with 158 additions and 41 deletions

View File

@@ -1,4 +1,4 @@
Version 2.16.0.9 (dev) not released yet (2025-12-31)
Version 2.16.0.9 (dev) not released yet (2025-01-12)
====================================================
**Incompatible changes**
@@ -15,6 +15,8 @@ Changes
Bugs
----
- CODE128: fix not handling FNC1 at end of data when in manual switching mode
or any FNC1 after manual C mode selected and no other non-C data
- CLI: fix "--scalexdimdp" X-dim inch units being divided instead of multiplied
on conversion to mm

View File

@@ -1,7 +1,7 @@
/* code128.c - Handles Code 128 and GS1-128 */
/*
libzint - the open source barcode library
Copyright (C) 2008-2025 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2008-2026 Robin Stuart <rstuart114@gmail.com>
Bugfixes thanks to Christian Sakowski and BogDan Vatra
Redistribution and use in source and binary forms, with or without
@@ -446,21 +446,24 @@ INTERNAL int zint_code128(struct zint_symbol *symbol, unsigned char source[], in
have_a |= !mask_0x60;
have_b |= mask_0x60 == 0x60;
}
} else if (have_fnc1) {
have_a = have_b = have_c = 1;
for (i = 0; i < length; i++) {
have_extended |= src[i] & 0x80;
}
} else {
int prev_digit, digit = 0;
for (i = 0; i < length; i++) {
const unsigned char ch = src[i];
const int is_fnc1 = ch == '\x1D' && fncs[i];
if (!is_fnc1) {
const unsigned char mask_0x60 = ch & 0x60; /* 0 for (ch & 0x7F) < 32, 0x60 for (ch & 0x7F) >= 96 */
const int manual = manuals[i];
have_extended |= ch & 0x80;
have_a |= !mask_0x60 || manual == C128_A0;
have_b |= mask_0x60 == 0x60 || manual == C128_B0;
prev_digit = digit;
digit = z_isdigit(ch);
have_c |= prev_digit && digit;
}
const unsigned char mask_0x60 = ch & 0x60; /* 0 for (ch & 0x7F) < 32, 0x60 for (ch & 0x7F) >= 96 */
const int manual = manuals[i];
assert(!(ch == '\x1D' && fncs[i])); /* Can't be FNC1 */
have_extended |= ch & 0x80;
have_a |= !mask_0x60 || manual == C128_A0;
have_b |= mask_0x60 == 0x60 || manual == C128_B0;
prev_digit = digit;
digit = z_isdigit(ch);
have_c |= prev_digit && digit;
}
}
c128_set_priority(priority, have_a, have_b, have_c, have_extended);

View File

@@ -336,7 +336,7 @@ static const unsigned int rmqr_format_info_right[64] = {
};
/* Pre-calculated QR and MicroQR mask tables, generated by "backend/tools/gen_qr_masks.php",
based on lowest common periodicy of the masks (6x12):
based on lowest common periodicity of the masks (6x12):
QR: 000: 2x2, 001: 1x2, 010: 3x1, 011: 3x3, 100: 6x4, 101: 6x6, 110: 6x6, 111: 6x6
MicroQR: 00 (001), 01 (100), 10 (110), 11 (111)
Taken from Barcode Writer in Pure PostScript (BWIPP)

View File

@@ -14,7 +14,7 @@
/* NOLINTEND(clang-diagnostic-comment) */
/*
libzint - the open source barcode library
Copyright (C) 2024-2025 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2024-2026 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -866,6 +866,15 @@ static const struct item data_data[] = {
/* 40*/ { 6, BARCODE_DOTCODE, -1, -1, -1, -1, -1, "\237", -1 }, /* As above L1090 */
/* 41*/ { 0, BARCODE_MAXICODE, -1, -1, -1, -1, -1, "\223\223\223\223\223\200\000\060\060\020\122\104\060\343\000\000\040\104\104\104\104\177\377\040\000\324\336\000\000\000\000\104\060\060\060\060\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\104\060\104\104\000\000\000\040\104\104\104\104\177\377\377\377\324\336\000\000\000\000\104\377\104\001\104\104\104\104\104\104\233\233\060\060\060\060\060\060\060\060\060\325\074", 107 }, /* #181 Nico Gunkel OSS-Fuzz - original OSS-Fuzz triggering data */
/* 42*/ { 1, BARCODE_MAXICODE, -1, -1, -1, -1, -1, "AaAaAaAaAaAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA123456789", -1 }, /* Add 6 lowercase a's so 6 SHIFTS inserted so 6 + 138 (max input len) = 144 and numbers come at end of buffer */
/* 43*/ { 0, BARCODE_CODE128, DATA_MODE | EXTRA_ESCAPE_MODE, -1, -1, -1, -1,
"\003\134\136\103\103\103\103\103\103\103\103\103\103\103\103\103\103\103\103\103\103\000\000\051\000\054\103\103\103\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\242\053\134\136\061\067\242\242\242\242\242"
"\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242"
"\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242"
"\136\136",
162
}, /* fuzz_data (1st) */
};
/* GS1_MODE data */

View File

@@ -1,6 +1,6 @@
/*
libzint - the open source barcode library
Copyright (C) 2020-2025 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2020-2026 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -106,7 +106,7 @@ static void test_large(const testCtx *const p_ctx) {
char cmp_msg[1024];
char ret_buf[8192] = {0}; /* Suppress clang -fsanitize=memory false positive */
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
/* Only do BWIPP/zxing-cpp tests if asked, too slow otherwise */
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript();
int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder();
@@ -294,7 +294,7 @@ static void test_hrt(const testCtx *const p_ctx) {
char cmp_msg[1024];
char ret_buf[8192];
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
/* Only do BWIPP/zxing-cpp tests if asked, too slow otherwise */
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript();
int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder();
@@ -419,7 +419,7 @@ static void test_reader_init(const testCtx *const p_ctx) {
char cmp_msg[1024];
char ret_buf[8192];
/* Only do ZXing-C++ test if asked, too slow otherwise */
/* Only do zxing-cpp test if asked, too slow otherwise */
int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder();
testStartSymbol(p_ctx->func_name, &symbol);
@@ -649,6 +649,17 @@ static void test_input(const testCtx *const p_ctx) {
/*139*/ { UNICODE_MODE, "12é12é", -1, 0, 123, 0, 1, "(11) 105 12 100 100 73 17 18 100 73 17 106", "StartC 12 CodeB FNC4 é 1 2 FNC4 é; BWIPP different encodation (StartB)" },
/*140*/ { UNICODE_MODE, "1234é123456é", -1, 0, 167, 1, 1, "(15) 105 12 34 100 100 73 99 12 34 56 100 100 73 15 106", "StartC 12 34 CodeB FNC4 é CodeC 12 34 56 CodeB FNC4 é" },
/*141*/ { DATA_MODE, "\256^a\357\033\270\017,\274u$B\305\311\006\011]\273\025u\315\2638\263\333", -1, 0, 453, 1, 899, "(41) 104 100 14 62 65 100 79 101 91 101 24 79 12 101 28 98 85 4 34 101 37 101 41 70 73 61", "" },
/*142*/ { DATA_MODE | EXTRA_ESCAPE_MODE, "\\^C\\^1", -1, 0, 46, 0, 0, "(4) 105 102 1 106", "StartC FNC1; From fuzz 2026-01-12; BWIPP see below; zxing-cpp empty text" },
/*143*/ { DATA_MODE | EXTRA_ESCAPE_MODE, "\\^A\\^1", -1, 0, 46, 0, 0, "(4) 103 102 102 106", "StartA FNC1; From fuzz 2026-01-12; BWIPP see below; zxing-cpp empty text" },
/*144*/ { DATA_MODE | EXTRA_ESCAPE_MODE, "\\^B\\^1", -1, 0, 46, 1, 0, "(4) 104 102 0 106", "StartB FNC1; From fuzz 2026-01-12; zxing-cpp empty text" },
/*145*/ { DATA_MODE | EXTRA_ESCAPE_MODE, "\\^1", -1, 0, 46, 0, 0, "(4) 105 102 1 106", "StartC FNC1; BWIPP see above; zxing-cpp empty text" },
/*146*/ { DATA_MODE | EXTRA_ESCAPE_MODE, "\\^C\\^1A", -1, 0, 68, 0, 3, "(6) 105 102 100 33 94 106", "StartC CodeB FNC1 A; BWIPP see below" },
/*147*/ { DATA_MODE | EXTRA_ESCAPE_MODE, "\\^A\\^1A", -1, 0, 57, 0, 3, "(5) 103 102 33 65 106", "StartA FNC1 A; BWIPP see below" },
/*148*/ { DATA_MODE | EXTRA_ESCAPE_MODE, "\\^B\\^1A", -1, 0, 57, 1, 3, "(5) 104 102 33 66 106", "StartB FNC1 A" },
/*149*/ { DATA_MODE | EXTRA_ESCAPE_MODE, "\\^1A", -1, 0, 57, 1, 3, "(5) 104 102 33 66 106", "StartB FNC1 A" },
/*150*/ { DATA_MODE | EXTRA_ESCAPE_MODE, "A\\^1", -1, 0, 57, 1, 3, "(5) 104 33 102 32 106", "StartB A FNC1" },
/*151*/ { DATA_MODE | EXTRA_ESCAPE_MODE, "\\^C\\^112", -1, 0, 57, 1, 3, "(5) 105 102 12 25 106", "StartC FNC1 12" },
/*152*/ { UNICODE_MODE | EXTRA_ESCAPE_MODE, "\\^C\\^1é", -1, 0, 79, 0, 1, "(7) 105 102 100 100 73 72 106", "StartC FNC1 CodeB FNC4 é; BWIPP different encodation (StartB)" },
};
const int data_size = ARRAY_SIZE(data);
int i, length, ret;
@@ -660,7 +671,7 @@ static void test_input(const testCtx *const p_ctx) {
char cmp_msg[1024];
char ret_buf[8192];
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
/* Only do BWIPP/zxing-cpp tests if asked, too slow otherwise */
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript();
int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder();
@@ -719,22 +730,28 @@ static void test_input(const testCtx *const p_ctx) {
}
}
if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data[i].data, length, debug)) {
int cmp_len, ret_len;
char modules_dump[4096];
assert_nonzero(data[i].zxingcpp_cmp, "i:%d data[i].zxingcpp_cmp == 0", i);
assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1,
"i:%d testUtilModulesDump == -1\n", i);
ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, data[i].zxingcpp_cmp,
cmp_buf, sizeof(cmp_buf), &cmp_len);
assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n",
i, testUtilBarcodeName(symbol->symbology), ret);
if (!data[i].zxingcpp_cmp) {
if (debug & ZINT_DEBUG_TEST_PRINT) {
printf("i:%d %s not zxing-cpp compatible (%s)\n",
i, testUtilBarcodeName(symbol->symbology), data[i].comment);
}
} else {
int cmp_len, ret_len;
char modules_dump[4096];
assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1,
"i:%d testUtilModulesDump == -1\n", i);
ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, data[i].zxingcpp_cmp,
cmp_buf, sizeof(cmp_buf), &cmp_len);
assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n",
i, testUtilBarcodeName(symbol->symbology), ret);
ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length,
NULL /*primary*/, ret_buf, &ret_len);
assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %s\nexpected: %s\n",
i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg,
testUtilEscape(cmp_buf, cmp_len, escaped, sizeof(escaped)),
testUtilEscape(ret_buf, ret_len, escaped2, sizeof(escaped2)));
ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length,
NULL /*primary*/, ret_buf, &ret_len);
assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %s\nexpected: %s\n",
i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg,
testUtilEscape(cmp_buf, cmp_len, escaped, sizeof(escaped)),
testUtilEscape(ret_buf, ret_len, escaped2, sizeof(escaped2)));
}
}
}
}
@@ -798,7 +815,7 @@ static void test_gs1_128_input(const testCtx *const p_ctx) {
char cmp_msg[1024];
char ret_buf[8192];
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
/* Only do BWIPP/zxing-cpp tests if asked, too slow otherwise */
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript();
int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder();
@@ -924,7 +941,7 @@ static void test_hibc_input(const testCtx *const p_ctx) {
char cmp_msg[1024];
char ret_buf[8192];
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
/* Only do BWIPP/zxing-cpp tests if asked, too slow otherwise */
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript();
int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder();
@@ -1215,7 +1232,7 @@ static void test_dpd_input(const testCtx *const p_ctx) {
char cmp_msg[1024];
char ret_buf[8192];
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
/* Only do BWIPP/zxing-cpp tests if asked, too slow otherwise */
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript();
int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder();
@@ -1340,8 +1357,8 @@ static void test_upu_s10_input(const testCtx *const p_ctx) {
char cmp_msg[1024];
char ret_buf[8192];
/* Only do ZXing-C++ test if asked, too slow otherwise */
/* Only do ZXing-C++ test if asked, too slow otherwise */
/* Only do zxing-cpp test if asked, too slow otherwise */
/* Only do zxing-cpp test if asked, too slow otherwise */
int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder();
testStartSymbol(p_ctx->func_name, &symbol);
@@ -1587,7 +1604,7 @@ static void test_encode(const testCtx *const p_ctx) {
char cmp_msg[1024];
char ret_buf[8192];
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
/* Only do BWIPP/zxing-cpp tests if asked, too slow otherwise */
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript();
int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder();
@@ -1673,6 +1690,91 @@ static void test_encode(const testCtx *const p_ctx) {
testFinish();
}
static void test_fuzz(const testCtx *const p_ctx) {
int debug = p_ctx->debug;
struct item {
int symbology;
int input_mode;
int option_1;
int option_2;
const char *data;
int length;
int ret;
const char *expected_errtxt;
int zxingcpp_cmp;
};
/* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */
static const struct item data[] = {
/* 0*/ { BARCODE_CODE128, DATA_MODE | EXTRA_ESCAPE_MODE, -1, -1,
"\003\134\136\103\103\103\103\103\103\103\103\103\103\103\103\103\103\103\103\103\103\000\000\051\000\054\103\103\103\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\242\053\134\136\061\067\242\242\242\242\242"
"\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242"
"\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242\242"
"\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) */
};
const int data_size = ARRAY_SIZE(data);
int i, length, ret;
struct zint_symbol *symbol = NULL;
char escaped[8192];
char cmp_buf[32768];
char cmp_msg[8192];
/* Only do zxing-cpp test if asked, too slow otherwise */
int do_zxingcpp = (debug & ZINT_DEBUG_TEST_ZXINGCPP) && testUtilHaveZXingCPPDecoder();
testStartSymbol(p_ctx->func_name, &symbol);
for (i = 0; i < data_size; i++) {
if (testContinue(p_ctx, i)) continue;
symbol = ZBarcode_Create();
assert_nonnull(symbol, "Symbol not created\n");
length = testUtilSetSymbol(symbol, data[i].symbology, data[i].input_mode, -1 /*eci*/,
data[i].option_1, data[i].option_2, -1 /*option_3*/, -1 /*output_options*/,
data[i].data, data[i].length, 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(symbol->errtxt[0] == '\0', ret == 0, "i:%d symbol->errtxt not %s (%s)\n",
i, ret ? "set" : "empty", symbol->errtxt);
assert_zero(strcmp(symbol->errtxt, data[i].expected_errtxt), "i:%d symbol->errtxt %s != %s\n",
i, symbol->errtxt, data[i].expected_errtxt);
if (ret < ZINT_ERROR) {
if (do_zxingcpp && testUtilCanZXingCPP(i, symbol, data[i].data, length, debug)) {
int cmp_len, ret_len;
char modules_dump[22801 + 1];
assert_nonzero(data[i].zxingcpp_cmp, "i:%d data[i].zxingcpp_cmp == 0", i);
assert_notequal(testUtilModulesDump(symbol, modules_dump, sizeof(modules_dump)), -1,
"i:%d testUtilModulesDump == -1\n", i);
ret = testUtilZXingCPP(i, symbol, data[i].data, length, modules_dump, data[i].zxingcpp_cmp,
cmp_buf, sizeof(cmp_buf), &cmp_len);
assert_zero(ret, "i:%d %s testUtilZXingCPP ret %d != 0\n",
i, testUtilBarcodeName(symbol->symbology), ret);
ret = testUtilZXingCPPCmp(symbol, cmp_msg, cmp_buf, cmp_len, data[i].data, length, NULL /*primary*/,
escaped, &ret_len);
assert_zero(ret, "i:%d %s testUtilZXingCPPCmp %d != 0 %s\n actual: %.*s\nexpected: %.*s\n",
i, testUtilBarcodeName(symbol->symbology), ret, cmp_msg, cmp_len, cmp_buf, ret_len,
escaped);
}
}
ZBarcode_Delete(symbol);
}
testFinish();
}
int main(int argc, char *argv[]) {
testFunction funcs[] = { /* name, func */
@@ -1687,6 +1789,7 @@ int main(int argc, char *argv[]) {
{ "test_dpd_input", test_dpd_input },
{ "test_upu_s10_input", test_upu_s10_input },
{ "test_encode", test_encode },
{ "test_fuzz", test_fuzz },
};
testRun(argc, argv, funcs, ARRAY_SIZE(funcs));