mirror of
https://github.com/zint/zint
synced 2024-11-16 20:57:25 +13:00
CODEONE/ULTRA overrun fixes; TELEPEN fixes; CODEONE/LOGMARS/VIN/CODABAR options; GUI updates; tests
This commit is contained in:
305
backend/code.c
305
backend/code.c
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user