Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/zint/frontend/main.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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/zint/frontend/main.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,2283 @@ +/* main.c - Command line handling routines for Zint */ +/* + libzint - the open source barcode library + Copyright (C) 2008-2024 Robin Stuart <rstuart114@gmail.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if !defined(_MSC_VER) && !defined(__NetBSD__) && !defined(_AIX) +# include <getopt.h> +# include <zint.h> +#else +# include "../getopt/getopt.h" +# ifdef _MSC_VER +# include "zint.h" +# if _MSC_VER > 1200 /* VC6 */ +# pragma warning(disable: 4996) /* function or variable may be unsafe */ +# endif +# else +# include <zint.h> +# endif +#endif + +/* Following copied from "backend/library.c" */ + +/* It's assumed that int is at least 32 bits, the following will compile-time fail if not + * https://stackoverflow.com/a/1980056 */ +typedef char static_assert_int_at_least_32bits[sizeof(int) * CHAR_BIT < 32 ? -1 : 1]; + +/* Following copied from "backend/common.h" */ + +#define ARRAY_SIZE(x) ((int) (sizeof(x) / sizeof((x)[0]))) + +#ifdef _MSC_VER +# include <malloc.h> +# define z_alloca(nmemb) _alloca(nmemb) +#elif defined(__COMPCERT__) +# define z_alloca(nmemb) malloc(nmemb) /* So links - leads to loads of leaks obs */ +#else +# if (defined(__GNUC__) && !defined(alloca) && !defined(__NetBSD__)) || defined(__NuttX__) || defined(_AIX) \ + || (defined(__sun) && defined(__SVR4) /*Solaris*/) +# include <alloca.h> +# endif +# define z_alloca(nmemb) alloca(nmemb) +#endif + +/* Print list of supported symbologies */ +static void types(void) { + /* Breaking up strings so don't get too long (i.e. 500 or so) */ + fputs(" # Name Description # Name Description\n" + " 1 CODE11 Code 11 75 NVE18 NVE-18\n" + " 2 C25STANDARD Standard 2 of 5 76 JAPANPOST Japanese Post\n" + " 3 C25INTER Interleaved 2 of 5 77 KOREAPOST Korea Post\n" + " 4 C25IATA IATA 2 of 5 79 DBAR_STK GS1 DataBar Stacked\n", stdout); + fputs(" 6 C25LOGIC Data Logic 2 of 5 80 DBAR_OMNSTK GS1 DataBar Stack Omni\n" + " 7 C25IND Industrial 2 of 5 81 DBAR_EXPSTK GS1 DataBar Exp Stack\n" + " 8 CODE39 Code 39 82 PLANET USPS PLANET\n" + " 9 EXCODE39 Extended Code 39 84 MICROPDF417 MicroPDF417\n" + "13 EANX EAN-2 to EAN-13 85 USPS_IMAIL USPS Intelligent Mail\n", stdout); + fputs("14 EANX_CHK EAN + Check Digit 86 PLESSEY UK Plessey\n" + "16 GS1_128 GS1-128 87 TELEPEN_NUM Telepen Numeric\n" + "18 CODABAR Codabar 89 ITF14 ITF-14\n" + "20 CODE128 Code 128 90 KIX Dutch Post KIX Code\n" + "21 DPLEIT Deutsche Post Leitcode 92 AZTEC Aztec Code\n", stdout); + fputs("22 DPIDENT Deutsche Post Identcode 93 DAFT DAFT Code\n" + "23 CODE16K Code 16K 96 DPD DPD Parcel Code 128\n" + "24 CODE49 Code 49 97 MICROQR Micro QR Code\n" + "25 CODE93 Code 93 98 HIBC_128 HIBC Code 128\n" + "28 FLAT Flattermarken 99 HIBC_39 HIBC Code 39\n", stdout); + fputs("29 DBAR_OMN GS1 DataBar Omni 102 HIBC_DM HIBC Data Matrix\n" + "30 DBAR_LTD GS1 DataBar Limited 104 HIBC_QR HIBC QR Code\n" + "31 DBAR_EXP GS1 DataBar Expanded 106 HIBC_PDF HIBC PDF417\n" + "32 TELEPEN Telepen Alpha 108 HIBC_MICPDF HIBC MicroPDF417\n" + "34 UPCA UPC-A 110 HIBC_BLOCKF HIBC Codablock-F\n", stdout); + fputs("35 UPCA_CHK UPC-A + Check Digit 112 HIBC_AZTEC HIBC Aztec Code\n" + "37 UPCE UPC-E 115 DOTCODE DotCode\n" + "38 UPCE_CHK UPC-E + Check Digit 116 HANXIN Han Xin Code\n" + "40 POSTNET USPS POSTNET 119 MAILMARK_2D Royal Mail 2D Mailmark\n" + "47 MSI_PLESSEY MSI Plessey 120 UPU_S10 UPU S10\n", stdout); + fputs("49 FIM Facing Ident Mark 121 MAILMARK_4S RM 4-State Mailmark\n" + "50 LOGMARS LOGMARS Code 39 128 AZRUNE Aztec Runes\n" + "51 PHARMA Pharmacode One-Track 129 CODE32 Code 32\n" + "52 PZN Pharmazentralnummer 130 EANX_CC Composite EAN\n" + "53 PHARMA_TWO Pharmacode Two-Track 131 GS1_128_CC Composite GS1-128\n", stdout); + fputs("54 CEPNET Brazilian CEPNet 132 DBAR_OMN_CC Comp DataBar Omni\n" + "55 PDF417 PDF417 133 DBAR_LTD_CC Comp DataBar Limited\n" + "56 PDF417COMP Compact PDF417 134 DBAR_EXP_CC Comp DataBar Expanded\n" + "57 MAXICODE MaxiCode 135 UPCA_CC Composite UPC-A\n" + "58 QRCODE QR Code 136 UPCE_CC Composite UPC-E\n", stdout); + fputs("60 CODE128AB Code 128 (Suppress C) 137 DBAR_STK_CC Comp DataBar Stacked\n" + "63 AUSPOST AP Standard Customer 138 DBAR_OMNSTK_CC Comp DataBar Stack Omn\n" + "66 AUSREPLY AP Reply Paid 139 DBAR_EXPSTK_CC Comp DataBar Exp Stack\n" + "67 AUSROUTE AP Routing 140 CHANNEL Channel Code\n" + "68 AUSREDIRECT AP Redirection 141 CODEONE Code One\n", stdout); + fputs("69 ISBNX ISBN 142 GRIDMATRIX Grid Matrix\n" + "70 RM4SCC Royal Mail 4SCC 143 UPNQR UPN QR Code\n" + "71 DATAMATRIX Data Matrix 144 ULTRA Ultracode\n" + "72 EAN14 EAN-14 145 RMQR Rectangular Micro QR\n" + "73 VIN Vehicle Information No. 146 BC412 BC412\n", stdout); + fputs("74 CODABLOCKF Codablock-F 147 DXFILMEDGE DX Film Edge Barcode\n", stdout); +} + +/* Output version information */ +static void version(const int no_png) { + const char *no_png_lib = no_png ? " (no libpng)" : ""; + const int zint_version = ZBarcode_Version(); + const int version_major = zint_version / 10000; + const int version_minor = (zint_version % 10000) / 100; + int version_release = zint_version % 100; + int version_build; + + if (version_release >= 9) { + /* This is a test release */ + version_release = version_release / 10; + version_build = zint_version % 10; + printf("Zint version %d.%d.%d.%d (dev)%s\n", version_major, version_minor, version_release, version_build, + no_png_lib); + } else { + /* This is a stable release */ + printf("Zint version %d.%d.%d%s\n", version_major, version_minor, version_release, no_png_lib); + } +} + +/* Output usage information */ +static void usage(const int no_png) { + const char *no_png_type = no_png ? "" : "/PNG"; + const char *no_png_ext = no_png ? "gif" : "png"; + + version(no_png); + + /* Breaking up strings so don't get too long (i.e. 500 or so) */ + printf("Encode input data in a barcode and save as BMP/EMF/EPS/GIF/PCX%s/SVG/TIF/TXT\n\n", no_png_type); + fputs( " -b, --barcode=TYPE Number or name of barcode type. Default is 20 (CODE128)\n" + " --addongap=INTEGER Set add-on gap in multiples of X-dimension for EAN/UPC\n" + " --batch Treat each line of input file as a separate data set\n" + " --bg=COLOUR Specify a background colour (as RGB(A) or \"C,M,Y,K\")\n" + " --binary Treat input as raw binary data\n", stdout); + fputs( " --bind Add boundary bars\n" + " --bindtop Add top boundary bar only\n" + " --bold Use bold text (HRT)\n" + " --border=INTEGER Set width of border in multiples of X-dimension\n" + " --box Add a box around the symbol\n", stdout); + fputs( " --cmyk Use CMYK colour space in EPS/TIF symbols\n" + " --cols=INTEGER Set the number of data columns in symbol\n" + " --compliantheight Warn if height not compliant, and use standard default\n" + " -d, --data=DATA Set the symbol data content (segment 0)\n" + " --direct Send output to stdout\n", stdout); + fputs( " --dmiso144 Use ISO format for 144x144 Data Matrix symbols\n" + " --dmre Allow Data Matrix Rectangular Extended\n" + " --dotsize=NUMBER Set radius of dots in dotty mode\n" + " --dotty Use dots instead of squares for matrix symbols\n" + " --dump Dump hexadecimal representation to stdout\n", stdout); + fputs( " -e, --ecinos Display ECI (Extended Channel Interpretation) table\n" + " --eci=INTEGER Set the ECI code for the data (segment 0)\n" + " --embedfont Embed font in vector output (SVG only)\n" + " --esc Process escape sequences in input data\n" + " --extraesc Process symbology-specific escape sequences (Code 128)\n", stdout); + fputs( " --fast Use faster encodation or other shortcuts if available\n" + " --fg=COLOUR Specify a foreground colour (as RGB(A) or \"C,M,Y,K\")\n", stdout); + printf(" --filetype=TYPE Set output file type BMP/EMF/EPS/GIF/PCX%s/SVG/TIF/TXT\n", no_png_type); + fputs( " --fullmultibyte Use multibyte for binary/Latin (QR/Han Xin/Grid Matrix)\n" + " --gs1 Treat input as GS1 compatible data\n" + " --gs1nocheck Do not check validity of GS1 data\n" + " --gs1parens Process parentheses \"()\" as GS1 AI delimiters, not \"[]\"\n" + " --gssep Use separator GS for GS1 (Data Matrix)\n", stdout); + fputs( " --guarddescent=NUMBER Set height of guard bar descent in X-dims (EAN/UPC)\n" + " --guardwhitespace Add quiet zone indicators (\"<\"/\">\") to HRT (EAN/UPC)\n" + " -h, --help Display help message\n" + " --height=NUMBER Set height of symbol in multiples of X-dimension\n" + " --heightperrow Treat height as per-row\n", stdout); + fputs( " -i, --input=FILE Read input data from FILE\n" + " --init Create Reader Initialisation (Programming) symbol\n" + " --mask=INTEGER Set masking pattern to use (QR/Han Xin/DotCode)\n" + " --mirror Use batch data to determine filename\n" + " --mode=INTEGER Set encoding mode (MaxiCode/Composite)\n", stdout); + printf(" --nobackground Remove background (EMF/EPS/GIF%s/SVG/TIF only)\n", no_png_type); + fputs( " --noquietzones Disable default quiet zones\n" + " --notext Remove human readable text (HRT)\n", stdout); + printf(" -o, --output=FILE Send output to FILE. Default is out.%s\n", no_png_ext); + fputs( " --primary=STRING Set primary message (MaxiCode/Composite)\n" + " --quietzones Add compliant quiet zones\n" + " -r, --reverse Reverse colours (white on black)\n" + " --rotate=INTEGER Rotate symbol by INTEGER (0, 90, 180, 270) degrees\n" + " --rows=INTEGER Set number of rows (Codablock-F/PDF417)\n", stdout); + fputs( " --scale=NUMBER Adjust size of X-dimension\n" + " --scalexdimdp=X[,R] Adjust size to X-dimension X at resolution R\n" + " --scmvv=INTEGER Prefix SCM with \"[)>\\R01\\Gvv\" (vv is INTEGER) (MaxiCode)\n" + " --secure=INTEGER Set error correction level (ECC)\n" + " --segN=ECI,DATA Set the ECI & data content for segment N, where N 1 to 9\n", stdout); + fputs( " --separator=INTEGER Set height of row separator bars (stacked symbologies)\n" + " --small Use small text (HRT)\n" + " --square Force Data Matrix symbols to be square\n" + " --structapp=I,C[,ID] Set Structured Append info (I index, C count)\n" + " -t, --types Display table of barcode types\n", stdout); + fputs( " --textgap=NUMBER Adjust gap between barcode and HRT in multiples of X-dim\n" + " --vers=INTEGER Set symbol version (size, check digits, other options)\n" + " -v, --version Display Zint version\n" + " --vwhitesp=INTEGER Set height of vertical whitespace in multiples of X-dim\n" + " -w, --whitesp=INTEGER Set width of horizontal whitespace in multiples of X-dim\n", stdout); + fputs( " --werror Convert all warnings into errors\n", stdout); +} + +/* Display supported ECI codes */ +static void show_eci(void) { + /* Breaking up strings so don't get too long (i.e. 500 or so) */ + fputs(" 3: ISO/IEC 8859-1 - Latin alphabet No. 1 (default)\n" + " 4: ISO/IEC 8859-2 - Latin alphabet No. 2\n" + " 5: ISO/IEC 8859-3 - Latin alphabet No. 3\n" + " 6: ISO/IEC 8859-4 - Latin alphabet No. 4\n" + " 7: ISO/IEC 8859-5 - Latin/Cyrillic alphabet\n", stdout); + fputs(" 8: ISO/IEC 8859-6 - Latin/Arabic alphabet\n" + " 9: ISO/IEC 8859-7 - Latin/Greek alphabet\n" + " 10: ISO/IEC 8859-8 - Latin/Hebrew alphabet\n" + " 11: ISO/IEC 8859-9 - Latin alphabet No. 5 (Turkish)\n" + " 12: ISO/IEC 8859-10 - Latin alphabet No. 6 (Nordic)\n", stdout); + fputs(" 13: ISO/IEC 8859-11 - Latin/Thai alphabet\n" + " 15: ISO/IEC 8859-13 - Latin alphabet No. 7 (Baltic)\n" + " 16: ISO/IEC 8859-14 - Latin alphabet No. 8 (Celtic)\n" + " 17: ISO/IEC 8859-15 - Latin alphabet No. 9\n" + " 18: ISO/IEC 8859-16 - Latin alphabet No. 10\n", stdout); + fputs(" 20: Shift JIS (JIS X 0208 and JIS X 0201)\n" + " 21: Windows 1250 - Latin 2 (Central Europe)\n" + " 22: Windows 1251 - Cyrillic\n" + " 23: Windows 1252 - Latin 1\n" + " 24: Windows 1256 - Arabic\n", stdout); + fputs(" 25: UTF-16BE (High order byte first)\n" + " 26: UTF-8\n" + " 27: ASCII (ISO/IEC 646 IRV)\n" + " 28: Big5 (Taiwan) Chinese Character Set\n" + " 29: GB 2312 (PRC) Chinese Character Set\n", stdout); + fputs(" 30: Korean Character Set EUC-KR (KS X 1001:2002)\n" + " 31: GBK Chinese Character Set\n" + " 32: GB 18030 Chinese Character Set\n" + " 33: UTF-16LE (Low order byte first)\n" + " 34: UTF-32BE (High order bytes first)\n", stdout); + fputs(" 35: UTF-32LE (Low order bytes first)\n" + "170: ISO/IEC 646 Invariant (ASCII subset)\n" + "899: 8-bit binary data\n", stdout); +} + +/* Verifies that a string (length <= 9) only uses digits. On success returns value in arg */ +static int validate_int(const char source[], int len, int *p_val) { + int val = 0; + int i; + const int length = len == -1 ? (int) strlen(source) : len; + + if (length > 9) { /* Prevent overflow */ + return 0; + } + for (i = 0; i < length; i++) { + if (source[i] < '0' || source[i] > '9') { + return 0; + } + val *= 10; + val += source[i] - '0'; + } + *p_val = val; + + return 1; +} + +/* Verifies that a string is a simplified form of floating point, max 7 significant decimal digits with + optional decimal point. On success returns val in arg. On failure sets `errbuf` */ +static int validate_float(const char source[], const int allow_neg, float *p_val, char errbuf[64]) { + static const float fract_muls[7] = { 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f }; + int val = 0; + int neg = 0; + const char *dot = strchr(source, '.'); + int int_len; + + if (*source == '+' || *source == '-') { + if (*source == '-') { + if (!allow_neg) { + strcpy(errbuf, "negative value not permitted"); + return 0; + } + neg = 1; + } + source++; + } + + int_len = dot ? (int) (dot - source) : (int) strlen(source); + if (int_len > 9) { + strcpy(errbuf, "integer part must be 7 digits maximum"); /* Say 7 not 9 to "manage expections" */ + return 0; + } + if (int_len) { + int tmp_val; + if (!validate_int(source, int_len, &val)) { + strcpy(errbuf, "integer part must be digits only"); + return 0; + } + for (int_len = 0, tmp_val = val; tmp_val; tmp_val /= 10, int_len++); /* log10(val) */ + if (int_len > 7) { + strcpy(errbuf, "integer part must be 7 digits maximum"); + return 0; + } + } + if (dot && *++dot) { + int val2, fract_len; + const char *e; + for (e = dot + strlen(dot) - 1; e > dot && *e == '0'; e--); /* Ignore trailing zeroes */ + fract_len = (int) (e + 1 - dot); + if (fract_len) { + if (fract_len > 7) { + strcpy(errbuf, "fractional part must be 7 digits maximum"); + return 0; + } + if (!validate_int(dot, fract_len, &val2)) { + strcpy(errbuf, "fractional part must be digits only"); + return 0; + } + if (val2 && int_len + fract_len > 7) { + if (val) { + strcpy(errbuf, "7 significant digits maximum"); + } else { + strcpy(errbuf, "fractional part must be 7 digits maximum"); + } + return 0; + } + *p_val = val + val2 * fract_muls[fract_len - 1]; + } else { + *p_val = (float) val; + } + } else { + *p_val = (float) val; + } + if (neg) { + *p_val = -*p_val; + } + return 1; +} + +/* Converts upper case characters to lower case in a string source[] */ +static void to_lower(char source[]) { + int i; + const int src_len = (int) strlen(source); + + for (i = 0; i < src_len; i++) { + if ((source[i] >= 'A') && (source[i] <= 'Z')) { + source[i] |= 0x20; + } + } +} + +/* Return symbology id if `barcode_name` a barcode name */ +static int get_barcode_name(const char *barcode_name) { + /* Must be sorted for binary search to work */ + static const struct { int symbology; const char *n; } names[] = { + { BARCODE_C25LOGIC, "2of5datalogic" }, /* Synonym */ + { BARCODE_C25IATA, "2of5iata" }, /* Synonym */ + { BARCODE_C25IND, "2of5ind" }, /* Synonym */ + { BARCODE_C25IND, "2of5industrial" }, /* Synonym */ + { BARCODE_C25INTER, "2of5inter" }, /* Synonym */ + { BARCODE_C25INTER, "2of5interleaved" }, /* Synonym */ + { BARCODE_C25LOGIC, "2of5logic" }, /* Synonym */ + { BARCODE_C25STANDARD, "2of5matrix" }, /* Synonym */ + { BARCODE_C25STANDARD, "2of5standard" }, /* Synonym */ + { BARCODE_AUSPOST, "auspost" }, + { BARCODE_AUSREDIRECT, "ausredirect" }, + { BARCODE_AUSREPLY, "ausreply" }, + { BARCODE_AUSROUTE, "ausroute" }, + { BARCODE_AZRUNE, "azrune" }, + { BARCODE_AZTEC, "aztec" }, + { BARCODE_AZTEC, "azteccode" }, /* Synonym */ + { BARCODE_AZRUNE, "aztecrune" }, /* Synonym */ + { BARCODE_AZRUNE, "aztecrunes" }, /* Synonym */ + { BARCODE_BC412, "bc412" }, + { BARCODE_C25LOGIC, "c25datalogic" }, /* Synonym */ + { BARCODE_C25IATA, "c25iata" }, + { BARCODE_C25IND, "c25ind" }, + { BARCODE_C25IND, "c25industrial" }, /* Synonym */ + { BARCODE_C25INTER, "c25inter" }, + { BARCODE_C25INTER, "c25interleaved" }, /* Synonym */ + { BARCODE_C25LOGIC, "c25logic" }, + { BARCODE_C25STANDARD, "c25matrix" }, + { BARCODE_C25STANDARD, "c25standard" }, + { BARCODE_CEPNET, "cepnet" }, + { BARCODE_CHANNEL, "channel" }, + { BARCODE_CHANNEL, "channelcode" }, /* Synonym */ + { BARCODE_CODABAR, "codabar" }, + { BARCODE_CODABLOCKF, "codablockf" }, + { BARCODE_CODE11, "code11" }, + { BARCODE_CODE128, "code128" }, + { BARCODE_CODE128AB, "code128ab" }, + { BARCODE_CODE128AB, "code128b" }, /* Synonym */ + { BARCODE_CODE16K, "code16k" }, + { BARCODE_C25LOGIC, "code2of5datalogic" }, /* Synonym */ + { BARCODE_C25IATA, "code2of5iata" }, /* Synonym */ + { BARCODE_C25IND, "code2of5ind" }, /* Synonym */ + { BARCODE_C25IND, "code2of5industrial" }, /* Synonym */ + { BARCODE_C25INTER, "code2of5inter" }, /* Synonym */ + { BARCODE_C25INTER, "code2of5interleaved" }, /* Synonym */ + { BARCODE_C25LOGIC, "code2of5logic" }, /* Synonym */ + { BARCODE_C25STANDARD, "code2of5matrix" }, /* Synonym */ + { BARCODE_C25STANDARD, "code2of5standard" }, /* Synonym */ + { BARCODE_CODE32, "code32" }, + { BARCODE_CODE39, "code39" }, + { BARCODE_CODE49, "code49" }, + { BARCODE_CODE93, "code93" }, + { BARCODE_CODEONE, "codeone" }, + { BARCODE_DAFT, "daft" }, + { BARCODE_DBAR_EXP, "databarexp" }, /* Synonym */ + { BARCODE_DBAR_EXP, "databarexpanded" }, /* Synonym */ + { BARCODE_DBAR_EXP_CC, "databarexpandedcc" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK, "databarexpandedstacked" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK_CC, "databarexpandedstackedcc" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK, "databarexpandedstk" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK_CC, "databarexpandedstkcc" }, /* Synonym */ + { BARCODE_DBAR_EXP_CC, "databarexpcc" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK, "databarexpstk" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK_CC, "databarexpstkcc" }, /* Synonym */ + { BARCODE_DBAR_LTD, "databarlimited" }, /* Synonym */ + { BARCODE_DBAR_LTD_CC, "databarlimitedcc" }, /* Synonym */ + { BARCODE_DBAR_LTD, "databarltd" }, /* Synonym */ + { BARCODE_DBAR_LTD_CC, "databarltdcc" }, /* Synonym */ + { BARCODE_DBAR_OMN, "databaromn" }, /* Synonym */ + { BARCODE_DBAR_OMN_CC, "databaromncc" }, /* Synonym */ + { BARCODE_DBAR_OMN, "databaromni" }, /* Synonym */ + { BARCODE_DBAR_OMN_CC, "databaromnicc" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK, "databaromnstk" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK_CC, "databaromnstkcc" }, /* Synonym */ + { BARCODE_DBAR_STK, "databarstacked" }, /* Synonym */ + { BARCODE_DBAR_STK_CC, "databarstackedcc" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK, "databarstackedomn" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK_CC, "databarstackedomncc" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK, "databarstackedomni" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK_CC, "databarstackedomnicc" }, /* Synonym */ + { BARCODE_DBAR_STK, "databarstk" }, /* Synonym */ + { BARCODE_DBAR_STK_CC, "databarstkcc" }, /* Synonym */ + { BARCODE_DATAMATRIX, "datamatrix" }, + { BARCODE_DBAR_EXP, "dbarexp" }, + { BARCODE_DBAR_EXP, "dbarexpanded" }, /* Synonym */ + { BARCODE_DBAR_EXP_CC, "dbarexpandedcc" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK, "dbarexpandedstacked" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK_CC, "dbarexpandedstackedcc" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK, "dbarexpandedstk" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK_CC, "dbarexpandedstkcc" }, /* Synonym */ + { BARCODE_DBAR_EXP_CC, "dbarexpcc" }, + { BARCODE_DBAR_EXPSTK, "dbarexpstk" }, + { BARCODE_DBAR_EXPSTK_CC, "dbarexpstkcc" }, + { BARCODE_DBAR_LTD, "dbarlimited" }, /* Synonym */ + { BARCODE_DBAR_LTD_CC, "dbarlimitedcc" }, /* Synonym */ + { BARCODE_DBAR_LTD, "dbarltd" }, + { BARCODE_DBAR_LTD_CC, "dbarltdcc" }, + { BARCODE_DBAR_OMN, "dbaromn" }, + { BARCODE_DBAR_OMN_CC, "dbaromncc" }, + { BARCODE_DBAR_OMN, "dbaromni" }, /* Synonym */ + { BARCODE_DBAR_OMN_CC, "dbaromnicc" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK, "dbaromnstk" }, + { BARCODE_DBAR_OMNSTK_CC, "dbaromnstkcc" }, + { BARCODE_DBAR_STK, "dbarstacked" }, /* Synonym */ + { BARCODE_DBAR_STK_CC, "dbarstackedcc" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK, "dbarstackedomn" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK_CC, "dbarstackedomncc" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK, "dbarstackedomni" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK_CC, "dbarstackedomnicc" }, /* Synonym */ + { BARCODE_DBAR_STK, "dbarstk" }, + { BARCODE_DBAR_STK_CC, "dbarstkcc" }, + { BARCODE_DOTCODE, "dotcode" }, + { BARCODE_DPD, "dpd" }, + { BARCODE_DPIDENT, "dpident" }, + { BARCODE_DPLEIT, "dpleit" }, + { BARCODE_DXFILMEDGE, "dxfilmedge" }, + { BARCODE_EANX, "ean" }, /* Synonym */ + { BARCODE_GS1_128, "ean128" }, /* Synonym */ + { BARCODE_GS1_128_CC, "ean128cc" }, /* Synonym */ + { BARCODE_EAN14, "ean14" }, + { BARCODE_EANX_CC, "eancc" }, /* Synonym */ + { BARCODE_EANX_CHK, "eanchk" }, /* Synonym */ + { BARCODE_EANX, "eanx" }, + { BARCODE_EANX_CC, "eanxcc" }, + { BARCODE_EANX_CHK, "eanxchk" }, + { BARCODE_EXCODE39, "excode39" }, + { BARCODE_EXCODE39, "extendedcode39" }, /* Synonym */ + { BARCODE_FIM, "fim" }, + { BARCODE_FLAT, "flat" }, + { BARCODE_GRIDMATRIX, "gridmatrix" }, + { BARCODE_GS1_128, "gs1128" }, + { BARCODE_GS1_128_CC, "gs1128cc" }, + { BARCODE_HANXIN, "hanxin" }, + { BARCODE_HIBC_128, "hibc128" }, + { BARCODE_HIBC_39, "hibc39" }, + { BARCODE_HIBC_AZTEC, "hibcaztec" }, + { BARCODE_HIBC_BLOCKF, "hibcblockf" }, + { BARCODE_HIBC_BLOCKF, "hibccodablockf" }, /* Synonym */ + { BARCODE_HIBC_128, "hibccode128" }, /* Synonym */ + { BARCODE_HIBC_39, "hibccode39" }, /* Synonym */ + { BARCODE_HIBC_DM, "hibcdatamatrix" }, /* Synonym */ + { BARCODE_HIBC_DM, "hibcdm" }, + { BARCODE_HIBC_MICPDF, "hibcmicpdf" }, + { BARCODE_HIBC_MICPDF, "hibcmicropdf" }, /* Synonym */ + { BARCODE_HIBC_MICPDF, "hibcmicropdf417" }, /* Synonym */ + { BARCODE_HIBC_PDF, "hibcpdf" }, + { BARCODE_HIBC_PDF, "hibcpdf417" }, /* Synonym */ + { BARCODE_HIBC_QR, "hibcqr" }, + { BARCODE_HIBC_QR, "hibcqrcode" }, /* Synonym */ + { BARCODE_C25IATA, "iata2of5" }, /* Synonym */ + { BARCODE_C25IATA, "iatacode2of5" }, /* Synonym */ + { BARCODE_C25IND, "industrial2of5" }, /* Synonym */ + { BARCODE_C25IND, "industrialcode2of5" }, /* Synonym */ + { BARCODE_C25INTER, "interleaved2of5" }, /* Synonym */ + { BARCODE_C25INTER, "interleavedcode2of5" }, /* Synonym */ + { BARCODE_ISBNX, "isbn" }, /* Synonym */ + { BARCODE_ISBNX, "isbnx" }, + { BARCODE_ITF14, "itf14" }, + { BARCODE_JAPANPOST, "japanpost" }, + { BARCODE_KIX, "kix" }, + { BARCODE_KOREAPOST, "koreapost" }, + { BARCODE_LOGMARS, "logmars" }, + { BARCODE_MAILMARK_4S, "mailmark" }, /* Synonym */ + { BARCODE_MAILMARK_2D, "mailmark2d" }, + { BARCODE_MAILMARK_4S, "mailmark4s" }, + { BARCODE_MAILMARK_4S, "mailmark4state" }, /* Synonym */ + { BARCODE_MAXICODE, "maxicode" }, + { BARCODE_MICROPDF417, "micropdf417" }, + { BARCODE_MICROQR, "microqr" }, + { BARCODE_MICROQR, "microqrcode" }, /* Synonym */ + { BARCODE_MSI_PLESSEY, "msi" }, /* Synonym */ + { BARCODE_MSI_PLESSEY, "msiplessey" }, + { BARCODE_NVE18, "nve18" }, + { BARCODE_USPS_IMAIL, "onecode" }, /* Synonym */ + { BARCODE_PDF417, "pdf417" }, + { BARCODE_PDF417COMP, "pdf417comp" }, + { BARCODE_PDF417COMP, "pdf417trunc" }, /* Synonym */ + { BARCODE_PHARMA, "pharma" }, + { BARCODE_PHARMA_TWO, "pharmatwo" }, + { BARCODE_PLANET, "planet" }, + { BARCODE_PLESSEY, "plessey" }, + { BARCODE_POSTNET, "postnet" }, + { BARCODE_PZN, "pzn" }, + { BARCODE_QRCODE, "qr" }, /* Synonym */ + { BARCODE_QRCODE, "qrcode" }, + { BARCODE_RM4SCC, "rm4scc" }, + { BARCODE_RMQR, "rmqr" }, + { BARCODE_DBAR_OMN, "rss14" }, /* Synonym */ + { BARCODE_DBAR_OMN_CC, "rss14cc" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK_CC, "rss14omnicc" }, /* Synonym */ + { BARCODE_DBAR_STK, "rss14stack" }, /* Synonym */ + { BARCODE_DBAR_STK_CC, "rss14stackcc" }, /* Synonym */ + { BARCODE_DBAR_OMNSTK, "rss14stackomni" }, /* Synonym */ + { BARCODE_DBAR_EXP, "rssexp" }, /* Synonym */ + { BARCODE_DBAR_EXP_CC, "rssexpcc" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK, "rssexpstack" }, /* Synonym */ + { BARCODE_DBAR_EXPSTK_CC, "rssexpstackcc" }, /* Synonym */ + { BARCODE_DBAR_LTD, "rssltd" }, /* Synonym */ + { BARCODE_DBAR_LTD_CC, "rssltdcc" }, /* Synonym */ + { BARCODE_C25STANDARD, "standardcode2of5" }, /* Synonym */ + { BARCODE_TELEPEN, "telepen" }, + { BARCODE_TELEPEN_NUM, "telepennum" }, + { BARCODE_ULTRA, "ultra" }, + { BARCODE_ULTRA, "ultracode" }, /* Synonym */ + { BARCODE_UPCA, "upca" }, + { BARCODE_UPCA_CC, "upcacc" }, + { BARCODE_UPCA_CHK, "upcachk" }, + { BARCODE_UPCE, "upce" }, + { BARCODE_UPCE_CC, "upcecc" }, + { BARCODE_UPCE_CHK, "upcechk" }, + { BARCODE_UPNQR, "upnqr" }, + { BARCODE_UPNQR, "upnqrcode" }, /* Synonym */ + { BARCODE_UPU_S10, "upus10" }, + { BARCODE_USPS_IMAIL, "uspsimail" }, + { BARCODE_VIN, "vin" }, + }; + int s = 0, e = ARRAY_SIZE(names) - 1; + + char n[30] = {0}; + int i, j, length; + + /* Ignore case and any "BARCODE" prefix */ + strncpy(n, barcode_name, 29); + to_lower(n); + length = (int) strlen(n); + if (strncmp(n, "barcode", 7) == 0) { + memmove(n, n + 7, length - 7 + 1); /* Include NUL char */ + length = (int) strlen(n); + } + + /* Ignore any non-alphanumeric characters */ + for (i = 0, j = 0; i < length; i++) { + if ((n[i] >= 'a' && n[i] <= 'z') || (n[i] >= '0' && n[i] <= '9')) { + n[j++] = n[i]; + } + } + if (j == 0) { + return 0; + } + n[j] = '\0'; + + while (s <= e) { + const int m = (s + e) / 2; + const int cmp = strcmp(names[m].n, n); + if (cmp < 0) { + s = m + 1; + } else if (cmp > 0) { + e = m - 1; + } else { + return names[m].symbology; + } + } + + return 0; +} + +/* Whether `filetype` supported by Zint. Sets `png_refused` if `no_png` and PNG requested */ +static int supported_filetype(const char *filetype, const int no_png, int *png_refused) { + static const char filetypes[][4] = { + "bmp", "emf", "eps", "gif", "pcx", "png", "svg", "tif", "txt", + }; + char lc_filetype[4] = {0}; + int i; + + if (png_refused) { + *png_refused = 0; + } + strncpy(lc_filetype, filetype, 3); + to_lower(lc_filetype); + + if (no_png && strcmp(lc_filetype, "png") == 0) { + if (png_refused) { + *png_refused = 1; + } + return 0; + } + + for (i = 0; i < ARRAY_SIZE(filetypes); i++) { + if (strcmp(lc_filetype, filetypes[i]) == 0) { + return 1; + } + } + return 0; +} + +/* Get file extension, excluding those of 4 or more letters */ +static char *get_extension(const char *file) { + char *dot; + + dot = strrchr(file, '.'); + if (dot && strlen(file) - (dot - file) <= 4) { /* Only recognize up to 3 letter extensions */ + return dot + 1; + } + return NULL; +} + +/* Set extension of `file` to `filetype`, replacing existing extension if any. + * Does nothing if file already has `filetype` extension */ +static void set_extension(char *file, const char *filetype) { + char lc_filetype[4] = {0}; + char *extension; + char lc_extension[4]; + + strncpy(lc_filetype, filetype, 3); + to_lower(lc_filetype); + + extension = get_extension(file); + if (extension) { + strcpy(lc_extension, extension); + to_lower(lc_extension); + if (strcmp(lc_filetype, lc_extension) == 0) { + return; + } + *(extension - 1) = '\0'; /* Cut off at dot */ + } + if (strlen(file) > 251) { + file[251] = '\0'; + } + strcat(file, "."); + strncat(file, filetype, 3); +} + +/* Whether `filetype` is raster type */ +static int is_raster(const char *filetype, const int no_png) { + static const char raster_filetypes[][4] = { + "bmp", "gif", "pcx", "png", "tif", + }; + int i; + char lc_filetype[4] = {0}; + + if (filetype == NULL) { + return 0; + } + strcpy(lc_filetype, filetype); + to_lower(lc_filetype); + + if (no_png && strcmp(lc_filetype, "png") == 0) { + return 0; + } + + for (i = 0; i < ARRAY_SIZE(raster_filetypes); i++) { + if (strcmp(lc_filetype, raster_filetypes[i]) == 0) { + return 1; + } + } + return 0; +} + +/* Helper for `validate_scalexdimdp()` to search for units, returning -2 on error, -1 if not found, else index */ +static int validate_units(char *buf, const char units[][5], int units_size) { + int i; + char *unit; + + to_lower(buf); + for (i = 0; i < units_size; i++) { + if ((unit = strstr(buf, units[i])) != NULL) { + if (strlen(units[i]) != strlen(unit)) { + return -2; + } + *unit = '\0'; + break; + } + } + if (i == units_size) { + i = -1; + } + return i; +} + +/* Parse and validate argument "xdim[,resolution]" to "--scalexdimdp" */ +static int validate_scalexdimdp(const char *arg, float *p_x_dim_mm, float *p_dpmm) { + static const char x_units[][5] = { "mm", "in" }; + static const char r_units[][5] = { "dpmm", "dpi" }; + char x_buf[7 + 1 + 4 + 1] = {0}; /* Allow for 7 digits + dot + 4-char unit + NUL */ + char r_buf[7 + 1 + 4 + 1] = {0}; /* As above */ + int units_i; /* For `validate_units()` */ + char errbuf[64]; /* For `validate_float()` */ + const char *comma = strchr(arg, ','); + if (comma) { + if (comma == arg || comma - arg >= ARRAY_SIZE(x_buf)) { + fprintf(stderr, "Error 174: scalexdimdp X-dim too %s\n", comma == arg ? "short" : "long"); + return 0; + } + strncpy(x_buf, arg, comma - arg); + comma++; + if (!*comma || strlen(comma) >= ARRAY_SIZE(r_buf)) { + fprintf(stderr, "Error 175: scalexdimdp resolution too %s\n", !*comma ? "short" : "long"); + return 0; + } + strcpy(r_buf, comma); + } else { + if (!*arg || strlen(arg) >= ARRAY_SIZE(x_buf)) { + fprintf(stderr, "Error 176: scalexdimdp X-dim too %s\n", !*arg ? "short" : "long"); + return 0; + } + strcpy(x_buf, arg); + } + if ((units_i = validate_units(x_buf, x_units, ARRAY_SIZE(x_units))) == -2) { + fprintf(stderr, "Error 177: scalexdimdp X-dim units must occur at end\n"); + return 0; + } + if (!validate_float(x_buf, 0 /*allow_neg*/, p_x_dim_mm, errbuf)) { + fprintf(stderr, "Error 178: scalexdimdp X-dim invalid floating point (%s)\n", errbuf); + return 0; + } + if (units_i > 0) { /* Ignore mm */ + *p_x_dim_mm /= 25.4f /*in*/; + } + *p_dpmm = 0.0f; + if (comma) { + if ((units_i = validate_units(r_buf, r_units, ARRAY_SIZE(r_units))) == -2) { + fprintf(stderr, "Error 179: scalexdimdp resolution units must occur at end\n"); + return 0; + } + if (!validate_float(r_buf, 0 /*allow_neg*/, p_dpmm, errbuf)) { + fprintf(stderr, "Error 180: scalexdimdp resolution invalid floating point (%s)\n", errbuf); + return 0; + } + if (units_i > 0) { /* Ignore dpmm */ + *p_dpmm /= 25.4f /*dpi*/; + } + } + if (*p_dpmm == 0.0f) { + *p_dpmm = 12.0f; /* 300 dpi */ + } + + return 1; +} + +/* Parse and validate Structured Append argument "index,count[,ID]" to "--structapp" */ +static int validate_structapp(const char *arg, struct zint_structapp *structapp) { + char index[10] = {0}, count[10] = {0}; + const char *comma = strchr(arg, ','); + const char *comma2; + if (!comma) { + fprintf(stderr, "Error 155: Invalid Structured Append argument, expect \"index,count[,ID]\"\n"); + return 0; + } + if (comma == arg || comma - arg > 9) { + fprintf(stderr, "Error 156: Structured Append index too %s\n", comma == arg ? "short" : "long"); + return 0; + } + strncpy(index, arg, comma - arg); + comma++; + comma2 = strchr(comma, ','); + if (comma2) { + if (comma2 == comma || comma2 - comma > 9) { + fprintf(stderr, "Error 157: Structured Append count too %s\n", comma2 == comma ? "short" : "long"); + return 0; + } + strncpy(count, comma, comma2 - comma); + comma2++; + if (!*comma2 || strlen(comma2) > 32) { + fprintf(stderr, "Error 158: Structured Append ID too %s\n", !*comma2 ? "short" : "long"); + return 0; + } + strncpy(structapp->id, comma2, 32); + } else { + if (!*comma || strlen(comma) > 9) { + fprintf(stderr, "Error 159: Structured Append count too %s\n", !*comma ? "short" : "long"); + return 0; + } + strcpy(count, comma); + } + if (!validate_int(index, -1 /*len*/, &structapp->index)) { + fprintf(stderr, "Error 160: Invalid Structured Append index (digits only)\n"); + return 0; + } + if (!validate_int(count, -1 /*len*/, &structapp->count)) { + fprintf(stderr, "Error 161: Invalid Structured Append count (digits only)\n"); + return 0; + } + if (structapp->count < 2) { + fprintf(stderr, "Error 162: Invalid Structured Append count '%d', must be greater than or equal to 2\n", + structapp->count); + return 0; + } + if (structapp->index < 1 || structapp->index > structapp->count) { + fprintf(stderr, "Error 163: Structured Append index '%d' out of range (1 to count '%d')\n", structapp->index, + structapp->count); + return 0; + } + + return 1; +} + +/* Parse and validate the segment argument "ECI,DATA" to "--segN" */ +static int validate_seg(const char *arg, const int N, struct zint_seg segs[10]) { + char eci[10] = {0}; + const char *comma = strchr(arg, ','); + if (!comma || comma == arg || comma - arg > 9 || *(comma + 1) == '\0') { + fprintf(stderr, "Error 166: Invalid segment argument, expect \"ECI,DATA\"\n"); + return 0; + } + strncpy(eci, arg, comma - arg); + if (!validate_int(eci, -1 /*len*/, &segs[N].eci)) { + fprintf(stderr, "Error 167: Invalid segment ECI (digits only)\n"); + return 0; + } + if (segs[N].eci > 999999) { + fprintf(stderr, "Error 168: Segment ECI code '%d' out of range (0 to 999999)\n", segs[N].eci); + return 0; + } + segs[N].length = (int) strlen(comma + 1); + segs[N].source = (unsigned char *) (comma + 1); + return 1; +} + +#ifdef _WIN32 +static FILE *win_fopen(const char *filename, const char *mode); /* Forward ref */ +#endif + +/* Batch mode - output symbol for each line of text in `filename` */ +static int batch_process(struct zint_symbol *symbol, const char *filename, const int mirror_mode, + const char *filetype, const int output_given, const int rotate_angle) { + FILE *file; + unsigned char buffer[ZINT_MAX_DATA_LEN] = {0}; /* Maximum HanXin input */ + unsigned char character = 0; + int buf_posn = 0, error_number = 0, warn_number = 0, line_count = 1; + char output_file[256]; + char number[12], reverse_number[12]; + int inpos, local_line_count; + char format_string[256], reversed_string[256], format_char; + int format_len, i, o, mirror_start_o = 0; + char adjusted[2] = {0}; + const int from_stdin = strcmp(filename, "-") == 0; /* Suppress clang-19 warning clang-analyzer-unix.Stream */ + + if (mirror_mode) { + /* Use directory if any from outfile */ + if (output_given && symbol->outfile[0]) { +#ifndef _WIN32 + const char *dir = strrchr(symbol->outfile, '/'); +#else + const char *dir = strrchr(symbol->outfile, '\\'); + if (!dir) { + dir = strrchr(symbol->outfile, '/'); + } +#endif + if (dir) { + mirror_start_o = (int) (dir + 1 - symbol->outfile); + if (mirror_start_o > 221) { /* Insist on leaving at least ~30 chars for filename */ + fprintf(stderr, "Warning 188: directory for mirrored batch output too long (greater than 220)," + " ignoring\n"); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; /* TODO: maybe new warning ZINT_WARN_INVALID_INPUT? */ + mirror_start_o = 0; + } else { + memcpy(output_file, symbol->outfile, mirror_start_o); + } + } + } + } else { + if (symbol->outfile[0] == '\0' || !output_given) { + strcpy(format_string, "~~~~~."); + strncat(format_string, filetype, 3); + } else { + strcpy(format_string, symbol->outfile); + set_extension(format_string, filetype); + } + } + + if (from_stdin) { + file = stdin; + } else { +#ifdef _WIN32 + file = win_fopen(filename, "rb"); +#else + file = fopen(filename, "rb"); +#endif + if (!file) { + fprintf(stderr, "Error 102: Unable to read input file '%s' (%d: %s)\n", filename, errno, strerror(errno)); + fflush(stderr); + return ZINT_ERROR_INVALID_DATA; + } + } + + do { + int intChar; + intChar = fgetc(file); + if (intChar == EOF) { + break; + } + character = (unsigned char) intChar; + if (character == '\n') { + if (buf_posn > 0 && buffer[buf_posn - 1] == '\r') { + /* CR+LF - assume Windows formatting and remove CR */ + buf_posn--; + buffer[buf_posn] = '\0'; + } + + if (mirror_mode == 0) { + inpos = 0; + local_line_count = line_count; + memset(number, 0, sizeof(number)); + memset(reverse_number, 0, sizeof(reverse_number)); + memset(reversed_string, 0, sizeof(reversed_string)); + memset(output_file, 0, sizeof(output_file)); + do { + number[inpos] = (local_line_count % 10) + '0'; + local_line_count /= 10; + inpos++; + } while (local_line_count > 0); + number[inpos] = '\0'; + + for (i = 0; i < inpos; i++) { + reverse_number[i] = number[inpos - i - 1]; + } + + format_len = (int) strlen(format_string); + for (i = format_len; i > 0; i--) { + format_char = format_string[i - 1]; + + switch (format_char) { + case '#': + if (inpos > 0) { + adjusted[0] = reverse_number[inpos - 1]; + inpos--; + } else { + adjusted[0] = ' '; + } + break; + case '~': + if (inpos > 0) { + adjusted[0] = reverse_number[inpos - 1]; + inpos--; + } else { + adjusted[0] = '0'; + } + break; + case '@': + if (inpos > 0) { + adjusted[0] = reverse_number[inpos - 1]; + inpos--; + } else { +#ifndef _WIN32 + adjusted[0] = '*'; +#else + adjusted[0] = '+'; +#endif + } + break; + default: + adjusted[0] = format_string[i - 1]; + break; + } + strcat(reversed_string, adjusted); + } + + for (i = 0; i < format_len; i++) { + output_file[i] = reversed_string[format_len - i - 1]; + } + } else { + /* Name the output file from the data being processed */ + i = 0; + o = mirror_start_o; + do { + if (buffer[i] < 0x20) { + output_file[o] = '_'; + } else { + switch (buffer[i]) { + case '!': + case '"': + case '*': + case '/': + case ':': + case '<': + case '>': + case '?': + case '\\': + case '|': + case 0x7f: /* DEL */ + output_file[o] = '_'; + break; + default: + output_file[o] = buffer[i]; + break; + } + } + + /* Skip escape characters */ + if ((buffer[i] == '\\') && (symbol->input_mode & ESCAPE_MODE)) { + i++; + if (buffer[i] == 'x') { + i += 2; + } else if (buffer[i] == 'd' || buffer[i] == 'o') { + i += 3; + } else if (buffer[i] == 'u') { + i += 4; + } else if (buffer[i] == 'U') { + i += 6; + } + } + i++; + o++; + } while (i < buf_posn && o < 251); + + /* Add file extension */ + output_file[o] = '.'; + output_file[o + 1] = '\0'; + + strncat(output_file, filetype, 3); + } + + strcpy(symbol->outfile, output_file); + warn_number = ZBarcode_Encode_and_Print(symbol, buffer, buf_posn, rotate_angle); + if (warn_number != 0) { + fprintf(stderr, "On line %d: %s\n", line_count, symbol->errtxt); + fflush(stderr); + if (warn_number >= ZINT_ERROR) { + error_number = warn_number; + } + } + ZBarcode_Clear(symbol); + memset(buffer, 0, sizeof(buffer)); + buf_posn = 0; + line_count++; + } else { + buffer[buf_posn] = character; + buf_posn++; + } + if (buf_posn >= (int) sizeof(buffer)) { + fprintf(stderr, "On line %d: Error 103: Input data too long\n", line_count); + fflush(stderr); + do { + if ((intChar = fgetc(file)) == EOF) { + break; + } + character = (unsigned char) intChar; + } while ((!feof(file)) && (character != '\n')); + } + } while ((!feof(file)) && (line_count < 2000000000)); + + if (character != '\n') { + fprintf(stderr, "Warning 104: No newline at end of file\n"); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; /* TODO: maybe new warning e.g. ZINT_WARN_INVALID_INPUT? */ + } + + if (!from_stdin) { + if (fclose(file) != 0) { + fprintf(stderr, "Warning 196: Failure on closing input file '%s' (%d: %s)\n", filename, errno, + strerror(errno)); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; /* TODO: maybe new warning e.g. ZINT_WARN_INVALID_INPUT? */ + } + } + if (error_number == 0) { + error_number = warn_number; + } + return error_number; +} + +/* Stuff to convert args on Windows command line to UTF-8 */ +#ifdef _WIN32 +#include <windows.h> + +#ifndef WC_ERR_INVALID_CHARS +#define WC_ERR_INVALID_CHARS 0x00000080 +#endif + +static int win_argc = 0; +static char **win_argv = NULL; + +/* Free Windows args */ +static void win_free_args(void) { + int i; + if (!win_argv) { + return; + } + for (i = 0; i < win_argc; i++) { + if (!win_argv[i]) { + break; + } + free(win_argv[i]); + win_argv[i] = NULL; + } + free(win_argv); + win_argv = NULL; +} + +/* Using Wine version of `CommandLineToArgvW()` (slightly adapted) to avoid loading shell32.dll - see + https://source.winehq.org/git/wine.git/blob/5a66eab72:/dlls/shcore/main.c#l264 + and https://news.ycombinator.com/item?id=18596841 */ +/* + * Copyright 2002 Jon Griffiths + * Copyright 2016 Sebastian Lackner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +static WCHAR **win_CommandLineToArgvW(const WCHAR *cmdline, int *numargs) { + int qcount, bcount; + const WCHAR *s; + WCHAR **argv; + DWORD argc; + WCHAR *d; + + /* Adapted to require non-empty command line */ + if (*cmdline == 0) { + return NULL; + } + + /* --- First count the arguments */ + argc = 1; + s = cmdline; + /* The first argument, the executable path, follows special rules */ + if (*s == '"') { + /* The executable path ends at the next quote, no matter what */ + s++; + while (*s) + if (*s++ == '"') + break; + } else { + /* The executable path ends at the next space, no matter what */ + while (*s && *s != ' ' && *s != '\t') + s++; + } + /* Skip to the first argument, if any */ + while (*s == ' ' || *s == '\t') + s++; + if (*s) + argc++; + + /* Analyze the remaining arguments */ + qcount = bcount = 0; + while (*s) { + if ((*s == ' ' || *s == '\t') && qcount == 0) { + /* Skip to the next argument and count it if any */ + while (*s == ' ' || *s == '\t') + s++; + if (*s) + argc++; + bcount = 0; + } else if (*s == '\\') { + /* '\', count them */ + bcount++; + s++; + } else if (*s == '"') { + /* '"' */ + if ((bcount & 1) == 0) + qcount++; /* Unescaped '"' */ + s++; + bcount = 0; + /* Consecutive quotes, see comment in copying code below */ + while (*s == '"') { + qcount++; + s++; + } + qcount = qcount % 3; + if (qcount == 2) + qcount = 0; + } else { + /* A regular character */ + bcount = 0; + s++; + } + } + + /* Allocate in a single lump, the string array, and the strings that go + * with it. This way the caller can make a single LocalFree() call to free + * both, as per MSDN. + */ + argv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(WCHAR *) + (lstrlenW(cmdline) + 1) * sizeof(WCHAR)); + if (!argv) + return NULL; + + /* --- Then split and copy the arguments */ + argv[0] = d = lstrcpyW((WCHAR *)(argv + argc + 1), cmdline); + argc = 1; + /* The first argument, the executable path, follows special rules */ + if (*d == '"') { + /* The executable path ends at the next quote, no matter what */ + s = d + 1; + while (*s) { + if (*s == '"') { + s++; + break; + } + *d++ = *s++; + } + } else { + /* The executable path ends at the next space, no matter what */ + while (*d && *d != ' ' && *d != '\t') + d++; + s = d; + if (*s) + s++; + } + /* Close the executable path */ + *d++ = 0; + /* Skip to the first argument and initialize it if any */ + while (*s == ' ' || *s == '\t') + s++; + if (!*s) { + /* There are no parameters so we are all done */ + argv[argc] = NULL; + *numargs = argc; + return argv; + } + + /* Split and copy the remaining arguments */ + argv[argc++] = d; + qcount = bcount = 0; + while (*s) { + if ((*s == ' ' || *s == '\t') && qcount == 0) { + /* Close the argument */ + *d++ = 0; + bcount = 0; + + /* Skip to the next one and initialize it if any */ + do { + s++; + } while (*s == ' ' || *s == '\t'); + if (*s) + argv[argc++] = d; + } else if (*s == '\\') { + *d++ = *s++; + bcount++; + } else if (*s == '"') { + if ((bcount & 1) == 0) { + /* Preceded by an even number of '\', this is half that + * number of '\', plus a quote which we erase. + */ + d -= bcount / 2; + qcount++; + } else { + /* Preceded by an odd number of '\', this is half that + * number of '\' followed by a '"' + */ + d = d - bcount / 2 - 1; + *d++ = '"'; + } + s++; + bcount = 0; + /* Now count the number of consecutive quotes. Note that qcount + * already takes into account the opening quote if any, as well as + * the quote that lead us here. + */ + while (*s == '"') { + if (++qcount == 3) { + *d++ = '"'; + qcount = 0; + } + s++; + } + if (qcount == 2) + qcount = 0; + } else { + /* A regular character */ + *d++ = *s++; + bcount = 0; + } + } + *d = '\0'; + argv[argc] = NULL; + *numargs = argc; + + return argv; +} + +/* For Windows replace args with UTF-8 versions */ +static void win_args(int *p_argc, char ***p_argv) { + int i; + LPWSTR *szArgList = win_CommandLineToArgvW(GetCommandLineW(), &win_argc); + if (szArgList) { + if (!(win_argv = (char **) calloc(win_argc + 1, sizeof(char *)))) { + LocalFree(szArgList); + } else { + for (i = 0; i < win_argc; i++) { + const int len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, szArgList[i], -1, NULL, 0, + NULL /*lpDefaultChar*/, NULL /*lpUsedDefaultChar*/); + if (len == 0 || !(win_argv[i] = malloc(len + 1))) { + win_free_args(); + LocalFree(szArgList); + return; + } + if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, szArgList[i], -1, win_argv[i], len, + NULL /*lpDefaultChar*/, NULL /*lpUsedDefaultChar*/) == 0) { + win_free_args(); + LocalFree(szArgList); + return; + } + } + for (i = 0; i < win_argc; i++) { + (*p_argv)[i] = win_argv[i]; + } + *p_argc = win_argc; + LocalFree(szArgList); + } + } +} + +/* Convert UTF-8 to Windows wide chars. Ticket #288, props Marcel */ +#define utf8_to_wide(u, w, r) \ + { \ + int lenW; /* Includes NUL terminator */ \ + if ((lenW = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u, -1, NULL, 0)) == 0) return r; \ + w = (wchar_t *) z_alloca(sizeof(wchar_t) * lenW); \ + if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u, -1, w, lenW) == 0) return r; \ + } + +/* Do `fopen()` on Windows, assuming `filename` is UTF-8 encoded. Ticket #288, props Marcel */ +static FILE *win_fopen(const char *filename, const char *mode) { + wchar_t *filenameW, *modeW; + + utf8_to_wide(filename, filenameW, NULL); + utf8_to_wide(mode, modeW, NULL); + + return _wfopen(filenameW, modeW); +} +#endif /* _WIN32 */ + +/* Helper to free Windows args on exit */ +static int do_exit(int error_number) { +#ifdef _WIN32 + win_free_args(); +#endif + exit(error_number); + return error_number; /* Not reached */ +} + +typedef struct { const char *arg; int opt; } arg_opt; + +int main(int argc, char **argv) { + struct zint_symbol *my_symbol; + struct zint_seg segs[10] = {{0}}; + int error_number = 0; + int warn_number = 0; + int rotate_angle = 0; + int help = 0; + int data_cnt = 0; + int input_cnt = 0; + int batch_mode = 0; + int mirror_mode = 0; + int fullmultibyte = 0; + int mask = 0; + int separator = 0; + int addon_gap = 0; + int rows = 0; + char filetype[4] = {0}; + int output_given = 0; + int png_refused; + int val; + int i; + int ret; + char *outfile_extension; + int data_arg_num = 0; + int seg_count = 0; + float x_dim_mm = 0.0f, dpmm = 0.0f; + float float_opt; + char errbuf[64]; /* For `validate_float()` */ + arg_opt *arg_opts = (arg_opt *) z_alloca(sizeof(arg_opt) * argc); + + const int no_png = ZBarcode_NoPng(); + + if (argc == 1) { + usage(no_png); + exit(ZINT_ERROR_INVALID_DATA); + } + + my_symbol = ZBarcode_Create(); + if (!my_symbol) { + fprintf(stderr, "Error 151: Memory failure\n"); + exit(ZINT_ERROR_MEMORY); + } + my_symbol->input_mode = UNICODE_MODE; + +#ifdef _WIN32 + win_args(&argc, &argv); +#endif + + opterr = 0; /* Disable `getopt_long_only()` printing errors */ + while (1) { + enum options { + OPT_ADDONGAP = 128, OPT_BATCH, OPT_BINARY, OPT_BG, OPT_BIND, OPT_BIND_TOP, OPT_BOLD, OPT_BORDER, OPT_BOX, + OPT_CMYK, OPT_COLS, OPT_COMPLIANTHEIGHT, + OPT_DIRECT, OPT_DMISO144, OPT_DMRE, OPT_DOTSIZE, OPT_DOTTY, OPT_DUMP, + OPT_ECI, OPT_EMBEDFONT, OPT_ESC, OPT_EXTRAESC, OPT_FAST, OPT_FG, OPT_FILETYPE, OPT_FULLMULTIBYTE, + OPT_GS1, OPT_GS1NOCHECK, OPT_GS1PARENS, OPT_GSSEP, OPT_GUARDDESCENT, OPT_GUARDWHITESPACE, + OPT_HEIGHT, OPT_HEIGHTPERROW, OPT_INIT, OPT_MIRROR, OPT_MASK, OPT_MODE, + OPT_NOBACKGROUND, OPT_NOQUIETZONES, OPT_NOTEXT, OPT_PRIMARY, OPT_QUIETZONES, + OPT_ROTATE, OPT_ROWS, OPT_SCALE, OPT_SCALEXDIM, OPT_SCMVV, OPT_SECURE, + OPT_SEG1, OPT_SEG2, OPT_SEG3, OPT_SEG4, OPT_SEG5, OPT_SEG6, OPT_SEG7, OPT_SEG8, OPT_SEG9, + OPT_SEPARATOR, OPT_SMALL, OPT_SQUARE, OPT_STRUCTAPP, OPT_TEXTGAP, + OPT_VERBOSE, OPT_VERS, OPT_VWHITESP, OPT_WERROR + }; + static const struct option long_options[] = { + {"addongap", 1, NULL, OPT_ADDONGAP}, + {"barcode", 1, NULL, 'b'}, + {"batch", 0, NULL, OPT_BATCH}, + {"binary", 0, NULL, OPT_BINARY}, + {"bg", 1, 0, OPT_BG}, + {"bgcolor", 1, 0, OPT_BG}, /* Synonym */ + {"bgcolour", 1, 0, OPT_BG}, /* Synonym */ + {"bind", 0, NULL, OPT_BIND}, + {"bindtop", 0, NULL, OPT_BIND_TOP}, + {"bold", 0, NULL, OPT_BOLD}, + {"border", 1, NULL, OPT_BORDER}, + {"box", 0, NULL, OPT_BOX}, + {"cmyk", 0, NULL, OPT_CMYK}, + {"cols", 1, NULL, OPT_COLS}, + {"compliantheight", 0, NULL, OPT_COMPLIANTHEIGHT}, + {"data", 1, NULL, 'd'}, + {"direct", 0, NULL, OPT_DIRECT}, + {"dmiso144", 0, NULL, OPT_DMISO144}, + {"dmre", 0, NULL, OPT_DMRE}, + {"dotsize", 1, NULL, OPT_DOTSIZE}, + {"dotty", 0, NULL, OPT_DOTTY}, + {"dump", 0, NULL, OPT_DUMP}, + {"eci", 1, NULL, OPT_ECI}, + {"ecinos", 0, NULL, 'e'}, + {"embedfont", 0, NULL, OPT_EMBEDFONT}, + {"esc", 0, NULL, OPT_ESC}, + {"extraesc", 0, NULL, OPT_EXTRAESC}, + {"fast", 0, NULL, OPT_FAST}, + {"fg", 1, 0, OPT_FG}, + {"fgcolor", 1, 0, OPT_FG}, /* Synonym */ + {"fgcolour", 1, 0, OPT_FG}, /* Synonym */ + {"filetype", 1, NULL, OPT_FILETYPE}, + {"fullmultibyte", 0, NULL, OPT_FULLMULTIBYTE}, + {"gs1", 0, 0, OPT_GS1}, + {"gs1nocheck", 0, NULL, OPT_GS1NOCHECK}, + {"gs1parens", 0, NULL, OPT_GS1PARENS}, + {"gssep", 0, NULL, OPT_GSSEP}, + {"guarddescent", 1, NULL, OPT_GUARDDESCENT}, + {"guardwhitespace", 0, NULL, OPT_GUARDWHITESPACE}, + {"height", 1, NULL, OPT_HEIGHT}, + {"heightperrow", 0, NULL, OPT_HEIGHTPERROW}, + {"help", 0, NULL, 'h'}, + {"init", 0, NULL, OPT_INIT}, + {"input", 1, NULL, 'i'}, + {"mirror", 0, NULL, OPT_MIRROR}, + {"mask", 1, NULL, OPT_MASK}, + {"mode", 1, NULL, OPT_MODE}, + {"nobackground", 0, NULL, OPT_NOBACKGROUND}, + {"noquietzones", 0, NULL, OPT_NOQUIETZONES}, + {"notext", 0, NULL, OPT_NOTEXT}, + {"output", 1, NULL, 'o'}, + {"primary", 1, NULL, OPT_PRIMARY}, + {"quietzones", 0, NULL, OPT_QUIETZONES}, + {"reverse", 0, NULL, 'r'}, + {"rotate", 1, NULL, OPT_ROTATE}, + {"rows", 1, NULL, OPT_ROWS}, + {"scale", 1, NULL, OPT_SCALE}, + {"scalexdimdp", 1, NULL, OPT_SCALEXDIM}, + {"scmvv", 1, NULL, OPT_SCMVV}, + {"secure", 1, NULL, OPT_SECURE}, + {"seg1", 1, NULL, OPT_SEG1}, + {"seg2", 1, NULL, OPT_SEG2}, + {"seg3", 1, NULL, OPT_SEG3}, + {"seg4", 1, NULL, OPT_SEG4}, + {"seg5", 1, NULL, OPT_SEG5}, + {"seg6", 1, NULL, OPT_SEG6}, + {"seg7", 1, NULL, OPT_SEG7}, + {"seg8", 1, NULL, OPT_SEG8}, + {"seg9", 1, NULL, OPT_SEG9}, + {"separator", 1, NULL, OPT_SEPARATOR}, + {"small", 0, NULL, OPT_SMALL}, + {"square", 0, NULL, OPT_SQUARE}, + {"structapp", 1, NULL, OPT_STRUCTAPP}, + {"textgap", 1, NULL, OPT_TEXTGAP}, + {"types", 0, NULL, 't'}, + {"verbose", 0, NULL, OPT_VERBOSE}, /* Currently undocumented, output some debug info */ + {"vers", 1, NULL, OPT_VERS}, + {"version", 0, NULL, 'v'}, + {"vwhitesp", 1, NULL, OPT_VWHITESP}, + {"werror", 0, NULL, OPT_WERROR}, + {"whitesp", 1, NULL, 'w'}, + {NULL, 0, NULL, 0} + }; + const int c = getopt_long_only(argc, argv, "b:d:ehi:o:rtvw:", long_options, NULL); + if (c == -1) break; + + switch (c) { + case OPT_ADDONGAP: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 139: Invalid add-on gap value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val >= 7 && val <= 12) { + addon_gap = val; + } else { + fprintf(stderr, "Warning 140: Add-on gap '%d' out of range (7 to 12), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_BATCH: + if (data_cnt == 0) { + /* Switch to batch processing mode */ + batch_mode = 1; + } else { + fprintf(stderr, "Warning 141: Can't use batch mode if data given, ignoring\n"); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_BG: + strncpy(my_symbol->bgcolour, optarg, 15); /* Allow for "CCC,MMM,YYY,KKK" */ + break; + case OPT_BINARY: + my_symbol->input_mode = (my_symbol->input_mode & ~0x07) | DATA_MODE; + break; + case OPT_BIND: + my_symbol->output_options |= BARCODE_BIND; + break; + case OPT_BIND_TOP: + my_symbol->output_options |= BARCODE_BIND_TOP; + break; + case OPT_BOLD: + my_symbol->output_options |= BOLD_TEXT; + break; + case OPT_BORDER: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 107: Invalid border width value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val <= 1000) { /* `val` >= 0 always */ + my_symbol->border_width = val; + } else { + fprintf(stderr, "Warning 108: Border width '%d' out of range (0 to 1000), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_BOX: + my_symbol->output_options |= BARCODE_BOX; + break; + case OPT_CMYK: + my_symbol->output_options |= CMYK_COLOUR; + break; + case OPT_COLS: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 131: Invalid columns value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if ((val >= 1) && (val <= 200)) { + my_symbol->option_2 = val; + } else { + fprintf(stderr, "Warning 111: Number of columns '%d' out of range (1 to 200), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_COMPLIANTHEIGHT: + my_symbol->output_options |= COMPLIANT_HEIGHT; + break; + case OPT_DIRECT: + my_symbol->output_options |= BARCODE_STDOUT; + break; + case OPT_DMISO144: + my_symbol->option_3 |= DM_ISO_144; + break; + case OPT_DMRE: + /* Square overwrites DMRE */ + if ((my_symbol->option_3 & 0x7F) != DM_SQUARE) { + my_symbol->option_3 = DM_DMRE | (my_symbol->option_3 & ~0x7F); + } + break; + case OPT_DOTSIZE: + if (!validate_float(optarg, 0 /*allow_neg*/, &float_opt, errbuf)) { + fprintf(stderr, "Error 181: Invalid dot radius floating point (%s)\n", errbuf); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (float_opt >= 0.01f) { + my_symbol->dot_size = float_opt; + } else { + fprintf(stderr, "Warning 106: Invalid dot radius value (less than 0.01), ignoring\n"); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_DOTTY: + my_symbol->output_options |= BARCODE_DOTTY_MODE; + break; + case OPT_DUMP: + my_symbol->output_options |= BARCODE_STDOUT; + strcpy(my_symbol->outfile, "dummy.txt"); + break; + case OPT_ECI: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 138: Invalid ECI code (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val <= 999999) { /* `val` >= 0 always */ + my_symbol->eci = val; + } else { + fprintf(stderr, "Warning 118: ECI code '%d' out of range (0 to 999999), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_EMBEDFONT: + my_symbol->output_options |= EMBED_VECTOR_FONT; + break; + case OPT_ESC: + my_symbol->input_mode |= ESCAPE_MODE; + break; + case OPT_EXTRAESC: + my_symbol->input_mode |= EXTRA_ESCAPE_MODE; + break; + case OPT_FAST: + my_symbol->input_mode |= FAST_MODE; + break; + case OPT_FG: + strncpy(my_symbol->fgcolour, optarg, 15); /* Allow for "CCC,MMM,YYY,KKK" */ + break; + case OPT_FILETYPE: + /* Select the type of output file */ + if (supported_filetype(optarg, no_png, &png_refused)) { + strncpy(filetype, optarg, (size_t) 3); + } else { + if (png_refused) { + fprintf(stderr, "Warning 152: PNG format disabled at compile time, ignoring\n"); + } else { + fprintf(stderr, "Warning 142: File type '%s' not supported, ignoring\n", optarg); + } + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_FULLMULTIBYTE: + fullmultibyte = 1; + break; + case OPT_GS1: + my_symbol->input_mode = (my_symbol->input_mode & ~0x07) | GS1_MODE; + break; + case OPT_GS1NOCHECK: + my_symbol->input_mode |= GS1NOCHECK_MODE; + break; + case OPT_GS1PARENS: + my_symbol->input_mode |= GS1PARENS_MODE; + break; + case OPT_GSSEP: + my_symbol->output_options |= GS1_GS_SEPARATOR; + break; + case OPT_GUARDDESCENT: + if (!validate_float(optarg, 0 /*allow_neg*/, &float_opt, errbuf)) { + fprintf(stderr, "Error 182: Invalid guard bar descent floating point (%s)\n", errbuf); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (float_opt >= 0.0f && float_opt <= 50.0f) { + my_symbol->guard_descent = float_opt; + } else { + fprintf(stderr, "Warning 135: Guard bar descent '%g' out of range (0 to 50), ignoring\n", + float_opt); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_GUARDWHITESPACE: + my_symbol->output_options |= EANUPC_GUARD_WHITESPACE; + break; + case OPT_HEIGHT: + if (!validate_float(optarg, 0 /*allow_neg*/, &float_opt, errbuf)) { + fprintf(stderr, "Error 183: Invalid symbol height floating point (%s)\n", errbuf); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (float_opt >= 0.5f && float_opt <= 2000.0f) { + my_symbol->height = float_opt; + } else { + fprintf(stderr, "Warning 110: Symbol height '%g' out of range (0.5 to 2000), ignoring\n", + float_opt); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_HEIGHTPERROW: + my_symbol->input_mode |= HEIGHTPERROW_MODE; + break; + case OPT_INIT: + my_symbol->output_options |= READER_INIT; + break; + case OPT_MIRROR: + /* Use filenames which reflect content */ + mirror_mode = 1; + break; + case OPT_MASK: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 148: Invalid mask value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val <= 7) { /* `val` >= 0 always */ + mask = val + 1; + } else { + /* mask pattern >= 0 and <= 7 (i.e. values >= 1 and <= 8) only permitted */ + fprintf(stderr, "Warning 147: Mask value '%d' out of range (0 to 7), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_MODE: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 136: Invalid mode value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val <= 6) { /* `val` >= 0 always */ + my_symbol->option_1 = val; + } else { + fprintf(stderr, "Warning 116: Mode value '%d' out of range (0 to 6), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_NOBACKGROUND: + strcpy(my_symbol->bgcolour, "ffffff00"); + break; + case OPT_NOQUIETZONES: + my_symbol->output_options |= BARCODE_NO_QUIET_ZONES; + break; + case OPT_NOTEXT: + my_symbol->show_hrt = 0; + break; + case OPT_PRIMARY: + if (strlen(optarg) <= 127) { + strcpy(my_symbol->primary, optarg); + } else { + strncpy(my_symbol->primary, optarg, 127); + fprintf(stderr, + "Warning 115: Primary data string too long (127 character maximum), truncating\n"); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_QUIETZONES: + my_symbol->output_options |= BARCODE_QUIET_ZONES; + break; + case OPT_ROTATE: + /* Only certain inputs allowed */ + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 117: Invalid rotation value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + switch (val) { + case 0: + case 90: + case 180: + case 270: + rotate_angle = val; + break; + default: + fprintf(stderr, "Warning 137: Rotation value '%d' out of range (0, 90, 180 or 270 only)," + " ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + break; + } + break; + case OPT_ROWS: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 132: Invalid rows value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if ((val >= 1) && (val <= 90)) { + rows = val; + } else { + fprintf(stderr, "Warning 112: Number of rows '%d' out of range (1 to 90), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_SCALE: + if (!validate_float(optarg, 0 /*allow_neg*/, &float_opt, errbuf)) { + fprintf(stderr, "Error 184: Invalid scale floating point (%s)\n", errbuf); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (float_opt >= 0.01f) { + my_symbol->scale = float_opt; + } else { + fprintf(stderr, "Warning 105: Invalid scale value '%g' (less than 0.01), ignoring\n", float_opt); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_SCALEXDIM: + if (!validate_scalexdimdp(optarg, &x_dim_mm, &dpmm)) { + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (x_dim_mm > 10.0f || dpmm > 1000.0f) { + if (x_dim_mm > 10.0f) { + fprintf(stderr, "Warning 185: scalexdimdp X-dim '%g' out of range (greater than 10)," + " ignoring\n", x_dim_mm); + } else { + fprintf(stderr, "Warning 186: scalexdimdp resolution '%g' out of range (greater than 1000)," + " ignoring\n", dpmm); + } + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + x_dim_mm = dpmm = 0.0f; + } + break; + case OPT_SCMVV: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 149: Invalid Structured Carrier Message version value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val <= 99) { /* `val` >= 0 always */ + my_symbol->option_2 = val + 1; + } else { + /* Version 00-99 only */ + fprintf(stderr, "Warning 150: Structured Carrier Message version '%d' out of range (0 to 99)," + " ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_SECURE: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 134: Invalid ECC value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val <= 8) { /* `val` >= 0 always */ + my_symbol->option_1 = val; + } else { + fprintf(stderr, "Warning 114: ECC level '%d' out of range (0 to 8), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_SEG1: + case OPT_SEG2: + case OPT_SEG3: + case OPT_SEG4: + case OPT_SEG5: + case OPT_SEG6: + case OPT_SEG7: + case OPT_SEG8: + case OPT_SEG9: + if (batch_mode == 0) { + val = c - OPT_SEG1 + 1; /* Segment number */ + if (segs[val].source) { + fprintf(stderr, "Error 164: Duplicate segment %d\n", val); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (!validate_seg(optarg, c - OPT_SEG1 + 1, segs)) { + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val >= seg_count) { + seg_count = val + 1; + } + } else { + fprintf(stderr, "Warning 165: Can't define segments in batch mode, ignoring '%s'\n", optarg); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_SEPARATOR: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 128: Invalid separator value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val <= 4) { /* `val` >= 0 always */ + separator = val; + } else { + /* Greater than 4 values are not permitted */ + fprintf(stderr, "Warning 127: Separator value '%d' out of range (0 to 4), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_SMALL: + my_symbol->output_options |= SMALL_TEXT; + break; + case OPT_SQUARE: + my_symbol->option_3 = DM_SQUARE | (my_symbol->option_3 & ~0x7F); + break; + case OPT_STRUCTAPP: + memset(&my_symbol->structapp, 0, sizeof(my_symbol->structapp)); + if (!validate_structapp(optarg, &my_symbol->structapp)) { + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + break; + case OPT_TEXTGAP: + if (!validate_float(optarg, 1 /*allow_neg*/, &float_opt, errbuf)) { + fprintf(stderr, "Error 194: Invalid text gap floating point (%s)\n", errbuf); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (float_opt >= -5.0f && float_opt <= 10.0f) { + my_symbol->text_gap = float_opt; + } else { + fprintf(stderr, "Warning 195: Text gap '%g' out of range (-5 to 10), ignoring\n", + float_opt); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_VERBOSE: + my_symbol->debug = 1; + break; + case OPT_VERS: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 133: Invalid version value (digits only)\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if ((val >= 1) && (val <= 999)) { + my_symbol->option_2 = val; + } else { + fprintf(stderr, "Warning 113: Version value '%d' out of range (1 to 999), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_VWHITESP: + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 153: Invalid vertical whitespace value '%s' (digits only)\n", optarg); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val <= 1000) { /* `val` >= 0 always */ + my_symbol->whitespace_height = val; + } else { + fprintf(stderr, + "Warning 154: Vertical whitespace value '%d' out of range (0 to 1000), ignoring\n", val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + case OPT_WERROR: + my_symbol->warn_level = WARN_FAIL_ALL; + break; + + case 'h': + usage(no_png); + help = 1; + break; + case 'v': + version(no_png); + help = 1; + break; + case 't': + types(); + help = 1; + break; + case 'e': + show_eci(); + help = 1; + break; + + case 'b': + if (!validate_int(optarg, -1 /*len*/, &val) && !(val = get_barcode_name(optarg))) { + fprintf(stderr, "Error 119: Invalid barcode type '%s'\n", optarg); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + my_symbol->symbology = val; + break; + + case 'w': + if (!validate_int(optarg, -1 /*len*/, &val)) { + fprintf(stderr, "Error 120: Invalid horizontal whitespace value '%s' (digits only)\n", optarg); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (val <= 1000) { /* `val` >= 0 always */ + my_symbol->whitespace_width = val; + } else { + fprintf(stderr, + "Warning 121: Horizontal whitespace value '%d' out of range (0 to 1000), ignoring\n", + val); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + + case 'd': /* we have some data! */ + if (batch_mode == 0) { + arg_opts[data_arg_num].arg = optarg; + arg_opts[data_arg_num].opt = c; + data_arg_num++; + data_cnt++; + } else { + fprintf(stderr, "Warning 122: Can't define data in batch mode, ignoring '%s'\n", optarg); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + + case 'i': /* Take data from file */ + if (batch_mode == 0 || input_cnt == 0) { + arg_opts[data_arg_num].arg = optarg; + arg_opts[data_arg_num].opt = c; + data_arg_num++; + input_cnt++; + } else { + fprintf(stderr, "Warning 143: Can only define one input file in batch mode, ignoring '%s'\n", + optarg); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + break; + + case 'o': + strncpy(my_symbol->outfile, optarg, 255); + output_given = 1; + break; + + case 'r': + strcpy(my_symbol->fgcolour, "ffffff"); + strcpy(my_symbol->bgcolour, "000000"); + break; + + case '?': + if (optopt) { + for (i = 0; i < ARRAY_SIZE(long_options) && long_options[i].val != optopt; i++); + if (i == ARRAY_SIZE(long_options)) { /* Shouldn't happen */ + fprintf(stderr, "Error 125: ?? unknown optopt '%d'\n", optopt); /* Not reached */ + return do_exit(ZINT_ERROR_ENCODING_PROBLEM); + } + if (long_options[i].has_arg) { + fprintf(stderr, "Error 109: option '%s' requires an argument\n", argv[optind - 1]); + } else { + const char *eqs = strchr(argv[optind - 1], '='); + const int optlen = eqs ? (int) (eqs - argv[optind - 1]) : (int) strlen(argv[optind - 1]); + fprintf(stderr, "Error 126: option '%.*s' does not take an argument\n", optlen, + argv[optind - 1]); + } + } else { + fprintf(stderr, "Error 101: unknown option '%s'\n", argv[optind - 1]); + } + return do_exit(ZINT_ERROR_INVALID_OPTION); + break; + + default: /* Shouldn't happen */ + fprintf(stderr, "Error 123: ?? getopt error 0%o\n", c); /* Not reached */ + return do_exit(ZINT_ERROR_ENCODING_PROBLEM); + break; + } + } + if (optind != argc) { + if (optind + 1 == argc) { + fprintf(stderr, "Warning 191: extra argument '%s' ignoring\n", argv[optind]); + } else { + fprintf(stderr, "Warning 192: extra arguments beginning with '%s' ignoring\n", argv[optind]); + } + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + + if (data_arg_num) { + const int symbology = my_symbol->symbology; + const unsigned int cap = ZBarcode_Cap(symbology, ZINT_CAP_STACKABLE | ZINT_CAP_EXTENDABLE | + ZINT_CAP_FULL_MULTIBYTE | ZINT_CAP_MASK); + if (fullmultibyte && (cap & ZINT_CAP_FULL_MULTIBYTE)) { + my_symbol->option_3 = ZINT_FULL_MULTIBYTE; + } + if (mask && (cap & ZINT_CAP_MASK)) { + my_symbol->option_3 |= mask << 8; + } + if (separator && (cap & ZINT_CAP_STACKABLE)) { + my_symbol->option_3 = separator; + } + if (addon_gap && (cap & ZINT_CAP_EXTENDABLE)) { + my_symbol->option_2 = addon_gap; + } + if (rows) { + if (symbology == BARCODE_PDF417 || symbology == BARCODE_PDF417COMP || symbology == BARCODE_HIBC_PDF + || symbology == BARCODE_DBAR_EXPSTK || symbology == BARCODE_DBAR_EXPSTK_CC) { + my_symbol->option_3 = rows; + } else if (symbology == BARCODE_CODABLOCKF || symbology == BARCODE_HIBC_BLOCKF + || symbology == BARCODE_CODE16K || symbology == BARCODE_CODE49) { + my_symbol->option_1 = rows; + } + } + + if (output_given && (my_symbol->output_options & BARCODE_STDOUT)) { + my_symbol->output_options &= ~BARCODE_STDOUT; + fprintf(stderr, "Warning 193: Output file given, ignoring '--direct' option\n"); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + if (batch_mode) { + /* Take each line of text as a separate data set */ + if (data_arg_num > 1) { + fprintf(stderr, "Warning 144: Processing first input file '%s' only\n", arg_opts[0].arg); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + if (seg_count) { + fprintf(stderr, "Warning 169: Ignoring segment arguments\n"); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + if (filetype[0] == '\0') { + outfile_extension = get_extension(my_symbol->outfile); + if (outfile_extension && supported_filetype(outfile_extension, no_png, NULL)) { + strcpy(filetype, outfile_extension); + } else { + strcpy(filetype, no_png ? "gif" : "png"); + } + } + if (dpmm) { /* Allow `x_dim_mm` to be zero */ + if (x_dim_mm == 0.0f) { + x_dim_mm = ZBarcode_Default_Xdim(symbology); + } + float_opt = ZBarcode_Scale_From_XdimDp(symbology, x_dim_mm, dpmm, filetype); + if (float_opt > 0.0f) { + my_symbol->scale = float_opt; + my_symbol->dpmm = dpmm; + } else { + fprintf(stderr, "Warning 187: Invalid scalexdimdp X-dim '%g', resolution '%g' combo, ignoring\n", + x_dim_mm, dpmm); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + } + if (((symbology != BARCODE_MAXICODE && my_symbol->scale < 0.5f) || my_symbol->scale < 0.2f) + && is_raster(filetype, no_png)) { + const int min = symbology != BARCODE_MAXICODE ? 5 : 2; + fprintf(stderr, "Warning 145: Scaling less than 0.%d will be set to 0.%d for '%s' output\n", min, min, + filetype); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + error_number = batch_process(my_symbol, arg_opts[0].arg, mirror_mode, filetype, output_given, + rotate_angle); + } else { + if (seg_count) { + if (data_arg_num > 1) { + fprintf(stderr, "Error 170: Cannot specify segments and multiple data arguments together\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + if (arg_opts[0].opt != 'd') { /* For simplicity disallow input args for now */ + fprintf(stderr, "Error 171: Cannot use input argument with segment arguments\n"); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + segs[0].eci = my_symbol->eci; + segs[0].source = (unsigned char *) arg_opts[0].arg; + segs[0].length = (int) strlen(arg_opts[0].arg); + for (i = 0; i < seg_count; i++) { + if (segs[i].source == NULL) { + fprintf(stderr, "Error 172: Segments must be consecutive - segment %d missing\n", i); + return do_exit(ZINT_ERROR_INVALID_OPTION); + } + } + } + if (filetype[0] != '\0') { + set_extension(my_symbol->outfile, filetype); + } + if (dpmm) { /* Allow `x_dim_mm` to be zero */ + if (x_dim_mm == 0.0f) { + x_dim_mm = ZBarcode_Default_Xdim(symbology); + } + float_opt = ZBarcode_Scale_From_XdimDp(symbology, x_dim_mm, dpmm, get_extension(my_symbol->outfile)); + if (float_opt > 0.0f) { + my_symbol->scale = float_opt; + my_symbol->dpmm = dpmm; + } else { + fprintf(stderr, "Warning 190: Invalid scalexdimdp X-dim '%g', resolution '%g' combo, ignoring\n", + x_dim_mm, dpmm); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + } + if (((symbology != BARCODE_MAXICODE && my_symbol->scale < 0.5f) || my_symbol->scale < 0.2f) + && is_raster(get_extension(my_symbol->outfile), no_png)) { + const int min = symbology != BARCODE_MAXICODE ? 5 : 2; + fprintf(stderr, "Warning 146: Scaling less than 0.%d will be set to 0.%d for '%s' output\n", min, min, + get_extension(my_symbol->outfile)); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + for (i = 0; i < data_arg_num; i++) { + if (arg_opts[i].opt == 'd') { + if (seg_count) { + ret = ZBarcode_Encode_Segs(my_symbol, segs, seg_count); + } else { + if (i == 1 && (ZBarcode_Cap(symbology, ZINT_CAP_STACKABLE) & ZINT_CAP_STACKABLE) == 0) { + fprintf(stderr, + "Error 173: Symbology must be stackable if multiple data arguments given\n"); + fflush(stderr); + error_number = ZINT_ERROR_INVALID_DATA; + break; + } + ret = ZBarcode_Encode(my_symbol, (unsigned char *) arg_opts[i].arg, + (int) strlen(arg_opts[i].arg)); + } + } else { + ret = ZBarcode_Encode_File(my_symbol, arg_opts[i].arg); + } + if (ret != 0) { + fprintf(stderr, "%s\n", my_symbol->errtxt); + fflush(stderr); + if (error_number < ZINT_ERROR) { + error_number = ret; + } + } + } + if (error_number < ZINT_ERROR) { + error_number = ZBarcode_Print(my_symbol, rotate_angle); + + if (error_number != 0) { + fprintf(stderr, "%s\n", my_symbol->errtxt); + fflush(stderr); + } + } + } + } else if (help == 0) { + fprintf(stderr, "Warning 124: No data received, no symbol generated\n"); + fflush(stderr); + warn_number = ZINT_WARN_INVALID_OPTION; + } + + ZBarcode_Delete(my_symbol); + + return do_exit(error_number ? error_number : warn_number); +} + +/* vim: set ts=4 sw=4 et : */
