1
0
mirror of https://git.code.sf.net/p/zint/code synced 2026-05-14 18:13:53 +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:
gitlost
2026-02-26 15:05:45 +00:00
parent 3b24d129d7
commit 0a8a79fa6c
59 changed files with 7504 additions and 4206 deletions

View File

@@ -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 */