comparison mupdf-source/thirdparty/zint/backend/plessey.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 /* plessey.c - Handles Plessey and MSI Plessey */
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 #define SSET_F (IS_NUM_F | IS_UHX_F) /* SSET "0123456789ABCDEF" */
37
38 static const char PlessTable[16][8] = {
39 {'1','3','1','3','1','3','1','3'}, {'3','1','1','3','1','3','1','3'}, {'1','3','3','1','1','3','1','3'},
40 {'3','1','3','1','1','3','1','3'}, {'1','3','1','3','3','1','1','3'}, {'3','1','1','3','3','1','1','3'},
41 {'1','3','3','1','3','1','1','3'}, {'3','1','3','1','3','1','1','3'}, {'1','3','1','3','1','3','3','1'},
42 {'3','1','1','3','1','3','3','1'}, {'1','3','3','1','1','3','3','1'}, {'3','1','3','1','1','3','3','1'},
43 {'1','3','1','3','3','1','3','1'}, {'3','1','1','3','3','1','3','1'}, {'1','3','3','1','3','1','3','1'},
44 {'3','1','3','1','3','1','3','1'}
45 };
46
47 static const char MSITable[10][8] = {
48 {'1','2','1','2','1','2','1','2'}, {'1','2','1','2','1','2','2','1'}, {'1','2','1','2','2','1','1','2'},
49 {'1','2','1','2','2','1','2','1'}, {'1','2','2','1','1','2','1','2'}, {'1','2','2','1','1','2','2','1'},
50 {'1','2','2','1','2','1','1','2'}, {'1','2','2','1','2','1','2','1'}, {'2','1','1','2','1','2','1','2'},
51 {'2','1','1','2','1','2','2','1'}
52 };
53
54 /* Not MSI/Plessey but the older Plessey standard */
55 INTERNAL int plessey(struct zint_symbol *symbol, unsigned char source[], int length) {
56
57 int i;
58 unsigned char checkptr[67 * 4 + 8] = {0};
59 static const char grid[9] = {1, 1, 1, 1, 0, 1, 0, 0, 1};
60 char dest[570]; /* 8 + 67 * 8 + 2 * 8 + 9 + 1 = 570 */
61 char *d = dest;
62 int error_number = 0;
63
64 if (length > 67) { /* 16 + 67 * 16 + 4 * 8 + 19 = 1139 */
65 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 370, "Input length %d too long (maximum 67)", length);
66 }
67 if ((i = not_sane(SSET_F, source, length))) {
68 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 371,
69 "Invalid character at position %d in input (digits and \"ABCDEF\" only)", i);
70 }
71
72 /* Start character */
73 memcpy(d, "31311331", 8);
74 d += 8;
75
76 /* Data area */
77 for (i = 0; i < length; i++, d += 8) {
78 unsigned int check = source[i] - '0' - (source[i] >> 6) * 7;
79 memcpy(d, PlessTable[check], 8);
80 checkptr[4 * i] = check & 1;
81 checkptr[4 * i + 1] = (check >> 1) & 1;
82 checkptr[4 * i + 2] = (check >> 2) & 1;
83 checkptr[4 * i + 3] = (check >> 3) & 1;
84 }
85
86 /* CRC check digit code adapted from code by Leonid A. Broukhis
87 used in GNU Barcode */
88
89 for (i = 0; i < (4 * length); i++) {
90 if (checkptr[i]) {
91 int j;
92 for (j = 0; j < 9; j++)
93 checkptr[i + j] ^= grid[j];
94 }
95 }
96
97 for (i = 0; i < 8; i++) {
98 switch (checkptr[length * 4 + i]) {
99 case 0: memcpy(d, "13", 2);
100 d += 2;
101 break;
102 case 1: memcpy(d, "31", 2);
103 d += 2;
104 break;
105 }
106 }
107
108 /* Stop character */
109 memcpy(d, "331311313", 9);
110 d += 9;
111
112 expand(symbol, dest, d - dest);
113
114 /* TODO: Find documentation on BARCODE_PLESSEY dimensions/height */
115
116 symbol->text[0] = '\0';
117 ustrncat(symbol->text, source, length);
118
119 return error_number;
120 }
121
122 /* Modulo 10 check digit - Luhn algorithm
123 See https://en.wikipedia.org/wiki/Luhn_algorithm */
124 static char msi_check_digit_mod10(const unsigned char source[], const int length) {
125 static const char vals[2][10] = {
126 { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 }, /* Doubled and digits summed */
127 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, /* Single */
128 };
129 int i, x = 0, undoubled = 0;
130
131 for (i = length - 1; i >= 0; i--) {
132 /* Note overflow impossible for max length 92 * max weight 9 * max val 15 == 12420 */
133 x += vals[undoubled][ctoi(source[i])];
134 undoubled = !undoubled;
135 }
136
137 return itoc((10 - x % 10) % 10);
138 }
139
140 /* Modulo 11 check digit - IBM weight system wrap = 7, NCR system wrap = 9
141 See https://en.wikipedia.org/wiki/MSI_Barcode */
142 static char msi_check_digit_mod11(const unsigned char source[], const int length, const int wrap) {
143 int i, x = 0, weight = 2;
144
145 for (i = length - 1; i >= 0; i--) {
146 /* Note overflow impossible for max length 92 * max weight 9 * max val 15 == 12420 */
147 x += weight * ctoi(source[i]);
148 weight++;
149 if (weight > wrap) {
150 weight = 2;
151 }
152 }
153
154 return itoc((11 - x % 11) % 11); /* Will return ':' for 10 */
155 }
156
157 /* Plain MSI Plessey - does not calculate any check character */
158 static char *msi_plessey_nomod(struct zint_symbol *symbol, const unsigned char source[], const int length,
159 char *d) {
160
161 int i;
162
163 for (i = 0; i < length; i++, d += 8) {
164 memcpy(d, MSITable[source[i] - '0'], 8);
165 }
166
167 symbol->text[0] = '\0';
168 ustrncat(symbol->text, source, length);
169
170 return d;
171 }
172
173 /* MSI Plessey with Modulo 10 check digit */
174 static char *msi_plessey_mod10(struct zint_symbol *symbol, const unsigned char source[], const int length,
175 const int no_checktext, char *d) {
176 int i;
177 char check_digit;
178
179 /* draw data section */
180 for (i = 0; i < length; i++, d += 8) {
181 memcpy(d, MSITable[source[i] - '0'], 8);
182 }
183
184 /* calculate check digit */
185 check_digit = msi_check_digit_mod10(source, length);
186
187 /* draw check digit */
188 memcpy(d, MSITable[check_digit - '0'], 8);
189 d += 8;
190
191 symbol->text[0] = '\0';
192 ustrncat(symbol->text, source, length);
193 if (!no_checktext) {
194 symbol->text[length] = check_digit;
195 symbol->text[length + 1] = '\0';
196 }
197
198 return d;
199 }
200
201 /* MSI Plessey with two Modulo 10 check digits */
202 static char *msi_plessey_mod1010(struct zint_symbol *symbol, const unsigned char source[], const int length,
203 const int no_checktext, char *d) {
204
205 int i;
206 unsigned char temp[92 + 2 + 1];
207
208 /* Append check digits */
209 temp[0] = '\0';
210 ustrncat(temp, source, length);
211 temp[length] = msi_check_digit_mod10(source, length);
212 temp[length + 1] = msi_check_digit_mod10(temp, length + 1);
213 temp[length + 2] = '\0';
214
215 /* draw data section */
216 for (i = 0; i < length + 2; i++, d += 8) {
217 memcpy(d, MSITable[temp[i] - '0'], 8);
218 }
219
220 if (no_checktext) {
221 symbol->text[0] = '\0';
222 ustrncat(symbol->text, source, length);
223 } else {
224 ustrcpy(symbol->text, temp);
225 }
226
227 return d;
228 }
229
230 /* MSI Plessey with Modulo 11 check digit */
231 static char *msi_plessey_mod11(struct zint_symbol *symbol, const unsigned char source[], const int length,
232 const int no_checktext, const int wrap, char *d) {
233 /* Uses the IBM weight system if wrap = 7, and the NCR system if wrap = 9 */
234 int i;
235 char check_digit;
236
237 /* draw data section */
238 for (i = 0; i < length; i++, d += 8) {
239 memcpy(d, MSITable[source[i] - '0'], 8);
240 }
241
242 /* Append check digit */
243 check_digit = msi_check_digit_mod11(source, length, wrap);
244 if (check_digit == ':') {
245 memcpy(d, MSITable[1], 8);
246 d += 8;
247 memcpy(d, MSITable[0], 8);
248 d += 8;
249 } else {
250 memcpy(d, MSITable[check_digit - '0'], 8);
251 d += 8;
252 }
253
254 symbol->text[0] = '\0';
255 ustrncat(symbol->text, source, length);
256 if (!no_checktext) {
257 if (check_digit == ':') {
258 ustrcat(symbol->text, "10");
259 } else {
260 symbol->text[length] = check_digit;
261 symbol->text[length + 1] = '\0';
262 }
263 }
264
265 return d;
266 }
267
268 /* MSI Plessey with Modulo 11 check digit and Modulo 10 check digit */
269 static char *msi_plessey_mod1110(struct zint_symbol *symbol, const unsigned char source[], const int length,
270 const int no_checktext, const int wrap, char *d) {
271 /* Uses the IBM weight system if wrap = 7, and the NCR system if wrap = 9 */
272 int i;
273 char check_digit;
274 unsigned char temp[92 + 3 + 1];
275 int temp_len = length;
276
277 temp[0] = '\0';
278 ustrncat(temp, source, length);
279
280 /* Append first (mod 11) digit */
281 check_digit = msi_check_digit_mod11(source, length, wrap);
282 if (check_digit == ':') {
283 temp[temp_len++] = '1';
284 temp[temp_len++] = '0';
285 } else {
286 temp[temp_len++] = check_digit;
287 }
288
289 /* Append second (mod 10) check digit */
290 temp[temp_len] = msi_check_digit_mod10(temp, temp_len);
291 temp[++temp_len] = '\0';
292
293 /* draw data section */
294 for (i = 0; i < temp_len; i++, d += 8) {
295 memcpy(d, MSITable[temp[i] - '0'], 8);
296 }
297
298 if (no_checktext) {
299 symbol->text[0] = '\0';
300 ustrncat(symbol->text, source, length);
301 } else {
302 ustrcpy(symbol->text, temp);
303 }
304
305 return d;
306 }
307
308 INTERNAL int msi_plessey(struct zint_symbol *symbol, unsigned char source[], int length) {
309 int error_number = 0;
310 int i;
311 char dest[766]; /* 2 + 92 * 8 + 3 * 8 + 3 + 1 = 766 */
312 char *d = dest;
313 int check_option = symbol->option_2;
314 int no_checktext = 0;
315
316 if (length > 92) { /* 3 (Start) + 92 * 12 + 3 * 12 + 4 (Stop) = 1147 */
317 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 372, "Input length %d too long (maximum 92)", length);
318 }
319 if ((i = not_sane(NEON_F, source, length))) {
320 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 377,
321 "Invalid character at position %d in input (digits only)", i);
322 }
323
324 if (check_option >= 11 && check_option <= 16) { /* +10 means don't print check digits in HRT */
325 check_option -= 10;
326 no_checktext = 1;
327 }
328 if ((check_option < 0) || (check_option > 6)) {
329 check_option = 0;
330 }
331
332 /* Start character */
333 memcpy(d, "21", 2);
334 d += 2;
335
336 switch (check_option) {
337 case 0: d = msi_plessey_nomod(symbol, source, length, d);
338 break;
339 case 1: d = msi_plessey_mod10(symbol, source, length, no_checktext, d);
340 break;
341 case 2: d = msi_plessey_mod1010(symbol, source, length, no_checktext, d);
342 break;
343 case 3: d = msi_plessey_mod11(symbol, source, length, no_checktext, 7 /*IBM wrap*/, d);
344 break;
345 case 4: d = msi_plessey_mod1110(symbol, source, length, no_checktext, 7 /*IBM wrap*/, d);
346 break;
347 case 5: d = msi_plessey_mod11(symbol, source, length, no_checktext, 9 /*NCR wrap*/, d);
348 break;
349 case 6: d = msi_plessey_mod1110(symbol, source, length, no_checktext, 9 /*NCR wrap*/, d);
350 break;
351 }
352
353 /* Stop character */
354 memcpy(d, "121", 3);
355 d += 3;
356
357 expand(symbol, dest, d - dest);
358
359 /* TODO: Find documentation on BARCODE_MSI_PLESSEY dimensions/height */
360
361 return error_number;
362 }
363
364 /* vim: set ts=4 sw=4 et : */