2016-07-26 00:52:29 +03:00
/* dotcode.c - Handles DotCode */
/*
libzint - the open source barcode library
2019-10-31 16:27:36 +03:00
Copyright ( C ) 2017 - 2019 Robin Stuart < rstuart114 @ gmail . com >
2016-07-26 00:52:29 +03:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
2017-10-23 22:37:52 +03:00
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2016-07-26 00:52:29 +03:00
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
2017-10-23 22:37:52 +03:00
documentation and / or other materials provided with the distribution .
2016-07-26 00:52:29 +03:00
3. Neither the name of the project nor the names of its contributors
may be used to endorse or promote products derived from this software
2017-10-23 22:37:52 +03:00
without specific prior written permission .
2016-07-26 00:52:29 +03:00
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
2017-10-23 22:37:52 +03:00
OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
2016-07-26 00:52:29 +03:00
*/
2019-11-27 19:16:14 +03:00
/* vim: set ts=4 sw=4 et : */
2016-07-26 00:52:29 +03:00
2017-10-23 22:37:52 +03:00
/*
2016-07-26 00:52:29 +03:00
* Attempts to encode DotCode according to AIMD013 Rev 1.34 a , dated Feb 19 , 2009
2019-10-31 16:27:36 +03:00
* Incorporating suggestions from Terry Burton at BWIPP
2016-07-26 00:52:29 +03:00
*/
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
2016-07-27 14:18:53 +03:00
# include <math.h>
2016-07-26 00:52:29 +03:00
# ifndef _MSC_VER
# include <stdint.h>
# else
2016-09-12 14:24:18 +03:00
# include "ms_stdint.h"
2016-07-26 00:52:29 +03:00
# include <malloc.h>
# endif
# include "common.h"
# include "gs1.h"
2016-07-27 14:18:53 +03:00
# define GF 113
# define PM 3
2019-10-31 16:27:36 +03:00
# define SCORE_UNLIT_EDGE -99999
2016-08-07 00:03:36 +03:00
/* DotCode symbol character dot patterns, from Annex C */
2017-08-09 11:13:37 +03:00
static const unsigned short int dot_patterns [ 113 ] = {
2016-08-07 22:11:51 +03:00
0x155 , 0x0ab , 0x0ad , 0x0b5 , 0x0d5 , 0x156 , 0x15a , 0x16a , 0x1aa , 0x0ae ,
0x0b6 , 0x0ba , 0x0d6 , 0x0da , 0x0ea , 0x12b , 0x12d , 0x135 , 0x14b , 0x14d ,
0x153 , 0x159 , 0x165 , 0x169 , 0x195 , 0x1a5 , 0x1a9 , 0x057 , 0x05b , 0x05d ,
0x06b , 0x06d , 0x075 , 0x097 , 0x09b , 0x09d , 0x0a7 , 0x0b3 , 0x0b9 , 0x0cb ,
0x0cd , 0x0d3 , 0x0d9 , 0x0e5 , 0x0e9 , 0x12e , 0x136 , 0x13a , 0x14e , 0x15c ,
0x166 , 0x16c , 0x172 , 0x174 , 0x196 , 0x19a , 0x1a6 , 0x1ac , 0x1b2 , 0x1b4 ,
0x1ca , 0x1d2 , 0x1d4 , 0x05e , 0x06e , 0x076 , 0x07a , 0x09e , 0x0bc , 0x0ce ,
0x0dc , 0x0e6 , 0x0ec , 0x0f2 , 0x0f4 , 0x117 , 0x11b , 0x11d , 0x127 , 0x133 ,
0x139 , 0x147 , 0x163 , 0x171 , 0x18b , 0x18d , 0x193 , 0x199 , 0x1a3 , 0x1b1 ,
0x1c5 , 0x1c9 , 0x1d1 , 0x02f , 0x037 , 0x03b , 0x03d , 0x04f , 0x067 , 0x073 ,
0x079 , 0x08f , 0x0c7 , 0x0e3 , 0x0f1 , 0x11e , 0x13c , 0x178 , 0x18e , 0x19c ,
0x1b8 , 0x1c6 , 0x1cc
2016-08-07 00:03:36 +03:00
} ;
2017-05-29 12:43:47 +03:00
static int get_dot ( char Dots [ ] , const int Hgt , const int Wid , const int x , const int y ) {
2016-08-07 00:03:36 +03:00
int retval = 0 ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
if ( ( x > = 0 ) & & ( x < Wid ) & & ( y > = 0 ) & & ( y < Hgt ) ) {
if ( Dots [ ( y * Wid ) + x ] = = ' 1 ' ) {
retval = 1 ;
}
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
return retval ;
}
2017-05-29 12:43:47 +03:00
static int clr_col ( char * Dots , const int Hgt , const int Wid , const int x ) {
2017-05-19 23:30:31 +03:00
int y ;
for ( y = x & 1 ; y < Hgt ; y + = 2 ) {
if ( get_dot ( Dots , Hgt , Wid , x , y ) ) {
return 0 ;
}
}
2017-10-23 22:37:52 +03:00
2017-05-19 23:30:31 +03:00
return 1 ;
}
2017-05-29 12:43:47 +03:00
static int clr_row ( char * Dots , const int Hgt , const int Wid , const int y ) {
2017-05-19 23:30:31 +03:00
int x ;
for ( x = y & 1 ; x < Wid ; x + = 2 ) {
if ( get_dot ( Dots , Hgt , Wid , x , y ) ) {
return 0 ;
}
}
2017-10-23 22:37:52 +03:00
2017-05-19 23:30:31 +03:00
return 1 ;
}
2016-08-07 00:03:36 +03:00
/* Dot pattern scoring routine from Annex A */
2017-05-29 12:43:47 +03:00
const int score_array ( char Dots [ ] , int Hgt , int Wid ) {
2016-08-07 00:03:36 +03:00
int x , y , worstedge , first , last , sum ;
2017-05-19 23:30:31 +03:00
int penalty_local = 0 ;
int penalty = 0 ;
// first, guard against "pathelogical" gaps in the array
if ( Hgt & 1 ) {
if ( Hgt < 12 ) {
sum = 0 ;
for ( x = 1 ; x < Wid - 1 ; x + + ) {
if ( ! ( clr_col ( Dots , Hgt , Wid , x ) ) ) {
sum = 0 ;
if ( penalty_local ) {
penalty + = penalty_local ;
penalty_local = 0 ;
}
} else {
sum + + ;
if ( sum = = 1 ) {
penalty_local = Hgt ;
} else {
penalty_local * = Hgt ;
}
}
}
}
} else {
if ( Wid < 12 ) {
sum = 0 ;
for ( y = 1 ; y < Hgt - 1 ; y + + ) {
if ( ! ( clr_row ( Dots , Hgt , Wid , y ) ) ) {
sum = 0 ;
if ( penalty_local ) {
penalty + = penalty_local ;
penalty_local = 0 ;
}
} else {
sum + + ;
if ( sum = = 1 ) {
penalty_local = Wid ;
} else {
penalty_local * = Wid ;
}
}
}
}
}
2017-10-23 22:37:52 +03:00
2016-08-07 00:03:36 +03:00
sum = 0 ;
first = - 1 ;
2016-08-07 23:00:27 +03:00
last = - 1 ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
// across the top edge, count printed dots and measure their extent
for ( x = 0 ; x < Wid ; x + = 2 )
2016-08-07 22:11:51 +03:00
if ( get_dot ( Dots , Hgt , Wid , x , 0 ) ) {
2016-08-07 00:03:36 +03:00
if ( first < 0 ) {
first = x ;
}
2016-08-07 22:11:51 +03:00
last = x ;
2016-08-07 00:03:36 +03:00
sum + + ;
}
2016-08-07 22:11:51 +03:00
worstedge = sum + last - first ;
2016-08-07 00:03:36 +03:00
worstedge * = Hgt ;
2019-10-31 16:27:36 +03:00
2018-06-20 02:10:30 +03:00
if ( sum = = 0 ) {
2019-10-31 16:27:36 +03:00
return SCORE_UNLIT_EDGE ; // guard against empty top edge
2018-06-20 02:10:30 +03:00
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
sum = 0 ;
first = - 1 ;
2017-05-19 23:30:31 +03:00
last = - 1 ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
//across the bottom edge, ditto
2016-08-07 22:11:51 +03:00
for ( x = Wid & 1 ; x < Wid ; x + = 2 )
if ( get_dot ( Dots , Hgt , Wid , x , Hgt - 1 ) ) {
2016-08-07 00:03:36 +03:00
if ( first < 0 ) {
first = x ;
}
2016-08-07 22:11:51 +03:00
last = x ;
2016-08-07 00:03:36 +03:00
sum + + ;
}
2016-08-07 22:11:51 +03:00
sum + = last - first ;
2016-08-07 00:03:36 +03:00
sum * = Hgt ;
if ( sum < worstedge ) {
worstedge = sum ;
}
2019-10-31 16:27:36 +03:00
2018-06-20 02:10:30 +03:00
if ( sum = = 0 ) {
2019-10-31 16:27:36 +03:00
return SCORE_UNLIT_EDGE ; // guard against empty bottom edge
2018-06-20 02:10:30 +03:00
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
sum = 0 ;
first = - 1 ;
2017-05-19 23:30:31 +03:00
last = - 1 ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
//down the left edge, ditto
2016-08-07 22:11:51 +03:00
for ( y = 0 ; y < Hgt ; y + = 2 )
if ( get_dot ( Dots , Hgt , Wid , 0 , y ) ) {
2016-08-07 00:03:36 +03:00
if ( first < 0 ) {
first = y ;
}
2016-08-07 22:11:51 +03:00
last = y ;
2016-08-07 00:03:36 +03:00
sum + + ;
}
2016-08-07 22:11:51 +03:00
sum + = last - first ;
2016-08-07 00:03:36 +03:00
sum * = Wid ;
if ( sum < worstedge ) {
worstedge = sum ;
}
2019-10-31 16:27:36 +03:00
2018-06-20 02:10:30 +03:00
if ( sum = = 0 ) {
2019-10-31 16:27:36 +03:00
return SCORE_UNLIT_EDGE ; // guard against empty left edge
2018-06-20 02:10:30 +03:00
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
sum = 0 ;
first = - 1 ;
2017-05-19 23:30:31 +03:00
last = - 1 ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
//down the right edge, ditto
2016-08-07 22:11:51 +03:00
for ( y = Hgt & 1 ; y < Hgt ; y + = 2 )
if ( get_dot ( Dots , Hgt , Wid , Wid - 1 , y ) ) {
2016-08-07 00:03:36 +03:00
if ( first < 0 ) {
first = y ;
}
2016-08-07 22:11:51 +03:00
last = y ;
2016-08-07 00:03:36 +03:00
sum + + ;
}
2016-08-07 22:11:51 +03:00
sum + = last - first ;
sum * = Wid ;
2016-08-07 00:03:36 +03:00
if ( sum < worstedge ) {
worstedge = sum ;
}
2019-10-31 16:27:36 +03:00
2018-06-20 02:10:30 +03:00
if ( sum = = 0 ) {
2019-10-31 16:27:36 +03:00
return SCORE_UNLIT_EDGE ; // guard against empty right edge
2018-06-20 02:10:30 +03:00
}
2016-08-07 00:03:36 +03:00
// throughout the array, count the # of unprinted 5-somes (cross patterns)
// plus the # of printed dots surrounded by 8 unprinted neighbors
sum = 0 ;
for ( y = 0 ; y < Hgt ; y + + ) {
for ( x = y & 1 ; x < Wid ; x + = 2 ) {
2016-08-07 22:11:51 +03:00
if ( ( ! get_dot ( Dots , Hgt , Wid , x - 1 , y - 1 ) )
& & ( ! get_dot ( Dots , Hgt , Wid , x + 1 , y - 1 ) )
& & ( ! get_dot ( Dots , Hgt , Wid , x - 1 , y + 1 ) )
2016-09-06 00:06:50 +03:00
& & ( ! get_dot ( Dots , Hgt , Wid , x + 1 , y + 1 ) )
2016-08-07 22:11:51 +03:00
& & ( ( ! get_dot ( Dots , Hgt , Wid , x , y ) )
| | ( ( ! get_dot ( Dots , Hgt , Wid , x - 2 , y ) )
& & ( ! get_dot ( Dots , Hgt , Wid , x , y - 2 ) )
& & ( ! get_dot ( Dots , Hgt , Wid , x + 2 , y ) )
& & ( ! get_dot ( Dots , Hgt , Wid , x , y + 2 ) ) ) ) ) {
2016-08-07 00:03:36 +03:00
sum + + ;
}
}
}
2016-08-07 22:11:51 +03:00
2017-05-19 23:30:31 +03:00
return ( worstedge - sum * sum - penalty ) ;
2016-08-07 00:03:36 +03:00
}
2016-07-27 14:18:53 +03:00
//-------------------------------------------------------------------------
// "rsencode(nd,nc)" adds "nc" R-S check words to "nd" data words in wd[]
// employing Galois Field GF, where GF is prime, with a prime modulus of PM
//-------------------------------------------------------------------------
2016-08-07 22:11:51 +03:00
void rsencode ( int nd , int nc , unsigned char * wd ) {
2016-07-27 14:18:53 +03:00
int i , j , k , nw , start , step , root [ GF ] , c [ GF ] ;
2016-08-07 22:11:51 +03:00
2016-07-27 14:18:53 +03:00
// Start by generating "nc" roots (antilogs):
root [ 0 ] = 1 ;
2017-01-22 22:12:11 +03:00
for ( i = 1 ; ( i < = nc ) & & ( i < GF ) ; i + + )
2016-08-07 22:11:51 +03:00
root [ i ] = ( PM * root [ i - 1 ] ) % GF ;
2016-07-27 14:18:53 +03:00
// Here we compute how many interleaved R-S blocks will be needed
2016-08-07 22:11:51 +03:00
nw = nd + nc ;
step = ( nw + GF - 2 ) / ( GF - 1 ) ;
2016-07-27 14:18:53 +03:00
// ...& then for each such block:
2016-08-07 22:11:51 +03:00
for ( start = 0 ; start < step ; start + + ) {
int ND = ( nd - start + step - 1 ) / step , NW = ( nw - start + step - 1 ) / step , NC = NW - ND ;
2016-07-27 14:18:53 +03:00
// first compute the generator polynomial "c" of order "NC":
2016-08-07 22:11:51 +03:00
for ( i = 1 ; i < = NC ; i + + )
c [ i ] = 0 ;
c [ 0 ] = 1 ;
for ( i = 1 ; i < = NC ; i + + ) {
for ( j = NC ; j > = 1 ; j - - ) {
c [ j ] = ( GF + c [ j ] - ( root [ i ] * c [ j - 1 ] ) % GF ) % GF ;
2016-07-27 14:18:53 +03:00
}
}
2016-08-07 22:11:51 +03:00
2016-07-27 14:18:53 +03:00
// & then compute the corresponding checkword values into wd[]
// ... (a) starting at wd[start] & (b) stepping by step
2016-08-07 22:11:51 +03:00
for ( i = ND ; i < NW ; i + + )
wd [ start + i * step ] = 0 ;
for ( i = 0 ; i < ND ; i + + ) {
k = ( wd [ start + i * step ] + wd [ start + ND * step ] ) % GF ;
for ( j = 0 ; j < NC - 1 ; j + + ) {
wd [ start + ( ND + j ) * step ] = ( GF - ( ( c [ j + 1 ] * k ) % GF ) + wd [ start + ( ND + j + 1 ) * step ] ) % GF ;
2016-07-27 14:18:53 +03:00
}
2016-08-07 22:11:51 +03:00
wd [ start + ( ND + NC - 1 ) * step ] = ( GF - ( ( c [ NC ] * k ) % GF ) ) % GF ;
2016-07-27 14:18:53 +03:00
}
2016-08-07 22:11:51 +03:00
for ( i = ND ; i < NW ; i + + )
wd [ start + i * step ] = ( GF - wd [ start + i * step ] ) % GF ;
2016-07-27 14:18:53 +03:00
}
}
2016-07-26 00:52:29 +03:00
/* Check if the next character is directly encodable in code set A (Annex F.II.D) */
2016-09-06 00:06:50 +03:00
int datum_a ( const unsigned char source [ ] , int position , int length ) {
2016-07-26 00:52:29 +03:00
int retval = 0 ;
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( position < length ) {
if ( source [ position ] < = 95 ) {
retval = 1 ;
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
return retval ;
}
/* Check if the next character is directly encodable in code set B (Annex F.II.D) */
2016-09-06 00:06:50 +03:00
int datum_b ( const unsigned char source [ ] , int position , int length ) {
2016-07-26 00:52:29 +03:00
int retval = 0 ;
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( position < length ) {
2017-05-19 23:30:31 +03:00
if ( ( source [ position ] > = 32 ) & & ( source [ position ] < = 127 ) ) {
2016-07-26 00:52:29 +03:00
retval = 1 ;
}
2016-08-07 22:11:51 +03:00
switch ( source [ position ] ) {
2016-07-26 00:52:29 +03:00
case 9 : // HT
case 28 : // FS
case 29 : // GS
case 30 : // RS
retval = 1 ;
}
if ( position ! = length - 2 ) {
if ( ( source [ position ] = = 13 ) & & ( source [ position + 1 ] = = 10 ) ) { // CRLF
retval = 1 ;
}
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
return retval ;
}
/* Check if the next characters are directly encodable in code set C (Annex F.II.D) */
2016-09-06 00:06:50 +03:00
int datum_c ( const unsigned char source [ ] , int position , int length ) {
2016-07-26 00:52:29 +03:00
int retval = 0 ;
2016-08-07 22:11:51 +03:00
2017-02-14 14:04:58 +03:00
if ( position < = length - 2 ) {
2016-07-26 00:52:29 +03:00
if ( ( ( source [ position ] > = ' 0 ' ) & & ( source [ position ] < = ' 9 ' ) )
& & ( ( source [ position + 1 ] > = ' 0 ' ) & & ( source [ position + 1 ] < = ' 9 ' ) ) )
retval = 1 ;
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
return retval ;
}
/* Returns how many consecutive digits lie immediately ahead (Annex F.II.A) */
2016-09-06 00:06:50 +03:00
int n_digits ( const unsigned char source [ ] , int position , int length ) {
2016-07-26 00:52:29 +03:00
int i ;
2016-08-07 22:11:51 +03:00
for ( i = position ; ( ( source [ i ] > = ' 0 ' ) & & ( source [ i ] < = ' 9 ' ) ) & & ( i < length ) ; i + + ) ;
2016-07-26 00:52:29 +03:00
return i - position ;
}
2016-08-07 00:03:36 +03:00
/* checks ahead for 10 or more digits starting "17xxxxxx10..." (Annex F.II.B) */
2016-09-06 00:06:50 +03:00
int seventeen_ten ( const unsigned char source [ ] , int position , int length ) {
2016-07-26 00:52:29 +03:00
int found = 0 ;
2016-08-07 22:11:51 +03:00
if ( n_digits ( source , position , length ) > = 10 ) {
if ( ( ( source [ position ] = = ' 1 ' ) & & ( source [ position + 1 ] = = ' 7 ' ) )
2016-07-26 00:52:29 +03:00
& & ( ( source [ position + 8 ] = = ' 1 ' ) & & ( source [ position + 9 ] = = ' 0 ' ) ) ) {
found = 1 ;
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
return found ;
}
/* checks how many characters ahead can be reached while datum_c is true,
* returning the resulting number of codewords ( Annex F . II . E )
*/
2016-09-06 00:06:50 +03:00
int ahead_c ( const unsigned char source [ ] , int position , int length ) {
2016-08-26 17:13:40 +03:00
int count = 0 ;
2016-09-06 00:06:50 +03:00
int i ;
2016-08-07 22:11:51 +03:00
2016-08-22 19:58:32 +03:00
for ( i = position ; ( i < length ) & & datum_c ( source , i , length ) ; i + = 2 ) {
2016-07-26 00:52:29 +03:00
count + + ;
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
return count ;
}
/* Annex F.II.F */
2016-09-06 00:06:50 +03:00
int try_c ( const unsigned char source [ ] , int position , int length ) {
2016-07-26 00:52:29 +03:00
int retval = 0 ;
2016-08-07 22:11:51 +03:00
if ( n_digits ( source , position , length ) > 0 ) {
if ( ahead_c ( source , position , length ) > ahead_c ( source , position + 1 , length ) ) {
2016-07-26 00:52:29 +03:00
retval = ahead_c ( source , position , length ) ;
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
return retval ;
}
/* Annex F.II.G */
2016-09-06 00:06:50 +03:00
int ahead_a ( const unsigned char source [ ] , int position , int length ) {
2016-08-26 17:13:40 +03:00
int count = 0 ;
2016-09-06 00:06:50 +03:00
int i ;
2016-08-07 22:11:51 +03:00
2016-08-22 19:58:32 +03:00
for ( i = position ; ( ( i < length ) & & datum_a ( source , i , length ) )
2016-07-26 00:52:29 +03:00
& & ( try_c ( source , i , length ) < 2 ) ; i + + ) {
count + + ;
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
return count ;
}
/* Annex F.II.H */
2016-09-06 00:06:50 +03:00
int ahead_b ( const unsigned char source [ ] , int position , int length ) {
2016-08-26 17:13:40 +03:00
int count = 0 ;
2016-09-06 00:06:50 +03:00
int i ;
2016-08-07 22:11:51 +03:00
2016-08-22 19:58:32 +03:00
for ( i = position ; ( ( i < length ) & & datum_b ( source , i , length ) )
2016-07-26 00:52:29 +03:00
& & ( try_c ( source , i , length ) < 2 ) ; i + + ) {
count + + ;
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
return count ;
}
/* checks if the next character is in the range 128 to 255 (Annex F.II.I) */
2017-02-19 01:17:49 +03:00
int binary ( const unsigned char source [ ] , int position ) {
2016-07-26 00:52:29 +03:00
int retval = 0 ;
2016-08-07 22:11:51 +03:00
if ( source [ position ] > = 128 ) {
2016-07-26 00:52:29 +03:00
retval = 1 ;
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
return retval ;
}
2016-08-07 00:03:36 +03:00
/* Analyse input data stream and encode using algorithm from Annex F */
2017-02-14 21:01:48 +03:00
int dotcode_encode_message ( struct zint_symbol * symbol , const unsigned char source [ ] , int length , unsigned char * codeword_array , int * binary_finish ) {
2016-07-26 00:52:29 +03:00
int input_position , array_length , i ;
char encoding_mode ;
2017-09-10 18:03:09 +03:00
int inside_macro ;
2017-04-11 12:05:38 +03:00
int debug = symbol - > debug ;
2016-07-26 00:52:29 +03:00
int binary_buffer_size = 0 ;
int lawrencium [ 6 ] ; // Reversed radix 103 values
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
# if defined(_MSC_VER) && _MSC_VER == 1200
uint64_t binary_buffer = 0 ;
# else
uint64_t binary_buffer = 0ULL ;
# endif
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
input_position = 0 ;
array_length = 0 ;
encoding_mode = ' C ' ;
inside_macro = 0 ;
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( symbol - > output_options & READER_INIT ) {
codeword_array [ array_length ] = 109 ; // FNC3
array_length + + ;
}
2016-08-07 22:11:51 +03:00
2019-11-27 19:16:14 +03:00
if ( ( symbol - > input_mode & 0x07 ) ! = GS1_MODE ) {
2017-05-19 23:30:31 +03:00
if ( length > 2 ) {
if ( ( ( source [ input_position ] > = ' 0 ' ) & & ( source [ input_position ] < = ' 9 ' ) ) & &
( ( source [ input_position + 1 ] > = ' 0 ' ) & & ( source [ input_position + 1 ] < = ' 9 ' ) ) ) {
codeword_array [ array_length ] = 107 ; // FNC1
array_length + + ;
}
}
2016-07-26 00:52:29 +03:00
}
2016-09-06 00:06:50 +03:00
2019-10-06 19:39:54 +03:00
if ( symbol - > eci > 0 ) {
2016-08-16 14:43:41 +03:00
codeword_array [ array_length ] = 108 ; // FNC2
array_length + + ;
2017-05-19 23:30:31 +03:00
if ( symbol - > eci < = 39 ) {
codeword_array [ array_length ] = symbol - > eci ;
array_length + + ;
} else {
// the next three codewords valued A, B & C encode the ECI value of
// (A - 40) * 12769 + B * 113 + C + 40 (Section 5.2.1)
int a , b , c ;
a = ( symbol - > eci - 40 ) % 12769 ;
b = ( ( symbol - > eci - 40 ) - ( 12769 * a ) ) % 113 ;
c = ( symbol - > eci - 40 ) - ( 12769 * a ) - ( 113 * b ) ;
2017-10-23 22:37:52 +03:00
2017-05-19 23:30:31 +03:00
codeword_array [ array_length ] = a + 40 ;
array_length + + ;
codeword_array [ array_length ] = b ;
array_length + + ;
codeword_array [ array_length ] = c ;
array_length + + ;
}
2016-08-16 14:43:41 +03:00
}
2016-08-07 22:11:51 +03:00
2017-05-19 23:30:31 +03:00
// Prevent encodation as a macro if a special character is in first position
if ( source [ input_position ] = = 9 ) {
codeword_array [ array_length ] = 101 ; // Latch A
array_length + + ;
codeword_array [ array_length ] = 73 ; // HT
array_length + + ;
encoding_mode = ' A ' ;
}
2017-10-23 22:37:52 +03:00
2017-05-19 23:30:31 +03:00
if ( source [ input_position ] = = 28 ) {
codeword_array [ array_length ] = 101 ; // Latch A
array_length + + ;
codeword_array [ array_length ] = 92 ; // FS
array_length + + ;
encoding_mode = ' A ' ;
}
2017-10-23 22:37:52 +03:00
2017-05-19 23:30:31 +03:00
if ( source [ input_position ] = = 29 ) {
codeword_array [ array_length ] = 101 ; // Latch A
array_length + + ;
codeword_array [ array_length ] = 93 ; // GS
array_length + + ;
encoding_mode = ' A ' ;
}
2017-10-23 22:37:52 +03:00
2017-05-19 23:30:31 +03:00
if ( source [ input_position ] = = 30 ) {
codeword_array [ array_length ] = 101 ; // Latch A
array_length + + ;
codeword_array [ array_length ] = 94 ; // RS
array_length + + ;
encoding_mode = ' A ' ;
}
2017-10-23 22:37:52 +03:00
2016-07-26 00:52:29 +03:00
do {
2017-09-10 18:03:09 +03:00
int done = 0 ;
2016-07-26 00:52:29 +03:00
/* Step A */
if ( ( input_position = = length - 2 ) & & ( inside_macro ! = 0 ) & & ( inside_macro ! = 100 ) ) {
// inside_macro only gets set to 97, 98 or 99 if the last two characters are RS/EOT
input_position + = 2 ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " A " ) ;
}
2016-07-26 00:52:29 +03:00
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( ( input_position = = length - 1 ) & & ( inside_macro = = 100 ) ) {
// inside_macro only gets set to 100 if the last character is EOT
input_position + + ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " A " ) ;
}
2016-07-26 00:52:29 +03:00
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step B1 */
if ( ( ! done ) & & ( encoding_mode = = ' C ' ) ) {
if ( ( array_length = = 0 ) & & ( length > 9 ) ) {
2016-08-07 22:11:51 +03:00
if ( ( source [ input_position ] = = ' [ ' )
2016-07-26 00:52:29 +03:00
& & ( source [ input_position + 1 ] = = ' ) ' )
& & ( source [ input_position + 2 ] = = ' > ' )
& & ( source [ input_position + 3 ] = = 30 ) // RS
2016-08-07 22:11:51 +03:00
& & ( source [ length - 1 ] = = 04 ) ) { // EOT
2016-07-26 00:52:29 +03:00
if ( ( source [ input_position + 6 ] = = 29 ) & & ( source [ length - 2 ] = = 30 ) ) { // GS/RS
if ( ( source [ input_position + 4 ] = = ' 0 ' ) & & ( source [ input_position + 5 ] = = ' 5 ' ) ) {
2017-05-19 23:30:31 +03:00
codeword_array [ array_length ] = 102 ; // Shift B
array_length + + ;
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = 97 ; // Macro
array_length + + ;
input_position + = 7 ;
inside_macro = 97 ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " B1/1 " ) ;
}
2016-07-26 00:52:29 +03:00
}
if ( ( source [ input_position + 4 ] = = ' 0 ' ) & & ( source [ input_position + 5 ] = = ' 6 ' ) ) {
2017-05-19 23:30:31 +03:00
codeword_array [ array_length ] = 102 ; // Shift B
array_length + + ;
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = 98 ; // Macro
array_length + + ;
input_position + = 7 ;
inside_macro = 98 ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " B1/2 " ) ;
}
2016-07-26 00:52:29 +03:00
}
if ( ( source [ input_position + 4 ] = = ' 1 ' ) & & ( source [ input_position + 5 ] = = ' 2 ' ) ) {
2017-05-19 23:30:31 +03:00
codeword_array [ array_length ] = 102 ; // Shift B
array_length + + ;
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = 99 ; // Macro
array_length + + ;
input_position + = 7 ;
inside_macro = 99 ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " B1/3 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
2016-08-07 22:11:51 +03:00
2017-05-19 23:30:31 +03:00
if ( ( ! done ) & & ( source [ input_position ] > = ' 0 ' ) & & ( source [ input_position ] < = ' 9 ' ) & &
( source [ input_position + 1 ] > = ' 0 ' ) & & ( source [ input_position + 1 ] < = ' 9 ' ) ) {
codeword_array [ array_length ] = 102 ; // Shift B
array_length + + ;
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = 100 ; // Macro
array_length + + ;
input_position + = 4 ;
inside_macro = 100 ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " B1/4 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step B2 */
if ( ( ! done ) & & ( encoding_mode = = ' C ' ) ) {
if ( seventeen_ten ( source , input_position , length ) ) {
codeword_array [ array_length ] = 100 ; // (17)...(10)
array_length + + ;
codeword_array [ array_length ] = ( ( source [ input_position + 2 ] - ' 0 ' ) * 10 ) + ( source [ input_position + 3 ] - ' 0 ' ) ;
array_length + + ;
codeword_array [ array_length ] = ( ( source [ input_position + 4 ] - ' 0 ' ) * 10 ) + ( source [ input_position + 5 ] - ' 0 ' ) ;
array_length + + ;
codeword_array [ array_length ] = ( ( source [ input_position + 6 ] - ' 0 ' ) * 10 ) + ( source [ input_position + 7 ] - ' 0 ' ) ;
array_length + + ;
input_position + = 10 ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " B2/1 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( ( ! done ) & & ( encoding_mode = = ' C ' ) ) {
2019-11-27 19:16:14 +03:00
if ( datum_c ( source , input_position , length ) | | ( ( source [ input_position ] = = ' [ ' ) & & ( ( symbol - > input_mode & 0x07 ) = = GS1_MODE ) ) ) {
2016-08-07 22:11:51 +03:00
if ( source [ input_position ] = = ' [ ' ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = 107 ; // FNC1
input_position + + ;
} else {
codeword_array [ array_length ] = ( ( source [ input_position ] - ' 0 ' ) * 10 ) + ( source [ input_position + 1 ] - ' 0 ' ) ;
input_position + = 2 ;
}
array_length + + ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " B2/2 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
2016-08-07 22:11:51 +03:00
2019-10-31 16:27:36 +03:00
/* Step B3 */
2016-07-26 00:52:29 +03:00
if ( ( ! done ) & & ( encoding_mode = = ' C ' ) ) {
2017-02-19 01:17:49 +03:00
if ( binary ( source , input_position ) ) {
2016-07-26 00:52:29 +03:00
if ( n_digits ( source , input_position + 1 , length ) > 0 ) {
2016-08-07 22:11:51 +03:00
if ( ( source [ input_position ] - 128 ) < 32 ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = 110 ; // Bin Shift A
array_length + + ;
codeword_array [ array_length ] = source [ input_position ] - 128 + 64 ;
array_length + + ;
} else {
codeword_array [ array_length ] = 111 ; // Bin Shift B
array_length + + ;
codeword_array [ array_length ] = source [ input_position ] - 128 - 32 ;
array_length + + ;
}
input_position + + ;
} else {
codeword_array [ array_length ] = 112 ; // Bin Latch
array_length + + ;
encoding_mode = ' X ' ;
2016-08-07 22:11:51 +03:00
}
2016-07-26 00:52:29 +03:00
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " B3 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step B4 */
if ( ( ! done ) & & ( encoding_mode = = ' C ' ) ) {
int m = ahead_a ( source , input_position , length ) ;
int n = ahead_b ( source , input_position , length ) ;
if ( m > n ) {
codeword_array [ array_length ] = 101 ; // Latch A
array_length + + ;
encoding_mode = ' A ' ;
} else {
if ( n < = 4 ) {
codeword_array [ array_length ] = 101 + n ; // nx Shift B
array_length + + ;
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < n ; i + + ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = source [ input_position ] - 32 ;
array_length + + ;
input_position + + ;
}
} else {
codeword_array [ array_length ] = 106 ; // Latch B
array_length + + ;
encoding_mode = ' B ' ;
}
}
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " B4 " ) ;
}
2016-07-26 00:52:29 +03:00
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step C1 */
if ( ( ! done ) & & ( encoding_mode = = ' B ' ) ) {
int n = try_c ( source , input_position , length ) ;
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( n > = 2 ) {
if ( n < = 4 ) {
codeword_array [ array_length ] = 103 + ( n - 2 ) ; // nx Shift C
array_length + + ;
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < n ; i + + ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = ( ( source [ input_position ] - ' 0 ' ) * 10 ) + ( source [ input_position + 1 ] - ' 0 ' ) ;
array_length + + ;
input_position + = 2 ;
}
} else {
codeword_array [ array_length ] = 106 ; // Latch C
array_length + + ;
encoding_mode = ' C ' ;
}
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " C1 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step C2 */
if ( ( ! done ) & & ( encoding_mode = = ' B ' ) ) {
2019-11-27 19:16:14 +03:00
if ( ( source [ input_position ] = = ' [ ' ) & & ( ( symbol - > input_mode & 0x07 ) = = GS1_MODE ) ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = 107 ; // FNC1
array_length + + ;
input_position + + ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " C2/1 " ) ;
}
2016-07-26 00:52:29 +03:00
} else {
if ( datum_b ( source , input_position , length ) ) {
2017-10-23 22:37:52 +03:00
2017-02-19 03:09:24 +03:00
if ( ( source [ input_position ] > = 32 ) & & ( source [ input_position ] < = 127 ) ) {
codeword_array [ array_length ] = source [ input_position ] - 32 ;
done = 1 ;
2017-10-23 22:37:52 +03:00
2017-02-19 03:09:24 +03:00
} else if ( source [ input_position ] = = 13 ) {
/* CR/LF */
codeword_array [ array_length ] = 96 ;
input_position + + ;
done = 1 ;
2017-10-23 22:37:52 +03:00
2017-02-19 03:09:24 +03:00
} else if ( input_position ! = 0 ) {
/* HT, FS, GS and RS in the first data position would be interpreted as a macro (see table 2) */
switch ( source [ input_position ] ) {
case 9 : // HT
codeword_array [ array_length ] = 97 ;
break ;
case 28 : // FS
codeword_array [ array_length ] = 98 ;
break ;
case 29 : // GS
codeword_array [ array_length ] = 99 ;
break ;
case 30 : // RS
codeword_array [ array_length ] = 100 ;
break ;
}
done = 1 ;
}
2017-10-23 22:37:52 +03:00
2017-02-19 03:09:24 +03:00
if ( done = = 1 ) {
array_length + + ;
input_position + + ;
if ( debug ) {
printf ( " C2/2 " ) ;
}
2016-08-07 22:11:51 +03:00
}
2016-07-26 00:52:29 +03:00
}
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step C3 */
if ( ( ! done ) & & ( encoding_mode = = ' B ' ) ) {
2017-02-19 01:17:49 +03:00
if ( binary ( source , input_position ) ) {
2016-07-26 00:52:29 +03:00
if ( datum_b ( source , input_position + 1 , length ) ) {
2016-08-07 22:11:51 +03:00
if ( ( source [ input_position ] - 128 ) < 32 ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = 110 ; // Bin Shift A
array_length + + ;
codeword_array [ array_length ] = source [ input_position ] - 128 + 64 ;
array_length + + ;
} else {
codeword_array [ array_length ] = 111 ; // Bin Shift B
array_length + + ;
codeword_array [ array_length ] = source [ input_position ] - 128 - 32 ;
array_length + + ;
}
input_position + + ;
} else {
codeword_array [ array_length ] = 112 ; // Bin Latch
array_length + + ;
encoding_mode = ' X ' ;
}
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " C3 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step C4 */
if ( ( ! done ) & & ( encoding_mode = = ' B ' ) ) {
if ( ahead_a ( source , input_position , length ) = = 1 ) {
codeword_array [ array_length ] = 101 ; // Shift A
array_length + + ;
if ( source [ input_position ] < 32 ) {
codeword_array [ array_length ] = source [ input_position ] + 64 ;
} else {
codeword_array [ array_length ] = source [ input_position ] - 32 ;
}
array_length + + ;
input_position + + ;
} else {
codeword_array [ array_length ] = 102 ; // Latch A
array_length + + ;
encoding_mode = ' A ' ;
}
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " C4 " ) ;
}
2016-07-26 00:52:29 +03:00
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step D1 */
if ( ( ! done ) & & ( encoding_mode = = ' A ' ) ) {
int n = try_c ( source , input_position , length ) ;
if ( n > = 2 ) {
if ( n < = 4 ) {
codeword_array [ array_length ] = 103 + ( n - 2 ) ; // nx Shift C
array_length + + ;
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < n ; i + + ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = ( ( source [ input_position ] - ' 0 ' ) * 10 ) + ( source [ input_position + 1 ] - ' 0 ' ) ;
array_length + + ;
input_position + = 2 ;
}
} else {
codeword_array [ array_length ] = 106 ; // Latch C
array_length + + ;
encoding_mode = ' C ' ;
}
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " D1 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step D2 */
if ( ( ! done ) & & ( encoding_mode = = ' A ' ) ) {
2019-11-27 19:16:14 +03:00
if ( ( source [ input_position ] = = ' [ ' ) & & ( ( symbol - > input_mode & 0x07 ) = = GS1_MODE ) ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = 107 ; // FNC1
array_length + + ;
input_position + + ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " D2/1 " ) ;
}
2016-07-26 00:52:29 +03:00
} else {
if ( datum_a ( source , input_position , length ) ) {
if ( source [ input_position ] < 32 ) {
2016-08-07 22:11:51 +03:00
codeword_array [ array_length ] = source [ input_position ] + 64 ;
2016-07-26 00:52:29 +03:00
} else {
codeword_array [ array_length ] = source [ input_position ] - 32 ;
}
array_length + + ;
input_position + + ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " D2/2 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step D3 */
if ( ( ! done ) & & ( encoding_mode = = ' A ' ) ) {
2017-02-19 01:17:49 +03:00
if ( binary ( source , input_position ) ) {
2016-07-26 00:52:29 +03:00
if ( datum_a ( source , input_position + 1 , length ) ) {
2016-08-07 22:11:51 +03:00
if ( ( source [ input_position ] - 128 ) < 32 ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = 110 ; // Bin Shift A
array_length + + ;
codeword_array [ array_length ] = source [ input_position ] - 128 + 64 ;
array_length + + ;
} else {
codeword_array [ array_length ] = 111 ; // Bin Shift B
array_length + + ;
codeword_array [ array_length ] = source [ input_position ] - 128 - 32 ;
array_length + + ;
}
input_position + + ;
} else {
codeword_array [ array_length ] = 112 ; // Bin Latch
array_length + + ;
encoding_mode = ' X ' ;
}
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " D3 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step D4 */
if ( ( ! done ) & & ( encoding_mode = = ' A ' ) ) {
int n = ahead_b ( source , input_position , length ) ;
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( n < = 6 ) {
codeword_array [ array_length ] = 95 + n ; // nx Shift B
array_length + + ;
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < n ; i + + ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = source [ input_position ] - 32 ;
array_length + + ;
input_position + + ;
}
} else {
codeword_array [ array_length ] = 102 ; // Latch B
array_length + + ;
encoding_mode = ' B ' ;
}
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " D4 " ) ;
}
2016-07-26 00:52:29 +03:00
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step E1 */
if ( ( ! done ) & & ( encoding_mode = = ' X ' ) ) {
int n = try_c ( source , input_position , length ) ;
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( n > = 2 ) {
/* Empty binary buffer */
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < ( binary_buffer_size + 1 ) ; i + + ) {
2016-07-26 00:52:29 +03:00
lawrencium [ i ] = binary_buffer % 103 ;
binary_buffer / = 103 ;
}
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < ( binary_buffer_size + 1 ) ; i + + ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = lawrencium [ binary_buffer_size - i ] ;
array_length + + ;
}
binary_buffer = 0 ;
binary_buffer_size = 0 ;
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( n < = 7 ) {
codeword_array [ array_length ] = 101 + n ; // Interrupt for nx Shift C
array_length + + ;
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < n ; i + + ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = ( ( source [ input_position ] - ' 0 ' ) * 10 ) + ( source [ input_position + 1 ] - ' 0 ' ) ;
array_length + + ;
input_position + = 2 ;
}
} else {
codeword_array [ array_length ] = 111 ; // Terminate with Latch to C
array_length + + ;
encoding_mode = ' C ' ;
}
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " E1 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step E2 */
/* Section 5.2.1.1 para D.2.i states:
* " Groups of six codewords, each valued between 0 and 102, are radix converted from
* base 103 into five base 259 values . . . "
*/
if ( ( ! done ) & & ( encoding_mode = = ' X ' ) ) {
2017-02-19 01:17:49 +03:00
if ( binary ( source , input_position )
| | binary ( source , input_position + 1 )
| | binary ( source , input_position + 2 )
| | binary ( source , input_position + 3 ) ) {
2016-07-26 00:52:29 +03:00
binary_buffer * = 259 ;
binary_buffer + = source [ input_position ] ;
binary_buffer_size + + ;
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( binary_buffer_size = = 5 ) {
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < 6 ; i + + ) {
2016-07-26 00:52:29 +03:00
lawrencium [ i ] = binary_buffer % 103 ;
binary_buffer / = 103 ;
}
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < 6 ; i + + ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = lawrencium [ 5 - i ] ;
array_length + + ;
}
binary_buffer = 0 ;
binary_buffer_size = 0 ;
}
input_position + + ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " E2 " ) ;
}
2016-07-26 00:52:29 +03:00
}
}
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
/* Step E3 */
if ( ( ! done ) & & ( encoding_mode = = ' X ' ) ) {
/* Empty binary buffer */
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < ( binary_buffer_size + 1 ) ; i + + ) {
2016-07-26 00:52:29 +03:00
lawrencium [ i ] = binary_buffer % 103 ;
binary_buffer / = 103 ;
}
2016-08-07 22:11:51 +03:00
for ( i = 0 ; i < ( binary_buffer_size + 1 ) ; i + + ) {
2016-07-26 00:52:29 +03:00
codeword_array [ array_length ] = lawrencium [ binary_buffer_size - i ] ;
array_length + + ;
}
binary_buffer = 0 ;
binary_buffer_size = 0 ;
2016-08-07 22:11:51 +03:00
2016-07-26 00:52:29 +03:00
if ( ahead_a ( source , input_position , length ) > ahead_b ( source , input_position , length ) ) {
codeword_array [ array_length ] = 109 ; // Terminate with Latch to A
encoding_mode = ' A ' ;
} else {
codeword_array [ array_length ] = 110 ; // Terminate with Latch to B
encoding_mode = ' B ' ;
}
array_length + + ;
done = 1 ;
2016-08-07 22:11:51 +03:00
if ( debug ) {
printf ( " E3 " ) ;
}
2016-07-26 00:52:29 +03:00
}
} while ( input_position < length ) ;
2017-02-19 01:17:49 +03:00
2017-02-14 21:01:48 +03:00
if ( encoding_mode = = ' X ' ) {
2017-05-19 23:30:31 +03:00
if ( binary_buffer_size ! = 0 ) {
/* Empty binary buffer */
for ( i = 0 ; i < ( binary_buffer_size + 1 ) ; i + + ) {
lawrencium [ i ] = binary_buffer % 103 ;
binary_buffer / = 103 ;
}
for ( i = 0 ; i < ( binary_buffer_size + 1 ) ; i + + ) {
codeword_array [ array_length ] = lawrencium [ binary_buffer_size - i ] ;
array_length + + ;
}
}
2017-02-14 21:01:48 +03:00
* ( binary_finish ) = 1 ;
}
2016-08-07 22:11:51 +03:00
if ( debug ) {
2018-06-20 02:10:30 +03:00
printf ( " \n " ) ;
2016-08-07 22:11:51 +03:00
}
2016-07-27 14:18:53 +03:00
return array_length ;
}
2016-08-07 00:03:36 +03:00
/* Convert codewords to binary data stream */
2016-09-06 00:06:50 +03:00
static size_t make_dotstream ( unsigned char masked_array [ ] , int array_length , char dot_stream [ ] ) {
2017-05-14 10:15:08 +03:00
int i ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
dot_stream [ 0 ] = ' \0 ' ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
/* Mask value is encoded as two dots */
2017-05-14 10:15:08 +03:00
bin_append ( masked_array [ 0 ] , 2 , dot_stream ) ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
/* The rest of the data uses 9-bit dot patterns from Annex C */
for ( i = 1 ; i < array_length ; i + + ) {
2017-05-14 10:15:08 +03:00
bin_append ( dot_patterns [ masked_array [ i ] ] , 9 , dot_stream ) ;
2016-08-07 00:03:36 +03:00
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
return strlen ( dot_stream ) ;
}
2017-10-23 22:37:52 +03:00
/* Determines if a given dot is a reserved corner dot
* to be used by one of the last six bits
2016-08-07 22:11:51 +03:00
*/
2016-08-07 00:03:36 +03:00
int is_corner ( int column , int row , int width , int height ) {
int corner = 0 ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
/* Top Left */
if ( ( column = = 0 ) & & ( row = = 0 ) ) {
corner = 1 ;
2016-08-07 22:11:51 +03:00
}
2016-08-07 00:03:36 +03:00
/* Top Right */
if ( height % 2 ) {
if ( ( ( column = = width - 2 ) & & ( row = = 0 ) )
| | ( ( column = = width - 1 ) & & ( row = = 1 ) ) ) {
corner = 1 ;
}
} else {
if ( ( column = = width - 1 ) & & ( row = = 0 ) ) {
corner = 1 ;
}
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
/* Bottom Left */
if ( height % 2 ) {
if ( ( column = = 0 ) & & ( row = = height - 1 ) ) {
corner = 1 ;
}
} else {
if ( ( ( column = = 0 ) & & ( row = = height - 2 ) )
| | ( ( column = = 1 ) & & ( row = = height - 1 ) ) ) {
corner = 1 ;
}
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
/* Bottom Right */
if ( ( ( column = = width - 2 ) & & ( row = = height - 1 ) )
| | ( ( column = = width - 1 ) & & ( row = = height - 2 ) ) ) {
corner = 1 ;
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
return corner ;
}
/* Place the dots in the symbol*/
void fold_dotstream ( char dot_stream [ ] , int width , int height , char dot_array [ ] ) {
int column , row ;
int input_position = 0 ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
if ( height % 2 ) {
/* Horizontal folding */
for ( row = 0 ; row < height ; row + + ) {
for ( column = 0 ; column < width ; column + + ) {
if ( ! ( ( column + row ) % 2 ) ) {
if ( is_corner ( column , row , width , height ) ) {
dot_array [ ( row * width ) + column ] = ' C ' ;
} else {
dot_array [ ( ( height - row - 1 ) * width ) + column ] = dot_stream [ input_position ] ;
input_position + + ;
}
} else {
dot_array [ ( ( height - row - 1 ) * width ) + column ] = ' ' ; // Non-data position
}
}
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
/* Corners */
dot_array [ width - 2 ] = dot_stream [ input_position ] ;
input_position + + ;
dot_array [ ( height * width ) - 2 ] = dot_stream [ input_position ] ;
input_position + + ;
dot_array [ ( width * 2 ) - 1 ] = dot_stream [ input_position ] ;
input_position + + ;
dot_array [ ( ( height - 1 ) * width ) - 1 ] = dot_stream [ input_position ] ;
input_position + + ;
dot_array [ 0 ] = dot_stream [ input_position ] ;
input_position + + ;
dot_array [ ( height - 1 ) * width ] = dot_stream [ input_position ] ;
} else {
/* Vertical folding */
for ( column = 0 ; column < width ; column + + ) {
for ( row = 0 ; row < height ; row + + ) {
if ( ! ( ( column + row ) % 2 ) ) {
if ( is_corner ( column , row , width , height ) ) {
dot_array [ ( row * width ) + column ] = ' C ' ;
} else {
dot_array [ ( row * width ) + column ] = dot_stream [ input_position ] ;
input_position + + ;
}
} else {
dot_array [ ( row * width ) + column ] = ' ' ; // Non-data position
}
}
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
/* Corners */
dot_array [ ( ( height - 1 ) * width ) - 1 ] = dot_stream [ input_position ] ;
input_position + + ;
dot_array [ ( height - 2 ) * width ] = dot_stream [ input_position ] ;
input_position + + ;
dot_array [ ( height * width ) - 2 ] = dot_stream [ input_position ] ;
input_position + + ;
dot_array [ ( ( height - 1 ) * width ) + 1 ] = dot_stream [ input_position ] ;
input_position + + ;
dot_array [ width - 1 ] = dot_stream [ input_position ] ;
input_position + + ;
dot_array [ 0 ] = dot_stream [ input_position ] ;
}
}
2018-06-20 02:10:30 +03:00
void apply_mask ( int mask , int data_length , unsigned char * masked_codeword_array , unsigned char * codeword_array , int ecc_length , char * dot_stream ) {
int weight = 0 ;
int j ;
2019-10-31 16:27:36 +03:00
2018-06-20 02:10:30 +03:00
switch ( mask ) {
case 0 :
masked_codeword_array [ 0 ] = 0 ;
for ( j = 0 ; j < data_length ; j + + ) {
masked_codeword_array [ j + 1 ] = codeword_array [ j ] ;
}
break ;
case 1 :
masked_codeword_array [ 0 ] = 1 ;
for ( j = 0 ; j < data_length ; j + + ) {
masked_codeword_array [ j + 1 ] = ( weight + codeword_array [ j ] ) % 113 ;
weight + = 3 ;
}
break ;
case 2 :
masked_codeword_array [ 0 ] = 2 ;
for ( j = 0 ; j < data_length ; j + + ) {
masked_codeword_array [ j + 1 ] = ( weight + codeword_array [ j ] ) % 113 ;
weight + = 7 ;
}
break ;
case 3 :
masked_codeword_array [ 0 ] = 3 ;
for ( j = 0 ; j < data_length ; j + + ) {
masked_codeword_array [ j + 1 ] = ( weight + codeword_array [ j ] ) % 113 ;
weight + = 17 ;
}
break ;
}
rsencode ( data_length + 1 , ecc_length , masked_codeword_array ) ;
}
void force_corners ( int width , int height , char * dot_array ) {
if ( width % 2 ) {
// "Vertical" symbol
dot_array [ 0 ] = ' 1 ' ;
dot_array [ width - 1 ] = ' 1 ' ;
dot_array [ ( height - 2 ) * width ] = ' 1 ' ;
dot_array [ ( ( height - 1 ) * width ) - 1 ] = ' 1 ' ;
dot_array [ ( ( height - 1 ) * width ) + 1 ] = ' 1 ' ;
dot_array [ ( height * width ) - 2 ] = ' 1 ' ;
} else {
// "Horizontal" symbol
dot_array [ 0 ] = ' 1 ' ;
dot_array [ width - 2 ] = ' 1 ' ;
dot_array [ ( 2 * width ) - 1 ] = ' 1 ' ;
dot_array [ ( ( height - 1 ) * width ) - 1 ] = ' 1 ' ;
dot_array [ ( height - 1 ) * width ] = ' 1 ' ;
dot_array [ ( height * width ) - 2 ] = ' 1 ' ;
}
}
2016-09-06 00:06:50 +03:00
int dotcode ( struct zint_symbol * symbol , const unsigned char source [ ] , int length ) {
2016-08-07 00:03:36 +03:00
int i , j , k ;
2017-05-29 12:43:47 +03:00
size_t jc , n_dots ;
2016-07-27 14:18:53 +03:00
int data_length , ecc_length ;
2017-05-29 12:43:47 +03:00
int min_dots , min_area ;
2017-02-19 01:17:49 +03:00
int height , width ;
2018-06-20 02:10:30 +03:00
int mask_score [ 8 ] ;
2016-09-06 00:06:50 +03:00
size_t dot_stream_length ;
2016-08-07 00:03:36 +03:00
int high_score , best_mask ;
2017-02-14 21:01:48 +03:00
int binary_finish = 0 ;
2018-06-20 02:10:30 +03:00
int debug = symbol - > debug ;
2017-02-19 01:17:49 +03:00
int padding_dots , is_first ;
2017-06-13 22:05:35 +03:00
# ifdef _MSC_VER
unsigned char * masked_codeword_array ;
# endif
2016-08-07 22:11:51 +03:00
2016-07-27 14:18:53 +03:00
# ifndef _MSC_VER
unsigned char codeword_array [ length * 3 ] ;
# else
2016-08-26 17:13:40 +03:00
char * dot_stream ;
char * dot_array ;
2016-08-07 22:11:51 +03:00
unsigned char * codeword_array = ( unsigned char * ) _alloca ( length * 3 * sizeof ( unsigned char ) ) ;
2016-07-27 14:18:53 +03:00
# endif /* _MSC_VER */
2017-10-23 22:37:52 +03:00
2017-07-23 19:59:51 +03:00
if ( symbol - > eci > 811799 ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 525: Invalid ECI " ) ;
2017-07-23 19:59:51 +03:00
return ZINT_ERROR_INVALID_OPTION ;
}
2016-08-07 22:11:51 +03:00
2017-02-14 21:01:48 +03:00
data_length = dotcode_encode_message ( symbol , source , length , codeword_array , & binary_finish ) ;
2016-08-07 22:11:51 +03:00
2016-07-27 14:18:53 +03:00
ecc_length = 3 + ( data_length / 2 ) ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
if ( debug ) {
printf ( " Codeword length = %d, ECC length = %d \n " , data_length , ecc_length ) ;
2018-06-20 02:10:30 +03:00
printf ( " Codewords: " ) ;
for ( i = 0 ; i < data_length ; i + + ) {
printf ( " [%d] " , codeword_array [ i ] ) ;
}
printf ( " \n " ) ;
2016-08-07 00:03:36 +03:00
}
2016-08-07 22:11:51 +03:00
2016-07-27 14:18:53 +03:00
min_dots = 9 * ( data_length + 3 + ( data_length / 2 ) ) + 2 ;
2017-02-14 14:04:58 +03:00
min_area = min_dots * 2 ;
2016-09-06 00:06:50 +03:00
2016-08-07 22:11:51 +03:00
if ( symbol - > option_2 = = 0 ) {
2017-02-14 14:04:58 +03:00
/* Automatic sizing */
/* Following Rule 3 (Section 5.2.2) and applying a recommended width to height ratio 3:2 */
/* Eliminates under sized symbols */
2017-02-19 01:17:49 +03:00
float h = ( float ) ( sqrt ( min_area * 0.666 ) ) ;
float w = ( float ) ( sqrt ( min_area * 1.5 ) ) ;
2017-02-14 14:04:58 +03:00
height = ( int ) h ;
width = ( int ) w ;
2017-02-19 01:17:49 +03:00
if ( ( width + height ) % 2 = = 1 ) {
if ( ( width * height ) < min_area ) {
2017-02-14 14:04:58 +03:00
width + + ;
height + + ;
}
} else {
2017-02-19 01:17:49 +03:00
if ( ( h * width ) < ( w * height ) ) {
2017-02-14 14:04:58 +03:00
width + + ;
2017-02-19 01:17:49 +03:00
if ( ( width * height ) < min_area ) {
2017-02-14 14:04:58 +03:00
width - - ;
height + + ;
2017-02-19 01:17:49 +03:00
if ( ( width * height ) < min_area ) {
2017-02-14 14:04:58 +03:00
width + = 2 ;
}
}
} else {
height + + ;
2017-02-19 01:17:49 +03:00
if ( ( width * height ) < min_area ) {
width + + ;
height - - ;
if ( ( width * height ) < min_area ) {
height + = 2 ;
}
2017-02-14 14:04:58 +03:00
}
}
2016-08-07 22:11:51 +03:00
}
} else {
2017-02-14 14:04:58 +03:00
/* User defined width */
/* Eliminates under sized symbols */
2017-02-19 01:17:49 +03:00
2016-08-07 22:11:51 +03:00
width = symbol - > option_2 ;
2017-02-14 14:04:58 +03:00
height = ( min_area + ( width - 1 ) ) / width ;
2016-08-07 22:11:51 +03:00
if ( ! ( ( width + height ) % 2 ) ) {
height + + ;
}
2016-07-27 14:18:53 +03:00
}
2016-08-07 22:11:51 +03:00
2016-08-21 23:58:38 +03:00
if ( ( height > 200 ) | | ( width > 200 ) ) {
2017-09-30 19:14:45 +03:00
strcpy ( symbol - > errtxt , " 526: Specified symbol size is too large " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
2017-10-23 22:37:52 +03:00
2017-09-30 19:14:45 +03:00
if ( ( height < 5 ) | | ( width < 5 ) ) {
strcpy ( symbol - > errtxt , " 527: Specified symbol size has a dimension which is too small " ) ;
2016-08-17 19:22:31 +03:00
return ZINT_ERROR_INVALID_OPTION ;
}
2016-09-06 00:06:50 +03:00
2016-07-27 14:18:53 +03:00
n_dots = ( height * width ) / 2 ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
# ifndef _MSC_VER
2016-09-06 00:06:50 +03:00
char dot_stream [ height * width * 3 ] ;
char dot_array [ width * height * sizeof ( char ) ] ;
2016-08-07 00:03:36 +03:00
# else
2016-09-06 00:06:50 +03:00
dot_stream = ( char * ) _alloca ( height * width * 3 ) ;
if ( ! dot_stream ) return ZINT_ERROR_MEMORY ;
2016-08-22 19:58:32 +03:00
dot_array = ( char * ) _alloca ( width * height * sizeof ( char ) ) ;
2016-09-06 00:06:50 +03:00
if ( ! dot_array ) return ZINT_ERROR_MEMORY ;
# endif
2016-08-07 22:11:51 +03:00
2016-07-27 14:18:53 +03:00
/* Add pad characters */
2017-02-19 01:17:49 +03:00
padding_dots = n_dots - min_dots ; /* get the number of free dots available for padding */
is_first = 1 ; /* first padding character flag */
while ( padding_dots > = 9 ) {
if ( padding_dots < 18 & & ( ( data_length % 2 ) = = 0 ) )
padding_dots - = 9 ;
else if ( padding_dots > = 18 ) {
if ( ( data_length % 2 ) = = 0 )
padding_dots - = 9 ;
else
padding_dots - = 18 ;
} else
break ; /* not enough padding dots left for padding */
if ( ( is_first = = 1 ) & & ( binary_finish = = 1 ) )
codeword_array [ data_length ] = 109 ;
else
codeword_array [ data_length ] = 106 ;
2016-08-07 00:03:36 +03:00
2016-07-27 14:18:53 +03:00
data_length + + ;
2017-02-19 01:17:49 +03:00
is_first = 0 ;
2016-07-27 14:18:53 +03:00
}
2016-09-06 00:06:50 +03:00
2016-07-27 14:18:53 +03:00
ecc_length = 3 + ( data_length / 2 ) ;
2016-09-06 00:06:50 +03:00
2017-02-19 01:17:49 +03:00
# ifndef _MSC_VER
unsigned char masked_codeword_array [ data_length + 1 + ecc_length ] ;
# else
2017-03-28 19:06:08 +03:00
masked_codeword_array = ( unsigned char * ) _alloca ( ( data_length + 1 + ecc_length ) * sizeof ( unsigned char ) ) ;
2017-02-19 01:17:49 +03:00
# endif /* _MSC_VER */
2016-07-27 14:18:53 +03:00
/* Evaluate data mask options */
for ( i = 0 ; i < 4 ; i + + ) {
2016-08-07 22:11:51 +03:00
2018-06-20 02:10:30 +03:00
apply_mask ( i , data_length , masked_codeword_array , codeword_array , ecc_length , dot_stream ) ;
2019-10-31 16:27:36 +03:00
2016-08-07 00:03:36 +03:00
dot_stream_length = make_dotstream ( masked_codeword_array , ( data_length + ecc_length + 1 ) , dot_stream ) ;
2016-09-06 00:06:50 +03:00
2016-08-07 00:03:36 +03:00
/* Add pad bits */
2016-09-06 00:06:50 +03:00
for ( jc = dot_stream_length ; jc < n_dots ; jc + + ) {
2016-08-07 00:03:36 +03:00
strcat ( dot_stream , " 1 " ) ;
2016-07-27 14:18:53 +03:00
}
2016-09-06 00:06:50 +03:00
2016-08-07 00:03:36 +03:00
fold_dotstream ( dot_stream , width , height , dot_array ) ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
mask_score [ i ] = score_array ( dot_array , height , width ) ;
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
if ( debug ) {
printf ( " Mask %d score is %d \n " , i , mask_score [ i ] ) ;
}
2016-07-26 00:52:29 +03:00
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
high_score = mask_score [ 0 ] ;
best_mask = 0 ;
2016-08-07 22:11:51 +03:00
for ( i = 1 ; i < 4 ; i + + ) {
2019-10-31 16:27:36 +03:00
if ( mask_score [ i ] > = high_score ) {
2016-08-07 00:03:36 +03:00
high_score = mask_score [ i ] ;
best_mask = i ;
}
}
2019-10-31 16:27:36 +03:00
2018-06-20 02:10:30 +03:00
/* Re-evaluate using forced corners if needed */
if ( best_mask < = ( height * width ) / 2 ) {
for ( i = 0 ; i < 4 ; i + + ) {
apply_mask ( i , data_length , masked_codeword_array , codeword_array , ecc_length , dot_stream ) ;
2019-10-31 16:27:36 +03:00
2018-06-20 02:10:30 +03:00
dot_stream_length = make_dotstream ( masked_codeword_array , ( data_length + ecc_length + 1 ) , dot_stream ) ;
/* Add pad bits */
for ( jc = dot_stream_length ; jc < n_dots ; jc + + ) {
strcat ( dot_stream , " 1 " ) ;
}
2016-08-07 22:11:51 +03:00
2018-06-20 02:10:30 +03:00
fold_dotstream ( dot_stream , width , height , dot_array ) ;
2019-10-31 16:27:36 +03:00
2018-06-20 02:10:30 +03:00
force_corners ( width , height , dot_array ) ;
2016-08-07 22:11:51 +03:00
2018-06-20 02:40:36 +03:00
mask_score [ i + 4 ] = score_array ( dot_array , height , width ) ;
2016-08-07 22:11:51 +03:00
2018-06-20 02:10:30 +03:00
if ( debug ) {
2018-06-20 02:40:36 +03:00
printf ( " Mask %d score is %d \n " , i + 4 , mask_score [ i + 4 ] ) ;
2018-06-20 02:10:30 +03:00
}
2016-08-07 00:03:36 +03:00
}
2019-10-31 16:27:36 +03:00
2018-06-20 02:40:36 +03:00
for ( i = 4 ; i < 8 ; i + + ) {
2019-10-31 16:27:36 +03:00
if ( mask_score [ i ] > = high_score ) {
2018-06-20 02:10:30 +03:00
high_score = mask_score [ i ] ;
best_mask = i ;
2016-08-07 00:03:36 +03:00
}
}
}
2019-10-31 16:27:36 +03:00
2018-06-20 02:40:36 +03:00
if ( debug ) {
printf ( " Applying mask %d \n " , best_mask ) ;
}
2016-08-07 22:11:51 +03:00
2018-06-20 02:10:30 +03:00
/* Apply best mask */
2018-06-20 02:40:36 +03:00
apply_mask ( best_mask % 4 , data_length , masked_codeword_array , codeword_array , ecc_length , dot_stream ) ;
2019-10-31 16:27:36 +03:00
2018-06-20 02:10:30 +03:00
dot_stream_length = make_dotstream ( masked_codeword_array , ( data_length + ecc_length + 1 ) , dot_stream ) ;
/* Add pad bits */
for ( jc = dot_stream_length ; jc < n_dots ; jc + + ) {
strcat ( dot_stream , " 1 " ) ;
}
fold_dotstream ( dot_stream , width , height , dot_array ) ;
2019-10-31 16:27:36 +03:00
2018-06-20 02:40:36 +03:00
if ( best_mask > = 4 ) {
2018-06-20 02:10:30 +03:00
force_corners ( width , height , dot_array ) ;
}
2016-08-07 00:03:36 +03:00
/* Copy values to symbol */
symbol - > width = width ;
symbol - > rows = height ;
for ( k = 0 ; k < height ; k + + ) {
for ( j = 0 ; j < width ; j + + ) {
if ( dot_array [ ( k * width ) + j ] = = ' 1 ' ) {
set_module ( symbol , k , j ) ;
}
}
symbol - > row_height [ k ] = 1 ;
}
2016-08-07 22:11:51 +03:00
2016-08-26 17:13:40 +03:00
if ( ! ( symbol - > output_options & BARCODE_DOTTY_MODE ) ) {
symbol - > output_options + = BARCODE_DOTTY_MODE ;
}
2016-08-07 22:11:51 +03:00
2016-08-07 00:03:36 +03:00
return 0 ;
2017-09-10 18:03:09 +03:00
}
2017-10-23 22:37:52 +03:00