diff --git a/backend/bmp.h b/backend/bmp.h
index 4f1f3843..9e9e784a 100644
--- a/backend/bmp.h
+++ b/backend/bmp.h
@@ -35,7 +35,7 @@
#ifdef __cplusplus
extern "C" {
-#endif
+#endif /* __cplusplus */
#ifdef OUT_USE_PRAGMA_PACK
#pragma pack(1)
@@ -75,7 +75,7 @@ extern "C" {
#ifdef __cplusplus
}
-#endif
+#endif /* __cplusplus */
/* vim: set ts=4 sw=4 et : */
#endif /* Z_BMP_H */
diff --git a/backend/code128.c b/backend/code128.c
index 1a18249f..4df55a11 100644
--- a/backend/code128.c
+++ b/backend/code128.c
@@ -75,167 +75,157 @@ INTERNAL_DATA const char C128Table[107][6] = { /* Used by CODABLOCKF and CODE16K
{'2','1','1','2','1','4'}, {'2','1','1','2','3','2'}, {/* Only used by CODE16K */ '2','1','1','1','3','3'}
};
-/* Determine appropriate mode for a given character */
-INTERNAL int c128_parunmodd(const unsigned char llyth, const int check_fnc1) {
- int modd;
+/* Whether `ch` can be encoded directly in code set `charset` (no shifts) (for `c128_define_mode()` below) */
+static int c128_can_aorb(const unsigned char ch, const int charset, const int check_fnc1) {
- if (llyth <= 31) {
- modd = check_fnc1 && llyth == '\x1D' ? C128_ABORC : C128_SHIFTA;
- } else if ((llyth >= 48) && (llyth <= 57)) {
- modd = C128_ABORC;
- } else if (llyth <= 95) {
- modd = C128_AORB;
- } else if (llyth <= 127) {
- modd = C128_SHIFTB;
- } else if (llyth <= 159) {
- modd = C128_SHIFTA;
- } else if (llyth <= 223) {
- modd = C128_AORB;
+ if (ch <= 31) {
+ return charset == 1 || (check_fnc1 && ch == '\x1D');
+ }
+ if (ch <= 95) {
+ return 1;
+ }
+ if (ch <= 127) {
+ return charset == 2;
+ }
+ if (ch <= 159) {
+ return charset == 1;
+ }
+ if (ch <= 223) {
+ return 1;
+ }
+ return charset == 2;
+}
+
+/* Whether `source[position]` can be encoded in code set C (for `c128_define_mode()` below) */
+static int c128_can_c(const unsigned char source[], const int length, const int position, const int check_fnc1) {
+ return (position + 1 < length && z_isdigit(source[position]) && z_isdigit(source[position + 1]))
+ || (check_fnc1 && source[position] == '\x1D');
+}
+
+/* Calculate the cost of encoding from `position` starting in code set `charset` (for `c128_define_mode()` below) */
+static int c128_cost(const unsigned char source[], const int length, const int position, const int charset,
+ const int ab_only, const char manual_set[C128_MAX], const unsigned char fncs[C128_MAX], int (*costs)[4],
+ char (*modes)[4]) {
+
+ /* Check if memoized */
+ if (costs[position][charset]) {
+ return costs[position][charset];
} else {
- modd = C128_SHIFTB;
- }
+ const int at_end = position + 1 >= length;
+ const int check_fnc1 = !fncs || fncs[position];
+ const int can_c = c128_can_c(source, length, position, check_fnc1);
+ const int manual_c_fail = !can_c && manual_set && manual_set[position] == 3; /* C requested but not doable */
+ int min_cost = 999999; /* Max possible cost 2 * 256 */
+ int min_latch = 0;
+ int tryset;
- return modd;
-}
-
-/**
- * Bring together same type blocks
- */
-static void c128_grwp(int list[2][C128_MAX], int *p_indexliste) {
-
- /* bring together same type blocks */
- if (*p_indexliste > 1) {
- int i = 1;
- while (i < *p_indexliste) {
- if (list[1][i - 1] == list[1][i]) {
- int j;
- /* bring together */
- list[0][i - 1] = list[0][i - 1] + list[0][i];
- j = i + 1;
-
- /* decrease the list */
- while (j < *p_indexliste) {
- list[0][j - 1] = list[0][j];
- list[1][j - 1] = list[1][j];
- j++;
- }
- *p_indexliste = *p_indexliste - 1;
- i--;
+ /* Try code set C first (preferring C over B over A as seems to better preserve previous encodation) */
+ if (!ab_only && can_c && (!manual_set || !manual_set[position] || manual_set[position] == 3)) {
+ const int advance = source[position] == '\x1D' ? 1 : 2;
+ int cost = 1;
+ int latch = 0; /* Continue current `charset` */
+ if (charset != 3) {
+ cost++;
+ latch = 3;
+ }
+ if (position + advance < length) {
+ cost += c128_cost(source, length, position + advance, 3, ab_only, manual_set, fncs, costs, modes);
+ }
+ if (cost < min_cost) {
+ min_cost = cost;
+ min_latch = latch;
}
- i++;
}
- }
-}
-
-/**
- * Implements rules from ISO 15417 Annex E
- */
-INTERNAL void c128_dxsmooth(int list[2][C128_MAX], int *p_indexliste, const char *manual_set) {
- int i, j, nextshift = 0 /*Suppresses gcc -Wmaybe-uninitialized false positive*/, nextshift_i = 0;
- const int indexliste = *p_indexliste;
-
- for (i = 0; i < indexliste; i++) {
- int current = list[1][i]; /* Either C128_ABORC, C128_AORB, C128_SHIFTA or C128_SHIFTB */
- int length = list[0][i];
- if (i == nextshift_i) {
- nextshift = 0;
- /* Set next shift to aid deciding between latching to A or B - taken from Okapi, props Daniel Gredler */
- for (j = i + 1; j < indexliste; j++) {
- if (list[1][j] == C128_SHIFTA || list[1][j] == C128_SHIFTB) {
- nextshift = list[1][j];
- nextshift_i = j;
- break;
+ /* Then code sets B and A */
+ for (tryset = 2; tryset >= 1; tryset--) {
+ if (manual_set && manual_set[position] && manual_set[position] != tryset && !manual_c_fail) {
+ continue;
+ }
+ if (c128_can_aorb(source[position], tryset, check_fnc1)) {
+ int cost = 1;
+ int latch = 0; /* Continue current `charset` */
+ if (charset != tryset) {
+ cost++;
+ latch = tryset;
+ }
+ if (!at_end) {
+ cost += c128_cost(source, length, position + 1, tryset, ab_only, manual_set, fncs, costs, modes);
+ }
+ if (cost < min_cost) {
+ min_cost = cost;
+ min_latch = latch;
+ }
+ if (charset != tryset && (charset == 1 || charset == 2)) {
+ cost = 2;
+ latch = 3 + charset; /* Shift A/B */
+ if (!at_end) {
+ cost += c128_cost(source, length, position + 1, charset, ab_only, manual_set, fncs, costs,
+ modes);
+ }
+ if (cost < min_cost) {
+ min_cost = cost;
+ min_latch = latch;
+ }
+ }
+ } else if (manual_set && manual_set[position] == tryset) {
+ /* Manually set, requires shift */
+ int cost = 2;
+ int latch = 3 + tryset; /* Shift A/B */
+ if (charset != tryset) {
+ cost++;
+ }
+ if (!at_end) {
+ cost += c128_cost(source, length, position + 1, tryset, ab_only, manual_set, fncs, costs, modes);
+ }
+ if (cost < min_cost) {
+ min_cost = cost;
+ min_latch = latch;
}
}
}
+ assert(min_cost != 999999);
- if (i == 0) { /* first block */
- if (current == C128_ABORC) {
- if (manual_set && manual_set[i]) {
- list[1][i] = manual_set[i];
- current = manual_set[i];
- } else if ((indexliste == 1) && (length == 2)) {
- /* Rule 1a */
- list[1][i] = C128_LATCHC;
- current = C128_LATCHC;
- } else if (length >= 4) {
- /* Rule 1b */
- list[1][i] = C128_LATCHC;
- current = C128_LATCHC;
- } else {
- current = C128_AORB; /* Determine below */
- }
- }
- if (current == C128_AORB) {
- if (manual_set && (manual_set[i] == 'A' || manual_set[i] == 'B')) {
- list[1][i] = manual_set[i];
- } else if (nextshift == C128_SHIFTA) {
- /* Rule 1c */
- list[1][i] = C128_LATCHA;
- } else {
- /* Rule 1d */
- list[1][i] = C128_LATCHB;
- }
- } else if (current == C128_SHIFTA) {
- /* Rule 1c */
- list[1][i] = C128_LATCHA;
- } else if (current == C128_SHIFTB) { /* Unless C128_LATCHX set above, can only be C128_SHIFTB */
- /* Rule 1d */
- list[1][i] = C128_LATCHB;
- }
+ costs[position][charset] = min_cost;
+ modes[position][charset] = min_latch;
+
+ return min_cost;
+ }
+}
+
+/* Minimal encoding using Divide-And-Conquer with Memoization by Alex Geller - see
+ https://github.com/zxing/zxing/commit/94fb277607003c070ffd1413754a782f3f87cbcd
+ (note minimal for non-extended characters only, which are dealt with non-optimally by `fset` logic) */
+static void c128_define_mode(char set[C128_MAX], const unsigned char source[], const int length,
+ const int ab_only, const char manual_set[C128_MAX], const unsigned char fncs[C128_MAX]) {
+ int (*costs)[4] = (int (*)[4]) z_alloca(sizeof(int) * 4 * length);
+ char (*modes)[4] = (char (*)[4]) z_alloca(4 * length);
+ int charset = 0;
+ int i;
+
+ memset(costs, 0, sizeof(int) * 4 * length);
+ memset(modes, 0, 4 * length);
+
+ c128_cost(source, length, 0 /*position*/, 0 /*charset*/, ab_only, manual_set, fncs, costs, modes);
+
+ for (i = 0; i < length; i++) {
+ const int latch = modes[i][charset];
+ if (latch >= 1 && latch <= 3) {
+ charset = latch;
+ set[i] = '@' + latch; /* A, B or C */
+ } else if (latch >= 4 && latch <= 5) {
+ /* Shift A/B */
+ charset = latch - 3;
+ set[i] = charset == 1 ? 'b' : 'a';
} else {
- int last = list[1][i - 1];
- if (current == C128_ABORC) {
- if (manual_set && manual_set[i]) {
- list[1][i] = manual_set[i];
- current = manual_set[i];
- } else if (length >= 4) {
- /* Rule 3 - note Rule 3b (odd C blocks) dealt with later */
- list[1][i] = C128_LATCHC;
- current = C128_LATCHC;
- } else {
- current = C128_AORB; /* Determine below */
- }
- }
- if (current == C128_AORB) {
- if (manual_set && (manual_set[i] == 'A' || manual_set[i] == 'B')) {
- list[1][i] = manual_set[i];
- } else if (last == C128_LATCHA || last == C128_SHIFTB) { /* Maintain state */
- list[1][i] = C128_LATCHA;
- } else if (last == C128_LATCHB || last == C128_SHIFTA) { /* Maintain state */
- list[1][i] = C128_LATCHB;
- } else if (nextshift == C128_SHIFTA) {
- list[1][i] = C128_LATCHA;
- } else {
- list[1][i] = C128_LATCHB;
- }
- } else if (current == C128_SHIFTA) {
- if (manual_set && manual_set[i] == 'A') {
- list[1][i] = C128_LATCHA;
- } else if (length > 1) {
- /* Rule 4 */
- list[1][i] = C128_LATCHA;
- } else if (last == C128_LATCHA || last == C128_SHIFTB) { /* Maintain state */
- list[1][i] = C128_LATCHA;
- } else if (last == C128_LATCHC) {
- list[1][i] = C128_LATCHA;
- }
- } else if (current == C128_SHIFTB) { /* Unless C128_LATCHX set above, can only be C128_SHIFTB */
- if (manual_set && manual_set[i] == 'B') {
- list[1][i] = C128_LATCHB;
- } else if (length > 1) {
- /* Rule 5 */
- list[1][i] = C128_LATCHB;
- } else if (last == C128_LATCHB || last == C128_SHIFTA) { /* Maintain state */
- list[1][i] = C128_LATCHB;
- } else if (last == C128_LATCHC) {
- list[1][i] = C128_LATCHB;
- }
- }
- } /* Rule 2 is implemented elsewhere, Rule 6 is implied */
+ /* Continue in same `charset` */
+ assert(charset);
+ set[i] = '@' + charset; /* A, B or C */
+ }
+ if (charset == 3 && source[i] != '\x1D') {
+ assert(i + 1 < length); /* Guaranteed by algorithm */
+ set[++i] = 'C';
+ }
}
-
- c128_grwp(list, p_indexliste);
}
/**
@@ -283,455 +273,16 @@ INTERNAL int c128_set_b(const unsigned char source, int values[], int *bar_chars
* This set handles numbers in a compressed form
*/
INTERNAL void c128_set_c(const unsigned char source_a, const unsigned char source_b, int values[], int *bar_chars) {
- int weight;
-
- weight = (10 * ctoi(source_a)) + ctoi(source_b);
- values[(*bar_chars)] = weight;
+ values[(*bar_chars)] = 10 * (source_a - '0') + source_b - '0';
(*bar_chars)++;
}
-/* Put set data into set[]. If source given (GS1_MODE or manual FNC1s) then resolves odd C blocks */
-INTERNAL void c128_put_in_set(int list[2][C128_MAX], const int indexliste, char set[C128_MAX],
- const unsigned char *source) {
- int read = 0;
- int i, j;
-
- for (i = 0; i < indexliste; i++) {
- for (j = 0; j < list[0][i]; j++) {
- set[read++] = list[1][i];
- }
- }
- if (source) {
- /* Watch out for odd-length Mode C blocks */
- int c_count = 0, have_nonc = 0;
- for (i = 0; i < read; i++) {
- if (set[i] == 'C') {
- if (source[i] == '\x1D') {
- if (c_count & 1) {
- have_nonc = 1;
- if (i > c_count) {
- set[i - c_count] = 'B';
- } else {
- set[i - 1] = 'B';
- }
- }
- c_count = 0;
- } else {
- c_count++;
- }
- } else {
- have_nonc = 1;
- if (c_count & 1) {
- if (i > c_count) {
- set[i - c_count] = 'B';
- } else {
- set[i - 1] = 'B';
- }
- }
- c_count = 0;
- }
- }
- if (c_count & 1) {
- if (i > c_count && have_nonc) {
- set[i - c_count] = 'B';
- if (c_count < 4) {
- /* Rule 1b */
- for (j = i - c_count + 1; j < i; j++) {
- set[j] = 'B';
- }
- }
- } else {
- set[i - 1] = 'B';
- }
- }
- for (i = 1; i < read - 1; i++) {
- if (set[i] == 'C' && set[i - 1] != 'C' && set[i + 1] != 'C') {
- set[i] = set[i + 1];
- }
- }
- if (read > 1 && set[read - 1] == 'C' && set[read - 2] != 'C') {
- set[read - 1] = set[read - 2];
- }
- }
-}
-
-/* Handle Code 128, 128B and HIBC 128 */
-INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int length) {
- int i, j, k, values[C128_MAX] = {0}, bar_characters = 0, read, total_sum;
- int error_number, indexchaine, indexliste, f_state = 0;
- unsigned char src_buf[C128_MAX + 1];
- unsigned char *src = source;
- char manual_set[C128_MAX] = {0};
- unsigned char fncs[C128_MAX] = {0}; /* Manual FNC1 positions */
- int list[2][C128_MAX] = {{0}};
- char set[C128_MAX] = {0}, fset[C128_MAX], mode, last_set, current_set = ' ';
- int have_fnc1 = 0; /* Whether have at least 1 manual FNC1 */
- int glyph_count = 0; /* Codeword estimate times 2 */
- char dest[1000];
+/* Helper to write out symbol, calculating check digit */
+static void c128_expand(struct zint_symbol *symbol, int values[C128_MAX], int bar_characters) {
+ char dest[640]; /* (1 (Start) + 2 (max initial extra) + 99 + 1 (check digit)) * 6 + 7 (Stop) == 625 */
char *d = dest;
-
- /* Suppresses clang-analyzer-core.UndefinedBinaryOperatorResult warning on fset which is fully set */
- assert(length > 0);
-
- if (length > C128_MAX) {
- /* This only blocks ridiculously long input - the actual length of the
- resulting barcode depends on the type of data, so this is trapped later */
- sprintf(symbol->errtxt, "340: Input too long (%d character maximum)", C128_MAX);
- return ZINT_ERROR_TOO_LONG;
- }
-
- /* Detect special Code Set escapes for Code 128 in extra escape mode only */
- if ((symbol->input_mode & EXTRA_ESCAPE_MODE) && symbol->symbology == BARCODE_CODE128) {
- char manual_ch = '\0';
- j = 0;
- for (i = 0; i < length; i++) {
- if (source[i] == '\\' && i + 2 < length && source[i + 1] == '^'
- && ((source[i + 2] >= 'A' && source[i + 2] <= 'C') || source[i + 2] == '1'
- || source[i + 2] == '^')) {
- if (source[i + 2] == '^') { /* Escape sequence '\^^' */
- manual_set[j] = manual_ch;
- src_buf[j++] = source[i++];
- manual_set[j] = manual_ch;
- src_buf[j++] = source[i++];
- /* Drop second '^' */
- } else if (source[i + 2] == '1') { /* FNC1 */
- i += 2;
- fncs[j] = have_fnc1 = 1;
- manual_set[j] = manual_ch;
- src_buf[j++] = '\x1D'; /* Manual FNC1 dummy */
- } else { /* Manual mode A/B/C */
- i += 2;
- manual_ch = source[i];
- }
- } else {
- manual_set[j] = manual_ch;
- src_buf[j++] = source[i];
- }
- }
- if (j != length) {
- length = j;
- if (length == 0) {
- strcpy(symbol->errtxt, "842: No input data");
- return ZINT_ERROR_INVALID_DATA;
- }
- src = src_buf;
- src[length] = '\0';
- if (symbol->debug & ZINT_DEBUG_PRINT) {
- fputs("MSet: ", stdout);
- for (i = 0; i < length; i++) printf("%c", manual_set[i] ? manual_set[i] : '.');
- fputc('\n', stdout);
- }
- }
- }
-
- /* Detect extended ASCII characters */
- for (i = 0; i < length; i++) {
- fset[i] = src[i] >= 128 ? 'f' : ' ';
- }
-
- /* Decide when to latch to extended mode - Annex E note 3 */
- j = 0;
- for (i = 0; i < length; i++) {
- if (fset[i] == 'f') {
- j++;
- } else {
- j = 0;
- }
-
- if (j >= 5) {
- for (k = i; k > (i - 5); k--) {
- fset[k] = 'F';
- }
- }
-
- if ((j >= 3) && (i == (length - 1))) {
- for (k = i; k > (i - 3); k--) {
- fset[k] = 'F';
- }
- }
- }
-
- /* Decide if it is worth reverting to 646 encodation for a few characters as described in 4.3.4.2 (d) */
- for (i = 1; i < length; i++) {
- if ((fset[i - 1] == 'F') && (fset[i] == ' ')) {
- /* Detected a change from 8859-1 to 646 - count how long for */
- for (j = 0; ((i + j) < length) && (fset[i + j] == ' '); j++);
- /* Count how many 8859-1 beyond */
- k = 0;
- if (i + j < length) {
- for (k = 1; ((i + j + k) < length) && (fset[i + j + k] != ' '); k++);
- }
- if (j < 3 || (j < 5 && k > 2)) {
- /* Change to shifting back rather than latching back */
- /* Inverts the same figures recommended by Annex E note 3 */
- for (k = 0; k < j; k++) {
- fset[i + k] = 'n';
- }
- }
- }
- }
-
- /* Decide on mode using same system as PDF417 and rules of ISO 15417 Annex E */
- indexliste = 0;
- indexchaine = 0;
-
- mode = c128_parunmodd(src[indexchaine], fncs[indexchaine]);
- if (mode == C128_ABORC
- && (symbol->symbology == BARCODE_CODE128AB
- || manual_set[indexchaine] == 'A' || manual_set[indexchaine] == 'B')) {
- mode = C128_AORB;
- }
-
- do {
- list[1][indexliste] = mode;
- while ((list[1][indexliste] == mode) && (indexchaine < length)) {
- list[0][indexliste]++;
- indexchaine++;
- if (indexchaine == length) {
- break;
- }
- mode = c128_parunmodd(src[indexchaine], fncs[indexchaine]);
- if (mode == C128_ABORC
- && (symbol->symbology == BARCODE_CODE128AB
- || manual_set[indexchaine] == 'A' || manual_set[indexchaine] == 'B')) {
- mode = C128_AORB;
- }
- if (manual_set[indexchaine] != manual_set[indexchaine - 1]) {
- break;
- }
- }
- indexliste++;
- } while (indexchaine < length);
-
- if (src == src_buf) {
- /* Need to re-index `manual_set` to have sames indexes as `list` blocks for `c128_dxsmooth()` */
- j = 0;
- for (i = 1; i < indexliste; i++) {
- j += list[0][i - 1];
- manual_set[i] = manual_set[j];
- }
- }
- c128_dxsmooth(list, &indexliste, src == src_buf ? manual_set : NULL);
-
- if (!have_fnc1) {
- /* Resolve odd length C128_LATCHC blocks */
- if ((list[1][0] == C128_LATCHC) && (list[0][0] & 1)) {
- /* Rule 2 */
- list[0][1]++;
- list[0][0]--;
- if (indexliste == 1) {
- list[0][1] = 1;
- list[1][1] = C128_LATCHB;
- indexliste = 2;
- }
- }
- if (indexliste > 1) {
- for (i = 1; i < indexliste; i++) {
- if ((list[1][i] == C128_LATCHC) && (list[0][i] & 1)) {
- /* Rule 3b */
- list[0][i - 1]++;
- list[0][i]--;
- }
- }
- }
- }
-
- /* Put set data into set[]. Give NULL as source if no manual FNC1s as used to resolve odd C blocks
- which has been done above */
- c128_put_in_set(list, indexliste, set, have_fnc1 ? src : NULL);
-
- if (symbol->debug & ZINT_DEBUG_PRINT) {
- printf("Data: %.*s (%d)\n", length, src, length);
- printf(" Set: %.*s\n", length, set);
- printf("FSet: %.*s\n", length, fset);
- }
-
- /* Now we can calculate how long the barcode is going to be - and stop it from
- being too long */
- last_set = set[0];
- for (i = 0; i < length; i++) {
- if ((set[i] == 'a') || (set[i] == 'b')) {
- glyph_count += 2; /* 1 codeword */
- }
- if ((fset[i] == 'f') || (fset[i] == 'n')) {
- glyph_count += 2; /* May be overestimate if in latch */
- }
- if (((set[i] == 'A') || (set[i] == 'B')) || (set[i] == 'C')) {
- if (set[i] != last_set) {
- last_set = set[i];
- glyph_count += 2;
- }
- }
- if (i == 0) {
- if (fset[i] == 'F') {
- glyph_count += 4; /* 2 codewords */
- }
- } else {
- if ((fset[i] == 'F') && (fset[i - 1] != 'F')) {
- glyph_count += 4;
- } else if ((fset[i] != 'F') && (fset[i - 1] == 'F')) {
- glyph_count += 4;
- }
- }
-
- if (set[i] == 'C' && !fncs[i]) {
- glyph_count += 1; /* Half a codeword */
- } else {
- glyph_count += 2;
- }
- }
- if (glyph_count > C128_SYMBOL_MAX * 2) {
- sprintf(symbol->errtxt, "341: Input too long (%d symbol character maximum)", C128_SYMBOL_MAX);
- return ZINT_ERROR_TOO_LONG;
- }
-
- /* So now we know what start character to use - we can get on with it! */
- if (symbol->output_options & READER_INIT) {
- /* Reader Initialisation mode */
- switch (set[0]) {
- case 'A': /* Start A */
- values[bar_characters++] = 103;
- current_set = 'A';
- values[bar_characters++] = 96; /* FNC3 */
- break;
- case 'B': /* Start B */
- values[bar_characters++] = 104;
- current_set = 'B';
- values[bar_characters++] = 96; /* FNC3 */
- break;
- case 'C': /* Start C */
- values[bar_characters++] = 104; /* Start B */
- values[bar_characters++] = 96; /* FNC3 */
- values[bar_characters++] = 99; /* Code C */
- current_set = 'C';
- break;
- }
- } else {
- /* Normal mode */
- switch (set[0]) {
- case 'A': /* Start A */
- values[bar_characters++] = 103;
- current_set = 'A';
- break;
- case 'B': /* Start B */
- values[bar_characters++] = 104;
- current_set = 'B';
- break;
- case 'C': /* Start C */
- values[bar_characters++] = 105;
- current_set = 'C';
- break;
- }
- }
-
- if (fset[0] == 'F') {
- switch (current_set) {
- case 'A':
- values[bar_characters++] = 101;
- values[bar_characters++] = 101;
- f_state = 1;
- break;
- case 'B':
- values[bar_characters++] = 100;
- values[bar_characters++] = 100;
- f_state = 1;
- break;
- }
- }
-
- /* Encode the data */
- read = 0;
- do {
-
- if (read != 0) {
- if (set[read] != current_set) {
- /* Latch different code set */
- switch (set[read]) {
- case 'A':
- values[bar_characters++] = 101;
- current_set = 'A';
- break;
- case 'B':
- values[bar_characters++] = 100;
- current_set = 'B';
- break;
- case 'C':
- values[bar_characters++] = 99;
- current_set = 'C';
- break;
- }
- }
-
- if ((fset[read] == 'F') && (f_state == 0)) {
- /* Latch beginning of extended mode */
- switch (current_set) {
- case 'A':
- values[bar_characters++] = 101;
- values[bar_characters++] = 101;
- f_state = 1;
- break;
- case 'B':
- values[bar_characters++] = 100;
- values[bar_characters++] = 100;
- f_state = 1;
- break;
- }
- }
- if ((fset[read] == ' ') && (f_state == 1)) {
- /* Latch end of extended mode */
- switch (current_set) {
- case 'A':
- values[bar_characters++] = 101;
- values[bar_characters++] = 101;
- f_state = 0;
- break;
- case 'B':
- values[bar_characters++] = 100;
- values[bar_characters++] = 100;
- f_state = 0;
- break;
- }
- }
- }
-
- if ((fset[read] == 'f' && f_state == 0) || (fset[read] == 'n' && f_state == 1)) {
- /* Shift to or from extended mode */
- switch (current_set) {
- case 'A':
- values[bar_characters++] = 101; /* FNC 4 */
- break;
- case 'B':
- values[bar_characters++] = 100; /* FNC 4 */
- break;
- }
- }
-
- if ((set[read] == 'a') || (set[read] == 'b')) {
- /* Insert shift character */
- values[bar_characters++] = 98;
- }
-
- if (!fncs[read]) {
- switch (set[read]) { /* Encode data characters */
- case 'a':
- case 'A':
- c128_set_a(src[read++], values, &bar_characters);
- break;
- case 'b':
- case 'B':
- (void) c128_set_b(src[read++], values, &bar_characters);
- break;
- case 'C':
- c128_set_c(src[read], src[read + 1], values, &bar_characters);
- read += 2;
- break;
- }
- } else {
- values[bar_characters++] = 102; /* FNC1 in all modes */
- read++;
- }
-
- } while (read < length);
+ int total_sum;
+ int i;
/* Destination setting and check digit calculation */
memcpy(d, C128Table[values[0]], 6);
@@ -768,6 +319,336 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len
#endif
expand(symbol, dest, d - dest);
+}
+
+/* Return codeword estimate (character encodation only) */
+static int c128_glyph_count(const unsigned char source[], const int length, const char set[C128_MAX],
+ const char fset[C128_MAX]) {
+ int glyph_count = 0;
+ char current_set = ' ';
+ int f_state = 0;
+ int i;
+
+ switch (set[0]) {
+ case 'A':
+ case 'b': /* Manual switching can cause immediate shift */
+ current_set = 'A';
+ break;
+ case 'B':
+ case 'a':
+ current_set = 'B';
+ break;
+ case 'C':
+ current_set = 'C';
+ break;
+ }
+
+ for (i = 0; i < length; i++) {
+ if (set[i] != current_set) {
+ /* Latch different code set */
+ switch (set[0]) {
+ case 'A':
+ case 'b': /* Manual switching can cause immediate shift */
+ if (current_set != 'A') {
+ current_set = 'A';
+ glyph_count++;
+ }
+ break;
+ case 'B':
+ case 'a':
+ if (current_set != 'B') {
+ current_set = 'B';
+ glyph_count++;
+ }
+ break;
+ case 'C':
+ current_set = 'C';
+ glyph_count++;
+ break;
+ }
+ }
+ if (fset) {
+ if ((fset[i] == 'F' && f_state == 0) || (fset[i] == ' ' && f_state == 1)) {
+ /* Latch beginning/end of extended mode */
+ f_state = !f_state;
+ glyph_count += 2;
+ } else if ((fset[i] == 'f' && f_state == 0) || (fset[i] == 'n' && f_state == 1)) {
+ /* Shift to or from extended mode */
+ glyph_count++;
+ }
+ }
+ if ((set[i] == 'a') || (set[i] == 'b')) {
+ /* Insert shift character */
+ glyph_count++;
+ }
+
+ /* Actual character */
+ glyph_count++;
+
+ if (set[i] == 'C' && source[i] != '\x1D') {
+ i++;
+ }
+ }
+
+ return glyph_count;
+}
+
+/* Handle Code 128, 128B and HIBC 128 */
+INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int length) {
+ int i, j, k, read;
+ int error_number;
+ int values[C128_MAX] = {0}, bar_characters = 0;
+ unsigned char src_buf[C128_MAX + 1];
+ unsigned char *src = source;
+ char manual_set[C128_MAX] = {0};
+ unsigned char fncs[C128_MAX] = {0}; /* Manual FNC1 positions */
+ char set[C128_MAX] = {0}, fset[C128_MAX], current_set = ' ';
+ int f_state = 0;
+ int have_fnc1 = 0; /* Whether have at least 1 manual FNC1 */
+ char manual_ch = 0;
+
+ /* Suppresses clang-analyzer-core.UndefinedBinaryOperatorResult warning on fset which is fully set */
+ assert(length > 0);
+
+ if (length > C128_MAX) {
+ /* This only blocks ridiculously long input - the actual length of the
+ resulting barcode depends on the type of data, so this is trapped later */
+ sprintf(symbol->errtxt, "340: Input too long (%d character maximum)", C128_MAX);
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* Detect special Code Set escapes for Code 128 in extra escape mode only */
+ if ((symbol->input_mode & EXTRA_ESCAPE_MODE) && symbol->symbology == BARCODE_CODE128) {
+ j = 0;
+ for (i = 0; i < length; i++) {
+ if (source[i] == '\\' && i + 2 < length && source[i + 1] == '^'
+ && ((source[i + 2] >= 'A' && source[i + 2] <= 'C') || source[i + 2] == '1'
+ || source[i + 2] == '^')) {
+ if (source[i + 2] == '^') { /* Escape sequence '\^^' */
+ manual_set[j] = manual_ch;
+ src_buf[j++] = source[i++];
+ manual_set[j] = manual_ch;
+ src_buf[j++] = source[i++];
+ /* Drop second '^' */
+ } else if (source[i + 2] == '1') { /* FNC1 */
+ i += 2;
+ fncs[j] = have_fnc1 = 1;
+ manual_set[j] = manual_ch;
+ src_buf[j++] = '\x1D'; /* Manual FNC1 dummy */
+ } else { /* Manual mode A/B/C */
+ i += 2;
+ manual_ch = source[i] - '@'; /* 1 (A), 2 (B), 3 (C) */
+ }
+ } else {
+ manual_set[j] = manual_ch;
+ src_buf[j++] = source[i];
+ }
+ }
+ if (j != length) {
+ length = j;
+ if (length == 0) {
+ strcpy(symbol->errtxt, "842: No input data");
+ return ZINT_ERROR_INVALID_DATA;
+ }
+ src = src_buf;
+ src[length] = '\0';
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ fputs("MSet: ", stdout);
+ for (i = 0; i < length; i++) printf("%c", manual_set[i] + '@');
+ fputc('\n', stdout);
+ }
+ }
+ }
+
+ c128_define_mode(set, src, length, symbol->symbology == BARCODE_CODE128AB /*ab_only*/,
+ manual_ch ? manual_set : NULL, have_fnc1 ? fncs : NULL);
+
+ /* Detect extended ASCII characters */
+ for (i = 0; i < length; i++) {
+ fset[i] = src[i] >= 128 ? 'f' : ' ';
+ }
+
+ /* Decide when to latch to extended mode - Annex E note 3 */
+ j = 0;
+ for (i = 0; i < length; i++) {
+ if (fset[i] == 'f') {
+ j++;
+ } else {
+ j = 0;
+ }
+
+ if (j >= 5) {
+ for (k = i; k > (i - 5); k--) {
+ fset[k] = 'F';
+ }
+ }
+ }
+ if (j >= 3) {
+ for (k = length - 1; k > length - 1 - j; k--) {
+ fset[k] = 'F';
+ }
+ }
+
+ /* Decide if it is worth reverting to 646 encodation for a few characters as described in 4.3.4.2 (d) */
+ for (i = 1; i < length; i++) {
+ if ((fset[i - 1] == 'F') && (fset[i] == ' ')) {
+ int c = 0;
+ /* Detected a change from 8859-1 to 646 - count how long for */
+ for (j = 0; ((i + j) < length) && (fset[i + j] == ' '); j++) {
+ c += set[i + j] == 'C'; /* Count code set C so can subtract when deciding below */
+ }
+ /* Count how many 8859-1 beyond */
+ k = 0;
+ if (i + j < length) {
+ for (k = 1; ((i + j + k) < length) && (fset[i + j + k] != ' '); k++);
+ }
+ if (j - c < 3 || (j - c < 5 && k > 2)) {
+ /* Change to shifting back rather than latching back */
+ /* Inverts the same figures recommended by Annex E note 3 */
+ for (k = 0; k < j; k++) {
+ fset[i + k] = 'n';
+ }
+ }
+ }
+ }
+
+ if (symbol->debug & ZINT_DEBUG_PRINT) {
+ printf("Data: %.*s (%d)\n", length, src, length);
+ printf(" Set: %.*s\n", length, set);
+ printf("FSet: %.*s\n", length, fset);
+ }
+
+ /* Now we can calculate how long the barcode is going to be - and stop it from
+ being too long */
+ if (c128_glyph_count(source, length, set, fset) > C128_SYMBOL_MAX) {
+ sprintf(symbol->errtxt, "341: Input too long (%d symbol character maximum)", C128_SYMBOL_MAX);
+ return ZINT_ERROR_TOO_LONG;
+ }
+
+ /* So now we know what start character to use - we can get on with it! */
+ if (symbol->output_options & READER_INIT) {
+ /* Reader Initialisation mode */
+ switch (set[0]) {
+ case 'A': /* Start A */
+ case 'b': /* Manual switching can cause immediate shift */
+ values[bar_characters++] = 103;
+ current_set = 'A';
+ values[bar_characters++] = 96; /* FNC3 */
+ break;
+ case 'B': /* Start B */
+ case 'a':
+ values[bar_characters++] = 104;
+ current_set = 'B';
+ values[bar_characters++] = 96; /* FNC3 */
+ break;
+ case 'C': /* Start C */
+ values[bar_characters++] = 104; /* Start B */
+ values[bar_characters++] = 96; /* FNC3 */
+ values[bar_characters++] = 99; /* Code C */
+ current_set = 'C';
+ break;
+ }
+ } else {
+ /* Normal mode */
+ switch (set[0]) {
+ case 'A': /* Start A */
+ case 'b': /* Manual switching can cause immediate shift */
+ values[bar_characters++] = 103;
+ current_set = 'A';
+ break;
+ case 'B': /* Start B */
+ case 'a':
+ values[bar_characters++] = 104;
+ current_set = 'B';
+ break;
+ case 'C': /* Start C */
+ values[bar_characters++] = 105;
+ current_set = 'C';
+ break;
+ }
+ }
+
+ /* Encode the data */
+ for (read = 0; read < length; read++) {
+
+ if (set[read] != current_set) {
+ /* Latch different code set */
+ switch (set[read]) {
+ case 'A':
+ case 'b': /* Manual switching can cause immediate shift */
+ if (current_set != 'A') {
+ values[bar_characters++] = 101;
+ current_set = 'A';
+ }
+ break;
+ case 'B':
+ case 'a':
+ if (current_set != 'B') {
+ values[bar_characters++] = 100;
+ current_set = 'B';
+ }
+ break;
+ case 'C':
+ values[bar_characters++] = 99;
+ current_set = 'C';
+ break;
+ }
+ }
+
+ if ((fset[read] == 'F' && f_state == 0) || (fset[read] == ' ' && f_state == 1)) {
+ /* Latch beginning/end of extended mode */
+ switch (current_set) {
+ case 'A':
+ values[bar_characters++] = 101;
+ values[bar_characters++] = 101;
+ f_state = !f_state;
+ break;
+ case 'B':
+ values[bar_characters++] = 100;
+ values[bar_characters++] = 100;
+ f_state = !f_state;
+ break;
+ }
+ } else if ((fset[read] == 'f' && f_state == 0) || (fset[read] == 'n' && f_state == 1)) {
+ /* Shift to or from extended mode */
+ switch (current_set) {
+ case 'A':
+ values[bar_characters++] = 101; /* FNC4 */
+ break;
+ case 'B':
+ values[bar_characters++] = 100; /* FNC4 */
+ break;
+ }
+ }
+
+ if ((set[read] == 'a') || (set[read] == 'b')) {
+ /* Insert shift character */
+ values[bar_characters++] = 98;
+ }
+
+ /* Encode data characters */
+ if (!fncs[read]) {
+ switch (set[read]) {
+ case 'A':
+ case 'a':
+ c128_set_a(src[read], values, &bar_characters);
+ break;
+ case 'B':
+ case 'b':
+ (void) c128_set_b(src[read], values, &bar_characters);
+ break;
+ case 'C':
+ c128_set_c(src[read], src[read + 1], values, &bar_characters);
+ read++;
+ break;
+ }
+ } else {
+ values[bar_characters++] = 102; /* FNC1 in all modes */
+ }
+
+ }
+
+ c128_expand(symbol, values, bar_characters);
/* ISO/IEC 15417:2007 leaves dimensions/height as application specification */
@@ -789,13 +670,10 @@ INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int len
/* Handle EAN-128 (Now known as GS1-128), and composite version if `cc_mode` set */
INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_mode,
const int cc_rows) {
- int i, values[C128_MAX] = {0}, bar_characters = 0, read, total_sum;
- int error_number, indexchaine, indexliste;
- int list[2][C128_MAX] = {{0}};
- char set[C128_MAX] = {0}, mode, last_set;
- int glyph_count = 0; /* Codeword estimate times 2 */
- char dest[1000];
- char *d = dest;
+ int i, read;
+ int error_number;
+ int values[C128_MAX] = {0}, bar_characters = 0;
+ char set[C128_MAX] = {0};
int separator_row = 0, linkage_flag = 0;
int reduced_length;
unsigned char *reduced = (unsigned char *) z_alloca(length + 1);
@@ -821,29 +699,7 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int
reduced_length = (int) ustrlen(reduced);
- /* Decide on mode using same system as PDF417 and rules of ISO 15417 Annex E */
- indexliste = 0;
- indexchaine = 0;
-
- mode = c128_parunmodd(reduced[indexchaine], 1 /*check_fnc1*/);
-
- do {
- list[1][indexliste] = mode;
- while ((list[1][indexliste] == mode) && (indexchaine < reduced_length)) {
- list[0][indexliste]++;
- indexchaine++;
- if (indexchaine == reduced_length) {
- break;
- }
- mode = c128_parunmodd(reduced[indexchaine], 1 /*check_fnc1*/);
- }
- indexliste++;
- } while (indexchaine < reduced_length);
-
- c128_dxsmooth(list, &indexliste, NULL /*manual_set*/);
-
- /* Put set data into set[], resolving odd C blocks */
- c128_put_in_set(list, indexliste, set, reduced);
+ c128_define_mode(set, reduced, reduced_length, 0 /*ab_only*/, NULL, NULL /*fncs*/);
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("Data: %s (%d)\n", reduced, reduced_length);
@@ -852,33 +708,14 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int
/* Now we can calculate how long the barcode is going to be - and stop it from
being too long */
- last_set = set[0];
- for (i = 0; i < reduced_length; i++) {
- if ((set[i] == 'A') || (set[i] == 'B') || (set[i] == 'C')) {
- if (set[i] != last_set) {
- last_set = set[i];
- glyph_count += 2; /* 1 codeword */
- }
- } else if ((set[i] == 'a') || (set[i] == 'b')) {
- glyph_count += 2; /* Not reached */
- }
-
- if ((set[i] == 'C') && (reduced[i] != '\x1D')) {
- glyph_count += 1; /* Half a codeword */
- } else {
- glyph_count += 2;
- }
- }
- if (glyph_count > C128_SYMBOL_MAX * 2) {
+ if (c128_glyph_count(reduced, reduced_length, set, NULL /*fset*/) > C128_SYMBOL_MAX) {
sprintf(symbol->errtxt, "344: Input too long (%d symbol character maximum)", C128_SYMBOL_MAX);
return ZINT_ERROR_TOO_LONG;
}
/* So now we know what start character to use - we can get on with it! */
+ assert(set[0] == 'B' || set[0] == 'C');
switch (set[0]) {
- case 'A': /* Start A */
- values[bar_characters++] = 103; /* Not reached */
- break;
case 'B': /* Start B */
values[bar_characters++] = 104;
break;
@@ -890,14 +727,12 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int
values[bar_characters++] = 102; /* FNC1 */
/* Encode the data */
- read = 0;
- do {
+ for (read = 0; read < reduced_length; read++) {
+ assert(set[read] == 'B' || set[read] == 'C');
- if ((read != 0) && (set[read] != set[read - 1])) { /* Latch different code set */
+ if ((read != 0) && (set[read] != set[read - 1])) {
+ /* Latch different code set */
switch (set[read]) {
- case 'A':
- values[bar_characters++] = 101; /* Not reached */
- break;
case 'B':
values[bar_characters++] = 100;
break;
@@ -907,31 +742,20 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int
}
}
- if ((set[read] == 'a') || (set[read] == 'b')) {
- /* Insert shift character */
- values[bar_characters++] = 98; /* Not reached */
- }
-
if (reduced[read] != '\x1D') {
switch (set[read]) { /* Encode data characters */
- case 'A':
- case 'a':
- c128_set_a(reduced[read++], values, &bar_characters); /* Not reached */
- break;
case 'B':
- case 'b':
- (void) c128_set_b(reduced[read++], values, &bar_characters);
+ (void) c128_set_b(reduced[read], values, &bar_characters);
break;
case 'C':
c128_set_c(reduced[read], reduced[read + 1], values, &bar_characters);
- read += 2;
+ read++;
break;
}
} else {
values[bar_characters++] = 102; /* FNC1 in all modes */
- read++;
}
- } while (read < reduced_length);
+ }
/* "...note that the linkage flag is an extra code set character between
the last data character and the Symbol Check Character" (GS1 Specification) */
@@ -943,8 +767,6 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int
case 2:
/* CC-A or CC-B 2D component */
switch (set[reduced_length - 1]) {
- case 'A': linkage_flag = 100; /* Not reached */
- break;
case 'B': linkage_flag = 99;
break;
case 'C': linkage_flag = 101;
@@ -954,8 +776,6 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int
case 3:
/* CC-C 2D component */
switch (set[reduced_length - 1]) {
- case 'A': linkage_flag = 99; /* Not reached */
- break;
case 'B': linkage_flag = 101;
break;
case 'C': linkage_flag = 100;
@@ -968,40 +788,7 @@ INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int
values[bar_characters++] = linkage_flag;
}
- /* Destination setting and check digit calculation */
- memcpy(d, C128Table[values[0]], 6);
- d += 6;
- total_sum = values[0];
-
- for (i = 1; i < bar_characters; i++, d += 6) {
- memcpy(d, C128Table[values[i]], 6);
- total_sum += values[i] * i; /* Note can't overflow as 106 * C128_SYMBOL_MAX * C128_SYMBOL_MAX = 1038906 */
- }
- total_sum %= 103;
- memcpy(d, C128Table[total_sum], 6);
- d += 6;
- values[bar_characters++] = total_sum;
-
- /* Stop character */
- memcpy(d, "2331112", 7);
- d += 7;
- values[bar_characters++] = 106;
-
- if (symbol->debug & ZINT_DEBUG_PRINT) {
- fputs("Codewords:", stdout);
- for (i = 0; i < bar_characters; i++) {
- printf(" %d", values[i]);
- }
- printf(" (%d)\n", bar_characters);
- printf("Barspaces: %.*s\n", (int) (d - dest), dest);
- }
-#ifdef ZINT_TEST
- if (symbol->debug & ZINT_DEBUG_TEST) {
- debug_test_codeword_dump_int(symbol, values, bar_characters);
- }
-#endif
-
- expand(symbol, dest, d - dest);
+ c128_expand(symbol, values, bar_characters);
/* Add the separator pattern for composite symbols */
if (symbol->symbology == BARCODE_GS1_128_CC) {
diff --git a/backend/code128.h b/backend/code128.h
index 3102eb60..78e09677 100644
--- a/backend/code128.h
+++ b/backend/code128.h
@@ -39,23 +39,11 @@ extern "C" {
/* Allow for a reasonable number of special Code Set escapes and for GS1 AI delimiters */
#define C128_MAX 256
-#define C128_LATCHA 'A'
-#define C128_LATCHB 'B'
-#define C128_LATCHC 'C'
-#define C128_SHIFTA 'a'
-#define C128_SHIFTB 'b'
-#define C128_ABORC '9'
-#define C128_AORB 'Z'
-
INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int length);
-INTERNAL int c128_parunmodd(const unsigned char llyth, const int check_fnc1);
-INTERNAL void c128_dxsmooth(int list[2][C128_MAX], int *indexliste, const char *manual_set);
INTERNAL void c128_set_a(const unsigned char source, int values[], int *bar_chars);
INTERNAL int c128_set_b(const unsigned char source, int values[], int *bar_chars);
INTERNAL void c128_set_c(const unsigned char source_a, const unsigned char source_b, int values[], int *bar_chars);
-INTERNAL void c128_put_in_set(int list[2][C128_MAX], const int indexliste, char set[C128_MAX],
- const unsigned char *source);
INTERNAL_DATA_EXTERN const char C128Table[107][6];
diff --git a/backend/code16k.c b/backend/code16k.c
index bd757955..5e4bc672 100644
--- a/backend/code16k.c
+++ b/backend/code16k.c
@@ -39,6 +39,15 @@
#include "common.h"
#include "code128.h"
+/* Note these previously defined in "code128.h" - keeping `C128_` prefix for now */
+#define C128_LATCHA 'A'
+#define C128_LATCHB 'B'
+#define C128_LATCHC 'C'
+#define C128_SHIFTA 'a'
+#define C128_SHIFTB 'b'
+#define C128_ABORC '9'
+#define C128_AORB 'Z'
+
/* Note using C128Table with extra entry at 106 (Triple Shift) for C16KTable */
/* EN 12323 Table 3 and Table 4 - Start patterns and stop patterns */
@@ -56,6 +65,214 @@ static const unsigned char C16KStopValues[16] = {
0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 0, 1, 2, 3
};
+/* Determine appropriate mode for a given character (was `c128_parunmodd()`) */
+static int c16k_parunmodd(const unsigned char llyth, const int check_fnc1) {
+ int modd;
+
+ if (llyth <= 31) {
+ modd = check_fnc1 && llyth == '\x1D' ? C128_ABORC : C128_SHIFTA;
+ } else if ((llyth >= 48) && (llyth <= 57)) {
+ modd = C128_ABORC;
+ } else if (llyth <= 95) {
+ modd = C128_AORB;
+ } else if (llyth <= 127) {
+ modd = C128_SHIFTB;
+ } else if (llyth <= 159) {
+ modd = C128_SHIFTA;
+ } else if (llyth <= 223) {
+ modd = C128_AORB;
+ } else {
+ modd = C128_SHIFTB;
+ }
+
+ return modd;
+}
+
+/* Bring together same type blocks (was `c128_grwp()`) */
+static void c16k_grwp(int list[2][C128_MAX], int *p_indexliste) {
+
+ if (*p_indexliste > 1) {
+ int i = 1;
+ while (i < *p_indexliste) {
+ if (list[1][i - 1] == list[1][i]) {
+ int j;
+ /* Bring together */
+ list[0][i - 1] = list[0][i - 1] + list[0][i];
+ j = i + 1;
+
+ /* Decrease the list */
+ while (j < *p_indexliste) {
+ list[0][j - 1] = list[0][j];
+ list[1][j - 1] = list[1][j];
+ j++;
+ }
+ *p_indexliste = *p_indexliste - 1;
+ i--;
+ }
+ i++;
+ }
+ }
+}
+
+/* Implements rules from ISO/IEC 15417:2007 Annex E (was `c128_dxsmooth()`) */
+static void c16k_dxsmooth(int list[2][C128_MAX], int *p_indexliste) {
+ int i, j, nextshift = 0 /*Suppresses gcc -Wmaybe-uninitialized false positive*/, nextshift_i = 0;
+ const int indexliste = *p_indexliste;
+
+ for (i = 0; i < indexliste; i++) {
+ int current = list[1][i]; /* Either C128_ABORC, C128_AORB, C128_SHIFTA or C128_SHIFTB */
+ int length = list[0][i];
+ if (i == nextshift_i) {
+ nextshift = 0;
+ /* Set next shift to aid deciding between latching to A or B - taken from Okapi, props Daniel Gredler */
+ for (j = i + 1; j < indexliste; j++) {
+ if (list[1][j] == C128_SHIFTA || list[1][j] == C128_SHIFTB) {
+ nextshift = list[1][j];
+ nextshift_i = j;
+ break;
+ }
+ }
+ }
+
+ if (i == 0) { /* first block */
+ if (current == C128_ABORC) {
+ if ((indexliste == 1) && (length == 2)) {
+ /* Rule 1a */
+ list[1][i] = C128_LATCHC;
+ current = C128_LATCHC;
+ } else if (length >= 4) {
+ /* Rule 1b */
+ list[1][i] = C128_LATCHC;
+ current = C128_LATCHC;
+ } else {
+ current = C128_AORB; /* Determine below */
+ }
+ }
+ if (current == C128_AORB) {
+ if (nextshift == C128_SHIFTA) {
+ /* Rule 1c */
+ list[1][i] = C128_LATCHA;
+ } else {
+ /* Rule 1d */
+ list[1][i] = C128_LATCHB;
+ }
+ } else if (current == C128_SHIFTA) {
+ /* Rule 1c */
+ list[1][i] = C128_LATCHA;
+ } else if (current == C128_SHIFTB) { /* Unless C128_LATCHX set above, can only be C128_SHIFTB */
+ /* Rule 1d */
+ list[1][i] = C128_LATCHB;
+ }
+ } else {
+ int last = list[1][i - 1];
+ if (current == C128_ABORC) {
+ if (length >= 4) {
+ /* Rule 3 - note Rule 3b (odd C blocks) dealt with later */
+ list[1][i] = C128_LATCHC;
+ current = C128_LATCHC;
+ } else {
+ current = C128_AORB; /* Determine below */
+ }
+ }
+ if (current == C128_AORB) {
+ if (last == C128_LATCHA || last == C128_SHIFTB) { /* Maintain state */
+ list[1][i] = C128_LATCHA;
+ } else if (last == C128_LATCHB || last == C128_SHIFTA) { /* Maintain state */
+ list[1][i] = C128_LATCHB;
+ } else if (nextshift == C128_SHIFTA) {
+ list[1][i] = C128_LATCHA;
+ } else {
+ list[1][i] = C128_LATCHB;
+ }
+ } else if (current == C128_SHIFTA) {
+ if (length > 1) {
+ /* Rule 4 */
+ list[1][i] = C128_LATCHA;
+ } else if (last == C128_LATCHA || last == C128_SHIFTB) { /* Maintain state */
+ list[1][i] = C128_LATCHA;
+ } else if (last == C128_LATCHC) {
+ list[1][i] = C128_LATCHA;
+ }
+ } else if (current == C128_SHIFTB) { /* Unless C128_LATCHX set above, can only be C128_SHIFTB */
+ if (length > 1) {
+ /* Rule 5 */
+ list[1][i] = C128_LATCHB;
+ } else if (last == C128_LATCHB || last == C128_SHIFTA) { /* Maintain state */
+ list[1][i] = C128_LATCHB;
+ } else if (last == C128_LATCHC) {
+ list[1][i] = C128_LATCHB;
+ }
+ }
+ } /* Rule 2 is implemented elsewhere, Rule 6 is implied */
+ }
+
+ c16k_grwp(list, p_indexliste);
+}
+
+/* Put set data into set[]. Resolves odd C blocks (was `c128_put_in_set()`) */
+static void c16k_put_in_set(int list[2][C128_MAX], const int indexliste, char set[C128_MAX],
+ const unsigned char *source) {
+ int read = 0;
+ int i, j;
+ int c_count = 0, have_nonc = 0;
+
+ for (i = 0; i < indexliste; i++) {
+ for (j = 0; j < list[0][i]; j++) {
+ set[read++] = list[1][i];
+ }
+ }
+ /* Watch out for odd-length Mode C blocks */
+ for (i = 0; i < read; i++) {
+ if (set[i] == 'C') {
+ if (source[i] == '\x1D') {
+ if (c_count & 1) {
+ have_nonc = 1;
+ if (i > c_count) {
+ set[i - c_count] = 'B';
+ } else {
+ set[i - 1] = 'B';
+ }
+ }
+ c_count = 0;
+ } else {
+ c_count++;
+ }
+ } else {
+ have_nonc = 1;
+ if (c_count & 1) {
+ if (i > c_count) {
+ set[i - c_count] = 'B';
+ } else {
+ set[i - 1] = 'B';
+ }
+ }
+ c_count = 0;
+ }
+ }
+ if (c_count & 1) {
+ if (i > c_count && have_nonc) {
+ set[i - c_count] = 'B';
+ if (c_count < 4) {
+ /* Rule 1b */
+ for (j = i - c_count + 1; j < i; j++) {
+ set[j] = 'B';
+ }
+ }
+ } else {
+ set[i - 1] = 'B';
+ }
+ }
+ for (i = 1; i < read - 1; i++) {
+ if (set[i] == 'C' && set[i - 1] != 'C' && set[i + 1] != 'C') {
+ set[i] = set[i + 1];
+ }
+ }
+ if (read > 1 && set[read - 1] == 'C' && set[read - 2] != 'C') {
+ set[read - 1] = set[read - 2];
+ }
+}
+
+/* Code 16k EN 12323:2005 */
INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int length) {
char width_pattern[40]; /* 4 (start) + 1 (guard) + 5*6 (chars) + 4 (stop) + 1 */
int current_row, rows, looper, first_check, second_check;
@@ -90,7 +307,7 @@ INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int len
indexliste = 0;
indexchaine = 0;
- mode = c128_parunmodd(source[indexchaine], gs1 /*check_fnc1*/);
+ mode = c16k_parunmodd(source[indexchaine], gs1 /*check_fnc1*/);
do {
list[1][indexliste] = mode;
@@ -100,15 +317,15 @@ INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int len
if (indexchaine == length) {
break;
}
- mode = c128_parunmodd(source[indexchaine], gs1 /*check_fnc1*/);
+ mode = c16k_parunmodd(source[indexchaine], gs1 /*check_fnc1*/);
}
indexliste++;
} while (indexchaine < length);
- c128_dxsmooth(list, &indexliste, NULL /*manual_set*/);
+ c16k_dxsmooth(list, &indexliste);
/* Put set data into set[], resolving odd C blocks */
- c128_put_in_set(list, indexliste, set, source);
+ c16k_put_in_set(list, indexliste, set, source);
if (debug_print) {
printf("Data: %.*s\n", length, source);
diff --git a/backend/common.c b/backend/common.c
index 9267db49..890c3c58 100644
--- a/backend/common.c
+++ b/backend/common.c
@@ -185,6 +185,7 @@ INTERNAL int bin_append_posn(const int arg, const int length, char *binary, cons
}
#ifndef Z_COMMON_INLINE
+
/* Returns true (1) if a module is dark/black, otherwise false (0) */
INTERNAL int module_is_set(const struct zint_symbol *symbol, const int y_coord, const int x_coord) {
return (symbol->encoded_data[y_coord][x_coord >> 3] >> (x_coord & 0x07)) & 1;
@@ -209,7 +210,8 @@ INTERNAL void set_module_colour(struct zint_symbol *symbol, const int y_coord, c
INTERNAL void unset_module(struct zint_symbol *symbol, const int y_coord, const int x_coord) {
symbol->encoded_data[y_coord][x_coord >> 3] &= ~(1 << (x_coord & 0x07));
}
-#endif
+
+#endif /* Z_COMMON_INLINE */
/* Expands from a width pattern to a bit pattern */
INTERNAL void expand(struct zint_symbol *symbol, const char data[], const int length) {
@@ -662,6 +664,6 @@ INTERNAL void debug_test_codeword_dump_int(struct zint_symbol *symbol, const int
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 7
#pragma GCC diagnostic pop
#endif
-#endif /*ZINT_TEST*/
+#endif /* ZINT_TEST */
/* vim: set ts=4 sw=4 et : */
diff --git a/backend/common.h b/backend/common.h
index 2225fa48..5fe06341 100644
--- a/backend/common.h
+++ b/backend/common.h
@@ -53,6 +53,7 @@ typedef unsigned __int64 uint64_t;
#endif
/* Note if change following must also change "frontend/main.c" copy */
+
#define ARRAY_SIZE(x) ((int) (sizeof(x) / sizeof((x)[0])))
#ifdef _MSC_VER
@@ -67,6 +68,7 @@ typedef unsigned __int64 uint64_t;
# endif
# define z_alloca(nmemb) alloca(nmemb)
#endif
+
/* End of "frontend/main.c" copy */
#ifdef _MSC_VER
@@ -198,12 +200,15 @@ INTERNAL int bin_append_posn(const int arg, const int length, char *binary, cons
#define Z_COMMON_INLINE 1
#ifdef Z_COMMON_INLINE
+
# define module_is_set(s, y, x) (((s)->encoded_data[y][(x) >> 3] >> ((x) & 0x07)) & 1)
# define set_module(s, y, x) do { (s)->encoded_data[y][(x) >> 3] |= 1 << ((x) & 0x07); } while (0)
# define module_colour_is_set(s, y, x) ((s)->encoded_data[y][x])
# define set_module_colour(s, y, x, c) do { (s)->encoded_data[y][x] = (c); } while (0)
# define unset_module(s, y, x) do { (s)->encoded_data[y][(x) >> 3] &= ~(1 << ((x) & 0x07)); } while (0)
-#else
+
+#else /* Z_COMMON_INLINE */
+
/* Returns true (1) if a module is dark/black, otherwise false (0) */
INTERNAL int module_is_set(const struct zint_symbol *symbol, const int y_coord, const int x_coord);
@@ -219,8 +224,10 @@ INTERNAL void set_module_colour(struct zint_symbol *symbol, const int y_coord, c
/* Sets a dark/black module to white (i.e. unsets) */
INTERNAL void unset_module(struct zint_symbol *symbol, const int y_coord, const int x_coord);
+
#endif /* Z_COMMON_INLINE */
+
/* Expands from a width pattern to a bit pattern */
INTERNAL void expand(struct zint_symbol *symbol, const char data[], const int length);
@@ -282,6 +289,7 @@ INTERNAL void segs_cpy(const struct zint_symbol *symbol, const struct zint_seg s
struct zint_seg local_segs[]);
+/* Helper for ZINT_DEBUG_PRINT to put all but graphical ASCII in angle brackets */
INTERNAL char *debug_print_escape(const unsigned char *source, const int first_len, char *buf);
#ifdef ZINT_TEST
diff --git a/backend/eci.h b/backend/eci.h
index 272aad28..60d65fde 100644
--- a/backend/eci.h
+++ b/backend/eci.h
@@ -1,7 +1,7 @@
/* eci.c - Extended Channel Interpretations to Unicode tables */
/*
libzint - the open source barcode library
- Copyright (C) 2009-2022 Robin Stuart A shorter version of GS1-128 which encodes GTIN data only. A 13-digit
-number is required. The GTIN check digit and AI (01) are added by
-Zint.zint -b EAN14 --compliantheight -d "9889876543210"
zint -b NVE18 --compliantheight -d "37612345000001003"<
A variation of Code 128 the ‘Nummer der Versandeinheit’ standard,
also known as SSCC-18 (Serial Shipping Container Code), includes both a
visible modulo-10 and a hidden modulo-103 check digit. NVE-18 requires a
-17-digit numerical input. Check digits and AI (00) are added by
-Zint.
+17-digit numerical input. Check digits and HRT-only AI “(00)” are added
+by Zint.
6.1.10.6 HIBC Code 128
aria-hidden="true">zint -b DBAR_OMN --compliantheight -d "0950110153001"
Previously known as RSS-14 this standard encodes a 13-digit item
-code. A check digit and Application Identifier of (01) are added by
-Zint. (A 14-digit code that appends the check digit may be given, in
-which case the check digit will be verified.)
+code. A check digit and HRT-only Application Identifier of “(01)” are
+added by Zint. (A 14-digit code that appends the check digit may be
+given, in which case the check digit will be verified.)
GS1 DataBar Omnidirectional symbols should have a height of 33 or
greater. To produce a GS1 DataBar Truncated symbol set the symbol height
to a value between 13 and 32. Truncated symbols may not be scannable by
@@ -5033,9 +5033,9 @@ aria-hidden="true">zint -b DBAR_LTD --compliantheight -d "0950110153001"
code and can be used in the same way as GS1 DataBar Omnidirectional
above. GS1 DataBar Limited, however, is limited to data starting with
digits 0 and 1 (i.e. numbers in the range 0 to 1999999999999). As with
-GS1 DataBar Omnidirectional a check digit and Application Identifier of
-(01) are added by Zint, and a 14-digit code may be given in which case
-the check digit will be verified.
+GS1 DataBar Omnidirectional a check digit and HRT-only Application
+Identifier of “(01)” are added by Zint, and a 14-digit code may be given
+in which case the check digit will be verified.
6.1.11.3 GS1 DataBar Expanded
--border option.
--boldUse bold text for the Human Readable Text (HRT).
+Use a bold font for the Human Readable Text (HRT).
--border=INTEGER--smallUse small text for Human Readable Text (HRT).
+Use a smaller font for Human Readable Text (HRT).
--squareCopyright © 2023 Robin Stuart. Released under GNU GPL 3.0 or +
Copyright © 2024 Robin Stuart. Released under GNU GPL 3.0 or later.