Mercurial > hgrepos > Python2 > PyMuPDF
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 : */ |
