#include <assert.h>
#include <stdio.h>
#include "common.h"
static const char SILVER[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd";
#define ARSENIC_F (IS_NUM_F | IS_ARS_F)
static const char C39Table[43 + 1][10] = {
{'1','1','1','2','2','1','2','1','1','1'}, {'2','1','1','2','1','1','1','1','2','1'},
{'1','1','2','2','1','1','1','1','2','1'}, {'2','1','2','2','1','1','1','1','1','1'},
{'1','1','1','2','2','1','1','1','2','1'}, {'2','1','1','2','2','1','1','1','1','1'},
{'1','1','2','2','2','1','1','1','1','1'}, {'1','1','1','2','1','1','2','1','2','1'},
{'2','1','1','2','1','1','2','1','1','1'}, {'1','1','2','2','1','1','2','1','1','1'},
{'2','1','1','1','1','2','1','1','2','1'}, {'1','1','2','1','1','2','1','1','2','1'},
{'2','1','2','1','1','2','1','1','1','1'}, {'1','1','1','1','2','2','1','1','2','1'},
{'2','1','1','1','2','2','1','1','1','1'}, {'1','1','2','1','2','2','1','1','1','1'},
{'1','1','1','1','1','2','2','1','2','1'}, {'2','1','1','1','1','2','2','1','1','1'},
{'1','1','2','1','1','2','2','1','1','1'}, {'1','1','1','1','2','2','2','1','1','1'},
{'2','1','1','1','1','1','1','2','2','1'}, {'1','1','2','1','1','1','1','2','2','1'},
{'2','1','2','1','1','1','1','2','1','1'}, {'1','1','1','1','2','1','1','2','2','1'},
{'2','1','1','1','2','1','1','2','1','1'}, {'1','1','2','1','2','1','1','2','1','1'},
{'1','1','1','1','1','1','2','2','2','1'}, {'2','1','1','1','1','1','2','2','1','1'},
{'1','1','2','1','1','1','2','2','1','1'}, {'1','1','1','1','2','1','2','2','1','1'},
{'2','2','1','1','1','1','1','1','2','1'}, {'1','2','2','1','1','1','1','1','2','1'},
{'2','2','2','1','1','1','1','1','1','1'}, {'1','2','1','1','2','1','1','1','2','1'},
{'2','2','1','1','2','1','1','1','1','1'}, {'1','2','2','1','2','1','1','1','1','1'},
{'1','2','1','1','1','1','2','1','2','1'}, {'2','2','1','1','1','1','2','1','1','1'},
{'1','2','2','1','1','1','2','1','1','1'}, {'1','2','1','2','1','2','1','1','1','1'},
{'1','2','1','2','1','1','1','2','1','1'}, {'1','2','1','1','1','2','1','2','1','1'},
{'1','1','1','2','1','2','1','2','1','1'},
{'1','2','1','1','2','1','2','1','1','1'}
};
static const char EC39Ctrl[128][2] = {
{'%','U'}, {'$','A'}, {'$','B'}, {'$','C'}, {'$','D'}, {'$','E'}, {'$','F'}, {'$','G'}, {'$','H'}, {'$','I'},
{'$','J'}, {'$','K'}, {'$','L'}, {'$','M'}, {'$','N'}, {'$','O'}, {'$','P'}, {'$','Q'}, {'$','R'}, {'$','S'},
{'$','T'}, {'$','U'}, {'$','V'}, {'$','W'}, {'$','X'}, {'$','Y'}, {'$','Z'}, {'%','A'}, {'%','B'}, {'%','C'},
{'%','D'}, {'%','E'}, { " " }, {'/','A'}, {'/','B'}, {'/','C'}, {'/','D'}, {'/','E'}, {'/','F'}, {'/','G'},
{'/','H'}, {'/','I'}, {'/','J'}, {'/','K'}, {'/','L'}, { "-" }, { "." }, {'/','O'}, { "0" }, { "1" },
{ "2" }, { "3" }, { "4" }, { "5" }, { "6" }, { "7" }, { "8" }, { "9" }, {'/','Z'}, {'%','F'},
{'%','G'}, {'%','H'}, {'%','I'}, {'%','J'}, {'%','V'}, { "A" }, { "B" }, { "C" }, { "D" }, { "E" },
{ "F" }, { "G" }, { "H" }, { "I" }, { "J" }, { "K" }, { "L" }, { "M" }, { "N" }, { "O" },
{ "P" }, { "Q" }, { "R" }, { "S" }, { "T" }, { "U" }, { "V" }, { "W" }, { "X" }, { "Y" },
{ "Z" }, {'%','K'}, {'%','L'}, {'%','M'}, {'%','N'}, {'%','O'}, {'%','W'}, {'+','A'}, {'+','B'}, {'+','C'},
{'+','D'}, {'+','E'}, {'+','F'}, {'+','G'}, {'+','H'}, {'+','I'}, {'+','J'}, {'+','K'}, {'+','L'}, {'+','M'},
{'+','N'}, {'+','O'}, {'+','P'}, {'+','Q'}, {'+','R'}, {'+','S'}, {'+','T'}, {'+','U'}, {'+','V'}, {'+','W'},
{'+','X'}, {'+','Y'}, {'+','Z'}, {'%','P'}, {'%','Q'}, {'%','R'}, {'%','S'}, {'%','T'}
};
static const char C93Ctrl[128][2] = {
{'b','U'}, {'a','A'}, {'a','B'}, {'a','C'}, {'a','D'}, {'a','E'}, {'a','F'}, {'a','G'}, {'a','H'}, {'a','I'},
{'a','J'}, {'a','K'}, {'a','L'}, {'a','M'}, {'a','N'}, {'a','O'}, {'a','P'}, {'a','Q'}, {'a','R'}, {'a','S'},
{'a','T'}, {'a','U'}, {'a','V'}, {'a','W'}, {'a','X'}, {'a','Y'}, {'a','Z'}, {'b','A'}, {'b','B'}, {'b','C'},
{'b','D'}, {'b','E'}, { " " }, {'c','A'}, {'c','B'}, {'c','C'}, { "$" }, { "%" }, {'c','F'}, {'c','G'},
{'c','H'}, {'c','I'}, {'c','J'}, { "+" }, {'c','L'}, { "-" }, { "." }, { "/" }, { "0" }, { "1" },
{ "2" }, { "3" }, { "4" }, { "5" }, { "6" }, { "7" }, { "8" }, { "9" }, {'c','Z'}, {'b','F'},
{'b','G'}, {'b','H'}, {'b','I'}, {'b','J'}, {'b','V'}, { "A" }, { "B" }, { "C" }, { "D" }, { "E" },
{ "F" }, { "G" }, { "H" }, { "I" }, { "J" }, { "K" }, { "L" }, { "M" }, { "N" }, { "O" },
{ "P" }, { "Q" }, { "R" }, { "S" }, { "T" }, { "U" }, { "V" }, { "W" }, { "X" }, { "Y" },
{ "Z" }, {'b','K'}, {'b','L'}, {'b','M'}, {'b','N'}, {'b','O'}, {'b','W'}, {'d','A'}, {'d','B'}, {'d','C'},
{'d','D'}, {'d','E'}, {'d','F'}, {'d','G'}, {'d','H'}, {'d','I'}, {'d','J'}, {'d','K'}, {'d','L'}, {'d','M'},
{'d','N'}, {'d','O'}, {'d','P'}, {'d','Q'}, {'d','R'}, {'d','S'}, {'d','T'}, {'d','U'}, {'d','V'}, {'d','W'},
{'d','X'}, {'d','Y'}, {'d','Z'}, {'b','P'}, {'b','Q'}, {'b','R'}, {'b','S'}, {'b','T'}
};
static const char C93Table[47][6] = {
{'1','3','1','1','1','2'}, {'1','1','1','2','1','3'}, {'1','1','1','3','1','2'}, {'1','1','1','4','1','1'},
{'1','2','1','1','1','3'}, {'1','2','1','2','1','2'}, {'1','2','1','3','1','1'}, {'1','1','1','1','1','4'},
{'1','3','1','2','1','1'}, {'1','4','1','1','1','1'}, {'2','1','1','1','1','3'}, {'2','1','1','2','1','2'},
{'2','1','1','3','1','1'}, {'2','2','1','1','1','2'}, {'2','2','1','2','1','1'}, {'2','3','1','1','1','1'},
{'1','1','2','1','1','3'}, {'1','1','2','2','1','2'}, {'1','1','2','3','1','1'}, {'1','2','2','1','1','2'},
{'1','3','2','1','1','1'}, {'1','1','1','1','2','3'}, {'1','1','1','2','2','2'}, {'1','1','1','3','2','1'},
{'1','2','1','1','2','2'}, {'1','3','1','1','2','1'}, {'2','1','2','1','1','2'}, {'2','1','2','2','1','1'},
{'2','1','1','1','2','2'}, {'2','1','1','2','2','1'}, {'2','2','1','1','2','1'}, {'2','2','2','1','1','1'},
{'1','1','2','1','2','2'}, {'1','1','2','2','2','1'}, {'1','2','2','1','2','1'}, {'1','2','3','1','1','1'},
{'1','2','1','1','3','1'}, {'3','1','1','1','1','2'}, {'3','1','1','2','1','1'}, {'3','2','1','1','1','1'},
{'1','1','2','1','3','1'}, {'1','1','3','1','2','1'}, {'2','1','1','1','3','1'}, {'1','2','1','2','2','1'},
{'3','1','2','1','1','1'}, {'3','1','1','1','2','1'}, {'1','2','2','2','1','1'}
};
INTERNAL int zint_code39(struct zint_symbol *symbol, unsigned char source[], int length) {
int i;
int counter;
int posns[86];
char dest[890];
char *d = dest;
char check_digit = '\0';
int error_number = 0;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
if (symbol->option_2 < 0 || symbol->option_2 > 2) {
symbol->option_2 = 0;
}
if (symbol->symbology == BARCODE_LOGMARS && length > 30) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 322, "Input length %d too long (maximum 30)", length);
} else if (symbol->symbology == BARCODE_HIBC_39 && length > 70) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 319, "Input length %d too long (maximum 68)", length - 2);
} else if (length > 86) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 323, "Input length %d too long (maximum 86)", length);
}
z_to_upper(source, length);
if ((i = z_not_sane_lookup(SILVER, 43 , source, length, posns))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 324,
"Invalid character at position %d in input (alphanumerics, space and \"-.$/+%%\" only)", i);
}
memcpy(d, C39Table[43], 10);
d += 10;
for (i = 0, counter = 0; i < length; i++, d += 10) {
memcpy(d, C39Table[posns[i]], 10);
counter += posns[i];
}
if (symbol->option_2 == 1 || symbol->option_2 == 2) {
counter %= 43;
check_digit = SILVER[counter];
memcpy(d, C39Table[counter], 10);
d += 10;
if (symbol->debug & ZINT_DEBUG_PRINT) printf("Check digit: %c\n", check_digit);
}
memcpy(d, C39Table[43], 9);
d += 9;
if (symbol->symbology == BARCODE_LOGMARS || symbol->symbology == BARCODE_HIBC_39) {
counter = d - dest;
for (i = 0; i < counter; i++) {
if (dest[i] == '2') {
dest[i] = '3';
}
}
}
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("Barspaces: %.*s\n", (int) (d - dest), dest);
}
z_expand(symbol, dest, d - dest);
if (symbol->output_options & COMPLIANT_HEIGHT) {
if (symbol->symbology == BARCODE_LOGMARS) {
const float default_height = 45.4545441f;
const float max_height = 116.666664f;
error_number = z_set_height(symbol, 6.25f, default_height, max_height, 0 );
} else if (symbol->symbology == BARCODE_CODE39 || symbol->symbology == BARCODE_EXCODE39
|| symbol->symbology == BARCODE_HIBC_39) {
const float min_height = z_stripf((10.0f * (length + (symbol->option_2 == 1)) + 19.0f) * 0.15f);
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, 0.0f, 50.f, 0.0f, 1 );
}
if (symbol->option_2 == 1 && check_digit == ' ') {
check_digit = '_';
}
if (symbol->symbology == BARCODE_CODE39) {
z_hrt_cpy_chr(symbol, '*');
z_hrt_cat_nochk(symbol, source, length);
if (symbol->option_2 == 1) {
z_hrt_cat_chr_nochk(symbol, check_digit);
}
z_hrt_cat_chr_nochk(symbol, '*');
} else {
z_hrt_cpy_cat_nochk(symbol, source, length, (char) (symbol->option_2 == 1 ? check_digit : '\xFF'),
NULL , 0);
}
if (content_segs) {
if (z_ct_cpy_cat(symbol, source, length,
(char) (check_digit ? check_digit == '_' ? ' ' : check_digit : '\xFF'), NULL , 0)) {
return ZINT_ERROR_MEMORY;
}
}
return error_number;
}
INTERNAL int zint_excode39(struct zint_symbol *symbol, unsigned char source[], int length) {
int i;
unsigned char buffer[86 * 2 + 1] = {0};
unsigned char *b = buffer;
unsigned char check_digit = '\0';
int error_number;
const int saved_option_2 = symbol->option_2;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
if (length > 86) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 328, "Input length %d too long (maximum 86)", length);
}
for (i = 0; i < length; i++) {
if (!z_isascii(source[i])) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 329,
"Invalid character at position %d in input, extended ASCII not allowed", i + 1);
}
memcpy(b, EC39Ctrl[source[i]], 2);
b += EC39Ctrl[source[i]][1] ? 2 : 1;
}
if (b - buffer > 86) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 317,
"Input too long, requires %d symbol characters (maximum 86)", (int) (b - buffer));
}
*b = '\0';
if (saved_option_2 == 2) {
symbol->option_2 = 1;
}
if (content_segs) {
symbol->output_options &= ~BARCODE_CONTENT_SEGS;
}
if ((error_number = zint_code39(symbol, buffer, b - buffer)) >= ZINT_ERROR) {
return error_number;
}
if (saved_option_2 == 2) {
symbol->option_2 = 2;
}
if (content_segs) {
symbol->output_options |= BARCODE_CONTENT_SEGS;
}
if (symbol->option_2 == 1 || (content_segs && symbol->option_2 == 2)) {
check_digit = symbol->text[symbol->text_length - 1];
}
(void) z_hrt_cpy_iso8859_1(symbol, source, length);
if (symbol->option_2 == 1) {
z_hrt_cat_chr_nochk(symbol, check_digit);
}
if (content_segs && z_ct_cpy_cat(symbol, source, length,
(char) (check_digit ? check_digit == '_' ? ' ' : check_digit : '\xFF'),
NULL , 0)) {
return ZINT_ERROR_MEMORY;
}
return error_number;
}
INTERNAL int zint_code93(struct zint_symbol *symbol, unsigned char source[], int length) {
int i;
int h, weight, c, k, error_number = 0;
int values[125];
char buffer[247];
char *b = buffer;
char dest[764];
char *d = dest;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
assert(length > 0);
if (length > 123) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 330, "Input length %d too long (maximum 123)", length);
}
for (i = 0; i < length; i++) {
if (!z_isascii(source[i])) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 331,
"Invalid character at position %d in input, extended ASCII not allowed", i + 1);
}
memcpy(b, C93Ctrl[source[i]], 2);
b += C93Ctrl[source[i]][1] ? 2 : 1;
}
h = b - buffer;
if (h > 123) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 332,
"Input too long, requires %d symbol characters (maximum 123)", h);
}
for (i = 0; i < h; i++) {
values[i] = z_posn(SILVER, buffer[i]);
}
c = 0;
weight = 1;
for (i = h - 1; i >= 0; i--) {
c += values[i] * weight;
weight++;
if (weight == 21)
weight = 1;
}
c = c % 47;
values[h] = c;
k = 0;
weight = 1;
for (i = h; i >= 0; i--) {
k += values[i] * weight;
weight++;
if (weight == 16)
weight = 1;
}
k = k % 47;
values[h + 1] = k;
h += 2;
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("Check digit c: %c (%d), k: %c (%d)\n", SILVER[c], c, SILVER[k], k);
}
memcpy(d, "111141", 6);
d += 6;
for (i = 0; i < h; i++, d += 6) {
memcpy(d, C93Table[values[i]], 6);
}
memcpy(d, "1111411", 7);
d += 7;
z_expand(symbol, dest, d - dest);
if (symbol->output_options & COMPLIANT_HEIGHT) {
const float min_height = z_stripf((symbol->width + 20) * 0.15f);
error_number = z_set_height(symbol, min_height, min_height > 40.0f ? min_height : 40.0f, 0.0f,
0 );
} else {
(void) z_set_height(symbol, 0.0f, 50.0f, 0.0f, 1 );
}
(void) z_hrt_cpy_iso8859_1(symbol, source, length);
if (symbol->option_2 == 1) {
z_hrt_cat_chr_nochk(symbol, SILVER[c]);
z_hrt_cat_chr_nochk(symbol, SILVER[k]);
}
if (content_segs && z_ct_cpy_cat(symbol, source, length, SILVER[c], (const unsigned char *) SILVER + k, 1)) {
return ZINT_ERROR_MEMORY;
}
return error_number;
}
INTERNAL int zint_vin(struct zint_symbol *symbol, unsigned char source[], int length) {
char dest[200];
char *d = dest;
char input_check;
char output_check;
int sum;
int i;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
static const char weight[17] = { 8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2 };
if (length != 17) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 336, "Input length %d wrong (17 characters required)", length);
}
if ((i = z_not_sane(ARSENIC_F, source, length))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 337,
"Invalid character at position %d in input (alphanumerics only, excluding \"IOQ\")", i);
}
z_to_upper(source, length);
if (source[0] >= '1' && source[0] <= '5') {
input_check = source[8];
sum = 0;
for (i = 0; i < 17; i++) {
int value;
if (source[i] <= '9') {
value = source[i] - '0';
} else if (source[i] <= 'H') {
value = (source[i] - 'A') + 1;
} else if (source[i] <= 'R') {
value = (source[i] - 'J') + 1;
} else {
value = (source[i] - 'S') + 2;
}
sum += value * weight[i];
}
output_check = '0' + (sum % 11);
if (output_check == ':') {
output_check = 'X';
}
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("Producing VIN code: %s\n", source);
printf("Input check was %c, calculated check is %c\n", input_check, output_check);
}
if (input_check != output_check) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 338,
"Invalid check digit '%1$c' (position 9), expecting '%2$c'", input_check,
output_check);
}
}
memcpy(d, C39Table[43], 10);
d += 10;
if (symbol->option_2 == 1) {
memcpy(d, C39Table[18], 10);
d += 10;
}
for (i = 0; i < 17; i++, d += 10) {
memcpy(d, C39Table[z_posn(SILVER, source[i])], 10);
}
memcpy(d, C39Table[43], 9);
d += 9;
z_expand(symbol, dest, d - dest);
z_hrt_cpy_nochk(symbol, source, length);
if (content_segs && z_ct_cpy_cat(symbol, NULL , 0, (char) (symbol->option_2 == 1 ? 'I' : '\xFF'),
source, length)) {
return ZINT_ERROR_MEMORY;
}
return 0;
}