2020-07-29 22:43:08 +03:00
/* rss.c - GS1 DataBar (formerly Reduced Space Symbology) */
2008-07-14 01:15:55 +04:00
/*
libzint - the open source barcode library
2021-01-18 23:10:52 +03:00
Copyright ( C ) 2008 - 2021 Robin Stuart < rstuart114 @ gmail . com >
2008-07-14 01:15:55 +04: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 :
2008-07-14 01:15:55 +04:00
2017-10-23 22:37:52 +03:00
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2013-05-16 21:26:38 +04:00
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
2017-10-23 22:37:52 +03:00
documentation and / or other materials provided with the distribution .
2013-05-16 21:26:38 +04: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
2017-10-23 22:37:52 +03:00
without specific prior written permission .
2008-07-14 01:15:55 +04:00
2013-05-16 21:26:38 +04: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
2017-10-23 22:37:52 +03:00
OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
2013-05-16 21:26:38 +04:00
SUCH DAMAGE .
2016-02-20 14:29:19 +03:00
*/
2019-10-17 12:06:21 +03:00
/* vim: set ts=4 sw=4 et : */
2008-07-14 01:15:55 +04:00
2021-06-27 13:47:55 +03:00
/* The functions "rss_combins" and "getRSSwidths" are copyright BSI and are
2008-07-14 01:15:55 +04:00
released with permission under the following terms :
2017-10-23 22:37:52 +03:00
2008-07-14 01:15:55 +04: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 .
2017-10-23 22:37:52 +03:00
2008-07-14 01:15:55 +04: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 . "
2017-10-23 22:37:52 +03:00
2008-07-14 01:15:55 +04:00
The date of publication for these functions is 30 November 2006
2016-02-20 14:29:19 +03:00
*/
2010-05-23 11:18:15 +04:00
/* Includes numerous bugfixes thanks to Pablo Orduña @ the PIRAmIDE project */
2016-02-17 16:01:56 +03:00
/* Note: This code reflects the symbol names as used in ISO/IEC 24724:2006. These names
* were updated in ISO / IEC 24724 : 2011 as follows :
2017-10-23 22:37:52 +03:00
*
2016-02-17 16:01:56 +03:00
* RSS - 14 > GS1 DataBar Omnidirectional
* RSS - 14 Truncated > GS1 DataBar Truncated
* RSS - 14 Stacked > GS1 DataBar Stacked
* RSS - 14 Stacked Omnidirectional > GS1 DataBar Stacked Omnidirectional
* RSS Limited > GS1 DataBar Limited
* RSS Expanded > GS1 DataBar Expanded Omnidirectional
* RSS Expanded Stacked > GS1 DataBar Expanded Stacked Omnidirectional
*/
2016-02-20 14:29:19 +03:00
2008-07-14 01:15:55 +04:00
# include <stdio.h>
2009-06-03 00:23:38 +04:00
# ifdef _MSC_VER
2017-10-23 22:37:52 +03:00
# include <malloc.h>
2009-06-03 00:23:38 +04:00
# endif
2008-07-14 01:15:55 +04:00
# include "common.h"
# include "large.h"
# include "rss.h"
2009-01-08 11:43:25 +03:00
# include "gs1.h"
2019-10-31 05:01:42 +03:00
# include "general_field.h"
2008-07-14 01:15:55 +04:00
2021-06-27 13:47:55 +03:00
/****************************************************************************
* rss_combins ( n , r ) : returns the number of Combinations of r selected from n :
2016-02-20 14:29:19 +03:00
* Combinations = n ! / ( ( n - r ) ! * r ! )
2021-06-27 13:47:55 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int rss_combins ( const int n , const int r ) {
2016-02-20 14:29:19 +03:00
int i , j ;
int maxDenom , minDenom ;
int val ;
if ( n - r > r ) {
minDenom = r ;
maxDenom = n - r ;
} else {
minDenom = n - r ;
maxDenom = r ;
}
val = 1 ;
j = 1 ;
for ( i = n ; i > maxDenom ; i - - ) {
val * = i ;
if ( j < = minDenom ) {
val / = j ;
j + + ;
}
}
for ( ; j < = minDenom ; j + + ) {
val / = j ;
}
return ( val ) ;
2008-07-14 01:15:55 +04:00
}
/**********************************************************************
2016-02-20 14:29:19 +03:00
* getRSSwidths
* routine to generate widths for RSS elements for a given value . #
*
* Calling arguments :
2020-07-10 21:39:32 +03:00
* int widths [ ] = element widths
2016-02-20 14:29:19 +03:00
* val = required value
* n = number of modules
* elements = elements in a set ( RSS - 14 & Expanded = 4 ; RSS Limited = 7 )
* maxWidth = maximum module width of an element
* noNarrow = 0 will skip patterns without a one module wide element
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-12-21 22:30:07 +03:00
static void getRSSwidths ( int widths [ ] , int val , int n , const int elements , const int maxWidth , const int noNarrow ) {
2016-02-20 14:29:19 +03:00
int bar ;
int elmWidth ;
int mxwElement ;
int subVal , lessVal ;
int narrowMask = 0 ;
for ( bar = 0 ; bar < elements - 1 ; bar + + ) {
for ( elmWidth = 1 , narrowMask | = ( 1 < < bar ) ;
;
elmWidth + + , narrowMask & = ~ ( 1 < < bar ) ) {
/* get all combinations */
2021-06-27 13:47:55 +03:00
subVal = rss_combins ( n - elmWidth - 1 , elements - bar - 2 ) ;
2016-02-20 14:29:19 +03:00
/* less combinations with no single-module element */
2021-06-27 13:47:55 +03:00
if ( ( ! noNarrow ) & & ( ! narrowMask )
& & ( n - elmWidth - ( elements - bar - 1 ) > = elements - bar - 1 ) ) {
subVal - = rss_combins ( n - elmWidth - ( elements - bar ) , elements - bar - 2 ) ;
2016-02-20 14:29:19 +03:00
}
/* less combinations with elements > maxVal */
if ( elements - bar - 1 > 1 ) {
lessVal = 0 ;
for ( mxwElement = n - elmWidth - ( elements - bar - 2 ) ;
mxwElement > maxWidth ;
mxwElement - - ) {
2021-06-27 13:47:55 +03:00
lessVal + = rss_combins ( n - elmWidth - mxwElement - 1 , elements - bar - 3 ) ;
2016-02-20 14:29:19 +03:00
}
subVal - = lessVal * ( elements - 1 - bar ) ;
} else if ( n - elmWidth > maxWidth ) {
subVal - - ;
}
val - = subVal ;
if ( val < 0 ) break ;
}
val + = subVal ;
n - = elmWidth ;
widths [ bar ] = elmWidth ;
}
widths [ bar ] = n ;
return ;
2008-07-14 01:15:55 +04:00
}
2020-07-10 21:39:32 +03:00
/* Set GTIN-14 human readable text */
2021-06-27 13:47:55 +03:00
static void rss_set_gtin14_hrt ( struct zint_symbol * symbol , const unsigned char * source , const int src_len ) {
2020-07-10 21:39:32 +03:00
int i ;
2021-07-13 19:39:03 +03:00
unsigned char * hrt = symbol - > text + 4 ;
2020-07-10 21:39:32 +03:00
ustrcpy ( symbol - > text , " (01) " ) ;
for ( i = 0 ; i < 12 ; i + + ) {
hrt [ i ] = ' 0 ' ;
}
for ( i = 0 ; i < src_len ; i + + ) {
hrt [ 12 - i ] = source [ src_len - i - 1 ] ;
}
2021-06-27 13:47:55 +03:00
hrt [ 13 ] = gs1_check_digit ( hrt , 13 ) ;
2020-07-10 21:39:32 +03:00
hrt [ 14 ] = ' \0 ' ;
}
/* Expand from a width pattern to a bit pattern */
2020-12-21 22:30:07 +03:00
static int rss_expand ( struct zint_symbol * symbol , int writer , int * p_latch , const int width ) {
2020-07-10 21:39:32 +03:00
int j ;
int latch = * p_latch ;
for ( j = 0 ; j < width ; j + + ) {
2020-12-21 22:30:07 +03:00
if ( latch ) {
2020-07-10 21:39:32 +03:00
set_module ( symbol , symbol - > rows , writer ) ;
} else {
unset_module ( symbol , symbol - > rows , writer ) ;
}
writer + + ;
}
2020-12-21 22:30:07 +03:00
* p_latch = ! latch ;
2020-07-10 21:39:32 +03:00
return writer ;
}
/* Adjust top/bottom separator for finder patterns */
2020-12-21 22:30:07 +03:00
static void rss14_finder_adjust ( struct zint_symbol * symbol , const int separator_row , const int above_below ,
const int finder_start ) {
2020-07-10 21:39:32 +03:00
int i , finder_end ;
int module_row = separator_row + above_below ;
int latch ;
/* Alternation is always left-to-right for Omnidirectional separators (unlike for Expanded) */
2020-12-21 22:30:07 +03:00
latch = 1 ;
2020-07-10 21:39:32 +03:00
for ( i = finder_start , finder_end = finder_start + 13 ; i < finder_end ; i + + ) {
if ( ! module_is_set ( symbol , module_row , i ) ) {
2020-12-21 22:30:07 +03:00
if ( latch ) {
2020-07-10 21:39:32 +03:00
set_module ( symbol , separator_row , i ) ;
2020-12-21 22:30:07 +03:00
latch = 0 ;
2020-07-10 21:39:32 +03:00
} else {
unset_module ( symbol , separator_row , i ) ;
2020-12-21 22:30:07 +03:00
latch = 1 ;
2020-07-10 21:39:32 +03:00
}
} else {
unset_module ( symbol , separator_row , i ) ;
2020-12-21 22:30:07 +03:00
latch = 1 ;
2020-07-10 21:39:32 +03:00
}
}
}
/* Top/bottom separator for DataBar */
2020-12-21 22:30:07 +03:00
static void rss14_separator ( struct zint_symbol * symbol , int width , const int separator_row , const int above_below ,
const int finder_start , const int finder2_start , const int bottom_finder_value_3 ) {
2020-07-10 21:39:32 +03:00
int i , finder_end , finder_value_3_set ;
int module_row = separator_row + above_below ;
for ( i = 4 , width - = 4 ; i < width ; i + + ) {
if ( ! module_is_set ( symbol , module_row , i ) ) {
set_module ( symbol , separator_row , i ) ;
}
}
if ( bottom_finder_value_3 ) {
/* ISO/IEC 24724:2011 5.3.2.2 "The single dark module that occurs in the 13 modules over finder value 3 is
2021-06-19 15:11:23 +03:00
shifted one module to the right so that it is over the start of the three module - wide finder bar . " */
2020-07-10 21:39:32 +03:00
finder_value_3_set = finder_start + 10 ;
for ( i = finder_start , finder_end = finder_start + 13 ; i < finder_end ; i + + ) {
if ( i = = finder_value_3_set ) {
set_module ( symbol , separator_row , i ) ;
} else {
unset_module ( symbol , separator_row , i ) ;
}
}
} else {
if ( finder_start ) {
rss14_finder_adjust ( symbol , separator_row , above_below , finder_start ) ;
}
if ( finder2_start ) {
rss14_finder_adjust ( symbol , separator_row , above_below , finder2_start ) ;
}
}
}
2021-06-19 15:11:23 +03:00
/* Set Databar Stacked height, maintaining 5:7 ratio of the 2 main row heights */
INTERNAL int rss14_stk_set_height ( struct zint_symbol * symbol , const int first_row ) {
int error_number = 0 ;
float fixed_height = 0.0f ;
int second_row = first_row + 2 ; /* 2 row separator */
int i ;
for ( i = 0 ; i < symbol - > rows ; i + + ) {
if ( i ! = first_row & & i ! = second_row ) {
fixed_height + = symbol - > row_height [ i ] ;
}
}
if ( symbol - > height ) {
symbol - > row_height [ first_row ] = ( symbol - > height - fixed_height ) * symbol - > row_height [ first_row ] /
( symbol - > row_height [ first_row ] + symbol - > row_height [ second_row ] ) ;
if ( symbol - > row_height [ first_row ] < 0.5f ) { /* Absolute minimum */
symbol - > row_height [ first_row ] = 0.5f ;
symbol - > row_height [ second_row ] = 0.7f ;
} else {
symbol - > row_height [ second_row ] = symbol - > height - fixed_height - symbol - > row_height [ first_row ] ;
if ( symbol - > row_height [ second_row ] < 0.7f ) {
symbol - > row_height [ second_row ] = 0.7f ;
}
}
}
symbol - > height = symbol - > row_height [ first_row ] + symbol - > row_height [ second_row ] + fixed_height ;
# ifdef COMPLIANT_HEIGHTS
if ( symbol - > row_height [ first_row ] < 5.0f | | symbol - > row_height [ second_row ] < 7.0f ) {
error_number = ZINT_WARN_NONCOMPLIANT ;
strcpy ( symbol - > errtxt , " 379: Height not compliant with standards " ) ;
}
# endif
return error_number ;
}
/* GS1 DataBar Omnidirectional/Truncated/Stacked, allowing for composite if `cc_rows` set */
INTERNAL int rss14_cc ( struct zint_symbol * symbol , unsigned char source [ ] , int src_len , const int cc_rows ) {
int error_number , i ;
2020-06-14 16:42:40 +03:00
large_int accum ;
uint64_t left_pair , right_pair ;
int data_character [ 4 ] = { 0 } , data_group [ 4 ] = { 0 } , v_odd [ 4 ] , v_even [ 4 ] ;
2016-02-20 14:29:19 +03:00
int data_widths [ 8 ] [ 4 ] , checksum , c_left , c_right , total_widths [ 46 ] , writer ;
2020-12-21 22:30:07 +03:00
int latch ;
2017-09-10 18:03:09 +03:00
int separator_row ;
2020-07-10 21:39:32 +03:00
int widths [ 4 ] ;
2008-07-14 01:15:55 +04:00
2016-02-20 14:29:19 +03:00
separator_row = 0 ;
2008-07-14 01:15:55 +04:00
2020-07-10 21:39:32 +03:00
if ( src_len > 14 ) { /* Allow check digit to be specified (will be verified and ignored) */
2021-06-27 13:47:55 +03:00
strcpy ( symbol - > errtxt , " 380: Input too long (14 character maximum) " ) ;
2016-02-20 14:29:19 +03:00
return ZINT_ERROR_TOO_LONG ;
}
error_number = is_sane ( NEON , source , src_len ) ;
if ( error_number = = ZINT_ERROR_INVALID_DATA ) {
2021-07-06 21:53:31 +03:00
strcpy ( symbol - > errtxt , " 381: Invalid character in data (digits only) " ) ;
2016-02-20 14:29:19 +03:00
return error_number ;
}
2008-07-14 01:15:55 +04:00
2020-07-10 21:39:32 +03:00
if ( src_len = = 14 ) { /* Verify check digit */
2021-06-27 13:47:55 +03:00
if ( gs1_check_digit ( source , 13 ) ! = source [ 13 ] ) {
sprintf ( symbol - > errtxt , " 388: Invalid check digit '%c', expecting '%c' " ,
source [ 13 ] , gs1_check_digit ( source , 13 ) ) ;
2020-07-10 21:39:32 +03:00
return ZINT_ERROR_INVALID_CHECK ;
}
src_len - - ; /* Ignore */
}
2016-02-20 14:29:19 +03:00
/* make some room for a separator row for composite symbols */
switch ( symbol - > symbology ) {
2020-07-29 22:43:08 +03:00
case BARCODE_DBAR_OMN_CC :
case BARCODE_DBAR_STK_CC :
case BARCODE_DBAR_OMNSTK_CC :
2016-02-20 14:29:19 +03:00
separator_row = symbol - > rows ;
symbol - > row_height [ separator_row ] = 1 ;
symbol - > rows + = 1 ;
break ;
}
2008-07-14 01:15:55 +04:00
2020-06-14 16:42:40 +03:00
large_load_str_u64 ( & accum , source , src_len ) ;
2008-07-14 01:15:55 +04:00
2021-06-19 15:11:23 +03:00
if ( cc_rows ) {
2016-02-20 14:29:19 +03:00
/* Add symbol linkage flag */
2020-06-14 16:42:40 +03:00
large_add_u64 ( & accum , 10000000000000 ) ;
2016-02-20 14:29:19 +03:00
}
2008-07-14 01:15:55 +04:00
2016-02-20 14:29:19 +03:00
/* Calculate left and right pair values */
2020-06-14 16:42:40 +03:00
right_pair = large_div_u64 ( & accum , 4537077 ) ;
left_pair = large_lo ( & accum ) ;
2016-02-20 14:29:19 +03:00
/* Calculate four data characters */
2020-12-21 22:30:07 +03:00
data_character [ 0 ] = ( int ) ( left_pair / 1597 ) ;
data_character [ 1 ] = ( int ) ( left_pair % 1597 ) ;
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
data_character [ 2 ] = ( int ) ( right_pair / 1597 ) ;
data_character [ 3 ] = ( int ) ( right_pair % 1597 ) ;
2016-02-20 14:29:19 +03:00
/* Calculate odd and even subset values */
2020-12-21 22:30:07 +03:00
if ( data_character [ 0 ] < = 160 ) {
2016-02-20 14:29:19 +03:00
data_group [ 0 ] = 0 ;
2020-12-21 22:30:07 +03:00
} else if ( data_character [ 0 ] < = 960 ) {
2016-02-20 14:29:19 +03:00
data_group [ 0 ] = 1 ;
2020-12-21 22:30:07 +03:00
} else if ( data_character [ 0 ] < = 2014 ) {
2016-02-20 14:29:19 +03:00
data_group [ 0 ] = 2 ;
2020-12-21 22:30:07 +03:00
} else if ( data_character [ 0 ] < = 2714 ) {
2016-02-20 14:29:19 +03:00
data_group [ 0 ] = 3 ;
2020-12-21 22:30:07 +03:00
} else {
2016-02-20 14:29:19 +03:00
data_group [ 0 ] = 4 ;
}
2020-07-10 21:39:32 +03:00
2020-12-21 22:30:07 +03:00
if ( data_character [ 1 ] < = 335 ) {
2016-02-20 14:29:19 +03:00
data_group [ 1 ] = 5 ;
2020-12-21 22:30:07 +03:00
} else if ( data_character [ 1 ] < = 1035 ) {
2016-02-20 14:29:19 +03:00
data_group [ 1 ] = 6 ;
2020-12-21 22:30:07 +03:00
} else if ( data_character [ 1 ] < = 1515 ) {
2016-02-20 14:29:19 +03:00
data_group [ 1 ] = 7 ;
2020-12-21 22:30:07 +03:00
} else {
2016-02-20 14:29:19 +03:00
data_group [ 1 ] = 8 ;
}
2020-07-10 21:39:32 +03:00
2020-12-21 22:30:07 +03:00
if ( data_character [ 3 ] < = 335 ) {
2016-02-20 14:29:19 +03:00
data_group [ 3 ] = 5 ;
2020-12-21 22:30:07 +03:00
} else if ( data_character [ 3 ] < = 1035 ) {
2016-02-20 14:29:19 +03:00
data_group [ 3 ] = 6 ;
2020-12-21 22:30:07 +03:00
} else if ( data_character [ 3 ] < = 1515 ) {
2016-02-20 14:29:19 +03:00
data_group [ 3 ] = 7 ;
2020-12-21 22:30:07 +03:00
} else {
2016-02-20 14:29:19 +03:00
data_group [ 3 ] = 8 ;
}
2020-07-10 21:39:32 +03:00
2020-12-21 22:30:07 +03:00
if ( data_character [ 2 ] < = 160 ) {
2016-02-20 14:29:19 +03:00
data_group [ 2 ] = 0 ;
2020-12-21 22:30:07 +03:00
} else if ( data_character [ 2 ] < = 960 ) {
2016-02-20 14:29:19 +03:00
data_group [ 2 ] = 1 ;
2020-12-21 22:30:07 +03:00
} else if ( data_character [ 2 ] < = 2014 ) {
2016-02-20 14:29:19 +03:00
data_group [ 2 ] = 2 ;
2020-12-21 22:30:07 +03:00
} else if ( data_character [ 2 ] < = 2714 ) {
2016-02-20 14:29:19 +03:00
data_group [ 2 ] = 3 ;
2020-12-21 22:30:07 +03:00
} else {
2016-02-20 14:29:19 +03:00
data_group [ 2 ] = 4 ;
}
v_odd [ 0 ] = ( data_character [ 0 ] - g_sum_table [ data_group [ 0 ] ] ) / t_table [ data_group [ 0 ] ] ;
v_even [ 0 ] = ( data_character [ 0 ] - g_sum_table [ data_group [ 0 ] ] ) % t_table [ data_group [ 0 ] ] ;
v_odd [ 1 ] = ( data_character [ 1 ] - g_sum_table [ data_group [ 1 ] ] ) % t_table [ data_group [ 1 ] ] ;
v_even [ 1 ] = ( data_character [ 1 ] - g_sum_table [ data_group [ 1 ] ] ) / t_table [ data_group [ 1 ] ] ;
v_odd [ 3 ] = ( data_character [ 3 ] - g_sum_table [ data_group [ 3 ] ] ) % t_table [ data_group [ 3 ] ] ;
v_even [ 3 ] = ( data_character [ 3 ] - g_sum_table [ data_group [ 3 ] ] ) / t_table [ data_group [ 3 ] ] ;
v_odd [ 2 ] = ( data_character [ 2 ] - g_sum_table [ data_group [ 2 ] ] ) / t_table [ data_group [ 2 ] ] ;
v_even [ 2 ] = ( data_character [ 2 ] - g_sum_table [ data_group [ 2 ] ] ) % t_table [ data_group [ 2 ] ] ;
/* Use RSS subset width algorithm */
for ( i = 0 ; i < 4 ; i + + ) {
if ( ( i = = 0 ) | | ( i = = 2 ) ) {
2020-07-10 21:39:32 +03:00
getRSSwidths ( widths , v_odd [ i ] , modules_odd [ data_group [ i ] ] , 4 , widest_odd [ data_group [ i ] ] , 1 ) ;
2016-02-20 14:29:19 +03:00
data_widths [ 0 ] [ i ] = widths [ 0 ] ;
data_widths [ 2 ] [ i ] = widths [ 1 ] ;
data_widths [ 4 ] [ i ] = widths [ 2 ] ;
data_widths [ 6 ] [ i ] = widths [ 3 ] ;
2020-07-10 21:39:32 +03:00
getRSSwidths ( widths , v_even [ i ] , modules_even [ data_group [ i ] ] , 4 , widest_even [ data_group [ i ] ] , 0 ) ;
2016-02-20 14:29:19 +03:00
data_widths [ 1 ] [ i ] = widths [ 0 ] ;
data_widths [ 3 ] [ i ] = widths [ 1 ] ;
data_widths [ 5 ] [ i ] = widths [ 2 ] ;
data_widths [ 7 ] [ i ] = widths [ 3 ] ;
} else {
2020-07-10 21:39:32 +03:00
getRSSwidths ( widths , v_odd [ i ] , modules_odd [ data_group [ i ] ] , 4 , widest_odd [ data_group [ i ] ] , 0 ) ;
2016-02-20 14:29:19 +03:00
data_widths [ 0 ] [ i ] = widths [ 0 ] ;
data_widths [ 2 ] [ i ] = widths [ 1 ] ;
data_widths [ 4 ] [ i ] = widths [ 2 ] ;
data_widths [ 6 ] [ i ] = widths [ 3 ] ;
2020-07-10 21:39:32 +03:00
getRSSwidths ( widths , v_even [ i ] , modules_even [ data_group [ i ] ] , 4 , widest_even [ data_group [ i ] ] , 1 ) ;
2016-02-20 14:29:19 +03:00
data_widths [ 1 ] [ i ] = widths [ 0 ] ;
data_widths [ 3 ] [ i ] = widths [ 1 ] ;
data_widths [ 5 ] [ i ] = widths [ 2 ] ;
data_widths [ 7 ] [ i ] = widths [ 3 ] ;
}
}
checksum = 0 ;
/* Calculate the checksum */
for ( i = 0 ; i < 8 ; i + + ) {
checksum + = checksum_weight [ i ] * data_widths [ i ] [ 0 ] ;
checksum + = checksum_weight [ i + 8 ] * data_widths [ i ] [ 1 ] ;
checksum + = checksum_weight [ i + 16 ] * data_widths [ i ] [ 2 ] ;
checksum + = checksum_weight [ i + 24 ] * data_widths [ i ] [ 3 ] ;
}
checksum % = 79 ;
/* Calculate the two check characters */
if ( checksum > = 8 ) {
checksum + + ;
}
if ( checksum > = 72 ) {
checksum + + ;
}
c_left = checksum / 9 ;
c_right = checksum % 9 ;
2020-07-10 21:39:32 +03:00
if ( symbol - > debug & ZINT_DEBUG_PRINT ) {
printf ( " c_left: %d, c_right: %d \n " , c_left , c_right ) ;
}
2016-02-20 14:29:19 +03:00
/* Put element widths together */
total_widths [ 0 ] = 1 ;
total_widths [ 1 ] = 1 ;
total_widths [ 44 ] = 1 ;
total_widths [ 45 ] = 1 ;
for ( i = 0 ; i < 8 ; i + + ) {
total_widths [ i + 2 ] = data_widths [ i ] [ 0 ] ;
total_widths [ i + 15 ] = data_widths [ 7 - i ] [ 1 ] ;
total_widths [ i + 23 ] = data_widths [ i ] [ 3 ] ;
total_widths [ i + 36 ] = data_widths [ 7 - i ] [ 2 ] ;
}
for ( i = 0 ; i < 5 ; i + + ) {
total_widths [ i + 10 ] = finder_pattern [ i + ( 5 * c_left ) ] ;
total_widths [ i + 31 ] = finder_pattern [ ( 4 - i ) + ( 5 * c_right ) ] ;
}
/* Put this data into the symbol */
2020-07-29 22:43:08 +03:00
if ( ( symbol - > symbology = = BARCODE_DBAR_OMN ) | | ( symbol - > symbology = = BARCODE_DBAR_OMN_CC ) ) {
2016-02-20 14:29:19 +03:00
writer = 0 ;
2020-12-21 22:30:07 +03:00
latch = 0 ;
2016-02-20 14:29:19 +03:00
for ( i = 0 ; i < 46 ; i + + ) {
2020-07-10 21:39:32 +03:00
writer = rss_expand ( symbol , writer , & latch , total_widths [ i ] ) ;
2016-02-20 14:29:19 +03:00
}
if ( symbol - > width < writer ) {
symbol - > width = writer ;
}
2020-07-29 22:43:08 +03:00
if ( symbol - > symbology = = BARCODE_DBAR_OMN_CC ) {
2016-02-20 14:29:19 +03:00
/* separator pattern for composite symbol */
2020-07-10 21:39:32 +03:00
rss14_separator ( symbol , 96 , separator_row , 1 /*above*/ , 18 , 63 , 0 /*bottom_finder_value_3*/ ) ;
2016-02-20 14:29:19 +03:00
}
symbol - > rows = symbol - > rows + 1 ;
2020-07-10 21:39:32 +03:00
/* Set human readable text */
2021-06-27 13:47:55 +03:00
rss_set_gtin14_hrt ( symbol , source , src_len ) ;
2017-10-23 22:37:52 +03:00
2021-06-19 15:11:23 +03:00
# ifdef COMPLIANT_HEIGHTS
/* Minimum height is 13X for truncated symbol ISO/IEC 24724:2011 5.3.1
Default height is 33 X for DataBar Omnidirectional ISO / IEC 24724 : 2011 5.2 */
if ( symbol - > symbology = = BARCODE_DBAR_OMN_CC ) {
symbol - > height = symbol - > height ? 13.0f : 33.0f ; /* Pass back min row or default height */
} else {
error_number = set_height ( symbol , 13.0f , 33.0f , 0.0f , 0 /*no_errtxt*/ ) ;
}
# else
if ( symbol - > symbology = = BARCODE_DBAR_OMN_CC ) {
symbol - > height = 14.0f ; /* 14X truncated min row height used (should be 13X) */
} else {
( void ) set_height ( symbol , 0.0f , 50.0f , 0.0f , 1 /*no_errtxt*/ ) ;
}
# endif
2016-02-20 14:29:19 +03:00
2021-06-19 15:11:23 +03:00
} else if ( ( symbol - > symbology = = BARCODE_DBAR_STK ) | | ( symbol - > symbology = = BARCODE_DBAR_STK_CC ) ) {
2016-02-20 14:29:19 +03:00
/* top row */
writer = 0 ;
2020-12-21 22:30:07 +03:00
latch = 0 ;
2016-02-20 14:29:19 +03:00
for ( i = 0 ; i < 23 ; i + + ) {
2020-07-10 21:39:32 +03:00
writer = rss_expand ( symbol , writer , & latch , total_widths [ i ] ) ;
2016-02-20 14:29:19 +03:00
}
set_module ( symbol , symbol - > rows , writer ) ;
unset_module ( symbol , symbol - > rows , writer + 1 ) ;
2021-06-19 15:11:23 +03:00
symbol - > row_height [ symbol - > rows ] = 5.0f ; /* ISO/IEC 24724:2011 5.3.2.1 set to 5X */
2020-07-10 21:39:32 +03:00
2016-02-20 14:29:19 +03:00
/* bottom row */
symbol - > rows = symbol - > rows + 2 ;
set_module ( symbol , symbol - > rows , 0 ) ;
unset_module ( symbol , symbol - > rows , 1 ) ;
2020-07-10 21:39:32 +03:00
writer = 2 ;
2020-12-21 22:30:07 +03:00
latch = 1 ;
2016-02-20 14:29:19 +03:00
for ( i = 23 ; i < 46 ; i + + ) {
2020-07-10 21:39:32 +03:00
writer = rss_expand ( symbol , writer , & latch , total_widths [ i ] ) ;
2016-02-20 14:29:19 +03:00
}
2021-06-19 15:11:23 +03:00
symbol - > row_height [ symbol - > rows ] = 7.0f ; /* ISO/IEC 24724:2011 5.3.2.1 set to 7X */
2020-07-10 21:39:32 +03:00
2016-02-20 14:29:19 +03:00
/* separator pattern */
2020-07-10 21:39:32 +03:00
/* See #183 for this interpretation of ISO/IEC 24724:2011 5.3.2.1 */
2020-03-28 19:09:24 +03:00
for ( i = 1 ; i < 46 ; i + + ) {
2016-02-20 14:29:19 +03:00
if ( module_is_set ( symbol , symbol - > rows - 2 , i ) = = module_is_set ( symbol , symbol - > rows , i ) ) {
if ( ! ( module_is_set ( symbol , symbol - > rows - 2 , i ) ) ) {
set_module ( symbol , symbol - > rows - 1 , i ) ;
}
} else {
if ( ! ( module_is_set ( symbol , symbol - > rows - 1 , i - 1 ) ) ) {
set_module ( symbol , symbol - > rows - 1 , i ) ;
}
}
}
2020-03-28 19:09:24 +03:00
unset_module ( symbol , symbol - > rows - 1 , 1 ) ;
unset_module ( symbol , symbol - > rows - 1 , 2 ) ;
unset_module ( symbol , symbol - > rows - 1 , 3 ) ;
2016-02-20 14:29:19 +03:00
symbol - > row_height [ symbol - > rows - 1 ] = 1 ;
2020-07-10 21:39:32 +03:00
2020-07-29 22:43:08 +03:00
if ( symbol - > symbology = = BARCODE_DBAR_STK_CC ) {
2016-02-20 14:29:19 +03:00
/* separator pattern for composite symbol */
2020-07-10 21:39:32 +03:00
rss14_separator ( symbol , 50 , separator_row , 1 /*above*/ , 18 , 0 , 0 /*bottom_finder_value_3*/ ) ;
2016-02-20 14:29:19 +03:00
}
symbol - > rows = symbol - > rows + 1 ;
if ( symbol - > width < 50 ) {
symbol - > width = 50 ;
}
2021-06-19 15:11:23 +03:00
if ( symbol - > symbology ! = BARCODE_DBAR_STK_CC ) { /* Composite calls rss14_stk_set_height() itself */
error_number = rss14_stk_set_height ( symbol , 0 /*first_row*/ ) ;
}
} else if ( ( symbol - > symbology = = BARCODE_DBAR_OMNSTK ) | | ( symbol - > symbology = = BARCODE_DBAR_OMNSTK_CC ) ) {
2016-02-20 14:29:19 +03:00
/* top row */
writer = 0 ;
2020-12-21 22:30:07 +03:00
latch = 0 ;
2016-02-20 14:29:19 +03:00
for ( i = 0 ; i < 23 ; i + + ) {
2020-07-10 21:39:32 +03:00
writer = rss_expand ( symbol , writer , & latch , total_widths [ i ] ) ;
2016-02-20 14:29:19 +03:00
}
set_module ( symbol , symbol - > rows , writer ) ;
unset_module ( symbol , symbol - > rows , writer + 1 ) ;
2020-07-10 21:39:32 +03:00
2016-02-20 14:29:19 +03:00
/* bottom row */
symbol - > rows = symbol - > rows + 4 ;
set_module ( symbol , symbol - > rows , 0 ) ;
unset_module ( symbol , symbol - > rows , 1 ) ;
2020-07-10 21:39:32 +03:00
writer = 2 ;
2020-12-21 22:30:07 +03:00
latch = 1 ;
2016-02-20 14:29:19 +03:00
for ( i = 23 ; i < 46 ; i + + ) {
2020-07-10 21:39:32 +03:00
writer = rss_expand ( symbol , writer , & latch , total_widths [ i ] ) ;
2016-02-20 14:29:19 +03:00
}
2020-07-10 21:39:32 +03:00
2016-02-20 14:29:19 +03:00
/* middle separator */
for ( i = 5 ; i < 46 ; i + = 2 ) {
set_module ( symbol , symbol - > rows - 2 , i ) ;
}
symbol - > row_height [ symbol - > rows - 2 ] = 1 ;
2020-07-10 21:39:32 +03:00
2016-02-20 14:29:19 +03:00
/* top separator */
2020-07-10 21:39:32 +03:00
rss14_separator ( symbol , 50 , symbol - > rows - 3 , - 1 /*below*/ , 18 , 0 , 0 /*bottom_finder_value_3*/ ) ;
2016-02-20 14:29:19 +03:00
symbol - > row_height [ symbol - > rows - 3 ] = 1 ;
2020-07-10 21:39:32 +03:00
2016-02-20 14:29:19 +03:00
/* bottom separator */
2020-07-10 21:39:32 +03:00
/* 17 == 2 (guard) + 15 (inner char); +2 to skip over finder elements 4 & 5 (right to left) */
rss14_separator ( symbol , 50 , symbol - > rows - 1 , 1 /*above*/ , 17 + 2 , 0 , c_right = = 3 ) ;
2016-02-20 14:29:19 +03:00
symbol - > row_height [ symbol - > rows - 1 ] = 1 ;
if ( symbol - > width < 50 ) {
symbol - > width = 50 ;
}
2020-07-10 21:39:32 +03:00
2020-07-29 22:43:08 +03:00
if ( symbol - > symbology = = BARCODE_DBAR_OMNSTK_CC ) {
2016-02-20 14:29:19 +03:00
/* separator pattern for composite symbol */
2020-07-10 21:39:32 +03:00
rss14_separator ( symbol , 50 , separator_row , 1 /*above*/ , 18 , 0 , 0 /*bottom_finder_value_3*/ ) ;
2016-02-20 14:29:19 +03:00
}
symbol - > rows = symbol - > rows + 1 ;
2017-10-23 22:37:52 +03:00
2021-06-19 15:11:23 +03:00
/* ISO/IEC 24724:2011 5.3.2.2 minimum 33X height per row */
if ( symbol - > symbology = = BARCODE_DBAR_OMNSTK_CC ) {
symbol - > height = symbol - > height ? 33.0f : 66.0f ; /* Pass back min row or default height */
} else {
# ifdef COMPLIANT_HEIGHTS
error_number = set_height ( symbol , 33.0f , 66.0f , 0.0f , 0 /*no_errtxt*/ ) ;
# else
( void ) set_height ( symbol , 0.0f , 66.0f , 0.0f , 1 /*no_errtxt*/ ) ;
# endif
}
2016-02-20 14:29:19 +03:00
}
return error_number ;
2008-07-14 01:15:55 +04:00
}
2021-06-19 15:11:23 +03:00
/* GS1 DataBar Omnidirectional/Truncated/Stacked */
INTERNAL int rss14 ( struct zint_symbol * symbol , unsigned char source [ ] , int src_len ) {
return rss14_cc ( symbol , source , src_len , 0 /*cc_rows*/ ) ;
}
/* GS1 DataBar Limited, allowing for composite if `cc_rows` set */
INTERNAL int rsslimited_cc ( struct zint_symbol * symbol , unsigned char source [ ] , int src_len , const int cc_rows ) {
int error_number , i ;
2020-06-14 16:42:40 +03:00
large_int accum ;
uint64_t left_character , right_character ;
2016-02-20 14:29:19 +03:00
int left_group , right_group , left_odd , left_even , right_odd , right_even ;
2020-06-14 16:42:40 +03:00
int left_widths [ 14 ] , right_widths [ 14 ] ;
2020-09-11 10:07:21 +03:00
int checksum , check_elements [ 14 ] , total_widths [ 47 ] , writer ;
2020-12-21 22:30:07 +03:00
int latch ;
2016-02-20 14:29:19 +03:00
int separator_row ;
2020-07-10 21:39:32 +03:00
int widths [ 7 ] ;
2008-07-14 01:15:55 +04:00
2016-02-20 14:29:19 +03:00
separator_row = 0 ;
2020-07-10 21:39:32 +03:00
if ( src_len > 14 ) { /* Allow check digit to be specified (will be verified and ignored) */
2021-06-27 13:47:55 +03:00
strcpy ( symbol - > errtxt , " 382: Input too long (14 character maximum) " ) ;
2016-02-20 14:29:19 +03:00
return ZINT_ERROR_TOO_LONG ;
}
error_number = is_sane ( NEON , source , src_len ) ;
if ( error_number = = ZINT_ERROR_INVALID_DATA ) {
2021-07-06 21:53:31 +03:00
strcpy ( symbol - > errtxt , " 383: Invalid character in data (digits only) " ) ;
2016-02-20 14:29:19 +03:00
return error_number ;
}
2020-07-10 21:39:32 +03:00
if ( src_len = = 14 ) { /* Verify check digit */
2021-06-27 13:47:55 +03:00
if ( gs1_check_digit ( source , 13 ) ! = source [ 13 ] ) {
sprintf ( symbol - > errtxt , " 389: Invalid check digit '%c', expecting '%c' " ,
source [ 13 ] , gs1_check_digit ( source , 13 ) ) ;
2020-07-10 21:39:32 +03:00
return ZINT_ERROR_INVALID_CHECK ;
}
src_len - - ; /* Ignore */
}
2016-02-20 14:29:19 +03:00
if ( src_len = = 13 ) {
if ( ( source [ 0 ] ! = ' 0 ' ) & & ( source [ 0 ] ! = ' 1 ' ) ) {
2021-06-27 13:47:55 +03:00
strcpy ( symbol - > errtxt , " 384: Input out of range (0 to 1999999999999) " ) ;
2016-02-20 14:29:19 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
}
/* make some room for a separator row for composite symbols */
2020-07-29 22:43:08 +03:00
if ( symbol - > symbology = = BARCODE_DBAR_LTD_CC ) {
2016-02-20 14:29:19 +03:00
separator_row = symbol - > rows ;
symbol - > row_height [ separator_row ] = 1 ;
symbol - > rows + = 1 ;
}
2020-06-14 16:42:40 +03:00
large_load_str_u64 ( & accum , source , src_len ) ;
2016-02-20 14:29:19 +03:00
2021-06-19 15:11:23 +03:00
if ( cc_rows ) {
2016-02-20 14:29:19 +03:00
/* Add symbol linkage flag */
2020-06-14 16:42:40 +03:00
large_add_u64 ( & accum , 2015133531096 ) ;
2016-02-20 14:29:19 +03:00
}
/* Calculate left and right pair values */
2020-06-14 16:42:40 +03:00
right_character = large_div_u64 ( & accum , 2013571 ) ;
left_character = large_lo ( & accum ) ;
2016-02-20 14:29:19 +03:00
2020-06-14 16:42:40 +03:00
if ( left_character > = 1996939 ) {
2016-02-20 14:29:19 +03:00
left_group = 6 ;
2020-06-14 16:42:40 +03:00
left_character - = 1996939 ;
} else if ( left_character > = 1979845 ) {
left_group = 5 ;
left_character - = 1979845 ;
} else if ( left_character > = 1491021 ) {
left_group = 4 ;
left_character - = 1491021 ;
} else if ( left_character > = 1000776 ) {
left_group = 3 ;
left_character - = 1000776 ;
} else if ( left_character > = 820064 ) {
left_group = 2 ;
left_character - = 820064 ;
} else if ( left_character > = 183064 ) {
left_group = 1 ;
left_character - = 183064 ;
} else {
left_group = 0 ;
2016-02-20 14:29:19 +03:00
}
2020-06-14 16:42:40 +03:00
if ( right_character > = 1996939 ) {
right_group = 6 ;
right_character - = 1996939 ;
} else if ( right_character > = 1979845 ) {
right_group = 5 ;
right_character - = 1979845 ;
} else if ( right_character > = 1491021 ) {
right_group = 4 ;
right_character - = 1491021 ;
} else if ( right_character > = 1000776 ) {
right_group = 3 ;
right_character - = 1000776 ;
} else if ( right_character > = 820064 ) {
right_group = 2 ;
right_character - = 820064 ;
} else if ( right_character > = 183064 ) {
right_group = 1 ;
right_character - = 183064 ;
} else {
right_group = 0 ;
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
left_odd = ( int ) ( left_character / t_even_ltd [ left_group ] ) ;
left_even = ( int ) ( left_character % t_even_ltd [ left_group ] ) ;
right_odd = ( int ) ( right_character / t_even_ltd [ right_group ] ) ;
right_even = ( int ) ( right_character % t_even_ltd [ right_group ] ) ;
2016-02-20 14:29:19 +03:00
2020-07-10 21:39:32 +03:00
getRSSwidths ( widths , left_odd , modules_odd_ltd [ left_group ] , 7 , widest_odd_ltd [ left_group ] , 1 ) ;
for ( i = 0 ; i < = 6 ; i + + ) {
left_widths [ i * 2 ] = widths [ i ] ;
}
getRSSwidths ( widths , left_even , modules_even_ltd [ left_group ] , 7 , widest_even_ltd [ left_group ] , 0 ) ;
for ( i = 0 ; i < = 6 ; i + + ) {
left_widths [ i * 2 + 1 ] = widths [ i ] ;
}
getRSSwidths ( widths , right_odd , modules_odd_ltd [ right_group ] , 7 , widest_odd_ltd [ right_group ] , 1 ) ;
for ( i = 0 ; i < = 6 ; i + + ) {
right_widths [ i * 2 ] = widths [ i ] ;
}
getRSSwidths ( widths , right_even , modules_even_ltd [ right_group ] , 7 , widest_even_ltd [ right_group ] , 0 ) ;
for ( i = 0 ; i < = 6 ; i + + ) {
right_widths [ i * 2 + 1 ] = widths [ i ] ;
}
2016-02-20 14:29:19 +03:00
checksum = 0 ;
/* Calculate the checksum */
for ( i = 0 ; i < 14 ; i + + ) {
2021-06-27 17:58:27 +03:00
# if _MSC_VER == 1900 && defined(_WIN64) /* MSVC 2015 x64 */
checksum % = 89 ; /* Hack to get around optimizer bug */
# endif
2016-02-20 14:29:19 +03:00
checksum + = checksum_weight_ltd [ i ] * left_widths [ i ] ;
checksum + = checksum_weight_ltd [ i + 14 ] * right_widths [ i ] ;
}
checksum % = 89 ;
for ( i = 0 ; i < 14 ; i + + ) {
check_elements [ i ] = finder_pattern_ltd [ i + ( checksum * 14 ) ] ;
}
total_widths [ 0 ] = 1 ;
total_widths [ 1 ] = 1 ;
total_widths [ 44 ] = 1 ;
total_widths [ 45 ] = 1 ;
2020-09-11 10:07:21 +03:00
total_widths [ 46 ] = 5 ;
2016-02-20 14:29:19 +03:00
for ( i = 0 ; i < 14 ; i + + ) {
total_widths [ i + 2 ] = left_widths [ i ] ;
total_widths [ i + 16 ] = check_elements [ i ] ;
total_widths [ i + 30 ] = right_widths [ i ] ;
}
writer = 0 ;
2020-12-21 22:30:07 +03:00
latch = 0 ;
2020-09-11 10:07:21 +03:00
for ( i = 0 ; i < 47 ; i + + ) {
2020-07-10 21:39:32 +03:00
writer = rss_expand ( symbol , writer , & latch , total_widths [ i ] ) ;
2016-02-20 14:29:19 +03:00
}
if ( symbol - > width < writer ) {
symbol - > width = writer ;
}
symbol - > rows = symbol - > rows + 1 ;
/* add separator pattern if composite symbol */
2020-07-29 22:43:08 +03:00
if ( symbol - > symbology = = BARCODE_DBAR_LTD_CC ) {
2016-02-20 14:29:19 +03:00
for ( i = 4 ; i < 70 ; i + + ) {
if ( ! ( module_is_set ( symbol , separator_row + 1 , i ) ) ) {
set_module ( symbol , separator_row , i ) ;
}
}
}
2020-07-10 21:39:32 +03:00
/* Set human readable text */
2021-06-27 13:47:55 +03:00
rss_set_gtin14_hrt ( symbol , source , src_len ) ;
2017-10-23 22:37:52 +03:00
2021-06-19 15:11:23 +03:00
/* ISO/IEC 24724:2011 6.2 10X minimum height, use as default also */
if ( symbol - > symbology = = BARCODE_DBAR_LTD_CC ) {
symbol - > height = 10.0f ; /* Pass back min row == default height */
} else {
# ifdef COMPLIANT_HEIGHTS
error_number = set_height ( symbol , 10.0f , 10.0f , 0.0f , 0 /*no_errtxt*/ ) ;
# else
( void ) set_height ( symbol , 0.0f , 50.0f , 0.0f , 1 /*no_errtxt*/ ) ;
# endif
}
2016-02-20 14:29:19 +03:00
return error_number ;
}
2021-06-19 15:11:23 +03:00
/* GS1 DataBar Limited */
INTERNAL int rsslimited ( struct zint_symbol * symbol , unsigned char source [ ] , int src_len ) {
return rsslimited_cc ( symbol , source , src_len , 0 /*cc_rows*/ ) ;
}
2020-12-21 22:30:07 +03:00
/* Check and convert date to RSS date value */
INTERNAL int rss_date ( const unsigned char source [ ] , const int src_posn ) {
int yy = to_int ( source + src_posn , 2 ) ;
int mm = to_int ( source + src_posn + 2 , 2 ) ;
int dd = to_int ( source + src_posn + 4 , 2 ) ;
/* Month can't be zero but day can (means last day of month,
2021-06-19 15:11:23 +03:00
GS1 General Specifications Sections 3.4 .2 to 3.4 .7 ) */
2020-12-21 22:30:07 +03:00
if ( yy < 0 | | mm < = 0 | | mm > 12 | | dd < 0 | | dd > 31 ) {
return - 1 ;
}
return yy * 384 + ( mm - 1 ) * 32 + dd ;
}
2016-02-20 14:29:19 +03:00
/* Handles all data encodation from section 7.2.5 of ISO/IEC 24724 */
2021-06-27 13:47:55 +03:00
static int rssexp_binary_string ( struct zint_symbol * symbol , const unsigned char source [ ] , char binary_string [ ] ,
int cols_per_row , int * p_bp ) {
2020-12-21 22:30:07 +03:00
int encoding_method , i , j , read_posn , debug = ( symbol - > debug & ZINT_DEBUG_PRINT ) , mode = NUMERIC ;
char last_digit = ' \0 ' ;
2021-06-27 13:47:55 +03:00
int symbol_characters , characters_per_row = cols_per_row * 2 ;
2020-12-21 22:30:07 +03:00
int length = ( int ) ustrlen ( source ) ;
2009-06-03 00:23:38 +04:00
# ifndef _MSC_VER
2020-12-21 22:30:07 +03:00
char general_field [ length + 1 ] ;
2009-06-03 00:23:38 +04:00
# else
2020-12-21 22:30:07 +03:00
char * general_field = ( char * ) _alloca ( length + 1 ) ;
2009-06-03 00:23:38 +04:00
# endif
2020-12-21 22:30:07 +03:00
int bp = * p_bp ;
2017-05-14 10:15:08 +03:00
int remainder , d1 , d2 ;
2020-12-21 22:30:07 +03:00
int cdf_bp_start ; /* Compressed data field start - debug only */
2008-10-03 12:31:53 +04:00
2016-02-20 14:29:19 +03:00
/* Decide whether a compressed data field is required and if so what
method to use - method 2 = no compressed data field */
2020-12-21 22:30:07 +03:00
if ( ( length > = 16 ) & & ( ( source [ 0 ] = = ' 0 ' ) & & ( source [ 1 ] = = ' 1 ' ) ) ) {
2016-02-20 14:29:19 +03:00
/* (01) and other AIs */
encoding_method = 1 ;
if ( debug ) printf ( " Choosing Method 1 \n " ) ;
} else {
/* any AIs */
encoding_method = 2 ;
2018-04-18 22:24:21 +03:00
if ( debug ) printf ( " Choosing Method 2 \n " ) ;
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
if ( ( ( length > = 20 ) & & ( encoding_method = = 1 ) ) & & ( ( source [ 2 ] = = ' 9 ' ) & & ( source [ 16 ] = = ' 3 ' ) ) ) {
2016-02-20 14:29:19 +03:00
/* Possibly encoding method > 2 */
2020-12-21 22:30:07 +03:00
2016-02-20 14:29:19 +03:00
if ( debug ) printf ( " Checking for other methods \n " ) ;
2020-12-21 22:30:07 +03:00
if ( ( length > = 26 ) & & ( source [ 17 ] = = ' 1 ' ) & & ( source [ 18 ] = = ' 0 ' ) ) {
2016-02-20 14:29:19 +03:00
/* Methods 3, 7, 9, 11 and 13 */
2020-12-21 22:30:07 +03:00
/* (01) and (310x) */
int weight = to_int ( source + 20 , 6 ) ;
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
/* Maximum weight = 99999 for 7 to 14 (ISO/IEC 24724:2011 7.2.5.4.4) */
if ( weight > = 0 & & weight < = 99999 ) {
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
if ( length = = 26 ) {
if ( ( source [ 19 ] = = ' 3 ' ) & & weight < = 32767 ) { /* In grams, max 32.767 kilos */
2016-02-20 14:29:19 +03:00
/* (01) and (3103) */
2020-12-21 22:30:07 +03:00
encoding_method = 3 ;
} else {
/* (01), (310x) - use method 7 with dummy date 38400 */
encoding_method = 7 ;
2016-02-20 14:29:19 +03:00
}
2021-06-27 13:47:55 +03:00
} else if ( ( length = = 34 ) & & ( source [ 26 ] = = ' 1 ' )
& & ( source [ 27 ] = = ' 1 ' | | source [ 27 ] = = ' 3 ' | | source [ 27 ] = = ' 5 ' | | source [ 27 ] = = ' 7 ' )
& & rss_date ( source , 28 ) > = 0 ) {
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
/* (01), (310x) and (11) - metric weight and production date */
/* (01), (310x) and (13) - metric weight and packaging date */
/* (01), (310x) and (15) - metric weight and "best before" date */
/* (01), (310x) and (17) - metric weight and expiration date */
encoding_method = 6 + ( source [ 27 ] - ' 0 ' ) ;
2016-02-20 14:29:19 +03:00
}
}
2020-12-21 22:30:07 +03:00
} else if ( ( length > = 26 ) & & ( source [ 17 ] = = ' 2 ' ) & & ( source [ 18 ] = = ' 0 ' ) ) {
2016-02-20 14:29:19 +03:00
/* Methods 4, 8, 10, 12 and 14 */
2020-12-21 22:30:07 +03:00
/* (01) and (320x) */
int weight = to_int ( source + 20 , 6 ) ;
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
/* Maximum weight = 99999 for 7 to 14 (ISO/IEC 24724:2011 7.2.5.4.4) */
if ( weight > = 0 & & weight < = 99999 ) {
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
/* (3202) in 0.01 pounds, max 99.99 pounds; (3203) in 0.001 pounds, max 22.767 pounds */
if ( length = = 26 ) {
if ( ( source [ 19 ] = = ' 2 ' & & weight < = 9999 ) | | ( source [ 19 ] = = ' 3 ' & & weight < = 22767 ) ) {
2016-02-20 14:29:19 +03:00
/* (01) and (3202)/(3203) */
2020-12-21 22:30:07 +03:00
encoding_method = 4 ;
} else {
/* (01), (320x) - use method 8 with dummy date 38400 */
encoding_method = 8 ;
2016-02-20 14:29:19 +03:00
}
2021-06-27 13:47:55 +03:00
} else if ( ( length = = 34 ) & & ( source [ 26 ] = = ' 1 ' )
& & ( source [ 27 ] = = ' 1 ' | | source [ 27 ] = = ' 3 ' | | source [ 27 ] = = ' 5 ' | | source [ 27 ] = = ' 7 ' )
& & rss_date ( source , 28 ) > = 0 ) {
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
/* (01), (320x) and (11) - English weight and production date */
/* (01), (320x) and (13) - English weight and packaging date */
/* (01), (320x) and (15) - English weight and "best before" date */
/* (01), (320x) and (17) - English weight and expiration date */
encoding_method = 7 + ( source [ 27 ] - ' 0 ' ) ;
2016-02-20 14:29:19 +03:00
}
}
2020-12-21 22:30:07 +03:00
} else if ( ( source [ 17 ] = = ' 9 ' ) & & ( ( source [ 19 ] > = ' 0 ' ) & & ( source [ 19 ] < = ' 3 ' ) ) ) {
2016-02-20 14:29:19 +03:00
/* Methods 5 and 6 */
2020-12-21 22:30:07 +03:00
if ( source [ 18 ] = = ' 2 ' ) {
2016-02-20 14:29:19 +03:00
/* (01) and (392x) */
encoding_method = 5 ;
2020-12-21 22:30:07 +03:00
} else if ( source [ 18 ] = = ' 3 ' & & to_int ( source + 20 , 3 ) > = 0 ) { /* Check 3-digit currency string */
2016-02-20 14:29:19 +03:00
/* (01) and (393x) */
encoding_method = 6 ;
}
}
2020-12-21 22:30:07 +03:00
if ( debug & & encoding_method ! = 1 ) printf ( " Now using method %d \n " , encoding_method ) ;
2016-02-20 14:29:19 +03:00
}
switch ( encoding_method ) { /* Encoding method - Table 10 */
2020-12-21 22:30:07 +03:00
case 1 : bp = bin_append_posn ( 4 , 3 , binary_string , bp ) ; /* "1XX" */
2016-02-20 14:29:19 +03:00
read_posn = 16 ;
break ;
2020-12-21 22:30:07 +03:00
case 2 : bp = bin_append_posn ( 0 , 4 , binary_string , bp ) ; /* "00XX" */
2016-02-20 14:29:19 +03:00
read_posn = 0 ;
break ;
2017-05-14 10:15:08 +03:00
case 3 : // 0100
case 4 : // 0101
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( 4 + ( encoding_method - 3 ) , 4 , binary_string , bp ) ;
read_posn = 26 ;
2016-02-20 14:29:19 +03:00
break ;
2020-12-21 22:30:07 +03:00
case 5 : bp = bin_append_posn ( 0x30 , 7 , binary_string , bp ) ; /* "01100XX" */
2016-02-20 14:29:19 +03:00
read_posn = 20 ;
break ;
2020-12-21 22:30:07 +03:00
case 6 : bp = bin_append_posn ( 0x34 , 7 , binary_string , bp ) ; /* "01101XX" */
2016-02-20 14:29:19 +03:00
read_posn = 23 ;
break ;
2017-05-14 10:15:08 +03:00
default : /* modes 7 to 14 */
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( 56 + ( encoding_method - 7 ) , 7 , binary_string , bp ) ;
read_posn = length ; /* 34 or 26 */
2016-02-20 14:29:19 +03:00
break ;
}
2020-12-21 22:30:07 +03:00
if ( debug ) printf ( " Setting binary = %.*s \n " , bp , binary_string ) ;
2016-02-20 14:29:19 +03:00
/* Variable length symbol bit field is just given a place holder (XX)
for the time being */
/* Verify that the data to be placed in the compressed data field is all
numeric data before carrying out compression */
for ( i = 0 ; i < read_posn ; i + + ) {
if ( ( source [ i ] < ' 0 ' ) | | ( source [ i ] > ' 9 ' ) ) {
2020-12-21 22:30:07 +03:00
if ( source [ i ] ! = ' [ ' ) {
2016-02-20 14:29:19 +03:00
/* Something is wrong */
2021-07-13 19:39:03 +03:00
strcpy ( symbol - > errtxt , " 385: Invalid character in Compressed Field data (digits only) " ) ;
2016-02-20 14:29:19 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
}
}
/* Now encode the compressed data field */
if ( debug ) printf ( " Proceeding to encode data \n " ) ;
2020-12-21 22:30:07 +03:00
cdf_bp_start = bp ; /* Debug use only */
2016-02-20 14:29:19 +03:00
if ( encoding_method = = 1 ) {
/* Encoding method field "1" - general item identification data */
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( ctoi ( source [ 2 ] ) , 4 , binary_string , bp ) ; /* Leading digit after stripped "01" */
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
for ( i = 3 ; i < 15 ; i + = 3 ) { /* Next 12 digits, excluding final check digit */
bp = bin_append_posn ( to_int ( source + i , 3 ) , 10 , binary_string , bp ) ;
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
} else if ( ( encoding_method = = 3 ) | | ( encoding_method = = 4 ) ) {
2016-02-20 14:29:19 +03:00
/* Encoding method field "0100" - variable weight item
( 0 , 001 kilogram icrements ) */
2017-05-14 10:15:08 +03:00
/* Encoding method field "0101" - variable weight item (0,01 or
0 , 001 pound increment ) */
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
for ( i = 3 ; i < 15 ; i + = 3 ) { /* Leading "019" stripped, and final check digit excluded */
bp = bin_append_posn ( to_int ( source + i , 3 ) , 10 , binary_string , bp ) ;
2016-02-20 14:29:19 +03:00
}
2017-05-14 10:15:08 +03:00
if ( ( encoding_method = = 4 ) & & ( source [ 19 ] = = ' 3 ' ) ) {
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( to_int ( source + 20 , 6 ) + 10000 , 15 , binary_string , bp ) ;
2017-05-14 10:15:08 +03:00
} else {
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( to_int ( source + 20 , 6 ) , 15 , binary_string , bp ) ;
2016-02-20 14:29:19 +03:00
}
2017-10-23 22:37:52 +03:00
2020-12-21 22:30:07 +03:00
} else if ( ( encoding_method = = 5 ) | | ( encoding_method = = 6 ) ) {
2017-05-14 10:15:08 +03:00
/* Encoding method "01100" - variable measure item and price */
/* Encoding method "01101" - variable measure item and price with ISO 4217
Currency Code */
2017-10-23 22:37:52 +03:00
2020-12-21 22:30:07 +03:00
for ( i = 3 ; i < 15 ; i + = 3 ) { /* Leading "019" stripped, and final check digit excluded */
bp = bin_append_posn ( to_int ( source + i , 3 ) , 10 , binary_string , bp ) ;
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( source [ 19 ] - ' 0 ' , 2 , binary_string , bp ) ; /* 0-3 x of 392x/393x */
2017-10-23 22:37:52 +03:00
2017-05-14 10:15:08 +03:00
if ( encoding_method = = 6 ) {
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( to_int ( source + 20 , 3 ) , 10 , binary_string , bp ) ; /* 3-digit currency */
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
} else if ( ( encoding_method > = 7 ) & & ( encoding_method < = 14 ) ) {
2016-02-20 14:29:19 +03:00
/* Encoding method fields "0111000" through "0111111" - variable
weight item plus date */
int group_val ;
char weight_str [ 8 ] ;
2020-12-21 22:30:07 +03:00
for ( i = 3 ; i < 15 ; i + = 3 ) { /* Leading "019" stripped, and final check digit excluded */
bp = bin_append_posn ( to_int ( source + i , 3 ) , 10 , binary_string , bp ) ;
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
weight_str [ 0 ] = source [ 19 ] ; /* 0-9 x of 310x/320x */
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
for ( i = 1 ; i < 6 ; i + + ) { /* Leading "0" of weight excluded */
weight_str [ i ] = source [ 20 + i ] ;
2016-02-20 14:29:19 +03:00
}
weight_str [ 6 ] = ' \0 ' ;
2017-10-23 22:37:52 +03:00
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( atoi ( weight_str ) , 20 , binary_string , bp ) ;
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
if ( length = = 34 ) {
2016-02-20 14:29:19 +03:00
/* Date information is included */
2020-12-21 22:30:07 +03:00
group_val = rss_date ( source , 28 ) ;
2016-02-20 14:29:19 +03:00
} else {
group_val = 38400 ;
}
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( ( int ) group_val , 16 , binary_string , bp ) ;
}
if ( debug & & bp > cdf_bp_start ) {
printf ( " Compressed data field (%d) = %.*s \n " , bp - cdf_bp_start , bp - cdf_bp_start ,
binary_string + cdf_bp_start ) ;
2016-02-20 14:29:19 +03: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 ;
2020-12-21 22:30:07 +03:00
for ( i = read_posn ; i < length ; i + + ) {
2016-02-20 14:29:19 +03:00
general_field [ j ] = source [ i ] ;
j + + ;
}
general_field [ j ] = ' \0 ' ;
2020-12-21 22:30:07 +03:00
2016-02-20 14:29:19 +03:00
if ( debug ) printf ( " General field data = %s \n " , general_field ) ;
2020-12-21 22:30:07 +03:00
if ( j ! = 0 ) { /* If general field not empty */
2021-07-13 19:39:03 +03:00
if ( ! general_field_encode ( general_field , j , & mode , & last_digit , binary_string , & bp ) ) { /* Failure should never happen */
/* Not reachable */
strcpy ( symbol - > errtxt , " 386: Invalid character in General Field data " ) ;
2020-12-21 22:30:07 +03:00
return ZINT_ERROR_INVALID_DATA ;
}
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
if ( debug ) printf ( " Resultant binary = %.*s \n \t Length: %d \n " , bp , binary_string , bp ) ;
remainder = 12 - ( bp % 12 ) ;
2016-02-20 14:29:19 +03:00
if ( remainder = = 12 ) {
remainder = 0 ;
}
2020-12-21 22:30:07 +03:00
symbol_characters = ( ( bp + remainder ) / 12 ) + 1 ;
2017-10-23 22:37:52 +03:00
2021-06-27 13:47:55 +03:00
if ( characters_per_row & & ( symbol_characters % characters_per_row ) = = 1 ) { // DBAR_EXPSTK
symbol_characters + + ;
2016-02-20 14:29:19 +03:00
}
2017-10-23 22:37:52 +03:00
2019-10-31 05:01:42 +03:00
if ( symbol_characters < 4 ) {
symbol_characters = 4 ;
2016-10-09 16:10:39 +03:00
}
2017-10-23 22:37:52 +03:00
2020-12-21 22:30:07 +03:00
remainder = ( 12 * ( symbol_characters - 1 ) ) - bp ;
2017-10-23 22:37:52 +03:00
2019-10-31 05:01:42 +03:00
if ( last_digit ) {
2016-02-20 14:29:19 +03:00
/* There is still one more numeric digit to encode */
if ( debug ) printf ( " Adding extra (odd) numeric digit \n " ) ;
2019-10-31 05:31:55 +03:00
if ( ( remainder > = 4 ) & & ( remainder < = 6 ) ) {
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( ctoi ( last_digit ) + 1 , 4 , binary_string , bp ) ;
2016-02-20 14:29:19 +03:00
} else {
2019-10-31 05:31:55 +03:00
d1 = ctoi ( last_digit ) ;
d2 = 10 ;
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( ( 11 * d1 ) + d2 + 8 , 7 , binary_string , bp ) ;
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
remainder = 12 - ( bp % 12 ) ;
2016-02-20 14:29:19 +03:00
if ( remainder = = 12 ) {
remainder = 0 ;
}
2020-12-21 22:30:07 +03:00
symbol_characters = ( ( bp + remainder ) / 12 ) + 1 ;
2016-10-09 16:10:39 +03:00
2021-06-27 13:47:55 +03:00
if ( characters_per_row & & ( symbol_characters % characters_per_row ) = = 1 ) { // DBAR_EXPSTK
symbol_characters + + ;
2016-10-09 16:10:39 +03:00
}
2019-10-31 05:01:42 +03:00
if ( symbol_characters < 4 ) {
symbol_characters = 4 ;
2016-02-20 14:29:19 +03:00
}
2016-10-09 16:10:39 +03:00
2020-12-21 22:30:07 +03:00
remainder = ( 12 * ( symbol_characters - 1 ) ) - bp ;
2017-10-23 22:37:52 +03:00
2020-12-21 22:30:07 +03:00
if ( debug ) printf ( " Resultant binary = %.*s \n \t Length: %d \n " , bp , binary_string , bp ) ;
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
if ( bp > 252 ) { /* 252 = (21 * 12) */
2021-06-27 13:47:55 +03:00
strcpy ( symbol - > errtxt , " 387: Input too long " ) ; // TODO: Better error message
2016-02-20 14:29:19 +03:00
return ZINT_ERROR_TOO_LONG ;
}
/* Now add padding to binary string (7.2.5.5.4) */
i = remainder ;
2019-10-31 05:01:42 +03:00
if ( mode = = NUMERIC ) {
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( 0 , 4 , binary_string , bp ) ; /* "0000" */
2016-02-20 14:29:19 +03:00
i - = 4 ;
}
for ( ; i > 0 ; i - = 5 ) {
2020-12-21 22:30:07 +03:00
bp = bin_append_posn ( 4 , 5 , binary_string , bp ) ; /* "00100" */
2016-02-20 14:29:19 +03:00
}
/* Patch variable length symbol bit field */
2016-10-09 16:10:39 +03:00
d1 = symbol_characters & 1 ;
if ( symbol_characters < = 14 ) {
2016-02-20 14:29:19 +03:00
d2 = 0 ;
} else {
d2 = 1 ;
}
if ( encoding_method = = 1 ) {
binary_string [ 2 ] = d1 ? ' 1 ' : ' 0 ' ;
binary_string [ 3 ] = d2 ? ' 1 ' : ' 0 ' ;
2020-12-21 22:30:07 +03:00
} else if ( encoding_method = = 2 ) {
2016-02-20 14:29:19 +03:00
binary_string [ 3 ] = d1 ? ' 1 ' : ' 0 ' ;
binary_string [ 4 ] = d2 ? ' 1 ' : ' 0 ' ;
2020-12-21 22:30:07 +03:00
} else if ( ( encoding_method = = 5 ) | | ( encoding_method = = 6 ) ) {
2016-02-20 14:29:19 +03:00
binary_string [ 6 ] = d1 ? ' 1 ' : ' 0 ' ;
binary_string [ 7 ] = d2 ? ' 1 ' : ' 0 ' ;
}
2020-12-21 22:30:07 +03:00
if ( debug ) {
printf ( " Resultant binary = %.*s \n \t Length: %d, Symbol chars: %d \n " , bp , binary_string , bp , symbol_characters ) ;
}
* p_bp = bp ;
2016-02-20 14:29:19 +03:00
return 0 ;
2008-07-14 01:15:55 +04:00
}
2020-12-21 22:30:07 +03:00
/* Separator for DataBar Expanded Stacked and DataBar Expanded Composite */
static void rssexp_separator ( struct zint_symbol * symbol , int width , const int cols , const int separator_row ,
const int above_below , const int special_case_row , const int left_to_right , const int odd_last_row ,
int * p_v2_latch ) {
2020-07-10 21:39:32 +03:00
int i , i_start , i_end , j , k ;
int module_row = separator_row + above_below ;
int v2_latch = p_v2_latch ? * p_v2_latch : 0 ;
int space_latch = 0 ;
for ( j = 4 + special_case_row , width - = 4 ; j < width ; j + + ) {
if ( module_is_set ( symbol , module_row , j ) ) {
unset_module ( symbol , separator_row , j ) ;
} else {
set_module ( symbol , separator_row , j ) ;
}
}
/* finder adjustment */
for ( j = 0 ; j < cols ; j + + ) {
2020-12-21 22:30:07 +03:00
/* 49 == data (17) + finder (15) + data(17) triplet, 19 == 2 (guard) + 17 (initial check/data character) */
k = ( 49 * j ) + 19 + special_case_row ;
2020-07-10 21:39:32 +03:00
if ( left_to_right ) {
2020-12-21 22:30:07 +03:00
/* Last 13 modules of version 2 finder and first 13 modules of version 1 finder */
i_start = v2_latch ? 2 : 0 ;
2020-07-10 21:39:32 +03:00
i_end = v2_latch ? 15 : 13 ;
for ( i = i_start ; i < i_end ; i + + ) {
if ( module_is_set ( symbol , module_row , i + k ) ) {
unset_module ( symbol , separator_row , i + k ) ;
space_latch = 0 ;
} else {
if ( space_latch ) {
unset_module ( symbol , separator_row , i + k ) ;
} else {
set_module ( symbol , separator_row , i + k ) ;
}
space_latch = ! space_latch ;
}
}
} else {
if ( odd_last_row ) {
k - = 17 ; /* No data char at beginning of row, i.e. ends with finder */
}
2020-12-21 22:30:07 +03:00
/* First 13 modules of version 1 finder and last 13 modules of version 2 finder */
i_start = v2_latch ? 14 : 12 ;
2020-07-10 21:39:32 +03:00
i_end = v2_latch ? 2 : 0 ;
for ( i = i_start ; i > = i_end ; i - - ) {
if ( module_is_set ( symbol , module_row , i + k ) ) {
unset_module ( symbol , separator_row , i + k ) ;
space_latch = 0 ;
} else {
if ( space_latch ) {
unset_module ( symbol , separator_row , i + k ) ;
} else {
set_module ( symbol , separator_row , i + k ) ;
}
space_latch = ! space_latch ;
}
}
}
v2_latch = ! v2_latch ;
}
if ( p_v2_latch & & above_below = = - 1 ) { /* Only set if below */
* p_v2_latch = v2_latch ;
}
}
2021-06-19 15:11:23 +03:00
/* GS1 DataBar Expanded, setting linkage for composite if `cc_rows` set */
INTERNAL int rssexpanded_cc ( struct zint_symbol * symbol , unsigned char source [ ] , int src_len , const int cc_rows ) {
int error_number , warn_number = 0 ;
2020-12-21 22:30:07 +03:00
int i , j , k , p , codeblocks , data_chars , vs , group , v_odd , v_even ;
int latch ;
2016-02-20 14:29:19 +03:00
int char_widths [ 21 ] [ 8 ] , checksum , check_widths [ 8 ] , c_group ;
int check_char , c_odd , c_even , elements [ 235 ] , pattern_width , reader , writer ;
int separator_row ;
2020-12-21 22:30:07 +03:00
/* Allow for 8 bits + 5-bit latch per char + 200 bits overhead/padding */
unsigned int bin_len = 13 * src_len + 200 + 1 ;
2020-07-10 21:39:32 +03:00
int widths [ 4 ] ;
2020-12-21 22:30:07 +03:00
int bp = 0 ;
2021-06-27 13:47:55 +03:00
int cols_per_row = 0 ;
2021-06-19 15:11:23 +03:00
int stack_rows = 1 ;
2009-06-03 00:23:38 +04:00
# ifndef _MSC_VER
2020-12-21 22:30:07 +03:00
unsigned char reduced [ src_len + 1 ] ;
char binary_string [ bin_len ] ;
2009-06-03 00:23:38 +04:00
# else
2020-12-21 22:30:07 +03:00
unsigned char * reduced = ( unsigned char * ) _alloca ( src_len + 1 ) ;
char * binary_string = ( char * ) _alloca ( bin_len ) ;
2009-06-03 00:23:38 +04:00
# endif
2008-07-14 01:15:55 +04:00
2020-07-19 12:31:12 +03:00
separator_row = 0 ;
2021-01-18 23:10:52 +03:00
error_number = gs1_verify ( symbol , source , src_len , reduced ) ;
if ( error_number > = ZINT_ERROR ) {
return error_number ;
2019-10-17 12:06:21 +03:00
}
2021-06-27 13:47:55 +03:00
warn_number = error_number ;
2019-10-17 12:06:21 +03:00
2020-12-21 22:30:07 +03:00
if ( symbol - > debug & ZINT_DEBUG_PRINT ) {
printf ( " Reduced (%d): %s \n " , ( int ) ustrlen ( reduced ) , reduced ) ;
}
2020-07-29 22:43:08 +03:00
if ( ( symbol - > symbology = = BARCODE_DBAR_EXP_CC ) | | ( symbol - > symbology = = BARCODE_DBAR_EXPSTK_CC ) ) {
2016-02-20 14:29:19 +03:00
/* make space for a composite separator pattern */
separator_row = symbol - > rows ;
symbol - > row_height [ separator_row ] = 1 ;
symbol - > rows + = 1 ;
}
2021-06-19 15:11:23 +03:00
if ( cc_rows ) { /* The "component linkage" flag */
2020-12-21 22:30:07 +03:00
binary_string [ bp + + ] = ' 1 ' ;
2016-02-20 14:29:19 +03:00
} else {
2020-12-21 22:30:07 +03:00
binary_string [ bp + + ] = ' 0 ' ;
2016-02-20 14:29:19 +03:00
}
2021-06-27 13:47:55 +03:00
if ( ( symbol - > symbology = = BARCODE_DBAR_EXPSTK ) | | ( symbol - > symbology = = BARCODE_DBAR_EXPSTK_CC ) ) {
cols_per_row = 2 ; /* Default */
if ( symbol - > option_2 > = 1 & & symbol - > option_2 < = 11 ) {
cols_per_row = symbol - > option_2 ;
if ( cc_rows & & ( cols_per_row = = 1 ) ) {
/* "There shall be a minimum of four symbol characters in the
first row of an RSS Expanded Stacked symbol when it is the linear
component of an EAN . UCC Composite symbol . " */
cols_per_row = 2 ;
}
}
}
error_number = rssexp_binary_string ( symbol , reduced , binary_string , cols_per_row , & bp ) ;
if ( error_number ! = 0 ) {
return error_number ;
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
data_chars = bp / 12 ;
2016-02-20 14:29:19 +03:00
for ( i = 0 ; i < data_chars ; i + + ) {
2020-12-21 22:30:07 +03:00
k = i * 12 ;
vs = 0 ;
2016-02-20 14:29:19 +03:00
for ( j = 0 ; j < 12 ; j + + ) {
2020-12-21 22:30:07 +03:00
if ( binary_string [ k + j ] = = ' 1 ' ) {
vs | = ( 0x800 > > j ) ;
2016-02-20 14:29:19 +03:00
}
}
2020-12-21 22:30:07 +03:00
if ( vs < = 347 ) {
group = 1 ;
} else if ( vs < = 1387 ) {
group = 2 ;
} else if ( vs < = 2947 ) {
group = 3 ;
} else if ( vs < = 3987 ) {
group = 4 ;
} else {
group = 5 ;
2016-02-20 14:29:19 +03:00
}
2020-12-21 22:30:07 +03:00
v_odd = ( vs - g_sum_exp [ group - 1 ] ) / t_even_exp [ group - 1 ] ;
v_even = ( vs - g_sum_exp [ group - 1 ] ) % t_even_exp [ group - 1 ] ;
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
getRSSwidths ( widths , v_odd , modules_odd_exp [ group - 1 ] , 4 , widest_odd_exp [ group - 1 ] , 0 ) ;
2016-02-20 14:29:19 +03:00
char_widths [ i ] [ 0 ] = widths [ 0 ] ;
char_widths [ i ] [ 2 ] = widths [ 1 ] ;
char_widths [ i ] [ 4 ] = widths [ 2 ] ;
char_widths [ i ] [ 6 ] = widths [ 3 ] ;
2020-12-21 22:30:07 +03:00
getRSSwidths ( widths , v_even , modules_even_exp [ group - 1 ] , 4 , widest_even_exp [ group - 1 ] , 1 ) ;
2016-02-20 14:29:19 +03:00
char_widths [ i ] [ 1 ] = widths [ 0 ] ;
char_widths [ i ] [ 3 ] = widths [ 1 ] ;
char_widths [ i ] [ 5 ] = widths [ 2 ] ;
char_widths [ i ] [ 7 ] = widths [ 3 ] ;
}
/* 7.2.6 Check character */
/* The checksum value is equal to the mod 211 residue of the weighted sum of the widths of the
elements in the data characters . */
checksum = 0 ;
for ( i = 0 ; i < data_chars ; i + + ) {
2017-09-10 18:03:09 +03:00
int row = weight_rows [ ( ( ( data_chars - 2 ) / 2 ) * 21 ) + i ] ;
2016-02-20 14:29:19 +03:00
for ( j = 0 ; j < 8 ; j + + ) {
checksum + = ( char_widths [ i ] [ j ] * checksum_weight_exp [ ( row * 8 ) + j ] ) ;
}
}
check_char = ( 211 * ( ( data_chars + 1 ) - 4 ) ) + ( checksum % 211 ) ;
2020-07-10 21:39:32 +03:00
if ( symbol - > debug & ZINT_DEBUG_PRINT ) {
printf ( " Data chars: %d, Check char: %d \n " , data_chars , check_char ) ;
}
2016-02-20 14:29:19 +03:00
if ( check_char < = 347 ) {
c_group = 1 ;
2020-12-21 22:30:07 +03:00
} else if ( check_char < = 1387 ) {
2016-02-20 14:29:19 +03:00
c_group = 2 ;
2020-12-21 22:30:07 +03:00
} else if ( check_char < = 2947 ) {
2016-02-20 14:29:19 +03:00
c_group = 3 ;
2020-12-21 22:30:07 +03:00
} else if ( check_char < = 3987 ) {
2016-02-20 14:29:19 +03:00
c_group = 4 ;
2020-12-21 22:30:07 +03:00
} else {
2016-02-20 14:29:19 +03:00
c_group = 5 ;
}
c_odd = ( check_char - g_sum_exp [ c_group - 1 ] ) / t_even_exp [ c_group - 1 ] ;
c_even = ( check_char - g_sum_exp [ c_group - 1 ] ) % t_even_exp [ c_group - 1 ] ;
2020-07-10 21:39:32 +03:00
getRSSwidths ( widths , c_odd , modules_odd_exp [ c_group - 1 ] , 4 , widest_odd_exp [ c_group - 1 ] , 0 ) ;
2016-02-20 14:29:19 +03:00
check_widths [ 0 ] = widths [ 0 ] ;
check_widths [ 2 ] = widths [ 1 ] ;
check_widths [ 4 ] = widths [ 2 ] ;
check_widths [ 6 ] = widths [ 3 ] ;
2020-07-10 21:39:32 +03:00
getRSSwidths ( widths , c_even , modules_even_exp [ c_group - 1 ] , 4 , widest_even_exp [ c_group - 1 ] , 1 ) ;
2016-02-20 14:29:19 +03:00
check_widths [ 1 ] = widths [ 0 ] ;
check_widths [ 3 ] = widths [ 1 ] ;
check_widths [ 5 ] = widths [ 2 ] ;
check_widths [ 7 ] = widths [ 3 ] ;
/* Initialise element array */
2020-12-21 22:30:07 +03:00
codeblocks = ( data_chars + 1 ) / 2 + ( ( data_chars + 1 ) & 1 ) ;
pattern_width = ( codeblocks * 5 ) + ( ( data_chars + 1 ) * 8 ) + 4 ;
memset ( elements , 0 , sizeof ( int ) * pattern_width ) ;
2016-02-20 14:29:19 +03:00
/* Put finder patterns in element array */
2020-12-21 22:30:07 +03:00
p = ( ( ( ( ( data_chars + 1 ) - 2 ) / 2 ) + ( ( data_chars + 1 ) & 1 ) ) - 1 ) * 11 ;
for ( i = 0 ; i < codeblocks ; i + + ) {
k = p + i ;
2016-02-20 14:29:19 +03:00
for ( j = 0 ; j < 5 ; j + + ) {
elements [ ( 21 * i ) + j + 10 ] = finder_pattern_exp [ ( ( finder_sequence [ k ] - 1 ) * 5 ) + j ] ;
}
}
/* Put check character in element array */
for ( i = 0 ; i < 8 ; i + + ) {
elements [ i + 2 ] = check_widths [ i ] ;
}
/* Put forward reading data characters in element array */
for ( i = 1 ; i < data_chars ; i + = 2 ) {
2020-12-21 22:30:07 +03:00
k = ( ( ( i - 1 ) / 2 ) * 21 ) + 23 ;
2016-02-20 14:29:19 +03:00
for ( j = 0 ; j < 8 ; j + + ) {
2020-12-21 22:30:07 +03:00
elements [ k + j ] = char_widths [ i ] [ j ] ;
2016-02-20 14:29:19 +03:00
}
}
/* Put reversed data characters in element array */
for ( i = 0 ; i < data_chars ; i + = 2 ) {
2020-12-21 22:30:07 +03:00
k = ( ( i / 2 ) * 21 ) + 15 ;
2016-02-20 14:29:19 +03:00
for ( j = 0 ; j < 8 ; j + + ) {
2020-12-21 22:30:07 +03:00
elements [ k + j ] = char_widths [ i ] [ 7 - j ] ;
2016-02-20 14:29:19 +03:00
}
}
2020-07-29 22:43:08 +03:00
if ( ( symbol - > symbology = = BARCODE_DBAR_EXP ) | | ( symbol - > symbology = = BARCODE_DBAR_EXP_CC ) ) {
2016-02-20 14:29:19 +03:00
/* Copy elements into symbol */
2017-10-23 22:37:52 +03:00
2016-10-15 12:54:23 +03:00
elements [ 0 ] = 1 ; // left guard
elements [ 1 ] = 1 ;
2017-10-23 22:37:52 +03:00
2016-10-15 12:54:23 +03:00
elements [ pattern_width - 2 ] = 1 ; // right guard
elements [ pattern_width - 1 ] = 1 ;
2017-10-23 22:37:52 +03:00
2016-02-20 14:29:19 +03:00
writer = 0 ;
2020-12-21 22:30:07 +03:00
latch = 0 ;
2016-02-20 14:29:19 +03:00
for ( i = 0 ; i < pattern_width ; i + + ) {
2020-07-10 21:39:32 +03:00
writer = rss_expand ( symbol , writer , & latch , elements [ i ] ) ;
2016-02-20 14:29:19 +03:00
}
if ( symbol - > width < writer ) {
symbol - > width = writer ;
}
symbol - > rows = symbol - > rows + 1 ;
/* Add human readable text */
for ( i = 0 ; i < = src_len ; i + + ) {
2021-07-13 19:39:03 +03:00
if ( source [ i ] = = ' [ ' ) {
symbol - > text [ i ] = ' ( ' ;
} else if ( source [ i ] = = ' ] ' ) {
symbol - > text [ i ] = ' ) ' ;
2016-02-20 14:29:19 +03:00
} else {
2021-07-13 19:39:03 +03:00
symbol - > text [ i ] = source [ i ] ;
2016-02-20 14:29:19 +03:00
}
}
} else {
2017-10-23 22:34:31 +03:00
int current_row , current_block , left_to_right ;
2020-07-10 21:39:32 +03:00
int v2_latch = 0 ;
2016-02-20 14:29:19 +03:00
/* RSS Expanded Stacked */
/* Bug corrected: Character missing for message
* [ 01 ] 90614141999996 [ 10 ] 1234222222222221
* Patch by Daniel Frede
*/
2021-06-27 13:47:55 +03:00
stack_rows = codeblocks / cols_per_row ;
if ( codeblocks % cols_per_row > 0 ) {
2016-02-20 14:29:19 +03:00
stack_rows + + ;
}
2017-10-16 20:26:54 +03:00
current_block = 0 ;
2016-02-20 14:29:19 +03:00
for ( current_row = 1 ; current_row < = stack_rows ; current_row + + ) {
2017-10-23 22:34:31 +03:00
int special_case_row = 0 ;
int elements_in_sub ;
2020-07-15 13:41:09 +03:00
int sub_elements [ 235 ] = { 0 } ;
int num_columns ;
/* Number of columns in current row */
2021-06-27 13:47:55 +03:00
if ( current_row * cols_per_row > codeblocks ) {
2020-07-15 13:41:09 +03:00
num_columns = codeblocks - current_block ;
} else {
2021-06-27 13:47:55 +03:00
num_columns = cols_per_row ;
2016-02-20 14:29:19 +03:00
}
/* Row Start */
2016-10-15 12:54:23 +03:00
sub_elements [ 0 ] = 1 ; // left guard
2016-02-20 14:29:19 +03:00
sub_elements [ 1 ] = 1 ;
2017-10-16 20:26:54 +03:00
elements_in_sub = 2 ;
2016-02-20 14:29:19 +03:00
2020-12-21 22:30:07 +03:00
/* If last row and is partial and even-numbered, and have even columns (segment pairs),
* and odd number of finders ( = = odd number of columns ) */
2021-06-27 13:47:55 +03:00
if ( ( current_row = = stack_rows ) & & ( num_columns ! = cols_per_row ) & & ! ( current_row & 1 )
& & ! ( cols_per_row & 1 ) & & ( num_columns & 1 ) ) {
2020-07-15 13:41:09 +03:00
/* Special case bottom row */
special_case_row = 1 ;
sub_elements [ 0 ] = 2 ; /* Extra space (latch set below) */
}
2020-12-21 22:30:07 +03:00
/* If odd number of columns or current row odd-numbered or special case last row then left-to-right,
* else right - to - left */
2021-06-27 13:47:55 +03:00
if ( ( cols_per_row & 1 ) | | ( current_row & 1 ) | | special_case_row ) {
2020-07-10 21:39:32 +03:00
left_to_right = 1 ;
} else {
left_to_right = 0 ;
}
2020-07-15 13:41:09 +03:00
if ( symbol - > debug & ZINT_DEBUG_PRINT ) {
if ( current_row = = stack_rows ) {
2020-12-21 22:30:07 +03:00
printf ( " Last row: number of columns: %d / %d, left to right: %d, special case: %d \n " ,
2021-06-27 13:47:55 +03:00
num_columns , cols_per_row , left_to_right , special_case_row ) ;
2020-07-15 13:41:09 +03:00
}
}
/* Row Data */
2016-02-20 14:29:19 +03:00
reader = 0 ;
do {
2020-07-15 13:41:09 +03:00
i = 2 + ( current_block * 21 ) ;
for ( j = 0 ; j < 21 ; j + + ) {
if ( ( i + j ) < pattern_width ) {
if ( left_to_right ) {
2020-07-10 21:39:32 +03:00
sub_elements [ j + ( reader * 21 ) + 2 ] = elements [ i + j ] ;
2020-07-15 13:41:09 +03:00
} else {
sub_elements [ ( 20 - j ) + ( num_columns - 1 - reader ) * 21 + 2 ] = elements [ i + j ] ;
2016-02-20 14:29:19 +03:00
}
}
2020-07-15 13:41:09 +03:00
elements_in_sub + + ;
2016-02-20 14:29:19 +03:00
}
reader + + ;
current_block + + ;
2021-06-27 13:47:55 +03:00
} while ( ( reader < cols_per_row ) & & ( current_block < codeblocks ) ) ;
2016-02-20 14:29:19 +03:00
/* Row Stop */
2016-10-15 12:54:23 +03:00
sub_elements [ elements_in_sub ] = 1 ; // right guard
2016-02-20 14:29:19 +03:00
sub_elements [ elements_in_sub + 1 ] = 1 ;
elements_in_sub + = 2 ;
2020-12-21 22:30:07 +03:00
latch = ( current_row & 1 ) | | special_case_row ? 0 : 1 ;
2016-02-20 14:29:19 +03:00
writer = 0 ;
for ( i = 0 ; i < elements_in_sub ; i + + ) {
2020-07-10 21:39:32 +03:00
writer = rss_expand ( symbol , writer , & latch , sub_elements [ i ] ) ;
2016-02-20 14:29:19 +03:00
}
if ( symbol - > width < writer ) {
symbol - > width = writer ;
}
if ( current_row ! = 1 ) {
2020-07-10 21:39:32 +03:00
int odd_last_row = ( current_row = = stack_rows ) & & ( data_chars % 2 = = 0 ) ;
2016-02-20 14:29:19 +03:00
/* middle separator pattern (above current row) */
2021-06-27 13:47:55 +03:00
for ( j = 5 ; j < ( 49 * cols_per_row ) ; j + = 2 ) {
2016-02-20 14:29:19 +03:00
set_module ( symbol , symbol - > rows - 2 , j ) ;
}
symbol - > row_height [ symbol - > rows - 2 ] = 1 ;
2020-07-10 21:39:32 +03:00
2016-02-20 14:29:19 +03:00
/* bottom separator pattern (above current row) */
2020-12-21 22:30:07 +03:00
rssexp_separator ( symbol , writer , reader , symbol - > rows - 1 , 1 /*above*/ , special_case_row ,
left_to_right , odd_last_row , & v2_latch ) ;
2016-02-20 14:29:19 +03:00
symbol - > row_height [ symbol - > rows - 1 ] = 1 ;
}
if ( current_row ! = stack_rows ) {
/* top separator pattern (below current row) */
2020-12-21 22:30:07 +03:00
rssexp_separator ( symbol , writer , reader , symbol - > rows + 1 , - 1 /*below*/ , 0 /*special_case_row*/ ,
left_to_right , 0 /*odd_last_row*/ , & v2_latch ) ;
2016-02-20 14:29:19 +03:00
symbol - > row_height [ symbol - > rows + 1 ] = 1 ;
}
symbol - > rows = symbol - > rows + 4 ;
}
symbol - > rows = symbol - > rows - 3 ;
2020-07-10 21:39:32 +03:00
}
2016-02-20 14:29:19 +03:00
2020-07-29 22:43:08 +03:00
if ( symbol - > symbology = = BARCODE_DBAR_EXP_CC | | symbol - > symbology = = BARCODE_DBAR_EXPSTK_CC ) {
2020-07-10 21:39:32 +03:00
/* Composite separator */
2020-12-21 22:30:07 +03:00
rssexp_separator ( symbol , symbol - > width , 4 , separator_row , 1 /*above*/ , 0 /*special_case_row*/ ,
1 /*left_to_right*/ , 0 /*odd_last_row*/ , NULL ) ;
2016-02-20 14:29:19 +03:00
}
2017-10-23 22:37:52 +03:00
2021-06-19 15:11:23 +03:00
/* DataBar Expanded ISO/IEC 24724:2011 7.2.1 and DataBar Expanded Stacked ISO/IEC 24724:2011 7.2.8
34 X min per row */
if ( symbol - > symbology = = BARCODE_DBAR_EXP_CC | | symbol - > symbology = = BARCODE_DBAR_EXPSTK_CC ) {
symbol - > height = symbol - > height ? 34.0f : 34.0f * stack_rows ; /* Pass back min row or default height */
} else {
# ifdef COMPLIANT_HEIGHTS
2021-06-27 13:47:55 +03:00
if ( warn_number ) {
( void ) set_height ( symbol , 34.0f , 34.0f * stack_rows , 0.0f , 0 /*no_errtxt*/ ) ;
} else {
warn_number = set_height ( symbol , 34.0f , 34.0f * stack_rows , 0.0f , 0 /*no_errtxt*/ ) ;
}
2021-06-19 15:11:23 +03:00
# else
( void ) set_height ( symbol , 0.0f , 34.0f * stack_rows , 0.0f , 1 /*no_errtxt*/ ) ;
# endif
2016-10-14 20:56:49 +03:00
}
2016-02-20 14:29:19 +03:00
2021-06-19 15:11:23 +03:00
return error_number ? error_number : warn_number ;
}
/* GS1 DataBar Expanded */
INTERNAL int rssexpanded ( struct zint_symbol * symbol , unsigned char source [ ] , int src_len ) {
return rssexpanded_cc ( symbol , source , src_len , 0 /*cc_rows*/ ) ;
2008-07-14 01:15:55 +04:00
}