Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/zint/backend/upcean.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/upcean.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,986 @@ +/* upcean.c - Handles UPC, EAN and ISBN */ +/* + libzint - the open source barcode library + Copyright (C) 2008-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 */ + +#define SODIUM_PLS_F (IS_NUM_F | IS_PLS_F) /* SODIUM "0123456789+" */ +#define ISBNX_SANE_F (IS_NUM_F | IS_UX__F) /* ISBNX_SANE "0123456789X" */ +#define ISBNX_ADDON_SANE_F (IS_NUM_F | IS_UX__F | IS_LX__F | IS_PLS_F) /* ISBNX_ADDON_SANE "0123456789Xx+" */ + +#include <assert.h> +#include <stdio.h> +#include "common.h" +#include "gs1.h" + +/* UPC and EAN tables checked against EN 797:1996 */ + +static const char UPCParity0[10][6] = { + /* Number set for UPC-E symbol (EN Table 4) */ + {'B','B','B','A','A','A'}, {'B','B','A','B','A','A'}, {'B','B','A','A','B','A'}, {'B','B','A','A','A','B'}, + {'B','A','B','B','A','A'}, {'B','A','A','B','B','A'}, {'B','A','A','A','B','B'}, {'B','A','B','A','B','A'}, + {'B','A','B','A','A','B'}, {'B','A','A','B','A','B'} +}; + +static const char UPCParity1[10][6] = { + /* Not covered by BS EN 797:1995 */ + {'A','A','A','B','B','B'}, {'A','A','B','A','B','B'}, {'A','A','B','B','A','B'}, {'A','A','B','B','B','A'}, + {'A','B','A','A','B','B'}, {'A','B','B','A','A','B'}, {'A','B','B','B','A','A'}, {'A','B','A','B','A','B'}, + {'A','B','A','B','B','A'}, {'A','B','B','A','B','A'} +}; + +static const char EAN2Parity[4][2] = { + /* Number sets for 2-digit add-on (EN Table 6) */ + {'A','A'}, {'A','B'}, {'B','A'}, {'B','B'} +}; + +static const char EAN5Parity[10][5] = { + /* Number set for 5-digit add-on (EN Table 7) */ + {'B','B','A','A','A'}, {'B','A','B','A','A'}, {'B','A','A','B','A'}, {'B','A','A','A','B'}, {'A','B','B','A','A'}, + {'A','A','B','B','A'}, {'A','A','A','B','B'}, {'A','B','A','B','A'}, {'A','B','A','A','B'}, {'A','A','B','A','B'} +}; + +static const char EAN13Parity[10][5] = { + /* Left hand of the EAN-13 symbol (EN Table 3) */ + {'A','A','A','A','A'}, {'A','B','A','B','B'}, {'A','B','B','A','B'}, {'A','B','B','B','A'}, {'B','A','A','B','B'}, + {'B','B','A','A','B'}, {'B','B','B','A','A'}, {'B','A','B','A','B'}, {'B','A','B','B','A'}, {'B','B','A','B','A'} +}; + +static const char EANsetA[10][4] = { + /* Representation set A and C (EN Table 1) */ + {'3','2','1','1'}, {'2','2','2','1'}, {'2','1','2','2'}, {'1','4','1','1'}, {'1','1','3','2'}, + {'1','2','3','1'}, {'1','1','1','4'}, {'1','3','1','2'}, {'1','2','1','3'}, {'3','1','1','2'} +}; + +static const char EANsetB[10][4] = { + /* Representation set B (EN Table 1) */ + {'1','1','2','3'}, {'1','2','2','2'}, {'2','2','1','2'}, {'1','1','4','1'}, {'2','3','1','1'}, + {'1','3','2','1'}, {'4','1','1','1'}, {'2','1','3','1'}, {'3','1','2','1'}, {'2','1','1','3'} +}; + +/* UPC A is usually used for 12 digit numbers, but this function takes a source of any length */ +static void upca_draw(const unsigned char source[], const int length, char *d) { + int i, half_way; + + half_way = length / 2; + + /* start character */ + memcpy(d, "111", 3); + d += 3; + + for (i = 0; i < length; i++, d += 4) { + if (i == half_way) { + /* middle character - separates manufacturer no. from product no. */ + /* also inverts right hand characters */ + memcpy(d, "11111", 5); + d += 5; + } + + memcpy(d, EANsetA[source[i] - '0'], 4); + } + + /* stop character */ + strcpy(d, "111"); +} + +/* Make a UPC-A barcode, allowing for composite if `cc_rows` set */ +static int upca_cc(struct zint_symbol *symbol, const unsigned char source[], int length, char dest[], int cc_rows) { + unsigned char *gtin = symbol->text; + int error_number = 0; + + ustrcpy(gtin, source); + + if (length == 11) { + gtin[length++] = gs1_check_digit(gtin, 11); + gtin[length] = '\0'; + } else { + if (source[length - 1] != gs1_check_digit(gtin, 11)) { + return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 270, "Invalid check digit '%1$c', expecting '%2$c'", + source[length - 1], gs1_check_digit(gtin, 11)); + } + } + if (symbol->debug & ZINT_DEBUG_PRINT) { + printf("UPC-A: %s, gtin: %s, Check digit: %c\n", source, gtin, + length == 11 ? gtin[length] : gtin[length - 1]); + } + + upca_draw(gtin, length, dest); + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* BS EN 797:1996 4.5.1 Nominal dimensions 22.85mm / 0.33mm (X) ~ 69.24, + same as minimum GS1 General Specifications 21.0.1 5.12.3.1 */ + const float height = 69.242424f; /* 22.85 / 0.33 */ + if (symbol->symbology == BARCODE_UPCA_CC) { + symbol->height = height; /* Pass back min row == default height */ + } else { + error_number = set_height(symbol, height, height, 0.0f, 0 /*no_errtxt*/); + } + } else { + const float height = 50.0f; + if (symbol->symbology == BARCODE_UPCA_CC) { + symbol->height = height - cc_rows * 2 - 6.0f; + } else { + (void) set_height(symbol, 0.0f, height, 0.0f, 1 /*no_errtxt*/); + } + } + + return error_number; +} + +/* UPC-A */ +static int upca(struct zint_symbol *symbol, const unsigned char source[], int length, char dest[]) { + return upca_cc(symbol, source, length, dest, 0 /*cc_rows*/); +} + +/* UPC-E, allowing for composite if `cc_rows` set */ +static int upce_cc(struct zint_symbol *symbol, unsigned char source[], int length, char *d, int cc_rows) { + int i, num_system; + char emode, check_digit; + const char *parity; + char src_check_digit = '\0'; + unsigned char equivalent[12]; + unsigned char *hrt = symbol->text; + int error_number = 0; + + if (length == 8 || symbol->symbology == BARCODE_UPCE_CHK) { + /* Will validate later */ + src_check_digit = source[--length]; + } + + /* Two number systems can be used - system 0 and system 1 */ + hrt[0] = '\0'; + if (length == 7) { + switch (source[0]) { + case '0': + num_system = 0; + ustrncat(hrt, source, length); + break; + case '1': + num_system = 1; + ustrncat(hrt, source, length); + break; + default: + num_system = 0; + /* First source char ignored */ + ustrncat(hrt, source, length); + hrt[0] = '0'; /* Overwrite HRT first char with '0' to correct TODO: error/warn in future */ + break; + } + for (i = 1; i <= length; i++) { + source[i - 1] = hrt[i]; + } + length--; + } else { + /* Length 6, insert leading zero */ + num_system = 0; + hrt[0] = '0'; + hrt[1] = '\0'; + ustrncat(hrt, source, length); + } + + /* Expand the zero-compressed UPCE code to make a UPCA equivalent (EN Table 5) */ + emode = source[5]; + for (i = 0; i < 11; i++) { + equivalent[i] = '0'; + } + if (num_system == 1) { + equivalent[0] = hrt[0]; + } + equivalent[1] = source[0]; + equivalent[2] = source[1]; + equivalent[11] = '\0'; + + switch (emode) { + case '0': + case '1': + case '2': + equivalent[3] = emode; + equivalent[8] = source[2]; + equivalent[9] = source[3]; + equivalent[10] = source[4]; + break; + case '3': + equivalent[3] = source[2]; + equivalent[9] = source[3]; + equivalent[10] = source[4]; + if (((source[2] == '0') || (source[2] == '1')) || (source[2] == '2')) { + /* Note 1 - "X3 shall not be equal to 0, 1 or 2" */ + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 271, + "For this UPC-E zero suppression, 3rd character cannot be \"0\", \"1\" or \"2\" (%.*s)", + length, source); + } + break; + case '4': + equivalent[3] = source[2]; + equivalent[4] = source[3]; + equivalent[10] = source[4]; + if (source[3] == '0') { + /* Note 2 - "X4 shall not be equal to 0" */ + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 272, + "For this UPC-E zero suppression, 4th character cannot be \"0\" (%.*s)", + length, source); + } + break; + case '5': + case '6': + case '7': + case '8': + case '9': + equivalent[3] = source[2]; + equivalent[4] = source[3]; + equivalent[5] = source[4]; + equivalent[10] = emode; + if (source[4] == '0') { + /* Note 3 - "X5 shall not be equal to 0" */ + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 273, + "For this UPC-E zero suppression, 5th character cannot be \"0\" (%.*s)", + length, source); + } + break; + } + + /* Get the check digit from the expanded UPCA code */ + + check_digit = gs1_check_digit(equivalent, 11); + + if (src_check_digit && src_check_digit != check_digit) { + return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 274, "Invalid check digit '%1$c', expecting '%2$c'", + src_check_digit, check_digit); + } + + /* Use the number system and check digit information to choose a parity scheme */ + if (num_system == 1) { + parity = UPCParity1[ctoi(check_digit)]; + } else { + parity = UPCParity0[ctoi(check_digit)]; + } + + /* Take all this information and make the barcode pattern */ + + /* start character */ + memcpy(d, "111", 3); + d += 3; + + for (i = 0; i < length; i++, d += 4) { + switch (parity[i]) { + case 'A': + memcpy(d, EANsetA[source[i] - '0'], 4); + break; + case 'B': + memcpy(d, EANsetB[source[i] - '0'], 4); + break; + } + } + + /* stop character */ + strcpy(d, "111111"); + + hrt[7] = check_digit; + hrt[8] = '\0'; + + if (symbol->debug & ZINT_DEBUG_PRINT) { + printf("UPC-E: %s, equivalent: %s, hrt: %s, Check digit: %c\n", source, equivalent, hrt, check_digit); + } + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* BS EN 797:1996 4.5.1 Nominal dimensions 22.85mm / 0.33mm (X) ~ 69.24, + same as minimum GS1 General Specifications 21.0.1 5.12.3.1 */ + const float height = 69.242424f; /* 22.85 / 0.33 */ + if (symbol->symbology == BARCODE_UPCE_CC) { + symbol->height = height; /* Pass back min row == default height */ + } else { + error_number = set_height(symbol, height, height, 0.0f, 0 /*no_errtxt*/); + } + } else { + const float height = 50.0f; + if (symbol->symbology == BARCODE_UPCE_CC) { + symbol->height = height - cc_rows * 2 - 6.0f; + } else { + (void) set_height(symbol, 0.0f, height, 0.0f, 1 /*no_errtxt*/); + } + } + + return error_number; +} + +/* UPC-E is a zero-compressed version of UPC-A */ +static int upce(struct zint_symbol *symbol, unsigned char source[], int length, char dest[]) { + return upce_cc(symbol, source, length, dest, 0 /*cc_rows*/); +} + +/* EAN-2 and EAN-5 add-on codes */ +static void ean_add_on(const unsigned char source[], const int length, char dest[], const int addon_gap) { + const char *parity; + int i; + char *d = dest + strlen(dest); + + /* If an add-on then append with space */ + if (addon_gap != 0) { + *d++ = itoc(addon_gap); + } + + /* Start character */ + memcpy(d, "112", 3); + d += 3; + + /* Calculate parity */ + if (length == 2) { /* EAN-2 */ + int code_value, parity_bit; + + code_value = (10 * ctoi(source[0])) + ctoi(source[1]); + parity_bit = code_value % 4; + parity = EAN2Parity[parity_bit]; + } else { /* EAN-5 */ + int values[6], parity_sum, parity_bit; + + for (i = 0; i < 6; i++) { + values[i] = ctoi(source[i]); + } + + parity_sum = (3 * (values[0] + values[2] + values[4])); + parity_sum += (9 * (values[1] + values[3])); + + parity_bit = parity_sum % 10; + parity = EAN5Parity[parity_bit]; + } + + for (i = 0; i < length; i++) { + switch (parity[i]) { + case 'A': + memcpy(d, EANsetA[source[i] - '0'], 4); + d += 4; + break; + case 'B': + memcpy(d, EANsetB[source[i] - '0'], 4); + d += 4; + break; + } + + /* Glyph separator */ + if (i != (length - 1)) { + memcpy(d, "11", 2); + d += 2; + } + } + *d = '\0'; +} + +/* ************************ EAN-13 ****************** */ + +static int ean13_cc(struct zint_symbol *symbol, const unsigned char source[], int length, char *d, + int cc_rows) { + int i, half_way; + const char *parity; + unsigned char *gtin = symbol->text; + int error_number = 0; + + ustrcpy(gtin, source); + + /* Add the appropriate check digit */ + + if (length == 12) { + gtin[length++] = gs1_check_digit(gtin, 12); + gtin[length] = '\0'; + } else { + if (source[length - 1] != gs1_check_digit(gtin, 12)) { + return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 275, "Invalid check digit '%1$c', expecting '%2$c'", + source[length - 1], gs1_check_digit(gtin, 12)); + } + } + if (symbol->debug & ZINT_DEBUG_PRINT) { + printf("EAN-13: %s, gtin: %s, Check digit: %c\n", source, gtin, gtin[length - 1]); + } + + /* Get parity for first half of the symbol */ + parity = EAN13Parity[gtin[0] - '0']; + + /* Now get on with the cipher */ + half_way = 7; + + /* start character */ + memcpy(d, "111", 3); + d += 3; + + for (i = 1; i < length; i++, d += 4) { + if (i == half_way) { + /* middle character - separates manufacturer no. from product no. */ + /* also inverses right hand characters */ + memcpy(d, "11111", 5); + d += 5; + } + + if (((i > 1) && (i < 7)) && (parity[i - 2] == 'B')) { + memcpy(d, EANsetB[gtin[i] - '0'], 4); + } else { + memcpy(d, EANsetA[gtin[i] - '0'], 4); + } + } + + /* stop character */ + strcpy(d, "111"); + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* BS EN 797:1996 4.5.1 Nominal dimensions 22.85mm / 0.33mm (X) ~ 69.24, + same as minimum GS1 General Specifications 21.0.1 5.12.3.1 */ + const float height = 69.242424f; /* 22.85 / 0.33 */ + if (symbol->symbology == BARCODE_EANX_CC) { + symbol->height = height; /* Pass back min row == default height */ + } else { + error_number = set_height(symbol, height, height, 0.0f, 0 /*no_errtxt*/); + } + } else { + const float height = 50.0f; + if (symbol->symbology == BARCODE_EANX_CC) { + symbol->height = height - cc_rows * 2 - 6.0f; + } else { + (void) set_height(symbol, 0.0f, height, 0.0f, 1 /*no_errtxt*/); + } + } + + return error_number; +} + +static int ean13(struct zint_symbol *symbol, const unsigned char source[], int length, char dest[]) { + return ean13_cc(symbol, source, length, dest, 0 /*cc_rows*/); +} + +static int ean8_cc(struct zint_symbol *symbol, const unsigned char source[], int length, char dest[], int cc_rows) { + /* EAN-8 is basically the same as UPC-A but with fewer digits */ + unsigned char *gtin = symbol->text; + int error_number = 0; + + ustrcpy(gtin, source); + + if (length == 7) { + gtin[length++] = gs1_check_digit(gtin, 7); + gtin[length] = '\0'; + } else { + if (source[length - 1] != gs1_check_digit(gtin, 7)) { + return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 276, "Invalid check digit '%1$c', expecting '%2$c'", + source[length - 1], gs1_check_digit(gtin, 7)); + } + } + if (symbol->debug & ZINT_DEBUG_PRINT) { + printf("EAN-8: %s, gtin: %s, Check digit: %c\n", source, gtin, + length == 7 ? gtin[length] : gtin[length - 1]); + } + + upca_draw(gtin, length, dest); + + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* BS EN 797:1996 4.5.1 Nominal dimensions 18.23mm / 0.33mm (X) ~ 55.24, + same as minimum GS1 General Specifications 21.0.1 5.12.3.1 */ + const float height = 55.242424f; /* 18.23 / 0.33 */ + if (symbol->symbology == BARCODE_EANX_CC) { + symbol->height = height; /* Pass back min row == default height */ + } else { + error_number = set_height(symbol, height, height, 0.0f, 0 /*no_errtxt*/); + } + } else { + const float height = 50.0f; + if (symbol->symbology == BARCODE_EANX_CC) { + symbol->height = height - cc_rows * 2 - 6.0f; + } else { + (void) set_height(symbol, 0.0f, height, 0.0f, 1 /*no_errtxt*/); + } + } + + return error_number; +} + +/* Make an EAN-8 barcode when we haven't been given the check digit */ +static int ean8(struct zint_symbol *symbol, const unsigned char source[], int length, char dest[]) { + return ean8_cc(symbol, source, length, dest, 0 /*cc_rows*/); +} + +/* For ISBN(10) and SBN only */ +static char isbnx_check(const unsigned char source[], const int length) { + int i, weight, sum, check; + char check_char; + + sum = 0; + weight = 1; + + for (i = 0; i < length; i++) { /* Length will always be 9 */ + sum += ctoi(source[i]) * weight; + weight++; + } + + check = sum % 11; + check_char = itoc(check); + if (check == 10) { + check_char = 'X'; + } + return check_char; +} + +/* Make an EAN-13 barcode from an SBN or ISBN */ +static int isbnx(struct zint_symbol *symbol, unsigned char source[], const int length, char dest[]) { + int i; + char check_digit; + + to_upper(source, length); + if (not_sane(ISBNX_SANE_F, source, length)) { /* As source has been zero-padded, don't report position */ + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 277, "Invalid character in input (digits and \"X\" only)"); + } + + /* Input must be 9, 10 or 13 characters */ + if (length != 9 && length != 10 && length != 13) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 278, "Input length %d wrong (9, 10, or 13 only)", length); + } + + if (length == 13) /* Using 13 character ISBN */ { + if (!(((source[0] == '9') && (source[1] == '7')) && + ((source[2] == '8') || (source[2] == '9')))) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 279, "Invalid ISBN (must begin with \"978\" or \"979\")"); + } + + /* "X" cannot occur */ + if (not_sane(NEON_F, source, 13)) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 282, + "Invalid character in input, \"X\" not allowed in ISBN-13"); + } + + check_digit = gs1_check_digit(source, 12); + if (source[12] != check_digit) { + return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 280, "Invalid ISBN check digit '%1$c', expecting '%2$c'", + source[12], check_digit); + } + source[12] = '\0'; + + } else { /* Using 10 digit ISBN or 9 digit SBN padded with leading zero */ + if (length == 9) /* Using 9 digit SBN */ { + /* Add leading zero */ + for (i = 10; i > 0; i--) { + source[i] = source[i - 1]; + } + source[0] = '0'; + } + + /* "X" can only occur in last position */ + if (not_sane(NEON_F, source, 9)) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 296, + "Invalid character in input, \"X\" allowed in last position only"); + } + + check_digit = isbnx_check(source, 9); + if (check_digit != source[9]) { + return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 281, + "Invalid %1$s check digit '%2$c', expecting '%3$c'", length == 9 ? "SBN" : "ISBN", + source[9], check_digit); + } + for (i = 11; i > 2; i--) { /* This drops the check digit */ + source[i] = source[i - 3]; + } + source[0] = '9'; + source[1] = '7'; + source[2] = '8'; + source[12] = '\0'; + } + + return ean13(symbol, source, 12, dest); +} + +/* Add leading zeroes to EAN and UPC strings */ +INTERNAL int ean_leading_zeroes(struct zint_symbol *symbol, const unsigned char source[], + unsigned char local_source[], int *p_with_addon, unsigned char *zfirst_part, + unsigned char *zsecond_part) { + unsigned char first_part[14], second_part[6]; + int with_addon = 0; + int first_len = 0, second_len = 0, zfirst_len = 0, zsecond_len = 0, i, h; + + h = (int) ustrlen(source); + for (i = 0; i < h; i++) { + if (source[i] == '+') { + with_addon = 1; + } else { + if (with_addon == 0) { + first_len++; + } else { + second_len++; + } + } + } + if (first_len > 13 || second_len > 5) { + if (first_len > 13) { + if (!second_len) { + errtxtf(0, symbol, 294, "Input length %d too long (maximum 13)", first_len); + } else { + errtxtf(0, symbol, 298, "Input EAN length %d too long (maximum 13)", first_len); + } + } else { + errtxtf(0, symbol, 297, "Input add-on length %d too long (maximum 5)", second_len); + } + if (p_with_addon) { + *p_with_addon = with_addon; + } + return 0; + } + + /* Split input into two strings */ + for (i = 0; i < first_len; i++) { + first_part[i] = source[i]; + } + first_part[first_len] = '\0'; + + for (i = 0; i < second_len; i++) { + second_part[i] = source[i + first_len + 1]; + } + second_part[second_len] = '\0'; + + /* Calculate target lengths */ + if (second_len == 0) { + zsecond_len = 0; + } else if (second_len <= 2) { + zsecond_len = 2; + } else { + zsecond_len = 5; + } + switch (symbol->symbology) { + case BARCODE_EANX: + case BARCODE_EANX_CC: + if (first_len <= 12) { + if (first_len <= 7) { + zfirst_len = 7; + } else { + zfirst_len = 12; + } + } + if (second_len == 0 && symbol->symbology == BARCODE_EANX) { /* No composite EAN-2/5 */ + if (first_len <= 5) { + if (first_len <= 2) { + zfirst_len = 2; + } else { + zfirst_len = 5; + } + } + } + break; + case BARCODE_EANX_CHK: + if (first_len <= 13) { + if (first_len <= 8) { + zfirst_len = 8; + } else { + zfirst_len = 13; + } + } + if (second_len == 0) { + if (first_len <= 5) { + if (first_len <= 2) { + zfirst_len = 2; + } else { + zfirst_len = 5; + } + } + } + break; + case BARCODE_UPCA: + case BARCODE_UPCA_CC: + zfirst_len = 11; + break; + case BARCODE_UPCA_CHK: + zfirst_len = 12; + break; + case BARCODE_UPCE: + case BARCODE_UPCE_CC: + if (first_len == 7) { + zfirst_len = 7; + } else if (first_len <= 6) { + zfirst_len = 6; + } + break; + case BARCODE_UPCE_CHK: + if (first_len == 8) { + zfirst_len = 8; + } else if (first_len <= 7) { + zfirst_len = 7; + } + break; + case BARCODE_ISBNX: + if (first_len <= 9) { + zfirst_len = 9; + } + break; + } + + /* Copy adjusted data back to local_source */ + + /* Add leading zeroes */ + for (i = 0; i < (zfirst_len - first_len); i++) { + local_source[i] = '0'; + } + ustrcpy(local_source + i, first_part); + if (zfirst_part) { + ustrcpy(zfirst_part, local_source); + } + + if (with_addon) { + h = (int) ustrlen(local_source); + local_source[h++] = '+'; + for (i = 0; i < (zsecond_len - second_len); i++) { + local_source[h + i] = '0'; + } + ustrcpy(local_source + h + i, second_part); + if (zsecond_part) { + ustrcpy(zsecond_part, local_source + h); + } + } else if (zsecond_part) { + *zsecond_part = '\0'; + } + + if (p_with_addon) { + *p_with_addon = with_addon; + } + + return 1; /* Success */ +} + +INTERNAL int eanx_cc(struct zint_symbol *symbol, unsigned char source[], int length, int cc_rows) { + unsigned char first_part[14], second_part[6]; + unsigned char local_source[20]; /* Allow 13 + "+" + 5 + 1 */ + char dest[1000] = {0}; + int with_addon; + int error_number = 0, i, plus_count; + int addon_gap = 0; + int first_part_len, second_part_len; + + if (length > 19) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 283, "Input length %d too long (maximum 19)", length); + } + if (symbol->symbology != BARCODE_ISBNX) { + /* ISBN has its own sanity routine */ + if ((i = not_sane(SODIUM_PLS_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 284, + "Invalid character at position %d in input (digits and \"+\" only)", i); + } + } else { + if ((i = not_sane(ISBNX_ADDON_SANE_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 285, + "Invalid character at position %d in input (digits, \"X\" and \"+\" only)", i); + } + /* Add-on will be checked separately to be numeric only below */ + } + + /* Check for multiple '+' characters */ + plus_count = 0; + for (i = 0; i < length; i++) { + if (source[i] == '+') { + plus_count++; + if (plus_count > 1) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 293, "Invalid add-on data (one \"+\" only)"); + } + } + } + + /* Add leading zeroes, checking max lengths of parts */ + if (!ean_leading_zeroes(symbol, source, local_source, &with_addon, first_part, second_part)) { + return ZINT_ERROR_TOO_LONG; /* `ean_leading_zeroes()` sets `errtxt` */ + } + + if (with_addon) { + if (symbol->symbology == BARCODE_UPCA || symbol->symbology == BARCODE_UPCA_CHK + || symbol->symbology == BARCODE_UPCA_CC) { + addon_gap = symbol->option_2 >= 9 && symbol->option_2 <= 12 ? symbol->option_2 : 9; + } else { + addon_gap = symbol->option_2 >= 7 && symbol->option_2 <= 12 ? symbol->option_2 : 7; + } + } + + first_part_len = (int) ustrlen(first_part); + + switch (symbol->symbology) { + case BARCODE_EANX: + case BARCODE_EANX_CHK: + switch (first_part_len) { + case 2: + case 5: + ean_add_on(first_part, first_part_len, dest, 0); + ustrcpy(symbol->text, first_part); + if (symbol->output_options & COMPLIANT_HEIGHT) { + /* 21.9mm from GS1 General Specifications 5.2.6.6, Figure 5.2.6.6-6 */ + const float height = 66.3636398f; /* 21.9 / 0.33 */ + error_number = set_height(symbol, height, height, 0.0f, 0 /*no_errtxt*/); + } else { + (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); + } + break; + case 7: + case 8: + error_number = ean8(symbol, first_part, first_part_len, dest); + break; + case 12: + case 13: + error_number = ean13(symbol, first_part, first_part_len, dest); + break; + default: + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 286, + "Input length %d wrong (2, 5, 7, 8, 12 or 13 only)", first_part_len); + break; + } + break; + case BARCODE_EANX_CC: + switch (first_part_len) { /* Adds vertical separator bars according to ISO/IEC 24723 section 11.4 */ + case 7: + set_module(symbol, symbol->rows, 1); + set_module(symbol, symbol->rows, 67); + set_module(symbol, symbol->rows + 1, 0); + set_module(symbol, symbol->rows + 1, 68); + set_module(symbol, symbol->rows + 2, 1); + set_module(symbol, symbol->rows + 2, 67); + symbol->row_height[symbol->rows] = 2; + symbol->row_height[symbol->rows + 1] = 2; + symbol->row_height[symbol->rows + 2] = 2; + symbol->rows += 3; + error_number = ean8_cc(symbol, first_part, first_part_len, dest, cc_rows); + break; + case 12: + case 13: + set_module(symbol, symbol->rows, 1); + set_module(symbol, symbol->rows, 95); + set_module(symbol, symbol->rows + 1, 0); + set_module(symbol, symbol->rows + 1, 96); + set_module(symbol, symbol->rows + 2, 1); + set_module(symbol, symbol->rows + 2, 95); + symbol->row_height[symbol->rows] = 2; + symbol->row_height[symbol->rows + 1] = 2; + symbol->row_height[symbol->rows + 2] = 2; + symbol->rows += 3; + error_number = ean13_cc(symbol, first_part, first_part_len, dest, cc_rows); + break; + default: + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 287, "Input length %d wrong (7, 12 or 13 only)", + first_part_len); + break; + } + break; + case BARCODE_UPCA: + case BARCODE_UPCA_CHK: + if ((first_part_len == 11) || (first_part_len == 12)) { + error_number = upca(symbol, first_part, first_part_len, dest); + } else { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 288, "Input length %d wrong (11 or 12 only)", + first_part_len); + } + break; + case BARCODE_UPCA_CC: + if (first_part_len == 11 || first_part_len == 12) { + set_module(symbol, symbol->rows, 1); + set_module(symbol, symbol->rows, 95); + set_module(symbol, symbol->rows + 1, 0); + set_module(symbol, symbol->rows + 1, 96); + set_module(symbol, symbol->rows + 2, 1); + set_module(symbol, symbol->rows + 2, 95); + symbol->row_height[symbol->rows] = 2; + symbol->row_height[symbol->rows + 1] = 2; + symbol->row_height[symbol->rows + 2] = 2; + symbol->rows += 3; + error_number = upca_cc(symbol, first_part, first_part_len, dest, cc_rows); + } else { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 289, "Input length %d wrong (11 or 12 only)", + first_part_len); + } + break; + case BARCODE_UPCE: + case BARCODE_UPCE_CHK: + if ((first_part_len >= 6) && (first_part_len <= 8)) { + error_number = upce(symbol, first_part, first_part_len, dest); + } else { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 290, "Input length %d wrong (6, 7 or 8 only)", + first_part_len); + } + break; + case BARCODE_UPCE_CC: + if ((first_part_len >= 6) && (first_part_len <= 8)) { + set_module(symbol, symbol->rows, 1); + set_module(symbol, symbol->rows, 51); + set_module(symbol, symbol->rows + 1, 0); + set_module(symbol, symbol->rows + 1, 52); + set_module(symbol, symbol->rows + 2, 1); + set_module(symbol, symbol->rows + 2, 51); + symbol->row_height[symbol->rows] = 2; + symbol->row_height[symbol->rows + 1] = 2; + symbol->row_height[symbol->rows + 2] = 2; + symbol->rows += 3; + error_number = upce_cc(symbol, first_part, first_part_len, dest, cc_rows); + } else { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 291, "Input length %d wrong (6, 7 or 8 only)", + first_part_len); + } + break; + case BARCODE_ISBNX: + error_number = isbnx(symbol, first_part, first_part_len, dest); + break; + } + + if (error_number >= ZINT_ERROR) { + return error_number; + } + + second_part_len = (int) ustrlen(second_part); + + if (symbol->symbology == BARCODE_ISBNX) { /* Need to further check that add-on numeric only */ + if (not_sane(NEON_F, second_part, second_part_len)) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 295, "Invalid add-on data (digits only)"); + } + } + + if (second_part_len) { + ean_add_on(second_part, second_part_len, dest, addon_gap); + ustrcat(symbol->text, "+"); + ustrcat(symbol->text, second_part); + } + + expand(symbol, dest, (int) strlen(dest)); + + switch (symbol->symbology) { + case BARCODE_EANX_CC: + case BARCODE_UPCA_CC: + case BARCODE_UPCE_CC: + /* shift the symbol to the right one space to allow for separator bars */ + for (i = (symbol->width + 1); i >= 1; i--) { + if (module_is_set(symbol, symbol->rows - 1, i - 1)) { + set_module(symbol, symbol->rows - 1, i); + } else { + unset_module(symbol, symbol->rows - 1, i); + } + } + unset_module(symbol, symbol->rows - 1, 0); + symbol->width += 1 + (second_part_len == 0); /* Only need right space if no add-on */ + break; + } + + return error_number; +} + +/* Handle UPC, EAN, ISBN */ +INTERNAL int eanx(struct zint_symbol *symbol, unsigned char source[], int length) { + return eanx_cc(symbol, source, length, 0 /*cc_rows*/); +} + +/* vim: set ts=4 sw=4 et : */
