comparison mupdf-source/thirdparty/zint/backend/medical.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 /* medical.c - Handles 1 track and 2 track pharmacode and Codabar */
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
36 INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int length);
37
38 static const char CALCIUM[] = "0123456789-$:/.+ABCD";
39 #define CALCIUM_INNER_F (IS_NUM_F | IS_MNS_F | IS_CLI_F | IS_PLS_F) /* CALCIUM_INNER "0123456789-$:/.+" */
40
41 /* Codabar table checked against EN 798:1995 */
42 static const char CodaTable[20][8] = {
43 {'1','1','1','1','1','2','2','1'}, {'1','1','1','1','2','2','1','1'}, {'1','1','1','2','1','1','2','1'},
44 {'2','2','1','1','1','1','1','1'}, {'1','1','2','1','1','2','1','1'}, {'2','1','1','1','1','2','1','1'},
45 {'1','2','1','1','1','1','2','1'}, {'1','2','1','1','2','1','1','1'}, {'1','2','2','1','1','1','1','1'},
46 {'2','1','1','2','1','1','1','1'}, {'1','1','1','2','2','1','1','1'}, {'1','1','2','2','1','1','1','1'},
47 {'2','1','1','1','2','1','2','1'}, {'2','1','2','1','1','1','2','1'}, {'2','1','2','1','2','1','1','1'},
48 {'1','1','2','1','2','1','2','1'}, {'1','1','2','2','1','2','1','1'}, {'1','2','1','2','1','1','2','1'},
49 {'1','1','1','2','1','2','2','1'}, {'1','1','1','2','2','2','1','1'}
50 };
51
52 INTERNAL int pharma(struct zint_symbol *symbol, unsigned char source[], int length) {
53 /* "Pharmacode can represent only a single integer from 3 to 131070. Unlike other
54 commonly used one-dimensional barcode schemes, pharmacode does not store the data in a
55 form corresponding to the human-readable digits; the number is encoded in binary, rather
56 than decimal. Pharmacode is read from right to left: with n as the bar position starting
57 at 0 on the right, each narrow bar adds 2^n to the value and each wide bar adds 2(2^n).
58 The minimum barcode is 2 bars and the maximum 16, so the smallest number that could
59 be encoded is 3 (2 narrow bars) and the biggest is 131070 (16 wide bars)."
60 - http://en.wikipedia.org/wiki/Pharmacode */
61
62 /* This code uses the One Track Pharamacode calculating algorithm as recommended by
63 the specification at http://www.laetus.com/laetus.php?request=file&id=69
64 (http://www.gomaro.ch/ftproot/Laetus_PHARMA-CODE.pdf) */
65
66 int i;
67 int tester;
68 int counter, error_number = 0, h;
69 char inter[18] = {0}; /* 131070 -> 17 bits */
70 char *in = inter;
71 char dest[64]; /* 17 * 2 + 1 */
72 char *d = dest;
73
74 if (length > 6) {
75 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 350, "Input length %d too long (maximum 6)", length);
76 }
77 if ((i = not_sane(NEON_F, source, length))) {
78 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 351,
79 "Invalid character at position %d in input (digits only)", i);
80 }
81
82 tester = to_int(source, length);
83 if ((tester < 3) || (tester > 131070)) {
84 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 352, "Input value '%d' out of range (3 to 131070)", tester);
85 }
86
87 do {
88 if (!(tester & 1)) {
89 *in++ = 'W';
90 tester = (tester - 2) / 2;
91 } else {
92 *in++ = 'N';
93 tester = (tester - 1) / 2;
94 }
95 } while (tester != 0);
96
97 h = in - inter;
98 for (counter = h - 1; counter >= 0; counter--) {
99 *d++ = inter[counter] == 'W' ? '3' : '1';
100 *d++ = '2';
101 }
102 *--d = '\0'; /* Chop off final bar */
103
104 expand(symbol, dest, d - dest);
105
106 if (symbol->output_options & COMPLIANT_HEIGHT) {
107 /* Laetus Pharmacode Guide 1.2 Standard one-track height 8mm / 0.5mm (X) */
108 error_number = set_height(symbol, 16.0f, 0.0f, 0.0f, 0 /*no_errtxt*/);
109 } else {
110 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/);
111 }
112
113 return error_number;
114 }
115
116 static int pharma_two_calc(int tester, char *d) {
117 /* This code uses the Two Track Pharamacode defined in the document at
118 http://www.laetus.com/laetus.php?request=file&id=69 and using a modified
119 algorithm from the One Track system. This standard accepts integet values
120 from 4 to 64570080. */
121
122 int counter, h;
123 char inter[17];
124 char *in = inter;
125
126 do {
127 switch (tester % 3) {
128 case 0:
129 *in++ = '3';
130 tester = (tester - 3) / 3;
131 break;
132 case 1:
133 *in++ = '1';
134 tester = (tester - 1) / 3;
135 break;
136 case 2:
137 *in++ = '2';
138 tester = (tester - 2) / 3;
139 break;
140 }
141 } while (tester != 0);
142
143 h = in - inter;
144 for (counter = h - 1; counter >= 0; counter--) {
145 *d++ = inter[counter];
146 }
147 *d = '\0';
148
149 return h;
150 }
151
152 INTERNAL int pharma_two(struct zint_symbol *symbol, unsigned char source[], int length) {
153 /* Draws the patterns for two track pharmacode */
154 int i;
155 int tester;
156 char height_pattern[200];
157 unsigned int loopey, h;
158 int writer;
159 int error_number = 0;
160
161 if (length > 8) {
162 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 354, "Input length %d too long (maximum 8)", length);
163 }
164 if ((i = not_sane(NEON_F, source, length))) {
165 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 355,
166 "Invalid character at position %d in input (digits only)", i);
167 }
168
169 tester = to_int(source, length);
170 if ((tester < 4) || (tester > 64570080)) {
171 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 353, "Input value '%d' out of range (4 to 64570080)", tester);
172 }
173 h = pharma_two_calc(tester, height_pattern);
174
175 writer = 0;
176 for (loopey = 0; loopey < h; loopey++) {
177 if ((height_pattern[loopey] == '2') || (height_pattern[loopey] == '3')) {
178 set_module(symbol, 0, writer);
179 }
180 if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '3')) {
181 set_module(symbol, 1, writer);
182 }
183 writer += 2;
184 }
185 symbol->rows = 2;
186 symbol->width = writer - 1;
187
188 if (symbol->output_options & COMPLIANT_HEIGHT) {
189 /* Laetus Pharmacode Guide 1.4
190 Two-track height min 8mm / 2mm (X max) = 4X (2X per row), standard 8mm / 1mm = 8X,
191 max 12mm / 0.8mm (X min) = 15X */
192 error_number = set_height(symbol, 2.0f, 8.0f, 15.0f, 0 /*no_errtxt*/);
193 } else {
194 (void) set_height(symbol, 0.0f, 10.0f, 0.0f, 1 /*no_errtxt*/);
195 }
196
197 return error_number;
198 }
199
200 /* The Codabar system consisting of simple substitution */
201 INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int length) {
202
203 int i, error_number = 0;
204 int posns[103];
205 char dest[833]; /* (103 + 1) * 8 + 1 == 833 */
206 char *d = dest;
207 int add_checksum, count = 0, checksum = 0;
208 int d_chars = 0;
209
210 if (length > 103) { /* No stack smashing please (103 + 1) * 11 = 1144 */
211 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 356, "Input length %d too long (maximum 103)", length);
212 }
213 /* BS EN 798:1995 4.2 "'Codabar' symbols shall consist of ... b) start character;
214 c) one or more symbol characters representing data ... d) stop character ..." */
215 if (length < 3) {
216 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 362, "Input length %d too short (minimum 3)", length);
217 }
218 to_upper(source, length);
219
220 /* Codabar must begin and end with the characters A, B, C or D */
221 if ((source[0] != 'A') && (source[0] != 'B') && (source[0] != 'C')
222 && (source[0] != 'D')) {
223 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 358, "Does not begin with \"A\", \"B\", \"C\" or \"D\"");
224 }
225 if ((source[length - 1] != 'A') && (source[length - 1] != 'B') &&
226 (source[length - 1] != 'C') && (source[length - 1] != 'D')) {
227 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 359, "Does not end with \"A\", \"B\", \"C\" or \"D\"");
228 }
229 if ((i = not_sane_lookup(CALCIUM, sizeof(CALCIUM) - 1, source, length, posns))) {
230 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 357,
231 "Invalid character at position %1$d in input (\"%2$s\" only)", i, CALCIUM);
232 }
233 /* And must not use A, B, C or D otherwise (BS EN 798:1995 4.3.2) */
234 if ((i = not_sane(CALCIUM_INNER_F, source + 1, length - 2))) {
235 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 363,
236 "Invalid character at position %d in input (cannot contain \"A\", \"B\", \"C\" or \"D\")", i);
237 }
238
239 /* Add check character: 1 don't show to HRT, 2 do show to HRT
240 (unfortunately to maintain back-compatibility, this is reverse of C25) */
241 add_checksum = symbol->option_2 == 1 || symbol->option_2 == 2;
242
243 for (i = 0; i < length; i++, d += 8) {
244 if (add_checksum) {
245 /* BS EN 798:1995 A.3 suggests using ISO 7064 algorithm but leaves it application defined.
246 Following BWIPP and TEC-IT, use this simple mod-16 algorithm (not in ISO 7064) */
247 count += posns[i];
248 if (i + 1 == length) {
249 checksum = count % 16;
250 if (checksum) {
251 checksum = 16 - checksum;
252 }
253 if (symbol->debug & ZINT_DEBUG_PRINT) {
254 printf("Codabar: %s, count %d, checksum %d (%c)\n", source, count, checksum, CALCIUM[checksum]);
255 }
256 memcpy(d, CodaTable[checksum], 8);
257 d += 8;
258 }
259 }
260 memcpy(d, CodaTable[posns[i]], 8);
261 if (source[i] == '/' || source[i] == ':' || source[i] == '.' || source[i] == '+') { /* Wide data characters */
262 d_chars++;
263 }
264 }
265
266 expand(symbol, dest, d - dest);
267
268 if (symbol->output_options & COMPLIANT_HEIGHT) {
269 /* BS EN 798:1995 4.4.1 (d) max of 5mm / 0.43mm (X max) ~ 11.628 or 15% of width where (taking N =
270 narrow/wide ratio as 2 and I = X) width = ((2 * N + 5) * C + (N – 1) * (D + 2)) * X + I * (C – 1) + 2Q
271 = ((4 + 5) * C + (D + 2) + C - 1 + 2 * 10) * X = (10 * C + D + 21) * X
272 Length (C) includes start/stop chars */
273 const float min_height_min = 11.6279068f; /* 5.0 / 0.43 */
274 float min_height = stripf((10.0f * ((add_checksum ? length + 1 : length) + 2.0f) + d_chars + 21.0f) * 0.15f);
275 if (min_height < min_height_min) {
276 min_height = min_height_min;
277 }
278 /* Using 50 as default as none recommended */
279 error_number = set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, 0 /*no_errtxt*/);
280 } else {
281 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/);
282 }
283
284 ustrcpy(symbol->text, source);
285 if (symbol->option_2 == 2) {
286 symbol->text[length - 1] = CALCIUM[checksum]; /* Place before final A/B/C/D character (BS EN 798:1995 A.3) */
287 symbol->text[length] = source[length - 1];
288 symbol->text[length + 1] = '\0';
289 }
290
291 return error_number;
292 }
293
294 /* Italian Pharmacode */
295 INTERNAL int code32(struct zint_symbol *symbol, unsigned char source[], int length) {
296 static const char TABELLA[] = "0123456789BCDFGHJKLMNPQRSTUVWXYZ";
297 int i, zeroes, error_number = 0, checksum, checkpart, checkdigit;
298 char localstr[10], risultante[7];
299 unsigned int pharmacode, devisor;
300 int codeword[6];
301
302 /* Validate the input */
303 if (length > 8) {
304 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 360, "Input length %d too long (maximum 8)", length);
305 }
306 if ((i = not_sane(NEON_F, source, length))) {
307 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 361,
308 "Invalid character at position %d in input (digits only)", i);
309 }
310
311 /* Add leading zeros as required */
312 zeroes = 8 - length;
313 memset(localstr, '0', zeroes);
314 ustrcpy(localstr + zeroes, source);
315
316 /* Calculate the check digit */
317 checksum = 0;
318 for (i = 0; i < 4; i++) {
319 checkpart = ctoi(localstr[i * 2]);
320 checksum += checkpart;
321 checkpart = 2 * (ctoi(localstr[(i * 2) + 1]));
322 if (checkpart >= 10) {
323 checksum += (checkpart - 10) + 1;
324 } else {
325 checksum += checkpart;
326 }
327 }
328
329 /* Add check digit to data string */
330 checkdigit = checksum % 10;
331 localstr[8] = itoc(checkdigit);
332 localstr[9] = '\0';
333
334 /* Convert string into an integer value */
335 pharmacode = atoi(localstr);
336
337 /* Convert from decimal to base-32 */
338 devisor = 33554432;
339 for (i = 5; i >= 0; i--) {
340 unsigned int remainder;
341 codeword[i] = pharmacode / devisor;
342 remainder = pharmacode % devisor;
343 pharmacode = remainder;
344 devisor /= 32;
345 }
346
347 /* Look up values in 'Tabella di conversione' */
348 for (i = 5; i >= 0; i--) {
349 risultante[5 - i] = TABELLA[codeword[i]];
350 }
351 risultante[6] = '\0';
352 /* Plot the barcode using Code 39 */
353 error_number = code39(symbol, (unsigned char *) risultante, 6);
354 if (error_number != 0) { /* Should never happen */
355 return error_number; /* Not reached */
356 }
357
358 if (symbol->output_options & COMPLIANT_HEIGHT) {
359 /* Allegato A Caratteristiche tecniche del bollino farmaceutico
360 (https://www.gazzettaufficiale.it/do/atto/serie_generale/caricaPdf?cdimg=14A0566800100010110001
361 &dgu=2014-07-18&art.dataPubblicazioneGazzetta=2014-07-18&art.codiceRedazionale=14A05668&art.num=1
362 &art.tiposerie=SG)
363 X given as 0.250mm; height (and quiet zones) left to ISO/IEC 16388:2007 (Code 39)
364 So min height 5mm = 5mm / 0.25mm = 20 > 15% of width, i.e. (10 * 8 + 19) * 0.15 = 14.85 */
365 error_number = set_height(symbol, 20.0f, 20.0f, 0.0f, 0 /*no_errtxt*/); /* Use as default also */
366 } else {
367 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/);
368 }
369
370 /* Override the normal text output with the Pharmacode number */
371 ustrcpy(symbol->text, "A");
372 ustrcat(symbol->text, localstr);
373
374 return error_number;
375 }
376
377 /* vim: set ts=4 sw=4 et : */