comparison mupdf-source/thirdparty/zint/backend/pdf417.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 /* pdf417.c - Handles PDF417 stacked symbology */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2008-2024 Robin Stuart <rstuart114@gmail.com>
5 Portions Copyright (C) 2004 Grandzebu
6 Bug Fixes thanks to KL Chin <klchin@users.sourceforge.net>
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17 3. Neither the name of the project nor the names of its contributors
18 may be used to endorse or promote products derived from this software
19 without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 SUCH DAMAGE.
32 */
33 /* SPDX-License-Identifier: BSD-3-Clause */
34
35 /* This code is adapted from "Code barre PDF 417 / PDF 417 barcode" v2.5.0
36 which is Copyright (C) 2004 (Grandzebu).
37 The original code (file pdf417.frm) can be downloaded from https://grandzebu.net/informatique/codbar/pdf417.zip */
38
39 /* NOTE: symbol->option_1 is used to specify the security level (i.e. control the
40 number of check codewords)
41
42 symbol->option_2 is used to adjust the width of the resulting symbol (i.e. the
43 number of codeword columns not including row start and end data)
44
45 symbol->option_3 is used to adjust the rows of the resulting symbol */
46
47 #include <assert.h>
48 #include <limits.h>
49 #include <math.h>
50 #include <stdio.h>
51 #include "common.h"
52 #include "pdf417.h"
53 #include "pdf417_tabs.h"
54
55 /* Modes */
56 #define PDF_ALP 1 /* Treating TEX sub-modes as pseudo-modes (minimal encode) */
57 #define PDF_LOW 2
58 #define PDF_MIX 3
59 #define PDF_PNC 4
60 #define PDF_TEX 4 /* Real modes */
61 #define PDF_BYT 5
62 #define PDF_NUM 6
63
64 #define PDF_NUM_MODES 6
65
66 /* Mode indicators including TEX pseudo-modes */
67 static const char pdf_smodes[] = { '?', 'A', 'L', 'M', 'P', 'B', 'N' };
68
69 /* Return (real) mode text */
70 static const char *pdf_mode_str(const int mode) {
71 static const char modes[3][7] = { "Text", "Byte", "Number" };
72 return mode >= PDF_TEX && mode <= PDF_NUM ? modes[mode - PDF_TEX] : "ERROR";
73 }
74
75 #define PDF_REAL_MODE(m) ((m) <= PDF_TEX ? PDF_TEX : (m))
76
77 /* TEX mode OR-able sub-modes (tables) */
78 #define T_ALPHA 1
79 #define T_LOWER 2
80 #define T_MIXED 4
81 #define T_PUNCT 8
82
83 #define T_ALWMX (T_ALPHA | T_LOWER | T_MIXED)
84 #define T_MXPNC (T_MIXED | T_PUNCT)
85
86 #define PDF_TABLE_TO_MODE(t) (((t) >> 1) + !!((t) & 0x07)) /* Hack to map 1,2,4,8 to 1,2,3,4 */
87
88 /*
89 Three figure numbers in comments give the location of command equivalents in the
90 original Visual Basic source code file pdf417.frm
91 this code retains some original (French) procedure and variable names to ease conversion */
92
93 /* text mode processing tables */
94
95 /* TEX sub-mode assignments */
96 static const char pdf_asciix[256] = {
97 0, 0, 0, 0, 0, 0, 0, 0, /* 00-07 */
98 0, T_MXPNC, T_PUNCT, 0, 0, T_MXPNC, 0, 0, /* 08-0F .<HT><LF>..<CR>.. */
99 0, 0, 0, 0, 0, 0, 0, 0, /* 10-17 */
100 0, 0, 0, 0, 0, 0, 0, 0, /* 18-1F */
101 T_ALWMX, T_PUNCT, T_PUNCT, T_MIXED, T_MXPNC, T_MIXED, T_MIXED, T_PUNCT, /* 20-27 <SP>!"#$%&' */
102 T_PUNCT, T_PUNCT, T_MXPNC, T_MIXED, T_MXPNC, T_MXPNC, T_MXPNC, T_MXPNC, /* 28-2F ()*+,-./ */
103 T_MIXED, T_MIXED, T_MIXED, T_MIXED, T_MIXED, T_MIXED, T_MIXED, T_MIXED, /* 30-37 01234567 */
104 T_MIXED, T_MIXED, T_MXPNC, T_PUNCT, T_PUNCT, T_MIXED, T_PUNCT, T_PUNCT, /* 38-3F 89:;<=>? */
105 T_PUNCT, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, /* 40-47 @ABCDEFG */
106 T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, /* 48-4F HIJKLMNO */
107 T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, /* 50-57 PQRSTUVW */
108 T_ALPHA, T_ALPHA, T_ALPHA, T_PUNCT, T_PUNCT, T_PUNCT, T_MIXED, T_PUNCT, /* 58-5F XYZ[\]^_ */
109 T_PUNCT, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, /* 60-67 `abcdefg */
110 T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, /* 68-6F hijklmno */
111 T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, /* 70-77 pqrstuvw */
112 T_LOWER, T_LOWER, T_LOWER, T_PUNCT, T_PUNCT, T_PUNCT, T_PUNCT, 0, /* 78-7E xyz{|}~D */
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80-9F*/
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*A0-BF*/
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*C0-DF*/
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*E0-FF*/
117 };
118
119 /* TEX sub-mode values */
120 static const char pdf_asciiy[127] = {
121 0, 0, 0, 0, 0, 0, 0, 0, /* 00-07 */
122 0, 12, 15, 0, 0, 11, 0, 0, /* 08-0F */
123 0, 0, 0, 0, 0, 0, 0, 0, /* 10-17 */
124 0, 0, 0, 0, 0, 0, 0, 0, /* 18-1F */
125 26, 10, 20, 15, 18, 21, 10, 28, /* 20-27 */
126 23, 24, 22, 20, 13, 16, 17, 19, /* 28-2F */
127 0, 1, 2, 3, 4, 5, 6, 7, /* 30-37 */
128 8, 9, 14, 0, 1, 23, 2, 25, /* 38-3F */
129 3, 0, 1, 2, 3, 4, 5, 6, /* 40-47 */
130 7, 8, 9, 10, 11, 12, 13, 14, /* 48-4F */
131 15, 16, 17, 18, 19, 20, 21, 22, /* 50-57 */
132 23, 24, 25, 4, 5, 6, 24, 7, /* 58-5F */
133 8, 0, 1, 2, 3, 4, 5, 6, /* 60-67 */
134 7, 8, 9, 10, 11, 12, 13, 14, /* 68-6F */
135 15, 16, 17, 18, 19, 20, 21, 22, /* 70-77 */
136 23, 24, 25, 26, 21, 27, 9 /* 78-7F */
137 };
138
139 /* Automatic sizing table */
140
141 static const char pdf_MicroAutosize[56] = {
142 4, 6, 7, 8, 10, 12, 13, 14, 16, 18, 19, 20, 24, 29, 30, 33, 34, 37, 39, 46, 54, 58, 70, 72, 82, 90, 108, 126,
143 1, 14, 2, 7, 3, 25, 8, 16, 5, 17, 9, 6, 10, 11, 28, 12, 19, 13, 29, 20, 30, 21, 22, 31, 23, 32, 33, 34
144 };
145
146 /* ISO/IEC 15438:2015 5.1.1 c) 3) Max possible number of characters at error correction level 0
147 (Numeric Compaction mode) */
148 #define PDF_MAX_LEN 2710
149 #define PDF_MAX_LEN_S "2710" /* String version of above */
150 #define PDF_MAX_STREAM_LEN (PDF_MAX_LEN * 3) /* Allow for tripling up due to shifts/latches (ticket #300 (#7)) */
151
152 /* ISO/IEC 24728:2006 5.1.1 c) 3) Max possible number of characters (Numeric Compaction mode) */
153 #define MICRO_PDF_MAX_LEN 366
154 #define MICRO_PDF_MAX_LEN_S "366" /* String version of above */
155
156 /* 866 */
157 /* Initial non-compressed categorization of input */
158 static int pdf_quelmode(const unsigned char codeascii) {
159 if (z_isdigit(codeascii)) {
160 return PDF_NUM;
161 }
162 if (pdf_asciix[codeascii]) {
163 return PDF_TEX;
164 }
165 /* 876 */
166
167 return PDF_BYT;
168 }
169
170 /* Helper to switch TEX mode sub-mode */
171 static int pdf_textprocess_switch(const int curtable, const int newtable, unsigned char chainet[PDF_MAX_STREAM_LEN],
172 int wnet) {
173 switch (curtable) {
174 case T_ALPHA:
175 switch (newtable) {
176 case T_LOWER: chainet[wnet++] = 27; /* LL */
177 break;
178 case T_MIXED: chainet[wnet++] = 28; /* ML */
179 break;
180 case T_PUNCT: chainet[wnet++] = 28; /* ML+PL */
181 chainet[wnet++] = 25;
182 break;
183 }
184 break;
185 case T_LOWER:
186 switch (newtable) {
187 case T_ALPHA: chainet[wnet++] = 28; /* ML+AL */
188 chainet[wnet++] = 28;
189 break;
190 case T_MIXED: chainet[wnet++] = 28; /* ML */
191 break;
192 case T_PUNCT: chainet[wnet++] = 28; /* ML+PL */
193 chainet[wnet++] = 25;
194 break;
195 }
196 break;
197 case T_MIXED:
198 switch (newtable) {
199 case T_ALPHA: chainet[wnet++] = 28; /* AL */
200 break;
201 case T_LOWER: chainet[wnet++] = 27; /* LL */
202 break;
203 case T_PUNCT: chainet[wnet++] = 25; /* PL */
204 break;
205 }
206 break;
207 case T_PUNCT:
208 switch (newtable) {
209 case T_ALPHA: chainet[wnet++] = 29; /* AL */
210 break;
211 case T_LOWER: chainet[wnet++] = 29; /* AL+LL */
212 chainet[wnet++] = 27;
213 break;
214 case T_MIXED: chainet[wnet++] = 29; /* AL+ML */
215 chainet[wnet++] = 28;
216 break;
217 }
218 break;
219 }
220
221 return wnet;
222 }
223
224 /* Check consecutive segments for text/num and return the length */
225 static int pdf_text_num_length(short liste[3][PDF_MAX_LEN], const int indexliste, const int start) {
226 int i, len = 0;
227 for (i = start; i < indexliste; i++) {
228 if (liste[1][i] == PDF_BYT)
229 break;
230
231 len += liste[0][i];
232 if (len >= 5) /* we don't care if it's longer than 5 */
233 break;
234 }
235
236 return len;
237 }
238
239 /* Calculate length of TEX allowing for sub-mode switches (no-output version of `pdf_textprocess()`) */
240 static int pdf_text_submode_length(const unsigned char chaine[], const int start, const int length, int *p_curtable) {
241 int j, indexlistet, curtable = *p_curtable, listet[PDF_MAX_LEN], wnet = 0;
242 unsigned char chainet[PDF_MAX_STREAM_LEN];
243
244 for (indexlistet = 0; indexlistet < length; indexlistet++) {
245 assert(pdf_asciix[chaine[start + indexlistet]]); /* Should only be dealing with TEX */
246 listet[indexlistet] = pdf_asciix[chaine[start + indexlistet]];
247 }
248
249 for (j = 0; j < length; j++) {
250 if (listet[j] & curtable) {
251 /* The character is in the current table */
252 wnet++;
253 } else {
254 /* Obliged to change table */
255 int newtable;
256 if (j == (length - 1) || !(listet[j] & listet[j + 1])) {
257 /* we change only one character - look for temporary switch */
258 if ((listet[j] & T_ALPHA) && (curtable == T_LOWER)) {
259 wnet += 2; /* AS+char */
260 continue;
261 }
262 if (listet[j] & T_PUNCT) { /* (T_PUNCT and T_ALPHA not both possible) */
263 wnet += 2; /* PS+char */
264 continue;
265 }
266 /* No temporary switch available */
267 newtable = listet[j];
268 } else {
269 newtable = listet[j] & listet[j + 1];
270 }
271
272 /* 599 */
273
274 /* Maintain the first if several tables are possible */
275 if (newtable == T_ALWMX) { /* (T_ALPHA | T_LOWER | T_MIXED) */
276 newtable = T_ALPHA;
277 } else if (newtable == T_MXPNC) { /* (T_MIXED | T_PUNCT) */
278 newtable = T_MIXED;
279 }
280
281 /* 619 - select the switch */
282 wnet = pdf_textprocess_switch(curtable, newtable, chainet, wnet);
283 curtable = newtable;
284 /* 659 - at last we add the character */
285 wnet++;
286 }
287 }
288
289 *p_curtable = curtable;
290
291 return wnet;
292 }
293
294 /* Whether to stay in numeric mode or not */
295 static int pdf_num_stay(const unsigned char *chaine, const int indexliste, short liste[3][PDF_MAX_LEN], const int i) {
296 int curtable, not_tex, last_len, last_ml, next_len, num_cws, tex_cws;
297
298 if (liste[0][i] >= 13 || (indexliste == 1 && liste[0][i] > 5)) {
299 return 1;
300 }
301 if (liste[0][i] < 11) {
302 return 0;
303 }
304
305 curtable = T_ALPHA;
306 not_tex = i == 0 || liste[1][i - 1] == PDF_BYT;
307 last_len = not_tex ? 0 : pdf_text_submode_length(chaine, liste[2][i - 1], liste[0][i - 1], &curtable);
308 last_ml = curtable == T_MIXED;
309
310 curtable = T_ALPHA; /* Next len if after NUM, sub-mode will be alpha */
311 not_tex = i == indexliste - 1 || liste[1][i + 1] == PDF_BYT;
312 next_len = not_tex ? 0 : pdf_text_submode_length(chaine, liste[2][i + 1], liste[0][i + 1], &curtable);
313 num_cws = ((last_len + 1) >> 1) + 1 + 4 + (liste[0][i] > 11) + 1 + ((next_len + 1) >> 1);
314
315 curtable = T_MIXED; /* Next len if stay TEX, sub-mode will be mixed */
316 next_len = not_tex ? 0 : pdf_text_submode_length(chaine, liste[2][i + 1], liste[0][i + 1], &curtable);
317 tex_cws = (last_len + !last_ml + liste[0][i] + next_len + 1) >> 1;
318
319 if (num_cws > tex_cws) {
320 return 0;
321 }
322 return 1;
323 }
324
325 /* Pack segments using the method described in Appendix D of the AIM specification (ISO/IEC 15438:2015 Annex N) */
326 static void pdf_appendix_d_encode(const unsigned char *chaine, short liste[3][PDF_MAX_LEN], int *p_indexliste) {
327 const int indexliste = *p_indexliste;
328 int i = 0, next, last = 0, stayintext = 0;
329
330 while (i < indexliste) {
331
332 if ((liste[1][i] == PDF_NUM) && pdf_num_stay(chaine, indexliste, liste, i)) {
333 /* leave as numeric */
334 liste[0][last] = liste[0][i];
335 liste[1][last] = PDF_NUM;
336 liste[2][last] = liste[2][i];
337 stayintext = 0;
338 last++;
339 } else if (((liste[1][i] == PDF_TEX) || (liste[1][i] == PDF_NUM))
340 && (stayintext || i == indexliste - 1 || (liste[0][i] >= 5)
341 || (pdf_text_num_length(liste, indexliste, i) >= 5))) {
342 /* set to text and combine additional text/short numeric segments */
343 liste[0][last] = liste[0][i];
344 liste[1][last] = PDF_TEX;
345 liste[2][last] = liste[2][i];
346 stayintext = 0;
347
348 next = i + 1;
349 while (next < indexliste) {
350 if ((liste[1][next] == PDF_NUM) && pdf_num_stay(chaine, indexliste, liste, next)) {
351 break;
352 } else if (liste[1][next] == PDF_BYT) {
353 break;
354 }
355
356 liste[0][last] += liste[0][next];
357 next++;
358 }
359
360 last++;
361 i = next;
362 continue;
363 } else {
364 /* build byte segment, including combining numeric/text segments that aren't long enough on their own */
365 liste[0][last] = liste[0][i];
366 liste[1][last] = PDF_BYT;
367 liste[2][last] = liste[2][i];
368 stayintext = 0;
369
370 next = i + 1;
371 while (next < indexliste) {
372 if (liste[1][next] != PDF_BYT) {
373 /* check for case of a single byte shift from text mode */
374 if ((liste[0][last] == 1) && (last > 0) && (liste[1][last - 1] == PDF_TEX)) {
375 stayintext = 1;
376 break;
377 }
378
379 if ((liste[0][next] >= 5) || (pdf_text_num_length(liste, indexliste, next) >= 5)) {
380 break;
381 }
382 }
383
384 liste[0][last] += liste[0][next];
385 next++;
386 }
387
388 last++;
389 i = next;
390 continue;
391 }
392
393 i++;
394 }
395
396 /* set the size of the list based on the last consolidated segment */
397 *p_indexliste = last;
398 }
399
400 /* Helper to pad TEX mode, allowing for whether last segment or not, writing out `chainet` */
401 static void pdf_textprocess_end(short *chainemc, int *p_mclength, const int is_last_seg,
402 unsigned char chainet[PDF_MAX_STREAM_LEN], int wnet, int *p_curtable, int *p_tex_padded) {
403 int i;
404
405 *p_tex_padded = wnet & 1;
406 if (*p_tex_padded) {
407 if (is_last_seg) {
408 chainet[wnet++] = 29; /* PS or AL */
409 } else { /* Can't use PS as may carry over to following segment */
410 /* This is sub-optimal if curtable T_ALPHA and following seg lower, or if curtable T_MIXED
411 and following seg is lower or punct; TODO: need peek-ahead to table of following seg */
412 chainet[wnet++] = 28 + (*p_curtable == T_PUNCT); /* ML (T_ALPHA/T_LOWER) or AL (T_MIXED/T_PUNCT) */
413 *p_curtable = *p_curtable == T_ALPHA || *p_curtable == T_LOWER ? T_MIXED : T_ALPHA;
414 }
415 }
416
417 /* Now translate the string chainet into codewords */
418
419 for (i = 0; i < wnet; i += 2) {
420 chainemc[(*p_mclength)++] = (30 * chainet[i]) + chainet[i + 1];
421 }
422 }
423
424 /* 547 */
425 /* Text compaction */
426 static void pdf_textprocess(short *chainemc, int *p_mclength, const unsigned char chaine[], const int start,
427 const int length, const int lastmode, const int is_last_seg, int *p_curtable, int *p_tex_padded) {
428 const int real_lastmode = PDF_REAL_MODE(lastmode);
429 int j, indexlistet;
430 int curtable = real_lastmode == PDF_TEX ? *p_curtable : T_ALPHA; /* Set default table upper alpha */
431 int listet[2][PDF_MAX_LEN] = {{0}};
432 unsigned char chainet[PDF_MAX_STREAM_LEN];
433 int wnet = 0;
434
435 /* add mode indicator if needed */
436 if (real_lastmode != PDF_TEX) {
437 chainemc[(*p_mclength)++] = 900;
438 }
439
440 /* listet will contain the table numbers and the value of each characters */
441 for (indexlistet = 0; indexlistet < length; indexlistet++) {
442 const int codeascii = chaine[start + indexlistet];
443 listet[0][indexlistet] = pdf_asciix[codeascii];
444 listet[1][indexlistet] = pdf_asciiy[codeascii];
445 }
446
447 /* 570 */
448
449 for (j = 0; j < length; j++) {
450 if (listet[0][j] & curtable) {
451 /* The character is in the current table */
452 chainet[wnet++] = listet[1][j];
453 } else {
454 /* Obliged to change table */
455 int newtable;
456 if (j == (length - 1) || !(listet[0][j] & listet[0][j + 1])) {
457 /* we change only one character - look for temporary switch */
458 if ((listet[0][j] & T_ALPHA) && (curtable == T_LOWER)) {
459 chainet[wnet++] = 27; /* AS */
460 chainet[wnet++] = listet[1][j];
461 continue;
462 }
463 if (listet[0][j] & T_PUNCT) { /* (T_PUNCT and T_ALPHA not both possible) */
464 chainet[wnet++] = 29; /* PS */
465 chainet[wnet++] = listet[1][j];
466 continue;
467 }
468 /* No temporary switch available */
469 newtable = listet[0][j];
470 } else {
471 newtable = listet[0][j] & listet[0][j + 1];
472 }
473
474 /* 599 */
475
476 /* Maintain the first if several tables are possible */
477 if (newtable == T_ALWMX) { /* (T_ALPHA | T_LOWER | T_MIXED) */
478 newtable = T_ALPHA;
479 } else if (newtable == T_MXPNC) { /* (T_MIXED | T_PUNCT) */
480 newtable = T_MIXED;
481 }
482
483 /* 619 - select the switch */
484 wnet = pdf_textprocess_switch(curtable, newtable, chainet, wnet);
485 curtable = newtable;
486 /* 659 - at last we add the character */
487 chainet[wnet++] = listet[1][j];
488 }
489 }
490
491 /* 663 */
492 *p_curtable = curtable;
493 pdf_textprocess_end(chainemc, p_mclength, is_last_seg, chainet, wnet, p_curtable, p_tex_padded);
494 }
495
496 /* Minimal text compaction */
497 static void pdf_textprocess_minimal(short *chainemc, int *p_mclength, const unsigned char chaine[],
498 short liste[3][PDF_MAX_LEN], const int indexliste, const int lastmode, const int is_last_seg,
499 int *p_curtable, int *p_tex_padded, int *p_i) {
500 const int real_lastmode = PDF_REAL_MODE(lastmode);
501 int i, j, k;
502 int curtable = real_lastmode == PDF_TEX ? *p_curtable : T_ALPHA; /* Set default table upper alpha */
503 unsigned char chainet[PDF_MAX_STREAM_LEN];
504 int wnet = 0;
505
506 /* add mode indicator if needed */
507 if (real_lastmode != PDF_TEX) {
508 chainemc[(*p_mclength)++] = 900;
509 }
510
511 for (i = *p_i; i < indexliste && PDF_REAL_MODE(liste[1][i]) == PDF_TEX; i++) {
512 static const unsigned char newtables[5] = { 0, T_ALPHA, T_LOWER, T_MIXED, T_PUNCT };
513 const int newtable = newtables[liste[1][i]];
514 const int from = liste[2][i];
515 for (j = 0; j < liste[0][i]; j++) {
516 const int c = chaine[from + j];
517 const int t_table = pdf_asciix[c];
518 if (!t_table) { /* BYT Shift? */
519 if (wnet & 1) {
520 chainet[wnet++] = 29; /* PS or AL (T_PUNCT) */
521 if (curtable == T_PUNCT) {
522 curtable = T_ALPHA;
523 }
524 }
525 for (k = 0; k < wnet; k += 2) {
526 chainemc[(*p_mclength)++] = (30 * chainet[k]) + chainet[k + 1];
527 }
528 chainemc[(*p_mclength)++] = 913; /* BYT Shift */
529 chainemc[(*p_mclength)++] = c;
530 wnet = 0;
531 continue;
532 }
533
534 if (newtable != curtable) {
535 wnet = pdf_textprocess_switch(curtable, newtable, chainet, wnet);
536 curtable = newtable;
537 }
538 if (curtable == T_LOWER && t_table == T_ALPHA) {
539 chainet[wnet++] = 27; /* AS */
540 } else if (curtable != T_PUNCT && (t_table & T_PUNCT) && (curtable != T_MIXED || !(t_table & T_MIXED))) {
541 chainet[wnet++] = 29; /* PS */
542 }
543 /* At last we add the character */
544 chainet[wnet++] = pdf_asciiy[c];
545 }
546 }
547 *p_i = i ? i - 1 : 0;
548
549 *p_curtable = curtable;
550 pdf_textprocess_end(chainemc, p_mclength, is_last_seg, chainet, wnet, p_curtable, p_tex_padded);
551 }
552
553 /* 671 */
554 /* Byte compaction */
555 INTERNAL void pdf_byteprocess(short *chainemc, int *p_mclength, const unsigned char chaine[], int start,
556 const int length, const int lastmode) {
557 const int real_lastmode = PDF_REAL_MODE(lastmode);
558
559 if (length == 1) {
560 /* shift or latch depending on previous mode */
561 chainemc[(*p_mclength)++] = real_lastmode == PDF_TEX ? 913 : 901;
562 chainemc[(*p_mclength)++] = chaine[start];
563 } else {
564 int len;
565 /* select the switch for multiple of 6 bytes */
566 if (length % 6 == 0) {
567 chainemc[(*p_mclength)++] = 924;
568 } else {
569 /* Default mode for MICROPDF417 is Byte Compaction (ISO/IEC 24728:2006 5.4.3), but not emitting it
570 * depends on whether an ECI has been emitted previously (or not) it appears, so simpler and safer
571 * to always emit it. */
572 chainemc[(*p_mclength)++] = 901;
573 }
574
575 len = 0;
576
577 while (len < length) {
578 uint64_t total;
579 unsigned int chunkLen = length - len;
580 if (6 <= chunkLen) { /* Take groups of 6 */
581 chunkLen = 6;
582 len += chunkLen;
583 total = 0;
584
585 while (chunkLen--) {
586 const uint64_t mantisa = chaine[start++];
587 total |= mantisa << (chunkLen * 8);
588 }
589
590 chunkLen = 5;
591
592 while (chunkLen--) {
593 chainemc[*p_mclength + chunkLen] = (int) (total % 900);
594 total /= 900;
595 }
596 *p_mclength += 5;
597 } else { /* If there remains a group of less than 6 bytes */
598 len += chunkLen;
599 while (chunkLen--) {
600 chainemc[(*p_mclength)++] = chaine[start++];
601 }
602 }
603 }
604 }
605 }
606
607 /* 712 */
608 /* Numeric compaction */
609 static void pdf_numbprocess(short *chainemc, int *p_mclength, const unsigned char chaine[], const int start,
610 const int length) {
611 int j;
612
613 chainemc[(*p_mclength)++] = 902;
614
615 j = 0;
616 while (j < length) {
617 int dumlength = 0;
618 int p, len, loop, nombre, dummy[50];
619 char chainemod[45];
620 int longueur = length - j;
621 if (longueur > 44) {
622 longueur = 44;
623 }
624 len = longueur + 1;
625 chainemod[0] = 1;
626 for (loop = 1; loop < len; loop++) {
627 chainemod[loop] = ctoi(chaine[start + loop + j - 1]);
628 }
629 do {
630 /* 877 - gosub Modulo */
631 p = 0;
632 nombre = 0;
633 for (loop = 0; loop < len; loop++) {
634 nombre *= 10;
635 nombre += chainemod[loop];
636 if (nombre < 900) {
637 if (p) {
638 chainemod[p++] = 0;
639 }
640 } else {
641 chainemod[p] = (nombre / 900);
642 nombre -= chainemod[p++] * 900; /* nombre % 900 */
643 }
644 }
645 /* return to 723 */
646
647 dummy[dumlength++] = nombre;
648 len = p;
649 } while (p);
650 for (loop = dumlength - 1; loop >= 0; loop--) {
651 chainemc[(*p_mclength)++] = dummy[loop];
652 }
653 j += longueur;
654 }
655 }
656
657 #ifdef ZINT_TEST /* Wrapper for direct testing */
658 INTERNAL void pdf_numbprocess_test(short *chainemc, int *p_mclength, const unsigned char chaine[], const int start,
659 const int length) {
660 pdf_numbprocess(chainemc, p_mclength, chaine, start, length);
661 }
662 #endif
663
664 /* Minimal encoding */
665
666 /* Return number of consecutive chars from `position` in table `t_table` */
667 static int pdf_table_length(const unsigned char source[], const int length, const int position, const int t_table) {
668 int i;
669
670 for (i = position; i < length && (pdf_asciix[source[i]] & t_table); i++);
671
672 return i - position;
673 }
674
675 struct pdf_edge {
676 unsigned char mode;
677 unsigned short from; /* Position in input data, 0-based */
678 unsigned short len;
679 unsigned short units; /* Cumulative TEX/NUM/BYT units since entering TEX/NUM/BYT mode */
680 unsigned short unit_size; /* Number of codewords based on units since entering TEX/NUM/BYT mode */
681 unsigned short size; /* Cumulative number of codewords in previous TEX/NUM/BYT modes */
682 unsigned short previous; /* Index into edges array */
683 };
684
685 /* Note 1st row of edges not used so valid previous cannot point there, i.e. won't be zero */
686 #define PDF_PREVIOUS(edges, edge) \
687 ((edge)->previous ? (edges) + (edge)->previous : NULL)
688
689 #if 0
690 #define PDF_TRACE
691 #endif
692 #include "pdf417_trace.h"
693
694 /* Initialize a new edge */
695 static int pdf_new_Edge(struct pdf_edge *edges, const int mode, const int from, const int len, const int t_table,
696 const int lastmode, struct pdf_edge *previous, struct pdf_edge *edge) {
697 const int real_mode = PDF_REAL_MODE(mode);
698 int previousMode, real_previousMode;
699 int units;
700 int unit_size = 0; /* Suppress clang-tidy clang-analyzer-core.uninitialized.Assign warning */
701 int dv, md;
702
703 edge->mode = mode;
704 edge->from = from;
705 edge->len = len;
706 if (previous) {
707 assert(previous->mode && previous->len && (previous->unit_size + previous->size));
708 previousMode = previous->mode;
709 real_previousMode = PDF_REAL_MODE(previousMode);
710 edge->previous = previous - edges;
711 if (real_mode != real_previousMode) {
712 edge->size = previous->size + previous->unit_size + 1; /* + TEX/NUM/BYT switch */
713 units = 0;
714 } else {
715 edge->size = previous->size;
716 units = previous->units;
717 }
718 } else {
719 previousMode = lastmode;
720 real_previousMode = PDF_REAL_MODE(previousMode);
721 edge->previous = 0;
722 edge->size = real_mode != real_previousMode || real_previousMode != PDF_TEX ? 1 : 0;
723 units = 0;
724 }
725
726 switch (mode) {
727 case PDF_ALP:
728 assert(!t_table || (t_table & (T_ALPHA | T_PUNCT)));
729 if (t_table) {
730 if (previousMode != mode && real_previousMode == PDF_TEX) {
731 units += 1 + (previousMode == PDF_LOW); /* AL or ML+AL */
732 }
733 units += (1 + !(t_table & T_ALPHA)) * len; /* chars or PS + char */
734 } else { /* Binary shift */
735 assert(len == 1);
736 if (units & 1) {
737 units++; /* PS or AL pad */
738 }
739 if (previousMode != mode && real_previousMode == PDF_TEX) {
740 units += 1 + (previousMode == PDF_LOW); /* AL or ML+AL */
741 }
742 units += 4; /* BYT SHIFT 913 (2 units) + byte (2 units) */
743 }
744 unit_size = (units + 1) >> 1;
745 break;
746
747 case PDF_LOW:
748 assert(!t_table || (t_table & (T_LOWER | T_PUNCT | T_ALPHA)));
749 if (t_table) {
750 if (previousMode != mode) {
751 units += 1 + (previousMode == PDF_PNC); /* LL or AL+LL */
752 }
753 units += (1 + !(t_table & T_LOWER)) * len; /* chars or PS/AS + char */
754 } else { /* Binary shift */
755 assert(len == 1);
756 if (units & 1) {
757 units++; /* PS or AL pad */
758 }
759 if (previousMode != mode) {
760 units += 1 + (previousMode == PDF_PNC); /* LL or AL+LL */
761 }
762 units += 4; /* BYT SHIFT 913 (2 units) + byte (2 units) */
763 }
764 unit_size = (units + 1) >> 1;
765 break;
766
767 case PDF_MIX:
768 assert(!t_table || (t_table & (T_MIXED | T_PUNCT)));
769 if (t_table) {
770 if (previousMode != mode) {
771 units += 1 + (previousMode == PDF_PNC); /* ML or AL+ML */
772 }
773 units += (1 + !(t_table & T_MIXED)) * len; /* chars or PS + char */
774 } else { /* Binary shift */
775 assert(len == 1);
776 if (units & 1) {
777 units++; /* PS pad */
778 }
779 if (previousMode != mode) {
780 units += 1 + (previousMode == PDF_PNC); /* ML or AL+ML */
781 }
782 units += 4; /* BYT SHIFT 913 (2 units) + byte (2 units) */
783 }
784 unit_size = (units + 1) >> 1;
785 break;
786
787 case PDF_PNC:
788 assert(!t_table || (t_table & T_PUNCT));
789 if (t_table) {
790 if (previousMode != mode) {
791 units += 1 + (previousMode != PDF_MIX); /* PL or ML+PL */
792 }
793 units += len; /* chars */
794 } else { /* Binary shift */
795 assert(len == 1);
796 if (units & 1) {
797 units += 3; /* AL pad + (after BYT SHIFT) ML+PL to return to PNC */
798 } else if (previousMode != mode) {
799 units += 1 + (previousMode != PDF_MIX); /* PL or ML+PL */
800 }
801 units += 4; /* BYT SHIFT 913 (2 units) + byte (2 units) */
802 }
803 unit_size = (units + 1) >> 1;
804 break;
805
806 case PDF_BYT:
807 units += len;
808 dv = units / 6;
809 unit_size = dv * 5 + (units - dv * 6);
810 break;
811
812 case PDF_NUM:
813 units += len;
814 dv = units / 44;
815 md = units - dv * 44;
816 unit_size = dv * 15 + (md ? md / 3 + 1 : 0);
817 break;
818 }
819 edge->units = units;
820 edge->unit_size = unit_size;
821
822 return edge->size + edge->unit_size;
823 }
824
825 /* Whether `new_units` likely to result in less (fractional) codewords than `existing_units`, allowing for `mode` */
826 static int pdf_new_units_better(const int mode, const int existing_units, const int new_units) {
827 if (PDF_REAL_MODE(mode) == PDF_TEX) {
828 if ((new_units & 1) != (existing_units & 1)) {
829 return (existing_units & 1);
830 }
831 } else if (mode == PDF_BYT) {
832 const int existing_md = existing_units % 6;
833 if (new_units % 6 != existing_md) {
834 return existing_md;
835 }
836 }
837 return new_units < existing_units;
838 }
839
840 /* Add an edge for a mode at a vertex if no existing edge or if more optimal than existing edge */
841 static void pdf_addEdge(const unsigned char *source, const int length, struct pdf_edge *edges, const int mode,
842 const int from, const int len, const int t_table, const int lastmode, struct pdf_edge *previous) {
843 struct pdf_edge edge;
844 const int new_size = pdf_new_Edge(edges, mode, from, len, t_table, lastmode, previous, &edge);
845 const int vertexIndex = from + len;
846 const int v_ij = vertexIndex * PDF_NUM_MODES + mode - 1;
847 const int v_size = edges[v_ij].size + edges[v_ij].unit_size;
848
849 if (edges[v_ij].mode == 0 || v_size > new_size
850 || (v_size == new_size && pdf_new_units_better(mode, edge.units, edges[v_ij].units))) {
851 PDF_TRACE_AddEdge(source, length, edges, previous, vertexIndex, t_table, &edge);
852 edges[v_ij] = edge;
853 } else {
854 PDF_TRACE_NotAddEdge(source, length, edges, previous, vertexIndex, t_table, &edge);
855 }
856 }
857
858 /* Add edges for the various modes at a vertex */
859 static void pdf_addEdges(const unsigned char source[], const int length, const int lastmode, struct pdf_edge *edges,
860 const int from, struct pdf_edge *previous) {
861 const unsigned char c = source[from];
862 const int t_table = pdf_asciix[c];
863
864 if (t_table & T_ALPHA) {
865 const int len = pdf_table_length(source, length, from, T_ALPHA);
866 pdf_addEdge(source, length, edges, PDF_ALP, from, len, T_ALPHA, lastmode, previous);
867 }
868 if (!t_table || (t_table & T_PUNCT)) { /* Binary shift or PS */
869 pdf_addEdge(source, length, edges, PDF_ALP, from, 1 /*len*/, t_table & ~T_ALPHA, lastmode, previous);
870 }
871
872 if (t_table & T_LOWER) {
873 const int len = pdf_table_length(source, length, from, T_LOWER);
874 pdf_addEdge(source, length, edges, PDF_LOW, from, len, T_LOWER, lastmode, previous);
875 }
876 if (!t_table || (t_table & (T_PUNCT | T_ALPHA))) { /* Binary shift or PS/AS */
877 pdf_addEdge(source, length, edges, PDF_LOW, from, 1 /*len*/, t_table & ~T_LOWER, lastmode, previous);
878 }
879
880 if (t_table & T_MIXED) {
881 const int len = pdf_table_length(source, length, from, T_MIXED);
882 pdf_addEdge(source, length, edges, PDF_MIX, from, len, T_MIXED, lastmode, previous);
883 if (len > 1 && z_isdigit(source[from + 1])) { /* Add single-length edge before digit to compare to NUM */
884 pdf_addEdge(source, length, edges, PDF_MIX, from, 1 /*len*/, T_MIXED, lastmode, previous);
885 }
886 }
887 if (!t_table || (t_table & T_PUNCT)) { /* Binary shift or PS */
888 pdf_addEdge(source, length, edges, PDF_MIX, from, 1 /*len*/, t_table & ~T_MIXED, lastmode, previous);
889 }
890
891 if (t_table & T_PUNCT) {
892 const int len = pdf_table_length(source, length, from, T_PUNCT);
893 pdf_addEdge(source, length, edges, PDF_PNC, from, len, T_PUNCT, lastmode, previous);
894 }
895 if (!t_table) { /* Binary shift */
896 pdf_addEdge(source, length, edges, PDF_PNC, from, 1 /*len*/, t_table, lastmode, previous);
897 }
898
899 if (z_isdigit(c)) {
900 const int len = cnt_digits(source, length, from, -1 /*all*/);
901 pdf_addEdge(source, length, edges, PDF_NUM, from, len, 0 /*t_table*/, lastmode, previous);
902 }
903
904 pdf_addEdge(source, length, edges, PDF_BYT, from, 1 /*len*/, 0 /*t_table*/, lastmode, previous);
905 }
906
907 /* Calculate optimized encoding modes */
908 static int pdf_define_mode(short liste[3][PDF_MAX_LEN], int *p_indexliste, const unsigned char source[],
909 const int length, const int lastmode, const int debug_print) {
910
911 int i, j, v_i;
912 int minimalJ, minimalSize;
913 struct pdf_edge *edge;
914 int mode_start, mode_len;
915
916 struct pdf_edge *edges = (struct pdf_edge *) calloc((length + 1) * PDF_NUM_MODES, sizeof(struct pdf_edge));
917 if (!edges) {
918 return 0;
919 }
920 pdf_addEdges(source, length, lastmode, edges, 0, NULL);
921
922 PDF_TRACE_Edges("DEBUG Initial situation\n", source, length, edges, 0);
923
924 for (i = 1; i < length; i++) {
925 v_i = i * PDF_NUM_MODES;
926 for (j = 0; j < PDF_NUM_MODES; j++) {
927 if (edges[v_i + j].mode) {
928 pdf_addEdges(source, length, lastmode, edges, i, edges + v_i + j);
929 }
930 }
931 PDF_TRACE_Edges("DEBUG situation after adding edges to vertices at position %d\n", source, length, edges, i);
932 }
933
934 PDF_TRACE_Edges("DEBUG Final situation\n", source, length, edges, length);
935
936 v_i = length * PDF_NUM_MODES;
937 minimalJ = -1;
938 minimalSize = INT_MAX;
939 for (j = 0; j < PDF_NUM_MODES; j++) {
940 edge = edges + v_i + j;
941 if (edge->mode) {
942 const int edge_size = edge->size + edge->unit_size;
943 if (debug_print) {
944 printf("edges[%d][%d][0] size %d(%d,%d)\n", length, j, edge_size, edge->unit_size, edge->size);
945 }
946 if (edge_size < minimalSize) {
947 minimalSize = edge_size;
948 minimalJ = j;
949 if (debug_print) printf(" set minimalJ %d\n", minimalJ);
950 }
951 } else {
952 if (debug_print) printf("edges[%d][%d][0] NULL\n", length, j);
953 }
954 }
955 assert(minimalJ >= 0);
956
957 edge = edges + v_i + minimalJ;
958 mode_len = 0;
959 mode_start = length;
960 while (edge) {
961 const int current_mode = edge->mode;
962 const int current_from = edge->from;
963 mode_len += edge->len;
964 edge = PDF_PREVIOUS(edges, edge);
965 if (!edge || edge->mode != current_mode) {
966 mode_start--;
967 liste[0][mode_start] = mode_len;
968 liste[1][mode_start] = current_mode;
969 liste[2][mode_start] = current_from;
970 mode_len = 0;
971 }
972 }
973 *p_indexliste = length - mode_start;
974 if (mode_start) {
975 memmove(liste[0], liste[0] + mode_start, sizeof(short) * (*p_indexliste));
976 memmove(liste[1], liste[1] + mode_start, sizeof(short) * (*p_indexliste));
977 memmove(liste[2], liste[2] + mode_start, sizeof(short) * (*p_indexliste));
978 }
979 if (debug_print) {
980 printf("modes (%d):", *p_indexliste);
981 for (i = 0; i < *p_indexliste; i++) printf(" %c(%d,%d)", pdf_smodes[liste[1][i]], liste[2][i], liste[0][i]);
982 fputc('\n', stdout);
983 }
984
985 free(edges);
986
987 return 1;
988 }
989
990 /* Initial processing of data, shared by `pdf417()` and `micropdf417()` */
991 static int pdf_initial(struct zint_symbol *symbol, const unsigned char chaine[], const int length, const int eci,
992 const int is_micro, const int is_last_seg, int *p_lastmode, int *p_curtable, int *p_tex_padded,
993 short chainemc[PDF_MAX_STREAM_LEN], int *p_mclength) {
994 int i, indexchaine = 0, indexliste = 0;
995 short liste[3][PDF_MAX_LEN] = {{0}};
996 int mclength;
997 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
998 const int fast_encode = symbol->input_mode & FAST_MODE;
999
1000 /* 456 */
1001
1002 if (fast_encode) {
1003 int mode = pdf_quelmode(chaine[0]);
1004
1005 /* 463 */
1006 do {
1007 liste[1][indexliste] = mode;
1008 liste[2][indexliste] = indexchaine;
1009 while ((liste[1][indexliste] == mode) && (indexchaine < length)) {
1010 liste[0][indexliste]++;
1011 indexchaine++;
1012 mode = pdf_quelmode(chaine[indexchaine]);
1013 }
1014 indexliste++;
1015 } while (indexchaine < length);
1016
1017 if (debug_print) {
1018 fputs("\nInitial block pattern:\n", stdout);
1019 for (i = 0; i < indexliste; i++) {
1020 int j;
1021 for (j = 0; j < liste[0][i]; j++) fputc(pdf_mode_str(liste[1][i])[0], stdout);
1022 }
1023 fputc('\n', stdout);
1024 }
1025
1026 pdf_appendix_d_encode(chaine, liste, &indexliste);
1027 } else {
1028 if (!pdf_define_mode(liste, &indexliste, chaine, length, *p_lastmode, debug_print)) {
1029 return errtxt(ZINT_ERROR_MEMORY, symbol, 749, "Insufficient memory for mode buffers");
1030 }
1031 }
1032
1033 if (debug_print) {
1034 fputs("\nCompacted block pattern:\n", stdout);
1035 for (i = 0; i < indexliste; i++) {
1036 int j;
1037 for (j = 0; j < liste[0][i]; j++) fputc(pdf_mode_str(PDF_REAL_MODE(liste[1][i]))[0], stdout);
1038 }
1039 fputc('\n', stdout);
1040 }
1041
1042 /* 541 - now compress the data */
1043 indexchaine = 0;
1044 mclength = *p_mclength;
1045 if (mclength == 0 && !is_micro) {
1046 mclength++; /* Allow for length descriptor for full symbol */
1047 }
1048
1049 if (*p_mclength == 0 && (symbol->output_options & READER_INIT)) {
1050 chainemc[mclength++] = 921; /* Reader Initialisation */
1051 }
1052
1053 if (eci != 0) {
1054 if (eci > 811799) {
1055 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 472, "ECI code '%d' out of range (0 to 811799)",
1056 symbol->eci);
1057 }
1058 /* Encoding ECI assignment number, according to Table 8 */
1059 if (eci <= 899) {
1060 chainemc[mclength++] = 927; /* ECI */
1061 chainemc[mclength++] = eci;
1062 } else if (eci <= 810899) {
1063 chainemc[mclength++] = 926; /* ECI */
1064 chainemc[mclength++] = (eci / 900) - 1;
1065 chainemc[mclength++] = eci % 900;
1066 } else {
1067 chainemc[mclength++] = 925; /* ECI */
1068 chainemc[mclength++] = eci - 810900;
1069 }
1070 }
1071
1072 for (i = 0; i < indexliste; i++) {
1073 const int real_mode = PDF_REAL_MODE(liste[1][i]);
1074 switch (real_mode) {
1075 case PDF_TEX: /* 547 - text mode */
1076 if (fast_encode) {
1077 pdf_textprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i], *p_lastmode, is_last_seg,
1078 p_curtable, p_tex_padded);
1079 indexchaine += liste[0][i];
1080 *p_lastmode = PDF_ALP;
1081 } else {
1082 pdf_textprocess_minimal(chainemc, &mclength, chaine, liste, indexliste, *p_lastmode, is_last_seg,
1083 p_curtable, p_tex_padded, &i);
1084 indexchaine = i + 1 < indexliste ? liste[2][i + 1] : length;
1085 *p_lastmode = PDF_TABLE_TO_MODE(*p_curtable);
1086 }
1087 break;
1088 case PDF_BYT: /* 670 - octet stream mode */
1089 pdf_byteprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i], *p_lastmode);
1090 /* don't switch mode on single byte shift from text mode */
1091 if (PDF_REAL_MODE(*p_lastmode) != PDF_TEX || liste[0][i] != 1) {
1092 *p_lastmode = PDF_BYT;
1093 } else if (*p_curtable == T_PUNCT && *p_tex_padded) { /* If T_PUNCT and padded with AL */
1094 /* Then need to reset to alpha - ISO/IEC 15438:2015 5.4.2.4 b) 2) */
1095 *p_curtable = T_ALPHA;
1096 }
1097 indexchaine += liste[0][i];
1098 break;
1099 case PDF_NUM: /* 712 - numeric mode */
1100 pdf_numbprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i]);
1101 *p_lastmode = PDF_NUM;
1102 indexchaine += liste[0][i];
1103 break;
1104 }
1105 }
1106
1107 *p_mclength = mclength;
1108
1109 return 0;
1110 }
1111
1112 /* Call `pdf_initial()` for each segment, dealing with Structured Append beforehand */
1113 static int pdf_initial_segs(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count,
1114 const int is_micro, short chainemc[PDF_MAX_STREAM_LEN], int *p_mclength, int structapp_cws[18],
1115 int *p_structapp_cp) {
1116 int i;
1117 int error_number = 0;
1118 int structapp_cp = 0;
1119 int lastmode;
1120 int curtable;
1121 int tex_padded;
1122
1123 *p_mclength = 0;
1124
1125 if (symbol->structapp.count) {
1126 int id_cnt = 0, ids[10];
1127
1128 if (symbol->structapp.count < 2 || symbol->structapp.count > 99999) {
1129 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 740,
1130 "Structured Append count '%d' out of range (2 to 99999)", symbol->structapp.count);
1131 }
1132 if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) {
1133 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 741,
1134 "Structured Append index '%1$d' out of range (1 to count %2$d)",
1135 symbol->structapp.index, symbol->structapp.count);
1136 }
1137 if (symbol->structapp.id[0]) {
1138 int id_len;
1139
1140 for (id_len = 1; id_len < 31 && symbol->structapp.id[id_len]; id_len++);
1141
1142 if (id_len > 30) { /* 10 triplets */
1143 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 742,
1144 "Structured Append ID length %d too long (30 digit maximum)", id_len);
1145 }
1146
1147 for (i = 0; i < id_len; i += 3, id_cnt++) {
1148 const int triplet_len = i + 3 < id_len ? 3 : id_len - i;
1149 ids[id_cnt] = to_int((const unsigned char *) (symbol->structapp.id + i), triplet_len);
1150 if (ids[id_cnt] == -1) {
1151 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 743,
1152 "Invalid Structured Append ID (digits only)");
1153 }
1154 if (ids[id_cnt] > 899) {
1155 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 744,
1156 "Structured Append ID triplet %1$d value '%2$03d' out of range (000 to 899)",
1157 id_cnt + 1, ids[id_cnt]);
1158 }
1159 }
1160 }
1161 structapp_cws[structapp_cp++] = 928; /* Macro marker */
1162 structapp_cws[structapp_cp++] = (100000 + symbol->structapp.index - 1) / 900; /* Segment index 1 */
1163 structapp_cws[structapp_cp++] = (100000 + symbol->structapp.index - 1) % 900; /* Segment index 2 */
1164 for (i = 0; i < id_cnt; i++) {
1165 structapp_cws[structapp_cp++] = ids[i];
1166 }
1167 structapp_cws[structapp_cp++] = 923; /* Optional field */
1168 structapp_cws[structapp_cp++] = 1; /* Segment count tag */
1169 structapp_cws[structapp_cp++] = (100000 + symbol->structapp.count) / 900; /* Segment count 1 */
1170 structapp_cws[structapp_cp++] = (100000 + symbol->structapp.count) % 900; /* Segment count 2 */
1171 if (symbol->structapp.index == symbol->structapp.count) {
1172 structapp_cws[structapp_cp++] = 922; /* Special last segment terminator */
1173 }
1174 }
1175 *p_structapp_cp = structapp_cp;
1176
1177 /* Default mode for PDF417 is Text Compaction Alpha (ISO/IEC 15438:2015 5.4.2.1), and for MICROPDF417 is Byte
1178 * Compaction (ISO/IEC 24728:2006 5.4.3) */
1179 lastmode = is_micro ? PDF_BYT : PDF_ALP;
1180 /* Start in upper alpha - tracked across calls to `pdf_textprocess()` to allow for interleaving byte shifts */
1181 curtable = T_ALPHA;
1182
1183 for (i = 0; i < seg_count; i++) {
1184 error_number = pdf_initial(symbol, segs[i].source, segs[i].length, segs[i].eci, is_micro, i + 1 == seg_count,
1185 &lastmode, &curtable, &tex_padded, chainemc, p_mclength);
1186 if (error_number) { /* Only errors >= ZINT_ERROR returned */
1187 return error_number;
1188 }
1189 }
1190
1191 return error_number;
1192 }
1193
1194 /* 366 */
1195 /* Encode PDF417 */
1196 static int pdf_enc(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
1197 int i, j, longueur, loop, mccorrection[520] = {0}, offset;
1198 int total, mclength, c1, c2, c3, dummy[35];
1199 short chainemc[PDF_MAX_STREAM_LEN];
1200 int rows, cols, ecc, ecc_cws, padding;
1201 char pattern[580];
1202 int bp = 0;
1203 int structapp_cws[18] = {0}; /* 3 (Index) + 10 (ID) + 4 (Count) + 1 (Last) */
1204 int structapp_cp = 0;
1205 int error_number;
1206 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
1207 static const short ecc_num_cws[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512 };
1208
1209 if ((i = segs_length(segs, seg_count)) > PDF_MAX_LEN) {
1210 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 463, "Input length %d too long (maximum " PDF_MAX_LEN_S ")", i);
1211 }
1212
1213 error_number = pdf_initial_segs(symbol, segs, seg_count, 0 /*is_micro*/, chainemc, &mclength, structapp_cws,
1214 &structapp_cp);
1215 if (error_number) { /* Only errors return >= ZINT_ERROR */
1216 return error_number;
1217 }
1218
1219 if (debug_print) {
1220 printf("\nCompressed data stream (%d):\n", mclength - 1);
1221 for (i = 1; i < mclength; i++) { /* Skip unset length descriptor */
1222 printf("%d ", chainemc[i]);
1223 }
1224 fputs("\n\n", stdout);
1225 }
1226
1227 /* 752 - Now take care of the number of CWs per row */
1228
1229 /* ECC */
1230 ecc = symbol->option_1;
1231 if (ecc < 0) { /* If not specified, set ECC depending on no. of codewords */
1232 const int data_cws = mclength - 1 + structapp_cp; /* -1 for length descriptor */
1233 /* ISO/IEC 15438:2015 Annex E Table E.1 Recommended minima */
1234 if (data_cws <= 40) {
1235 ecc = 2;
1236 } else if (data_cws <= 160) {
1237 ecc = 3;
1238 } else if (data_cws <= 320) {
1239 ecc = 4;
1240 } else if (data_cws <= 863) {
1241 ecc = 5;
1242 } else {
1243 ecc = 6; /* Not mentioned in Table E.1 */
1244 }
1245 }
1246 ecc_cws = ecc_num_cws[ecc];
1247
1248 longueur = mclength + structapp_cp + ecc_cws;
1249
1250 if (debug_print) printf("Total No. of Codewords: %d, ECC %d, No. of ECC Codewords: %d\n", longueur, ecc, ecc_cws);
1251
1252 if (longueur > 928) {
1253 /* Enforce maximum codeword limit */
1254 return errtxt(ZINT_ERROR_TOO_LONG, symbol, 464, "Input too long, requires too many codewords (maximum 928)");
1255 }
1256
1257 cols = symbol->option_2;
1258 rows = symbol->option_3;
1259 if (rows) { /* Rows given */
1260 if (cols < 1) { /* Cols automatic */
1261 cols = (longueur + rows - 1) / rows;
1262 if (cols <= 1) {
1263 cols = 1;
1264 } else {
1265 /* Increase rows if would need > 30 columns */
1266 for (; cols > 30 && rows < 90; rows++, cols = (longueur + rows - 1) / rows);
1267 assert(cols <= 30);
1268 /* Increase rows if multiple too big */
1269 for (; cols >= 1 && rows < 90 && rows * cols > 928; rows++, cols = (longueur + rows - 1) / rows);
1270 if (rows * cols > 928) {
1271 return errtxt(ZINT_ERROR_TOO_LONG, symbol, 465,
1272 "Input too long, requires too many codewords (maximum 928)");
1273 }
1274 }
1275 } else { /* Cols given */
1276 /* Increase rows if multiple too big */
1277 for (; rows <= 90 && rows * cols < longueur; rows++);
1278 if (rows > 90 || rows * cols > 928) {
1279 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 745, "Input too long for number of columns '%d'", cols);
1280 }
1281 }
1282 if (rows != symbol->option_3) {
1283 error_number = errtxtf(ZINT_WARN_INVALID_OPTION, symbol, 746,
1284 "Number of rows increased from %1$d to %2$d", symbol->option_3, rows);
1285 }
1286 } else { /* Rows automatic, cols automatic or given */
1287 if (cols < 1) { /* Cols automatic */
1288 cols = (int) round(sqrt((longueur - 1) / 3.0)); /* -1 (length descriptor) for back-compatibility */
1289 }
1290 rows = (longueur + cols - 1) / cols;
1291 if (rows <= 3) {
1292 rows = 3;
1293 } else {
1294 /* Increase cols if would need > 90 rows - do this even if cols specified for better back-compatibility
1295 (though previously only increased once) */
1296 for (; rows > 90 && cols < 30; cols++, rows = (longueur + cols - 1) / cols);
1297 assert(rows <= 90);
1298 /* Increase cols if multiple too big */
1299 for (; rows >= 3 && cols < 30 && rows * cols > 928; cols++, rows = (longueur + cols - 1) / cols);
1300 if (rows * cols > 928) {
1301 return errtxt(ZINT_ERROR_TOO_LONG, symbol, 747,
1302 "Input too long, requires too many codewords (maximum 928)");
1303 }
1304 if (symbol->option_2 && cols != symbol->option_2) { /* Note previously did not warn if cols auto-upped */
1305 error_number = errtxtf(ZINT_WARN_INVALID_OPTION, symbol, 748,
1306 "Number of columns increased from %1$d to %2$d", symbol->option_2, cols);
1307 }
1308 }
1309 }
1310 assert(rows * cols >= longueur);
1311
1312 /* 781 - Padding calculation */
1313 padding = rows * cols - longueur;
1314
1315 /* We add the padding */
1316 for (i = 0; i < padding; i++) {
1317 chainemc[mclength++] = 900;
1318 }
1319 if (debug_print) printf("Padding: %d\n", padding);
1320
1321 /* We add the Structured Append Macro Control Block if any */
1322 if (structapp_cp) {
1323 for (i = 0; i < structapp_cp; i++) {
1324 chainemc[mclength++] = structapp_cws[i];
1325 }
1326 }
1327
1328 /* Set the length descriptor */
1329 chainemc[0] = mclength;
1330
1331 /* 796 - we now take care of the Reed Solomon codes */
1332 switch (ecc) {
1333 case 1: offset = 2;
1334 break;
1335 case 2: offset = 6;
1336 break;
1337 case 3: offset = 14;
1338 break;
1339 case 4: offset = 30;
1340 break;
1341 case 5: offset = 62;
1342 break;
1343 case 6: offset = 126;
1344 break;
1345 case 7: offset = 254;
1346 break;
1347 case 8: offset = 510;
1348 break;
1349 default: offset = 0;
1350 break;
1351 }
1352
1353 for (i = 0; i < mclength; i++) {
1354 total = (chainemc[i] + mccorrection[ecc_cws - 1]) % 929;
1355 for (j = ecc_cws - 1; j > 0; j--) {
1356 mccorrection[j] = (mccorrection[j - 1] + 929 - (total * pdf_coefrs[offset + j]) % 929) % 929;
1357 }
1358 mccorrection[0] = (929 - (total * pdf_coefrs[offset]) % 929) % 929;
1359 }
1360
1361 /* we add these codes to the string */
1362 for (i = ecc_cws - 1; i >= 0; i--) {
1363 chainemc[mclength++] = mccorrection[i] ? 929 - mccorrection[i] : 0;
1364 }
1365
1366 if (debug_print) {
1367 printf("Complete CW string (%d):\n", mclength);
1368 for (i = 0; i < mclength; i++) {
1369 printf("%d ", chainemc[i]);
1370 }
1371 fputc('\n', stdout);
1372 }
1373 #ifdef ZINT_TEST
1374 if (symbol->debug & ZINT_DEBUG_TEST) {
1375 debug_test_codeword_dump_short(symbol, chainemc, mclength);
1376 }
1377 #endif
1378
1379 if (debug_print) printf("\nSymbol size:\n%d columns x %d rows\n", cols, rows);
1380
1381 /* 818 - The CW string is finished */
1382 c1 = (rows - 1) / 3;
1383 c2 = ecc * 3 + (rows - 1) % 3;
1384 c3 = cols - 1;
1385
1386 /* we now encode each row */
1387 for (i = 0; i < rows; i++) {
1388 const int k = (i / 3) * 30;
1389 bp = 0;
1390 for (j = 0; j < cols; j++) {
1391 dummy[j + 1] = chainemc[i * cols + j];
1392 }
1393 switch (i % 3) {
1394 case 0:
1395 dummy[0] = k + c1;
1396 dummy[cols + 1] = k + c3;
1397 offset = 0; /* cluster(0) */
1398 break;
1399 case 1:
1400 dummy[0] = k + c2;
1401 dummy[cols + 1] = k + c1;
1402 offset = 929; /* cluster(3) */
1403 break;
1404 case 2:
1405 dummy[0] = k + c3;
1406 dummy[cols + 1] = k + c2;
1407 offset = 1858; /* cluster(6) */
1408 break;
1409 }
1410 bp = bin_append_posn(0x1FEA8, 17, pattern, bp); /* Row start */
1411
1412 for (j = 0; j <= cols; j++) {
1413 bp = bin_append_posn(pdf_bitpattern[offset + dummy[j]], 16, pattern, bp);
1414 pattern[bp++] = '0';
1415 }
1416
1417 if (symbol->symbology != BARCODE_PDF417COMP) {
1418 bp = bin_append_posn(pdf_bitpattern[offset + dummy[j]], 16, pattern, bp);
1419 pattern[bp++] = '0';
1420 bp = bin_append_posn(0x3FA29, 18, pattern, bp); /* Row Stop */
1421 } else {
1422 pattern[bp++] = '1'; /* Compact PDF417 Stop pattern */
1423 }
1424
1425 for (loop = 0; loop < bp; loop++) {
1426 if (pattern[loop] == '1') {
1427 set_module(symbol, i, loop);
1428 }
1429 }
1430 }
1431 symbol->width = bp;
1432 symbol->rows = rows;
1433
1434 /* ISO/IEC 15438:2015 Section 5.8.2 3X minimum row height */
1435 if (error_number) {
1436 (void) set_height(symbol, 3.0f, 0.0f, 0.0f, 1 /*no_errtxt*/);
1437 } else {
1438 error_number = set_height(symbol, 3.0f, 0.0f, 0.0f, 0 /*no_errtxt*/);
1439 }
1440
1441 /* 843 */
1442 return error_number;
1443 }
1444
1445 /* 345 */
1446 INTERNAL int pdf417(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
1447 int codeerr, error_number;
1448
1449 error_number = 0;
1450
1451 if ((symbol->option_1 < -1) || (symbol->option_1 > 8)) {
1452 errtxtf(0, symbol, 460, "Error correction level '%d' out of range (0 to 8)", symbol->option_1);
1453 if (symbol->warn_level == WARN_FAIL_ALL) {
1454 return ZINT_ERROR_INVALID_OPTION;
1455 }
1456 error_number = errtxt_adj(ZINT_WARN_INVALID_OPTION, symbol, "%1$s%2$s", ", ignoring");
1457 symbol->option_1 = -1;
1458 }
1459 if ((symbol->option_2 < 0) || (symbol->option_2 > 30)) {
1460 errtxtf(0, symbol, 461, "Number of columns '%d' out of range (1 to 30)", symbol->option_2);
1461 if (symbol->warn_level == WARN_FAIL_ALL) {
1462 return ZINT_ERROR_INVALID_OPTION;
1463 }
1464 error_number = errtxt_adj(ZINT_WARN_INVALID_OPTION, symbol, "%1$s%2$s", ", ignoring");
1465 symbol->option_2 = 0;
1466 }
1467 if (symbol->option_3 && (symbol->option_3 < 3 || symbol->option_3 > 90)) {
1468 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 466, "Number of rows '%d' out of range (3 to 90)",
1469 symbol->option_3);
1470 }
1471 if (symbol->option_2 && symbol->option_3 && symbol->option_2 * symbol->option_3 > 928) {
1472 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 475, "Columns x rows value '%d' out of range (1 to 928)",
1473 symbol->option_2 * symbol->option_3);
1474 }
1475
1476 /* 349 */
1477 codeerr = pdf_enc(symbol, segs, seg_count);
1478
1479 /* 352 */
1480 if (codeerr != 0) {
1481 error_number = codeerr;
1482 }
1483
1484 /* 364 */
1485 return error_number;
1486 }
1487
1488 /* like PDF417 only much smaller! */
1489 INTERNAL int micropdf417(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
1490 int i, k, j, longueur, mccorrection[50] = {0}, offset;
1491 int total, mclength, error_number = 0;
1492 short chainemc[PDF_MAX_STREAM_LEN];
1493 char pattern[580];
1494 int bp = 0;
1495 int structapp_cws[18] = {0}; /* 3 (Index) + 10 (ID) + 4 (Count) + 1 (Last) */
1496 int structapp_cp = 0;
1497 int variant;
1498 int LeftRAP, CentreRAP, RightRAP, Cluster, loop;
1499 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
1500 /* From ISO/IEC 24728:2006 Table 1 — MicroPDF417 version characteristics */
1501 static char col_max_codewords[5] = { 0, 20, 37, 82, 126 };
1502
1503 if ((i = segs_length(segs, seg_count)) > MICRO_PDF_MAX_LEN) {
1504 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 474, "Input length %d too long (maximum " MICRO_PDF_MAX_LEN_S ")",
1505 i);
1506 }
1507 if (symbol->option_3) {
1508 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 476, "Cannot specify rows for MicroPDF417");
1509 }
1510
1511 /* Encoding starts out the same as PDF417, so use the same code */
1512
1513 error_number = pdf_initial_segs(symbol, segs, seg_count, 1 /*is_micro*/, chainemc, &mclength, structapp_cws,
1514 &structapp_cp);
1515 if (error_number) { /* Only errors return >= ZINT_ERROR */
1516 return error_number;
1517 }
1518
1519 /* This is where it all changes! */
1520
1521 if (mclength + structapp_cp > 126) {
1522 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 467, "Input too long, requires %d codewords (maximum 126)",
1523 mclength + structapp_cp);
1524 }
1525 if (symbol->option_2 > 4) {
1526 if (symbol->warn_level == WARN_FAIL_ALL) {
1527 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 471, "Number of columns '%d' out of range (1 to 4)",
1528 symbol->option_2);
1529 }
1530 error_number = errtxtf(ZINT_WARN_INVALID_OPTION, symbol, 468,
1531 "Number of columns '%d' out of range (1 to 4), ignoring", symbol->option_2);
1532 symbol->option_2 = 0;
1533 }
1534
1535 if (debug_print) {
1536 printf("\nEncoded Data Stream (%d):\n", mclength);
1537 for (i = 0; i < mclength; i++) {
1538 printf("%3d ", chainemc[i]);
1539 }
1540 fputc('\n', stdout);
1541 }
1542
1543 /* Now figure out which variant of the symbol to use and load values accordingly */
1544
1545 variant = 0;
1546
1547 if (symbol->option_2 >= 1 && mclength + structapp_cp > col_max_codewords[symbol->option_2]) {
1548 /* The user specified the column but the data doesn't fit - go to automatic */
1549 if (symbol->warn_level == WARN_FAIL_ALL) {
1550 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 469,
1551 "Input too long for number of columns '%1$d', requires %2$d codewords (maximum %3$d)",
1552 symbol->option_2, mclength + structapp_cp, col_max_codewords[symbol->option_2]);
1553 }
1554 error_number = errtxtf(ZINT_WARN_INVALID_OPTION, symbol, 470,
1555 "Input too long for number of columns '%d', ignoring", symbol->option_2);
1556 symbol->option_2 = 0;
1557 }
1558
1559 if (symbol->option_2 == 1) {
1560 /* the user specified 1 column and the data does fit */
1561 if (mclength + structapp_cp <= 4) {
1562 variant = 1;
1563 } else if (mclength + structapp_cp <= 7) {
1564 variant = 2;
1565 } else if (mclength + structapp_cp <= 10) {
1566 variant = 3;
1567 } else if (mclength + structapp_cp <= 12) {
1568 variant = 4;
1569 } else if (mclength + structapp_cp <= 16) {
1570 variant = 5;
1571 } else {
1572 variant = 6;
1573 }
1574 } else if (symbol->option_2 == 2) {
1575 /* the user specified 2 columns and the data does fit */
1576 if (mclength + structapp_cp <= 8) {
1577 variant = 7;
1578 } else if (mclength + structapp_cp <= 13) {
1579 variant = 8;
1580 } else if (mclength + structapp_cp <= 19) {
1581 variant = 9;
1582 } else if (mclength + structapp_cp <= 24) {
1583 variant = 10;
1584 } else if (mclength + structapp_cp <= 29) {
1585 variant = 11;
1586 } else if (mclength + structapp_cp <= 33) {
1587 variant = 12;
1588 } else {
1589 variant = 13;
1590 }
1591 } else if (symbol->option_2 == 3) {
1592 /* the user specified 3 columns and the data does fit */
1593 if (mclength + structapp_cp <= 6) {
1594 variant = 14;
1595 } else if (mclength + structapp_cp <= 10) {
1596 variant = 15;
1597 } else if (mclength + structapp_cp <= 14) {
1598 variant = 16;
1599 } else if (mclength + structapp_cp <= 18) {
1600 variant = 17;
1601 } else if (mclength + structapp_cp <= 24) {
1602 variant = 18;
1603 } else if (mclength + structapp_cp <= 34) {
1604 variant = 19;
1605 } else if (mclength + structapp_cp <= 46) {
1606 variant = 20;
1607 } else if (mclength + structapp_cp <= 58) {
1608 variant = 21;
1609 } else if (mclength + structapp_cp <= 70) {
1610 variant = 22;
1611 } else {
1612 variant = 23;
1613 }
1614 } else if (symbol->option_2 == 4) {
1615 /* the user specified 4 columns and the data does fit */
1616 if (mclength + structapp_cp <= 8) {
1617 variant = 24;
1618 } else if (mclength + structapp_cp <= 12) {
1619 variant = 25;
1620 } else if (mclength + structapp_cp <= 18) {
1621 variant = 26;
1622 } else if (mclength + structapp_cp <= 24) {
1623 variant = 27;
1624 } else if (mclength + structapp_cp <= 30) {
1625 variant = 28;
1626 } else if (mclength + structapp_cp <= 39) {
1627 variant = 29;
1628 } else if (mclength + structapp_cp <= 54) {
1629 variant = 30;
1630 } else if (mclength + structapp_cp <= 72) {
1631 variant = 31;
1632 } else if (mclength + structapp_cp <= 90) {
1633 variant = 32;
1634 } else if (mclength + structapp_cp <= 108) {
1635 variant = 33;
1636 } else {
1637 variant = 34;
1638 }
1639 } else {
1640 /* Zint can choose automatically from all available variations */
1641 for (i = 27; i >= 0; i--) {
1642 /* Note mclength + structapp_cp <= 126 and pdf_MicroAutosize[27] == 126 so variant will be set */
1643 if (pdf_MicroAutosize[i] >= mclength + structapp_cp) {
1644 variant = pdf_MicroAutosize[i + 28];
1645 } else {
1646 break;
1647 }
1648 }
1649 }
1650 assert(variant > 0); /* Suppress clang-tidy clang-analyzer-core.uninitialized.Assign */
1651
1652 /* Now we have the variant we can load the data */
1653 variant--;
1654 symbol->option_2 = pdf_MicroVariants[variant]; /* columns */
1655 symbol->rows = pdf_MicroVariants[variant + 34]; /* rows */
1656 k = pdf_MicroVariants[variant + 68]; /* number of EC CWs */
1657 longueur = (symbol->option_2 * symbol->rows) - k; /* number of non-EC CWs */
1658 i = longueur - (mclength + structapp_cp); /* amount of padding required */
1659 offset = pdf_MicroVariants[variant + 102]; /* coefficient offset */
1660
1661 if (debug_print) {
1662 fputs("\nChoose symbol size:\n", stdout);
1663 printf("%d columns x %d rows, variant %d\n", symbol->option_2, symbol->rows, variant + 1);
1664 printf("%d data codewords (including %d pads), %d ecc codewords\n", longueur, i, k);
1665 fputc('\n', stdout);
1666 }
1667
1668 /* We add the padding */
1669 while (i > 0) {
1670 chainemc[mclength++] = 900;
1671 i--;
1672 }
1673
1674 /* We add the Structured Append Macro Control Block if any */
1675 if (structapp_cp) {
1676 for (i = 0; i < structapp_cp; i++) {
1677 chainemc[mclength++] = structapp_cws[i];
1678 }
1679 }
1680
1681 /* Reed-Solomon error correction */
1682 longueur = mclength;
1683 for (i = 0; i < longueur; i++) {
1684 total = (chainemc[i] + mccorrection[k - 1]) % 929;
1685 for (j = k - 1; j >= 0; j--) {
1686 if (j == 0) {
1687 mccorrection[j] = (929 - (total * pdf_Microcoeffs[offset + j]) % 929) % 929;
1688 } else {
1689 mccorrection[j] = (mccorrection[j - 1] + 929 - (total * pdf_Microcoeffs[offset + j]) % 929) % 929;
1690 }
1691 }
1692 }
1693
1694 for (j = 0; j < k; j++) {
1695 if (mccorrection[j] != 0) {
1696 mccorrection[j] = 929 - mccorrection[j];
1697 }
1698 }
1699 /* we add these codes to the string */
1700 for (i = k - 1; i >= 0; i--) {
1701 chainemc[mclength++] = mccorrection[i];
1702 }
1703
1704 if (debug_print) {
1705 printf("Encoded Data Stream with ECC (%d):\n", mclength);
1706 for (i = 0; i < mclength; i++) {
1707 printf("%3d ", chainemc[i]);
1708 }
1709 fputc('\n', stdout);
1710 }
1711 #ifdef ZINT_TEST
1712 if (symbol->debug & ZINT_DEBUG_TEST) {
1713 debug_test_codeword_dump_short(symbol, chainemc, mclength);
1714 }
1715 #endif
1716
1717 /* Now get the RAP (Row Address Pattern) start values */
1718 LeftRAP = pdf_RAPTable[variant];
1719 CentreRAP = pdf_RAPTable[variant + 34];
1720 RightRAP = pdf_RAPTable[variant + 68];
1721 Cluster = pdf_RAPTable[variant + 102] / 3;
1722
1723 /* That's all values loaded, get on with the encoding */
1724
1725 /* Cluster can be 0, 1 or 2 for Cluster(0), Cluster(3) and Cluster(6) */
1726
1727 if (debug_print) fputs("\nInternal row representation:\n", stdout);
1728 for (i = 0; i < symbol->rows; i++) {
1729 if (debug_print) printf("row %d: ", i);
1730 bp = 0;
1731 offset = 929 * Cluster;
1732 k = i * symbol->option_2;
1733
1734 /* Copy the data into codebarre */
1735 bp = bin_append_posn(pdf_rap_side[LeftRAP - 1], 10, pattern, bp);
1736 bp = bin_append_posn(pdf_bitpattern[offset + chainemc[k]], 16, pattern, bp);
1737 pattern[bp++] = '0';
1738 if (symbol->option_2 >= 2) {
1739 if (symbol->option_2 == 3) {
1740 bp = bin_append_posn(pdf_rap_centre[CentreRAP - 1], 10, pattern, bp);
1741 }
1742 bp = bin_append_posn(pdf_bitpattern[offset + chainemc[k + 1]], 16, pattern, bp);
1743 pattern[bp++] = '0';
1744 if (symbol->option_2 >= 3) {
1745 if (symbol->option_2 == 4) {
1746 bp = bin_append_posn(pdf_rap_centre[CentreRAP - 1], 10, pattern, bp);
1747 }
1748 bp = bin_append_posn(pdf_bitpattern[offset + chainemc[k + 2]], 16, pattern, bp);
1749 pattern[bp++] = '0';
1750 if (symbol->option_2 == 4) {
1751 bp = bin_append_posn(pdf_bitpattern[offset + chainemc[k + 3]], 16, pattern, bp);
1752 pattern[bp++] = '0';
1753 }
1754 }
1755 }
1756 bp = bin_append_posn(pdf_rap_side[RightRAP - 1], 10, pattern, bp);
1757 pattern[bp++] = '1'; /* stop */
1758 if (debug_print) printf("%.*s\n", bp, pattern);
1759
1760 /* so now pattern[] holds the string of '1's and '0's. - copy this to the symbol */
1761 for (loop = 0; loop < bp; loop++) {
1762 if (pattern[loop] == '1') {
1763 set_module(symbol, i, loop);
1764 }
1765 }
1766
1767 /* Set up RAPs and Cluster for next row */
1768 LeftRAP++;
1769 CentreRAP++;
1770 RightRAP++;
1771 Cluster++;
1772
1773 if (LeftRAP == 53) {
1774 LeftRAP = 1;
1775 }
1776 if (CentreRAP == 53) {
1777 CentreRAP = 1;
1778 }
1779 if (RightRAP == 53) {
1780 RightRAP = 1;
1781 }
1782 if (Cluster == 3) {
1783 Cluster = 0;
1784 }
1785 }
1786 symbol->width = bp;
1787
1788 /* ISO/IEC 24728:2006 Section 5.8.2 2X minimum row height */
1789 if (error_number) {
1790 (void) set_height(symbol, 2.0f, 0.0f, 0.0f, 1 /*no_errtxt*/);
1791 } else {
1792 error_number = set_height(symbol, 2.0f, 0.0f, 0.0f, 0 /*no_errtxt*/);
1793 }
1794
1795 return error_number;
1796 }
1797
1798 #undef T_ALPHA
1799 #undef T_LOWER
1800 #undef T_MIXED
1801 #undef T_PUNCT
1802 #undef T_ALWMX
1803 #undef T_MXPNC
1804
1805 /* vim: set ts=4 sw=4 et : */