mirror of
https://git.code.sf.net/p/zint/code
synced 2026-09-19 18:52:37 +00:00
GS1: new GS1RAW_MODE (CLI "--gs1raw") and GS1 Syntax Engine
"Unbracketed AI" (caret) options for specifying GS1 input (ticket #350, props Mario Verbruggen) DBAR_EXP_CC/DBAR_EXPSTK_CC: fix separator over finder patterns when linear part is greater than 4 codeblocks general: left-over raw_text -> content_segs in comments; update & expand some GS1 General Specs refs; some minor code fiddling test suite: suppress some additional ZINT_SANITIZEM false positives (& add new ZINT_TESTUTIL_SANITIZEM_INIT helpers)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/* 2of5_based.c - Handles Code 2 of 5 Interleaved derivatives ITF-14, DP Leitcode and DP Identcode */
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2008-2025 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2008-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
|
||||
@@ -109,7 +109,7 @@ INTERNAL int zint_itf14(struct zint_symbol *symbol, unsigned char source[], int
|
||||
|
||||
z_hrt_cpy_nochk(symbol, local_source, 14);
|
||||
|
||||
/* Use `raw_text` set by `zint_c25_inter_common()` */
|
||||
/* Use `content_segs` set by `zint_c25_inter_common()` */
|
||||
|
||||
return error_number;
|
||||
}
|
||||
@@ -161,7 +161,7 @@ INTERNAL int zint_dpleit(struct zint_symbol *symbol, unsigned char source[], int
|
||||
z_hrt_printf_nochk(symbol, "%.5s.%.3s.%.3s.%.3s", local_source, local_source + 5, local_source + 8,
|
||||
local_source + 11);
|
||||
|
||||
/* Use `raw_text` set by `zint_c25_inter_common()` */
|
||||
/* Use `content_segs` set by `zint_c25_inter_common()` */
|
||||
|
||||
return error_number;
|
||||
}
|
||||
@@ -204,7 +204,7 @@ INTERNAL int zint_dpident(struct zint_symbol *symbol, unsigned char source[], in
|
||||
z_hrt_printf_nochk(symbol, "%.2s.%.2s %c.%.3s.%.3s %c", local_source, local_source + 2, local_source[4],
|
||||
local_source + 5, local_source + 8, local_source[11]);
|
||||
|
||||
/* Use `raw_text` set by `zint_c25_inter_common()` */
|
||||
/* Use `content_segs` set by `zint_c25_inter_common()` */
|
||||
|
||||
return error_number;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ endif()
|
||||
if(NOT ZINT_SANITIZE AND ZINT_SANITIZEM AND CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -O2)
|
||||
link_libraries(-fsanitize=memory)
|
||||
zint_target_compile_definitions(PRIVATE ZINT_SANITIZEM)
|
||||
zint_target_compile_definitions(PUBLIC ZINT_SANITIZEM)
|
||||
endif()
|
||||
|
||||
if(ZINT_TEST)
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/* aztec_trace.h - Trace routines for optimized AZTEC encodation algorithm */
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 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
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the project nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
*/
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef Z_AZTEC_TRACE_H
|
||||
#define Z_AZTEC_TRACE_H
|
||||
|
||||
static void AZ_TRACE_EdgeToString(char *buf, const unsigned char *source, const int length, const char initial_mode,
|
||||
struct az_edge *edges, struct az_edge *edge) {
|
||||
struct az_edge *previous_edge = AZ_PREVIOUS(edges, edge);
|
||||
int previousMode = previous_edge ? previous_edge->mode : initial_mode;
|
||||
int previous = previous_edge ? (int) (previous_edge - edges) : 0;
|
||||
int current = (int) (edge - edges);
|
||||
(void)length;
|
||||
if (buf) {
|
||||
sprintf(buf, "%d_%c_%d %c(%d,%d) %d -> %d_%c_%d",
|
||||
edge->from, az_mode_char(previousMode), previous, az_mode_char(edge->mode), source[edge->from], edge->len,
|
||||
edge->size, edge->from + 1, az_mode_char(edge->mode), current);
|
||||
} else {
|
||||
printf("%d_%c_%d %c(%d,%d) %d -> %d_%c_%d",
|
||||
edge->from, az_mode_char(previousMode), previous, az_mode_char(edge->mode), source[edge->from], edge->len,
|
||||
edge->size, edge->from + 1, az_mode_char(edge->mode), current);
|
||||
}
|
||||
}
|
||||
|
||||
static void AZ_TRACE_Path(const unsigned char *source, const int length, const char initial_mode,
|
||||
struct az_edge *edges, struct az_edge *edge, char *result, const int result_size) {
|
||||
struct az_edge *current;
|
||||
AZ_TRACE_EdgeToString(result, source, length, initial_mode, edges, edge);
|
||||
current = AZ_PREVIOUS(edges, edge);
|
||||
while (current) {
|
||||
char s[256];
|
||||
char *pos;
|
||||
int len;
|
||||
AZ_TRACE_EdgeToString(s, source, length, initial_mode, edges, current);
|
||||
pos = strrchr(s, ' ');
|
||||
assert(pos);
|
||||
len = strlen(result);
|
||||
if ((pos - s) + 1 + len + 1 >= result_size) {
|
||||
memcpy(result + result_size - 4, "...", 4); /* Include terminating NUL */
|
||||
break;
|
||||
}
|
||||
memmove(result + (pos - s) + 1, result, len + 1);
|
||||
memcpy(result, s, (pos - s) + 1);
|
||||
current = AZ_PREVIOUS(edges, current);
|
||||
}
|
||||
puts(result);
|
||||
}
|
||||
|
||||
static void AZ_TRACE_Edges(const char *prefix, const unsigned char *source, const int length, const char initial_mode,
|
||||
struct az_edge *edges, const int vertexIndex) {
|
||||
int i, j, e_i;
|
||||
char result[1024 * 2];
|
||||
if (vertexIndex) {
|
||||
printf(prefix, vertexIndex);
|
||||
} else {
|
||||
fputs(prefix, stdout);
|
||||
}
|
||||
for (i = vertexIndex; i <= length; i++) {
|
||||
e_i = i * AZ_NUM_MODES;
|
||||
for (j = 0; j < AZ_NUM_MODES; j++) {
|
||||
if (edges[e_i + j].mode) {
|
||||
fputs(" **** ", stdout);
|
||||
AZ_TRACE_Path(source, length, initial_mode, edges, edges + e_i + j, result, (int) ARRAY_SIZE(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void AZ_TRACE_AddEdge(const unsigned char *source, const int length, struct az_edge *edges,
|
||||
struct az_edge *previous, const int vertexIndex, struct az_edge *edge) {
|
||||
const int v_ij = vertexIndex * AZ_NUM_MODES + AZ_MASK(edge->mode) - 1;
|
||||
|
||||
(void)source; (void)length;
|
||||
|
||||
printf("add mode %c_%d, previous %d, from %d, len %d, v_ij mode %d || v_ij.size %d >= edge->size %d\n",
|
||||
az_mode_char(edge->mode), v_ij, previous ? (int) (previous - edges) : 0, edge->from, edge->len,
|
||||
edges[v_ij].mode, edges[v_ij].size, edge->size);
|
||||
}
|
||||
|
||||
static void AZ_TRACE_NotAddEdge(const unsigned char *source, const int length, struct az_edge *edges,
|
||||
struct az_edge *previous, const int vertexIndex, const int e_ij, struct az_edge *edge) {
|
||||
const int v_ij = vertexIndex * AZ_NUM_MODES + AZ_MASK(edge->mode) - 1;
|
||||
|
||||
(void)source; (void)length; (void)e_ij;
|
||||
|
||||
printf("NOT mode %c_%d, previous %d, from %d, len %d, v_ij.size %d < edge->size %d\n",
|
||||
az_mode_char(edge->mode), v_ij, previous ? (int) (previous - edges) : 0, edge->from, edge->len,
|
||||
edges[v_ij].size, edge->size);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et : */
|
||||
#endif /* Z_AZTEC_TRACE_H */
|
||||
+4
-9
@@ -542,7 +542,7 @@ INTERNAL int zint_gs1_128_cc(struct zint_symbol *symbol, unsigned char source[],
|
||||
symbol->row_height[separator_row] = 1;
|
||||
}
|
||||
|
||||
error_number = zint_gs1_verify(symbol, source, length, reduced, &reduced_length);
|
||||
error_number = zint_gs1_verify(symbol, source, length, reduced, &reduced_length, 1 /*set_hrt*/);
|
||||
if (error_number >= ZINT_ERROR) {
|
||||
return error_number;
|
||||
}
|
||||
@@ -612,7 +612,7 @@ INTERNAL int zint_gs1_128_cc(struct zint_symbol *symbol, unsigned char source[],
|
||||
}
|
||||
}
|
||||
|
||||
if (reduced_length > 48) { /* GS1 General Specifications 5.4.4.3 */
|
||||
if (reduced_length > 48) { /* GS1 General Specifications Release 26.0 5.4.4.3 Maximum symbol length */
|
||||
if (error_number == 0) { /* Don't overwrite any `zint_gs1_verify()` warning */
|
||||
error_number = z_errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 843,
|
||||
"Input too long, requires %d characters (maximum 48)", reduced_length);
|
||||
@@ -620,7 +620,7 @@ INTERNAL int zint_gs1_128_cc(struct zint_symbol *symbol, unsigned char source[],
|
||||
}
|
||||
|
||||
if (symbol->output_options & COMPLIANT_HEIGHT) {
|
||||
/* GS1 General Specifications 21.0.1 5.12.3.2 table 2, including footnote (**):
|
||||
/* GS1 General Specifications Release 26.0 5.12.3.2 Symbol specification table 2, including footnote (**):
|
||||
same as ITF-14: "in case of further space constraints" height 5.8mm / 1.016mm (X max) ~ 5.7;
|
||||
default 31.75mm / 0.495mm ~ 64.14 */
|
||||
const float min_height = 5.70866156f; /* 5.8 / 1.016 */
|
||||
@@ -650,12 +650,7 @@ INTERNAL int zint_gs1_128_cc(struct zint_symbol *symbol, unsigned char source[],
|
||||
"Cannot use Reader Initialisation in GS1 mode, ignoring");
|
||||
}
|
||||
|
||||
/* Note won't overflow `text` buffer due to symbol character maximum restricted to C128_SYMBOL_MAX */
|
||||
if (symbol->input_mode & GS1PARENS_MODE) {
|
||||
z_hrt_cpy_nochk(symbol, source, length);
|
||||
} else {
|
||||
z_hrt_conv_gs1_brackets_nochk(symbol, source, length);
|
||||
}
|
||||
/* HRT set by `zint_gs1_verify()` */
|
||||
|
||||
if (content_segs && z_ct_cpy(symbol, reduced, reduced_length)) {
|
||||
return ZINT_ERROR_MEMORY; /* `z_ct_cpy()` only fails with OOM */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* code128_based.c - Handles Code 128 derivatives NVE-18, EAN-14, DPD and Universal Postal Union S10 */
|
||||
/*
|
||||
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
|
||||
@@ -94,7 +94,7 @@ static int nve18_or_ean14(struct zint_symbol *symbol, const unsigned char source
|
||||
|
||||
error_number = zint_gs1_128(symbol, ean128_equiv, data_len + 5);
|
||||
|
||||
/* Use `raw_text` set by `zint_gs1_128()` */
|
||||
/* Use `content_segs` set by `zint_gs1_128()` */
|
||||
|
||||
return error_number;
|
||||
}
|
||||
@@ -219,7 +219,7 @@ INTERNAL int zint_dpd(struct zint_symbol *symbol, unsigned char source[], int le
|
||||
|
||||
z_hrt_cpy_nochk(symbol, hrt, p + 1);
|
||||
|
||||
/* Use `raw_text` from `zint_code128()` */
|
||||
/* Use `content_segs` from `zint_code128()` */
|
||||
|
||||
/* Some compliance checks */
|
||||
if (z_not_sane(NEON_F, local_source + length - 16, 16)) {
|
||||
@@ -323,7 +323,7 @@ INTERNAL int zint_upu_s10(struct zint_symbol *symbol, unsigned char source[], in
|
||||
}
|
||||
z_hrt_cpy_nochk(symbol, hrt, j);
|
||||
|
||||
/* Use `raw_text` set by `zint_code128()` */
|
||||
/* Use `content_segs` set by `zint_code128()` */
|
||||
|
||||
if (symbol->output_options & COMPLIANT_HEIGHT) {
|
||||
/* Universal Postal Union S10 Section 8, using max X 0.51mm & minimum height 12.5mm or 15% of width */
|
||||
|
||||
+13
-6
@@ -117,7 +117,7 @@ static const unsigned short flags[256] = {
|
||||
|
||||
/* Whether a character `ch` matches `flag` */
|
||||
INTERNAL int z_is_chr(const unsigned int flag, const unsigned int ch) {
|
||||
return z_isascii(ch) && (flags[ch] & flag); /* As passed an int ch need to check it's ASCII */
|
||||
return z_isascii(ch) && (flags[ch] & flag); /* As `ch` passed as an int need to check it's ASCII */
|
||||
}
|
||||
|
||||
/* Verifies if a string only uses valid characters, returning 1-based position in `source` if not, 0 for success */
|
||||
@@ -780,15 +780,16 @@ INTERNAL int z_utf8_to_unicode(struct zint_symbol *symbol, const unsigned char s
|
||||
INTERNAL int z_hrt_cpy_iso8859_1(struct zint_symbol *symbol, const unsigned char source[], const int length) {
|
||||
int i, j;
|
||||
int warn_number = 0;
|
||||
const int text_size = ARRAY_SIZE(symbol->text);
|
||||
|
||||
for (i = 0, j = 0; i < length && j < ARRAY_SIZE(symbol->text); i++) {
|
||||
for (i = 0, j = 0; i < length && j < text_size; i++) {
|
||||
if (z_isascii(source[i])) {
|
||||
symbol->text[j++] = z_iscntrl(source[i]) ? ' ' : source[i];
|
||||
} else if (source[i] < 0xC0) {
|
||||
if (source[i] < 0xA0) { /* 0x80-0x9F not valid ISO/IEC 8859-1 */
|
||||
symbol->text[j++] = ' ';
|
||||
} else {
|
||||
if (j + 2 >= ARRAY_SIZE(symbol->text)) {
|
||||
if (j + 2 >= text_size) {
|
||||
warn_number = ZINT_WARN_HRT_TRUNCATED;
|
||||
break;
|
||||
}
|
||||
@@ -796,7 +797,7 @@ INTERNAL int z_hrt_cpy_iso8859_1(struct zint_symbol *symbol, const unsigned char
|
||||
symbol->text[j++] = source[i];
|
||||
}
|
||||
} else {
|
||||
if (j + 2 >= ARRAY_SIZE(symbol->text)) {
|
||||
if (j + 2 >= text_size) {
|
||||
warn_number = ZINT_WARN_HRT_TRUNCATED;
|
||||
break;
|
||||
}
|
||||
@@ -804,7 +805,7 @@ INTERNAL int z_hrt_cpy_iso8859_1(struct zint_symbol *symbol, const unsigned char
|
||||
symbol->text[j++] = source[i] - 0x40;
|
||||
}
|
||||
}
|
||||
if (j == ARRAY_SIZE(symbol->text)) {
|
||||
if (j == text_size) {
|
||||
warn_number = ZINT_WARN_HRT_TRUNCATED;
|
||||
j--;
|
||||
}
|
||||
@@ -955,7 +956,7 @@ static int ct_init_seg_source(struct zint_symbol *symbol, const int seg_idx, con
|
||||
assert(length > 0);
|
||||
|
||||
if (!(symbol->content_segs[seg_idx].source = (unsigned char *) malloc((size_t) length))) {
|
||||
return z_errtxt(ZINT_ERROR_MEMORY, symbol, 245, "Insufficient memory for content text source buffer");
|
||||
return z_errtxt(ZINT_ERROR_MEMORY, symbol, 245, "Insufficient memory for content segs source buffer");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1013,6 +1014,9 @@ INTERNAL int z_ct_cpy_cat(struct zint_symbol *symbol, const unsigned char source
|
||||
if (z_ct_init_segs(symbol, 1 /*seg_count*/) || ct_init_seg_source(symbol, 0 /*seg_idx*/, total_length)) {
|
||||
return ZINT_ERROR_MEMORY; /* `z_ct_init_segs()` & `ct_init_seg_source()` only fail with OOM */
|
||||
}
|
||||
#ifdef ZINT_SANITIZEM /* Suppress clang-22 -fsanitize=memory false positive (seems unable to track `*s++ =`) */
|
||||
memset(symbol->content_segs[0].source, 0, total_length);
|
||||
#endif
|
||||
s = symbol->content_segs[0].source;
|
||||
if (length > 0) {
|
||||
memcpy(s, source, (size_t) length);
|
||||
@@ -1044,6 +1048,9 @@ INTERNAL int z_ct_cpy_iso8859_1(struct zint_symbol *symbol, const unsigned char
|
||||
if (z_ct_init_segs(symbol, 1 /*seg_count*/) || ct_init_seg_source(symbol, 0 /*seg_idx*/, length + iso_cnt)) {
|
||||
return ZINT_ERROR_MEMORY; /* `z_ct_init_segs()` & `ct_init_seg_source()` only fail with OOM */
|
||||
}
|
||||
#ifdef ZINT_SANITIZEM /* Suppress clang-22 -fsanitize=memory false positive (seems unable to track `*s++ =`) */
|
||||
memset(symbol->content_segs[0].source, 0, length + iso_cnt);
|
||||
#endif
|
||||
s = symbol->content_segs[0].source;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
|
||||
+492
-152
@@ -95,7 +95,7 @@ static int gs1_numeric(const unsigned char *data, int data_len, int offset, int
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* GS1 General Specifications 21.0.1 Figure 7.9.5-1. GS1 AI encodable character reference values.
|
||||
/* GS1 General Specifications Release 26.0 Table 7-18 GS1 AI encodable character reference values.
|
||||
Also used to determine if character in set 82 - a value of 82 means not in */
|
||||
static const char gs1_c82[] = {
|
||||
/* ! " # $ % & ' ( ) * */
|
||||
@@ -118,7 +118,8 @@ static const char gs1_c82[] = {
|
||||
72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
|
||||
};
|
||||
|
||||
/* Validate of character set 82 (GS1 General Specifications Figure 7.11-1) */
|
||||
/* Validate of character set 82
|
||||
(GS1 General Specifications Release 26.0 Table 7-20 GS1 AI encodable character set 82) */
|
||||
static int gs1_cset82(const unsigned char *data, int data_len, int offset, int min, int max, int *p_err_no,
|
||||
int *p_err_posn, char err_msg[50]) {
|
||||
|
||||
@@ -144,7 +145,8 @@ static int gs1_cset82(const unsigned char *data, int data_len, int offset, int m
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Validate of character set 39 (GS1 General Specifications Figure 7.11-2) */
|
||||
/* Validate of character set 39
|
||||
(GS1 General Specifications Release 26.0 Table 7-21 GS1 AI encodable character set 39) */
|
||||
static int gs1_cset39(const unsigned char *data, int data_len, int offset, int min, int max, int *p_err_no,
|
||||
int *p_err_posn, char err_msg[50]) {
|
||||
|
||||
@@ -203,7 +205,8 @@ static int gs1_cset64(const unsigned char *data, int data_len, int offset, int m
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check a check digit (GS1 General Specifications 7.9.1) */
|
||||
/* Check a check digit
|
||||
(GS1 General Specifications Release 26.0 7.9.1 Standard check digit calculations for GS1 data structures) */
|
||||
static int gs1_csum(const unsigned char *data, int data_len, int offset, int min, int max, int *p_err_no,
|
||||
int *p_err_posn, char err_msg[50], const int length_only) {
|
||||
|
||||
@@ -237,7 +240,8 @@ static int gs1_csum(const unsigned char *data, int data_len, int offset, int min
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check alphanumeric check characters (GS1 General Specifications 7.9.5) */
|
||||
/* Check alphanumeric check characters
|
||||
(GS1 General Specifications Release 26.0 7.9.5 Check character calculation (for alphanumeric keys)) */
|
||||
static int gs1_csumalpha(const unsigned char *data, int data_len, int offset, int min, int max, int *p_err_no,
|
||||
int *p_err_posn, char err_msg[50], const int length_only) {
|
||||
|
||||
@@ -280,7 +284,7 @@ static int gs1_csumalpha(const unsigned char *data, int data_len, int offset, in
|
||||
|
||||
#define GS1_GCP_MIN_LENGTH 4 /* Minimum length of GS1 Company Prefix */
|
||||
|
||||
/* Check for a GS1 Prefix (GS1 General Specifications GS1 1.4.2) */
|
||||
/* Check for a GS1 Prefix (GS1 General Specifications Release 26.0 1.2.3.3 GS1 Company Prefix) */
|
||||
static int gs1_gcppos1(const unsigned char *data, int data_len, int offset, int min, int max, int *p_err_no,
|
||||
int *p_err_posn, char err_msg[50], const int length_only) {
|
||||
(void)max;
|
||||
@@ -406,7 +410,8 @@ static int gs1_yymmd0(const unsigned char *data, int data_len, int offset, int m
|
||||
|
||||
if (!length_only && data_len) {
|
||||
/* For leap year detection, only matters if 00 represents century divisible by 400 or not */
|
||||
/* Following good until 2050 when 00 will mean 2100 (GS1 General Specifications 7.12) */
|
||||
/* Following good until 2050 when 00 will mean 2100
|
||||
(GS1 General Specifications Release 26.0 7.12 Determination of century in dates) */
|
||||
unsigned char buf[8] = { '2', '0' };
|
||||
|
||||
memcpy(buf + 2, data + offset, 6);
|
||||
@@ -697,7 +702,8 @@ static int gs1_yesno(const unsigned char *data, int data_len, int offset, int mi
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for importer index (GS1 General Specifications 3.8.17) */
|
||||
/* Check for importer index
|
||||
(GS1 General Specifications Release 26.0 3.8.18 GS1 UIC with Extension 1 and Importer index: AI (7040)) */
|
||||
static int gs1_importeridx(const unsigned char *data, int data_len, int offset, int min, int max, int *p_err_no,
|
||||
int *p_err_posn, char err_msg[50], const int length_only) {
|
||||
(void)max;
|
||||
@@ -745,7 +751,7 @@ static int gs1_nonzero(const unsigned char *data, int data_len, int offset, int
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check winding direction (0/1/9) (GS1 General Specifications 3.9.1) */
|
||||
/* Check winding direction (0/1/9) (GS1 General Specifications Release 26.0 3.9.1 Roll products) */
|
||||
static int gs1_winding(const unsigned char *data, int data_len, int offset, int min, int max, int *p_err_no,
|
||||
int *p_err_posn, char err_msg[50], const int length_only) {
|
||||
(void)max;
|
||||
@@ -789,7 +795,9 @@ static int gs1_zero(const unsigned char *data, int data_len, int offset, int min
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check piece of a trade item (GS1 General Specifications 3.9.6 and 3.9.17) */
|
||||
/* Check piece of a trade item
|
||||
(GS1 General Specifications Release 26.0 3.9.6 Identification of an individual trade item piece
|
||||
and 3.9.18 Identification of pieces of a trade item (ITIP) contained in a logistic unit) */
|
||||
static int gs1_pieceoftotal(const unsigned char *data, int data_len, int offset, int min, int max, int *p_err_no,
|
||||
int *p_err_posn, char err_msg[50], const int length_only) {
|
||||
(void)max;
|
||||
@@ -914,8 +922,8 @@ static int gs1_nozeroprefix(const unsigned char *data, int data_len, int offset,
|
||||
}
|
||||
|
||||
if (!length_only && data_len) {
|
||||
/* GS1 General Specifications 3.9.11 "The C/P serial number SHALL NOT begin with a "0" digit, unless the
|
||||
entire serial number consists of the single digit '0'." */
|
||||
/* GS1 General Specifications Release 26.0 3.9.11 "The C/P serial number SHALL NOT begin with a "0" digit,
|
||||
unless the entire serial number consists of the single digit '0'." */
|
||||
if (data[0] == '0' && data_len != 1) {
|
||||
*p_err_no = 3;
|
||||
*p_err_posn = offset + 1;
|
||||
@@ -1609,34 +1617,72 @@ static int gs1_packagetype(const unsigned char *data, int data_len, int offset,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Helper to say if AI pointed to by `source` has predefined length according to GS1 General Specifications 26.0
|
||||
Figure 7-6 "Element strings with predefined length using GS1 Application Identifiers" */
|
||||
static int gs1_predefined_len(const unsigned char source[]) {
|
||||
const int ai2 = z_to_int(source, 2); /* First 2 digits */
|
||||
|
||||
/* NOTE: previously allowed legacy 23, removed 2026-02-26 */
|
||||
return (ai2 >= 0 && ai2 <= 4) || (ai2 >= 11 && ai2 <= 20) || (ai2 >= 31 && ai2 <= 36) || ai2 == 41;
|
||||
}
|
||||
|
||||
/* Generated by "php backend/tools/gen_gs1_linter.php > backend/gs1_lint.h" */
|
||||
#include "gs1_lint.h"
|
||||
|
||||
#ifdef ZINT_TEST /* Wrapper for direct testing */
|
||||
INTERNAL int zint_test_gs1_lint_parse_raw_caret(const unsigned char source[], const int length,
|
||||
const int ai_max, int *ai_vals, int *ai_locs, int *data_locs, int *data_lens, int *p_ai_count,
|
||||
int *p_err_no, int *p_err_posn) {
|
||||
return gs1_lint_parse_raw_caret(source, length,
|
||||
ai_max, ai_vals, ai_locs, data_locs, data_lens, p_ai_count, p_err_no, p_err_posn);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Whether starts with Digital Link URI */
|
||||
static int gs1_is_digital_link(const unsigned char *source, const int length) {
|
||||
return (length >= 8 && (memcmp(source, "https://", 8) == 0 || memcmp(source, "HTTPS://", 8) == 0))
|
||||
|| (length >= 7 && (memcmp(source, "http://", 7) == 0 || memcmp(source, "HTTP://", 7) == 0));
|
||||
return length >= 7 && (memcmp(source, "http://", 7) == 0 || memcmp(source, "HTTP://", 7) == 0
|
||||
|| (length >= 8 && (memcmp(source, "https://", 8) == 0
|
||||
|| memcmp(source, "HTTPS://", 8) == 0)));
|
||||
}
|
||||
|
||||
/* If built with GS1 Syntax Engine library */
|
||||
#ifdef ZINT_HAVE_GS1SE
|
||||
|
||||
/* Helper to set `errtxt` on internal error and exit, freeing `ctx` */
|
||||
static int gs1se_internal_errtxt(struct zint_symbol *symbol, const int err_id, gs1_encoder *ctx) {
|
||||
const char *errmsg = gs1_encoder_getErrMsg(ctx);
|
||||
z_errtxtf(0, symbol, err_id, "Internal error using GS1 Syntax Engine: %.80s", *errmsg ? errmsg : "unknown");
|
||||
gs1_encoder_free(ctx);
|
||||
return ZINT_ERROR_ENCODING_PROBLEM;
|
||||
}
|
||||
|
||||
/* Helper to replace GSs with carets */
|
||||
static void gs1se_gs_caret_sub(const unsigned char *src, const int length, unsigned char *dst) {
|
||||
int i;
|
||||
for (i = 0; i < length; i++) {
|
||||
dst[i] = src[i] == '\x1D' ? '^' : src[i];
|
||||
}
|
||||
dst[length] = '\0';
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
int i, j;
|
||||
const int is_composite = z_is_composite(symbol->symbology);
|
||||
const int primary_len = is_composite ? (int) strlen(symbol->primary) : 0;
|
||||
const int primary_len = z_is_composite(symbol->symbology) ? (int) strlen(symbol->primary) : 0;
|
||||
const int gs1parens_mode = symbol->input_mode & GS1PARENS_MODE;
|
||||
const char obracket = gs1parens_mode ? '(' : '[';
|
||||
const int parens_cnt = !gs1parens_mode ? z_chr_cnt(source, length, '(') : 0;
|
||||
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);
|
||||
const int parens_cnt = !gs1parens_mode && !gs1raw_mode && !gs1_caret ? z_chr_cnt(source, length, '(') : 0;
|
||||
|
||||
int local_length = length;
|
||||
const unsigned char *local_source = source;
|
||||
const unsigned char *local_source2 = source;
|
||||
unsigned char *local_source_buf = (unsigned char *) z_alloca(ARRAY_SIZE(symbol->primary) + length + 1);
|
||||
unsigned char *local_source_buf = (unsigned char *) z_alloca(ARRAY_SIZE(symbol->primary) + 4 + length + 1);
|
||||
unsigned char *local_source2_buf = (unsigned char *) z_alloca(ARRAY_SIZE(symbol->primary) * 2 + length
|
||||
+ parens_cnt + 1);
|
||||
int is_digital_link = 0;
|
||||
int linear_len = 0;
|
||||
char msgBuf[120];
|
||||
gs1_encoder_init_status_t status = GS1_ENCODERS_INIT_SUCCESS;
|
||||
gs1_encoder_init_opts_t opts = {
|
||||
@@ -1646,35 +1692,89 @@ static int gs1se_verify(struct zint_symbol *symbol, const unsigned char source[]
|
||||
gs1_encoder *ctx;
|
||||
int gs1se_ret;
|
||||
|
||||
if (length < 2 + gs1_caret) {
|
||||
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 802, "Data does not start with an AI");
|
||||
}
|
||||
|
||||
/* Only matrix symbols can encode Digital Link URIs */
|
||||
if (is_digital_link && !z_is_fixed_ratio(symbol->symbology)) {
|
||||
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 264, "Data does not start with an AI");
|
||||
}
|
||||
|
||||
/* Need "linear|composite" format to check required AIs */
|
||||
if (is_composite && primary_len) {
|
||||
if (primary_len) {
|
||||
if (symbol->symbology == BARCODE_GS1_128_CC || symbol->symbology == BARCODE_DBAR_EXP_CC
|
||||
|| symbol->symbology == BARCODE_DBAR_EXPSTK_CC) {
|
||||
memcpy(local_source_buf, symbol->primary, primary_len);
|
||||
local_source_buf[primary_len] = '|';
|
||||
memcpy(local_source_buf + 1 + primary_len, source, length + 1); /* Include terminating NUL */
|
||||
local_length += 1 + primary_len;
|
||||
/* These take GS1 data in the linear part */
|
||||
if (gs1raw_mode) {
|
||||
/* Need to add initial carets */
|
||||
local_source_buf[0] = '^';
|
||||
local_length = 1;
|
||||
if (symbol->primary[0] == '\x1D') { /* Allow initial GS */
|
||||
gs1se_gs_caret_sub(ZCUCP(symbol->primary + 1), primary_len - 1, local_source_buf + 1); /* Linear GSs */
|
||||
local_length += primary_len - 1;
|
||||
} else {
|
||||
gs1se_gs_caret_sub(ZCUCP(symbol->primary), primary_len, local_source_buf + 1); /* Linear GSs */
|
||||
local_length += primary_len;
|
||||
}
|
||||
local_source_buf[local_length++] = '|';
|
||||
local_source_buf[local_length++] = '^';
|
||||
if (source[0] == '\x1D') { /* Allow initial GS */
|
||||
gs1se_gs_caret_sub(source + 1, length - 1, local_source_buf + primary_len + 3); /* CC GSs */
|
||||
local_length += length - 1;
|
||||
} else {
|
||||
gs1se_gs_caret_sub(source, length, local_source_buf + primary_len + 3); /* CC GSs */
|
||||
local_length += length;
|
||||
}
|
||||
linear_len = primary_len;
|
||||
} else {
|
||||
memcpy(local_source_buf, symbol->primary, primary_len);
|
||||
local_source_buf[primary_len] = '|';
|
||||
memcpy(local_source_buf + primary_len + 1, source, length + 1); /* Include terminating NUL */
|
||||
local_length += primary_len + 1;
|
||||
linear_len = primary_len - 1; /* Only actual linear data counts - exclude initial caret */
|
||||
}
|
||||
} else {
|
||||
/* Just use dummy "01" linear */
|
||||
memcpy(local_source_buf, gs1parens_mode ? "(01)12345678901231|" : "[01]12345678901231|", 19);
|
||||
memcpy(local_source_buf + 19, source, length + 1); /* Include terminating NUL */
|
||||
local_length += 19;
|
||||
if (gs1_caret || gs1raw_mode) {
|
||||
memcpy(local_source_buf, "^0112345678901231|^", 18 + gs1raw_mode);
|
||||
if (gs1_caret) {
|
||||
memcpy(local_source_buf + 18, source, length + 1); /* Include terminating NUL */
|
||||
} else {
|
||||
gs1se_gs_caret_sub(source, length, local_source_buf + 19);
|
||||
}
|
||||
local_length += 18 + gs1raw_mode;
|
||||
} else {
|
||||
memcpy(local_source_buf, gs1parens_mode ? "(01)12345678901231|" : "[01]12345678901231|", 19);
|
||||
memcpy(local_source_buf + 19, source, length + 1); /* Include terminating NUL */
|
||||
local_length += 19;
|
||||
}
|
||||
linear_len = 16; /* Only actual linear data "0112345678901231" counts */
|
||||
}
|
||||
local_source = local_source_buf;
|
||||
local_source2 = local_source_buf;
|
||||
} else if (gs1raw_mode && !is_digital_link) {
|
||||
if (symbol->symbology == BARCODE_GS1_128 || symbol->symbology == BARCODE_DBAR_EXP
|
||||
|| symbol->symbology == BARCODE_DBAR_EXPSTK || z_is_fixed_ratio(symbol->symbology)
|
||||
|| symbol->symbology == BARCODE_CODABLOCKF) { /* Codablock-F will be GS1-enabled in the future */
|
||||
/* Prefix caret */
|
||||
local_source_buf[0] = '^';
|
||||
if (source[0] == '\x1D') { /* Allow initial GS */
|
||||
gs1se_gs_caret_sub(source + 1, length - 1, local_source_buf + 1);
|
||||
} else {
|
||||
gs1se_gs_caret_sub(source, length, local_source_buf + 1);
|
||||
local_length++;
|
||||
}
|
||||
} else {
|
||||
/* Just copy over */
|
||||
memcpy(local_source_buf, source, length + 1); /* Include terminating NULL */
|
||||
}
|
||||
local_source = local_source_buf;
|
||||
local_source2 = local_source_buf;
|
||||
}
|
||||
|
||||
if (local_source[0] != obracket) {
|
||||
if (!z_is_fixed_ratio(symbol->symbology)) { /* Only matrix symbols can encode Digital Link URIs */
|
||||
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 264, "Data does not start with an AI");
|
||||
}
|
||||
if (!(is_digital_link = gs1_is_digital_link(local_source, local_length))) {
|
||||
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 265,
|
||||
"Data does not start with an AI or a Digital Link URI");
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_digital_link) {
|
||||
if (!is_digital_link && !gs1raw_mode && !gs1_caret) {
|
||||
assert(local_length > 0);
|
||||
/* Convert to GS1 Syntax Engine parenthesis mode */
|
||||
if (!gs1parens_mode) {
|
||||
/* Replace '[' and ']' with '(' and ')' & escape any data opening parentheses (not closing parentheses) */
|
||||
@@ -1711,19 +1811,20 @@ static int gs1se_verify(struct zint_symbol *symbol, const unsigned char source[]
|
||||
if (!(ctx = gs1_encoder_init_ex(NULL /*mem*/, &opts))) {
|
||||
const int error_number = status == GS1_ENCODERS_INIT_FAILED_NO_MEM
|
||||
? ZINT_ERROR_MEMORY : ZINT_ERROR_ENCODING_PROBLEM;
|
||||
return z_errtxtf(error_number, symbol, 266, "GS1 Syntax Engine: %s", opts.msgBuf);
|
||||
return z_errtxtf(error_number, symbol, 266, "Failed to initialize GS1 Syntax Engine: %.80s",
|
||||
*opts.msgBuf ? opts.msgBuf : "unknown error");
|
||||
}
|
||||
/* Do not check for required checks for GS1-128 as may be spread across multiple barcodes - ticket #348
|
||||
and https://github.com/gs1/gs1-syntax-dictionary/issues/24 */
|
||||
if (symbol->symbology == BARCODE_GS1_128) {
|
||||
if (!gs1_encoder_setValidationEnabled(ctx, gs1_encoder_vREQUISITE_AIS, false)) {
|
||||
const char *errmsg = gs1_encoder_getErrMsg(ctx);
|
||||
return z_errtxtf(ZINT_ERROR_ENCODING_PROBLEM, symbol, 0, "Internal error using GS1SE: %.80s",
|
||||
errmsg ? errmsg : "unknown");
|
||||
return gs1se_internal_errtxt(symbol, 0 /*err_id*/, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_digital_link) {
|
||||
if (is_digital_link || gs1raw_mode || gs1_caret) {
|
||||
/* Required for `gs1_encoder_getScanData()` */
|
||||
gs1_encoder_setSym(ctx, primary_len ? gs1_encoder_sGS1_128_CCA : gs1_encoder_sDM);
|
||||
gs1se_ret = gs1_encoder_setDataStr(ctx, ZCCP(local_source2));
|
||||
} else {
|
||||
gs1se_ret = gs1_encoder_setAIdataStr(ctx, ZCCP(local_source2));
|
||||
@@ -1733,81 +1834,285 @@ static int gs1se_verify(struct zint_symbol *symbol, const unsigned char source[]
|
||||
const int errmsg_len = (int) strlen(errmsg);
|
||||
const char *errmarkup = gs1_encoder_getErrMarkup(ctx);
|
||||
int errmarkup_len = (int) strlen(errmarkup);
|
||||
if (errmarkup_len && errmsg_len + 1 + errmarkup_len < ARRAY_SIZE(symbol->errtxt)) {
|
||||
int errtxt_set = 0;
|
||||
if (errmsg_len && errmarkup_len && errmsg_len + 1 + errmarkup_len < ARRAY_SIZE(symbol->errtxt)) {
|
||||
char *local_errmarkup = (char *) z_alloca(errmarkup_len * 4 + 1);
|
||||
z_debug_print_escape(ZCUCP(errmarkup), errmarkup_len, local_errmarkup);
|
||||
errmarkup_len = (int) strlen(local_errmarkup);
|
||||
if (errmsg_len + 1 + errmarkup_len < ARRAY_SIZE(symbol->errtxt)) {
|
||||
ZEXT z_errtxtf(0, symbol, 267, "%1$s %2$s", errmsg, local_errmarkup);
|
||||
} else {
|
||||
z_errtxt(0, symbol, 268, errmsg);
|
||||
errtxt_set = 1;
|
||||
}
|
||||
} else {
|
||||
z_errtxt(0, symbol, 268, errmsg);
|
||||
}
|
||||
if (!errtxt_set) {
|
||||
z_errtxt(0, symbol, 268, *errmsg ? errmsg : "Unknown error using GS1 Syntax Engine");
|
||||
}
|
||||
gs1_encoder_free(ctx);
|
||||
return ZINT_ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
/* If Digital Link, set `reduced` */
|
||||
if (is_digital_link) {
|
||||
/* If Digital Link or raw/caret mode, set `reduced` */
|
||||
if (is_digital_link || gs1raw_mode || gs1_caret) {
|
||||
const char *scan_data;
|
||||
|
||||
gs1_encoder_setSym(ctx, gs1_encoder_sDM); /* Required for `gs1_encoder_getScanData()` */
|
||||
int reduced_length;
|
||||
|
||||
if (!(scan_data = gs1_encoder_getScanData(ctx))) { /* Shouldn't happen */
|
||||
const char *errmsg = gs1_encoder_getErrMsg(ctx);
|
||||
z_errtxt(0, symbol, 269, strlen(errmsg) ? errmsg : "Internal error");
|
||||
gs1_encoder_free(ctx);
|
||||
return ZINT_ERROR_ENCODING_PROBLEM;
|
||||
return gs1se_internal_errtxt(symbol, 269 /*err_id*/, ctx);
|
||||
}
|
||||
*p_reduced_length = (int) strlen(scan_data);
|
||||
reduced_length = (int) strlen(scan_data);
|
||||
|
||||
/* Skip over Symbology Identifier */
|
||||
if (*p_reduced_length >= 3 && scan_data[0] == ']') {
|
||||
if (reduced_length >= 3 && scan_data[0] == ']') {
|
||||
scan_data += 3;
|
||||
*p_reduced_length -= 3;
|
||||
reduced_length -= 3;
|
||||
}
|
||||
/* Skip over any linear stuff */
|
||||
if (linear_len) {
|
||||
scan_data += linear_len;
|
||||
reduced_length -= linear_len;
|
||||
/* Need to check if the last linear AI was non-predefined length, when a GS is added */
|
||||
if (*scan_data == '\x1D') { /* Skip */
|
||||
scan_data++;
|
||||
reduced_length--;
|
||||
}
|
||||
}
|
||||
assert(reduced_length <= length);
|
||||
|
||||
memcpy(reduced, scan_data, *p_reduced_length + 1); /* Include terminating NUL */
|
||||
memcpy(reduced, scan_data, reduced_length + 1); /* Include terminating NUL */
|
||||
reduced[reduced_length] = '\0';
|
||||
*p_reduced_length = reduced_length;
|
||||
} else {
|
||||
*p_reduced_length = 0; /* Not Digital Link & `reduced` not set */
|
||||
*p_reduced_length = 0; /* `reduced` not set */
|
||||
}
|
||||
|
||||
gs1_encoder_free(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ZINT_HAVE_GS1SE */
|
||||
|
||||
/* Check for valid AI values and data lengths according to GS1 General Specifications Release 26, January 2026 */
|
||||
static int gs1_run_lint(struct zint_symbol *symbol, const unsigned char source[], const int ai_count,
|
||||
int *ai_vals, int *ai_locs, int *data_locs, int *data_lens) {
|
||||
int i;
|
||||
int error_number = 0;
|
||||
|
||||
for (i = 0; i < ai_count; i++) {
|
||||
int err_no, err_posn;
|
||||
char err_msg[50];
|
||||
if (!gs1_lint(ai_vals[i], source + data_locs[i], data_lens[i], &err_no, &err_posn,
|
||||
err_msg)) {
|
||||
if (err_no == 1) {
|
||||
ZEXT z_errtxtf(0, symbol, 260, "Invalid AI (%1$02d) at position %2$d",
|
||||
ai_vals[i], ai_locs[i] + 1);
|
||||
} else if (err_no == 2 || err_no == 4) { /* 4 is backward-incompatible bad length */
|
||||
ZEXT z_errtxtf(0, symbol, 259, "Invalid data length for AI (%1$02d) at position %2$d",
|
||||
ai_vals[i], ai_locs[i] + 1);
|
||||
} else {
|
||||
ZEXT z_errtxtf(0, symbol, 261, "AI (%1$02d) data position %2$d: %3$s", ai_vals[i], err_posn, err_msg);
|
||||
}
|
||||
/* For backward compatibility only error on unknown AI or bad length */
|
||||
if (err_no == 1 || err_no == 2) {
|
||||
return ZINT_ERROR_INVALID_DATA;
|
||||
}
|
||||
error_number = ZINT_WARN_NONCOMPLIANT;
|
||||
}
|
||||
}
|
||||
return error_number;
|
||||
}
|
||||
|
||||
/* Helper to convert parsed AIs to HRT */
|
||||
static int gs1_hrt_conv_parsed(struct zint_symbol *symbol, const unsigned char source[], const int length,
|
||||
const int ai_count, const int *ai_vals, const int *ai_locs, const int *data_locs, const int *data_lens,
|
||||
const int no_errtxt) {
|
||||
int i, j;
|
||||
int warn_number = 0;
|
||||
const int text_size = ARRAY_SIZE(symbol->text);
|
||||
#ifdef NDEBUG
|
||||
(void)length;
|
||||
#endif
|
||||
|
||||
for (i = 0, j = 0; i < ai_count && j < text_size; i++) {
|
||||
const int ai_len = 2 + (ai_vals[i] >= 100) + (ai_vals[i] >= 1000);
|
||||
if (j + 1 + ai_len + 1 + data_lens[i] >= text_size) {
|
||||
warn_number = ZINT_WARN_HRT_TRUNCATED;
|
||||
break;
|
||||
}
|
||||
symbol->text[j++] = '(';
|
||||
memcpy(symbol->text + j, source + ai_locs[i], ai_len);
|
||||
j += ai_len;
|
||||
symbol->text[j++] = ')';
|
||||
assert(data_locs[i] + data_lens[i] <= length);
|
||||
memcpy(symbol->text + j, source + data_locs[i], data_lens[i]);
|
||||
j += data_lens[i];
|
||||
}
|
||||
|
||||
if (j == text_size) {
|
||||
warn_number = ZINT_WARN_HRT_TRUNCATED;
|
||||
j--;
|
||||
}
|
||||
symbol->text_length = j;
|
||||
symbol->text[j] = '\0';
|
||||
|
||||
if (warn_number && !no_errtxt) {
|
||||
z_errtxt(0, symbol, 799, "Human Readable Text truncated");
|
||||
}
|
||||
return warn_number;
|
||||
|
||||
}
|
||||
|
||||
#ifdef ZINT_TEST /* Wrapper for direct testing */
|
||||
INTERNAL int zint_test_gs1_hrt_conv_parsed(struct zint_symbol *symbol, const unsigned char source[], const int length,
|
||||
const int ai_count, const int *ai_vals, const int *ai_locs, const int *data_locs, const int *data_lens,
|
||||
const int no_errtxt) {
|
||||
return gs1_hrt_conv_parsed(symbol, source, length, ai_count, ai_vals, ai_locs, data_locs, data_lens,
|
||||
no_errtxt);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Helper to set HRT when have GS1PARENS_MODE - truncates if too long for HRT buffer */
|
||||
static int gs1_hrt_cpy(struct zint_symbol *symbol, const unsigned char source[], const int length,
|
||||
const int no_errtxt) {
|
||||
int warn_number;
|
||||
const int text_size = ARRAY_SIZE(symbol->text);
|
||||
|
||||
assert(symbol->input_mode & GS1PARENS_MODE);
|
||||
assert(source[0] == '(');
|
||||
|
||||
if (length < text_size) {
|
||||
memcpy(symbol->text, source, length + 1); /* Include terminating NUL */
|
||||
symbol->text_length = length;
|
||||
warn_number = 0;
|
||||
} else {
|
||||
/* Find last full AI - need to scan forward to track escaped opening parens */
|
||||
int i, last_opening_bracket = 0;
|
||||
for (i = 0; i < text_size; i++) {
|
||||
if (source[i] == '\\' && i + 1 < length && (source[i + 1] == '\\' || source[i + 1] == '(')) {
|
||||
i++;
|
||||
} else if (source[i] == '(') {
|
||||
last_opening_bracket = i;
|
||||
}
|
||||
}
|
||||
if (text_size < length && source[text_size] == '(') {
|
||||
/* Finished at end of AI data */
|
||||
memcpy(symbol->text, source, text_size - 1);
|
||||
symbol->text_length = text_size - 1;
|
||||
symbol->text[text_size - 1] = '\0';
|
||||
} else {
|
||||
/* Use last full AI + data */
|
||||
memcpy(symbol->text, source, last_opening_bracket);
|
||||
symbol->text_length = last_opening_bracket;
|
||||
symbol->text[last_opening_bracket] = '\0';
|
||||
}
|
||||
warn_number = ZINT_WARN_HRT_TRUNCATED;
|
||||
if (!no_errtxt) {
|
||||
z_errtxt(0, symbol, 801, "Human Readable Text truncated");
|
||||
}
|
||||
}
|
||||
return warn_number;
|
||||
}
|
||||
|
||||
#ifdef ZINT_TEST /* Wrapper for direct testing */
|
||||
INTERNAL int zint_test_gs1_hrt_cpy(struct zint_symbol *symbol, const unsigned char source[], const int length,
|
||||
const int no_errtxt) {
|
||||
return gs1_hrt_cpy(symbol, source, length, no_errtxt);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Helper to set HRT when don't have GS1PARENS_MODE - substitutes square brackets with parentheses
|
||||
& truncates if too long for HRT buffer */
|
||||
static int gs1_hrt_conv_brackets(struct zint_symbol *symbol, const unsigned char source[], const int length,
|
||||
const int no_errtxt) {
|
||||
int i;
|
||||
int warn_number = 0;
|
||||
int bracket_level = 0; /* Non-compliant closing square brackets may be in text */
|
||||
int last_opening_bracket = 0;
|
||||
const int text_size = ARRAY_SIZE(symbol->text);
|
||||
const int max_len = length > text_size ? text_size : length;
|
||||
|
||||
assert((symbol->input_mode & GS1PARENS_MODE) == 0);
|
||||
assert(source[0] == '[');
|
||||
|
||||
for (i = 0; i < max_len; i++) {
|
||||
if (source[i] == '[') {
|
||||
symbol->text[i] = '(';
|
||||
bracket_level++;
|
||||
last_opening_bracket = i;
|
||||
} else if (source[i] == ']' && bracket_level) {
|
||||
symbol->text[i] = ')';
|
||||
bracket_level--;
|
||||
} else {
|
||||
symbol->text[i] = source[i];
|
||||
}
|
||||
}
|
||||
if (i == text_size) {
|
||||
i--;
|
||||
if (source[i] != '[') {
|
||||
i = last_opening_bracket;
|
||||
}
|
||||
warn_number = ZINT_WARN_HRT_TRUNCATED;
|
||||
}
|
||||
symbol->text_length = i;
|
||||
symbol->text[i] = '\0';
|
||||
|
||||
if (warn_number && !no_errtxt) {
|
||||
z_errtxt(0, symbol, 798, "Human Readable Text truncated");
|
||||
}
|
||||
return warn_number;
|
||||
}
|
||||
|
||||
#ifdef ZINT_TEST /* Wrapper for direct testing */
|
||||
INTERNAL int zint_test_gs1_hrt_conv_brackets(struct zint_symbol *symbol, const unsigned char source[],
|
||||
const int length, const int no_errtxt) {
|
||||
return gs1_hrt_conv_brackets(symbol, source, length, no_errtxt);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define GS1_PARENS_PLACEHOLDER_MASK 0x20 /* Mask `(` or `)` by this if escaped (get BS (\x08) or HT (\x09)) */
|
||||
|
||||
/* Helper to re-instate escaped parentheses */
|
||||
static void gs1_reinstate_escaped_parens(unsigned char source[], const int length) {
|
||||
int i;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (source[i] < '\x1D') {
|
||||
source[i] |= GS1_PARENS_PLACEHOLDER_MASK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify a GS1 input string */
|
||||
INTERNAL int zint_gs1_verify(struct zint_symbol *symbol, const unsigned char source[], const int length,
|
||||
unsigned char reduced[], int *p_reduced_length) {
|
||||
unsigned char reduced[], int *p_reduced_length, const int set_hrt) {
|
||||
int i, j;
|
||||
int error_number = 0;
|
||||
int error_number = 0, warn_number = 0;
|
||||
int bracket_level = 0;
|
||||
int ai_latch;
|
||||
int local_length = length;
|
||||
const unsigned char *local_source = source;
|
||||
unsigned char *local_source_buf = (unsigned char *) z_alloca(length + 1);
|
||||
int *ai_vals, *ai_locs, *data_locs, *data_lens;
|
||||
|
||||
const int gs1parens_mode = symbol->input_mode & GS1PARENS_MODE;
|
||||
const char obracket = gs1parens_mode ? '(' : '[';
|
||||
const char cbracket = gs1parens_mode ? ')' : ']';
|
||||
int done_gs1se = 0;
|
||||
int is_digital_link = 0; /* Is Digital Link? */
|
||||
const int gs1raw_mode = symbol->input_mode & GS1RAW_MODE;
|
||||
const int gs1nocheck_mode = symbol->input_mode & GS1NOCHECK_MODE;
|
||||
|
||||
/* Note: Digital Link URIs only validated if have GS1 Syntax Engine and GS1SYNTAXENGINE_MODE set */
|
||||
|
||||
*p_reduced_length = 0;
|
||||
|
||||
#ifdef ZINT_HAVE_GS1SE
|
||||
if ((symbol->input_mode & GS1SYNTAXENGINE_MODE) && !(symbol->input_mode & GS1NOCHECK_MODE)) {
|
||||
if ((symbol->input_mode & GS1SYNTAXENGINE_MODE) && !gs1nocheck_mode) {
|
||||
/* Strict verification */
|
||||
if ((error_number = gs1se_verify(symbol, source, length, reduced, p_reduced_length))) {
|
||||
return error_number;
|
||||
}
|
||||
done_gs1se = 1;
|
||||
is_digital_link = *p_reduced_length != 0; /* `p_reduced_length` will be set if Digital Link */
|
||||
/* `p_reduced_length` will be set if Digital Link or raw/caret */
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1821,7 +2126,7 @@ INTERNAL int zint_gs1_verify(struct zint_symbol *symbol, const unsigned char sou
|
||||
if (source[i] == '\0') {
|
||||
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 262, "NUL characters not permitted in GS1 mode");
|
||||
}
|
||||
if (source[i] < 32) {
|
||||
if (source[i] < 32 && (!gs1raw_mode || source[i] != '\x1D')) {
|
||||
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 251, "Control characters are not supported by GS1");
|
||||
}
|
||||
if (source[i] == 127) {
|
||||
@@ -1829,24 +2134,90 @@ INTERNAL int zint_gs1_verify(struct zint_symbol *symbol, const unsigned char sou
|
||||
}
|
||||
}
|
||||
|
||||
is_digital_link = gs1_is_digital_link(source, length);
|
||||
|
||||
if (source[0] != obracket && !is_digital_link && (gs1raw_mode || source[0] == '^')) {
|
||||
int ai_count;
|
||||
int err_no, err_posn;
|
||||
const int ai_max = (length + 2) / 3 + 1; /* Min AI 2, min data 1 */
|
||||
|
||||
ai_vals = (int *) z_alloca(sizeof(int) * ai_max);
|
||||
ai_locs = (int *) z_alloca(sizeof(int) * ai_max);
|
||||
data_locs = (int *) z_alloca(sizeof(int) * ai_max);
|
||||
data_lens = (int *) z_alloca(sizeof(int) * ai_max);
|
||||
if (!gs1_lint_parse_raw_caret(source, length, ai_max, ai_vals, ai_locs, data_locs, data_lens, &ai_count,
|
||||
&err_no, &err_posn)) {
|
||||
/* Both raw & caret modes require valid AIs and underlong data lengths to work, so check regardless of
|
||||
GS1NOCHECK_MODE */
|
||||
if (err_no == 1) {
|
||||
if (ai_vals[ai_count] != -1) {
|
||||
ZEXT z_errtxtf(0, symbol, 856, "Invalid AI (%1$02d) at position %2$d", ai_vals[ai_count],
|
||||
err_posn);
|
||||
} else {
|
||||
z_errtxtf(0, symbol, 857, "Invalid AI at position %d", err_posn);
|
||||
}
|
||||
} else {
|
||||
assert(err_no == 2);
|
||||
if (data_lens[ai_count] == 0) {
|
||||
ZEXT z_errtxtf(0, symbol, 858, "Empty data field for AI (%1$02d) at position %2$d",
|
||||
ai_vals[ai_count], err_posn);
|
||||
} else {
|
||||
ZEXT z_errtxtf(0, symbol, 859, "Invalid data length for AI (%1$02d) at position %2$d",
|
||||
ai_vals[ai_count], err_posn);
|
||||
}
|
||||
}
|
||||
return ZINT_ERROR_INVALID_DATA;
|
||||
}
|
||||
assert(ai_count < ai_max); /* Suppress clang-tidy-22 clang-analyzer-security.ArrayBound */
|
||||
if (!gs1nocheck_mode) {
|
||||
/* Do lint to check that data values are ok */
|
||||
error_number = gs1_run_lint(symbol, source, ai_count, ai_vals, ai_locs, data_locs, data_lens);
|
||||
if (error_number >= ZINT_ERROR) {
|
||||
return error_number;
|
||||
}
|
||||
}
|
||||
|
||||
if (set_hrt) {
|
||||
warn_number = gs1_hrt_conv_parsed(symbol, source, length, ai_count, ai_vals, ai_locs, data_locs,
|
||||
data_lens, error_number != 0 /*no_errtxt*/);
|
||||
}
|
||||
|
||||
/* Set reduced - need to set it via `ai_vals` etc. so as to lose any superfluous carets/GSs */
|
||||
for (i = 0, j = 0; i < ai_count; i++) {
|
||||
const int ai_len = 2 + (ai_vals[i] >= 100) + (ai_vals[i] >= 1000);
|
||||
memcpy(reduced + j, source + ai_locs[i], ai_len);
|
||||
j += ai_len;
|
||||
memcpy(reduced + j, source + data_locs[i], data_lens[i]);
|
||||
j += data_lens[i];
|
||||
if (i + 1 != ai_count && !gs1_predefined_len(source + ai_locs[i])) {
|
||||
reduced[j++] = '\x1D';
|
||||
}
|
||||
}
|
||||
reduced[j] = '\0';
|
||||
*p_reduced_length = j;
|
||||
return error_number ? error_number : warn_number;
|
||||
}
|
||||
if (source[0] != obracket) {
|
||||
if (!z_is_fixed_ratio(symbol->symbology)) { /* Only matrix symbols can encode Digital Link URIs */
|
||||
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 252, "Data does not start with an AI");
|
||||
}
|
||||
if (!(is_digital_link = gs1_is_digital_link(source, length))) {
|
||||
if (!is_digital_link) {
|
||||
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 855,
|
||||
"Data does not start with an AI or Digital Link URI");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_digital_link) {
|
||||
if (is_digital_link || (done_gs1se && *p_reduced_length)) {
|
||||
if (!done_gs1se) {
|
||||
/* Just copy over Digital Link URI - no verification */
|
||||
memcpy(reduced, source, length + 1); /* Include terminating NUL */
|
||||
*p_reduced_length = length;
|
||||
if (set_hrt) {
|
||||
error_number = z_hrt_cpy_iso8859_1(symbol, source, length);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return error_number;
|
||||
}
|
||||
|
||||
if (gs1parens_mode) {
|
||||
@@ -1881,10 +2252,11 @@ INTERNAL int zint_gs1_verify(struct zint_symbol *symbol, const unsigned char sou
|
||||
int ai_zero_len_no_data = 0, ai_single_digit = 0, ai_nonnumeric = 0;
|
||||
int ai_nonnumeric_pos = 0; /* Suppress gcc 14 "-Wmaybe-uninitialized" false positive */
|
||||
const int ai_max = z_chr_cnt(local_source, local_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);
|
||||
|
||||
ai_vals = (int *) z_alloca(sizeof(int) * ai_max);
|
||||
ai_locs = (int *) z_alloca(sizeof(int) * ai_max);
|
||||
data_locs = (int *) z_alloca(sizeof(int) * ai_max);
|
||||
data_lens = (int *) z_alloca(sizeof(int) * ai_max);
|
||||
|
||||
/* Check the balance of the brackets & AI lengths */
|
||||
ai_latch = 0;
|
||||
@@ -1941,7 +2313,7 @@ INTERNAL int zint_gs1_verify(struct zint_symbol *symbol, const unsigned char sou
|
||||
if (min_ai_length <= 1) {
|
||||
/* Allow too short AI if GS1NOCHECK_MODE and no single-digit AIs and all zero-length AIs have some data
|
||||
- permits dummy "[]" workaround for ticket #204 data with no valid AI */
|
||||
if (!(symbol->input_mode & GS1NOCHECK_MODE) || ai_single_digit || ai_zero_len_no_data) {
|
||||
if (!gs1nocheck_mode || ai_single_digit || ai_zero_len_no_data) {
|
||||
/* AI is too short */
|
||||
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 256,
|
||||
"Invalid AI at position %d in input (AI too short)", min_ai_pos);
|
||||
@@ -1954,36 +2326,32 @@ INTERNAL int zint_gs1_verify(struct zint_symbol *symbol, const unsigned char sou
|
||||
"Invalid AI at position %d in input (non-numeric characters in AI)", ai_nonnumeric_pos);
|
||||
}
|
||||
|
||||
if (!(symbol->input_mode & GS1NOCHECK_MODE)) {
|
||||
if (!gs1nocheck_mode) {
|
||||
const unsigned char *local_source2 = local_source;
|
||||
unsigned char *local_source2_buf = (unsigned char *) z_alloca(local_length + 1);
|
||||
int ai_count = 0;
|
||||
for (i = 1; i < local_length; i++) {
|
||||
if (local_source[i - 1] == obracket) {
|
||||
ai_location[ai_count] = i;
|
||||
ai_locs[ai_count] = i - 1;
|
||||
for (j = 1; local_source[i + j] != cbracket; j++);
|
||||
ai_value[ai_count] = z_to_int(local_source + i, j);
|
||||
ai_vals[ai_count] = z_to_int(local_source + i, j);
|
||||
ai_count++;
|
||||
i += j;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ai_count; i++) {
|
||||
if (ai_value[i] >= 1000) {
|
||||
data_location[i] = ai_location[i] + 5;
|
||||
} else if (ai_value[i] >= 100) {
|
||||
data_location[i] = ai_location[i] + 4;
|
||||
} else {
|
||||
data_location[i] = ai_location[i] + 3;
|
||||
data_locs[i] = ai_locs[i] + 2 /*brackets*/ + 2 + (ai_vals[i] >= 100) + (ai_vals[i] >= 1000);
|
||||
data_lens[i] = 0;
|
||||
while (data_locs[i] + data_lens[i] < local_length
|
||||
&& local_source[data_locs[i] + data_lens[i]] != obracket) {
|
||||
data_lens[i]++;
|
||||
}
|
||||
data_length[i] = 0;
|
||||
while (data_location[i] + data_length[i] < local_length
|
||||
&& local_source[data_location[i] + data_length[i]] != obracket) {
|
||||
data_length[i]++;
|
||||
}
|
||||
if (data_length[i] == 0) {
|
||||
if (data_lens[i] == 0) {
|
||||
/* No data for given AI */
|
||||
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 258, "Empty data field in input");
|
||||
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 258,
|
||||
"Empty data field for AI (%1$02d) at position %2$d",
|
||||
ai_vals[i], ai_locs[i] + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1991,82 +2359,54 @@ INTERNAL int zint_gs1_verify(struct zint_symbol *symbol, const unsigned char sou
|
||||
/* Temporarily re-instate escaped parentheses before linting */
|
||||
local_source2 = local_source2_buf;
|
||||
memcpy(local_source2_buf, local_source, local_length + 1); /* Include terminating NUL */
|
||||
for (i = 0; i < local_length; i++) {
|
||||
if (local_source2_buf[i] < '\x1D') {
|
||||
local_source2_buf[i] |= GS1_PARENS_PLACEHOLDER_MASK;
|
||||
}
|
||||
}
|
||||
gs1_reinstate_escaped_parens(local_source2_buf, local_length);
|
||||
}
|
||||
|
||||
/* Check for valid AI values and data lengths according to GS1 General
|
||||
Specifications Release 25, January 2025 */
|
||||
for (i = 0; i < ai_count; i++) {
|
||||
int err_no, err_posn;
|
||||
char err_msg[50];
|
||||
if (!gs1_lint(ai_value[i], local_source2 + data_location[i], data_length[i], &err_no, &err_posn,
|
||||
err_msg)) {
|
||||
if (err_no == 1) {
|
||||
z_errtxtf(0, symbol, 260, "Invalid AI (%02d)", ai_value[i]);
|
||||
} else if (err_no == 2 || err_no == 4) { /* 4 is backward-incompatible bad length */
|
||||
z_errtxtf(0, symbol, 259, "Invalid data length for AI (%02d)", ai_value[i]);
|
||||
} else {
|
||||
ZEXT z_errtxtf(0, symbol, 261, "AI (%1$02d) position %2$d: %3$s", ai_value[i], err_posn,
|
||||
err_msg);
|
||||
}
|
||||
/* For backward compatibility only error on unknown AI or bad length */
|
||||
if (err_no == 1 || err_no == 2) {
|
||||
return ZINT_ERROR_INVALID_DATA;
|
||||
}
|
||||
error_number = ZINT_WARN_NONCOMPLIANT;
|
||||
}
|
||||
/* Check AI/data */
|
||||
error_number = gs1_run_lint(symbol, local_source2, ai_count, ai_vals, ai_locs, data_locs, data_lens);
|
||||
if (error_number >= ZINT_ERROR) {
|
||||
return error_number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Resolve AI data - put resulting string in 'reduced' */
|
||||
j = 0;
|
||||
ai_latch = 1;
|
||||
for (i = 0; i < local_length; i++) {
|
||||
if (local_source[i] == obracket) {
|
||||
bracket_level++;
|
||||
/* Start of an AI string */
|
||||
if (ai_latch == 0) {
|
||||
reduced[j++] = '\x1D';
|
||||
}
|
||||
if (i + 1 != local_length) {
|
||||
int last_ai = z_to_int(local_source + i + 1, 2);
|
||||
ai_latch = 0;
|
||||
/* The following values from GS1 General Specifications Release 25.0
|
||||
Figure 7.8.5-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 (!*p_reduced_length) {
|
||||
/* Resolve AI data - put resulting string in `reduced` */
|
||||
j = 0;
|
||||
ai_latch = 1;
|
||||
for (i = 0; i < local_length; i++) {
|
||||
if (local_source[i] == obracket) {
|
||||
bracket_level++;
|
||||
/* Start of an AI string */
|
||||
if (ai_latch == 0) {
|
||||
reduced[j++] = '\x1D';
|
||||
}
|
||||
if (i + 1 != local_length) {
|
||||
ai_latch = gs1_predefined_len(local_source + i + 1);
|
||||
}
|
||||
} else if (local_source[i] == cbracket && bracket_level) {
|
||||
bracket_level--;
|
||||
} else {
|
||||
reduced[j++] = local_source[i];
|
||||
}
|
||||
} else if (local_source[i] == cbracket && bracket_level) {
|
||||
/* The closing bracket is simply dropped from the input */
|
||||
bracket_level--;
|
||||
} else {
|
||||
reduced[j++] = local_source[i];
|
||||
}
|
||||
}
|
||||
reduced[j] = '\0';
|
||||
*p_reduced_length = j;
|
||||
reduced[j] = '\0';
|
||||
*p_reduced_length = j;
|
||||
|
||||
if (local_length != length) {
|
||||
/* Re-instate escaped parentheses */
|
||||
for (i = 0; i < *p_reduced_length; i++) {
|
||||
if (reduced[i] < '\x1D') {
|
||||
reduced[i] |= GS1_PARENS_PLACEHOLDER_MASK;
|
||||
if (local_length != length) {
|
||||
gs1_reinstate_escaped_parens(reduced, *p_reduced_length);
|
||||
}
|
||||
if (set_hrt) {
|
||||
if (gs1parens_mode) {
|
||||
warn_number = gs1_hrt_cpy(symbol, source, length, error_number != 0 /*no_errtxt*/);
|
||||
} else {
|
||||
warn_number = gs1_hrt_conv_brackets(symbol, source, length, error_number != 0 /*no_errtxt*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* The character '\x1D' (GS) in the reduced string refers to the FNC1 character */
|
||||
|
||||
return error_number;
|
||||
return error_number ? error_number : warn_number;
|
||||
}
|
||||
|
||||
/* Helper to return standard GS1 check digit (GS1 General Specifications 7.9.1) */
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/* gs1.h - Verifies GS1 data */
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2009-2025 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2009-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
|
||||
@@ -38,7 +38,7 @@ extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
INTERNAL int zint_gs1_verify(struct zint_symbol *symbol, const unsigned char source[], const int length,
|
||||
unsigned char reduced[], int *p_reduced_length);
|
||||
unsigned char reduced[], int *p_reduced_length, const int set_hrt);
|
||||
INTERNAL char zint_gs1_check_digit(const unsigned char source[], const int length);
|
||||
INTERNAL int zint_gs1_iso3166_alpha2(const unsigned char *cc);
|
||||
|
||||
|
||||
+384
-1
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2021-2025 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2021-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
|
||||
@@ -713,6 +713,7 @@ static int gs1_lint(const int ai, const unsigned char *data, const int data_len,
|
||||
|
||||
/* Assume data length failure */
|
||||
*p_err_no = 2;
|
||||
*p_err_posn = 1;
|
||||
|
||||
if (ai < 100) {
|
||||
|
||||
@@ -1072,4 +1073,386 @@ static int gs1_lint(const int ai, const unsigned char *data, const int data_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper to parse non-bracketed input */
|
||||
static int gs1_lint_parse_ai(const unsigned char source[], const int length, const int position,
|
||||
int *p_ai, int *p_min, int *p_max) {
|
||||
int ai, ai2, ai3 = -1, ai4 = -1, min, max = 0;
|
||||
|
||||
*p_ai = -1;
|
||||
|
||||
if (position + 1 >= length || !z_isdigit(source[position]) || !z_isdigit(source[position + 1])) {
|
||||
return 0;
|
||||
}
|
||||
ai2 = z_to_int(source + position, 2);
|
||||
if (position + 3 < length && z_isdigit(source[position + 2])) {
|
||||
ai3 = z_to_int(source + position, 3);
|
||||
if (position + 4 < length && z_isdigit(source[position + 3])) {
|
||||
ai4 = z_to_int(source + position, 4);
|
||||
}
|
||||
}
|
||||
|
||||
ai = ai2;
|
||||
if (ai == 0) {
|
||||
min = 18, max = 18;
|
||||
} else if (ai >= 1 && ai <= 3) {
|
||||
min = 14, max = 14;
|
||||
} else if (ai == 10 || ai == 21 || ai == 22) {
|
||||
min = 1, max = 20;
|
||||
} else if ((ai >= 11 && ai <= 13) || (ai >= 15 && ai <= 17)) {
|
||||
min = 6, max = 6;
|
||||
} else if (ai == 20) {
|
||||
min = 2, max = 2;
|
||||
} else if (ai == 30 || ai == 37) {
|
||||
min = 1, max = 8;
|
||||
} else if (ai == 90) {
|
||||
min = 1, max = 30;
|
||||
} else if (ai >= 91) {
|
||||
min = 1, max = 90;
|
||||
}
|
||||
|
||||
if (max == 0 && ai3 != -1) {
|
||||
|
||||
if (ai3 < 300) {
|
||||
ai = ai3;
|
||||
if (ai == 235) {
|
||||
min = 1, max = 28;
|
||||
} else if (ai == 240 || ai == 241 || ai == 250 || ai == 251) {
|
||||
min = 1, max = 30;
|
||||
} else if (ai == 242) {
|
||||
min = 1, max = 6;
|
||||
} else if (ai == 243 || ai == 254) {
|
||||
min = 1, max = 20;
|
||||
} else if (ai == 253) {
|
||||
min = 13, max = 30;
|
||||
} else if (ai == 255) {
|
||||
min = 13, max = 25;
|
||||
}
|
||||
|
||||
} else if (ai3 < 500) {
|
||||
ai = ai3;
|
||||
if (ai == 400 || ai == 403) {
|
||||
min = 1, max = 30;
|
||||
} else if (ai == 401) {
|
||||
min = 1, max = 30;
|
||||
} else if (ai == 402) {
|
||||
min = 17, max = 17;
|
||||
} else if (ai >= 410 && ai <= 417) {
|
||||
min = 13, max = 13;
|
||||
} else if (ai == 420) {
|
||||
min = 1, max = 20;
|
||||
} else if (ai == 421) {
|
||||
min = 4, max = 12;
|
||||
} else if (ai == 422 || ai == 424 || ai == 426) {
|
||||
min = 3, max = 3;
|
||||
} else if (ai == 423 || ai == 425) {
|
||||
min = 3, max = 15;
|
||||
} else if (ai == 427) {
|
||||
min = 1, max = 3;
|
||||
}
|
||||
|
||||
} else if (ai3 < 800) {
|
||||
ai = ai3;
|
||||
if (ai >= 710 && ai <= 717) {
|
||||
min = 1, max = 20;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (max == 0 && ai4 != -1) {
|
||||
|
||||
if (ai4 < 3200) {
|
||||
ai = ai4;
|
||||
if ((ai >= 3100 && ai <= 3105) || (ai >= 3110 && ai <= 3115) || (ai >= 3120 && ai <= 3125)
|
||||
|| (ai >= 3130 && ai <= 3135) || (ai >= 3140 && ai <= 3145) || (ai >= 3150 && ai <= 3155)
|
||||
|| (ai >= 3160 && ai <= 3165)) {
|
||||
min = 6, max = 6;
|
||||
}
|
||||
|
||||
} else if (ai4 < 3300) {
|
||||
ai = ai4;
|
||||
if (ai <= 3205 || (ai >= 3210 && ai <= 3215) || (ai >= 3220 && ai <= 3225) || (ai >= 3230 && ai <= 3235)
|
||||
|| (ai >= 3240 && ai <= 3245) || (ai >= 3250 && ai <= 3255) || (ai >= 3260 && ai <= 3265)
|
||||
|| (ai >= 3270 && ai <= 3275) || (ai >= 3280 && ai <= 3285) || (ai >= 3290 && ai <= 3295)) {
|
||||
min = 6, max = 6;
|
||||
}
|
||||
|
||||
} else if (ai4 < 3400) {
|
||||
ai = ai4;
|
||||
if (ai <= 3305 || (ai >= 3310 && ai <= 3315) || (ai >= 3320 && ai <= 3325) || (ai >= 3330 && ai <= 3335)
|
||||
|| (ai >= 3340 && ai <= 3345) || (ai >= 3350 && ai <= 3355) || (ai >= 3360 && ai <= 3365)
|
||||
|| (ai >= 3370 && ai <= 3375)) {
|
||||
min = 6, max = 6;
|
||||
}
|
||||
|
||||
} else if (ai4 < 3500) {
|
||||
ai = ai4;
|
||||
if (ai <= 3405 || (ai >= 3410 && ai <= 3415) || (ai >= 3420 && ai <= 3425) || (ai >= 3430 && ai <= 3435)
|
||||
|| (ai >= 3440 && ai <= 3445) || (ai >= 3450 && ai <= 3455) || (ai >= 3460 && ai <= 3465)
|
||||
|| (ai >= 3470 && ai <= 3475) || (ai >= 3480 && ai <= 3485) || (ai >= 3490 && ai <= 3495)) {
|
||||
min = 6, max = 6;
|
||||
}
|
||||
|
||||
} else if (ai4 < 3600) {
|
||||
ai = ai4;
|
||||
if (ai <= 3505 || (ai >= 3510 && ai <= 3515) || (ai >= 3520 && ai <= 3525) || (ai >= 3530 && ai <= 3535)
|
||||
|| (ai >= 3540 && ai <= 3545) || (ai >= 3550 && ai <= 3555) || (ai >= 3560 && ai <= 3565)
|
||||
|| (ai >= 3570 && ai <= 3575)) {
|
||||
min = 6, max = 6;
|
||||
}
|
||||
|
||||
} else if (ai4 < 3700) {
|
||||
ai = ai4;
|
||||
if (ai <= 3605 || (ai >= 3610 && ai <= 3615) || (ai >= 3620 && ai <= 3625) || (ai >= 3630 && ai <= 3635)
|
||||
|| (ai >= 3640 && ai <= 3645) || (ai >= 3650 && ai <= 3655) || (ai >= 3660 && ai <= 3665)
|
||||
|| (ai >= 3670 && ai <= 3675) || (ai >= 3680 && ai <= 3685) || (ai >= 3690 && ai <= 3695)) {
|
||||
min = 6, max = 6;
|
||||
}
|
||||
|
||||
} else if (ai4 < 4000) {
|
||||
ai = ai4;
|
||||
if ((ai >= 3900 && ai <= 3909) || (ai >= 3920 && ai <= 3929)) {
|
||||
min = 1, max = 15;
|
||||
} else if ((ai >= 3910 && ai <= 3919) || (ai >= 3930 && ai <= 3939)) {
|
||||
min = 4, max = 18;
|
||||
} else if (ai >= 3940 && ai <= 3943) {
|
||||
min = 4, max = 4;
|
||||
} else if (ai >= 3950 && ai <= 3955) {
|
||||
min = 6, max = 6;
|
||||
}
|
||||
|
||||
} else if (ai4 < 4400) {
|
||||
ai = ai4;
|
||||
if (ai == 4300 || ai == 4301 || ai == 4310 || ai == 4311 || ai == 4320) {
|
||||
min = 1, max = 35;
|
||||
} else if ((ai >= 4302 && ai <= 4306) || (ai >= 4312 && ai <= 4316)) {
|
||||
min = 1, max = 70;
|
||||
} else if (ai == 4307 || ai == 4317) {
|
||||
min = 2, max = 2;
|
||||
} else if (ai == 4308 || ai == 4319) {
|
||||
min = 1, max = 30;
|
||||
} else if (ai == 4309) {
|
||||
min = 20, max = 20;
|
||||
} else if (ai == 4318) {
|
||||
min = 1, max = 20;
|
||||
} else if (ai >= 4321 && ai <= 4323) {
|
||||
min = 1, max = 1;
|
||||
} else if (ai == 4324 || ai == 4325) {
|
||||
min = 10, max = 10;
|
||||
} else if (ai == 4326) {
|
||||
min = 6, max = 6;
|
||||
} else if (ai >= 4330 && ai <= 4333) {
|
||||
min = 6, max = 7;
|
||||
}
|
||||
|
||||
} else if (ai4 < 7100) {
|
||||
ai = ai4;
|
||||
if (ai == 7001) {
|
||||
min = 13, max = 13;
|
||||
} else if (ai == 7002) {
|
||||
min = 1, max = 30;
|
||||
} else if (ai == 7003) {
|
||||
min = 10, max = 10;
|
||||
} else if (ai == 7004) {
|
||||
min = 1, max = 4;
|
||||
} else if (ai == 7005) {
|
||||
min = 1, max = 12;
|
||||
} else if (ai == 7006) {
|
||||
min = 6, max = 6;
|
||||
} else if (ai == 7007) {
|
||||
min = 6, max = 12;
|
||||
} else if (ai == 7008) {
|
||||
min = 1, max = 3;
|
||||
} else if (ai == 7009) {
|
||||
min = 1, max = 10;
|
||||
} else if (ai == 7010) {
|
||||
min = 1, max = 2;
|
||||
} else if (ai == 7011) {
|
||||
min = 6, max = 10;
|
||||
} else if (ai >= 7020 && ai <= 7022) {
|
||||
min = 1, max = 20;
|
||||
} else if (ai == 7023) {
|
||||
min = 1, max = 30;
|
||||
} else if (ai >= 7030 && ai <= 7039) {
|
||||
min = 4, max = 30;
|
||||
} else if (ai == 7040) {
|
||||
min = 4, max = 4;
|
||||
} else if (ai == 7041) {
|
||||
min = 1, max = 4;
|
||||
}
|
||||
|
||||
} else if (ai4 < 7300) {
|
||||
ai = ai4;
|
||||
if (ai >= 7230 && ai <= 7239) {
|
||||
min = 3, max = 30;
|
||||
} else if (ai == 7240) {
|
||||
min = 1, max = 20;
|
||||
} else if (ai == 7241) {
|
||||
min = 2, max = 2;
|
||||
} else if (ai == 7242) {
|
||||
min = 1, max = 25;
|
||||
} else if (ai == 7250) {
|
||||
min = 8, max = 8;
|
||||
} else if (ai == 7251) {
|
||||
min = 12, max = 12;
|
||||
} else if (ai == 7252) {
|
||||
min = 1, max = 1;
|
||||
} else if (ai == 7253 || ai == 7254 || ai == 7259) {
|
||||
min = 1, max = 40;
|
||||
} else if (ai == 7255) {
|
||||
min = 1, max = 10;
|
||||
} else if (ai == 7256) {
|
||||
min = 1, max = 90;
|
||||
} else if (ai == 7257) {
|
||||
min = 1, max = 70;
|
||||
} else if (ai == 7258) {
|
||||
min = 3, max = 3;
|
||||
}
|
||||
|
||||
} else if (ai4 < 8100) {
|
||||
ai = ai4;
|
||||
if (ai == 8001) {
|
||||
min = 14, max = 14;
|
||||
} else if (ai == 8002 || ai == 8012) {
|
||||
min = 1, max = 20;
|
||||
} else if (ai == 8003) {
|
||||
min = 14, max = 30;
|
||||
} else if (ai == 8004) {
|
||||
min = 1, max = 30;
|
||||
} else if (ai == 8005) {
|
||||
min = 6, max = 6;
|
||||
} else if (ai == 8006 || ai == 8026) {
|
||||
min = 18, max = 18;
|
||||
} else if (ai == 8007) {
|
||||
min = 1, max = 34;
|
||||
} else if (ai == 8008) {
|
||||
min = 8, max = 12;
|
||||
} else if (ai == 8009) {
|
||||
min = 1, max = 50;
|
||||
} else if (ai == 8010) {
|
||||
min = 1, max = 30;
|
||||
} else if (ai == 8011) {
|
||||
min = 1, max = 12;
|
||||
} else if (ai == 8013) {
|
||||
min = 1, max = 25;
|
||||
} else if (ai == 8014) {
|
||||
min = 1, max = 25;
|
||||
} else if (ai == 8017 || ai == 8018) {
|
||||
min = 18, max = 18;
|
||||
} else if (ai == 8019) {
|
||||
min = 1, max = 10;
|
||||
} else if (ai == 8020) {
|
||||
min = 1, max = 25;
|
||||
} else if (ai == 8030) {
|
||||
min = 1, max = 90;
|
||||
} else if (ai == 8040 || ai == 8041) {
|
||||
min = 15, max = 15;
|
||||
} else if (ai == 8042) {
|
||||
min = 32, max = 32;
|
||||
} else if (ai == 8043) {
|
||||
min = 18, max = 20;
|
||||
}
|
||||
|
||||
} else if (ai4 < 8200) {
|
||||
ai = ai4;
|
||||
if (ai == 8110) {
|
||||
min = 1, max = 70;
|
||||
} else if (ai == 8111) {
|
||||
min = 4, max = 4;
|
||||
} else if (ai == 8112) {
|
||||
min = 1, max = 70;
|
||||
}
|
||||
|
||||
} else if (ai4 < 8300) {
|
||||
ai = ai4;
|
||||
if (ai == 8200) {
|
||||
min = 1, max = 70;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (max == 0) {
|
||||
*p_ai = ai2; /* Use 2-digit as feedback */
|
||||
return 0;
|
||||
}
|
||||
assert(ai >= 0 && ai <= 9999);
|
||||
assert(min >= 1);
|
||||
assert(max >= min);
|
||||
|
||||
*p_ai = ai;
|
||||
if (p_min) {
|
||||
*p_min = min;
|
||||
}
|
||||
if (p_max) {
|
||||
*p_max = max;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse non-bracketed input */
|
||||
static int gs1_lint_parse_raw_caret(const unsigned char source[], const int length,
|
||||
const int ai_max, int *ai_vals, int *ai_locs, int *data_locs, int *data_lens, int *p_ai_count,
|
||||
int *p_err_no, int *p_err_posn) {
|
||||
int i, j;
|
||||
const int gs1_caret = source[0] == '^';
|
||||
const unsigned char separator = gs1_caret ? '^' : '\x1D';
|
||||
int ai, max;
|
||||
int ai_count = 0, ai_len;
|
||||
#ifdef NDEBUG
|
||||
(void)ai_max;
|
||||
#endif
|
||||
|
||||
i = gs1_caret || source[0] == '\x1D'; /* Allow GS at start also */
|
||||
|
||||
if (i >= length) {
|
||||
*p_ai_count = 0; /* For feedback */
|
||||
ai_vals[0] = -1;
|
||||
ai_locs[0] = i - 1;
|
||||
*p_err_no = 1;
|
||||
*p_err_posn = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (i < length) {
|
||||
int data_start, data_max, on_separator;
|
||||
assert(ai_count < ai_max);
|
||||
ai_locs[ai_count] = i;
|
||||
if (!gs1_lint_parse_ai(source, length, i, &ai, NULL /*min*/, &max)) {
|
||||
*p_ai_count = ai_count; /* For feedback */
|
||||
ai_vals[ai_count] = ai; /* May be -1 */
|
||||
*p_err_no = 1;
|
||||
*p_err_posn = i + 1; /* Position 1-base */
|
||||
return 0;
|
||||
}
|
||||
ai_vals[ai_count] = ai;
|
||||
ai_len = ai < 100 ? 2 : ai < 1000 ? 3 : 4;
|
||||
|
||||
/* Following GS1 Syntax Engine tolerating superfluous FNC1s at end of AI data
|
||||
(for both final AI and AIs with predefined length) */
|
||||
data_start = i + ai_len;
|
||||
data_max = data_start + max;
|
||||
for (j = data_start; j < length && j < data_max; j++) {
|
||||
if (source[j] == separator) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
data_locs[ai_count] = data_start;
|
||||
/* Only checking that have at least one char, and haven't exceeded max */
|
||||
on_separator = j < length && source[j] == separator;
|
||||
if (j == data_start || (j + 1 == length && length > data_max && !on_separator)) {
|
||||
*p_ai_count = ai_count; /* For feedback */
|
||||
data_lens[ai_count] = j - data_start;
|
||||
*p_err_no = 2;
|
||||
*p_err_posn = i + 1; /* Position 1-base */
|
||||
return 0;
|
||||
}
|
||||
data_lens[ai_count] = j - data_locs[ai_count];
|
||||
ai_count++;
|
||||
i = j + on_separator;
|
||||
}
|
||||
|
||||
*p_ai_count = ai_count;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* Z_GS1_LINT_H */
|
||||
|
||||
+2
-2
@@ -1218,7 +1218,7 @@ int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[
|
||||
if (is_composite || !check_force_gs1(symbol->symbology)) {
|
||||
unsigned char *reduced = (unsigned char *) z_alloca(local_segs[0].length + 1);
|
||||
error_number = zint_gs1_verify(symbol, local_segs[0].source, local_segs[0].length, reduced,
|
||||
&local_segs[0].length);
|
||||
&local_segs[0].length, 0 /*set_hrt*/);
|
||||
if (error_number) {
|
||||
#ifdef ZINT_HAVE_GS1SE
|
||||
if (is_composite && !(symbol->input_mode & GS1SYNTAXENGINE_MODE)) {
|
||||
@@ -1387,7 +1387,7 @@ static int txt_hex_plot(struct zint_symbol *symbol) {
|
||||
}
|
||||
|
||||
if (!zint_fm_close(fmp, symbol)) {
|
||||
return ZEXT z_errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 792, "Failure on closing TXT output file (%1$d: %2$s)",
|
||||
return ZEXT z_errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 796, "Failure on closing TXT output file (%1$d: %2$s)",
|
||||
fmp->err, strerror(fmp->err));
|
||||
}
|
||||
|
||||
|
||||
+10
-19
@@ -1,7 +1,7 @@
|
||||
/* rss.c - GS1 DataBar (formerly Reduced Space Symbology) */
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2008-2025 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2008-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
|
||||
@@ -1188,17 +1188,6 @@ static void dbar_exp_separator(struct zint_symbol *symbol, int width, const int
|
||||
}
|
||||
}
|
||||
|
||||
/* Set HRT for DataBar Expanded */
|
||||
static void dbar_exp_hrt(struct zint_symbol *symbol, unsigned char source[], const int length) {
|
||||
|
||||
/* Max possible length is 77 digits so will fit */
|
||||
if (symbol->input_mode & GS1PARENS_MODE) {
|
||||
z_hrt_cpy_nochk(symbol, source, length);
|
||||
} else {
|
||||
z_hrt_conv_gs1_brackets_nochk(symbol, source, length);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return DataBar Expanded group (-1) */
|
||||
static int dbar_exp_group(const int val) {
|
||||
int i;
|
||||
@@ -1225,10 +1214,11 @@ INTERNAL int zint_dbar_exp_cc(struct zint_symbol *symbol, unsigned char source[]
|
||||
int reduced_length;
|
||||
/* Allow for 8 bits + 5-bit latch per char + 200 bits overhead/padding */
|
||||
char *binary_string = (char *) z_alloca(13 * length + 200 + 1);
|
||||
const int set_hrt = symbol->symbology == BARCODE_DBAR_EXP || symbol->symbology == BARCODE_DBAR_EXP_CC;
|
||||
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
|
||||
const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
|
||||
|
||||
error_number = zint_gs1_verify(symbol, source, length, reduced, &reduced_length);
|
||||
error_number = zint_gs1_verify(symbol, source, length, reduced, &reduced_length, set_hrt);
|
||||
if (error_number >= ZINT_ERROR) {
|
||||
return error_number;
|
||||
}
|
||||
@@ -1318,10 +1308,6 @@ INTERNAL int zint_dbar_exp_cc(struct zint_symbol *symbol, unsigned char source[]
|
||||
|
||||
check_char = 211 * (symbol_chars - 4) + checksum % 211;
|
||||
|
||||
if (debug_print) {
|
||||
printf("Data chars: %d, Check char: %d\n", data_chars, check_char);
|
||||
}
|
||||
|
||||
group = dbar_exp_group(check_char);
|
||||
|
||||
odd = (check_char - dbar_exp_g_sum[group]) / dbar_exp_t_even[group];
|
||||
@@ -1335,6 +1321,11 @@ INTERNAL int zint_dbar_exp_cc(struct zint_symbol *symbol, unsigned char source[]
|
||||
pattern_width = codeblocks * 5 + symbol_chars * 8 + 4;
|
||||
memset(elements, 0, sizeof(int) * pattern_width);
|
||||
|
||||
if (debug_print) {
|
||||
printf("Data chars: %d, Check char: %d, Codeblocks: %d, Symbol chars: %d\n",
|
||||
data_chars, check_char, codeblocks, symbol_chars);
|
||||
}
|
||||
|
||||
/* Put finder patterns in element array */
|
||||
p = (symbol_chars - 1) / 2 - 1;
|
||||
for (i = 0; i < codeblocks; i++) {
|
||||
@@ -1380,7 +1371,7 @@ INTERNAL int zint_dbar_exp_cc(struct zint_symbol *symbol, unsigned char source[]
|
||||
}
|
||||
symbol->rows++;
|
||||
|
||||
dbar_exp_hrt(symbol, source, length);
|
||||
/* HRT set by `zint_gs1_verify()` */
|
||||
|
||||
if (content_segs && z_ct_cpy(symbol, reduced, reduced_length)) {
|
||||
return ZINT_ERROR_MEMORY; /* `z_ct_cpy()` only fails with OOM */
|
||||
@@ -1498,7 +1489,7 @@ INTERNAL int zint_dbar_exp_cc(struct zint_symbol *symbol, unsigned char source[]
|
||||
|
||||
if (symbol->symbology == BARCODE_DBAR_EXP_CC || symbol->symbology == BARCODE_DBAR_EXPSTK_CC) {
|
||||
/* Composite separator */
|
||||
dbar_exp_separator(symbol, symbol->width, 4, separator_row, 1 /*above*/, 0 /*special_case_row*/,
|
||||
dbar_exp_separator(symbol, symbol->width, codeblocks, separator_row, 1 /*above*/, 0 /*special_case_row*/,
|
||||
1 /*left_to_right*/, 0 /*odd_last_row*/, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -4934,7 +4934,7 @@ static void test_encode(const testCtx *const p_ctx) {
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[8192];
|
||||
char cmp_buf[32768];
|
||||
char cmp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
|
||||
|
||||
@@ -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
|
||||
@@ -2897,7 +2897,7 @@ static void test_encode(const testCtx *const p_ctx) {
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[8192];
|
||||
char bwipp_buf[32768];
|
||||
char bwipp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char bwipp_msg[1024];
|
||||
|
||||
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */
|
||||
@@ -3286,7 +3286,7 @@ static void test_encode_segs(const testCtx *const p_ctx) {
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[8192];
|
||||
char bwipp_buf[32768];
|
||||
char bwipp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char bwipp_msg[1024];
|
||||
|
||||
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */
|
||||
@@ -3574,7 +3574,7 @@ static void test_fuzz(const testCtx *const p_ctx) {
|
||||
int i, length, ret;
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char bwipp_buf[32768];
|
||||
char bwipp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char bwipp_msg[1024];
|
||||
|
||||
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */
|
||||
|
||||
@@ -104,7 +104,7 @@ static void test_large(const testCtx *const p_ctx) {
|
||||
char escaped2[1024];
|
||||
char cmp_buf[8192];
|
||||
char cmp_msg[1024];
|
||||
char ret_buf[8192] = {0}; /* Suppress clang -fsanitize=memory false positive */
|
||||
char ret_buf[8192] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
|
||||
/* Only do BWIPP/zxing-cpp tests if asked, too slow otherwise */
|
||||
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript();
|
||||
@@ -937,7 +937,7 @@ static void test_hibc_input(const testCtx *const p_ctx) {
|
||||
|
||||
char escaped[1024];
|
||||
char escaped2[1024];
|
||||
char cmp_buf[8192];
|
||||
char cmp_buf[8192] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
char ret_buf[8192];
|
||||
|
||||
|
||||
+693
-231
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2019-2025 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2019-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
|
||||
@@ -360,7 +360,7 @@ static void test_large(const testCtx *const p_ctx) {
|
||||
|
||||
char data_buf[ZINT_MAX_DATA_LEN];
|
||||
|
||||
char escaped[8192];
|
||||
char escaped[8192] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_buf[32768];
|
||||
char cmp_msg[1024];
|
||||
|
||||
@@ -1304,7 +1304,7 @@ static void test_input(const testCtx *const p_ctx) {
|
||||
&& data[i].option_3 == data[i - 1].option_3
|
||||
&& data[i].output_options == data[i - 1].output_options
|
||||
&& strcmp(data[i].data, data[i - 1].data) == 0) {
|
||||
unsigned char binary[2][2200];
|
||||
unsigned char binary[2][2200] ZINT_TESTUTIL_SANITIZEM_INIT_2D;
|
||||
int gs1;
|
||||
int binlen;
|
||||
int binlens[2] = {0};
|
||||
@@ -1319,7 +1319,7 @@ static void test_input(const testCtx *const p_ctx) {
|
||||
i, expected_rows_width, prev_expected_rows_width);
|
||||
|
||||
if ((data[i].input_mode & 0x07) == GS1_MODE) {
|
||||
ret = zint_gs1_verify(symbol, ZUCP(data[i].data), length, reduced, &length);
|
||||
ret = zint_gs1_verify(symbol, ZUCP(data[i].data), length, reduced, &length, 0 /*set_hrt*/);
|
||||
assert_zero(ret, "i:%d zint_gs1_verify() ret %d != 0 (%s)\n", i, ret, symbol->errtxt);
|
||||
text = reduced;
|
||||
} else {
|
||||
@@ -6395,7 +6395,7 @@ static void test_encode_segs(const testCtx *const p_ctx) {
|
||||
testFinish();
|
||||
}
|
||||
|
||||
static void test_rt(const testCtx *const p_ctx) {
|
||||
static void test_ct(const testCtx *const p_ctx) {
|
||||
int debug = p_ctx->debug;
|
||||
|
||||
struct item {
|
||||
@@ -6427,9 +6427,11 @@ static void test_rt(const testCtx *const p_ctx) {
|
||||
/* 11*/ { BARCODE_DATAMATRIX, UNICODE_MODE, 899, BARCODE_CONTENT_SEGS, "é", -1, 0, 899, "é", -1, 899 },
|
||||
/* 12*/ { BARCODE_DATAMATRIX, GS1_MODE, -1, -1, "[01]04912345123459[15]970331[30]128[10]ABC123", -1, 0, 0, "", -1, 0 },
|
||||
/* 13*/ { BARCODE_DATAMATRIX, GS1_MODE, -1, BARCODE_CONTENT_SEGS, "[01]04912345123459[15]970331[30]128[10]ABC123", -1, 0, 0, "01049123451234591597033130128\03510ABC123", -1, 3 },
|
||||
/* 14*/ { BARCODE_DATAMATRIX, GS1_MODE, 28, BARCODE_CONTENT_SEGS, "[01]04912345123459[15]970331[30]128[10]ABC123", -1, 0, 28, "01049123451234591597033130128\03510ABC123", -1, 3 }, /* Note: content seg ECI rremains at default 3 */
|
||||
/* 15*/ { BARCODE_HIBC_DM, UNICODE_MODE, -1, -1, "H123ABC01234567890", -1, 0, 0, "", -1, 0 },
|
||||
/* 16*/ { BARCODE_HIBC_DM, UNICODE_MODE, -1, BARCODE_CONTENT_SEGS, "H123ABC01234567890", -1, 0, 0, "+H123ABC01234567890D", -1, 3 },
|
||||
/* 14*/ { BARCODE_DATAMATRIX, GS1_MODE, 28, BARCODE_CONTENT_SEGS, "[01]04912345123459[15]970331[30]128[10]ABC123", -1, 0, 28, "01049123451234591597033130128\03510ABC123", -1, 3 }, /* Note: content seg ECI remains at default 3 */
|
||||
/* 15*/ { BARCODE_DATAMATRIX, GS1_MODE, -1, -1, "https://example.com/01/09506000134369", -1, 0, 0, "", -1, 0 },
|
||||
/* 16*/ { BARCODE_DATAMATRIX, GS1_MODE, -1, BARCODE_CONTENT_SEGS, "https://example.com/01/09506000134369", -1, 0, 0, "https://example.com/01/09506000134369", -1, 3 },
|
||||
/* 17*/ { BARCODE_HIBC_DM, UNICODE_MODE, -1, -1, "H123ABC01234567890", -1, 0, 0, "", -1, 0 },
|
||||
/* 18*/ { BARCODE_HIBC_DM, UNICODE_MODE, -1, BARCODE_CONTENT_SEGS, "H123ABC01234567890", -1, 0, 0, "+H123ABC01234567890D", -1, 3 },
|
||||
};
|
||||
const int data_size = ARRAY_SIZE(data);
|
||||
int i, length, ret;
|
||||
@@ -6487,7 +6489,7 @@ static void test_rt(const testCtx *const p_ctx) {
|
||||
testFinish();
|
||||
}
|
||||
|
||||
static void test_rt_segs(const testCtx *const p_ctx) {
|
||||
static void test_ct_segs(const testCtx *const p_ctx) {
|
||||
int debug = p_ctx->debug;
|
||||
|
||||
struct item {
|
||||
@@ -7686,8 +7688,8 @@ int main(int argc, char *argv[]) {
|
||||
{ "test_input", test_input },
|
||||
{ "test_encode", test_encode },
|
||||
{ "test_encode_segs", test_encode_segs },
|
||||
{ "test_rt", test_rt },
|
||||
{ "test_rt_segs", test_rt_segs },
|
||||
{ "test_ct", test_ct },
|
||||
{ "test_ct_segs", test_ct_segs },
|
||||
#ifdef ZINT_TEST_ENCODING
|
||||
{ "test_minimalenc", test_minimalenc },
|
||||
#endif
|
||||
|
||||
@@ -71,7 +71,7 @@ static void test_large(const testCtx *const p_ctx) {
|
||||
char data_buf[4096];
|
||||
|
||||
char escaped[8192];
|
||||
char cmp_buf[50000];
|
||||
char cmp_buf[50000] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do BWIPP/zxing-cpp tests if asked, too slow otherwise */
|
||||
@@ -294,7 +294,7 @@ static void test_input(const testCtx *const p_ctx) {
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[1024];
|
||||
char cmp_buf[32768];
|
||||
char cmp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
|
||||
|
||||
+2949
-2247
File diff suppressed because it is too large
Load Diff
+854
-416
File diff suppressed because it is too large
Load Diff
@@ -195,15 +195,15 @@ static void test_checks(const testCtx *const p_ctx) {
|
||||
/*131*/ { BARCODE_CODE128, -1, "\\o200", -1, UNICODE_MODE | ESCAPE_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_ERROR_INVALID_DATA, "Error 245: Invalid UTF-8 in input", -1 },
|
||||
/*132*/ { BARCODE_MAXICODE, -1, "\200", -1, UNICODE_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_ERROR_INVALID_DATA, "Error 245: Invalid UTF-8 in input", -1 },
|
||||
/*133*/ { BARCODE_MAXICODE, -1, "\\o200", -1, UNICODE_MODE | ESCAPE_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_ERROR_INVALID_DATA, "Error 245: Invalid UTF-8 in input", -1 },
|
||||
/*134*/ { BARCODE_GS1_128, -1, "[01]12345678901234", -1, GS1_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_WARN_NONCOMPLIANT, "Warning 261: AI (01) position 14: Bad checksum '4', expected '1'", -1 },
|
||||
/*135*/ { BARCODE_GS1_128, -1, "[01]12345678901234", -1, GS1_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_NONCOMPLIANT, "Error 261: AI (01) position 14: Bad checksum '4', expected '1'", -1 },
|
||||
/*134*/ { BARCODE_GS1_128, -1, "[01]12345678901234", -1, GS1_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_WARN_NONCOMPLIANT, "Warning 261: AI (01) data position 14: Bad checksum '4', expected '1'", -1 },
|
||||
/*135*/ { BARCODE_GS1_128, -1, "[01]12345678901234", -1, GS1_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_NONCOMPLIANT, "Error 261: AI (01) data position 14: Bad checksum '4', expected '1'", -1 },
|
||||
/*136*/ { BARCODE_QRCODE, -1, "ก", -1, UNICODE_MODE, 13, 0, 0, 0, 0, -1, -1, 0, -1, -1, 0, "", -1 },
|
||||
/*137*/ { BARCODE_QRCODE, -1, "ก", -1, UNICODE_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_WARN_USES_ECI, "Warning 222: Encoded data includes ECI 13", -1 },
|
||||
/*138*/ { BARCODE_QRCODE, -1, "ก", -1, UNICODE_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_USES_ECI, "Error 222: Encoded data includes ECI 13", -1 },
|
||||
/*139*/ { BARCODE_CODEONE, -1, "[01]12345678901231", -1, GS1_MODE, 3, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_WARN_INVALID_OPTION, "Warning 512: ECI ignored for GS1 mode", -1 },
|
||||
/*140*/ { BARCODE_CODEONE, -1, "[01]12345678901231", -1, GS1_MODE, 3, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_INVALID_OPTION, "Error 512: ECI ignored for GS1 mode", -1 },
|
||||
/*141*/ { BARCODE_CODEONE, -1, "[01]12345678901234", -1, GS1_MODE, 3, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_WARN_INVALID_OPTION, "Warning 512: ECI ignored for GS1 mode", -1 }, /* Warning in encoder overrides library warnings */
|
||||
/*142*/ { BARCODE_CODEONE, -1, "[01]12345678901234", -1, GS1_MODE, 3, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_NONCOMPLIANT, "Error 261: AI (01) position 14: Bad checksum '4', expected '1'", -1 }, /* But not errors */
|
||||
/*142*/ { BARCODE_CODEONE, -1, "[01]12345678901234", -1, GS1_MODE, 3, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_NONCOMPLIANT, "Error 261: AI (01) data position 14: Bad checksum '4', expected '1'", -1 }, /* But not errors */
|
||||
/*143*/ { BARCODE_AZTEC, -1, "ก", -1, UNICODE_MODE, 13, 0, 0, 0, 0, -1, -1, 0, -1, -1, 0, "", -1 },
|
||||
/*144*/ { BARCODE_AZTEC, -1, "ก", -1, UNICODE_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, -1, ZINT_WARN_USES_ECI, "Warning 222: Encoded data includes ECI 13", -1 },
|
||||
/*145*/ { BARCODE_AZTEC, -1, "ก", -1, UNICODE_MODE, -1, 0, 0, 0, 0, -1, -1, 0, -1, WARN_FAIL_ALL, ZINT_ERROR_USES_ECI, "Error 222: Encoded data includes ECI 13", -1 },
|
||||
@@ -2105,7 +2105,7 @@ static int test_prev_ZBarcode_BarcodeName(int symbol_id, char name[32]) {
|
||||
static void test_barcode_name(const testCtx *const p_ctx) {
|
||||
|
||||
int ret;
|
||||
char name[32] = {0}; /* Suppress clang -fsanitize=memory false positive */
|
||||
char name[32] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
int symbol_id;
|
||||
|
||||
(void)p_ctx;
|
||||
@@ -2810,8 +2810,8 @@ static void test_utf8_to_eci(const testCtx *const p_ctx) {
|
||||
|
||||
for (i = 0; i < data_size; i++) {
|
||||
int ret_dest;
|
||||
unsigned char dest[1024];
|
||||
int dest_length;
|
||||
unsigned char dest[1024] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
int dest_length ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
|
||||
if (testContinue(p_ctx, i)) continue;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2019-2025 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2019-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
|
||||
@@ -648,7 +648,7 @@ static void test_2d_encode(const testCtx *const p_ctx) {
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[8192];
|
||||
char cmp_buf[32768];
|
||||
char cmp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
|
||||
|
||||
+10
-10
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2019-2025 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2019-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
|
||||
@@ -70,10 +70,10 @@ static void test_qr_large(const testCtx *const p_ctx) {
|
||||
int i, length, ret;
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char data_buf[ZINT_MAX_DATA_LEN];
|
||||
char data_buf[ZINT_MAX_DATA_LEN] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
|
||||
char escaped[ZINT_MAX_DATA_LEN] = {0}; /* Suppress clang -fsanitize=memory false positive */
|
||||
char cmp_buf[177 * 177 + 1] = {0}; /* Suppress clang -fsanitize=memory false positive */
|
||||
char escaped[ZINT_MAX_DATA_LEN] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_buf[177 * 177 + 1] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
|
||||
@@ -489,7 +489,7 @@ static void test_qr_input(const testCtx *const p_ctx) {
|
||||
char escaped[4096];
|
||||
char escaped2[4096];
|
||||
char ret_buf[4096];
|
||||
char cmp_buf[32768] = {0}; /* Suppress clang -fsanitize=memory false positive */
|
||||
char cmp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
|
||||
@@ -856,7 +856,7 @@ static void test_qr_optimize(const testCtx *const p_ctx) {
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[4096];
|
||||
char cmp_buf[32768] = {0}; /* Suppress clang -fsanitize=memory false positive */
|
||||
char cmp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
|
||||
@@ -4740,7 +4740,7 @@ static void test_qr_encode_segs(const testCtx *const p_ctx) {
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[4096];
|
||||
char cmp_buf[32768];
|
||||
char cmp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
|
||||
@@ -7369,7 +7369,7 @@ static void test_upnqr_encode(const testCtx *const p_ctx) {
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[4096];
|
||||
char cmp_buf[32768];
|
||||
char cmp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
#if 0 /* Need to add "force binary mode" to BWIPP for this to work */
|
||||
@@ -8078,7 +8078,7 @@ static void test_rmqr_large(const testCtx *const p_ctx) {
|
||||
char data_buf[ZINT_MAX_DATA_LEN];
|
||||
|
||||
char escaped[4096];
|
||||
char cmp_buf[32768];
|
||||
char cmp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do ZXing-C++ test if asked, too slow otherwise */
|
||||
@@ -9397,7 +9397,7 @@ static void test_rmqr_encode_segs(const testCtx *const p_ctx) {
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[4096];
|
||||
char cmp_buf[32768] = {0}; /* Suppress clang -fsanitize=memory false positive */
|
||||
char cmp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
|
||||
|
||||
+21
-19
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2019-2025 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2019-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
|
||||
@@ -790,7 +790,7 @@ static void test_examples(const testCtx *const p_ctx) {
|
||||
"00000100010110000110100000001010101010111100111101110010110001110011101000000000100010000011010010000100011110111011001000101010101010011101111111010000000000000000000000000000000000000000000000000000"
|
||||
"00100011101001111001001111110000010101000011000010001101001110001100010111111111001101111100101101111011100001000100110011000000000101100010000000101010000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
/* 90*/ { BARCODE_DBAR_EXPSTK, -1, -1, 2, "[8110]106141416543213500110000310123196000", 0, 5, 200, 1, "NACAG Figure 1 (& Appendix C: Example 6) specifying max rows",
|
||||
/* 90*/ { BARCODE_DBAR_EXPSTK, -1, -1, 2, "[8110]106141416543213500110000310123196000", 0, 5, 200, 0, "NACAG Figure 1 (& Appendix C: Example 6) specifying max rows; BWIPP need segments arg, see above",
|
||||
"01001100101110001110111111110000101000001101000001010111100110111000101111100000011011010001000000110000111100001010100011111100001010000010101111000111010000011001101011111111001110000001101101000101"
|
||||
"00000011010001110001000000001010010111110010111110101000011001000111010000010101000100101110111111001111000011110101010100000010100101111101010000111000101111100110010100000000100001111110010010110000"
|
||||
"00000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010000"
|
||||
@@ -804,7 +804,7 @@ static void test_examples(const testCtx *const p_ctx) {
|
||||
"0000001000100001011010000000010000111001101101100001100111100100100010100001010100100001101011111000000000000000000000000000000000000000000000000000000"
|
||||
"1011110111011110100101111111100111000110010010011110011000011011011100011110000001011110010100000100100000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
/* 92*/ { BARCODE_DBAR_EXPSTK, -1, -1, 2, "[8110]10614141011111275110111", 0, 5, 151, 1, "NACAG Figure 3 specifying max rows",
|
||||
/* 92*/ { BARCODE_DBAR_EXPSTK, -1, -1, 2, "[8110]10614141011111275110111", 0, 5, 151, 0, "NACAG Figure 3 specifying max rows; BWIPP need segments arg, see above",
|
||||
"0101011110011100001011111111000010100000110100000101011110011011100010111110000001101101000100000011000011100001101010001111110000101010000011000111010"
|
||||
"0000100001100011110100000000101001011111001011111010100001100100011101000001010100010010111011111100111100011110010101010000001010010101111100111000000"
|
||||
"0000010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010100000"
|
||||
@@ -818,7 +818,7 @@ static void test_examples(const testCtx *const p_ctx) {
|
||||
"0000011010011011100010100101010100100111000100000101010000111000110010100000101010001111000101110100011001110001101000100000001010101011011110000111010111110001101011101000000000100011110100100010000110101100111000001000101010101000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
"0010000101100100011100011000000001011000111011111010101111000111001101011111000000110000111010001011100110001110010111001111110000010100100001111000101000001110010100010111111111001100001011011101111001010011000111110011000000000101000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
/* 94*/ { BARCODE_DBAR_EXPSTK, -1, -1, 2, "[8110]106141410222223100110222111101231023456721104561045678991201", 0, 5, 298, 1, "NACAG Figure 4, specifying max rows",
|
||||
/* 94*/ { BARCODE_DBAR_EXPSTK, -1, -1, 2, "[8110]106141410222223100110222111101231023456721104561045678991201", 0, 5, 298, 0, "NACAG Figure 4, specifying max rows; BWIPP need segments arg, see above",
|
||||
"0100101111101001111011111111000010110010000011001101011110011011100010111100000000101101000100000011000011100001101010001111110000101011000011100001010111000011011110101111000000111010011111000101110001110110011001100011110000001011100110000101000110101111110111001011111111001110011010011100001101"
|
||||
"0000010000010110000100000000101001001101111100110010100001100100011101000010101010010010111011111100111100011110010101010000001010010100111100011110101000111100100001010000101010000101100000111010001110001001100110010100001010100100011001111010111001010000001000110100000000100001100101100011110000"
|
||||
"0000010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010000"
|
||||
@@ -832,7 +832,7 @@ static void test_examples(const testCtx *const p_ctx) {
|
||||
"000001110000100101101000000101000011110100100011100111100001001101001010010101010010011111110101101100010010110011111010000010101000111101010000010001110001001100110010001010101010100011000111001011000010011010000010100000000010000000000000000000000"
|
||||
"101110001111011010010111111000011100001011011100011000011110110010110001100000000101100000001010010011101101001100000101111100000011000010101111101110001110110011001100110000000001011100111000110100111101100101111101011111111100110100000000000000000"
|
||||
},
|
||||
/* 96*/ { BARCODE_DBAR_EXPSTK, -1, -1, 2, "[8110]1061414165432131501101201211014092110256100126663101231", 0, 5, 249, 1, "NACAG Appendix C: Example 1, specifying max row",
|
||||
/* 96*/ { BARCODE_DBAR_EXPSTK, -1, -1, 2, "[8110]1061414165432131501101201211014092110256100126663101231", 0, 5, 249, 0, "NACAG Appendix C: Example 1, specifying max row; BWIPP need segments arg, see above",
|
||||
"010111101100011011101111111100001011001000001100110101111001101110001011110000000010110100010000001100001111000010101000111111000010100000101011110001110100000110011010111100000011101001111000101111000111011001001110001111000000101011001000001110010"
|
||||
"000000010011100100010000000010100100110111110011001010000110010001110100001010101001001011101111110011110000111101010101000000101001011111010100001110001011111001100101000010101000010110000111010000111000100110110001010000101010010100110111110000000"
|
||||
"000001010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010100000"
|
||||
@@ -872,8 +872,8 @@ static void test_examples(const testCtx *const p_ctx) {
|
||||
int i, length, ret;
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[4096] = {0}; /* Suppress clang -fsanitize=memory false positive */
|
||||
char cmp_buf[16384];
|
||||
char escaped[4096] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_buf[16384] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char cmp_msg[1024];
|
||||
|
||||
/* Only do BWIPP/ZXing-C++ tests if asked, too slow otherwise */
|
||||
@@ -1332,12 +1332,14 @@ static void test_hrt(const testCtx *const p_ctx) {
|
||||
/* 9*/ { BARCODE_DBAR_LTD, BARCODE_CONTENT_SEGS, "13410567901384", 0, "(01)13410567901384", "0113410567901384" },
|
||||
/* 10*/ { BARCODE_DBAR_EXP, -1, "[01]12345678901231", 0, "(01)12345678901231", "" }, /* See test_hrt() in "test_gs1.c" for full HRT tests */
|
||||
/* 11*/ { BARCODE_DBAR_EXP, BARCODE_CONTENT_SEGS, "[01]12345678901231", 0, "(01)12345678901231", "0112345678901231" },
|
||||
/* 12*/ { BARCODE_DBAR_STK, -1, "12345678901231", 0, "", "" }, /* No HRT for stacked */
|
||||
/* 13*/ { BARCODE_DBAR_STK, BARCODE_CONTENT_SEGS, "12345678901231", 0, "", "0112345678901231" }, /* But have content segs */
|
||||
/* 14*/ { BARCODE_DBAR_OMNSTK, -1, "10000000000090", 0, "", "" },
|
||||
/* 15*/ { BARCODE_DBAR_OMNSTK, BARCODE_CONTENT_SEGS, "10000000000090", 0, "", "0110000000000090" },
|
||||
/* 16*/ { BARCODE_DBAR_EXPSTK, -1, "[01]12345678901231", 0, "", "" },
|
||||
/* 17*/ { BARCODE_DBAR_EXPSTK, BARCODE_CONTENT_SEGS, "[01]12345678901231", 0, "", "0112345678901231" },
|
||||
/* 12*/ { BARCODE_DBAR_EXP, -1, "^0112345678901231", 0, "(01)12345678901231", "" },
|
||||
/* 13*/ { BARCODE_DBAR_EXP, BARCODE_CONTENT_SEGS, "^0112345678901231", 0, "(01)12345678901231", "0112345678901231" },
|
||||
/* 14*/ { BARCODE_DBAR_STK, -1, "12345678901231", 0, "", "" }, /* No HRT for stacked */
|
||||
/* 15*/ { BARCODE_DBAR_STK, BARCODE_CONTENT_SEGS, "12345678901231", 0, "", "0112345678901231" }, /* But have content segs */
|
||||
/* 16*/ { BARCODE_DBAR_OMNSTK, -1, "10000000000090", 0, "", "" },
|
||||
/* 17*/ { BARCODE_DBAR_OMNSTK, BARCODE_CONTENT_SEGS, "10000000000090", 0, "", "0110000000000090" },
|
||||
/* 18*/ { BARCODE_DBAR_EXPSTK, -1, "[01]12345678901231", 0, "", "" },
|
||||
/* 19*/ { BARCODE_DBAR_EXPSTK, BARCODE_CONTENT_SEGS, "[01]12345678901231", 0, "", "0112345678901231" },
|
||||
};
|
||||
const int data_size = ARRAY_SIZE(data);
|
||||
int i, length, ret;
|
||||
@@ -1441,16 +1443,16 @@ static void test_input(const testCtx *const p_ctx) {
|
||||
/* 34*/ { BARCODE_DBAR_LTD, -1, -1, -1, "[01)12345678901231", ZINT_ERROR_TOO_LONG, -1, -1, "Error 382: Input length 18 too long (maximum 14)", 0, 0 },
|
||||
/* 35*/ { BARCODE_DBAR_LTD, -1, -1, -1, "[10]12345678901231", ZINT_ERROR_TOO_LONG, -1, -1, "Error 382: Input length 18 too long (maximum 14)", 0, 0 },
|
||||
/* 36*/ { BARCODE_DBAR_LTD, GS1NOCHECK_MODE, -1, -1, "22345678901238", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 384: Input value out of range (0 to 1999999999999)", 0, 0 },
|
||||
/* 37*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]12345678901234", ZINT_WARN_NONCOMPLIANT, 1, 134, "Warning 261: AI (01) position 14: Bad checksum '4', expected '1'", 0, 0 },
|
||||
/* 37*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]12345678901234", ZINT_WARN_NONCOMPLIANT, 1, 134, "Warning 261: AI (01) data position 14: Bad checksum '4', expected '1'", 0, 0 },
|
||||
/* 38*/ { BARCODE_DBAR_EXP, GS1NOCHECK_MODE, -1, -1, "[01]12345678901234", 0, 1, 134, "", 0, 0 },
|
||||
/* 39*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]12345678901231", 0, 1, 134, "", 0, 0 },
|
||||
/* 40*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]1234567890123A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 385: Invalid character in Compressed Field data (digits only)", 0, 0 },
|
||||
/* 41*/ { BARCODE_DBAR_EXP, GS1NOCHECK_MODE, -1, -1, "[01]1234567890123A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 385: Invalid character in Compressed Field data (digits only)", 0, 0 },
|
||||
/* 42*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]123456789012315", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 259: Invalid data length for AI (01)", 0, 0 },
|
||||
/* 42*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]123456789012315", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 259: Invalid data length for AI (01) at position 1", 0, 0 },
|
||||
/* 43*/ { BARCODE_DBAR_EXP, GS1NOCHECK_MODE, -1, -1, "[01]123456789012315", 0, 1, 151, "", 0, 0 },
|
||||
/* 44*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]12345678901234", ZINT_WARN_NONCOMPLIANT, 1, 134, "Warning 261: AI (01) position 14: Bad checksum '4', expected '1'", 0, 0 },
|
||||
/* 44*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]12345678901234", ZINT_WARN_NONCOMPLIANT, 1, 134, "Warning 261: AI (01) data position 14: Bad checksum '4', expected '1'", 0, 0 },
|
||||
/* 45*/ { BARCODE_DBAR_EXP, GS1NOCHECK_MODE, -1, -1, "[01]12345678901234", 0, 1, 134, "", 0, 0 },
|
||||
/* 46*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]12345678901231[91]!\"%&'()*+,-./:;<=>?_ ", ZINT_WARN_NONCOMPLIANT, 1, 526, "Warning 261: AI (91) position 21: Invalid CSET 82 character ' '", 0, 0 }, /* ISOIEC punc */
|
||||
/* 46*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]12345678901231[91]!\"%&'()*+,-./:;<=>?_ ", ZINT_WARN_NONCOMPLIANT, 1, 526, "Warning 261: AI (91) data position 21: Invalid CSET 82 character ' '", 0, 0 }, /* ISOIEC punc */
|
||||
/* 47*/ { BARCODE_DBAR_EXP, GS1NOCHECK_MODE, -1, -1, "[01]12345678901231[91]!\"%&'()*+,-./:;<=>?_ ", 0, 1, 526, "", 0, 0 },
|
||||
/* 48*/ { BARCODE_DBAR_EXP, -1, -1, -1, "[01]12345678901231[91]!\"%&'()*+,-./:;<=>?_", 0, 1, 494, "", 0, 0 }, /* ISOIEC punc less space */
|
||||
/* 49*/ { BARCODE_DBAR_EXP, GS1NOCHECK_MODE, -1, -1, "[01]12345678901231[91]!\"%&'()*+,-./:;<=>?_", 0, 1, 494, "", 0, 0 },
|
||||
@@ -1486,12 +1488,12 @@ static void test_input(const testCtx *const p_ctx) {
|
||||
/* 79*/ { BARCODE_DBAR_OMNSTK, -1, -1, -1, "(01)12345678901231", 0, 5, 50, "", 0, 0 }, /* Allow '(01)' prefix if check digit given */
|
||||
/* 80*/ { BARCODE_DBAR_OMNSTK, -1, -1, -1, "(01)1234567890123", 0, 5, 50, "", 0, 0 }, /* Or not */
|
||||
/* 81*/ { BARCODE_DBAR_OMNSTK, -1, -1, -1, "(00)12345678901231", ZINT_ERROR_TOO_LONG, -1, -1, "Error 380: Input length 18 too long (maximum 14)", 0, 0 },
|
||||
/* 82*/ { BARCODE_DBAR_EXPSTK, -1, -1, -1, "[01]12345678901234", ZINT_WARN_NONCOMPLIANT, 5, 102, "Warning 261: AI (01) position 14: Bad checksum '4', expected '1'", 2, 0 },
|
||||
/* 82*/ { BARCODE_DBAR_EXPSTK, -1, -1, -1, "[01]12345678901234", ZINT_WARN_NONCOMPLIANT, 5, 102, "Warning 261: AI (01) data position 14: Bad checksum '4', expected '1'", 2, 0 },
|
||||
/* 83*/ { BARCODE_DBAR_EXPSTK, GS1NOCHECK_MODE, -1, -1, "[01]12345678901234", 0, 5, 102, "", 2, 0 },
|
||||
/* 84*/ { BARCODE_DBAR_EXPSTK, -1, -1, -1, "[01]12345678901231", 0, 5, 102, "", 2, 0 },
|
||||
/* 85*/ { BARCODE_DBAR_EXPSTK, -1, -1, -1, "[01]1234567890123A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 385: Invalid character in Compressed Field data (digits only)", 0, 0 },
|
||||
/* 86*/ { BARCODE_DBAR_EXPSTK, GS1NOCHECK_MODE, -1, -1, "[01]1234567890123A", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 385: Invalid character in Compressed Field data (digits only)", 0, 0 },
|
||||
/* 87*/ { BARCODE_DBAR_EXPSTK, -1, -1, -1, "[01]123456789012315", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 259: Invalid data length for AI (01)", 0, 0 },
|
||||
/* 87*/ { BARCODE_DBAR_EXPSTK, -1, -1, -1, "[01]123456789012315", ZINT_ERROR_INVALID_DATA, -1, -1, "Error 259: Invalid data length for AI (01) at position 1", 0, 0 },
|
||||
/* 88*/ { BARCODE_DBAR_EXPSTK, GS1NOCHECK_MODE, -1, -1, "[01]123456789012315", 0, 5, 102, "", 2, 0 },
|
||||
/* 89*/ { BARCODE_DBAR_EXPSTK, -1, 12, -1, "[01]12345678901231", 0, 5, 102, "", 2, 0 }, /* Cols > 11 ignored */
|
||||
/* 90*/ { BARCODE_DBAR_EXPSTK, -1, -1, 12, "[01]12345678901231", 0, 5, 102, "", 2, 0 }, /* Rows > 11 ignored */
|
||||
|
||||
@@ -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
|
||||
@@ -810,7 +810,7 @@ static void test_encode(const testCtx *const p_ctx) {
|
||||
struct zint_symbol *symbol = NULL;
|
||||
|
||||
char escaped[1024];
|
||||
char bwipp_buf[32768];
|
||||
char bwipp_buf[32768] ZINT_TESTUTIL_SANITIZEM_INIT;
|
||||
char bwipp_msg[1024];
|
||||
|
||||
int do_bwipp = (debug & ZINT_DEBUG_TEST_BWIPP) && testUtilHaveGhostscript(); /* Only do BWIPP test if asked, too slow otherwise */
|
||||
|
||||
+54
-34
@@ -570,6 +570,7 @@ const char *testUtilInputModeName(int input_mode) {
|
||||
{ "FAST_MODE", FAST_MODE, 0x0080 },
|
||||
{ "EXTRA_ESCAPE_MODE", EXTRA_ESCAPE_MODE, 0x0100 },
|
||||
{ "GS1SYNTAXENGINE_MODE", GS1SYNTAXENGINE_MODE, 0x0200 },
|
||||
{ "GS1RAW_MODE", GS1RAW_MODE, 0x0400 },
|
||||
};
|
||||
const int data_size = ARRAY_SIZE(data);
|
||||
int set, i;
|
||||
@@ -2296,7 +2297,7 @@ int testUtilVerifyTiffInfo(const char *filename, int debug) {
|
||||
|
||||
/* Map Zint symbology to BWIPP routine */
|
||||
static const char *testUtilBwippName(int index, const struct zint_symbol *symbol, int option_1, int option_2,
|
||||
int option_3, int debug, int *linear_row_height, int *gs1_cvt) {
|
||||
int option_3, int debug, int *p_linear_row_height, int *p_gs1_cvt) {
|
||||
struct item {
|
||||
const char *name;
|
||||
int define;
|
||||
@@ -2324,7 +2325,7 @@ static const char *testUtilBwippName(int index, const struct zint_symbol *symbol
|
||||
{ "ean13", BARCODE_EANX, 13, 0, 1, 0, 0, 1 /*gs1_cvt*/, },
|
||||
{ "ean13", BARCODE_EANX_CHK, 14, 0, 1, 0, 0, 1, },
|
||||
{ "ean13", BARCODE_EAN13, 15, 0, 1, 0, 0, 1, },
|
||||
{ "gs1-128", BARCODE_GS1_128, 16, 0, 0, 0, 0, 1 /*gs1_cvt*/, },
|
||||
{ "gs1-128", BARCODE_GS1_128, 16, 0, 0, 1 /*GS1CARET*/, 0, 1 /*gs1_cvt*/, },
|
||||
{ "", -1, 17, 0, 0, 0, 0, 0, },
|
||||
{ "rationalizedCodabar", BARCODE_CODABAR, 18, 0, 1, 0, 0, 0, },
|
||||
{ "", -1, 19, 0, 0, 0, 0, 0, },
|
||||
@@ -2339,7 +2340,7 @@ static const char *testUtilBwippName(int index, const struct zint_symbol *symbol
|
||||
{ "flattermarken", BARCODE_FLAT, 28, 0, 0, 0, 0, 0, },
|
||||
{ "databaromni", BARCODE_DBAR_OMN, 29, 0, 0, 0, 0, 1 /*gs1_cvt*/, },
|
||||
{ "databarlimited", BARCODE_DBAR_LTD, 30, 0, 0, 0, 0, 1, },
|
||||
{ "databarexpanded", BARCODE_DBAR_EXP, 31, 0, 1, 0, 1 /*linear_row_height*/, 1, },
|
||||
{ "databarexpanded", BARCODE_DBAR_EXP, 31, 0, 1, 1 /*GS1CARET*/, 1 /*linear_row_height*/, 1, },
|
||||
{ "telepen", BARCODE_TELEPEN, 32, 0, 0, 0, 0, 0, },
|
||||
{ "", -1, 33, 0, 0, 0, 0, 0, },
|
||||
{ "upca", BARCODE_UPCA, 34, 0, 1, 0, 0, 1 /*gs1_cvt*/, },
|
||||
@@ -2380,7 +2381,7 @@ static const char *testUtilBwippName(int index, const struct zint_symbol *symbol
|
||||
{ "isbn", BARCODE_ISBNX, 69, 0, 1, 0, 0, 1 /*gs1_cvt*/, },
|
||||
{ "royalmail", BARCODE_RM4SCC, 70, 0, 0, 0, 0, 0, },
|
||||
{ "datamatrix", BARCODE_DATAMATRIX, 71, 0, 1, 1, 1, 0, },
|
||||
{ "ean14", BARCODE_EAN14, 72, 0, 0, 0, 0, 1 /*gs1_cvt*/, },
|
||||
{ "ean14", BARCODE_EAN14, 72, 0, 0, 1 /*GS1CARET*/, 0, 1 /*gs1_cvt*/, },
|
||||
{ "code39", BARCODE_VIN, 73, 0, 0, 0, 0, 0, },
|
||||
{ "codablockf", BARCODE_CODABLOCKF, 74, 1, 1, 0, 10 /*linear_row_height*/, 0, },
|
||||
{ "sscc18", BARCODE_NVE18, 75, 0, 0, 0, 0, 1 /*gs1_cvt*/, },
|
||||
@@ -2389,7 +2390,7 @@ static const char *testUtilBwippName(int index, const struct zint_symbol *symbol
|
||||
{ "", -1, 78, 0, 0, 0, 0, 0, },
|
||||
{ "databarstacked", BARCODE_DBAR_STK, 79, 0, 0, 0, 0, 1 /*gs1_cvt*/, },
|
||||
{ "databarstackedomni", BARCODE_DBAR_OMNSTK, 80, 0, 0, 0, 33 /*linear_row_height*/, 1, },
|
||||
{ "databarexpandedstacked", BARCODE_DBAR_EXPSTK, 81, 0, 1, 0, 34 /*linear_row_height*/, 1, },
|
||||
{ "databarexpandedstacked", BARCODE_DBAR_EXPSTK, 81, 0, 1, 1 /*GS1CARET*/, 34 /*linear_row_height*/, 1, },
|
||||
{ "planet", BARCODE_PLANET, 82, 0, 0, 0, 0, 0, },
|
||||
{ "", -1, 83, 0, 0, 0, 0, 0, },
|
||||
{ "micropdf417", BARCODE_MICROPDF417, 84, 0, 1, 0, 0, 0, },
|
||||
@@ -2439,15 +2440,15 @@ static const char *testUtilBwippName(int index, const struct zint_symbol *symbol
|
||||
{ "aztecrune", BARCODE_AZRUNE, 128, 0, 0, 0, 0, 0, },
|
||||
{ "code32", BARCODE_CODE32, 129, 0, 0, 0, 0, 0, },
|
||||
{ "ean13composite", BARCODE_EANX_CC, 130, 1, 1, 0, 72 /*linear_row_height*/, 1 /*gs1_cvt*/, },
|
||||
{ "gs1-128composite", BARCODE_GS1_128_CC, 131, 1, 0, 0, 36, 1, },
|
||||
{ "gs1-128composite", BARCODE_GS1_128_CC, 131, 1, 0, 1 /*GS1CARET*/, 36, 1, },
|
||||
{ "databaromnicomposite", BARCODE_DBAR_OMN_CC, 132, 1, 0, 0, 33, 1, },
|
||||
{ "databarlimitedcomposite", BARCODE_DBAR_LTD_CC, 133, 1, 0, 0, 10 /*linear_row_height*/, 1, },
|
||||
{ "databarexpandedcomposite", BARCODE_DBAR_EXP_CC, 134, 1, 1, 0, 34 /*linear_row_height*/, 1, },
|
||||
{ "databarexpandedcomposite", BARCODE_DBAR_EXP_CC, 134, 1, 1, 1 /*GS1CARET*/, 34 /*linear_row_height*/, 1, },
|
||||
{ "upcacomposite", BARCODE_UPCA_CC, 135, 1, 1, 0, 72, 1, },
|
||||
{ "upcecomposite", BARCODE_UPCE_CC, 136, 1, 1, 0, 72, 1, },
|
||||
{ "databarstackedcomposite", BARCODE_DBAR_STK_CC, 137, 1, 0, 0, 0, 1, },
|
||||
{ "databarstackedomnicomposite", BARCODE_DBAR_OMNSTK_CC, 138, 1, 0, 0, 33 /*linear_row_height*/, 1, },
|
||||
{ "databarexpandedstackedcomposite", BARCODE_DBAR_EXPSTK_CC, 139, 1, 1, 0, 34 /*linear_row_height*/, 1, },
|
||||
{ "databarexpandedstackedcomposite", BARCODE_DBAR_EXPSTK_CC, 139, 1, 1, 1 /*GS1CARET*/, 34 /*lin_r_h*/, 1, },
|
||||
{ "channelcode", BARCODE_CHANNEL, 140, 0, 0, 0, 0, 0, },
|
||||
{ "codeone", BARCODE_CODEONE, 141, 0, 1, 0, 0, 0, },
|
||||
{ "", BARCODE_GRIDMATRIX, 142, 0, 0, 0, 0, 0, },
|
||||
@@ -2462,7 +2463,9 @@ static const char *testUtilBwippName(int index, const struct zint_symbol *symbol
|
||||
const int data_size = ARRAY_SIZE(data);
|
||||
|
||||
const int symbology = symbol->symbology;
|
||||
const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE;
|
||||
const int gs1raw_mode = !!(symbol->input_mode & GS1RAW_MODE);
|
||||
const int gs1_caret = option_3 != -1 && !!(option_3 & ZINT_TESTUTIL_GS1CARET); /* Hack indicator */
|
||||
const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE || gs1raw_mode || gs1_caret;
|
||||
|
||||
if (symbology < 0 || symbology >= data_size) {
|
||||
fprintf(stderr, "testUtilBwippName: unknown symbology (%d)\n", symbology);
|
||||
@@ -2544,16 +2547,30 @@ static const char *testUtilBwippName(int index, const struct zint_symbol *symbol
|
||||
}
|
||||
}
|
||||
|
||||
if (linear_row_height) {
|
||||
*linear_row_height = data[symbology].linear_row_height;
|
||||
if (p_linear_row_height) {
|
||||
*p_linear_row_height = data[symbology].linear_row_height;
|
||||
}
|
||||
if (gs1_cvt) {
|
||||
*gs1_cvt = data[symbology].gs1_cvt;
|
||||
if (p_gs1_cvt) {
|
||||
*p_gs1_cvt = data[symbology].gs1_cvt;
|
||||
}
|
||||
if (gs1) {
|
||||
if (gs1raw_mode) {
|
||||
if (debug & ZINT_DEBUG_TEST_PRINT) {
|
||||
printf("i:%d %s not BWIPP compatible, GS1RAW_MODE not supported\n",
|
||||
index, testUtilBarcodeName(symbology));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (gs1_caret) {
|
||||
if (debug & ZINT_DEBUG_TEST_PRINT) {
|
||||
printf("i:%d %s not BWIPP compatible, GS1 Syntax Engine caret input not supported\n",
|
||||
index, testUtilBarcodeName(symbology));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (symbology == BARCODE_DATAMATRIX) {
|
||||
if (gs1_cvt) {
|
||||
*gs1_cvt = 1;
|
||||
if (p_gs1_cvt) {
|
||||
*p_gs1_cvt = 1;
|
||||
}
|
||||
return "gs1datamatrix";
|
||||
} else if (symbology == BARCODE_AZTEC || symbology == BARCODE_CODE16K || symbology == BARCODE_ULTRA
|
||||
@@ -2564,13 +2581,13 @@ static const char *testUtilBwippName(int index, const struct zint_symbol *symbol
|
||||
}
|
||||
return NULL;
|
||||
} else if (symbology == BARCODE_QRCODE) {
|
||||
if (gs1_cvt) {
|
||||
*gs1_cvt = 1;
|
||||
if (p_gs1_cvt) {
|
||||
*p_gs1_cvt = 1;
|
||||
}
|
||||
return "gs1qrcode";
|
||||
} else if (symbology == BARCODE_DOTCODE) {
|
||||
if (gs1_cvt) {
|
||||
*gs1_cvt = 1;
|
||||
if (p_gs1_cvt) {
|
||||
*p_gs1_cvt = 1;
|
||||
}
|
||||
return "gs1dotcode";
|
||||
}
|
||||
@@ -3876,8 +3893,8 @@ static const char *testUtilZXingCPPName(int index, const struct zint_symbol *sym
|
||||
{ "", -1, 5, },
|
||||
{ "", BARCODE_C25LOGIC, 6, },
|
||||
{ "", BARCODE_C25IND, 7, },
|
||||
{ "Code39", BARCODE_CODE39, 8, },
|
||||
{ "Code39", BARCODE_EXCODE39, 9, }, /* TODO: Code39 with specially encoded chars */
|
||||
{ "Code39Std", BARCODE_CODE39, 8, },
|
||||
{ "Code39", BARCODE_EXCODE39, 9, },
|
||||
{ "EAN8", BARCODE_EAN8, 10, },
|
||||
{ "", BARCODE_EAN_2ADDON, 11, },
|
||||
{ "", BARCODE_EAN_5ADDON, 12, },
|
||||
@@ -3918,9 +3935,9 @@ static const char *testUtilZXingCPPName(int index, const struct zint_symbol *sym
|
||||
{ "", BARCODE_MSI_PLESSEY, 47, },
|
||||
{ "", -1, 48, },
|
||||
{ "", BARCODE_FIM, 49, },
|
||||
{ "Code39", BARCODE_LOGMARS, 50, },
|
||||
{ "Code39Std", BARCODE_LOGMARS, 50, },
|
||||
{ "", BARCODE_PHARMA, 51, },
|
||||
{ "Code39", BARCODE_PZN, 52, },
|
||||
{ "Code39Std", BARCODE_PZN, 52, },
|
||||
{ "", BARCODE_PHARMA_TWO, 53, },
|
||||
{ "", -1, 54, },
|
||||
{ "PDF417", BARCODE_PDF417, 55, },
|
||||
@@ -3941,7 +3958,7 @@ static const char *testUtilZXingCPPName(int index, const struct zint_symbol *sym
|
||||
{ "", BARCODE_RM4SCC, 70, },
|
||||
{ "DataMatrix", BARCODE_DATAMATRIX, 71, },
|
||||
{ "Code128", BARCODE_EAN14, 72, },
|
||||
{ "Code39", BARCODE_VIN, 73, },
|
||||
{ "Code39Std", BARCODE_VIN, 73, },
|
||||
{ "CodablockF", BARCODE_CODABLOCKF, 74, },
|
||||
{ "Code128", BARCODE_NVE18, 75, },
|
||||
{ "", BARCODE_JAPANPOST, 76, },
|
||||
@@ -3967,7 +3984,7 @@ static const char *testUtilZXingCPPName(int index, const struct zint_symbol *sym
|
||||
{ "Code128", BARCODE_DPD, 96, },
|
||||
{ "MicroQRCode", BARCODE_MICROQR, 97, },
|
||||
{ "Code128", BARCODE_HIBC_128, 98, },
|
||||
{ "Code39", BARCODE_HIBC_39, 99, },
|
||||
{ "Code39Std", BARCODE_HIBC_39, 99, },
|
||||
{ "", -1, 100, },
|
||||
{ "", -1, 101, },
|
||||
{ "DataMatrix", BARCODE_HIBC_DM, 102, },
|
||||
@@ -4127,12 +4144,12 @@ int testUtilZXingCPP(int index, struct zint_symbol *symbol, const char *source,
|
||||
|
||||
if (symbology == BARCODE_EXCODE39) {
|
||||
if (symbol->option_2 == 1) {
|
||||
opts = "tryCode39ExtendedMode,validateCode39CheckSum";
|
||||
opts = "tryCode39ExtendedMode,validateOptionalChecksum";
|
||||
} else {
|
||||
opts = "tryCode39ExtendedMode";
|
||||
}
|
||||
} else if ((symbology == BARCODE_CODE39 || symbology == BARCODE_LOGMARS) && symbol->option_2 == 1) {
|
||||
opts = "validateCode39CheckSum";
|
||||
opts = "validateOptionalChecksum";
|
||||
}
|
||||
|
||||
if (zxingcpp_cmp > 1 && symbol->eci == 0) {
|
||||
@@ -4283,8 +4300,8 @@ int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, in
|
||||
const int is_extra_escaped = (symbol->input_mode & EXTRA_ESCAPE_MODE) && symbol->symbology == BARCODE_CODE128;
|
||||
const int is_escaped = (symbol->input_mode & ESCAPE_MODE) || is_extra_escaped;
|
||||
const int is_hibc = symbology >= BARCODE_HIBC_128 && symbology <= BARCODE_HIBC_AZTEC;
|
||||
const int have_c25checkdigit = symbol->option_2 == 1 || symbol->option_2 == 2;
|
||||
const int have_c25inter = (symbology == BARCODE_C25INTER && ((expected_len & 1) || have_c25checkdigit))
|
||||
const int have_ccheckdigit = symbol->option_2 == 1 || symbol->option_2 == 2; /* Good for C25, CODE39, CODABAR */
|
||||
const int have_c25inter = (symbology == BARCODE_C25INTER && ((expected_len & 1) || have_ccheckdigit))
|
||||
|| symbology == BARCODE_ITF14 || symbology == BARCODE_DPLEIT
|
||||
|| symbology == BARCODE_DPIDENT;
|
||||
const int is_upcean = (ZBarcode_Cap(symbology, ZINT_CAP_EANUPC) & ZINT_CAP_EANUPC) == ZINT_CAP_EANUPC;
|
||||
@@ -4362,7 +4379,7 @@ int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, in
|
||||
expected = escaped;
|
||||
}
|
||||
if (gs1 && symbology != BARCODE_EAN14 && symbology != BARCODE_NVE18) {
|
||||
ret = zint_gs1_verify(symbol, ZUCP(expected), expected_len, ZUCP(reduced), &expected_len);
|
||||
ret = zint_gs1_verify(symbol, ZUCP(expected), expected_len, ZUCP(reduced), &expected_len, 0 /*set_hrt*/);
|
||||
if (ret >= ZINT_ERROR) {
|
||||
sprintf(msg, "zint_gs1_verify %d != 0", ret);
|
||||
return 3;
|
||||
@@ -4441,7 +4458,7 @@ int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, in
|
||||
cmp_len -= 2;
|
||||
expected++;
|
||||
expected_len -= 2;
|
||||
if (symbol->option_2 == 1 || symbol->option_2 == 2) {
|
||||
if (have_ccheckdigit) {
|
||||
cmp_len--; /* Too messy to calc the check digit so ignore */
|
||||
}
|
||||
} else if (is_vin_international) {
|
||||
@@ -4451,15 +4468,15 @@ int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, in
|
||||
expected = vin;
|
||||
} else if (have_c25inter) {
|
||||
if (symbology == BARCODE_C25INTER) {
|
||||
if ((expected_len & 1) || have_c25checkdigit) {
|
||||
if (((expected_len & 1) && !have_c25checkdigit) || (!(expected_len & 1) && have_c25checkdigit)) {
|
||||
if ((expected_len & 1) || have_ccheckdigit) {
|
||||
if (((expected_len & 1) && !have_ccheckdigit) || (!(expected_len & 1) && have_ccheckdigit)) {
|
||||
c25inter[0] = '0';
|
||||
memcpy(c25inter + 1, expected, expected_len);
|
||||
expected_len++;
|
||||
} else {
|
||||
memcpy(c25inter, expected, expected_len);
|
||||
}
|
||||
if (have_c25checkdigit) {
|
||||
if (have_ccheckdigit) {
|
||||
c25inter[expected_len] = zint_gs1_check_digit((const unsigned char *) c25inter, expected_len);
|
||||
expected_len++;
|
||||
}
|
||||
@@ -4652,6 +4669,9 @@ int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, in
|
||||
expected = azrune;
|
||||
expected_len = 3;
|
||||
}
|
||||
} else if ((symbology == BARCODE_CODE39 || symbology == BARCODE_EXCODE39 || symbology == BARCODE_LOGMARS)
|
||||
&& have_ccheckdigit) {
|
||||
cmp_len--; /* Too tedious to calculate so ignore */
|
||||
}
|
||||
|
||||
if (ret_buf) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2019-2025 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2019-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
|
||||
@@ -49,6 +49,17 @@ extern "C" {
|
||||
#define ZINT_DEBUG_TEST_ZXINGCPP 512
|
||||
#define ZINT_DEBUG_TEST_BWIPP_ZXINGCPP 1024
|
||||
|
||||
#ifdef ZINT_SANITIZEM /* Suppress clang -fsanitize=memory false positives */
|
||||
#define ZINT_TESTUTIL_SANITIZEM_INIT = {0}
|
||||
#define ZINT_TESTUTIL_SANITIZEM_INIT_2D = {{0}}
|
||||
#else
|
||||
#define ZINT_TESTUTIL_SANITIZEM_INIT
|
||||
#define ZINT_TESTUTIL_SANITIZEM_INIT_2D
|
||||
#endif
|
||||
|
||||
/* Hack `option_3` flag to indicate GS1 Syntax Engine caret input */
|
||||
#define ZINT_TESTUTIL_GS1CARET (1 << 24)
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "../common.h"
|
||||
|
||||
Binary file not shown.
@@ -2,7 +2,7 @@
|
||||
/* Generate GS1 verify include "backend/gs1_lint.h" for "backend/gs1.c" */
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2021-2025 <rstuart114@gmail.com>
|
||||
Copyright (C) 2021-2026 <rstuart114@gmail.com>
|
||||
*/
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
@@ -76,8 +76,8 @@ foreach ($lines as $line) {
|
||||
}
|
||||
|
||||
if (($hyphen = strpos($ai, '-')) !== false) {
|
||||
if ($fixed !== '') {
|
||||
$fixed_ais[substr($ai, 0, 2)] = true;
|
||||
if ($fixed) {
|
||||
$fixed_ais[substr($ai, 0, 2)] = strlen(substr($ai, 0, $hyphen));
|
||||
}
|
||||
$ai_s = (int) substr($ai, 0, $hyphen);
|
||||
$ai_e = (int) substr($ai, $hyphen + 1);
|
||||
@@ -98,8 +98,8 @@ foreach ($lines as $line) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($fixed !== '') {
|
||||
$fixed_ais[substr($ai, 0, 2)] = true;
|
||||
if ($fixed) {
|
||||
$fixed_ais[substr($ai, 0, 2)] = strlen($ai);
|
||||
}
|
||||
$ai = (int) $ai;
|
||||
$ais[] = $ai;
|
||||
@@ -243,7 +243,7 @@ if ($print_copyright) {
|
||||
print <<<'EOD'
|
||||
/*
|
||||
libzint - the open source barcode library
|
||||
Copyright (C) 2021-2025 Robin Stuart <rstuart114@gmail.com>
|
||||
Copyright (C) 2021-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
|
||||
@@ -365,6 +365,7 @@ $tab$tab{$tab}char err_msg[50]) {
|
||||
|
||||
$tab/* Assume data length failure */
|
||||
$tab*p_err_no = 2;
|
||||
$tab*p_err_posn = 1;
|
||||
|
||||
EOD;
|
||||
|
||||
@@ -477,6 +478,237 @@ $tab}
|
||||
|
||||
EOD;
|
||||
|
||||
print <<<EOD
|
||||
|
||||
/* Helper to parse non-bracketed input */
|
||||
static int gs1_lint_parse_ai(const unsigned char source[], const int length, const int position,
|
||||
$tab$tab{$tab}int *p_ai, int *p_min, int *p_max) {
|
||||
${tab}int ai, ai2, ai3 = -1, ai4 = -1, min, max = 0;
|
||||
|
||||
{$tab}*p_ai = -1;
|
||||
|
||||
{$tab}if (position + 1 >= length || !z_isdigit(source[position]) || !z_isdigit(source[position + 1])) {
|
||||
$tab{$tab}return 0;
|
||||
{$tab}}
|
||||
{$tab}ai2 = z_to_int(source + position, 2);
|
||||
{$tab}if (position + 3 < length && z_isdigit(source[position + 2])) {
|
||||
$tab{$tab}ai3 = z_to_int(source + position, 3);
|
||||
$tab{$tab}if (position + 4 < length && z_isdigit(source[position + 3])) {
|
||||
$tab$tab{$tab}ai4 = z_to_int(source + position, 4);
|
||||
$tab{$tab}}
|
||||
{$tab}}
|
||||
|
||||
EOD;
|
||||
|
||||
$not_first_batch = false;
|
||||
$last_batch_e = -1;
|
||||
$big_batch = 2;
|
||||
foreach ($batches as $batch => $batch_specs) {
|
||||
if (empty($batch_specs)) {
|
||||
continue;
|
||||
}
|
||||
$batch_s = $batch * 100;
|
||||
$batch_e = $batch_s + 100;
|
||||
$n = $batch_s < 100 ? 2 : ($batch_s < 1000 ? 3 : 4);
|
||||
$first_tab = $n == 2 ? "" : $tab . $tab;
|
||||
if ($n == 2) {
|
||||
print "\n{$first_tab}{$tab}ai = ai2;\n";
|
||||
} else {
|
||||
if ($n != $big_batch) {
|
||||
if ($n == 3) {
|
||||
print "\n{$tab}if (max == 0 && ai3 != -1) {\n";
|
||||
} else {
|
||||
print "{$first_tab}}\n\n{$tab}}\n\n{$tab}if (max == 0 && ai4 != -1) {\n";
|
||||
}
|
||||
$not_first_batch = false;
|
||||
}
|
||||
if ($not_first_batch) {
|
||||
print "\n$first_tab} else if (ai" . $n. " < $batch_e) {\n{$first_tab}{$tab}ai = ai" . $n . ";\n";
|
||||
} else {
|
||||
print "\n{$first_tab}if (ai" . $n . " < $batch_e) {\n{$first_tab}{$tab}ai = ai" . $n . ";\n";
|
||||
$not_first_batch = true;
|
||||
}
|
||||
}
|
||||
$not_first_spec = false;
|
||||
foreach ($batch_specs as $spec) {
|
||||
$total_min = $spec_ais[$spec][0];
|
||||
$total_max = $spec_ais[$spec][1];
|
||||
$ais = $spec_ais[$spec][2];
|
||||
|
||||
if ($not_first_spec) {
|
||||
$str = "$first_tab{$tab}} else if (";
|
||||
} else {
|
||||
$str = "$first_tab{$tab}if (";
|
||||
$not_first_spec = true;
|
||||
}
|
||||
print $str;
|
||||
$width = strlen($str);
|
||||
|
||||
// Count the applicable AIs
|
||||
$ais_cnt = 0;
|
||||
foreach ($ais as $ai) {
|
||||
if (is_array($ai)) {
|
||||
if ($ai[1] < $batch_s || $ai[0] >= $batch_e) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if ($ai < $batch_s || $ai >= $batch_e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$ais_cnt++;
|
||||
}
|
||||
|
||||
// Output
|
||||
$not_first_ai = false;
|
||||
foreach ($ais as $ai) {
|
||||
if (is_array($ai)) {
|
||||
if ($ai[1] < $batch_s || $ai[0] >= $batch_e) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if ($ai < $batch_s || $ai >= $batch_e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$str = '';
|
||||
if ($not_first_ai) {
|
||||
$str .= " || ";
|
||||
} else {
|
||||
$not_first_ai = true;
|
||||
}
|
||||
if (is_array($ai)) {
|
||||
if ($ai[0] === $last_batch_e) { // Don't need 1st element of range if excluded by previous batch
|
||||
$str .= "ai <= " . $ai[1];
|
||||
} else if ($ai[1] + 1 == $batch_e) { // Don't need 2nd element of range if excluded by this batch
|
||||
$str .= "ai >= " . $ai[0];
|
||||
} else {
|
||||
if ($ais_cnt > 1) {
|
||||
$str .= "(ai >= " . $ai[0] . " && ai <= " . $ai[1] . ")";
|
||||
} else {
|
||||
$str .= "ai >= " . $ai[0] . " && ai <= " . $ai[1];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$str .= "ai == " . $ai;
|
||||
}
|
||||
if ($width + strlen($str) > 118) {
|
||||
print "\n";
|
||||
$str2 = "$first_tab$tab$tab ";
|
||||
print $str2;
|
||||
$width = strlen($str2);
|
||||
}
|
||||
print $str;
|
||||
$width += strlen($str);
|
||||
}
|
||||
list($min, $max) = $spec_ais[$spec];
|
||||
$str = "$first_tab$tab{$tab}min = $min, max = $max;";
|
||||
print ") {\n$str\n";
|
||||
print <<<EOD
|
||||
|
||||
EOD;
|
||||
}
|
||||
$last_batch_e = $batch_e;
|
||||
if ($big_batch != $n) {
|
||||
$big_batch = $n;
|
||||
}
|
||||
print <<<EOD
|
||||
$first_tab{$tab}}
|
||||
|
||||
EOD;
|
||||
}
|
||||
|
||||
print <<<EOD
|
||||
$first_tab}
|
||||
$tab}
|
||||
|
||||
{$tab}if (max == 0) {
|
||||
$tab{$tab}*p_ai = ai2; /* Use 2-digit as feedback */
|
||||
$tab{$tab}return 0;
|
||||
$tab}
|
||||
{$tab}assert(ai >= 0 && ai <= 9999);
|
||||
{$tab}assert(min >= 1);
|
||||
{$tab}assert(max >= min);
|
||||
|
||||
{$tab}*p_ai = ai;
|
||||
{$tab}if (p_min) {
|
||||
$tab{$tab}*p_min = min;
|
||||
{$tab}}
|
||||
{$tab}if (p_max) {
|
||||
$tab{$tab}*p_max = max;
|
||||
{$tab}}
|
||||
{$tab}return 1;
|
||||
}
|
||||
|
||||
/* Parse non-bracketed input */
|
||||
static int gs1_lint_parse_raw_caret(const unsigned char source[], const int length,
|
||||
$tab$tab{$tab}const int ai_max, int *ai_vals, int *ai_locs, int *data_locs, int *data_lens, int *p_ai_count,
|
||||
$tab$tab{$tab}int *p_err_no, int *p_err_posn) {
|
||||
{$tab}int i, j;
|
||||
{$tab}const int gs1_caret = source[0] == '^';
|
||||
{$tab}const unsigned char separator = gs1_caret ? '^' : '\\x1D';
|
||||
{$tab}int ai, max;
|
||||
{$tab}int ai_count = 0, ai_len;
|
||||
{$tab}#ifdef NDEBUG
|
||||
{$tab}(void)ai_max;
|
||||
{$tab}#endif
|
||||
|
||||
{$tab}i = gs1_caret || source[0] == '\\x1D'; /* Allow GS at start also */
|
||||
|
||||
{$tab}if (i >= length) {
|
||||
$tab{$tab}*p_ai_count = 0; /* For feedback */
|
||||
$tab{$tab}ai_vals[0] = -1;
|
||||
$tab{$tab}ai_locs[0] = i - 1;
|
||||
$tab{$tab}*p_err_no = 1;
|
||||
$tab{$tab}*p_err_posn = i;
|
||||
$tab{$tab}return 0;
|
||||
{$tab}}
|
||||
|
||||
{$tab}while (i < length) {
|
||||
$tab{$tab}int data_start, data_max, on_separator;
|
||||
$tab{$tab}assert(ai_count < ai_max);
|
||||
$tab{$tab}ai_locs[ai_count] = i;
|
||||
$tab{$tab}if (!gs1_lint_parse_ai(source, length, i, &ai, NULL /*min*/, &max)) {
|
||||
$tab$tab{$tab}*p_ai_count = ai_count; /* For feedback */
|
||||
$tab$tab{$tab}ai_vals[ai_count] = ai; /* May be -1 */
|
||||
$tab$tab{$tab}*p_err_no = 1;
|
||||
$tab$tab{$tab}*p_err_posn = i + 1; /* Position 1-base */
|
||||
$tab$tab{$tab}return 0;
|
||||
$tab{$tab}}
|
||||
$tab{$tab}ai_vals[ai_count] = ai;
|
||||
$tab{$tab}ai_len = ai < 100 ? 2 : ai < 1000 ? 3 : 4;
|
||||
|
||||
$tab{$tab}/* Following GS1 Syntax Engine tolerating superfluous FNC1s at end of AI data
|
||||
$tab{$tab} (for both final AI and AIs with predefined length) */
|
||||
$tab{$tab}data_start = i + ai_len;
|
||||
$tab{$tab}data_max = data_start + max;
|
||||
$tab{$tab}for (j = data_start; j < length && j < data_max; j++) {
|
||||
$tab$tab{$tab}if (source[j] == separator) {
|
||||
$tab$tab$tab{$tab}break;
|
||||
$tab$tab{$tab}}
|
||||
$tab{$tab}}
|
||||
$tab{$tab}data_locs[ai_count] = data_start;
|
||||
$tab{$tab}/* Only checking that have at least one char, and haven't exceeded max */
|
||||
$tab{$tab}on_separator = j < length && source[j] == separator;
|
||||
$tab{$tab}if (j == data_start || (j + 1 == length && length > data_max && !on_separator)) {
|
||||
$tab$tab{$tab}*p_ai_count = ai_count; /* For feedback */
|
||||
$tab$tab{$tab}data_lens[ai_count] = j - data_start;
|
||||
$tab$tab{$tab}*p_err_no = 2;
|
||||
$tab$tab{$tab}*p_err_posn = i + 1; /* Position 1-base */
|
||||
$tab$tab{$tab}return 0;
|
||||
$tab{$tab}}
|
||||
$tab{$tab}data_lens[ai_count] = j - data_locs[ai_count];
|
||||
$tab{$tab}ai_count++;
|
||||
$tab{$tab}i = j + on_separator;
|
||||
{$tab}}
|
||||
|
||||
{$tab}*p_ai_count = ai_count;
|
||||
{$tab}return 1;
|
||||
}
|
||||
|
||||
EOD;
|
||||
|
||||
if ($print_h_guard) {
|
||||
print <<<'EOD'
|
||||
|
||||
|
||||
@@ -326,6 +326,7 @@ extern "C" {
|
||||
#define EXTRA_ESCAPE_MODE 0x0100 /* Process special symbology-specific escape sequences as well as others */
|
||||
/* Note: currently Code 128 only */
|
||||
#define GS1SYNTAXENGINE_MODE 0x0200 /* Use the GS1 Syntax Engine (if available) to strictly validate GS1 input */
|
||||
#define GS1RAW_MODE 0x0400 /* Process GS1 data literally (no AI delimiters), parsing GSs as FNC1s */
|
||||
|
||||
/* Aztec Code specific options (`symbol->option_3`) */
|
||||
#define ZINT_AZTEC_FULL 128 /* Only consider Full versions on automatic symbol size selection */
|
||||
|
||||
Reference in New Issue
Block a user