comparison mupdf-source/thirdparty/zint/backend/common.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 /* common.c - Contains functions needed for a number of barcodes */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2008-2024 Robin Stuart <rstuart114@gmail.com>
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. Neither the name of the project nor the names of its contributors
16 may be used to endorse or promote products derived from this software
17 without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 SUCH DAMAGE.
30 */
31 /* SPDX-License-Identifier: BSD-3-Clause */
32
33 #include <assert.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include "common.h"
37
38 /* Converts a character 0-9, A-F to its equivalent integer value */
39 INTERNAL int ctoi(const char source) {
40 if (z_isdigit(source))
41 return (source - '0');
42 if ((source >= 'A') && (source <= 'F'))
43 return (source - 'A' + 10);
44 if ((source >= 'a') && (source <= 'f'))
45 return (source - 'a' + 10);
46 return -1;
47 }
48
49 /* Converts decimal string of length <= 9 to integer value. Returns -1 if not numeric */
50 INTERNAL int to_int(const unsigned char source[], const int length) {
51 int val = 0;
52 int non_digit = 0;
53 int i;
54
55 for (i = 0; i < length; i++) {
56 val *= 10;
57 val += source[i] - '0';
58 non_digit |= !z_isdigit(source[i]);
59 }
60
61 return non_digit ? -1 : val;
62 }
63
64 /* Converts lower case characters to upper case in string `source` */
65 INTERNAL void to_upper(unsigned char source[], const int length) {
66 int i;
67
68 for (i = 0; i < length; i++) {
69 source[i] &= z_islower(source[i]) ? 0x5F : 0xFF;
70 }
71 }
72
73 /* Returns the number of times a character occurs in `source` */
74 INTERNAL int chr_cnt(const unsigned char source[], const int length, const unsigned char c) {
75 int count = 0;
76 int i;
77 for (i = 0; i < length; i++) {
78 count += source[i] == c;
79 }
80 return count;
81 }
82
83 /* Flag table for `is_chr()` and `not_sane()` */
84 #define IS_CLS_F (IS_CLI_F | IS_SIL_F)
85 static const unsigned short flgs[256] = {
86 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, /*00-1F*/
87 IS_SPC_F, IS_C82_F, IS_C82_F, IS_HSH_F, /*20-23*/ /* !"# */
88 IS_CLS_F, IS_SIL_F | IS_C82_F, IS_C82_F, IS_C82_F, /*24-27*/ /* $%&' */
89 IS_C82_F, IS_C82_F, IS_AST_F, IS_PLS_F, /*28-2B*/ /* ()*+ */
90 IS_C82_F, IS_MNS_F, IS_CLS_F | IS_C82_F, IS_CLS_F | IS_C82_F, /*2B-2F*/ /* ,-./ */
91 IS_NUM_F, IS_NUM_F, IS_NUM_F, IS_NUM_F, /*30-33*/ /* 0123 */
92 IS_NUM_F, IS_NUM_F, IS_NUM_F, IS_NUM_F, /*34-37*/ /* 4567 */
93 IS_NUM_F, IS_NUM_F, IS_CLI_F | IS_C82_F, IS_C82_F, /*38-3B*/ /* 89:; */
94 IS_C82_F, IS_C82_F, IS_C82_F, IS_C82_F, /*3B-3F*/ /* <=>? */
95 0, IS_UHX_F | IS_ARS_F, IS_UHX_F | IS_ARS_F, IS_UHX_F | IS_ARS_F, /*40-43*/ /* @ABC */
96 IS_UHX_F | IS_ARS_F, IS_UHX_F | IS_ARS_F, IS_UHX_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, /*44-47*/ /* DEFG */
97 IS_UPO_F | IS_ARS_F, IS_UPO_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, /*48-4B*/ /* HIJK */
98 IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, IS_UPO_F, /*4B-4F*/ /* LMNO */
99 IS_UPO_F | IS_ARS_F, IS_UPO_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, /*50-53*/ /* PQRS */
100 IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, /*53-57*/ /* TUVW */
101 IS_UX__F | IS_ARS_F, IS_UPO_F | IS_ARS_F, IS_UPO_F | IS_ARS_F, 0, /*58-5B*/ /* XYZ[ */
102 0, 0, 0, IS_C82_F, /*5B-5F*/ /* \]^_ */
103 0, IS_LHX_F, IS_LHX_F, IS_LHX_F, /*60-63*/ /* `abc */
104 IS_LHX_F, IS_LHX_F, IS_LHX_F, IS_LWO_F, /*64-67*/ /* defg */
105 IS_LWO_F, IS_LWO_F, IS_LWO_F, IS_LWO_F, /*68-6B*/ /* hijk */
106 IS_LWO_F, IS_LWO_F, IS_LWO_F, IS_LWO_F, /*6B-6F*/ /* lmno */
107 IS_LWO_F, IS_LWO_F, IS_LWO_F, IS_LWO_F, /*70-73*/ /* pqrs */
108 IS_LWO_F, IS_LWO_F, IS_LWO_F, IS_LWO_F, /*74-77*/ /* tuvw */
109 IS_LX__F, IS_LWO_F, IS_LWO_F, 0, /*78-7B*/ /* xyz{ */
110 0, 0, 0, 0, /*7B-7F*/ /* |}~D */
111 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*/
112 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*/
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, /*C0-DF*/
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, /*E0-FF*/
115 };
116
117 /* Whether a character matches `flg` */
118 INTERNAL int is_chr(const unsigned int flg, const unsigned int c) {
119 return c < 0x80 && (flgs[c] & flg) != 0;
120 }
121
122 /* Verifies if a string only uses valid characters, returning 1-based position in `source` if not, 0 for success */
123 INTERNAL int not_sane(const unsigned int flg, const unsigned char source[], const int length) {
124 int i;
125
126 for (i = 0; i < length; i++) {
127 if (!(flgs[source[i]] & flg)) {
128 return i + 1;
129 }
130 }
131 return 0;
132 }
133
134 /* Replaces huge switch statements for looking up in tables */
135 /* Verifies if a string only uses valid characters as above, but also returns `test_string` position of each in
136 `posns` array */
137 INTERNAL int not_sane_lookup(const char test_string[], const int test_length, const unsigned char source[],
138 const int length, int *posns) {
139 int i, j;
140
141 for (i = 0; i < length; i++) {
142 posns[i] = -1;
143 for (j = 0; j < test_length; j++) {
144 if (source[i] == test_string[j]) {
145 posns[i] = j;
146 break;
147 }
148 }
149 if (posns[i] == -1) {
150 return i + 1;
151 }
152 }
153
154 return 0;
155 }
156
157 /* Returns the position of `data` in `set_string`, or -1 if not found */
158 INTERNAL int posn(const char set_string[], const char data) {
159 const char *s;
160
161 for (s = set_string; *s; s++) {
162 if (data == *s) {
163 return s - set_string;
164 }
165 }
166 return -1;
167 }
168
169 /* Converts `arg` to a string representing its binary equivalent of length `length` and places in `binary` at
170 `bin_posn`. Returns `bin_posn` + `length` */
171 INTERNAL int bin_append_posn(const int arg, const int length, char *binary, const int bin_posn) {
172 int i;
173 const int end = length - 1;
174
175 for (i = 0; i < length; i++) {
176 binary[bin_posn + i] = '0' + ((arg >> (end - i)) & 1);
177 }
178 return bin_posn + length;
179 }
180
181 #ifndef Z_COMMON_INLINE
182
183 /* Returns true (1) if a module is dark/black, otherwise false (0) */
184 INTERNAL int module_is_set(const struct zint_symbol *symbol, const int y_coord, const int x_coord) {
185 return (symbol->encoded_data[y_coord][x_coord >> 3] >> (x_coord & 0x07)) & 1;
186 }
187
188 /* Sets a module to dark/black */
189 INTERNAL void set_module(struct zint_symbol *symbol, const int y_coord, const int x_coord) {
190 symbol->encoded_data[y_coord][x_coord >> 3] |= 1 << (x_coord & 0x07);
191 }
192
193 /* Returns true (1-8) if a module is colour, otherwise false (0) */
194 INTERNAL int module_colour_is_set(const struct zint_symbol *symbol, const int y_coord, const int x_coord) {
195 return symbol->encoded_data[y_coord][x_coord];
196 }
197
198 /* Sets a module to a colour */
199 INTERNAL void set_module_colour(struct zint_symbol *symbol, const int y_coord, const int x_coord, const int colour) {
200 symbol->encoded_data[y_coord][x_coord] = colour;
201 }
202
203 /* Sets a dark/black module to white (i.e. unsets) */
204 INTERNAL void unset_module(struct zint_symbol *symbol, const int y_coord, const int x_coord) {
205 symbol->encoded_data[y_coord][x_coord >> 3] &= ~(1 << (x_coord & 0x07));
206 }
207
208 #endif /* Z_COMMON_INLINE */
209
210 /* Expands from a width pattern to a bit pattern */
211 INTERNAL void expand(struct zint_symbol *symbol, const char data[], const int length) {
212
213 int reader;
214 int writer = 0;
215 int latch = 1;
216 const int row = symbol->rows;
217
218 symbol->rows++;
219
220 for (reader = 0; reader < length; reader++) {
221 int i;
222 const int num = data[reader] - '0';
223 assert(num >= 0);
224 for (i = 0; i < num; i++) {
225 if (latch) {
226 set_module(symbol, row, writer);
227 }
228 writer++;
229 }
230
231 latch = !latch;
232 }
233
234 if (writer > symbol->width) {
235 symbol->width = writer;
236 }
237 }
238
239 /* Helper for `errtxt()` & `errtxtf()` to set "err_id: " part of error message, returning length */
240 static int errtxt_id_str(char *errtxt, int num) {
241 int len = 0;
242 if (num == -1) {
243 errtxt[0] = '\0';
244 return 0;
245 }
246 if (num < 0 || num > 9999) { /* Restrict to 4 digits */
247 num = 9999;
248 }
249 if (num >= 1000) {
250 errtxt[len++] = '0' + (num / 1000);
251 num %= 1000;
252 }
253 errtxt[len++] = '0' + (num / 100);
254 num %= 100;
255 errtxt[len++] = '0' + (num / 10);
256 num %= 10;
257 errtxt[len++] = '0' + num;
258 errtxt[len++] = ':';
259 errtxt[len++] = ' ';
260 return len;
261 }
262
263 /* Set `symbol->errtxt` to "err_id: msg", returning `error_number`. If `err_id` is -1, the "err_id: " prefix is
264 omitted */
265 INTERNAL int errtxt(const int error_number, struct zint_symbol *symbol, const int err_id, const char *msg) {
266 const int max_len = (int) sizeof(symbol->errtxt) - 1;
267 const int id_len = errtxt_id_str(symbol->errtxt, err_id);
268 int msg_len = (int) strlen(msg);
269
270 if (id_len + msg_len > max_len) {
271 if (!(symbol->debug & ZINT_DEBUG_TEST)) assert(0); /* Catch truncations */
272 msg_len = max_len - id_len;
273 }
274 memcpy(symbol->errtxt + id_len, msg, msg_len);
275
276 symbol->errtxt[id_len + msg_len] = '\0';
277
278 return error_number;
279 }
280
281 static int errtxtf_dpad(const char *fmt); /* Forward reference */
282
283 /* Helper for `errtxtf()` to parse numbered specifier "n$" (where "n" 1-9), returning `fmt` advance increment */
284 static int errtxtf_num_arg(const char *fmt, int *p_arg) {
285 int ret = 0;
286 int arg = -2;
287 if (!errtxtf_dpad(fmt) && z_isdigit(fmt[0])) {
288 arg = fmt[1] == '$' ? fmt[0] - '0' - 1 : -1;
289 ret = 2;
290 }
291 if (p_arg) {
292 *p_arg = arg;
293 }
294 return ret;
295 }
296
297 /* Helper for `errtxtf()` to parse length precision, returning `fmt` advance increment */
298 static int errtxtf_slen(const char *fmt, const int arg, int *p_arg_cnt, int *p_len) {
299 int ret = 0;
300 int len = -1;
301 if (fmt[0] == '.') {
302 if (z_isdigit(fmt[1]) && fmt[1] != '0') {
303 len = fmt[1] - '0';
304 for (ret = 2; z_isdigit(fmt[ret]); ret++) {
305 len = len * 10 + fmt[ret] - '0';
306 }
307 if (fmt[ret] != 's') {
308 len = -1;
309 }
310 } else if (fmt[1] == '*' && fmt[2] == 's' && arg < 0) {
311 len = 0;
312 ret = 2;
313 } else if (fmt[1] == '*' && z_isdigit(fmt[2]) && fmt[3] == '$' && fmt[4] == 's') {
314 if (arg == -1 || arg == fmt[2] - '0') {
315 len = 0;
316 if (p_arg_cnt) {
317 (*p_arg_cnt)++;
318 }
319 }
320 ret = 4;
321 } else {
322 ret = 1;
323 }
324 }
325 if (p_len) {
326 *p_len = len;
327 }
328 return ret;
329 }
330
331 /* Helper for `errtxtf()` to parse zero-padded minimum field length for "%d", returning `fmt` advance increment */
332 static int errtxtf_dpad(const char *fmt) {
333 /* Allow one leading zero plus one or two digits only */
334 if (fmt[0] == '0' && z_isdigit(fmt[1])) {
335 if (fmt[1] != '0' && fmt[2] == 'd') {
336 return 2;
337 }
338 if (z_isdigit(fmt[1]) && fmt[1] != '0' && z_isdigit(fmt[2]) && fmt[3] == 'd') {
339 return 3;
340 }
341 }
342 return 0;
343 }
344
345 /* Set `symbol->errtxt` to "err_id: msg" with restricted subset of `printf()` formatting, returning `error_number`.
346 If `err_id` is -1, the "err_id: " prefix is omitted. Only the following specifiers are supported: "c", "d", "f",
347 "g" and "s", with no modifiers apart from "<n>$" numbering for l10n ("<n>" 1-9), in which case all specifiers must
348 be numbered, "%s" with length precisions: "%.*s", "%<n+1>$.*<n>$s", "%.<p>s" and "%<n>$.<p>s", and "%d" with
349 zero-padded minimum field lengths: "%0<m>d" or %<n>$0<m>d" ("<m>" 1-99) */
350 INTERNAL int errtxtf(const int error_number, struct zint_symbol *symbol, const int err_id, const char *fmt, ...) {
351 const int max_len = (int) sizeof(symbol->errtxt) - 1;
352 int p = errtxt_id_str(symbol->errtxt, err_id);
353 const char *f;
354 int i;
355 int arg_cnt = 0;
356 int have_num_arg = 0, have_unnum_arg = 0;
357 va_list ap;
358 int idxs[9] = {0}; /* Argument order */
359 char specs[9] = {0}; /* Format specifiers */
360 const char *ss[9] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /* "%s" */
361 int slens[9] = {0}; /* "%s" length precisions */
362 int have_slens[9] = {0}; /* Bools for if "%s" has length precision */
363 char dpads[9][3] = {{0}}; /* 2-digit minimum field length */
364 char dfgs[9][100] = {{0}}; /* "%d", "%f" and "%g", allowing for padding up to 99 */
365 int cs[9] = {0}; /* "%c" */
366
367 /* Get argument order and specifiers */
368 for (f = fmt, i = 0; *f; f++) {
369 if (*f == '%') {
370 int inc, arg, len;
371 if (*++f == '%') {
372 continue;
373 }
374 if ((inc = errtxtf_num_arg(f, &arg))) {
375 if (arg == -1) {
376 if (!(symbol->debug & ZINT_DEBUG_TEST)) assert(0);
377 return errtxt(ZINT_ERROR_ENCODING_PROBLEM, symbol, 0,
378 "Internal error: invalid numbered format specifer");
379 }
380 if (i >= 9) {
381 if (!(symbol->debug & ZINT_DEBUG_TEST)) assert(0);
382 return errtxt(ZINT_ERROR_ENCODING_PROBLEM, symbol, 0,
383 "Internal error: too many format specifiers (9 maximum)");
384 }
385 f += inc;
386 have_num_arg = 1;
387 idxs[i] = arg;
388 } else {
389 if (i >= 9) {
390 if (!(symbol->debug & ZINT_DEBUG_TEST)) assert(0);
391 return errtxt(ZINT_ERROR_ENCODING_PROBLEM, symbol, 0,
392 "Internal error: too many format specifiers (9 maximum)");
393 }
394 have_unnum_arg = 1;
395 idxs[i] = i;
396 }
397 if ((inc = errtxtf_slen(f, arg, &arg_cnt, &len))) {
398 if (len == -1) {
399 if (!(symbol->debug & ZINT_DEBUG_TEST)) assert(0);
400 return errtxt(ZINT_ERROR_ENCODING_PROBLEM, symbol, 0, "Internal error: invalid length precision");
401 }
402 slens[idxs[i]] = len == 0 ? -1 : len; /* TODO: keep `slens` separate else last mentioned trumps */
403 have_slens[idxs[i]] = 1;
404 f += inc;
405 }
406 if ((inc = errtxtf_dpad(f))) {
407 memcpy(dpads[idxs[i]], f + 1, inc - 1); /* TODO: keep `dpads` separate else last mentioned trumps */
408 dpads[idxs[i]][inc - 1] = '\0';
409 f += inc;
410 }
411 if (*f != 'c' && *f != 'd' && *f != 'f' && *f != 'g' && *f != 's') {
412 if (!(symbol->debug & ZINT_DEBUG_TEST)) assert(0);
413 return errtxt(ZINT_ERROR_ENCODING_PROBLEM, symbol, 0,
414 "Internal error: unknown format specifier ('%c','%d','%f','%g','%s' only)");
415 }
416 specs[idxs[i++]] = *f;
417 arg_cnt++;
418 }
419 }
420 if (have_num_arg && have_unnum_arg) {
421 if (!(symbol->debug & ZINT_DEBUG_TEST)) assert(0);
422 return errtxt(ZINT_ERROR_ENCODING_PROBLEM, symbol, 0,
423 "Internal error: mixed numbered and unnumbered format specifiers");
424 }
425
426 /* Get arguments */
427 va_start(ap, fmt);
428 for (i = 0; i < arg_cnt; i++) {
429 if (specs[i] == 'c') {
430 cs[i] = va_arg(ap, int);
431 } else if (specs[i] == 'd') {
432 if (dpads[i][0]) {
433 char dpad_fmt[30]; /* Make 30 to suppress gcc 14 "-Wformat-overflow=" false positive */
434 sprintf(dpad_fmt, "%%0%sd", dpads[i]); /* TODO: keep `dpads` separate else last mentioned trumps */
435 sprintf(dfgs[i], dpad_fmt, va_arg(ap, int));
436 } else {
437 sprintf(dfgs[i], "%d", va_arg(ap, int));
438 }
439 } else if (specs[i] == 'f' || specs[i] == 'g') {
440 sprintf(dfgs[i], specs[i] == 'f' ? "%f" : "%g", va_arg(ap, double));
441 } else if (specs[i] == 's') {
442 if (have_slens[i] && slens[i] == -1) {
443 slens[i] = va_arg(ap, int); /* TODO: keep `slens` separate else last mentioned trumps */
444 }
445 ss[i] = va_arg(ap, char *);
446 }
447 }
448 va_end(ap);
449
450 /* Populate `errtxt` */
451 for (f = fmt, i = 0; *f && p < max_len; f++) {
452 if (*f == '%') {
453 int idx;
454 if (*++f == '%') {
455 symbol->errtxt[p++] = '%';
456 continue;
457 }
458 f += errtxtf_num_arg(f, NULL /*p_arg*/);
459 f += errtxtf_slen(f, -1 /*arg*/, NULL /*arg_cnt*/, NULL /*p_len*/);
460 f += errtxtf_dpad(f);
461 idx = idxs[i];
462 if (specs[idx] == 'c') {
463 symbol->errtxt[p++] = cs[idx];
464 } else {
465 int len;
466 if (specs[idx] == 's') {
467 if (have_slens[idx]) {
468 const char *si = ss[idx];
469 for (len = 0; len < slens[idx] && si[len]; len++);
470 } else {
471 len = (int) strlen(ss[idx]);
472 }
473 } else {
474 len = (int) strlen(dfgs[idx]);
475 }
476 if (len) {
477 if (p + len > max_len) {
478 if (!(symbol->debug & ZINT_DEBUG_TEST)) assert(0); /* Catch truncations */
479 len = max_len - p;
480 }
481 memcpy(symbol->errtxt + p, specs[idx] == 's' ? ss[idx] : dfgs[idx], len);
482 p += len;
483 }
484 }
485 i++;
486 } else {
487 symbol->errtxt[p++] = *f;
488 }
489 }
490 if (*f) {
491 if (!(symbol->debug & ZINT_DEBUG_TEST)) assert(0); /* Catch truncations */
492 }
493
494 symbol->errtxt[p] = '\0';
495
496 return error_number;
497 }
498
499 /* Helper to prepend/append to existing `symbol->errtxt` by calling `errtxtf(fmt)` with 2 arguments (copy of `errtxt`
500 & `msg`) if `msg` not NULL, or 1 argument (just copy of `errtxt`) if `msg` NULL, returning `error_number` */
501 INTERNAL int errtxt_adj(const int error_number, struct zint_symbol *symbol, const char *fmt, const char *msg) {
502 char err_buf[sizeof(symbol->errtxt)];
503
504 err_buf[0] = '\0';
505
506 /* Suppress gcc 14 warning output may be truncated */
507 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 14
508 #pragma GCC diagnostic push
509 #pragma GCC diagnostic ignored "-Wstringop-truncation"
510 #endif
511
512 strncat(err_buf, symbol->errtxt, sizeof(symbol->errtxt) - 1);
513
514 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 14
515 #pragma GCC diagnostic pop
516 #endif
517
518 if (msg) {
519 errtxtf(0, symbol, -1, fmt, err_buf, msg);
520 } else {
521 errtxtf(0, symbol, -1, fmt, err_buf);
522 }
523
524 return error_number;
525 }
526
527 /* Whether `symbology` can have row binding */
528 INTERNAL int is_stackable(const int symbology) {
529 if (symbology < BARCODE_PHARMA_TWO && symbology != BARCODE_POSTNET) {
530 return 1;
531 }
532
533 switch (symbology) {
534 case BARCODE_CODE128AB:
535 case BARCODE_ISBNX:
536 case BARCODE_EAN14:
537 case BARCODE_NVE18:
538 case BARCODE_KOREAPOST:
539 case BARCODE_PLESSEY:
540 case BARCODE_TELEPEN_NUM:
541 case BARCODE_ITF14:
542 case BARCODE_CODE32:
543 case BARCODE_CODABLOCKF:
544 case BARCODE_HIBC_BLOCKF:
545 return 1;
546 break;
547 }
548
549 return 0;
550 }
551
552 /* Whether `symbology` is EAN/UPC */
553 INTERNAL int is_upcean(const int symbology) {
554
555 switch (symbology) {
556 case BARCODE_EANX:
557 case BARCODE_EANX_CHK:
558 case BARCODE_UPCA:
559 case BARCODE_UPCA_CHK:
560 case BARCODE_UPCE:
561 case BARCODE_UPCE_CHK:
562 case BARCODE_ISBNX:
563 case BARCODE_EANX_CC:
564 case BARCODE_UPCA_CC:
565 case BARCODE_UPCE_CC:
566 return 1;
567 break;
568 }
569
570 return 0;
571 }
572
573 /* Whether `symbology` can have composite 2D component data */
574 INTERNAL int is_composite(const int symbology) {
575 return symbology >= BARCODE_EANX_CC && symbology <= BARCODE_DBAR_EXPSTK_CC;
576 }
577
578 /* Whether `symbology` is a matrix design renderable as dots */
579 INTERNAL int is_dotty(const int symbology) {
580
581 switch (symbology) {
582 /* Note MAXICODE and ULTRA absent */
583 case BARCODE_QRCODE:
584 case BARCODE_DATAMATRIX:
585 case BARCODE_MICROQR:
586 case BARCODE_HIBC_DM:
587 case BARCODE_AZTEC:
588 case BARCODE_HIBC_QR:
589 case BARCODE_HIBC_AZTEC:
590 case BARCODE_AZRUNE:
591 case BARCODE_CODEONE:
592 case BARCODE_GRIDMATRIX:
593 case BARCODE_HANXIN:
594 case BARCODE_MAILMARK_2D:
595 case BARCODE_DOTCODE:
596 case BARCODE_UPNQR:
597 case BARCODE_RMQR:
598 return 1;
599 break;
600 }
601
602 return 0;
603 }
604
605 /* Whether `symbology` has a fixed aspect ratio (matrix design) */
606 INTERNAL int is_fixed_ratio(const int symbology) {
607
608 if (is_dotty(symbology)) {
609 return 1;
610 }
611
612 switch (symbology) {
613 case BARCODE_MAXICODE:
614 case BARCODE_ULTRA:
615 return 1;
616 break;
617 }
618
619 return 0;
620 }
621
622 /* Whether next two characters are digits */
623 INTERNAL int is_twodigits(const unsigned char source[], const int length, const int position) {
624 if ((position + 1 < length) && z_isdigit(source[position]) && z_isdigit(source[position + 1])) {
625 return 1;
626 }
627
628 return 0;
629 }
630
631 /* Returns how many consecutive digits lie immediately ahead up to `max`, or all if `max` is -1 */
632 INTERNAL int cnt_digits(const unsigned char source[], const int length, const int position, const int max) {
633 int i;
634 const int max_length = max == -1 || position + max > length ? length : position + max;
635
636 for (i = position; i < max_length && z_isdigit(source[i]); i++);
637
638 return i - position;
639 }
640
641 /* State machine to decode UTF-8 to Unicode codepoints (state 0 means done, state 12 means error) */
642 INTERNAL unsigned int decode_utf8(unsigned int *state, unsigned int *codep, const unsigned char byte) {
643 /*
644 Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
645
646 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
647 documentation files (the "Software"), to deal in the Software without restriction, including without
648 limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
649 Software, and to permit persons to whom the Software is furnished to do so, subject to the following
650 conditions:
651
652 The above copyright notice and this permission notice shall be included in all copies or substantial portions
653 of the Software.
654
655 See https://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
656 */
657
658 static const unsigned char utf8d[] = {
659 /* The first part of the table maps bytes to character classes that
660 * reduce the size of the transition table and create bitmasks. */
661 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,
662 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,
663 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,
664 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,
665 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
666 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
667 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
668 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
669
670 /* The second part is a transition table that maps a combination
671 * of a state of the automaton and a character class to a state. */
672 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
673 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
674 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
675 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
676 12,36,12,12,12,12,12,12,12,12,12,12,
677 };
678
679 const unsigned int type = utf8d[byte];
680
681 *codep = *state != 0 ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & byte;
682
683 *state = utf8d[256 + *state + type];
684
685 return *state;
686 }
687
688 /* Is string valid UTF-8? */
689 INTERNAL int is_valid_utf8(const unsigned char source[], const int length) {
690 int i;
691 unsigned int codepoint, state = 0;
692
693 for (i = 0; i < length; i++) {
694 if (decode_utf8(&state, &codepoint, source[i]) == 12) {
695 return 0;
696 }
697 }
698
699 return state == 0;
700 }
701
702 /* Converts UTF-8 to Unicode. If `disallow_4byte` unset, allows all values (UTF-32). If `disallow_4byte` set,
703 * only allows codepoints <= U+FFFF (ie four-byte sequences not allowed) (UTF-16, no surrogates) */
704 INTERNAL int utf8_to_unicode(struct zint_symbol *symbol, const unsigned char source[], unsigned int vals[],
705 int *length, const int disallow_4byte) {
706 int bpos;
707 int jpos;
708 unsigned int codepoint, state = 0;
709
710 bpos = 0;
711 jpos = 0;
712
713 while (bpos < *length) {
714 do {
715 decode_utf8(&state, &codepoint, source[bpos++]);
716 } while (bpos < *length && state != 0 && state != 12);
717
718 if (state != 0) {
719 strcpy(symbol->errtxt, "240: Corrupt Unicode data");
720 return ZINT_ERROR_INVALID_DATA;
721 }
722 if (disallow_4byte && codepoint > 0xffff) {
723 strcpy(symbol->errtxt, "242: Unicode sequences of more than 3 bytes not supported");
724 return ZINT_ERROR_INVALID_DATA;
725 }
726
727 vals[jpos] = codepoint;
728 jpos++;
729 }
730
731 *length = jpos;
732
733 return 0;
734 }
735
736 /* Treats source as ISO/IEC 8859-1 and copies into `symbol->text`, converting to UTF-8. Control chars (incl. DEL) and
737 non-ISO/IEC 8859-1 (0x80-9F) are replaced with spaces. Returns warning if truncated, else 0 */
738 INTERNAL int hrt_cpy_iso8859_1(struct zint_symbol *symbol, const unsigned char source[], const int length) {
739 int i, j;
740 int warn_number = 0;
741
742 for (i = 0, j = 0; i < length && j < (int) sizeof(symbol->text); i++) {
743 if (source[i] < 0x80) {
744 symbol->text[j++] = source[i] >= ' ' && source[i] != 0x7F ? source[i] : ' ';
745 } else if (source[i] < 0xC0) {
746 if (source[i] >= 0xA0) { /* 0x80-0x9F not valid ISO/IEC 8859-1 */
747 if (j + 2 >= (int) sizeof(symbol->text)) {
748 warn_number = ZINT_WARN_HRT_TRUNCATED;
749 break;
750 }
751 symbol->text[j++] = 0xC2;
752 symbol->text[j++] = source[i];
753 } else {
754 symbol->text[j++] = ' ';
755 }
756 } else {
757 if (j + 2 >= (int) sizeof(symbol->text)) {
758 warn_number = ZINT_WARN_HRT_TRUNCATED;
759 break;
760 }
761 symbol->text[j++] = 0xC3;
762 symbol->text[j++] = source[i] - 0x40;
763 }
764 }
765 if (j == sizeof(symbol->text)) {
766 warn_number = ZINT_WARN_HRT_TRUNCATED;
767 j--;
768 }
769 symbol->text[j] = '\0';
770
771 if (warn_number) {
772 errtxt(0, symbol, 249, "Human Readable Text truncated");
773 }
774 return warn_number;
775 }
776
777 /* Sets symbol height, returning a warning if not within minimum and/or maximum if given.
778 `default_height` does not include height of fixed-height rows (i.e. separators/composite data) */
779 INTERNAL int set_height(struct zint_symbol *symbol, const float min_row_height, const float default_height,
780 const float max_height, const int no_errtxt) {
781 int error_number = 0;
782 float fixed_height = 0.0f;
783 int zero_count = 0;
784 float row_height;
785 int i;
786 const int rows = symbol->rows ? symbol->rows : 1; /* Sometimes called before expand() */
787
788 for (i = 0; i < rows; i++) {
789 if (symbol->row_height[i]) {
790 fixed_height += symbol->row_height[i];
791 } else {
792 zero_count++;
793 }
794 }
795
796 if (zero_count) {
797 if (symbol->height) {
798 if (symbol->input_mode & HEIGHTPERROW_MODE) {
799 row_height = stripf(symbol->height);
800 } else {
801 row_height = stripf((symbol->height - fixed_height) / zero_count);
802 }
803 } else if (default_height) {
804 row_height = stripf(default_height / zero_count);
805 } else {
806 row_height = stripf(min_row_height);
807 }
808 if (row_height < 0.5f) { /* Absolute minimum */
809 row_height = 0.5f;
810 }
811 if (min_row_height) {
812 if (stripf(row_height) < stripf(min_row_height)) {
813 error_number = ZINT_WARN_NONCOMPLIANT;
814 if (!no_errtxt) {
815 errtxt(0, symbol, 247, "Height not compliant with standards");
816 }
817 }
818 }
819 symbol->height = stripf(row_height * zero_count + fixed_height);
820 } else {
821 symbol->height = stripf(fixed_height); /* Ignore any given height */
822 }
823 if (max_height) {
824 if (stripf(symbol->height) > stripf(max_height)) {
825 error_number = ZINT_WARN_NONCOMPLIANT;
826 if (!no_errtxt) {
827 errtxt(0, symbol, 248, "Height not compliant with standards");
828 }
829 }
830 }
831
832 return error_number;
833 }
834
835 /* Prevent inlining of `stripf()` which can optimize away its effect */
836 #if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
837 #define ZINT_NOINLINE __attribute__((__noinline__))
838 #elif defined(_MSC_VER) && _MSC_VER >= 1310 /* MSVC 2003 (VC++ 7.1) */
839 #define ZINT_NOINLINE __declspec(noinline)
840 #else
841 #define ZINT_NOINLINE
842 #endif
843
844 /* Removes excess precision from floats - see https://stackoverflow.com/q/503436 */
845 INTERNAL ZINT_NOINLINE float stripf(const float arg) {
846 return *((volatile const float *) &arg);
847 }
848
849 /* Returns total length of segments */
850 INTERNAL int segs_length(const struct zint_seg segs[], const int seg_count) {
851 int total_len = 0;
852 int i;
853
854 for (i = 0; i < seg_count; i++) {
855 total_len += segs[i].length == -1 ? (int) ustrlen(segs[i].source) : segs[i].length;
856 }
857
858 return total_len;
859 }
860
861 /* Shallow copies segments, adjusting default ECIs */
862 INTERNAL void segs_cpy(const struct zint_symbol *symbol, const struct zint_seg segs[], const int seg_count,
863 struct zint_seg local_segs[]) {
864 const int default_eci = symbol->symbology == BARCODE_GRIDMATRIX ? 29 : symbol->symbology == BARCODE_UPNQR ? 4 : 3;
865 int i;
866
867 local_segs[0] = segs[0];
868 for (i = 1; i < seg_count; i++) {
869 local_segs[i] = segs[i];
870 /* Ensure default ECI set if follows non-default ECI */
871 if (local_segs[i].eci == 0 && local_segs[i - 1].eci != 0 && local_segs[i - 1].eci != default_eci) {
872 local_segs[i].eci = default_eci;
873 }
874 }
875 }
876
877 /* Helper for ZINT_DEBUG_PRINT to put all but graphical ASCII in hex escapes. Output to `buf` if non-NULL, else
878 stdout */
879 INTERNAL char *debug_print_escape(const unsigned char *source, const int first_len, char *buf) {
880 int i;
881 if (buf) {
882 int j = 0;
883 for (i = 0; i < first_len; i++) {
884 const unsigned char ch = source[i];
885 if (ch < 32 || ch >= 127) {
886 j += sprintf(buf + j, "\\x%02X", ch & 0xFF);
887 } else {
888 buf[j++] = ch;
889 }
890 }
891 buf[j] = '\0';
892 } else {
893 for (i = 0; i < first_len; i++) {
894 const unsigned char ch = source[i];
895 if (ch < 32 || ch >= 127) {
896 printf("\\x%02X", ch & 0xFF);
897 } else {
898 fputc(ch, stdout);
899 }
900 }
901 }
902 return buf;
903 }
904
905 #ifdef ZINT_TEST
906 /* Suppress gcc warning null destination pointer [-Wformat-overflow=] false-positive */
907 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 7
908 #pragma GCC diagnostic push
909 #pragma GCC diagnostic ignored "-Wformat-overflow="
910 #endif
911 /* Dumps hex-formatted codewords in symbol->errtxt (for use in testing) */
912 INTERNAL void debug_test_codeword_dump(struct zint_symbol *symbol, const unsigned char *codewords, const int length) {
913 int i, max = length, cnt_len = 0;
914 assert(sizeof(symbol->errtxt) >= 100);
915 if (length > 30) { /* 30*3 < errtxt 92 (100 - "Warning ") chars */
916 sprintf(symbol->errtxt, "(%d) ", length); /* Place the number of codewords at the front */
917 cnt_len = (int) strlen(symbol->errtxt);
918 max = 30 - (cnt_len + 2) / 3;
919 }
920 for (i = 0; i < max; i++) {
921 sprintf(symbol->errtxt + cnt_len + i * 3, "%02X ", codewords[i]);
922 }
923 symbol->errtxt[strlen(symbol->errtxt) - 1] = '\0'; /* Zap last space */
924 }
925
926 /* Dumps decimal-formatted codewords in symbol->errtxt (for use in testing) */
927 INTERNAL void debug_test_codeword_dump_short(struct zint_symbol *symbol, const short *codewords, const int length) {
928 int i, max = 0, cnt_len, errtxt_len;
929 char temp[20];
930 assert(sizeof(symbol->errtxt) >= 100);
931 errtxt_len = sprintf(symbol->errtxt, "(%d) ", length); /* Place the number of codewords at the front */
932 for (i = 0, cnt_len = errtxt_len; i < length; i++) {
933 cnt_len += sprintf(temp, "%d ", codewords[i]);
934 if (cnt_len > 92) {
935 break;
936 }
937 max++;
938 }
939 for (i = 0; i < max; i++) {
940 errtxt_len += sprintf(symbol->errtxt + errtxt_len, "%d ", codewords[i]);
941 }
942 symbol->errtxt[strlen(symbol->errtxt) - 1] = '\0'; /* Zap last space */
943 }
944
945 /* Dumps decimal-formatted codewords in symbol->errtxt (for use in testing) */
946 INTERNAL void debug_test_codeword_dump_int(struct zint_symbol *symbol, const int *codewords, const int length) {
947 int i, max = 0, cnt_len, errtxt_len;
948 char temp[20];
949 assert(sizeof(symbol->errtxt) >= 100);
950 errtxt_len = sprintf(symbol->errtxt, "(%d) ", length); /* Place the number of codewords at the front */
951 for (i = 0, cnt_len = errtxt_len; i < length; i++) {
952 cnt_len += sprintf(temp, "%d ", codewords[i]);
953 if (cnt_len > 92) {
954 break;
955 }
956 max++;
957 }
958 for (i = 0; i < max; i++) {
959 errtxt_len += sprintf(symbol->errtxt + errtxt_len, "%d ", codewords[i]);
960 }
961 symbol->errtxt[strlen(symbol->errtxt) - 1] = '\0'; /* Zap last space */
962 }
963 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 7
964 #pragma GCC diagnostic pop
965 #endif
966 #endif /* ZINT_TEST */
967
968 /* vim: set ts=4 sw=4 et : */