comparison mupdf-source/thirdparty/zint/backend/composite.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 /* composite.c - Handles GS1 Composite Symbols */
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 /* The functions "getBit", "init928" and "encode928" are copyright BSI and are
34 released with permission under the following terms:
35
36 "Copyright subsists in all BSI publications. BSI also holds the copyright, in the
37 UK, of the international standardisation bodies. Except as
38 permitted under the Copyright, Designs and Patents Act 1988 no extract may be
39 reproduced, stored in a retrieval system or transmitted in any form or by any
40 means - electronic, photocopying, recording or otherwise - without prior written
41 permission from BSI.
42
43 "This does not preclude the free use, in the course of implementing the standard,
44 of necessary details such as symbols, and size, type or grade designations. If these
45 details are to be used for any other purpose than implementation then the prior
46 written permission of BSI must be obtained."
47
48 The date of publication for these functions is 31 May 2006
49 */
50
51 #include <assert.h>
52 #include <math.h>
53 #include <stdio.h>
54 #include "common.h"
55 #include "pdf417.h"
56 #include "gs1.h"
57 #include "general_field.h"
58
59 #include "composite.h"
60
61 INTERNAL int gs1_128_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_mode,
62 const int cc_rows);
63
64 INTERNAL int eanx_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows);
65 INTERNAL int ean_leading_zeroes(struct zint_symbol *symbol, const unsigned char source[],
66 unsigned char local_source[], int *p_with_addon, unsigned char *zfirst_part,
67 unsigned char *zsecond_part);
68
69 INTERNAL int dbar_omnstk_set_height(struct zint_symbol *symbol, const int first_row);
70 INTERNAL int dbar_omn_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows);
71 INTERNAL int dbar_ltd_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows);
72 INTERNAL int dbar_exp_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows);
73 INTERNAL int dbar_date(const unsigned char source[], const int length, const int src_posn);
74
75 static int cc_min(const int first, const int second) {
76
77 if (first <= second)
78 return first;
79 else
80 return second;
81 }
82
83 /* gets bit in bitString at bitPos */
84 static int cc_getBit(const unsigned short *bitStr, const int bitPos) {
85 return !!(bitStr[bitPos >> 4] & (0x8000 >> (bitPos & 15)));
86 }
87
88 /* converts bit string to base 928 values, codeWords[0] is highest order */
89 static int cc_encode928(const unsigned short bitString[], unsigned short codeWords[], const int bitLng) {
90 int i, j, b, cwNdx, cwLng;
91 for (cwNdx = cwLng = b = 0; b < bitLng; b += 69, cwNdx += 7) {
92 const int bitCnt = cc_min(bitLng - b, 69);
93 int cwCnt;
94 cwLng += cwCnt = bitCnt / 10 + 1;
95 for (i = 0; i < cwCnt; i++)
96 codeWords[cwNdx + i] = 0; /* init 0 */
97 for (i = 0; i < bitCnt; i++) {
98 if (cc_getBit(bitString, b + bitCnt - i - 1)) {
99 for (j = 0; j < cwCnt; j++)
100 codeWords[cwNdx + j] += cc_pwr928[i][j + 7 - cwCnt];
101 }
102 }
103 for (i = cwCnt - 1; i > 0; i--) {
104 /* add "carries" */
105 codeWords[cwNdx + i - 1] += codeWords[cwNdx + i] / 928;
106 codeWords[cwNdx + i] %= 928;
107 }
108 }
109 return (cwLng);
110 }
111
112 /* CC-A 2D component */
113 static void cc_a(struct zint_symbol *symbol, const char source[], const int cc_width) {
114 int i, segment, bitlen, cwCnt, variant, rows;
115 int k, offset, j, total, rsCodeWords[8] = {0};
116 int LeftRAPStart, RightRAPStart, CentreRAPStart, StartCluster;
117 int LeftRAP, RightRAP, CentreRAP, Cluster;
118 int loop;
119 unsigned short codeWords[28] = {0};
120 unsigned short bitStr[13] = {0};
121 char pattern[580];
122 int bp = 0;
123 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
124
125 variant = 0;
126
127 bitlen = (int) strlen(source);
128
129 for (segment = 0; segment < 13; segment++) {
130 const int strpos = segment * 16;
131 if (strpos >= bitlen) {
132 break;
133 }
134 for (i = 0; i < 16 && strpos + i < bitlen; i++) {
135 if (source[strpos + i] == '1') {
136 bitStr[segment] |= (0x8000 >> i);
137 }
138 }
139 }
140
141 /* encode codeWords from bitStr */
142 cwCnt = cc_encode928(bitStr, codeWords, bitlen);
143
144 switch (cc_width) {
145 case 2:
146 switch (cwCnt) {
147 case 6: variant = 0;
148 break;
149 case 8: variant = 1;
150 break;
151 case 9: variant = 2;
152 break;
153 case 11: variant = 3;
154 break;
155 case 12: variant = 4;
156 break;
157 case 14: variant = 5;
158 break;
159 case 17: variant = 6;
160 break;
161 }
162 break;
163 case 3:
164 switch (cwCnt) {
165 case 8: variant = 7;
166 break;
167 case 10: variant = 8;
168 break;
169 case 12: variant = 9;
170 break;
171 case 14: variant = 10;
172 break;
173 case 17: variant = 11;
174 break;
175 }
176 break;
177 case 4:
178 switch (cwCnt) {
179 case 8: variant = 12;
180 break;
181 case 11: variant = 13;
182 break;
183 case 14: variant = 14;
184 break;
185 case 17: variant = 15;
186 break;
187 case 20: variant = 16;
188 break;
189 }
190 break;
191 }
192
193 rows = cc_aVariants[variant];
194 k = cc_aVariants[17 + variant];
195 offset = cc_aVariants[34 + variant];
196
197 /* Reed-Solomon error correction */
198
199 for (i = 0; i < cwCnt; i++) {
200 total = (codeWords[i] + rsCodeWords[k - 1]) % 929;
201 for (j = k - 1; j >= 0; j--) {
202 if (j == 0) {
203 rsCodeWords[j] = (929 - (total * cc_aCoeffs[offset + j]) % 929) % 929;
204 } else {
205 rsCodeWords[j] = (rsCodeWords[j - 1] + 929 - (total * cc_aCoeffs[offset + j]) % 929) % 929;
206 }
207 }
208 }
209
210 for (j = 0; j < k; j++) {
211 if (rsCodeWords[j] != 0) {
212 rsCodeWords[j] = 929 - rsCodeWords[j];
213 }
214 }
215
216 for (i = k - 1; i >= 0; i--) {
217 codeWords[cwCnt] = rsCodeWords[i];
218 cwCnt++;
219 }
220
221 /* Place data into table */
222 LeftRAPStart = cc_aRAPTable[variant];
223 CentreRAPStart = cc_aRAPTable[variant + 17];
224 RightRAPStart = cc_aRAPTable[variant + 34];
225 StartCluster = cc_aRAPTable[variant + 51] / 3;
226
227 LeftRAP = LeftRAPStart;
228 CentreRAP = CentreRAPStart;
229 RightRAP = RightRAPStart;
230 Cluster = StartCluster; /* Cluster can be 0, 1 or 2 for Cluster(0), Cluster(3) and Cluster(6) */
231
232 for (i = 0; i < rows; i++) {
233 bp = 0;
234 offset = 929 * Cluster;
235 k = i * cc_width;
236 /* Copy the data into codebarre */
237 if (cc_width != 3) {
238 bp = bin_append_posn(pdf_rap_side[LeftRAP - 1], 10, pattern, bp);
239 }
240 bp = bin_append_posn(pdf_bitpattern[offset + codeWords[k]], 16, pattern, bp);
241 pattern[bp++] = '0';
242 if (cc_width >= 2) {
243 if (cc_width == 3) {
244 bp = bin_append_posn(pdf_rap_centre[CentreRAP - 1], 10, pattern, bp);
245 }
246 bp = bin_append_posn(pdf_bitpattern[offset + codeWords[k + 1]], 16, pattern, bp);
247 pattern[bp++] = '0';
248 if (cc_width >= 3) {
249 if (cc_width == 4) {
250 bp = bin_append_posn(pdf_rap_centre[CentreRAP - 1], 10, pattern, bp);
251 }
252 bp = bin_append_posn(pdf_bitpattern[offset + codeWords[k + 2]], 16, pattern, bp);
253 pattern[bp++] = '0';
254 if (cc_width == 4) {
255 bp = bin_append_posn(pdf_bitpattern[offset + codeWords[k + 3]], 16, pattern, bp);
256 pattern[bp++] = '0';
257 }
258 }
259 }
260 bp = bin_append_posn(pdf_rap_side[RightRAP - 1], 10, pattern, bp);
261 pattern[bp++] = '1'; /* stop */
262
263 /* so now pattern[] holds the string of '1's and '0's. - copy this to the symbol */
264 for (loop = 0; loop < bp; loop++) {
265 if (pattern[loop] == '1') {
266 set_module(symbol, i, loop);
267 }
268 }
269 symbol->row_height[i] = 2;
270 symbol->rows++;
271
272 /* Set up RAPs and Cluster for next row */
273 LeftRAP++;
274 CentreRAP++;
275 RightRAP++;
276 Cluster++;
277
278 if (LeftRAP == 53) {
279 LeftRAP = 1;
280 }
281 if (CentreRAP == 53) {
282 CentreRAP = 1;
283 }
284 if (RightRAP == 53) {
285 RightRAP = 1;
286 }
287 if (Cluster == 3) {
288 Cluster = 0;
289 }
290 }
291 symbol->width = bp;
292
293 if (debug_print) {
294 printf("CC-A Columns: %d, Rows: %d, Variant: %d, CodeWords: %d\n", cc_width, symbol->rows, variant, cwCnt);
295 }
296 }
297
298 /* CC-B 2D component */
299 static void cc_b(struct zint_symbol *symbol, const char source[], const int cc_width) {
300 const int length = (int) strlen(source) / 8;
301 int i;
302 unsigned char *data_string = (unsigned char *) z_alloca(length + 3);
303 short chainemc[180];
304 int mclength = 0;
305 int k, j, p, longueur, mccorrection[50] = {0}, offset;
306 int total;
307 char pattern[580];
308 int variant, LeftRAPStart, CentreRAPStart, RightRAPStart, StartCluster;
309 int LeftRAP, CentreRAP, RightRAP, Cluster, loop;
310 int columns;
311 int bp = 0;
312 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
313
314 for (i = 0; i < length; i++) {
315 const int binloc = i * 8;
316
317 data_string[i] = 0;
318 for (p = 0; p < 8; p++) {
319 if (source[binloc + p] == '1') {
320 data_string[i] |= (0x80 >> p);
321 }
322 }
323 }
324
325 /* "the CC-B component shall have codeword 920 in the first symbol character position" (section 9a) */
326 chainemc[mclength++] = 920;
327
328 pdf_byteprocess(chainemc, &mclength, data_string, 0, length, 0);
329
330 /* Now figure out which variant of the symbol to use and load values accordingly */
331
332 variant = 0;
333
334 if (cc_width == 2) {
335 if (mclength <= 8) {
336 variant = 7;
337 } else if (mclength <= 13) {
338 variant = 8;
339 } else if (mclength <= 19) {
340 variant = 9;
341 } else if (mclength <= 24) {
342 variant = 10;
343 } else if (mclength <= 29) {
344 variant = 11;
345 } else if (mclength <= 33) {
346 variant = 12;
347 } else {
348 variant = 13;
349 }
350 } else if (cc_width == 3) {
351 if (mclength <= 6) {
352 variant = 14;
353 } else if (mclength <= 10) {
354 variant = 15;
355 } else if (mclength <= 14) {
356 variant = 16;
357 } else if (mclength <= 18) {
358 variant = 17;
359 } else if (mclength <= 24) {
360 variant = 18;
361 } else if (mclength <= 34) {
362 variant = 19;
363 } else if (mclength <= 46) {
364 variant = 20;
365 } else if (mclength <= 58) {
366 variant = 21;
367 } else if (mclength <= 70) {
368 variant = 22;
369 } else {
370 variant = 23;
371 }
372 } else if (cc_width == 4) {
373 if (mclength <= 8) {
374 variant = 24;
375 } else if (mclength <= 12) {
376 variant = 25;
377 } else if (mclength <= 18) {
378 variant = 26;
379 } else if (mclength <= 24) {
380 variant = 27;
381 } else if (mclength <= 30) {
382 variant = 28;
383 } else if (mclength <= 39) {
384 variant = 29;
385 } else if (mclength <= 54) {
386 variant = 30;
387 } else if (mclength <= 72) {
388 variant = 31;
389 } else if (mclength <= 90) {
390 variant = 32;
391 } else if (mclength <= 108) {
392 variant = 33;
393 } else {
394 variant = 34;
395 }
396 }
397
398 /* Now we have the variant we can load the data - from here on the same as MicroPDF417 code */
399 variant--;
400 assert(variant >= 0);
401 columns = pdf_MicroVariants[variant]; /* columns */
402 symbol->rows = pdf_MicroVariants[variant + 34]; /* rows */
403 k = pdf_MicroVariants[variant + 68]; /* number of EC CWs */
404 longueur = (columns * symbol->rows) - k; /* number of non-EC CWs */
405 i = longueur - mclength; /* amount of padding required */
406 offset = pdf_MicroVariants[variant + 102]; /* coefficient offset */
407
408 /* Binary input padded to target length so no padding should be necessary */
409 while (i > 0) {
410 chainemc[mclength++] = 900; /* Not reached */
411 i--;
412 }
413
414 /* Reed-Solomon error correction */
415 longueur = mclength;
416 for (i = 0; i < longueur; i++) {
417 total = (chainemc[i] + mccorrection[k - 1]) % 929;
418 for (j = k - 1; j >= 0; j--) {
419 if (j == 0) {
420 mccorrection[j] = (929 - (total * pdf_Microcoeffs[offset + j]) % 929) % 929;
421 } else {
422 mccorrection[j] = (mccorrection[j - 1] + 929 - (total * pdf_Microcoeffs[offset + j]) % 929) % 929;
423 }
424 }
425 }
426
427 for (j = 0; j < k; j++) {
428 if (mccorrection[j] != 0) {
429 mccorrection[j] = 929 - mccorrection[j];
430 }
431 }
432 /* we add these codes to the string */
433 for (i = k - 1; i >= 0; i--) {
434 chainemc[mclength++] = mccorrection[i];
435 }
436
437 /* Now get the RAP (Row Address Pattern) start values */
438 LeftRAPStart = pdf_RAPTable[variant];
439 CentreRAPStart = pdf_RAPTable[variant + 34];
440 RightRAPStart = pdf_RAPTable[variant + 68];
441 StartCluster = pdf_RAPTable[variant + 102] / 3;
442
443 /* That's all values loaded, get on with the encoding */
444
445 LeftRAP = LeftRAPStart;
446 CentreRAP = CentreRAPStart;
447 RightRAP = RightRAPStart;
448 Cluster = StartCluster;
449 /* Cluster can be 0, 1 or 2 for Cluster(0), Cluster(3) and Cluster(6) */
450
451 for (i = 0; i < symbol->rows; i++) {
452 bp = 0;
453 offset = 929 * Cluster;
454 k = i * columns;
455 /* Copy the data into codebarre */
456 bp = bin_append_posn(pdf_rap_side[LeftRAP - 1], 10, pattern, bp);
457 bp = bin_append_posn(pdf_bitpattern[offset + chainemc[k]], 16, pattern, bp);
458 pattern[bp++] = '0';
459 if (cc_width >= 2) {
460 if (cc_width == 3) {
461 bp = bin_append_posn(pdf_rap_centre[CentreRAP - 1], 10, pattern, bp);
462 }
463 bp = bin_append_posn(pdf_bitpattern[offset + chainemc[k + 1]], 16, pattern, bp);
464 pattern[bp++] = '0';
465 if (cc_width >= 3) {
466 if (cc_width == 4) {
467 bp = bin_append_posn(pdf_rap_centre[CentreRAP - 1], 10, pattern, bp);
468 }
469 bp = bin_append_posn(pdf_bitpattern[offset + chainemc[k + 2]], 16, pattern, bp);
470 pattern[bp++] = '0';
471 if (cc_width == 4) {
472 bp = bin_append_posn(pdf_bitpattern[offset + chainemc[k + 3]], 16, pattern, bp);
473 pattern[bp++] = '0';
474 }
475 }
476 }
477 bp = bin_append_posn(pdf_rap_side[RightRAP - 1], 10, pattern, bp);
478 pattern[bp++] = '1'; /* stop */
479
480 /* so now pattern[] holds the string of '1's and '0's. - copy this to the symbol */
481 for (loop = 0; loop < bp; loop++) {
482 if (pattern[loop] == '1') {
483 set_module(symbol, i, loop);
484 }
485 }
486 symbol->row_height[i] = 2;
487
488 /* Set up RAPs and Cluster for next row */
489 LeftRAP++;
490 CentreRAP++;
491 RightRAP++;
492 Cluster++;
493
494 if (LeftRAP == 53) {
495 LeftRAP = 1;
496 }
497 if (CentreRAP == 53) {
498 CentreRAP = 1;
499 }
500 if (RightRAP == 53) {
501 RightRAP = 1;
502 }
503 if (Cluster == 3) {
504 Cluster = 0;
505 }
506 }
507 symbol->width = bp;
508
509 if (debug_print) {
510 printf("CC-B Columns: %d, Rows: %d, Variant: %d, CodeWords: %d\n",
511 cc_width, symbol->rows, variant + 1, mclength);
512 }
513 }
514
515 /* CC-C 2D component - byte compressed PDF417 */
516 static void cc_c(struct zint_symbol *symbol, const char source[], const int cc_width, const int ecc_level) {
517 const int length = (int) strlen(source) / 8;
518 int i, p;
519 unsigned char *data_string = (unsigned char *) z_alloca(length + 4);
520 short chainemc[1000];
521 int mclength = 0, k;
522 int offset, longueur, loop, total, j, mccorrection[520] = {0};
523 int c1, c2, c3, dummy[35];
524 char pattern[580];
525 int bp = 0;
526 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
527
528 for (i = 0; i < length; i++) {
529 const int binloc = i * 8;
530
531 data_string[i] = 0;
532 for (p = 0; p < 8; p++) {
533 if (source[binloc + p] == '1') {
534 data_string[i] |= (0x80 >> p);
535 }
536 }
537 }
538
539 chainemc[mclength++] = 0; /* space for length descriptor */
540 chainemc[mclength++] = 920; /* CC-C identifier */
541
542 pdf_byteprocess(chainemc, &mclength, data_string, 0, length, 0);
543
544 chainemc[0] = mclength;
545
546 if (debug_print) {
547 printf("CC-C Codewords (%d):", mclength);
548 for (i = 0; i < mclength; i++) printf(" %d", chainemc[i]);
549 fputc('\n', stdout);
550 }
551
552 k = 1;
553 for (i = 1; i <= (ecc_level + 1); i++) {
554 k *= 2;
555 }
556
557 /* 796 - we now take care of the Reed Solomon codes */
558 switch (ecc_level) {
559 case 1: offset = 2; /* Not reached */
560 break;
561 case 2: offset = 6; /* Min ECC currently used is 2 */
562 break;
563 case 3: offset = 14;
564 break;
565 case 4: offset = 30;
566 break;
567 case 5: offset = 62; /* Max ECC currently used is 5 */
568 break;
569 case 6: offset = 126; /* Not reached */
570 break;
571 case 7: offset = 254; /* Not reached */
572 break;
573 case 8: offset = 510; /* Not reached */
574 break;
575 default: offset = 0; /* Not reached */
576 break;
577 }
578
579 longueur = mclength;
580 for (i = 0; i < longueur; i++) {
581 total = (chainemc[i] + mccorrection[k - 1]) % 929;
582 for (j = k - 1; j >= 0; j--) {
583 if (j == 0) {
584 mccorrection[j] = (929 - (total * pdf_coefrs[offset + j]) % 929) % 929;
585 } else {
586 mccorrection[j] = (mccorrection[j - 1] + 929 - (total * pdf_coefrs[offset + j]) % 929) % 929;
587 }
588 }
589 }
590
591 for (j = 0; j < k; j++) {
592 if (mccorrection[j] != 0) {
593 mccorrection[j] = 929 - mccorrection[j];
594 }
595 }
596 /* we add these codes to the string */
597 for (i = k - 1; i >= 0; i--) {
598 chainemc[mclength++] = mccorrection[i];
599 }
600
601 /* 818 - The CW string is finished */
602 symbol->rows = mclength / cc_width;
603 c1 = (symbol->rows - 1) / 3;
604 c2 = ecc_level * 3 + (symbol->rows - 1) % 3;
605 c3 = cc_width - 1;
606
607 /* we now encode each row */
608 for (i = 0; i <= symbol->rows - 1; i++) {
609 for (j = 0; j < cc_width; j++) {
610 dummy[j + 1] = chainemc[i * cc_width + j];
611 }
612 k = (i / 3) * 30;
613 switch (i % 3) {
614 case 0:
615 dummy[0] = k + c1;
616 dummy[cc_width + 1] = k + c3;
617 offset = 0; /* cluster(0) */
618 break;
619 case 1:
620 dummy[0] = k + c2;
621 dummy[cc_width + 1] = k + c1;
622 offset = 929; /* cluster(3) */
623 break;
624 case 2:
625 dummy[0] = k + c3;
626 dummy[cc_width + 1] = k + c2;
627 offset = 1858; /* cluster(6) */
628 break;
629 }
630 bp = 0;
631 bp = bin_append_posn(0x1FEA8, 17, pattern, bp); /* Row start */
632
633 for (j = 0; j <= cc_width + 1; j++) {
634 bp = bin_append_posn(pdf_bitpattern[offset + dummy[j]], 16, pattern, bp);
635 pattern[bp++] = '0';
636 }
637 bp = bin_append_posn(0x3FA29, 18, pattern, bp); /* Row Stop */
638
639 for (loop = 0; loop < bp; loop++) {
640 if (pattern[loop] == '1') {
641 set_module(symbol, i, loop);
642 }
643 }
644 symbol->row_height[i] = 3;
645 }
646 symbol->width = bp;
647
648 if (debug_print) {
649 printf("CC-C Columns: %d, Rows: %d, CodeWords: %d, ECC Level: %d\n",
650 cc_width, symbol->rows, mclength, ecc_level);
651 }
652 }
653
654 static int cc_a_calc_padding(const int binary_length, const int cc_width) {
655 int target_bitsize = 0;
656
657 switch (cc_width) {
658 case 2:
659 if (binary_length <= 59) {
660 target_bitsize = 59;
661 } else if (binary_length <= 78) {
662 target_bitsize = 78;
663 } else if (binary_length <= 88) {
664 target_bitsize = 88;
665 } else if (binary_length <= 108) {
666 target_bitsize = 108;
667 } else if (binary_length <= 118) {
668 target_bitsize = 118;
669 } else if (binary_length <= 138) {
670 target_bitsize = 138;
671 } else if (binary_length <= 167) {
672 target_bitsize = 167;
673 }
674 break;
675 case 3:
676 if (binary_length <= 78) {
677 target_bitsize = 78;
678 } else if (binary_length <= 98) {
679 target_bitsize = 98;
680 } else if (binary_length <= 118) {
681 target_bitsize = 118;
682 } else if (binary_length <= 138) {
683 target_bitsize = 138;
684 } else if (binary_length <= 167) {
685 target_bitsize = 167;
686 }
687 break;
688 case 4:
689 if (binary_length <= 78) {
690 target_bitsize = 78;
691 } else if (binary_length <= 108) {
692 target_bitsize = 108;
693 } else if (binary_length <= 138) {
694 target_bitsize = 138;
695 } else if (binary_length <= 167) {
696 target_bitsize = 167;
697 } else if (binary_length <= 197) {
698 target_bitsize = 197;
699 }
700 break;
701 }
702
703 return target_bitsize;
704 }
705
706 static int cc_b_calc_padding(const int binary_length, const int cc_width) {
707 int target_bitsize = 0;
708
709 switch (cc_width) {
710 case 2:
711 if (binary_length <= 56) {
712 target_bitsize = 56;
713 } else if (binary_length <= 104) {
714 target_bitsize = 104;
715 } else if (binary_length <= 160) {
716 target_bitsize = 160;
717 } else if (binary_length <= 208) {
718 target_bitsize = 208;
719 } else if (binary_length <= 256) {
720 target_bitsize = 256;
721 } else if (binary_length <= 296) {
722 target_bitsize = 296;
723 } else if (binary_length <= 336) {
724 target_bitsize = 336;
725 }
726 break;
727 case 3:
728 if (binary_length <= 32) {
729 target_bitsize = 32;
730 } else if (binary_length <= 72) {
731 target_bitsize = 72;
732 } else if (binary_length <= 112) {
733 target_bitsize = 112;
734 } else if (binary_length <= 152) {
735 target_bitsize = 152;
736 } else if (binary_length <= 208) {
737 target_bitsize = 208;
738 } else if (binary_length <= 304) {
739 target_bitsize = 304;
740 } else if (binary_length <= 416) {
741 target_bitsize = 416;
742 } else if (binary_length <= 536) {
743 target_bitsize = 536;
744 } else if (binary_length <= 648) {
745 target_bitsize = 648;
746 } else if (binary_length <= 768) {
747 target_bitsize = 768;
748 }
749 break;
750 case 4:
751 if (binary_length <= 56) {
752 target_bitsize = 56;
753 } else if (binary_length <= 96) {
754 target_bitsize = 96;
755 } else if (binary_length <= 152) {
756 target_bitsize = 152;
757 } else if (binary_length <= 208) {
758 target_bitsize = 208;
759 } else if (binary_length <= 264) {
760 target_bitsize = 264;
761 } else if (binary_length <= 352) {
762 target_bitsize = 352;
763 } else if (binary_length <= 496) {
764 target_bitsize = 496;
765 } else if (binary_length <= 672) {
766 target_bitsize = 672;
767 } else if (binary_length <= 840) {
768 target_bitsize = 840;
769 } else if (binary_length <= 1016) {
770 target_bitsize = 1016;
771 } else if (binary_length <= 1184) {
772 target_bitsize = 1184;
773 }
774 break;
775 }
776
777 return target_bitsize;
778 }
779
780 static int cc_c_calc_padding(const int binary_length, int *p_cc_width, const int linear_width, int *p_ecc_level) {
781 int target_bitsize = 0;
782 int byte_length, codewords_used, ecc_level, ecc_codewords, rows;
783 int codewords_total, target_codewords, target_bytesize;
784
785 byte_length = binary_length / 8;
786 if (binary_length % 8 != 0) {
787 byte_length++;
788 }
789
790 codewords_used = (byte_length / 6) * 5;
791 codewords_used += byte_length % 6;
792
793 /* Recommended minimum ecc levels ISO/IEC 1543:2015 (PDF417) Annex E Table E.1,
794 restricted by CC-C codeword max 900 (30 cols * 30 rows), GS1 General Specifications 19.1 5.9.2.3 */
795 if (codewords_used <= 40) {
796 ecc_level = 2;
797 } else if (codewords_used <= 160) {
798 ecc_level = 3;
799 } else if (codewords_used <= 320) {
800 ecc_level = 4;
801 } else if (codewords_used <= 833) { /* 900 - 3 - 64 */
802 ecc_level = 5;
803 } else if (codewords_used <= 865) { /* 900 - 3 - 32 */
804 ecc_level = 4; /* Not recommended but allow to meet advertised "up to 2361 digits" (allows max 2372) */
805 } else {
806 return 0;
807 }
808 *p_ecc_level = ecc_level;
809 ecc_codewords = 1 << (ecc_level + 1);
810
811 codewords_used += ecc_codewords;
812 codewords_used += 3;
813
814 /* Minimum possible linear width (with GS1_NO_CHECK) is 11*5 (start, FNC1, linkage, data, check) + 13 stop */
815 assert(linear_width >= 68);
816 /* -52 = 7 left shift (section 12.3 f) + 10 right quiet zone - 17 start + 2x17 row indicators + 18 stop */
817 *p_cc_width = linear_width == 68 ? 1 : (linear_width - 52) / 17; /* Ensure > 0 */
818 if (*p_cc_width > 30) {
819 *p_cc_width = 30;
820 }
821 assert(*p_cc_width > 0);
822 rows = (int) ceil((double) codewords_used / *p_cc_width);
823 /* stop the symbol from becoming too high */
824 while (rows > 30 && *p_cc_width < 30) {
825 (*p_cc_width)++;
826 rows = (int) ceil((double) codewords_used / *p_cc_width);
827 }
828
829 if (rows > 30) { /* Should never happen given `codewords_used` check above (865 / 30 ~ 28.83) */
830 return 0; /* Not reached */
831 }
832 if (rows < 3) {
833 rows = 3;
834 }
835
836 codewords_total = *p_cc_width * rows;
837
838 target_codewords = codewords_total - ecc_codewords;
839 target_codewords -= 3;
840
841 target_bytesize = 6 * (target_codewords / 5);
842 target_bytesize += target_codewords % 5;
843
844 target_bitsize = 8 * target_bytesize;
845
846 return target_bitsize;
847 }
848
849 /* Handles all data encodation from section 5 of ISO/IEC 24723 */
850 static int cc_binary_string(struct zint_symbol *symbol, const unsigned char source[], const int length,
851 char binary_string[], const int cc_mode, int *p_cc_width, int *p_ecc_level, const int linear_width) {
852 int encoding_method, read_posn, alpha_pad;
853 int i, j, ai_crop, ai_crop_posn, fnc1_latch;
854 int ai90_mode, remainder;
855 char last_digit = '\0';
856 int mode;
857 char *general_field = (char *) z_alloca(length + 1);
858 int target_bitsize;
859 int bp = 0;
860 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
861
862 encoding_method = 1;
863 read_posn = 0;
864 ai_crop = 0;
865 ai_crop_posn = -1;
866 fnc1_latch = 0;
867 alpha_pad = 0;
868 *p_ecc_level = 0;
869 target_bitsize = 0;
870 mode = NUMERIC;
871
872 if (length > 1 && (source[0] == '1') && ((source[1] == '0') || (source[1] == '1') || (source[1] == '7'))) {
873 /* Source starts (10), (11) or (17) */
874 if (source[1] == '0' || dbar_date(source, length, 2) >= 0) { /* Check date valid if (11) or (17) */
875 encoding_method = 2;
876 }
877 } else if (length > 1 && (source[0] == '9') && (source[1] == '0')) {
878 /* Source starts (90) */
879 encoding_method = 3;
880 }
881
882 if (encoding_method == 1) {
883 binary_string[bp++] = '0';
884 if (debug_print) printf("CC-%c Encodation Method: 0\n", 'A' + (cc_mode - 1));
885
886 } else if (encoding_method == 2) {
887 /* Encoding Method field "10" - date and lot number */
888
889 bp = bin_append_posn(2, 2, binary_string, bp); /* "10" */
890
891 if (source[1] == '0') {
892 /* No date data */
893 bp = bin_append_posn(3, 2, binary_string, bp); /* "11" */
894 read_posn = 2;
895 } else {
896 /* Production Date (11) or Expiration Date (17) */
897 assert(length >= 8); /* Due to `dbar_date()` check above */
898
899 bp = bin_append_posn(dbar_date(source, length, 2), 16, binary_string, bp);
900
901 if (source[1] == '1') {
902 /* Production Date AI 11 */
903 binary_string[bp++] = '0';
904 } else {
905 /* Expiration Date AI 17 */
906 binary_string[bp++] = '1';
907 }
908 read_posn = 8;
909
910 if (read_posn + 1 < length && (source[read_posn] == '1') && (source[read_posn + 1] == '0')) {
911 /* Followed by AI 10 - strip this from general field */
912 read_posn += 2;
913 } else if (source[read_posn]) {
914 /* ISO/IEC 24723:2010 5.3.1 "If a lot number does not directly follow the date element string,
915 a FNC1 is encoded following the date element string ..." */
916 fnc1_latch = 1;
917 } else {
918 /* "... even if no more data follows the date element string" */
919 /* So still need FNC1 character but can't do single FNC1 in numeric mode, so insert alphanumeric latch
920 "0000" and alphanumeric FNC1 "01111" (this implementation detail taken from BWIPP
921 https://github.com/bwipp/postscriptbarcode Copyright (c) 2004-2019 Terry Burton) */
922 bp = bin_append_posn(15, 9, binary_string, bp); /* "000001111" */
923 /* Note an alphanumeric FNC1 is also a numeric latch, so now in numeric mode */
924 }
925 }
926
927 if (debug_print) {
928 printf("CC-%c Encodation Method: 10, Compaction Field: %.*s\n", 'A' + (cc_mode - 1), read_posn, source);
929 }
930
931 } else if (encoding_method == 3) {
932 /* Encodation Method field of "11" - AI 90 */
933 unsigned char *ninety = (unsigned char *) z_alloca(length + 1);
934 int ninety_len, alpha, alphanum, numeric, alpha_posn;
935
936 /* "This encodation method may be used if an element string with an AI
937 90 occurs at the start of the data message, and if the data field
938 following the two-digit AI 90 starts with an alphanumeric string which
939 complies with a specific format." (para 5.3.2) */
940
941 i = 0;
942 if (length > 2) {
943 do {
944 ninety[i] = source[i + 2];
945 i++;
946 } while (i + 2 < length && source[i + 2] != '\x1D');
947 }
948 ninety[i] = '\0';
949 ninety_len = i;
950
951 /* Find out if the AI 90 data is alphabetic or numeric or both */
952
953 alpha = 0;
954 alphanum = 0;
955 numeric = 0;
956
957 for (i = 0; i < ninety_len; i++) {
958
959 if (z_isupper(ninety[i])) {
960 /* Character is alphabetic */
961 alpha += 1;
962 } else if (z_isdigit(ninety[i])) {
963 /* Character is numeric */
964 numeric += 1;
965 } else {
966 alphanum += 1;
967 }
968 }
969
970 /* must start with 0, 1, 2 or 3 digits followed by an uppercase character */
971 alpha_posn = -1;
972 if (ninety_len && ninety[0] != '0') { /* Leading zeros are not permitted */
973 for (i = 0; i < ninety_len && i < 4; i++) {
974 if (z_isupper(ninety[i])) {
975 alpha_posn = i;
976 break;
977 }
978 if (!z_isdigit(ninety[i])) {
979 break;
980 }
981 }
982 }
983
984 if (alpha_posn != -1) {
985 int next_ai_posn;
986 int numeric_value;
987 int table3_letter;
988 /* Encodation method "11" can be used */
989 bp = bin_append_posn(3, 2, binary_string, bp); /* "11" */
990
991 numeric -= alpha_posn;
992 alpha--;
993
994 /* Decide on numeric, alpha or alphanumeric mode */
995 /* Alpha mode is a special mode for AI 90 */
996
997 if (alphanum == 0 && alpha > numeric) {
998 /* Alpha mode */
999 bp = bin_append_posn(3, 2, binary_string, bp); /* "11" */
1000 ai90_mode = 2;
1001 } else if (alphanum == 0 && alpha == 0) {
1002 /* Numeric mode */
1003 bp = bin_append_posn(2, 2, binary_string, bp); /* "10" */
1004 ai90_mode = 3;
1005 } else {
1006 /* Note if first 4 are digits then it would be shorter to go into NUMERIC mode first; not
1007 implemented */
1008 /* Alphanumeric mode */
1009 binary_string[bp++] = '0';
1010 ai90_mode = 1;
1011 mode = ALPHANUMERIC;
1012 }
1013
1014 next_ai_posn = 2 + ninety_len;
1015
1016 if (next_ai_posn < length && source[next_ai_posn] == '\x1D') {
1017 /* There are more AIs afterwards */
1018 if (next_ai_posn + 2 < length
1019 && (source[next_ai_posn + 1] == '2') && (source[next_ai_posn + 2] == '1')) {
1020 /* AI 21 follows */
1021 ai_crop = 1;
1022 } else if (next_ai_posn + 4 < length
1023 && (source[next_ai_posn + 1] == '8') && (source[next_ai_posn + 2] == '0')
1024 && (source[next_ai_posn + 3] == '0') && (source[next_ai_posn + 4] == '4')) {
1025 /* AI 8004 follows */
1026 ai_crop = 3;
1027 }
1028 }
1029
1030 switch (ai_crop) {
1031 case 0: binary_string[bp++] = '0';
1032 break;
1033 case 1: bp = bin_append_posn(2, 2, binary_string, bp); /* "10" */
1034 ai_crop_posn = next_ai_posn + 1;
1035 break;
1036 case 3: bp = bin_append_posn(3, 2, binary_string, bp); /* "11" */
1037 ai_crop_posn = next_ai_posn + 1;
1038 break;
1039 }
1040
1041 numeric_value = alpha_posn ? to_int(ninety, alpha_posn) : 0;
1042
1043 table3_letter = -1;
1044 if (numeric_value < 31) {
1045 table3_letter = posn("BDHIJKLNPQRSTVWZ", ninety[alpha_posn]);
1046 }
1047
1048 if (table3_letter != -1) {
1049 /* Encoding can be done according to 5.3.2 c) 2) */
1050 /* five bit binary string representing value before letter */
1051 bp = bin_append_posn(numeric_value, 5, binary_string, bp);
1052
1053 /* followed by four bit representation of letter from Table 3 */
1054 bp = bin_append_posn(table3_letter, 4, binary_string, bp);
1055 } else {
1056 /* Encoding is done according to 5.3.2 c) 3) */
1057 bp = bin_append_posn(31, 5, binary_string, bp);
1058 /* ten bit representation of number */
1059 bp = bin_append_posn(numeric_value, 10, binary_string, bp);
1060
1061 /* five bit representation of ASCII character */
1062 bp = bin_append_posn(ninety[alpha_posn] - 65, 5, binary_string, bp);
1063 }
1064
1065 read_posn = alpha_posn + 3; /* +2 for 90 and +1 to go beyond alpha position */
1066
1067 /* Do Alpha mode encoding of the rest of the AI 90 data field here */
1068 if (ai90_mode == 2) {
1069 /* Alpha encodation (section 5.3.3) */
1070 do {
1071 if (z_isupper(source[read_posn])) {
1072 bp = bin_append_posn(source[read_posn] - 65, 5, binary_string, bp);
1073
1074 } else if (z_isdigit(source[read_posn])) {
1075 bp = bin_append_posn(source[read_posn] + 4, 6, binary_string, bp);
1076
1077 } else if (source[read_posn] == '\x1D') {
1078 bp = bin_append_posn(31, 5, binary_string, bp);
1079 }
1080
1081 read_posn++;
1082 } while (source[read_posn - 1] != '\x1D' && source[read_posn - 1] != '\0');
1083 alpha_pad = 1; /* This is overwritten if a general field is encoded */
1084 }
1085
1086 if (debug_print) {
1087 printf("CC-%c Encodation Method: 11, Compaction Field: %.*s, Binary: %.*s (%d)\n",
1088 'A' + (cc_mode - 1), read_posn, source, bp, binary_string, bp);
1089 }
1090 } else {
1091 /* Use general field encodation instead */
1092 binary_string[bp++] = '0';
1093 read_posn = 0;
1094 if (debug_print) printf("CC-%c Encodation Method: 0\n", 'A' + (cc_mode - 1));
1095 }
1096 }
1097
1098 /* The compressed data field has been processed if appropriate - the
1099 rest of the data (if any) goes into a general-purpose data compaction field */
1100
1101 j = 0;
1102 if (fnc1_latch == 1) {
1103 /* Encodation method "10" has been used but it is not followed by
1104 AI 10, so a FNC1 character needs to be added */
1105 general_field[j] = '\x1D';
1106 j++;
1107 }
1108
1109 for (i = read_posn; i < length; i++) {
1110 /* Skip "[21" or "[8004" AIs if encodation method "11" used */
1111 if (i == ai_crop_posn) {
1112 i += ai_crop;
1113 } else {
1114 general_field[j] = source[i];
1115 j++;
1116 }
1117 }
1118 general_field[j] = '\0';
1119
1120 if (debug_print) {
1121 printf("Mode %s, General Field: %.40s%s\n",
1122 mode == NUMERIC ? "NUMERIC" : mode == ALPHANUMERIC ? "ALPHANUMERIC" : "ISO646",
1123 general_field, j > 40 ? "..." : "");
1124 }
1125
1126 if (j != 0) { /* If general field not empty */
1127 alpha_pad = 0;
1128
1129 if (!general_field_encode(general_field, j, &mode, &last_digit, binary_string, &bp)) {
1130 /* Invalid character in input data */
1131 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 441, "Invalid character in input (2D component)");
1132 }
1133 }
1134
1135 switch (cc_mode) {
1136 case 1:
1137 target_bitsize = cc_a_calc_padding(bp, *p_cc_width);
1138 break;
1139 case 2:
1140 target_bitsize = cc_b_calc_padding(bp, *p_cc_width);
1141 break;
1142 case 3:
1143 target_bitsize = cc_c_calc_padding(bp, p_cc_width, linear_width, p_ecc_level);
1144 break;
1145 }
1146
1147 if (target_bitsize == 0) {
1148 return errtxt(ZINT_ERROR_TOO_LONG, symbol, 442, "Input too long (2D component)");
1149 }
1150
1151 remainder = target_bitsize - bp;
1152
1153 if (last_digit) {
1154 /* There is still one more numeric digit to encode */
1155
1156 if ((remainder >= 4) && (remainder <= 6)) {
1157 /* ISO/IEC 24723:2010 5.4.1 c) 2) "If four to six bits remain, add 1 to the digit value and encode the
1158 result in the next four bits. ..." */
1159 bp = bin_append_posn(ctoi(last_digit) + 1, 4, binary_string, bp);
1160 if (remainder > 4) {
1161 /* "... The fifth and sixth bits, if present, shall be “0”s." (Covered by adding truncated
1162 alphanumeric latch below but do explicitly anyway) */
1163 bp = bin_append_posn(0, remainder - 4, binary_string, bp);
1164 }
1165 } else {
1166 bp = bin_append_posn((11 * ctoi(last_digit)) + 18, 7, binary_string, bp);
1167 /* This may push the symbol up to the next size */
1168 }
1169 }
1170
1171 switch (cc_mode) {
1172 case 1:
1173 target_bitsize = cc_a_calc_padding(bp, *p_cc_width);
1174 break;
1175 case 2:
1176 target_bitsize = cc_b_calc_padding(bp, *p_cc_width);
1177 break;
1178 case 3:
1179 target_bitsize = cc_c_calc_padding(bp, p_cc_width, linear_width, p_ecc_level);
1180 break;
1181 }
1182
1183 if (target_bitsize == 0) {
1184 return errtxt(ZINT_ERROR_TOO_LONG, symbol, 444, "Input too long (2D component)");
1185 }
1186
1187 if (bp < target_bitsize) {
1188 /* Now add padding to binary string */
1189 if (alpha_pad == 1) {
1190 bp = bin_append_posn(31, 5, binary_string, bp); /* "11111" */
1191 /* Extra FNC1 character required after Alpha encodation (section 5.3.3) */
1192 }
1193
1194 if (mode == NUMERIC) {
1195 bp = bin_append_posn(0, 4, binary_string, bp); /* "0000" */
1196 }
1197
1198 while (bp < target_bitsize) {
1199 bp = bin_append_posn(4, 5, binary_string, bp); /* "00100" */
1200 }
1201 }
1202 binary_string[target_bitsize] = '\0';
1203
1204 if (debug_print) {
1205 printf("ECC: %d, CC width %d\n", *p_ecc_level, *p_cc_width);
1206 printf("Binary: %s (%d)\n", binary_string, target_bitsize);
1207 }
1208
1209 return 0;
1210 }
1211
1212 /* Calculate the width of the linear part (primary) */
1213 static int cc_linear_dummy_run(int input_mode, unsigned char *source, const int length, const int debug,
1214 char *errtxt) {
1215 struct zint_symbol dummy = {0};
1216 int error_number;
1217 int linear_width;
1218
1219 dummy.symbology = BARCODE_GS1_128_CC;
1220 dummy.option_1 = -1;
1221 dummy.input_mode = input_mode;
1222 dummy.debug = debug;
1223 error_number = gs1_128_cc(&dummy, source, length, 3 /*cc_mode*/, 0 /*cc_rows*/);
1224 linear_width = dummy.width;
1225 if (error_number >= ZINT_ERROR || (debug & ZINT_DEBUG_TEST)) {
1226 strcpy(errtxt, dummy.errtxt);
1227 }
1228
1229 if (error_number >= ZINT_ERROR) {
1230 return 0;
1231 }
1232 return linear_width;
1233 }
1234
1235 INTERNAL int composite(struct zint_symbol *symbol, unsigned char source[], int length) {
1236 int error_number, cc_mode, cc_width = 0, ecc_level = 0;
1237 int j, i, k;
1238 /* Allow for 8 bits + 5-bit latch per char + 1000 bits overhead/padding */
1239 const unsigned int bs = 13 * length + 1000 + 1;
1240 char *binary_string = (char *) z_alloca(bs);
1241 unsigned int pri_len;
1242 struct zint_symbol *linear;
1243 int top_shift, bottom_shift;
1244 int linear_width = 0;
1245 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
1246
1247 if (debug_print) printf("Reduced length: %d\n", length);
1248
1249 /* Perform sanity checks on input options first */
1250 error_number = 0;
1251 pri_len = (int) strlen(symbol->primary);
1252 if (pri_len == 0) {
1253 /* TODO: change to more appropiate ZINT_ERROR_INVALID_DATA */
1254 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 445, "No primary (linear) message");
1255 }
1256
1257 if (length > 2990) {
1258 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 446,
1259 "2D component input too long, requires %d characters (maximum 2990)", length);
1260 }
1261
1262 cc_mode = symbol->option_1;
1263 if ((cc_mode == 3) && (symbol->symbology != BARCODE_GS1_128_CC)) {
1264 /* CC-C can only be used with a GS1-128 linear part */
1265 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 447,
1266 "Invalid mode (CC-C only valid with GS1-128 linear component)");
1267 }
1268
1269 if (symbol->symbology == BARCODE_GS1_128_CC) {
1270 /* Do a test run of encoding the linear component to establish its width */
1271 linear_width = cc_linear_dummy_run(symbol->input_mode, (unsigned char *) symbol->primary, pri_len,
1272 symbol->debug, symbol->errtxt);
1273 if (linear_width == 0) {
1274 return errtxt_adj(ZINT_ERROR_INVALID_DATA, symbol, "%1$s%2$s", " (linear component)");
1275 }
1276 if (debug_print) {
1277 printf("GS1-128 linear width: %d\n", linear_width);
1278 }
1279 }
1280
1281 switch (symbol->symbology) {
1282 /* Determine width of 2D component according to ISO/IEC 24723 Table 1 */
1283 case BARCODE_EANX_CC:
1284 if (pri_len < 20) {
1285 int padded_pri_len;
1286 int with_addon;
1287 unsigned char padded_pri[21];
1288 if (!ean_leading_zeroes(symbol, (unsigned char *) symbol->primary, padded_pri, &with_addon, NULL,
1289 NULL)) {
1290 return errtxt_adj(ZINT_ERROR_TOO_LONG, symbol, "%1$s%2$s", " (linear component)");
1291 }
1292 padded_pri_len = (int) ustrlen(padded_pri);
1293 if (padded_pri_len <= 7) { /* EAN-8 */
1294 cc_width = 3;
1295 } else {
1296 switch (padded_pri_len) {
1297 case 10: /* EAN-8 + 2 */
1298 cc_width = 3;
1299 break;
1300 case 13: /* EAN-13 CHK or EAN-8 + 5 */
1301 cc_width = with_addon ? 3 : 4;
1302 break;
1303 case 12: /* EAN-13 */
1304 case 15: /* EAN-13 + 2 */
1305 case 16: /* EAN-13 CHK + 2 */
1306 case 18: /* EAN-13 + 5 */
1307 case 19: /* EAN-13 CHK + 5 */
1308 cc_width = 4;
1309 break;
1310 }
1311 }
1312 }
1313 if (cc_width == 0) {
1314 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 449, "Input length %d wrong (linear component)", pri_len);
1315 }
1316 break;
1317 case BARCODE_GS1_128_CC: cc_width = 4;
1318 break;
1319 case BARCODE_DBAR_OMN_CC: cc_width = 4;
1320 break;
1321 case BARCODE_DBAR_LTD_CC: cc_width = 3;
1322 break;
1323 case BARCODE_DBAR_EXP_CC: cc_width = 4;
1324 break;
1325 case BARCODE_UPCA_CC: cc_width = 4;
1326 break;
1327 case BARCODE_UPCE_CC: cc_width = 2;
1328 break;
1329 case BARCODE_DBAR_STK_CC: cc_width = 2;
1330 break;
1331 case BARCODE_DBAR_OMNSTK_CC: cc_width = 2;
1332 break;
1333 case BARCODE_DBAR_EXPSTK_CC: cc_width = 4;
1334 break;
1335 }
1336
1337 if (cc_mode < 1 || cc_mode > 3) {
1338 cc_mode = 1;
1339 }
1340
1341 if (cc_mode == 1) {
1342 i = cc_binary_string(symbol, source, length, binary_string, cc_mode, &cc_width, &ecc_level, linear_width);
1343 if (i == ZINT_ERROR_TOO_LONG) {
1344 symbol->errtxt[0] = '\0'; /* Unset error text */
1345 cc_mode = 2;
1346 } else if (i != 0) {
1347 return i;
1348 }
1349 }
1350
1351 if (cc_mode == 2) {
1352 /* If the data didn't fit into CC-A it is recalculated for CC-B */
1353 i = cc_binary_string(symbol, source, length, binary_string, cc_mode, &cc_width, &ecc_level, linear_width);
1354 if (i == ZINT_ERROR_TOO_LONG) {
1355 if (symbol->symbology != BARCODE_GS1_128_CC) {
1356 return ZINT_ERROR_TOO_LONG;
1357 }
1358 symbol->errtxt[0] = '\0'; /* Unset error text */
1359 cc_mode = 3;
1360 } else if (i != 0) {
1361 return i;
1362 }
1363 }
1364
1365 if (cc_mode == 3) {
1366 /* If the data didn't fit in CC-B (and linear part is GS1-128) it is recalculated for CC-C */
1367 i = cc_binary_string(symbol, source, length, binary_string, cc_mode, &cc_width, &ecc_level, linear_width);
1368 if (i != 0) {
1369 return i;
1370 }
1371 }
1372
1373 switch (cc_mode) {
1374 /* Note that ecc_level is only relevant to CC-C */
1375 case 1: cc_a(symbol, binary_string, cc_width);
1376 break;
1377 case 2: cc_b(symbol, binary_string, cc_width);
1378 break;
1379 case 3: cc_c(symbol, binary_string, cc_width, ecc_level);
1380 break;
1381 }
1382
1383 /* 2D component done, now calculate linear component */
1384 linear = ZBarcode_Create(); /* Symbol contains the 2D component and Linear contains the rest */
1385
1386 linear->symbology = symbol->symbology;
1387 linear->input_mode = symbol->input_mode;
1388 linear->output_options = symbol->output_options;
1389 linear->show_hrt = symbol->show_hrt;
1390 linear->option_2 = symbol->option_2;
1391 linear->option_3 = symbol->option_3;
1392 /* If symbol->height given minimum row height will be returned, else default height */
1393 linear->height = symbol->height;
1394 linear->debug = symbol->debug;
1395
1396 if (linear->symbology != BARCODE_GS1_128_CC) {
1397 /* Set the "component linkage" flag in the linear component */
1398 linear->option_1 = 2;
1399 }
1400
1401 switch (symbol->symbology) {
1402 case BARCODE_EANX_CC:
1403 error_number = eanx_cc(linear, (unsigned char *) symbol->primary, pri_len, symbol->rows);
1404 break;
1405 case BARCODE_GS1_128_CC:
1406 /* GS1-128 needs to know which type of 2D component is used */
1407 error_number = gs1_128_cc(linear, (unsigned char *) symbol->primary, pri_len, cc_mode, symbol->rows);
1408 break;
1409 case BARCODE_DBAR_OMN_CC:
1410 error_number = dbar_omn_cc(linear, (unsigned char *) symbol->primary, pri_len, symbol->rows);
1411 break;
1412 case BARCODE_DBAR_LTD_CC:
1413 error_number = dbar_ltd_cc(linear, (unsigned char *) symbol->primary, pri_len, symbol->rows);
1414 break;
1415 case BARCODE_DBAR_EXP_CC:
1416 error_number = dbar_exp_cc(linear, (unsigned char *) symbol->primary, pri_len, symbol->rows);
1417 break;
1418 case BARCODE_UPCA_CC:
1419 error_number = eanx_cc(linear, (unsigned char *) symbol->primary, pri_len, symbol->rows);
1420 break;
1421 case BARCODE_UPCE_CC:
1422 error_number = eanx_cc(linear, (unsigned char *) symbol->primary, pri_len, symbol->rows);
1423 break;
1424 case BARCODE_DBAR_STK_CC:
1425 error_number = dbar_omn_cc(linear, (unsigned char *) symbol->primary, pri_len, symbol->rows);
1426 break;
1427 case BARCODE_DBAR_OMNSTK_CC:
1428 error_number = dbar_omn_cc(linear, (unsigned char *) symbol->primary, pri_len, symbol->rows);
1429 break;
1430 case BARCODE_DBAR_EXPSTK_CC:
1431 error_number = dbar_exp_cc(linear, (unsigned char *) symbol->primary, pri_len, symbol->rows);
1432 break;
1433 }
1434
1435 if (error_number) {
1436 errtxtf(0, symbol, -1, "%1$s%2$s", linear->errtxt, " (linear component)");
1437 if (error_number >= ZINT_ERROR) {
1438 ZBarcode_Delete(linear);
1439 return error_number;
1440 }
1441 }
1442
1443 /* Merge the linear component with the 2D component */
1444
1445 top_shift = 0;
1446 bottom_shift = 0;
1447
1448 switch (symbol->symbology) {
1449 /* Determine horizontal alignment (according to section 12.3) */
1450 case BARCODE_EANX_CC:
1451 switch (ustrlen(linear->text)) { /* Use zero-padded length */
1452 case 8: /* EAN-8 */
1453 case 11: /* EAN-8 + 2 */
1454 case 14: /* EAN-8 + 5 */
1455 if (cc_mode == 1) {
1456 bottom_shift = 3;
1457 } else {
1458 bottom_shift = 13;
1459 }
1460 break;
1461 case 13: /* EAN-13 */
1462 case 16: /* EAN-13 + 2 */
1463 case 19: /* EAN-13 + 5 */
1464 bottom_shift = 2;
1465 break;
1466 }
1467 break;
1468 case BARCODE_GS1_128_CC:
1469 if (cc_mode == 3) {
1470 bottom_shift = 7; /* ISO/IEC 24723:2010 12.3 f) */
1471 } else {
1472 /* ISO/IEC 24723:2010 12.3 g) "GS1-128 components linked to the right quiet zone of the CC-A or CC-B:
1473 the CC-A or CC-B component is aligned with the last space module of one of the rightmost symbol
1474 characters of the linear component. To calculate the target Code 128 symbol character position for
1475 alignment, number the positions from right to left (0 is the Stop character, 1 is the Check
1476 character, etc.), and then Position = (total number of Code 128 symbol characters – 9) div 2"
1477 */
1478 const int num_symbols = (linear_width - 2) / 11;
1479 const int position = (num_symbols - 9) / 2;
1480 /* Less 1 to align with last space module */
1481 int calc_shift = linear->width - position * 11 - 1 - symbol->width;
1482 if (position) {
1483 calc_shift -= 2; /* Less additional stop modules */
1484 }
1485 if (calc_shift > 0) {
1486 top_shift = calc_shift;
1487 } else if (calc_shift < 0) {
1488 bottom_shift = -calc_shift;
1489 }
1490 }
1491 break;
1492 case BARCODE_DBAR_OMN_CC: bottom_shift = 4;
1493 break;
1494 case BARCODE_DBAR_LTD_CC:
1495 if (cc_mode == 1) {
1496 top_shift = 1;
1497 } else {
1498 bottom_shift = 9;
1499 }
1500 break;
1501 case BARCODE_DBAR_EXP_CC:
1502 for (k = 1; !module_is_set(linear, 1, k - 1) && module_is_set(linear, 1, k); k++);
1503 top_shift = k;
1504 break;
1505 case BARCODE_UPCA_CC: bottom_shift = 2;
1506 break;
1507 case BARCODE_UPCE_CC: bottom_shift = 2;
1508 break;
1509 case BARCODE_DBAR_STK_CC: top_shift = 1;
1510 break;
1511 case BARCODE_DBAR_OMNSTK_CC: top_shift = 1;
1512 break;
1513 case BARCODE_DBAR_EXPSTK_CC:
1514 for (k = 1; !module_is_set(linear, 1, k - 1) && module_is_set(linear, 1, k); k++);
1515 top_shift = k;
1516 break;
1517 }
1518
1519 if (debug_print) {
1520 printf("Top shift: %d, Bottom shift: %d\n", top_shift, bottom_shift);
1521 }
1522
1523 if (top_shift != 0) {
1524 /* Move the 2D component of the symbol horizontally */
1525 for (i = 0; i <= symbol->rows; i++) {
1526 for (j = (symbol->width + top_shift); j >= top_shift; j--) {
1527 if (module_is_set(symbol, i, j - top_shift)) {
1528 set_module(symbol, i, j);
1529 } else {
1530 unset_module(symbol, i, j);
1531 }
1532 }
1533 for (j = 0; j < top_shift; j++) {
1534 unset_module(symbol, i, j);
1535 }
1536 }
1537 }
1538
1539 /* Merge linear and 2D components into one structure */
1540 for (i = 0; i <= linear->rows; i++) {
1541 symbol->row_height[symbol->rows + i] = linear->row_height[i];
1542 for (j = 0; j <= linear->width; j++) {
1543 if (module_is_set(linear, i, j)) {
1544 set_module(symbol, i + symbol->rows, j + bottom_shift);
1545 } else {
1546 unset_module(symbol, i + symbol->rows, j + bottom_shift);
1547 }
1548 }
1549 }
1550 if ((linear->width + bottom_shift) > symbol->width + top_shift) {
1551 symbol->width = linear->width + bottom_shift;
1552 } else if ((symbol->width + top_shift) > linear->width + bottom_shift) {
1553 symbol->width += top_shift;
1554 }
1555 symbol->rows += linear->rows;
1556 if (symbol->output_options & COMPLIANT_HEIGHT) {
1557 if (symbol->symbology == BARCODE_DBAR_STK_CC) {
1558 /* Databar Stacked needs special treatment due to asymmetric rows */
1559 error_number = dbar_omnstk_set_height(symbol, symbol->rows - linear->rows + 1 /*first_row*/);
1560 } else if (symbol->symbology == BARCODE_DBAR_EXP_CC || symbol->symbology == BARCODE_DBAR_EXPSTK_CC) {
1561 /* If symbol->height given then min row height was returned, else default height */
1562 if (error_number == 0) { /* Avoid overwriting any `gs1_verify()` warning */
1563 error_number = set_height(symbol, symbol->height ? linear->height : 0.0f,
1564 symbol->height ? 0.0f : linear->height, 0.0f, 0 /*no_errtxt*/);
1565 } else {
1566 (void) set_height(symbol, symbol->height ? linear->height : 0.0f,
1567 symbol->height ? 0.0f : linear->height, 0.0f, 1 /*no_errtxt*/);
1568 }
1569 } else {
1570 /* If symbol->height given then min row height was returned, else default height */
1571 error_number = set_height(symbol, symbol->height ? linear->height : 0.0f,
1572 symbol->height ? 0.0f : linear->height, 0.0f, 0 /*no_errtxt*/);
1573 }
1574 } else {
1575 if (symbol->symbology == BARCODE_DBAR_STK_CC) {
1576 (void) dbar_omnstk_set_height(symbol, symbol->rows - linear->rows + 1 /*first_row*/);
1577 } else {
1578 (void) set_height(symbol, symbol->height ? linear->height : 0.0f, symbol->height ? 0.0f : linear->height,
1579 0.0f, 1 /*no_errtxt*/);
1580 }
1581 }
1582
1583 ustrcpy(symbol->text, linear->text);
1584
1585 ZBarcode_Delete(linear);
1586
1587 return error_number;
1588 }
1589
1590 /* vim: set ts=4 sw=4 et : */