Mercurial > hgrepos > Python2 > PyMuPDF
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/zint/backend/library.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,2078 @@ +/* library.c - external functions of libzint */ +/* + libzint - the open source barcode library + Copyright (C) 2009-2024 Robin Stuart <rstuart114@gmail.com> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <math.h> +#include <stdio.h> +#include "common.h" +#include "eci.h" +#include "gs1.h" +#include "output.h" +#include "zfiletypes.h" + +/* 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]; + +typedef char static_assert_uint16_is_16bits[sizeof(uint16_t) * CHAR_BIT != 16 ? -1 : 1]; +typedef char static_assert_int32_is_32bits[sizeof(int32_t) * CHAR_BIT != 32 ? -1 : 1]; +typedef char static_assert_uint32_is_32bits[sizeof(uint32_t) * CHAR_BIT != 32 ? -1 : 1]; +typedef char static_assert_uint64_at_least_64bits[sizeof(uint64_t) * CHAR_BIT < 64 ? -1 : 1]; + +/* Set `symbol` to defaults (does not zeroize) */ +static void set_symbol_defaults(struct zint_symbol *symbol) { + + symbol->symbology = BARCODE_CODE128; + symbol->scale = 1.0f; + strcpy(symbol->fgcolour, "000000"); + symbol->fgcolor = &symbol->fgcolour[0]; + strcpy(symbol->bgcolour, "ffffff"); + symbol->bgcolor = &symbol->bgcolour[0]; +#ifdef ZINT_NO_PNG + strcpy(symbol->outfile, "out.gif"); +#else + strcpy(symbol->outfile, "out.png"); +#endif + symbol->option_1 = -1; + symbol->show_hrt = 1; /* Show human readable text */ + symbol->input_mode = DATA_MODE; + symbol->eci = 0; /* Default 0 uses ECI 3 */ + symbol->dot_size = 0.8f; /* 0.4 / 0.5 */ + symbol->text_gap = 1.0f; + symbol->guard_descent = 5.0f; + symbol->warn_level = WARN_DEFAULT; + symbol->bitmap = NULL; + symbol->alphamap = NULL; + symbol->vector = NULL; + symbol->memfile = NULL; +} + +/* Create and initialize a symbol structure */ +struct zint_symbol *ZBarcode_Create(void) { + struct zint_symbol *symbol; + + symbol = (struct zint_symbol *) calloc(1, sizeof(*symbol)); + if (!symbol) return NULL; + + set_symbol_defaults(symbol); + + return symbol; +} + +INTERNAL void vector_free(struct zint_symbol *symbol); /* Free vector structures */ + +/* Free any output buffers that may have been created and initialize output fields */ +void ZBarcode_Clear(struct zint_symbol *symbol) { + int i; + + if (!symbol) return; + + for (i = 0; i < symbol->rows; i++) { + memset(symbol->encoded_data[i], 0, sizeof(symbol->encoded_data[0])); + } + symbol->rows = 0; + symbol->width = 0; + memset(symbol->row_height, 0, sizeof(symbol->row_height)); + memset(symbol->text, 0, sizeof(symbol->text)); + symbol->errtxt[0] = '\0'; + if (symbol->bitmap != NULL) { + free(symbol->bitmap); + symbol->bitmap = NULL; + } + if (symbol->alphamap != NULL) { + free(symbol->alphamap); + symbol->alphamap = NULL; + } + symbol->bitmap_width = 0; + symbol->bitmap_height = 0; + if (symbol->memfile != NULL) { + free(symbol->memfile); + symbol->memfile = NULL; + } + symbol->memfile_size = 0; + + /* If there is a rendered version, ensure its memory is released */ + vector_free(symbol); +} + +/* Free any output buffers that may have been created and reset all fields to defaults */ +void ZBarcode_Reset(struct zint_symbol *symbol) { + if (!symbol) return; + + if (symbol->bitmap != NULL) + free(symbol->bitmap); + if (symbol->alphamap != NULL) + free(symbol->alphamap); + if (symbol->memfile != NULL) + free(symbol->memfile); + + vector_free(symbol); + + memset(symbol, 0, sizeof(*symbol)); + set_symbol_defaults(symbol); +} + +/* Free a symbol structure, including any output buffers */ +void ZBarcode_Delete(struct zint_symbol *symbol) { + if (!symbol) return; + + if (symbol->bitmap != NULL) + free(symbol->bitmap); + if (symbol->alphamap != NULL) + free(symbol->alphamap); + if (symbol->memfile != NULL) + free(symbol->memfile); + + vector_free(symbol); + + free(symbol); +} + +/* Symbology handlers */ +INTERNAL int eanx(struct zint_symbol *symbol, unsigned char source[], int length); /* EAN system barcodes */ +INTERNAL int code39(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 3 from 9 (or Code 39) */ +INTERNAL int pzn(struct zint_symbol *symbol, unsigned char source[], int length); /* Pharmazentral Nummer (PZN) */ +/* Extended Code 3 from 9 (or Code 39+) */ +INTERNAL int excode39(struct zint_symbol *symbol, unsigned char source[], int length); +/* Codabar - a simple substitution cipher */ +INTERNAL int codabar(struct zint_symbol *symbol, unsigned char source[], int length); +/* Code 2 of 5 Standard (& Matrix) */ +INTERNAL int c25standard(struct zint_symbol *symbol, unsigned char source[], int length); +INTERNAL int c25ind(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 Industrial */ +INTERNAL int c25iata(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 IATA */ +INTERNAL int c25inter(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 Interleaved */ +INTERNAL int c25logic(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 2 of 5 Data Logic */ +INTERNAL int itf14(struct zint_symbol *symbol, unsigned char source[], int length); /* ITF-14 */ +INTERNAL int dpleit(struct zint_symbol *symbol, unsigned char source[], int length); /* Deutsche Post Leitcode */ +INTERNAL int dpident(struct zint_symbol *symbol, unsigned char source[], int length); /* Deutsche Post Identcode */ +/* Code 93 - a re-working of Code 39+, generates 2 check digits */ +INTERNAL int code93(struct zint_symbol *symbol, unsigned char source[], int length); +INTERNAL int code128(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 128 and NVE-18 */ +INTERNAL int gs1_128(struct zint_symbol *symbol, unsigned char source[], int length); /* EAN-128 (GS1-128) */ +INTERNAL int code11(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 11 */ +INTERNAL int msi_plessey(struct zint_symbol *symbol, unsigned char source[], int length); /* MSI Plessey */ +INTERNAL int telepen(struct zint_symbol *symbol, unsigned char source[], int length); /* Telepen ASCII */ +INTERNAL int telepen_num(struct zint_symbol *symbol, unsigned char source[], int length); /* Telepen Numeric */ +INTERNAL int plessey(struct zint_symbol *symbol, unsigned char source[], int length); /* Plessey Code */ +INTERNAL int pharma(struct zint_symbol *symbol, unsigned char source[], int length); /* Pharmacode One Track */ +INTERNAL int flat(struct zint_symbol *symbol, unsigned char source[], int length); /* Flattermarken */ +INTERNAL int fim(struct zint_symbol *symbol, unsigned char source[], int length); /* Facing Identification Mark */ +INTERNAL int pharma_two(struct zint_symbol *symbol, unsigned char source[], int length); /* Pharmacode Two Track */ +INTERNAL int postnet(struct zint_symbol *symbol, unsigned char source[], int length); /* Postnet */ +INTERNAL int planet(struct zint_symbol *symbol, unsigned char source[], int length); /* PLANET */ +/* Intelligent Mail (aka USPS OneCode) */ +INTERNAL int usps_imail(struct zint_symbol *symbol, unsigned char source[], int length); +INTERNAL int rm4scc(struct zint_symbol *symbol, unsigned char source[], int length); /* RM4SCC */ +INTERNAL int auspost(struct zint_symbol *symbol, unsigned char source[], int length); /* Australia Post 4-state */ +INTERNAL int code16k(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 16k */ +INTERNAL int pdf417(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* PDF417 */ +INTERNAL int micropdf417(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Micro PDF417 */ +INTERNAL int maxicode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Maxicode */ +INTERNAL int dbar_omn(struct zint_symbol *symbol, unsigned char source[], int length); /* DataBar Omnidirectional */ +INTERNAL int dbar_ltd(struct zint_symbol *symbol, unsigned char source[], int length); /* DataBar Limited */ +INTERNAL int dbar_exp(struct zint_symbol *symbol, unsigned char source[], int length); /* DataBar Expanded */ +INTERNAL int composite(struct zint_symbol *symbol, unsigned char source[], int length); /* Composite Symbology */ +INTERNAL int kix(struct zint_symbol *symbol, unsigned char source[], int length); /* TNT KIX Code */ +INTERNAL int aztec(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Aztec Code */ +INTERNAL int code32(struct zint_symbol *symbol, unsigned char source[], int length); /* Italian Pharmacode */ +INTERNAL int daft(struct zint_symbol *symbol, unsigned char source[], int length); /* DAFT Code */ +INTERNAL int ean14(struct zint_symbol *symbol, unsigned char source[], int length); /* EAN-14 */ +INTERNAL int nve18(struct zint_symbol *symbol, unsigned char source[], int length); /* NVE-18 */ +INTERNAL int microqr(struct zint_symbol *symbol, unsigned char source[], int length); /* Micro QR Code */ +INTERNAL int azrune(struct zint_symbol *symbol, unsigned char source[], int length); /* Aztec Runes */ +INTERNAL int koreapost(struct zint_symbol *symbol, unsigned char source[], int length); /* Korea Post */ +INTERNAL int japanpost(struct zint_symbol *symbol, unsigned char source[], int length); /* Japanese Post */ +INTERNAL int code49(struct zint_symbol *symbol, unsigned char source[], int length); /* Code 49 */ +INTERNAL int channel(struct zint_symbol *symbol, unsigned char source[], int length); /* Channel Code */ +INTERNAL int codeone(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Code One */ +INTERNAL int gridmatrix(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Grid Matrix */ +INTERNAL int hanxin(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Han Xin */ +INTERNAL int dotcode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* DotCode */ +INTERNAL int codablockf(struct zint_symbol *symbol, unsigned char source[], int length); /* Codablock */ +INTERNAL int upnqr(struct zint_symbol *symbol, unsigned char source[], int length); /* UPNQR */ +INTERNAL int qrcode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* QR Code */ +/* Data Matrix (IEC16022) */ +INTERNAL int datamatrix(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); +/* VIN Code (Vehicle Identification Number) */ +INTERNAL int vin(struct zint_symbol *symbol, unsigned char source[], int length); +/* Royal Mail 2D Mailmark */ +INTERNAL int mailmark_2d(struct zint_symbol *symbol, unsigned char source[], int length); +/* Royal Mail 4-state Mailmark */ +INTERNAL int mailmark_4s(struct zint_symbol *symbol, unsigned char source[], int length); +INTERNAL int upu_s10(struct zint_symbol *symbol, unsigned char source[], int length); /* Universal Postal Union S10 */ +INTERNAL int ultra(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* Ultracode */ +INTERNAL int rmqr(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); /* rMQR */ +INTERNAL int dpd(struct zint_symbol *symbol, unsigned char source[], int length); /* DPD Code */ +INTERNAL int bc412(struct zint_symbol *symbol, unsigned char source[], int length); /* BC412 */ +INTERNAL int dxfilmedge(struct zint_symbol *symbol, unsigned char source[], int length); /* DX Film Edge Barcode */ + +/* Output handlers */ +/* Plot to BMP/GIF/PCX/PNG/TIF */ +INTERNAL int plot_raster(struct zint_symbol *symbol, int rotate_angle, int file_type); +/* Plot to EMF/EPS/SVG */ +INTERNAL int plot_vector(struct zint_symbol *symbol, int rotate_angle, int file_type); + +/* Prefix error message with Error/Warning */ +static int error_tag(int error_number, struct zint_symbol *symbol, const int err_id, const char *error_string) { + + if (error_number != 0) { + if (error_string) { + errtxt(0, symbol, err_id, error_string); + } + if (error_number < ZINT_ERROR && symbol->warn_level == WARN_FAIL_ALL) { + /* Convert to error equivalent */ + if (error_number == ZINT_WARN_NONCOMPLIANT) { + error_number = ZINT_ERROR_NONCOMPLIANT; + } else if (error_number == ZINT_WARN_USES_ECI) { + error_number = ZINT_ERROR_USES_ECI; + } else if (error_number == ZINT_WARN_INVALID_OPTION) { + error_number = ZINT_ERROR_INVALID_OPTION; + } else if (error_number == ZINT_WARN_HRT_TRUNCATED) { + error_number = ZINT_ERROR_HRT_TRUNCATED; + } else { /* Shouldn't happen */ + assert(0); /* Not reached */ + error_number = ZINT_ERROR_ENCODING_PROBLEM; + } + } + if (error_number >= ZINT_ERROR) { + errtxt_adj(0, symbol, "Error %s", NULL); + } else { + errtxt_adj(0, symbol, "Warning %s", NULL); + } + } + + return error_number; +} + +#ifdef ZINT_TEST /* Wrapper for direct testing */ +INTERNAL int error_tag_test(int error_number, struct zint_symbol *symbol, const int err_id, + const char *error_string) { + return error_tag(error_number, symbol, err_id, error_string); +} +#endif + +/* Output a hexadecimal representation of the rendered symbol */ +static int dump_plot(struct zint_symbol *symbol) { + FILE *f; + int i, r; + static const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + int space = 0; + const int output_to_stdout = symbol->output_options & BARCODE_STDOUT; + + if (output_to_stdout) { + f = stdout; + } else { +#ifdef _WIN32 + f = out_win_fopen(symbol->outfile, "w"); +#else + f = fopen(symbol->outfile, "w"); +#endif + if (!f) { + return errtxt(ZINT_ERROR_FILE_ACCESS, symbol, 201, "Could not open output file"); + } + } + + for (r = 0; r < symbol->rows; r++) { + int byt = 0; + for (i = 0; i < symbol->width; i++) { + byt = byt << 1; + if (symbol->symbology == BARCODE_ULTRA) { + if (module_colour_is_set(symbol, r, i)) { + byt += 1; + } + } else { + if (module_is_set(symbol, r, i)) { + byt += 1; + } + } + if (((i + 1) % 4) == 0) { + fputc(hex[byt], f); + space++; + byt = 0; + } + if (space == 2 && i + 1 < symbol->width) { + fputc(' ', f); + space = 0; + } + } + + if ((symbol->width % 4) != 0) { + byt = byt << (4 - (symbol->width % 4)); + fputc(hex[byt], f); + } + fputc('\n', f); + space = 0; + } + + if (ferror(f)) { + errtxtf(0, symbol, 795, "Incomplete write to output (%1$d: %2$s)", errno, strerror(errno)); + if (!output_to_stdout) { + (void) fclose(f); + } + return ZINT_ERROR_FILE_WRITE; + } + + if (output_to_stdout) { + if (fflush(f) != 0) { + return errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 796, "Incomplete flush to output (%1$d: %2$s)", + errno, strerror(errno)); + } + } else { + if (fclose(f) != 0) { + return errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 792, "Failure on closing output file (%1$d: %2$s)", + errno, strerror(errno)); + } + } + + return 0; +} + +/* Permitted HIBC characters */ +static const char TECHNETIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; /* Same as SILVER (CODE39) */ + +/* Process health industry bar code data */ +static int hibc(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { + unsigned char *source = segs[0].source; + int length = segs[0].length; + + int i; + int counter, error_number = 0; + char to_process[110 + 2 + 1]; + int posns[110]; + + /* without "+" and check: max 110 characters in HIBC 2.6 */ + if (length > 110) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 202, "Input length %d too long for HIBC LIC (maximum 110)", + length); + } + to_upper(source, length); + if ((i = not_sane_lookup(TECHNETIUM, sizeof(TECHNETIUM) - 1, source, length, posns))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 203, + "Invalid character at position %d in input (alphanumerics, space and \"-.$/+%%\" only)", i); + } + + counter = 41; + for (i = 0; i < length; i++) { + counter += posns[i]; + } + counter = counter % 43; + + to_process[0] = '+'; + memcpy(to_process + 1, source, length); + to_process[++length] = TECHNETIUM[counter]; + to_process[++length] = '\0'; + + segs[0].source = (unsigned char *) to_process; + segs[0].length = length; + + if (symbol->debug & ZINT_DEBUG_PRINT) printf("HIBC processed source: %s\n", to_process); + + switch (symbol->symbology) { + case BARCODE_HIBC_128: + error_number = code128(symbol, segs[0].source, segs[0].length); + ustrcpy(symbol->text, "*"); + ustrcat(symbol->text, to_process); + ustrcat(symbol->text, "*"); + break; + case BARCODE_HIBC_39: + symbol->option_2 = 0; + error_number = code39(symbol, segs[0].source, segs[0].length); + ustrcpy(symbol->text, "*"); + ustrcat(symbol->text, to_process); + ustrcat(symbol->text, "*"); + break; + case BARCODE_HIBC_DM: + error_number = datamatrix(symbol, segs, seg_count); + break; + case BARCODE_HIBC_QR: + error_number = qrcode(symbol, segs, seg_count); + break; + case BARCODE_HIBC_PDF: + error_number = pdf417(symbol, segs, seg_count); + break; + case BARCODE_HIBC_MICPDF: + error_number = micropdf417(symbol, segs, seg_count); + break; + case BARCODE_HIBC_AZTEC: + error_number = aztec(symbol, segs, seg_count); + break; + case BARCODE_HIBC_BLOCKF: + error_number = codablockf(symbol, segs[0].source, segs[0].length); + break; + } + + return error_number; +} + +/* Returns 1 if symbology MUST have GS1 data */ +static int check_force_gs1(const int symbology) { + + switch (symbology) { + case BARCODE_GS1_128: + case BARCODE_EAN14: + case BARCODE_NVE18: + case BARCODE_DBAR_EXP: + case BARCODE_DBAR_EXPSTK: + return 1; + break; + } + + return is_composite(symbology); +} + +/* Returns 1 if symbology supports GS1 data */ +static int gs1_compliant(const int symbology) { + + switch (symbology) { + case BARCODE_CODE16K: + case BARCODE_AZTEC: + case BARCODE_DATAMATRIX: + case BARCODE_CODE49: + case BARCODE_QRCODE: + case BARCODE_DOTCODE: + case BARCODE_CODEONE: + case BARCODE_ULTRA: + case BARCODE_RMQR: + /* TODO: case BARCODE_CODABLOCKF: */ + /* TODO: case BARCODE_HANXIN: */ + /* TODO: case BARCODE_GRIDMATRIX: */ + return 1; + break; + } + + return check_force_gs1(symbology); +} + +/* Returns 1 if symbology can encode the ECI character */ +static int supports_eci(const int symbology) { + + switch (symbology) { + case BARCODE_AZTEC: + case BARCODE_DATAMATRIX: + case BARCODE_MAXICODE: + case BARCODE_MICROPDF417: + case BARCODE_PDF417: + case BARCODE_PDF417COMP: + case BARCODE_QRCODE: + case BARCODE_DOTCODE: + case BARCODE_CODEONE: + case BARCODE_GRIDMATRIX: + case BARCODE_HANXIN: + case BARCODE_ULTRA: + case BARCODE_RMQR: + return 1; + break; + } + + return 0; +} + +/* Returns 1 if symbology supports HRT */ +static int has_hrt(const int symbology) { + + if (is_fixed_ratio(symbology)) { + return 0; + } + + switch (symbology) { /* These don't support HRT */ + case BARCODE_CODE16K: + case BARCODE_CODE49: + case BARCODE_FLAT: + case BARCODE_POSTNET: + case BARCODE_FIM: + case BARCODE_PHARMA: + case BARCODE_PHARMA_TWO: + case BARCODE_DXFILMEDGE: + case BARCODE_CEPNET: + case BARCODE_PDF417: + case BARCODE_PDF417COMP: + case BARCODE_AUSPOST: + case BARCODE_AUSREPLY: + case BARCODE_AUSROUTE: + case BARCODE_AUSREDIRECT: + case BARCODE_RM4SCC: + case BARCODE_CODABLOCKF: + case BARCODE_JAPANPOST: + case BARCODE_DBAR_STK: + case BARCODE_DBAR_OMNSTK: + case BARCODE_DBAR_EXPSTK: + case BARCODE_PLANET: + case BARCODE_MICROPDF417: + case BARCODE_USPS_IMAIL: + case BARCODE_KIX: + case BARCODE_DAFT: + case BARCODE_HIBC_PDF: + case BARCODE_HIBC_MICPDF: + case BARCODE_HIBC_BLOCKF: + case BARCODE_MAILMARK_2D: + case BARCODE_MAILMARK_4S: + case BARCODE_DBAR_STK_CC: + case BARCODE_DBAR_OMNSTK_CC: + case BARCODE_DBAR_EXPSTK_CC: + return 0; + break; + } + + return 1; +} + +typedef int (*barcode_src_func_t)(struct zint_symbol *, unsigned char[], int); +typedef int (*barcode_seg_func_t)(struct zint_symbol *, struct zint_seg[], const int); + +/* Used for dispatching `barcode_src_func_t` barcodes */ +/* Also used, with `barcode_seg_funcs` below, for testing whether symbol id valid in `ZBarcode_ValidID()` */ +static const barcode_src_func_t barcode_src_funcs[BARCODE_LAST + 1] = { + NULL, code11, c25standard, c25inter, c25iata, /*0-4*/ + NULL, c25logic, c25ind, code39, excode39, /*5-9*/ + NULL, NULL, NULL, eanx, eanx, /*10-14*/ + NULL, gs1_128, NULL, codabar, NULL, /*15-19*/ + code128, dpleit, dpident, code16k, code49, /*20-24*/ + code93, NULL, NULL, flat, dbar_omn, /*25-29*/ + dbar_ltd, dbar_exp, telepen, NULL, eanx, /*30-34*/ + eanx, NULL, eanx, eanx, NULL, /*35-39*/ + postnet, NULL, NULL, NULL, NULL, /*40-44*/ + NULL, NULL, msi_plessey, NULL, fim, /*45-49*/ + code39, pharma, pzn, pharma_two, postnet, /*50-54*/ + NULL, NULL, NULL, NULL, NULL, /*55-59*/ + code128, NULL, NULL, auspost, NULL, /*60-64*/ + NULL, auspost, auspost, auspost, eanx, /*65-69*/ + rm4scc, NULL, ean14, vin, codablockf, /*70-74*/ + nve18, japanpost, koreapost, NULL, dbar_omn, /*75-79*/ + dbar_omn, dbar_exp, planet, NULL, NULL, /*80-84*/ + usps_imail, plessey, telepen_num, NULL, itf14, /*85-89*/ + kix, NULL, NULL, daft, NULL, /*90-94*/ + NULL, dpd, microqr, NULL, NULL, /*95-99*/ + NULL, NULL, NULL, NULL, NULL, /*100-104*/ + NULL, NULL, NULL, NULL, NULL, /*105-109*/ + NULL, NULL, NULL, NULL, NULL, /*110-114*/ + NULL, NULL, NULL, NULL, mailmark_2d, /*115-119*/ + upu_s10, mailmark_4s, NULL, NULL, NULL, /*120-124*/ + NULL, NULL, NULL, azrune, code32, /*125-129*/ + composite, composite, composite, composite, composite, /*130-134*/ + composite, composite, composite, composite, composite, /*135-139*/ + channel, NULL, NULL, upnqr, NULL, /*140-144*/ + NULL, bc412, dxfilmedge, /*145-147*/ +}; + +#define LIB_SEG_FUNCS_START 55 + +/* Used for dispatching `barcode_seg_func_t` barcodes */ +static const barcode_seg_func_t barcode_seg_funcs[BARCODE_LAST + 1 - LIB_SEG_FUNCS_START] = { + pdf417, pdf417, maxicode, qrcode, NULL, /*55-59*/ + NULL, NULL, NULL, NULL, NULL, /*60-64*/ + NULL, NULL, NULL, NULL, NULL, /*65-69*/ + NULL, datamatrix, NULL, NULL, NULL, /*70-74*/ + NULL, NULL, NULL, NULL, NULL, /*75-79*/ + NULL, NULL, NULL, NULL, micropdf417, /*80-84*/ + NULL, NULL, NULL, NULL, NULL, /*85-89*/ + NULL, NULL, aztec, NULL, NULL, /*90-94*/ + NULL, NULL, NULL, hibc, hibc, /*95-99*/ + NULL, NULL, hibc, NULL, hibc, /*100-104*/ + NULL, hibc, NULL, hibc, NULL, /*105-109*/ + hibc, NULL, hibc, NULL, NULL, /*110-114*/ + dotcode, hanxin, NULL, NULL, NULL, /*115-119*/ + NULL, NULL, NULL, NULL, NULL, /*120-124*/ + NULL, NULL, NULL, NULL, NULL, /*125-129*/ + NULL, NULL, NULL, NULL, NULL, /*130-134*/ + NULL, NULL, NULL, NULL, NULL, /*135-139*/ + NULL, codeone, gridmatrix, NULL, ultra, /*140-144*/ + rmqr, NULL, /*145-146*/ +}; + +static int reduced_charset(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count); + +/* Main dispatch, checking for barcodes which handle ECIs/character sets themselves, otherwise calling + `reduced_charset()` */ +static int extended_or_reduced_charset(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { + int error_number = 0; + + switch (symbol->symbology) { + /* These are the "elite" standards which have support for specific character sets + ECI */ + case BARCODE_QRCODE: + case BARCODE_GRIDMATRIX: + case BARCODE_HANXIN: + case BARCODE_RMQR: + error_number = barcode_seg_funcs[symbol->symbology - LIB_SEG_FUNCS_START](symbol, segs, seg_count); + break; + /* These are the standards which have support for specific character sets but not ECI */ + case BARCODE_MICROQR: + case BARCODE_UPNQR: + error_number = barcode_src_funcs[symbol->symbology](symbol, segs[0].source, segs[0].length); + break; + default: error_number = reduced_charset(symbol, segs, seg_count); + break; + } + + return error_number; +} + +/* These are the "norm" standards which only support Latin-1 at most, though a few support ECI */ +static int reduced_charset(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { + int error_number = 0; + int i; + struct zint_seg *local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * seg_count); + int *convertible = (int *) z_alloca(sizeof(int) * seg_count); + + if ((symbol->input_mode & 0x07) == UNICODE_MODE && is_eci_convertible_segs(segs, seg_count, convertible)) { + unsigned char *preprocessed; + const int eci_length_segs = get_eci_length_segs(segs, seg_count); + unsigned char *preprocessed_buf = (unsigned char *) z_alloca(eci_length_segs + seg_count); + + /* Prior check ensures ECI only set for those that support it */ + segs_cpy(symbol, segs, seg_count, local_segs); /* Shallow copy (needed to set default ECIs) */ + preprocessed = preprocessed_buf; + for (i = 0; i < seg_count; i++) { + if (convertible[i]) { + error_number = utf8_to_eci(local_segs[i].eci, local_segs[i].source, preprocessed, + &local_segs[i].length); + if (error_number != 0) { + if (local_segs[i].eci) { + return errtxtf(error_number, symbol, 244, "Invalid character in input for ECI '%d'", + local_segs[i].eci); + } + return errtxt(error_number, symbol, 204, "Invalid character in input (ISO/IEC 8859-1 only)"); + } + local_segs[i].source = preprocessed; + preprocessed += local_segs[i].length + 1; + } + } + if (barcode_src_funcs[symbol->symbology]) { + error_number = barcode_src_funcs[symbol->symbology](symbol, local_segs[0].source, local_segs[0].length); + } else { + assert(symbol->symbology >= LIB_SEG_FUNCS_START); /* Suppress clang-tidy-20 warning */ + assert(barcode_seg_funcs[symbol->symbology - LIB_SEG_FUNCS_START]); /* Suppress clang-tidy-20 warning */ + error_number = barcode_seg_funcs[symbol->symbology - LIB_SEG_FUNCS_START](symbol, local_segs, seg_count); + } + } else { + if (barcode_src_funcs[symbol->symbology]) { + error_number = barcode_src_funcs[symbol->symbology](symbol, segs[0].source, segs[0].length); + } else { + assert(symbol->symbology >= LIB_SEG_FUNCS_START); /* Suppress clang-tidy-19 warning */ + assert(barcode_seg_funcs[symbol->symbology - LIB_SEG_FUNCS_START]); /* Suppress clang-tidy-19 warning */ + segs_cpy(symbol, segs, seg_count, local_segs); /* Shallow copy (needed to set default ECIs) */ + error_number = barcode_seg_funcs[symbol->symbology - LIB_SEG_FUNCS_START](symbol, local_segs, seg_count); + } + } + + return error_number; +} + +/* Remove Unicode BOM at start of data */ +static void strip_bom(unsigned char *source, int *input_length) { + int i; + + /* Note if BOM is only data then not stripped */ + if (*input_length > 3 && (source[0] == 0xef) && (source[1] == 0xbb) && (source[2] == 0xbf)) { + /* BOM at start of input data, strip in accordance with RFC 3629 */ + for (i = 3; i <= *input_length; i++) { /* Include terminating NUL */ + source[i - 3] = source[i]; + } + *input_length -= 3; + } +} + +#ifdef ZINT_TEST /* Wrapper for direct testing */ +INTERNAL void strip_bom_test(unsigned char *source, int *input_length) { + strip_bom(source, input_length); +} +#endif + +/* Helper to convert base octal, decimal, hexadecimal escape sequence */ +static int esc_base(struct zint_symbol *symbol, const unsigned char *input_string, const int length, + const int in_posn, const unsigned char base) { + int c1, c2, c3; + int min_len = base == 'x' ? 2 : 3; + int val = -1; + + if (in_posn + min_len > length) { + return errtxtf(-1, symbol, 232, "Incomplete '\\%c' escape sequence in input", base); + } + c1 = ctoi(input_string[in_posn]); + c2 = ctoi(input_string[in_posn + 1]); + if (base == 'd') { + c3 = ctoi(input_string[in_posn + 2]); + if ((c1 >= 0 && c1 <= 9) && (c2 >= 0 && c2 <= 9) && (c3 >= 0 && c3 <= 9)) { + val = c1 * 100 + c2 * 10 + c3; + } + } else if (base == 'o') { + c3 = ctoi(input_string[in_posn + 2]); + if ((c1 >= 0 && c1 <= 7) && (c2 >= 0 && c2 <= 7) && (c3 >= 0 && c3 <= 7)) { + val = (c1 << 6) | (c2 << 3) | c3; + } + } else { + if ((c1 >= 0) && (c2 >= 0)) { + val = (c1 << 4) | c2; + } + } + + if (val == -1) { + return errtxtf(-1, symbol, 238, "Invalid character in escape sequence '%2$.*1$s' in input (%3$s only)", + base == 'x' ? 4 : 5, input_string + in_posn - 2, + base == 'd' ? "decimal" : base == 'o' ? "octal" : "hexadecimal"); + } + if (val > 255) { + assert(base != 'x'); + return errtxtf(-1, symbol, 237, "Value of escape sequence '%1$.5s' in input out of range (000 to %2$s)", + input_string + in_posn - 2, base == 'd' ? "255" : "377"); + } + + return val; +} + +/* Helper to parse escape sequences. If `escaped_string` NULL, calculates length only */ +static int escape_char_process(struct zint_symbol *symbol, const unsigned char *input_string, int *p_length, + unsigned char *escaped_string) { + /* NUL EOT BEL BS HT LF VT FF CR ESC GS RS \ */ + static const char escs[] = { '0', 'E', 'a', 'b', 't', 'n', 'v', 'f', 'r', 'e', 'G', 'R', '\\', '\0' }; + static const char vals[] = { 0x00, 0x04, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x1B, 0x1D, 0x1E, 0x5C }; + const int length = *p_length; + int in_posn = 0, out_posn = 0; + unsigned char ch; + int val; + int i; + unsigned int unicode; + const int extra_escape_mode = (symbol->input_mode & EXTRA_ESCAPE_MODE) && symbol->symbology == BARCODE_CODE128; + + do { + if (input_string[in_posn] == '\\') { + if (in_posn + 1 >= length) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 236, "Incomplete escape character in input"); + } + ch = input_string[in_posn + 1]; + /* NOTE: if add escape character, must also update regex in "frontend_qt/datawindow.php" */ + switch (ch) { + case '0': + case 'E': + case 'a': + case 'b': + case 't': + case 'n': + case 'v': + case 'f': + case 'r': + case 'e': + case 'G': + case 'R': + case '\\': + if (escaped_string) escaped_string[out_posn] = vals[posn(escs, ch)]; + in_posn += 2; + break; + case '^': /* CODE128 specific */ + if (!extra_escape_mode) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 798, + "Escape '\\^' only valid for Code 128 in extra escape mode"); + } + /* Pass thru unaltered */ + if (escaped_string) { + escaped_string[out_posn++] = '\\'; + escaped_string[out_posn] = '^'; + } else { + out_posn++; + } + in_posn += 2; + if (in_posn < length) { /* Note allowing '\\^' on its own at end */ + if (escaped_string) { + escaped_string[++out_posn] = input_string[in_posn++]; + } else { + ++out_posn; + in_posn++; + } + } + break; + case 'd': + case 'o': + case 'x': + if ((val = esc_base(symbol, input_string, length, in_posn + 2, ch)) == -1) { + return ZINT_ERROR_INVALID_DATA; + } + if (escaped_string) escaped_string[out_posn] = val; + in_posn += 4 + (ch != 'x'); + break; + case 'u': + case 'U': + if (in_posn + 6 > length || (ch == 'U' && in_posn + 8 > length)) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 209, + "Incomplete '\\%c' escape sequence in input", ch); + } + unicode = 0; + for (i = 0; i < 6; i++) { + if ((val = ctoi(input_string[in_posn + i + 2])) == -1) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 211, + "Invalid character for '\\%c' escape sequence in input (hexadecimal only)", + ch); + } + unicode = (unicode << 4) | val; + if (i == 3 && ch == 'u') { + break; + } + } + /* Exclude reversed BOM and surrogates and out-of-range */ + if (unicode == 0xfffe || (unicode >= 0xd800 && unicode < 0xe000) || unicode > 0x10ffff) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 246, + "Value of escape sequence '%.*s' in input out of range", + ch == 'u' ? 6 : 8, input_string + in_posn); + } + if (unicode < 0x80) { + if (escaped_string) escaped_string[out_posn] = (unsigned char) unicode; + } else if (unicode < 0x800) { + if (escaped_string) { + escaped_string[out_posn++] = (unsigned char) (0xC0 | (unicode >> 6)); + escaped_string[out_posn] = (unsigned char) (0x80 | (unicode & 0x3F)); + } else { + out_posn++; + } + } else if (unicode < 0x10000) { + if (escaped_string) { + escaped_string[out_posn++] = (unsigned char) (0xE0 | (unicode >> 12)); + escaped_string[out_posn++] = (unsigned char) (0x80 | ((unicode >> 6) & 0x3F)); + escaped_string[out_posn] = (unsigned char) (0x80 | (unicode & 0x3F)); + } else { + out_posn += 2; + } + } else { + if (escaped_string) { + escaped_string[out_posn++] = (unsigned char) (0xF0 | (unicode >> 18)); + escaped_string[out_posn++] = (unsigned char) (0x80 | ((unicode >> 12) & 0x3F)); + escaped_string[out_posn++] = (unsigned char) (0x80 | ((unicode >> 6) & 0x3F)); + escaped_string[out_posn] = (unsigned char) (0x80 | (unicode & 0x3F)); + } else { + out_posn += 3; + } + } + in_posn += 6 + (ch == 'U') * 2; + break; + default: + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 234, + "Unrecognised escape character '\\%c' in input", ch); + break; + } + } else { + if (escaped_string) escaped_string[out_posn] = input_string[in_posn]; + in_posn++; + } + out_posn++; + } while (in_posn < length); + + if (escaped_string) { + escaped_string[out_posn] = '\0'; + } + *p_length = out_posn; + + return 0; +} + +#ifdef ZINT_TEST /* Wrapper for direct testing (also used by `testUtilZXingCPPCmp()` in "tests/testcommon.c") */ +INTERNAL int escape_char_process_test(struct zint_symbol *symbol, const unsigned char *input_string, int *p_length, + unsigned char *escaped_string) { + return escape_char_process(symbol, input_string, p_length, escaped_string); +} +#endif + +/* For backward-compatibility, map certain invalid symbol ids to zint equivalents, some silently, some with warning */ +static int map_invalid_symbology(struct zint_symbol *symbol) { + + /* Symbol ids 1 to 126 are defined by tbarcode */ + /* 26 allowed: UPC-A up to tbarcode 9, ISSN for tbarcode 10+, mapped to UPC-A */ + /* 27 error: UPCD1 up to tbarcode 9, ISSN + 2 digit add-on for tbarcode 10+ */ + /* 91 warning: BC412 up to tbarcode 9, Code 32 for tbarcode 10+, mapped to Code 128 */ + /* Note: non-zero table entries map silently, i.e. do not produce a warning */ + #define LIB_ID_MAP_LAST 111 + static const unsigned char id_map[LIB_ID_MAP_LAST + 1] = { + 0, 0, 0, 0, 0, /*0-4*/ + BARCODE_C25STANDARD, 0, 0, 0, 0, /*5-9*/ + BARCODE_EANX, BARCODE_EANX, BARCODE_EANX, 0, 0, /*10-14*/ + BARCODE_EANX, 0, BARCODE_UPCA, 0, BARCODE_CODABAR, /*15-19*/ + 0, 0, 0, 0, 0, /*20-24*/ + 0, BARCODE_UPCA, 0, 0, 0, /*25-29*/ + 0, 0, 0, BARCODE_GS1_128, 0, /*30-34*/ + 0, BARCODE_UPCA, 0, 0, BARCODE_UPCE, /*35-39*/ + 0, BARCODE_POSTNET, BARCODE_POSTNET, BARCODE_POSTNET, BARCODE_POSTNET, /*40-44*/ + BARCODE_POSTNET, BARCODE_PLESSEY, 0, BARCODE_NVE18, 0, /*45-49*/ + 0, 0, 0, 0, 0, /*50-54*/ + 0, 0, 0, 0, BARCODE_CODE128, /*55-59*/ + 0, BARCODE_CODE128, BARCODE_CODE93, 0, BARCODE_AUSPOST, /*60-64*/ + BARCODE_AUSPOST, 0, 0, 0, 0, /*65-69*/ + 0, 0, 0, 0, 0, /*70-74*/ + 0, 0, 0, BARCODE_DBAR_OMN, 0, /*75-79*/ + 0, 0, 0, BARCODE_PLANET, 0, /*80-84*/ + 0, 0, 0, BARCODE_GS1_128, 0, /*85-89*/ + 0, 0, 0, 0, 0, /*90-94*/ + 0, 0, 0, 0, 0, /*95-99*/ + BARCODE_HIBC_128, BARCODE_HIBC_39, 0, BARCODE_HIBC_DM, 0, /*100-104*/ + BARCODE_HIBC_QR, 0, BARCODE_HIBC_PDF, 0, BARCODE_HIBC_MICPDF, /*105-109*/ + 0, BARCODE_HIBC_BLOCKF, /*110-111*/ + }; + const int orig_symbology = symbol->symbology; /* For self-check */ + int warn_number = 0; + + if (symbol->symbology == 19) { + /* Has specific error message */ + warn_number = error_tag(ZINT_WARN_INVALID_OPTION, symbol, 207, "Codabar 18 not supported"); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + symbol->symbology = BARCODE_CODABAR; + } else if (symbol->symbology == 27) { + /* Not mapped */ + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 208, "UPCD1 not supported"); + + } else if (symbol->symbology <= 0 || symbol->symbology > LIB_ID_MAP_LAST || id_map[symbol->symbology] == 0) { + warn_number = error_tag(ZINT_WARN_INVALID_OPTION, symbol, 206, "Symbology out of range"); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + symbol->symbology = BARCODE_CODE128; + } else { + symbol->symbology = id_map[symbol->symbology]; + } + + if (symbol->symbology == orig_symbology) { /* Should never happen */ + assert(0); /* Not reached */ + return error_tag(ZINT_ERROR_ENCODING_PROBLEM, symbol, 0, "Internal error"); + } + + return warn_number; +} + +/* Encode a barcode. If `length` is 0, `source` must be NUL-terminated */ +int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int length) { + struct zint_seg segs[1]; + + if (!symbol) return ZINT_ERROR_INVALID_DATA; + + segs[0].eci = symbol->eci; + segs[0].source = (unsigned char *) source; + segs[0].length = length; + + return ZBarcode_Encode_Segs(symbol, segs, 1); +} + +/* Encode a barcode with multiple ECI segments. */ +int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[], const int seg_count) { + int error_number, warn_number = 0; + int total_len = 0; + int have_zero_eci = 0; + int escape_mode; + int i; + unsigned char *local_source; + struct zint_seg *local_segs; + unsigned char *local_sources; + + if (!symbol) return ZINT_ERROR_INVALID_DATA; + + if (segs == NULL) { + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 200, "Input segments NULL"); + } + /* `seg_count` zero dealt with via `total_len` zero below */ + if (seg_count > ZINT_MAX_SEG_COUNT) { + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 771, "Too many input segments (maximum 256)"); + } + + if ((symbol->input_mode & 0x07) > 2) { + symbol->input_mode = DATA_MODE; /* Reset completely */ + warn_number = error_tag(ZINT_WARN_INVALID_OPTION, symbol, 212, "Invalid input mode - reset to DATA_MODE"); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + } + + /* Check the symbology field */ + if (!ZBarcode_ValidID(symbol->symbology)) { + warn_number = map_invalid_symbology(symbol); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + } + + escape_mode = (symbol->input_mode & ESCAPE_MODE) + || ((symbol->input_mode & EXTRA_ESCAPE_MODE) && symbol->symbology == BARCODE_CODE128); + + local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * (seg_count > 0 ? seg_count : 1)); + + /* Check segment lengths */ + for (i = 0; i < seg_count; i++) { + local_segs[i] = segs[i]; + if (local_segs[i].source == NULL) { + errtxtf(0, symbol, 772, "Input segment %d source NULL", i); + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL); + } + if (local_segs[i].length <= 0) { + local_segs[i].length = (int) ustrlen(local_segs[i].source); + } + if (local_segs[i].length <= 0) { + if (i == 0) { + if (is_composite(symbol->symbology) + && ((symbol->input_mode & 0x07) == GS1_MODE || check_force_gs1(symbol->symbology))) { + errtxt(0, symbol, 779, "No composite data (2D component)"); + } else if (supports_eci(symbol->symbology)) { + errtxt(0, symbol, 228, "No input data (segment 0 empty)"); + } else { + errtxt(0, symbol, 778, "No input data"); + } + } else { + errtxtf(0, symbol, 773, "Input segment %d empty", i); + } + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL); + } + /* Calculate de-escaped length for check against ZINT_MAX_DATA_LEN */ + if (escape_mode) { + int escaped_len = local_segs[i].length; + error_number = escape_char_process(symbol, local_segs[i].source, &escaped_len, NULL /*escaped_string*/); + if (error_number != 0) { /* Only returns errors, not warnings */ + return error_tag(error_number, symbol, -1, NULL); + } + if (escaped_len > ZINT_MAX_DATA_LEN) { + return error_tag(ZINT_ERROR_TOO_LONG, symbol, 797, "Input too long"); + } + total_len += escaped_len; + } else { + if (local_segs[i].length > ZINT_MAX_DATA_LEN) { + return error_tag(ZINT_ERROR_TOO_LONG, symbol, 777, "Input too long"); + } + total_len += local_segs[i].length; + } + } + + if (total_len == 0) { + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 205, "No input data"); + } + + if (symbol->debug & ZINT_DEBUG_PRINT) { + const int len = local_segs[0].length; + const int primary_len = symbol->primary[0] ? (int) strlen(symbol->primary) : 0; + char name[32]; + char source[151], primary[151]; /* 30*5 + 1 = 151 */ + (void) ZBarcode_BarcodeName(symbol->symbology, name); + debug_print_escape(local_segs[0].source, len > 30 ? 30 : len, source); + debug_print_escape((const unsigned char *) symbol->primary, primary_len > 30 ? 30 : primary_len, primary); + printf("\nZBarcode_Encode_Segs: %s (%d), input_mode: 0x%X, ECI: %d, option_1/2/3: (%d, %d, %d)\n" + " scale: %g, output_options: 0x%X, fg: %s, bg: %s, seg_count: %d,\n" + " %ssource%s (%d): \"%s\",\n" + " %sprimary (%d): \"%s\"\n", + name, symbol->symbology, symbol->input_mode, symbol->eci, symbol->option_1, symbol->option_2, + symbol->option_3, symbol->scale, symbol->output_options, symbol->fgcolour, symbol->bgcolour, + seg_count, len > 30 ? "first 30 " : "", seg_count > 1 ? "[0]" : "", len, source, + primary_len > 30 ? "first 30 " : "", primary_len, primary); + fflush(stdout); + } + + if (total_len > ZINT_MAX_DATA_LEN) { + return error_tag(ZINT_ERROR_TOO_LONG, symbol, 243, "Input too long"); + } + + /* Reconcile symbol ECI and first segment ECI if both set */ + if (symbol->eci != local_segs[0].eci) { + if (symbol->eci && local_segs[0].eci) { + errtxtf(0, symbol, 774, "Symbol ECI '%1$d' must match segment zero ECI '%2$d'", + symbol->eci, local_segs[0].eci); + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, -1, NULL); + } + if (symbol->eci) { + local_segs[0].eci = symbol->eci; + } else { + symbol->eci = local_segs[0].eci; + } + } + + if (seg_count > 1 && !supports_eci(symbol->symbology)) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 775, "Symbology does not support multiple segments"); + } + + /* Check ECI(s) */ + for (i = 0; i < seg_count; i++) { + if (local_segs[i].eci) { + if (!supports_eci(symbol->symbology)) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 217, "Symbology does not support ECI switching"); + } + if (local_segs[i].eci < 0 || local_segs[i].eci == 1 || local_segs[i].eci == 2 || local_segs[i].eci == 14 + || local_segs[i].eci == 19 || local_segs[i].eci > 999999) { + errtxtf(0, symbol, 218, "ECI code '%d' out of range (0 to 999999, excluding 1, 2, 14 and 19)", + local_segs[i].eci); + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, -1, NULL); + } + } else { + have_zero_eci = 1; + } + } + + /* Check other symbol fields */ + if ((symbol->scale < 0.01f) || (symbol->scale > 200.0f)) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 227, "Scale out of range (0.01 to 200)"); + } + if ((symbol->dot_size < 0.01f) || (symbol->dot_size > 20.0f)) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 221, "Dot size out of range (0.01 to 20)"); + } + + if ((symbol->height < 0.0f) || (symbol->height > 2000.0f)) { /* Allow for 44 row CODABLOCKF at 45X each */ + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 765, "Height out of range (0 to 2000)"); + } + if ((symbol->guard_descent < 0.0f) || (symbol->guard_descent > 50.0f)) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 769, "Guard bar descent out of range (0 to 50)"); + } + if ((symbol->text_gap < -5.0f) || (symbol->text_gap > 10.0f)) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 219, "Text gap out of range (-5 to 10)"); + } + if ((symbol->whitespace_width < 0) || (symbol->whitespace_width > 100)) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 766, "Whitespace width out of range (0 to 100)"); + } + if ((symbol->whitespace_height < 0) || (symbol->whitespace_height > 100)) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 767, "Whitespace height out of range (0 to 100)"); + } + if ((symbol->border_width < 0) || (symbol->border_width > 100)) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 768, "Border width out of range (0 to 100)"); + } + + if (symbol->rows >= 200) { /* Check for stacking too many symbols */ + return error_tag(ZINT_ERROR_TOO_LONG, symbol, 770, "Too many stacked symbols"); + } + if (symbol->rows < 0) { /* Silently defend against out-of-bounds access */ + symbol->rows = 0; + } + + if ((symbol->input_mode & 0x07) == GS1_MODE && !gs1_compliant(symbol->symbology)) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 220, "Selected symbology does not support GS1 mode"); + } + if (seg_count > 1) { + /* Note: GS1_MODE not currently supported when using multiple segments */ + if ((symbol->input_mode & 0x07) == GS1_MODE) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 776, "GS1 mode not supported for multiple segments"); + } + } + + local_sources = (unsigned char *) z_alloca(total_len + seg_count); + + /* Copy input, de-escaping if required */ + for (i = 0, local_source = local_sources; i < seg_count; i++) { + local_segs[i].source = local_source; + if (escape_mode) { + /* Checked already */ + (void) escape_char_process(symbol, segs[i].source, &local_segs[i].length, local_segs[i].source); + } else { + memcpy(local_segs[i].source, segs[i].source, local_segs[i].length); + local_segs[i].source[local_segs[i].length] = '\0'; + } + local_source += local_segs[i].length + 1; + } + + if (escape_mode && symbol->primary[0] && strchr(symbol->primary, '\\') != NULL) { + char primary[sizeof(symbol->primary)]; + int primary_len = (int) strlen(symbol->primary); + if (primary_len >= (int) sizeof(symbol->primary)) { + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 799, "Invalid primary string"); + } + ustrcpy(primary, symbol->primary); + error_number = escape_char_process(symbol, (unsigned char *) primary, &primary_len, + (unsigned char *) symbol->primary); + if (error_number != 0) { /* Only returns errors, not warnings */ + return error_tag(error_number, symbol, -1, NULL); + } + } + + if ((symbol->input_mode & 0x07) == UNICODE_MODE) { + for (i = 0; i < seg_count; i++) { + if (!is_valid_utf8(local_segs[i].source, local_segs[i].length)) { + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 245, "Invalid UTF-8 in input"); + } + } + /* Only strip BOM on first segment */ + strip_bom(local_segs[0].source, &local_segs[0].length); + } + + if (((symbol->input_mode & 0x07) == GS1_MODE) || (check_force_gs1(symbol->symbology))) { + if (gs1_compliant(symbol->symbology)) { + /* Reduce input for composite and non-forced symbologies, others (EAN128 and RSS_EXP based) will + handle it themselves */ + if (is_composite(symbol->symbology) || !check_force_gs1(symbol->symbology)) { + unsigned char *reduced = (unsigned char *) z_alloca(local_segs[0].length + 1); + error_number = gs1_verify(symbol, local_segs[0].source, local_segs[0].length, reduced); + if (error_number) { + if (is_composite(symbol->symbology)) { + errtxt_adj(0, symbol, "%1$s%2$s", " (2D component)"); + } + error_number = error_tag(error_number, symbol, -1, NULL); + if (error_number >= ZINT_ERROR) { + return error_number; + } + warn_number = error_number; /* Override any previous warning (errtxt has been overwritten) */ + } + ustrcpy(local_segs[0].source, reduced); /* Cannot contain NUL char */ + local_segs[0].length = (int) ustrlen(reduced); + } + } else { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 210, "Selected symbology does not support GS1 mode"); + } + } + + error_number = extended_or_reduced_charset(symbol, local_segs, seg_count); + + if ((error_number == ZINT_ERROR_INVALID_DATA) && have_zero_eci && supports_eci(symbol->symbology) + && (symbol->input_mode & 0x07) == UNICODE_MODE) { + /* Try another ECI mode */ + const int first_eci_set = get_best_eci_segs(symbol, local_segs, seg_count); + error_number = extended_or_reduced_charset(symbol, local_segs, seg_count); + /* Inclusion of ECI more noteworthy than other warnings, so overwrite (if any) */ + if (error_number < ZINT_ERROR) { + error_number = ZINT_WARN_USES_ECI; + if (!(symbol->debug & ZINT_DEBUG_TEST)) { + errtxtf(0, symbol, 222, "Encoded data includes ECI %d", first_eci_set); + } + if (symbol->debug & ZINT_DEBUG_PRINT) printf("Added ECI %d\n", first_eci_set); + } + } + + if (error_number == 0) { + error_number = warn_number; /* Already tagged */ + } else { + error_number = error_tag(error_number, symbol, -1, NULL); + } + + if (error_number < ZINT_ERROR) { + if (symbol->height < 0.5f) { /* Absolute minimum */ + (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); + } + } + + return error_number; +} + +/* Helper for output routines to check `rotate_angle` and dottiness */ +static int check_output_args(struct zint_symbol *symbol, int rotate_angle) { + + if (!symbol) return ZINT_ERROR_INVALID_DATA; + + switch (rotate_angle) { + case 0: + case 90: + case 180: + case 270: + break; + default: + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 223, "Invalid rotation angle"); + break; + } + + if ((symbol->output_options & BARCODE_DOTTY_MODE) && !(is_dotty(symbol->symbology))) { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 224, "Selected symbology cannot be rendered as dots"); + } + + return 0; +} + +static const struct { const char extension[4]; int is_raster; int filetype; } filetypes[] = { + { "BMP", 1, OUT_BMP_FILE }, { "EMF", 0, OUT_EMF_FILE }, { "EPS", 0, OUT_EPS_FILE }, + { "GIF", 1, OUT_GIF_FILE }, { "PCX", 1, OUT_PCX_FILE }, { "PNG", 1, OUT_PNG_FILE }, + { "SVG", 0, OUT_SVG_FILE }, { "TIF", 1, OUT_TIF_FILE }, { "TXT", 0, 0 } +}; + +/* Return index of `extension` in `filetypes`, or -1 if not found */ +static int filetype_idx(const char *extension) { + char uc_extension[4] = {0}; + int i; + + if (strlen(extension) != 3) { + return -1; + } + memcpy(uc_extension, extension, 3); + to_upper((unsigned char *) uc_extension, 3); + + for (i = 0; i < ARRAY_SIZE(filetypes); i++) { + if (strcmp(uc_extension, filetypes[i].extension) == 0) { + break; + } + } + + return i == ARRAY_SIZE(filetypes) ? -1 : i; +} + +/* Output a previously encoded symbol to file `symbol->outfile` */ +int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) { + int error_number; + int len; + + if ((error_number = check_output_args(symbol, rotate_angle))) { /* >= ZINT_ERROR only */ + return error_number; /* Already tagged */ + } + + len = (int) strlen(symbol->outfile); + if (len > 3) { + int i = filetype_idx(symbol->outfile + len - 3); + if (i >= 0) { + if (filetypes[i].filetype) { + if (filetypes[i].is_raster) { + error_number = plot_raster(symbol, rotate_angle, filetypes[i].filetype); + } else { + error_number = plot_vector(symbol, rotate_angle, filetypes[i].filetype); + } + } else { + error_number = dump_plot(symbol); + } + } else { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 225, "Unknown output format"); + } + } else { + return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 226, "Unknown output format"); + } + + return error_tag(error_number, symbol, -1, NULL); +} + +/* Output a previously encoded symbol to memory as raster (`symbol->bitmap`) */ +int ZBarcode_Buffer(struct zint_symbol *symbol, int rotate_angle) { + int error_number; + + if ((error_number = check_output_args(symbol, rotate_angle))) { /* >= ZINT_ERROR only */ + return error_number; /* Already tagged */ + } + + error_number = plot_raster(symbol, rotate_angle, OUT_BUFFER); + return error_tag(error_number, symbol, -1, NULL); +} + +/* Output a previously encoded symbol to memory as vector (`symbol->vector`) */ +int ZBarcode_Buffer_Vector(struct zint_symbol *symbol, int rotate_angle) { + int error_number; + + if ((error_number = check_output_args(symbol, rotate_angle))) { /* >= ZINT_ERROR only */ + return error_number; /* Already tagged */ + } + + error_number = plot_vector(symbol, rotate_angle, OUT_BUFFER); + return error_tag(error_number, symbol, -1, NULL); +} + +/* Encode and output a symbol to file `symbol->outfile` */ +int ZBarcode_Encode_and_Print(struct zint_symbol *symbol, const unsigned char *source, int length, int rotate_angle) { + struct zint_seg segs[1]; + + if (!symbol) return ZINT_ERROR_INVALID_DATA; + + segs[0].eci = symbol->eci; + segs[0].source = (unsigned char *) source; + segs[0].length = length; + + return ZBarcode_Encode_Segs_and_Print(symbol, segs, 1, rotate_angle); +} + +/* Encode a symbol with multiple ECI segments and output to file `symbol->outfile` */ +int ZBarcode_Encode_Segs_and_Print(struct zint_symbol *symbol, const struct zint_seg segs[], const int seg_count, + int rotate_angle) { + int error_number; + int warn_number; + + warn_number = ZBarcode_Encode_Segs(symbol, segs, seg_count); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + + error_number = ZBarcode_Print(symbol, rotate_angle); + + return error_number ? error_number : warn_number; +} + +/* Encode and output a symbol to memory as raster (`symbol->bitmap`) */ +int ZBarcode_Encode_and_Buffer(struct zint_symbol *symbol, const unsigned char *source, int length, + int rotate_angle) { + struct zint_seg segs[1]; + + if (!symbol) return ZINT_ERROR_INVALID_DATA; + + segs[0].eci = symbol->eci; + segs[0].source = (unsigned char *) source; + segs[0].length = length; + + return ZBarcode_Encode_Segs_and_Buffer(symbol, segs, 1, rotate_angle); +} + +/* Encode a symbol with multiple ECI segments and output to memory as raster (`symbol->bitmap`) */ +int ZBarcode_Encode_Segs_and_Buffer(struct zint_symbol *symbol, const struct zint_seg segs[], + const int seg_count, int rotate_angle) { + int error_number; + int warn_number; + + warn_number = ZBarcode_Encode_Segs(symbol, segs, seg_count); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + + error_number = ZBarcode_Buffer(symbol, rotate_angle); + + return error_number ? error_number : warn_number; +} + +/* Encode and output a symbol to memory as vector (`symbol->vector`) */ +int ZBarcode_Encode_and_Buffer_Vector(struct zint_symbol *symbol, const unsigned char *source, int length, + int rotate_angle) { + struct zint_seg segs[1]; + + if (!symbol) return ZINT_ERROR_INVALID_DATA; + + segs[0].eci = symbol->eci; + segs[0].source = (unsigned char *) source; + segs[0].length = length; + + return ZBarcode_Encode_Segs_and_Buffer_Vector(symbol, segs, 1, rotate_angle); +} + +/* Encode a symbol with multiple ECI segments and output to memory as vector (`symbol->vector`) */ +int ZBarcode_Encode_Segs_and_Buffer_Vector(struct zint_symbol *symbol, const struct zint_seg segs[], + const int seg_count, int rotate_angle) { + int error_number; + int warn_number; + + warn_number = ZBarcode_Encode_Segs(symbol, segs, seg_count); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + + error_number = ZBarcode_Buffer_Vector(symbol, rotate_angle); + + return error_number ? error_number : warn_number; +} + +/* Encode a barcode using input data from file `filename` */ +int ZBarcode_Encode_File(struct zint_symbol *symbol, const char *filename) { + FILE *file; + int file_opened = 0; + unsigned char *buffer; + long fileLen; + size_t n; + size_t nRead = 0; + int ret; + + if (!symbol) return ZINT_ERROR_INVALID_DATA; + + if (!filename) { + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 239, "Filename NULL"); + } + + if (strcmp(filename, "-") == 0) { + file = stdin; + fileLen = ZINT_MAX_DATA_LEN; + } else { +#ifdef _WIN32 + file = out_win_fopen(filename, "rb"); +#else + file = fopen(filename, "rb"); +#endif + if (!file) { + errtxtf(0, symbol, 229, "Unable to read input file (%1$d: %2$s)", errno, strerror(errno)); + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL); + } + file_opened = 1; + + /* Get file length */ + if (fseek(file, 0, SEEK_END) != 0) { + errtxtf(0, symbol, 797, "Unable to seek input file (%1$d: %2$s)", errno, strerror(errno)); + (void) fclose(file); + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL); + } + + fileLen = ftell(file); + + /* On many Linux distros `ftell()` returns LONG_MAX not -1 on error */ + if (fileLen <= 0 || fileLen == LONG_MAX) { + (void) fclose(file); + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, 235, "Input file empty or unseekable"); + } + if (fileLen > ZINT_MAX_DATA_LEN) { + (void) fclose(file); + return error_tag(ZINT_ERROR_TOO_LONG, symbol, 230, "Input file too long"); + } + + if (fseek(file, 0, SEEK_SET) != 0) { + errtxtf(0, symbol, 793, "Unable to seek input file (%1$d: %2$s)", errno, strerror(errno)); + (void) fclose(file); + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL); + } + } + + /* Allocate memory */ + buffer = (unsigned char *) malloc(fileLen); + if (!buffer) { + if (file_opened) { + (void) fclose(file); + } + return error_tag(ZINT_ERROR_MEMORY, symbol, 231, "Insufficient memory for file read buffer"); + } + + /* Read file contents into buffer */ + + do { + n = fread(buffer + nRead, 1, fileLen - nRead, file); + if (ferror(file)) { + errtxtf(0, symbol, 241, "Input file read error (%1$d: %2$s)", errno, strerror(errno)); + free(buffer); + if (file_opened) { + (void) fclose(file); + } + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL); + } + nRead += n; + } while (!feof(file) && (0 < n) && ((long) nRead < fileLen)); + + if (file_opened) { + if (fclose(file) != 0) { + errtxtf(0, symbol, 794, "Failure on closing input file (%1$d: %2$s)", errno, strerror(errno)); + free(buffer); + return error_tag(ZINT_ERROR_INVALID_DATA, symbol, -1, NULL); + } + } + ret = ZBarcode_Encode(symbol, buffer, (int) nRead); + free(buffer); + return ret; +} + +/* Encode a symbol using input data from file `filename` and output to file `symbol->outfile` */ +int ZBarcode_Encode_File_and_Print(struct zint_symbol *symbol, const char *filename, int rotate_angle) { + int error_number; + int warn_number; + + warn_number = ZBarcode_Encode_File(symbol, filename); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + + error_number = ZBarcode_Print(symbol, rotate_angle); + + return error_number ? error_number : warn_number; +} + +/* Encode a symbol using input data from file `filename` and output to memory as raster (`symbol->bitmap`) */ +int ZBarcode_Encode_File_and_Buffer(struct zint_symbol *symbol, char const *filename, int rotate_angle) { + int error_number; + int warn_number; + + warn_number = ZBarcode_Encode_File(symbol, filename); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + + error_number = ZBarcode_Buffer(symbol, rotate_angle); + + return error_number ? error_number : warn_number; +} + +/* Encode a symbol using input data from file `filename` and output to memory as vector (`symbol->vector`) */ +int ZBarcode_Encode_File_and_Buffer_Vector(struct zint_symbol *symbol, const char *filename, int rotate_angle) { + int error_number; + int warn_number; + + warn_number = ZBarcode_Encode_File(symbol, filename); + if (warn_number >= ZINT_ERROR) { + return warn_number; + } + + error_number = ZBarcode_Buffer_Vector(symbol, rotate_angle); + + return error_number ? error_number : warn_number; +} + +/* Checks whether a symbology is supported */ +int ZBarcode_ValidID(int symbol_id) { + + if (symbol_id <= 0 || symbol_id > BARCODE_LAST) { + return 0; + } + + return barcode_src_funcs[symbol_id] != NULL + || (symbol_id >= LIB_SEG_FUNCS_START && barcode_seg_funcs[symbol_id - LIB_SEG_FUNCS_START] != NULL); +} + +/* Copy BARCODE_XXX name of `symbol_id` into `name` buffer, NUL-terminated. + Returns 0 if valid, 1 if not valid */ +int ZBarcode_BarcodeName(int symbol_id, char name[32]) { + static const char *const names[] = { + "", "CODE11", "C25STANDARD", "C25INTER", "C25IATA", /*0-4*/ + "", "C25LOGIC", "C25IND", "CODE39", "EXCODE39", /*5-9*/ + "", "", "", "EANX", "EANX_CHK", /*10-14*/ + "", "GS1_128", "", "CODABAR", "", /*15-19*/ + "CODE128", "DPLEIT", "DPIDENT", "CODE16K", "CODE49", /*20-24*/ + "CODE93", "", "", "FLAT", "DBAR_OMN", /*25-29*/ + "DBAR_LTD", "DBAR_EXP", "TELEPEN", "", "UPCA", /*30-34*/ + "UPCA_CHK", "", "UPCE", "UPCE_CHK", "", /*35-39*/ + "POSTNET", "", "", "", "", /*40-44*/ + "", "", "MSI_PLESSEY", "", "FIM", /*45-49*/ + "LOGMARS", "PHARMA", "PZN", "PHARMA_TWO", "CEPNET", /*50-54*/ + "PDF417", "PDF417COMP", "MAXICODE", "QRCODE", "", /*55-59*/ + "CODE128AB", "", "", "AUSPOST", "", /*60-64*/ + "", "AUSREPLY", "AUSROUTE", "AUSREDIRECT", "ISBNX", /*65-69*/ + "RM4SCC", "DATAMATRIX", "EAN14", "VIN", "CODABLOCKF", /*70-74*/ + "NVE18", "JAPANPOST", "KOREAPOST", "", "DBAR_STK", /*75-79*/ + "DBAR_OMNSTK", "DBAR_EXPSTK", "PLANET", "", "MICROPDF417", /*80-84*/ + "USPS_IMAIL", "PLESSEY", "TELEPEN_NUM", "", "ITF14", /*85-89*/ + "KIX", "", "AZTEC", "DAFT", "", /*90-94*/ + "", "DPD", "MICROQR", "HIBC_128", "HIBC_39", /*95-99*/ + "", "", "HIBC_DM", "", "HIBC_QR", /*100-104*/ + "", "HIBC_PDF", "", "HIBC_MICPDF", "", /*105-109*/ + "HIBC_BLOCKF", "", "HIBC_AZTEC", "", "", /*110-114*/ + "DOTCODE", "HANXIN", "", "", "MAILMARK_2D", /*115-119*/ + "UPU_S10", "MAILMARK_4S", "", "", "", /*120-124*/ + "", "", "", "AZRUNE", "CODE32", /*125-129*/ + "EANX_CC", "GS1_128_CC", "DBAR_OMN_CC", "DBAR_LTD_CC", "DBAR_EXP_CC", /*130-134*/ + "UPCA_CC", "UPCE_CC", "DBAR_STK_CC", "DBAR_OMNSTK_CC", "DBAR_EXPSTK_CC", /*135-139*/ + "CHANNEL", "CODEONE", "GRIDMATRIX", "UPNQR", "ULTRA", /*140-144*/ + "RMQR", "BC412", "DXFILMEDGE", /*145-147*/ + }; + + name[0] = '\0'; + + if (!ZBarcode_ValidID(symbol_id)) { + return 1; + } + assert(symbol_id >= 0 && symbol_id < ARRAY_SIZE(names) && names[symbol_id][0]); + + memcpy(name, "BARCODE_", 8); + strcpy(name + 8, names[symbol_id]); + + return 0; +} + +/* Return the capability flags for symbology `symbol_id` that match `cap_flag` */ +unsigned int ZBarcode_Cap(int symbol_id, unsigned int cap_flag) { + unsigned int result = 0; + + if (!ZBarcode_ValidID(symbol_id)) { + return 0; + } + + if ((cap_flag & ZINT_CAP_HRT) && has_hrt(symbol_id)) { + result |= ZINT_CAP_HRT; + } + if ((cap_flag & ZINT_CAP_STACKABLE) && is_stackable(symbol_id)) { + result |= ZINT_CAP_STACKABLE; + } + if ((cap_flag & ZINT_CAP_EANUPC) && is_upcean(symbol_id)) { + result |= ZINT_CAP_EANUPC; + } + if ((cap_flag & ZINT_CAP_COMPOSITE) && is_composite(symbol_id)) { + result |= ZINT_CAP_COMPOSITE; + } + if ((cap_flag & ZINT_CAP_ECI) && supports_eci(symbol_id)) { + result |= ZINT_CAP_ECI; + } + if ((cap_flag & ZINT_CAP_GS1) && gs1_compliant(symbol_id)) { + result |= ZINT_CAP_GS1; + } + if ((cap_flag & ZINT_CAP_DOTTY) && is_dotty(symbol_id)) { + result |= ZINT_CAP_DOTTY; + } + if (cap_flag & ZINT_CAP_QUIET_ZONES) { + switch (symbol_id) { /* See `out_quiet_zones()` in "output.c" */ + case BARCODE_CODE16K: + case BARCODE_CODE49: + case BARCODE_CODABLOCKF: + case BARCODE_HIBC_BLOCKF: + case BARCODE_ITF14: + case BARCODE_EANX: + case BARCODE_EANX_CHK: + case BARCODE_EANX_CC: + case BARCODE_ISBNX: + case BARCODE_UPCA: + case BARCODE_UPCA_CHK: + case BARCODE_UPCA_CC: + case BARCODE_UPCE: + case BARCODE_UPCE_CHK: + case BARCODE_UPCE_CC: + result |= ZINT_CAP_QUIET_ZONES; + break; + } + } + if ((cap_flag & ZINT_CAP_FIXED_RATIO) && is_fixed_ratio(symbol_id)) { + result |= ZINT_CAP_FIXED_RATIO; + } + if (cap_flag & ZINT_CAP_READER_INIT) { + /* Note does not include HIBC versions */ + switch (symbol_id) { + case BARCODE_CODE128: /* Note does not include GS1_128 or NVE18 */ + case BARCODE_CODE128AB: + case BARCODE_CODE16K: + case BARCODE_CODABLOCKF: + case BARCODE_PDF417: + case BARCODE_PDF417COMP: + case BARCODE_DATAMATRIX: + case BARCODE_MICROPDF417: + case BARCODE_AZTEC: + case BARCODE_DOTCODE: + case BARCODE_GRIDMATRIX: + case BARCODE_ULTRA: + result |= ZINT_CAP_READER_INIT; + break; + } + } + if (cap_flag & ZINT_CAP_FULL_MULTIBYTE) { + switch (symbol_id) { + case BARCODE_QRCODE: + case BARCODE_MICROQR: + /* case BARCODE_HIBC_QR: Note character set restricted to ASCII subset */ + /* case BARCODE_UPNQR: Note does not use Kanji mode */ + case BARCODE_RMQR: + case BARCODE_HANXIN: + case BARCODE_GRIDMATRIX: + result |= ZINT_CAP_FULL_MULTIBYTE; + break; + } + } + if (cap_flag & ZINT_CAP_MASK) { + switch (symbol_id) { + case BARCODE_QRCODE: + case BARCODE_MICROQR: + case BARCODE_UPNQR: + case BARCODE_HANXIN: + case BARCODE_DOTCODE: + result |= ZINT_CAP_MASK; + break; + } + } + if (cap_flag & ZINT_CAP_STRUCTAPP) { + switch (symbol_id) { + case BARCODE_PDF417: + case BARCODE_PDF417COMP: + case BARCODE_MAXICODE: + case BARCODE_QRCODE: /* Note does not include MICROQR, UPNQR or rMQR */ + case BARCODE_DATAMATRIX: + case BARCODE_MICROPDF417: + case BARCODE_AZTEC: + case BARCODE_HIBC_DM: + case BARCODE_HIBC_QR: + case BARCODE_HIBC_PDF: + case BARCODE_HIBC_MICPDF: + case BARCODE_HIBC_AZTEC: + case BARCODE_DOTCODE: + case BARCODE_CODEONE: + case BARCODE_GRIDMATRIX: + case BARCODE_ULTRA: + result |= ZINT_CAP_STRUCTAPP; + break; + } + } + if ((cap_flag & ZINT_CAP_COMPLIANT_HEIGHT) && !is_fixed_ratio(symbol_id)) { + switch (symbol_id) { + /* These don't have a compliant height defined */ + case BARCODE_CODE11: /* TODO: Find doc */ + case BARCODE_C25STANDARD: /* For C25 only have doc for C25INTER */ + case BARCODE_C25IATA: + case BARCODE_C25LOGIC: + case BARCODE_C25IND: + case BARCODE_CODE128: /* Left to application */ + case BARCODE_CODE128AB: + case BARCODE_DPLEIT: /* TODO: Find doc */ + case BARCODE_DPIDENT: /* TODO: Find doc */ + case BARCODE_FLAT: /* TODO: Find doc */ + case BARCODE_MSI_PLESSEY: /* TODO: Find doc */ + case BARCODE_PDF417: /* Has compliant height but already warns & uses for default */ + case BARCODE_PDF417COMP: + case BARCODE_VIN: /* Spec unlikely */ + case BARCODE_KOREAPOST: /* TODO: Find doc */ + case BARCODE_MICROPDF417: /* See PDF417 */ + case BARCODE_PLESSEY: /* TODO: Find doc */ + case BARCODE_DAFT: /* Generic */ + case BARCODE_HIBC_128: /* See CODE128 */ + case BARCODE_HIBC_PDF: /* See PDF417 */ + case BARCODE_HIBC_MICPDF: /* See PDF417 */ + break; + default: + result |= ZINT_CAP_COMPLIANT_HEIGHT; + break; + } + } + + return result; +} + +/* Return default X-dimension in mm for symbology `symbol_id`. Returns 0 on error (invalid `symbol_id`) */ +float ZBarcode_Default_Xdim(int symbol_id) { + float x_dim_mm; + + if (!ZBarcode_ValidID(symbol_id)) { + return 0.0f; + } + switch (symbol_id) { + /* Postal 2/4-track */ + case BARCODE_AUSPOST: + case BARCODE_AUSREPLY: + case BARCODE_AUSROUTE: + case BARCODE_AUSREDIRECT: + /* Australia Post Customer Barcoding Technical Specifications, average of 0.4 to 0.6 mm */ + x_dim_mm = 0.5f; + break; + case BARCODE_CEPNET: + case BARCODE_POSTNET: + case BARCODE_PLANET: + case BARCODE_USPS_IMAIL: + /* USPS-B-3200 Section 2.3.1, height 0.145" (average of 0.125, 0.165) / 6.235 (Zint height), same as + USPS DMM 300 Section 708.4.2.5 using bar pitch (1" / 43) ~ 0.023" */ + x_dim_mm = 0.591f; + break; + case BARCODE_RM4SCC: + case BARCODE_KIX: + case BARCODE_MAILMARK_4S: + /* Royal Mail Mailmark Barcode Definition Document, height 5.1mm / 8 (Zint height) == 0.6375 */ + x_dim_mm = 0.638f; /* Seems better fit to round up to 3 d.p. */ + break; + case BARCODE_JAPANPOST: + x_dim_mm = 0.6f; /* Japan Post Zip/Barcode Manual */ + break; + + /* GS1 (excluding GS1-128, ITF-14, GS1 QRCODE & GS1 DATAMATRIX - see default) */ + case BARCODE_EANX: + case BARCODE_EANX_CHK: + case BARCODE_EANX_CC: + case BARCODE_ISBNX: + case BARCODE_UPCA: + case BARCODE_UPCA_CHK: + case BARCODE_UPCA_CC: + case BARCODE_UPCE: + case BARCODE_UPCE_CHK: + case BARCODE_UPCE_CC: + case BARCODE_DBAR_OMN: + case BARCODE_DBAR_OMN_CC: + case BARCODE_DBAR_LTD: + case BARCODE_DBAR_LTD_CC: + case BARCODE_DBAR_EXP: + case BARCODE_DBAR_EXP_CC: + case BARCODE_DBAR_STK: + case BARCODE_DBAR_STK_CC: + case BARCODE_DBAR_OMNSTK: + case BARCODE_DBAR_OMNSTK_CC: + case BARCODE_DBAR_EXPSTK: + case BARCODE_DBAR_EXPSTK_CC: + x_dim_mm = 0.33f; /* GS1 General Standards 22.0 Section 5.12.3 Table 1 except DBAR_LTD Table 4 */ + break; + case BARCODE_DXFILMEDGE: + /* Measured on Kodak 35mm film, a DX Film Edge with frame number with 31 symbols is 12,51 mm long */ + x_dim_mm = 0.403548f; + break; + /* Specific */ + case BARCODE_BC412: + x_dim_mm = 0.12f; /* SEMI T1-95 Table 1 */ + break; + case BARCODE_CODABAR: + x_dim_mm = 0.38f; /* EN 798:1996 Appendix D.1 (d), average of 0.33 to 0.43 mm */ + break; + case BARCODE_CODE32: + x_dim_mm = 0.25f; /* Allegato A Caratteristiche tecniche del bollino farmaceutico, 0.25mm */ + break; + case BARCODE_DPD: + x_dim_mm = 0.375f; /* DPD Parcel Label Specification Version 2.4.1 (19.01.2021) Section 4.6.1.2 */ + break; + case BARCODE_FIM: + /* USPS DMM 300 Section 708.9.3, 0.03125" */ + x_dim_mm = 0.79375f; + break; + case BARCODE_LOGMARS: + x_dim_mm = 0.34925f; /* MIL-STD-1189 Rev. B Section 5.2, average of 0.0075" and 0.02" */ + break; + case BARCODE_MAILMARK_2D: + /* Royal Mail Mailmark Barcode Definition Document, Section 2.4 */ + x_dim_mm = 0.5f; + break; + case BARCODE_MAXICODE: + /* ISO/IEC 16023:2000 Table 7, based on L = 25.5mm */ + x_dim_mm = 0.88f; + break; + case BARCODE_PHARMA: + x_dim_mm = 0.5f; /* Laetus Pharmacode Guide Section 1.2, standard 0.5mm */ + break; + case BARCODE_PHARMA_TWO: + x_dim_mm = 1.0f; /* Laetus Pharmacode Guide Section 1.4, standard 1mm */ + break; + case BARCODE_PZN: + x_dim_mm = 0.25f; /* Technical Information regarding PZN, "normal" X 0.25mm */ + break; + case BARCODE_TELEPEN: + case BARCODE_TELEPEN_NUM: + /* Telepen Barcode Symbology information and History, average of between 0.010" and 0.0125" */ + x_dim_mm = 0.28575f; + break; + case BARCODE_UPU_S10: + x_dim_mm = 0.42f; /* Universal Postal Union S10 Section 8, average of 0.33mm & 0.51mm */ + break; + + /* Stacked (excluding GS1 DataBar) */ + case BARCODE_CODE16K: /* Application-defined */ + case BARCODE_CODE49: /* ANSI/AIM BC6-2000 Appendix D.2.4, C grade if > 0.25mm */ + case BARCODE_CODABLOCKF: /* Application-defined */ + case BARCODE_HIBC_BLOCKF: + case BARCODE_PDF417: /* Maybe 0.27mm following ISO/IEC 15438:2015 Annex S.2.2 example? */ + case BARCODE_PDF417COMP: + case BARCODE_HIBC_PDF: + case BARCODE_MICROPDF417: + case BARCODE_HIBC_MICPDF: + /* Fairly arbitrarily using ISO/IEC 15416:2016 Section 5.3.1 Table 1, aperature diameters 0.125 & 0.250 + (also fits in 0.25 <= X < 0.5 range for aperature 0.2 from ISO/IEC 15415:2011 Annex D Table D.1) */ + x_dim_mm = 0.33f; + break; + + /* Application defined (and hence pretty arbitrary) */ + default: + if (is_fixed_ratio(symbol_id)) { + /* GS1 General Standards 22.0 Section 5.12.3 Table 1 (general retail) */ + x_dim_mm = 0.625f; + } else { + /* GS1 General Standards 22.0 Section 5.12.3.4 GS1-128 Tables 2, 4, 5, 6, 8 */ + x_dim_mm = 0.495f; + } + break; + } + + return x_dim_mm; +} + +/* Return the scale to use for `symbol_id` for non-zero X-dimension `x_dim_mm` at `dpmm` dots per mm for + `filetype`. If `dpmm` zero defaults to 12. If `filetype` NULL/empty, defaults to "GIF". Returns 0 on error */ +float ZBarcode_Scale_From_XdimDp(int symbol_id, float x_dim_mm, float dpmm, const char *filetype) { + int i; + float scale; + + if (!ZBarcode_ValidID(symbol_id)) { + return 0.0f; + } + if (x_dim_mm <= 0.0f || x_dim_mm > 10.0f) { /* 10mm == 0.39" */ + return 0.0f; + } + if (dpmm == 0.0f) { + dpmm = 12.0f; /* ~300 dpi */ + } else if (dpmm < 0.0f || dpmm > 1000.0f) { /* 1000 dpmm == 25400 dpi */ + return 0.0f; + } + if (filetype && *filetype) { + if ((i = filetype_idx(filetype)) < 0 || filetypes[i].filetype == 0) { /* Not found or TXT */ + return 0.0f; + } + } else { + i = filetype_idx("GIF"); /* Default to raster */ + } + + scale = stripf(stripf(x_dim_mm) * stripf(dpmm)); + + if (symbol_id == BARCODE_MAXICODE) { + if (filetypes[i].is_raster) { + scale /= 10.0f; + } else if (filetypes[i].filetype == OUT_EMF_FILE) { + scale /= 40.0f; + } else { + scale /= 2.0f; + } + } else { + if (filetypes[i].is_raster) { + scale = roundf(scale) / 2.0f; /* Half-integer increments */ + } else { + scale /= 2.0f; + } + } + scale = stripf(scale); + + if (scale > 200.0f) { + scale = 200.0f; + } else { + if (filetypes[i].is_raster) { + if (symbol_id == BARCODE_MAXICODE) { + if (scale < 0.2f) { + scale = 0.2f; + } + } else if (scale < 0.5f) { + scale = 0.5f; /* Note if dotty mode needs further bounding to 1.0 */ + } + } else { + if (scale < 0.1f) { + scale = 0.1f; + } + } + } + + return scale; +} + +/* Reverse of `ZBarcode_Scale_From_XdimDp()` above to estimate the X-dimension or dpmm given non-zero `scale` and + non-zero `x_dim_mm_or_dpmm`. Return value bound to dpmm max not X-dimension max. Returns 0 on error */ +float ZBarcode_XdimDp_From_Scale(int symbol_id, float scale, float xdim_mm_or_dpmm, const char *filetype) { + int i; + + if (!ZBarcode_ValidID(symbol_id)) { + return 0.0f; + } + if (scale <= 0.0f || scale > 200.0f) { + return 0.0f; + } + if (xdim_mm_or_dpmm <= 0.0f || xdim_mm_or_dpmm > 1000.0f) { /* 1000 dpmm == 25400 dpi */ + return 0.0f; + } + if (filetype && *filetype) { + if ((i = filetype_idx(filetype)) < 0 || filetypes[i].filetype == 0) { /* Not found or TXT */ + return 0.0f; + } + } else { + i = filetype_idx("GIF"); /* Default to raster */ + } + + if (symbol_id == BARCODE_MAXICODE) { + if (filetypes[i].is_raster) { + scale *= 10.0f; + } else if (filetypes[i].filetype == OUT_EMF_FILE) { + scale *= 40.0f; + } else { + scale *= 2.0f; + } + } else { + scale *= 2.0f; + } + + xdim_mm_or_dpmm = stripf(stripf(scale) / stripf(xdim_mm_or_dpmm)); + + if (xdim_mm_or_dpmm > 1000.0f) { /* Note if X-dimension sought needs to be further bound to <= 10 on return */ + xdim_mm_or_dpmm = 1000.0f; + } + + return xdim_mm_or_dpmm; +} + +/* Whether Zint built without PNG support */ +int ZBarcode_NoPng(void) { +#ifdef ZINT_NO_PNG + return 1; +#else + return 0; +#endif +} + +/* Return the version of Zint linked to */ +int ZBarcode_Version(void) { +#if ZINT_VERSION_BUILD + return (ZINT_VERSION_MAJOR * 10000) + (ZINT_VERSION_MINOR * 100) + ZINT_VERSION_RELEASE * 10 + ZINT_VERSION_BUILD; +#else + return (ZINT_VERSION_MAJOR * 10000) + (ZINT_VERSION_MINOR * 100) + ZINT_VERSION_RELEASE; +#endif +} + +/* vim: set ts=4 sw=4 et : */
