#include <assert.h>
#include <stdio.h>
#include "common.h"
#include "code128.h"
#include "gs1.h"
INTERNAL int zint_gs1_128(struct zint_symbol *symbol, unsigned char source[], int length);
static int nve18_or_ean14(struct zint_symbol *symbol, const unsigned char source[], int length, const int data_len) {
static const char prefix[2][2][5] = {
{ "(01)", "[01]" },
{ "(00)", "[00]" },
};
const int idx = data_len == 17;
unsigned char ean128_equiv[23];
int i, zeroes;
unsigned char have_check_digit = '\0';
unsigned char check_digit;
int error_number;
if ((length == data_len + 4 || length == data_len + 1 + 4)
&& (memcmp(source, prefix[idx][0], 4) == 0 || memcmp(source, prefix[idx][1], 4) == 0)) {
source += 4;
length -= 4;
} else if ((length == data_len + 2 || length == data_len + 1 + 2)
&& source[0] == prefix[idx][0][1] && source[1] == prefix[idx][0][2]) {
source += 2;
length -= 2;
}
if (length > data_len + 1) {
return ZEXT z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 345, "Input length %1$d too long (maximum %2$d)",
length, data_len + 1);
}
if ((i = z_not_sane(NEON_F, source, length))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 346,
"Invalid character at position %d in input (digits only)", i);
}
if (length == data_len + 1) {
have_check_digit = source[data_len];
length--;
}
zeroes = data_len - length;
memcpy(ean128_equiv, prefix[idx][!(symbol->input_mode & GS1PARENS_MODE)], 4);
memset(ean128_equiv + 4, '0', zeroes);
memcpy(ean128_equiv + 4 + zeroes, source, length);
check_digit = (unsigned char) zint_gs1_check_digit(ean128_equiv + 4, data_len);
if (have_check_digit && have_check_digit != check_digit) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 347, "Invalid check digit '%1$c', expecting '%2$c'",
have_check_digit, check_digit);
}
ean128_equiv[data_len + 4] = check_digit;
ean128_equiv[data_len + 5] = '\0';
error_number = zint_gs1_128(symbol, ean128_equiv, data_len + 5);
return error_number;
}
INTERNAL int zint_nve18(struct zint_symbol *symbol, unsigned char source[], int length) {
return nve18_or_ean14(symbol, source, length, 17 );
}
INTERNAL int zint_ean14(struct zint_symbol *symbol, unsigned char source[], int length) {
return nve18_or_ean14(symbol, source, length, 13 );
}
static const char KRSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
#define KRSET_F (IS_NUM_F | IS_UPR_F)
INTERNAL int zint_dpd(struct zint_symbol *symbol, unsigned char source[], int length) {
int i, p;
unsigned char ident_tag;
unsigned char local_source_buf[29];
unsigned char *local_source;
unsigned char hrt[37];
int cd;
int error_number;
const int mod = 36;
const int relabel = symbol->option_2 == 1;
if ((length != 27 && length != 28) || (length == 28 && relabel)) {
if (relabel) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 830,
"DPD relabel input length %d wrong (27 characters required)", length);
}
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 349, "DPD input length %d wrong (27 or 28 characters required)",
length);
}
if (length == 27 && !relabel) {
local_source_buf[0] = '%';
memcpy(local_source_buf + 1, source, ++length);
local_source = local_source_buf;
} else {
local_source = source;
}
ident_tag = local_source[0];
z_to_upper(local_source + !relabel, length - !relabel);
if ((i = z_not_sane(KRSET_F, local_source + !relabel, length - !relabel))) {
if (local_source == local_source_buf || relabel) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 300,
"Invalid character at position %d in input (alphanumerics only)", i);
}
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 299,
"Invalid character at position %d in input (alphanumerics only after first)", i);
}
if (z_iscntrl(ident_tag) || !z_isascii(ident_tag)) {
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 343,
"Invalid DPD identification tag (first character), ASCII values 32 to 126 only");
}
if ((error_number = zint_code128(symbol, local_source, length))) {
assert(error_number == ZINT_ERROR_MEMORY);
return error_number;
}
if (!(symbol->output_options & (BARCODE_BOX | BARCODE_BIND | BARCODE_BIND_TOP))) {
symbol->output_options |= BARCODE_BIND_TOP;
if (symbol->border_width == 0) {
symbol->border_width = 3;
}
}
if (symbol->output_options & COMPLIANT_HEIGHT) {
if (relabel) {
const float default_height = 33.3333321f;
error_number = z_set_height(symbol, 31.25f, default_height, 0.0f, 0 );
} else {
const float default_height = 66.6666641f;
error_number = z_set_height(symbol, 62.5f, default_height, 0.0f, 0 );
}
} else {
(void) z_set_height(symbol, 0.0f, relabel ? 25.0f : 50.0f, 0.0f, 1 );
}
cd = mod;
for (i = !relabel, p = 0; i < length; i++) {
hrt[p++] = local_source[i];
cd += z_posn(KRSET, local_source[i]);
if (cd > mod) cd -= mod;
cd *= 2;
if (cd >= (mod + 1)) cd -= mod + 1;
switch (i + relabel) {
case 4:
case 7:
case 11:
case 15:
case 19:
case 21:
case 24:
case 27:
hrt[p++] = ' ';
break;
}
}
cd = mod + 1 - cd;
if (cd == mod) cd = 0;
hrt[p] = z_xtoc(cd);
z_hrt_cpy_nochk(symbol, hrt, p + 1);
if (z_not_sane(NEON_F, local_source + length - 16, 16)) {
if (z_not_sane(NEON_F, local_source + length - 3, 3)) {
z_errtxt(0, symbol, 831, "Destination Country Code (last 3 characters) should be numeric");
} else if (z_not_sane(NEON_F, local_source + length - 6, 3)) {
z_errtxt(0, symbol, 832, "Service Code (characters 6-4 from end) should be numeric");
} else {
z_errtxt(0, symbol, 833,
"Last 10 characters of Tracking Number (characters 16-7 from end) should be numeric");
}
error_number = ZINT_WARN_NONCOMPLIANT;
}
return error_number;
}
INTERNAL int zint_upu_s10(struct zint_symbol *symbol, unsigned char source[], int length) {
static const char weights[8] = { 8, 6, 4, 2, 3, 5, 9, 7 };
unsigned char local_source[13 + 1];
unsigned char have_check_digit = '\0';
unsigned char hrt[18];
int i, j;
int check_digit;
int error_number;
if (length != 12 && length != 13) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 834, "Input length %d wrong (12 or 13 characters required)",
length);
}
if (length == 13) {
have_check_digit = source[10];
memcpy(local_source, source, 10);
memcpy(local_source + 10, source + 11, length - 11);
length--;
} else {
memcpy(local_source, source, length);
}
z_to_upper(local_source, length);
if (!z_isupper(local_source[0]) || !z_isupper(local_source[1])) {
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 835,
"Invalid character in Service Indicator (first 2 characters) (alphabetic only)");
}
if (z_not_sane(NEON_F, local_source + 2, 12 - 4) || (have_check_digit && !z_isdigit(have_check_digit))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 836,
"Invalid character in Serial Number (middle %d characters) (digits only)",
have_check_digit ? 9 : 8);
}
if (!z_isupper(local_source[10]) || !z_isupper(local_source[11])) {
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 837,
"Invalid character in Country Code (last 2 characters) (alphabetic only)");
}
check_digit = 0;
for (i = 2; i < 10; i++) {
check_digit += z_ctoi(local_source[i]) * weights[i - 2];
}
check_digit %= 11;
check_digit = 11 - check_digit;
if (check_digit == 10) {
check_digit = 0;
} else if (check_digit == 11) {
check_digit = 5;
}
if (have_check_digit && z_ctoi(have_check_digit) != check_digit) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 838, "Invalid check digit '%1$c', expecting '%2$c'",
have_check_digit, z_itoc(check_digit));
}
local_source[12] = local_source[11];
local_source[11] = local_source[10];
local_source[10] = z_itoc(check_digit);
local_source[13] = '\0';
if ((error_number = zint_code128(symbol, local_source, 13))) {
assert(error_number == ZINT_ERROR_MEMORY);
return error_number;
}
if (strchr("JKSTW", local_source[0]) != NULL) {
error_number = z_errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 839,
"Invalid Service Indicator '%.2s' (first character should not be any of \"JKSTW\")",
local_source);
} else if (strchr("FIOXY", local_source[0]) != NULL) {
error_number = z_errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 840,
"Non-standard Service Indicator '%.2s' (first 2 characters)", local_source);
} else if (!zint_gs1_iso3166_alpha2(local_source + 11)) {
error_number = z_errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 841,
"Country Code '%.2s' (last two characters) is not ISO 3166-1", local_source + 11);
}
for (i = 0, j = 0; i < 13; i++) {
if (i == 2 || i == 5 || i == 8 || i == 11) {
hrt[j++] = ' ';
}
hrt[j++] = local_source[i];
}
z_hrt_cpy_nochk(symbol, hrt, j);
if (symbol->output_options & COMPLIANT_HEIGHT) {
const float min_height_min = 24.5098038f;
float min_height = z_stripf(symbol->width * 0.15f);
if (min_height < min_height_min) {
min_height = min_height_min;
}
if (error_number == 0) {
error_number = z_set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f,
0 );
} else {
(void) z_set_height(symbol, min_height, min_height > 50.0f ? min_height : 50.0f, 0.0f, 1 );
}
} else {
(void) z_set_height(symbol, 0.0f, 50.0f, 0.0f, 1 );
}
return error_number;
}