#define SODIUM_PLS_SPC_F (IS_NUM_F | IS_PLS_F | IS_SPC_F)
#define ISBNX_SANE_F (IS_NUM_F | IS_UX__F)
#define ISBNX_ADDON_SANE_F (IS_NUM_F | IS_UX__F | IS_LX__F | IS_PLS_F | IS_SPC_F)
#include <assert.h>
#include <stdio.h>
#include "common.h"
#include "gs1.h"
static const char UPCParity0[10][6] = {
{'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] = {
{'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] = {
{'A','A'}, {'A','B'}, {'B','A'}, {'B','B'}
};
static const char EAN5Parity[10][5] = {
{'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] = {
{'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] = {
{'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] = {
{'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'}
};
static void upca_set_dest(const unsigned char source[], const int length, char *d) {
int i, half_way;
half_way = length / 2;
memcpy(d, "111", 3);
d += 3;
for (i = 0; i < length; i++, d += 4) {
if (i == half_way) {
memcpy(d, "11111", 5);
d += 5;
}
memcpy(d, EANsetA[source[i] - '0'], 4);
}
memcpy(d, "111", 4);
}
static int upca_cc(struct zint_symbol *symbol, const unsigned char source[], int length, char dest[],
const int cc_rows) {
const unsigned char *gtin = symbol->text;
int error_number = 0;
z_hrt_cpy_nochk(symbol, source, length);
if (length == 11) {
z_hrt_cat_chr_nochk(symbol, zint_gs1_check_digit(gtin, 11));
} else {
if (source[length - 1] != zint_gs1_check_digit(gtin, 11)) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 270,
"Invalid check digit '%1$c', expecting '%2$c'",
source[length - 1], zint_gs1_check_digit(gtin, 11));
}
}
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("UPC-A: %s, gtin: %s, Check digit: %c\n", source, gtin, gtin[symbol->text_length - 1]);
}
upca_set_dest(gtin, symbol->text_length, dest);
if (symbol->output_options & COMPLIANT_HEIGHT) {
const float height = 69.242424f;
if (symbol->symbology == BARCODE_UPCA_CC) {
symbol->height = height;
} else {
error_number = z_set_height(symbol, height, height, 0.0f, 0 );
}
} else {
const float height = 50.0f;
if (symbol->symbology == BARCODE_UPCA_CC) {
symbol->height = height - cc_rows * 2 - 6.0f;
} else {
(void) z_set_height(symbol, 0.0f, height, 0.0f, 1 );
}
}
return error_number;
}
static int upca(struct zint_symbol *symbol, const unsigned char source[], int length, char dest[]) {
return upca_cc(symbol, source, length, dest, 0 );
}
static int upce_cc(struct zint_symbol *symbol, unsigned char source[], int length, char *d, const int cc_rows,
unsigned char equivalent[12]) {
int i;
int num_system = 0;
char emode, check_digit;
const char *parity;
char src_check_digit = '\0';
const unsigned char *hrt = symbol->text;
int error_number = 0;
if (length == 8 || symbol->symbology == BARCODE_UPCE_CHK) {
src_check_digit = source[--length];
}
if (length == 7) {
switch (source[0]) {
case '0':
z_hrt_cpy_nochk(symbol, source, length);
break;
case '1':
num_system = 1;
z_hrt_cpy_nochk(symbol, source, length);
break;
default:
z_hrt_cpy_cat_nochk(symbol, NULL, 0, '0', source + 1, length - 1);
error_number = z_errtxt(ZINT_WARN_INVALID_OPTION, symbol, 851,
"Ignoring first digit which is not '0' or '1'");
break;
}
for (i = 1; i <= length; i++) {
source[i - 1] = hrt[i];
}
length--;
} else {
z_hrt_cpy_cat_nochk(symbol, NULL, 0, '0', source, length);
}
emode = source[5];
memset(equivalent, '0', 11);
if (num_system == 1) {
equivalent[0] = hrt[0];
}
equivalent[1] = source[0];
equivalent[2] = source[1];
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') {
return z_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') {
return z_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') {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 273,
"For this UPC-E zero suppression, 5th character cannot be \"0\" (%.*s)",
length, source);
}
break;
}
check_digit = zint_gs1_check_digit(equivalent, 11);
if (src_check_digit && src_check_digit != check_digit) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 274, "Invalid check digit '%1$c', expecting '%2$c'",
src_check_digit, check_digit);
}
equivalent[11] = check_digit;
if (num_system == 1) {
parity = UPCParity1[z_ctoi(check_digit)];
} else {
parity = UPCParity0[z_ctoi(check_digit)];
}
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;
}
}
memcpy(d, "111111", 7);
z_hrt_cat_chr_nochk(symbol, check_digit);
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("UPC-E: %s, equivalent: %.11s, hrt: %.8s, Check digit: %c\n", source, equivalent, hrt, check_digit);
}
if (symbol->output_options & COMPLIANT_HEIGHT) {
const float height = 69.242424f;
if (symbol->symbology == BARCODE_UPCE_CC) {
symbol->height = height;
} else {
int warn_number = z_set_height(symbol, height, height, 0.0f, 0 );
if (warn_number) {
error_number = warn_number;
}
}
} else {
const float height = 50.0f;
if (symbol->symbology == BARCODE_UPCE_CC) {
symbol->height = height - cc_rows * 2 - 6.0f;
} else {
(void) z_set_height(symbol, 0.0f, height, 0.0f, 1 );
}
}
return error_number;
}
static int upce(struct zint_symbol *symbol, unsigned char source[], int length, char dest[],
unsigned char equivalent[12]) {
return upce_cc(symbol, source, length, dest, 0 , equivalent);
}
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 (addon_gap != 0) {
*d++ = z_itoc(addon_gap);
}
memcpy(d, "112", 3);
d += 3;
if (length == 2) {
int code_value, parity_bit;
code_value = 10 * z_ctoi(source[0]) + z_ctoi(source[1]);
parity_bit = code_value % 4;
parity = EAN2Parity[parity_bit];
} else {
int values[6], parity_sum, parity_bit;
for (i = 0; i < 6; i++) {
values[i] = z_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;
}
if (i != (length - 1)) {
memcpy(d, "11", 2);
d += 2;
}
}
*d = '\0';
}
static int ean13_cc(struct zint_symbol *symbol, const unsigned char source[], int length, char *d,
const int cc_rows) {
int i, half_way;
const char *parity;
const unsigned char *gtin = symbol->text;
int error_number = 0;
z_hrt_cpy_nochk(symbol, source, length);
if (length == 12) {
z_hrt_cat_chr_nochk(symbol, zint_gs1_check_digit(gtin, 12));
} else {
if (source[length - 1] != zint_gs1_check_digit(gtin, 12)) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 275,
"Invalid check digit '%1$c', expecting '%2$c'",
source[length - 1], zint_gs1_check_digit(gtin, 12));
}
}
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("EAN-13: %s, gtin: %s, Check digit: %c\n", source, gtin, gtin[symbol->text_length - 1]);
}
parity = EAN13Parity[gtin[0] - '0'];
half_way = 7;
memcpy(d, "111", 3);
d += 3;
for (i = 1; i < symbol->text_length; i++, d += 4) {
if (i == half_way) {
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);
}
}
memcpy(d, "111", 4);
if (symbol->output_options & COMPLIANT_HEIGHT) {
const float height = 69.242424f;
if (symbol->symbology == BARCODE_EANX_CC || symbol->symbology == BARCODE_EAN8_CC
|| symbol->symbology == BARCODE_EAN13_CC) {
symbol->height = height;
} else {
error_number = z_set_height(symbol, height, height, 0.0f, 0 );
}
} else {
const float height = 50.0f;
if (symbol->symbology == BARCODE_EANX_CC || symbol->symbology == BARCODE_EAN8_CC
|| symbol->symbology == BARCODE_EAN13_CC) {
symbol->height = height - cc_rows * 2 - 6.0f;
} else {
(void) z_set_height(symbol, 0.0f, height, 0.0f, 1 );
}
}
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 );
}
static int ean8_cc(struct zint_symbol *symbol, const unsigned char source[], int length, char dest[],
const int cc_rows) {
const unsigned char *gtin = symbol->text;
int error_number = 0;
z_hrt_cpy_nochk(symbol, source, length);
if (length == 7) {
z_hrt_cat_chr_nochk(symbol, zint_gs1_check_digit(gtin, 7));
} else {
if (source[length - 1] != zint_gs1_check_digit(gtin, 7)) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 276,
"Invalid EAN-8 check digit '%1$c', expecting '%2$c'",
source[length - 1], zint_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_set_dest(gtin, symbol->text_length, dest);
if (symbol->output_options & COMPLIANT_HEIGHT) {
const float height = 55.242424f;
if (symbol->symbology == BARCODE_EANX_CC || symbol->symbology == BARCODE_EAN8_CC
|| symbol->symbology == BARCODE_EAN13_CC) {
symbol->height = height;
} else {
error_number = z_set_height(symbol, height, height, 0.0f, 0 );
}
} else {
const float height = 50.0f;
if (symbol->symbology == BARCODE_EANX_CC || symbol->symbology == BARCODE_EAN8_CC
|| symbol->symbology == BARCODE_EAN13_CC) {
symbol->height = height - cc_rows * 2 - 6.0f;
} else {
(void) z_set_height(symbol, 0.0f, height, 0.0f, 1 );
}
}
return error_number;
}
static int ean8(struct zint_symbol *symbol, const unsigned char source[], int length, char dest[]) {
return ean8_cc(symbol, source, length, dest, 0 );
}
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++) {
sum += z_ctoi(source[i]) * weight;
weight++;
}
check = sum % 11;
check_char = z_itoc(check);
if (check == 10) {
check_char = 'X';
}
return check_char;
}
static int isbnx(struct zint_symbol *symbol, unsigned char source[], const int length, char dest[]) {
int i;
char check_digit;
z_to_upper(source, length);
if (z_not_sane(ISBNX_SANE_F, source, length)) {
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 277, "Invalid character in input (digits and \"X\" only)");
}
if (length != 9 && length != 10 && length != 13) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 278, "Input length %d wrong (9, 10, or 13 characters required)",
length);
}
if (length == 13) {
if (source[0] != '9' || source[1] != '7' || (source[2] != '8' && source[2] != '9')) {
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 279,
"Invalid ISBN (must begin with \"978\" or \"979\")");
}
if (z_not_sane(NEON_F, source, 13)) {
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 282,
"Invalid character in input, \"X\" not allowed in ISBN-13");
}
check_digit = zint_gs1_check_digit(source, 12);
if (source[12] != check_digit) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 280,
"Invalid ISBN check digit '%1$c', expecting '%2$c'", source[12], check_digit);
}
source[12] = '\0';
} else {
if (length == 9) {
for (i = 10; i > 0; i--) {
source[i] = source[i - 1];
}
source[0] = '0';
}
if (z_not_sane(NEON_F, source, 9)) {
return z_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 ZEXT z_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--) {
source[i] = source[i - 3];
}
source[0] = '9';
source[1] = '7';
source[2] = '8';
source[12] = '\0';
}
return ean13(symbol, source, 12, dest);
}
static int ean_is_upce(const unsigned char source[], unsigned char *out) {
static const char zeroes[5] = { '0', '0', '0', '0', '0' };
if (source[0] != '0' || source[1] > '1') {
return 0;
}
out[0] = source[1];
out[7] = source[12];
out[8] = '\0';
if (source[11] >= '5' && source[6] != '0' && memcmp(source + 7, zeroes, 4) == 0) {
memcpy(out + 1, source + 2, 5);
out[6] = source[11];
return 1;
}
if (source[5] != '0' && memcmp(source + 6, zeroes, 5) == 0) {
memcpy(out + 1, source + 2, 4);
out[5] = source[11];
out[6] = '4';
return 1;
}
if (source[4] <= '2' && memcmp(source + 5, zeroes, 4) == 0) {
out[1] = source[2];
out[2] = source[3];
memcpy(out + 3, source + 9, 3);
out[6] = source[4];
return 1;
}
if (source[4] >= '3' && memcmp(source + 5, zeroes, 5) == 0) {
memcpy(out + 1, source + 2, 3);
out[4] = source[10];
out[5] = source[11];
out[6] = '3';
return 1;
}
return 0;
}
INTERNAL int zint_ean_leading_zeroes(struct zint_symbol *symbol, const unsigned char source[], const int length,
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;
const int symbology = symbol->symbology;
const int max = symbology == BARCODE_EAN8 || symbology == BARCODE_EAN8_CC ? 8 :
symbology == BARCODE_EAN_2ADDON ? 2 : symbology == BARCODE_EAN_5ADDON ? 5 : 13;
if ((length == 13 || length == 15 || length == 18) && !z_not_sane(NEON_F, source, length)
&& zint_gs1_check_digit(ZCUCP(source), 12) == source[12]) {
int local_length = 0;
if (symbology == BARCODE_EAN13 || symbology == BARCODE_EAN13_CC
|| symbology == BARCODE_EANX || symbology == BARCODE_EANX_CHK || symbology == BARCODE_EANX_CC) {
memcpy(local_source, source, 13);
local_length = 13;
} else if ((symbology == BARCODE_EAN8 || symbology == BARCODE_EAN8_CC) && memcmp(source, "00000", 5) == 0) {
memcpy(local_source, source + 5, 8);
local_length = 8;
} else if ((symbology == BARCODE_UPCA || symbology == BARCODE_UPCA_CHK || symbology == BARCODE_UPCA_CC)
&& source[0] == '0') {
memcpy(local_source, source + 1, 12);
local_length = 12;
} else if ((symbology == BARCODE_UPCE || symbology == BARCODE_UPCE_CHK || symbology == BARCODE_UPCE_CC)
&& ean_is_upce(source, local_source)) {
local_length = 8;
}
if (local_length) {
if (length > 13) {
local_source[local_length] = '+';
memcpy(local_source + local_length + 1, source + 13, length - 13);
local_source[local_length + 1 + (length - 13)] = '\0';
} else {
local_source[local_length] = '\0';
}
if (zfirst_part) {
memcpy(zfirst_part, local_source, local_length);
zfirst_part[local_length] = '\0';
}
if (zsecond_part) {
if (length > 13) {
memcpy(zsecond_part, source + 13, length - 13);
}
zsecond_part[length - 13] = '\0';
}
if (p_with_addon) {
*p_with_addon = length > 13;
}
return 1;
}
}
for (i = 0; i < length; i++) {
if (source[i] == '+' || source[i] == ' ') {
with_addon = 1;
} else {
if (with_addon == 0) {
first_len++;
} else {
second_len++;
}
}
}
if (first_len > max || second_len > 5) {
if (first_len > max) {
if (!second_len || symbology == BARCODE_EAN_2ADDON || symbology == BARCODE_EAN_5ADDON) {
ZEXT z_errtxtf(0, symbol, 294, "Input length %1$d too long (maximum %2$d)", first_len, max);
} else {
ZEXT z_errtxtf(0, symbol, 298, "Input EAN length %1$d too long (maximum %2$d)", first_len, max);
}
} else {
z_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;
}
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';
if (second_len == 0) {
zsecond_len = 0;
} else if (second_len <= 2) {
zsecond_len = 2;
} else {
zsecond_len = 5;
}
switch (symbology) {
case BARCODE_EAN8:
case BARCODE_EAN8_CC:
zfirst_len = first_len <= 7 ? 7 : 8;
break;
case BARCODE_EAN_2ADDON:
zfirst_len = 2;
break;
case BARCODE_EAN_5ADDON:
zfirst_len = 5;
break;
case BARCODE_EAN13:
case BARCODE_EAN13_CC:
zfirst_len = first_len <= 12 ? 12 : 13;
break;
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 && symbology == BARCODE_EANX) {
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;
}
for (i = 0; i < (zfirst_len - first_len); i++) {
local_source[i] = '0';
}
memcpy(local_source + i, first_part, first_len + 1);
if (zfirst_part) {
memcpy(zfirst_part, local_source, z_ustrlen(local_source) + 1);
}
if (with_addon) {
int h = (int) z_ustrlen(local_source);
local_source[h++] = '+';
for (i = 0; i < (zsecond_len - second_len); i++) {
local_source[h + i] = '0';
}
memcpy(local_source + h + i, second_part, second_len + 1);
if (zsecond_part) {
memcpy(zsecond_part, local_source + h, z_ustrlen(local_source + h) + 1);
}
} else if (zsecond_part) {
*zsecond_part = '\0';
}
if (p_with_addon) {
*p_with_addon = with_addon;
}
return 1;
}
INTERNAL int zint_eanx_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows) {
unsigned char first_part[14], second_part[6];
unsigned char local_source[20];
unsigned char equivalent[12] = {0};
char dest[1000] = {0};
int with_addon;
int error_number = 0, i, sep_count;
int addon_gap = 0;
int first_part_len, second_part_len;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
if (length > 19) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 283, "Input length %d too long (maximum 19)", length);
}
if (symbol->symbology == BARCODE_ISBNX) {
if ((i = z_not_sane(ISBNX_ADDON_SANE_F, source, length))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 285,
"Invalid character at position %d in input (digits, \"X\" and \"+\" or space only)", i);
}
} else if (symbol->symbology == BARCODE_EAN_2ADDON || symbol->symbology == BARCODE_EAN_5ADDON) {
if ((i = z_not_sane(NEON_F, source, length))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 852,
"Invalid character at position %d in input (digits only)", i);
}
} else {
if ((i = z_not_sane(SODIUM_PLS_SPC_F, source, length))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 284,
"Invalid character at position %d in input (digits and \"+\" or space only)", i);
}
}
sep_count = 0;
for (i = 0; i < length; i++) {
if (source[i] == '+' || source[i] == ' ') {
if (++sep_count > 1) {
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 293,
"Invalid add-on data (one \"+\" or space only)");
}
}
}
if (!zint_ean_leading_zeroes(symbol, source, length, local_source, &with_addon, first_part, second_part)) {
return ZINT_ERROR_TOO_LONG;
}
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) z_ustrlen(first_part);
switch (symbol->symbology) {
case BARCODE_EAN8:
case BARCODE_EAN_2ADDON:
case BARCODE_EAN_5ADDON:
case BARCODE_EANX:
case BARCODE_EANX_CHK:
case BARCODE_EAN13:
switch (first_part_len) {
case 2:
case 5:
ean_add_on(first_part, first_part_len, dest, 0);
z_hrt_cpy_nochk(symbol, first_part, first_part_len);
if (symbol->output_options & COMPLIANT_HEIGHT) {
const float height = 66.3636398f;
error_number = z_set_height(symbol, height, height, 0.0f, 0 );
} else {
(void) z_set_height(symbol, 0.0f, 50.0f, 0.0f, 1 );
}
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:
assert(symbol->symbology == BARCODE_EANX || symbol->symbology == BARCODE_EANX_CHK);
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 286,
"Input length %d wrong (2, 5, 7, 8, 12 or 13 characters required)",
first_part_len);
break;
}
break;
case BARCODE_EANX_CC:
case BARCODE_EAN8_CC:
case BARCODE_EAN13_CC:
switch (first_part_len) {
case 7:
case 8:
z_set_module(symbol, symbol->rows, 1);
z_set_module(symbol, symbol->rows, 67);
z_set_module(symbol, symbol->rows + 1, 0);
z_set_module(symbol, symbol->rows + 1, 68);
z_set_module(symbol, symbol->rows + 2, 1);
z_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:
z_set_module(symbol, symbol->rows, 1);
z_set_module(symbol, symbol->rows, 95);
z_set_module(symbol, symbol->rows + 1, 0);
z_set_module(symbol, symbol->rows + 1, 96);
z_set_module(symbol, symbol->rows + 2, 1);
z_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:
assert(symbol->symbology == BARCODE_EANX_CC);
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 287,
"Input length %d wrong (7, 12 or 13 characters required)", first_part_len);
break;
}
break;
case BARCODE_UPCA:
case BARCODE_UPCA_CHK:
if (first_part_len <= 12) {
error_number = upca(symbol, first_part, first_part_len, dest);
} else {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 288,
"Input length %d too long (maximum 12)", first_part_len);
}
break;
case BARCODE_UPCA_CC:
if (first_part_len <= 12) {
z_set_module(symbol, symbol->rows, 1);
z_set_module(symbol, symbol->rows, 95);
z_set_module(symbol, symbol->rows + 1, 0);
z_set_module(symbol, symbol->rows + 1, 96);
z_set_module(symbol, symbol->rows + 2, 1);
z_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 z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 289,
"Input length %d too long (maximum 12)", first_part_len);
}
break;
case BARCODE_UPCE:
case BARCODE_UPCE_CHK:
if (first_part_len <= 8) {
error_number = upce(symbol, first_part, first_part_len, dest, equivalent);
} else {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 290,
"Input length %d too long (maximum 8)", first_part_len);
}
break;
case BARCODE_UPCE_CC:
if (first_part_len <= 8) {
z_set_module(symbol, symbol->rows, 1);
z_set_module(symbol, symbol->rows, 51);
z_set_module(symbol, symbol->rows + 1, 0);
z_set_module(symbol, symbol->rows + 1, 52);
z_set_module(symbol, symbol->rows + 2, 1);
z_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, equivalent);
} else {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 291,
"Input length %d too long (maximum 8)", 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) z_ustrlen(second_part);
if (symbol->symbology == BARCODE_ISBNX) {
if (z_not_sane(NEON_F, second_part, second_part_len)) {
return z_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);
z_hrt_cat_chr_nochk(symbol, '+');
z_hrt_cat_nochk(symbol, second_part, second_part_len);
if (first_part_len <= 8 && (symbol->symbology == BARCODE_EAN8 || symbol->symbology == BARCODE_EANX
|| symbol->symbology == BARCODE_EANX_CHK || symbol->symbology == BARCODE_EANX_CC
|| symbol->symbology == BARCODE_EAN8_CC)) {
error_number = z_errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 292, "EAN-8 with add-on is non-standard");
}
}
if (content_segs) {
const int is_ean = z_is_ean(symbol->symbology);
if (is_ean && symbol->text_length <= 8 && !second_part_len) {
if (z_ct_cpy(symbol, symbol->text, symbol->text_length)) {
return ZINT_ERROR_MEMORY;
}
} else {
unsigned char gtin13[13];
if (is_ean && symbol->text_length >= 13) {
memcpy(gtin13, symbol->text, 13);
} else if (*equivalent) {
gtin13[0] = '0';
memcpy(gtin13 + 1, equivalent, 12);
} else {
const int zeroes = 13 - (symbol->text_length - (second_part_len ? second_part_len + 1 : 0));
assert(zeroes > 0);
memset(gtin13, '0', zeroes);
memcpy(gtin13 + zeroes, symbol->text, 13 - zeroes);
}
if (z_ct_cpy_cat(symbol, gtin13, 13, '\xFF' , second_part, second_part_len)) {
return ZINT_ERROR_MEMORY;
}
}
}
z_expand(symbol, dest, (int) strlen(dest));
switch (symbol->symbology) {
case BARCODE_EANX_CC:
case BARCODE_EAN8_CC:
case BARCODE_EAN13_CC:
case BARCODE_UPCA_CC:
case BARCODE_UPCE_CC:
for (i = (symbol->width + 1); i >= 1; i--) {
if (z_module_is_set(symbol, symbol->rows - 1, i - 1)) {
z_set_module(symbol, symbol->rows - 1, i);
} else {
z_unset_module(symbol, symbol->rows - 1, i);
}
}
z_unset_module(symbol, symbol->rows - 1, 0);
symbol->width += 1 + (second_part_len == 0);
break;
}
return error_number;
}
INTERNAL int zint_eanx(struct zint_symbol *symbol, unsigned char source[], int length) {
return zint_eanx_cc(symbol, source, length, 0 );
}