2008-07-14 09:15:55 +12:00
|
|
|
/* upcean.c - Handles UPC, EAN and ISBN
|
|
|
|
|
|
|
|
libzint - the open source barcode library
|
2020-07-11 06:39:32 +12:00
|
|
|
Copyright (C) 2008 - 2020 Robin Stuart <rstuart114@gmail.com>
|
2008-07-14 09:15:55 +12:00
|
|
|
|
2013-05-17 05:26:38 +12:00
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
2013-05-17 05:26:38 +12:00
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in the
|
2016-02-21 00:29:19 +13:00
|
|
|
documentation and/or other materials provided with the distribution.
|
2013-05-17 05:26:38 +12:00
|
|
|
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
|
2016-02-21 00:29:19 +13:00
|
|
|
without specific prior written permission.
|
2013-05-17 05:26:38 +12:00
|
|
|
|
|
|
|
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
|
2016-02-21 00:29:19 +13:00
|
|
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
2013-05-17 05:26:38 +12:00
|
|
|
SUCH DAMAGE.
|
2016-02-21 00:29:19 +13:00
|
|
|
*/
|
2019-12-19 13:37:55 +13:00
|
|
|
/* vim: set ts=4 sw=4 et : */
|
2008-07-14 09:15:55 +12:00
|
|
|
|
2020-07-11 06:39:32 +12:00
|
|
|
#define SODIUM "0123456789+"
|
|
|
|
#define EAN2 102
|
|
|
|
#define EAN5 105
|
2008-07-14 09:15:55 +12:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
/* UPC and EAN tables checked against EN 797:1996 */
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
static const char *UPCParity0[10] = {
|
|
|
|
/* Number set for UPC-E symbol (EN Table 4) */
|
|
|
|
"BBBAAA", "BBABAA", "BBAABA", "BBAAAB", "BABBAA", "BAABBA", "BAAABB",
|
|
|
|
"BABABA", "BABAAB", "BAABAB"
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *UPCParity1[10] = {
|
|
|
|
/* Not covered by BS EN 797:1995 */
|
|
|
|
"AAABBB", "AABABB", "AABBAB", "AABBBA", "ABAABB", "ABBAAB", "ABBBAA",
|
|
|
|
"ABABAB", "ABABBA", "ABBABA"
|
2016-03-03 10:12:38 +13:00
|
|
|
};
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
static const char *EAN2Parity[4] = {
|
|
|
|
/* Number sets for 2-digit add-on (EN Table 6) */
|
|
|
|
"AA", "AB", "BA", "BB"
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *EAN5Parity[10] = {
|
|
|
|
/* Number set for 5-digit add-on (EN Table 7) */
|
|
|
|
"BBAAA", "BABAA", "BAABA", "BAAAB", "ABBAA", "AABBA", "AAABB", "ABABA",
|
|
|
|
"ABAAB", "AABAB"
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *EAN13Parity[10] = {
|
|
|
|
/* Left hand of the EAN-13 symbol (EN Table 3) */
|
|
|
|
"AAAAA", "ABABB", "ABBAB", "ABBBA", "BAABB", "BBAAB", "BBBAA", "BABAB",
|
|
|
|
"BABBA", "BBABA"
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *EANsetA[10] = {
|
|
|
|
/* Representation set A and C (EN Table 1) */
|
2016-03-03 10:12:38 +13:00
|
|
|
"3211", "2221", "2122", "1411", "1132", "1231", "1114", "1312", "1213", "3112"
|
2016-02-21 00:29:19 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
static const char *EANsetB[10] = {
|
|
|
|
/* Representation set B (EN Table 1) */
|
|
|
|
"1123", "1222", "2212", "1141", "2311", "1321", "4111", "2131", "3121", "2113"
|
2016-03-03 10:12:38 +13:00
|
|
|
};
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
/* Calculate the correct check digit for a UPC barcode */
|
2019-12-19 13:37:55 +13:00
|
|
|
static char upc_check(char source[]) {
|
2016-02-21 00:29:19 +13:00
|
|
|
unsigned int i, count, check_digit;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < strlen(source); i++) {
|
|
|
|
count += ctoi(source[i]);
|
|
|
|
|
|
|
|
if (!(i & 1)) {
|
|
|
|
count += 2 * (ctoi(source[i]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
check_digit = 10 - (count % 10);
|
|
|
|
if (check_digit == 10) {
|
|
|
|
check_digit = 0;
|
|
|
|
}
|
|
|
|
return itoc(check_digit);
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* UPC A is usually used for 12 digit numbers, but this function takes a source of any length */
|
2019-12-19 13:37:55 +13:00
|
|
|
static void upca_draw(char source[], char dest[]) {
|
2020-10-27 01:21:43 +13:00
|
|
|
unsigned int i, half_way, length = strlen(source);
|
2008-07-14 09:15:55 +12:00
|
|
|
|
2020-10-27 01:21:43 +13:00
|
|
|
half_way = length / 2;
|
2008-07-14 09:15:55 +12:00
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* start character */
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat(dest, "111");
|
2008-07-14 09:15:55 +12:00
|
|
|
|
2020-10-27 01:21:43 +13:00
|
|
|
for (i = 0; i < length; i++) {
|
2016-02-21 00:29:19 +13:00
|
|
|
if (i == half_way) {
|
|
|
|
/* middle character - separates manufacturer no. from product no. */
|
|
|
|
/* also inverts right hand characters */
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat(dest, "11111");
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
2008-07-14 09:15:55 +12:00
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
lookup(NEON, EANsetA, source[i], dest);
|
|
|
|
}
|
2008-07-14 09:15:55 +12:00
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* stop character */
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat(dest, "111");
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* Make a UPC A barcode when we haven't been given the check digit */
|
2019-12-19 13:37:55 +13:00
|
|
|
static int upca(struct zint_symbol *symbol, unsigned char source[], char dest[]) {
|
2016-02-21 00:29:19 +13:00
|
|
|
int length;
|
|
|
|
char gtin[15];
|
2020-10-01 00:19:12 +13:00
|
|
|
int error_number = 0;
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
strcpy(gtin, (char*) source);
|
|
|
|
length = strlen(gtin);
|
2017-10-24 08:37:52 +13:00
|
|
|
|
2016-10-29 07:43:08 +13:00
|
|
|
if (length == 11) {
|
|
|
|
gtin[length] = upc_check(gtin);
|
|
|
|
gtin[length + 1] = '\0';
|
|
|
|
} else {
|
|
|
|
gtin[length - 1] = '\0';
|
|
|
|
if (source[length - 1] != upc_check(gtin)) {
|
2020-10-01 00:19:12 +13:00
|
|
|
if (symbol->debug & ZINT_DEBUG_PRINT) {
|
2020-10-06 11:22:06 +13:00
|
|
|
printf("UPC-A: Invalid check digit %s, gtin: %s, Check digit: %c\n", source, gtin, upc_check(gtin));
|
2020-10-01 00:19:12 +13:00
|
|
|
}
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 270;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid check digit"));
|
2019-09-02 07:23:15 +12:00
|
|
|
return ZINT_ERROR_INVALID_CHECK;
|
2016-10-29 07:43:08 +13:00
|
|
|
}
|
|
|
|
gtin[length - 1] = upc_check(gtin);
|
|
|
|
}
|
2020-10-06 11:22:06 +13:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
upca_draw(gtin, dest);
|
2020-10-06 11:22:06 +13:00
|
|
|
ustrcpy(symbol->text, gtin);
|
2020-10-01 00:19:12 +13:00
|
|
|
|
|
|
|
return error_number;
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* UPC E is a zero-compressed version of UPC A */
|
2019-12-19 13:37:55 +13:00
|
|
|
static int upce(struct zint_symbol *symbol, unsigned char source[], char dest[]) {
|
2020-10-27 01:21:43 +13:00
|
|
|
unsigned int i, num_system, length;
|
2019-09-02 07:23:15 +12:00
|
|
|
char emode, equivalent[12], check_digit, parity[8], temp[9];
|
2016-02-21 00:29:19 +13:00
|
|
|
char hrt[9];
|
2020-10-01 00:19:12 +13:00
|
|
|
int error_number = 0;
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
/* Two number systems can be used - system 0 and system 1 */
|
2016-10-29 07:43:08 +13:00
|
|
|
if (symbol->symbology != BARCODE_UPCE_CHK) {
|
|
|
|
/* No check digit in input data */
|
|
|
|
if (ustrlen(source) == 7) {
|
|
|
|
switch (source[0]) {
|
|
|
|
case '0': num_system = 0;
|
|
|
|
break;
|
|
|
|
case '1': num_system = 1;
|
|
|
|
break;
|
|
|
|
default: num_system = 0;
|
2020-10-06 11:22:06 +13:00
|
|
|
/* First source char ignored */
|
2016-10-29 07:43:08 +13:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
strcpy(temp, (char*) source);
|
|
|
|
strcpy(hrt, (char*) source);
|
|
|
|
for (i = 1; i <= 7; i++) {
|
|
|
|
source[i - 1] = temp[i];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
num_system = 0;
|
|
|
|
hrt[0] = '0';
|
|
|
|
hrt[1] = '\0';
|
|
|
|
strcat(hrt, (char*) source);
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
|
|
|
} else {
|
2016-10-29 07:43:08 +13:00
|
|
|
/* Check digit is included in input data */
|
|
|
|
if (ustrlen(source) == 8) {
|
|
|
|
switch (source[0]) {
|
|
|
|
case '0': num_system = 0;
|
|
|
|
break;
|
|
|
|
case '1': num_system = 1;
|
|
|
|
break;
|
|
|
|
default: num_system = 0;
|
2020-10-06 11:22:06 +13:00
|
|
|
/* First source char ignored */
|
2016-10-29 07:43:08 +13:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
strcpy(temp, (char*) source);
|
|
|
|
strcpy(hrt, (char*) source);
|
2019-09-02 07:23:15 +12:00
|
|
|
for (i = 1; i <= 8; i++) {
|
2016-10-29 07:43:08 +13:00
|
|
|
source[i - 1] = temp[i];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
num_system = 0;
|
|
|
|
hrt[0] = '0';
|
|
|
|
hrt[1] = '\0';
|
|
|
|
strcat(hrt, (char*) source);
|
|
|
|
}
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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] = temp[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" */
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 271;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid UPC-E data"));
|
2016-10-29 07:43:08 +13:00
|
|
|
return ZINT_ERROR_INVALID_DATA;
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
|
|
|
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" */
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 272;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid UPC-E data"));
|
2016-10-29 07:43:08 +13:00
|
|
|
return ZINT_ERROR_INVALID_DATA;
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
|
|
|
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" */
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 273;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid UPC-E data"));
|
2016-10-29 07:43:08 +13:00
|
|
|
return ZINT_ERROR_INVALID_DATA;
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the check digit from the expanded UPCA code */
|
|
|
|
|
|
|
|
check_digit = upc_check(equivalent);
|
|
|
|
|
|
|
|
/* Use the number system and check digit information to choose a parity scheme */
|
|
|
|
if (num_system == 1) {
|
|
|
|
strcpy(parity, UPCParity1[ctoi(check_digit)]);
|
|
|
|
} else {
|
|
|
|
strcpy(parity, UPCParity0[ctoi(check_digit)]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Take all this information and make the barcode pattern */
|
|
|
|
|
|
|
|
/* start character */
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat(dest, "111");
|
2016-02-21 00:29:19 +13:00
|
|
|
|
2020-10-27 01:21:43 +13:00
|
|
|
length = ustrlen(source);
|
|
|
|
for (i = 0; i < length; i++) {
|
2016-02-21 00:29:19 +13:00
|
|
|
switch (parity[i]) {
|
|
|
|
case 'A': lookup(NEON, EANsetA, source[i], dest);
|
|
|
|
break;
|
|
|
|
case 'B': lookup(NEON, EANsetB, source[i], dest);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stop character */
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat(dest, "111111");
|
2016-02-21 00:29:19 +13:00
|
|
|
|
2016-10-29 07:43:08 +13:00
|
|
|
if (symbol->symbology != BARCODE_UPCE_CHK) {
|
|
|
|
hrt[7] = check_digit;
|
|
|
|
hrt[8] = '\0';
|
|
|
|
} else {
|
|
|
|
if (hrt[7] != check_digit) {
|
2020-10-06 11:22:06 +13:00
|
|
|
if (symbol->debug & ZINT_DEBUG_PRINT) {
|
|
|
|
printf("UPC-E: Invalid check digit %s, equivalent: %s, hrt: %s, Check digit: %c\n", source, equivalent, hrt, check_digit);
|
|
|
|
}
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 274;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid check digit"));
|
2019-09-02 07:23:15 +12:00
|
|
|
return ZINT_ERROR_INVALID_CHECK;
|
2016-10-29 07:43:08 +13:00
|
|
|
}
|
|
|
|
}
|
2020-10-06 11:22:06 +13:00
|
|
|
if (symbol->debug & ZINT_DEBUG_PRINT) {
|
|
|
|
printf("UPC-E: %s, equivalent: %s, hrt: %s, Check digit: %c\n", source, equivalent, hrt, check_digit);
|
|
|
|
}
|
|
|
|
|
|
|
|
ustrcpy(symbol->text, hrt);
|
2020-10-01 00:19:12 +13:00
|
|
|
|
|
|
|
return error_number;
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* EAN-2 and EAN-5 add-on codes */
|
2020-07-16 06:00:12 +12:00
|
|
|
static void add_on(unsigned char source[], char dest[], int addon_gap) {
|
2016-02-21 00:29:19 +13:00
|
|
|
char parity[6];
|
2020-10-27 01:21:43 +13:00
|
|
|
unsigned int i, code_type, length;
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
/* If an add-on then append with space */
|
2020-07-16 06:00:12 +12:00
|
|
|
if (addon_gap != 0) {
|
|
|
|
i = strlen(dest);
|
|
|
|
dest[i] = itoc(addon_gap);
|
|
|
|
dest[i + 1] = '\0';
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Start character */
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat(dest, "112");
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
/* Determine EAN2 or EAN5 add-on */
|
|
|
|
if (ustrlen(source) == 2) {
|
|
|
|
code_type = EAN2;
|
|
|
|
} else {
|
|
|
|
code_type = EAN5;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate parity for EAN2 */
|
|
|
|
if (code_type == EAN2) {
|
|
|
|
int code_value, parity_bit;
|
|
|
|
|
|
|
|
code_value = (10 * ctoi(source[0])) + ctoi(source[1]);
|
|
|
|
parity_bit = code_value % 4;
|
|
|
|
strcpy(parity, EAN2Parity[parity_bit]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (code_type == EAN5) {
|
|
|
|
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;
|
|
|
|
strcpy(parity, EAN5Parity[parity_bit]);
|
|
|
|
}
|
|
|
|
|
2020-10-27 01:21:43 +13:00
|
|
|
length = ustrlen(source);
|
|
|
|
for (i = 0; i < length; i++) {
|
2016-02-21 00:29:19 +13:00
|
|
|
switch (parity[i]) {
|
|
|
|
case 'A': lookup(NEON, EANsetA, source[i], dest);
|
|
|
|
break;
|
|
|
|
case 'B': lookup(NEON, EANsetB, source[i], dest);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Glyph separator */
|
|
|
|
if (i != (ustrlen(source) - 1)) {
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat(dest, "11");
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
|
|
|
}
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************ EAN-13 ****************** */
|
2016-03-03 10:12:38 +13:00
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* Calculate the correct check digit for a EAN-13 barcode */
|
2019-12-19 13:37:55 +13:00
|
|
|
static char ean_check(char source[]) {
|
2016-02-21 00:29:19 +13:00
|
|
|
int i;
|
|
|
|
unsigned int h, count, check_digit;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
h = strlen(source);
|
|
|
|
for (i = h - 1; i >= 0; i--) {
|
|
|
|
count += ctoi(source[i]);
|
|
|
|
|
|
|
|
if (i & 1) {
|
|
|
|
count += 2 * ctoi(source[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
check_digit = 10 - (count % 10);
|
|
|
|
if (check_digit == 10) {
|
|
|
|
check_digit = 0;
|
|
|
|
}
|
|
|
|
return itoc(check_digit);
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
2019-12-19 13:37:55 +13:00
|
|
|
static int ean13(struct zint_symbol *symbol, unsigned char source[], char dest[]) {
|
2016-02-21 00:29:19 +13:00
|
|
|
unsigned int length, i, half_way;
|
|
|
|
char parity[6];
|
|
|
|
char gtin[15];
|
2020-10-01 00:19:12 +13:00
|
|
|
int error_number = 0;
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
strcpy(parity, "");
|
|
|
|
strcpy(gtin, (char*) source);
|
|
|
|
|
|
|
|
/* Add the appropriate check digit */
|
|
|
|
length = strlen(gtin);
|
2017-10-24 08:37:52 +13:00
|
|
|
|
2016-10-29 07:43:08 +13:00
|
|
|
if (length == 12) {
|
|
|
|
gtin[length] = ean_check(gtin);
|
|
|
|
gtin[length + 1] = '\0';
|
|
|
|
} else {
|
|
|
|
gtin[length - 1] = '\0';
|
|
|
|
if (source[length - 1] != ean_check(gtin)) {
|
2020-10-06 11:22:06 +13:00
|
|
|
if (symbol->debug & ZINT_DEBUG_PRINT) {
|
|
|
|
printf("EAN-13 Invalid check digit: %s, gtin: %s, Check digit: %c\n", source, gtin, ean_check(gtin));
|
|
|
|
}
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 275;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid check digit"));
|
2020-10-06 11:22:06 +13:00
|
|
|
return ZINT_ERROR_INVALID_CHECK;
|
2016-10-29 07:43:08 +13:00
|
|
|
}
|
|
|
|
gtin[length - 1] = ean_check(gtin);
|
|
|
|
}
|
2020-10-06 11:22:06 +13:00
|
|
|
if (symbol->debug & ZINT_DEBUG_PRINT) {
|
|
|
|
printf("EAN-13: %s, gtin: %s, Check digit: %c\n", source, gtin, length == 12 ? gtin[length] : gtin[length - 1]);
|
|
|
|
}
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
/* Get parity for first half of the symbol */
|
|
|
|
lookup(SODIUM, EAN13Parity, gtin[0], parity);
|
|
|
|
|
|
|
|
/* Now get on with the cipher */
|
|
|
|
half_way = 7;
|
|
|
|
|
|
|
|
/* start character */
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat(dest, "111");
|
2016-02-21 00:29:19 +13:00
|
|
|
length = strlen(gtin);
|
2020-10-27 01:21:43 +13:00
|
|
|
for (i = 1; i < length; i++) {
|
2016-02-21 00:29:19 +13:00
|
|
|
if (i == half_way) {
|
|
|
|
/* middle character - separates manufacturer no. from product no. */
|
|
|
|
/* also inverses right hand characters */
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat(dest, "11111");
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
if (((i > 1) && (i < 7)) && (parity[i - 2] == 'B')) {
|
|
|
|
lookup(NEON, EANsetB, gtin[i], dest);
|
|
|
|
} else {
|
|
|
|
lookup(NEON, EANsetA, gtin[i], dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stop character */
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat(dest, "111");
|
2020-10-06 11:22:06 +13:00
|
|
|
ustrcpy(symbol->text, gtin);
|
2020-10-01 00:19:12 +13:00
|
|
|
|
|
|
|
return error_number;
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* Make an EAN-8 barcode when we haven't been given the check digit */
|
2019-12-19 13:37:55 +13:00
|
|
|
static int ean8(struct zint_symbol *symbol, unsigned char source[], char dest[]) {
|
2016-02-21 00:29:19 +13:00
|
|
|
/* EAN-8 is basically the same as UPC-A but with fewer digits */
|
|
|
|
int length;
|
|
|
|
char gtin[10];
|
2020-10-01 00:19:12 +13:00
|
|
|
int error_number = 0;
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
strcpy(gtin, (char*) source);
|
|
|
|
length = strlen(gtin);
|
2017-10-24 08:37:52 +13:00
|
|
|
|
2016-10-29 07:43:08 +13:00
|
|
|
if (length == 7) {
|
|
|
|
gtin[length] = upc_check(gtin);
|
|
|
|
gtin[length + 1] = '\0';
|
|
|
|
} else {
|
|
|
|
gtin[length - 1] = '\0';
|
|
|
|
if (source[length - 1] != upc_check(gtin)) {
|
2020-10-06 11:22:06 +13:00
|
|
|
if (symbol->debug & ZINT_DEBUG_PRINT) {
|
|
|
|
printf("EAN-8: Invalid check digit %s, gtin: %s, Check digit: %c\n", source, gtin, upc_check(gtin));
|
|
|
|
}
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 276;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid check digit"));
|
2020-10-06 11:22:06 +13:00
|
|
|
return ZINT_ERROR_INVALID_CHECK;
|
2016-10-29 07:43:08 +13:00
|
|
|
}
|
|
|
|
gtin[length - 1] = upc_check(gtin);
|
|
|
|
}
|
2020-10-06 11:22:06 +13:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
upca_draw(gtin, dest);
|
2020-10-06 11:22:06 +13:00
|
|
|
ustrcpy(symbol->text, gtin);
|
2017-10-24 08:37:52 +13:00
|
|
|
|
2020-10-01 00:19:12 +13:00
|
|
|
return error_number;
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* For ISBN(13) only */
|
2019-12-19 13:37:55 +13:00
|
|
|
static char isbn13_check(unsigned char source[]) {
|
2016-02-21 00:29:19 +13:00
|
|
|
unsigned int i, weight, sum, check, h;
|
2008-07-14 09:15:55 +12:00
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
sum = 0;
|
|
|
|
weight = 1;
|
|
|
|
h = ustrlen(source) - 1;
|
2008-07-14 09:15:55 +12:00
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
for (i = 0; i < h; i++) {
|
|
|
|
sum += ctoi(source[i]) * weight;
|
|
|
|
if (weight == 1) weight = 3;
|
|
|
|
else weight = 1;
|
|
|
|
}
|
2008-07-14 09:15:55 +12:00
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
check = sum % 10;
|
|
|
|
check = 10 - check;
|
|
|
|
if (check == 10) check = 0;
|
|
|
|
return itoc(check);
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* For ISBN(10) and SBN only */
|
2019-12-19 13:37:55 +13:00
|
|
|
static char isbn_check(unsigned char source[]) {
|
2016-02-21 00:29:19 +13:00
|
|
|
unsigned int i, weight, sum, check, h;
|
|
|
|
char check_char;
|
|
|
|
|
|
|
|
sum = 0;
|
|
|
|
weight = 1;
|
|
|
|
h = ustrlen(source) - 1;
|
|
|
|
|
|
|
|
for (i = 0; i < h; i++) {
|
|
|
|
sum += ctoi(source[i]) * weight;
|
|
|
|
weight++;
|
|
|
|
}
|
|
|
|
|
|
|
|
check = sum % 11;
|
|
|
|
check_char = itoc(check);
|
|
|
|
if (check == 10) {
|
|
|
|
check_char = 'X';
|
|
|
|
}
|
|
|
|
return check_char;
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* Make an EAN-13 barcode from an SBN or ISBN */
|
2017-05-29 21:43:47 +12:00
|
|
|
static int isbn(struct zint_symbol *symbol, unsigned char source[], const size_t src_len, char dest[]) {
|
2016-02-21 00:29:19 +13:00
|
|
|
int i, error_number;
|
|
|
|
char check_digit;
|
|
|
|
|
|
|
|
to_upper(source);
|
|
|
|
error_number = is_sane("0123456789X", source, src_len);
|
|
|
|
if (error_number == ZINT_ERROR_INVALID_DATA) {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 277;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid character in data"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return error_number;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Input must be 9, 10 or 13 characters */
|
2019-09-02 07:23:15 +12:00
|
|
|
if (src_len != 9 && src_len != 10 && src_len != 13) {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 278;
|
|
|
|
strcpy(symbol->errtxt, _("Input wrong length"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_TOO_LONG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (src_len == 13) /* Using 13 character ISBN */ {
|
|
|
|
if (!(((source[0] == '9') && (source[1] == '7')) &&
|
|
|
|
((source[2] == '8') || (source[2] == '9')))) {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 279;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid ISBN"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
check_digit = isbn13_check(source);
|
|
|
|
if (source[src_len - 1] != check_digit) {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 280;
|
|
|
|
strcpy(symbol->errtxt, _("Incorrect ISBN check"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_INVALID_CHECK;
|
|
|
|
}
|
|
|
|
source[12] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (src_len == 9) /* Using 9 digit SBN */ {
|
|
|
|
/* Add leading zero */
|
|
|
|
for (i = 10; i > 0; i--) {
|
|
|
|
source[i] = source[i - 1];
|
|
|
|
}
|
|
|
|
source[0] = '0';
|
2019-09-02 07:23:15 +12:00
|
|
|
}
|
2016-02-21 00:29:19 +13:00
|
|
|
|
2019-09-02 07:23:15 +12:00
|
|
|
if (src_len == 9 || src_len == 10) /* Using 10 digit ISBN or 9 digit SBN padded with leading zero */ {
|
2016-02-21 00:29:19 +13:00
|
|
|
check_digit = isbn_check(source);
|
|
|
|
if (check_digit != source[ustrlen(source) - 1]) {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 281;
|
|
|
|
strcpy(symbol->errtxt, src_len == 9 ? _("Incorrect SBN check") : _("Incorrect ISBN check"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_INVALID_CHECK;
|
|
|
|
}
|
2019-09-02 07:23:15 +12:00
|
|
|
for (i = 11; i > 2; i--) {
|
2016-02-21 00:29:19 +13:00
|
|
|
source[i] = source[i - 3];
|
|
|
|
}
|
|
|
|
source[0] = '9';
|
|
|
|
source[1] = '7';
|
|
|
|
source[2] = '8';
|
|
|
|
source[12] = '\0';
|
|
|
|
}
|
|
|
|
|
2019-09-02 07:23:15 +12:00
|
|
|
return ean13(symbol, source, dest);
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* Add leading zeroes to EAN and UPC strings */
|
2020-10-06 11:22:06 +13:00
|
|
|
INTERNAL void ean_leading_zeroes(struct zint_symbol *symbol, unsigned char source[], unsigned char local_source[], int *p_with_addon) {
|
|
|
|
unsigned char first_part[20], second_part[7], zfirst_part[20], zsecond_part[7];
|
2016-02-21 00:29:19 +13:00
|
|
|
int with_addon = 0;
|
|
|
|
int first_len = 0, second_len = 0, zfirst_len = 0, zsecond_len = 0, i, h;
|
|
|
|
|
|
|
|
h = ustrlen(source);
|
|
|
|
for (i = 0; i < h; i++) {
|
|
|
|
if (source[i] == '+') {
|
|
|
|
with_addon = 1;
|
|
|
|
} else {
|
|
|
|
if (with_addon == 0) {
|
|
|
|
first_len++;
|
|
|
|
} else {
|
|
|
|
second_len++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Split input into two strings */
|
|
|
|
for (i = 0; i < first_len; i++) {
|
|
|
|
first_part[i] = source[i];
|
|
|
|
}
|
2020-10-06 11:22:06 +13:00
|
|
|
first_part[first_len] = '\0';
|
2016-02-21 00:29:19 +13:00
|
|
|
|
2020-03-26 22:35:04 +13:00
|
|
|
if (second_len >= 6) { /* Allow 6 (actual max 5) so as to trigger too long error */
|
|
|
|
second_len = 6;
|
|
|
|
}
|
2016-02-21 00:29:19 +13:00
|
|
|
for (i = 0; i < second_len; i++) {
|
|
|
|
second_part[i] = source[i + first_len + 1];
|
|
|
|
}
|
2020-10-06 11:22:06 +13:00
|
|
|
second_part[second_len] = '\0';
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
/* Calculate target lengths */
|
|
|
|
if (second_len <= 5) {
|
|
|
|
zsecond_len = 5;
|
|
|
|
}
|
|
|
|
if (second_len <= 2) {
|
|
|
|
zsecond_len = 2;
|
|
|
|
}
|
|
|
|
if (second_len == 0) {
|
|
|
|
zsecond_len = 0;
|
|
|
|
}
|
|
|
|
switch (symbol->symbology) {
|
|
|
|
case BARCODE_EANX:
|
|
|
|
case BARCODE_EANX_CC:
|
|
|
|
if (first_len <= 12) {
|
|
|
|
zfirst_len = 12;
|
|
|
|
}
|
|
|
|
if (first_len <= 7) {
|
|
|
|
zfirst_len = 7;
|
|
|
|
}
|
2019-10-15 10:20:16 +13:00
|
|
|
if (second_len == 0 && symbol->symbology == BARCODE_EANX) { /* No composite EAN-2/5 */
|
2016-02-21 00:29:19 +13:00
|
|
|
if (first_len <= 5) {
|
|
|
|
zfirst_len = 5;
|
|
|
|
}
|
|
|
|
if (first_len <= 2) {
|
|
|
|
zfirst_len = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2016-10-29 07:43:08 +13:00
|
|
|
case BARCODE_EANX_CHK:
|
|
|
|
if (first_len <= 13) {
|
|
|
|
zfirst_len = 13;
|
|
|
|
}
|
|
|
|
if (first_len <= 8) {
|
|
|
|
zfirst_len = 8;
|
|
|
|
}
|
|
|
|
if (second_len == 0) {
|
|
|
|
if (first_len <= 5) {
|
|
|
|
zfirst_len = 5;
|
|
|
|
}
|
|
|
|
if (first_len <= 2) {
|
|
|
|
zfirst_len = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2016-02-21 00:29:19 +13:00
|
|
|
case BARCODE_UPCA:
|
|
|
|
case BARCODE_UPCA_CC:
|
|
|
|
zfirst_len = 11;
|
|
|
|
break;
|
2016-10-29 07:43:08 +13:00
|
|
|
case BARCODE_UPCA_CHK:
|
|
|
|
zfirst_len = 12;
|
|
|
|
break;
|
2016-02-21 00:29:19 +13:00
|
|
|
case BARCODE_UPCE:
|
|
|
|
case BARCODE_UPCE_CC:
|
|
|
|
if (first_len == 7) {
|
|
|
|
zfirst_len = 7;
|
|
|
|
}
|
|
|
|
if (first_len <= 6) {
|
|
|
|
zfirst_len = 6;
|
|
|
|
}
|
|
|
|
break;
|
2016-10-29 07:43:08 +13:00
|
|
|
case BARCODE_UPCE_CHK:
|
|
|
|
if (first_len == 8) {
|
|
|
|
zfirst_len = 8;
|
|
|
|
}
|
|
|
|
if (first_len <= 7) {
|
|
|
|
zfirst_len = 7;
|
|
|
|
}
|
|
|
|
break;
|
2016-02-21 00:29:19 +13:00
|
|
|
case BARCODE_ISBNX:
|
|
|
|
if (first_len <= 9) {
|
|
|
|
zfirst_len = 9;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Add leading zeroes */
|
2020-10-06 11:22:06 +13:00
|
|
|
zfirst_part[0] = '\0';
|
2016-02-21 00:29:19 +13:00
|
|
|
for (i = 0; i < (zfirst_len - first_len); i++) {
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat((char*) zfirst_part, "0");
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat((char*) zfirst_part, (char*) first_part);
|
2020-10-06 11:22:06 +13:00
|
|
|
|
|
|
|
zsecond_part[0] = '\0';
|
2016-02-21 00:29:19 +13:00
|
|
|
for (i = 0; i < (zsecond_len - second_len); i++) {
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat((char*) zsecond_part, "0");
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat((char*) zsecond_part, (char*) second_part);
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
/* Copy adjusted data back to local_source */
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat((char*) local_source, (char*) zfirst_part);
|
2019-10-15 10:20:16 +13:00
|
|
|
if (ustrlen(zsecond_part)) {
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat((char*) local_source, "+");
|
|
|
|
strcat((char*) local_source, (char*) zsecond_part);
|
2016-02-21 00:29:19 +13:00
|
|
|
}
|
2020-10-06 11:22:06 +13:00
|
|
|
|
|
|
|
if (p_with_addon) {
|
|
|
|
*p_with_addon = with_addon;
|
|
|
|
}
|
2009-05-27 21:06:28 +12:00
|
|
|
}
|
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
/* splits string to parts before and after '+' parts */
|
2019-12-19 13:37:55 +13:00
|
|
|
INTERNAL int eanx(struct zint_symbol *symbol, unsigned char source[], int src_len) {
|
2020-03-26 22:35:04 +13:00
|
|
|
unsigned char first_part[20] = {0}, second_part[7] = {0}, dest[1000] = {0};
|
2020-10-06 11:22:06 +13:00
|
|
|
unsigned char local_source[21] = {0}; /* Allow 13 + "+" + 6 (too long add-on) + 1 */
|
|
|
|
unsigned int latch, reader, writer;
|
|
|
|
int with_addon;
|
2020-02-16 10:28:40 +13:00
|
|
|
int error_number, i, plus_count;
|
2020-07-16 06:00:12 +12:00
|
|
|
int addon_gap = 0;
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
latch = FALSE;
|
|
|
|
writer = 0;
|
|
|
|
|
|
|
|
if (src_len > 19) {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 283;
|
|
|
|
strcpy(symbol->errtxt, _("Input too long"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_TOO_LONG;
|
|
|
|
}
|
|
|
|
if (symbol->symbology != BARCODE_ISBNX) {
|
2020-07-16 06:00:12 +12:00
|
|
|
/* ISBN has its own checking routine */
|
2016-02-21 00:29:19 +13:00
|
|
|
error_number = is_sane("0123456789+", source, src_len);
|
|
|
|
if (error_number == ZINT_ERROR_INVALID_DATA) {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 284;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid character in data"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return error_number;
|
|
|
|
}
|
|
|
|
} else {
|
2019-11-12 10:38:21 +13:00
|
|
|
error_number = is_sane("0123456789Xx+", source, src_len);
|
2016-02-21 00:29:19 +13:00
|
|
|
if (error_number == ZINT_ERROR_INVALID_DATA) {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 285;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid character in data"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return error_number;
|
|
|
|
}
|
|
|
|
}
|
2020-02-16 10:28:40 +13:00
|
|
|
|
|
|
|
/* Check for multiple '+' characters */
|
|
|
|
plus_count = 0;
|
|
|
|
for (i = 0; i < src_len; i++) {
|
|
|
|
if (source[i] == '+') {
|
|
|
|
plus_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (plus_count > 1) {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 293;
|
|
|
|
strcpy(symbol->errtxt, _("Invalid add-on data"));
|
2020-02-16 10:28:40 +13:00
|
|
|
return ZINT_ERROR_INVALID_DATA;
|
|
|
|
}
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
/* Add leading zeroes */
|
2020-10-06 11:22:06 +13:00
|
|
|
ean_leading_zeroes(symbol, source, local_source, &with_addon);
|
2016-02-21 00:29:19 +13:00
|
|
|
|
|
|
|
reader = 0;
|
|
|
|
if (with_addon) {
|
|
|
|
do {
|
|
|
|
if (local_source[reader] == '+') {
|
|
|
|
first_part[writer] = '\0';
|
|
|
|
latch = TRUE;
|
|
|
|
reader++;
|
|
|
|
writer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (latch) {
|
|
|
|
second_part[writer] = local_source[reader];
|
|
|
|
reader++;
|
|
|
|
writer++;
|
|
|
|
} else {
|
|
|
|
first_part[writer] = local_source[reader];
|
|
|
|
reader++;
|
|
|
|
writer++;
|
|
|
|
}
|
|
|
|
} while (reader <= ustrlen(local_source));
|
2020-07-16 06:00:12 +12:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2016-02-21 00:29:19 +13:00
|
|
|
} else {
|
|
|
|
strcpy((char*) first_part, (char*) local_source);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (symbol->symbology) {
|
|
|
|
case BARCODE_EANX:
|
2016-10-29 07:43:08 +13:00
|
|
|
case BARCODE_EANX_CHK:
|
2016-02-21 00:29:19 +13:00
|
|
|
switch (ustrlen(first_part)) {
|
|
|
|
case 2: add_on(first_part, (char*) dest, 0);
|
|
|
|
ustrcpy(symbol->text, first_part);
|
|
|
|
break;
|
|
|
|
case 5: add_on(first_part, (char*) dest, 0);
|
|
|
|
ustrcpy(symbol->text, first_part);
|
|
|
|
break;
|
2016-10-29 07:43:08 +13:00
|
|
|
case 7:
|
|
|
|
case 8: error_number = ean8(symbol, first_part, (char*) dest);
|
2016-02-21 00:29:19 +13:00
|
|
|
break;
|
2017-10-24 08:37:52 +13:00
|
|
|
case 12:
|
2016-10-29 07:43:08 +13:00
|
|
|
case 13: error_number = ean13(symbol, first_part, (char*) dest);
|
2016-02-21 00:29:19 +13:00
|
|
|
break;
|
2020-11-08 08:26:10 +13:00
|
|
|
default:
|
|
|
|
symbol->err_origin = 286;
|
|
|
|
strcpy(symbol->errtxt, _("Input wrong length"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_TOO_LONG;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BARCODE_EANX_CC:
|
|
|
|
switch (ustrlen(first_part)) { /* 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);
|
2019-10-05 23:08:58 +13:00
|
|
|
set_module(symbol, symbol->rows + 2, 67);
|
2016-02-21 00:29:19 +13:00
|
|
|
symbol->row_height[symbol->rows] = 2;
|
|
|
|
symbol->row_height[symbol->rows + 1] = 2;
|
|
|
|
symbol->row_height[symbol->rows + 2] = 2;
|
|
|
|
symbol->rows += 3;
|
2016-10-29 07:43:08 +13:00
|
|
|
error_number = ean8(symbol, first_part, (char*) dest);
|
2016-02-21 00:29:19 +13:00
|
|
|
break;
|
2020-10-06 11:22:06 +13:00
|
|
|
case 12:
|
|
|
|
case 13:set_module(symbol, symbol->rows, 1);
|
2016-02-21 00:29:19 +13:00
|
|
|
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;
|
2016-10-29 07:43:08 +13:00
|
|
|
error_number = ean13(symbol, first_part, (char*) dest);
|
2016-02-21 00:29:19 +13:00
|
|
|
break;
|
2020-11-08 08:26:10 +13:00
|
|
|
default:
|
|
|
|
symbol->err_origin = 287;
|
|
|
|
strcpy(symbol->errtxt, _("Input wrong length"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_TOO_LONG;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BARCODE_UPCA:
|
2016-10-29 07:43:08 +13:00
|
|
|
case BARCODE_UPCA_CHK:
|
|
|
|
if ((ustrlen(first_part) == 11) || (ustrlen(first_part) == 12)) {
|
|
|
|
error_number = upca(symbol, first_part, (char*) dest);
|
2016-02-21 00:29:19 +13:00
|
|
|
} else {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 288;
|
|
|
|
strcpy(symbol->errtxt, _("Input wrong length"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_TOO_LONG;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BARCODE_UPCA_CC:
|
2020-10-01 00:19:12 +13:00
|
|
|
if (ustrlen(first_part) == 11 || ustrlen(first_part) == 12) {
|
2016-02-21 00:29:19 +13:00
|
|
|
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;
|
2016-10-29 07:43:08 +13:00
|
|
|
error_number = upca(symbol, first_part, (char*) dest);
|
2016-02-21 00:29:19 +13:00
|
|
|
} else {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 289;
|
|
|
|
strcpy(symbol->errtxt, _("Input wrong length"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_TOO_LONG;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BARCODE_UPCE:
|
2016-10-29 07:43:08 +13:00
|
|
|
case BARCODE_UPCE_CHK:
|
2019-09-02 07:23:15 +12:00
|
|
|
if ((ustrlen(first_part) >= 6) && (ustrlen(first_part) <= (symbol->symbology == BARCODE_UPCE ? 7 : 8))) {
|
2016-10-29 07:43:08 +13:00
|
|
|
error_number = upce(symbol, first_part, (char*) dest);
|
2016-02-21 00:29:19 +13:00
|
|
|
} else {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 290;
|
|
|
|
strcpy(symbol->errtxt, _("Input wrong length"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_TOO_LONG;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BARCODE_UPCE_CC:
|
|
|
|
if ((ustrlen(first_part) >= 6) && (ustrlen(first_part) <= 7)) {
|
|
|
|
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;
|
2016-10-29 07:43:08 +13:00
|
|
|
error_number = upce(symbol, first_part, (char*) dest);
|
2016-02-21 00:29:19 +13:00
|
|
|
} else {
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 291;
|
|
|
|
strcpy(symbol->errtxt, _("Input wrong length"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_TOO_LONG;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BARCODE_ISBNX:
|
|
|
|
error_number = isbn(symbol, first_part, ustrlen(first_part), (char*) dest);
|
|
|
|
break;
|
|
|
|
}
|
2017-10-24 08:37:52 +13:00
|
|
|
|
2020-10-01 00:19:12 +13:00
|
|
|
if (error_number >= ZINT_ERROR) {
|
2016-10-29 07:43:08 +13:00
|
|
|
return error_number;
|
|
|
|
}
|
2017-10-24 08:37:52 +13:00
|
|
|
|
2016-02-21 00:29:19 +13:00
|
|
|
switch (ustrlen(second_part)) {
|
|
|
|
case 0: break;
|
|
|
|
case 2:
|
2020-07-16 06:00:12 +12:00
|
|
|
add_on(second_part, (char*) dest, addon_gap);
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat((char*) symbol->text, "+");
|
|
|
|
strcat((char*) symbol->text, (char*) second_part);
|
2016-02-21 00:29:19 +13:00
|
|
|
break;
|
|
|
|
case 5:
|
2020-07-16 06:00:12 +12:00
|
|
|
add_on(second_part, (char*) dest, addon_gap);
|
2016-03-03 10:12:38 +13:00
|
|
|
strcat((char*) symbol->text, "+");
|
|
|
|
strcat((char*) symbol->text, (char*) second_part);
|
2016-02-21 00:29:19 +13:00
|
|
|
break;
|
|
|
|
default:
|
2020-11-08 08:26:10 +13:00
|
|
|
symbol->err_origin = 292;
|
|
|
|
strcpy(symbol->errtxt, _("Add-on input wrong length"));
|
2016-02-21 00:29:19 +13:00
|
|
|
return ZINT_ERROR_TOO_LONG;
|
|
|
|
}
|
|
|
|
|
|
|
|
expand(symbol, (char*) 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 += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-10-01 00:19:12 +13:00
|
|
|
return error_number;
|
2008-07-14 09:15:55 +12:00
|
|
|
}
|