comparison mupdf-source/thirdparty/zint/backend/library.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 /* library.c - external functions of libzint */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2009-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 <assert.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <math.h>
37 #include <stdio.h>
38 #include "common.h"
39 #include "eci.h"
40 #include "gs1.h"
41 #include "output.h"
42 #include "zfiletypes.h"
43
44 /* It's assumed that int is at least 32 bits, the following will compile-time fail if not
45 * https://stackoverflow.com/a/1980056 */
46 typedef char static_assert_int_at_least_32bits[sizeof(int) * CHAR_BIT < 32 ? -1 : 1];
47
48 typedef char static_assert_uint16_is_16bits[sizeof(uint16_t) * CHAR_BIT != 16 ? -1 : 1];
49 typedef char static_assert_int32_is_32bits[sizeof(int32_t) * CHAR_BIT != 32 ? -1 : 1];
50 typedef char static_assert_uint32_is_32bits[sizeof(uint32_t) * CHAR_BIT != 32 ? -1 : 1];
51 typedef char static_assert_uint64_at_least_64bits[sizeof(uint64_t) * CHAR_BIT < 64 ? -1 : 1];
52
53 /* Set `symbol` to defaults (does not zeroize) */
54 static void set_symbol_defaults(struct zint_symbol *symbol) {
55
56 symbol->symbology = BARCODE_CODE128;
57 symbol->scale = 1.0f;
58 strcpy(symbol->fgcolour, "000000");
59 symbol->fgcolor = &symbol->fgcolour[0];
60 strcpy(symbol->bgcolour, "ffffff");
61 symbol->bgcolor = &symbol->bgcolour[0];
62 #ifdef ZINT_NO_PNG
63 strcpy(symbol->outfile, "out.gif");
64 #else
65 strcpy(symbol->outfile, "out.png");
66 #endif
67 symbol->option_1 = -1;
68 symbol->show_hrt = 1; /* Show human readable text */
69 symbol->input_mode = DATA_MODE;
70 symbol->eci = 0; /* Default 0 uses ECI 3 */
71 symbol->dot_size = 0.8f; /* 0.4 / 0.5 */
72 symbol->text_gap = 1.0f;
73 symbol->guard_descent = 5.0f;
74 symbol->warn_level = WARN_DEFAULT;
75 symbol->bitmap = NULL;
76 symbol->alphamap = NULL;
77 symbol->vector = NULL;
78 symbol->memfile = NULL;
79 }
80
81 /* Create and initialize a symbol structure */
82 struct zint_symbol *ZBarcode_Create(void) {
83 struct zint_symbol *symbol;
84
85 symbol = (struct zint_symbol *) calloc(1, sizeof(*symbol));
86 if (!symbol) return NULL;
87
88 set_symbol_defaults(symbol);
89
90 return symbol;
91 }
92
93 INTERNAL void vector_free(struct zint_symbol *symbol); /* Free vector structures */
94
95 /* Free any output buffers that may have been created and initialize output fields */
96 void ZBarcode_Clear(struct zint_symbol *symbol) {
97 int i;
98
99 if (!symbol) return;
100
101 for (i = 0; i < symbol->rows; i++) {
102 memset(symbol->encoded_data[i], 0, sizeof(symbol->encoded_data[0]));
103 }
104 symbol->rows = 0;
105 symbol->width = 0;
106 memset(symbol->row_height, 0, sizeof(symbol->row_height));
107 memset(symbol->text, 0, sizeof(symbol->text));
108 symbol->errtxt[0] = '\0';
109 if (symbol->bitmap != NULL) {
110 free(symbol->bitmap);
111 symbol->bitmap = NULL;
112 }
113 if (symbol->alphamap != NULL) {
114 free(symbol->alphamap);
115 symbol->alphamap = NULL;
116 }
117 symbol->bitmap_width = 0;
118 symbol->bitmap_height = 0;
119 if (symbol->memfile != NULL) {
120 free(symbol->memfile);
121 symbol->memfile = NULL;
122 }
123 symbol->memfile_size = 0;
124
125 /* If there is a rendered version, ensure its memory is released */
126 vector_free(symbol);
127 }
128
129 /* Free any output buffers that may have been created and reset all fields to defaults */
130 void ZBarcode_Reset(struct zint_symbol *symbol) {
131 if (!symbol) return;
132
133 if (symbol->bitmap != NULL)
134 free(symbol->bitmap);
135 if (symbol->alphamap != NULL)
136 free(symbol->alphamap);
137 if (symbol->memfile != NULL)
138 free(symbol->memfile);
139
140 vector_free(symbol);
141
142 memset(symbol, 0, sizeof(*symbol));
143 set_symbol_defaults(symbol);
144 }
145
146 /* Free a symbol structure, including any output buffers */
147 void ZBarcode_Delete(struct zint_symbol *symbol) {
148 if (!symbol) return;
149
150 if (symbol->bitmap != NULL)
151 free(symbol->bitmap);
152 if (symbol->alphamap != NULL)
153 free(symbol->alphamap);
154 if (symbol->memfile != NULL)
155 free(symbol->memfile);
156
157 vector_free(symbol);
158
159 free(symbol);
160 }
161
162 /* Symbology handlers */
163 INTERNAL int eanx(struct zint_symbol *symbol, unsigned char source[], int length); /* EAN system barcodes */
164 INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 3 from 9 (or Code 39) */
165 INTERNAL int pzn(struct zint_symbol *symbol, unsigned char source[], int length); /* Pharmazentral Nummer (PZN) */
166 /* Extended Code 3 from 9 (or Code 39+) */
167 INTERNAL int excode39(struct zint_symbol *symbol, unsigned char source[], int length);
168 /* Codabar - a simple substitution cipher */
169 INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int length);
170 /* Code 2 of 5 Standard (& Matrix) */
171 INTERNAL int c25standard(struct zint_symbol *symbol, unsigned char source[], int length);
172 INTERNAL int c25ind(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 Industrial */
173 INTERNAL int c25iata(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 IATA */
174 INTERNAL int c25inter(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 Interleaved */
175 INTERNAL int c25logic(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 Data Logic */
176 INTERNAL int itf14(struct zint_symbol *symbol, unsigned char source[], int length); /* ITF-14 */
177 INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int length); /* Deutsche Post Leitcode */
178 INTERNAL int dpident(struct zint_symbol *symbol, unsigned char source[], int length); /* Deutsche Post Identcode */
179 /* Code 93 - a re-working of Code 39+, generates 2 check digits */
180 INTERNAL int code93(struct zint_symbol *symbol, unsigned char source[], int length);
181 INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 128 and NVE-18 */
182 INTERNAL int gs1_128(struct zint_symbol *symbol, unsigned char source[], int length); /* EAN-128 (GS1-128) */
183 INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 11 */
184 INTERNAL int msi_plessey(struct zint_symbol *symbol, unsigned char source[], int length); /* MSI Plessey */
185 INTERNAL int telepen(struct zint_symbol *symbol, unsigned char source[], int length); /* Telepen ASCII */
186 INTERNAL int telepen_num(struct zint_symbol *symbol, unsigned char source[], int length); /* Telepen Numeric */
187 INTERNAL int plessey(struct zint_symbol *symbol, unsigned char source[], int length); /* Plessey Code */
188 INTERNAL int pharma(struct zint_symbol *symbol, unsigned char source[], int length); /* Pharmacode One Track */
189 INTERNAL int flat(struct zint_symbol *symbol, unsigned char source[], int length); /* Flattermarken */
190 INTERNAL int fim(struct zint_symbol *symbol, unsigned char source[], int length); /* Facing Identification Mark */
191 INTERNAL int pharma_two(struct zint_symbol *symbol, unsigned char source[], int length); /* Pharmacode Two Track */
192 INTERNAL int postnet(struct zint_symbol *symbol, unsigned char source[], int length); /* Postnet */
193 INTERNAL int planet(struct zint_symbol *symbol, unsigned char source[], int length); /* PLANET */
194 /* Intelligent Mail (aka USPS OneCode) */
195 INTERNAL int usps_imail(struct zint_symbol *symbol, unsigned char source[], int length);
196 INTERNAL int rm4scc(struct zint_symbol *symbol, unsigned char source[], int length); /* RM4SCC */
197 INTERNAL int auspost(struct zint_symbol *symbol, unsigned char source[], int length); /* Australia Post 4-state */
198 INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 16k */
199 INTERNAL int pdf417(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* PDF417 */
200 INTERNAL int micropdf417(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Micro PDF417 */
201 INTERNAL int maxicode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Maxicode */
202 INTERNAL int dbar_omn(struct zint_symbol *symbol, unsigned char source[], int length); /* DataBar Omnidirectional */
203 INTERNAL int dbar_ltd(struct zint_symbol *symbol, unsigned char source[], int length); /* DataBar Limited */
204 INTERNAL int dbar_exp(struct zint_symbol *symbol, unsigned char source[], int length); /* DataBar Expanded */
205 INTERNAL int composite(struct zint_symbol *symbol, unsigned char source[], int length); /* Composite Symbology */
206 INTERNAL int kix(struct zint_symbol *symbol, unsigned char source[], int length); /* TNT KIX Code */
207 INTERNAL int aztec(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Aztec Code */
208 INTERNAL int code32(struct zint_symbol *symbol, unsigned char source[], int length); /* Italian Pharmacode */
209 INTERNAL int daft(struct zint_symbol *symbol, unsigned char source[], int length); /* DAFT Code */
210 INTERNAL int ean14(struct zint_symbol *symbol, unsigned char source[], int length); /* EAN-14 */
211 INTERNAL int nve18(struct zint_symbol *symbol, unsigned char source[], int length); /* NVE-18 */
212 INTERNAL int microqr(struct zint_symbol *symbol, unsigned char source[], int length); /* Micro QR Code */
213 INTERNAL int azrune(struct zint_symbol *symbol, unsigned char source[], int length); /* Aztec Runes */
214 INTERNAL int koreapost(struct zint_symbol *symbol, unsigned char source[], int length); /* Korea Post */
215 INTERNAL int japanpost(struct zint_symbol *symbol, unsigned char source[], int length); /* Japanese Post */
216 INTERNAL int code49(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 49 */
217 INTERNAL int channel(struct zint_symbol *symbol, unsigned char source[], int length); /* Channel Code */
218 INTERNAL int codeone(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Code One */
219 INTERNAL int gridmatrix(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Grid Matrix */
220 INTERNAL int hanxin(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Han Xin */
221 INTERNAL int dotcode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* DotCode */
222 INTERNAL int codablockf(struct zint_symbol *symbol, unsigned char source[], int length); /* Codablock */
223 INTERNAL int upnqr(struct zint_symbol *symbol, unsigned char source[], int length); /* UPNQR */
224 INTERNAL int qrcode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* QR Code */
225 /* Data Matrix (IEC16022) */
226 INTERNAL int datamatrix(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count);
227 /* VIN Code (Vehicle Identification Number) */
228 INTERNAL int vin(struct zint_symbol *symbol, unsigned char source[], int length);
229 /* Royal Mail 2D Mailmark */
230 INTERNAL int mailmark_2d(struct zint_symbol *symbol, unsigned char source[], int length);
231 /* Royal Mail 4-state Mailmark */
232 INTERNAL int mailmark_4s(struct zint_symbol *symbol, unsigned char source[], int length);
233 INTERNAL int upu_s10(struct zint_symbol *symbol, unsigned char source[], int length); /* Universal Postal Union S10 */
234 INTERNAL int ultra(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Ultracode */
235 INTERNAL int rmqr(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* rMQR */
236 INTERNAL int dpd(struct zint_symbol *symbol, unsigned char source[], int length); /* DPD Code */
237 INTERNAL int bc412(struct zint_symbol *symbol, unsigned char source[], int length); /* BC412 */
238 INTERNAL int dxfilmedge(struct zint_symbol *symbol, unsigned char source[], int length); /* DX Film Edge Barcode */
239
240 /* Output handlers */
241 /* Plot to BMP/GIF/PCX/PNG/TIF */
242 INTERNAL int plot_raster(struct zint_symbol *symbol, int rotate_angle, int file_type);
243 /* Plot to EMF/EPS/SVG */
244 INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type);
245
246 /* Prefix error message with Error/Warning */
247 static int error_tag(int error_number, struct zint_symbol *symbol, const int err_id, const char *error_string) {
248
249 if (error_number != 0) {
250 if (error_string) {
251 errtxt(0, symbol, err_id, error_string);
252 }
253 if (error_number < ZINT_ERROR && symbol->warn_level == WARN_FAIL_ALL) {
254 /* Convert to error equivalent */
255 if (error_number == ZINT_WARN_NONCOMPLIANT) {
256 error_number = ZINT_ERROR_NONCOMPLIANT;
257 } else if (error_number == ZINT_WARN_USES_ECI) {
258 error_number = ZINT_ERROR_USES_ECI;
259 } else if (error_number == ZINT_WARN_INVALID_OPTION) {
260 error_number = ZINT_ERROR_INVALID_OPTION;
261 } else if (error_number == ZINT_WARN_HRT_TRUNCATED) {
262 error_number = ZINT_ERROR_HRT_TRUNCATED;
263 } else { /* Shouldn't happen */
264 assert(0); /* Not reached */
265 error_number = ZINT_ERROR_ENCODING_PROBLEM;
266 }
267 }
268 if (error_number >= ZINT_ERROR) {
269 errtxt_adj(0, symbol, "Error %s", NULL);
270 } else {
271 errtxt_adj(0, symbol, "Warning %s", NULL);
272 }
273 }
274
275 return error_number;
276 }
277
278 #ifdef ZINT_TEST /* Wrapper for direct testing */
279 INTERNAL int error_tag_test(int error_number, struct zint_symbol *symbol, const int err_id,
280 const char *error_string) {
281 return error_tag(error_number, symbol, err_id, error_string);
282 }
283 #endif
284
285 /* Output a hexadecimal representation of the rendered symbol */
286 static int dump_plot(struct zint_symbol *symbol) {
287 FILE *f;
288 int i, r;
289 static const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
290 int space = 0;
291 const int output_to_stdout = symbol->output_options & BARCODE_STDOUT;
292
293 if (output_to_stdout) {
294 f = stdout;
295 } else {
296 #ifdef _WIN32
297 f = out_win_fopen(symbol->outfile, "w");
298 #else
299 f = fopen(symbol->outfile, "w");
300 #endif
301 if (!f) {
302 return errtxt(ZINT_ERROR_FILE_ACCESS, symbol, 201, "Could not open output file");
303 }
304 }
305
306 for (r = 0; r < symbol->rows; r++) {
307 int byt = 0;
308 for (i = 0; i < symbol->width; i++) {
309 byt = byt << 1;
310 if (symbol->symbology == BARCODE_ULTRA) {
311 if (module_colour_is_set(symbol, r, i)) {
312 byt += 1;
313 }
314 } else {
315 if (module_is_set(symbol, r, i)) {
316 byt += 1;
317 }
318 }
319 if (((i + 1) % 4) == 0) {
320 fputc(hex[byt], f);
321 space++;
322 byt = 0;
323 }
324 if (space == 2 && i + 1 < symbol->width) {
325 fputc(' ', f);
326 space = 0;
327 }
328 }
329
330 if ((symbol->width % 4) != 0) {
331 byt = byt << (4 - (symbol->width % 4));
332 fputc(hex[byt], f);
333 }
334 fputc('\n', f);
335 space = 0;
336 }
337
338 if (ferror(f)) {
339 errtxtf(0, symbol, 795, "Incomplete write to output (%1$d: %2$s)", errno, strerror(errno));
340 if (!output_to_stdout) {
341 (void) fclose(f);
342 }
343 return ZINT_ERROR_FILE_WRITE;
344 }
345
346 if (output_to_stdout) {
347 if (fflush(f) != 0) {
348 return errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 796, "Incomplete flush to output (%1$d: %2$s)",
349 errno, strerror(errno));
350 }
351 } else {
352 if (fclose(f) != 0) {
353 return errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 792, "Failure on closing output file (%1$d: %2$s)",
354 errno, strerror(errno));
355 }
356 }
357
358 return 0;
359 }
360
361 /* Permitted HIBC characters */
362 static const char TECHNETIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; /* Same as SILVER (CODE39) */
363
364 /* Process health industry bar code data */
365 static int hibc(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
366 unsigned char *source = segs[0].source;
367 int length = segs[0].length;
368
369 int i;
370 int counter, error_number = 0;
371 char to_process[110 + 2 + 1];
372 int posns[110];
373
374 /* without "+" and check: max 110 characters in HIBC 2.6 */
375 if (length > 110) {
376 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 202, "Input length %d too long for HIBC LIC (maximum 110)",
377 length);
378 }
379 to_upper(source, length);
380 if ((i = not_sane_lookup(TECHNETIUM, sizeof(TECHNETIUM) - 1, source, length, posns))) {
381 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 203,
382 "Invalid character at position %d in input (alphanumerics, space and \"-.$/+%%\" only)", i);
383 }
384
385 counter = 41;
386 for (i = 0; i < length; i++) {
387 counter += posns[i];
388 }
389 counter = counter % 43;
390
391 to_process[0] = '+';
392 memcpy(to_process + 1, source, length);
393 to_process[++length] = TECHNETIUM[counter];
394 to_process[++length] = '\0';
395
396 segs[0].source = (unsigned char *) to_process;
397 segs[0].length = length;
398
399 if (symbol->debug & ZINT_DEBUG_PRINT) printf("HIBC processed source: %s\n", to_process);
400
401 switch (symbol->symbology) {
402 case BARCODE_HIBC_128:
403 error_number = code128(symbol, segs[0].source, segs[0].length);
404 ustrcpy(symbol->text, "*");
405 ustrcat(symbol->text, to_process);
406 ustrcat(symbol->text, "*");
407 break;
408 case BARCODE_HIBC_39:
409 symbol->option_2 = 0;
410 error_number = code39(symbol, segs[0].source, segs[0].length);
411 ustrcpy(symbol->text, "*");
412 ustrcat(symbol->text, to_process);
413 ustrcat(symbol->text, "*");
414 break;
415 case BARCODE_HIBC_DM:
416 error_number = datamatrix(symbol, segs, seg_count);
417 break;
418 case BARCODE_HIBC_QR:
419 error_number = qrcode(symbol, segs, seg_count);
420 break;
421 case BARCODE_HIBC_PDF:
422 error_number = pdf417(symbol, segs, seg_count);
423 break;
424 case BARCODE_HIBC_MICPDF:
425 error_number = micropdf417(symbol, segs, seg_count);
426 break;
427 case BARCODE_HIBC_AZTEC:
428 error_number = aztec(symbol, segs, seg_count);
429 break;
430 case BARCODE_HIBC_BLOCKF:
431 error_number = codablockf(symbol, segs[0].source, segs[0].length);
432 break;
433 }
434
435 return error_number;
436 }
437
438 /* Returns 1 if symbology MUST have GS1 data */
439 static int check_force_gs1(const int symbology) {
440
441 switch (symbology) {
442 case BARCODE_GS1_128:
443 case BARCODE_EAN14:
444 case BARCODE_NVE18:
445 case BARCODE_DBAR_EXP:
446 case BARCODE_DBAR_EXPSTK:
447 return 1;
448 break;
449 }
450
451 return is_composite(symbology);
452 }
453
454 /* Returns 1 if symbology supports GS1 data */
455 static int gs1_compliant(const int symbology) {
456
457 switch (symbology) {
458 case BARCODE_CODE16K:
459 case BARCODE_AZTEC:
460 case BARCODE_DATAMATRIX:
461 case BARCODE_CODE49:
462 case BARCODE_QRCODE:
463 case BARCODE_DOTCODE:
464 case BARCODE_CODEONE:
465 case BARCODE_ULTRA:
466 case BARCODE_RMQR:
467 /* TODO: case BARCODE_CODABLOCKF: */
468 /* TODO: case BARCODE_HANXIN: */
469 /* TODO: case BARCODE_GRIDMATRIX: */
470 return 1;
471 break;
472 }
473
474 return check_force_gs1(symbology);
475 }
476
477 /* Returns 1 if symbology can encode the ECI character */
478 static int supports_eci(const int symbology) {
479
480 switch (symbology) {
481 case BARCODE_AZTEC:
482 case BARCODE_DATAMATRIX:
483 case BARCODE_MAXICODE:
484 case BARCODE_MICROPDF417:
485 case BARCODE_PDF417:
486 case BARCODE_PDF417COMP:
487 case BARCODE_QRCODE:
488 case BARCODE_DOTCODE:
489 case BARCODE_CODEONE:
490 case BARCODE_GRIDMATRIX:
491 case BARCODE_HANXIN:
492 case BARCODE_ULTRA:
493 case BARCODE_RMQR:
494 return 1;
495 break;
496 }
497
498 return 0;
499 }
500
501 /* Returns 1 if symbology supports HRT */
502 static int has_hrt(const int symbology) {
503
504 if (is_fixed_ratio(symbology)) {
505 return 0;
506 }
507
508 switch (symbology) { /* These don't support HRT */
509 case BARCODE_CODE16K:
510 case BARCODE_CODE49:
511 case BARCODE_FLAT:
512 case BARCODE_POSTNET:
513 case BARCODE_FIM:
514 case BARCODE_PHARMA:
515 case BARCODE_PHARMA_TWO:
516 case BARCODE_DXFILMEDGE:
517 case BARCODE_CEPNET:
518 case BARCODE_PDF417:
519 case BARCODE_PDF417COMP:
520 case BARCODE_AUSPOST:
521 case BARCODE_AUSREPLY:
522 case BARCODE_AUSROUTE:
523 case BARCODE_AUSREDIRECT:
524 case BARCODE_RM4SCC:
525 case BARCODE_CODABLOCKF:
526 case BARCODE_JAPANPOST:
527 case BARCODE_DBAR_STK:
528 case BARCODE_DBAR_OMNSTK:
529 case BARCODE_DBAR_EXPSTK:
530 case BARCODE_PLANET:
531 case BARCODE_MICROPDF417:
532 case BARCODE_USPS_IMAIL:
533 case BARCODE_KIX:
534 case BARCODE_DAFT:
535 case BARCODE_HIBC_PDF:
536 case BARCODE_HIBC_MICPDF:
537 case BARCODE_HIBC_BLOCKF:
538 case BARCODE_MAILMARK_2D:
539 case BARCODE_MAILMARK_4S:
540 case BARCODE_DBAR_STK_CC:
541 case BARCODE_DBAR_OMNSTK_CC:
542 case BARCODE_DBAR_EXPSTK_CC:
543 return 0;
544 break;
545 }
546
547 return 1;
548 }
549
550 typedef int (*barcode_src_func_t)(struct zint_symbol *, unsigned char[], int);
551 typedef int (*barcode_seg_func_t)(struct zint_symbol *, struct zint_seg[], const int);
552
553 /* Used for dispatching `barcode_src_func_t` barcodes */
554 /* Also used, with `barcode_seg_funcs` below, for testing whether symbol id valid in `ZBarcode_ValidID()` */
555 static const barcode_src_func_t barcode_src_funcs[BARCODE_LAST + 1] = {
556 NULL, code11, c25standard, c25inter, c25iata, /*0-4*/
557 NULL, c25logic, c25ind, code39, excode39, /*5-9*/
558 NULL, NULL, NULL, eanx, eanx, /*10-14*/
559 NULL, gs1_128, NULL, codabar, NULL, /*15-19*/
560 code128, dpleit, dpident, code16k, code49, /*20-24*/
561 code93, NULL, NULL, flat, dbar_omn, /*25-29*/
562 dbar_ltd, dbar_exp, telepen, NULL, eanx, /*30-34*/
563 eanx, NULL, eanx, eanx, NULL, /*35-39*/
564 postnet, NULL, NULL, NULL, NULL, /*40-44*/
565 NULL, NULL, msi_plessey, NULL, fim, /*45-49*/
566 code39, pharma, pzn, pharma_two, postnet, /*50-54*/
567 NULL, NULL, NULL, NULL, NULL, /*55-59*/
568 code128, NULL, NULL, auspost, NULL, /*60-64*/
569 NULL, auspost, auspost, auspost, eanx, /*65-69*/
570 rm4scc, NULL, ean14, vin, codablockf, /*70-74*/
571 nve18, japanpost, koreapost, NULL, dbar_omn, /*75-79*/
572 dbar_omn, dbar_exp, planet, NULL, NULL, /*80-84*/
573 usps_imail, plessey, telepen_num, NULL, itf14, /*85-89*/
574 kix, NULL, NULL, daft, NULL, /*90-94*/
575 NULL, dpd, microqr, NULL, NULL, /*95-99*/
576 NULL, NULL, NULL, NULL, NULL, /*100-104*/
577 NULL, NULL, NULL, NULL, NULL, /*105-109*/
578 NULL, NULL, NULL, NULL, NULL, /*110-114*/
579 NULL, NULL, NULL, NULL, mailmark_2d, /*115-119*/
580 upu_s10, mailmark_4s, NULL, NULL, NULL, /*120-124*/
581 NULL, NULL, NULL, azrune, code32, /*125-129*/
582 composite, composite, composite, composite, composite, /*130-134*/
583 composite, composite, composite, composite, composite, /*135-139*/
584 channel, NULL, NULL, upnqr, NULL, /*140-144*/
585 NULL, bc412, dxfilmedge, /*145-147*/
586 };
587
588 #define LIB_SEG_FUNCS_START 55
589
590 /* Used for dispatching `barcode_seg_func_t` barcodes */
591 static const barcode_seg_func_t barcode_seg_funcs[BARCODE_LAST + 1 - LIB_SEG_FUNCS_START] = {
592 pdf417, pdf417, maxicode, qrcode, NULL, /*55-59*/
593 NULL, NULL, NULL, NULL, NULL, /*60-64*/
594 NULL, NULL, NULL, NULL, NULL, /*65-69*/
595 NULL, datamatrix, NULL, NULL, NULL, /*70-74*/
596 NULL, NULL, NULL, NULL, NULL, /*75-79*/
597 NULL, NULL, NULL, NULL, micropdf417, /*80-84*/
598 NULL, NULL, NULL, NULL, NULL, /*85-89*/
599 NULL, NULL, aztec, NULL, NULL, /*90-94*/
600 NULL, NULL, NULL, hibc, hibc, /*95-99*/
601 NULL, NULL, hibc, NULL, hibc, /*100-104*/
602 NULL, hibc, NULL, hibc, NULL, /*105-109*/
603 hibc, NULL, hibc, NULL, NULL, /*110-114*/
604 dotcode, hanxin, NULL, NULL, NULL, /*115-119*/
605 NULL, NULL, NULL, NULL, NULL, /*120-124*/
606 NULL, NULL, NULL, NULL, NULL, /*125-129*/
607 NULL, NULL, NULL, NULL, NULL, /*130-134*/
608 NULL, NULL, NULL, NULL, NULL, /*135-139*/
609 NULL, codeone, gridmatrix, NULL, ultra, /*140-144*/
610 rmqr, NULL, /*145-146*/
611 };
612
613 static int reduced_charset(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count);
614
615 /* Main dispatch, checking for barcodes which handle ECIs/character sets themselves, otherwise calling
616 `reduced_charset()` */
617 static int extended_or_reduced_charset(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
618 int error_number = 0;
619
620 switch (symbol->symbology) {
621 /* These are the "elite" standards which have support for specific character sets + ECI */
622 case BARCODE_QRCODE:
623 case BARCODE_GRIDMATRIX:
624 case BARCODE_HANXIN:
625 case BARCODE_RMQR:
626 error_number = barcode_seg_funcs[symbol->symbology - LIB_SEG_FUNCS_START](symbol, segs, seg_count);
627 break;
628 /* These are the standards which have support for specific character sets but not ECI */
629 case BARCODE_MICROQR:
630 case BARCODE_UPNQR:
631 error_number = barcode_src_funcs[symbol->symbology](symbol, segs[0].source, segs[0].length);
632 break;
633 default: error_number = reduced_charset(symbol, segs, seg_count);
634 break;
635 }
636
637 return error_number;
638 }
639
640 /* These are the "norm" standards which only support Latin-1 at most, though a few support ECI */
641 static int reduced_charset(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
642 int error_number = 0;
643 int i;
644 struct zint_seg *local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * seg_count);
645 int *convertible = (int *) z_alloca(sizeof(int) * seg_count);
646
647 if ((symbol->input_mode & 0x07) == UNICODE_MODE && is_eci_convertible_segs(segs, seg_count, convertible)) {
648 unsigned char *preprocessed;
649 const int eci_length_segs = get_eci_length_segs(segs, seg_count);
650 unsigned char *preprocessed_buf = (unsigned char *) z_alloca(eci_length_segs + seg_count);
651
652 /* Prior check ensures ECI only set for those that support it */
653 segs_cpy(symbol, segs, seg_count, local_segs); /* Shallow copy (needed to set default ECIs) */
654 preprocessed = preprocessed_buf;
655 for (i = 0; i < seg_count; i++) {
656 if (convertible[i]) {
657 error_number = utf8_to_eci(local_segs[i].eci, local_segs[i].source, preprocessed,
658 &local_segs[i].length);
659 if (error_number != 0) {
660 if (local_segs[i].eci) {
661 return errtxtf(error_number, symbol, 244, "Invalid character in input for ECI '%d'",
662 local_segs[i].eci);
663 }
664 return errtxt(error_number, symbol, 204, "Invalid character in input (ISO/IEC 8859-1 only)");
665 }
666 local_segs[i].source = preprocessed;
667 preprocessed += local_segs[i].length + 1;
668 }
669 }
670 if (barcode_src_funcs[symbol->symbology]) {
671 error_number = barcode_src_funcs[symbol->symbology](symbol, local_segs[0].source, local_segs[0].length);
672 } else {
673 assert(symbol->symbology >= LIB_SEG_FUNCS_START); /* Suppress clang-tidy-20 warning */
674 assert(barcode_seg_funcs[symbol->symbology - LIB_SEG_FUNCS_START]); /* Suppress clang-tidy-20 warning */
675 error_number = barcode_seg_funcs[symbol->symbology - LIB_SEG_FUNCS_START](symbol, local_segs, seg_count);
676 }
677 } else {
678 if (barcode_src_funcs[symbol->symbology]) {
679 error_number = barcode_src_funcs[symbol->symbology](symbol, segs[0].source, segs[0].length);
680 } else {
681 assert(symbol->symbology >= LIB_SEG_FUNCS_START); /* Suppress clang-tidy-19 warning */
682 assert(barcode_seg_funcs[symbol->symbology - LIB_SEG_FUNCS_START]); /* Suppress clang-tidy-19 warning */
683 segs_cpy(symbol, segs, seg_count, local_segs); /* Shallow copy (needed to set default ECIs) */
684 error_number = barcode_seg_funcs[symbol->symbology - LIB_SEG_FUNCS_START](symbol, local_segs, seg_count);
685 }
686 }
687
688 return error_number;
689 }
690
691 /* Remove Unicode BOM at start of data */
692 static void strip_bom(unsigned char *source, int *input_length) {
693 int i;
694
695 /* Note if BOM is only data then not stripped */
696 if (*input_length > 3 && (source[0] == 0xef) && (source[1] == 0xbb) && (source[2] == 0xbf)) {
697 /* BOM at start of input data, strip in accordance with RFC 3629 */
698 for (i = 3; i <= *input_length; i++) { /* Include terminating NUL */
699 source[i - 3] = source[i];
700 }
701 *input_length -= 3;
702 }
703 }
704
705 #ifdef ZINT_TEST /* Wrapper for direct testing */
706 INTERNAL void strip_bom_test(unsigned char *source, int *input_length) {
707 strip_bom(source, input_length);
708 }
709 #endif
710
711 /* Helper to convert base octal, decimal, hexadecimal escape sequence */
712 static int esc_base(struct zint_symbol *symbol, const unsigned char *input_string, const int length,
713 const int in_posn, const unsigned char base) {
714 int c1, c2, c3;
715 int min_len = base == 'x' ? 2 : 3;
716 int val = -1;
717
718 if (in_posn + min_len > length) {
719 return errtxtf(-1, symbol, 232, "Incomplete '\\%c' escape sequence in input", base);
720 }
721 c1 = ctoi(input_string[in_posn]);
722 c2 = ctoi(input_string[in_posn + 1]);
723 if (base == 'd') {
724 c3 = ctoi(input_string[in_posn + 2]);
725 if ((c1 >= 0 && c1 <= 9) && (c2 >= 0 && c2 <= 9) && (c3 >= 0 && c3 <= 9)) {
726 val = c1 * 100 + c2 * 10 + c3;
727 }
728 } else if (base == 'o') {
729 c3 = ctoi(input_string[in_posn + 2]);
730 if ((c1 >= 0 && c1 <= 7) && (c2 >= 0 && c2 <= 7) && (c3 >= 0 && c3 <= 7)) {
731 val = (c1 << 6) | (c2 << 3) | c3;
732 }
733 } else {
734 if ((c1 >= 0) && (c2 >= 0)) {
735 val = (c1 << 4) | c2;
736 }
737 }
738
739 if (val == -1) {
740 return errtxtf(-1, symbol, 238, "Invalid character in escape sequence '%2$.*1$s' in input (%3$s only)",
741 base == 'x' ? 4 : 5, input_string + in_posn - 2,
742 base == 'd' ? "decimal" : base == 'o' ? "octal" : "hexadecimal");
743 }
744 if (val > 255) {
745 assert(base != 'x');
746 return errtxtf(-1, symbol, 237, "Value of escape sequence '%1$.5s' in input out of range (000 to %2$s)",
747 input_string + in_posn - 2, base == 'd' ? "255" : "377");
748 }
749
750 return val;
751 }
752
753 /* Helper to parse escape sequences. If `escaped_string` NULL, calculates length only */
754 static int escape_char_process(struct zint_symbol *symbol, const unsigned char *input_string, int *p_length,
755 unsigned char *escaped_string) {
756 /* NUL EOT BEL BS HT LF VT FF CR ESC GS RS \ */
757 static const char escs[] = { '0', 'E', 'a', 'b', 't', 'n', 'v', 'f', 'r', 'e', 'G', 'R', '\\', '\0' };
758 static const char vals[] = { 0x00, 0x04, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x1B, 0x1D, 0x1E, 0x5C };
759 const int length = *p_length;
760 int in_posn = 0, out_posn = 0;
761 unsigned char ch;
762 int val;
763 int i;
764 unsigned int unicode;
765 const int extra_escape_mode = (symbol->input_mode & EXTRA_ESCAPE_MODE) && symbol->symbology == BARCODE_CODE128;
766
767 do {
768 if (input_string[in_posn] == '\\') {
769 if (in_posn + 1 >= length) {
770 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 236, "Incomplete escape character in input");
771 }
772 ch = input_string[in_posn + 1];
773 /* NOTE: if add escape character, must also update regex in "frontend_qt/datawindow.php" */
774 switch (ch) {
775 case '0':
776 case 'E':
777 case 'a':
778 case 'b':
779 case 't':
780 case 'n':
781 case 'v':
782 case 'f':
783 case 'r':
784 case 'e':
785 case 'G':
786 case 'R':
787 case '\\':
788 if (escaped_string) escaped_string[out_posn] = vals[posn(escs, ch)];
789 in_posn += 2;
790 break;
791 case '^': /* CODE128 specific */
792 if (!extra_escape_mode) {
793 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 798,
794 "Escape '\\^' only valid for Code 128 in extra escape mode");
795 }
796 /* Pass thru unaltered */
797 if (escaped_string) {
798 escaped_string[out_posn++] = '\\';
799 escaped_string[out_posn] = '^';
800 } else {
801 out_posn++;
802 }
803 in_posn += 2;
804 if (in_posn < length) { /* Note allowing '\\^' on its own at end */
805 if (escaped_string) {
806 escaped_string[++out_posn] = input_string[in_posn++];
807 } else {
808 ++out_posn;
809 in_posn++;
810 }
811 }
812 break;
813 case 'd':
814 case 'o':
815 case 'x':
816 if ((val = esc_base(symbol, input_string, length, in_posn + 2, ch)) == -1) {
817 return ZINT_ERROR_INVALID_DATA;
818 }
819 if (escaped_string) escaped_string[out_posn] = val;
820 in_posn += 4 + (ch != 'x');
821 break;
822 case 'u':
823 case 'U':
824 if (in_posn + 6 > length || (ch == 'U' && in_posn + 8 > length)) {
825 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 209,
826 "Incomplete '\\%c' escape sequence in input", ch);
827 }
828 unicode = 0;
829 for (i = 0; i < 6; i++) {
830 if ((val = ctoi(input_string[in_posn + i + 2])) == -1) {
831 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 211,
832 "Invalid character for '\\%c' escape sequence in input (hexadecimal only)",
833 ch);
834 }
835 unicode = (unicode << 4) | val;
836 if (i == 3 && ch == 'u') {
837 break;
838 }
839 }
840 /* Exclude reversed BOM and surrogates and out-of-range */
841 if (unicode == 0xfffe || (unicode >= 0xd800 && unicode < 0xe000) || unicode > 0x10ffff) {
842 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 246,
843 "Value of escape sequence '%.*s' in input out of range",
844 ch == 'u' ? 6 : 8, input_string + in_posn);
845 }
846 if (unicode < 0x80) {
847 if (escaped_string) escaped_string[out_posn] = (unsigned char) unicode;
848 } else if (unicode < 0x800) {
849 if (escaped_string) {
850 escaped_string[out_posn++] = (unsigned char) (0xC0 | (unicode >> 6));
851 escaped_string[out_posn] = (unsigned char) (0x80 | (unicode & 0x3F));
852 } else {
853 out_posn++;
854 }
855 } else if (unicode < 0x10000) {
856 if (escaped_string) {
857 escaped_string[out_posn++] = (unsigned char) (0xE0 | (unicode >> 12));
858 escaped_string[out_posn++] = (unsigned char) (0x80 | ((unicode >> 6) & 0x3F));
859 escaped_string[out_posn] = (unsigned char) (0x80 | (unicode & 0x3F));
860 } else {
861 out_posn += 2;
862 }
863 } else {
864 if (escaped_string) {
865 escaped_string[out_posn++] = (unsigned char) (0xF0 | (unicode >> 18));
866 escaped_string[out_posn++] = (unsigned char) (0x80 | ((unicode >> 12) & 0x3F));
867 escaped_string[out_posn++] = (unsigned char) (0x80 | ((unicode >> 6) & 0x3F));
868 escaped_string[out_posn] = (unsigned char) (0x80 | (unicode & 0x3F));
869 } else {
870 out_posn += 3;
871 }
872 }
873 in_posn += 6 + (ch == 'U') * 2;
874 break;
875 default:
876 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 234,
877 "Unrecognised escape character '\\%c' in input", ch);
878 break;
879 }
880 } else {
881 if (escaped_string) escaped_string[out_posn] = input_string[in_posn];
882 in_posn++;
883 }
884 out_posn++;
885 } while (in_posn < length);
886
887 if (escaped_string) {
888 escaped_string[out_posn] = '\0';
889 }
890 *p_length = out_posn;
891
892 return 0;
893 }
894
895 #ifdef ZINT_TEST /* Wrapper for direct testing (also used by `testUtilZXingCPPCmp()` in "tests/testcommon.c") */
896 INTERNAL int escape_char_process_test(struct zint_symbol *symbol, const unsigned char *input_string, int *p_length,
897 unsigned char *escaped_string) {
898 return escape_char_process(symbol, input_string, p_length, escaped_string);
899 }
900 #endif
901
902 /* For backward-compatibility, map certain invalid symbol ids to zint equivalents, some silently, some with warning */
903 static int map_invalid_symbology(struct zint_symbol *symbol) {
904
905 /* Symbol ids 1 to 126 are defined by tbarcode */
906 /* 26 allowed: UPC-A up to tbarcode 9, ISSN for tbarcode 10+, mapped to UPC-A */
907 /* 27 error: UPCD1 up to tbarcode 9, ISSN + 2 digit add-on for tbarcode 10+ */
908 /* 91 warning: BC412 up to tbarcode 9, Code 32 for tbarcode 10+, mapped to Code 128 */
909 /* Note: non-zero table entries map silently, i.e. do not produce a warning */
910 #define LIB_ID_MAP_LAST 111
911 static const unsigned char id_map[LIB_ID_MAP_LAST + 1] = {
912 0, 0, 0, 0, 0, /*0-4*/
913 BARCODE_C25STANDARD, 0, 0, 0, 0, /*5-9*/
914 BARCODE_EANX, BARCODE_EANX, BARCODE_EANX, 0, 0, /*10-14*/
915 BARCODE_EANX, 0, BARCODE_UPCA, 0, BARCODE_CODABAR, /*15-19*/
916 0, 0, 0, 0, 0, /*20-24*/
917 0, BARCODE_UPCA, 0, 0, 0, /*25-29*/
918 0, 0, 0, BARCODE_GS1_128, 0, /*30-34*/
919 0, BARCODE_UPCA, 0, 0, BARCODE_UPCE, /*35-39*/
920 0, BARCODE_POSTNET, BARCODE_POSTNET, BARCODE_POSTNET, BARCODE_POSTNET, /*40-44*/
921 BARCODE_POSTNET, BARCODE_PLESSEY, 0, BARCODE_NVE18, 0, /*45-49*/
922 0, 0, 0, 0, 0, /*50-54*/
923 0, 0, 0, 0, BARCODE_CODE128, /*55-59*/
924 0, BARCODE_CODE128, BARCODE_CODE93, 0, BARCODE_AUSPOST, /*60-64*/
925 BARCODE_AUSPOST, 0, 0, 0, 0, /*65-69*/
926 0, 0, 0, 0, 0, /*70-74*/
927 0, 0, 0, BARCODE_DBAR_OMN, 0, /*75-79*/
928 0, 0, 0, BARCODE_PLANET, 0, /*80-84*/
929 0, 0, 0, BARCODE_GS1_128, 0, /*85-89*/
930 0, 0, 0, 0, 0, /*90-94*/
931 0, 0, 0, 0, 0, /*95-99*/
932 BARCODE_HIBC_128, BARCODE_HIBC_39, 0, BARCODE_HIBC_DM, 0, /*100-104*/
933 BARCODE_HIBC_QR, 0, BARCODE_HIBC_PDF, 0, BARCODE_HIBC_MICPDF, /*105-109*/
934 0, BARCODE_HIBC_BLOCKF, /*110-111*/
935 };
936 const int orig_symbology = symbol->symbology; /* For self-check */
937 int warn_number = 0;
938
939 if (symbol->symbology == 19) {
940 /* Has specific error message */
941 warn_number = error_tag(ZINT_WARN_INVALID_OPTION, symbol, 207, "Codabar 18 not supported");
942 if (warn_number >= ZINT_ERROR) {
943 return warn_number;
944 }
945 symbol->symbology = BARCODE_CODABAR;
946 } else if (symbol->symbology == 27) {
947 /* Not mapped */
948 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 208, "UPCD1 not supported");
949
950 } else if (symbol->symbology <= 0 || symbol->symbology > LIB_ID_MAP_LAST || id_map[symbol->symbology] == 0) {
951 warn_number = error_tag(ZINT_WARN_INVALID_OPTION, symbol, 206, "Symbology out of range");
952 if (warn_number >= ZINT_ERROR) {
953 return warn_number;
954 }
955 symbol->symbology = BARCODE_CODE128;
956 } else {
957 symbol->symbology = id_map[symbol->symbology];
958 }
959
960 if (symbol->symbology == orig_symbology) { /* Should never happen */
961 assert(0); /* Not reached */
962 return error_tag(ZINT_ERROR_ENCODING_PROBLEM, symbol, 0, "Internal error");
963 }
964
965 return warn_number;
966 }
967
968 /* Encode a barcode. If `length` is 0, `source` must be NUL-terminated */
969 int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int length) {
970 struct zint_seg segs[1];
971
972 if (!symbol) return ZINT_ERROR_INVALID_DATA;
973
974 segs[0].eci = symbol->eci;
975 segs[0].source = (unsigned char *) source;
976 segs[0].length = length;
977
978 return ZBarcode_Encode_Segs(symbol, segs, 1);
979 }
980
981 /* Encode a barcode with multiple ECI segments. */
982 int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[], const int seg_count) {
983 int error_number, warn_number = 0;
984 int total_len = 0;
985 int have_zero_eci = 0;
986 int escape_mode;
987 int i;
988 unsigned char *local_source;
989 struct zint_seg *local_segs;
990 unsigned char *local_sources;
991
992 if (!symbol) return ZINT_ERROR_INVALID_DATA;
993
994 if (segs == NULL) {
995 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 200, "Input segments NULL");
996 }
997 /* `seg_count` zero dealt with via `total_len` zero below */
998 if (seg_count > ZINT_MAX_SEG_COUNT) {
999 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 771, "Too many input segments (maximum 256)");
1000 }
1001
1002 if ((symbol->input_mode & 0x07) > 2) {
1003 symbol->input_mode = DATA_MODE; /* Reset completely */
1004 warn_number = error_tag(ZINT_WARN_INVALID_OPTION, symbol, 212, "Invalid input mode - reset to DATA_MODE");
1005 if (warn_number >= ZINT_ERROR) {
1006 return warn_number;
1007 }
1008 }
1009
1010 /* Check the symbology field */
1011 if (!ZBarcode_ValidID(symbol->symbology)) {
1012 warn_number = map_invalid_symbology(symbol);
1013 if (warn_number >= ZINT_ERROR) {
1014 return warn_number;
1015 }
1016 }
1017
1018 escape_mode = (symbol->input_mode & ESCAPE_MODE)
1019 || ((symbol->input_mode & EXTRA_ESCAPE_MODE) && symbol->symbology == BARCODE_CODE128);
1020
1021 local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * (seg_count > 0 ? seg_count : 1));
1022
1023 /* Check segment lengths */
1024 for (i = 0; i < seg_count; i++) {
1025 local_segs[i] = segs[i];
1026 if (local_segs[i].source == NULL) {
1027 errtxtf(0, symbol, 772, "Input segment %d source NULL", i);
1028 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL);
1029 }
1030 if (local_segs[i].length <= 0) {
1031 local_segs[i].length = (int) ustrlen(local_segs[i].source);
1032 }
1033 if (local_segs[i].length <= 0) {
1034 if (i == 0) {
1035 if (is_composite(symbol->symbology)
1036 && ((symbol->input_mode & 0x07) == GS1_MODE || check_force_gs1(symbol->symbology))) {
1037 errtxt(0, symbol, 779, "No composite data (2D component)");
1038 } else if (supports_eci(symbol->symbology)) {
1039 errtxt(0, symbol, 228, "No input data (segment 0 empty)");
1040 } else {
1041 errtxt(0, symbol, 778, "No input data");
1042 }
1043 } else {
1044 errtxtf(0, symbol, 773, "Input segment %d empty", i);
1045 }
1046 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL);
1047 }
1048 /* Calculate de-escaped length for check against ZINT_MAX_DATA_LEN */
1049 if (escape_mode) {
1050 int escaped_len = local_segs[i].length;
1051 error_number = escape_char_process(symbol, local_segs[i].source, &escaped_len, NULL /*escaped_string*/);
1052 if (error_number != 0) { /* Only returns errors, not warnings */
1053 return error_tag(error_number, symbol, -1, NULL);
1054 }
1055 if (escaped_len > ZINT_MAX_DATA_LEN) {
1056 return error_tag(ZINT_ERROR_TOO_LONG, symbol, 797, "Input too long");
1057 }
1058 total_len += escaped_len;
1059 } else {
1060 if (local_segs[i].length > ZINT_MAX_DATA_LEN) {
1061 return error_tag(ZINT_ERROR_TOO_LONG, symbol, 777, "Input too long");
1062 }
1063 total_len += local_segs[i].length;
1064 }
1065 }
1066
1067 if (total_len == 0) {
1068 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 205, "No input data");
1069 }
1070
1071 if (symbol->debug & ZINT_DEBUG_PRINT) {
1072 const int len = local_segs[0].length;
1073 const int primary_len = symbol->primary[0] ? (int) strlen(symbol->primary) : 0;
1074 char name[32];
1075 char source[151], primary[151]; /* 30*5 + 1 = 151 */
1076 (void) ZBarcode_BarcodeName(symbol->symbology, name);
1077 debug_print_escape(local_segs[0].source, len > 30 ? 30 : len, source);
1078 debug_print_escape((const unsigned char *) symbol->primary, primary_len > 30 ? 30 : primary_len, primary);
1079 printf("\nZBarcode_Encode_Segs: %s (%d), input_mode: 0x%X, ECI: %d, option_1/2/3: (%d, %d, %d)\n"
1080 " scale: %g, output_options: 0x%X, fg: %s, bg: %s, seg_count: %d,\n"
1081 " %ssource%s (%d): \"%s\",\n"
1082 " %sprimary (%d): \"%s\"\n",
1083 name, symbol->symbology, symbol->input_mode, symbol->eci, symbol->option_1, symbol->option_2,
1084 symbol->option_3, symbol->scale, symbol->output_options, symbol->fgcolour, symbol->bgcolour,
1085 seg_count, len > 30 ? "first 30 " : "", seg_count > 1 ? "[0]" : "", len, source,
1086 primary_len > 30 ? "first 30 " : "", primary_len, primary);
1087 fflush(stdout);
1088 }
1089
1090 if (total_len > ZINT_MAX_DATA_LEN) {
1091 return error_tag(ZINT_ERROR_TOO_LONG, symbol, 243, "Input too long");
1092 }
1093
1094 /* Reconcile symbol ECI and first segment ECI if both set */
1095 if (symbol->eci != local_segs[0].eci) {
1096 if (symbol->eci && local_segs[0].eci) {
1097 errtxtf(0, symbol, 774, "Symbol ECI '%1$d' must match segment zero ECI '%2$d'",
1098 symbol->eci, local_segs[0].eci);
1099 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, -1, NULL);
1100 }
1101 if (symbol->eci) {
1102 local_segs[0].eci = symbol->eci;
1103 } else {
1104 symbol->eci = local_segs[0].eci;
1105 }
1106 }
1107
1108 if (seg_count > 1 && !supports_eci(symbol->symbology)) {
1109 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 775, "Symbology does not support multiple segments");
1110 }
1111
1112 /* Check ECI(s) */
1113 for (i = 0; i < seg_count; i++) {
1114 if (local_segs[i].eci) {
1115 if (!supports_eci(symbol->symbology)) {
1116 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 217, "Symbology does not support ECI switching");
1117 }
1118 if (local_segs[i].eci < 0 || local_segs[i].eci == 1 || local_segs[i].eci == 2 || local_segs[i].eci == 14
1119 || local_segs[i].eci == 19 || local_segs[i].eci > 999999) {
1120 errtxtf(0, symbol, 218, "ECI code '%d' out of range (0 to 999999, excluding 1, 2, 14 and 19)",
1121 local_segs[i].eci);
1122 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, -1, NULL);
1123 }
1124 } else {
1125 have_zero_eci = 1;
1126 }
1127 }
1128
1129 /* Check other symbol fields */
1130 if ((symbol->scale < 0.01f) || (symbol->scale > 200.0f)) {
1131 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 227, "Scale out of range (0.01 to 200)");
1132 }
1133 if ((symbol->dot_size < 0.01f) || (symbol->dot_size > 20.0f)) {
1134 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 221, "Dot size out of range (0.01 to 20)");
1135 }
1136
1137 if ((symbol->height < 0.0f) || (symbol->height > 2000.0f)) { /* Allow for 44 row CODABLOCKF at 45X each */
1138 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 765, "Height out of range (0 to 2000)");
1139 }
1140 if ((symbol->guard_descent < 0.0f) || (symbol->guard_descent > 50.0f)) {
1141 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 769, "Guard bar descent out of range (0 to 50)");
1142 }
1143 if ((symbol->text_gap < -5.0f) || (symbol->text_gap > 10.0f)) {
1144 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 219, "Text gap out of range (-5 to 10)");
1145 }
1146 if ((symbol->whitespace_width < 0) || (symbol->whitespace_width > 100)) {
1147 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 766, "Whitespace width out of range (0 to 100)");
1148 }
1149 if ((symbol->whitespace_height < 0) || (symbol->whitespace_height > 100)) {
1150 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 767, "Whitespace height out of range (0 to 100)");
1151 }
1152 if ((symbol->border_width < 0) || (symbol->border_width > 100)) {
1153 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 768, "Border width out of range (0 to 100)");
1154 }
1155
1156 if (symbol->rows >= 200) { /* Check for stacking too many symbols */
1157 return error_tag(ZINT_ERROR_TOO_LONG, symbol, 770, "Too many stacked symbols");
1158 }
1159 if (symbol->rows < 0) { /* Silently defend against out-of-bounds access */
1160 symbol->rows = 0;
1161 }
1162
1163 if ((symbol->input_mode & 0x07) == GS1_MODE && !gs1_compliant(symbol->symbology)) {
1164 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 220, "Selected symbology does not support GS1 mode");
1165 }
1166 if (seg_count > 1) {
1167 /* Note: GS1_MODE not currently supported when using multiple segments */
1168 if ((symbol->input_mode & 0x07) == GS1_MODE) {
1169 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 776, "GS1 mode not supported for multiple segments");
1170 }
1171 }
1172
1173 local_sources = (unsigned char *) z_alloca(total_len + seg_count);
1174
1175 /* Copy input, de-escaping if required */
1176 for (i = 0, local_source = local_sources; i < seg_count; i++) {
1177 local_segs[i].source = local_source;
1178 if (escape_mode) {
1179 /* Checked already */
1180 (void) escape_char_process(symbol, segs[i].source, &local_segs[i].length, local_segs[i].source);
1181 } else {
1182 memcpy(local_segs[i].source, segs[i].source, local_segs[i].length);
1183 local_segs[i].source[local_segs[i].length] = '\0';
1184 }
1185 local_source += local_segs[i].length + 1;
1186 }
1187
1188 if (escape_mode && symbol->primary[0] && strchr(symbol->primary, '\\') != NULL) {
1189 char primary[sizeof(symbol->primary)];
1190 int primary_len = (int) strlen(symbol->primary);
1191 if (primary_len >= (int) sizeof(symbol->primary)) {
1192 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 799, "Invalid primary string");
1193 }
1194 ustrcpy(primary, symbol->primary);
1195 error_number = escape_char_process(symbol, (unsigned char *) primary, &primary_len,
1196 (unsigned char *) symbol->primary);
1197 if (error_number != 0) { /* Only returns errors, not warnings */
1198 return error_tag(error_number, symbol, -1, NULL);
1199 }
1200 }
1201
1202 if ((symbol->input_mode & 0x07) == UNICODE_MODE) {
1203 for (i = 0; i < seg_count; i++) {
1204 if (!is_valid_utf8(local_segs[i].source, local_segs[i].length)) {
1205 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 245, "Invalid UTF-8 in input");
1206 }
1207 }
1208 /* Only strip BOM on first segment */
1209 strip_bom(local_segs[0].source, &local_segs[0].length);
1210 }
1211
1212 if (((symbol->input_mode & 0x07) == GS1_MODE) || (check_force_gs1(symbol->symbology))) {
1213 if (gs1_compliant(symbol->symbology)) {
1214 /* Reduce input for composite and non-forced symbologies, others (EAN128 and RSS_EXP based) will
1215 handle it themselves */
1216 if (is_composite(symbol->symbology) || !check_force_gs1(symbol->symbology)) {
1217 unsigned char *reduced = (unsigned char *) z_alloca(local_segs[0].length + 1);
1218 error_number = gs1_verify(symbol, local_segs[0].source, local_segs[0].length, reduced);
1219 if (error_number) {
1220 if (is_composite(symbol->symbology)) {
1221 errtxt_adj(0, symbol, "%1$s%2$s", " (2D component)");
1222 }
1223 error_number = error_tag(error_number, symbol, -1, NULL);
1224 if (error_number >= ZINT_ERROR) {
1225 return error_number;
1226 }
1227 warn_number = error_number; /* Override any previous warning (errtxt has been overwritten) */
1228 }
1229 ustrcpy(local_segs[0].source, reduced); /* Cannot contain NUL char */
1230 local_segs[0].length = (int) ustrlen(reduced);
1231 }
1232 } else {
1233 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 210, "Selected symbology does not support GS1 mode");
1234 }
1235 }
1236
1237 error_number = extended_or_reduced_charset(symbol, local_segs, seg_count);
1238
1239 if ((error_number == ZINT_ERROR_INVALID_DATA) && have_zero_eci && supports_eci(symbol->symbology)
1240 && (symbol->input_mode & 0x07) == UNICODE_MODE) {
1241 /* Try another ECI mode */
1242 const int first_eci_set = get_best_eci_segs(symbol, local_segs, seg_count);
1243 error_number = extended_or_reduced_charset(symbol, local_segs, seg_count);
1244 /* Inclusion of ECI more noteworthy than other warnings, so overwrite (if any) */
1245 if (error_number < ZINT_ERROR) {
1246 error_number = ZINT_WARN_USES_ECI;
1247 if (!(symbol->debug & ZINT_DEBUG_TEST)) {
1248 errtxtf(0, symbol, 222, "Encoded data includes ECI %d", first_eci_set);
1249 }
1250 if (symbol->debug & ZINT_DEBUG_PRINT) printf("Added ECI %d\n", first_eci_set);
1251 }
1252 }
1253
1254 if (error_number == 0) {
1255 error_number = warn_number; /* Already tagged */
1256 } else {
1257 error_number = error_tag(error_number, symbol, -1, NULL);
1258 }
1259
1260 if (error_number < ZINT_ERROR) {
1261 if (symbol->height < 0.5f) { /* Absolute minimum */
1262 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/);
1263 }
1264 }
1265
1266 return error_number;
1267 }
1268
1269 /* Helper for output routines to check `rotate_angle` and dottiness */
1270 static int check_output_args(struct zint_symbol *symbol, int rotate_angle) {
1271
1272 if (!symbol) return ZINT_ERROR_INVALID_DATA;
1273
1274 switch (rotate_angle) {
1275 case 0:
1276 case 90:
1277 case 180:
1278 case 270:
1279 break;
1280 default:
1281 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 223, "Invalid rotation angle");
1282 break;
1283 }
1284
1285 if ((symbol->output_options & BARCODE_DOTTY_MODE) && !(is_dotty(symbol->symbology))) {
1286 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 224, "Selected symbology cannot be rendered as dots");
1287 }
1288
1289 return 0;
1290 }
1291
1292 static const struct { const char extension[4]; int is_raster; int filetype; } filetypes[] = {
1293 { "BMP", 1, OUT_BMP_FILE }, { "EMF", 0, OUT_EMF_FILE }, { "EPS", 0, OUT_EPS_FILE },
1294 { "GIF", 1, OUT_GIF_FILE }, { "PCX", 1, OUT_PCX_FILE }, { "PNG", 1, OUT_PNG_FILE },
1295 { "SVG", 0, OUT_SVG_FILE }, { "TIF", 1, OUT_TIF_FILE }, { "TXT", 0, 0 }
1296 };
1297
1298 /* Return index of `extension` in `filetypes`, or -1 if not found */
1299 static int filetype_idx(const char *extension) {
1300 char uc_extension[4] = {0};
1301 int i;
1302
1303 if (strlen(extension) != 3) {
1304 return -1;
1305 }
1306 memcpy(uc_extension, extension, 3);
1307 to_upper((unsigned char *) uc_extension, 3);
1308
1309 for (i = 0; i < ARRAY_SIZE(filetypes); i++) {
1310 if (strcmp(uc_extension, filetypes[i].extension) == 0) {
1311 break;
1312 }
1313 }
1314
1315 return i == ARRAY_SIZE(filetypes) ? -1 : i;
1316 }
1317
1318 /* Output a previously encoded symbol to file `symbol->outfile` */
1319 int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) {
1320 int error_number;
1321 int len;
1322
1323 if ((error_number = check_output_args(symbol, rotate_angle))) { /* >= ZINT_ERROR only */
1324 return error_number; /* Already tagged */
1325 }
1326
1327 len = (int) strlen(symbol->outfile);
1328 if (len > 3) {
1329 int i = filetype_idx(symbol->outfile + len - 3);
1330 if (i >= 0) {
1331 if (filetypes[i].filetype) {
1332 if (filetypes[i].is_raster) {
1333 error_number = plot_raster(symbol, rotate_angle, filetypes[i].filetype);
1334 } else {
1335 error_number = plot_vector(symbol, rotate_angle, filetypes[i].filetype);
1336 }
1337 } else {
1338 error_number = dump_plot(symbol);
1339 }
1340 } else {
1341 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 225, "Unknown output format");
1342 }
1343 } else {
1344 return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 226, "Unknown output format");
1345 }
1346
1347 return error_tag(error_number, symbol, -1, NULL);
1348 }
1349
1350 /* Output a previously encoded symbol to memory as raster (`symbol->bitmap`) */
1351 int ZBarcode_Buffer(struct zint_symbol *symbol, int rotate_angle) {
1352 int error_number;
1353
1354 if ((error_number = check_output_args(symbol, rotate_angle))) { /* >= ZINT_ERROR only */
1355 return error_number; /* Already tagged */
1356 }
1357
1358 error_number = plot_raster(symbol, rotate_angle, OUT_BUFFER);
1359 return error_tag(error_number, symbol, -1, NULL);
1360 }
1361
1362 /* Output a previously encoded symbol to memory as vector (`symbol->vector`) */
1363 int ZBarcode_Buffer_Vector(struct zint_symbol *symbol, int rotate_angle) {
1364 int error_number;
1365
1366 if ((error_number = check_output_args(symbol, rotate_angle))) { /* >= ZINT_ERROR only */
1367 return error_number; /* Already tagged */
1368 }
1369
1370 error_number = plot_vector(symbol, rotate_angle, OUT_BUFFER);
1371 return error_tag(error_number, symbol, -1, NULL);
1372 }
1373
1374 /* Encode and output a symbol to file `symbol->outfile` */
1375 int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, const unsigned char *source, int length, int rotate_angle) {
1376 struct zint_seg segs[1];
1377
1378 if (!symbol) return ZINT_ERROR_INVALID_DATA;
1379
1380 segs[0].eci = symbol->eci;
1381 segs[0].source = (unsigned char *) source;
1382 segs[0].length = length;
1383
1384 return ZBarcode_Encode_Segs_and_Print(symbol, segs, 1, rotate_angle);
1385 }
1386
1387 /* Encode a symbol with multiple ECI segments and output to file `symbol->outfile` */
1388 int ZBarcode_Encode_Segs_and_Print(struct zint_symbol *symbol, const struct zint_seg segs[], const int seg_count,
1389 int rotate_angle) {
1390 int error_number;
1391 int warn_number;
1392
1393 warn_number = ZBarcode_Encode_Segs(symbol, segs, seg_count);
1394 if (warn_number >= ZINT_ERROR) {
1395 return warn_number;
1396 }
1397
1398 error_number = ZBarcode_Print(symbol, rotate_angle);
1399
1400 return error_number ? error_number : warn_number;
1401 }
1402
1403 /* Encode and output a symbol to memory as raster (`symbol->bitmap`) */
1404 int ZBarcode_Encode_and_Buffer(struct zint_symbol *symbol, const unsigned char *source, int length,
1405 int rotate_angle) {
1406 struct zint_seg segs[1];
1407
1408 if (!symbol) return ZINT_ERROR_INVALID_DATA;
1409
1410 segs[0].eci = symbol->eci;
1411 segs[0].source = (unsigned char *) source;
1412 segs[0].length = length;
1413
1414 return ZBarcode_Encode_Segs_and_Buffer(symbol, segs, 1, rotate_angle);
1415 }
1416
1417 /* Encode a symbol with multiple ECI segments and output to memory as raster (`symbol->bitmap`) */
1418 int ZBarcode_Encode_Segs_and_Buffer(struct zint_symbol *symbol, const struct zint_seg segs[],
1419 const int seg_count, int rotate_angle) {
1420 int error_number;
1421 int warn_number;
1422
1423 warn_number = ZBarcode_Encode_Segs(symbol, segs, seg_count);
1424 if (warn_number >= ZINT_ERROR) {
1425 return warn_number;
1426 }
1427
1428 error_number = ZBarcode_Buffer(symbol, rotate_angle);
1429
1430 return error_number ? error_number : warn_number;
1431 }
1432
1433 /* Encode and output a symbol to memory as vector (`symbol->vector`) */
1434 int ZBarcode_Encode_and_Buffer_Vector(struct zint_symbol *symbol, const unsigned char *source, int length,
1435 int rotate_angle) {
1436 struct zint_seg segs[1];
1437
1438 if (!symbol) return ZINT_ERROR_INVALID_DATA;
1439
1440 segs[0].eci = symbol->eci;
1441 segs[0].source = (unsigned char *) source;
1442 segs[0].length = length;
1443
1444 return ZBarcode_Encode_Segs_and_Buffer_Vector(symbol, segs, 1, rotate_angle);
1445 }
1446
1447 /* Encode a symbol with multiple ECI segments and output to memory as vector (`symbol->vector`) */
1448 int ZBarcode_Encode_Segs_and_Buffer_Vector(struct zint_symbol *symbol, const struct zint_seg segs[],
1449 const int seg_count, int rotate_angle) {
1450 int error_number;
1451 int warn_number;
1452
1453 warn_number = ZBarcode_Encode_Segs(symbol, segs, seg_count);
1454 if (warn_number >= ZINT_ERROR) {
1455 return warn_number;
1456 }
1457
1458 error_number = ZBarcode_Buffer_Vector(symbol, rotate_angle);
1459
1460 return error_number ? error_number : warn_number;
1461 }
1462
1463 /* Encode a barcode using input data from file `filename` */
1464 int ZBarcode_Encode_File(struct zint_symbol *symbol, const char *filename) {
1465 FILE *file;
1466 int file_opened = 0;
1467 unsigned char *buffer;
1468 long fileLen;
1469 size_t n;
1470 size_t nRead = 0;
1471 int ret;
1472
1473 if (!symbol) return ZINT_ERROR_INVALID_DATA;
1474
1475 if (!filename) {
1476 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 239, "Filename NULL");
1477 }
1478
1479 if (strcmp(filename, "-") == 0) {
1480 file = stdin;
1481 fileLen = ZINT_MAX_DATA_LEN;
1482 } else {
1483 #ifdef _WIN32
1484 file = out_win_fopen(filename, "rb");
1485 #else
1486 file = fopen(filename, "rb");
1487 #endif
1488 if (!file) {
1489 errtxtf(0, symbol, 229, "Unable to read input file (%1$d: %2$s)", errno, strerror(errno));
1490 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL);
1491 }
1492 file_opened = 1;
1493
1494 /* Get file length */
1495 if (fseek(file, 0, SEEK_END) != 0) {
1496 errtxtf(0, symbol, 797, "Unable to seek input file (%1$d: %2$s)", errno, strerror(errno));
1497 (void) fclose(file);
1498 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL);
1499 }
1500
1501 fileLen = ftell(file);
1502
1503 /* On many Linux distros `ftell()` returns LONG_MAX not -1 on error */
1504 if (fileLen <= 0 || fileLen == LONG_MAX) {
1505 (void) fclose(file);
1506 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 235, "Input file empty or unseekable");
1507 }
1508 if (fileLen > ZINT_MAX_DATA_LEN) {
1509 (void) fclose(file);
1510 return error_tag(ZINT_ERROR_TOO_LONG, symbol, 230, "Input file too long");
1511 }
1512
1513 if (fseek(file, 0, SEEK_SET) != 0) {
1514 errtxtf(0, symbol, 793, "Unable to seek input file (%1$d: %2$s)", errno, strerror(errno));
1515 (void) fclose(file);
1516 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL);
1517 }
1518 }
1519
1520 /* Allocate memory */
1521 buffer = (unsigned char *) malloc(fileLen);
1522 if (!buffer) {
1523 if (file_opened) {
1524 (void) fclose(file);
1525 }
1526 return error_tag(ZINT_ERROR_MEMORY, symbol, 231, "Insufficient memory for file read buffer");
1527 }
1528
1529 /* Read file contents into buffer */
1530
1531 do {
1532 n = fread(buffer + nRead, 1, fileLen - nRead, file);
1533 if (ferror(file)) {
1534 errtxtf(0, symbol, 241, "Input file read error (%1$d: %2$s)", errno, strerror(errno));
1535 free(buffer);
1536 if (file_opened) {
1537 (void) fclose(file);
1538 }
1539 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL);
1540 }
1541 nRead += n;
1542 } while (!feof(file) && (0 < n) && ((long) nRead < fileLen));
1543
1544 if (file_opened) {
1545 if (fclose(file) != 0) {
1546 errtxtf(0, symbol, 794, "Failure on closing input file (%1$d: %2$s)", errno, strerror(errno));
1547 free(buffer);
1548 return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL);
1549 }
1550 }
1551 ret = ZBarcode_Encode(symbol, buffer, (int) nRead);
1552 free(buffer);
1553 return ret;
1554 }
1555
1556 /* Encode a symbol using input data from file `filename` and output to file `symbol->outfile` */
1557 int ZBarcode_Encode_File_and_Print(struct zint_symbol *symbol, const char *filename, int rotate_angle) {
1558 int error_number;
1559 int warn_number;
1560
1561 warn_number = ZBarcode_Encode_File(symbol, filename);
1562 if (warn_number >= ZINT_ERROR) {
1563 return warn_number;
1564 }
1565
1566 error_number = ZBarcode_Print(symbol, rotate_angle);
1567
1568 return error_number ? error_number : warn_number;
1569 }
1570
1571 /* Encode a symbol using input data from file `filename` and output to memory as raster (`symbol->bitmap`) */
1572 int ZBarcode_Encode_File_and_Buffer(struct zint_symbol *symbol, char const *filename, int rotate_angle) {
1573 int error_number;
1574 int warn_number;
1575
1576 warn_number = ZBarcode_Encode_File(symbol, filename);
1577 if (warn_number >= ZINT_ERROR) {
1578 return warn_number;
1579 }
1580
1581 error_number = ZBarcode_Buffer(symbol, rotate_angle);
1582
1583 return error_number ? error_number : warn_number;
1584 }
1585
1586 /* Encode a symbol using input data from file `filename` and output to memory as vector (`symbol->vector`) */
1587 int ZBarcode_Encode_File_and_Buffer_Vector(struct zint_symbol *symbol, const char *filename, int rotate_angle) {
1588 int error_number;
1589 int warn_number;
1590
1591 warn_number = ZBarcode_Encode_File(symbol, filename);
1592 if (warn_number >= ZINT_ERROR) {
1593 return warn_number;
1594 }
1595
1596 error_number = ZBarcode_Buffer_Vector(symbol, rotate_angle);
1597
1598 return error_number ? error_number : warn_number;
1599 }
1600
1601 /* Checks whether a symbology is supported */
1602 int ZBarcode_ValidID(int symbol_id) {
1603
1604 if (symbol_id <= 0 || symbol_id > BARCODE_LAST) {
1605 return 0;
1606 }
1607
1608 return barcode_src_funcs[symbol_id] != NULL
1609 || (symbol_id >= LIB_SEG_FUNCS_START && barcode_seg_funcs[symbol_id - LIB_SEG_FUNCS_START] != NULL);
1610 }
1611
1612 /* Copy BARCODE_XXX name of `symbol_id` into `name` buffer, NUL-terminated.
1613 Returns 0 if valid, 1 if not valid */
1614 int ZBarcode_BarcodeName(int symbol_id, char name[32]) {
1615 static const char *const names[] = {
1616 "", "CODE11", "C25STANDARD", "C25INTER", "C25IATA", /*0-4*/
1617 "", "C25LOGIC", "C25IND", "CODE39", "EXCODE39", /*5-9*/
1618 "", "", "", "EANX", "EANX_CHK", /*10-14*/
1619 "", "GS1_128", "", "CODABAR", "", /*15-19*/
1620 "CODE128", "DPLEIT", "DPIDENT", "CODE16K", "CODE49", /*20-24*/
1621 "CODE93", "", "", "FLAT", "DBAR_OMN", /*25-29*/
1622 "DBAR_LTD", "DBAR_EXP", "TELEPEN", "", "UPCA", /*30-34*/
1623 "UPCA_CHK", "", "UPCE", "UPCE_CHK", "", /*35-39*/
1624 "POSTNET", "", "", "", "", /*40-44*/
1625 "", "", "MSI_PLESSEY", "", "FIM", /*45-49*/
1626 "LOGMARS", "PHARMA", "PZN", "PHARMA_TWO", "CEPNET", /*50-54*/
1627 "PDF417", "PDF417COMP", "MAXICODE", "QRCODE", "", /*55-59*/
1628 "CODE128AB", "", "", "AUSPOST", "", /*60-64*/
1629 "", "AUSREPLY", "AUSROUTE", "AUSREDIRECT", "ISBNX", /*65-69*/
1630 "RM4SCC", "DATAMATRIX", "EAN14", "VIN", "CODABLOCKF", /*70-74*/
1631 "NVE18", "JAPANPOST", "KOREAPOST", "", "DBAR_STK", /*75-79*/
1632 "DBAR_OMNSTK", "DBAR_EXPSTK", "PLANET", "", "MICROPDF417", /*80-84*/
1633 "USPS_IMAIL", "PLESSEY", "TELEPEN_NUM", "", "ITF14", /*85-89*/
1634 "KIX", "", "AZTEC", "DAFT", "", /*90-94*/
1635 "", "DPD", "MICROQR", "HIBC_128", "HIBC_39", /*95-99*/
1636 "", "", "HIBC_DM", "", "HIBC_QR", /*100-104*/
1637 "", "HIBC_PDF", "", "HIBC_MICPDF", "", /*105-109*/
1638 "HIBC_BLOCKF", "", "HIBC_AZTEC", "", "", /*110-114*/
1639 "DOTCODE", "HANXIN", "", "", "MAILMARK_2D", /*115-119*/
1640 "UPU_S10", "MAILMARK_4S", "", "", "", /*120-124*/
1641 "", "", "", "AZRUNE", "CODE32", /*125-129*/
1642 "EANX_CC", "GS1_128_CC", "DBAR_OMN_CC", "DBAR_LTD_CC", "DBAR_EXP_CC", /*130-134*/
1643 "UPCA_CC", "UPCE_CC", "DBAR_STK_CC", "DBAR_OMNSTK_CC", "DBAR_EXPSTK_CC", /*135-139*/
1644 "CHANNEL", "CODEONE", "GRIDMATRIX", "UPNQR", "ULTRA", /*140-144*/
1645 "RMQR", "BC412", "DXFILMEDGE", /*145-147*/
1646 };
1647
1648 name[0] = '\0';
1649
1650 if (!ZBarcode_ValidID(symbol_id)) {
1651 return 1;
1652 }
1653 assert(symbol_id >= 0 && symbol_id < ARRAY_SIZE(names) && names[symbol_id][0]);
1654
1655 memcpy(name, "BARCODE_", 8);
1656 strcpy(name + 8, names[symbol_id]);
1657
1658 return 0;
1659 }
1660
1661 /* Return the capability flags for symbology `symbol_id` that match `cap_flag` */
1662 unsigned int ZBarcode_Cap(int symbol_id, unsigned int cap_flag) {
1663 unsigned int result = 0;
1664
1665 if (!ZBarcode_ValidID(symbol_id)) {
1666 return 0;
1667 }
1668
1669 if ((cap_flag & ZINT_CAP_HRT) && has_hrt(symbol_id)) {
1670 result |= ZINT_CAP_HRT;
1671 }
1672 if ((cap_flag & ZINT_CAP_STACKABLE) && is_stackable(symbol_id)) {
1673 result |= ZINT_CAP_STACKABLE;
1674 }
1675 if ((cap_flag & ZINT_CAP_EANUPC) && is_upcean(symbol_id)) {
1676 result |= ZINT_CAP_EANUPC;
1677 }
1678 if ((cap_flag & ZINT_CAP_COMPOSITE) && is_composite(symbol_id)) {
1679 result |= ZINT_CAP_COMPOSITE;
1680 }
1681 if ((cap_flag & ZINT_CAP_ECI) && supports_eci(symbol_id)) {
1682 result |= ZINT_CAP_ECI;
1683 }
1684 if ((cap_flag & ZINT_CAP_GS1) && gs1_compliant(symbol_id)) {
1685 result |= ZINT_CAP_GS1;
1686 }
1687 if ((cap_flag & ZINT_CAP_DOTTY) && is_dotty(symbol_id)) {
1688 result |= ZINT_CAP_DOTTY;
1689 }
1690 if (cap_flag & ZINT_CAP_QUIET_ZONES) {
1691 switch (symbol_id) { /* See `out_quiet_zones()` in "output.c" */
1692 case BARCODE_CODE16K:
1693 case BARCODE_CODE49:
1694 case BARCODE_CODABLOCKF:
1695 case BARCODE_HIBC_BLOCKF:
1696 case BARCODE_ITF14:
1697 case BARCODE_EANX:
1698 case BARCODE_EANX_CHK:
1699 case BARCODE_EANX_CC:
1700 case BARCODE_ISBNX:
1701 case BARCODE_UPCA:
1702 case BARCODE_UPCA_CHK:
1703 case BARCODE_UPCA_CC:
1704 case BARCODE_UPCE:
1705 case BARCODE_UPCE_CHK:
1706 case BARCODE_UPCE_CC:
1707 result |= ZINT_CAP_QUIET_ZONES;
1708 break;
1709 }
1710 }
1711 if ((cap_flag & ZINT_CAP_FIXED_RATIO) && is_fixed_ratio(symbol_id)) {
1712 result |= ZINT_CAP_FIXED_RATIO;
1713 }
1714 if (cap_flag & ZINT_CAP_READER_INIT) {
1715 /* Note does not include HIBC versions */
1716 switch (symbol_id) {
1717 case BARCODE_CODE128: /* Note does not include GS1_128 or NVE18 */
1718 case BARCODE_CODE128AB:
1719 case BARCODE_CODE16K:
1720 case BARCODE_CODABLOCKF:
1721 case BARCODE_PDF417:
1722 case BARCODE_PDF417COMP:
1723 case BARCODE_DATAMATRIX:
1724 case BARCODE_MICROPDF417:
1725 case BARCODE_AZTEC:
1726 case BARCODE_DOTCODE:
1727 case BARCODE_GRIDMATRIX:
1728 case BARCODE_ULTRA:
1729 result |= ZINT_CAP_READER_INIT;
1730 break;
1731 }
1732 }
1733 if (cap_flag & ZINT_CAP_FULL_MULTIBYTE) {
1734 switch (symbol_id) {
1735 case BARCODE_QRCODE:
1736 case BARCODE_MICROQR:
1737 /* case BARCODE_HIBC_QR: Note character set restricted to ASCII subset */
1738 /* case BARCODE_UPNQR: Note does not use Kanji mode */
1739 case BARCODE_RMQR:
1740 case BARCODE_HANXIN:
1741 case BARCODE_GRIDMATRIX:
1742 result |= ZINT_CAP_FULL_MULTIBYTE;
1743 break;
1744 }
1745 }
1746 if (cap_flag & ZINT_CAP_MASK) {
1747 switch (symbol_id) {
1748 case BARCODE_QRCODE:
1749 case BARCODE_MICROQR:
1750 case BARCODE_UPNQR:
1751 case BARCODE_HANXIN:
1752 case BARCODE_DOTCODE:
1753 result |= ZINT_CAP_MASK;
1754 break;
1755 }
1756 }
1757 if (cap_flag & ZINT_CAP_STRUCTAPP) {
1758 switch (symbol_id) {
1759 case BARCODE_PDF417:
1760 case BARCODE_PDF417COMP:
1761 case BARCODE_MAXICODE:
1762 case BARCODE_QRCODE: /* Note does not include MICROQR, UPNQR or rMQR */
1763 case BARCODE_DATAMATRIX:
1764 case BARCODE_MICROPDF417:
1765 case BARCODE_AZTEC:
1766 case BARCODE_HIBC_DM:
1767 case BARCODE_HIBC_QR:
1768 case BARCODE_HIBC_PDF:
1769 case BARCODE_HIBC_MICPDF:
1770 case BARCODE_HIBC_AZTEC:
1771 case BARCODE_DOTCODE:
1772 case BARCODE_CODEONE:
1773 case BARCODE_GRIDMATRIX:
1774 case BARCODE_ULTRA:
1775 result |= ZINT_CAP_STRUCTAPP;
1776 break;
1777 }
1778 }
1779 if ((cap_flag & ZINT_CAP_COMPLIANT_HEIGHT) && !is_fixed_ratio(symbol_id)) {
1780 switch (symbol_id) {
1781 /* These don't have a compliant height defined */
1782 case BARCODE_CODE11: /* TODO: Find doc */
1783 case BARCODE_C25STANDARD: /* For C25 only have doc for C25INTER */
1784 case BARCODE_C25IATA:
1785 case BARCODE_C25LOGIC:
1786 case BARCODE_C25IND:
1787 case BARCODE_CODE128: /* Left to application */
1788 case BARCODE_CODE128AB:
1789 case BARCODE_DPLEIT: /* TODO: Find doc */
1790 case BARCODE_DPIDENT: /* TODO: Find doc */
1791 case BARCODE_FLAT: /* TODO: Find doc */
1792 case BARCODE_MSI_PLESSEY: /* TODO: Find doc */
1793 case BARCODE_PDF417: /* Has compliant height but already warns & uses for default */
1794 case BARCODE_PDF417COMP:
1795 case BARCODE_VIN: /* Spec unlikely */
1796 case BARCODE_KOREAPOST: /* TODO: Find doc */
1797 case BARCODE_MICROPDF417: /* See PDF417 */
1798 case BARCODE_PLESSEY: /* TODO: Find doc */
1799 case BARCODE_DAFT: /* Generic */
1800 case BARCODE_HIBC_128: /* See CODE128 */
1801 case BARCODE_HIBC_PDF: /* See PDF417 */
1802 case BARCODE_HIBC_MICPDF: /* See PDF417 */
1803 break;
1804 default:
1805 result |= ZINT_CAP_COMPLIANT_HEIGHT;
1806 break;
1807 }
1808 }
1809
1810 return result;
1811 }
1812
1813 /* Return default X-dimension in mm for symbology `symbol_id`. Returns 0 on error (invalid `symbol_id`) */
1814 float ZBarcode_Default_Xdim(int symbol_id) {
1815 float x_dim_mm;
1816
1817 if (!ZBarcode_ValidID(symbol_id)) {
1818 return 0.0f;
1819 }
1820 switch (symbol_id) {
1821 /* Postal 2/4-track */
1822 case BARCODE_AUSPOST:
1823 case BARCODE_AUSREPLY:
1824 case BARCODE_AUSROUTE:
1825 case BARCODE_AUSREDIRECT:
1826 /* Australia Post Customer Barcoding Technical Specifications, average of 0.4 to 0.6 mm */
1827 x_dim_mm = 0.5f;
1828 break;
1829 case BARCODE_CEPNET:
1830 case BARCODE_POSTNET:
1831 case BARCODE_PLANET:
1832 case BARCODE_USPS_IMAIL:
1833 /* USPS-B-3200 Section 2.3.1, height 0.145" (average of 0.125, 0.165) / 6.235 (Zint height), same as
1834 USPS DMM 300 Section 708.4.2.5 using bar pitch (1" / 43) ~ 0.023" */
1835 x_dim_mm = 0.591f;
1836 break;
1837 case BARCODE_RM4SCC:
1838 case BARCODE_KIX:
1839 case BARCODE_MAILMARK_4S:
1840 /* Royal Mail Mailmark Barcode Definition Document, height 5.1mm / 8 (Zint height) == 0.6375 */
1841 x_dim_mm = 0.638f; /* Seems better fit to round up to 3 d.p. */
1842 break;
1843 case BARCODE_JAPANPOST:
1844 x_dim_mm = 0.6f; /* Japan Post Zip/Barcode Manual */
1845 break;
1846
1847 /* GS1 (excluding GS1-128, ITF-14, GS1 QRCODE & GS1 DATAMATRIX - see default) */
1848 case BARCODE_EANX:
1849 case BARCODE_EANX_CHK:
1850 case BARCODE_EANX_CC:
1851 case BARCODE_ISBNX:
1852 case BARCODE_UPCA:
1853 case BARCODE_UPCA_CHK:
1854 case BARCODE_UPCA_CC:
1855 case BARCODE_UPCE:
1856 case BARCODE_UPCE_CHK:
1857 case BARCODE_UPCE_CC:
1858 case BARCODE_DBAR_OMN:
1859 case BARCODE_DBAR_OMN_CC:
1860 case BARCODE_DBAR_LTD:
1861 case BARCODE_DBAR_LTD_CC:
1862 case BARCODE_DBAR_EXP:
1863 case BARCODE_DBAR_EXP_CC:
1864 case BARCODE_DBAR_STK:
1865 case BARCODE_DBAR_STK_CC:
1866 case BARCODE_DBAR_OMNSTK:
1867 case BARCODE_DBAR_OMNSTK_CC:
1868 case BARCODE_DBAR_EXPSTK:
1869 case BARCODE_DBAR_EXPSTK_CC:
1870 x_dim_mm = 0.33f; /* GS1 General Standards 22.0 Section 5.12.3 Table 1 except DBAR_LTD Table 4 */
1871 break;
1872 case BARCODE_DXFILMEDGE:
1873 /* Measured on Kodak 35mm film, a DX Film Edge with frame number with 31 symbols is 12,51 mm long */
1874 x_dim_mm = 0.403548f;
1875 break;
1876 /* Specific */
1877 case BARCODE_BC412:
1878 x_dim_mm = 0.12f; /* SEMI T1-95 Table 1 */
1879 break;
1880 case BARCODE_CODABAR:
1881 x_dim_mm = 0.38f; /* EN 798:1996 Appendix D.1 (d), average of 0.33 to 0.43 mm */
1882 break;
1883 case BARCODE_CODE32:
1884 x_dim_mm = 0.25f; /* Allegato A Caratteristiche tecniche del bollino farmaceutico, 0.25mm */
1885 break;
1886 case BARCODE_DPD:
1887 x_dim_mm = 0.375f; /* DPD Parcel Label Specification Version 2.4.1 (19.01.2021) Section 4.6.1.2 */
1888 break;
1889 case BARCODE_FIM:
1890 /* USPS DMM 300 Section 708.9.3, 0.03125" */
1891 x_dim_mm = 0.79375f;
1892 break;
1893 case BARCODE_LOGMARS:
1894 x_dim_mm = 0.34925f; /* MIL-STD-1189 Rev. B Section 5.2, average of 0.0075" and 0.02" */
1895 break;
1896 case BARCODE_MAILMARK_2D:
1897 /* Royal Mail Mailmark Barcode Definition Document, Section 2.4 */
1898 x_dim_mm = 0.5f;
1899 break;
1900 case BARCODE_MAXICODE:
1901 /* ISO/IEC 16023:2000 Table 7, based on L = 25.5mm */
1902 x_dim_mm = 0.88f;
1903 break;
1904 case BARCODE_PHARMA:
1905 x_dim_mm = 0.5f; /* Laetus Pharmacode Guide Section 1.2, standard 0.5mm */
1906 break;
1907 case BARCODE_PHARMA_TWO:
1908 x_dim_mm = 1.0f; /* Laetus Pharmacode Guide Section 1.4, standard 1mm */
1909 break;
1910 case BARCODE_PZN:
1911 x_dim_mm = 0.25f; /* Technical Information regarding PZN, "normal" X 0.25mm */
1912 break;
1913 case BARCODE_TELEPEN:
1914 case BARCODE_TELEPEN_NUM:
1915 /* Telepen Barcode Symbology information and History, average of between 0.010" and 0.0125" */
1916 x_dim_mm = 0.28575f;
1917 break;
1918 case BARCODE_UPU_S10:
1919 x_dim_mm = 0.42f; /* Universal Postal Union S10 Section 8, average of 0.33mm & 0.51mm */
1920 break;
1921
1922 /* Stacked (excluding GS1 DataBar) */
1923 case BARCODE_CODE16K: /* Application-defined */
1924 case BARCODE_CODE49: /* ANSI/AIM BC6-2000 Appendix D.2.4, C grade if > 0.25mm */
1925 case BARCODE_CODABLOCKF: /* Application-defined */
1926 case BARCODE_HIBC_BLOCKF:
1927 case BARCODE_PDF417: /* Maybe 0.27mm following ISO/IEC 15438:2015 Annex S.2.2 example? */
1928 case BARCODE_PDF417COMP:
1929 case BARCODE_HIBC_PDF:
1930 case BARCODE_MICROPDF417:
1931 case BARCODE_HIBC_MICPDF:
1932 /* Fairly arbitrarily using ISO/IEC 15416:2016 Section 5.3.1 Table 1, aperature diameters 0.125 & 0.250
1933 (also fits in 0.25 <= X < 0.5 range for aperature 0.2 from ISO/IEC 15415:2011 Annex D Table D.1) */
1934 x_dim_mm = 0.33f;
1935 break;
1936
1937 /* Application defined (and hence pretty arbitrary) */
1938 default:
1939 if (is_fixed_ratio(symbol_id)) {
1940 /* GS1 General Standards 22.0 Section 5.12.3 Table 1 (general retail) */
1941 x_dim_mm = 0.625f;
1942 } else {
1943 /* GS1 General Standards 22.0 Section 5.12.3.4 GS1-128 Tables 2, 4, 5, 6, 8 */
1944 x_dim_mm = 0.495f;
1945 }
1946 break;
1947 }
1948
1949 return x_dim_mm;
1950 }
1951
1952 /* Return the scale to use for `symbol_id` for non-zero X-dimension `x_dim_mm` at `dpmm` dots per mm for
1953 `filetype`. If `dpmm` zero defaults to 12. If `filetype` NULL/empty, defaults to "GIF". Returns 0 on error */
1954 float ZBarcode_Scale_From_XdimDp(int symbol_id, float x_dim_mm, float dpmm, const char *filetype) {
1955 int i;
1956 float scale;
1957
1958 if (!ZBarcode_ValidID(symbol_id)) {
1959 return 0.0f;
1960 }
1961 if (x_dim_mm <= 0.0f || x_dim_mm > 10.0f) { /* 10mm == 0.39" */
1962 return 0.0f;
1963 }
1964 if (dpmm == 0.0f) {
1965 dpmm = 12.0f; /* ~300 dpi */
1966 } else if (dpmm < 0.0f || dpmm > 1000.0f) { /* 1000 dpmm == 25400 dpi */
1967 return 0.0f;
1968 }
1969 if (filetype && *filetype) {
1970 if ((i = filetype_idx(filetype)) < 0 || filetypes[i].filetype == 0) { /* Not found or TXT */
1971 return 0.0f;
1972 }
1973 } else {
1974 i = filetype_idx("GIF"); /* Default to raster */
1975 }
1976
1977 scale = stripf(stripf(x_dim_mm) * stripf(dpmm));
1978
1979 if (symbol_id == BARCODE_MAXICODE) {
1980 if (filetypes[i].is_raster) {
1981 scale /= 10.0f;
1982 } else if (filetypes[i].filetype == OUT_EMF_FILE) {
1983 scale /= 40.0f;
1984 } else {
1985 scale /= 2.0f;
1986 }
1987 } else {
1988 if (filetypes[i].is_raster) {
1989 scale = roundf(scale) / 2.0f; /* Half-integer increments */
1990 } else {
1991 scale /= 2.0f;
1992 }
1993 }
1994 scale = stripf(scale);
1995
1996 if (scale > 200.0f) {
1997 scale = 200.0f;
1998 } else {
1999 if (filetypes[i].is_raster) {
2000 if (symbol_id == BARCODE_MAXICODE) {
2001 if (scale < 0.2f) {
2002 scale = 0.2f;
2003 }
2004 } else if (scale < 0.5f) {
2005 scale = 0.5f; /* Note if dotty mode needs further bounding to 1.0 */
2006 }
2007 } else {
2008 if (scale < 0.1f) {
2009 scale = 0.1f;
2010 }
2011 }
2012 }
2013
2014 return scale;
2015 }
2016
2017 /* Reverse of `ZBarcode_Scale_From_XdimDp()` above to estimate the X-dimension or dpmm given non-zero `scale` and
2018 non-zero `x_dim_mm_or_dpmm`. Return value bound to dpmm max not X-dimension max. Returns 0 on error */
2019 float ZBarcode_XdimDp_From_Scale(int symbol_id, float scale, float xdim_mm_or_dpmm, const char *filetype) {
2020 int i;
2021
2022 if (!ZBarcode_ValidID(symbol_id)) {
2023 return 0.0f;
2024 }
2025 if (scale <= 0.0f || scale > 200.0f) {
2026 return 0.0f;
2027 }
2028 if (xdim_mm_or_dpmm <= 0.0f || xdim_mm_or_dpmm > 1000.0f) { /* 1000 dpmm == 25400 dpi */
2029 return 0.0f;
2030 }
2031 if (filetype && *filetype) {
2032 if ((i = filetype_idx(filetype)) < 0 || filetypes[i].filetype == 0) { /* Not found or TXT */
2033 return 0.0f;
2034 }
2035 } else {
2036 i = filetype_idx("GIF"); /* Default to raster */
2037 }
2038
2039 if (symbol_id == BARCODE_MAXICODE) {
2040 if (filetypes[i].is_raster) {
2041 scale *= 10.0f;
2042 } else if (filetypes[i].filetype == OUT_EMF_FILE) {
2043 scale *= 40.0f;
2044 } else {
2045 scale *= 2.0f;
2046 }
2047 } else {
2048 scale *= 2.0f;
2049 }
2050
2051 xdim_mm_or_dpmm = stripf(stripf(scale) / stripf(xdim_mm_or_dpmm));
2052
2053 if (xdim_mm_or_dpmm > 1000.0f) { /* Note if X-dimension sought needs to be further bound to <= 10 on return */
2054 xdim_mm_or_dpmm = 1000.0f;
2055 }
2056
2057 return xdim_mm_or_dpmm;
2058 }
2059
2060 /* Whether Zint built without PNG support */
2061 int ZBarcode_NoPng(void) {
2062 #ifdef ZINT_NO_PNG
2063 return 1;
2064 #else
2065 return 0;
2066 #endif
2067 }
2068
2069 /* Return the version of Zint linked to */
2070 int ZBarcode_Version(void) {
2071 #if ZINT_VERSION_BUILD
2072 return (ZINT_VERSION_MAJOR * 10000) + (ZINT_VERSION_MINOR * 100) + ZINT_VERSION_RELEASE * 10 + ZINT_VERSION_BUILD;
2073 #else
2074 return (ZINT_VERSION_MAJOR * 10000) + (ZINT_VERSION_MINOR * 100) + ZINT_VERSION_RELEASE;
2075 #endif
2076 }
2077
2078 /* vim: set ts=4 sw=4 et : */