comparison mupdf-source/thirdparty/zint/backend/postal.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 /* postal.c - Handles POSTNET, PLANET, CEPNet, FIM. RM4SCC and Flattermarken */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2008-2024 Robin Stuart <rstuart114@gmail.com>
5 Including bug fixes by Bryan Hatton
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of the project nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31 */
32 /* SPDX-License-Identifier: BSD-3-Clause */
33
34 #include <stdio.h>
35 #include "common.h"
36
37 static const char DAFTSET[] = "FADT";
38 static const char KRSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
39 static const char KASUTSET[] = "1234567890-abcdefgh";
40 static const char CHKASUTSET[] = "0123456789-abcdefgh";
41 #define SHKASUTSET_F (IS_NUM_F | IS_MNS_F | IS_UPR_F) /* SHKASUTSET "1234567890-ABCDEFGHIJKLMNOPQRSTUVWXYZ" */
42
43 /* PostNet number encoding table - In this table L is long as S is short */
44 static const char PNTable[10][5] = {
45 {'L','L','S','S','S'}, {'S','S','S','L','L'}, {'S','S','L','S','L'}, {'S','S','L','L','S'}, {'S','L','S','S','L'},
46 {'S','L','S','L','S'}, {'S','L','L','S','S'}, {'L','S','S','S','L'}, {'L','S','S','L','S'}, {'L','S','L','S','S'}
47 };
48
49 static const char PLTable[10][5] = {
50 {'S','S','L','L','L'}, {'L','L','L','S','S'}, {'L','L','S','L','S'}, {'L','L','S','S','L'}, {'L','S','L','L','S'},
51 {'L','S','L','S','L'}, {'L','S','S','L','L'}, {'S','L','L','L','S'}, {'S','L','L','S','L'}, {'S','L','S','L','L'}
52 };
53
54 static const char RoyalValues[36][2] = {
55 { 1, 1 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 1, 5 }, { 1, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 }, { 2, 4 },
56 { 2, 5 }, { 2, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 }, { 3, 4 }, { 3, 5 }, { 3, 0 }, { 4, 1 }, { 4, 2 },
57 { 4, 3 }, { 4, 4 }, { 4, 5 }, { 4, 0 }, { 5, 1 }, { 5, 2 }, { 5, 3 }, { 5, 4 }, { 5, 5 }, { 5, 0 },
58 { 0, 1 }, { 0, 2 }, { 0, 3 }, { 0, 4 }, { 0, 5 }, { 0, 0 }
59 };
60
61 /* 0 = Full, 1 = Ascender, 2 = Descender, 3 = Tracker */
62 static const char RoyalTable[36][4] = {
63 {'3','3','0','0'}, {'3','2','1','0'}, {'3','2','0','1'}, {'2','3','1','0'}, {'2','3','0','1'}, {'2','2','1','1'},
64 {'3','1','2','0'}, {'3','0','3','0'}, {'3','0','2','1'}, {'2','1','3','0'}, {'2','1','2','1'}, {'2','0','3','1'},
65 {'3','1','0','2'}, {'3','0','1','2'}, {'3','0','0','3'}, {'2','1','1','2'}, {'2','1','0','3'}, {'2','0','1','3'},
66 {'1','3','2','0'}, {'1','2','3','0'}, {'1','2','2','1'}, {'0','3','3','0'}, {'0','3','2','1'}, {'0','2','3','1'},
67 {'1','3','0','2'}, {'1','2','1','2'}, {'1','2','0','3'}, {'0','3','1','2'}, {'0','3','0','3'}, {'0','2','1','3'},
68 {'1','1','2','2'}, {'1','0','3','2'}, {'1','0','2','3'}, {'0','1','3','2'}, {'0','1','2','3'}, {'0','0','3','3'}
69 };
70
71 static const char FlatTable[10][4] = {
72 {'0','5','0','4'}, { "18" }, {'0','1','1','7'}, {'0','2','1','6'}, {'0','3','1','5'},
73 {'0','4','1','4'}, {'0','5','1','3'}, {'0','6','1','2'}, {'0','7','1','1'}, {'0','8','1','0'}
74 };
75
76 static const char KoreaTable[10][10] = {
77 {'1','3','1','3','1','5','0','6','1','3'}, {'0','7','1','3','1','3','1','3','1','3'},
78 {'0','4','1','7','1','3','1','3','1','3'}, {'1','5','0','6','1','3','1','3','1','3'},
79 {'0','4','1','3','1','7','1','3','1','3'}, { "17171313" },
80 {'1','3','1','5','0','6','1','3','1','3'}, {'0','4','1','3','1','3','1','7','1','3'},
81 { "17131713" }, { "13171713" }
82 };
83
84 static const char JapanTable[19][3] = {
85 {'1','1','4'}, {'1','3','2'}, {'3','1','2'}, {'1','2','3'}, {'1','4','1'},
86 {'3','2','1'}, {'2','1','3'}, {'2','3','1'}, {'4','1','1'}, {'1','4','4'},
87 {'4','1','4'}, {'3','2','4'}, {'3','4','2'}, {'2','3','4'}, {'4','3','2'},
88 {'2','4','3'}, {'4','2','3'}, {'4','4','1'}, {'1','1','1'}
89 };
90
91 /* Set height for POSTNET/PLANET/CEPNet codes, maintaining ratio */
92 static int usps_set_height(struct zint_symbol *symbol, const int no_errtxt) {
93 /* USPS Domestic Mail Manual (USPS DMM 300) Jan 8, 2006 (updated 2011) 708.4.2.5 POSTNET Barcode Dimensions and
94 Spacing
95 http://web.archive.org/web/20061113174253/http://pe.usps.com/cpim/ftp/manuals/dmm300/full/mailingStandards.pdf
96 Using bar pitch as X (1" / 43) ~ 0.023" based on 22 bars + 21 spaces per inch (bar width 0.015" - 0.025")
97 Half bar height 0.05" +- 0.01; 0.040" (min) / 0.025" (X max) = 1.6 min, 0.060" (max) / 0.015" (X min) = 4 max
98 Full bar height 0.125" +- 0.01; 0.115" (min) / 0.025" (X max) = 4.6 min, 0.135" (max) / 0.015" (X min) = 9 max
99 */
100 /* CEPNet e Código Bidimensional Datamatrix 2D (26/05/2021) 3.3.2 Arquitetura das barras - same as POSTNET */
101 int error_number = 0;
102
103 /* No legacy for CEPNet as new */
104 if ((symbol->output_options & COMPLIANT_HEIGHT) || symbol->symbology == BARCODE_CEPNET) {
105 symbol->row_height[0] = 3.2249999f; /* 0.075 * 43 */
106 symbol->row_height[1] = 2.1500001f; /* 0.05 * 43 */
107 } else {
108 symbol->row_height[0] = 6.0f;
109 symbol->row_height[1] = 6.0f;
110 }
111 if (symbol->height) {
112 /* Half ratio */
113 const float h_ratio = symbol->row_height[1] / (symbol->row_height[0] + symbol->row_height[1]); /* 0.4 */
114 symbol->row_height[1] = stripf(symbol->height * h_ratio);
115 if (symbol->row_height[1] < 0.5f) { /* Absolute minimum */
116 symbol->row_height[1] = 0.5f;
117 symbol->row_height[0] = stripf(0.5f / h_ratio - 0.5f); /* 0.75 */
118 } else {
119 symbol->row_height[0] = stripf(symbol->height - symbol->row_height[1]);
120 }
121 }
122 symbol->height = stripf(symbol->row_height[0] + symbol->row_height[1]);
123
124 if (symbol->output_options & COMPLIANT_HEIGHT) {
125 if (symbol->height < 4.6f || symbol->height > 9.0f) {
126 error_number = ZINT_WARN_NONCOMPLIANT;
127 if (!no_errtxt) {
128 errtxt(0, symbol, 498, "Height not compliant with standards");
129 }
130 }
131 }
132
133 return error_number;
134 }
135
136 /* Handles the POSTNET system used for Zip codes in the US */
137 /* Also handles Brazilian CEPNet - more information CEPNet e Código Bidimensional Datamatrix 2D (26/05/2021) at
138 https://www.correios.com.br/enviar/correspondencia/arquivos/nacional/
139 guia-tecnico-cepnet-e-2d-triagem-enderecamento-27-04-2021.pdf/view
140 */
141 static int postnet_enc(struct zint_symbol *symbol, const unsigned char source[], char *d, const int length) {
142 int i, sum, check_digit;
143 int error_number = 0;
144
145 if (length > 38) {
146 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 480, "Input length %d too long (maximum 38)", length);
147 }
148
149 if (symbol->symbology == BARCODE_CEPNET) {
150 if (length != 8) {
151 error_number = errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 780, "Input length %d wrong (should be 8 digits)",
152 length);
153 }
154 } else {
155 if (length != 5 && length != 9 && length != 11) {
156 error_number = errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 479,
157 "Input length %d is not standard (5, 9 or 11)", length);
158 }
159 }
160 if ((i = not_sane(NEON_F, source, length))) {
161 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 481,
162 "Invalid character at position %d in input (digits only)", i);
163 }
164 sum = 0;
165
166 /* start character */
167 *d++ = 'L';
168
169 for (i = 0; i < length; i++, d += 5) {
170 const int val = source[i] - '0';
171 memcpy(d, PNTable[val], 5);
172 sum += val;
173 }
174
175 check_digit = (10 - (sum % 10)) % 10;
176 memcpy(d, PNTable[check_digit], 5);
177 d += 5;
178
179 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit);
180
181 /* stop character */
182 strcpy(d, "L");
183
184 return error_number;
185 }
186
187 /* Puts POSTNET barcodes into the pattern matrix */
188 INTERNAL int postnet(struct zint_symbol *symbol, unsigned char source[], int length) {
189 /* Suppress clang-tidy-20 garbage value false positive by initializing (see "vector.c" `vection_add_rect()`) */
190 char height_pattern[256] = {0}; /* 5 + 38 * 5 + 5 + 5 + 1 = 206 */
191 unsigned int loopey, h;
192 int writer;
193 int error_number, warn_number;
194
195 error_number = postnet_enc(symbol, source, height_pattern, length);
196 if (error_number >= ZINT_ERROR) {
197 return error_number;
198 }
199
200 writer = 0;
201 h = (int) strlen(height_pattern);
202 for (loopey = 0; loopey < h; loopey++) {
203 if (height_pattern[loopey] == 'L') {
204 set_module(symbol, 0, writer);
205 }
206 set_module(symbol, 1, writer);
207 writer += 2;
208 }
209 warn_number = usps_set_height(symbol, error_number /*no_errtxt*/);
210 symbol->rows = 2;
211 symbol->width = writer - 1;
212
213 return error_number ? error_number : warn_number;
214 }
215
216 /* Handles the PLANET system used for item tracking in the US */
217 static int planet_enc(struct zint_symbol *symbol, const unsigned char source[], char *d, const int length) {
218 int i, sum, check_digit;
219 int error_number = 0;
220
221 if (length > 38) {
222 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 482, "Input length %d too long (maximum 38)", length);
223 }
224 if (length != 11 && length != 13) {
225 error_number = errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 478, "Input length %d is not standard (11 or 13)",
226 length);
227 }
228 if ((i = not_sane(NEON_F, source, length))) {
229 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 483,
230 "Invalid character at position %d in input (digits only)", i);
231 }
232 sum = 0;
233
234 /* start character */
235 *d++ = 'L';
236
237 for (i = 0; i < length; i++, d += 5) {
238 const int val = source[i] - '0';
239 memcpy(d, PLTable[val], 5);
240 sum += val;
241 }
242
243 check_digit = (10 - (sum % 10)) % 10;
244 memcpy(d, PLTable[check_digit], 5);
245 d += 5;
246
247 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit);
248
249 /* stop character */
250 strcpy(d, "L");
251
252 return error_number;
253 }
254
255 /* Puts PLANET barcodes into the pattern matrix */
256 INTERNAL int planet(struct zint_symbol *symbol, unsigned char source[], int length) {
257 /* Suppress clang-tidy-20 garbage value false positive by initializing (see "vector.c" `vection_add_rect()`) */
258 char height_pattern[256] = {0}; /* 5 + 38 * 5 + 5 + 5 + 1 = 206 */
259 unsigned int loopey, h;
260 int writer;
261 int error_number, warn_number;
262
263 error_number = planet_enc(symbol, source, height_pattern, length);
264 if (error_number >= ZINT_ERROR) {
265 return error_number;
266 }
267
268 writer = 0;
269 h = (int) strlen(height_pattern);
270 for (loopey = 0; loopey < h; loopey++) {
271 if (height_pattern[loopey] == 'L') {
272 set_module(symbol, 0, writer);
273 }
274 set_module(symbol, 1, writer);
275 writer += 2;
276 }
277 warn_number = usps_set_height(symbol, error_number /*no_errtxt*/);
278 symbol->rows = 2;
279 symbol->width = writer - 1;
280
281 return error_number ? error_number : warn_number;
282 }
283
284 /* Korean Postal Authority */
285 INTERNAL int koreapost(struct zint_symbol *symbol, unsigned char source[], int length) {
286 int total, i, check, zeroes, error_number = 0;
287 char localstr[8], dest[80];
288 char *d = dest;
289 int posns[6];
290
291 if (length > 6) {
292 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 484, "Input length %d too long (maximum 6)", length);
293 }
294 if ((i = not_sane(NEON_F, source, length))) {
295 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 485,
296 "Invalid character at position %d in input (digits only)", i);
297 }
298 zeroes = 6 - length;
299 memset(localstr, '0', zeroes);
300 ustrcpy(localstr + zeroes, source);
301
302 total = 0;
303 for (i = 0; i < 6; i++) {
304 posns[i] = ctoi(localstr[i]);
305 total += posns[i];
306 }
307 check = 10 - (total % 10);
308 if (check == 10) {
309 check = 0;
310 }
311 localstr[6] = itoc(check);
312 localstr[7] = '\0';
313
314 for (i = 5; i >= 0; i--) {
315 const char *const entry = KoreaTable[posns[i]];
316 memcpy(d, entry, 10);
317 d += entry[8] ? 10 : 8;
318 }
319 memcpy(d, KoreaTable[check], 10);
320 d += KoreaTable[check][8] ? 10 : 8;
321
322 expand(symbol, dest, d - dest);
323
324 ustrcpy(symbol->text, localstr);
325
326 /* TODO: Find documentation on BARCODE_KOREAPOST dimensions/height */
327
328 return error_number;
329 }
330
331 /* The simplest barcode symbology ever! Supported by MS Word, so here it is!
332 glyphs from http://en.wikipedia.org/wiki/Facing_Identification_Mark */
333 INTERNAL int fim(struct zint_symbol *symbol, unsigned char source[], int length) {
334 int error_number = 0;
335
336 if (length > 1) {
337 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 486, "Input length %d too long (maximum 1)", length);
338 }
339
340 switch ((char) source[0]) {
341 case 'a':
342 case 'A':
343 expand(symbol, "111515111", 9);
344 break;
345 case 'b':
346 case 'B':
347 expand(symbol, "13111311131", 11);
348 break;
349 case 'c':
350 case 'C':
351 expand(symbol, "11131313111", 11);
352 break;
353 case 'd':
354 case 'D':
355 expand(symbol, "1111131311111", 13);
356 break;
357 case 'e':
358 case 'E':
359 expand(symbol, "1317131", 7);
360 break;
361 default:
362 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 487,
363 "Invalid character in input (\"A\", \"B\", \"C\", \"D\" or \"E\" only)");
364 break;
365 }
366
367 if (symbol->output_options & COMPLIANT_HEIGHT) {
368 /* USPS Domestic Mail Manual (USPS DMM 300) Jan 8, 2006 (updated 2011) 708.9.3
369 X 0.03125" (1/32) +- 0.008" so X max 0.03925", height 0.625" (5/8) +- 0.125" (1/8) */
370 const float min_height = 12.7388535f; /* 0.5 / 0.03925 */
371 const float default_height = 20.0f; /* 0.625 / 0.03125 */
372 const float max_height = 31.0559006f; /* 0.75 / 0.02415 */
373 error_number = set_height(symbol, min_height, default_height, max_height, 0 /*no_errtxt*/);
374 } else {
375 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/);
376 }
377
378 return error_number;
379 }
380
381 /* Set height for DAFT-type codes, maintaining ratio. Expects row_height[0] & row_height[1] to be set */
382 /* Used by auspost.c also */
383 INTERNAL int daft_set_height(struct zint_symbol *symbol, const float min_height, const float max_height) {
384 int error_number = 0;
385
386 if (symbol->height) {
387 /* Tracker ratio */
388 const float t_ratio = stripf(symbol->row_height[1] / stripf(symbol->row_height[0] * 2
389 + symbol->row_height[1]));
390 symbol->row_height[1] = stripf(symbol->height * t_ratio);
391 if (symbol->row_height[1] < 0.5f) { /* Absolute minimum */
392 symbol->row_height[1] = 0.5f;
393 symbol->row_height[0] = stripf(0.25f / t_ratio - 0.25f);
394 } else {
395 symbol->row_height[0] = stripf(stripf(symbol->height - symbol->row_height[1]) / 2.0f);
396 }
397 if (symbol->row_height[0] < 0.5f) {
398 symbol->row_height[0] = 0.5f;
399 symbol->row_height[1] = stripf(t_ratio / (1.0f - t_ratio));
400 }
401 }
402 symbol->row_height[2] = symbol->row_height[0];
403 symbol->height = stripf(stripf(symbol->row_height[0] + symbol->row_height[1]) + symbol->row_height[2]);
404
405 if (symbol->output_options & COMPLIANT_HEIGHT) {
406 if ((min_height && symbol->height < min_height) || (max_height && symbol->height > max_height)) {
407 error_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 499, "Height not compliant with standards");
408 }
409 }
410
411 return error_number;
412 }
413
414 /* Handles the 4 State barcodes used in the UK by Royal Mail */
415 static void rm4scc_enc(const struct zint_symbol *symbol, const int *posns, char *d, const int length) {
416 int i;
417 int top, bottom, row, column, check_digit;
418
419 top = 0;
420 bottom = 0;
421
422 /* start character */
423 *d++ = '1';
424
425 for (i = 0; i < length; i++, d += 4) {
426 const int p = posns[i];
427 memcpy(d, RoyalTable[p], 4);
428 top += RoyalValues[p][0];
429 bottom += RoyalValues[p][1];
430 }
431
432 /* Calculate the check digit */
433 row = (top % 6) - 1;
434 column = (bottom % 6) - 1;
435 if (row == -1) {
436 row = 5;
437 }
438 if (column == -1) {
439 column = 5;
440 }
441 check_digit = (6 * row) + column;
442 memcpy(d, RoyalTable[check_digit], 4);
443 d += 4;
444
445 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %d\n", check_digit);
446
447 /* stop character */
448 strcpy(d, "0");
449 }
450
451 /* Puts RM4SCC into the data matrix */
452 INTERNAL int rm4scc(struct zint_symbol *symbol, unsigned char source[], int length) {
453 int i;
454 char height_pattern[210];
455 int posns[50];
456 int loopey, h;
457 int writer;
458 int error_number = 0;
459
460 if (length > 50) {
461 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 488, "Input length %d too long (maximum 50)", length);
462 }
463 to_upper(source, length);
464 if ((i = not_sane_lookup(KRSET, 36, source, length, posns))) {
465 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 489,
466 "Invalid character at position %d in input (alphanumerics only)", i);
467 }
468 rm4scc_enc(symbol, posns, height_pattern, length);
469
470 writer = 0;
471 h = (int) strlen(height_pattern);
472 for (loopey = 0; loopey < h; loopey++) {
473 if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '0')) {
474 set_module(symbol, 0, writer);
475 }
476 set_module(symbol, 1, writer);
477 if ((height_pattern[loopey] == '2') || (height_pattern[loopey] == '0')) {
478 set_module(symbol, 2, writer);
479 }
480 writer += 2;
481 }
482
483 if (symbol->output_options & COMPLIANT_HEIGHT) {
484 /* Royal Mail Know How User's Manual Appendix C: using CBC
485 (https://web.archive.org/web/20120120060743/
486 http://www.royalmail.com/sites/default/files/docs/pdf/Know How 2006 PIP vs 1.6a Accepted Changes.pdf)
487 Bar pitch and min/maxes same as Mailmark, so using recommendations from
488 Royal Mail Mailmark Barcode Definition Document (15 Sept 2015) Section 3.5.1
489 */
490 const float min_height = 6.47952747f; /* (4.22 * 39) / 25.4 */
491 const float max_height = 10.8062992f; /* (5.84 * 47) / 25.4 */
492 symbol->row_height[0] = 3.16417313f; /* (1.9 * 42.3) / 25.4 */
493 symbol->row_height[1] = 2.16496062f; /* (1.3 * 42.3) / 25.4 */
494 /* Note using max X for minimum and min X for maximum */
495 error_number = daft_set_height(symbol, min_height, max_height);
496 } else {
497 symbol->row_height[0] = 3.0f;
498 symbol->row_height[1] = 2.0f;
499 (void) daft_set_height(symbol, 0.0f, 0.0f);
500 }
501 symbol->rows = 3;
502 symbol->width = writer - 1;
503
504 return error_number;
505 }
506
507 /* Handles Dutch Post TNT KIX symbols
508 The same as RM4SCC but without check digit or stop/start chars
509 Specification at http://www.tntpost.nl/zakelijk/klantenservice/downloads/kIX_code/download.aspx */
510 INTERNAL int kix(struct zint_symbol *symbol, unsigned char source[], int length) {
511 char height_pattern[75];
512 char *d = height_pattern;
513 int posns[18];
514 int loopey;
515 int writer, i, h;
516 int error_number = 0;
517
518 if (length > 18) {
519 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 490, "Input length %d too long (maximum 18)", length);
520 }
521 to_upper(source, length);
522 if ((i = not_sane_lookup(KRSET, 36, source, length, posns))) {
523 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 491,
524 "Invalid character at position %d in input (alphanumerics only)", i);
525 }
526
527 /* Encode data */
528 for (i = 0; i < length; i++, d += 4) {
529 memcpy(d, RoyalTable[posns[i]], 4);
530 }
531
532 writer = 0;
533 h = d - height_pattern;
534 for (loopey = 0; loopey < h; loopey++) {
535 if ((height_pattern[loopey] == '1') || (height_pattern[loopey] == '0')) {
536 set_module(symbol, 0, writer);
537 }
538 set_module(symbol, 1, writer);
539 if ((height_pattern[loopey] == '2') || (height_pattern[loopey] == '0')) {
540 set_module(symbol, 2, writer);
541 }
542 writer += 2;
543 }
544
545 if (symbol->output_options & COMPLIANT_HEIGHT) {
546 /* Dimensions same as RM4SCC */
547 const float min_height = 6.47952747f; /* (4.22 * 39) / 25.4 */
548 const float max_height = 10.8062992f; /* (5.84 * 47) / 25.4 */
549 symbol->row_height[0] = 3.16417313f; /* (1.9 * 42.3) / 25.4 */
550 symbol->row_height[1] = 2.16496062f; /* (1.3 * 42.3) / 25.4 */
551 /* Note using max X for minimum and min X for maximum */
552 error_number = daft_set_height(symbol, min_height, max_height);
553 } else {
554 symbol->row_height[0] = 3.0f;
555 symbol->row_height[1] = 2.0f;
556 (void) daft_set_height(symbol, 0.0f, 0.0f);
557 }
558 symbol->rows = 3;
559 symbol->width = writer - 1;
560
561 return error_number;
562 }
563
564 /* Handles DAFT Code symbols */
565 INTERNAL int daft(struct zint_symbol *symbol, unsigned char source[], int length) {
566 int i;
567 int posns[576];
568 int loopey;
569 int writer;
570
571 if (length > 576) { /* 576 * 2 = 1152 */
572 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 492, "Input length %d too long (maximum 576)", length);
573 }
574 to_upper(source, length);
575
576 if ((i = not_sane_lookup(DAFTSET, 4, source, length, posns))) {
577 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 493,
578 "Invalid character at position %d in input (\"D\", \"A\", \"F\" and \"T\" only)", i);
579 }
580
581 writer = 0;
582 for (loopey = 0; loopey < length; loopey++) {
583 if ((posns[loopey] == 1) || (posns[loopey] == 0)) {
584 set_module(symbol, 0, writer);
585 }
586 set_module(symbol, 1, writer);
587 if ((posns[loopey] == 2) || (posns[loopey] == 0)) {
588 set_module(symbol, 2, writer);
589 }
590 writer += 2;
591 }
592
593 /* Allow ratio of tracker to be specified in thousandths */
594 if (symbol->option_2 >= 50 && symbol->option_2 <= 900) {
595 const float t_ratio = symbol->option_2 / 1000.0f;
596 if (symbol->height < 0.5f) {
597 symbol->height = 8.0f;
598 }
599 symbol->row_height[1] = stripf(symbol->height * t_ratio);
600 symbol->row_height[0] = stripf((symbol->height - symbol->row_height[1]) / 2.0f);
601 } else {
602 symbol->row_height[0] = 3.0f;
603 symbol->row_height[1] = 2.0f;
604 }
605
606 /* DAFT generic barcode so no dimensions/height specification */
607 (void) daft_set_height(symbol, 0.0f, 0.0f);
608 symbol->rows = 3;
609 symbol->width = writer - 1;
610
611 return 0;
612 }
613
614 /* Flattermarken - Not really a barcode symbology! */
615 INTERNAL int flat(struct zint_symbol *symbol, unsigned char source[], int length) {
616 int i, error_number = 0;
617 char dest[512]; /* 128 * 4 = 512 */
618 char *d = dest;
619
620 if (length > 128) { /* 128 * 9 = 1152 */
621 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 494, "Input length %d too long (maximum 128)", length);
622 }
623 if ((i = not_sane(NEON_F, source, length))) {
624 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 495,
625 "Invalid character at position %d in input (digits only)", i);
626 }
627
628 for (i = 0; i < length; i++) {
629 const char *const entry = FlatTable[source[i] - '0'];
630 memcpy(d, entry, 4);
631 d += entry[2] ? 4 : 2;
632 }
633
634 expand(symbol, dest, d - dest);
635
636 /* TODO: Find documentation on BARCODE_FLAT dimensions/height */
637
638 return error_number;
639 }
640
641 /* Japanese Postal Code (Kasutama Barcode) */
642 INTERNAL int japanpost(struct zint_symbol *symbol, unsigned char source[], int length) {
643 int error_number = 0, h;
644 char pattern[69];
645 char *d = pattern;
646 int writer, loopey, inter_posn, i, sum, check;
647 char check_char;
648 char inter[20 + 1];
649
650 if (length > 20) {
651 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 496, "Input length %d too long (maximum 20)", length);
652 }
653
654 to_upper(source, length);
655
656 if ((i = not_sane(SHKASUTSET_F, source, length))) {
657 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 497,
658 "Invalid character at position %d in input (alphanumerics and \"-\" only)", i);
659 }
660 memset(inter, 'd', 20); /* Pad character CC4 */
661 inter[20] = '\0';
662
663 i = 0;
664 inter_posn = 0;
665 do {
666 if (z_isdigit(source[i]) || (source[i] == '-')) {
667 inter[inter_posn] = source[i];
668 inter_posn++;
669 } else {
670 if (source[i] <= 'J') {
671 inter[inter_posn] = 'a';
672 inter[inter_posn + 1] = source[i] - 'A' + '0';
673 } else if (source[i] <= 'T') {
674 inter[inter_posn] = 'b';
675 inter[inter_posn + 1] = source[i] - 'K' + '0';
676 } else { /* (source[i] >= 'U') && (source[i] <= 'Z') */
677 inter[inter_posn] = 'c';
678 inter[inter_posn + 1] = source[i] - 'U' + '0';
679 }
680 inter_posn += 2;
681 }
682 i++;
683 } while ((i < length) && (inter_posn < 20));
684
685 if (i != length || inter[20] != '\0') {
686 return errtxt(ZINT_ERROR_TOO_LONG, symbol, 477,
687 "Input too long, requires too many symbol characters (maximum 20)");
688 }
689
690 memcpy(d, "13", 2); /* Start */
691 d += 2;
692
693 sum = 0;
694 for (i = 0; i < 20; i++, d += 3) {
695 memcpy(d, JapanTable[posn(KASUTSET, inter[i])], 3);
696 sum += posn(CHKASUTSET, inter[i]);
697 }
698
699 /* Calculate check digit */
700 check = 19 - (sum % 19);
701 if (check == 19) {
702 check = 0;
703 }
704 if (check <= 9) {
705 check_char = check + '0';
706 } else if (check == 10) {
707 check_char = '-';
708 } else {
709 check_char = (check - 11) + 'a';
710 }
711 memcpy(d, JapanTable[posn(KASUTSET, check_char)], 3);
712 d += 3;
713
714 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check: %d, char: %c\n", check, check_char);
715
716 memcpy(d, "31", 2); /* Stop */
717 d += 2;
718
719 /* Resolve pattern to 4-state symbols */
720 writer = 0;
721 h = d - pattern;
722 for (loopey = 0; loopey < h; loopey++) {
723 if ((pattern[loopey] == '2') || (pattern[loopey] == '1')) {
724 set_module(symbol, 0, writer);
725 }
726 set_module(symbol, 1, writer);
727 if ((pattern[loopey] == '3') || (pattern[loopey] == '1')) {
728 set_module(symbol, 2, writer);
729 }
730 writer += 2;
731 }
732
733 symbol->rows = 3;
734 symbol->width = writer - 1;
735
736 if (symbol->output_options & COMPLIANT_HEIGHT) {
737 /* Japan Post Zip/Barcode Manual pp.11-12 https://www.post.japanpost.jp/zipcode/zipmanual/p11.html
738 X 0.6mm (0.5mm - 0.7mm)
739 Tracker height 1.2mm (1.05mm - 1.35mm) / 0.6mm = 2,
740 Ascender/descender = 1.2mm (Full 3.6mm (3.4mm - 3.6mm, max preferred) less T divided by 2) / 0.6mm = 2 */
741 const float min_height = 4.85714293f; /* 3.4 / 0.7 */
742 const float max_height = 7.19999981f; /* 3.6 / 0.5 */
743 symbol->row_height[0] = 2.0f;
744 symbol->row_height[1] = 2.0f;
745 error_number = daft_set_height(symbol, min_height, max_height);
746 } else {
747 symbol->row_height[0] = 3.0f;
748 symbol->row_height[1] = 2.0f;
749 (void) daft_set_height(symbol, 0.0f, 0.0f);
750 }
751
752 return error_number;
753 }
754
755 /* vim: set ts=4 sw=4 et : */