Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/2of5.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 /* 2of5.c - Handles Code 2 of 5 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 <stdio.h> | |
| 34 #include "common.h" | |
| 35 #include "gs1.h" | |
| 36 | |
| 37 /* First 5 of each entry Interleaved also */ | |
| 38 static const char C25MatrixTable[10][6] = { | |
| 39 {'1','1','3','3','1','1'}, {'3','1','1','1','3','1'}, {'1','3','1','1','3','1'}, {'3','3','1','1','1','1'}, | |
| 40 {'1','1','3','1','3','1'}, {'3','1','3','1','1','1'}, {'1','3','3','1','1','1'}, {'1','1','1','3','3','1'}, | |
| 41 {'3','1','1','3','1','1'}, {'1','3','1','3','1','1'} | |
| 42 }; | |
| 43 | |
| 44 static const char C25IndustTable[10][10] = { | |
| 45 {'1','1','1','1','3','1','3','1','1','1'}, {'3','1','1','1','1','1','1','1','3','1'}, | |
| 46 {'1','1','3','1','1','1','1','1','3','1'}, {'3','1','3','1','1','1','1','1','1','1'}, | |
| 47 {'1','1','1','1','3','1','1','1','3','1'}, {'3','1','1','1','3','1','1','1','1','1'}, | |
| 48 {'1','1','3','1','3','1','1','1','1','1'}, {'1','1','1','1','1','1','3','1','3','1'}, | |
| 49 {'3','1','1','1','1','1','3','1','1','1'}, {'1','1','3','1','1','1','3','1','1','1'} | |
| 50 }; | |
| 51 | |
| 52 /* Note `c25_common()` assumes Stop string length one less than Start */ | |
| 53 static const char C25MatrixStartStop[2][6] = { {'4', '1', '1', '1', '1', '1'}, {'4', '1', '1', '1', '1'} }; | |
| 54 static const char C25IndustStartStop[2][6] = { {'3', '1', '3', '1', '1', '1'}, {'3', '1', '1', '1', '3'} }; | |
| 55 static const char C25IataLogicStartStop[2][6] = { {'1', '1', '1', '1'}, {'3', '1', '1'} }; | |
| 56 | |
| 57 /* Common to Standard (Matrix), Industrial, IATA, and Data Logic */ | |
| 58 static int c25_common(struct zint_symbol *symbol, const unsigned char source[], int length, const int max, | |
| 59 const int is_matrix, const char start_stop[2][6], const int start_length, const int error_base) { | |
| 60 | |
| 61 int i; | |
| 62 char dest[818]; /* Largest destination 4 + (80 + 1) * 10 + 3 + 1 = 818 */ | |
| 63 char *d = dest; | |
| 64 unsigned char temp[113 + 1 + 1]; /* Largest maximum 113 + optional check digit */ | |
| 65 const int have_checkdigit = symbol->option_2 == 1 || symbol->option_2 == 2; | |
| 66 | |
| 67 if (length > max) { | |
| 68 /* errtxt 301: 303: 305: 307: */ | |
| 69 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, error_base, "Input length %1$d too long (maximum %2$d)", length, | |
| 70 max); | |
| 71 } | |
| 72 if ((i = not_sane(NEON_F, source, length))) { | |
| 73 /* Note: for all "at position" error messages, escape sequences not accounted for */ | |
| 74 /* errtxt 302: 304: 306: 308: */ | |
| 75 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, error_base + 1, | |
| 76 "Invalid character at position %d in input (digits only)", i); | |
| 77 } | |
| 78 | |
| 79 ustrcpy(temp, source); | |
| 80 | |
| 81 if (have_checkdigit) { | |
| 82 /* Add standard GS1 check digit */ | |
| 83 temp[length] = gs1_check_digit(source, length); | |
| 84 temp[++length] = '\0'; | |
| 85 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %c\n", temp[length - 1]); | |
| 86 } | |
| 87 | |
| 88 /* Start character */ | |
| 89 memcpy(d, start_stop[0], start_length); | |
| 90 d += start_length; | |
| 91 | |
| 92 if (is_matrix) { | |
| 93 for (i = 0; i < length; i++, d += 6) { | |
| 94 memcpy(d, C25MatrixTable[temp[i] - '0'], 6); | |
| 95 } | |
| 96 } else { | |
| 97 for (i = 0; i < length; i++, d += 10) { | |
| 98 memcpy(d, C25IndustTable[temp[i] - '0'], 10); | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 /* Stop character */ | |
| 103 memcpy(d, start_stop[1], start_length - 1); | |
| 104 d += start_length - 1; | |
| 105 | |
| 106 expand(symbol, dest, d - dest); | |
| 107 | |
| 108 ustrcpy(symbol->text, temp); | |
| 109 if (symbol->option_2 == 2) { | |
| 110 /* Remove check digit from HRT */ | |
| 111 symbol->text[length - 1] = '\0'; | |
| 112 } | |
| 113 | |
| 114 return 0; | |
| 115 } | |
| 116 | |
| 117 /* Code 2 of 5 Standard (Code 2 of 5 Matrix) */ | |
| 118 INTERNAL int c25standard(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 119 /* 9 + (112 + 1) * 10 + 8 = 1147 */ | |
| 120 return c25_common(symbol, source, length, 112, 1 /*is_matrix*/, C25MatrixStartStop, 6, 301); | |
| 121 } | |
| 122 | |
| 123 /* Code 2 of 5 Industrial */ | |
| 124 INTERNAL int c25ind(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 125 /* 10 + (79 + 1) * 14 + 9 = 1139 */ | |
| 126 return c25_common(symbol, source, length, 79, 0 /*is_matrix*/, C25IndustStartStop, 6, 303); | |
| 127 } | |
| 128 | |
| 129 /* Code 2 of 5 IATA */ | |
| 130 INTERNAL int c25iata(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 131 /* 4 + (80 + 1) * 14 + 5 = 1143 */ | |
| 132 return c25_common(symbol, source, length, 80, 0 /*is_matrix*/, C25IataLogicStartStop, 4, 305); | |
| 133 } | |
| 134 | |
| 135 /* Code 2 of 5 Data Logic */ | |
| 136 INTERNAL int c25logic(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 137 /* 4 + (113 + 1) * 10 + 5 = 1149 */ | |
| 138 return c25_common(symbol, source, length, 113, 1 /*is_matrix*/, C25IataLogicStartStop, 4, 307); | |
| 139 } | |
| 140 | |
| 141 /* Common to Interleaved, ITF-14, DP Leitcode, DP Identcode */ | |
| 142 static int c25_inter_common(struct zint_symbol *symbol, unsigned char source[], int length, | |
| 143 const int checkdigit_option, const int dont_set_height) { | |
| 144 int i, j, error_number = 0; | |
| 145 char dest[638]; /* 4 + (125 + 1) * 5 + 3 + 1 = 638 */ | |
| 146 char *d = dest; | |
| 147 unsigned char temp[125 + 1 + 1]; | |
| 148 const int have_checkdigit = checkdigit_option == 1 || checkdigit_option == 2; | |
| 149 | |
| 150 if (length > 125) { /* 4 + (125 + 1) * 9 + 5 = 1143 */ | |
| 151 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 309, "Input length %d too long (maximum 125)", length); | |
| 152 } | |
| 153 if ((i = not_sane(NEON_F, source, length))) { | |
| 154 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 310, | |
| 155 "Invalid character at position %d in input (digits only)", i); | |
| 156 } | |
| 157 | |
| 158 /* Input must be an even number of characters for Interlaced 2 of 5 to work: | |
| 159 if an odd number of characters has been entered and no check digit or an even number and have check digit | |
| 160 then add a leading zero */ | |
| 161 if (have_checkdigit == !(length & 1)) { | |
| 162 temp[0] = '0'; | |
| 163 memcpy(temp + 1, source, length++); | |
| 164 } else { | |
| 165 memcpy(temp, source, length); | |
| 166 } | |
| 167 temp[length] = '\0'; | |
| 168 | |
| 169 if (have_checkdigit) { | |
| 170 /* Add standard GS1 check digit */ | |
| 171 temp[length] = gs1_check_digit(temp, length); | |
| 172 temp[++length] = '\0'; | |
| 173 } | |
| 174 | |
| 175 /* Start character */ | |
| 176 memcpy(d, "1111", 4); | |
| 177 d += 4; | |
| 178 | |
| 179 for (i = 0; i < length; i += 2) { | |
| 180 /* Look up the bars and the spaces */ | |
| 181 const char *const bars = C25MatrixTable[temp[i] - '0']; | |
| 182 const char *const spaces = C25MatrixTable[temp[i + 1] - '0']; | |
| 183 | |
| 184 /* Then merge (interlace) the strings together */ | |
| 185 for (j = 0; j < 5; j++) { | |
| 186 *d++ = bars[j]; | |
| 187 *d++ = spaces[j]; | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 /* Stop character */ | |
| 192 memcpy(d, "311", 3); | |
| 193 d += 3; | |
| 194 | |
| 195 expand(symbol, dest, d - dest); | |
| 196 | |
| 197 ustrcpy(symbol->text, temp); | |
| 198 if (checkdigit_option == 2) { | |
| 199 /* Remove check digit from HRT */ | |
| 200 symbol->text[length - 1] = '\0'; | |
| 201 } | |
| 202 | |
| 203 if (!dont_set_height) { | |
| 204 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 205 /* ISO/IEC 16390:2007 Section 4.4 min height 5mm or 15% of symbol width whichever greater where | |
| 206 (P = character pairs, N = wide/narrow ratio = 3) | |
| 207 width = (P(4N + 6) + N + 6)X = (length / 2) * 18 + 9 */ | |
| 208 /* Taking min X = 0.330mm from Annex D.3.1 (application specification) */ | |
| 209 const float min_height_min = 15.151515f; /* 5.0 / 0.33 */ | |
| 210 float min_height = stripf((18.0f * (length / 2) + 9.0f) * 0.15f); | |
| 211 if (min_height < min_height_min) { | |
| 212 min_height = min_height_min; | |
| 213 } | |
| 214 /* Using 50 as default as none recommended */ | |
| 215 error_number = set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, | |
| 216 0 /*no_errtxt*/); | |
| 217 } else { | |
| 218 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 return error_number; | |
| 223 } | |
| 224 | |
| 225 /* Code 2 of 5 Interleaved ISO/IEC 16390:2007 */ | |
| 226 INTERNAL int c25inter(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 227 return c25_inter_common(symbol, source, length, symbol->option_2 /*checkdigit_option*/, 0 /*dont_set_height*/); | |
| 228 } | |
| 229 | |
| 230 /* Interleaved 2-of-5 (ITF-14) */ | |
| 231 INTERNAL int itf14(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 232 int i, error_number, zeroes; | |
| 233 unsigned char localstr[16] = {0}; | |
| 234 | |
| 235 if (length > 13) { | |
| 236 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 311, "Input length %d too long (maximum 13)", length); | |
| 237 } | |
| 238 | |
| 239 if ((i = not_sane(NEON_F, source, length))) { | |
| 240 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 312, | |
| 241 "Invalid character at position %d in input (digits only)", i); | |
| 242 } | |
| 243 | |
| 244 /* Add leading zeros as required */ | |
| 245 zeroes = 13 - length; | |
| 246 for (i = 0; i < zeroes; i++) { | |
| 247 localstr[i] = '0'; | |
| 248 } | |
| 249 ustrcpy(localstr + zeroes, source); | |
| 250 | |
| 251 /* Calculate the check digit - the same method used for EAN-13 */ | |
| 252 localstr[13] = gs1_check_digit(localstr, 13); | |
| 253 localstr[14] = '\0'; | |
| 254 error_number = c25_inter_common(symbol, localstr, 14, 0 /*checkdigit_option*/, 1 /*dont_set_height*/); | |
| 255 ustrcpy(symbol->text, localstr); | |
| 256 | |
| 257 if (error_number < ZINT_ERROR) { | |
| 258 if (!(symbol->output_options & (BARCODE_BOX | BARCODE_BIND | BARCODE_BIND_TOP))) { | |
| 259 /* If no option has been selected then uses default box option */ | |
| 260 symbol->output_options |= BARCODE_BOX; | |
| 261 if (symbol->border_width == 0) { /* Allow override if non-zero */ | |
| 262 /* GS1 General Specifications 21.0.1 Sections 5.3.2.4 & 5.3.6 (4.83 / 1.016 ~ 4.75) */ | |
| 263 symbol->border_width = 5; /* Note change from previous value 8 */ | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 268 /* GS1 General Specifications 21.0.1 5.12.3.2 table 2, including footnote (**): (note bind/box additional | |
| 269 to symbol->height), same as GS1-128: "in case of further space constraints" | |
| 270 height 5.8mm / 1.016mm (X max) ~ 5.7; default 31.75mm / 0.495mm ~ 64.14 */ | |
| 271 const float min_height = 5.70866156f; /* 5.8 / 1.016 */ | |
| 272 const float default_height = 64.1414108f; /* 31.75 / 0.495 */ | |
| 273 error_number = set_height(symbol, min_height, default_height, 0.0f, 0 /*no_errtxt*/); | |
| 274 } else { | |
| 275 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); | |
| 276 } | |
| 277 } | |
| 278 | |
| 279 return error_number; | |
| 280 } | |
| 281 | |
| 282 /* Deutsche Post check digit */ | |
| 283 static char c25_dp_check_digit(const unsigned int count) { | |
| 284 return itoc((10 - (count % 10)) % 10); | |
| 285 } | |
| 286 | |
| 287 /* Deutsche Post Leitcode */ | |
| 288 /* Documentation (of a very incomplete and non-technical type): | |
| 289 https://www.deutschepost.de/content/dam/dpag/images/D_d/dialogpost-schwer/dp-dialogpost-schwer-broschuere-072021.pdf | |
| 290 */ | |
| 291 INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 292 int i, j, error_number; | |
| 293 unsigned int count; | |
| 294 int factor; | |
| 295 unsigned char localstr[16] = {0}; | |
| 296 int zeroes; | |
| 297 | |
| 298 count = 0; | |
| 299 if (length > 13) { | |
| 300 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 313, "Input length %d too long (maximum 13)", length); | |
| 301 } | |
| 302 if ((i = not_sane(NEON_F, source, length))) { | |
| 303 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 314, | |
| 304 "Invalid character at position %d in input (digits only)", i); | |
| 305 } | |
| 306 | |
| 307 zeroes = 13 - length; | |
| 308 for (i = 0; i < zeroes; i++) | |
| 309 localstr[i] = '0'; | |
| 310 ustrcpy(localstr + zeroes, source); | |
| 311 | |
| 312 factor = 4; | |
| 313 for (i = 12; i >= 0; i--) { | |
| 314 count += factor * ctoi(localstr[i]); | |
| 315 factor ^= 0x0D; /* Toggles 4 and 9 */ | |
| 316 } | |
| 317 localstr[13] = c25_dp_check_digit(count); | |
| 318 localstr[14] = '\0'; | |
| 319 error_number = c25_inter_common(symbol, localstr, 14, 0 /*checkdigit_option*/, 1 /*dont_set_height*/); | |
| 320 | |
| 321 /* HRT formatting as per DIALOGPOST SCHWER brochure but TEC-IT differs as do examples at | |
| 322 https://www.philaseiten.de/cgi-bin/index.pl?ST=8615&CP=0&F=1#M147 */ | |
| 323 for (i = 0, j = 0; i <= 14; i++) { | |
| 324 symbol->text[j++] = localstr[i]; | |
| 325 if (i == 4 || i == 7 || i == 10) { | |
| 326 symbol->text[j++] = '.'; | |
| 327 } | |
| 328 } | |
| 329 | |
| 330 /* TODO: Find documentation on BARCODE_DPLEIT dimensions/height */ | |
| 331 /* Based on eyeballing DIALOGPOST SCHWER, using 72X as default */ | |
| 332 (void) set_height(symbol, 0.0f, 72.0f, 0.0f, 1 /*no_errtxt*/); | |
| 333 | |
| 334 return error_number; | |
| 335 } | |
| 336 | |
| 337 /* Deutsche Post Identcode */ | |
| 338 /* See dpleit() for (sort of) documentation reference */ | |
| 339 INTERNAL int dpident(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 340 int i, j, error_number, zeroes; | |
| 341 unsigned int count; | |
| 342 int factor; | |
| 343 unsigned char localstr[16] = {0}; | |
| 344 | |
| 345 count = 0; | |
| 346 if (length > 11) { | |
| 347 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 315, "Input length %d too long (maximum 11)", length); | |
| 348 } | |
| 349 if ((i = not_sane(NEON_F, source, length))) { | |
| 350 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 316, | |
| 351 "Invalid character at position %d in input (digits only)", i); | |
| 352 } | |
| 353 | |
| 354 zeroes = 11 - length; | |
| 355 for (i = 0; i < zeroes; i++) | |
| 356 localstr[i] = '0'; | |
| 357 ustrcpy(localstr + zeroes, source); | |
| 358 | |
| 359 factor = 4; | |
| 360 for (i = 10; i >= 0; i--) { | |
| 361 count += factor * ctoi(localstr[i]); | |
| 362 factor ^= 0x0D; /* Toggles 4 and 9 */ | |
| 363 } | |
| 364 localstr[11] = c25_dp_check_digit(count); | |
| 365 localstr[12] = '\0'; | |
| 366 error_number = c25_inter_common(symbol, localstr, 12, 0 /*checkdigit_option*/, 1 /*dont_set_height*/); | |
| 367 | |
| 368 /* HRT formatting as per DIALOGPOST SCHWER brochure but TEC-IT differs as do other examples (see above) */ | |
| 369 for (i = 0, j = 0; i <= 12; i++) { | |
| 370 symbol->text[j++] = localstr[i]; | |
| 371 if (i == 1 || i == 4 || i == 7) { | |
| 372 symbol->text[j++] = '.'; | |
| 373 } else if (i == 3 || i == 10) { | |
| 374 symbol->text[j++] = ' '; | |
| 375 } | |
| 376 } | |
| 377 | |
| 378 /* TODO: Find documentation on BARCODE_DPIDENT dimensions/height */ | |
| 379 /* Based on eyeballing DIALOGPOST SCHWER, using 72X as default */ | |
| 380 (void) set_height(symbol, 0.0f, 72.0f, 0.0f, 1 /*no_errtxt*/); | |
| 381 | |
| 382 return error_number; | |
| 383 } | |
| 384 | |
| 385 /* vim: set ts=4 sw=4 et : */ |
