comparison mupdf-source/thirdparty/zint/backend/codablock.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 /* codablock.c - Handles Codablock-F */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2016-2024 Harald Oehlmann
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 #include <assert.h>
34 #include <math.h>
35 #include <stdio.h>
36 #include "common.h"
37 #include "code128.h"
38
39 #define uchar unsigned char
40
41 /* FTab C128 flags - may be added */
42 #define CodeA 1
43 #define CodeB 2
44 #define CodeC 4
45 #define CEnd 8
46 #define CShift 16
47 #define CFill 32
48 #define CodeFNC1 64
49 #define CodeFNC4 128
50 #define ZTNum (CodeA + CodeB + CodeC)
51 #define ZTFNC1 (CodeA + CodeB + CodeC + CodeFNC1)
52
53 /* ASCII-Extension for Codablock-F */
54 #define aFNC1 ((uchar) 128)
55 #define aFNC2 ((uchar) 129)
56 #define aFNC3 ((uchar) 130)
57 #define aFNC4 ((uchar) 131)
58 #define aCodeA ((uchar) 132)
59 #define aCodeB ((uchar) 133)
60 #define aCodeC ((uchar) 134)
61 #define aShift ((uchar) 135)
62
63 /* Code F Analysing-Chart */
64 typedef struct sCharacterSetTable {
65 int CharacterSet; /* Still possible character sets for actual*/
66 int AFollowing; /* Still following Characters in Charset A */
67 int BFollowing; /* Still following Characters in Charset B */
68 int CFollowing; /* Still following Characters in Charset C */
69 } CharacterSetTable;
70
71 /* Find the possible Code-128 Character sets for a character
72 * The result is an or of CodeA, CodeB, CodeC, CodeFNC1, CodeFNC4 depending on the
73 * possible Code 128 character sets.
74 */
75 static int GetPossibleCharacterSet(unsigned char C) {
76 if (C <= '\x1f') /* Control chars */
77 return CodeA;
78 if (z_isdigit(C))
79 return ZTNum; /* ZTNum=CodeA+CodeB+CodeC */
80 if (C == aFNC1) /* FNC1s (GS1) not used */
81 return ZTFNC1; /* ZTFNC1=CodeA+CodeB+CodeC+CodeFNC1 */ /* Not reached */
82 if (C == aFNC4)
83 return (CodeA | CodeB | CodeFNC4);
84 if (C >= '\x60' && C <= '\x7f') /* 60 to 127 */
85 return CodeB;
86 return CodeA + CodeB;
87 }
88
89 /* Create a Table with the following information for each Data character:
90 * int CharacterSet is an or of CodeA, CodeB, CodeC, CodeFNC1, CodeFNC4,
91 * depending on which character set is applicable.
92 * (Result of GetPossibleCharacterSet)
93 * int AFollowing,BFollowing The number of source characters you still may encode
94 * in this character set.
95 * int CFollowing The number of characters encodable in CodeC if we
96 * start here.
97 */
98 static void CreateCharacterSetTable(CharacterSetTable T[], unsigned char *data, const int dataLength) {
99 int charCur;
100 int runChar;
101
102 /* Treat the Data backwards */
103 charCur = dataLength - 1;
104 T[charCur].CharacterSet = GetPossibleCharacterSet(data[charCur]);
105 T[charCur].AFollowing = ((T[charCur].CharacterSet & CodeA) == 0) ? 0 : 1;
106 T[charCur].BFollowing = ((T[charCur].CharacterSet & CodeB) == 0) ? 0 : 1;
107 T[charCur].CFollowing = 0;
108
109 for (charCur--; charCur >= 0; charCur--) {
110 T[charCur].CharacterSet = GetPossibleCharacterSet(data[charCur]);
111 T[charCur].AFollowing = ((T[charCur].CharacterSet & CodeA) == 0) ? 0 : T[charCur + 1].AFollowing + 1;
112 T[charCur].BFollowing = ((T[charCur].CharacterSet & CodeB) == 0) ? 0 : T[charCur + 1].BFollowing + 1;
113 T[charCur].CFollowing = 0;
114 }
115 /* Find the CodeC-chains */
116 for (charCur = 0; charCur < dataLength; charCur++) {
117 T[charCur].CFollowing = 0;
118 if ((T[charCur].CharacterSet & CodeC) != 0) {
119 /* CodeC possible */
120 runChar = charCur;
121 do {
122 /* Whether this is FNC1, whether next is */
123 /* numeric */
124 if (T[runChar].CharacterSet == ZTFNC1) /* FNC1s (GS1) not used */
125 ++(T[charCur].CFollowing); /* Not reached */
126 else {
127 ++runChar;
128 if (runChar >= dataLength)
129 break;
130 /* Only a Number may follow */
131 if (T[runChar].CharacterSet == ZTNum)
132 T[charCur].CFollowing += 2;
133 else
134 break;
135 }
136 ++runChar;
137 } while (runChar < dataLength);
138 }
139 }
140 }
141
142 /* Find the amount of numerical characters in pairs which will fit in
143 * one bundle into the line (up to here). This is calculated online because
144 * it depends on the space in the line.
145 */
146 static int RemainingDigits(CharacterSetTable *T, int charCur, int emptyColumns) {
147 int digitCount; /* Numerical digits fitting in the line */
148 int runChar;
149 runChar = charCur;
150 digitCount = 0;
151 while (emptyColumns > 0 && runChar < charCur + T[charCur].CFollowing) {
152 if (T[runChar].CharacterSet != ZTFNC1) {
153 /* NOT FNC1 */
154 digitCount += 2;
155 runChar++;
156 }
157 runChar++;
158 emptyColumns--;
159 }
160 return digitCount;
161 }
162
163 /* Find the Character distribution at a given column count.
164 * If too many rows (>44) are requested the columns are extended.
165 * Parameters :
166 * T Pointer on the Characters which fit in the row
167 * If a different count is calculated it is corrected
168 * in the callers workspace.
169 * pFillings Output of filling characters
170 * pSet Output of the character sets used, allocated by me.
171 * Return value Resulting row count
172 */
173 static int Columns2Rows(struct zint_symbol *symbol, CharacterSetTable *T, const int dataLength, int *pRows,
174 int *pUseColumns, int *pSet, int *pFillings) {
175 int useColumns; /* Usable Characters per line */
176 int fillings = 0; /* Number of filling characters */
177 int rowsCur;
178 int runChar;
179 int emptyColumns; /* Number of codes still empty in line. */
180 int emptyColumns2; /* Alternative emptyColumns to compare */
181 int CPaires; /* Number of digit pairs which may fit in the line */
182 int characterSetCur; /* Current Character Set */
183 int isFNC4; /* Set if current character FNC4 */
184
185 useColumns = *pUseColumns;
186
187 /* >>> Loop until rowsCur <= 44 */
188 do {
189 int charCur = 0;
190 memset(pSet, 0, sizeof(int) * dataLength);
191 rowsCur = 0;
192
193 /* >>> Line Loop */
194 do {
195 /* >> Start Character */
196 emptyColumns = useColumns; /* Remained place in Line */
197
198 /* >>Choose in Set A or B */
199 /* (C is changed as an option later on) */
200
201 pSet[charCur] = characterSetCur = (T[charCur].AFollowing > T[charCur].BFollowing) ? CodeA : CodeB;
202
203 /* >> Test on Numeric Mode C */
204 CPaires = RemainingDigits(T, charCur, emptyColumns);
205 if (CPaires >= 4) {
206 /* 4 Digits in Numeric compression ->OK */
207 /* > May an odd start find more ? */
208 /* Skip leading <FNC1>'s */
209 /* Typical structure : <FNC1><FNC1>12... */
210 /* Test if numeric after one isn't better.*/
211 runChar = charCur;
212 emptyColumns2 = emptyColumns;
213 while (T[runChar].CharacterSet == ZTFNC1) { /* FNC1s (GS1) not used */
214 ++runChar; /* Not reached */
215 --emptyColumns2;
216 }
217 if (CPaires >= RemainingDigits(T, runChar + 1, emptyColumns2 - 1)) {
218 /* Start odd is not better */
219 /* We start in C */
220 pSet[charCur] = characterSetCur = CodeC;
221 /* Increment charCur */
222 if (T[charCur].CharacterSet != ZTFNC1)
223 ++charCur; /* 2 Num.Digits */
224 }
225 }
226 ++charCur;
227 --emptyColumns;
228
229 /* >> Following characters */
230 while (emptyColumns > 0 && charCur < dataLength) {
231 isFNC4 = (T[charCur].CharacterSet & CodeFNC4);
232 switch (characterSetCur) {
233 case CodeA:
234 case CodeB:
235 /* >> Check switching to CodeC */
236 /* Switch if :
237 * - Character not FNC1
238 * - 4 real Digits will fit in line
239 * - an odd Start will not be better
240 */
241 if (T[charCur].CharacterSet == ZTNum
242 && (CPaires = RemainingDigits(T, charCur, emptyColumns - 1)) >= 4
243 && CPaires > RemainingDigits(T, charCur + 1, emptyColumns - 2)) {
244 /* > Change to C */
245 pSet[charCur] = characterSetCur = CodeC;
246 charCur += 2; /* 2 Digit */
247 emptyColumns -= 2; /* <SwitchC>12 */
248 } else if (characterSetCur == CodeA) {
249 if (T[charCur].AFollowing == 0 || (isFNC4 && T[charCur].AFollowing == 1)) {
250 /* Must change to B */
251 if (emptyColumns == 1 || (isFNC4 && emptyColumns == 2)) {
252 /* Can't switch: */
253 pSet[charCur - 1] |= CEnd + CFill;
254 emptyColumns = 0;
255 } else {
256 /* <Shift> or <switchB>? */
257 if (T[charCur].BFollowing == 1 || (isFNC4 && T[charCur].BFollowing == 2)) {
258 /* Note using order "FNC4 shift char" (same as CODE128) not "shift FNC4 char"
259 as given in Table B.1 and Table B.2 */
260 if (isFNC4) { /* So skip FNC4 and shift value instead */
261 --emptyColumns;
262 ++charCur;
263 }
264 pSet[charCur] |= CShift;
265 } else {
266 pSet[charCur] |= CodeB;
267 characterSetCur = CodeB;
268 }
269 emptyColumns -= 2;
270 ++charCur;
271 }
272 } else if (isFNC4 && emptyColumns == 1) {
273 /* Can't fit extended ASCII on same line */
274 pSet[charCur - 1] |= CEnd + CFill;
275 emptyColumns = 0;
276 } else {
277 --emptyColumns;
278 ++charCur;
279 }
280 } else { /* Last possibility : CodeB */
281 if (T[charCur].BFollowing == 0 || (isFNC4 && T[charCur].BFollowing == 1)) {
282 /* Must change to A */
283 if (emptyColumns == 1 || (isFNC4 && emptyColumns == 2)) {
284 /* Can't switch: */
285 pSet[charCur - 1] |= CEnd + CFill;
286 emptyColumns = 0;
287 } else {
288 /* <Shift> or <switchA>? */
289 if (T[charCur].AFollowing == 1 || (isFNC4 && T[charCur].AFollowing == 2)) {
290 /* Note using order "FNC4 shift char" (same as CODE128) not "shift FNC4 char"
291 as given in Table B.1 and Table B.2 */
292 if (isFNC4) { /* So skip FNC4 and shift value instead */
293 --emptyColumns;
294 ++charCur;
295 }
296 pSet[charCur] |= CShift;
297 } else {
298 pSet[charCur] |= CodeA;
299 characterSetCur = CodeA;
300 }
301 emptyColumns -= 2;
302 ++charCur;
303 }
304 } else if (isFNC4 && emptyColumns == 1) {
305 /* Can't fit extended ASCII on same line */
306 pSet[charCur - 1] |= CEnd + CFill;
307 emptyColumns = 0;
308 } else {
309 --emptyColumns;
310 ++charCur;
311 }
312 }
313 break;
314 case CodeC:
315 if (T[charCur].CFollowing > 0) {
316 charCur += (T[charCur].CharacterSet == ZTFNC1) ? 1 : 2;
317 emptyColumns--;
318 } else {
319 /* Must change to A or B */
320 if (emptyColumns == 1 || (isFNC4 && emptyColumns == 2)) {
321 /* Can't switch: */
322 pSet[charCur - 1] |= CEnd + CFill;
323 emptyColumns = 0;
324 } else {
325 /*<SwitchA> or <switchA>?*/
326 characterSetCur = pSet[charCur]
327 = (T[charCur].AFollowing > T[charCur].BFollowing) ? CodeA : CodeB;
328 emptyColumns -= 2;
329 ++charCur;
330 }
331 }
332 break;
333 } /* switch */
334 } /* while */
335
336 /* > End of Codeline */
337 pSet[charCur - 1] |= CEnd;
338 ++rowsCur;
339 } while (charCur < dataLength); /* <= Data.Len-1 */
340
341 /* Allow for check characters K1, K2 */
342 switch (emptyColumns) {
343 case 1:
344 pSet[charCur - 1] |= CFill;
345 /* fall through */
346 case 0:
347 ++rowsCur;
348 fillings = useColumns - 2 + emptyColumns;
349 break;
350 case 2: fillings = 0; break;
351 default: pSet[charCur - 1] |= CFill; fillings = emptyColumns - 2;
352 }
353
354 if (rowsCur > 44) {
355 ++useColumns;
356 if (useColumns > 62) {
357 return ZINT_ERROR_TOO_LONG;
358 }
359 } else if (rowsCur == 1) {
360 rowsCur = 2;
361 fillings += useColumns;
362 }
363 } while (rowsCur > 44);
364 if (symbol->debug & ZINT_DEBUG_PRINT) {
365 printf(" -> out: rowsCur <%d>, useColumns <%d>, fillings <%d>\n", rowsCur, useColumns, fillings);
366 }
367 *pUseColumns = useColumns;
368 *pRows = rowsCur;
369 *pFillings = fillings;
370 return 0;
371 }
372
373 /* Find columns if row count is given.
374 */
375 static int Rows2Columns(struct zint_symbol *symbol, CharacterSetTable *T, const int dataLength, int *pRows,
376 int *pUseColumns, int *pSet, int *pFillings) {
377 int rowsCur;
378 int rowsRequested; /* Number of requested rows */
379 int columnsRequested; /* Number of requested columns (if any) */
380 int fillings;
381 int useColumns;
382 int testColumns; /* To enter into Width2Rows */
383 int testListSize = 0;
384 int pTestList[62 + 1];
385 int *pBackupSet = (int *) z_alloca(sizeof(int) * dataLength);
386
387 rowsRequested = *pRows;
388 columnsRequested = *pUseColumns >= 4 ? *pUseColumns : 0;
389
390 if (symbol->debug & ZINT_DEBUG_PRINT) {
391 printf("Optimizer : Searching <%d> rows\n", rowsRequested);
392 }
393
394 if (columnsRequested) {
395 testColumns = columnsRequested;
396 } else {
397 /* First guess */
398 testColumns = dataLength / rowsRequested;
399 if (testColumns > 62)
400 testColumns = 62;
401 else if (testColumns < 4)
402 testColumns = 4;
403 }
404
405 for (;;) {
406 int errorCur;
407 pTestList[testListSize] = testColumns;
408 testListSize++;
409 useColumns = testColumns; /* Make a copy because it may be modified */
410 errorCur = Columns2Rows(symbol, T, dataLength, &rowsCur, &useColumns, pSet, &fillings);
411 if (errorCur != 0)
412 return errorCur;
413 if (rowsCur <= rowsRequested) {
414 /* Less or exactly line number found */
415 /* check if column count below already tested or at smallest/requested */
416 int fInTestList = (rowsCur == 2 || testColumns == 4 || testColumns == columnsRequested);
417 int posCur;
418 for (posCur = 0; posCur < testListSize && !fInTestList; posCur++) {
419 if (pTestList[posCur] == testColumns - 1)
420 fInTestList = 1;
421 }
422 if (fInTestList) {
423 /* >> Smaller Width already tested
424 */
425 if (rowsCur < rowsRequested) {
426 fillings += useColumns * (rowsRequested - rowsCur);
427 rowsCur = rowsRequested;
428 }
429 /* Exit with actual */
430 *pFillings = fillings;
431 *pRows = rowsCur;
432 *pUseColumns = useColumns;
433 return 0;
434 }
435 /* > Test more rows (shorter CDB) */
436 memcpy(pBackupSet, pSet, sizeof(int) * dataLength);
437 --testColumns;
438 } else {
439 /* > Too many rows */
440 /* > Test less rows (longer code) */
441 memcpy(pBackupSet, pSet, sizeof(int) * dataLength);
442 if (++testColumns > 62) {
443 return ZINT_ERROR_TOO_LONG;
444 }
445 }
446 }
447 }
448
449 /* Print a character in character set A
450 */
451 static void A2C128_A(uchar **ppOutPos, uchar c) {
452 uchar *pOutPos = *ppOutPos;
453 switch (c) {
454 case aCodeB: *pOutPos = 100; break;
455 case aFNC4: *pOutPos = 101; break;
456 case aFNC1: *pOutPos = 102; break; /* FNC1s (GS1) not used */ /* Not reached */
457 case aFNC2: *pOutPos = 97; break; /* FNC2s (Message Append) not used */ /* Not reached */
458 case aFNC3: *pOutPos = 96; break;
459 case aCodeC: *pOutPos = 99; break;
460 case aShift: *pOutPos = 98; break;
461 default:
462 /* +++ HaO 13.11.98 c>' ' && c < '\x1F' corrected */
463 if (c >= ' ' && c <= '_')
464 *pOutPos = (uchar) (c - ' ');
465 else
466 *pOutPos = (uchar) (c + 64);
467 break;
468 }
469 (*ppOutPos)++;
470 }
471
472 /* Output c in Set B
473 */
474 static void A2C128_B(uchar **ppOutPos, uchar c) {
475 uchar *pOutPos = *ppOutPos;
476 switch (c) {
477 case aFNC1: *pOutPos = 102; break; /* FNC1s (GS1) not used */ /* Not reached */
478 case aFNC2: *pOutPos = 97; break; /* FNC2s (Message Append) not used */ /* Not reached */
479 case aFNC3: *pOutPos = 96; break;
480 case aFNC4: *pOutPos = 100; break;
481 case aCodeA: *pOutPos = 101; break;
482 case aCodeC: *pOutPos = 99; break;
483 case aShift: *pOutPos = 98; break;
484 default: *pOutPos = (uchar) (c - ' '); break;
485 }
486 ++(*ppOutPos);
487 }
488
489 /* Output c1, c2 in Set C
490 */
491 static void A2C128_C(uchar **ppOutPos, uchar c1, uchar c2) {
492 uchar *pOutPos = *ppOutPos;
493 switch (c1) {
494 case aFNC1: *pOutPos = 102; break; /* FNC1s (GS1) not used */ /* Not reached */
495 case aCodeB: *pOutPos = 100; break;
496 case aCodeA: *pOutPos = 101; break;
497 default: *pOutPos = (uchar) (10 * (c1 - '0') + (c2 - '0')); break;
498 }
499 (*ppOutPos)++;
500 }
501
502 /* Output a character in Characterset
503 */
504 static void ASCIIZ128(uchar **ppOutPos, int CharacterSet, uchar c1, uchar c2) {
505 if (CharacterSet == CodeA)
506 A2C128_A(ppOutPos, c1);
507 else if (CharacterSet == CodeB)
508 A2C128_B(ppOutPos, c1);
509 else
510 A2C128_C(ppOutPos, c1, c2);
511 }
512
513 /* XLate Tables D.2, D.3 and F.1 of Codablock-F Specification and call output
514 */
515 static void SumASCII(uchar **ppOutPos, int Sum, int CharacterSet) {
516 switch (CharacterSet) {
517 case CodeA: /* Row # Indicators and Data Check Characters K1/K2 for CodeA and CodeB are the same */
518 case CodeB:
519 if (Sum <= 31)
520 A2C128_B(ppOutPos, (uchar) (Sum + 96));
521 else if (Sum <= 47)
522 A2C128_B(ppOutPos, (uchar) Sum);
523 else
524 A2C128_B(ppOutPos, (uchar) (Sum + 10));
525 break;
526 case CodeC:
527 A2C128_C(ppOutPos, (uchar) (Sum / 10 + '0'), (uchar) (Sum % 10 + '0'));
528 break;
529 }
530 }
531
532 /* Main function called by zint framework
533 */
534 INTERNAL int codablockf(struct zint_symbol *symbol, unsigned char source[], int length) {
535 int charCur, dataLength;
536 int error_number;
537 int rows, columns, useColumns;
538 int fillings;
539 int Sum1, Sum2;
540 uchar *pOutPos;
541 int rowCur;
542 int characterSetCur;
543 int emptyColumns;
544 char dest[1000];
545 int r, c;
546 CharacterSetTable *T;
547 unsigned char *data;
548 int *pSet;
549 uchar *pOutput;
550
551 /* Suppresses clang-analyzer-core.VLASize warning */
552 assert(length > 0);
553
554 /* Parameter check */
555 /* option1: rows <= 0: automatic, 1..44 */
556 rows = symbol->option_1;
557 if (rows == 1) {
558 error_number = code128(symbol, source, length);
559 if (error_number < ZINT_ERROR) {
560 symbol->output_options |= BARCODE_BIND;
561 if (symbol->border_width == 0) { /* Allow override if non-zero */
562 symbol->border_width = 1; /* AIM ISS-X-24 Section 4.6.1 b) (note change from previous default 2) */
563 }
564 symbol->text[0] = '\0'; /* Disable HRT for compatibility with CODABLOCKF */
565 if (symbol->output_options & COMPLIANT_HEIGHT) {
566 /* AIM ISS-X-24 Section 4.6.1 minimum row height 8X (for compatibility with CODABLOCKF, not specced
567 for CODE128) */
568 if (error_number == 0) {
569 error_number = set_height(symbol, 8.0f, 10.0f, 0.0f, 0 /*no_errtxt*/);
570 } else {
571 (void) set_height(symbol, 8.0f, 10.0f, 0.0f, 1 /*no_errtxt*/);
572 }
573 } else {
574 (void) set_height(symbol, 0.0f, 5.0f, 0.0f, 1 /*no_errtxt*/);
575 }
576 }
577 return error_number;
578 }
579 if (rows > 44) {
580 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 410, "Number of rows '%d' out of range (0 to 44)", rows);
581 }
582 /* option_2: (usable data) columns: <= 0: automatic, 9..67 (min 9 == 4 data, max 67 == 62 data) */
583 columns = symbol->option_2;
584 if (!(columns <= 0 || (columns >= 9 && columns <= 67))) {
585 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 411, "Number of columns '%d' out of range (9 to 67)",
586 columns);
587 }
588 if (columns < 0) { /* Protect against negative overflow (ticket #300 (#9) Andre Maute) */
589 columns = 0;
590 }
591
592 data = (unsigned char *) z_alloca(length * 2 + 1);
593
594 dataLength = 0;
595 if (symbol->output_options & READER_INIT) {
596 data[dataLength] = aFNC3;
597 dataLength++;
598 }
599 /* Replace all Codes>127 with <fnc4>Code-128 */
600 for (charCur = 0; charCur < length; charCur++) {
601 if (source[charCur] > 127) {
602 data[dataLength] = aFNC4;
603 dataLength++;
604 data[dataLength] = (unsigned char) (source[charCur] & 127);
605 } else
606 data[dataLength] = source[charCur];
607 dataLength++;
608 }
609
610 /* Build character set table */
611 T = (CharacterSetTable *) z_alloca(sizeof(CharacterSetTable) * dataLength);
612 pSet = (int *) z_alloca(sizeof(int) * dataLength);
613 CreateCharacterSetTable(T, data, dataLength);
614
615 /* Find final row and column count */
616 /* nor row nor column count given */
617 if (rows <= 0 && columns <= 0) {
618 /* use 1/1 aspect/ratio Codablock */
619 columns = (int) floor(sqrt(dataLength)) + 5;
620 if (columns > 67) {
621 columns = 67;
622 } else if (columns < 9) {
623 columns = 9;
624 }
625 if (symbol->debug & ZINT_DEBUG_PRINT) {
626 printf("Auto column count for %d characters:%d\n", dataLength, columns);
627 }
628 }
629 /* There are 5 Codewords for Organisation Start(2),row(1),CheckSum,Stop */
630 useColumns = columns - 5;
631 if (rows > 0) {
632 /* row count given */
633 error_number = Rows2Columns(symbol, T, dataLength, &rows, &useColumns, pSet, &fillings);
634 } else {
635 /* column count given */
636 error_number = Columns2Rows(symbol, T, dataLength, &rows, &useColumns, pSet, &fillings);
637 }
638 if (error_number != 0) {
639 return errtxt(error_number, symbol, 413,
640 "Input too long, requires too many symbol characters (maximum 2726)");
641 }
642 /* Suppresses clang-analyzer-core.VLASize warning */
643 assert(rows >= 2 && useColumns >= 4);
644
645 /* Data Check Characters K1 and K2, Annex F */
646 Sum1 = Sum2 = 0;
647 for (charCur = 0; charCur < length; charCur++) {
648 Sum1 = (Sum1 + (charCur + 1) * source[charCur]) % 86; /* Mod as we go along to avoid overflow */
649 Sum2 = (Sum2 + charCur * source[charCur]) % 86;
650 }
651
652 if (symbol->debug & ZINT_DEBUG_PRINT) { /* start a new level of local variables */
653 int DPos;
654 fputs("\nData:", stdout);
655 for (DPos = 0; DPos < dataLength; DPos++)
656 fputc(data[DPos], stdout);
657 fputs("\n Set:", stdout);
658 for (DPos = 0; DPos < dataLength; DPos++) {
659 switch (pSet[DPos] & (CodeA + CodeB + CodeC)) {
660 case CodeA: fputc('A', stdout); break;
661 case CodeB: fputc('B', stdout); break;
662 case CodeC: fputc('C', stdout); break;
663 default: fputc('.', stdout); break;
664 }
665 }
666 fputs("\nFNC1:", stdout);
667 for (DPos = 0; DPos < dataLength; DPos++)
668 fputc((pSet[DPos] & CodeFNC1) == 0 ? '.' : 'X', stdout);
669 fputs("\n END:", stdout);
670 for (DPos = 0; DPos < dataLength; DPos++)
671 fputc((pSet[DPos] & CEnd) == 0 ? '.' : 'X', stdout);
672 fputs("\nShif:", stdout);
673 for (DPos = 0; DPos < dataLength; DPos++)
674 fputc((pSet[DPos] & CShift) == 0 ? '.' : 'X', stdout);
675 fputs("\nFILL:", stdout);
676 for (DPos = 0; DPos < dataLength; DPos++)
677 fputc((pSet[DPos] & CFill) == 0 ? '.' : 'X', stdout);
678 fputc('\n', stdout);
679 printf("K1 %d, K2 %d\n", Sum1, Sum2);
680 }
681
682 columns = useColumns + 5;
683
684 /* >>> Build C128 code numbers */
685 /* The C128 column count contains Start (2CW), Row ID, Checksum, Stop */
686 pOutput = (unsigned char *) z_alloca(columns * rows);
687 pOutPos = pOutput;
688 charCur = 0;
689 /* >> Loop over rows */
690 for (rowCur = 0; rowCur < rows; rowCur++) {
691 if (charCur >= dataLength) {
692 /* >> Empty line with StartA, aCodeB, row #, and then filler aCodeC aCodeB etc */
693 *pOutPos = '\x67';
694 pOutPos++;
695 *pOutPos = 100; /* aCodeB */
696 pOutPos++;
697 characterSetCur = CodeB;
698 SumASCII(&pOutPos, rowCur + 42, characterSetCur); /* Row # */
699 emptyColumns = useColumns;
700 if (rowCur == rows - 1) {
701 emptyColumns -= 2;
702 }
703 while (emptyColumns > 0) {
704 if (characterSetCur == CodeC) {
705 A2C128_C(&pOutPos, aCodeB, '\0');
706 characterSetCur = CodeB;
707 } else {
708 A2C128_B(&pOutPos, aCodeC);
709 characterSetCur = CodeC;
710 }
711 --emptyColumns;
712 }
713 } else {
714 /* >> Normal Line */
715 /* > Startcode */
716 switch (pSet[charCur] & (CodeA + CodeB + CodeC)) {
717 case CodeA:
718 *pOutPos = '\x67';
719 pOutPos++;
720 *pOutPos = '\x62';
721 pOutPos++;
722 characterSetCur = CodeA;
723 break;
724 case CodeB:
725 *pOutPos = '\x67';
726 pOutPos++;
727 *pOutPos = '\x64';
728 pOutPos++;
729 characterSetCur = CodeB;
730 break;
731 case CodeC:
732 default:
733 *pOutPos = '\x67';
734 pOutPos++;
735 *pOutPos = '\x63';
736 pOutPos++;
737 characterSetCur = CodeC;
738 break;
739 }
740 /* > Set F1 */
741 /* In first line : # of rows */
742 SumASCII(&pOutPos, rowCur == 0 ? rows - 2 : rowCur + 42, characterSetCur);
743 /* >>> Data */
744 emptyColumns = useColumns;
745 /* >> Character loop */
746 while (emptyColumns > 0 && charCur < dataLength) {
747 /* ? Change character set */
748 if (emptyColumns < useColumns) {
749 if ((pSet[charCur] & CodeA) != 0) {
750 /* Change to A */
751 ASCIIZ128(&pOutPos, characterSetCur, aCodeA, '\0');
752 --emptyColumns;
753 characterSetCur = CodeA;
754 } else if ((pSet[charCur] & CodeB) != 0) {
755 /* Change to B */
756 ASCIIZ128(&pOutPos, characterSetCur, aCodeB, '\0');
757 --emptyColumns;
758 characterSetCur = CodeB;
759 } else if ((pSet[charCur] & CodeC) != 0) {
760 /* Change to C */
761 ASCIIZ128(&pOutPos, characterSetCur, aCodeC, '\0');
762 --emptyColumns;
763 characterSetCur = CodeC;
764 }
765 }
766 if ((pSet[charCur] & CShift) != 0) {
767 /* >> Shift it and put out the shifted character */
768 ASCIIZ128(&pOutPos, characterSetCur, aShift, '\0');
769 emptyColumns -= 2;
770 characterSetCur = (characterSetCur == CodeB) ? CodeA : CodeB;
771 ASCIIZ128(&pOutPos, characterSetCur, data[charCur], '\0');
772 characterSetCur = (characterSetCur == CodeB) ? CodeA : CodeB;
773 } else {
774 /* Normal Character */
775 if (characterSetCur == CodeC) {
776 if (data[charCur] == aFNC1) /* FNC1s (GS1) not used */
777 A2C128_C(&pOutPos, aFNC1, '\0'); /* Not reached */
778 else {
779 A2C128_C(&pOutPos, data[charCur],
780 (uchar) (charCur + 1 < dataLength ? data[charCur + 1] : 0));
781 ++charCur;
782 /* We need this here to get the good index */
783 /* for the termination flags in Set. */
784 }
785 } else
786 ASCIIZ128(&pOutPos, characterSetCur, data[charCur], '\0');
787 --emptyColumns;
788 }
789 /* >> End Criteria */
790 if ((pSet[charCur] & CFill) || (pSet[charCur] & CEnd)) {
791 /* Fill Line but leave space for checks in last line */
792 if (rowCur == rows - 1) {
793 emptyColumns -= 2;
794 }
795 while (emptyColumns > 0) {
796 switch (characterSetCur) {
797 case CodeC:
798 A2C128_C(&pOutPos, aCodeB, '\0');
799 characterSetCur = CodeB;
800 break;
801 case CodeB:
802 A2C128_B(&pOutPos, aCodeC);
803 characterSetCur = CodeC;
804 break;
805 case CodeA:
806 A2C128_A(&pOutPos, aCodeC);
807 characterSetCur = CodeC;
808 break;
809 }
810 --emptyColumns;
811 }
812 }
813 ++charCur;
814 } /* Loop over characters */
815 } /* if filling-Line / normal */
816
817 /* Add checksum in last line */
818 if (rowCur == rows - 1) {
819 SumASCII(&pOutPos, Sum1, characterSetCur);
820 SumASCII(&pOutPos, Sum2, characterSetCur);
821 }
822 /* Add Code 128 checksum */
823 {
824 int Sum = pOutput[columns * rowCur] % 103;
825 int Pos = 1;
826 for (; Pos < useColumns + 3; Pos++) {
827 Sum = (Sum + pOutput[columns * rowCur + Pos] * Pos) % 103;
828 }
829 *pOutPos = (uchar) Sum;
830 pOutPos++;
831 }
832 /* Add end character */
833 *pOutPos = 106;
834 pOutPos++;
835 } /* End Lineloop */
836
837 if (symbol->debug & ZINT_DEBUG_PRINT) {
838 /* Dump the output to the screen
839 */
840 fputs("\nCode 128 Code Numbers:\n", stdout);
841 { /* start a new level of local variables */
842 int DPos, DPos2;
843 for (DPos = 0; DPos < rows; DPos++) {
844 for (DPos2 = 0; DPos2 < columns; DPos2++) {
845 printf("%3d ", (int) (pOutput[DPos * columns + DPos2]));
846 }
847 fputc('\n', stdout);
848 }
849 }
850 printf("rows=%d columns=%d (%d data) fillings=%d\n", rows, columns, columns - 5, fillings);
851 }
852 #ifdef ZINT_TEST
853 if (symbol->debug & ZINT_DEBUG_TEST) {
854 debug_test_codeword_dump(symbol, pOutput, rows * columns);
855 }
856 #endif
857
858 /* Paint the C128 patterns */
859 for (r = 0; r < rows; r++) {
860 const int rc = r * columns;
861 char *d = dest;
862 for (c = 0; c < columns - 1; c++, d += 6) {
863 memcpy(d, C128Table[pOutput[rc + c]], 6);
864 }
865 memcpy(d, "2331112", 7); /* Stop character (106, not in C128Table) */
866 d += 7;
867 expand(symbol, dest, d - dest);
868 }
869
870 if (symbol->output_options & COMPLIANT_HEIGHT) {
871 /* AIM ISS-X-24 Section 4.6.1 minimum row height; use 10 * rows as default */
872 float min_row_height = stripf(0.55f * useColumns + 3.0f);
873 if (min_row_height < 8.0f) {
874 min_row_height = 8.0f;
875 }
876 error_number = set_height(symbol, min_row_height, (min_row_height > 10.0f ? min_row_height : 10.0f) * rows,
877 0.0f, 0 /*no_errtxt*/);
878 } else {
879 (void) set_height(symbol, 0.0f, 10.0f * rows, 0.0f, 1 /*no_errtxt*/);
880 }
881
882 symbol->output_options |= BARCODE_BIND;
883
884 if (symbol->border_width == 0) { /* Allow override if non-zero */
885 symbol->border_width = 1; /* AIM ISS-X-24 Section 4.6.1 b) (note change from previous default 2) */
886 }
887
888 return error_number;
889 }
890
891 /* vim: set ts=4 sw=4 et : */