2008-07-13 21:15:55 +00:00
/* code16k.c - Handles Code 16k stacked symbology */
/*
libzint - the open source barcode library
2023-01-15 00:22:43 +00:00
Copyright ( C ) 2008 - 2023 Robin Stuart < rstuart114 @ gmail . com >
2013-05-16 19:26:38 +02: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 09:38:03 +00:00
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2013-05-16 19:26:38 +02: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 09:38:03 +00:00
documentation and / or other materials provided with the distribution .
2013-05-16 19:26:38 +02: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 09:38:03 +00:00
without specific prior written permission .
2013-05-16 19:26:38 +02: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 09:38:03 +00:00
OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
2013-05-16 19:26:38 +02:00
SUCH DAMAGE .
2016-02-20 09:38:03 +00:00
*/
2022-09-13 21:16:31 +01:00
/* SPDX-License-Identifier: BSD-3-Clause */
2008-07-13 21:15:55 +00:00
/* Updated to comply with BS EN 12323:2005 */
2016-02-20 09:38:03 +00:00
/* Code 16k can hold up to 77 characters or 154 numbers */
2008-07-13 21:15:55 +00:00
2022-09-13 21:16:31 +01:00
# include <assert.h>
# include <stdio.h>
2022-09-13 22:08:08 +01:00
# include "common.h"
# include "code128.h"
2008-07-13 21:15:55 +00:00
2021-10-20 23:05:30 +01:00
/* Note using C128Table with extra entry at 106 (Triple Shift) for C16KTable */
2016-02-20 09:38:03 +00:00
2021-10-20 23:05:30 +01:00
static const char C16KStartStop [ 8 ] [ 4 ] = {
2016-02-20 09:38:03 +00:00
/* EN 12323 Table 3 and Table 4 - Start patterns and stop patterns */
2021-10-20 23:05:30 +01:00
{ ' 3 ' , ' 2 ' , ' 1 ' , ' 1 ' } , { ' 2 ' , ' 2 ' , ' 2 ' , ' 1 ' } , { ' 2 ' , ' 1 ' , ' 2 ' , ' 2 ' } , { ' 1 ' , ' 4 ' , ' 1 ' , ' 1 ' } ,
{ ' 1 ' , ' 1 ' , ' 3 ' , ' 2 ' } , { ' 1 ' , ' 2 ' , ' 3 ' , ' 1 ' } , { ' 1 ' , ' 1 ' , ' 1 ' , ' 4 ' } , { ' 3 ' , ' 1 ' , ' 1 ' , ' 2 ' }
2016-02-20 09:38:03 +00:00
} ;
2008-07-13 21:15:55 +00:00
/* EN 12323 Table 5 - Start and stop values defining row numbers */
2016-02-20 09:38:03 +00:00
static const int C16KStartValues [ 16 ] = {
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7
} ;
static const int C16KStopValues [ 16 ] = {
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 4 , 5 , 6 , 7 , 0 , 1 , 2 , 3
} ;
2020-12-23 10:57:24 +00:00
INTERNAL int code16k ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) {
2022-10-13 13:33:59 +01:00
char width_pattern [ 40 ] ; /* 4 (start) + 1 (guard) + 5*6 (chars) + 4 (stop) + 1 */
2020-09-30 12:19:12 +01:00
int current_row , rows , looper , first_check , second_check ;
2020-05-21 18:22:28 +01:00
int indexchaine ;
int list [ 2 ] [ C128_MAX ] = { { 0 } } ;
2022-10-13 13:33:59 +01:00
char set [ C128_MAX ] = { 0 } , fset [ C128_MAX ] = { 0 } , mode , current_set ;
2021-10-20 23:05:30 +01:00
int pads_needed , indexliste , i , m , read , mx_reader ;
2021-11-20 11:32:30 +00:00
int extra_pads = 0 ;
2020-05-21 18:22:28 +01:00
int values [ C128_MAX ] = { 0 } ;
int bar_characters ;
2021-06-19 13:11:23 +01:00
int error_number = 0 , first_sum , second_sum ;
2022-10-13 13:33:59 +01:00
const int gs1 = ( symbol - > input_mode & 0x07 ) = = GS1_MODE ;
const int debug_print = symbol - > debug & ZINT_DEBUG_PRINT ;
2016-02-20 09:38:03 +00:00
2022-10-13 13:33:59 +01:00
if ( length > C128_MAX ) {
2017-07-27 16:01:53 +01:00
strcpy ( symbol - > errtxt , " 420: Input too long " ) ;
2016-02-20 09:38:03 +00:00
return ZINT_ERROR_TOO_LONG ;
}
2022-10-13 13:33:59 +01:00
if ( symbol - > option_1 = = 1 | | symbol - > option_1 > 16 ) {
strcpy ( symbol - > errtxt , " 424: Minimum number of rows out of range (2 to 16) " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
2016-02-20 09:38:03 +00:00
/* Detect extended ASCII characters */
2022-10-13 13:33:59 +01:00
for ( i = 0 ; i < length ; i + + ) {
2020-05-21 18:22:28 +01:00
fset [ i ] = source [ i ] > = 128 ? ' f ' : ' ' ;
2016-02-20 09:38:03 +00:00
}
2020-05-21 18:22:28 +01:00
/* Note to be safe not using extended ASCII latch as not mentioned in BS EN 12323:2005 */
2016-02-20 09:38:03 +00:00
/* Detect mode A, B and C characters */
indexliste = 0 ;
indexchaine = 0 ;
2021-10-20 23:05:30 +01:00
mode = c128_parunmodd ( source [ indexchaine ] ) ;
2016-02-20 09:38:03 +00:00
do {
list [ 1 ] [ indexliste ] = mode ;
2022-10-13 13:33:59 +01:00
while ( ( list [ 1 ] [ indexliste ] = = mode ) & & ( indexchaine < length ) ) {
2016-02-20 09:38:03 +00:00
list [ 0 ] [ indexliste ] + + ;
indexchaine + + ;
2022-10-13 13:33:59 +01:00
if ( indexchaine = = length ) {
2020-05-21 18:22:28 +01:00
break ;
}
2021-10-20 23:05:30 +01:00
mode = c128_parunmodd ( source [ indexchaine ] ) ;
2016-02-20 09:38:03 +00:00
if ( ( gs1 ) & & ( source [ indexchaine ] = = ' [ ' ) ) {
2021-10-20 23:05:30 +01:00
mode = C128_ABORC ;
2016-02-20 09:38:03 +00:00
} /* FNC1 */
}
indexliste + + ;
2022-10-13 13:33:59 +01:00
} while ( indexchaine < length ) ;
2016-02-20 09:38:03 +00:00
2023-01-15 00:22:43 +00:00
c128_dxsmooth ( list , & indexliste , NULL /*manual_set*/ ) ;
2016-02-20 09:38:03 +00:00
2021-10-20 23:05:30 +01:00
/* Put set data into set[], resolving odd C blocks */
c128_put_in_set ( list , indexliste , set , source ) ;
2016-02-20 09:38:03 +00:00
2022-10-13 13:33:59 +01:00
if ( debug_print ) {
printf ( " Data: %.*s \n " , length , source ) ;
printf ( " Set: %.*s \n " , length , set ) ;
printf ( " FSet: %.*s \n " , length , fset ) ;
2021-11-20 11:32:30 +00:00
}
2016-02-20 09:38:03 +00:00
/* start with the mode character - Table 2 */
m = 0 ;
switch ( set [ 0 ] ) {
case ' A ' : m = 0 ;
break ;
case ' B ' : m = 1 ;
break ;
case ' C ' : m = 2 ;
break ;
}
if ( symbol - > output_options & READER_INIT ) {
if ( gs1 ) {
2017-07-27 16:01:53 +01:00
strcpy ( symbol - > errtxt , " 422: Cannot use both GS1 mode and Reader Initialisation " ) ;
2016-02-20 09:38:03 +00:00
return ZINT_ERROR_INVALID_OPTION ;
}
2022-10-13 13:33:59 +01:00
if ( m = = 2 ) {
m = 5 ;
} else if ( ( set [ 0 ] = = ' B ' ) & & ( set [ 1 ] = = ' C ' ) & & fset [ 0 ] ! = ' f ' ) {
m = 6 ;
}
values [ 1 ] = 96 ; /* FNC3 */
bar_characters = 2 ;
2016-02-20 09:38:03 +00:00
} else {
if ( gs1 ) {
/* Integrate FNC1 */
switch ( set [ 0 ] ) {
case ' B ' : m = 3 ;
break ;
case ' C ' : m = 4 ;
break ;
}
} else {
if ( ( set [ 0 ] = = ' B ' ) & & ( set [ 1 ] = = ' C ' ) ) {
2022-10-13 13:33:59 +01:00
m = fset [ 0 ] = = ' f ' ? 6 : 5 ;
} else if ( ( set [ 0 ] = = ' B ' ) & & ( set [ 1 ] = = ' B ' ) & & ( set [ 2 ] = = ' C ' ) & & fset [ 0 ] ! = ' f ' & & fset [ 1 ] ! = ' f ' ) {
2016-02-20 09:38:03 +00:00
m = 6 ;
}
}
2022-10-13 13:33:59 +01:00
bar_characters = 1 ;
2016-02-20 09:38:03 +00:00
}
current_set = set [ 0 ] ;
read = 0 ;
/* Encode the data */
2022-10-13 13:33:59 +01:00
/* TODO: make use of extra (non-CODE128) shifts: 1SB, 2SA/B/C, 3SB/C */
2016-02-20 09:38:03 +00:00
do {
2022-10-13 13:33:59 +01:00
if ( ( read ! = 0 ) & & ( set [ read ] ! = current_set ) ) {
2016-02-20 09:38:03 +00:00
/* Latch different code set */
switch ( set [ read ] ) {
case ' A ' :
2022-10-13 13:33:59 +01:00
values [ bar_characters + + ] = 101 ;
2016-02-20 09:38:03 +00:00
current_set = ' A ' ;
break ;
case ' B ' :
2022-10-13 13:33:59 +01:00
values [ bar_characters + + ] = 100 ;
2016-02-20 09:38:03 +00:00
current_set = ' B ' ;
break ;
case ' C ' :
2022-10-13 13:33:59 +01:00
/* If not Mode C/Shift B and not Mode C/Double Shift B */
if ( ! ( read = = 1 & & m > = 5 ) & & ! ( read = = 2 & & m = = 6 ) ) {
values [ bar_characters + + ] = 99 ;
2016-02-20 09:38:03 +00:00
}
current_set = ' C ' ;
break ;
}
}
2020-05-21 18:22:28 +01:00
if ( fset [ read ] = = ' f ' ) {
2016-02-20 09:38:03 +00:00
/* Shift extended mode */
switch ( current_set ) {
case ' A ' :
2022-10-13 13:33:59 +01:00
values [ bar_characters + + ] = 101 ; /* FNC 4 */
2016-02-20 09:38:03 +00:00
break ;
case ' B ' :
2022-10-13 13:33:59 +01:00
values [ bar_characters + + ] = 100 ; /* FNC 4 */
2016-02-20 09:38:03 +00:00
break ;
}
}
2020-05-21 18:22:28 +01:00
if ( ( set [ read ] = = ' a ' ) | | ( set [ read ] = = ' b ' ) ) {
2016-02-20 09:38:03 +00:00
/* Insert shift character */
2022-10-13 13:33:59 +01:00
values [ bar_characters + + ] = 98 ;
2016-02-20 09:38:03 +00:00
}
if ( ! ( ( gs1 ) & & ( source [ read ] = = ' [ ' ) ) ) {
switch ( set [ read ] ) { /* Encode data characters */
case ' A ' :
2022-10-13 13:33:59 +01:00
case ' a ' : c128_set_a ( source [ read ] , values , & bar_characters ) ;
2016-02-20 09:38:03 +00:00
read + + ;
break ;
case ' B ' :
2022-10-13 13:33:59 +01:00
case ' b ' : ( void ) c128_set_b ( source [ read ] , values , & bar_characters ) ;
2016-02-20 09:38:03 +00:00
read + + ;
break ;
2021-10-20 23:05:30 +01:00
case ' C ' : c128_set_c ( source [ read ] , source [ read + 1 ] , values , & bar_characters ) ;
2016-02-20 09:38:03 +00:00
read + = 2 ;
break ;
}
} else {
2022-10-13 13:33:59 +01:00
values [ bar_characters + + ] = 102 ;
2016-02-20 09:38:03 +00:00
read + + ;
}
2022-10-13 13:33:59 +01:00
if ( bar_characters > 80 - 2 ) { /* Max rows 16 * 5 - 2 check chars */
strcpy ( symbol - > errtxt , " 421: Input too long " ) ;
return ZINT_ERROR_TOO_LONG ;
}
} while ( read < length ) ;
2016-02-20 09:38:03 +00:00
pads_needed = 5 - ( ( bar_characters + 2 ) % 5 ) ;
if ( pads_needed = = 5 ) {
pads_needed = 0 ;
}
if ( ( bar_characters + pads_needed ) < 8 ) {
pads_needed + = 8 - ( bar_characters + pads_needed ) ;
}
2022-10-13 13:33:59 +01:00
rows = ( bar_characters + pads_needed + 4 ) / 5 ;
if ( symbol - > option_1 > rows ) {
extra_pads = ( symbol - > option_1 - rows ) * 5 ;
rows = symbol - > option_1 ;
}
2021-11-20 11:32:30 +00:00
for ( i = 0 ; i < pads_needed + extra_pads ; i + + ) {
2022-10-13 13:33:59 +01:00
values [ bar_characters + + ] = 103 ;
2016-02-20 09:38:03 +00:00
}
2022-10-13 13:33:59 +01:00
values [ 0 ] = ( 7 * ( rows - 2 ) ) + m ; /* see 4.3.4.2 */
2016-02-20 09:38:03 +00:00
/* Calculate check digits */
first_sum = 0 ;
second_sum = 0 ;
for ( i = 0 ; i < bar_characters ; i + + ) {
first_sum + = ( i + 2 ) * values [ i ] ;
second_sum + = ( i + 1 ) * values [ i ] ;
}
first_check = first_sum % 107 ;
second_sum + = first_check * ( bar_characters + 1 ) ;
second_check = second_sum % 107 ;
values [ bar_characters ] = first_check ;
values [ bar_characters + 1 ] = second_check ;
bar_characters + = 2 ;
2022-10-13 13:33:59 +01:00
if ( debug_print ) {
printf ( " Codewords (%d): " , bar_characters ) ;
2020-05-21 18:22:28 +01:00
for ( i = 0 ; i < bar_characters ; i + + ) {
2022-10-13 13:33:59 +01:00
if ( i % 5 = = 0 ) {
2023-06-12 01:25:55 +01:00
fputc ( ' \n ' , stdout ) ;
2022-10-13 13:33:59 +01:00
}
printf ( " %3d " , values [ i ] ) ;
2020-05-21 18:22:28 +01:00
}
2023-06-12 01:25:55 +01:00
fputc ( ' \n ' , stdout ) ;
2020-05-21 18:22:28 +01:00
}
# ifdef ZINT_TEST
if ( symbol - > debug & ZINT_DEBUG_TEST ) {
debug_test_codeword_dump_int ( symbol , values , bar_characters ) ; /* Missing row start/stop */
}
# endif
2022-10-13 13:33:59 +01:00
assert ( rows * 5 = = bar_characters ) ;
2020-09-30 12:19:12 +01:00
for ( current_row = 0 ; current_row < rows ; current_row + + ) {
2020-05-21 18:22:28 +01:00
int writer ;
2017-10-23 21:34:31 +02:00
int flip_flop ;
2020-05-21 18:22:28 +01:00
int len ;
2021-10-20 23:05:30 +01:00
char * d = width_pattern ;
2016-02-20 09:38:03 +00:00
2021-10-20 23:05:30 +01:00
memcpy ( d , C16KStartStop [ C16KStartValues [ current_row ] ] , 4 ) ;
d + = 4 ;
* d + + = ' 1 ' ;
for ( i = 0 ; i < 5 ; i + + , d + = 6 ) {
memcpy ( d , C128Table [ values [ ( current_row * 5 ) + i ] ] , 6 ) ;
2016-02-20 09:38:03 +00:00
}
2021-10-20 23:05:30 +01:00
memcpy ( d , C16KStartStop [ C16KStopValues [ current_row ] ] , 4 ) ;
d + = 4 ;
2016-02-20 09:38:03 +00:00
/* Write the information into the symbol */
2017-10-16 19:26:54 +02:00
writer = 0 ;
flip_flop = 1 ;
2021-10-20 23:05:30 +01:00
for ( mx_reader = 0 , len = d - width_pattern ; mx_reader < len ; mx_reader + + ) {
2016-02-20 09:38:03 +00:00
for ( looper = 0 ; looper < ctoi ( width_pattern [ mx_reader ] ) ; looper + + ) {
if ( flip_flop = = 1 ) {
set_module ( symbol , current_row , writer ) ;
}
2022-10-13 13:33:59 +01:00
writer + + ;
2016-02-20 09:38:03 +00:00
}
2022-10-13 13:33:59 +01:00
flip_flop = ! flip_flop ;
2016-02-20 09:38:03 +00:00
}
}
2020-09-30 12:19:12 +01:00
symbol - > rows = rows ;
2016-02-20 09:38:03 +00:00
symbol - > width = 70 ;
2020-05-21 18:22:28 +01:00
Add compliant height, using ZINT_COMPLIANT_HEIGHT flag for back-compatibility
Rename barcode funcs to same as BARCODE_XXX name
library: barcode funcs array for dispatch, used for ZBarcode_ValidID() also
general: change is_sane() comparison to nonzero from ZINT_ERROR_INVALID_OPTION
MAILMARK: fuller error messages
CODABAR: add option to show check character in HRT
zint.h: use 0xNNNN for OR-able defines
GUI: add guard descent height reset button, add Zint version to window title,
static get_zint_version() method, use QStringLiteral (QSL shorthand),
use SIGNAL(toggled()), add errtxt "popup" and status bar, add icons,
add saveAs shortcut, add main menu, context menus and actions, add help,
reset_view() -> reset_colours(), add copy to clipboard as EMF/GIF/PNG/TIF,
lessen triggering of update_preview(), shorten names of getters/setters,
simplify/shorten some update_preview() logic in switch,
CODEONE disable structapp for Version S
qzint.cpp: add on_errored signal, add missing getters, add test
2021-10-09 00:13:39 +01:00
if ( symbol - > output_options & COMPLIANT_HEIGHT ) {
/* BS EN 12323:2005 Section 4.5 (d) minimum 8X; use 10X as default
Section 4.5 ( b ) H = X [ r ( h + g ) + g ] = rows * row_height + ( rows - 1 ) * separator as borders not included
in symbol - > height ( added on ) */
const int separator = symbol - > option_3 > = 1 & & symbol - > option_3 < = 4 ? symbol - > option_3 : 1 ;
const float min_row_height = stripf ( ( 8.0f * rows + separator * ( rows - 1 ) ) / rows ) ;
const float default_height = 10.0f * rows + separator * ( rows - 1 ) ;
error_number = set_height ( symbol , min_row_height , default_height , 0.0f , 0 /*no_errtxt*/ ) ;
} else {
( void ) set_height ( symbol , 0.0f , 10.0f * rows , 0.0f , 1 /*no_errtxt*/ ) ;
}
2021-06-19 13:11:23 +01:00
2020-05-21 18:22:28 +01:00
symbol - > output_options | = BARCODE_BIND ;
if ( symbol - > border_width = = 0 ) { /* Allow override if non-zero */
symbol - > border_width = 1 ; /* BS EN 12323:2005 Section 4.3.7 minimum (note change from previous default 2) */
}
2020-09-30 12:19:12 +01:00
return error_number ;
2008-07-13 21:15:55 +00:00
}
2022-09-13 21:16:31 +01:00
/* vim: set ts=4 sw=4 et : */