comparison mupdf-source/thirdparty/zint/backend/dotcode.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 /* dotcode.c - Handles DotCode */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2017-2024 Robin Stuart <rstuart114@gmail.com>
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. Neither the name of the project nor the names of its contributors
16 may be used to endorse or promote products derived from this software
17 without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 SUCH DAMAGE.
30 */
31 /* SPDX-License-Identifier: BSD-3-Clause */
32
33 /*
34 * Attempts to encode DotCode according to (AIMD013) ISS DotCode Rev. 4.0, DRAFT 0.15, TSC Pre-PR #5,
35 * dated May 28, 2019
36 * Incorporating suggestions from Terry Burton at BWIPP
37 */
38
39 #include <assert.h>
40 #include <math.h>
41 #include <stdio.h>
42 #include "common.h"
43 #include "gs1.h"
44
45 #define GF 113
46 #define PM 3
47 #define SCORE_UNLIT_EDGE -99999
48
49 /* DotCode symbol character dot patterns, from Annex C */
50 static const unsigned short dc_dot_patterns[113] = {
51 0x155, 0x0ab, 0x0ad, 0x0b5, 0x0d5, 0x156, 0x15a, 0x16a, 0x1aa, 0x0ae,
52 0x0b6, 0x0ba, 0x0d6, 0x0da, 0x0ea, 0x12b, 0x12d, 0x135, 0x14b, 0x14d,
53 0x153, 0x159, 0x165, 0x169, 0x195, 0x1a5, 0x1a9, 0x057, 0x05b, 0x05d,
54 0x06b, 0x06d, 0x075, 0x097, 0x09b, 0x09d, 0x0a7, 0x0b3, 0x0b9, 0x0cb,
55 0x0cd, 0x0d3, 0x0d9, 0x0e5, 0x0e9, 0x12e, 0x136, 0x13a, 0x14e, 0x15c,
56 0x166, 0x16c, 0x172, 0x174, 0x196, 0x19a, 0x1a6, 0x1ac, 0x1b2, 0x1b4,
57 0x1ca, 0x1d2, 0x1d4, 0x05e, 0x06e, 0x076, 0x07a, 0x09e, 0x0bc, 0x0ce,
58 0x0dc, 0x0e6, 0x0ec, 0x0f2, 0x0f4, 0x117, 0x11b, 0x11d, 0x127, 0x133,
59 0x139, 0x147, 0x163, 0x171, 0x18b, 0x18d, 0x193, 0x199, 0x1a3, 0x1b1,
60 0x1c5, 0x1c9, 0x1d1, 0x02f, 0x037, 0x03b, 0x03d, 0x04f, 0x067, 0x073,
61 0x079, 0x08f, 0x0c7, 0x0e3, 0x0f1, 0x11e, 0x13c, 0x178, 0x18e, 0x19c,
62 0x1b8, 0x1c6, 0x1cc
63 };
64
65 /* Printed() routine from Annex A adapted to char array of ASCII 1's and 0's */
66 static int dc_get_dot(const char Dots[], const int Hgt, const int Wid, const int x, const int y) {
67
68 if ((x >= 0) && (x < Wid) && (y >= 0) && (y < Hgt)) {
69 if (Dots[(y * Wid) + x] == '1') {
70 return 1;
71 }
72 }
73
74 return 0;
75 }
76
77 static int dc_clr_col(const char *Dots, const int Hgt, const int Wid, const int x) {
78 int y;
79 for (y = x & 1; y < Hgt; y += 2) {
80 if (dc_get_dot(Dots, Hgt, Wid, x, y)) {
81 return 0;
82 }
83 }
84
85 return 1;
86 }
87
88 static int dc_clr_row(const char *Dots, const int Hgt, const int Wid, const int y) {
89 int x;
90 for (x = y & 1; x < Wid; x += 2) {
91 if (dc_get_dot(Dots, Hgt, Wid, x, y)) {
92 return 0;
93 }
94 }
95
96 return 1;
97 }
98
99 /* calc penalty for empty interior columns */
100 static int dc_col_penalty(const char *Dots, const int Hgt, const int Wid) {
101 int x, penalty = 0, penalty_local = 0;
102
103 for (x = 1; x < Wid - 1; x++) {
104 if (dc_clr_col(Dots, Hgt, Wid, x)) {
105 if (penalty_local == 0) {
106 penalty_local = Hgt;
107 } else {
108 penalty_local *= Hgt;
109 }
110 } else {
111 if (penalty_local) {
112 penalty += penalty_local;
113 penalty_local = 0;
114 }
115 }
116 }
117
118 return penalty + penalty_local;
119 }
120
121 /* calc penalty for empty interior rows */
122 static int dc_row_penalty(const char *Dots, const int Hgt, const int Wid) {
123 int y, penalty = 0, penalty_local = 0;
124
125 for (y = 1; y < Hgt - 1; y++) {
126 if (dc_clr_row(Dots, Hgt, Wid, y)) {
127 if (penalty_local == 0) {
128 penalty_local = Wid;
129 } else {
130 penalty_local *= Wid;
131 }
132 } else {
133 if (penalty_local) {
134 penalty += penalty_local;
135 penalty_local = 0;
136 }
137 }
138 }
139
140 return penalty + penalty_local;
141 }
142
143 /* Dot pattern scoring routine from Annex A */
144 static int dc_score_array(const char Dots[], const int Hgt, const int Wid) {
145 int x, y, worstedge, first, last, sum;
146 int penalty = 0;
147
148 /* first, guard against "pathelogical" gaps in the array
149 subtract a penalty score for empty rows/columns from total code score for each mask,
150 where the penalty is Sum(N ^ n), where N is the number of positions in a column/row,
151 and n is the number of consecutive empty rows/columns */
152 penalty = dc_row_penalty(Dots, Hgt, Wid) + dc_col_penalty(Dots, Hgt, Wid);
153
154 sum = 0;
155 first = -1;
156 last = -1;
157
158 /* across the top edge, count printed dots and measure their extent */
159 for (x = 0; x < Wid; x += 2) {
160 if (dc_get_dot(Dots, Hgt, Wid, x, 0)) {
161 if (first < 0) {
162 first = x;
163 }
164 last = x;
165 sum++;
166 }
167 }
168 if (sum == 0) {
169 return SCORE_UNLIT_EDGE; /* guard against empty top edge */
170 }
171
172 worstedge = sum + last - first;
173 worstedge *= Hgt;
174
175 sum = 0;
176 first = -1;
177 last = -1;
178
179 /* across the bottom edge, ditto */
180 for (x = Wid & 1; x < Wid; x += 2) {
181 if (dc_get_dot(Dots, Hgt, Wid, x, Hgt - 1)) {
182 if (first < 0) {
183 first = x;
184 }
185 last = x;
186 sum++;
187 }
188 }
189 if (sum == 0) {
190 return SCORE_UNLIT_EDGE; /* guard against empty bottom edge */
191 }
192
193 sum += last - first;
194 sum *= Hgt;
195 if (sum < worstedge) {
196 worstedge = sum;
197 }
198
199 sum = 0;
200 first = -1;
201 last = -1;
202
203 /* down the left edge, ditto */
204 for (y = 0; y < Hgt; y += 2) {
205 if (dc_get_dot(Dots, Hgt, Wid, 0, y)) {
206 if (first < 0) {
207 first = y;
208 }
209 last = y;
210 sum++;
211 }
212 }
213 if (sum == 0) {
214 return SCORE_UNLIT_EDGE; /* guard against empty left edge */
215 }
216
217 sum += last - first;
218 sum *= Wid;
219 if (sum < worstedge) {
220 worstedge = sum;
221 }
222
223 sum = 0;
224 first = -1;
225 last = -1;
226
227 /* down the right edge, ditto */
228 for (y = Hgt & 1; y < Hgt; y += 2) {
229 if (dc_get_dot(Dots, Hgt, Wid, Wid - 1, y)) {
230 if (first < 0) {
231 first = y;
232 }
233 last = y;
234 sum++;
235 }
236 }
237 if (sum == 0) {
238 return SCORE_UNLIT_EDGE; /* guard against empty right edge */
239 }
240
241 sum += last - first;
242 sum *= Wid;
243 if (sum < worstedge) {
244 worstedge = sum;
245 }
246
247 /* throughout the array, count the # of unprinted 5-somes (cross patterns)
248 plus the # of printed dots surrounded by 8 unprinted neighbors */
249 sum = 0;
250 for (y = 0; y < Hgt; y++) {
251 for (x = y & 1; x < Wid; x += 2) {
252 if (!dc_get_dot(Dots, Hgt, Wid, x - 1, y - 1) && !dc_get_dot(Dots, Hgt, Wid, x + 1, y - 1)
253 && !dc_get_dot(Dots, Hgt, Wid, x - 1, y + 1) && !dc_get_dot(Dots, Hgt, Wid, x + 1, y + 1)
254 && (!dc_get_dot(Dots, Hgt, Wid, x, y)
255 || (!dc_get_dot(Dots, Hgt, Wid, x - 2, y) && !dc_get_dot(Dots, Hgt, Wid, x, y - 2)
256 && !dc_get_dot(Dots, Hgt, Wid, x + 2, y) && !dc_get_dot(Dots, Hgt, Wid, x, y + 2)))) {
257 sum++;
258 }
259 }
260 }
261
262 return (worstedge - sum * sum - penalty);
263 }
264
265 /*-------------------------------------------------------------------------
266 // "rsencode(nd,nc)" adds "nc" R-S check words to "nd" data words in wd[]
267 // employing Galois Field GF, where GF is prime, with a prime modulus of PM
268 //-------------------------------------------------------------------------*/
269
270 static void dc_rsencode(const int nd, const int nc, unsigned char *wd) {
271 /* Pre-calculated coefficients for GF(113) of generator polys of degree 3 to 39. To generate run
272 "backend/tests/test_dotcode -f generate -g" and place result below */
273 static const char coefs[820 - 5] = { /* 40*(41 + 1)/2 == 820 less 2 + 3 (degrees 1 and 2) */
274 1, 74, 12, 62,
275 1, 106, 7, 107, 63,
276 1, 89, 13, 101, 52, 59,
277 1, 38, 107, 3, 99, 6, 42,
278 1, 111, 56, 17, 92, 1, 28, 15,
279 1, 104, 70, 77, 86, 35, 21, 45, 8,
280 1, 83, 33, 76, 51, 37, 77, 56, 80, 58,
281 1, 20, 2, 31, 9, 101, 6, 64, 55, 103, 75,
282 1, 57, 64, 105, 26, 95, 14, 60, 50, 104, 44, 63,
283 1, 55, 63, 90, 42, 43, 50, 32, 43, 4, 62, 88, 100,
284 1, 49, 72, 51, 67, 17, 18, 71, 77, 85, 38, 55, 24, 78,
285 1, 31, 94, 111, 53, 54, 51, 86, 42, 55, 90, 49, 51, 98, 65,
286 1, 90, 2, 7, 48, 17, 73, 44, 31, 47, 58, 48, 4, 56, 84, 106,
287 1, 41, 112, 22, 44, 38, 31, 83, 22, 110, 15, 31, 25, 86, 52, 58, 4,
288 1, 7, 74, 56, 87, 11, 95, 46, 25, 40, 4, 86, 101, 27, 66, 98, 66, 90,
289 1, 18, 38, 79, 25, 64, 103, 74, 79, 89, 105, 17, 30, 8, 24, 33, 14, 25, 86,
290 1, 51, 67, 90, 33, 98, 68, 83, 35, 97, 104, 92, 26, 94, 62, 34, 86, 35, 7, 13,
291 1, 37, 31, 56, 16, 88, 52, 35, 3, 59, 102, 105, 94, 69, 102, 70, 62, 74, 82, 28, 44,
292 1, 108, 59, 110, 37, 94, 85, 111, 2, 46, 110, 2, 91, 76, 29, 80, 60, 69, 25, 87, 111, 73,
293 1, 95, 11, 21, 76, 65, 106, 23, 28, 20, 77, 41, 65, 23, 58, 42, 37, 80, 32, 101, 110, 99,
294 68,
295 1, 56, 35, 44, 48, 39, 57, 70, 35, 58, 88, 89, 48, 87, 65, 40, 94, 106, 76, 96, 13, 103,
296 49, 60,
297 1, 52, 37, 17, 98, 73, 14, 68, 94, 31, 82, 76, 31, 8, 56, 6, 47, 69, 104, 18, 81, 51,
298 89, 90, 99,
299 1, 40, 91, 25, 7, 27, 42, 13, 69, 33, 49, 109, 23, 88, 73, 12, 88, 70, 67, 13, 91, 96,
300 42, 39, 36, 55,
301 1, 4, 7, 26, 11, 1, 87, 83, 53, 35, 104, 40, 54, 51, 69, 96, 108, 66, 33, 87, 75, 97,
302 89, 109, 101, 2, 54,
303 1, 9, 27, 61, 28, 56, 92, 66, 16, 74, 53, 108, 28, 95, 98, 102, 23, 41, 24, 26, 58, 20,
304 9, 102, 81, 55, 64, 44,
305 1, 24, 49, 14, 39, 24, 28, 90, 102, 88, 33, 112, 66, 63, 54, 103, 84, 47, 74, 47, 109, 99,
306 83, 11, 29, 27, 98, 100, 95,
307 1, 69, 112, 72, 104, 84, 91, 107, 84, 45, 38, 15, 21, 95, 64, 47, 86, 98, 42, 100, 77, 32,
308 18, 17, 72, 89, 70, 103, 75, 94,
309 1, 91, 48, 50, 106, 112, 18, 75, 65, 85, 11, 60, 12, 105, 7, 99, 103, 69, 51, 7, 17, 31,
310 44, 74, 107, 91, 107, 61, 81, 49, 34,
311 1, 44, 65, 54, 16, 102, 65, 20, 43, 81, 84, 108, 17, 106, 44, 109, 83, 87, 85, 96, 27, 23,
312 56, 40, 19, 34, 11, 4, 39, 84, 104, 97,
313 1, 16, 76, 42, 86, 106, 34, 8, 48, 7, 76, 16, 44, 82, 14, 7, 82, 23, 22, 89, 51, 58,
314 90, 54, 29, 67, 76, 35, 40, 9, 12, 10, 109,
315 1, 45, 88, 99, 61, 1, 57, 90, 54, 43, 53, 73, 56, 2, 19, 74, 59, 28, 11, 49, 33, 68,
316 77, 65, 13, 4, 98, 92, 38, 39, 47, 19, 60, 110,
317 1, 19, 48, 71, 86, 110, 31, 77, 87, 108, 65, 51, 79, 15, 80, 32, 56, 76, 74, 102, 2, 1,
318 4, 97, 18, 5, 107, 30, 19, 68, 50, 40, 18, 19, 78,
319 1, 54, 35, 56, 85, 69, 39, 32, 70, 102, 3, 66, 56, 68, 40, 7, 46, 2, 22, 93, 69, 71,
320 39, 11, 23, 70, 56, 46, 52, 55, 57, 95, 62, 84, 65, 18,
321 1, 46, 55, 2, 89, 67, 52, 59, 40, 107, 91, 42, 93, 72, 61, 26, 103, 86, 6, 30, 3, 84,
322 36, 38, 48, 112, 61, 50, 23, 91, 69, 91, 93, 40, 71, 63, 82,
323 1, 22, 81, 38, 41, 78, 26, 54, 93, 51, 9, 5, 102, 100, 28, 31, 44, 100, 89, 112, 74, 12,
324 54, 78, 40, 90, 85, 55, 66, 104, 32, 17, 56, 68, 15, 54, 39, 66,
325 1, 63, 79, 82, 17, 64, 60, 103, 47, 22, 66, 35, 81, 101, 60, 49, 72, 96, 8, 32, 33, 108,
326 94, 32, 74, 35, 46, 37, 61, 98, 2, 86, 75, 104, 91, 104, 106, 83, 107,
327 1, 73, 31, 81, 46, 8, 22, 25, 60, 40, 60, 17, 92, 7, 53, 84, 110, 25, 64, 112, 14, 99,
328 44, 68, 55, 97, 57, 45, 92, 30, 78, 106, 31, 63, 1, 110, 16, 13, 33, 53,
329 };
330 static const short cinds[39 - 2] = { /* Indexes into above coefs[] array */
331 0, 4, 9, 15, 22, 30, 39, 49, 60, 72, 85, 99, 114, 130, 147, 165, 184, 204, 225, 247, 270, 294,
332 319, 345, 372, 400, 429, 459, 490, 522, 555, 589, 624, 660, 697, 735, 774,
333 };
334 int i, j, k, nw, start, step;
335 const char *c;
336
337 /* Here we compute how many interleaved R-S blocks will be needed */
338 nw = nd + nc;
339 step = (nw + GF - 2) / (GF - 1);
340
341 /* ...& then for each such block: */
342 for (start = 0; start < step; start++) {
343 const int ND = (nd - start + step - 1) / step;
344 const int NW = (nw - start + step - 1) / step;
345 const int NC = NW - ND;
346 unsigned char *const e = wd + start + ND * step;
347
348 /* first set the generator polynomial "c" of order "NC": */
349 c = coefs + cinds[NC - 3];
350
351 /* & then compute the corresponding checkword values into wd[]
352 ... (a) starting at wd[start] & (b) stepping by step */
353 for (i = 0; i < NC; i++) {
354 e[i * step] = 0;
355 }
356 for (i = 0; i < ND; i++) {
357 k = (wd[start + i * step] + e[0]) % GF;
358 for (j = 0; j < NC - 1; j++) {
359 e[j * step] = (GF - ((c[j + 1] * k) % GF) + e[(j + 1) * step]) % GF;
360 }
361 e[(NC - 1) * step] = (GF - ((c[NC] * k) % GF)) % GF;
362 }
363 for (i = 0; i < NC; i++) {
364 if (e[i * step]) {
365 e[i * step] = GF - e[i * step];
366 }
367 }
368 }
369 }
370
371 /* Check if the next character is directly encodable in code set A (Annex F.II.D) */
372 static int dc_datum_a(const unsigned char source[], const int length, const int position) {
373
374 if (position < length && source[position] <= 95) {
375 return 1;
376 }
377
378 return 0;
379 }
380
381 /* Check if the next character is directly encodable in code set B (Annex F.II.D).
382 * Note changed to return 2 if CR/LF */
383 static int dc_datum_b(const unsigned char source[], const int length, const int position) {
384
385 if (position < length) {
386 if ((source[position] >= 32) && (source[position] <= 127)) {
387 return 1;
388 }
389
390 switch (source[position]) {
391 case 9: /* HT */
392 case 28: /* FS */
393 case 29: /* GS */
394 case 30: /* RS */
395 return 1;
396 break;
397 }
398
399 if ((position + 1 < length) && (source[position] == 13) && (source[position + 1] == 10)) { /* CRLF */
400 return 2;
401 }
402 }
403
404 return 0;
405 }
406
407 /* Check if the next characters are directly encodable in code set C (Annex F.II.D) */
408 static int dc_datum_c(const unsigned char source[], const int length, const int position) {
409 return is_twodigits(source, length, position);
410 }
411
412 /* Checks ahead for 10 or more digits starting "17xxxxxx10..." (Annex F.II.B) */
413 static int dc_seventeen_ten(const unsigned char source[], const int length, const int position) {
414
415 if (position + 9 < length && source[position] == '1' && source[position + 1] == '7'
416 && source[position + 8] == '1' && source[position + 9] == '0'
417 && cnt_digits(source, length, position + 2, 6) >= 6) {
418 return 1;
419 }
420
421 return 0;
422 }
423
424 /* Checks how many characters ahead can be reached while dc_datum_c is true,
425 * returning the resulting number of codewords (Annex F.II.E)
426 */
427 static int dc_ahead_c(const unsigned char source[], const int length, const int position) {
428 int count = 0;
429 int i;
430
431 for (i = position; (i < length) && dc_datum_c(source, length, i); i += 2) {
432 count++;
433 }
434
435 return count;
436 }
437
438 /* Annex F.II.F */
439 static int dc_try_c(const unsigned char source[], const int length, const int position) {
440
441 if (position < length && z_isdigit(source[position])) { /* cnt_digits(position) > 0 */
442 const int ahead_c_position = dc_ahead_c(source, length, position);
443 if (ahead_c_position > dc_ahead_c(source, length, position + 1)) {
444 return ahead_c_position;
445 }
446 }
447
448 return 0;
449 }
450
451 /* Annex F.II.G */
452 static int dc_ahead_a(const unsigned char source[], const int length, const int position) {
453 int count = 0;
454 int i;
455
456 for (i = position; i < length && dc_datum_a(source, length, i) && dc_try_c(source, length, i) < 2; i++) {
457 count++;
458 }
459
460 return count;
461 }
462
463 /* Annex F.II.H Note: changed to return number of chars encodable. Number of codewords returned in *p_nx. */
464 static int dc_ahead_b(const unsigned char source[], const int length, const int position, int *p_nx) {
465 int count = 0;
466 int i, incr;
467
468 for (i = position; i < length && (incr = dc_datum_b(source, length, i))
469 && dc_try_c(source, length, i) < 2; i += incr) {
470 count++;
471 }
472
473 if (p_nx != NULL) {
474 *p_nx = count;
475 }
476
477 return i - position;
478 }
479
480 /* Checks if the next character is in the range 128 to 255 (Annex F.II.I) */
481 static int dc_binary(const unsigned char source[], const int length, const int position) {
482
483 if (position < length && source[position] >= 128) {
484 return 1;
485 }
486
487 return 0;
488 }
489
490 /* Empty binary buffer */
491 static int dc_empty_bin_buf(unsigned char *codeword_array, int ap, uint64_t *p_bin_buf, int *p_bin_buf_size) {
492 int i;
493 int lawrencium[6]; /* Reversed radix 103 values */
494 uint64_t bin_buf = *p_bin_buf;
495 int bin_buf_size = *p_bin_buf_size;
496
497 if (bin_buf_size) {
498 for (i = 0; i < bin_buf_size + 1; i++) {
499 lawrencium[i] = (int) (bin_buf % 103);
500 bin_buf /= 103;
501 }
502
503 for (i = 0; i < bin_buf_size + 1; i++) {
504 codeword_array[ap++] = lawrencium[bin_buf_size - i];
505 }
506 }
507
508 *p_bin_buf = 0;
509 *p_bin_buf_size = 0;
510
511 return ap;
512 }
513
514 /* Add value to binary buffer, emptying if full */
515 static int dc_append_to_bin_buf(unsigned char *codeword_array, int ap, unsigned int val, uint64_t *p_bin_buf,
516 int *p_bin_buf_size) {
517
518 *p_bin_buf *= 259;
519 *p_bin_buf += val;
520 (*p_bin_buf_size)++;
521
522 if (*p_bin_buf_size == 5) {
523 ap = dc_empty_bin_buf(codeword_array, ap, p_bin_buf, p_bin_buf_size);
524 }
525
526 return ap;
527 }
528
529 /* Analyse input data stream and encode using algorithm from Annex F */
530 static int dc_encode_message(struct zint_symbol *symbol, const unsigned char source[], const int length,
531 const int eci, const int last_seg, const int last_EOT, const int last_RSEOT,
532 int ap, unsigned char *codeword_array, char *p_encoding_mode, int *p_inside_macro,
533 uint64_t *p_bin_buf, int *p_bin_buf_size, unsigned char structapp_array[], int *p_structapp_size) {
534 static const char lead_specials[] = "\x09\x1C\x1D\x1E"; /* HT, FS, GS, RS */
535
536 int i;
537 int position = 0;
538 char encoding_mode = *p_encoding_mode;
539 int inside_macro = *p_inside_macro;
540 uint64_t bin_buf = *p_bin_buf;
541 int bin_buf_size = *p_bin_buf_size;
542 int nx;
543
544 const int first_seg = ap == 0;
545 const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE;
546 const int debug_print = (symbol->debug & ZINT_DEBUG_PRINT);
547
548 if (first_seg) {
549 if (symbol->output_options & READER_INIT) {
550 codeword_array[ap++] = 109; /* FNC3 */
551
552 } else if (!gs1 && eci == 0 && length > 2 && is_twodigits(source, length, 0)) {
553 codeword_array[ap++] = 107; /* FNC1 */
554
555 } else if (posn(lead_specials, source[0]) != -1) {
556 /* Prevent encodation as a macro if a special character is in first position */
557 codeword_array[ap++] = 101; /* Latch A */
558 codeword_array[ap++] = source[0] + 64;
559 encoding_mode = 'A';
560 position++;
561
562 } else if (length > 5) { /* Note assuming macro headers don't straddle segments */
563 /* Step C1 */
564 if (source[0] == '[' && source[1] == ')' && source[2] == '>' && source[3] == 30 /*RS*/ && last_EOT) {
565 int format_050612 = (source[4] == '0' && (source[5] == '5' || source[5] == '6'))
566 || (source[4] == '1' && source[5] == '2');
567 inside_macro = 0;
568 if (length > 6 && format_050612 && source[6] == 29 /*GS*/ && last_RSEOT) {
569 if (source[5] == '5') {
570 inside_macro = 97;
571 } else if (source[5] == '6') {
572 inside_macro = 98;
573 } else {
574 inside_macro = 99;
575 }
576 } else if (!format_050612 && is_twodigits(source, length, 4) ) {
577 inside_macro = 100; /* Note no longer using for malformed 05/06/12 */
578 }
579 if (inside_macro) {
580 codeword_array[ap++] = 106; /* Latch B */
581 encoding_mode = 'B';
582 codeword_array[ap++] = inside_macro; /* Macro */
583 if (inside_macro == 100) {
584 codeword_array[ap++] = ctoi(source[4]) + 16;
585 codeword_array[ap++] = ctoi(source[5]) + 16;
586 position += 6;
587 } else {
588 position += 7;
589 }
590 if (debug_print) printf("C1/%d ", inside_macro - 96);
591 }
592 }
593 }
594 }
595
596 if (eci > 0) {
597 if (encoding_mode == 'X') {
598 if (eci <= 0xFF) {
599 ap = dc_append_to_bin_buf(codeword_array, ap, 256, &bin_buf, &bin_buf_size);
600 ap = dc_append_to_bin_buf(codeword_array, ap, eci, &bin_buf, &bin_buf_size);
601 /* Following BWIPP, assuming big-endian byte order */
602 } else if (eci <= 0xFFFF) {
603 ap = dc_append_to_bin_buf(codeword_array, ap, 257, &bin_buf, &bin_buf_size);
604 ap = dc_append_to_bin_buf(codeword_array, ap, eci >> 8, &bin_buf, &bin_buf_size);
605 ap = dc_append_to_bin_buf(codeword_array, ap, eci & 0xFF, &bin_buf, &bin_buf_size);
606 } else {
607 ap = dc_append_to_bin_buf(codeword_array, ap, 258, &bin_buf, &bin_buf_size);
608 ap = dc_append_to_bin_buf(codeword_array, ap, eci >> 16, &bin_buf, &bin_buf_size);
609 ap = dc_append_to_bin_buf(codeword_array, ap, (eci >> 8) & 0xFF, &bin_buf, &bin_buf_size);
610 ap = dc_append_to_bin_buf(codeword_array, ap, eci & 0xFF, &bin_buf, &bin_buf_size);
611 }
612 } else {
613 codeword_array[ap++] = 108; /* FNC2 */
614 if (eci <= 39) {
615 codeword_array[ap++] = eci;
616 } else {
617 /* the next three codewords valued A, B & C encode the ECI value of
618 (A - 40) * 12769 + B * 113 + C + 40 (Section 5.2.1) */
619 int a, b, c;
620 a = (eci - 40) / 12769;
621 b = ((eci - 40) - (12769 * a)) / 113;
622 c = (eci - 40) - (12769 * a) - (113 * b);
623
624 codeword_array[ap++] = a + 40;
625 codeword_array[ap++] = b;
626 codeword_array[ap++] = c;
627 }
628 }
629 }
630
631 while (position < length) {
632 /* Step A */
633 if (last_seg && (position == length - 2) && (inside_macro != 0) && (inside_macro != 100)) {
634 /* inside_macro only gets set to 97, 98 or 99 if the last two characters are RS/EOT */
635 position += 2;
636 if (debug_print) fputs("A ", stdout);
637 continue;
638 }
639
640 /* Step B */
641 if (last_seg && (position == length - 1) && (inside_macro == 100)) {
642 /* inside_macro only gets set to 100 if the last character is EOT */
643 position++;
644 if (debug_print) fputs("B ", stdout);
645 continue;
646 }
647
648 if (encoding_mode == 'C') {
649
650 /* Step C2 */
651 if (dc_seventeen_ten(source, length, position)) {
652 codeword_array[ap++] = 100; /* (17)...(10) */
653 codeword_array[ap++] = to_int(source + position + 2, 2);
654 codeword_array[ap++] = to_int(source + position + 4, 2);
655 codeword_array[ap++] = to_int(source + position + 6, 2);
656 position += 10;
657 if (debug_print) fputs("C2/1 ", stdout);
658 continue;
659 }
660
661 if (dc_datum_c(source, length, position) || (gs1 && source[position] == '\x1D')) {
662 if (source[position] == '\x1D') {
663 codeword_array[ap++] = 107; /* FNC1 */
664 position++;
665 } else {
666 codeword_array[ap++] = to_int(source + position, 2);
667 position += 2;
668 }
669 if (debug_print) fputs("C2/2 ", stdout);
670 continue;
671 }
672
673 /* Step C3 */
674 if (dc_binary(source, length, position)) {
675 /* cnt_digits(position + 1) > 0 */
676 if (position + 1 < length && z_isdigit(source[position + 1])) {
677 if ((source[position] - 128) < 32) {
678 codeword_array[ap++] = 110; /* Upper Shift A */
679 codeword_array[ap++] = source[position] - 128 + 64;
680 } else {
681 codeword_array[ap++] = 111; /* Upper Shift B */
682 codeword_array[ap++] = source[position] - 128 - 32;
683 }
684 position++;
685 } else {
686 codeword_array[ap++] = 112; /* Bin Latch */
687 encoding_mode = 'X';
688 }
689 if (debug_print) fputs("C3 ", stdout);
690 continue;
691 }
692
693 /* Step C4 */
694 {
695 const int m = dc_ahead_a(source, length, position);
696 const int n = dc_ahead_b(source, length, position, &nx);
697 if (m > n) {
698 codeword_array[ap++] = 101; /* Latch A */
699 encoding_mode = 'A';
700 } else {
701 if (nx >= 1 && nx <= 4) {
702 codeword_array[ap++] = 101 + nx; /* nx Shift B */
703
704 for (i = 0; i < nx; i++) {
705 if (source[position] >= 32) {
706 codeword_array[ap++] = source[position] - 32;
707 } else if (source[position] == 13) { /* CR/LF */
708 codeword_array[ap++] = 96;
709 position++;
710 } else {
711 switch (source[position]) {
712 case 9: codeword_array[ap++] = 97; break; /* HT */
713 case 28: codeword_array[ap++] = 98; break; /* FS */
714 case 29: codeword_array[ap++] = 99; break; /* GS */
715 case 30: codeword_array[ap++] = 100; break; /* RS */
716 }
717 }
718 position++;
719 }
720 } else {
721 codeword_array[ap++] = 106; /* Latch B */
722 encoding_mode = 'B';
723 }
724 }
725 if (debug_print) fputs("C4 ", stdout);
726 continue;
727 }
728 } /* encoding_mode == 'C' */
729
730 if (encoding_mode == 'B') {
731 /* Step D1 */
732 const int n = dc_try_c(source, length, position);
733
734 if (n >= 2) {
735 if (n <= 4) {
736 codeword_array[ap++] = 103 + (n - 2); /* nx Shift C */
737 for (i = 0; i < n; i++) {
738 codeword_array[ap++] = to_int(source + position, 2);
739 position += 2;
740 }
741 } else {
742 codeword_array[ap++] = 106; /* Latch C */
743 encoding_mode = 'C';
744 }
745 if (debug_print) fputs("D1 ", stdout);
746 continue;
747 }
748
749 /* Step D2 */
750 if (gs1 && source[position] == '\x1D') {
751 codeword_array[ap++] = 107; /* FNC1 */
752 position++;
753 if (debug_print) fputs("D2/1 ", stdout);
754 continue;
755 }
756
757 if (dc_datum_b(source, length, position)) {
758 int done = 0;
759
760 if ((source[position] >= 32) && (source[position] <= 127)) {
761 codeword_array[ap++] = source[position] - 32;
762 done = 1;
763
764 } else if (source[position] == 13) {
765 /* CR/LF */
766 codeword_array[ap++] = 96;
767 position++;
768 done = 1;
769
770 } else if (!first_seg || position != 0) {
771 /* HT, FS, GS and RS in the first data position would be interpreted as a macro
772 * (see table 2) */
773 switch (source[position]) {
774 case 9: codeword_array[ap++] = 97; break; /* HT */
775 case 28: codeword_array[ap++] = 98; break; /* FS */
776 case 29: codeword_array[ap++] = 99; break; /* GS */
777 case 30: codeword_array[ap++] = 100; break; /* RS */
778 }
779 done = 1;
780 }
781
782 if (done == 1) {
783 position++;
784 if (debug_print) fputs("D2/2 ", stdout);
785 continue;
786 }
787 }
788
789 /* Step D3 */
790 if (dc_binary(source, length, position)) {
791 if (dc_datum_b(source, length, position + 1)) {
792 if ((source[position] - 128) < 32) {
793 codeword_array[ap++] = 110; /* Bin Shift A */
794 codeword_array[ap++] = source[position] - 128 + 64;
795 } else {
796 codeword_array[ap++] = 111; /* Bin Shift B */
797 codeword_array[ap++] = source[position] - 128 - 32;
798 }
799 position++;
800 } else {
801 codeword_array[ap++] = 112; /* Bin Latch */
802 encoding_mode = 'X';
803 }
804 if (debug_print) fputs("D3 ", stdout);
805 continue;
806 }
807
808 /* Step D4 */
809 if (dc_ahead_a(source, length, position) == 1) {
810 codeword_array[ap++] = 101; /* Shift A */
811 if (source[position] < 32) {
812 codeword_array[ap++] = source[position] + 64;
813 } else {
814 codeword_array[ap++] = source[position] - 32;
815 }
816 position++;
817 } else {
818 codeword_array[ap++] = 102; /* Latch A */
819 encoding_mode = 'A';
820 }
821 if (debug_print) fputs("D4 ", stdout);
822 continue;
823 } /* encoding_mode == 'B' */
824
825 if (encoding_mode == 'A') {
826 /* Step E1 */
827 const int n = dc_try_c(source, length, position);
828 if (n >= 2) {
829 if (n <= 4) {
830 codeword_array[ap++] = 103 + (n - 2); /* nx Shift C */
831 for (i = 0; i < n; i++) {
832 codeword_array[ap++] = to_int(source + position, 2);
833 position += 2;
834 }
835 } else {
836 codeword_array[ap++] = 106; /* Latch C */
837 encoding_mode = 'C';
838 }
839 if (debug_print) fputs("E1 ", stdout);
840 continue;
841 }
842
843 /* Step E2 */
844 if (gs1 && source[position] == '\x1D') {
845 /* Note: this branch probably never reached as no reason to be in Code Set A for GS1 data */
846 codeword_array[ap++] = 107; /* FNC1 */
847 position++;
848 if (debug_print) fputs("E2/1 ", stdout);
849 continue;
850 }
851 if (dc_datum_a(source, length, position)) {
852 if (source[position] < 32) {
853 codeword_array[ap++] = source[position] + 64;
854 } else {
855 codeword_array[ap++] = source[position] - 32;
856 }
857 position++;
858 if (debug_print) fputs("E2/2 ", stdout);
859 continue;
860 }
861
862 /* Step E3 */
863 if (dc_binary(source, length, position)) {
864 if (dc_datum_a(source, length, position + 1)) {
865 if ((source[position] - 128) < 32) {
866 codeword_array[ap++] = 110; /* Bin Shift A */
867 codeword_array[ap++] = source[position] - 128 + 64;
868 } else {
869 codeword_array[ap++] = 111; /* Bin Shift B */
870 codeword_array[ap++] = source[position] - 128 - 32;
871 }
872 position++;
873 } else {
874 codeword_array[ap++] = 112; /* Bin Latch */
875 encoding_mode = 'X';
876 }
877 if (debug_print) fputs("E3 ", stdout);
878 continue;
879 }
880
881 /* Step E4 */
882 dc_ahead_b(source, length, position, &nx);
883
884 if (nx >= 1 && nx <= 6) {
885 codeword_array[ap++] = 95 + nx; /* nx Shift B */
886 for (i = 0; i < nx; i++) {
887 if (source[position] >= 32) {
888 codeword_array[ap++] = source[position] - 32;
889 } else if (source[position] == 13) { /* CR/LF */
890 codeword_array[ap++] = 96;
891 position++;
892 } else {
893 switch (source[position]) {
894 case 9: codeword_array[ap++] = 97; break; /* HT */
895 case 28: codeword_array[ap++] = 98; break; /* FS */
896 case 29: codeword_array[ap++] = 99; break; /* GS */
897 case 30: codeword_array[ap++] = 100; break; /* RS */
898 }
899 }
900 position++;
901 }
902 } else {
903 codeword_array[ap++] = 102; /* Latch B */
904 encoding_mode = 'B';
905 }
906 if (debug_print) fputs("E4 ", stdout);
907 continue;
908 } /* encoding_mode == 'A' */
909
910 /* Step F1 */
911 if (encoding_mode == 'X') {
912 const int n = dc_try_c(source, length, position);
913
914 if (n >= 2) {
915 ap = dc_empty_bin_buf(codeword_array, ap, &bin_buf, &bin_buf_size);
916
917 if (n <= 7) {
918 codeword_array[ap++] = 101 + n; /* Interrupt for nx Shift C */
919 for (i = 0; i < n; i++) {
920 codeword_array[ap++] = to_int(source + position, 2);
921 position += 2;
922 }
923 } else {
924 codeword_array[ap++] = 111; /* Terminate with Latch to C */
925 encoding_mode = 'C';
926 }
927 if (debug_print) fputs("F1 ", stdout);
928 continue;
929 }
930
931 /* Step F2 */
932 /* Section 5.2.1.1 para D.2.i states:
933 * "Groups of six codewords, each valued between 0 and 102, are radix converted from
934 * base 103 into five base 259 values..."
935 */
936 if (dc_binary(source, length, position)
937 || dc_binary(source, length, position + 1)
938 || dc_binary(source, length, position + 2)
939 || dc_binary(source, length, position + 3)) {
940 ap = dc_append_to_bin_buf(codeword_array, ap, source[position], &bin_buf, &bin_buf_size);
941 position++;
942 if (debug_print) fputs("F2 ", stdout);
943 continue;
944 }
945
946 /* Step F3 */
947 ap = dc_empty_bin_buf(codeword_array, ap, &bin_buf, &bin_buf_size); /* Empty binary buffer */
948
949 if (dc_ahead_a(source, length, position) > dc_ahead_b(source, length, position, NULL)) {
950 codeword_array[ap++] = 109; /* Terminate with Latch to A */
951 encoding_mode = 'A';
952 } else {
953 codeword_array[ap++] = 110; /* Terminate with Latch to B */
954 encoding_mode = 'B';
955 }
956 if (debug_print) fputs("F3 ", stdout);
957 } /* encoding_mode == 'X' */
958 }
959
960 if (last_seg) {
961 if (encoding_mode == 'X' && bin_buf_size != 0) {
962 /* Empty binary buffer */
963 ap = dc_empty_bin_buf(codeword_array, ap, &bin_buf, &bin_buf_size);
964 }
965
966 if (symbol->structapp.count) {
967 int sp = 0;
968 /* Need Code Set A or B - choosing A here (TEC-IT chooses B) */
969 if (encoding_mode == 'C') {
970 structapp_array[sp++] = 101; /* Latch A */
971 } else if (encoding_mode == 'X') {
972 structapp_array[sp++] = 109; /* Terminate with Latch A */
973 }
974 if (symbol->structapp.index < 10) {
975 structapp_array[sp++] = 16 + symbol->structapp.index; /* '0' + index for 1-9 */
976 } else {
977 structapp_array[sp++] = 33 + symbol->structapp.index - 10; /* 'A' + index for A-Z */
978 }
979 if (symbol->structapp.count < 10) {
980 structapp_array[sp++] = 16 + symbol->structapp.count; /* '0' + count for 1-9 */
981 } else {
982 structapp_array[sp++] = 33 + symbol->structapp.count - 10; /* 'A' + count for A-Z */
983 }
984 structapp_array[sp++] = 108; /* FNC2 as last codeword */
985 *p_structapp_size = sp;
986 }
987 }
988
989 if (debug_print) {
990 fputc('\n', stdout);
991 }
992
993 *p_encoding_mode = encoding_mode;
994 *p_inside_macro = inside_macro;
995 *p_bin_buf = bin_buf;
996 *p_bin_buf_size = bin_buf_size;
997
998 return ap;
999 }
1000
1001 /* Call `dc_encode_message()` for each segment */
1002 static int dc_encode_message_segs(struct zint_symbol *symbol, const struct zint_seg segs[], const int seg_count,
1003 unsigned char *codeword_array, int *p_binary_finish, unsigned char structapp_array[],
1004 int *p_structapp_size) {
1005 int i;
1006
1007 int last_EOT = 0;
1008 int last_RSEOT = 0;
1009 int ap = 0;
1010 char encoding_mode = 'C';
1011 int inside_macro = 0;
1012 uint64_t bin_buf = 0;
1013 int bin_buf_size = 0;
1014
1015 const struct zint_seg *last_seg = &segs[seg_count - 1];
1016
1017 last_EOT = last_seg->source[last_seg->length - 1] == 4; /* EOT */
1018 if (last_EOT && last_seg->length > 1) {
1019 last_RSEOT = last_seg->source[last_seg->length - 2] == 30; /* RS */
1020 }
1021
1022 for (i = 0; i < seg_count; i++) {
1023 ap = dc_encode_message(symbol, segs[i].source, segs[i].length, segs[i].eci, i == seg_count - 1 /*last_seg*/,
1024 last_EOT, last_RSEOT, ap, codeword_array, &encoding_mode, &inside_macro, &bin_buf, &bin_buf_size,
1025 structapp_array, p_structapp_size);
1026 }
1027
1028 *p_binary_finish = encoding_mode == 'X';
1029
1030 return ap + *p_structapp_size;
1031 }
1032
1033 /* Convert codewords to binary data stream */
1034 static int dc_make_dotstream(const unsigned char masked_array[], const int array_length, char dot_stream[]) {
1035 int i;
1036 int bp = 0;
1037
1038 /* Mask value is encoded as two dots */
1039 bp = bin_append_posn(masked_array[0], 2, dot_stream, bp);
1040
1041 /* The rest of the data uses 9-bit dot patterns from Annex C */
1042 for (i = 1; i < array_length; i++) {
1043 bp = bin_append_posn(dc_dot_patterns[masked_array[i]], 9, dot_stream, bp);
1044 }
1045
1046 return bp;
1047 }
1048
1049 /* Determines if a given dot is a reserved corner dot
1050 * to be used by one of the last six bits
1051 */
1052 static int dc_is_corner(const int column, const int row, const int width, const int height) {
1053
1054 /* Top Left */
1055 if ((column == 0) && (row == 0)) {
1056 return 1;
1057 }
1058
1059 /* Top Right */
1060 if (height & 1) {
1061 if (((column == width - 2) && (row == 0))
1062 || ((column == width - 1) && (row == 1))) {
1063 return 1;
1064 }
1065 } else {
1066 if ((column == width - 1) && (row == 0)) {
1067 return 1;
1068 }
1069 }
1070
1071 /* Bottom Left */
1072 if (height & 1) {
1073 if ((column == 0) && (row == height - 1)) {
1074 return 1;
1075 }
1076 } else {
1077 if (((column == 0) && (row == height - 2))
1078 || ((column == 1) && (row == height - 1))) {
1079 return 1;
1080 }
1081 }
1082
1083 /* Bottom Right */
1084 if (((column == width - 2) && (row == height - 1))
1085 || ((column == width - 1) && (row == height - 2))) {
1086 return 1;
1087 }
1088
1089 return 0;
1090 }
1091
1092 /* Place the dots in the symbol*/
1093 static void dc_fold_dotstream(const char dot_stream[], const int width, const int height, char dot_array[]) {
1094 int column, row;
1095 int position = 0;
1096
1097 if (height & 1) {
1098 /* Horizontal folding */
1099 for (row = 0; row < height; row++) {
1100 for (column = 0; column < width; column++) {
1101 if (!((column + row) & 1)) {
1102 if (dc_is_corner(column, row, width, height)) {
1103 dot_array[(row * width) + column] = 'C';
1104 } else {
1105 dot_array[((height - row - 1) * width) + column] = dot_stream[position++];
1106 }
1107 } else {
1108 dot_array[((height - row - 1) * width) + column] = ' '; /* Non-data position */
1109 }
1110 }
1111 }
1112
1113 /* Corners */
1114 dot_array[width - 2] = dot_stream[position++];
1115 dot_array[(height * width) - 2] = dot_stream[position++];
1116 dot_array[(width * 2) - 1] = dot_stream[position++];
1117 dot_array[((height - 1) * width) - 1] = dot_stream[position++];
1118 dot_array[0] = dot_stream[position++];
1119 dot_array[(height - 1) * width] = dot_stream[position];
1120 } else {
1121 /* Vertical folding */
1122 for (column = 0; column < width; column++) {
1123 for (row = 0; row < height; row++) {
1124 if (!((column + row) & 1)) {
1125 if (dc_is_corner(column, row, width, height)) {
1126 dot_array[(row * width) + column] = 'C';
1127 } else {
1128 dot_array[(row * width) + column] = dot_stream[position++];
1129 }
1130 } else {
1131 dot_array[(row * width) + column] = ' '; /* Non-data position */
1132 }
1133 }
1134 }
1135
1136 /* Corners */
1137 dot_array[((height - 1) * width) - 1] = dot_stream[position++];
1138 dot_array[(height - 2) * width] = dot_stream[position++];
1139 dot_array[(height * width) - 2] = dot_stream[position++];
1140 dot_array[((height - 1) * width) + 1] = dot_stream[position++];
1141 dot_array[width - 1] = dot_stream[position++];
1142 dot_array[0] = dot_stream[position];
1143 }
1144 }
1145
1146 static void dc_apply_mask(const int mask, const int data_length, unsigned char *masked_codeword_array,
1147 const unsigned char *codeword_array, const int ecc_length) {
1148 int weight = 0;
1149 int j;
1150
1151 assert(mask >= 0 && mask <= 3); /* Suppress clang-analyzer taking default branch */
1152 assert(data_length > 0); /* Suppress clang-analyzer-core.UndefinedBinaryOperatorResult */
1153 switch (mask) {
1154 case 0:
1155 masked_codeword_array[0] = 0;
1156 for (j = 0; j < data_length; j++) {
1157 masked_codeword_array[j + 1] = codeword_array[j];
1158 }
1159 break;
1160 case 1:
1161 masked_codeword_array[0] = 1;
1162 for (j = 0; j < data_length; j++) {
1163 masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113;
1164 weight += 3;
1165 }
1166 break;
1167 case 2:
1168 masked_codeword_array[0] = 2;
1169 for (j = 0; j < data_length; j++) {
1170 masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113;
1171 weight += 7;
1172 }
1173 break;
1174 case 3:
1175 masked_codeword_array[0] = 3;
1176 for (j = 0; j < data_length; j++) {
1177 masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113;
1178 weight += 17;
1179 }
1180 break;
1181 }
1182
1183 dc_rsencode(data_length + 1, ecc_length, masked_codeword_array);
1184 }
1185
1186 static void dc_force_corners(const int width, const int height, char *dot_array) {
1187 if (width & 1) {
1188 /* "Vertical" symbol */
1189 dot_array[0] = '1';
1190 dot_array[width - 1] = '1';
1191 dot_array[(height - 2) * width] = '1';
1192 dot_array[((height - 1) * width) - 1] = '1';
1193 dot_array[((height - 1) * width) + 1] = '1';
1194 dot_array[(height * width) - 2] = '1';
1195 } else {
1196 /* "Horizontal" symbol */
1197 dot_array[0] = '1';
1198 dot_array[width - 2] = '1';
1199 dot_array[(2 * width) - 1] = '1';
1200 dot_array[((height - 1) * width) - 1] = '1';
1201 dot_array[(height - 1) * width] = '1';
1202 dot_array[(height * width) - 2] = '1';
1203 }
1204 }
1205
1206 INTERNAL int dotcode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
1207 int warn_number = 0;
1208 int i, j, k;
1209 int jc, n_dots;
1210 int data_length, ecc_length;
1211 int min_dots, min_area;
1212 int height, width;
1213 int mask_score[8];
1214 int user_mask;
1215 int dot_stream_length;
1216 int high_score, best_mask;
1217 int binary_finish = 0;
1218 unsigned char structapp_array[5];
1219 int structapp_size = 0;
1220 int padding_dots;
1221 const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE;
1222 const int debug_print = (symbol->debug & ZINT_DEBUG_PRINT);
1223 /* Allow 4 codewords per input + 2 (FNC) + seg_count * 4 (ECI) + 2 (special char 1st position)
1224 + 5 (Structured Append) + 10 (PAD) */
1225 const int codeword_array_len = segs_length(segs, seg_count) * 4 + 2 + seg_count * 4 + 2 + 5 + 10;
1226 unsigned char *codeword_array = (unsigned char *) z_alloca(codeword_array_len);
1227 char *dot_stream;
1228 char *dot_array;
1229 unsigned char *masked_codeword_array;
1230
1231 if (symbol->eci > 811799) {
1232 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 525, "ECI code '%d' out of range (0 to 811799)",
1233 symbol->eci);
1234 }
1235
1236 user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is mask + 1, so >= 1 and <= 8 */
1237 if (user_mask > 8) {
1238 user_mask = 0; /* Ignore */
1239 }
1240
1241 if (symbol->structapp.count) {
1242 if (symbol->structapp.count < 2 || symbol->structapp.count > 35) {
1243 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 730,
1244 "Structured Append count '%d' out of range (2 to 35)", symbol->structapp.count);
1245 }
1246 if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) {
1247 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 731,
1248 "Structured Append index '%1$d' out of range (1 to count %2$d)",
1249 symbol->structapp.index, symbol->structapp.count);
1250 }
1251 if (symbol->structapp.id[0]) {
1252 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 732, "Structured Append ID not available for DotCode");
1253 }
1254 }
1255
1256 /* GS1 General Specifications 22.0 section 5.8.2 says Structured Append and ECIs not supported
1257 for GS1 DotCode so check and return ZINT_WARN_NONCOMPLIANT if either true */
1258 if (gs1 && warn_number == 0) {
1259 for (i = 0; i < seg_count; i++) {
1260 if (segs[i].eci) {
1261 warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 733,
1262 "Using ECI in GS1 mode not supported by GS1 standards");
1263 break;
1264 }
1265 }
1266 if (warn_number == 0 && symbol->structapp.count) {
1267 warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 734,
1268 "Using Structured Append in GS1 mode not supported by GS1 standards");
1269 }
1270 }
1271
1272 data_length = dc_encode_message_segs(symbol, segs, seg_count, codeword_array, &binary_finish, structapp_array,
1273 &structapp_size);
1274
1275 /* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult/uninitialized.ArraySubscript
1276 * warnings */
1277 assert(data_length > 0);
1278
1279 ecc_length = 3 + (data_length / 2);
1280
1281 min_dots = 9 * (data_length + 3 + (data_length / 2)) + 2;
1282 min_area = min_dots * 2;
1283
1284 if (symbol->option_2 == 0) {
1285 /* Automatic sizing */
1286 /* Following Rule 3 (Section 5.2.2) and applying a recommended width to height ratio 3:2 */
1287 /* Eliminates under sized symbols */
1288
1289 float h = (float) (sqrt(min_area * 0.666));
1290 float w = (float) (sqrt(min_area * 1.5));
1291
1292 height = (int) h;
1293 width = (int) w;
1294
1295 if (((width + height) & 1) == 1) {
1296 if ((width * height) < min_area) {
1297 width++;
1298 height++;
1299 }
1300 } else {
1301 if ((h * width) < (w * height)) {
1302 width++;
1303 if ((width * height) < min_area) {
1304 width--;
1305 height++;
1306 if ((width * height) < min_area) {
1307 width += 2;
1308 }
1309 }
1310 } else {
1311 height++;
1312 if ((width * height) < min_area) {
1313 width++;
1314 height--;
1315 if ((width * height) < min_area) {
1316 height += 2;
1317 }
1318 }
1319 }
1320 }
1321
1322 } else {
1323 /* User defined width */
1324 /* Eliminates under sized symbols */
1325
1326 width = symbol->option_2;
1327 height = (min_area + (width - 1)) / width;
1328
1329 if (!((width + height) & 1)) {
1330 height++;
1331 }
1332 }
1333
1334 if (debug_print) {
1335 printf("Width = %d, Height = %d\n", width, height);
1336 }
1337
1338 if ((height > 200) || (width > 200)) {
1339 if (height > 200 && width > 200) {
1340 errtxtf(0, symbol, 526, "Symbol size '%1$dx%2$d' (WxH) is too large", width, height);
1341 } else {
1342 errtxtf(0, symbol, 528, "Symbol %1$s '%2$d' is too large",
1343 width > 200 ? "width" : "height", width > 200 ? width : height);
1344 }
1345 return ZINT_ERROR_INVALID_OPTION;
1346 }
1347
1348 if ((height < 5) || (width < 5)) {
1349 if (height < 5 && width < 5) { /* Won't happen as if width < 5, min height is 19 */
1350 errtxtf(0, symbol, 527, "Symbol size '%1$dx%2$d' (WxH) is too small", width, height); /* Not reached */
1351 } else {
1352 errtxtf(0, symbol, 529, "Symbol %1$s '%2$d' is too small",
1353 width < 5 ? "width" : "height", width < 5 ? width : height);
1354 }
1355 return ZINT_ERROR_INVALID_OPTION;
1356 }
1357
1358 n_dots = (height * width) / 2;
1359
1360 dot_stream = (char *) z_alloca(height * width * 3);
1361 dot_array = (char *) z_alloca(width * height);
1362
1363 /* Add pad characters */
1364 padding_dots = n_dots - min_dots; /* get the number of free dots available for padding */
1365
1366 if (padding_dots >= 9) {
1367 int is_first = 1; /* first padding character flag */
1368 int padp = data_length - structapp_size;
1369 while (padding_dots >= 9) {
1370 if (padding_dots < 18 && (data_length & 1) == 0) {
1371 padding_dots -= 9;
1372 } else if (padding_dots >= 18) {
1373 if ((data_length & 1) == 0) {
1374 padding_dots -= 9;
1375 } else {
1376 padding_dots -= 18;
1377 }
1378 } else {
1379 break; /* not enough padding dots left for padding */
1380 }
1381 if (is_first && binary_finish) {
1382 codeword_array[padp++] = 109;
1383 } else {
1384 codeword_array[padp++] = 106;
1385 }
1386
1387 data_length++;
1388 is_first = 0;
1389 }
1390 if (structapp_size) {
1391 if (structapp_array[0] == 109) { /* Binary latch no longer valid */
1392 structapp_array[0] = 106;
1393 }
1394 for (i = 0; i < structapp_size; i++) {
1395 codeword_array[padp++] = structapp_array[i];
1396 }
1397 }
1398 } else if (structapp_size) {
1399 data_length -= structapp_size;
1400 for (i = 0; i < structapp_size; i++) {
1401 codeword_array[data_length++] = structapp_array[i];
1402 }
1403 }
1404
1405 if (debug_print) {
1406 printf("Codeword length = %d, ECC length = %d\n", data_length, ecc_length);
1407 fputs("Codewords:", stdout);
1408 for (i = 0; i < data_length; i++) {
1409 printf(" %d", codeword_array[i]);
1410 }
1411 fputc('\n', stdout);
1412 }
1413 #ifdef ZINT_TEST
1414 if (symbol->debug & ZINT_DEBUG_TEST) {
1415 debug_test_codeword_dump(symbol, codeword_array, data_length);
1416 }
1417 #endif
1418
1419 ecc_length = 3 + (data_length / 2);
1420
1421 masked_codeword_array = (unsigned char *) z_alloca(data_length + 1 + ecc_length);
1422
1423 if (user_mask) {
1424 best_mask = user_mask - 1;
1425 if (debug_print) {
1426 printf("Applying mask %d (specified)\n", best_mask);
1427 }
1428 } else {
1429 /* Evaluate data mask options */
1430 for (i = 0; i < 4; i++) {
1431
1432 dc_apply_mask(i, data_length, masked_codeword_array, codeword_array, ecc_length);
1433
1434 dot_stream_length = dc_make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream);
1435
1436 /* Add pad bits */
1437 for (jc = dot_stream_length; jc < n_dots; jc++) {
1438 dot_stream[dot_stream_length++] = '1';
1439 }
1440
1441 dc_fold_dotstream(dot_stream, width, height, dot_array);
1442
1443 mask_score[i] = dc_score_array(dot_array, height, width);
1444
1445 if (debug_print) {
1446 printf("Mask %d score is %d\n", i, mask_score[i]);
1447 }
1448 }
1449
1450 high_score = mask_score[0];
1451 best_mask = 0;
1452
1453 for (i = 1; i < 4; i++) {
1454 if (mask_score[i] >= high_score) {
1455 high_score = mask_score[i];
1456 best_mask = i;
1457 }
1458 }
1459
1460 /* Re-evaluate using forced corners if needed */
1461 if (high_score <= (height * width) / 2) {
1462 if (debug_print) {
1463 printf("High score %d <= %d (height * width) / 2\n", high_score, (height * width) / 2);
1464 }
1465
1466 for (i = 0; i < 4; i++) {
1467
1468 dc_apply_mask(i, data_length, masked_codeword_array, codeword_array, ecc_length);
1469
1470 dot_stream_length = dc_make_dotstream(masked_codeword_array, (data_length + ecc_length + 1),
1471 dot_stream);
1472
1473 /* Add pad bits */
1474 for (jc = dot_stream_length; jc < n_dots; jc++) {
1475 dot_stream[dot_stream_length++] = '1';
1476 }
1477
1478 dc_fold_dotstream(dot_stream, width, height, dot_array);
1479
1480 dc_force_corners(width, height, dot_array);
1481
1482 mask_score[i + 4] = dc_score_array(dot_array, height, width);
1483
1484 if (debug_print) {
1485 printf("Mask %d score is %d\n", i + 4, mask_score[i + 4]);
1486 }
1487 }
1488
1489 for (i = 4; i < 8; i++) {
1490 if (mask_score[i] >= high_score) {
1491 high_score = mask_score[i];
1492 best_mask = i;
1493 }
1494 }
1495 }
1496
1497 if (debug_print) {
1498 printf("Applying mask %d, high_score %d\n", best_mask, high_score);
1499 }
1500 }
1501
1502 /* Apply best mask */
1503 dc_apply_mask(best_mask % 4, data_length, masked_codeword_array, codeword_array, ecc_length);
1504
1505 if (debug_print) {
1506 printf("Masked codewords (%d):", data_length);
1507 for (i = 1; i < data_length + 1; i++) {
1508 printf(" [%d]", masked_codeword_array[i]);
1509 }
1510 fputc('\n', stdout);
1511 printf("Masked ECCs (%d):", ecc_length);
1512 for (i = data_length + 1; i < data_length + ecc_length + 1; i++) {
1513 printf(" [%d]", masked_codeword_array[i]);
1514 }
1515 fputc('\n', stdout);
1516 }
1517
1518 dot_stream_length = dc_make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream);
1519
1520 /* Add pad bits */
1521 for (jc = dot_stream_length; jc < n_dots; jc++) {
1522 dot_stream[dot_stream_length++] = '1';
1523 }
1524 if (debug_print) printf("Binary (%d): %.*s\n", dot_stream_length, dot_stream_length, dot_stream);
1525
1526 dc_fold_dotstream(dot_stream, width, height, dot_array);
1527
1528 if (best_mask >= 4) {
1529 dc_force_corners(width, height, dot_array);
1530 }
1531
1532 /* Copy values to symbol */
1533 symbol->width = width;
1534 symbol->rows = height;
1535
1536 for (k = 0; k < height; k++) {
1537 for (j = 0; j < width; j++) {
1538 if (dot_array[(k * width) + j] == '1') {
1539 set_module(symbol, k, j);
1540 }
1541 }
1542 symbol->row_height[k] = 1;
1543 }
1544 symbol->height = height;
1545
1546 symbol->output_options |= BARCODE_DOTTY_MODE;
1547
1548 return warn_number;
1549 }
1550
1551 /* vim: set ts=4 sw=4 et : */