Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/code.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 /* code.c - Handles Code 11, 39, 39+, 93, PZN, Channel and VIN */ | |
| 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 /* In version 0.5 this file was 1,553 lines long! */ | |
| 34 | |
| 35 #include <assert.h> | |
| 36 #include <stdio.h> | |
| 37 #include "common.h" | |
| 38 | |
| 39 #define SODIUM_MNS_F (IS_NUM_F | IS_MNS_F) /* SODIUM "0123456789-" */ | |
| 40 | |
| 41 /* Same as TECHNETIUM (HIBC) with "abcd" added for CODE93 */ | |
| 42 static const char SILVER[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd"; | |
| 43 | |
| 44 #define ARSENIC_F (IS_NUM_F | IS_ARS_F) /* ARSENIC "0123456789ABCDEFGHJKLMNPRSTUVWXYZ" */ | |
| 45 | |
| 46 static const char C11Table[11 + 1][6] = { | |
| 47 {'1','1','1','1','2','1'}, {'2','1','1','1','2','1'}, {'1','2','1','1','2','1'}, {'2','2','1','1','1','1'}, | |
| 48 {'1','1','2','1','2','1'}, {'2','1','2','1','1','1'}, {'1','2','2','1','1','1'}, {'1','1','1','2','2','1'}, | |
| 49 {'2','1','1','2','1','1'}, {'2','1','1','1','1','1'}, {'1','1','2','1','1','1'}, | |
| 50 {'1','1','2','2','1','1'} /* Start character (full 6), Stop character (first 5) */ | |
| 51 }; | |
| 52 | |
| 53 /* Code 39 character assignments (ISO/IEC 16388:2007 Table 1 and Table A.1) */ | |
| 54 static const char C39Table[43 + 1][10] = { | |
| 55 {'1','1','1','2','2','1','2','1','1','1'}, {'2','1','1','2','1','1','1','1','2','1'}, | |
| 56 {'1','1','2','2','1','1','1','1','2','1'}, {'2','1','2','2','1','1','1','1','1','1'}, | |
| 57 {'1','1','1','2','2','1','1','1','2','1'}, {'2','1','1','2','2','1','1','1','1','1'}, | |
| 58 {'1','1','2','2','2','1','1','1','1','1'}, {'1','1','1','2','1','1','2','1','2','1'}, | |
| 59 {'2','1','1','2','1','1','2','1','1','1'}, {'1','1','2','2','1','1','2','1','1','1'}, | |
| 60 {'2','1','1','1','1','2','1','1','2','1'}, {'1','1','2','1','1','2','1','1','2','1'}, | |
| 61 {'2','1','2','1','1','2','1','1','1','1'}, {'1','1','1','1','2','2','1','1','2','1'}, | |
| 62 {'2','1','1','1','2','2','1','1','1','1'}, {'1','1','2','1','2','2','1','1','1','1'}, | |
| 63 {'1','1','1','1','1','2','2','1','2','1'}, {'2','1','1','1','1','2','2','1','1','1'}, | |
| 64 {'1','1','2','1','1','2','2','1','1','1'}, {'1','1','1','1','2','2','2','1','1','1'}, | |
| 65 {'2','1','1','1','1','1','1','2','2','1'}, {'1','1','2','1','1','1','1','2','2','1'}, | |
| 66 {'2','1','2','1','1','1','1','2','1','1'}, {'1','1','1','1','2','1','1','2','2','1'}, | |
| 67 {'2','1','1','1','2','1','1','2','1','1'}, {'1','1','2','1','2','1','1','2','1','1'}, | |
| 68 {'1','1','1','1','1','1','2','2','2','1'}, {'2','1','1','1','1','1','2','2','1','1'}, | |
| 69 {'1','1','2','1','1','1','2','2','1','1'}, {'1','1','1','1','2','1','2','2','1','1'}, | |
| 70 {'2','2','1','1','1','1','1','1','2','1'}, {'1','2','2','1','1','1','1','1','2','1'}, | |
| 71 {'2','2','2','1','1','1','1','1','1','1'}, {'1','2','1','1','2','1','1','1','2','1'}, | |
| 72 {'2','2','1','1','2','1','1','1','1','1'}, {'1','2','2','1','2','1','1','1','1','1'}, | |
| 73 {'1','2','1','1','1','1','2','1','2','1'}, {'2','2','1','1','1','1','2','1','1','1'}, | |
| 74 {'1','2','2','1','1','1','2','1','1','1'}, {'1','2','1','2','1','2','1','1','1','1'}, | |
| 75 {'1','2','1','2','1','1','1','2','1','1'}, {'1','2','1','1','1','2','1','2','1','1'}, | |
| 76 {'1','1','1','2','1','2','1','2','1','1'}, | |
| 77 {'1','2','1','1','2','1','2','1','1','1'} /* Start character (full 10), Stop character (first 9) */ | |
| 78 }; | |
| 79 | |
| 80 /* Encoding the full ASCII character set in Code 39 (ISO/IEC 16388:2007 Table A.2) */ | |
| 81 static const char EC39Ctrl[128][2] = { | |
| 82 {'%','U'}, {'$','A'}, {'$','B'}, {'$','C'}, {'$','D'}, {'$','E'}, {'$','F'}, {'$','G'}, {'$','H'}, {'$','I'}, | |
| 83 {'$','J'}, {'$','K'}, {'$','L'}, {'$','M'}, {'$','N'}, {'$','O'}, {'$','P'}, {'$','Q'}, {'$','R'}, {'$','S'}, | |
| 84 {'$','T'}, {'$','U'}, {'$','V'}, {'$','W'}, {'$','X'}, {'$','Y'}, {'$','Z'}, {'%','A'}, {'%','B'}, {'%','C'}, | |
| 85 {'%','D'}, {'%','E'}, { " " }, {'/','A'}, {'/','B'}, {'/','C'}, {'/','D'}, {'/','E'}, {'/','F'}, {'/','G'}, | |
| 86 {'/','H'}, {'/','I'}, {'/','J'}, {'/','K'}, {'/','L'}, { "-" }, { "." }, {'/','O'}, { "0" }, { "1" }, | |
| 87 { "2" }, { "3" }, { "4" }, { "5" }, { "6" }, { "7" }, { "8" }, { "9" }, {'/','Z'}, {'%','F'}, | |
| 88 {'%','G'}, {'%','H'}, {'%','I'}, {'%','J'}, {'%','V'}, { "A" }, { "B" }, { "C" }, { "D" }, { "E" }, | |
| 89 { "F" }, { "G" }, { "H" }, { "I" }, { "J" }, { "K" }, { "L" }, { "M" }, { "N" }, { "O" }, | |
| 90 { "P" }, { "Q" }, { "R" }, { "S" }, { "T" }, { "U" }, { "V" }, { "W" }, { "X" }, { "Y" }, | |
| 91 { "Z" }, {'%','K'}, {'%','L'}, {'%','M'}, {'%','N'}, {'%','O'}, {'%','W'}, {'+','A'}, {'+','B'}, {'+','C'}, | |
| 92 {'+','D'}, {'+','E'}, {'+','F'}, {'+','G'}, {'+','H'}, {'+','I'}, {'+','J'}, {'+','K'}, {'+','L'}, {'+','M'}, | |
| 93 {'+','N'}, {'+','O'}, {'+','P'}, {'+','Q'}, {'+','R'}, {'+','S'}, {'+','T'}, {'+','U'}, {'+','V'}, {'+','W'}, | |
| 94 {'+','X'}, {'+','Y'}, {'+','Z'}, {'%','P'}, {'%','Q'}, {'%','R'}, {'%','S'}, {'%','T'} | |
| 95 }; | |
| 96 | |
| 97 /* Code 93 ANSI/AIM BC5-1995 Table 3 */ | |
| 98 static const char C93Ctrl[128][2] = { | |
| 99 {'b','U'}, {'a','A'}, {'a','B'}, {'a','C'}, {'a','D'}, {'a','E'}, {'a','F'}, {'a','G'}, {'a','H'}, {'a','I'}, | |
| 100 {'a','J'}, {'a','K'}, {'a','L'}, {'a','M'}, {'a','N'}, {'a','O'}, {'a','P'}, {'a','Q'}, {'a','R'}, {'a','S'}, | |
| 101 {'a','T'}, {'a','U'}, {'a','V'}, {'a','W'}, {'a','X'}, {'a','Y'}, {'a','Z'}, {'b','A'}, {'b','B'}, {'b','C'}, | |
| 102 {'b','D'}, {'b','E'}, { " " }, {'c','A'}, {'c','B'}, {'c','C'}, { "$" }, { "%" }, {'c','F'}, {'c','G'}, | |
| 103 {'c','H'}, {'c','I'}, {'c','J'}, { "+" }, {'c','L'}, { "-" }, { "." }, { "/" }, { "0" }, { "1" }, | |
| 104 { "2" }, { "3" }, { "4" }, { "5" }, { "6" }, { "7" }, { "8" }, { "9" }, {'c','Z'}, {'b','F'}, | |
| 105 {'b','G'}, {'b','H'}, {'b','I'}, {'b','J'}, {'b','V'}, { "A" }, { "B" }, { "C" }, { "D" }, { "E" }, | |
| 106 { "F" }, { "G" }, { "H" }, { "I" }, { "J" }, { "K" }, { "L" }, { "M" }, { "N" }, { "O" }, | |
| 107 { "P" }, { "Q" }, { "R" }, { "S" }, { "T" }, { "U" }, { "V" }, { "W" }, { "X" }, { "Y" }, | |
| 108 { "Z" }, {'b','K'}, {'b','L'}, {'b','M'}, {'b','N'}, {'b','O'}, {'b','W'}, {'d','A'}, {'d','B'}, {'d','C'}, | |
| 109 {'d','D'}, {'d','E'}, {'d','F'}, {'d','G'}, {'d','H'}, {'d','I'}, {'d','J'}, {'d','K'}, {'d','L'}, {'d','M'}, | |
| 110 {'d','N'}, {'d','O'}, {'d','P'}, {'d','Q'}, {'d','R'}, {'d','S'}, {'d','T'}, {'d','U'}, {'d','V'}, {'d','W'}, | |
| 111 {'d','X'}, {'d','Y'}, {'d','Z'}, {'b','P'}, {'b','Q'}, {'b','R'}, {'b','S'}, {'b','T'} | |
| 112 }; | |
| 113 | |
| 114 /* Code 93 ANSI/AIM BC5-1995 Table 2 */ | |
| 115 static const char C93Table[47][6] = { | |
| 116 {'1','3','1','1','1','2'}, {'1','1','1','2','1','3'}, {'1','1','1','3','1','2'}, {'1','1','1','4','1','1'}, | |
| 117 {'1','2','1','1','1','3'}, {'1','2','1','2','1','2'}, {'1','2','1','3','1','1'}, {'1','1','1','1','1','4'}, | |
| 118 {'1','3','1','2','1','1'}, {'1','4','1','1','1','1'}, {'2','1','1','1','1','3'}, {'2','1','1','2','1','2'}, | |
| 119 {'2','1','1','3','1','1'}, {'2','2','1','1','1','2'}, {'2','2','1','2','1','1'}, {'2','3','1','1','1','1'}, | |
| 120 {'1','1','2','1','1','3'}, {'1','1','2','2','1','2'}, {'1','1','2','3','1','1'}, {'1','2','2','1','1','2'}, | |
| 121 {'1','3','2','1','1','1'}, {'1','1','1','1','2','3'}, {'1','1','1','2','2','2'}, {'1','1','1','3','2','1'}, | |
| 122 {'1','2','1','1','2','2'}, {'1','3','1','1','2','1'}, {'2','1','2','1','1','2'}, {'2','1','2','2','1','1'}, | |
| 123 {'2','1','1','1','2','2'}, {'2','1','1','2','2','1'}, {'2','2','1','1','2','1'}, {'2','2','2','1','1','1'}, | |
| 124 {'1','1','2','1','2','2'}, {'1','1','2','2','2','1'}, {'1','2','2','1','2','1'}, {'1','2','3','1','1','1'}, | |
| 125 {'1','2','1','1','3','1'}, {'3','1','1','1','1','2'}, {'3','1','1','2','1','1'}, {'3','2','1','1','1','1'}, | |
| 126 {'1','1','2','1','3','1'}, {'1','1','3','1','2','1'}, {'2','1','1','1','3','1'}, {'1','2','1','2','2','1'}, | |
| 127 {'3','1','2','1','1','1'}, {'3','1','1','1','2','1'}, {'1','2','2','2','1','1'} | |
| 128 }; | |
| 129 | |
| 130 /* Code 11 */ | |
| 131 INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 132 | |
| 133 int i; | |
| 134 int h, c_digit, c_weight, c_count, k_digit, k_weight, k_count; | |
| 135 int weight[141]; /* 140 + 1 extra for 1st check */ | |
| 136 char dest[864]; /* 6 + 140 * 6 + 2 * 6 + 5 + 1 = 864 */ | |
| 137 int error_number = 0; | |
| 138 char *d = dest; | |
| 139 int num_check_digits; | |
| 140 char checkstr[3] = {0}; | |
| 141 static const char checkchrs[11] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-' }; | |
| 142 | |
| 143 /* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warning */ | |
| 144 assert(length > 0); | |
| 145 | |
| 146 if (length > 140) { /* 8 (Start) + 140 * 8 + 2 * 8 (Check) + 7 (Stop) = 1151 */ | |
| 147 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 320, "Input length %d too long (maximum 140)", length); | |
| 148 } | |
| 149 if ((i = not_sane(SODIUM_MNS_F, source, length))) { | |
| 150 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 321, | |
| 151 "Invalid character at position %d in input (digits and \"-\" only)", i); | |
| 152 } | |
| 153 | |
| 154 if (symbol->option_2 < 0 || symbol->option_2 > 2) { | |
| 155 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 339, "Invalid check digit version '%d' (1 or 2 only)", | |
| 156 symbol->option_2); | |
| 157 } | |
| 158 if (symbol->option_2 == 2) { | |
| 159 num_check_digits = 0; | |
| 160 } else if (symbol->option_2 == 1) { | |
| 161 num_check_digits = 1; | |
| 162 } else { | |
| 163 num_check_digits = 2; | |
| 164 } | |
| 165 | |
| 166 c_weight = 1; | |
| 167 c_count = 0; | |
| 168 k_weight = 1; | |
| 169 k_count = 0; | |
| 170 | |
| 171 /* start character */ | |
| 172 memcpy(d, C11Table[11], 6); | |
| 173 d += 6; | |
| 174 | |
| 175 /* Draw main body of barcode */ | |
| 176 for (i = 0; i < length; i++, d += 6) { | |
| 177 if (source[i] == '-') | |
| 178 weight[i] = 10; | |
| 179 else | |
| 180 weight[i] = ctoi(source[i]); | |
| 181 memcpy(d, C11Table[weight[i]], 6); | |
| 182 } | |
| 183 | |
| 184 if (num_check_digits) { | |
| 185 /* Calculate C checksum */ | |
| 186 for (h = length - 1; h >= 0; h--) { | |
| 187 c_count += (c_weight * weight[h]); | |
| 188 c_weight++; | |
| 189 | |
| 190 if (c_weight > 10) { | |
| 191 c_weight = 1; | |
| 192 } | |
| 193 } | |
| 194 c_digit = c_count % 11; | |
| 195 | |
| 196 checkstr[0] = checkchrs[c_digit]; | |
| 197 memcpy(d, C11Table[c_digit], 6); | |
| 198 d += 6; | |
| 199 | |
| 200 if (num_check_digits == 2) { | |
| 201 weight[length] = c_digit; | |
| 202 | |
| 203 /* Calculate K checksum */ | |
| 204 for (h = length; h >= 0; h--) { | |
| 205 k_count += (k_weight * weight[h]); | |
| 206 k_weight++; | |
| 207 | |
| 208 if (k_weight > 9) { | |
| 209 k_weight = 1; | |
| 210 } | |
| 211 } | |
| 212 k_digit = k_count % 11; | |
| 213 | |
| 214 checkstr[1] = checkchrs[k_digit]; | |
| 215 memcpy(d, C11Table[k_digit], 6); | |
| 216 d += 6; | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 if (symbol->debug & ZINT_DEBUG_PRINT) { | |
| 221 printf("Check digit (%d): %s\n", num_check_digits, num_check_digits ? checkstr : "<none>"); | |
| 222 } | |
| 223 | |
| 224 /* Stop character */ | |
| 225 memcpy(d, C11Table[11], 5); | |
| 226 d += 5; | |
| 227 | |
| 228 expand(symbol, dest, d - dest); | |
| 229 | |
| 230 /* TODO: Find documentation on BARCODE_CODE11 dimensions/height */ | |
| 231 | |
| 232 ustrcpy(symbol->text, source); | |
| 233 if (num_check_digits) { | |
| 234 ustrcat(symbol->text, checkstr); | |
| 235 } | |
| 236 return error_number; | |
| 237 } | |
| 238 | |
| 239 /* Code 39 */ | |
| 240 INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 241 int i; | |
| 242 int counter; | |
| 243 int error_number = 0; | |
| 244 int posns[86]; | |
| 245 char dest[890]; /* 10 (Start) + 86 * 10 + 10 (Check) + 9 (Stop) + 1 = 890 */ | |
| 246 char *d = dest; | |
| 247 char localstr[2] = {0}; | |
| 248 | |
| 249 counter = 0; | |
| 250 | |
| 251 if ((symbol->option_2 < 0) || (symbol->option_2 > 2)) { | |
| 252 symbol->option_2 = 0; | |
| 253 } | |
| 254 | |
| 255 /* LOGMARS MIL-STD-1189 Rev. B https://apps.dtic.mil/dtic/tr/fulltext/u2/a473534.pdf */ | |
| 256 if ((symbol->symbology == BARCODE_LOGMARS) && (length > 30)) { /* MIL-STD-1189 Rev. B Section 5.2.6.2 */ | |
| 257 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 322, "Input length %d too long (maximum 30)", length); | |
| 258 /* Prevent encoded_data out-of-bounds >= 143 for BARCODE_HIBC_39 due to wider 'wide' bars */ | |
| 259 } else if ((symbol->symbology == BARCODE_HIBC_39) && (length > 70)) { /* 16 (Start) + 70*16 + 15 (Stop) = 1151 */ | |
| 260 /* 70 less '+' and check */ | |
| 261 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 319, "Input length %d too long (maximum 68)", length - 2); | |
| 262 } else if (length > 86) { /* 13 (Start) + 86*13 + 12 (Stop) = 1143 */ | |
| 263 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 323, "Input length %d too long (maximum 86)", length); | |
| 264 } | |
| 265 | |
| 266 to_upper(source, length); | |
| 267 if ((i = not_sane_lookup(SILVER, 43 /* Up to "%" */, source, length, posns))) { | |
| 268 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 324, | |
| 269 "Invalid character at position %d in input (alphanumerics, space and \"-.$/+%%\" only)", i); | |
| 270 } | |
| 271 | |
| 272 /* Start character */ | |
| 273 memcpy(d, C39Table[43], 10); | |
| 274 d += 10; | |
| 275 | |
| 276 for (i = 0; i < length; i++, d += 10) { | |
| 277 memcpy(d, C39Table[posns[i]], 10); | |
| 278 counter += posns[i]; | |
| 279 } | |
| 280 | |
| 281 if (symbol->option_2 == 1 || symbol->option_2 == 2) { /* Visible or hidden check digit */ | |
| 282 | |
| 283 char check_digit; | |
| 284 counter %= 43; | |
| 285 check_digit = SILVER[counter]; | |
| 286 memcpy(d, C39Table[counter], 10); | |
| 287 d += 10; | |
| 288 | |
| 289 /* Display a space check digit as _, otherwise it looks like an error */ | |
| 290 if (check_digit == ' ') { | |
| 291 check_digit = '_'; | |
| 292 } | |
| 293 | |
| 294 if (symbol->option_2 == 1) { /* Visible check digit */ | |
| 295 localstr[0] = check_digit; | |
| 296 localstr[1] = '\0'; | |
| 297 } | |
| 298 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %c\n", check_digit); | |
| 299 } | |
| 300 | |
| 301 /* Stop character */ | |
| 302 memcpy(d, C39Table[43], 9); | |
| 303 d += 9; | |
| 304 | |
| 305 if ((symbol->symbology == BARCODE_LOGMARS) || (symbol->symbology == BARCODE_HIBC_39)) { | |
| 306 /* LOGMARS and HIBC use wider 'wide' bars than normal Code 39 */ | |
| 307 counter = d - dest; | |
| 308 for (i = 0; i < counter; i++) { | |
| 309 if (dest[i] == '2') { | |
| 310 dest[i] = '3'; | |
| 311 } | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 if (symbol->debug & ZINT_DEBUG_PRINT) { | |
| 316 printf("Barspaces: %.*s\n", (int) (d - dest), dest); | |
| 317 } | |
| 318 | |
| 319 expand(symbol, dest, d - dest); | |
| 320 | |
| 321 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 322 if (symbol->symbology == BARCODE_LOGMARS) { | |
| 323 /* MIL-STD-1189 Rev. B Section 5.2 | |
| 324 Min height 0.25" / 0.04" (X max) = 6.25 | |
| 325 Default height 0.625" (average of 0.375" - 0.875") / 0.01375" (average of 0.0075" - 0.02") ~ 45.45 */ | |
| 326 const float default_height = 45.4545441f; /* 0.625 / 0.01375 */ | |
| 327 const float max_height = 116.666664f; /* 0.875 / 0.0075 */ | |
| 328 error_number = set_height(symbol, 6.25f, default_height, max_height, 0 /*no_errtxt*/); | |
| 329 } else if (symbol->symbology == BARCODE_CODE39 || symbol->symbology == BARCODE_EXCODE39 | |
| 330 || symbol->symbology == BARCODE_HIBC_39) { | |
| 331 /* ISO/IEC 16388:2007 4.4 (e) recommended min height 5.0mm or 15% of width excluding quiet zones; | |
| 332 as X left to application specification use | |
| 333 width = (C + 2) * (3 * N + 6) * X + (C + 1) * I = (C + 2) * 9 + C + 1) * X = (10 * C + 19); | |
| 334 use 50 as default as none recommended */ | |
| 335 const float min_height = stripf((10.0f * (symbol->option_2 == 1 ? length + 1 : length) + 19.0f) * 0.15f); | |
| 336 error_number = set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, | |
| 337 0 /*no_errtxt*/); | |
| 338 } | |
| 339 /* PZN and CODE32 set their own heights */ | |
| 340 } else { | |
| 341 (void) set_height(symbol, 0.0f, 50.f, 0.0f, 1 /*no_errtxt*/); | |
| 342 } | |
| 343 | |
| 344 if (symbol->symbology == BARCODE_CODE39) { | |
| 345 ustrcpy(symbol->text, "*"); | |
| 346 ustrncat(symbol->text, source, length); | |
| 347 ustrcat(symbol->text, localstr); | |
| 348 ustrcat(symbol->text, "*"); | |
| 349 } else { | |
| 350 ustrcpy(symbol->text, source); | |
| 351 ustrcat(symbol->text, localstr); | |
| 352 } | |
| 353 return error_number; | |
| 354 } | |
| 355 | |
| 356 /* Pharmazentralnummer (PZN) */ | |
| 357 /* PZN https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/IFA_Info_Code_39_EN.pdf */ | |
| 358 /* PZN https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/ | |
| 359 IFA-Info_Check_Digit_Calculations_PZN_PPN_UDI_EN.pdf */ | |
| 360 INTERNAL int pzn(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 361 | |
| 362 int i, error_number, zeroes; | |
| 363 int count, check_digit; | |
| 364 unsigned char have_check_digit = '\0'; | |
| 365 char localstr[1 + 8 + 1]; /* '-' prefix + 8 digits + NUL */ | |
| 366 const int pzn7 = symbol->option_2 == 1; | |
| 367 | |
| 368 if (length > 8 - pzn7) { | |
| 369 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 325, "Input length %1$d too long (maximum %2$d)", length, | |
| 370 8 - pzn7); | |
| 371 } | |
| 372 if (length == 8 - pzn7) { | |
| 373 have_check_digit = source[7 - pzn7]; | |
| 374 length--; | |
| 375 } | |
| 376 if ((i = not_sane(NEON_F, source, length))) { | |
| 377 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 326, | |
| 378 "Invalid character at position %d in input (digits only)", i); | |
| 379 } | |
| 380 | |
| 381 localstr[0] = '-'; | |
| 382 zeroes = 7 - pzn7 - length + 1; | |
| 383 for (i = 1; i < zeroes; i++) | |
| 384 localstr[i] = '0'; | |
| 385 ustrcpy(localstr + zeroes, source); | |
| 386 | |
| 387 count = 0; | |
| 388 for (i = 1; i < 8 - pzn7; i++) { | |
| 389 count += (i + pzn7) * ctoi(localstr[i]); | |
| 390 } | |
| 391 | |
| 392 check_digit = count % 11; | |
| 393 | |
| 394 if (symbol->debug & ZINT_DEBUG_PRINT) { | |
| 395 printf("PZN: %s, check digit %d\n", localstr, (int) check_digit); | |
| 396 } | |
| 397 | |
| 398 if (check_digit == 10) { | |
| 399 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 327, "Invalid PZN, check digit is '10'"); | |
| 400 } | |
| 401 if (have_check_digit && ctoi(have_check_digit) != check_digit) { | |
| 402 return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 890, "Invalid check digit '%1$c', expecting '%2$c'", | |
| 403 have_check_digit, itoc(check_digit)); | |
| 404 } | |
| 405 | |
| 406 localstr[8 - pzn7] = itoc(check_digit); | |
| 407 localstr[9 - pzn7] = '\0'; | |
| 408 | |
| 409 if (pzn7) { | |
| 410 symbol->option_2 = 0; /* Need to overwrite this so `code39()` doesn't add a check digit itself */ | |
| 411 } | |
| 412 | |
| 413 error_number = code39(symbol, (unsigned char *) localstr, 9 - pzn7); | |
| 414 | |
| 415 if (pzn7) { | |
| 416 symbol->option_2 = 1; /* Restore */ | |
| 417 } | |
| 418 | |
| 419 ustrcpy(symbol->text, "PZN - "); /* Note changed to put space after hyphen */ | |
| 420 ustrcat(symbol->text, localstr + 1); | |
| 421 | |
| 422 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 423 /* Technical Information regarding PZN Coding V 2.1 (25 Feb 2019) Code size | |
| 424 https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/IFA_Info_Code_39_EN.pdf | |
| 425 "normal" X 0.25mm (0.187mm - 0.45mm), height 8mm - 20mm for 0.25mm X, 10mm mentioned so use that | |
| 426 as default, 10mm / 0.25mm = 40 */ | |
| 427 if (error_number < ZINT_ERROR) { | |
| 428 const float min_height = 17.7777786f; /* 8.0 / 0.45 */ | |
| 429 const float max_height = 106.951874f; /* 20.0 / 0.187 */ | |
| 430 error_number = set_height(symbol, min_height, 40.0f, max_height, 0 /*no_errtxt*/); | |
| 431 } | |
| 432 } else { | |
| 433 if (error_number < ZINT_ERROR) { | |
| 434 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); | |
| 435 } | |
| 436 } | |
| 437 | |
| 438 return error_number; | |
| 439 } | |
| 440 | |
| 441 /* Extended Code 39 - ISO/IEC 16388:2007 Annex A */ | |
| 442 INTERNAL int excode39(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 443 | |
| 444 unsigned char buffer[86 * 2 + 1] = {0}; | |
| 445 unsigned char *b = buffer; | |
| 446 unsigned char check_digit = '\0'; | |
| 447 int i; | |
| 448 int error_number; | |
| 449 | |
| 450 if (length > 86) { | |
| 451 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 328, "Input length %d too long (maximum 86)", length); | |
| 452 } | |
| 453 | |
| 454 /* Creates a buffer string and places control characters into it */ | |
| 455 for (i = 0; i < length; i++) { | |
| 456 if (source[i] > 127) { | |
| 457 /* Cannot encode extended ASCII */ | |
| 458 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 329, | |
| 459 "Invalid character at position %d in input, extended ASCII not allowed", i + 1); | |
| 460 } | |
| 461 memcpy(b, EC39Ctrl[source[i]], 2); | |
| 462 b += EC39Ctrl[source[i]][1] ? 2 : 1; | |
| 463 } | |
| 464 if (b - buffer > 86) { | |
| 465 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 317, "Input too long, requires %d symbol characters (maximum 86)", | |
| 466 (int) (b - buffer)); | |
| 467 } | |
| 468 *b = '\0'; | |
| 469 | |
| 470 /* Then sends the buffer to the C39 function */ | |
| 471 error_number = code39(symbol, buffer, b - buffer); | |
| 472 | |
| 473 /* Save visible check digit */ | |
| 474 if (symbol->option_2 == 1) { | |
| 475 const int len = (int) ustrlen(symbol->text); | |
| 476 if (len > 0) { | |
| 477 check_digit = symbol->text[len - 1]; | |
| 478 } | |
| 479 } | |
| 480 | |
| 481 /* Copy over source to HRT, subbing space for unprintables */ | |
| 482 for (i = 0; i < length; i++) | |
| 483 symbol->text[i] = source[i] >= ' ' && source[i] != 0x7F ? source[i] : ' '; | |
| 484 | |
| 485 if (check_digit) { | |
| 486 symbol->text[i++] = check_digit; | |
| 487 } | |
| 488 symbol->text[i] = '\0'; | |
| 489 | |
| 490 return error_number; | |
| 491 } | |
| 492 | |
| 493 /* Code 93 is an advancement on Code 39 and the definition is a lot tighter */ | |
| 494 INTERNAL int code93(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 495 | |
| 496 /* SILVER includes the extra characters a, b, c and d to represent Code 93 specific | |
| 497 shift characters 1, 2, 3 and 4 respectively. These characters are never used by | |
| 498 `code39()` and `excode39()` */ | |
| 499 | |
| 500 int i; | |
| 501 int h, weight, c, k, error_number = 0; | |
| 502 int values[125]; /* 123 + 2 (Checks) */ | |
| 503 char buffer[247]; /* 123*2 (123 full ASCII) + 1 = 247 */ | |
| 504 char *b = buffer; | |
| 505 char dest[764]; /* 6 (Start) + 123*6 + 2*6 (Checks) + 7 (Stop) + 1 (NUL) = 764 */ | |
| 506 char *d = dest; | |
| 507 | |
| 508 /* Suppresses clang-tidy clang-analyzer-core.CallAndMessage warning */ | |
| 509 assert(length > 0); | |
| 510 | |
| 511 if (length > 123) { /* 9 (Start) + 123*9 + 2*9 (Checks) + 10 (Stop) = 1144 */ | |
| 512 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 330, "Input length %d too long (maximum 123)", length); | |
| 513 } | |
| 514 | |
| 515 /* Message Content */ | |
| 516 for (i = 0; i < length; i++) { | |
| 517 if (source[i] > 127) { | |
| 518 /* Cannot encode extended ASCII */ | |
| 519 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 331, | |
| 520 "Invalid character at position %d in input, extended ASCII not allowed", i + 1); | |
| 521 } | |
| 522 memcpy(b, C93Ctrl[source[i]], 2); | |
| 523 b += C93Ctrl[source[i]][1] ? 2 : 1; | |
| 524 symbol->text[i] = source[i] >= ' ' && source[i] != 0x7F ? source[i] : ' '; | |
| 525 } | |
| 526 | |
| 527 /* Now we can check the true length of the barcode */ | |
| 528 h = b - buffer; | |
| 529 if (h > 123) { | |
| 530 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 332, | |
| 531 "Input too long, requires %d symbol characters (maximum 123)", h); | |
| 532 } | |
| 533 | |
| 534 for (i = 0; i < h; i++) { | |
| 535 values[i] = posn(SILVER, buffer[i]); | |
| 536 } | |
| 537 | |
| 538 /* Putting the data into dest[] is not done until after check digits are calculated */ | |
| 539 | |
| 540 /* Check digit C */ | |
| 541 c = 0; | |
| 542 weight = 1; | |
| 543 for (i = h - 1; i >= 0; i--) { | |
| 544 c += values[i] * weight; | |
| 545 weight++; | |
| 546 if (weight == 21) | |
| 547 weight = 1; | |
| 548 } | |
| 549 c = c % 47; | |
| 550 values[h] = c; | |
| 551 | |
| 552 /* Check digit K */ | |
| 553 k = 0; | |
| 554 weight = 1; | |
| 555 for (i = h; i >= 0; i--) { | |
| 556 k += values[i] * weight; | |
| 557 weight++; | |
| 558 if (weight == 16) | |
| 559 weight = 1; | |
| 560 } | |
| 561 k = k % 47; | |
| 562 values[h + 1] = k; | |
| 563 h += 2; | |
| 564 | |
| 565 if (symbol->debug & ZINT_DEBUG_PRINT) { | |
| 566 printf("Check digit c: %d, k: %d\n", c, k); | |
| 567 } | |
| 568 | |
| 569 /* Start character */ | |
| 570 memcpy(d, "111141", 6); | |
| 571 d += 6; | |
| 572 | |
| 573 for (i = 0; i < h; i++, d += 6) { | |
| 574 memcpy(d, C93Table[values[i]], 6); | |
| 575 } | |
| 576 | |
| 577 /* Stop character */ | |
| 578 memcpy(d, "1111411", 7); | |
| 579 d += 7; | |
| 580 | |
| 581 expand(symbol, dest, d - dest); | |
| 582 | |
| 583 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 584 /* ANSI/AIM BC5-1995 Section 2.6 minimum height 0.2" or 15% of symbol length, whichever is greater | |
| 585 no max X given so for min height use symbol length = (9 * (C + 4) + 1) * X + 2 * Q = symbol->width + 20; | |
| 586 use 40 as default height based on figures in spec */ | |
| 587 const float min_height = stripf((symbol->width + 20) * 0.15f); | |
| 588 error_number = set_height(symbol, min_height, min_height > 40.0f ? min_height : 40.0f, 0.0f, 0 /*no_errtxt*/); | |
| 589 } else { | |
| 590 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); | |
| 591 } | |
| 592 | |
| 593 if (symbol->option_2 == 1) { | |
| 594 symbol->text[length] = SILVER[c]; | |
| 595 symbol->text[length + 1] = SILVER[k]; | |
| 596 symbol->text[length + 2] = '\0'; | |
| 597 } | |
| 598 | |
| 599 return error_number; | |
| 600 } | |
| 601 | |
| 602 typedef const struct s_channel_precalc { | |
| 603 int value; unsigned char B[8]; unsigned char S[8]; unsigned char bmax[7]; unsigned char smax[7]; | |
| 604 } channel_precalc; | |
| 605 | |
| 606 #if 0 | |
| 607 #define CHANNEL_GENERATE_PRECALCS | |
| 608 #endif | |
| 609 | |
| 610 #ifdef CHANNEL_GENERATE_PRECALCS | |
| 611 /* To generate precalc tables uncomment CHANNEL_GENERATE_PRECALCS define and run | |
| 612 "backend/tests/test_channel -f generate -g" and place result in "channel_precalcs.h" */ | |
| 613 static void channel_generate_precalc(int channels, int value, int mod, int last, int B[8], int S[8], int bmax[7], | |
| 614 int smax[7]) { | |
| 615 int i; | |
| 616 if (value == mod) printf("static channel_precalc channel_precalcs%d[] = {\n", channels); | |
| 617 printf(" { %7ld, {", value); for (i = 0; i < 8; i++) printf(" %d,", B[i]); fputs(" },", stdout); | |
| 618 fputs(" {", stdout); for (i = 0; i < 8; i++) printf(" %d,", S[i]); fputs(" },", stdout); | |
| 619 fputs(" {", stdout); for (i = 0; i < 7; i++) printf(" %d,", bmax[i]); fputs(" },", stdout); | |
| 620 fputs(" {", stdout); for (i = 0; i < 7; i++) printf(" %d,", smax[i]); fputs(" }, },\n", stdout); | |
| 621 if (value == last) fputs("};\n", stdout); | |
| 622 } | |
| 623 #else | |
| 624 #include "channel_precalcs.h" | |
| 625 #endif | |
| 626 | |
| 627 static int channel_copy_precalc(channel_precalc *const precalc, int B[8], int S[8], int bmax[7], int smax[7]) { | |
| 628 int i; | |
| 629 | |
| 630 for (i = 0; i < 7; i++) { | |
| 631 B[i] = precalc->B[i]; | |
| 632 S[i] = precalc->S[i]; | |
| 633 bmax[i] = precalc->bmax[i]; | |
| 634 smax[i] = precalc->smax[i]; | |
| 635 } | |
| 636 B[7] = precalc->B[7]; | |
| 637 S[7] = precalc->S[7]; | |
| 638 | |
| 639 return precalc->value; | |
| 640 } | |
| 641 | |
| 642 /* CHNCHR is adapted from ANSI/AIM BC12-1998 Annex D Figure D5 and is Copyright (c) AIM 1997 */ | |
| 643 | |
| 644 /* It is used here on the understanding that it forms part of the specification | |
| 645 for Channel Code and therefore its use is permitted under the following terms | |
| 646 set out in that document: | |
| 647 | |
| 648 "It is the intent and understanding of AIM [t]hat the symbology presented in this | |
| 649 specification is entirely in the public domain and free of all use restrictions, | |
| 650 licenses and fees. AIM USA, its member companies, or individual officers | |
| 651 assume no liability for the use of this document." */ | |
| 652 static void CHNCHR(int channels, int target_value, int B[8], int S[8]) { | |
| 653 /* Use of initial pre-calculations taken from Barcode Writer in Pure PostScript (BWIPP) | |
| 654 * Copyright (c) 2004-2020 Terry Burton (MIT/X-Consortium license) */ | |
| 655 static channel_precalc initial_precalcs[6] = { | |
| 656 { 0, { 1, 1, 1, 1, 1, 2, 1, 2, }, { 1, 1, 1, 1, 1, 1, 1, 3, }, { 1, 1, 1, 1, 1, 3, 2, }, | |
| 657 { 1, 1, 1, 1, 1, 3, 3, }, }, | |
| 658 { 0, { 1, 1, 1, 1, 2, 1, 1, 3, }, { 1, 1, 1, 1, 1, 1, 1, 4, }, { 1, 1, 1, 1, 4, 3, 3, }, | |
| 659 { 1, 1, 1, 1, 4, 4, 4, }, }, | |
| 660 { 0, { 1, 1, 1, 2, 1, 1, 2, 3, }, { 1, 1, 1, 1, 1, 1, 1, 5, }, { 1, 1, 1, 5, 4, 4, 4, }, | |
| 661 { 1, 1, 1, 5, 5, 5, 5, }, }, | |
| 662 { 0, { 1, 1, 2, 1, 1, 2, 1, 4, }, { 1, 1, 1, 1, 1, 1, 1, 6, }, { 1, 1, 6, 5, 5, 5, 4, }, | |
| 663 { 1, 1, 6, 6, 6, 6, 6, }, }, | |
| 664 { 0, { 1, 2, 1, 1, 2, 1, 1, 5, }, { 1, 1, 1, 1, 1, 1, 1, 7, }, { 1, 7, 6, 6, 6, 5, 5, }, | |
| 665 { 1, 7, 7, 7, 7, 7, 7, }, }, | |
| 666 { 0, { 2, 1, 1, 2, 1, 1, 2, 5, }, { 1, 1, 1, 1, 1, 1, 1, 8, }, { 8, 7, 7, 7, 6, 6, 6, }, | |
| 667 { 8, 8, 8, 8, 8, 8, 8, }, }, | |
| 668 }; | |
| 669 int bmax[7], smax[7]; | |
| 670 int value = 0; | |
| 671 | |
| 672 channel_copy_precalc(&initial_precalcs[channels - 3], B, S, bmax, smax); | |
| 673 | |
| 674 #ifndef CHANNEL_GENERATE_PRECALCS | |
| 675 if (channels == 7 && target_value >= channel_precalcs7[0].value) { | |
| 676 value = channel_copy_precalc(&channel_precalcs7[(target_value / channel_precalcs7[0].value) - 1], B, S, bmax, | |
| 677 smax); | |
| 678 } else if (channels == 8 && target_value >= channel_precalcs8[0].value) { | |
| 679 value = channel_copy_precalc(&channel_precalcs8[(target_value / channel_precalcs8[0].value) - 1], B, S, bmax, | |
| 680 smax); | |
| 681 } | |
| 682 #endif | |
| 683 | |
| 684 goto chkchr; | |
| 685 | |
| 686 ls0:smax[1] = smax[0] + 1 - S[0]; B[0] = 1; | |
| 687 if (S[0] == 1) goto nb0; | |
| 688 lb0: bmax[1] = bmax[0] + 1 - B[0]; S[1] = 1; | |
| 689 ls1: smax[2] = smax[1] + 1 - S[1]; B[1] = 1; | |
| 690 if (S[0] + B[0] + S[1] == 3) goto nb1; | |
| 691 lb1: bmax[2] = bmax[1] + 1 - B[1]; S[2] = 1; | |
| 692 ls2: smax[3] = smax[2] + 1 - S[2]; B[2] = 1; | |
| 693 if (B[0] + S[1] + B[1] + S[2] == 4) goto nb2; | |
| 694 lb2: bmax[3] = bmax[2] + 1 - B[2]; S[3] = 1; | |
| 695 ls3: smax[4] = smax[3] + 1 - S[3]; B[3] = 1; | |
| 696 if (B[1] + S[2] + B[2] + S[3] == 4) goto nb3; | |
| 697 lb3: bmax[4] = bmax[3] + 1 - B[3]; S[4] = 1; | |
| 698 ls4: smax[5] = smax[4] + 1 - S[4]; B[4] = 1; | |
| 699 if (B[2] + S[3] + B[3] + S[4] == 4) goto nb4; | |
| 700 lb4: bmax[5] = bmax[4] + 1 - B[4]; S[5] = 1; | |
| 701 ls5: smax[6] = smax[5] + 1 - S[5]; B[5] = 1; | |
| 702 if (B[3] + S[4] + B[4] + S[5] == 4) goto nb5; | |
| 703 lb5: bmax[6] = bmax[5] + 1 - B[5]; S[6] = 1; | |
| 704 ls6: S[7] = smax[6] + 1 - S[6]; B[6] = 1; | |
| 705 if (B[4] + S[5] + B[5] + S[6] == 4) goto nb6; | |
| 706 lb6: B[7] = bmax[6] + 1 - B[6]; | |
| 707 if (B[5] + S[6] + B[6] + S[7] + B[7] == 5) goto nb6; | |
| 708 chkchr: | |
| 709 #ifdef CHANNEL_GENERATE_PRECALCS | |
| 710 /* 115338 == (576688 + 2) / 5 */ | |
| 711 if (channels == 7 && value && value % 115338 == 0) { | |
| 712 channel_generate_precalc(channels, value, 115338, | |
| 713 115338 * (5 - 1), B, S, bmax, smax); | |
| 714 /* 119121 == (7742862 + 3) / 65 */ | |
| 715 } else if (channels == 8 && value && value % 119121 == 0) { | |
| 716 channel_generate_precalc(channels, value, 119121, | |
| 717 119121 * (65 - 1), B, S, bmax, smax); | |
| 718 } | |
| 719 #endif | |
| 720 if (value == target_value) return; | |
| 721 value++; | |
| 722 nb6: if (++B[6] <= bmax[6]) goto lb6; | |
| 723 if (++S[6] <= smax[6]) goto ls6; | |
| 724 nb5: if (++B[5] <= bmax[5]) goto lb5; | |
| 725 if (++S[5] <= smax[5]) goto ls5; | |
| 726 nb4: if (++B[4] <= bmax[4]) goto lb4; | |
| 727 if (++S[4] <= smax[4]) goto ls4; | |
| 728 nb3: if (++B[3] <= bmax[3]) goto lb3; | |
| 729 if (++S[3] <= smax[3]) goto ls3; | |
| 730 nb2: if (++B[2] <= bmax[2]) goto lb2; | |
| 731 if (++S[2] <= smax[2]) goto ls2; | |
| 732 nb1: if (++B[1] <= bmax[1]) goto lb1; | |
| 733 if (++S[1] <= smax[1]) goto ls1; | |
| 734 nb0: if (++B[0] <= bmax[0]) goto lb0; | |
| 735 if (++S[0] <= smax[0]) goto ls0; | |
| 736 } | |
| 737 | |
| 738 /* Channel Code - According to ANSI/AIM BC12-1998 */ | |
| 739 INTERNAL int channel(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 740 static const int max_ranges[] = { -1, -1, -1, 26, 292, 3493, 44072, 576688, 7742862 }; | |
| 741 int S[8] = {0}, B[8] = {0}; | |
| 742 int target_value; | |
| 743 char dest[30]; | |
| 744 char *d = dest; | |
| 745 int channels, i; | |
| 746 int error_number = 0, zeroes; | |
| 747 | |
| 748 if (length > 7) { | |
| 749 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 333, "Input length %d too long (maximum 7)", length); | |
| 750 } | |
| 751 if ((i = not_sane(NEON_F, source, length))) { | |
| 752 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 334, | |
| 753 "Invalid character at position %d in input (digits only)", i); | |
| 754 } | |
| 755 target_value = to_int(source, length); | |
| 756 | |
| 757 if ((symbol->option_2 < 3) || (symbol->option_2 > 8)) { | |
| 758 channels = 0; | |
| 759 } else { | |
| 760 channels = symbol->option_2; | |
| 761 } | |
| 762 | |
| 763 if (channels == 0) { | |
| 764 channels = length + 1; | |
| 765 if (target_value > 576688 && channels < 8) { | |
| 766 channels = 8; | |
| 767 } else if (target_value > 44072 && channels < 7) { | |
| 768 channels = 7; | |
| 769 } else if (target_value > 3493 && channels < 6) { | |
| 770 channels = 6; | |
| 771 } else if (target_value > 292 && channels < 5) { | |
| 772 channels = 5; | |
| 773 } else if (target_value > 26 && channels < 4) { | |
| 774 channels = 4; | |
| 775 } | |
| 776 } | |
| 777 if (channels == 2) { | |
| 778 channels = 3; | |
| 779 } | |
| 780 | |
| 781 if (target_value > max_ranges[channels]) { | |
| 782 if (channels == 8) { | |
| 783 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 318, "Input value \"%1$d\" out of range (0 to %2$d)", | |
| 784 target_value, max_ranges[channels]); | |
| 785 } | |
| 786 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 335, | |
| 787 "Input value \"%1$d\" out of range (0 to %2$d for %3$d channels)", | |
| 788 target_value, max_ranges[channels], channels); | |
| 789 } | |
| 790 | |
| 791 CHNCHR(channels, target_value, B, S); | |
| 792 | |
| 793 memcpy(d, "111111111", 9); /* Finder pattern */ | |
| 794 d += 9; | |
| 795 for (i = 8 - channels; i < 8; i++) { | |
| 796 *d++ = itoc(S[i]); | |
| 797 *d++ = itoc(B[i]); | |
| 798 } | |
| 799 | |
| 800 zeroes = channels - 1 - length; | |
| 801 if (zeroes < 0) { | |
| 802 zeroes = 0; | |
| 803 } else if (zeroes) { | |
| 804 memset(symbol->text, '0', zeroes); | |
| 805 } | |
| 806 ustrcpy(symbol->text + zeroes, source); | |
| 807 | |
| 808 expand(symbol, dest, d - dest); | |
| 809 | |
| 810 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 811 /* ANSI/AIM BC12-1998 gives min height as 5mm or 15% of length; X left as application specification so use | |
| 812 length = 1X (left qz) + (9 (finder) + 4 * 8 - 2) * X + 2X (right qz); | |
| 813 use 20 as default based on figures in spec */ | |
| 814 const float min_height = stripf((1 + 9 + 4 * channels - 2 + 2) * 0.15f); | |
| 815 error_number = set_height(symbol, min_height, 20.0f, 0.0f, 0 /*no_errtxt*/); | |
| 816 } else { | |
| 817 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); | |
| 818 } | |
| 819 | |
| 820 return error_number; | |
| 821 } | |
| 822 | |
| 823 /* Vehicle Identification Number (VIN) */ | |
| 824 INTERNAL int vin(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 825 | |
| 826 /* This code verifies the check digit present in North American VIN codes */ | |
| 827 | |
| 828 char dest[200]; /* 10 + 10 + 17 * 10 + 9 + 1 = 200 */ | |
| 829 char *d = dest; | |
| 830 char input_check; | |
| 831 char output_check; | |
| 832 int sum; | |
| 833 int i; | |
| 834 static const char weight[17] = { 8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2 }; | |
| 835 | |
| 836 /* Check length */ | |
| 837 if (length != 17) { | |
| 838 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 336, "Input length %d wrong (17 only)", length); | |
| 839 } | |
| 840 | |
| 841 /* Check input characters, I, O and Q are not allowed */ | |
| 842 if ((i = not_sane(ARSENIC_F, source, length))) { | |
| 843 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 337, | |
| 844 "Invalid character at position %d in input (alphanumerics only, excluding \"IOQ\")", i); | |
| 845 } | |
| 846 | |
| 847 to_upper(source, length); | |
| 848 | |
| 849 /* Check digit only valid for North America */ | |
| 850 if (source[0] >= '1' && source[0] <= '5') { | |
| 851 input_check = source[8]; | |
| 852 | |
| 853 sum = 0; | |
| 854 for (i = 0; i < 17; i++) { | |
| 855 int value; | |
| 856 if (source[i] <= '9') { | |
| 857 value = source[i] - '0'; | |
| 858 } else if (source[i] <= 'H') { | |
| 859 value = (source[i] - 'A') + 1; | |
| 860 } else if (source[i] <= 'R') { | |
| 861 value = (source[i] - 'J') + 1; | |
| 862 } else { /* (source[i] >= 'S') && (source[i] <= 'Z') */ | |
| 863 value = (source[i] - 'S') + 2; | |
| 864 } | |
| 865 sum += value * weight[i]; | |
| 866 } | |
| 867 | |
| 868 output_check = '0' + (sum % 11); | |
| 869 | |
| 870 if (output_check == ':') { | |
| 871 /* Check digit was 10 */ | |
| 872 output_check = 'X'; | |
| 873 } | |
| 874 | |
| 875 if (symbol->debug & ZINT_DEBUG_PRINT) { | |
| 876 printf("Producing VIN code: %s\n", source); | |
| 877 printf("Input check was %c, calculated check is %c\n", input_check, output_check); | |
| 878 } | |
| 879 | |
| 880 if (input_check != output_check) { | |
| 881 return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 338, | |
| 882 "Invalid check digit '%1$c' (position 9), expecting '%2$c'", input_check, output_check); | |
| 883 } | |
| 884 } | |
| 885 | |
| 886 /* Start character */ | |
| 887 memcpy(d, C39Table[43], 10); | |
| 888 d += 10; | |
| 889 | |
| 890 /* Import character 'I' prefix? */ | |
| 891 if (symbol->option_2 & 1) { | |
| 892 memcpy(d, C39Table[18], 10); | |
| 893 d += 10; | |
| 894 } | |
| 895 | |
| 896 /* Copy glyphs to symbol */ | |
| 897 for (i = 0; i < 17; i++, d += 10) { | |
| 898 memcpy(d, C39Table[posn(SILVER, source[i])], 10); | |
| 899 } | |
| 900 | |
| 901 /* Stop character */ | |
| 902 memcpy(d, C39Table[43], 9); | |
| 903 d += 9; | |
| 904 | |
| 905 expand(symbol, dest, d - dest); | |
| 906 | |
| 907 ustrcpy(symbol->text, source); | |
| 908 | |
| 909 /* Specification of dimensions/height for BARCODE_VIN unlikely */ | |
| 910 | |
| 911 return 0; | |
| 912 } | |
| 913 | |
| 914 /* vim: set ts=4 sw=4 et : */ |
