diff --git a/backend/common.c b/backend/common.c index 9ba3b326..34661da0 100644 --- a/backend/common.c +++ b/backend/common.c @@ -128,10 +128,22 @@ int posn(const char set_string[], const char data) { for (i = 0; i < n; i++) { if (data == set_string[i]) { - return i; + return i; } } - return -1; + return -1; +} + +/* Returns the number of times a character occurs in a string */ +int ustrchr_cnt(const unsigned char string[], const size_t length, const unsigned char c) { + int count = 0; + int i; + for (i = 0; i < length; i++) { + if (string[i] == c) { + count++; + } + } + return count; } /* Return true (1) if a module is dark/black, otherwise false (0) */ diff --git a/backend/common.h b/backend/common.h index 7e1cfab3..3bb535d8 100644 --- a/backend/common.h +++ b/backend/common.h @@ -63,6 +63,7 @@ extern "C" { extern void lookup(const char set_string[], const char *table[], const char data, char dest[]); extern void bin_append(const int arg, const int length, char *binary); extern int posn(const char set_string[], const char data); + extern int ustrchr_cnt(const unsigned char string[], const size_t length, const unsigned char c); extern int module_is_set(const struct zint_symbol *symbol, const int y_coord, const int x_coord); extern void set_module(struct zint_symbol *symbol, const int y_coord, const int x_coord); extern int istwodigits(const unsigned char source[], const size_t position); diff --git a/backend/composite.c b/backend/composite.c index e9ba370f..7d057e5f 100644 --- a/backend/composite.c +++ b/backend/composite.c @@ -899,7 +899,6 @@ int calc_padding_ccc(int binary_length, int *cc_width, int lin_width, int *ecc) int target_bitsize = 0; int byte_length, codewords_used, ecc_level, ecc_codewords, rows; int codewords_total, target_codewords, target_bytesize; - int i; byte_length = binary_length / 8; if (binary_length % 8 != 0) { @@ -909,48 +908,47 @@ int calc_padding_ccc(int binary_length, int *cc_width, int lin_width, int *ecc) codewords_used = (byte_length / 6) * 5; codewords_used += byte_length % 6; - ecc_level = 7; - if (codewords_used <= 1280) { - ecc_level = 6; - } - if (codewords_used <= 640) { - ecc_level = 5; - } - if (codewords_used <= 320) { - ecc_level = 4; - } - if (codewords_used <= 160) { - ecc_level = 3; - } + /* Recommended minimum ecc levels ISO/IEC 1543:2015 (PDF417) Annex E Table E.1, + restricted by CC-C codeword max 900 (30 cols * 30 rows), GS1 General Specifications 19.1 5.9.2.3 */ if (codewords_used <= 40) { ecc_level = 2; + } else if (codewords_used <= 160) { + ecc_level = 3; + } else if (codewords_used <= 320) { + ecc_level = 4; + } else if (codewords_used <= 833) { /* 900 - 3 - 64 */ + ecc_level = 5; + } else if (codewords_used <= 865) { /* 900 - 3 - 32 */ + ecc_level = 4; /* Not recommended but allow to meet advertised "up to 2361 digits" (allows max 2372) */ + } else { + return 0; } *(ecc) = ecc_level; - ecc_codewords = 1; - for (i = 1; i <= (ecc_level + 1); i++) { - ecc_codewords *= 2; - } + ecc_codewords = 1 << (ecc_level + 1); codewords_used += ecc_codewords; codewords_used += 3; - *(cc_width) = (lin_width - 62) / 17; + *(cc_width) = (lin_width - 53) / 17; // -53 = (6 left quiet zone + 10 right quiet zone - (17 * 3 + 18)) + if (*(cc_width) > 30) { + *(cc_width) = 30; + } + rows = ceil((double) codewords_used / *(cc_width)); /* stop the symbol from becoming too high */ - do { + while (rows > 30 && *(cc_width) < 30) { *(cc_width) = *(cc_width) + 1; - rows = codewords_used / *(cc_width); - } while (rows > 90); + rows = ceil((double) codewords_used / *(cc_width)); + } - if (codewords_used % *(cc_width) != 0) { - rows++; + if (rows > 30) { + return 0; + } + if (rows < 3) { + rows = 3; } codewords_total = *(cc_width) * rows; - if (codewords_total > 928) { // PDF_MAX - return 0; - } - target_codewords = codewords_total - ecc_codewords; target_codewords -= 3; @@ -1368,14 +1366,13 @@ int linear_dummy_run(unsigned char *source, int length) { int composite(struct zint_symbol *symbol, unsigned char source[], int length) { int error_number, cc_mode, cc_width, ecc_level; int j, i, k; - unsigned int rs = length + 1; - unsigned int bs = 20 * rs; - unsigned int pri_len; + unsigned int bs = 13 * length + 500 + 1; /* Allow for 8 bits + 5-bit latch per char + 500 bits overhead/padding */ #ifndef _MSC_VER char binary_string[bs]; #else char* binary_string = (char*) _alloca(bs); #endif + unsigned int pri_len; struct zint_symbol *linear; int top_shift, bottom_shift; int linear_width = 0; diff --git a/backend/gs1.c b/backend/gs1.c index bb6969db..3391a9c1 100644 --- a/backend/gs1.c +++ b/backend/gs1.c @@ -29,6 +29,7 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* vim: set ts=4 sw=4 et : */ #include #include @@ -73,7 +74,16 @@ int gs1_verify(struct zint_symbol *symbol, const unsigned char source[], const s int i, j, last_ai, ai_latch; char ai_string[6]; int bracket_level, max_bracket_level, ai_length, max_ai_length, min_ai_length; - int ai_value[100], ai_location[100], ai_count, data_location[100], data_length[100]; + int ai_count; + int ai_max = ustrchr_cnt(source, src_len, '['); +#ifndef _MSC_VER + int ai_value[ai_max], ai_location[ai_max], data_location[ai_max], data_length[ai_max]; +#else + int ai_value = (int*) _alloca(ai_max * sizeof(int)); + int ai_location = (int*) _alloca(ai_max * sizeof(int)); + int data_location = (int*) _alloca(ai_max * sizeof(int)); + int data_length = (int*) _alloca(ai_max * sizeof(int)); +#endif int error_latch; /* Detect extended ASCII characters */ diff --git a/backend/rss.c b/backend/rss.c index 53d73aa1..b6b331ac 100644 --- a/backend/rss.c +++ b/backend/rss.c @@ -1463,7 +1463,7 @@ int rss_binary_string(struct zint_symbol *symbol, char source[], char binary_str if (debug) printf("\tLength: %d\n", (int) strlen(binary_string)); } - if (strlen(binary_string) > 252) { + if (strlen(binary_string) > 252) { /* 252 = (21 * 12) */ strcpy(symbol->errtxt, "387: Input too long"); return ZINT_ERROR_TOO_LONG; } @@ -1516,11 +1516,12 @@ int rssexpanded(struct zint_symbol *symbol, unsigned char source[], int src_len) int char_widths[21][8], checksum, check_widths[8], c_group; int check_char, c_odd, c_even, elements[235], pattern_width, reader, writer; int separator_row; + unsigned int bin_len = 13 * src_len + 200 + 1; /* Allow for 8 bits + 5-bit latch per char + 200 bits overhead/padding */ #ifndef _MSC_VER - char reduced[src_len + 1], binary_string[(7 * src_len) + 1]; + char reduced[src_len + 1], binary_string[bin_len]; #else char* reduced = (char*) _alloca(src_len + 1); - char* binary_string = (char*) _alloca((7 * src_len) + 1); + char* binary_string = (char*) _alloca(bin_len); #endif separator_row = 0; diff --git a/backend/tests/test_composite.c b/backend/tests/test_composite.c index 5a18fd0d..790e545a 100644 --- a/backend/tests/test_composite.c +++ b/backend/tests/test_composite.c @@ -34,6 +34,7 @@ //#define TEST_EXAMPLES_GENERATE_EXPECTED 1 //#define TEST_ODD_NUMBERED_NUMERIC_GENERATE_EXPECTED 1 //#define TEST_EAN128_CC_SHIFT_GENERATE_EXPECTED 1 +//#define TEST_EAN128_CC_WIDTH_GENERATE_EXPECTED 1 //#define TEST_ENCODATION_0_GENERATE_EXPECTED 1 //#define TEST_ENCODATION_10_GENERATE_EXPECTED 1 //#define TEST_ENCODATION_11_GENERATE_EXPECTED 1 @@ -282,6 +283,15 @@ static void test_examples(void) "000000111001111101010100001010100101011111000010100000000000000000000000000000000000000000000000000000" "010111000110000010100011110000001010100000111101000100000000000000000000000000000000000000000000000000" }, + /*13*/ { BARCODE_EAN128_CC, "[00]030123456789012340", "[02]13012345678909[37]24[10]1234567ABCDEFG", 3, 0, 0, 0, 7, 174, "24723:2010 Figure 12 — A GS1-128 Composite symbol (with CC-C)", + "111111110101010001111010101111000011010111011110000111011111011101001000001000010001011110101100111110111010010001110001000100011000011011111010100111110111111101000101001000" + "111111110101010001111110101000111010000100111101000110011110101111101111010001010000011111000110010100111001011100011001001001111101100011111101010111000111111101000101001000" + "111111110101010001010100011110000011001111100001010110100010111110001110111101011100011000001101011110101111001000000101100001011111101011101010001111110111111101000101001000" + "111111110101010001010111100111100011110100001011110101011111011111001101010000110000011010011100011110101111001111010001100011101101000011101001011100000111111101000101001000" + "111111110101010001110101110000110011111010100011000100100001111000101110000001011001011110010110001100111100101101100001111011000110100011101011100110000111111101000101001000" + "000000000101100011000010100010010011001101101100111001100100110001001000101000100111011110100110010010000100110010011000100100010011101011101000010001000100001010011100010100" + "000000011010011100111101011101101100110010010011000110011011001110110111010111011000100001011001101101111011001101100111011011101100010100010111101110111011110101100011101011" + }, }; int data_size = sizeof(data) / sizeof(struct item); @@ -579,6 +589,69 @@ static void test_ean128_cc_shift(void) testFinish(); } +static void test_ean128_cc_width(void) +{ + testStart(""); + + int ret; + struct item { + unsigned char* data; + unsigned char* composite; + int ret; + + int expected_rows; + int expected_width; + char* comment; + }; + // Verified manually with bwipp (except very large tests) + struct item data[] = { + /* 0*/ { "[91]1", "[02]13012345678909", 0, 11, 103, "" }, + /* 1*/ { "[91]12", "[02]13012345678909", 0, 20, 86, "" }, + /* 2*/ { "[91]123", "[02]13012345678909", 0, 11, 108, "" }, + /* 3*/ { "[91]123A", "[02]13012345678909", 0, 8, 120, "" }, + /* 4*/ { "[91]123A1", "[02]13012345678909", 0, 7, 137, "" }, + /* 5*/ { "[91]123A12", "[02]13012345678909", 0, 7, 141, "" }, + /* 6*/ { "[91]123A123", "[02]13012345678909", 0, 6, 154, "" }, + /* 7*/ { "[91]123A1234", "[02]13012345678909", 0, 6, 154, "" }, + /* 8*/ { "[91]123A1234A", "[02]13012345678909", 0, 5, 174, "" }, + /* 9*/ { "[91]123A1234A1", "[02]13012345678909", 0, 5, 188, "" }, + /*10*/ { "[91]123A1234A12", "[02]13012345678909", 0, 5, 205, "" }, + /*11*/ { "[00]123456789012345678", "[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[91]1234567890", 0, 32, 579, "With composite 2372 digits == max" }, + /*12*/ { "[00]123456789012345678", "[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[00]123456789012345678[91]12345678901", ZINT_ERROR_TOO_LONG, 0, 0, "With composite 2373 digits > max" }, + }; + int data_size = sizeof(data) / sizeof(struct item); + + for (int i = 0; i < data_size; i++) { + + struct zint_symbol* symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + symbol->symbology = BARCODE_EAN128_CC; + symbol->option_1 = 3; + int length = strlen(data[i].data); + assert_zero(length >= 128, "i:%d length %d >= 128\n", i, length); + strcpy(symbol->primary, data[i].data); + + int composite_length = strlen(data[i].composite); + + ret = ZBarcode_Encode(symbol, data[i].composite, composite_length); + assert_equal(ret, data[i].ret, "i:%d ret %d != %d %s\n", i, ret, data[i].ret, symbol->errtxt); + + #ifdef TEST_EAN128_CC_WIDTH_GENERATE_EXPECTED + printf(" /*%2d*/ { \"%s\", \"%s\", %s, %d, %d, \"%s\" },\n", + i, data[i].data, data[i].composite, testUtilErrorName(ret), symbol->rows, symbol->width, data[i].comment); + #else + + 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); + #endif + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + // Test general-purpose data compaction static void test_encodation_0(void) { @@ -1539,13 +1612,14 @@ static void test_encodation_11(void) int main() { + test_eanx_leading_zeroes(); test_examples(); test_odd_numbered_numeric(); test_ean128_cc_shift(); + test_ean128_cc_width(); test_encodation_0(); test_encodation_10(); test_encodation_11(); - test_eanx_leading_zeroes(); testReport(); diff --git a/backend/tests/test_rss.c b/backend/tests/test_rss.c index 379ed733..d4ded5b7 100644 --- a/backend/tests/test_rss.c +++ b/backend/tests/test_rss.c @@ -34,6 +34,7 @@ //#define TEST_RSS_BINARY_DIV_MODULO_DIVISOR_GENERATE_EXPECTED 1 //#define TEST_EXAMPLES_GENERATE_EXPECTED 1 //#define TEST_GENERAL_FIELD_GENERATE_EXPECTED 1 +//#define TEST_BINARY_BUFFER_SIZE_GENERATE_EXPECTED 1 static void test_binary_div_modulo_divisor(void) { @@ -533,11 +534,63 @@ static void test_general_field(void) testFinish(); } +static void test_binary_buffer_size(void) +{ + testStart(""); + + int ret; + struct item { + unsigned char* data; + int ret; + + int expected_rows; + int expected_width; + char* comment; + }; + struct item data[] = { + /* 0*/ { "[91]1", 0, 1, 102, "Minimum digit" }, + /* 1*/ { "[91]+", 0, 1, 102, "Minimum ISO-646" }, + /* 2*/ { "[00]123456789012345678[00]123456789012345678[00]123456789012345678[91]12345678", 0, 1, 543, "70 == any AIs max" }, + /* 3*/ { "[00]123456789012345678[00]123456789012345678[00]123456789012345678[91]123456789", ZINT_ERROR_TOO_LONG, 0, 0, "71 > any AIs max" }, + /* 4*/ { "[01]12345678901234[00]123456789012345678[00]123456789012345678[91]1234567890123456", 0, 1, 543, "74 == 01 + other AIs max" }, + /* 5*/ { "[01]12345678901234[00]123456789012345678[00]123456789012345678[91]12345678901234567", ZINT_ERROR_TOO_LONG, 0, 0, "75 > 01 + other AIs max" }, + /* 6*/ { "[01]92345678901234[3920]123456789012345[00]123456789012345678[91]1234567890123456789", 0, 1, 543, "77 (incl. FNC1 after 3920) == 01 + 392x + other AIs max" }, + /* 7*/ { "[01]92345678901234[3920]123456789012345[00]123456789012345678[91]12345678901234567890", ZINT_ERROR_TOO_LONG, 0, 0, "78 > 01 + 392x + other AIs max" }, + }; + int data_size = sizeof(data) / sizeof(struct item); + + for (int i = 0; i < data_size; i++) { + + struct zint_symbol* symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + symbol->symbology = BARCODE_RSS_EXP; + int length = strlen(data[i].data); + + ret = ZBarcode_Encode(symbol, data[i].data, length); + assert_equal(ret, data[i].ret, "i:%d ret %d != %d %s\n", i, ret, data[i].ret, symbol->errtxt); + + #ifdef TEST_BINARY_BUFFER_SIZE_GENERATE_EXPECTED + printf(" /*%2d*/ { \"%s\", %s, %d, %d, \"%s\" },\n", + i, data[i].data, testUtilErrorName(ret), symbol->rows, symbol->width, data[i].comment); + #else + + 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); + #endif + + ZBarcode_Delete(symbol); + } + + testFinish(); +} + int main() { test_binary_div_modulo_divisor(); test_examples(); test_general_field(); + test_binary_buffer_size(); testReport(); diff --git a/backend/vector.c b/backend/vector.c index 47c3723f..caace5dc 100644 --- a/backend/vector.c +++ b/backend/vector.c @@ -28,6 +28,7 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* vim: set ts=4 sw=4 et : */ #include #include @@ -499,7 +500,7 @@ int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type) { int block_width = 0; do { block_width++; - } while (module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i)); + } while (i + block_width < symbol->width && module_is_set(symbol, this_row, i + block_width) == module_is_set(symbol, this_row, i)); if ((addon_latch == 0) && (r == (symbol->rows - 1)) && (i > main_symbol_width_x)) { addon_text_posn = row_posn + 8.0f; addon_latch = 1; diff --git a/backend_qt/qzint.cpp b/backend_qt/qzint.cpp index 417169ea..65d386f1 100644 --- a/backend_qt/qzint.cpp +++ b/backend_qt/qzint.cpp @@ -306,9 +306,9 @@ namespace Zint { qreal gheight = m_zintSymbol->vector->height; if (paintRect.width() / gwidth < paintRect.height() / gheight) { - scale = (qreal) floor(paintRect.width() / gwidth); + scale = paintRect.width() / gwidth; } else { - scale = (qreal) floor(paintRect.height() / gheight); + scale = paintRect.height() / gheight; } xtr += (qreal) (paintRect.width() - gwidth * scale) / 2.0; diff --git a/frontend_qt/barcodeitem.cpp b/frontend_qt/barcodeitem.cpp index 9ab7cd04..5bb34480 100644 --- a/frontend_qt/barcodeitem.cpp +++ b/frontend_qt/barcodeitem.cpp @@ -22,6 +22,7 @@ BarcodeItem::BarcodeItem() { w=693; h=378; // Default widget size when created + ar = Zint::QZint::AspectRatioMode::IgnoreAspectRatio; } BarcodeItem::~BarcodeItem()