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 : */