2016-04-07 19:13:43 +03:00
/* hanxin.c - Han Xin Code
libzint - the open source barcode library
2021-01-11 21:11:41 +03:00
Copyright ( C ) 2009 - 2021 Robin Stuart < rstuart114 @ gmail . com >
2016-04-07 19:13:43 +03:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
3. Neither the name of the project nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
*/
2019-11-27 19:16:14 +03:00
/* vim: set ts=4 sw=4 et : */
2016-04-07 19:13:43 +03:00
2020-11-27 15:54:44 +03:00
/* This code attempts to implement Han Xin Code according to ISO/IEC 20830 (draft 2019-10-10)
* ( previously AIMD - 015 : 2010 ( Rev 0.8 ) ) */
2016-04-07 19:13:43 +03:00
# include <stdio.h>
# ifdef _MSC_VER
# include <malloc.h>
# endif
# include "common.h"
# include "reedsol.h"
# include "hanxin.h"
2017-05-14 16:43:49 +03:00
# include "gb2312.h"
2016-05-02 00:10:50 +03:00
# include "gb18030.h"
2021-01-11 21:11:41 +03:00
# include "eci.h"
# include <assert.h>
2016-04-07 19:13:43 +03:00
2016-04-09 19:01:21 +03:00
/* Find which submode to use for a text character */
2020-11-27 15:54:44 +03:00
static int getsubmode ( const unsigned int input ) {
2017-10-23 22:37:52 +03:00
2016-04-09 19:01:21 +03:00
if ( ( input > = ' 0 ' ) & & ( input < = ' 9 ' ) ) {
2020-11-27 15:54:44 +03:00
return 1 ;
2016-04-09 19:01:21 +03:00
}
2017-10-23 22:37:52 +03:00
2016-04-09 19:01:21 +03:00
if ( ( input > = ' A ' ) & & ( input < = ' Z ' ) ) {
2020-11-27 15:54:44 +03:00
return 1 ;
2016-04-09 19:01:21 +03:00
}
2017-10-23 22:37:52 +03:00
2016-04-09 19:01:21 +03:00
if ( ( input > = ' a ' ) & & ( input < = ' z ' ) ) {
2020-11-27 15:54:44 +03:00
return 1 ;
2016-04-09 19:01:21 +03:00
}
2017-10-23 22:37:52 +03:00
2020-11-27 15:54:44 +03:00
return 2 ;
2016-04-09 19:01:21 +03:00
}
2019-12-08 19:15:34 +03:00
/* Return length of terminator for encoding mode */
2020-11-27 15:54:44 +03:00
static int terminator_length ( const char mode ) {
2019-12-08 19:15:34 +03:00
int result = 0 ;
switch ( mode ) {
case ' n ' :
result = 10 ;
break ;
case ' t ' :
result = 6 ;
break ;
case ' 1 ' :
case ' 2 ' :
result = 12 ;
break ;
case ' d ' :
result = 15 ;
break ;
}
return result ;
}
/* Calculate the length of the binary string */
2020-11-27 15:54:44 +03:00
static int calculate_binlength ( const char mode [ ] , const unsigned int source [ ] , const int length , const int eci ) {
int i ;
2019-12-08 19:15:34 +03:00
char lastmode = ' \0 ' ;
2016-04-08 00:30:37 +03:00
int est_binlen = 0 ;
2016-04-09 19:01:21 +03:00
int submode = 1 ;
2019-12-08 19:15:34 +03:00
int numeric_run = 0 ;
2017-10-23 22:37:52 +03:00
2019-10-06 19:39:54 +03:00
if ( eci ! = 0 ) {
2019-12-08 19:15:34 +03:00
est_binlen + = 4 ;
if ( eci < = 127 ) {
est_binlen + = 8 ;
2020-11-27 15:54:44 +03:00
} else if ( eci < = 16383 ) {
2019-12-08 19:15:34 +03:00
est_binlen + = 16 ;
} else {
est_binlen + = 24 ;
}
2016-08-16 14:43:41 +03:00
}
2017-10-23 22:37:52 +03:00
2016-05-02 00:10:50 +03:00
i = 0 ;
do {
2019-12-08 19:15:34 +03:00
if ( mode [ i ] ! = lastmode ) {
if ( i > 0 ) {
est_binlen + = terminator_length ( lastmode ) ;
}
/* GB 4-byte has indicator for each character (and no terminator) so not included here */
/* Region1/Region2 have special terminator to go directly into each other's mode so not included here */
if ( mode [ i ] ! = ' f ' | | ( ( mode [ i ] = = ' 1 ' & & lastmode = = ' 2 ' ) | | ( mode [ i ] = = ' 2 ' & & lastmode = = ' 1 ' ) ) ) {
est_binlen + = 4 ;
}
if ( mode [ i ] = = ' b ' ) { /* Byte mode has byte count (and no terminator) */
est_binlen + = 13 ;
}
lastmode = mode [ i ] ;
submode = 1 ;
numeric_run = 0 ;
}
2016-04-08 00:30:37 +03:00
switch ( mode [ i ] ) {
case ' n ' :
2019-12-08 19:15:34 +03:00
if ( numeric_run % 3 = = 0 ) {
est_binlen + = 10 ;
2016-04-08 00:30:37 +03:00
}
2019-12-08 19:15:34 +03:00
numeric_run + + ;
2016-04-08 00:30:37 +03:00
break ;
case ' t ' :
2019-12-08 19:15:34 +03:00
if ( getsubmode ( source [ i ] ) ! = submode ) {
2016-04-09 19:01:21 +03:00
est_binlen + = 6 ;
2019-12-08 19:15:34 +03:00
submode = getsubmode ( source [ i ] ) ;
2016-04-08 00:30:37 +03:00
}
est_binlen + = 6 ;
2016-04-10 22:36:57 +03:00
break ;
2016-04-08 00:30:37 +03:00
case ' b ' :
2019-12-08 19:15:34 +03:00
est_binlen + = source [ i ] > 0xFF ? 16 : 8 ;
2016-04-10 22:36:57 +03:00
break ;
2016-05-02 00:10:50 +03:00
case ' 1 ' :
case ' 2 ' :
est_binlen + = 12 ;
break ;
case ' d ' :
est_binlen + = 15 ;
break ;
case ' f ' :
2019-12-08 19:15:34 +03:00
est_binlen + = 25 ;
2016-05-02 00:10:50 +03:00
i + + ;
break ;
2016-04-08 00:30:37 +03:00
}
2016-05-02 00:10:50 +03:00
i + + ;
} while ( i < length ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
est_binlen + = terminator_length ( lastmode ) ;
2016-04-08 00:30:37 +03:00
return est_binlen ;
}
2020-11-27 15:54:44 +03:00
static int isRegion1 ( const unsigned int glyph ) {
unsigned int byte ;
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
byte = glyph > > 8 ;
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
if ( ( byte > = 0xb0 ) & & ( byte < = 0xd7 ) ) {
byte = glyph & 0xff ;
if ( ( byte > = 0xa1 ) & & ( byte < = 0xfe ) ) {
return 1 ;
2016-05-02 00:10:50 +03:00
}
2020-11-27 15:54:44 +03:00
} else if ( ( byte > = 0xa1 ) & & ( byte < = 0xa3 ) ) {
byte = glyph & 0xff ;
if ( ( byte > = 0xa1 ) & & ( byte < = 0xfe ) ) {
return 1 ;
2016-05-02 00:10:50 +03:00
}
2020-11-27 15:54:44 +03:00
} else if ( ( glyph > = 0xa8a1 ) & & ( glyph < = 0xa8c0 ) ) {
return 1 ;
2016-05-02 00:10:50 +03:00
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
return 0 ;
2016-05-02 00:10:50 +03:00
}
2020-11-27 15:54:44 +03:00
static int isRegion2 ( const unsigned int glyph ) {
unsigned int byte ;
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
byte = glyph > > 8 ;
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
if ( ( byte > = 0xd8 ) & & ( byte < = 0xf7 ) ) {
byte = glyph & 0xff ;
if ( ( byte > = 0xa1 ) & & ( byte < = 0xfe ) ) {
return 1 ;
2016-05-02 00:10:50 +03:00
}
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
return 0 ;
2016-05-02 00:10:50 +03:00
}
2020-11-27 15:54:44 +03:00
static int isDoubleByte ( const unsigned int glyph ) {
unsigned int byte ;
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
byte = glyph > > 8 ;
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
if ( ( byte > = 0x81 ) & & ( byte < = 0xfe ) ) {
byte = glyph & 0xff ;
if ( ( byte > = 0x40 ) & & ( byte < = 0x7e ) ) {
return 1 ;
2016-05-02 00:10:50 +03:00
}
2020-11-27 15:54:44 +03:00
if ( ( byte > = 0x80 ) & & ( byte < = 0xfe ) ) {
return 1 ;
2016-05-02 00:10:50 +03:00
}
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
return 0 ;
2016-05-02 00:10:50 +03:00
}
2020-11-27 15:54:44 +03:00
static int isFourByte ( const unsigned int glyph , const unsigned int glyph2 ) {
unsigned int byte ;
byte = glyph > > 8 ;
if ( ( byte > = 0x81 ) & & ( byte < = 0xfe ) ) {
byte = glyph & 0xff ;
if ( ( byte > = 0x30 ) & & ( byte < = 0x39 ) ) {
byte = glyph2 > > 8 ;
if ( ( byte > = 0x81 ) & & ( byte < = 0xfe ) ) {
byte = glyph2 & 0xff ;
if ( ( byte > = 0x30 ) & & ( byte < = 0x39 ) ) {
return 1 ;
2016-05-02 00:10:50 +03:00
}
}
}
}
2017-10-23 22:37:52 +03:00
2020-11-27 15:54:44 +03:00
return 0 ;
2016-05-02 00:10:50 +03:00
}
2016-04-08 00:30:37 +03:00
/* Convert Text 1 sub-mode character to encoding value, as given in table 3 */
2020-11-27 15:54:44 +03:00
static int lookup_text1 ( const unsigned int input ) {
2017-10-23 22:37:52 +03:00
2016-04-08 00:30:37 +03:00
if ( ( input > = ' 0 ' ) & & ( input < = ' 9 ' ) ) {
2020-11-27 15:54:44 +03:00
return input - ' 0 ' ;
2016-04-08 00:30:37 +03:00
}
2017-10-23 22:37:52 +03:00
2016-04-08 00:30:37 +03:00
if ( ( input > = ' A ' ) & & ( input < = ' Z ' ) ) {
2020-11-27 15:54:44 +03:00
return input - ' A ' + 10 ;
2016-04-08 00:30:37 +03:00
}
2017-10-23 22:37:52 +03:00
2016-04-08 00:30:37 +03:00
if ( ( input > = ' a ' ) & & ( input < = ' z ' ) ) {
2020-11-27 15:54:44 +03:00
return input - ' a ' + 36 ;
2016-04-08 00:30:37 +03:00
}
2017-10-23 22:37:52 +03:00
2020-11-27 15:54:44 +03:00
return - 1 ;
2016-04-08 00:30:37 +03:00
}
/* Convert Text 2 sub-mode character to encoding value, as given in table 4 */
2020-11-27 15:54:44 +03:00
static int lookup_text2 ( const unsigned int input ) {
2017-10-23 22:37:52 +03:00
2019-12-08 19:15:34 +03:00
if ( input < = 27 ) {
2020-11-27 15:54:44 +03:00
return input ;
2016-04-08 00:30:37 +03:00
}
2017-10-23 22:37:52 +03:00
2016-04-08 00:30:37 +03:00
if ( ( input > = ' ' ) & & ( input < = ' / ' ) ) {
2020-11-27 15:54:44 +03:00
return input - ' ' + 28 ;
2016-04-08 00:30:37 +03:00
}
2017-10-23 22:37:52 +03:00
2019-12-08 19:15:34 +03:00
if ( ( input > = ' : ' ) & & ( input < = ' @ ' ) ) {
2020-11-27 15:54:44 +03:00
return input - ' : ' + 44 ;
2019-12-08 19:15:34 +03:00
}
2016-04-08 00:30:37 +03:00
if ( ( input > = ' [ ' ) & & ( input < = 96 ) ) {
2020-11-27 15:54:44 +03:00
return input - ' [ ' + 51 ;
2016-04-08 00:30:37 +03:00
}
2017-10-23 22:37:52 +03:00
2016-04-08 00:30:37 +03:00
if ( ( input > = ' { ' ) & & ( input < = 127 ) ) {
2020-11-27 15:54:44 +03:00
return input - ' { ' + 57 ;
2016-04-08 00:30:37 +03:00
}
2017-10-23 22:37:52 +03:00
2020-11-27 15:54:44 +03:00
return - 1 ;
2016-04-08 00:30:37 +03:00
}
2019-12-08 19:15:34 +03:00
/* hx_define_mode() stuff */
/* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */
# define HX_MULT 6
2020-11-27 15:54:44 +03:00
/* Whether in numeric or not. If in numeric, *p_end is set to position after numeric,
* and * p_cost is set to per - numeric cost */
static int in_numeric ( const unsigned int gbdata [ ] , const int length , const int in_posn ,
unsigned int * p_end , unsigned int * p_cost ) {
int i , digit_cnt ;
2019-12-08 19:15:34 +03:00
2020-11-27 15:54:44 +03:00
if ( in_posn < ( int ) * p_end ) {
2019-12-08 19:15:34 +03:00
return 1 ;
}
/* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times HX_MULT) */
2020-11-27 15:54:44 +03:00
for ( i = in_posn ; i < length & & i < in_posn + 4 & & gbdata [ i ] > = ' 0 ' & & gbdata [ i ] < = ' 9 ' ; i + + ) ;
2019-12-08 19:15:34 +03:00
2020-11-27 15:54:44 +03:00
digit_cnt = i - in_posn ;
2019-12-08 23:22:10 +03:00
if ( digit_cnt = = 0 ) {
2019-12-08 19:15:34 +03:00
* p_end = 0 ;
return 0 ;
}
* p_end = i ;
2021-06-19 15:11:23 +03:00
* p_cost = digit_cnt = = 1
? 60 /* 10 * HX_MULT */ : digit_cnt = = 2 ? 30 /* (10 / 2) * HX_MULT */ : 20 /* (10 / 3) * HX_MULT */ ;
2019-12-08 19:15:34 +03:00
return 1 ;
}
2020-11-27 15:54:44 +03:00
/* Whether in four-byte or not. If in four-byte, *p_fourbyte is set to position after four-byte,
* and * p_fourbyte_cost is set to per - position cost */
static int in_fourbyte ( const unsigned int gbdata [ ] , const int length , const int in_posn ,
unsigned int * p_end , unsigned int * p_cost ) {
if ( in_posn < ( int ) * p_end ) {
2019-12-08 19:15:34 +03:00
return 1 ;
}
2020-11-27 15:54:44 +03:00
if ( in_posn = = length - 1 | | ! isFourByte ( gbdata [ in_posn ] , gbdata [ in_posn + 1 ] ) ) {
2019-12-08 19:15:34 +03:00
* p_end = 0 ;
return 0 ;
}
2020-11-27 15:54:44 +03:00
* p_end = in_posn + 2 ;
2019-12-08 19:15:34 +03:00
* p_cost = 75 ; /* ((4 + 21) / 2) * HX_MULT */
return 1 ;
}
/* Indexes into mode_types array */
# define HX_N 0 /* Numeric */
# define HX_T 1 /* Text */
# define HX_B 2 /* Binary */
# define HX_1 3 /* Common Chinese Region One */
# define HX_2 4 /* Common Chinese Region Two */
# define HX_D 5 /* GB 18030 2-byte Region */
# define HX_F 6 /* GB 18030 4-byte Region */
/* Note Unicode, GS1 and URI modes not implemented */
# define HX_NUM_MODES 7
2020-11-27 15:54:44 +03:00
/* Calculate optimized encoding modes. Adapted from Project Nayuki */
/* Copyright (c) Project Nayuki. (MIT License) See qr.c for detailed notice */
static void hx_define_mode ( char * mode , const unsigned int gbdata [ ] , const int length , const int debug ) {
/* Must be in same order as HX_N etc */
static const char mode_types [ ] = { ' n ' , ' t ' , ' b ' , ' 1 ' , ' 2 ' , ' d ' , ' f ' , ' \0 ' } ;
/* Initial mode costs */
2019-12-08 19:15:34 +03:00
static unsigned int head_costs [ HX_NUM_MODES ] = {
/* N T B 1 2 D F */
4 * HX_MULT , 4 * HX_MULT , ( 4 + 13 ) * HX_MULT , 4 * HX_MULT , 4 * HX_MULT , 4 * HX_MULT , 0
} ;
2020-11-27 15:54:44 +03:00
/* Cost of switching modes from k to j */
2019-12-19 03:37:55 +03:00
static const unsigned int switch_costs [ HX_NUM_MODES ] [ HX_NUM_MODES ] = {
2019-12-08 19:15:34 +03:00
/* N T B 1 2 D F */
/*N*/ { 0 , ( 10 + 4 ) * HX_MULT , ( 10 + 4 + 13 ) * HX_MULT , ( 10 + 4 ) * HX_MULT , ( 10 + 4 ) * HX_MULT , ( 10 + 4 ) * HX_MULT , 10 * HX_MULT } ,
/*T*/ { ( 6 + 4 ) * HX_MULT , 0 , ( 6 + 4 + 13 ) * HX_MULT , ( 6 + 4 ) * HX_MULT , ( 6 + 4 ) * HX_MULT , ( 6 + 4 ) * HX_MULT , 6 * HX_MULT } ,
/*B*/ { 4 * HX_MULT , 4 * HX_MULT , 0 , 4 * HX_MULT , 4 * HX_MULT , 4 * HX_MULT , 0 } ,
/*1*/ { ( 12 + 4 ) * HX_MULT , ( 12 + 4 ) * HX_MULT , ( 12 + 4 + 13 ) * HX_MULT , 0 , 12 * HX_MULT , ( 12 + 4 ) * HX_MULT , 12 * HX_MULT } ,
/*2*/ { ( 12 + 4 ) * HX_MULT , ( 12 + 4 ) * HX_MULT , ( 12 + 4 + 13 ) * HX_MULT , 12 * HX_MULT , 0 , ( 12 + 4 ) * HX_MULT , 12 * HX_MULT } ,
/*D*/ { ( 15 + 4 ) * HX_MULT , ( 15 + 4 ) * HX_MULT , ( 15 + 4 + 13 ) * HX_MULT , ( 15 + 4 ) * HX_MULT , ( 15 + 4 ) * HX_MULT , 0 , 15 * HX_MULT } ,
/*F*/ { 4 * HX_MULT , 4 * HX_MULT , ( 4 + 13 ) * HX_MULT , 4 * HX_MULT , 4 * HX_MULT , 4 * HX_MULT , 0 } ,
} ;
2020-11-27 15:54:44 +03:00
/* Final end-of-data costs */
2019-12-19 03:37:55 +03:00
static const unsigned int eod_costs [ HX_NUM_MODES ] = {
2019-12-08 19:15:34 +03:00
/* N T B 1 2 D F */
10 * HX_MULT , 6 * HX_MULT , 0 , 12 * HX_MULT , 12 * HX_MULT , 15 * HX_MULT , 0
} ;
2020-11-27 15:54:44 +03:00
unsigned int numeric_end = 0 , numeric_cost = 0 , text_submode = 1 , fourbyte_end = 0 , fourbyte_cost = 0 ; /* State */
2019-12-08 19:15:34 +03:00
int text1 , text2 ;
2020-11-27 15:54:44 +03:00
int i , j , k , cm_i ;
unsigned int min_cost ;
char cur_mode ;
unsigned int prev_costs [ HX_NUM_MODES ] ;
unsigned int cur_costs [ HX_NUM_MODES ] ;
# ifndef _MSC_VER
char char_modes [ length * HX_NUM_MODES ] ;
# else
char * char_modes = ( char * ) _alloca ( length * HX_NUM_MODES ) ;
# endif
/* char_modes[i * HX_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 */
memset ( char_modes , 0 , length * HX_NUM_MODES ) ;
2019-12-08 19:15:34 +03:00
2020-11-27 15:54:44 +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 ] */
memcpy ( prev_costs , head_costs , HX_NUM_MODES * sizeof ( unsigned int ) ) ;
2019-12-08 19:15:34 +03:00
2020-11-27 15:54:44 +03:00
/* Calculate costs using dynamic programming */
for ( i = 0 , cm_i = 0 ; i < length ; i + + , cm_i + = HX_NUM_MODES ) {
memset ( cur_costs , 0 , HX_NUM_MODES * sizeof ( unsigned int ) ) ;
if ( in_numeric ( gbdata , length , i , & numeric_end , & numeric_cost ) ) {
cur_costs [ HX_N ] = prev_costs [ HX_N ] + numeric_cost ;
char_modes [ cm_i + HX_N ] = ' n ' ;
2020-11-27 18:24:37 +03:00
text1 = 1 ;
text2 = 0 ;
} else {
text1 = lookup_text1 ( gbdata [ i ] ) ! = - 1 ;
text2 = lookup_text2 ( gbdata [ i ] ) ! = - 1 ;
2020-11-27 15:54:44 +03:00
}
if ( text1 | | text2 ) {
if ( ( text_submode = = 1 & & text2 ) | | ( text_submode = = 2 & & text1 ) ) {
cur_costs [ HX_T ] = prev_costs [ HX_T ] + 72 ; /* (6 + 6) * HX_MULT */
text_submode = text2 ? 2 : 1 ;
} else {
cur_costs [ HX_T ] = prev_costs [ HX_T ] + 36 ; /* 6 * HX_MULT */
}
char_modes [ cm_i + HX_T ] = ' t ' ;
2019-12-08 19:15:34 +03:00
} else {
2020-11-27 15:54:44 +03:00
text_submode = 1 ;
2019-12-08 19:15:34 +03:00
}
2020-11-27 15:54:44 +03:00
/* Binary mode can encode anything */
cur_costs [ HX_B ] = prev_costs [ HX_B ] + ( gbdata [ i ] > 0xFF ? 96 : 48 ) ; /* (16 : 8) * HX_MULT */
char_modes [ cm_i + HX_B ] = ' b ' ;
2019-12-08 19:15:34 +03:00
2020-11-27 15:54:44 +03:00
if ( in_fourbyte ( gbdata , length , i , & fourbyte_end , & fourbyte_cost ) ) {
cur_costs [ HX_F ] = prev_costs [ HX_F ] + fourbyte_cost ;
char_modes [ cm_i + HX_F ] = ' f ' ;
2020-11-27 18:24:37 +03:00
} else {
if ( isDoubleByte ( gbdata [ i ] ) ) {
cur_costs [ HX_D ] = prev_costs [ HX_D ] + 90 ; /* 15 * HX_MULT */
char_modes [ cm_i + HX_D ] = ' d ' ;
if ( isRegion1 ( gbdata [ i ] ) ) { /* Subset */
cur_costs [ HX_1 ] = prev_costs [ HX_1 ] + 72 ; /* 12 * HX_MULT */
char_modes [ cm_i + HX_1 ] = ' 1 ' ;
} else if ( isRegion2 ( gbdata [ i ] ) ) { /* Subset */
cur_costs [ HX_2 ] = prev_costs [ HX_2 ] + 72 ; /* 12 * HX_MULT */
char_modes [ cm_i + HX_2 ] = ' 2 ' ;
}
}
2020-11-27 15:54:44 +03:00
}
if ( i = = length - 1 ) { /* Add end of data costs if last character */
for ( j = 0 ; j < HX_NUM_MODES ; j + + ) {
if ( char_modes [ cm_i + j ] ) {
cur_costs [ j ] + = eod_costs [ j ] ;
}
}
}
/* Start new segment at the end to switch modes */
for ( j = 0 ; j < HX_NUM_MODES ; j + + ) { /* To mode */
for ( k = 0 ; k < HX_NUM_MODES ; k + + ) { /* From mode */
if ( j ! = k & & char_modes [ cm_i + k ] ) {
unsigned int new_cost = cur_costs [ k ] + switch_costs [ 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 , HX_NUM_MODES * sizeof ( unsigned int ) ) ;
2019-12-08 19:15:34 +03:00
}
2020-11-27 15:54:44 +03:00
/* Find optimal ending mode */
min_cost = prev_costs [ 0 ] ;
cur_mode = mode_types [ 0 ] ;
for ( i = 1 ; i < HX_NUM_MODES ; i + + ) {
if ( prev_costs [ i ] < min_cost ) {
min_cost = prev_costs [ i ] ;
cur_mode = mode_types [ i ] ;
}
2019-12-08 19:15:34 +03:00
}
2020-11-27 15:54:44 +03:00
/* Get optimal mode for each code point by tracing backwards */
for ( i = length - 1 , cm_i = i * HX_NUM_MODES ; i > = 0 ; i - - , cm_i - = HX_NUM_MODES ) {
j = strchr ( mode_types , cur_mode ) - mode_types ;
cur_mode = char_modes [ cm_i + j ] ;
mode [ i ] = cur_mode ;
}
2019-12-08 19:15:34 +03:00
2020-11-27 15:54:44 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
printf ( " Mode: %.*s \n " , length , mode ) ;
}
2019-12-08 19:15:34 +03:00
}
2016-04-08 00:30:37 +03:00
/* Convert input data to binary stream */
2020-11-27 15:54:44 +03:00
static void calculate_binary ( char binary [ ] , const char mode [ ] , unsigned int source [ ] , const int length , const int eci ,
int * bin_len , const int debug ) {
int position = 0 ;
2017-05-14 10:15:08 +03:00
int i , count , encoding_value ;
2016-05-02 00:10:50 +03:00
int first_byte , second_byte ;
int third_byte , fourth_byte ;
int glyph ;
2016-08-16 14:43:41 +03:00
int submode ;
2020-11-27 15:54:44 +03:00
int bp = 0 ;
2016-09-06 00:06:50 +03:00
2019-10-06 19:39:54 +03:00
if ( eci ! = 0 ) {
2017-06-18 15:00:22 +03:00
/* Encoding ECI assignment number, according to Table 5 */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 8 , 4 , binary , bp ) ; // ECI
2017-06-18 15:00:22 +03:00
if ( eci < = 127 ) {
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( eci , 8 , binary , bp ) ;
} else if ( eci < = 16383 ) {
bp = bin_append_posn ( 2 , 2 , binary , bp ) ;
bp = bin_append_posn ( eci , 14 , binary , bp ) ;
} else {
bp = bin_append_posn ( 6 , 3 , binary , bp ) ;
bp = bin_append_posn ( eci , 21 , binary , bp ) ;
2017-06-18 15:00:22 +03:00
}
2016-08-16 14:43:41 +03:00
}
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
do {
2017-09-10 18:03:09 +03:00
int block_length = 0 ;
2019-12-08 19:15:34 +03:00
int double_byte = 0 ;
2016-04-08 00:30:37 +03:00
do {
2019-12-08 19:15:34 +03:00
if ( mode [ position ] = = ' b ' & & source [ position + block_length ] > 0xFF ) {
double_byte + + ;
}
2016-04-08 00:30:37 +03:00
block_length + + ;
2019-12-08 19:15:34 +03:00
} while ( position + block_length < length & & mode [ position + block_length ] = = mode [ position ] ) ;
2016-09-06 00:06:50 +03:00
switch ( mode [ position ] ) {
2016-04-08 00:30:37 +03:00
case ' n ' :
/* Numeric mode */
/* Mode indicator */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 1 , 4 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2016-04-08 00:30:37 +03:00
printf ( " Numeric \n " ) ;
}
2016-09-06 00:06:50 +03:00
2019-11-27 19:16:14 +03:00
count = 0 ; /* Suppress gcc -Wmaybe-uninitialized */
2016-04-08 00:30:37 +03:00
i = 0 ;
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
while ( i < block_length ) {
2017-09-10 18:03:09 +03:00
int first = 0 ;
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
first = posn ( NEON , ( char ) source [ position + i ] ) ;
count = 1 ;
encoding_value = first ;
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
if ( i + 1 < block_length & & mode [ position + i + 1 ] = = ' n ' ) {
2017-09-10 18:03:09 +03:00
int second = posn ( NEON , ( char ) source [ position + i + 1 ] ) ;
2016-04-08 00:30:37 +03:00
count = 2 ;
encoding_value = ( encoding_value * 10 ) + second ;
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
if ( i + 2 < block_length & & mode [ position + i + 2 ] = = ' n ' ) {
2017-09-10 18:03:09 +03:00
int third = posn ( NEON , ( char ) source [ position + i + 2 ] ) ;
2016-04-08 00:30:37 +03:00
count = 3 ;
encoding_value = ( encoding_value * 10 ) + third ;
}
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( encoding_value , 10 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2020-11-27 15:54:44 +03:00
printf ( " 0x%3x (%d) " , encoding_value , encoding_value ) ;
2016-04-08 00:30:37 +03:00
}
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
i + = count ;
}
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
/* Mode terminator depends on number of characters in last group (Table 2) */
switch ( count ) {
case 1 :
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 1021 , 10 , binary , bp ) ;
2016-04-08 00:30:37 +03:00
break ;
case 2 :
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 1022 , 10 , binary , bp ) ;
2016-04-08 00:30:37 +03:00
break ;
case 3 :
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 1023 , 10 , binary , bp ) ;
2016-04-08 00:30:37 +03:00
break ;
}
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2016-04-08 00:30:37 +03:00
printf ( " (TERM %d) \n " , count ) ;
}
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
break ;
case ' t ' :
/* Text mode */
2019-12-08 19:15:34 +03:00
/* Mode indicator */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 2 , 4 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
printf ( " Text \n " ) ;
2016-04-08 00:30:37 +03:00
}
2016-09-06 00:06:50 +03:00
2016-07-04 13:08:08 +03:00
submode = 1 ;
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
i = 0 ;
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
while ( i < block_length ) {
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( getsubmode ( source [ i + position ] ) ! = submode ) {
2016-04-08 00:30:37 +03:00
/* Change submode */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 62 , 6 , binary , bp ) ;
2019-12-08 19:15:34 +03:00
submode = getsubmode ( source [ i + position ] ) ;
if ( debug & ZINT_DEBUG_PRINT ) {
2016-04-08 00:30:37 +03:00
printf ( " SWITCH " ) ;
}
}
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
if ( submode = = 1 ) {
2019-12-08 19:15:34 +03:00
encoding_value = lookup_text1 ( source [ i + position ] ) ;
2016-04-08 00:30:37 +03:00
} else {
2019-12-08 19:15:34 +03:00
encoding_value = lookup_text2 ( source [ i + position ] ) ;
2016-04-08 00:30:37 +03:00
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( encoding_value , 6 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2019-11-17 17:56:43 +03:00
printf ( " %.2x [ASC %.2x] " , encoding_value , source [ i + position ] ) ;
2016-04-08 00:30:37 +03:00
}
i + + ;
}
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
/* Terminator */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 63 , 6 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2016-04-08 00:30:37 +03:00
printf ( " \n " ) ;
}
break ;
case ' b ' :
/* Binary Mode */
/* Mode indicator */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 3 , 4 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
/* Count indicator */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( block_length + double_byte , 13 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
printf ( " Binary (length %d) \n " , block_length + double_byte ) ;
2016-04-08 00:30:37 +03:00
}
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
i = 0 ;
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
while ( i < block_length ) {
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
/* 8-bit bytes with no conversion */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( source [ i + position ] , source [ i + position ] > 0xFF ? 16 : 8 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2016-04-08 00:30:37 +03:00
printf ( " %d " , source [ i + position ] ) ;
}
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
i + + ;
}
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2016-04-08 00:30:37 +03:00
printf ( " \n " ) ;
}
break ;
2016-05-02 00:10:50 +03:00
case ' 1 ' :
/* Region 1 encoding */
/* Mode indicator */
2019-12-08 19:15:34 +03:00
if ( position = = 0 | | mode [ position - 1 ] ! = ' 2 ' ) { /* Unless previous mode Region 2 */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 4 , 4 , binary , bp ) ;
2019-12-08 19:15:34 +03:00
}
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2020-11-27 15:54:44 +03:00
printf ( " Region 1%s \n " , position = = 0 | | mode [ position - 1 ] ! = ' 2 ' ? " " : " (NO indicator) " ) ;
2016-05-02 00:10:50 +03:00
}
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
i = 0 ;
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
while ( i < block_length ) {
first_byte = ( source [ i + position ] & 0xff00 ) > > 8 ;
second_byte = source [ i + position ] & 0xff ;
/* Subset 1 */
glyph = ( 0x5e * ( first_byte - 0xb0 ) ) + ( second_byte - 0xa1 ) ;
/* Subset 2 */
if ( ( first_byte > = 0xa1 ) & & ( first_byte < = 0xa3 ) ) {
if ( ( second_byte > = 0xa1 ) & & ( second_byte < = 0xfe ) ) {
2019-11-17 17:56:43 +03:00
glyph = ( 0x5e * ( first_byte - 0xa1 ) ) + ( second_byte - 0xa1 ) + 0xeb0 ;
2016-05-02 00:10:50 +03:00
}
}
/* Subset 3 */
if ( ( source [ i + position ] > = 0xa8a1 ) & & ( source [ i + position ] < = 0xa8c0 ) ) {
glyph = ( second_byte - 0xa1 ) + 0xfca ;
}
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2020-11-27 15:54:44 +03:00
printf ( " %.3x [GB %.4x] " , glyph , source [ i + position ] ) ;
2016-05-02 00:10:50 +03:00
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( glyph , 12 , binary , bp ) ;
2016-05-02 00:10:50 +03:00
i + + ;
}
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
/* Terminator */
2021-06-19 15:11:23 +03:00
bp = bin_append_posn ( position + block_length = = length | | mode [ position + block_length ] ! = ' 2 '
? 4095 : 4094 , 12 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2021-06-19 15:11:23 +03:00
printf ( " (TERM %x) \n " , position + block_length = = length | | mode [ position + block_length ] ! = ' 2 '
? 4095 : 4094 ) ;
2016-05-02 00:10:50 +03:00
}
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
break ;
case ' 2 ' :
/* Region 2 encoding */
/* Mode indicator */
2019-12-08 19:15:34 +03:00
if ( position = = 0 | | mode [ position - 1 ] ! = ' 1 ' ) { /* Unless previous mode Region 1 */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 5 , 4 , binary , bp ) ;
2019-12-08 19:15:34 +03:00
}
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2020-11-27 15:54:44 +03:00
printf ( " Region 2%s \n " , position = = 0 | | mode [ position - 1 ] ! = ' 1 ' ? " " : " (NO indicator) " ) ;
2016-05-02 00:10:50 +03:00
}
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
i = 0 ;
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
while ( i < block_length ) {
first_byte = ( source [ i + position ] & 0xff00 ) > > 8 ;
second_byte = source [ i + position ] & 0xff ;
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
glyph = ( 0x5e * ( first_byte - 0xd8 ) ) + ( second_byte - 0xa1 ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2020-11-27 15:54:44 +03:00
printf ( " %.3x [GB %.4x] " , glyph , source [ i + position ] ) ;
2016-05-02 00:10:50 +03:00
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( glyph , 12 , binary , bp ) ;
2016-05-02 00:10:50 +03:00
i + + ;
}
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
/* Terminator */
2021-06-19 15:11:23 +03:00
bp = bin_append_posn ( position + block_length = = length | | mode [ position + block_length ] ! = ' 1 '
? 4095 : 4094 , 12 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2021-06-19 15:11:23 +03:00
printf ( " (TERM %x) \n " , position + block_length = = length | | mode [ position + block_length ] ! = ' 1 '
? 4095 : 4094 ) ;
2016-09-06 00:06:50 +03:00
}
2020-11-27 15:54:44 +03:00
2016-05-02 00:10:50 +03:00
break ;
case ' d ' :
/* Double byte encoding */
/* Mode indicator */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 6 , 4 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2016-05-02 00:10:50 +03:00
printf ( " Double byte \n " ) ;
}
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
i = 0 ;
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
while ( i < block_length ) {
first_byte = ( source [ i + position ] & 0xff00 ) > > 8 ;
second_byte = source [ i + position ] & 0xff ;
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
if ( second_byte < = 0x7e ) {
glyph = ( 0xbe * ( first_byte - 0x81 ) ) + ( second_byte - 0x40 ) ;
} else {
glyph = ( 0xbe * ( first_byte - 0x81 ) ) + ( second_byte - 0x41 ) ;
}
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2019-11-17 17:56:43 +03:00
printf ( " %.4x " , glyph ) ;
2016-05-02 00:10:50 +03:00
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( glyph , 15 , binary , bp ) ;
2016-05-02 00:10:50 +03:00
i + + ;
}
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
/* Terminator */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 32767 , 15 , binary , bp ) ;
2016-10-27 14:35:53 +03:00
/* Terminator sequence of length 12 is a mistake
- confirmed by Wang Yi */
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2016-05-02 00:10:50 +03:00
printf ( " \n " ) ;
2016-09-06 00:06:50 +03:00
}
2016-05-02 00:10:50 +03:00
break ;
case ' f ' :
/* Four-byte encoding */
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2016-05-02 00:10:50 +03:00
printf ( " Four byte \n " ) ;
}
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
i = 0 ;
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
while ( i < block_length ) {
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
/* Mode indicator */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 7 , 4 , binary , bp ) ;
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
first_byte = ( source [ i + position ] & 0xff00 ) > > 8 ;
second_byte = source [ i + position ] & 0xff ;
third_byte = ( source [ i + position + 1 ] & 0xff00 ) > > 8 ;
fourth_byte = source [ i + position + 1 ] & 0xff ;
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
glyph = ( 0x3138 * ( first_byte - 0x81 ) ) + ( 0x04ec * ( second_byte - 0x30 ) ) +
( 0x0a * ( third_byte - 0x81 ) ) + ( fourth_byte - 0x30 ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2016-05-02 00:10:50 +03:00
printf ( " %d " , glyph ) ;
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( glyph , 21 , binary , bp ) ;
2016-05-02 00:10:50 +03:00
i + = 2 ;
}
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
/* No terminator */
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
2016-05-02 00:10:50 +03:00
printf ( " \n " ) ;
}
break ;
2016-04-08 00:30:37 +03:00
}
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
position + = block_length ;
2016-09-06 00:06:50 +03:00
2016-04-08 00:30:37 +03:00
} while ( position < length ) ;
2020-11-27 15:54:44 +03:00
binary [ bp ] = ' \0 ' ;
if ( debug & ZINT_DEBUG_PRINT ) printf ( " Binary (%d): %s \n " , bp , binary ) ;
* bin_len = bp ;
2016-04-08 00:30:37 +03:00
}
2016-04-09 19:01:21 +03:00
/* Finder pattern for top left of symbol */
2020-11-27 15:54:44 +03:00
static void hx_place_finder_top_left ( unsigned char * grid , const int size ) {
2016-04-09 19:01:21 +03:00
int xp , yp ;
int x = 0 , y = 0 ;
2017-08-07 10:37:02 +03:00
char finder [ ] = { 0x7F , 0x40 , 0x5F , 0x50 , 0x57 , 0x57 , 0x57 } ;
2017-10-23 22:37:52 +03:00
2016-04-09 19:01:21 +03:00
for ( xp = 0 ; xp < 7 ; xp + + ) {
for ( yp = 0 ; yp < 7 ; yp + + ) {
2017-08-07 10:37:02 +03:00
if ( finder [ yp ] & 0x40 > > xp ) {
2016-04-09 19:01:21 +03:00
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x11 ;
} else {
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x10 ;
}
}
}
}
/* Finder pattern for top right and bottom left of symbol */
2020-11-27 15:54:44 +03:00
static void hx_place_finder ( unsigned char * grid , const int size , const int x , const int y ) {
2016-04-09 19:01:21 +03:00
int xp , yp ;
2017-08-07 10:37:02 +03:00
char finder [ ] = { 0x7F , 0x01 , 0x7D , 0x05 , 0x75 , 0x75 , 0x75 } ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
for ( xp = 0 ; xp < 7 ; xp + + ) {
for ( yp = 0 ; yp < 7 ; yp + + ) {
2017-08-07 10:37:02 +03:00
if ( finder [ yp ] & 0x40 > > xp ) {
2016-04-09 19:01:21 +03:00
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x11 ;
} else {
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x10 ;
}
}
}
}
/* Finder pattern for bottom right of symbol */
2020-11-27 15:54:44 +03:00
static void hx_place_finder_bottom_right ( unsigned char * grid , const int size ) {
2016-04-09 19:01:21 +03:00
int xp , yp ;
int x = size - 7 , y = size - 7 ;
2017-08-07 10:37:02 +03:00
char finder [ ] = { 0x75 , 0x75 , 0x75 , 0x05 , 0x7D , 0x01 , 0x7F } ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
for ( xp = 0 ; xp < 7 ; xp + + ) {
for ( yp = 0 ; yp < 7 ; yp + + ) {
2017-08-07 10:37:02 +03:00
if ( finder [ yp ] & 0x40 > > xp ) {
2016-04-09 19:01:21 +03:00
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x11 ;
} else {
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x10 ;
}
}
}
}
/* Avoid plotting outside symbol or over finder patterns */
2020-11-27 15:54:44 +03:00
static void hx_safe_plot ( unsigned char * grid , const int size , const int x , const int y , const int value ) {
2016-04-09 19:01:21 +03:00
if ( ( x > = 0 ) & & ( x < size ) ) {
if ( ( y > = 0 ) & & ( y < size ) ) {
if ( grid [ ( y * size ) + x ] = = 0 ) {
grid [ ( y * size ) + x ] = value ;
}
}
}
}
/* Plot an alignment pattern around top and right of a module */
2021-06-19 15:11:23 +03:00
static void hx_plot_alignment ( unsigned char * grid , const int size , const int x , const int y , const int w ,
const int h ) {
2016-04-09 19:01:21 +03:00
int i ;
hx_safe_plot ( grid , size , x , y , 0x11 ) ;
hx_safe_plot ( grid , size , x - 1 , y + 1 , 0x10 ) ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
for ( i = 1 ; i < = w ; i + + ) {
/* Top */
hx_safe_plot ( grid , size , x - i , y , 0x11 ) ;
hx_safe_plot ( grid , size , x - i - 1 , y + 1 , 0x10 ) ;
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
for ( i = 1 ; i < h ; i + + ) {
/* Right */
hx_safe_plot ( grid , size , x , y + i , 0x11 ) ;
hx_safe_plot ( grid , size , x - 1 , y + i + 1 , 0x10 ) ;
}
}
2016-04-10 22:36:57 +03:00
/* Plot assistant alignment patterns */
2020-11-27 15:54:44 +03:00
static void hx_plot_assistant ( unsigned char * grid , const int size , const int x , const int y ) {
2016-04-09 19:01:21 +03:00
hx_safe_plot ( grid , size , x - 1 , y - 1 , 0x10 ) ;
hx_safe_plot ( grid , size , x , y - 1 , 0x10 ) ;
hx_safe_plot ( grid , size , x + 1 , y - 1 , 0x10 ) ;
hx_safe_plot ( grid , size , x - 1 , y , 0x10 ) ;
hx_safe_plot ( grid , size , x , y , 0x11 ) ;
hx_safe_plot ( grid , size , x + 1 , y , 0x10 ) ;
hx_safe_plot ( grid , size , x - 1 , y + 1 , 0x10 ) ;
hx_safe_plot ( grid , size , x , y + 1 , 0x10 ) ;
2016-09-06 00:06:50 +03:00
hx_safe_plot ( grid , size , x + 1 , y + 1 , 0x10 ) ;
2016-04-09 19:01:21 +03:00
}
/* Put static elements in the grid */
2020-11-27 15:54:44 +03:00
static void hx_setup_grid ( unsigned char * grid , const int size , const int version ) {
int i ;
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
memset ( grid , 0 , ( size_t ) size * size ) ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
/* Add finder patterns */
hx_place_finder_top_left ( grid , size ) ;
hx_place_finder ( grid , size , 0 , size - 7 ) ;
hx_place_finder ( grid , size , size - 7 , 0 ) ;
hx_place_finder_bottom_right ( grid , size ) ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
/* Add finder pattern separator region */
for ( i = 0 ; i < 8 ; i + + ) {
/* Top left */
grid [ ( 7 * size ) + i ] = 0x10 ;
grid [ ( i * size ) + 7 ] = 0x10 ;
2016-09-06 00:06:50 +03:00
/* Top right */
grid [ ( 7 * size ) + ( size - i - 1 ) ] = 0x10 ;
2016-04-09 19:01:21 +03:00
grid [ ( ( size - i - 1 ) * size ) + 7 ] = 0x10 ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
/* Bottom left */
grid [ ( i * size ) + ( size - 8 ) ] = 0x10 ;
grid [ ( ( size - 8 ) * size ) + i ] = 0x10 ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
/* Bottom right */
grid [ ( ( size - 8 ) * size ) + ( size - i - 1 ) ] = 0x10 ;
grid [ ( ( size - i - 1 ) * size ) + ( size - 8 ) ] = 0x10 ;
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
/* Reserve function information region */
for ( i = 0 ; i < 9 ; i + + ) {
/* Top left */
grid [ ( 8 * size ) + i ] = 0x10 ;
grid [ ( i * size ) + 8 ] = 0x10 ;
2016-09-06 00:06:50 +03:00
/* Top right */
grid [ ( 8 * size ) + ( size - i - 1 ) ] = 0x10 ;
2016-04-09 19:01:21 +03:00
grid [ ( ( size - i - 1 ) * size ) + 8 ] = 0x10 ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
/* Bottom left */
grid [ ( i * size ) + ( size - 9 ) ] = 0x10 ;
grid [ ( ( size - 9 ) * size ) + i ] = 0x10 ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
/* Bottom right */
grid [ ( ( size - 9 ) * size ) + ( size - i - 1 ) ] = 0x10 ;
grid [ ( ( size - i - 1 ) * size ) + ( size - 9 ) ] = 0x10 ;
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
if ( version > 3 ) {
int k = hx_module_k [ version - 1 ] ;
int r = hx_module_r [ version - 1 ] ;
int m = hx_module_m [ version - 1 ] ;
int x , y , row_switch , column_switch ;
int module_height , module_width ;
int mod_x , mod_y ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
/* Add assistant alignment patterns to left and right */
y = 0 ;
mod_y = 0 ;
do {
if ( mod_y < m ) {
module_height = k ;
} else {
module_height = r - 1 ;
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
if ( ( mod_y & 1 ) = = 0 ) {
if ( ( m & 1 ) = = 1 ) {
2016-04-09 19:01:21 +03:00
hx_plot_assistant ( grid , size , 0 , y ) ;
}
} else {
2020-11-27 15:54:44 +03:00
if ( ( m & 1 ) = = 0 ) {
2016-04-09 19:01:21 +03:00
hx_plot_assistant ( grid , size , 0 , y ) ;
}
hx_plot_assistant ( grid , size , size - 1 , y ) ;
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
mod_y + + ;
y + = module_height ;
} while ( y < size ) ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
/* Add assistant alignment patterns to top and bottom */
x = ( size - 1 ) ;
mod_x = 0 ;
do {
if ( mod_x < m ) {
module_width = k ;
} else {
module_width = r - 1 ;
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
if ( ( mod_x & 1 ) = = 0 ) {
if ( ( m & 1 ) = = 1 ) {
2016-04-09 19:01:21 +03:00
hx_plot_assistant ( grid , size , x , ( size - 1 ) ) ;
}
} else {
2020-11-27 15:54:44 +03:00
if ( ( m & 1 ) = = 0 ) {
2016-04-09 19:01:21 +03:00
hx_plot_assistant ( grid , size , x , ( size - 1 ) ) ;
}
hx_plot_assistant ( grid , size , x , 0 ) ;
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
mod_x + + ;
x - = module_width ;
} while ( x > = 0 ) ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
/* Add alignment pattern */
column_switch = 1 ;
y = 0 ;
2016-09-06 00:06:50 +03:00
mod_y = 0 ;
2016-04-09 19:01:21 +03:00
do {
if ( mod_y < m ) {
module_height = k ;
} else {
module_height = r - 1 ;
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
if ( column_switch = = 1 ) {
row_switch = 1 ;
column_switch = 0 ;
} else {
row_switch = 0 ;
column_switch = 1 ;
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
x = ( size - 1 ) ;
mod_x = 0 ;
do {
if ( mod_x < m ) {
module_width = k ;
} else {
module_width = r - 1 ;
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
if ( row_switch = = 1 ) {
if ( ! ( y = = 0 & & x = = ( size - 1 ) ) ) {
hx_plot_alignment ( grid , size , x , y , module_width , module_height ) ;
}
row_switch = 0 ;
} else {
row_switch = 1 ;
}
mod_x + + ;
x - = module_width ;
} while ( x > = 0 ) ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
mod_y + + ;
y + = module_height ;
} while ( y < size ) ;
}
}
2016-04-16 14:57:45 +03:00
/* Calculate error correction codes */
2020-11-27 15:54:44 +03:00
static void hx_add_ecc ( unsigned char fullstream [ ] , const unsigned char datastream [ ] , const int data_codewords ,
const int version , const int ecc_level ) {
2016-04-16 14:57:45 +03:00
unsigned char data_block [ 180 ] ;
unsigned char ecc_block [ 36 ] ;
int i , j , block ;
int input_position = - 1 ;
int output_position = - 1 ;
2017-04-10 10:06:53 +03:00
int table_d1_pos = ( ( version - 1 ) * 36 ) + ( ( ecc_level - 1 ) * 9 ) ;
2020-11-27 15:54:44 +03:00
rs_t rs ;
rs_init_gf ( & rs , 0x163 ) ; // x^8 + x^6 + x^5 + x + 1 = 0
2016-09-06 00:06:50 +03:00
2016-04-16 14:57:45 +03:00
for ( i = 0 ; i < 3 ; i + + ) {
2017-09-10 18:03:09 +03:00
int batch_size = hx_table_d1 [ table_d1_pos + ( 3 * i ) ] ;
int data_length = hx_table_d1 [ table_d1_pos + ( 3 * i ) + 1 ] ;
int ecc_length = hx_table_d1 [ table_d1_pos + ( 3 * i ) + 2 ] ;
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
rs_init_code ( & rs , ecc_length , 1 ) ;
2016-09-06 00:06:50 +03:00
for ( block = 0 ; block < batch_size ; block + + ) {
2016-04-16 14:57:45 +03:00
for ( j = 0 ; j < data_length ; j + + ) {
input_position + + ;
output_position + + ;
2019-12-08 19:15:34 +03:00
data_block [ j ] = input_position < data_codewords ? datastream [ input_position ] : 0 ;
fullstream [ output_position ] = data_block [ j ] ;
2016-04-16 14:57:45 +03:00
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
rs_encode ( & rs , data_length , data_block , ecc_block ) ;
2016-09-06 00:06:50 +03:00
2016-04-16 14:57:45 +03:00
for ( j = 0 ; j < ecc_length ; j + + ) {
output_position + + ;
fullstream [ output_position ] = ecc_block [ ecc_length - j - 1 ] ;
}
}
}
}
2020-11-27 15:54:44 +03:00
static void hx_set_function_info ( unsigned char * grid , const int size , const int version , const int ecc_level ,
const int bitmask , const int debug ) {
int i , j ;
char function_information [ 34 ] ;
unsigned char fi_cw [ 3 ] = { 0 } ;
unsigned char fi_ecc [ 4 ] ;
int bp = 0 ;
rs_t rs ;
/* Form function information string */
bp = bin_append_posn ( version + 20 , 8 , function_information , bp ) ;
bp = bin_append_posn ( ecc_level - 1 , 2 , function_information , bp ) ;
bp = bin_append_posn ( bitmask , 2 , function_information , bp ) ;
for ( i = 0 ; i < 3 ; i + + ) {
for ( j = 0 ; j < 4 ; j + + ) {
if ( function_information [ ( i * 4 ) + j ] = = ' 1 ' ) {
fi_cw [ i ] + = ( 0x08 > > j ) ;
}
}
}
rs_init_gf ( & rs , 0x13 ) ;
rs_init_code ( & rs , 4 , 1 ) ;
rs_encode ( & rs , 3 , fi_cw , fi_ecc ) ;
for ( i = 3 ; i > = 0 ; i - - ) {
bp = bin_append_posn ( fi_ecc [ i ] , 4 , function_information , bp ) ;
}
/* This alternating filler pattern at end not mentioned in ISO/IEC 20830 (draft 2019-10-10) and does not appear
* in Figure 1 or the figures in Annex K but does appear in Figure 2 and Figures 4 - 9 */
for ( i = 28 ; i < 34 ; i + + ) {
if ( i & 1 ) {
function_information [ i ] = ' 1 ' ;
} else {
function_information [ i ] = ' 0 ' ;
}
}
if ( debug & ZINT_DEBUG_PRINT ) {
2021-06-19 15:11:23 +03:00
printf ( " Version: %d, ECC: %d, Mask: %d, Structural Info: %.34s \n " , version , ecc_level , bitmask ,
function_information ) ;
2020-11-27 15:54:44 +03:00
}
/* Add function information to symbol */
for ( i = 0 ; i < 9 ; i + + ) {
if ( function_information [ i ] = = ' 1 ' ) {
grid [ ( 8 * size ) + i ] = 0x01 ;
grid [ ( ( size - 8 - 1 ) * size ) + ( size - i - 1 ) ] = 0x01 ;
}
if ( function_information [ i + 8 ] = = ' 1 ' ) {
grid [ ( ( 8 - i ) * size ) + 8 ] = 0x01 ;
grid [ ( ( size - 8 - 1 + i ) * size ) + ( size - 8 - 1 ) ] = 0x01 ;
}
if ( function_information [ i + 17 ] = = ' 1 ' ) {
grid [ ( i * size ) + ( size - 1 - 8 ) ] = 0x01 ;
grid [ ( ( size - 1 - i ) * size ) + 8 ] = 0x01 ;
}
if ( function_information [ i + 25 ] = = ' 1 ' ) {
grid [ ( 8 * size ) + ( size - 1 - 8 + i ) ] = 0x01 ;
grid [ ( ( size - 1 - 8 ) * size ) + ( 8 - i ) ] = 0x01 ;
}
}
}
2016-04-16 14:57:45 +03:00
/* Rearrange data in batches of 13 codewords (section 5.8.2) */
2020-11-27 15:54:44 +03:00
static void make_picket_fence ( const unsigned char fullstream [ ] , unsigned char picket_fence [ ] , const int streamsize ) {
2016-04-16 14:57:45 +03:00
int i , start ;
int output_position = 0 ;
2017-10-23 22:37:52 +03:00
2016-04-16 14:57:45 +03:00
for ( start = 0 ; start < 13 ; start + + ) {
for ( i = start ; i < streamsize ; i + = 13 ) {
if ( i < streamsize ) {
picket_fence [ output_position ] = fullstream [ i ] ;
output_position + + ;
}
}
}
}
2016-04-20 22:44:59 +03:00
/* Evaluate a bitmask according to table 9 */
2020-11-27 15:54:44 +03:00
static int hx_evaluate ( const unsigned char * local , const int size ) {
static const unsigned char h1010111 [ 7 ] = { 1 , 0 , 1 , 0 , 1 , 1 , 1 } ;
static const unsigned char h1110101 [ 7 ] = { 1 , 1 , 1 , 0 , 1 , 0 , 1 } ;
int x , y , r , block ;
2016-04-20 22:44:59 +03:00
int result = 0 ;
2020-11-27 15:54:44 +03:00
int state ;
2016-04-20 22:44:59 +03:00
int a , b , afterCount , beforeCount ;
2020-11-27 15:54:44 +03:00
/* Test 1: 1:1:1:1:3 or 3:1:1:1:1 ratio pattern in row/column */
2016-04-20 22:44:59 +03:00
/* Vertical */
for ( x = 0 ; x < size ; x + + ) {
2020-11-27 15:54:44 +03:00
for ( y = 0 ; y < = ( size - 7 ) ; y + + ) {
if ( local [ y * size + x ] & & local [ ( y + 1 ) * size + x ] ! = local [ ( y + 5 ) * size + x ] & &
local [ ( y + 2 ) * size + x ] & & ! local [ ( y + 3 ) * size + x ] & &
local [ ( y + 4 ) * size + x ] & & local [ ( y + 6 ) * size + x ] ) {
2016-04-20 22:44:59 +03:00
/* Pattern found, check before and after */
beforeCount = 0 ;
2020-11-27 15:54:44 +03:00
for ( b = ( y - 1 ) ; b > = ( y - 3 ) ; b - - ) {
if ( b < 0 ) { /* Count < edge as whitespace */
beforeCount = 3 ;
break ;
}
if ( local [ ( b * size ) + x ] ) {
break ;
2016-04-20 22:44:59 +03:00
}
2020-11-27 15:54:44 +03:00
beforeCount + + ;
2016-04-20 22:44:59 +03:00
}
2020-11-27 15:54:44 +03:00
if ( beforeCount = = 3 ) {
/* Pattern is preceded by light area 3 modules wide */
result + = 50 ;
} else {
afterCount = 0 ;
for ( a = ( y + 7 ) ; a < = ( y + 9 ) ; a + + ) {
if ( a > = size ) { /* Count > edge as whitespace */
afterCount = 3 ;
break ;
}
if ( local [ ( a * size ) + x ] ) {
2019-12-08 19:15:34 +03:00
break ;
2016-04-20 22:44:59 +03:00
}
2020-11-27 15:54:44 +03:00
afterCount + + ;
}
if ( afterCount = = 3 ) {
/* Pattern is followed by light area 3 modules wide */
result + = 50 ;
2016-04-20 22:44:59 +03:00
}
}
2020-11-27 15:54:44 +03:00
y + + ; /* Skip to next possible match */
2016-04-20 22:44:59 +03:00
}
}
}
/* Horizontal */
for ( y = 0 ; y < size ; y + + ) {
2020-11-27 15:54:44 +03:00
r = y * size ;
for ( x = 0 ; x < = ( size - 7 ) ; x + + ) {
if ( memcmp ( local + r + x , h1010111 , 7 ) = = 0 | | memcmp ( local + r + x , h1110101 , 7 ) = = 0 ) {
2016-04-20 22:44:59 +03:00
/* Pattern found, check before and after */
beforeCount = 0 ;
2020-11-27 15:54:44 +03:00
for ( b = ( x - 1 ) ; b > = ( x - 3 ) ; b - - ) {
if ( b < 0 ) { /* Count < edge as whitespace */
beforeCount = 3 ;
break ;
}
if ( local [ r + b ] ) {
break ;
2016-04-20 22:44:59 +03:00
}
2020-11-27 15:54:44 +03:00
beforeCount + + ;
2016-04-20 22:44:59 +03:00
}
2020-11-27 15:54:44 +03:00
if ( beforeCount = = 3 ) {
/* Pattern is preceded by light area 3 modules wide */
result + = 50 ;
} else {
afterCount = 0 ;
for ( a = ( x + 7 ) ; a < = ( x + 9 ) ; a + + ) {
if ( a > = size ) { /* Count > edge as whitespace */
afterCount = 3 ;
2019-12-08 19:15:34 +03:00
break ;
2016-04-20 22:44:59 +03:00
}
2020-11-27 15:54:44 +03:00
if ( local [ r + a ] ) {
break ;
}
afterCount + + ;
}
if ( afterCount = = 3 ) {
/* Pattern is followed by light area 3 modules wide */
result + = 50 ;
2016-04-20 22:44:59 +03:00
}
}
2020-11-27 15:54:44 +03:00
x + + ; /* Skip to next possible match */
2016-04-20 22:44:59 +03:00
}
}
}
2016-09-06 00:06:50 +03:00
2016-04-20 22:44:59 +03:00
/* Test 2: Adjacent modules in row/column in same colour */
2016-06-19 11:07:50 +03:00
/* In AIMD-15 section 5.8.3.2 it is stated... “In Table 9 below, i refers to the row
* position of the module . ” - however i being the length of the run of the
* same colour ( i . e . " block " below ) in the same fashion as ISO / IEC 18004
2016-10-27 14:35:53 +03:00
* makes more sense . - - Confirmed by Wang Yi */
2021-06-19 15:11:23 +03:00
/* Fixed in ISO/IEC 20830 (draft 2019-10-10) section 5.8.3.2 "In Table 12 below, i refers to the modules with
same color . " */
2016-09-06 00:06:50 +03:00
2016-04-20 22:44:59 +03:00
/* Vertical */
for ( x = 0 ; x < size ; x + + ) {
block = 0 ;
2019-12-08 19:15:34 +03:00
state = 0 ;
2016-04-20 22:44:59 +03:00
for ( y = 0 ; y < size ; y + + ) {
2020-11-27 15:54:44 +03:00
if ( local [ ( y * size ) + x ] = = state ) {
2016-04-20 22:44:59 +03:00
block + + ;
} else {
2019-12-08 19:15:34 +03:00
if ( block > = 3 ) {
2020-11-27 15:54:44 +03:00
result + = block * 4 ;
2016-04-20 22:44:59 +03:00
}
2019-12-08 19:15:34 +03:00
block = 1 ;
2016-04-20 22:44:59 +03:00
state = local [ ( y * size ) + x ] ;
}
}
2019-12-08 19:15:34 +03:00
if ( block > = 3 ) {
2020-11-27 15:54:44 +03:00
result + = block * 4 ;
2016-04-20 22:44:59 +03:00
}
}
/* Horizontal */
for ( y = 0 ; y < size ; y + + ) {
2020-11-27 15:54:44 +03:00
r = y * size ;
2016-04-20 22:44:59 +03:00
block = 0 ;
2020-11-27 15:54:44 +03:00
state = 0 ;
2016-04-20 22:44:59 +03:00
for ( x = 0 ; x < size ; x + + ) {
2020-11-27 15:54:44 +03:00
if ( local [ r + x ] = = state ) {
2016-04-20 22:44:59 +03:00
block + + ;
} else {
2019-12-08 19:15:34 +03:00
if ( block > = 3 ) {
2020-11-27 15:54:44 +03:00
result + = block * 4 ;
2016-04-20 22:44:59 +03:00
}
2019-12-08 19:15:34 +03:00
block = 1 ;
2020-11-27 15:54:44 +03:00
state = local [ r + x ] ;
2016-04-20 22:44:59 +03:00
}
}
2019-12-08 19:15:34 +03:00
if ( block > = 3 ) {
2020-11-27 15:54:44 +03:00
result + = block * 4 ;
2016-04-20 22:44:59 +03:00
}
}
return result ;
}
/* Apply the four possible bitmasks for evaluation */
2020-11-27 15:54:44 +03:00
/* TODO: Haven't been able to replicate (or even get close to) the penalty scores in ISO/IEC 20830
* ( draft 2019 - 10 - 10 ) Annex K examples ; however they don ' t use alternating filler pattern on structural info */
static void hx_apply_bitmask ( unsigned char * grid , const int size , const int version , const int ecc_level ,
const int user_mask , const int debug ) {
2016-04-20 22:44:59 +03:00
int x , y ;
2020-11-27 15:54:44 +03:00
int i , j , r , k ;
int pattern , penalty [ 4 ] = { 0 } ;
int best_pattern ;
2016-04-20 22:44:59 +03:00
int bit ;
2020-11-27 15:54:44 +03:00
int size_squared = size * size ;
2016-09-06 00:06:50 +03:00
2016-04-20 22:44:59 +03:00
# ifndef _MSC_VER
2020-11-27 15:54:44 +03:00
unsigned char mask [ size_squared ] ;
unsigned char local [ size_squared ] ;
2016-04-20 22:44:59 +03:00
# else
2021-06-19 15:11:23 +03:00
unsigned char * mask = ( unsigned char * ) _alloca ( size_squared ) ;
unsigned char * local = ( unsigned char * ) _alloca ( size_squared ) ;
2016-04-20 22:44:59 +03:00
# endif
2016-09-06 00:06:50 +03:00
2016-04-20 22:44:59 +03:00
/* Perform data masking */
2020-11-27 15:54:44 +03:00
memset ( mask , 0 , size_squared ) ;
for ( y = 0 ; y < size ; y + + ) {
r = y * size ;
for ( x = 0 ; x < size ; x + + ) {
k = r + x ;
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
if ( ! ( grid [ k ] & 0xf0 ) ) {
j = x + 1 ;
i = y + 1 ;
if ( ( ( i + j ) & 1 ) = = 0 ) {
mask [ k ] | = 0x02 ;
2016-04-20 22:44:59 +03:00
}
2020-11-27 15:54:44 +03:00
if ( ( ( ( ( i + j ) % 3 ) + ( j % 3 ) ) & 1 ) = = 0 ) {
mask [ k ] | = 0x04 ;
2016-04-20 22:44:59 +03:00
}
2020-11-27 15:54:44 +03:00
if ( ( ( ( i % j ) + ( j % i ) + ( i % 3 ) + ( j % 3 ) ) & 1 ) = = 0 ) {
mask [ k ] | = 0x08 ;
2016-04-20 22:44:59 +03:00
}
}
}
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
if ( user_mask ) {
best_pattern = user_mask - 1 ;
} else {
// apply data masks to grid, result in local
2016-04-20 22:44:59 +03:00
2020-11-27 15:54:44 +03:00
/* Do null pattern 00 separately first */
pattern = 0 ;
for ( k = 0 ; k < size_squared ; k + + ) {
local [ k ] = grid [ k ] & 0x0f ;
2016-04-20 22:44:59 +03:00
}
2020-11-27 15:54:44 +03:00
/* Set the Structural Info */
hx_set_function_info ( local , size , version , ecc_level , pattern , 0 /*debug*/ ) ;
/* Evaluate result */
penalty [ pattern ] = hx_evaluate ( local , size ) ;
best_pattern = 0 ;
for ( pattern = 1 ; pattern < 4 ; pattern + + ) {
bit = 1 < < pattern ;
for ( k = 0 ; k < size_squared ; k + + ) {
if ( mask [ k ] & bit ) {
local [ k ] = grid [ k ] ^ 0x01 ;
} else {
local [ k ] = grid [ k ] & 0x0f ;
}
}
/* Set the Structural Info */
hx_set_function_info ( local , size , version , ecc_level , pattern , 0 /*debug*/ ) ;
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
/* Evaluate result */
penalty [ pattern ] = hx_evaluate ( local , size ) ;
if ( penalty [ pattern ] < penalty [ best_pattern ] ) {
best_pattern = pattern ;
}
}
2016-04-20 22:44:59 +03:00
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
if ( debug & ZINT_DEBUG_PRINT ) {
printf ( " Mask: %d (%s) " , best_pattern , user_mask ? " specified " : " automatic " ) ;
if ( ! user_mask ) {
for ( pattern = 0 ; pattern < 4 ; pattern + + ) printf ( " %d:%d " , pattern , penalty [ pattern ] ) ;
2016-04-20 22:44:59 +03:00
}
2020-11-27 15:54:44 +03:00
printf ( " \n " ) ;
2016-04-20 22:44:59 +03:00
}
2016-09-06 00:06:50 +03:00
2016-04-20 22:44:59 +03:00
/* Apply mask */
2020-11-27 15:54:44 +03:00
if ( best_pattern ) { /* If not null mask */
if ( ! user_mask & & best_pattern = = 3 ) { /* Reuse last */
memcpy ( grid , local , size_squared ) ;
} else {
bit = 1 < < best_pattern ;
for ( k = 0 ; k < size_squared ; k + + ) {
if ( mask [ k ] & bit ) {
grid [ k ] ^ = 0x01 ;
2016-04-20 22:44:59 +03:00
}
}
}
}
2020-11-27 15:54:44 +03:00
/* Set the Structural Info */
hx_set_function_info ( grid , size , version , ecc_level , best_pattern , debug ) ;
2016-04-20 22:44:59 +03:00
}
2016-04-08 00:30:37 +03:00
/* Han Xin Code - main */
2020-11-27 15:54:44 +03:00
INTERNAL int han_xin ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) {
2016-04-08 00:30:37 +03:00
int est_binlen ;
2016-04-30 12:25:16 +03:00
int ecc_level = symbol - > option_1 ;
2020-11-27 15:54:44 +03:00
int i , j , j_max , version ;
2020-04-02 16:41:13 +03:00
int full_multibyte ;
2020-11-27 15:54:44 +03:00
int user_mask ;
2016-09-04 18:35:11 +03:00
int data_codewords = 0 , size ;
2020-11-27 15:54:44 +03:00
int size_squared ;
2017-04-10 10:06:53 +03:00
int codewords ;
int bin_len ;
2021-01-11 21:11:41 +03:00
int eci_length = get_eci_length ( symbol - > eci , source , length ) ;
2016-09-06 00:06:50 +03:00
2016-05-02 00:10:50 +03:00
# ifndef _MSC_VER
2021-01-11 21:11:41 +03:00
unsigned int gbdata [ eci_length + 1 ] ;
char mode [ eci_length ] ;
2016-05-02 00:10:50 +03:00
# else
2021-01-11 21:11:41 +03:00
unsigned int * gbdata = ( unsigned int * ) _alloca ( ( eci_length + 1 ) * sizeof ( unsigned int ) ) ;
char * mode = ( char * ) _alloca ( eci_length ) ;
char * binary ;
2016-09-06 00:06:50 +03:00
unsigned char * datastream ;
2016-08-16 14:43:41 +03:00
unsigned char * fullstream ;
unsigned char * picket_fence ;
unsigned char * grid ;
2016-05-02 00:10:50 +03:00
# endif
2016-09-06 00:06:50 +03:00
2021-01-11 21:11:41 +03:00
/* If ZINT_FULL_MULTIBYTE set use Hanzi mode in DATA_MODE or for non-GB 18030 in UNICODE_MODE */
2020-11-27 15:54:44 +03:00
full_multibyte = ( symbol - > option_3 & 0xFF ) = = ZINT_FULL_MULTIBYTE ;
user_mask = ( symbol - > option_3 > > 8 ) & 0x0F ; /* User mask is pattern + 1, so >= 1 and <= 4 */
if ( user_mask > 4 ) {
user_mask = 0 ; /* Ignore */
}
2020-04-02 16:41:13 +03:00
2019-12-08 19:15:34 +03:00
if ( ( symbol - > input_mode & 0x07 ) = = DATA_MODE ) {
2020-04-02 16:41:13 +03:00
gb18030_cpy ( source , & length , gbdata , full_multibyte ) ;
2016-08-16 14:43:41 +03:00
} else {
2019-12-08 19:15:34 +03:00
int done = 0 ;
if ( symbol - > eci ! = 29 ) { /* Unless ECI 29 (GB) */
2021-01-11 21:11:41 +03:00
/* Try other conversions (ECI 0 defaults to ISO/IEC 8859-1) */
int error_number = gb18030_utf8_to_eci ( symbol - > eci , source , & length , gbdata , full_multibyte ) ;
2019-12-08 19:15:34 +03:00
if ( error_number = = 0 ) {
2017-04-23 22:15:50 +03:00
done = 1 ;
2021-01-11 21:11:41 +03:00
} else if ( symbol - > eci ) {
2021-07-06 21:53:31 +03:00
sprintf ( symbol - > errtxt , " 545: Invalid character in input data for ECI %d " , symbol - > eci ) ;
2019-12-08 19:15:34 +03:00
return error_number ;
2017-04-23 22:15:50 +03:00
}
2019-12-08 19:15:34 +03:00
}
if ( ! done ) {
/* Try GB 18030 */
2021-01-11 21:11:41 +03:00
int error_number = gb18030_utf8 ( symbol , source , & length , gbdata ) ;
2019-12-08 19:15:34 +03:00
if ( error_number ! = 0 ) {
return error_number ;
2017-04-23 22:15:50 +03:00
}
2016-08-16 14:43:41 +03:00
}
2016-05-02 00:10:50 +03:00
}
2016-04-08 00:30:37 +03:00
2019-12-08 19:15:34 +03:00
hx_define_mode ( mode , gbdata , length , symbol - > debug ) ;
2016-09-06 00:06:50 +03:00
2016-08-16 14:43:41 +03:00
est_binlen = calculate_binlength ( mode , gbdata , length , symbol - > eci ) ;
2016-09-06 00:06:50 +03:00
2016-08-16 14:43:41 +03:00
# ifndef _MSC_VER
2019-12-08 19:15:34 +03:00
char binary [ est_binlen + 1 ] ;
2016-08-16 14:43:41 +03:00
# else
2021-01-11 21:11:41 +03:00
binary = ( char * ) _alloca ( ( est_binlen + 1 ) ) ;
2016-08-16 14:43:41 +03:00
# endif
2016-09-06 00:06:50 +03:00
2016-04-30 12:25:16 +03:00
if ( ( ecc_level < = 0 ) | | ( ecc_level > = 5 ) ) {
ecc_level = 1 ;
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
calculate_binary ( binary , mode , gbdata , length , symbol - > eci , & bin_len , symbol - > debug ) ;
codewords = bin_len > > 3 ;
if ( bin_len & 0x07 ) {
2017-04-10 10:06:53 +03:00
codewords + + ;
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
version = 85 ;
for ( i = 84 ; i > 0 ; i - - ) {
switch ( ecc_level ) {
case 1 :
2017-04-10 10:06:53 +03:00
if ( hx_data_codewords_L1 [ i - 1 ] > codewords ) {
2016-04-09 19:01:21 +03:00
version = i ;
2016-04-10 22:36:57 +03:00
data_codewords = hx_data_codewords_L1 [ i - 1 ] ;
2016-04-09 19:01:21 +03:00
}
break ;
case 2 :
2017-04-10 10:06:53 +03:00
if ( hx_data_codewords_L2 [ i - 1 ] > codewords ) {
2016-04-09 19:01:21 +03:00
version = i ;
2016-04-10 22:36:57 +03:00
data_codewords = hx_data_codewords_L2 [ i - 1 ] ;
2016-04-09 19:01:21 +03:00
}
break ;
case 3 :
2017-04-10 10:06:53 +03:00
if ( hx_data_codewords_L3 [ i - 1 ] > codewords ) {
2016-04-09 19:01:21 +03:00
version = i ;
2016-04-10 22:36:57 +03:00
data_codewords = hx_data_codewords_L3 [ i - 1 ] ;
2016-04-09 19:01:21 +03:00
}
break ;
case 4 :
2017-04-10 10:06:53 +03:00
if ( hx_data_codewords_L4 [ i - 1 ] > codewords ) {
2016-04-09 19:01:21 +03:00
version = i ;
2016-04-10 22:36:57 +03:00
data_codewords = hx_data_codewords_L4 [ i - 1 ] ;
2016-04-09 19:01:21 +03:00
}
break ;
2016-09-06 00:06:50 +03:00
default :
assert ( 0 ) ;
break ;
2016-04-09 19:01:21 +03:00
}
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
if ( version = = 85 ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 541: Input too long for selected error correction level " ) ;
2016-04-09 19:01:21 +03:00
return ZINT_ERROR_TOO_LONG ;
}
2016-09-06 00:06:50 +03:00
2016-04-30 12:25:16 +03:00
if ( ( symbol - > option_2 < 0 ) | | ( symbol - > option_2 > 84 ) ) {
symbol - > option_2 = 0 ;
}
2016-09-06 00:06:50 +03:00
2016-04-30 12:25:16 +03:00
if ( symbol - > option_2 > version ) {
version = symbol - > option_2 ;
}
2017-10-23 22:37:52 +03:00
2017-04-11 11:26:39 +03:00
if ( ( symbol - > option_2 ! = 0 ) & & ( symbol - > option_2 < version ) ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 542: Input too long for selected symbol size " ) ;
2017-04-11 11:26:39 +03:00
return ZINT_ERROR_TOO_LONG ;
}
2016-09-06 00:06:50 +03:00
2016-04-30 12:25:16 +03:00
/* If there is spare capacity, increase the level of ECC */
2016-09-06 00:06:50 +03:00
2021-06-19 15:11:23 +03:00
/* Unless explicitly specified (within min/max bounds) by user */
if ( symbol - > option_1 = = - 1 | | symbol - > option_1 ! = ecc_level ) {
2019-12-08 19:15:34 +03:00
if ( ( ecc_level = = 1 ) & & ( codewords < hx_data_codewords_L2 [ version - 1 ] ) ) {
ecc_level = 2 ;
data_codewords = hx_data_codewords_L2 [ version - 1 ] ;
}
2016-08-22 20:07:27 +03:00
2019-12-08 19:15:34 +03:00
if ( ( ecc_level = = 2 ) & & ( codewords < hx_data_codewords_L3 [ version - 1 ] ) ) {
ecc_level = 3 ;
data_codewords = hx_data_codewords_L3 [ version - 1 ] ;
}
2016-08-22 20:07:27 +03:00
2019-12-08 19:15:34 +03:00
if ( ( ecc_level = = 3 ) & & ( codewords < hx_data_codewords_L4 [ version - 1 ] ) ) {
ecc_level = 4 ;
data_codewords = hx_data_codewords_L4 [ version - 1 ] ;
}
2016-04-30 12:25:16 +03:00
}
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
size = ( version * 2 ) + 21 ;
2020-11-27 15:54:44 +03:00
size_squared = size * size ;
2016-04-16 14:57:45 +03:00
2016-04-09 19:01:21 +03:00
# ifndef _MSC_VER
2016-04-16 14:57:45 +03:00
unsigned char datastream [ data_codewords ] ;
unsigned char fullstream [ hx_total_codewords [ version - 1 ] ] ;
unsigned char picket_fence [ hx_total_codewords [ version - 1 ] ] ;
2020-11-27 15:54:44 +03:00
unsigned char grid [ size_squared ] ;
2016-04-09 19:01:21 +03:00
# else
2021-06-19 15:11:23 +03:00
datastream = ( unsigned char * ) _alloca ( data_codewords ) ;
fullstream = ( unsigned char * ) _alloca ( hx_total_codewords [ version - 1 ] ) ;
picket_fence = ( unsigned char * ) _alloca ( hx_total_codewords [ version - 1 ] ) ;
grid = ( unsigned char * ) _alloca ( size_squared ) ;
2016-04-09 19:01:21 +03:00
# endif
2016-04-16 14:57:45 +03:00
2020-11-27 15:54:44 +03:00
memset ( datastream , 0 , data_codewords ) ;
2016-09-06 00:06:50 +03:00
2017-04-10 10:06:53 +03:00
for ( i = 0 ; i < bin_len ; i + + ) {
2016-04-10 22:36:57 +03:00
if ( binary [ i ] = = ' 1 ' ) {
2020-11-27 15:54:44 +03:00
datastream [ i > > 3 ] | = 0x80 > > ( i & 0x07 ) ;
2016-04-10 22:36:57 +03:00
}
}
2016-04-16 14:57:45 +03:00
2019-12-08 19:15:34 +03:00
if ( symbol - > debug & ZINT_DEBUG_PRINT ) {
2019-11-17 17:56:43 +03:00
printf ( " Datastream length: %d \n " , data_codewords ) ;
printf ( " Datastream: \n " ) ;
for ( i = 0 ; i < data_codewords ; i + + ) {
printf ( " %.2x " , datastream [ i ] ) ;
}
printf ( " \n " ) ;
}
2019-12-19 03:37:55 +03:00
# ifdef ZINT_TEST
2019-12-16 20:31:52 +03:00
if ( symbol - > debug & ZINT_DEBUG_TEST ) debug_test_codeword_dump ( symbol , datastream , data_codewords ) ;
2019-12-19 03:37:55 +03:00
# endif
2019-11-17 17:56:43 +03:00
2016-04-09 19:01:21 +03:00
hx_setup_grid ( grid , size , version ) ;
2016-09-06 00:06:50 +03:00
2019-12-08 19:15:34 +03:00
hx_add_ecc ( fullstream , datastream , data_codewords , version , ecc_level ) ;
2016-09-06 00:06:50 +03:00
2016-04-16 14:57:45 +03:00
make_picket_fence ( fullstream , picket_fence , hx_total_codewords [ version - 1 ] ) ;
2016-09-06 00:06:50 +03:00
2016-04-20 22:44:59 +03:00
/* Populate grid */
j = 0 ;
2020-11-27 15:54:44 +03:00
j_max = hx_total_codewords [ version - 1 ] * 8 ;
for ( i = 0 ; i < size_squared ; i + + ) {
2016-04-20 22:44:59 +03:00
if ( grid [ i ] = = 0x00 ) {
2020-11-27 15:54:44 +03:00
if ( j < j_max ) {
if ( picket_fence [ ( j > > 3 ) ] & ( 0x80 > > ( j & 0x07 ) ) ) {
2016-04-20 22:44:59 +03:00
grid [ i ] = 0x01 ;
}
j + + ;
2016-04-23 17:26:51 +03:00
} else {
2020-11-27 15:54:44 +03:00
break ;
2016-04-23 17:26:51 +03:00
}
}
}
2016-09-06 00:06:50 +03:00
2020-11-27 15:54:44 +03:00
hx_apply_bitmask ( grid , size , version , ecc_level , user_mask , symbol - > debug ) ;
2016-09-06 00:06:50 +03:00
2016-04-09 19:01:21 +03:00
symbol - > width = size ;
symbol - > rows = size ;
for ( i = 0 ; i < size ; i + + ) {
2020-11-27 15:54:44 +03:00
int r = i * size ;
2016-04-09 19:01:21 +03:00
for ( j = 0 ; j < size ; j + + ) {
2020-11-27 15:54:44 +03:00
if ( grid [ r + j ] & 0x01 ) {
2016-04-09 19:01:21 +03:00
set_module ( symbol , i , j ) ;
}
}
symbol - > row_height [ i ] = 1 ;
}
2021-06-19 15:11:23 +03:00
symbol - > height = size ;
2016-04-16 14:57:45 +03:00
2016-04-30 12:25:16 +03:00
return 0 ;
2016-09-06 00:06:50 +03:00
}