CODEONE/ULTRA overrun fixes; TELEPEN fixes; CODEONE/LOGMARS/VIN/CODABAR options; GUI updates; tests

This commit is contained in:
gitlost
2020-06-04 18:45:25 +01:00
parent 8131471573
commit 6242e02638
80 changed files with 6393 additions and 2179 deletions

View File

@ -1,8 +1,11 @@
/* code.c - Handles Code 11, 39, 39+ and 93 */
/* code.c - Handles Code 11, 39, 39+, 93, PZN, Channel and VIN */
/* LOGMARS MIL-STD-1189 Rev. B https://apps.dtic.mil/dtic/tr/fulltext/u2/a473534.pdf */
/* PZN https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/IFA_Info_Code_39_EN.pdf */
/* PZN https://www.ifaffm.de/mandanten/1/documents/04_ifa_coding_system/IFA-Info_Check_Digit_Calculations_PZN_PPN_UDI_EN.pdf */
/*
libzint - the open source barcode library
Copyright (C) 2008-2017 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2008 - 2020 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@ -33,13 +36,12 @@
/* In version 0.5 this file was 1,553 lines long! */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "common.h"
#define SODIUM "0123456789-"
#define SILVER "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd"
#define SODIUM "0123456789-"
#define SILVER "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd"
#define ARSENIC "0123456789ABCDEFGHJKLMNPRSTUVWXYZ"
static const char *C11Table[11] = {
@ -108,11 +110,15 @@ static void NextB(int Chan, int i, int MaxB, int MaxS);
/* *********************** CODE 11 ******************** */
INTERNAL int code_11(struct zint_symbol *symbol, unsigned char source[], int length) { /* Code 11 */
unsigned int i;
int i;
int h, c_digit, c_weight, c_count, k_digit, k_weight, k_count;
int weight[128], error_number;
char dest[1024]; /* 6 + 121 * 6 + 2 * 6 + 5 + 1 ~ 1024*/
int weight[122], error_number;
char dest[750]; /* 6 + 121 * 6 + 2 * 6 + 5 + 1 == 750 */
char checkstr[3];
int num_check_digits;
/* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warning */
assert(length > 0);
if (length > 121) {
strcpy(symbol->errtxt, "320: Input too long");
@ -123,6 +129,19 @@ INTERNAL int code_11(struct zint_symbol *symbol, unsigned char source[], int len
strcpy(symbol->errtxt, "321: Invalid characters in data");
return error_number;
}
if (symbol->option_2 < 0 || symbol->option_2 > 2) {
strcpy(symbol->errtxt, "339: Invalid check digit version");
return ZINT_ERROR_INVALID_OPTION;
}
if (symbol->option_2 == 2) {
num_check_digits = 0;
} else if (symbol->option_2 == 1) {
num_check_digits = 1;
} else {
num_check_digits = 2;
}
c_weight = 1;
c_count = 0;
k_weight = 1;
@ -132,7 +151,7 @@ INTERNAL int code_11(struct zint_symbol *symbol, unsigned char source[], int len
strcpy(dest, "112211");
/* Draw main body of barcode */
for (i = 0; i < (unsigned int) length; i++) {
for (i = 0; i < length; i++) {
lookup(SODIUM, C11Table, source[i], dest);
if (source[i] == '-')
weight[i] = 10;
@ -140,41 +159,52 @@ INTERNAL int code_11(struct zint_symbol *symbol, unsigned char source[], int len
weight[i] = ctoi(source[i]);
}
/* Calculate C checksum */
for (h = length - 1; h >= 0; h--) {
c_count += (c_weight * weight[h]);
c_weight++;
if (num_check_digits) {
/* Calculate C checksum */
for (h = length - 1; h >= 0; h--) {
c_count += (c_weight * weight[h]);
c_weight++;
if (c_weight > 10) {
c_weight = 1;
if (c_weight > 10) {
c_weight = 1;
}
}
c_digit = c_count % 11;
if (num_check_digits == 1) {
checkstr[0] = itoc(c_digit);
if (checkstr[0] == 'A') {
checkstr[0] = '-';
}
checkstr[1] = '\0';
lookup(SODIUM, C11Table, checkstr[0], dest);
} else {
weight[length] = c_digit;
/* Calculate K checksum */
for (h = length; h >= 0; h--) {
k_count += (k_weight * weight[h]);
k_weight++;
if (k_weight > 9) {
k_weight = 1;
}
}
k_digit = k_count % 11;
checkstr[0] = itoc(c_digit);
checkstr[1] = itoc(k_digit);
if (checkstr[0] == 'A') {
checkstr[0] = '-';
}
if (checkstr[1] == 'A') {
checkstr[1] = '-';
}
checkstr[2] = '\0';
lookup(SODIUM, C11Table, checkstr[0], dest);
lookup(SODIUM, C11Table, checkstr[1], dest);
}
}
c_digit = c_count % 11;
weight[length] = c_digit;
/* Calculate K checksum */
for (h = length; h >= 0; h--) {
k_count += (k_weight * weight[h]);
k_weight++;
if (k_weight > 9) {
k_weight = 1;
}
}
k_digit = k_count % 11;
checkstr[0] = itoc(c_digit);
checkstr[1] = itoc(k_digit);
if (checkstr[0] == 'A') {
checkstr[0] = '-';
}
if (checkstr[1] == 'A') {
checkstr[1] = '-';
}
checkstr[2] = '\0';
lookup(SODIUM, C11Table, checkstr[0], dest);
lookup(SODIUM, C11Table, checkstr[1], dest);
/* Stop character */
strcat(dest, "11221");
@ -182,16 +212,18 @@ INTERNAL int code_11(struct zint_symbol *symbol, unsigned char source[], int len
expand(symbol, dest);
ustrcpy(symbol->text, source);
strcat((char*) symbol->text, checkstr);
if (num_check_digits) {
ustrcat(symbol->text, checkstr);
}
return error_number;
}
/* Code 39 */
INTERNAL int c39(struct zint_symbol *symbol, unsigned char source[], const size_t length) {
unsigned int i;
unsigned int counter;
int i;
int counter;
int error_number;
char dest[775];
char dest[880]; /* 10 (Start) + 85 * 10 + 10 (Check) + 9 (Stop) + 1 = 880 */
char localstr[2] = {0};
counter = 0;
@ -200,10 +232,13 @@ INTERNAL int c39(struct zint_symbol *symbol, unsigned char source[], const size_
symbol->option_2 = 0;
}
if ((symbol->symbology == BARCODE_LOGMARS) && (length > 59)) {
if ((symbol->symbology == BARCODE_LOGMARS) && (length > 30)) { /* MIL-STD-1189 Rev. B Section 5.2.6.2 */
strcpy(symbol->errtxt, "322: Input too long");
return ZINT_ERROR_TOO_LONG;
} else if (length > 74) {
} else if ((symbol->symbology == BARCODE_HIBC_39) && (length > 68)) { /* Prevent encoded_data out-of-bounds >= 143 due to wider 'wide' bars */
strcpy(symbol->errtxt, "319: Input too long"); /* Note use 319 (2of5 range) as 340 taken by CODE128 */
return ZINT_ERROR_TOO_LONG;
} else if (length > 85) {
strcpy(symbol->errtxt, "323: Input too long");
return ZINT_ERROR_TOO_LONG;
}
@ -217,12 +252,12 @@ INTERNAL int c39(struct zint_symbol *symbol, unsigned char source[], const size_
/* Start character */
strcpy(dest, "1211212111");
for (i = 0; i < (unsigned int) length; i++) {
for (i = 0; i < (int) length; i++) {
lookup(SILVER, C39Table, source[i], dest);
counter += posn(SILVER, source[i]);
}
if ((symbol->symbology == BARCODE_LOGMARS) || (symbol->option_2 == 1)) {
if (symbol->option_2 == 1) {
char check_digit;
counter = counter % 43;
@ -268,7 +303,7 @@ INTERNAL int c39(struct zint_symbol *symbol, unsigned char source[], const size_
if ((symbol->symbology == BARCODE_LOGMARS) || (symbol->symbology == BARCODE_HIBC_39)) {
/* LOGMARS uses wider 'wide' bars than normal Code 39 */
counter = (unsigned int) strlen(dest);
counter = strlen(dest);
for (i = 0; i < counter; i++) {
if (dest[i] == '2') {
dest[i] = '3';
@ -279,13 +314,13 @@ INTERNAL int c39(struct zint_symbol *symbol, unsigned char source[], const size_
expand(symbol, dest);
if (symbol->symbology == BARCODE_CODE39) {
strcpy((char*) symbol->text, "*");
strcat((char*) symbol->text, (char*) source);
strcat((char*) symbol->text, localstr);
strcat((char*) symbol->text, "*");
ustrcpy(symbol->text, "*");
ustrcat(symbol->text, source);
ustrcat(symbol->text, localstr);
ustrcat(symbol->text, "*");
} else {
strcpy((char*) symbol->text, (char*) source);
strcat((char*) symbol->text, localstr);
ustrcpy(symbol->text, source);
ustrcat(symbol->text, localstr);
}
return error_number;
}
@ -297,7 +332,6 @@ INTERNAL int pharmazentral(struct zint_symbol *symbol, unsigned char source[], i
unsigned int count, check_digit;
char localstr[11];
count = 0;
if (length > 7) {
strcpy(symbol->errtxt, "325: Input wrong length");
return ZINT_ERROR_TOO_LONG;
@ -312,54 +346,57 @@ INTERNAL int pharmazentral(struct zint_symbol *symbol, unsigned char source[], i
zeroes = 7 - length + 1;
for (i = 1; i < zeroes; i++)
localstr[i] = '0';
strcpy(localstr + zeroes, (char *) source);
ustrcpy(localstr + zeroes, source);
count = 0;
for (i = 1; i < 8; i++) {
count += i * ctoi(localstr[i]);
}
check_digit = count % 11;
if (check_digit == 11) {
check_digit = 0;
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("PZN: %s, check digit %d\n", localstr, check_digit);
}
localstr[8] = itoc(check_digit);
localstr[9] = '\0';
if (localstr[8] == 'A') {
if (check_digit == 10) {
strcpy(symbol->errtxt, "327: Invalid PZN Data");
return ZINT_ERROR_INVALID_DATA;
}
localstr[8] = itoc(check_digit);
localstr[9] = '\0';
error_number = c39(symbol, (unsigned char *) localstr, strlen(localstr));
ustrcpy(symbol->text, (unsigned char *) "PZN");
strcat((char*) symbol->text, localstr);
ustrcpy(symbol->text, "PZN ");
ustrcat(symbol->text, localstr);
return error_number;
}
/* Extended Code 39 - ISO/IEC 16388:2007 Annex A */
INTERNAL int ec39(struct zint_symbol *symbol, unsigned char source[], int length) {
unsigned char buffer[150] = {0};
unsigned int i;
unsigned char buffer[85 * 2 + 1] = {0};
int i;
int error_number;
if (length > 74) {
if (length > 85) {
strcpy(symbol->errtxt, "328: Input too long");
return ZINT_ERROR_TOO_LONG;
}
/* Creates a buffer string and places control characters into it */
for (i = 0; i < (unsigned int) length; i++) {
for (i = 0; i < length; i++) {
if (source[i] > 127) {
/* Cannot encode extended ASCII */
strcpy(symbol->errtxt, "329: Invalid characters in input data");
return ZINT_ERROR_INVALID_DATA;
}
strcat((char*) buffer, EC39Ctrl[source[i]]);
ustrcat(buffer, EC39Ctrl[source[i]]);
}
/* Then sends the buffer to the C39 function */
error_number = c39(symbol, buffer, ustrlen(buffer));
for (i = 0; i < (unsigned int) length; i++)
for (i = 0; i < length; i++)
symbol->text[i] = source[i] ? source[i] : ' ';
symbol->text[length] = '\0';
@ -587,8 +624,8 @@ INTERNAL int channel_code(struct zint_symbol *symbol, unsigned char source[], in
zeroes = 0;
}
memset(hrt, '0', zeroes);
strcpy(hrt + zeroes, (char *) source);
ustrcpy(symbol->text, (unsigned char *) hrt);
ustrcpy(hrt + zeroes, source);
ustrcpy(symbol->text, hrt);
expand(symbol, pattern);
@ -598,10 +635,9 @@ INTERNAL int channel_code(struct zint_symbol *symbol, unsigned char source[], in
/* Vehicle Identification Number (VIN) */
INTERNAL int vin(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) {
/* This code verifies the check digit present in North American VIN codes */
int zeros;
char local_source[18];
char dest[200];
char input_check;
@ -611,85 +647,80 @@ INTERNAL int vin(struct zint_symbol *symbol, const unsigned char source[], const
int sum;
int i;
int length = (int) in_length;
// Check length
if (length > 17) {
strcpy(symbol->errtxt, "336: Input too long");
if (length != 17) {
strcpy(symbol->errtxt, "336: Input wrong length, 17 characters required");
return ZINT_ERROR_TOO_LONG;
}
// Pad with zeros
zeros = 17 - length;
for (i = 0; i < 17; i++) {
local_source[i] = '0';
}
local_source[17] = '\0';
for (i = 0; i < length; i++) {
local_source[zeros + i] = source[i];
}
to_upper((unsigned char *) local_source);
// Check input characters, I, O and Q are not allowed
if (is_sane(ARSENIC, (unsigned char *) local_source, length) == ZINT_ERROR_INVALID_DATA) {
if (is_sane(ARSENIC, source, length) == ZINT_ERROR_INVALID_DATA) {
strcpy(symbol->errtxt, "337: Invalid characters in input data");
return ZINT_ERROR_INVALID_DATA;
}
input_check = local_source[8];
for (i = 0; i < 17; i++) {
if ((local_source[i] >= '0') && (local_source[i] <= '9')) {
value[i] = local_source[i] - '0';
ustrcpy(local_source, source);
to_upper((unsigned char *) local_source);
// Check digit only valid for North America
if (local_source[0] >= '1' && local_source[0] <= '5') {
input_check = local_source[8];
for (i = 0; i < 17; i++) {
if ((local_source[i] >= '0') && (local_source[i] <= '9')) {
value[i] = local_source[i] - '0';
} else if ((local_source[i] >= 'A') && (local_source[i] <= 'I')) {
value[i] = (local_source[i] - 'A') + 1;
} else if ((local_source[i] >= 'J') && (local_source[i] <= 'R')) {
value[i] = (local_source[i] - 'J') + 1;
} else if ((local_source[i] >= 'S') && (local_source[i] <= 'Z')) {
value[i] = (local_source[i] - 'S') + 2;
}
}
if ((local_source[i] >= 'A') && (local_source[i] <= 'I')) {
value[i] = (local_source[i] - 'A') + 1;
sum = 0;
for (i = 0; i < 17; i++) {
sum += value[i] * weight[i];
}
if ((local_source[i] >= 'J') && (local_source[i] <= 'R')) {
value[i] = (local_source[i] - 'J') + 1;
output_check = '0' + (sum % 11);
if (output_check == ':') {
// Check digit was 10
output_check = 'X';
}
if ((local_source[i] >= 'S') && (local_source[i] <= 'Z')) {
value[i] = (local_source[i] - 'S') + 2;
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("Producing VIN code: %s\n", local_source);
printf("Input check was %c, calculated check is %c\n", input_check, output_check);
}
if (input_check != output_check) {
strcpy(symbol->errtxt, "338: Invalid check digit in input data");
return ZINT_ERROR_INVALID_DATA;
}
}
sum = 0;
for (i = 0; i < 17; i++) {
sum += value[i] * weight[i];
}
output_check = '0' + (sum % 11);
if (output_check == ':') {
// Check digit was 10
output_check = 'X';
}
if (symbol->debug) {
printf("Producing VIN code: %s\n", local_source);
printf("Input check was %c, calculated check is %c\n", input_check, output_check);
}
if (input_check != output_check) {
strcpy(symbol->errtxt, "338: Invalid check digit in input data");
return ZINT_ERROR_INVALID_DATA;
}
/* Start character */
strcpy(dest, "1211212111");
/* Import character 'I' prefix? */
if (symbol->option_2 & 1) {
strcat(dest, "1121122111");
}
// Copy glyphs to symbol
for (i = 0; i < 17; i++) {
lookup(SILVER, C39Table, local_source[i], dest);
}
/* Stop character */
strcat(dest, "121121211");
ustrcpy(symbol->text, (unsigned char *) local_source);
ustrcpy(symbol->text, local_source);
expand(symbol, dest);
return 0;
}