comparison mupdf-source/thirdparty/zint/backend/code16k.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /* code16k.c - Handles Code 16k stacked symbology */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2008-2024 Robin Stuart <rstuart114@gmail.com>
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. Neither the name of the project nor the names of its contributors
16 may be used to endorse or promote products derived from this software
17 without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 SUCH DAMAGE.
30 */
31 /* SPDX-License-Identifier: BSD-3-Clause */
32
33 /* Updated to comply with BS EN 12323:2005 */
34
35 /* Code 16k can hold up to 77 characters or 154 numbers */
36
37 #include <assert.h>
38 #include <stdio.h>
39 #include "common.h"
40 #include "code128.h"
41
42 /* Note these previously defined in "code128.h" with `C128_` prefix */
43 #define C16K_LATCHA 'A'
44 #define C16K_LATCHB 'B'
45 #define C16K_LATCHC 'C'
46 #define C16K_SHIFTA 'a'
47 #define C16K_SHIFTB 'b'
48 #define C16K_ABORC '9'
49 #define C16K_AORB 'Z'
50
51 /* Note using C128Table with extra entry at 106 (Triple Shift) for C16KTable */
52
53 /* EN 12323 Table 3 and Table 4 - Start patterns and stop patterns */
54 static const char C16KStartStop[8][4] = {
55 {'3','2','1','1'}, {'2','2','2','1'}, {'2','1','2','2'}, {'1','4','1','1'},
56 {'1','1','3','2'}, {'1','2','3','1'}, {'1','1','1','4'}, {'3','1','1','2'}
57 };
58
59 /* EN 12323 Table 5 - Start and stop values defining row numbers */
60 static const unsigned char C16KStartValues[16] = {
61 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7
62 };
63
64 static const unsigned char C16KStopValues[16] = {
65 0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 0, 1, 2, 3
66 };
67
68 /* Determine appropriate mode for a given character (was `c128_parunmodd()`) */
69 static int c16k_parunmodd(const unsigned char llyth, const int check_fnc1) {
70 int modd;
71
72 if (llyth <= 31) {
73 modd = check_fnc1 && llyth == '\x1D' ? C16K_ABORC : C16K_SHIFTA;
74 } else if ((llyth >= 48) && (llyth <= 57)) {
75 modd = C16K_ABORC;
76 } else if (llyth <= 95) {
77 modd = C16K_AORB;
78 } else if (llyth <= 127) {
79 modd = C16K_SHIFTB;
80 } else if (llyth <= 159) {
81 modd = C16K_SHIFTA;
82 } else if (llyth <= 223) {
83 modd = C16K_AORB;
84 } else {
85 modd = C16K_SHIFTB;
86 }
87
88 return modd;
89 }
90
91 /* Bring together same type blocks (was `c128_grwp()`) */
92 static void c16k_grwp(int list[2][C128_MAX], int *p_indexliste) {
93
94 if (*p_indexliste > 1) {
95 int i = 1;
96 while (i < *p_indexliste) {
97 if (list[1][i - 1] == list[1][i]) {
98 int j;
99 /* Bring together */
100 list[0][i - 1] = list[0][i - 1] + list[0][i];
101 j = i + 1;
102
103 /* Decrease the list */
104 while (j < *p_indexliste) {
105 list[0][j - 1] = list[0][j];
106 list[1][j - 1] = list[1][j];
107 j++;
108 }
109 *p_indexliste = *p_indexliste - 1;
110 i--;
111 }
112 i++;
113 }
114 }
115 }
116
117 /* Implements rules from ISO/IEC 15417:2007 Annex E (was `c128_dxsmooth()`) */
118 static void c16k_dxsmooth(int list[2][C128_MAX], int *p_indexliste) {
119 int i, j, nextshift = 0 /*Suppresses gcc -Wmaybe-uninitialized false positive*/, nextshift_i = 0;
120 const int indexliste = *p_indexliste;
121
122 for (i = 0; i < indexliste; i++) {
123 int current = list[1][i]; /* Either C16K_ABORC, C16K_AORB, C16K_SHIFTA or C16K_SHIFTB */
124 int length = list[0][i];
125 if (i == nextshift_i) {
126 nextshift = 0;
127 /* Set next shift to aid deciding between latching to A or B - taken from Okapi, props Daniel Gredler */
128 for (j = i + 1; j < indexliste; j++) {
129 if (list[1][j] == C16K_SHIFTA || list[1][j] == C16K_SHIFTB) {
130 nextshift = list[1][j];
131 nextshift_i = j;
132 break;
133 }
134 }
135 }
136
137 if (i == 0) { /* first block */
138 if (current == C16K_ABORC) {
139 if ((indexliste == 1) && (length == 2)) {
140 /* Rule 1a */
141 list[1][i] = C16K_LATCHC;
142 current = C16K_LATCHC;
143 } else if (length >= 4) {
144 /* Rule 1b */
145 list[1][i] = C16K_LATCHC;
146 current = C16K_LATCHC;
147 } else {
148 current = C16K_AORB; /* Determine below */
149 }
150 }
151 if (current == C16K_AORB) {
152 if (nextshift == C16K_SHIFTA) {
153 /* Rule 1c */
154 list[1][i] = C16K_LATCHA;
155 } else {
156 /* Rule 1d */
157 list[1][i] = C16K_LATCHB;
158 }
159 } else if (current == C16K_SHIFTA) {
160 /* Rule 1c */
161 list[1][i] = C16K_LATCHA;
162 } else if (current == C16K_SHIFTB) { /* Unless C16K_LATCHX set above, can only be C16K_SHIFTB */
163 /* Rule 1d */
164 list[1][i] = C16K_LATCHB;
165 }
166 } else {
167 int last = list[1][i - 1];
168 if (current == C16K_ABORC) {
169 if (length >= 4) {
170 /* Rule 3 - note Rule 3b (odd C blocks) dealt with later */
171 list[1][i] = C16K_LATCHC;
172 current = C16K_LATCHC;
173 } else {
174 current = C16K_AORB; /* Determine below */
175 }
176 }
177 if (current == C16K_AORB) {
178 if (last == C16K_LATCHA || last == C16K_SHIFTB) { /* Maintain state */
179 list[1][i] = C16K_LATCHA;
180 } else if (last == C16K_LATCHB || last == C16K_SHIFTA) { /* Maintain state */
181 list[1][i] = C16K_LATCHB;
182 } else if (nextshift == C16K_SHIFTA) {
183 list[1][i] = C16K_LATCHA;
184 } else {
185 list[1][i] = C16K_LATCHB;
186 }
187 } else if (current == C16K_SHIFTA) {
188 if (length > 1) {
189 /* Rule 4 */
190 list[1][i] = C16K_LATCHA;
191 } else if (last == C16K_LATCHA || last == C16K_SHIFTB) { /* Maintain state */
192 list[1][i] = C16K_LATCHA;
193 } else if (last == C16K_LATCHC) {
194 list[1][i] = C16K_LATCHA;
195 }
196 } else if (current == C16K_SHIFTB) { /* Unless C16K_LATCHX set above, can only be C16K_SHIFTB */
197 if (length > 1) {
198 /* Rule 5 */
199 list[1][i] = C16K_LATCHB;
200 } else if (last == C16K_LATCHB || last == C16K_SHIFTA) { /* Maintain state */
201 list[1][i] = C16K_LATCHB;
202 } else if (last == C16K_LATCHC) {
203 list[1][i] = C16K_LATCHB;
204 }
205 }
206 } /* Rule 2 is implemented elsewhere, Rule 6 is implied */
207 }
208
209 c16k_grwp(list, p_indexliste);
210 }
211
212 /* Put set data into set[]. Resolves odd C blocks (was `c128_put_in_set()`) */
213 static void c16k_put_in_set(int list[2][C128_MAX], const int indexliste, char set[C128_MAX],
214 const unsigned char *source) {
215 int read = 0;
216 int i, j;
217 int c_count = 0, have_nonc = 0;
218
219 for (i = 0; i < indexliste; i++) {
220 for (j = 0; j < list[0][i]; j++) {
221 set[read++] = list[1][i];
222 }
223 }
224 /* Watch out for odd-length Mode C blocks */
225 for (i = 0; i < read; i++) {
226 if (set[i] == 'C') {
227 if (source[i] == '\x1D') {
228 if (c_count & 1) {
229 have_nonc = 1;
230 if (i > c_count) {
231 set[i - c_count] = 'B';
232 } else {
233 set[i - 1] = 'B';
234 }
235 }
236 c_count = 0;
237 } else {
238 c_count++;
239 }
240 } else {
241 have_nonc = 1;
242 if (c_count & 1) {
243 if (i > c_count) {
244 set[i - c_count] = 'B';
245 } else {
246 set[i - 1] = 'B';
247 }
248 }
249 c_count = 0;
250 }
251 }
252 if (c_count & 1) {
253 if (i > c_count && have_nonc) {
254 set[i - c_count] = 'B';
255 if (c_count < 4) {
256 /* Rule 1b */
257 for (j = i - c_count + 1; j < i; j++) {
258 set[j] = 'B';
259 }
260 }
261 } else {
262 set[i - 1] = 'B';
263 }
264 }
265 for (i = 1; i < read - 1; i++) {
266 if (set[i] == 'C' && set[i - 1] != 'C' && set[i + 1] != 'C') {
267 set[i] = set[i + 1];
268 }
269 }
270 if (read > 1 && set[read - 1] == 'C' && set[read - 2] != 'C') {
271 set[read - 1] = set[read - 2];
272 }
273 }
274
275 /**
276 * Translate Code 128 Set A characters into barcodes (was `c128_set_a()`).
277 * This set handles all control characters NUL to US
278 */
279 static void c16k_set_a(const unsigned char source, int values[], int *bar_chars) {
280
281 if (source >= 128) {
282 if (source < 160) {
283 values[(*bar_chars)] = (source - 128) + 64;
284 } else {
285 values[(*bar_chars)] = (source - 128) - 32;
286 }
287 } else {
288 if (source < 32) {
289 values[(*bar_chars)] = source + 64;
290 } else {
291 values[(*bar_chars)] = source - 32;
292 }
293 }
294 (*bar_chars)++;
295 }
296
297 /**
298 * Translate Code 128 Set B characters into barcodes (was `c128_set_b()`).
299 * This set handles all characters which are not part of long numbers and not
300 * control characters
301 */
302 static int c16k_set_b(const unsigned char source, int values[], int *bar_chars) {
303 if (source >= 128 + 32) {
304 values[(*bar_chars)] = source - 32 - 128;
305 } else if (source >= 128) { /* Should never happen */
306 return 0; /* Not reached */
307 } else if (source >= 32) {
308 values[(*bar_chars)] = source - 32;
309 } else { /* Should never happen */
310 return 0; /* Not reached */
311 }
312 (*bar_chars)++;
313 return 1;
314 }
315
316 /* Translate Code 128 Set C characters into barcodes (was `c128_set_c()`).
317 * This set handles numbers in a compressed form
318 */
319 static void c16k_set_c(const unsigned char source_a, const unsigned char source_b, int values[], int *bar_chars) {
320 values[(*bar_chars)] = 10 * (source_a - '0') + source_b - '0';
321 (*bar_chars)++;
322 }
323
324 /* Code 16k EN 12323:2005 */
325 INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int length) {
326 char width_pattern[40]; /* 4 (start) + 1 (guard) + 5*6 (chars) + 4 (stop) + 1 */
327 int current_row, rows, looper, first_check, second_check;
328 int indexchaine;
329 int list[2][C128_MAX] = {{0}};
330 char set[C128_MAX] = {0}, fset[C128_MAX] = {0}, mode, current_set;
331 int pads_needed, indexliste, i, m, read, mx_reader;
332 int extra_pads = 0;
333 int values[C128_MAX] = {0};
334 int bar_characters;
335 int error_number = 0, first_sum, second_sum;
336 const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE;
337 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
338
339 if (length > C128_MAX) {
340 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 420, "Input length %d too long (maximum " C128_MAX_S ")", length);
341 }
342
343 if (symbol->option_1 == 1 || symbol->option_1 > 16) {
344 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 424, "Minimum number of rows '%d' out of range (2 to 16)",
345 symbol->option_1);
346 }
347
348 /* Detect extended ASCII characters */
349 for (i = 0; i < length; i++) {
350 fset[i] = source[i] >= 128 ? 'f' : ' ';
351 }
352 /* Note to be safe not using extended ASCII latch as not mentioned in BS EN 12323:2005 */
353
354 /* Detect mode A, B and C characters */
355 indexliste = 0;
356 indexchaine = 0;
357
358 mode = c16k_parunmodd(source[indexchaine], gs1 /*check_fnc1*/);
359
360 do {
361 list[1][indexliste] = mode;
362 while ((list[1][indexliste] == mode) && (indexchaine < length)) {
363 list[0][indexliste]++;
364 indexchaine++;
365 if (indexchaine == length) {
366 break;
367 }
368 mode = c16k_parunmodd(source[indexchaine], gs1 /*check_fnc1*/);
369 }
370 indexliste++;
371 } while (indexchaine < length);
372
373 c16k_dxsmooth(list, &indexliste);
374
375 /* Put set data into set[], resolving odd C blocks */
376 c16k_put_in_set(list, indexliste, set, source);
377
378 if (debug_print) {
379 printf("Data: %.*s\n", length, source);
380 printf(" Set: %.*s\n", length, set);
381 printf("FSet: %.*s\n", length, fset);
382 }
383
384 /* start with the mode character - Table 2 */
385 m = 0;
386 switch (set[0]) {
387 case 'A': m = 0;
388 break;
389 case 'B': m = 1;
390 break;
391 case 'C': m = 2;
392 break;
393 }
394
395 if (symbol->output_options & READER_INIT) {
396 if (gs1) {
397 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 422, "Cannot use Reader Initialisation in GS1 mode");
398 }
399 if (m == 2) {
400 m = 5;
401 } else if ((set[0] == 'B') && (set[1] == 'C') && fset[0] != 'f') {
402 m = 6;
403 }
404 values[1] = 96; /* FNC3 */
405 bar_characters = 2;
406 } else {
407 if (gs1) {
408 /* Integrate FNC1 */
409 switch (set[0]) {
410 case 'B': m = 3;
411 break;
412 case 'C': m = 4;
413 break;
414 }
415 } else {
416 if ((set[0] == 'B') && (set[1] == 'C')) {
417 m = fset[0] == 'f' ? 6 : 5;
418 } else if ((set[0] == 'B') && (set[1] == 'B') && (set[2] == 'C') && fset[0] != 'f' && fset[1] != 'f') {
419 m = 6;
420 }
421 }
422 bar_characters = 1;
423 }
424
425 current_set = set[0];
426 read = 0;
427
428 /* Encode the data */
429 /* TODO: make use of extra (non-CODE128) shifts: 1SB, 2SA/B/C, 3SB/C */
430 do {
431
432 if ((read != 0) && (set[read] != current_set)) {
433 /* Latch different code set */
434 switch (set[read]) {
435 case 'A':
436 values[bar_characters++] = 101;
437 current_set = 'A';
438 break;
439 case 'B':
440 values[bar_characters++] = 100;
441 current_set = 'B';
442 break;
443 case 'C':
444 /* If not Mode C/Shift B and not Mode C/Double Shift B */
445 if (!(read == 1 && m >= 5) && !(read == 2 && m == 6)) {
446 values[bar_characters++] = 99;
447 }
448 current_set = 'C';
449 break;
450 }
451 }
452
453 if (fset[read] == 'f') {
454 /* Shift extended mode */
455 switch (current_set) {
456 case 'A':
457 values[bar_characters++] = 101; /* FNC 4 */
458 break;
459 case 'B':
460 values[bar_characters++] = 100; /* FNC 4 */
461 break;
462 }
463 }
464
465 if ((set[read] == 'a') || (set[read] == 'b')) {
466 /* Insert shift character */
467 values[bar_characters++] = 98;
468 }
469
470 if (!gs1 || source[read] != '\x1D') {
471 switch (set[read]) { /* Encode data characters */
472 case 'A':
473 case 'a': c16k_set_a(source[read], values, &bar_characters);
474 read++;
475 break;
476 case 'B':
477 case 'b': (void) c16k_set_b(source[read], values, &bar_characters);
478 read++;
479 break;
480 case 'C': c16k_set_c(source[read], source[read + 1], values, &bar_characters);
481 read += 2;
482 break;
483 }
484 } else {
485 values[bar_characters++] = 102;
486 read++;
487 }
488
489 if (bar_characters > 80 - 2) { /* Max rows 16 * 5 - 2 check chars */
490 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 421,
491 "Input too long, requires %d symbol characters (maximum 78)", bar_characters);
492 }
493 } while (read < length);
494
495 pads_needed = 5 - ((bar_characters + 2) % 5);
496 if (pads_needed == 5) {
497 pads_needed = 0;
498 }
499 if ((bar_characters + pads_needed) < 8) {
500 pads_needed += 8 - (bar_characters + pads_needed);
501 }
502
503 rows = (bar_characters + pads_needed + 4) / 5;
504 if (symbol->option_1 > rows) {
505 extra_pads = (symbol->option_1 - rows) * 5;
506 rows = symbol->option_1;
507 }
508
509 for (i = 0; i < pads_needed + extra_pads; i++) {
510 values[bar_characters++] = 103;
511 }
512 values[0] = (7 * (rows - 2)) + m; /* see 4.3.4.2 */
513
514 /* Calculate check digits */
515 first_sum = 0;
516 second_sum = 0;
517 for (i = 0; i < bar_characters; i++) {
518 first_sum += (i + 2) * values[i];
519 second_sum += (i + 1) * values[i];
520 }
521 first_check = first_sum % 107;
522 second_sum += first_check * (bar_characters + 1);
523 second_check = second_sum % 107;
524 values[bar_characters] = first_check;
525 values[bar_characters + 1] = second_check;
526 bar_characters += 2;
527
528 if (debug_print) {
529 printf("Codewords (%d):", bar_characters);
530 for (i = 0; i < bar_characters; i++) {
531 if (i % 5 == 0) {
532 fputc('\n', stdout);
533 }
534 printf(" %3d", values[i]);
535 }
536 fputc('\n', stdout);
537 }
538 #ifdef ZINT_TEST
539 if (symbol->debug & ZINT_DEBUG_TEST) {
540 debug_test_codeword_dump_int(symbol, values, bar_characters); /* Missing row start/stop */
541 }
542 #endif
543
544 assert(rows * 5 == bar_characters);
545
546 for (current_row = 0; current_row < rows; current_row++) {
547 int writer;
548 int flip_flop;
549 int len;
550 char *d = width_pattern;
551
552 memcpy(d, C16KStartStop[C16KStartValues[current_row]], 4);
553 d += 4;
554 *d++ = '1';
555 for (i = 0; i < 5; i++, d += 6) {
556 memcpy(d, C128Table[values[(current_row * 5) + i]], 6);
557 }
558 memcpy(d, C16KStartStop[C16KStopValues[current_row]], 4);
559 d += 4;
560
561 /* Write the information into the symbol */
562 writer = 0;
563 flip_flop = 1;
564 for (mx_reader = 0, len = d - width_pattern; mx_reader < len; mx_reader++) {
565 for (looper = 0; looper < ctoi(width_pattern[mx_reader]); looper++) {
566 if (flip_flop == 1) {
567 set_module(symbol, current_row, writer);
568 }
569 writer++;
570 }
571 flip_flop = !flip_flop;
572 }
573 }
574
575 symbol->rows = rows;
576 symbol->width = 70;
577
578 if (symbol->output_options & COMPLIANT_HEIGHT) {
579 /* BS EN 12323:2005 Section 4.5 (d) minimum 8X; use 10X as default
580 Section 4.5 (b) H = X[r(h + g) + g] = rows * row_height + (rows - 1) * separator as borders not included
581 in symbol->height (added on) */
582 const int separator = symbol->option_3 >= 1 && symbol->option_3 <= 4 ? symbol->option_3 : 1;
583 const float min_row_height = stripf((8.0f * rows + separator * (rows - 1)) / rows);
584 const float default_height = 10.0f * rows + separator * (rows - 1);
585 error_number = set_height(symbol, min_row_height, default_height, 0.0f, 0 /*no_errtxt*/);
586 } else {
587 (void) set_height(symbol, 0.0f, 10.0f * rows, 0.0f, 1 /*no_errtxt*/);
588 }
589
590 symbol->output_options |= BARCODE_BIND;
591
592 if (symbol->border_width == 0) { /* Allow override if non-zero */
593 symbol->border_width = 1; /* BS EN 12323:2005 Section 4.3.7 minimum (note change from previous default 2) */
594 }
595
596 return error_number;
597 }
598
599 /* vim: set ts=4 sw=4 et : */