2009-01-08 11:43:25 +03:00
/* gs1.c - Verifies GS1 data */
/*
libzint - the open source barcode library
2016-02-20 12:38:03 +03:00
Copyright ( C ) 2009 - 2016 Robin Stuart < rstuart114 @ gmail . com >
2009-01-08 11:43:25 +03:00
2013-05-16 21:26:38 +04:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
3. Neither the name of the project nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
2016-02-20 12:38:03 +03:00
*/
2009-01-08 11:43:25 +03:00
# include <string.h>
# include <stdlib.h>
2009-01-11 10:42:10 +03:00
# include <stdio.h>
2009-06-03 00:23:38 +04:00
# ifdef _MSC_VER
# include <malloc.h>
# endif
2009-01-08 11:43:25 +03:00
# include "common.h"
2009-06-03 00:23:38 +04:00
# include "gs1.h"
2009-01-08 11:43:25 +03:00
2009-01-11 10:42:10 +03:00
/* This code does some checks on the integrity of GS1 data. It is not intended
to be bulletproof , nor does it report very accurately what problem was found
or where , but should prevent some of the more common encoding errors */
2016-02-20 12:38:03 +03:00
void itostr ( char ai_string [ ] , int ai_value ) {
int thou , hund , ten , unit ;
char temp [ 2 ] ;
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
strcpy ( ai_string , " ( " ) ;
thou = ai_value / 1000 ;
hund = ( ai_value - ( 1000 * thou ) ) / 100 ;
ten = ( ai_value - ( ( 1000 * thou ) + ( 100 * hund ) ) ) / 10 ;
unit = ai_value - ( ( 1000 * thou ) + ( 100 * hund ) + ( 10 * ten ) ) ;
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
temp [ 1 ] = ' \0 ' ;
if ( ai_value > = 1000 ) {
temp [ 0 ] = itoc ( thou ) ;
2016-03-03 00:12:38 +03:00
strcat ( ai_string , temp ) ;
2016-02-20 12:38:03 +03:00
}
if ( ai_value > = 100 ) {
temp [ 0 ] = itoc ( hund ) ;
2016-03-03 00:12:38 +03:00
strcat ( ai_string , temp ) ;
2016-02-20 12:38:03 +03:00
}
temp [ 0 ] = itoc ( ten ) ;
2016-03-03 00:12:38 +03:00
strcat ( ai_string , temp ) ;
2016-02-20 12:38:03 +03:00
temp [ 0 ] = itoc ( unit ) ;
2016-03-03 00:12:38 +03:00
strcat ( ai_string , temp ) ;
strcat ( ai_string , " ) " ) ;
2009-01-11 23:54:27 +03:00
}
2016-09-06 00:06:50 +03:00
int gs1_verify ( struct zint_symbol * symbol , const unsigned char source [ ] , const size_t src_len , char reduced [ ] ) {
2016-02-20 12:38:03 +03:00
int i , j , last_ai , ai_latch ;
char ai_string [ 6 ] ;
int bracket_level , max_bracket_level , ai_length , max_ai_length , min_ai_length ;
int ai_value [ 100 ] , ai_location [ 100 ] , ai_count , data_location [ 100 ] , data_length [ 100 ] ;
int error_latch ;
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
/* Detect extended ASCII characters */
for ( i = 0 ; i < src_len ; i + + ) {
if ( source [ i ] > = 128 ) {
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Extended ASCII characters are not supported by GS1 (B50) " ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
if ( source [ i ] < 32 ) {
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Control characters are not supported by GS1 (B51) " ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
if ( source [ 0 ] ! = ' [ ' ) {
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Data does not start with an AI (B52) " ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
/* Check the position of the brackets */
bracket_level = 0 ;
max_bracket_level = 0 ;
ai_length = 0 ;
max_ai_length = 0 ;
min_ai_length = 5 ;
j = 0 ;
ai_latch = 0 ;
for ( i = 0 ; i < src_len ; i + + ) {
ai_length + = j ;
if ( ( ( j = = 1 ) & & ( source [ i ] ! = ' ] ' ) ) & & ( ( source [ i ] < ' 0 ' ) | | ( source [ i ] > ' 9 ' ) ) ) {
ai_latch = 1 ;
}
if ( source [ i ] = = ' [ ' ) {
bracket_level + + ;
j = 1 ;
}
if ( source [ i ] = = ' ] ' ) {
bracket_level - - ;
if ( ai_length < min_ai_length ) {
min_ai_length = ai_length ;
}
j = 0 ;
ai_length = 0 ;
}
if ( bracket_level > max_bracket_level ) {
max_bracket_level = bracket_level ;
}
if ( ai_length > max_ai_length ) {
max_ai_length = ai_length ;
}
}
min_ai_length - - ;
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
if ( bracket_level ! = 0 ) {
/* Not all brackets are closed */
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Malformed AI in input data (brackets don \' t match) (B53) " ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
if ( max_bracket_level > 1 ) {
/* Nested brackets */
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Found nested brackets in input data (B54) " ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
if ( max_ai_length > 4 ) {
/* AI is too long */
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Invalid AI in input data (AI too long) (B55) " ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
if ( min_ai_length < = 1 ) {
/* AI is too short */
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Invalid AI in input data (AI too short) (B56) " ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
if ( ai_latch = = 1 ) {
/* Non-numeric data in AI */
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Invalid AI in input data (non-numeric characters in AI) (B57) " ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
ai_count = 0 ;
for ( i = 1 ; i < src_len ; i + + ) {
if ( source [ i - 1 ] = = ' [ ' ) {
ai_location [ ai_count ] = i ;
j = 0 ;
do {
ai_string [ j ] = source [ i + j ] ;
j + + ;
} while ( ai_string [ j - 1 ] ! = ' ] ' ) ;
ai_string [ j - 1 ] = ' \0 ' ;
ai_value [ ai_count ] = atoi ( ai_string ) ;
ai_count + + ;
}
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
for ( i = 0 ; i < ai_count ; i + + ) {
data_location [ i ] = ai_location [ i ] + 3 ;
if ( ai_value [ i ] > = 100 ) {
data_location [ i ] + + ;
}
if ( ai_value [ i ] > = 1000 ) {
data_location [ i ] + + ;
}
data_length [ i ] = 0 ;
do {
data_length [ i ] + + ;
} while ( ( source [ data_location [ i ] + data_length [ i ] - 1 ] ! = ' [ ' ) & & ( data_location [ i ] + data_length [ i ] < = src_len ) ) ;
data_length [ i ] - - ;
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
for ( i = 0 ; i < ai_count ; i + + ) {
if ( data_length [ i ] = = 0 ) {
/* No data for given AI */
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Empty data field in input data (B58) " ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
error_latch = 0 ;
strcpy ( ai_string , " " ) ;
for ( i = 0 ; i < ai_count ; i + + ) {
switch ( ai_value [ i ] ) {
case 0 : if ( data_length [ i ] ! = 18 ) {
error_latch = 1 ;
}
break ;
case 1 :
case 2 :
case 3 : if ( data_length [ i ] ! = 14 ) {
error_latch = 1 ;
}
break ;
case 4 : if ( data_length [ i ] ! = 16 ) {
error_latch = 1 ;
}
break ;
case 11 :
case 12 :
case 13 :
case 14 :
case 15 :
case 16 :
case 17 :
case 18 :
case 19 : if ( data_length [ i ] ! = 6 ) {
error_latch = 1 ;
}
break ;
case 20 : if ( data_length [ i ] ! = 2 ) {
error_latch = 1 ;
}
break ;
case 23 :
case 24 :
case 25 :
case 39 :
case 40 :
case 41 :
case 42 :
case 70 :
case 80 :
case 81 : error_latch = 2 ;
break ;
}
if (
( ( ai_value [ i ] > = 100 ) & & ( ai_value [ i ] < = 179 ) )
| | ( ( ai_value [ i ] > = 1000 ) & & ( ai_value [ i ] < = 1799 ) )
| | ( ( ai_value [ i ] > = 200 ) & & ( ai_value [ i ] < = 229 ) )
| | ( ( ai_value [ i ] > = 2000 ) & & ( ai_value [ i ] < = 2299 ) )
| | ( ( ai_value [ i ] > = 300 ) & & ( ai_value [ i ] < = 309 ) )
| | ( ( ai_value [ i ] > = 3000 ) & & ( ai_value [ i ] < = 3099 ) )
| | ( ( ai_value [ i ] > = 31 ) & & ( ai_value [ i ] < = 36 ) )
| | ( ( ai_value [ i ] > = 310 ) & & ( ai_value [ i ] < = 369 ) )
) {
error_latch = 2 ;
}
if ( ( ai_value [ i ] > = 3100 ) & & ( ai_value [ i ] < = 3699 ) ) {
if ( data_length [ i ] ! = 6 ) {
error_latch = 1 ;
}
}
if (
( ( ai_value [ i ] > = 370 ) & & ( ai_value [ i ] < = 379 ) )
| | ( ( ai_value [ i ] > = 3700 ) & & ( ai_value [ i ] < = 3799 ) )
) {
error_latch = 2 ;
}
if ( ( ai_value [ i ] > = 410 ) & & ( ai_value [ i ] < = 415 ) ) {
if ( data_length [ i ] ! = 13 ) {
error_latch = 1 ;
}
}
if (
( ( ai_value [ i ] > = 4100 ) & & ( ai_value [ i ] < = 4199 ) )
| | ( ( ai_value [ i ] > = 700 ) & & ( ai_value [ i ] < = 703 ) )
| | ( ( ai_value [ i ] > = 800 ) & & ( ai_value [ i ] < = 810 ) )
| | ( ( ai_value [ i ] > = 900 ) & & ( ai_value [ i ] < = 999 ) )
| | ( ( ai_value [ i ] > = 9000 ) & & ( ai_value [ i ] < = 9999 ) )
) {
error_latch = 2 ;
}
if ( ( error_latch < 4 ) & & ( error_latch > 0 ) ) {
/* error has just been detected: capture AI */
itostr ( ai_string , ai_value [ i ] ) ;
error_latch + = 4 ;
}
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
if ( error_latch = = 5 ) {
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Invalid data length for AI (B59) " ) ;
2016-03-03 00:12:38 +03:00
strcat ( symbol - > errtxt , ai_string ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
if ( error_latch = = 6 ) {
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " Invalid AI value (B60) " ) ;
2016-03-03 00:12:38 +03:00
strcat ( symbol - > errtxt , ai_string ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
2009-01-11 10:42:10 +03:00
2016-02-20 12:38:03 +03:00
/* Resolve AI data - put resulting string in 'reduced' */
j = 0 ;
last_ai = 0 ;
ai_latch = 1 ;
for ( i = 0 ; i < src_len ; i + + ) {
if ( ( source [ i ] ! = ' [ ' ) & & ( source [ i ] ! = ' ] ' ) ) {
reduced [ j + + ] = source [ i ] ;
}
if ( source [ i ] = = ' [ ' ) {
/* Start of an AI string */
if ( ai_latch = = 0 ) {
reduced [ j + + ] = ' [ ' ;
}
ai_string [ 0 ] = source [ i + 1 ] ;
ai_string [ 1 ] = source [ i + 2 ] ;
ai_string [ 2 ] = ' \0 ' ;
last_ai = atoi ( ai_string ) ;
ai_latch = 0 ;
/* The following values from "GS-1 General Specification version 8.0 issue 2, May 2008"
figure 5.4 .8 .2 .1 - 1 " Element Strings with Pre-Defined Length Using Application Identifiers " */
if (
( ( last_ai > = 0 ) & & ( last_ai < = 4 ) )
| | ( ( last_ai > = 11 ) & & ( last_ai < = 20 ) )
| | ( last_ai = = 23 ) /* legacy support - see 5.3.8.2.2 */
| | ( ( last_ai > = 31 ) & & ( last_ai < = 36 ) )
| | ( last_ai = = 41 )
) {
ai_latch = 1 ;
}
}
/* The ']' character is simply dropped from the input */
}
reduced [ j ] = ' \0 ' ;
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
/* the character '[' in the reduced string refers to the FNC1 character */
return 0 ;
2009-01-13 23:42:45 +03:00
}
2016-02-29 22:42:32 +03:00
int ugs1_verify ( struct zint_symbol * symbol , const unsigned char source [ ] , const unsigned int src_len , unsigned char reduced [ ] ) {
2016-02-20 12:38:03 +03:00
/* Only to keep the compiler happy */
2009-06-03 00:23:38 +04:00
# ifndef _MSC_VER
2016-02-20 12:38:03 +03:00
char temp [ src_len + 5 ] ;
2009-06-03 00:23:38 +04:00
# else
2016-02-20 12:38:03 +03:00
char * temp = ( char * ) _alloca ( src_len + 5 ) ;
2009-06-03 00:23:38 +04:00
# endif
2016-02-20 12:38:03 +03:00
int error_number ;
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
error_number = gs1_verify ( symbol , source , src_len , temp ) ;
if ( error_number ! = 0 ) {
return error_number ;
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
if ( strlen ( temp ) < src_len + 5 ) {
ustrcpy ( reduced , ( unsigned char * ) temp ) ;
return 0 ;
}
2016-10-29 00:40:40 +03:00
strcpy ( symbol - > errtxt , " ugs1_verify overflow (B61) " ) ;
2016-02-20 12:38:03 +03:00
return ZINT_ERROR_INVALID_DATA ;
2009-01-13 23:42:45 +03:00
}