2008-07-14 01:15:55 +04:00
/* common.c - Contains functions needed for a number of barcodes */
/*
libzint - the open source barcode library
2020-06-04 20:45:25 +03:00
Copyright ( C ) 2008 - 2020 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
2016-02-20 12:38:03 +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
2016-02-20 12:38:03 +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
2016-02-20 12:38:03 +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
2016-02-20 12:38:03 +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 12:38:03 +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
# include <stdio.h>
2020-05-02 03:02:37 +03:00
# ifdef _MSC_VER
# include <malloc.h>
# endif
2008-07-14 01:15:55 +04:00
# include "common.h"
2016-02-20 12:38:03 +03:00
/* Converts a character 0-9 to its equivalent integer value */
2019-12-19 03:37:55 +03:00
INTERNAL int ctoi ( const char source ) {
2016-02-20 12:38:03 +03:00
if ( ( source > = ' 0 ' ) & & ( source < = ' 9 ' ) )
return ( source - ' 0 ' ) ;
2017-10-21 14:45:50 +03:00
if ( ( source > = ' A ' ) & & ( source < = ' F ' ) )
return ( source - ' A ' + 10 ) ;
if ( ( source > = ' a ' ) & & ( source < = ' f ' ) )
return ( source - ' a ' + 10 ) ;
return - 1 ;
2008-07-14 01:15:55 +04:00
}
2017-05-14 10:15:08 +03:00
/* Convert an integer value to a string representing its binary equivalent */
2019-12-19 03:37:55 +03:00
INTERNAL void bin_append ( const int arg , const int length , char * binary ) {
2020-11-01 21:32:55 +03:00
int posn = ( int ) strlen ( binary ) ;
2019-12-04 16:45:01 +03:00
bin_append_posn ( arg , length , binary , posn ) ;
binary [ posn + length ] = ' \0 ' ;
}
/* Convert an integer value to a string representing its binary equivalent at a set position */
2020-11-01 21:32:55 +03:00
INTERNAL int bin_append_posn ( const int arg , const int length , char * binary , int posn ) {
2017-05-14 10:15:08 +03:00
int i ;
int start ;
2017-10-23 22:37:52 +03:00
2017-05-14 10:15:08 +03:00
start = 0x01 < < ( length - 1 ) ;
2017-10-23 22:37:52 +03:00
2017-05-14 10:15:08 +03:00
for ( i = 0 ; i < length ; i + + ) {
if ( arg & ( start > > i ) ) {
binary [ posn + i ] = ' 1 ' ;
2020-10-26 15:21:43 +03:00
} else {
binary [ posn + i ] = ' 0 ' ;
2017-05-14 10:15:08 +03:00
}
}
2020-11-01 21:32:55 +03:00
return posn + length ;
2017-05-14 10:15:08 +03:00
}
2017-07-21 16:16:23 +03:00
/* Converts an integer value to its hexadecimal character */
2019-12-19 03:37:55 +03:00
INTERNAL char itoc ( const int source ) {
2017-07-21 16:16:23 +03:00
if ( ( source > = 0 ) & & ( source < = 9 ) ) {
return ( ' 0 ' + source ) ;
} else {
return ( ' A ' + ( source - 10 ) ) ;
}
}
2019-12-19 03:37:55 +03:00
2016-02-20 12:38:03 +03:00
/* Converts lower case characters to upper case in a string source[] */
2019-12-19 03:37:55 +03:00
INTERNAL void to_upper ( unsigned char source [ ] ) {
2016-09-06 00:06:50 +03:00
size_t i , src_len = ustrlen ( source ) ;
2008-07-14 01:15:55 +04:00
2016-02-20 12:38:03 +03:00
for ( i = 0 ; i < src_len ; i + + ) {
if ( ( source [ i ] > = ' a ' ) & & ( source [ i ] < = ' z ' ) ) {
2020-08-05 00:22:26 +03:00
source [ i ] = ( source [ i ] - ' a ' ) + ' A ' ;
2016-02-20 12:38:03 +03:00
}
}
2008-07-14 01:15:55 +04:00
}
2016-02-20 12:38:03 +03:00
/* Verifies that a string only uses valid characters */
2019-12-19 03:37:55 +03:00
INTERNAL int is_sane ( const char test_string [ ] , const unsigned char source [ ] , const size_t length ) {
2017-09-10 18:03:09 +03:00
unsigned int j ;
2016-09-06 00:06:50 +03:00
size_t i , lt = strlen ( test_string ) ;
2016-02-20 12:38:03 +03:00
for ( i = 0 ; i < length ; i + + ) {
2017-09-10 18:03:09 +03:00
unsigned int latch = FALSE ;
2016-02-20 12:38:03 +03:00
for ( j = 0 ; j < lt ; j + + ) {
if ( source [ i ] = = test_string [ j ] ) {
latch = TRUE ;
break ;
}
}
if ( ! ( latch ) ) {
return ZINT_ERROR_INVALID_DATA ;
}
}
return 0 ;
2008-07-14 01:15:55 +04:00
}
2017-05-29 12:43:47 +03:00
/* Replaces huge switch statements for looking up in tables */
2019-12-19 03:37:55 +03:00
INTERNAL void lookup ( const char set_string [ ] , const char * table [ ] , const char data , char dest [ ] ) {
2020-10-26 15:21:43 +03:00
int i , n = ( int ) strlen ( set_string ) ;
2008-07-14 01:15:55 +04:00
2016-02-20 12:38:03 +03:00
for ( i = 0 ; i < n ; i + + ) {
if ( data = = set_string [ i ] ) {
2017-05-29 12:43:47 +03:00
strcat ( dest , table [ i ] ) ;
2020-10-26 15:21:43 +03:00
break ;
2016-02-20 12:38:03 +03:00
}
}
2008-07-14 01:15:55 +04:00
}
2017-05-29 12:43:47 +03:00
/* Returns the position of data in set_string */
2019-12-19 03:37:55 +03:00
INTERNAL int posn ( const char set_string [ ] , const char data ) {
2020-10-26 15:21:43 +03:00
int i , n = ( int ) strlen ( set_string ) ;
2008-07-14 01:15:55 +04:00
2016-02-20 12:38:03 +03:00
for ( i = 0 ; i < n ; i + + ) {
if ( data = = set_string [ i ] ) {
2019-11-05 17:16:48 +03:00
return i ;
2016-02-20 12:38:03 +03:00
}
}
2019-11-05 17:16:48 +03:00
return - 1 ;
}
2020-11-01 21:32:55 +03:00
# ifndef COMMON_INLINE
/* Return true (1) if a module is dark/black, otherwise false (0) */
2019-12-19 03:37:55 +03:00
INTERNAL int module_is_set ( const struct zint_symbol * symbol , const int y_coord , const int x_coord ) {
2020-11-01 21:32:55 +03:00
return ( symbol - > encoded_data [ y_coord ] [ x_coord > > 3 ] > > ( x_coord & 0x07 ) ) & 1 ;
2009-06-01 00:33:54 +04:00
}
2016-02-20 12:38:03 +03:00
/* Set a module to dark/black */
2019-12-19 03:37:55 +03:00
INTERNAL void set_module ( struct zint_symbol * symbol , const int y_coord , const int x_coord ) {
2020-11-01 21:32:55 +03:00
symbol - > encoded_data [ y_coord ] [ x_coord > > 3 ] | = 1 < < ( x_coord & 0x07 ) ;
}
/* Return true (1-8) if a module is colour, otherwise false (0) */
INTERNAL int module_colour_is_set ( const struct zint_symbol * symbol , const int y_coord , const int x_coord ) {
return symbol - > encoded_data [ y_coord ] [ x_coord ] ;
2020-06-04 20:45:25 +03:00
}
/* Set a module to a colour */
INTERNAL void set_module_colour ( struct zint_symbol * symbol , const int y_coord , const int x_coord , const int colour ) {
symbol - > encoded_data [ y_coord ] [ x_coord ] = colour ;
2009-06-01 00:33:54 +04:00
}
2020-11-01 21:32:55 +03:00
# endif
2009-06-01 00:33:54 +04:00
2020-09-30 14:19:12 +03:00
/* Set a dark/black module to white (i.e. unset) */
2019-12-19 03:37:55 +03:00
INTERNAL void unset_module ( struct zint_symbol * symbol , const int y_coord , const int x_coord ) {
2020-11-01 21:32:55 +03:00
symbol - > encoded_data [ y_coord ] [ x_coord > > 3 ] & = ~ ( 1 < < ( x_coord & 0x07 ) ) ;
2009-06-01 00:33:54 +04:00
}
2016-02-20 12:38:03 +03:00
/* Expands from a width pattern to a bit pattern */
2019-12-19 03:37:55 +03:00
INTERNAL void expand ( struct zint_symbol * symbol , const char data [ ] ) {
2016-02-20 12:38:03 +03:00
2020-10-26 15:21:43 +03:00
int reader , n = ( int ) strlen ( data ) ;
2016-02-20 12:38:03 +03:00
int writer , i ;
2020-10-26 15:21:43 +03:00
int latch , num ;
2016-02-20 12:38:03 +03:00
writer = 0 ;
2020-10-26 15:21:43 +03:00
latch = 1 ;
2016-02-20 12:38:03 +03:00
for ( reader = 0 ; reader < n ; reader + + ) {
2020-10-26 15:21:43 +03:00
num = ctoi ( data [ reader ] ) ;
for ( i = 0 ; i < num ; i + + ) {
if ( latch ) {
2016-02-20 12:38:03 +03:00
set_module ( symbol , symbol - > rows , writer ) ;
}
writer + + ;
}
2020-10-26 15:21:43 +03:00
latch = ! latch ;
2016-02-20 12:38:03 +03:00
}
if ( symbol - > symbology ! = BARCODE_PHARMA ) {
if ( writer > symbol - > width ) {
symbol - > width = writer ;
}
} else {
/* Pharmacode One ends with a space - adjust for this */
if ( writer > symbol - > width + 2 ) {
symbol - > width = writer - 2 ;
}
}
symbol - > rows = symbol - > rows + 1 ;
2008-07-14 01:15:55 +04:00
}
2008-12-25 00:29:31 +03:00
2020-09-30 14:19:12 +03:00
/* Indicates which symbologies can have row binding */
2019-12-19 03:37:55 +03:00
INTERNAL int is_stackable ( const int symbology ) {
2020-09-30 14:19:12 +03:00
if ( symbology < BARCODE_PHARMA_TWO & & symbology ! = BARCODE_POSTNET ) {
2017-05-29 12:43:47 +03:00
return 1 ;
2016-09-04 13:04:41 +03:00
}
2017-10-23 22:37:52 +03:00
2016-09-04 13:04:41 +03:00
switch ( symbology ) {
case BARCODE_CODE128B :
case BARCODE_ISBNX :
case BARCODE_EAN14 :
case BARCODE_NVE18 :
case BARCODE_KOREAPOST :
case BARCODE_PLESSEY :
case BARCODE_TELEPEN_NUM :
case BARCODE_ITF14 :
case BARCODE_CODE32 :
2016-09-12 23:47:40 +03:00
case BARCODE_CODABLOCKF :
2020-05-16 12:22:33 +03:00
case BARCODE_HIBC_BLOCKF :
2017-05-29 12:43:47 +03:00
return 1 ;
2016-09-04 13:04:41 +03:00
}
2017-05-29 12:43:47 +03:00
return 0 ;
2008-12-25 00:29:31 +03:00
}
2020-09-30 14:19:12 +03:00
/* Indicates which symbols can have addon (EAN-2 and EAN-5) */
2019-12-19 03:37:55 +03:00
INTERNAL int is_extendable ( const int symbology ) {
2020-07-15 21:00:12 +03:00
switch ( symbology ) {
case BARCODE_EANX :
case BARCODE_EANX_CHK :
case BARCODE_UPCA :
case BARCODE_UPCA_CHK :
case BARCODE_UPCE :
case BARCODE_UPCE_CHK :
case BARCODE_ISBNX :
case BARCODE_EANX_CC :
case BARCODE_UPCA_CC :
case BARCODE_UPCE_CC :
return 1 ;
2016-02-20 12:38:03 +03:00
}
return 0 ;
2009-06-18 14:20:23 +04:00
}
2019-10-17 12:06:21 +03:00
/* Indicates which symbols can have composite 2D component data */
2020-08-05 17:58:21 +03:00
INTERNAL int is_composite ( const int symbology ) {
2020-07-29 22:43:08 +03:00
return symbology > = BARCODE_EANX_CC & & symbology < = BARCODE_DBAR_EXPSTK_CC ;
2019-10-17 12:06:21 +03:00
}
2020-06-04 20:45:25 +03:00
INTERNAL int istwodigits ( const unsigned char source [ ] , const int length , const int position ) {
if ( ( position + 1 < length ) & & ( source [ position ] > = ' 0 ' ) & & ( source [ position ] < = ' 9 ' )
& & ( source [ position + 1 ] > = ' 0 ' ) & & ( source [ position + 1 ] < = ' 9 ' ) ) {
return 1 ;
2016-02-20 12:38:03 +03:00
}
2012-12-31 17:41:59 +04:00
2016-02-20 12:38:03 +03:00
return 0 ;
2009-07-05 00:48:42 +04:00
}
2019-11-27 19:16:14 +03:00
/* State machine to decode UTF-8 to Unicode codepoints (state 0 means done, state 12 means error) */
2020-07-10 21:39:32 +03:00
INTERNAL unsigned int decode_utf8 ( unsigned int * state , unsigned int * codep , const unsigned char byte ) {
2019-11-27 19:16:14 +03:00
/*
Copyright ( c ) 2008 - 2009 Bjoern Hoehrmann < bjoern @ hoehrmann . de >
Permission is hereby granted , free of charge , to any person obtaining a copy of this software and associated documentation
files ( the " Software " ) , to deal in the Software without restriction , including without limitation the rights to use , copy ,
modify , merge , publish , distribute , sublicense , and / or sell copies of the Software , and to permit persons to whom the
Software is furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software .
See https : //bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
*/
static const unsigned char utf8d [ ] = {
/* The first part of the table maps bytes to character classes that
* reduce the size of the transition table and create bitmasks . */
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 ,
7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 ,
8 , 8 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 ,
10 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 4 , 3 , 3 , 11 , 6 , 6 , 6 , 5 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 ,
/* The second part is a transition table that maps a combination
* of a state of the automaton and a character class to a state . */
0 , 12 , 24 , 36 , 60 , 96 , 84 , 12 , 12 , 12 , 48 , 72 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 ,
12 , 0 , 12 , 12 , 12 , 12 , 12 , 0 , 12 , 0 , 12 , 12 , 12 , 24 , 12 , 12 , 12 , 12 , 12 , 24 , 12 , 24 , 12 , 12 ,
12 , 12 , 12 , 12 , 12 , 12 , 12 , 24 , 12 , 12 , 12 , 12 , 12 , 24 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 24 , 12 , 12 ,
12 , 12 , 12 , 12 , 12 , 12 , 12 , 36 , 12 , 36 , 12 , 12 , 12 , 36 , 12 , 12 , 12 , 12 , 12 , 36 , 12 , 36 , 12 , 12 ,
12 , 36 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 ,
} ;
unsigned int type = utf8d [ byte ] ;
* codep = * state ! = 0 ? ( byte & 0x3fu ) | ( * codep < < 6 ) : ( 0xff > > type ) & byte ;
* state = utf8d [ 256 + * state + type ] ;
return * state ;
}
2019-12-08 19:15:34 +03:00
/* Convert UTF-8 to Unicode. If `disallow_4byte` unset, allow all values (UTF-32).
* If ` disallow_4byte ` set , only allow codepoints < = U + FFFF ( ie four - byte sequences not allowed ) ( UTF - 16 , no surrogates ) */
2019-12-19 03:37:55 +03:00
INTERNAL int utf8_to_unicode ( struct zint_symbol * symbol , const unsigned char source [ ] , unsigned int vals [ ] , size_t * length , int disallow_4byte ) {
2017-05-29 12:43:47 +03:00
size_t bpos ;
2019-11-27 19:16:14 +03:00
int jpos ;
unsigned int codepoint , state = 0 ;
2016-02-20 12:38:03 +03:00
bpos = 0 ;
jpos = 0 ;
2019-11-27 19:16:14 +03:00
while ( bpos < * length ) {
do {
decode_utf8 ( & state , & codepoint , source [ bpos + + ] ) ;
} while ( bpos < * length & & state ! = 0 & & state ! = 12 ) ;
if ( state ! = 0 ) {
strcpy ( symbol - > errtxt , " 240: Corrupt Unicode data " ) ;
return ZINT_ERROR_INVALID_DATA ;
}
2019-12-08 19:15:34 +03:00
if ( disallow_4byte & & codepoint > 0xffff ) {
2019-11-27 19:16:14 +03:00
strcpy ( symbol - > errtxt , " 242: Unicode sequences of more than 3 bytes not supported " ) ;
return ZINT_ERROR_INVALID_DATA ;
2016-02-20 12:38:03 +03:00
}
2019-11-27 19:16:14 +03:00
vals [ jpos ] = codepoint ;
jpos + + ;
}
2019-12-04 16:45:01 +03:00
2016-02-20 12:38:03 +03:00
* length = jpos ;
2019-11-27 19:16:14 +03:00
return 0 ;
2009-10-06 23:03:00 +04:00
}
2009-09-29 13:45:46 +04:00
2019-12-08 19:15:34 +03:00
/* Enforce minimum permissable height of rows */
2019-12-19 03:37:55 +03:00
INTERNAL void set_minimum_height ( struct zint_symbol * symbol , const int min_height ) {
2016-10-14 20:56:49 +03:00
int fixed_height = 0 ;
int zero_count = 0 ;
int i ;
2017-10-23 22:37:52 +03:00
2016-10-14 20:56:49 +03:00
for ( i = 0 ; i < symbol - > rows ; i + + ) {
fixed_height + = symbol - > row_height [ i ] ;
2017-10-23 22:37:52 +03:00
2016-10-14 20:56:49 +03:00
if ( symbol - > row_height [ i ] = = 0 ) {
zero_count + + ;
}
}
2017-10-23 22:37:52 +03:00
2016-10-27 11:32:12 +03:00
if ( zero_count > 0 ) {
if ( ( ( symbol - > height - fixed_height ) / zero_count ) < min_height ) {
for ( i = 0 ; i < symbol - > rows ; i + + ) {
if ( symbol - > row_height [ i ] = = 0 ) {
symbol - > row_height [ i ] = min_height ;
}
2016-10-14 20:56:49 +03:00
}
}
}
}
2017-10-23 22:37:52 +03:00
2019-12-08 19:15:34 +03:00
/* Calculate optimized encoding modes. Adapted from Project Nayuki */
2020-07-10 21:39:32 +03:00
INTERNAL void pn_define_mode ( char * mode , const unsigned int data [ ] , const size_t length , const int debug ,
unsigned int state [ ] , const char mode_types [ ] , const int num_modes ,
pn_head_costs head_costs , pn_switch_cost switch_cost , pn_eod_cost eod_cost , pn_cur_cost cur_cost ) {
2019-12-08 19:15:34 +03:00
/*
* Copyright ( c ) Project Nayuki . ( MIT License )
* https : //www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted , free of charge , to any person obtaining a copy of
* this software and associated documentation files ( the " Software " ) , to deal in
* the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of
* the Software , and to permit persons to whom the Software is furnished to do so ,
* subject to the following conditions :
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*/
int i , j , k , cm_i ;
unsigned int min_cost ;
char cur_mode ;
# ifndef _MSC_VER
unsigned int prev_costs [ num_modes ] ;
char char_modes [ length * num_modes ] ;
unsigned int cur_costs [ num_modes ] ;
# else
2020-07-10 21:39:32 +03:00
unsigned int * prev_costs ;
char * char_modes ;
unsigned int * cur_costs ;
prev_costs = ( unsigned int * ) _alloca ( num_modes * sizeof ( unsigned int ) ) ;
char_modes = ( char * ) _alloca ( length * num_modes ) ;
cur_costs = ( unsigned int * ) _alloca ( num_modes * sizeof ( unsigned int ) ) ;
2019-12-08 19:15:34 +03:00
# endif
2019-12-19 03:37:55 +03:00
/* char_modes[i * num_modes + j] represents the mode to encode the code point at index i such that the final
* segment ends in mode_types [ j ] and the total number of bits is minimized over all possible choices */
2019-12-08 19:15:34 +03:00
memset ( char_modes , 0 , length * num_modes ) ;
2019-12-19 03:37:55 +03:00
/* At the beginning of each iteration of the loop below, prev_costs[j] is the minimum number of 1/6 (1/XX_MULT)
* bits needed to encode the entire string prefix of length i , and end in mode_types [ j ] */
2019-12-08 19:15:34 +03:00
memcpy ( prev_costs , ( * head_costs ) ( state ) , num_modes * sizeof ( unsigned int ) ) ;
/* Calculate costs using dynamic programming */
2020-03-30 13:59:16 +03:00
for ( i = 0 , cm_i = 0 ; i < ( int ) length ; i + + , cm_i + = num_modes ) {
2019-12-08 19:15:34 +03:00
memset ( cur_costs , 0 , num_modes * sizeof ( unsigned int ) ) ;
( * cur_cost ) ( state , data , length , i , char_modes , prev_costs , cur_costs ) ;
2020-03-30 13:59:16 +03:00
if ( eod_cost & & i = = ( int ) length - 1 ) { /* Add end of data costs if last character */
2019-12-08 19:15:34 +03:00
for ( j = 0 ; j < num_modes ; j + + ) {
if ( char_modes [ cm_i + j ] ) {
cur_costs [ j ] + = ( * eod_cost ) ( state , j ) ;
}
}
}
/* Start new segment at the end to switch modes */
for ( j = 0 ; j < num_modes ; j + + ) { /* To mode */
for ( k = 0 ; k < num_modes ; k + + ) { /* From mode */
if ( j ! = k & & char_modes [ cm_i + k ] ) {
unsigned int new_cost = cur_costs [ k ] + ( * switch_cost ) ( state , k , j ) ;
if ( ! char_modes [ cm_i + j ] | | new_cost < cur_costs [ j ] ) {
cur_costs [ j ] = new_cost ;
char_modes [ cm_i + j ] = mode_types [ k ] ;
}
}
}
}
memcpy ( prev_costs , cur_costs , num_modes * sizeof ( unsigned int ) ) ;
}
/* Find optimal ending mode */
min_cost = prev_costs [ 0 ] ;
cur_mode = mode_types [ 0 ] ;
for ( i = 1 ; i < num_modes ; i + + ) {
if ( prev_costs [ i ] < min_cost ) {
min_cost = prev_costs [ i ] ;
cur_mode = mode_types [ i ] ;
}
}
/* Get optimal mode for each code point by tracing backwards */
for ( i = length - 1 , cm_i = i * num_modes ; i > = 0 ; i - - , cm_i - = num_modes ) {
j = strchr ( mode_types , cur_mode ) - mode_types ;
cur_mode = char_modes [ cm_i + j ] ;
mode [ i ] = cur_mode ;
}
if ( debug & ZINT_DEBUG_PRINT ) {
2020-07-10 21:39:32 +03:00
printf ( " Mode: %.*s \n " , ( int ) length , mode ) ;
2019-12-08 19:15:34 +03:00
}
}
2019-12-16 20:31:52 +03:00
2020-08-12 15:19:56 +03:00
INTERNAL int colour_to_red ( int colour ) {
int return_val = 0 ;
switch ( colour ) {
case 8 : // White
case 3 : // Magenta
case 4 : // Red
case 5 : // Yellow
return_val = 255 ;
break ;
}
return return_val ;
}
INTERNAL int colour_to_green ( int colour ) {
int return_val = 0 ;
switch ( colour ) {
case 8 : // White
case 1 : // Cyan
case 5 : // Yellow
case 6 : // Green
return_val = 255 ;
break ;
}
return return_val ;
}
INTERNAL int colour_to_blue ( int colour ) {
int return_val = 0 ;
switch ( colour ) {
case 8 : // White
case 1 : // Cyan
case 2 : // Blue
case 3 : // Magenta
return_val = 255 ;
break ;
}
return return_val ;
}
2019-12-19 03:37:55 +03:00
# ifdef ZINT_TEST
2019-12-16 20:31:52 +03:00
/* Dumps hex-formatted codewords in symbol->errtxt (for use in testing) */
2020-07-10 21:39:32 +03:00
void debug_test_codeword_dump ( struct zint_symbol * symbol , unsigned char * codewords , int length ) {
2019-12-16 20:31:52 +03:00
int i , max = length , cnt_len = 0 ;
if ( length > 30 ) { /* 30*3 < errtxt 92 (100 - "Warning ") chars */
sprintf ( symbol - > errtxt , " (%d) " , length ) ; /* Place the number of codewords at the front */
cnt_len = strlen ( symbol - > errtxt ) ;
max = 30 - ( cnt_len + 2 ) / 3 ;
}
for ( i = 0 ; i < max ; i + + ) {
sprintf ( symbol - > errtxt + cnt_len + i * 3 , " %02X " , codewords [ i ] ) ;
}
symbol - > errtxt [ strlen ( symbol - > errtxt ) - 1 ] = ' \0 ' ; /* Zap last space */
}
2020-04-10 00:08:54 +03:00
2020-07-10 21:39:32 +03:00
void debug_test_codeword_dump_int ( struct zint_symbol * symbol , int * codewords , int length ) {
2020-04-10 00:08:54 +03:00
int i , max = 0 , cnt_len , errtxt_len ;
char temp [ 20 ] ;
errtxt_len = sprintf ( symbol - > errtxt , " (%d) " , length ) ; /* Place the number of codewords at the front */
for ( i = 0 , cnt_len = errtxt_len ; i < length ; i + + ) {
cnt_len + = sprintf ( temp , " %d " , codewords [ i ] ) ;
if ( cnt_len > 92 ) {
break ;
}
max + + ;
}
for ( i = 0 ; i < max ; i + + ) {
errtxt_len + = sprintf ( symbol - > errtxt + errtxt_len , " %d " , codewords [ i ] ) ;
}
symbol - > errtxt [ strlen ( symbol - > errtxt ) - 1 ] = ' \0 ' ; /* Zap last space */
}
2019-12-19 03:37:55 +03:00
# endif