2016-02-18 03:33:17 +13:00
/* composite.c - Handles GS1 Composite Symbols */
2008-07-14 09:15:55 +12:00
/*
libzint - the open source barcode library
2020-07-11 06:39:32 +12:00
Copyright ( C ) 2008 - 2020 Robin Stuart < rstuart114 @ gmail . com >
2013-05-17 05:26:38 +12:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
2016-02-20 22:38:03 +13:00
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2013-05-17 05:26:38 +12:00
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
2016-02-20 22:38:03 +13:00
documentation and / or other materials provided with the distribution .
2013-05-17 05:26:38 +12:00
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
2016-02-20 22:38:03 +13:00
without specific prior written permission .
2013-05-17 05:26:38 +12:00
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
2016-02-20 22:38:03 +13:00
OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
2013-05-17 05:26:38 +12:00
SUCH DAMAGE .
2016-02-20 22:38:03 +13:00
*/
2019-10-30 11:54:18 +13:00
/* vim: set ts=4 sw=4 et : */
2008-07-14 09:15:55 +12:00
/* The functions "getBit", "init928" and "encode928" are copyright BSI and are
released with permission under the following terms :
2013-01-01 02:41:59 +13:00
2008-07-14 09:15:55 +12:00
" Copyright subsists in all BSI publications. BSI also holds the copyright, in the
UK , of the international standardisation bodies . Except as
permitted under the Copyright , Designs and Patents Act 1988 no extract may be
reproduced , stored in a retrieval system or transmitted in any form or by any
means - electronic , photocopying , recording or otherwise - without prior written
permission from BSI .
2013-01-01 02:41:59 +13:00
2008-07-14 09:15:55 +12:00
" This does not preclude the free use, in the course of implementing the standard,
of necessary details such as symbols , and size , type or grade designations . If these
details are to be used for any other purpose than implementation then the prior
written permission of BSI must be obtained . "
2013-01-01 02:41:59 +13:00
2008-07-14 09:15:55 +12:00
The date of publication for these functions is 31 May 2006
2016-02-20 22:38:03 +13:00
*/
2008-07-14 09:15:55 +12:00
# include <stdio.h>
2017-07-22 01:16:23 +12:00
# include <assert.h>
2008-07-14 09:15:55 +12:00
# include <math.h>
2009-06-03 08:23:38 +12:00
# ifdef _MSC_VER
2016-02-20 22:38:03 +13:00
# include <malloc.h>
2009-06-03 08:23:38 +12:00
# endif
2008-07-14 09:15:55 +12:00
# include "common.h"
# include "pdf417.h"
2009-01-08 21:43:25 +13:00
# include "gs1.h"
2019-10-30 11:54:18 +13:00
# include "general_field.h"
2008-10-03 22:26:27 +13:00
2008-07-14 09:15:55 +12:00
# define UINT unsigned short
2020-07-11 06:39:32 +12:00
# include "composite.h"
2008-07-14 09:15:55 +12:00
2019-12-19 13:37:55 +13:00
INTERNAL int eanx ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) ;
INTERNAL int ean_128 ( struct zint_symbol * symbol , unsigned char source [ ] , const size_t length ) ;
2020-10-06 11:22:06 +13:00
INTERNAL void ean_leading_zeroes ( struct zint_symbol * symbol , unsigned char source [ ] , unsigned char local_source [ ] , int * p_with_addon ) ;
2019-12-19 13:37:55 +13:00
INTERNAL int rss14 ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) ;
INTERNAL int rsslimited ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) ;
INTERNAL int rssexpanded ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) ;
2008-07-14 09:15:55 +12:00
2017-05-29 21:43:47 +12:00
static int _min ( int first , int second ) {
2009-08-07 07:44:30 +12:00
2016-02-20 22:38:03 +13:00
if ( first < = second )
2009-08-07 07:44:30 +12:00
return first ;
2016-02-20 22:38:03 +13:00
else
2009-08-07 07:44:30 +12:00
return second ;
2008-07-14 09:15:55 +12:00
}
/* gets bit in bitString at bitPos */
2017-05-29 21:43:47 +12:00
static int getBit ( UINT * bitStr , int bitPos ) {
2016-02-20 22:38:03 +13:00
return ! ! ( bitStr [ bitPos > > 4 ] & ( 0x8000 > > ( bitPos & 15 ) ) ) ;
2008-07-14 09:15:55 +12:00
}
/* converts bit string to base 928 values, codeWords[0] is highest order */
2017-05-29 21:43:47 +12:00
static int encode928 ( UINT bitString [ ] , UINT codeWords [ ] , int bitLng ) {
2017-09-11 03:03:09 +12:00
int i , j , b , cwNdx , cwLng ;
2016-02-20 22:38:03 +13:00
for ( cwNdx = cwLng = b = 0 ; b < bitLng ; b + = 69 , cwNdx + = 7 ) {
2017-09-11 03:03:09 +12:00
int bitCnt = _min ( bitLng - b , 69 ) ;
int cwCnt ;
2016-02-20 22:38:03 +13:00
cwLng + = cwCnt = bitCnt / 10 + 1 ;
for ( i = 0 ; i < cwCnt ; i + + )
codeWords [ cwNdx + i ] = 0 ; /* init 0 */
for ( i = 0 ; i < bitCnt ; i + + ) {
if ( getBit ( bitString , b + bitCnt - i - 1 ) ) {
for ( j = 0 ; j < cwCnt ; j + + )
codeWords [ cwNdx + j ] + = pwr928 [ i ] [ j + 7 - cwCnt ] ;
}
}
for ( i = cwCnt - 1 ; i > 0 ; i - - ) {
/* add "carries" */
codeWords [ cwNdx + i - 1 ] + = codeWords [ cwNdx + i ] / 928L ;
codeWords [ cwNdx + i ] % = 928L ;
}
}
return ( cwLng ) ;
2008-07-14 09:15:55 +12:00
}
2016-02-20 22:38:03 +13:00
/* CC-A 2D component */
2017-10-24 08:37:52 +13:00
static int cc_a ( struct zint_symbol * symbol , char source [ ] , int cc_width ) {
2017-09-11 03:03:09 +12:00
int i , segment , bitlen , cwCnt , variant , rows ;
2016-02-20 22:38:03 +13:00
int k , offset , j , total , rsCodeWords [ 8 ] ;
int LeftRAPStart , RightRAPStart , CentreRAPStart , StartCluster ;
int LeftRAP , RightRAP , CentreRAP , Cluster , dummy [ 5 ] ;
2017-06-10 09:00:22 +12:00
int loop ;
2016-02-20 22:38:03 +13:00
UINT codeWords [ 28 ] ;
UINT bitStr [ 13 ] ;
2017-06-10 09:00:22 +12:00
char pattern [ 580 ] ;
2016-02-20 22:38:03 +13:00
char local_source [ 210 ] ; /* A copy of source but with padding zeroes to make 208 bits */
variant = 0 ;
for ( i = 0 ; i < 13 ; i + + ) {
bitStr [ i ] = 0 ;
}
for ( i = 0 ; i < 28 ; i + + ) {
codeWords [ i ] = 0 ;
}
2019-10-15 10:20:16 +13:00
bitlen = ( int ) strlen ( source ) ;
2016-02-20 22:38:03 +13:00
for ( i = 0 ; i < 208 ; i + + ) {
local_source [ i ] = ' 0 ' ;
}
for ( i = 0 ; i < bitlen ; i + + ) {
local_source [ i ] = source [ i ] ;
}
local_source [ 208 ] = ' \0 ' ;
for ( segment = 0 ; segment < 13 ; segment + + ) {
2017-09-11 03:03:09 +12:00
int strpos = segment * 16 ;
2016-02-20 22:38:03 +13:00
for ( i = 0 ; i < 16 ; i + + ) {
if ( local_source [ strpos + i ] = = ' 1 ' ) {
bitStr [ segment ] + = ( 0x8000 > > i ) ;
}
}
}
/* encode codeWords from bitStr */
cwCnt = encode928 ( bitStr , codeWords , bitlen ) ;
switch ( cc_width ) {
case 2 :
switch ( cwCnt ) {
case 6 : variant = 0 ;
break ;
case 8 : variant = 1 ;
break ;
case 9 : variant = 2 ;
break ;
case 11 : variant = 3 ;
break ;
case 12 : variant = 4 ;
break ;
case 14 : variant = 5 ;
break ;
case 17 : variant = 6 ;
break ;
}
break ;
case 3 :
switch ( cwCnt ) {
case 8 : variant = 7 ;
break ;
case 10 : variant = 8 ;
break ;
case 12 : variant = 9 ;
break ;
case 14 : variant = 10 ;
break ;
case 17 : variant = 11 ;
break ;
}
break ;
case 4 :
switch ( cwCnt ) {
case 8 : variant = 12 ;
break ;
case 11 : variant = 13 ;
break ;
case 14 : variant = 14 ;
break ;
case 17 : variant = 15 ;
break ;
case 20 : variant = 16 ;
break ;
}
break ;
}
rows = ccaVariants [ variant ] ;
k = ccaVariants [ 17 + variant ] ;
offset = ccaVariants [ 34 + variant ] ;
/* Reed-Solomon error correction */
for ( i = 0 ; i < 8 ; i + + ) {
rsCodeWords [ i ] = 0 ;
}
for ( i = 0 ; i < cwCnt ; i + + ) {
total = ( codeWords [ i ] + rsCodeWords [ k - 1 ] ) % 929 ;
for ( j = k - 1 ; j > = 0 ; j - - ) {
if ( j = = 0 ) {
rsCodeWords [ j ] = ( 929 - ( total * ccaCoeffs [ offset + j ] ) % 929 ) % 929 ;
} else {
rsCodeWords [ j ] = ( rsCodeWords [ j - 1 ] + 929 - ( total * ccaCoeffs [ offset + j ] ) % 929 ) % 929 ;
}
}
}
for ( j = 0 ; j < k ; j + + ) {
if ( rsCodeWords [ j ] ! = 0 ) {
rsCodeWords [ j ] = 929 - rsCodeWords [ j ] ;
}
}
for ( i = k - 1 ; i > = 0 ; i - - ) {
codeWords [ cwCnt ] = rsCodeWords [ i ] ;
cwCnt + + ;
}
/* Place data into table */
LeftRAPStart = aRAPTable [ variant ] ;
CentreRAPStart = aRAPTable [ variant + 17 ] ;
RightRAPStart = aRAPTable [ variant + 34 ] ;
StartCluster = aRAPTable [ variant + 51 ] / 3 ;
LeftRAP = LeftRAPStart ;
CentreRAP = CentreRAPStart ;
RightRAP = RightRAPStart ;
Cluster = StartCluster ; /* Cluster can be 0, 1 or 2 for Cluster(0), Cluster(3) and Cluster(6) */
for ( i = 0 ; i < rows ; i + + ) {
2017-06-10 09:00:22 +12:00
strcpy ( pattern , " " ) ;
2016-02-20 22:38:03 +13:00
offset = 929 * Cluster ;
for ( j = 0 ; j < 5 ; j + + ) {
dummy [ j ] = 0 ;
}
for ( j = 0 ; j < cc_width ; j + + ) {
dummy [ j + 1 ] = codeWords [ i * cc_width + j ] ;
}
/* Copy the data into codebarre */
2019-10-05 23:08:58 +13:00
if ( cc_width ! = 3 ) {
bin_append ( rap_side [ LeftRAP - 1 ] , 10 , pattern ) ;
}
2017-06-10 09:00:22 +12:00
bin_append ( pdf_bitpattern [ offset + dummy [ 1 ] ] , 16 , pattern ) ;
strcat ( pattern , " 0 " ) ;
2016-02-20 22:38:03 +13:00
if ( cc_width = = 3 ) {
2017-06-10 09:00:22 +12:00
bin_append ( rap_centre [ CentreRAP - 1 ] , 10 , pattern ) ;
2016-02-20 22:38:03 +13:00
}
if ( cc_width > = 2 ) {
2017-06-10 09:00:22 +12:00
bin_append ( pdf_bitpattern [ offset + dummy [ 2 ] ] , 16 , pattern ) ;
strcat ( pattern , " 0 " ) ;
2016-02-20 22:38:03 +13:00
}
if ( cc_width = = 4 ) {
2017-06-10 09:00:22 +12:00
bin_append ( rap_centre [ CentreRAP - 1 ] , 10 , pattern ) ;
2016-02-20 22:38:03 +13:00
}
if ( cc_width > = 3 ) {
2017-06-10 09:00:22 +12:00
bin_append ( pdf_bitpattern [ offset + dummy [ 3 ] ] , 16 , pattern ) ;
strcat ( pattern , " 0 " ) ;
2016-02-20 22:38:03 +13:00
}
if ( cc_width = = 4 ) {
2017-06-10 09:00:22 +12:00
bin_append ( pdf_bitpattern [ offset + dummy [ 4 ] ] , 16 , pattern ) ;
strcat ( pattern , " 0 " ) ;
2016-02-20 22:38:03 +13:00
}
2017-06-10 09:00:22 +12:00
bin_append ( rap_side [ RightRAP - 1 ] , 10 , pattern ) ;
strcat ( pattern , " 1 " ) ; /* stop */
2016-02-20 22:38:03 +13:00
/* so now pattern[] holds the string of '1's and '0's. - copy this to the symbol */
2016-03-01 08:42:32 +13:00
for ( loop = 0 ; loop < ( int ) strlen ( pattern ) ; loop + + ) {
2016-02-20 22:38:03 +13:00
if ( pattern [ loop ] = = ' 1 ' ) {
set_module ( symbol , i , loop ) ;
}
}
symbol - > row_height [ i ] = 2 ;
symbol - > rows + + ;
2017-06-10 09:00:22 +12:00
symbol - > width = strlen ( pattern ) ;
2016-02-20 22:38:03 +13:00
/* Set up RAPs and Cluster for next row */
LeftRAP + + ;
CentreRAP + + ;
RightRAP + + ;
Cluster + + ;
if ( LeftRAP = = 53 ) {
LeftRAP = 1 ;
}
if ( CentreRAP = = 53 ) {
CentreRAP = 1 ;
}
if ( RightRAP = = 53 ) {
RightRAP = 1 ;
}
if ( Cluster = = 3 ) {
Cluster = 0 ;
}
}
2020-07-11 06:39:32 +12:00
if ( symbol - > debug & ZINT_DEBUG_PRINT ) {
printf ( " CC-A Columns: %d, Rows: %d \n " , cc_width , symbol - > rows ) ;
}
2016-02-20 22:38:03 +13:00
return 0 ;
2008-07-14 09:15:55 +12:00
}
2016-02-20 22:38:03 +13:00
/* CC-B 2D component */
2017-10-24 08:37:52 +13:00
static int cc_b ( struct zint_symbol * symbol , char source [ ] , int cc_width ) {
2017-09-11 03:03:09 +12:00
int length , i ;
2009-06-03 08:23:38 +12:00
# ifndef _MSC_VER
2016-02-20 22:38:03 +13:00
unsigned char data_string [ ( strlen ( source ) / 8 ) + 3 ] ;
2009-06-03 08:23:38 +12:00
# else
2020-07-11 06:39:32 +12:00
unsigned char * data_string = ( unsigned char * ) _alloca ( ( strlen ( source ) / 8 ) + 3 ) ;
2009-06-03 08:23:38 +12:00
# endif
2016-02-20 22:38:03 +13:00
int chainemc [ 180 ] , mclength ;
2016-02-24 08:21:48 +13:00
int k , j , p , longueur , mccorrection [ 50 ] , offset ;
2016-02-20 22:38:03 +13:00
int total , dummy [ 5 ] ;
2017-06-10 09:00:22 +12:00
char pattern [ 580 ] ;
2016-02-20 22:38:03 +13:00
int variant , LeftRAPStart , CentreRAPStart , RightRAPStart , StartCluster ;
2017-06-10 09:00:22 +12:00
int LeftRAP , CentreRAP , RightRAP , Cluster , loop ;
2020-07-16 06:00:12 +12:00
int columns ;
2016-02-20 22:38:03 +13:00
length = strlen ( source ) / 8 ;
for ( i = 0 ; i < length ; i + + ) {
2017-09-11 03:03:09 +12:00
int binloc = i * 8 ;
2016-02-20 22:38:03 +13:00
data_string [ i ] = 0 ;
2016-02-24 08:21:48 +13:00
for ( p = 0 ; p < 8 ; p + + ) {
2016-02-20 22:38:03 +13:00
if ( source [ binloc + p ] = = ' 1 ' ) {
data_string [ i ] + = ( 0x80 > > p ) ;
}
}
}
mclength = 0 ;
/* "the CC-B component shall have codeword 920 in the first symbol character position" (section 9a) */
chainemc [ mclength ] = 920 ;
mclength + + ;
2020-07-18 03:39:01 +12:00
byteprocess ( chainemc , & mclength , data_string , 0 , length , symbol - > debug & ZINT_DEBUG_PRINT ) ;
2016-02-20 22:38:03 +13:00
/* Now figure out which variant of the symbol to use and load values accordingly */
variant = 0 ;
if ( cc_width = = 2 ) {
variant = 13 ;
if ( mclength < = 33 ) {
variant = 12 ;
}
if ( mclength < = 29 ) {
variant = 11 ;
}
if ( mclength < = 24 ) {
variant = 10 ;
}
if ( mclength < = 19 ) {
variant = 9 ;
}
if ( mclength < = 13 ) {
variant = 8 ;
}
if ( mclength < = 8 ) {
variant = 7 ;
}
}
if ( cc_width = = 3 ) {
variant = 23 ;
if ( mclength < = 70 ) {
variant = 22 ;
}
if ( mclength < = 58 ) {
variant = 21 ;
}
if ( mclength < = 46 ) {
variant = 20 ;
}
if ( mclength < = 34 ) {
variant = 19 ;
}
if ( mclength < = 24 ) {
variant = 18 ;
}
if ( mclength < = 18 ) {
variant = 17 ;
}
if ( mclength < = 14 ) {
variant = 16 ;
}
if ( mclength < = 10 ) {
variant = 15 ;
}
if ( mclength < = 6 ) {
variant = 14 ;
}
}
if ( cc_width = = 4 ) {
variant = 34 ;
if ( mclength < = 108 ) {
variant = 33 ;
}
if ( mclength < = 90 ) {
variant = 32 ;
}
if ( mclength < = 72 ) {
variant = 31 ;
}
if ( mclength < = 54 ) {
variant = 30 ;
}
if ( mclength < = 39 ) {
variant = 29 ;
}
if ( mclength < = 30 ) {
variant = 28 ;
}
if ( mclength < = 24 ) {
variant = 27 ;
}
if ( mclength < = 18 ) {
variant = 26 ;
}
if ( mclength < = 12 ) {
variant = 25 ;
}
if ( mclength < = 8 ) {
variant = 24 ;
}
}
/* Now we have the variant we can load the data - from here on the same as MicroPDF417 code */
variant - - ;
2017-06-29 07:46:29 +12:00
assert ( variant > = 0 ) ;
2020-07-16 06:00:12 +12:00
columns = MicroVariants [ variant ] ; /* columns */
2016-02-20 22:38:03 +13:00
symbol - > rows = MicroVariants [ variant + 34 ] ; /* rows */
k = MicroVariants [ variant + 68 ] ; /* number of EC CWs */
2020-07-16 06:00:12 +12:00
longueur = ( columns * symbol - > rows ) - k ; /* number of non-EC CWs */
2016-02-20 22:38:03 +13:00
i = longueur - mclength ; /* amount of padding required */
offset = MicroVariants [ variant + 102 ] ; /* coefficient offset */
/* We add the padding */
while ( i > 0 ) {
chainemc [ mclength ] = 900 ;
mclength + + ;
i - - ;
}
/* Reed-Solomon error correction */
longueur = mclength ;
for ( loop = 0 ; loop < 50 ; loop + + ) {
mccorrection [ loop ] = 0 ;
}
for ( i = 0 ; i < longueur ; i + + ) {
total = ( chainemc [ i ] + mccorrection [ k - 1 ] ) % 929 ;
for ( j = k - 1 ; j > = 0 ; j - - ) {
if ( j = = 0 ) {
mccorrection [ j ] = ( 929 - ( total * Microcoeffs [ offset + j ] ) % 929 ) % 929 ;
} else {
mccorrection [ j ] = ( mccorrection [ j - 1 ] + 929 - ( total * Microcoeffs [ offset + j ] ) % 929 ) % 929 ;
}
}
}
for ( j = 0 ; j < k ; j + + ) {
if ( mccorrection [ j ] ! = 0 ) {
mccorrection [ j ] = 929 - mccorrection [ j ] ;
}
}
/* we add these codes to the string */
for ( i = k - 1 ; i > = 0 ; i - - ) {
chainemc [ mclength ] = mccorrection [ i ] ;
mclength + + ;
}
/* Now get the RAP (Row Address Pattern) start values */
LeftRAPStart = RAPTable [ variant ] ;
CentreRAPStart = RAPTable [ variant + 34 ] ;
RightRAPStart = RAPTable [ variant + 68 ] ;
StartCluster = RAPTable [ variant + 102 ] / 3 ;
/* That's all values loaded, get on with the encoding */
LeftRAP = LeftRAPStart ;
CentreRAP = CentreRAPStart ;
RightRAP = RightRAPStart ;
Cluster = StartCluster ;
/* Cluster can be 0, 1 or 2 for Cluster(0), Cluster(3) and Cluster(6) */
for ( i = 0 ; i < symbol - > rows ; i + + ) {
2017-06-10 09:00:22 +12:00
strcpy ( pattern , " " ) ;
2016-02-20 22:38:03 +13:00
offset = 929 * Cluster ;
for ( j = 0 ; j < 5 ; j + + ) {
dummy [ j ] = 0 ;
}
2020-07-16 06:00:12 +12:00
for ( j = 0 ; j < columns ; j + + ) {
dummy [ j + 1 ] = chainemc [ i * columns + j ] ;
2016-02-20 22:38:03 +13:00
}
/* Copy the data into codebarre */
2017-06-10 09:00:22 +12:00
bin_append ( rap_side [ LeftRAP - 1 ] , 10 , pattern ) ;
bin_append ( pdf_bitpattern [ offset + dummy [ 1 ] ] , 16 , pattern ) ;
strcat ( pattern , " 0 " ) ;
2016-02-20 22:38:03 +13:00
if ( cc_width = = 3 ) {
2017-06-10 09:00:22 +12:00
bin_append ( rap_centre [ CentreRAP - 1 ] , 10 , pattern ) ;
2016-02-20 22:38:03 +13:00
}
if ( cc_width > = 2 ) {
2017-06-10 09:00:22 +12:00
bin_append ( pdf_bitpattern [ offset + dummy [ 2 ] ] , 16 , pattern ) ;
strcat ( pattern , " 0 " ) ;
2016-02-20 22:38:03 +13:00
}
if ( cc_width = = 4 ) {
2017-06-10 09:00:22 +12:00
bin_append ( rap_centre [ CentreRAP - 1 ] , 10 , pattern ) ;
2016-02-20 22:38:03 +13:00
}
if ( cc_width > = 3 ) {
2017-06-10 09:00:22 +12:00
bin_append ( pdf_bitpattern [ offset + dummy [ 3 ] ] , 16 , pattern ) ;
strcat ( pattern , " 0 " ) ;
2016-02-20 22:38:03 +13:00
}
if ( cc_width = = 4 ) {
2017-06-10 09:00:22 +12:00
bin_append ( pdf_bitpattern [ offset + dummy [ 4 ] ] , 16 , pattern ) ;
strcat ( pattern , " 0 " ) ;
2016-02-20 22:38:03 +13:00
}
2017-06-10 09:00:22 +12:00
bin_append ( rap_side [ RightRAP - 1 ] , 10 , pattern ) ;
strcat ( pattern , " 1 " ) ; /* stop */
2016-02-20 22:38:03 +13:00
/* so now pattern[] holds the string of '1's and '0's. - copy this to the symbol */
2016-03-01 08:42:32 +13:00
for ( loop = 0 ; loop < ( int ) strlen ( pattern ) ; loop + + ) {
2016-02-20 22:38:03 +13:00
if ( pattern [ loop ] = = ' 1 ' ) {
set_module ( symbol , i , loop ) ;
}
}
symbol - > row_height [ i ] = 2 ;
2017-06-10 09:00:22 +12:00
symbol - > width = strlen ( pattern ) ;
2016-02-20 22:38:03 +13:00
/* Set up RAPs and Cluster for next row */
LeftRAP + + ;
CentreRAP + + ;
RightRAP + + ;
Cluster + + ;
if ( LeftRAP = = 53 ) {
LeftRAP = 1 ;
}
if ( CentreRAP = = 53 ) {
CentreRAP = 1 ;
}
if ( RightRAP = = 53 ) {
RightRAP = 1 ;
}
if ( Cluster = = 3 ) {
Cluster = 0 ;
}
}
2020-07-11 06:39:32 +12:00
if ( symbol - > debug & ZINT_DEBUG_PRINT ) {
printf ( " CC-B Columns: %d, Rows: %d \n " , cc_width , symbol - > rows ) ;
}
2016-02-20 22:38:03 +13:00
return 0 ;
2008-07-14 09:15:55 +12:00
}
2016-02-20 22:38:03 +13:00
/* CC-C 2D component - byte compressed PDF417 */
2017-10-24 08:37:52 +13:00
static int cc_c ( struct zint_symbol * symbol , char source [ ] , int cc_width , int ecc_level ) {
2017-09-11 03:03:09 +12:00
int length , i , p ;
2009-06-03 08:23:38 +12:00
# ifndef _MSC_VER
2016-02-20 22:38:03 +13:00
unsigned char data_string [ ( strlen ( source ) / 8 ) + 4 ] ;
2009-06-03 08:23:38 +12:00
# else
2020-07-11 06:39:32 +12:00
unsigned char * data_string = ( unsigned char * ) _alloca ( ( strlen ( source ) / 8 ) + 4 ) ;
2009-06-03 08:23:38 +12:00
# endif
2016-02-20 22:38:03 +13:00
int chainemc [ 1000 ] , mclength , k ;
int offset , longueur , loop , total , j , mccorrection [ 520 ] ;
int c1 , c2 , c3 , dummy [ 35 ] ;
2017-06-10 09:00:22 +12:00
char pattern [ 580 ] ;
2016-02-20 22:38:03 +13:00
length = strlen ( source ) / 8 ;
for ( i = 0 ; i < length ; i + + ) {
2017-09-11 03:03:09 +12:00
int binloc = i * 8 ;
2016-02-20 22:38:03 +13:00
data_string [ i ] = 0 ;
2016-02-24 08:21:48 +13:00
for ( p = 0 ; p < 8 ; p + + ) {
2016-02-20 22:38:03 +13:00
if ( source [ binloc + p ] = = ' 1 ' ) {
data_string [ i ] + = ( 0x80 > > p ) ;
}
}
}
mclength = 0 ;
chainemc [ mclength ] = 0 ; /* space for length descriptor */
mclength + + ;
chainemc [ mclength ] = 920 ; /* CC-C identifier */
mclength + + ;
2020-07-18 03:39:01 +12:00
byteprocess ( chainemc , & mclength , data_string , 0 , length , symbol - > debug & ZINT_DEBUG_PRINT ) ;
2016-02-20 22:38:03 +13:00
chainemc [ 0 ] = mclength ;
k = 1 ;
for ( i = 1 ; i < = ( ecc_level + 1 ) ; i + + ) {
k * = 2 ;
}
/* 796 - we now take care of the Reed Solomon codes */
switch ( ecc_level ) {
case 1 : offset = 2 ;
break ;
case 2 : offset = 6 ;
break ;
case 3 : offset = 14 ;
break ;
case 4 : offset = 30 ;
break ;
case 5 : offset = 62 ;
break ;
case 6 : offset = 126 ;
break ;
case 7 : offset = 254 ;
break ;
case 8 : offset = 510 ;
break ;
default : offset = 0 ;
break ;
}
longueur = mclength ;
for ( loop = 0 ; loop < 520 ; loop + + ) {
mccorrection [ loop ] = 0 ;
}
for ( i = 0 ; i < longueur ; i + + ) {
total = ( chainemc [ i ] + mccorrection [ k - 1 ] ) % 929 ;
for ( j = k - 1 ; j > = 0 ; j - - ) {
if ( j = = 0 ) {
mccorrection [ j ] = ( 929 - ( total * coefrs [ offset + j ] ) % 929 ) % 929 ;
} else {
mccorrection [ j ] = ( mccorrection [ j - 1 ] + 929 - ( total * coefrs [ offset + j ] ) % 929 ) % 929 ;
}
}
}
for ( j = 0 ; j < k ; j + + ) {
if ( mccorrection [ j ] ! = 0 ) {
mccorrection [ j ] = 929 - mccorrection [ j ] ;
}
}
/* we add these codes to the string */
for ( i = k - 1 ; i > = 0 ; i - - ) {
chainemc [ mclength ] = mccorrection [ i ] ;
mclength + + ;
}
/* 818 - The CW string is finished */
c1 = ( mclength / cc_width - 1 ) / 3 ;
c2 = ecc_level * 3 + ( mclength / cc_width - 1 ) % 3 ;
c3 = cc_width - 1 ;
/* we now encode each row */
for ( i = 0 ; i < = ( mclength / cc_width ) - 1 ; i + + ) {
for ( j = 0 ; j < cc_width ; j + + ) {
dummy [ j + 1 ] = chainemc [ i * cc_width + j ] ;
}
k = ( i / 3 ) * 30 ;
switch ( i % 3 ) {
case 0 :
dummy [ 0 ] = k + c1 ;
dummy [ cc_width + 1 ] = k + c3 ;
2017-06-10 09:00:22 +12:00
offset = 0 ; /* cluster(0) */
2016-02-20 22:38:03 +13:00
break ;
case 1 :
dummy [ 0 ] = k + c2 ;
dummy [ cc_width + 1 ] = k + c1 ;
2017-06-10 09:00:22 +12:00
offset = 929 ; /* cluster(3) */
2016-02-20 22:38:03 +13:00
break ;
case 2 :
dummy [ 0 ] = k + c3 ;
dummy [ cc_width + 1 ] = k + c2 ;
2017-06-10 09:00:22 +12:00
offset = 1858 ; /* cluster(6) */
2016-02-20 22:38:03 +13:00
break ;
}
2017-06-10 09:00:22 +12:00
strcpy ( pattern , " " ) ;
bin_append ( 0x1FEA8 , 17 , pattern ) ; /* Row start */
2016-02-20 22:38:03 +13:00
for ( j = 0 ; j < = cc_width + 1 ; j + + ) {
2017-06-10 09:00:22 +12:00
bin_append ( pdf_bitpattern [ offset + dummy [ j ] ] , 16 , pattern ) ;
strcat ( pattern , " 0 " ) ;
2016-02-20 22:38:03 +13:00
}
2017-06-10 09:00:22 +12:00
bin_append ( 0x3FA29 , 18 , pattern ) ; /* Row Stop */
2016-02-20 22:38:03 +13:00
2016-03-01 08:42:32 +13:00
for ( loop = 0 ; loop < ( int ) strlen ( pattern ) ; loop + + ) {
2016-02-20 22:38:03 +13:00
if ( pattern [ loop ] = = ' 1 ' ) {
set_module ( symbol , i , loop ) ;
}
}
symbol - > row_height [ i ] = 3 ;
}
symbol - > rows = ( mclength / cc_width ) ;
2017-05-29 21:43:47 +12:00
symbol - > width = ( int ) strlen ( pattern ) ;
2016-02-20 22:38:03 +13:00
2020-07-11 06:39:32 +12:00
if ( symbol - > debug & ZINT_DEBUG_PRINT ) {
printf ( " CC-C Columns: %d, Rows: %d \n " , cc_width , symbol - > rows ) ;
}
2016-02-20 22:38:03 +13:00
return 0 ;
2008-07-14 09:15:55 +12:00
}
2017-05-29 21:43:47 +12:00
static int calc_padding_cca ( int binary_length , int cc_width ) {
2016-09-25 23:09:20 +13:00
int target_bitsize = 0 ;
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
switch ( cc_width ) {
case 2 :
if ( binary_length < = 167 ) {
target_bitsize = 167 ;
}
if ( binary_length < = 138 ) {
target_bitsize = 138 ;
}
if ( binary_length < = 118 ) {
target_bitsize = 118 ;
}
if ( binary_length < = 108 ) {
target_bitsize = 108 ;
}
if ( binary_length < = 88 ) {
target_bitsize = 88 ;
}
if ( binary_length < = 78 ) {
target_bitsize = 78 ;
}
if ( binary_length < = 59 ) {
target_bitsize = 59 ;
}
break ;
case 3 :
if ( binary_length < = 167 ) {
target_bitsize = 167 ;
}
if ( binary_length < = 138 ) {
target_bitsize = 138 ;
}
if ( binary_length < = 118 ) {
target_bitsize = 118 ;
}
if ( binary_length < = 98 ) {
target_bitsize = 98 ;
}
if ( binary_length < = 78 ) {
target_bitsize = 78 ;
}
break ;
case 4 :
if ( binary_length < = 197 ) {
target_bitsize = 197 ;
}
if ( binary_length < = 167 ) {
target_bitsize = 167 ;
}
if ( binary_length < = 138 ) {
target_bitsize = 138 ;
}
if ( binary_length < = 108 ) {
target_bitsize = 108 ;
}
if ( binary_length < = 78 ) {
target_bitsize = 78 ;
}
break ;
2020-07-11 06:39:32 +12:00
}
2017-10-24 08:37:52 +13:00
2020-07-11 06:39:32 +12:00
return target_bitsize ;
2016-09-25 23:09:20 +13:00
}
2019-12-19 13:37:55 +13:00
static int calc_padding_ccb ( int binary_length , int cc_width ) {
2016-09-25 23:09:20 +13:00
int target_bitsize = 0 ;
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
switch ( cc_width ) {
case 2 :
if ( binary_length < = 336 ) {
target_bitsize = 336 ;
}
if ( binary_length < = 296 ) {
target_bitsize = 296 ;
}
if ( binary_length < = 256 ) {
target_bitsize = 256 ;
}
if ( binary_length < = 208 ) {
target_bitsize = 208 ;
}
if ( binary_length < = 160 ) {
target_bitsize = 160 ;
}
if ( binary_length < = 104 ) {
target_bitsize = 104 ;
}
if ( binary_length < = 56 ) {
target_bitsize = 56 ;
}
break ;
case 3 :
if ( binary_length < = 768 ) {
target_bitsize = 768 ;
}
if ( binary_length < = 648 ) {
target_bitsize = 648 ;
}
if ( binary_length < = 536 ) {
target_bitsize = 536 ;
}
if ( binary_length < = 416 ) {
target_bitsize = 416 ;
}
if ( binary_length < = 304 ) {
target_bitsize = 304 ;
}
if ( binary_length < = 208 ) {
target_bitsize = 208 ;
}
if ( binary_length < = 152 ) {
target_bitsize = 152 ;
}
if ( binary_length < = 112 ) {
target_bitsize = 112 ;
}
if ( binary_length < = 72 ) {
target_bitsize = 72 ;
}
if ( binary_length < = 32 ) {
target_bitsize = 32 ;
}
break ;
case 4 :
if ( binary_length < = 1184 ) {
target_bitsize = 1184 ;
}
if ( binary_length < = 1016 ) {
target_bitsize = 1016 ;
}
if ( binary_length < = 840 ) {
target_bitsize = 840 ;
}
if ( binary_length < = 672 ) {
target_bitsize = 672 ;
}
if ( binary_length < = 496 ) {
target_bitsize = 496 ;
}
if ( binary_length < = 352 ) {
target_bitsize = 352 ;
}
if ( binary_length < = 264 ) {
target_bitsize = 264 ;
}
if ( binary_length < = 208 ) {
target_bitsize = 208 ;
}
if ( binary_length < = 152 ) {
target_bitsize = 152 ;
}
if ( binary_length < = 96 ) {
target_bitsize = 96 ;
}
if ( binary_length < = 56 ) {
target_bitsize = 56 ;
}
break ;
}
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
return target_bitsize ;
}
2019-12-19 13:37:55 +13:00
static int calc_padding_ccc ( int binary_length , int * cc_width , int lin_width , int * ecc ) {
2016-09-25 23:09:20 +13:00
int target_bitsize = 0 ;
int byte_length , codewords_used , ecc_level , ecc_codewords , rows ;
int codewords_total , target_codewords , target_bytesize ;
byte_length = binary_length / 8 ;
if ( binary_length % 8 ! = 0 ) {
byte_length + + ;
}
codewords_used = ( byte_length / 6 ) * 5 ;
codewords_used + = byte_length % 6 ;
2019-11-06 03:16:48 +13:00
/* Recommended minimum ecc levels ISO/IEC 1543:2015 (PDF417) Annex E Table E.1,
restricted by CC - C codeword max 900 ( 30 cols * 30 rows ) , GS1 General Specifications 19.1 5.9 .2 .3 */
2016-09-25 23:09:20 +13:00
if ( codewords_used < = 40 ) {
ecc_level = 2 ;
2019-11-06 03:16:48 +13:00
} else if ( codewords_used < = 160 ) {
ecc_level = 3 ;
} else if ( codewords_used < = 320 ) {
ecc_level = 4 ;
} else if ( codewords_used < = 833 ) { /* 900 - 3 - 64 */
ecc_level = 5 ;
} else if ( codewords_used < = 865 ) { /* 900 - 3 - 32 */
ecc_level = 4 ; /* Not recommended but allow to meet advertised "up to 2361 digits" (allows max 2372) */
} else {
return 0 ;
2016-09-25 23:09:20 +13:00
}
* ( ecc ) = ecc_level ;
2019-11-06 03:16:48 +13:00
ecc_codewords = 1 < < ( ecc_level + 1 ) ;
2016-09-25 23:09:20 +13:00
codewords_used + = ecc_codewords ;
codewords_used + = 3 ;
2019-11-06 03:16:48 +13:00
* ( cc_width ) = ( lin_width - 53 ) / 17 ; // -53 = (6 left quiet zone + 10 right quiet zone - (17 * 3 + 18))
if ( * ( cc_width ) > 30 ) {
* ( cc_width ) = 30 ;
}
rows = ceil ( ( double ) codewords_used / * ( cc_width ) ) ;
2016-09-25 23:09:20 +13:00
/* stop the symbol from becoming too high */
2019-11-06 03:16:48 +13:00
while ( rows > 30 & & * ( cc_width ) < 30 ) {
2016-09-25 23:09:20 +13:00
* ( cc_width ) = * ( cc_width ) + 1 ;
2019-11-06 03:16:48 +13:00
rows = ceil ( ( double ) codewords_used / * ( cc_width ) ) ;
2016-09-25 23:09:20 +13:00
}
2019-11-06 03:16:48 +13:00
if ( rows > 30 ) {
2016-09-25 23:09:20 +13:00
return 0 ;
}
2019-11-06 03:16:48 +13:00
if ( rows < 3 ) {
rows = 3 ;
}
codewords_total = * ( cc_width ) * rows ;
2016-09-25 23:09:20 +13:00
target_codewords = codewords_total - ecc_codewords ;
target_codewords - = 3 ;
target_bytesize = 6 * ( target_codewords / 5 ) ;
target_bytesize + = target_codewords % 5 ;
target_bitsize = 8 * target_bytesize ;
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
return target_bitsize ;
}
2020-07-11 06:39:32 +12:00
/* Handles all data encodation from section 5 of ISO/IEC 24723 */
static int cc_binary_string ( struct zint_symbol * symbol , const char source [ ] , char binary_string [ ] , int cc_mode , int * cc_width , int * ecc , int lin_width ) {
2019-10-30 11:54:18 +13:00
int encoding_method , read_posn , alpha_pad ;
int i , j , ai_crop , ai_crop_posn , fnc1_latch ;
int ai90_mode , last_digit , remainder , binary_length ;
int mode ;
int source_len = strlen ( source ) ;
2009-06-03 08:23:38 +12:00
# ifndef _MSC_VER
2019-10-30 11:54:18 +13:00
char general_field [ source_len + 1 ] ;
2009-06-03 08:23:38 +12:00
# else
2020-07-11 06:39:32 +12:00
char * general_field = ( char * ) _alloca ( source_len + 1 ) ;
2009-06-03 08:23:38 +12:00
# endif
2016-02-20 22:38:03 +13:00
int target_bitsize ;
2020-07-11 06:39:32 +12:00
int debug = symbol - > debug & ZINT_DEBUG_PRINT ;
2016-02-20 22:38:03 +13:00
encoding_method = 1 ;
read_posn = 0 ;
ai_crop = 0 ;
2019-10-30 11:54:18 +13:00
ai_crop_posn = - 1 ;
2016-02-20 22:38:03 +13:00
fnc1_latch = 0 ;
alpha_pad = 0 ;
* ecc = 0 ;
target_bitsize = 0 ;
2019-10-30 11:54:18 +13:00
mode = NUMERIC ;
2016-02-20 22:38:03 +13:00
2019-10-30 11:54:18 +13:00
if ( ( source [ 0 ] = = ' 1 ' ) & & ( ( source [ 1 ] = = ' 0 ' ) | | ( source [ 1 ] = = ' 1 ' ) | | ( source [ 1 ] = = ' 7 ' ) ) ) {
2016-02-20 22:38:03 +13:00
/* Source starts (10), (11) or (17) */
encoding_method = 2 ;
}
if ( ( source [ 0 ] = = ' 9 ' ) & & ( source [ 1 ] = = ' 0 ' ) ) {
/* Source starts (90) */
encoding_method = 3 ;
}
if ( encoding_method = = 1 ) {
2016-03-03 10:12:38 +13:00
strcat ( binary_string , " 0 " ) ;
2020-07-11 06:39:32 +12:00
if ( debug ) printf ( " CC-%c Encodation Method: 0 \n " , ' A ' + ( cc_mode - 1 ) ) ;
2016-02-20 22:38:03 +13:00
}
if ( encoding_method = = 2 ) {
/* Encoding Method field "10" - date and lot number */
2016-03-03 10:12:38 +13:00
strcat ( binary_string , " 10 " ) ;
2016-02-20 22:38:03 +13:00
if ( source [ 1 ] = = ' 0 ' ) {
/* No date data */
2016-03-03 10:12:38 +13:00
strcat ( binary_string , " 11 " ) ;
2016-02-20 22:38:03 +13:00
read_posn = 2 ;
2017-10-24 08:34:31 +13:00
} else {
2017-10-17 06:26:54 +13:00
long int group_val ;
2016-02-20 22:38:03 +13:00
/* Production Date (11) or Expiration Date (17) */
2017-09-11 03:03:09 +12:00
char date_str [ 4 ] ;
2016-02-20 22:38:03 +13:00
date_str [ 0 ] = source [ 2 ] ;
date_str [ 1 ] = source [ 3 ] ;
date_str [ 2 ] = ' \0 ' ;
2017-10-17 06:26:54 +13:00
group_val = atoi ( date_str ) * 384 ;
2016-02-20 22:38:03 +13:00
date_str [ 0 ] = source [ 4 ] ;
date_str [ 1 ] = source [ 5 ] ;
group_val + = ( atoi ( date_str ) - 1 ) * 32 ;
date_str [ 0 ] = source [ 6 ] ;
date_str [ 1 ] = source [ 7 ] ;
group_val + = atoi ( date_str ) ;
2017-08-07 19:37:02 +12:00
bin_append ( group_val , 16 , binary_string ) ;
2016-02-20 22:38:03 +13:00
if ( source [ 1 ] = = ' 1 ' ) {
/* Production Date AI 11 */
2016-03-03 10:12:38 +13:00
strcat ( binary_string , " 0 " ) ;
2016-02-20 22:38:03 +13:00
} else {
/* Expiration Date AI 17 */
2016-03-03 10:12:38 +13:00
strcat ( binary_string , " 1 " ) ;
2016-02-20 22:38:03 +13:00
}
read_posn = 8 ;
2019-10-30 11:54:18 +13:00
if ( ( source [ read_posn ] = = ' 1 ' ) & & ( source [ read_posn + 1 ] = = ' 0 ' ) ) {
/* Followed by AI 10 - strip this from general field */
read_posn + = 2 ;
} else if ( source [ read_posn ] ) {
/* ISO/IEC 24723:2010 5.3.1 "If a lot number does not directly follow the date element string, a FNC1 is encoded following the date element string ..." */
fnc1_latch = 1 ;
} else {
/* "... even if no more data follows the date element string" */
/* So still need FNC1 character but can't do single FNC1 in numeric mode, so insert alphanumeric latch "0000" and alphanumeric FNC1 "01111"
( this implementation detail taken from BWIPP https : //github.com/bwipp/postscriptbarcode Copyright (c) 2004-2019 Terry Burton) */
strcat ( binary_string , " 000001111 " ) ;
/* Note an alphanumeric FNC1 is also a numeric latch, so now in numeric mode */
}
2016-02-20 22:38:03 +13:00
}
2020-07-11 06:39:32 +12:00
if ( debug ) printf ( " CC-%c Encodation Method: 10, Compaction Field: %.*s \n " , ' A ' + ( cc_mode - 1 ) , read_posn , source ) ;
2016-02-20 22:38:03 +13:00
}
if ( encoding_method = = 3 ) {
/* Encodation Method field of "11" - AI 90 */
# ifndef _MSC_VER
2019-10-30 11:54:18 +13:00
char ninety [ source_len + 1 ] ;
2009-06-03 08:23:38 +12:00
# else
2020-07-11 06:39:32 +12:00
char * ninety = ( char * ) _alloca ( source_len + 1 ) ;
2009-06-03 08:23:38 +12:00
# endif
2019-10-30 11:54:18 +13:00
int ninety_len , alpha , alphanum , numeric , test1 , test2 , test3 ;
2016-02-20 22:38:03 +13:00
/* "This encodation method may be used if an element string with an AI
90 occurs at the start of the data message , and if the data field
following the two - digit AI 90 starts with an alphanumeric string which
2019-10-30 11:54:18 +13:00
complies with a specific format . " (para 5.3.2) */
2016-02-20 22:38:03 +13:00
2020-04-29 09:41:05 +12:00
memset ( ninety , 0 , source_len + 1 ) ;
2016-02-20 22:38:03 +13:00
i = 0 ;
do {
ninety [ i ] = source [ i + 2 ] ;
i + + ;
2019-10-30 11:54:18 +13:00
} while ( ( source_len > i + 2 ) & & ( ' [ ' ! = source [ i + 2 ] ) ) ;
2016-02-20 22:38:03 +13:00
ninety [ i ] = ' \0 ' ;
2019-10-30 11:54:18 +13:00
ninety_len = strlen ( ninety ) ;
2016-02-20 22:38:03 +13:00
/* Find out if the AI 90 data is alphabetic or numeric or both */
alpha = 0 ;
alphanum = 0 ;
numeric = 0 ;
2019-10-30 11:54:18 +13:00
for ( i = 0 ; i < ninety_len ; i + + ) {
2016-02-20 22:38:03 +13:00
if ( ( ninety [ i ] > = ' A ' ) & & ( ninety [ i ] < = ' Z ' ) ) {
/* Character is alphabetic */
alpha + = 1 ;
2019-10-30 11:54:18 +13:00
} else if ( ( ninety [ i ] > = ' 0 ' ) & & ( ninety [ i ] < = ' 9 ' ) ) {
2016-02-20 22:38:03 +13:00
/* Character is numeric */
numeric + = 1 ;
2019-10-30 11:54:18 +13:00
} else {
alphanum + = 1 ;
2016-02-20 22:38:03 +13:00
}
}
/* must start with 0, 1, 2 or 3 digits followed by an uppercase character */
test1 = - 1 ;
for ( i = 3 ; i > = 0 ; i - - ) {
if ( ( ninety [ i ] > = ' A ' ) & & ( ninety [ i ] < = ' Z ' ) ) {
test1 = i ;
}
}
test2 = 0 ;
for ( i = 0 ; i < test1 ; i + + ) {
if ( ! ( ( ninety [ i ] > = ' 0 ' ) & & ( ninety [ i ] < = ' 9 ' ) ) ) {
test2 = 1 ;
}
}
/* leading zeros are not permitted */
test3 = 0 ;
if ( ( test1 > = 1 ) & & ( ninety [ 0 ] = = ' 0 ' ) ) {
test3 = 1 ;
}
2017-10-24 08:34:31 +13:00
if ( ( test1 ! = - 1 ) & & ( test2 ! = 1 ) & & ( test3 = = 0 ) ) {
2017-10-17 06:26:54 +13:00
int next_ai_posn ;
2017-10-24 08:34:31 +13:00
char numeric_part [ 4 ] ;
int numeric_value ;
int table3_letter ;
2016-02-20 22:38:03 +13:00
/* Encodation method "11" can be used */
2016-03-03 10:12:38 +13:00
strcat ( binary_string , " 11 " ) ;
2016-02-20 22:38:03 +13:00
numeric - = test1 ;
alpha - - ;
/* Decide on numeric, alpha or alphanumeric mode */
/* Alpha mode is a special mode for AI 90 */
2019-10-30 11:54:18 +13:00
if ( alphanum = = 0 & & alpha > numeric ) {
2020-07-11 06:39:32 +12:00
/* Alpha mode */
2019-10-30 11:54:18 +13:00
strcat ( binary_string , " 11 " ) ;
ai90_mode = 2 ;
} else if ( alphanum = = 0 & & alpha = = 0 ) {
/* Numeric mode */
strcat ( binary_string , " 10 " ) ;
ai90_mode = 3 ;
2020-07-11 06:39:32 +12:00
} else { /* Note if first 4 are digits then it would be shorter to go into NUMERIC mode first; not implemented */
2016-02-20 22:38:03 +13:00
/* Alphanumeric mode */
2016-03-03 10:12:38 +13:00
strcat ( binary_string , " 0 " ) ;
2016-02-20 22:38:03 +13:00
ai90_mode = 1 ;
2020-07-11 06:39:32 +12:00
mode = ALPHANUMERIC ;
2016-02-20 22:38:03 +13:00
}
2019-10-30 11:54:18 +13:00
next_ai_posn = 2 + ninety_len ;
2016-02-20 22:38:03 +13:00
2020-07-11 06:39:32 +12:00
if ( next_ai_posn < source_len & & source [ next_ai_posn ] = = ' [ ' ) {
2019-10-30 11:54:18 +13:00
/* There are more AIs afterwards */
2020-07-11 06:39:32 +12:00
if ( next_ai_posn + 2 < source_len & & ( source [ next_ai_posn + 1 ] = = ' 2 ' ) & & ( source [ next_ai_posn + 2 ] = = ' 1 ' ) ) {
2016-02-20 22:38:03 +13:00
/* AI 21 follows */
ai_crop = 1 ;
2020-07-11 06:39:32 +12:00
} else if ( next_ai_posn + 4 < source_len
& & ( source [ next_ai_posn + 1 ] = = ' 8 ' ) & & ( source [ next_ai_posn + 2 ] = = ' 0 ' )
& & ( source [ next_ai_posn + 3 ] = = ' 0 ' ) & & ( source [ next_ai_posn + 4 ] = = ' 4 ' ) ) {
2016-02-20 22:38:03 +13:00
/* AI 8004 follows */
2019-10-30 11:54:18 +13:00
ai_crop = 3 ;
2016-02-20 22:38:03 +13:00
}
}
switch ( ai_crop ) {
2016-03-03 10:12:38 +13:00
case 0 : strcat ( binary_string , " 0 " ) ;
2016-02-20 22:38:03 +13:00
break ;
2016-03-03 10:12:38 +13:00
case 1 : strcat ( binary_string , " 10 " ) ;
2019-10-30 11:54:18 +13:00
ai_crop_posn = next_ai_posn + 1 ;
2016-02-20 22:38:03 +13:00
break ;
2019-10-30 11:54:18 +13:00
case 3 : strcat ( binary_string , " 11 " ) ;
ai_crop_posn = next_ai_posn + 1 ;
2016-02-20 22:38:03 +13:00
break ;
}
if ( test1 = = 0 ) {
strcpy ( numeric_part , " 0 " ) ;
} else {
for ( i = 0 ; i < test1 ; i + + ) {
numeric_part [ i ] = ninety [ i ] ;
}
numeric_part [ i ] = ' \0 ' ;
}
2017-10-17 06:26:54 +13:00
numeric_value = atoi ( numeric_part ) ;
2016-02-20 22:38:03 +13:00
2017-10-17 06:26:54 +13:00
table3_letter = - 1 ;
2016-02-20 22:38:03 +13:00
if ( numeric_value < 31 ) {
2017-08-07 19:37:02 +12:00
table3_letter = posn ( " BDHIJKLNPQRSTVWZ " , ninety [ test1 ] ) ;
2016-02-20 22:38:03 +13:00
}
if ( table3_letter ! = - 1 ) {
2019-10-30 11:54:18 +13:00
/* Encoding can be done according to 5.3.2 c) 2) */
2016-02-20 22:38:03 +13:00
/* five bit binary string representing value before letter */
2017-08-07 19:37:02 +12:00
bin_append ( numeric_value , 5 , binary_string ) ;
2017-10-24 08:37:52 +13:00
2016-02-20 22:38:03 +13:00
/* followed by four bit representation of letter from Table 3 */
2017-08-07 19:37:02 +12:00
bin_append ( table3_letter , 4 , binary_string ) ;
2016-02-20 22:38:03 +13:00
} else {
2019-10-30 11:54:18 +13:00
/* Encoding is done according to 5.3.2 c) 3) */
2017-08-07 19:37:02 +12:00
bin_append ( 31 , 5 , binary_string ) ;
2016-02-20 22:38:03 +13:00
/* ten bit representation of number */
2017-08-07 19:37:02 +12:00
bin_append ( numeric_value , 10 , binary_string ) ;
2016-02-20 22:38:03 +13:00
/* five bit representation of ASCII character */
2017-08-07 19:37:02 +12:00
bin_append ( ninety [ test1 ] - 65 , 5 , binary_string ) ;
2016-02-20 22:38:03 +13:00
}
read_posn = test1 + 3 ;
2019-10-30 11:54:18 +13:00
/* Do Alpha mode encoding of the rest of the AI 90 data field here */
if ( ai90_mode = = 2 ) {
/* Alpha encodation (section 5.3.3) */
do {
if ( ( source [ read_posn ] > = ' A ' ) & & ( source [ read_posn ] < = ' Z ' ) ) {
bin_append ( source [ read_posn ] - 65 , 5 , binary_string ) ;
2016-02-20 22:38:03 +13:00
2019-10-30 11:54:18 +13:00
} else if ( ( source [ read_posn ] > = ' 0 ' ) & & ( source [ read_posn ] < = ' 9 ' ) ) {
bin_append ( source [ read_posn ] + 4 , 6 , binary_string ) ;
2016-02-20 22:38:03 +13:00
2019-10-30 11:54:18 +13:00
} else if ( source [ read_posn ] = = ' [ ' ) {
bin_append ( 31 , 5 , binary_string ) ;
}
2016-02-20 22:38:03 +13:00
2019-10-30 11:54:18 +13:00
read_posn + + ;
} while ( ( source [ read_posn - 1 ] ! = ' [ ' ) & & ( source [ read_posn - 1 ] ! = ' \0 ' ) ) ;
alpha_pad = 1 ; /* This is overwritten if a general field is encoded */
2016-02-20 22:38:03 +13:00
}
2020-07-11 06:39:32 +12:00
if ( debug ) {
printf ( " CC-%c Encodation Method: 11, Compaction Field: %.*s, Binary: %s (%d) \n " ,
' A ' + ( cc_mode - 1 ) , read_posn , source , binary_string , ( int ) strlen ( binary_string ) ) ;
}
2019-10-30 11:54:18 +13:00
} else {
/* Use general field encodation instead */
strcat ( binary_string , " 0 " ) ;
read_posn = 0 ;
2020-07-11 06:39:32 +12:00
if ( debug ) printf ( " CC-%c Encodation Method: 0 \n " , ' A ' + ( cc_mode - 1 ) ) ;
2019-10-30 11:54:18 +13:00
}
2016-02-20 22:38:03 +13:00
}
/* The compressed data field has been processed if appropriate - the
rest of the data ( if any ) goes into a general - purpose data compaction field */
j = 0 ;
if ( fnc1_latch = = 1 ) {
/* Encodation method "10" has been used but it is not followed by
AI 10 , so a FNC1 character needs to be added */
general_field [ j ] = ' [ ' ;
j + + ;
}
2019-10-30 11:54:18 +13:00
for ( i = read_posn ; i < source_len ; i + + ) {
/* Skip "[21" or "[8004" AIs if encodation method "11" used */
if ( i = = ai_crop_posn ) {
i + = ai_crop ;
} else {
general_field [ j ] = source [ i ] ;
j + + ;
}
2016-02-20 22:38:03 +13:00
}
general_field [ j ] = ' \0 ' ;
2020-07-11 06:39:32 +12:00
if ( debug ) {
printf ( " Mode %s, General Field: %.40s%s \n " ,
mode = = NUMERIC ? " NUMERIC " : mode = = ALPHANUMERIC ? " ALPHANUMERIC " : " ISO646 " ,
general_field , strlen ( general_field ) > 40 ? " ... " : " " ) ;
}
2016-02-20 22:38:03 +13:00
if ( strlen ( general_field ) ! = 0 ) {
alpha_pad = 0 ;
}
2019-10-30 11:54:18 +13:00
if ( ! general_field_encode ( general_field , & mode , & last_digit , binary_string ) ) {
2016-02-20 22:38:03 +13:00
/* Invalid characters in input data */
2020-11-08 08:26:10 +13:00
symbol - > err_origin = 441 ;
strcpy ( symbol - > errtxt , _ ( " Invalid character in data " ) ) ;
2016-02-20 22:38:03 +13:00
return ZINT_ERROR_INVALID_DATA ;
}
2017-05-29 21:43:47 +12:00
binary_length = ( int ) strlen ( binary_string ) ;
2016-09-25 23:09:20 +13:00
switch ( cc_mode ) {
case 1 :
target_bitsize = calc_padding_cca ( binary_length , * ( cc_width ) ) ;
break ;
case 2 :
target_bitsize = calc_padding_ccb ( binary_length , * ( cc_width ) ) ;
break ;
case 3 :
target_bitsize = calc_padding_ccc ( binary_length , cc_width , lin_width , ecc ) ;
break ;
2016-02-20 22:38:03 +13:00
}
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
if ( target_bitsize = = 0 ) {
2020-11-08 08:26:10 +13:00
symbol - > err_origin = 442 ;
strcpy ( symbol - > errtxt , _ ( " Input too long for selected 2D component " ) ) ;
2016-09-25 23:09:20 +13:00
return ZINT_ERROR_TOO_LONG ;
2016-02-20 22:38:03 +13:00
}
2016-09-25 23:09:20 +13:00
remainder = target_bitsize - binary_length ;
2016-02-20 22:38:03 +13:00
2019-10-30 11:54:18 +13:00
if ( last_digit ) {
2016-02-20 22:38:03 +13:00
/* There is still one more numeric digit to encode */
if ( ( remainder > = 4 ) & & ( remainder < = 6 ) ) {
2019-10-30 11:54:18 +13:00
/* ISO/IEC 24723:2010 5.4.1 c) 2) "If four to six bits remain, add 1 to the digit value and encode the result in the next four bits. ..." */
bin_append ( ctoi ( last_digit ) + 1 , 4 , binary_string ) ;
if ( remainder > 4 ) {
/* "... The fifth and sixth bits, if present, shall be “0”s." (Covered by adding truncated alphanumeric latch below but do explicitly anyway) */
bin_append ( 0 , remainder - 4 , binary_string ) ;
}
2016-02-20 22:38:03 +13:00
} else {
2019-10-30 11:54:18 +13:00
bin_append ( ( 11 * ctoi ( last_digit ) ) + 18 , 7 , binary_string ) ;
2016-02-20 22:38:03 +13:00
/* This may push the symbol up to the next size */
}
}
if ( strlen ( binary_string ) > 11805 ) { /* (2361 * 5) */
2020-11-08 08:26:10 +13:00
symbol - > err_origin = 443 ;
strcpy ( symbol - > errtxt , _ ( " Input too long " ) ) ;
2016-02-20 22:38:03 +13:00
return ZINT_ERROR_TOO_LONG ;
}
2017-05-29 21:43:47 +12:00
binary_length = ( int ) strlen ( binary_string ) ;
2016-09-25 23:09:20 +13:00
switch ( cc_mode ) {
case 1 :
target_bitsize = calc_padding_cca ( binary_length , * ( cc_width ) ) ;
break ;
case 2 :
target_bitsize = calc_padding_ccb ( binary_length , * ( cc_width ) ) ;
break ;
case 3 :
target_bitsize = calc_padding_ccc ( binary_length , cc_width , lin_width , ecc ) ;
break ;
2016-02-20 22:38:03 +13:00
}
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
if ( target_bitsize = = 0 ) {
2020-11-08 08:26:10 +13:00
symbol - > err_origin = 444 ;
strcpy ( symbol - > errtxt , _ ( " Input too long for selected 2D component " ) ) ;
2016-09-25 23:09:20 +13:00
return ZINT_ERROR_TOO_LONG ;
2016-02-20 22:38:03 +13:00
}
if ( binary_length < target_bitsize ) {
/* Now add padding to binary string */
if ( alpha_pad = = 1 ) {
2016-03-03 10:12:38 +13:00
strcat ( binary_string , " 11111 " ) ;
2019-10-30 11:54:18 +13:00
/* Extra FNC1 character required after Alpha encodation (section 5.3.3) */
2016-02-20 22:38:03 +13:00
}
2019-10-30 11:54:18 +13:00
if ( mode = = NUMERIC ) {
2016-03-03 10:12:38 +13:00
strcat ( binary_string , " 0000 " ) ;
2016-02-20 22:38:03 +13:00
}
2016-03-01 08:42:32 +13:00
while ( strlen ( binary_string ) < ( unsigned int ) target_bitsize ) {
2016-03-03 10:12:38 +13:00
strcat ( binary_string , " 00100 " ) ;
2016-02-20 22:38:03 +13:00
}
2016-03-01 08:42:32 +13:00
if ( strlen ( binary_string ) > ( unsigned int ) target_bitsize ) {
2016-02-20 22:38:03 +13:00
binary_string [ target_bitsize ] = ' \0 ' ;
}
}
2020-07-11 06:39:32 +12:00
if ( debug ) {
printf ( " ECC: %d, CC width %d \n " , * ecc , * cc_width ) ;
printf ( " Binary: %s (%d) \n " , binary_string , ( int ) strlen ( binary_string ) ) ;
}
2016-02-20 22:38:03 +13:00
return 0 ;
2008-07-14 09:15:55 +12:00
}
2020-10-01 00:19:12 +13:00
static int linear_dummy_run ( unsigned char * source , int length , char * errtxt ) {
2016-09-25 23:09:20 +13:00
struct zint_symbol * dummy ;
int error_number ;
int linear_width ;
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
dummy = ZBarcode_Create ( ) ;
2020-07-30 07:43:08 +12:00
dummy - > symbology = BARCODE_GS1_128_CC ;
2016-09-25 23:09:20 +13:00
dummy - > option_1 = 3 ;
error_number = ean_128 ( dummy , source , length ) ;
linear_width = dummy - > width ;
2020-10-01 00:19:12 +13:00
if ( error_number ! = 0 ) {
strcpy ( errtxt , dummy - > errtxt ) ;
}
2016-09-25 23:09:20 +13:00
ZBarcode_Delete ( dummy ) ;
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
if ( error_number = = 0 ) {
return linear_width ;
} else {
return 0 ;
}
}
2019-12-19 13:37:55 +13:00
INTERNAL int composite ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) {
2016-02-20 22:38:03 +13:00
int error_number , cc_mode , cc_width , ecc_level ;
int j , i , k ;
2019-11-06 03:16:48 +13:00
unsigned int bs = 13 * length + 500 + 1 ; /* Allow for 8 bits + 5-bit latch per char + 500 bits overhead/padding */
2009-06-03 08:23:38 +12:00
# ifndef _MSC_VER
2016-02-20 22:38:03 +13:00
char binary_string [ bs ] ;
2009-06-03 08:23:38 +12:00
# else
2020-07-11 06:39:32 +12:00
char * binary_string = ( char * ) _alloca ( bs ) ;
2009-06-03 08:23:38 +12:00
# endif
2019-11-06 03:16:48 +13:00
unsigned int pri_len ;
2016-02-20 22:38:03 +13:00
struct zint_symbol * linear ;
int top_shift , bottom_shift ;
2016-09-25 23:09:20 +13:00
int linear_width = 0 ;
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
/* Perform sanity checks on input options first */
2016-02-20 22:38:03 +13:00
error_number = 0 ;
2017-05-29 21:43:47 +12:00
pri_len = ( int ) strlen ( symbol - > primary ) ;
2016-02-20 22:38:03 +13:00
if ( pri_len = = 0 ) {
2020-11-08 08:26:10 +13:00
symbol - > err_origin = 445 ;
strcpy ( symbol - > errtxt , _ ( " No primary (linear) message in 2D composite " ) ) ;
2016-02-20 22:38:03 +13:00
return ZINT_ERROR_INVALID_OPTION ;
}
if ( length > 2990 ) {
2020-11-08 08:26:10 +13:00
symbol - > err_origin = 446 ;
2020-11-08 21:32:05 +13:00
strcpy ( symbol - > errtxt , _ ( " Input too long for selected 2D component " ) ) ;
2016-02-20 22:38:03 +13:00
return ZINT_ERROR_TOO_LONG ;
}
2017-10-24 08:37:52 +13:00
2016-02-20 22:38:03 +13:00
cc_mode = symbol - > option_1 ;
2020-07-30 07:43:08 +12:00
if ( ( cc_mode = = 3 ) & & ( symbol - > symbology ! = BARCODE_GS1_128_CC ) ) {
2016-02-20 22:38:03 +13:00
/* CC-C can only be used with a GS1-128 linear part */
2020-11-08 08:26:10 +13:00
symbol - > err_origin = 447 ;
strcpy ( symbol - > errtxt , _ ( " Invalid mode (CC-C only valid with GS1-128 linear component) " ) ) ;
2016-02-20 22:38:03 +13:00
return ZINT_ERROR_INVALID_OPTION ;
}
2020-07-30 07:43:08 +12:00
if ( symbol - > symbology = = BARCODE_GS1_128_CC ) {
2016-09-25 23:09:20 +13:00
/* Do a test run of encoding the linear component to establish its width */
2020-10-01 00:19:12 +13:00
linear_width = linear_dummy_run ( ( unsigned char * ) symbol - > primary , pri_len , symbol - > errtxt ) ;
2016-09-25 23:09:20 +13:00
if ( linear_width = = 0 ) {
2020-11-08 08:26:10 +13:00
strcat ( symbol - > errtxt , _ ( " in linear component " ) ) ;
2016-09-25 23:09:20 +13:00
return ZINT_ERROR_INVALID_DATA ;
}
2020-07-11 06:39:32 +12:00
if ( symbol - > debug & ZINT_DEBUG_PRINT ) {
printf ( " GS1-128 linear width: %d \n " , linear_width ) ;
}
2016-09-25 23:09:20 +13:00
}
2016-02-20 22:38:03 +13:00
switch ( symbol - > symbology ) {
/* Determine width of 2D component according to ISO/IEC 24723 Table 1 */
case BARCODE_EANX_CC :
2019-10-15 10:20:16 +13:00
cc_width = 0 ;
if ( pri_len < 20 ) {
int padded_pri_len ;
2020-10-06 11:22:06 +13:00
int with_addon ;
char padded_pri [ 21 ] ;
2019-10-15 10:20:16 +13:00
padded_pri [ 0 ] = ' \0 ' ;
2020-10-06 11:22:06 +13:00
ean_leading_zeroes ( symbol , ( unsigned char * ) symbol - > primary , ( unsigned char * ) padded_pri , & with_addon ) ;
2019-10-15 10:20:16 +13:00
padded_pri_len = strlen ( padded_pri ) ;
if ( padded_pri_len < = 7 ) { /* EAN-8 */
2016-02-20 22:38:03 +13:00
cc_width = 3 ;
2019-10-15 10:20:16 +13:00
} else {
switch ( padded_pri_len ) {
case 10 : /* EAN-8 + 2 */
cc_width = 3 ;
break ;
2020-10-06 11:22:06 +13:00
case 13 : /* EAN-13 CHK or EAN-8 + 5 */
cc_width = with_addon ? 3 : 4 ;
break ;
2019-10-15 10:20:16 +13:00
case 12 : /* EAN-13 */
case 15 : /* EAN-13 + 2 */
2020-10-06 11:22:06 +13:00
case 16 : /* EAN-13 CHK + 2 */
2019-10-15 10:20:16 +13:00
case 18 : /* EAN-13 + 5 */
2020-10-06 11:22:06 +13:00
case 19 : /* EAN-13 CHK + 5 */
2019-10-15 10:20:16 +13:00
cc_width = 4 ;
break ;
}
}
}
if ( cc_width = = 0 ) {
2020-11-08 08:26:10 +13:00
symbol - > err_origin = 449 ;
strcpy ( symbol - > errtxt , _ ( " Input wrong length in linear component " ) ) ;
2019-10-15 10:20:16 +13:00
return ZINT_ERROR_TOO_LONG ;
2016-02-20 22:38:03 +13:00
}
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_GS1_128_CC : cc_width = 4 ;
2016-02-20 22:38:03 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_OMN_CC : cc_width = 4 ;
2016-02-20 22:38:03 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_LTD_CC : cc_width = 3 ;
2016-02-20 22:38:03 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_EXP_CC : cc_width = 4 ;
2016-02-20 22:38:03 +13:00
break ;
case BARCODE_UPCA_CC : cc_width = 4 ;
break ;
case BARCODE_UPCE_CC : cc_width = 2 ;
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_STK_CC : cc_width = 2 ;
2016-02-20 22:38:03 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_OMNSTK_CC : cc_width = 2 ;
2016-02-20 22:38:03 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_EXPSTK_CC : cc_width = 4 ;
2016-02-20 22:38:03 +13:00
break ;
}
2017-10-24 08:37:52 +13:00
2016-02-20 22:38:03 +13:00
memset ( binary_string , 0 , bs ) ;
if ( cc_mode < 1 | | cc_mode > 3 ) {
cc_mode = 1 ;
}
if ( cc_mode = = 1 ) {
2019-10-06 23:30:21 +13:00
i = cc_binary_string ( symbol , ( char * ) source , binary_string , cc_mode , & cc_width , & ecc_level , linear_width ) ;
2016-02-20 22:38:03 +13:00
if ( i = = ZINT_ERROR_TOO_LONG ) {
cc_mode = 2 ;
2019-10-30 11:54:18 +13:00
memset ( binary_string , 0 , bs ) ;
} else if ( i ! = 0 ) {
return i ;
2016-02-20 22:38:03 +13:00
}
}
if ( cc_mode = = 2 ) {
/* If the data didn't fit into CC-A it is recalculated for CC-B */
2019-10-06 23:30:21 +13:00
i = cc_binary_string ( symbol , ( char * ) source , binary_string , cc_mode , & cc_width , & ecc_level , linear_width ) ;
2016-02-20 22:38:03 +13:00
if ( i = = ZINT_ERROR_TOO_LONG ) {
2020-07-30 07:43:08 +12:00
if ( symbol - > symbology ! = BARCODE_GS1_128_CC ) {
2016-02-20 22:38:03 +13:00
return ZINT_ERROR_TOO_LONG ;
}
2019-10-30 11:54:18 +13:00
cc_mode = 3 ;
memset ( binary_string , 0 , bs ) ;
} else if ( i ! = 0 ) {
return i ;
2016-02-20 22:38:03 +13:00
}
}
if ( cc_mode = = 3 ) {
/* If the data didn't fit in CC-B (and linear part is GS1-128) it is recalculated for CC-C */
2019-10-06 23:30:21 +13:00
i = cc_binary_string ( symbol , ( char * ) source , binary_string , cc_mode , & cc_width , & ecc_level , linear_width ) ;
2019-10-30 11:54:18 +13:00
if ( i ! = 0 ) {
return i ;
2016-02-20 22:38:03 +13:00
}
}
switch ( cc_mode ) {
2016-03-01 08:42:32 +13:00
/* Note that ecc_level is only relevant to CC-C */
2016-02-20 22:38:03 +13:00
case 1 : error_number = cc_a ( symbol , binary_string , cc_width ) ;
break ;
case 2 : error_number = cc_b ( symbol , binary_string , cc_width ) ;
break ;
case 3 : error_number = cc_c ( symbol , binary_string , cc_width , ecc_level ) ;
break ;
}
if ( error_number ! = 0 ) {
return ZINT_ERROR_ENCODING_PROBLEM ;
}
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
/* 2D component done, now calculate linear component */
linear = ZBarcode_Create ( ) ; /* Symbol contains the 2D component and Linear contains the rest */
2017-10-24 08:37:52 +13:00
2016-09-25 23:09:20 +13:00
linear - > symbology = symbol - > symbology ;
2020-08-05 11:14:11 +12:00
linear - > option_2 = symbol - > option_2 ;
2020-07-11 06:39:32 +12:00
linear - > debug = symbol - > debug ;
2016-09-25 23:09:20 +13:00
2020-07-30 07:43:08 +12:00
if ( linear - > symbology ! = BARCODE_GS1_128_CC ) {
2016-09-25 23:09:20 +13:00
/* Set the "component linkage" flag in the linear component */
linear - > option_1 = 2 ;
} else {
/* GS1-128 needs to know which type of 2D component is used */
linear - > option_1 = cc_mode ;
}
switch ( symbol - > symbology ) {
case BARCODE_EANX_CC : error_number = eanx ( linear , ( unsigned char * ) symbol - > primary , pri_len ) ;
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_GS1_128_CC : error_number = ean_128 ( linear , ( unsigned char * ) symbol - > primary , pri_len ) ;
2016-09-25 23:09:20 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_OMN_CC : error_number = rss14 ( linear , ( unsigned char * ) symbol - > primary , pri_len ) ;
2016-09-25 23:09:20 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_LTD_CC : error_number = rsslimited ( linear , ( unsigned char * ) symbol - > primary , pri_len ) ;
2016-09-25 23:09:20 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_EXP_CC : error_number = rssexpanded ( linear , ( unsigned char * ) symbol - > primary , pri_len ) ;
2016-09-25 23:09:20 +13:00
break ;
case BARCODE_UPCA_CC : error_number = eanx ( linear , ( unsigned char * ) symbol - > primary , pri_len ) ;
break ;
case BARCODE_UPCE_CC : error_number = eanx ( linear , ( unsigned char * ) symbol - > primary , pri_len ) ;
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_STK_CC : error_number = rss14 ( linear , ( unsigned char * ) symbol - > primary , pri_len ) ;
2016-09-25 23:09:20 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_OMNSTK_CC : error_number = rss14 ( linear , ( unsigned char * ) symbol - > primary , pri_len ) ;
2016-09-25 23:09:20 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_EXPSTK_CC : error_number = rssexpanded ( linear , ( unsigned char * ) symbol - > primary , pri_len ) ;
2016-09-25 23:09:20 +13:00
break ;
}
if ( error_number ! = 0 ) {
strcpy ( symbol - > errtxt , linear - > errtxt ) ;
2020-11-08 08:26:10 +13:00
strcat ( symbol - > errtxt , _ ( " in linear component " ) ) ;
2016-09-25 23:09:20 +13:00
ZBarcode_Delete ( linear ) ;
return error_number ;
}
2016-02-20 22:38:03 +13:00
/* Merge the linear component with the 2D component */
top_shift = 0 ;
bottom_shift = 0 ;
switch ( symbol - > symbology ) {
/* Determine horizontal alignment (according to section 12.3) */
case BARCODE_EANX_CC :
2019-10-15 10:20:16 +13:00
switch ( ustrlen ( linear - > text ) ) { /* Use zero-padded length */
case 8 : /* EAN-8 */
case 11 : /* EAN-8 + 2 */
case 14 : /* EAN-8 + 5 */
2019-10-05 23:08:58 +13:00
if ( cc_mode = = 1 ) {
bottom_shift = 3 ;
} else {
bottom_shift = 13 ;
}
2016-02-20 22:38:03 +13:00
break ;
2019-10-15 10:20:16 +13:00
case 13 : /* EAN-13 */
case 16 : /* EAN-13 + 2 */
case 19 : /* EAN-13 + 5 */
2016-02-20 22:38:03 +13:00
bottom_shift = 2 ;
break ;
}
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_GS1_128_CC : if ( cc_mode = = 3 ) {
2016-02-20 22:38:03 +13:00
bottom_shift = 7 ;
2019-10-30 11:54:18 +13:00
} else {
/* ISO/IEC 24723:2010 12.3 g) "GS1-128 components linked to the right quiet zone of the CC-A or CC-B: the CC-A or CC-B component is
aligned with the last space module of one of the rightmost symbol characters of the linear component . To
calculate the target Code 128 symbol character position for alignment , number the positions from right to
left ( 0 is the Stop character , 1 is the Check character , etc . ) , and then Position = ( total number of Code 128 symbol characters – 9 ) div 2 "
*/
int num_symbols = ( linear_width - 2 ) / 11 ;
int position = ( num_symbols - 9 ) / 2 ;
int calc_shift = linear - > width - position * 11 - 1 - symbol - > width ; /* Less 1 to align with last space module */
if ( position ) {
calc_shift - = 2 ; /* Less additional stop modules */
}
if ( calc_shift > 0 ) {
top_shift = calc_shift ;
} else if ( calc_shift < 0 ) {
bottom_shift = - calc_shift ;
}
2016-02-20 22:38:03 +13:00
}
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_OMN_CC : bottom_shift = 4 ;
2016-02-20 22:38:03 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_LTD_CC :
2019-10-05 23:08:58 +13:00
if ( cc_mode = = 1 ) {
top_shift = 1 ;
} else {
bottom_shift = 9 ;
}
2016-02-20 22:38:03 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_EXP_CC : k = 1 ;
2016-02-20 22:38:03 +13:00
while ( ( ! ( module_is_set ( linear , 1 , k - 1 ) ) ) & & module_is_set ( linear , 1 , k ) ) {
k + + ;
}
top_shift = k ;
break ;
case BARCODE_UPCA_CC : bottom_shift = 2 ;
break ;
case BARCODE_UPCE_CC : bottom_shift = 2 ;
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_STK_CC : top_shift = 1 ;
2016-02-20 22:38:03 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_OMNSTK_CC : top_shift = 1 ;
2016-02-20 22:38:03 +13:00
break ;
2020-07-30 07:43:08 +12:00
case BARCODE_DBAR_EXPSTK_CC : k = 1 ;
2016-02-20 22:38:03 +13:00
while ( ( ! ( module_is_set ( linear , 1 , k - 1 ) ) ) & & module_is_set ( linear , 1 , k ) ) {
k + + ;
}
top_shift = k ;
break ;
}
2020-07-11 06:39:32 +12:00
if ( symbol - > debug & ZINT_DEBUG_PRINT ) {
printf ( " Top shift: %d, Bottom shift: %d \n " , top_shift , bottom_shift ) ;
}
2016-02-20 22:38:03 +13:00
if ( top_shift ! = 0 ) {
2020-10-06 11:22:06 +13:00
/* Move the 2D component of the symbol horizontally */
2016-02-20 22:38:03 +13:00
for ( i = 0 ; i < = symbol - > rows ; i + + ) {
for ( j = ( symbol - > width + top_shift ) ; j > = top_shift ; j - - ) {
if ( module_is_set ( symbol , i , j - top_shift ) ) {
set_module ( symbol , i , j ) ;
} else {
unset_module ( symbol , i , j ) ;
}
}
for ( j = 0 ; j < top_shift ; j + + ) {
unset_module ( symbol , i , j ) ;
}
}
}
/* Merge linear and 2D components into one structure */
for ( i = 0 ; i < = linear - > rows ; i + + ) {
symbol - > row_height [ symbol - > rows + i ] = linear - > row_height [ i ] ;
for ( j = 0 ; j < = linear - > width ; j + + ) {
if ( module_is_set ( linear , i , j ) ) {
set_module ( symbol , i + symbol - > rows , j + bottom_shift ) ;
} else {
unset_module ( symbol , i + symbol - > rows , j + bottom_shift ) ;
}
}
}
2019-10-17 22:06:21 +13:00
if ( ( linear - > width + bottom_shift ) > symbol - > width + top_shift ) {
2016-02-20 22:38:03 +13:00
symbol - > width = linear - > width + bottom_shift ;
2019-10-17 22:06:21 +13:00
} else if ( ( symbol - > width + top_shift ) > linear - > width + bottom_shift ) {
2016-02-20 22:38:03 +13:00
symbol - > width + = top_shift ;
}
symbol - > rows + = linear - > rows ;
2020-07-11 06:39:32 +12:00
ustrcpy ( symbol - > text , linear - > text ) ;
2016-02-20 22:38:03 +13:00
ZBarcode_Delete ( linear ) ;
return error_number ;
2008-07-14 09:15:55 +12:00
}