2019-11-25 22:08:25 +03:00
/* qr.c Handles QR Code, Micro QR Code, UPNQR and rMQR
2016-02-17 13:52:48 +03:00
libzint - the open source barcode library
2021-01-11 21:11:41 +03:00
Copyright ( C ) 2009 - 2021 Robin Stuart < rstuart114 @ gmail . com >
2016-02-17 13:52:48 +03:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
2016-02-20 14:29:19 +03:00
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2016-02-17 13:52:48 +03:00
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
2016-02-20 14:29:19 +03:00
documentation and / or other materials provided with the distribution .
2016-02-17 13:52:48 +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
2016-02-20 14:29:19 +03:00
without specific prior written permission .
2016-02-17 13:52:48 +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
2016-02-20 14:29:19 +03:00
OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
2016-02-17 13:52:48 +03:00
SUCH DAMAGE .
2016-02-20 14:29:19 +03:00
*/
2019-11-27 19:16:14 +03:00
/* vim: set ts=4 sw=4 et : */
2016-02-17 13:52:48 +03:00
2020-11-27 15:54:44 +03:00
# include <math.h>
2016-02-17 13:52:48 +03:00
# ifdef _MSC_VER
# include <malloc.h>
# endif
# include "common.h"
# include <stdio.h>
2021-01-11 21:11:41 +03:00
# include "eci.h"
2016-02-17 13:52:48 +03:00
# include "sjis.h"
# include "qr.h"
# include "reedsol.h"
2016-02-29 22:42:32 +03:00
# include <assert.h>
2016-02-17 13:52:48 +03:00
2021-07-06 14:13:34 +03:00
# define LEVEL_L 1
# define LEVEL_M 2
# define LEVEL_Q 3
# define LEVEL_H 4
# define QR_PERCENT 38 /* Alphanumeric mode % */
# define RMQR_VERSION 41
# define MICROQR_VERSION 73
2016-02-20 14:29:19 +03:00
/* Returns true if input glyph is in the Alphanumeric set */
2019-12-16 20:31:52 +03:00
static int is_alpha ( const unsigned int glyph , const int gs1 ) {
2016-02-20 14:29:19 +03:00
int retval = 0 ;
2016-02-17 13:52:48 +03:00
2019-11-27 19:16:14 +03:00
if ( ( glyph > = ' 0 ' ) & & ( glyph < = ' 9 ' ) ) {
2016-02-20 14:29:19 +03:00
retval = 1 ;
2019-12-16 20:31:52 +03:00
} else if ( ( glyph > = ' A ' ) & & ( glyph < = ' Z ' ) ) {
2016-02-20 14:29:19 +03:00
retval = 1 ;
2019-12-16 20:31:52 +03:00
} else if ( gs1 & & glyph = = ' [ ' ) {
retval = 1 ;
} else {
switch ( glyph ) {
case ' ' :
case ' $ ' :
case ' % ' :
case ' * ' :
case ' + ' :
case ' - ' :
case ' . ' :
case ' / ' :
case ' : ' :
retval = 1 ;
break ;
}
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
return retval ;
2016-02-17 13:52:48 +03:00
}
2019-12-16 20:31:52 +03:00
/* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */
# define QR_MULT 6
2016-02-17 13:52:48 +03:00
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 jisdata [ ] , const int length , const int in_posn ,
unsigned int * p_end , unsigned int * p_cost ) {
int i , digit_cnt ;
2019-12-16 20:31:52 +03:00
2020-11-27 15:54:44 +03:00
if ( in_posn < ( int ) * p_end ) {
2019-12-16 20:31:52 +03:00
return 1 ;
}
/* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times QR_MULT) */
2020-11-27 15:54:44 +03:00
for ( i = in_posn ; i < length & & i < in_posn + 4 & & jisdata [ i ] > = ' 0 ' & & jisdata [ i ] < = ' 9 ' ; i + + ) ;
2019-12-16 20:31:52 +03:00
2020-11-27 15:54:44 +03:00
digit_cnt = i - in_posn ;
2019-12-16 20:31:52 +03:00
if ( digit_cnt = = 0 ) {
* p_end = 0 ;
return 0 ;
}
* p_end = i ;
2021-06-19 15:11:23 +03:00
* p_cost = digit_cnt = = 1
? 24 /* 4 * QR_MULT */ : digit_cnt = = 2 ? 21 /* (7 / 2) * QR_MULT */ : 20 /* (10 / 3) * QR_MULT) */ ;
2019-12-16 20:31:52 +03:00
return 1 ;
}
2020-11-27 15:54:44 +03:00
/* Whether in alpha or not. If in alpha, *p_end is set to position after alpha, and *p_cost is set to per-alpha cost.
* For GS1 , * p_pcent set if 2 nd char percent */
static int in_alpha ( const unsigned int jisdata [ ] , const int length , const int in_posn ,
unsigned int * p_end , unsigned int * p_cost , unsigned int * p_pcent , unsigned int gs1 ) {
2019-12-16 20:31:52 +03:00
int two_alphas ;
2020-11-27 15:54:44 +03:00
if ( in_posn < ( int ) * p_end ) {
2019-12-16 20:31:52 +03:00
if ( gs1 & & * p_pcent ) {
/* Previous 2nd char was a percent, so allow for second half of doubled-up percent here */
2020-11-27 15:54:44 +03:00
two_alphas = in_posn < length - 1 & & is_alpha ( jisdata [ in_posn + 1 ] , gs1 ) ;
2019-12-16 20:31:52 +03:00
* p_cost = two_alphas ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */ ;
* p_pcent = 0 ;
2016-02-20 14:29:19 +03:00
}
2019-12-16 20:31:52 +03:00
return 1 ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2019-12-16 20:31:52 +03:00
/* Attempt to calculate the average 'cost' of using alphanumeric mode in number of bits (times QR_MULT) */
2020-11-27 15:54:44 +03:00
if ( ! is_alpha ( jisdata [ in_posn ] , gs1 ) ) {
2019-12-16 20:31:52 +03:00
* p_end = 0 ;
* p_pcent = 0 ;
return 0 ;
}
2020-11-27 15:54:44 +03:00
if ( gs1 & & jisdata [ in_posn ] = = ' % ' ) { /* Must double-up so counts as 2 chars */
* p_end = in_posn + 1 ;
2019-12-16 20:31:52 +03:00
* p_cost = 66 ; /* 11 * QR_MULT */
* p_pcent = 0 ;
return 1 ;
}
2020-11-27 15:54:44 +03:00
two_alphas = in_posn < length - 1 & & is_alpha ( jisdata [ in_posn + 1 ] , gs1 ) ;
2019-12-16 20:31:52 +03:00
2020-11-27 15:54:44 +03:00
* p_end = two_alphas ? in_posn + 2 : in_posn + 1 ;
2019-12-16 20:31:52 +03:00
* p_cost = two_alphas ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */ ;
2020-11-27 15:54:44 +03:00
* p_pcent = two_alphas & & gs1 & & jisdata [ in_posn + 1 ] = = ' % ' ; /* 2nd char is percent */
2019-12-16 20:31:52 +03:00
return 1 ;
}
/* Indexes into mode_types array (and state array) */
# define QR_N 0 /* Numeric */
# define QR_A 1 /* Alphanumeric */
# define QR_B 2 /* Byte */
# define QR_K 3 /* Kanji */
2020-09-30 14:19:12 +03:00
static const char mode_types [ ] = { ' N ' , ' A ' , ' B ' , ' K ' , ' \0 ' } ; /* Must be in same order as QR_N etc */
2019-12-16 20:31:52 +03:00
# define QR_NUM_MODES 4
/* Indexes into state array (0..3 head costs) */
# define QR_VER 4 /* Version */
2020-11-27 15:54:44 +03:00
# define QR_N_END 5 /* Numeric end index */
# define QR_N_COST 6 /* Numeric cost */
# define QR_A_END 7 /* Alpha end index */
# define QR_A_COST 8 /* Alpha cost */
# define QR_A_PCENT 9 /* Alpha 2nd char percent (GS1-specific) */
2019-12-16 20:31:52 +03:00
/* Costs set to this for invalid MICROQR modes for versions M1 and M2.
* 128 is the max number of data bits for M4 - L ( ISO / IEC 18004 : 2015 Table 7 ) */
# define QR_MICROQR_MAX 774 /* (128 + 1) * QR_MULT */
/* Initial mode costs */
2020-11-27 15:54:44 +03:00
static unsigned int * qr_head_costs ( unsigned int state [ 10 ] ) {
static const unsigned int head_costs [ 7 ] [ QR_NUM_MODES ] = {
2019-12-16 20:31:52 +03:00
/* N A B K */
{ ( 10 + 4 ) * QR_MULT , ( 9 + 4 ) * QR_MULT , ( 8 + 4 ) * QR_MULT , ( 8 + 4 ) * QR_MULT , } , /* QR */
{ ( 12 + 4 ) * QR_MULT , ( 11 + 4 ) * QR_MULT , ( 16 + 4 ) * QR_MULT , ( 10 + 4 ) * QR_MULT , } ,
{ ( 14 + 4 ) * QR_MULT , ( 13 + 4 ) * QR_MULT , ( 16 + 4 ) * QR_MULT , ( 12 + 4 ) * QR_MULT , } ,
{ 3 * QR_MULT , QR_MICROQR_MAX , QR_MICROQR_MAX , QR_MICROQR_MAX , } , /* MICROQR */
{ ( 4 + 1 ) * QR_MULT , ( 3 + 1 ) * QR_MULT , QR_MICROQR_MAX , QR_MICROQR_MAX , } ,
{ ( 5 + 2 ) * QR_MULT , ( 4 + 2 ) * QR_MULT , ( 4 + 2 ) * QR_MULT , ( 3 + 2 ) * QR_MULT , } ,
{ ( 6 + 3 ) * QR_MULT , ( 5 + 3 ) * QR_MULT , ( 5 + 3 ) * QR_MULT , ( 4 + 3 ) * QR_MULT , }
} ;
int version ;
/* Head costs kept in states 0..3 */
version = state [ QR_VER ] ;
if ( version < RMQR_VERSION ) { /* QRCODE */
if ( version < 10 ) {
2020-11-27 15:54:44 +03:00
memcpy ( state , head_costs [ 0 ] , QR_NUM_MODES * sizeof ( unsigned int ) ) ;
2019-12-16 20:31:52 +03:00
} else if ( version < 27 ) {
2020-11-27 15:54:44 +03:00
memcpy ( state , head_costs [ 1 ] , QR_NUM_MODES * sizeof ( unsigned int ) ) ;
2019-12-16 20:31:52 +03:00
} else {
2020-11-27 15:54:44 +03:00
memcpy ( state , head_costs [ 2 ] , QR_NUM_MODES * sizeof ( unsigned int ) ) ;
2016-02-20 14:29:19 +03:00
}
2019-12-16 20:31:52 +03:00
} else if ( version < MICROQR_VERSION ) { /* RMQR */
version - = RMQR_VERSION ;
state [ QR_N ] = ( rmqr_numeric_cci [ version ] + 3 ) * QR_MULT ;
state [ QR_A ] = ( rmqr_alphanum_cci [ version ] + 3 ) * QR_MULT ;
state [ QR_B ] = ( rmqr_byte_cci [ version ] + 3 ) * QR_MULT ;
state [ QR_K ] = ( rmqr_kanji_cci [ version ] + 3 ) * QR_MULT ;
} else { /* MICROQR */
2020-11-27 15:54:44 +03:00
memcpy ( state , head_costs [ 3 + ( version - MICROQR_VERSION ) ] , QR_NUM_MODES * sizeof ( unsigned int ) ) ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2019-12-16 20:31:52 +03:00
return state ;
}
2020-11-27 15:54:44 +03:00
/* Calculate optimized encoding modes. Adapted from Project Nayuki */
static void qr_define_mode ( char mode [ ] , const unsigned int jisdata [ ] , const int length , const int gs1 ,
const int version , const int debug_print ) {
/*
* Copyright ( c ) Project Nayuki . ( MIT License )
* https : //www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted , free of charge , to any person obtaining a copy of
* this software and associated documentation files ( the " Software " ) , to deal in
* the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of
* the Software , and to permit persons to whom the Software is furnished to do so ,
* subject to the following conditions :
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*/
unsigned int state [ 10 ] = {
0 /*N*/ , 0 /*A*/ , 0 /*B*/ , 0 /*K*/ , /* Head/switch costs */
( unsigned int ) version ,
0 /*numeric_end*/ , 0 /*numeric_cost*/ , 0 /*alpha_end*/ , 0 /*alpha_cost*/ , 0 /*alpha_pcent*/
} ;
int m1 , m2 ;
2019-12-16 20:31:52 +03:00
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 [ QR_NUM_MODES ] ;
unsigned int cur_costs [ QR_NUM_MODES ] ;
# ifndef _MSC_VER
char char_modes [ length * QR_NUM_MODES ] ;
# else
char * char_modes = ( char * ) _alloca ( length * QR_NUM_MODES ) ;
# endif
/* char_modes[i * QR_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 * QR_NUM_MODES ) ;
/* At the beginning of each iteration of the loop below, prev_costs[j] is the minimum number of 1/6 (1/QR_MULT)
* bits needed to encode the entire string prefix of length i , and end in mode_types [ j ] */
memcpy ( prev_costs , qr_head_costs ( state ) , QR_NUM_MODES * sizeof ( unsigned int ) ) ;
/* Calculate costs using dynamic programming */
for ( i = 0 , cm_i = 0 ; i < length ; i + + , cm_i + = QR_NUM_MODES ) {
memset ( cur_costs , 0 , QR_NUM_MODES * sizeof ( unsigned int ) ) ;
m1 = version = = MICROQR_VERSION ;
m2 = version = = MICROQR_VERSION + 1 ;
if ( jisdata [ i ] > 0xFF ) {
cur_costs [ QR_B ] = prev_costs [ QR_B ] + ( ( m1 | | m2 ) ? QR_MICROQR_MAX : 96 ) ; /* 16 * QR_MULT */
char_modes [ cm_i + QR_B ] = ' B ' ;
cur_costs [ QR_K ] = prev_costs [ QR_K ] + ( ( m1 | | m2 ) ? QR_MICROQR_MAX : 78 ) ; /* 13 * QR_MULT */
char_modes [ cm_i + QR_K ] = ' K ' ;
} else {
if ( in_numeric ( jisdata , length , i , & state [ QR_N_END ] , & state [ QR_N_COST ] ) ) {
cur_costs [ QR_N ] = prev_costs [ QR_N ] + state [ QR_N_COST ] ;
char_modes [ cm_i + QR_N ] = ' N ' ;
}
if ( in_alpha ( jisdata , length , i , & state [ QR_A_END ] , & state [ QR_A_COST ] , & state [ QR_A_PCENT ] , gs1 ) ) {
cur_costs [ QR_A ] = prev_costs [ QR_A ] + ( m1 ? QR_MICROQR_MAX : state [ QR_A_COST ] ) ;
char_modes [ cm_i + QR_A ] = ' A ' ;
}
cur_costs [ QR_B ] = prev_costs [ QR_B ] + ( ( m1 | | m2 ) ? QR_MICROQR_MAX : 48 ) ; /* 8 * QR_MULT */
char_modes [ cm_i + QR_B ] = ' B ' ;
}
/* Start new segment at the end to switch modes */
for ( j = 0 ; j < QR_NUM_MODES ; j + + ) { /* To mode */
for ( k = 0 ; k < QR_NUM_MODES ; k + + ) { /* From mode */
if ( j ! = k & & char_modes [ cm_i + k ] ) {
unsigned int new_cost = cur_costs [ k ] + state [ j ] ; /* Switch costs same as head costs */
if ( ! char_modes [ cm_i + j ] | | new_cost < cur_costs [ j ] ) {
cur_costs [ j ] = new_cost ;
char_modes [ cm_i + j ] = mode_types [ k ] ;
}
}
}
2019-12-16 20:31:52 +03:00
}
2020-11-27 15:54:44 +03:00
memcpy ( prev_costs , cur_costs , QR_NUM_MODES * sizeof ( unsigned int ) ) ;
}
/* Find optimal ending mode */
min_cost = prev_costs [ 0 ] ;
cur_mode = mode_types [ 0 ] ;
for ( i = 1 ; i < QR_NUM_MODES ; i + + ) {
if ( prev_costs [ i ] < min_cost ) {
min_cost = prev_costs [ i ] ;
cur_mode = mode_types [ i ] ;
2016-02-20 14:29:19 +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 * QR_NUM_MODES ; i > = 0 ; i - - , cm_i - = QR_NUM_MODES ) {
j = strchr ( mode_types , cur_mode ) - mode_types ;
cur_mode = char_modes [ cm_i + j ] ;
mode [ i ] = cur_mode ;
}
if ( debug_print ) {
printf ( " Mode: %.*s \n " , length , mode ) ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
}
2020-11-27 15:54:44 +03:00
/* Returns mode indicator based on version and mode */
static int mode_indicator ( const int version , const int mode ) {
static const int mode_indicators [ 6 ] [ QR_NUM_MODES ] = {
/*N A B K */
{ 1 , 2 , 4 , 8 , } , /* QRCODE */
{ 1 , 2 , 3 , 4 , } , /* RMQR */
{ 0 , 0 , 0 , 0 , } , /* MICROQR */
{ 0 , 1 , 0 , 0 , } ,
{ 0 , 1 , 2 , 3 , } ,
{ 0 , 1 , 2 , 3 , } ,
2019-12-16 20:31:52 +03:00
} ;
2017-06-06 23:11:11 +03:00
2020-11-27 15:54:44 +03:00
int mode_index = strchr ( mode_types , mode ) - mode_types ;
if ( version < RMQR_VERSION ) {
return mode_indicators [ 0 ] [ mode_index ] ; /* QRCODE */
}
if ( version < MICROQR_VERSION ) {
return mode_indicators [ 1 ] [ mode_index ] /* RMQR */ ;
}
return mode_indicators [ 2 + version - MICROQR_VERSION ] [ mode_index ] ; /* MICROQR */
2019-12-16 20:31:52 +03:00
}
2017-06-06 23:11:11 +03:00
2019-12-16 20:31:52 +03:00
/* Return mode indicator bits based on version */
static int mode_bits ( const int version ) {
if ( version < RMQR_VERSION ) {
return 4 ; /* QRCODE */
2017-06-06 23:11:11 +03:00
}
2019-12-16 20:31:52 +03:00
if ( version < MICROQR_VERSION ) {
return 3 ; /* RMQR */
}
return version - MICROQR_VERSION ; /* MICROQR */
}
/* Return character count indicator bits based on version and mode */
static int cci_bits ( const int version , const int mode ) {
2019-12-19 03:37:55 +03:00
static const int cci_bits [ 7 ] [ QR_NUM_MODES ] = {
2019-12-16 20:31:52 +03:00
/* N A B K */
{ 10 , 9 , 8 , 8 , } , /* QRCODE */
{ 12 , 11 , 16 , 10 , } ,
{ 14 , 13 , 16 , 12 , } ,
{ 3 , 0 , 0 , 0 , } , /* MICROQR */
{ 4 , 3 , 0 , 0 , } ,
{ 5 , 4 , 4 , 3 , } ,
{ 6 , 5 , 5 , 4 , }
} ;
2020-11-27 15:54:44 +03:00
static const unsigned short int * rmqr_ccis [ QR_NUM_MODES ] = {
2019-12-16 20:31:52 +03:00
rmqr_numeric_cci , rmqr_alphanum_cci , rmqr_byte_cci , rmqr_kanji_cci ,
} ;
int mode_index = strchr ( mode_types , mode ) - mode_types ;
if ( version < RMQR_VERSION ) { /* QRCODE */
if ( version < 10 ) {
return cci_bits [ 0 ] [ mode_index ] ;
}
if ( version < 27 ) {
return cci_bits [ 1 ] [ mode_index ] ;
}
return cci_bits [ 2 ] [ mode_index ] ;
}
if ( version < MICROQR_VERSION ) { /* RMQR */
return rmqr_ccis [ mode_index ] [ version - RMQR_VERSION ] ;
}
return cci_bits [ 3 + ( version - MICROQR_VERSION ) ] [ mode_index ] ; /* MICROQR */
}
/* Returns terminator bits based on version */
static int terminator_bits ( const int version ) {
if ( version < RMQR_VERSION ) {
return 4 ; /* QRCODE */
}
if ( version < MICROQR_VERSION ) {
return 3 ; /* RMQR */
}
return 3 + ( version - MICROQR_VERSION ) * 2 ; /* MICROQR (Note not actually using this at the moment) */
2016-02-17 13:52:48 +03:00
}
2016-02-20 14:29:19 +03:00
/* Convert input data to a binary stream and add padding */
2020-11-27 15:54:44 +03:00
static void qr_binary ( unsigned char datastream [ ] , const int version , const int target_codewords , const char mode [ ] ,
const unsigned int jisdata [ ] , const int length , const int gs1 , const int eci , const int est_binlen ,
const int debug_print ) {
int position = 0 ;
int i , j , bp ;
int termbits , padbits , modebits ;
int current_bytes ;
2016-02-20 14:29:19 +03:00
int toggle , percent ;
2018-06-21 01:07:48 +03:00
int percent_count ;
2016-02-17 13:52:48 +03:00
# ifndef _MSC_VER
2016-02-20 14:29:19 +03:00
char binary [ est_binlen + 12 ] ;
2016-02-17 13:52:48 +03:00
# else
2021-06-19 15:11:23 +03:00
char * binary = ( char * ) _alloca ( est_binlen + 12 ) ;
2016-02-17 13:52:48 +03:00
# endif
2020-11-27 15:54:44 +03:00
* binary = ' \0 ' ;
bp = 0 ;
2016-02-17 13:52:48 +03:00
2019-12-16 20:31:52 +03:00
if ( gs1 ) { /* Not applicable to MICROQR */
2019-11-25 22:08:25 +03:00
if ( version < RMQR_VERSION ) {
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 5 , 4 , binary , bp ) ; /* FNC1 */
2019-11-25 22:08:25 +03:00
} else {
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 5 , 3 , binary , bp ) ;
2019-11-25 22:08:25 +03:00
}
2016-02-20 14:29:19 +03:00
}
2017-10-23 22:37:52 +03:00
2019-12-16 20:31:52 +03:00
if ( eci ! = 0 ) { /* Not applicable to RMQR or MICROQR */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 7 , 4 , binary , bp ) ; /* ECI (Table 4) */
2017-06-06 23:11:11 +03:00
if ( eci < = 127 ) {
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( eci , 8 , binary , bp ) ; /* 000000 to 000127 */
2017-06-06 23:11:11 +03:00
} else if ( eci < = 16383 ) {
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 0x8000 + eci , 16 , binary , bp ) ; /* 000128 to 016383 */
2017-06-06 23:11:11 +03:00
} else {
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 0xC00000 + eci , 24 , binary , bp ) ; /* 016384 to 999999 */
2017-06-06 23:11:11 +03:00
}
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
percent = 0 ;
2020-11-27 15:54:44 +03:00
modebits = mode_bits ( version ) ;
2016-02-20 14:29:19 +03:00
do {
2017-09-10 18:03:09 +03:00
char data_block = mode [ position ] ;
int short_data_block_length = 0 ;
2019-11-27 19:16:14 +03:00
int double_byte = 0 ;
2016-02-20 14:29:19 +03:00
do {
2019-11-27 19:16:14 +03:00
if ( data_block = = ' B ' & & jisdata [ position + short_data_block_length ] > 0xFF ) {
double_byte + + ;
}
2016-02-20 14:29:19 +03:00
short_data_block_length + + ;
2016-03-03 00:12:38 +03:00
} while ( ( ( short_data_block_length + position ) < length )
2016-02-20 14:29:19 +03:00
& & ( mode [ position + short_data_block_length ] = = data_block ) ) ;
2020-11-27 15:54:44 +03:00
/* Mode indicator */
if ( modebits ) {
bp = bin_append_posn ( mode_indicator ( version , data_block ) , modebits , binary , bp ) ;
}
2016-02-20 14:29:19 +03:00
switch ( data_block ) {
case ' K ' :
/* Kanji mode */
/* Character count indicator */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( short_data_block_length , cci_bits ( version , data_block ) , binary , bp ) ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2016-02-20 14:29:19 +03:00
printf ( " Kanji block (length %d) \n \t " , short_data_block_length ) ;
}
/* Character representation */
for ( i = 0 ; i < short_data_block_length ; i + + ) {
2019-11-27 19:16:14 +03:00
unsigned int jis = jisdata [ position + i ] ;
2017-04-21 21:54:35 +03:00
int prod ;
2017-10-23 22:37:52 +03:00
2017-04-21 21:54:35 +03:00
if ( jis > = 0x8140 & & jis < = 0x9ffc )
jis - = 0x8140 ;
2017-10-23 22:37:52 +03:00
2017-04-21 21:54:35 +03:00
else if ( jis > = 0xe040 & & jis < = 0xebbf )
2016-02-20 14:29:19 +03:00
jis - = 0xc140 ;
2017-10-23 22:37:52 +03:00
2017-04-21 21:54:35 +03:00
prod = ( ( jis > > 8 ) * 0xc0 ) + ( jis & 0xff ) ;
2017-10-23 22:37:52 +03:00
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( prod , 13 , binary , bp ) ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2019-12-16 20:31:52 +03:00
printf ( " 0x%04X " , prod ) ;
2016-02-18 15:17:50 +03:00
}
}
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2016-02-20 14:29:19 +03:00
printf ( " \n " ) ;
2016-02-18 15:17:50 +03:00
}
2016-02-20 14:29:19 +03:00
break ;
case ' B ' :
/* Byte mode */
/* Character count indicator */
2021-06-19 15:11:23 +03:00
bp = bin_append_posn ( short_data_block_length + double_byte , cci_bits ( version , data_block ) , binary ,
bp ) ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2019-11-27 19:16:14 +03:00
printf ( " Byte block (length %d) \n \t " , short_data_block_length + double_byte ) ;
2016-02-17 23:31:50 +03:00
}
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
/* Character representation */
for ( i = 0 ; i < short_data_block_length ; i + + ) {
2019-11-27 19:16:14 +03:00
unsigned int byte = jisdata [ position + i ] ;
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
if ( gs1 & & ( byte = = ' [ ' ) ) {
byte = 0x1d ; /* FNC1 */
}
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( byte , byte > 0xFF ? 16 : 8 , binary , bp ) ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2021-07-06 14:13:34 +03:00
printf ( " 0x%02X(%d) " , byte , ( int ) byte ) ;
2016-02-17 23:31:50 +03:00
}
}
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2016-02-20 14:29:19 +03:00
printf ( " \n " ) ;
}
break ;
case ' A ' :
/* Alphanumeric mode */
2018-06-21 01:07:48 +03:00
percent_count = 0 ;
2019-12-16 20:31:52 +03:00
if ( gs1 ) {
for ( i = 0 ; i < short_data_block_length ; i + + ) {
if ( jisdata [ position + i ] = = ' % ' ) {
percent_count + + ;
}
2018-06-21 01:07:48 +03:00
}
}
2019-11-27 19:16:14 +03:00
2016-02-20 14:29:19 +03:00
/* Character count indicator */
2021-06-19 15:11:23 +03:00
bp = bin_append_posn ( short_data_block_length + percent_count , cci_bits ( version , data_block ) , binary ,
bp ) ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2018-06-21 01:07:48 +03:00
printf ( " Alpha block (length %d) \n \t " , short_data_block_length + percent_count ) ;
2016-02-20 14:29:19 +03:00
}
/* Character representation */
i = 0 ;
while ( i < short_data_block_length ) {
int count ;
int first = 0 , second = 0 , prod ;
if ( percent = = 0 ) {
if ( gs1 & & ( jisdata [ position + i ] = = ' % ' ) ) {
2020-11-27 15:54:44 +03:00
first = QR_PERCENT ;
second = QR_PERCENT ;
2016-02-20 14:29:19 +03:00
count = 2 ;
prod = ( first * 45 ) + second ;
i + + ;
2016-02-17 23:31:50 +03:00
} else {
2016-02-20 14:29:19 +03:00
if ( gs1 & & ( jisdata [ position + i ] = = ' [ ' ) ) {
2020-11-27 15:54:44 +03:00
first = QR_PERCENT ; /* FNC1 */
2016-02-17 23:31:50 +03:00
} else {
2020-11-27 15:54:44 +03:00
first = qr_alphanumeric [ jisdata [ position + i ] - 32 ] ;
2016-02-20 14:29:19 +03:00
}
count = 1 ;
i + + ;
prod = first ;
if ( i < short_data_block_length & & mode [ position + i ] = = ' A ' ) {
if ( gs1 & & ( jisdata [ position + i ] = = ' % ' ) ) {
2020-11-27 15:54:44 +03:00
second = QR_PERCENT ;
2016-02-20 14:29:19 +03:00
count = 2 ;
prod = ( first * 45 ) + second ;
percent = 1 ;
} else {
if ( gs1 & & ( jisdata [ position + i ] = = ' [ ' ) ) {
2020-11-27 15:54:44 +03:00
second = QR_PERCENT ; /* FNC1 */
2016-02-20 14:29:19 +03:00
} else {
2020-11-27 15:54:44 +03:00
second = qr_alphanumeric [ jisdata [ position + i ] - 32 ] ;
2016-02-20 14:29:19 +03:00
}
count = 2 ;
i + + ;
prod = ( first * 45 ) + second ;
}
2016-02-17 23:31:50 +03:00
}
}
2016-02-20 14:29:19 +03:00
} else {
2020-11-27 15:54:44 +03:00
first = QR_PERCENT ;
2016-02-20 14:29:19 +03:00
count = 1 ;
i + + ;
prod = first ;
percent = 0 ;
if ( i < short_data_block_length & & mode [ position + i ] = = ' A ' ) {
if ( gs1 & & ( jisdata [ position + i ] = = ' % ' ) ) {
2020-11-27 15:54:44 +03:00
second = QR_PERCENT ;
2016-02-20 14:29:19 +03:00
count = 2 ;
prod = ( first * 45 ) + second ;
percent = 1 ;
2016-02-17 23:31:50 +03:00
} else {
2016-02-20 14:29:19 +03:00
if ( gs1 & & ( jisdata [ position + i ] = = ' [ ' ) ) {
2020-11-27 15:54:44 +03:00
second = QR_PERCENT ; /* FNC1 */
2016-02-20 14:29:19 +03:00
} else {
2020-11-27 15:54:44 +03:00
second = qr_alphanumeric [ jisdata [ position + i ] - 32 ] ;
2016-02-20 14:29:19 +03:00
}
count = 2 ;
i + + ;
prod = ( first * 45 ) + second ;
2016-02-17 23:31:50 +03:00
}
}
}
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( prod , 1 + ( 5 * count ) , binary , bp ) ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2019-12-16 20:31:52 +03:00
printf ( " 0x%X " , prod ) ;
2016-02-17 23:31:50 +03:00
}
2019-12-16 20:31:52 +03:00
}
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2016-02-20 14:29:19 +03:00
printf ( " \n " ) ;
2016-02-17 23:31:50 +03:00
}
2016-02-20 14:29:19 +03:00
break ;
case ' N ' :
/* Numeric mode */
/* Character count indicator */
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( short_data_block_length , cci_bits ( version , data_block ) , binary , bp ) ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2016-02-20 14:29:19 +03:00
printf ( " Number block (length %d) \n \t " , short_data_block_length ) ;
2016-02-17 23:31:50 +03:00
}
2016-02-20 14:29:19 +03:00
/* Character representation */
i = 0 ;
while ( i < short_data_block_length ) {
int count ;
2017-09-10 18:03:09 +03:00
int first = 0 , prod ;
2016-02-20 14:29:19 +03:00
first = posn ( NEON , ( char ) jisdata [ position + i ] ) ;
count = 1 ;
prod = first ;
if ( i + 1 < short_data_block_length & & mode [ position + i + 1 ] = = ' N ' ) {
2017-09-10 18:03:09 +03:00
int second = posn ( NEON , ( char ) jisdata [ position + i + 1 ] ) ;
2016-02-20 14:29:19 +03:00
count = 2 ;
prod = ( prod * 10 ) + second ;
if ( i + 2 < short_data_block_length & & mode [ position + i + 2 ] = = ' N ' ) {
2017-09-10 18:03:09 +03:00
int third = posn ( NEON , ( char ) jisdata [ position + i + 2 ] ) ;
2016-02-20 14:29:19 +03:00
count = 3 ;
prod = ( prod * 10 ) + third ;
2016-02-17 23:31:50 +03:00
}
}
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( prod , 1 + ( 3 * count ) , binary , bp ) ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2019-12-16 20:31:52 +03:00
printf ( " 0x%X(%d) " , prod , prod ) ;
2016-02-17 23:31:50 +03:00
}
2016-02-20 14:29:19 +03:00
i + = count ;
} ;
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2016-02-20 14:29:19 +03:00
printf ( " \n " ) ;
2016-02-17 23:31:50 +03:00
}
2016-02-20 14:29:19 +03:00
break ;
2016-02-17 23:31:50 +03:00
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
position + = short_data_block_length ;
} while ( position < length ) ;
2016-02-17 13:52:48 +03:00
2019-12-16 20:31:52 +03:00
if ( version > = MICROQR_VERSION & & version < MICROQR_VERSION + 4 ) {
/* MICROQR does its own terminating/padding */
2020-11-27 15:54:44 +03:00
binary [ bp ] = ' \0 ' ;
2021-06-19 15:11:23 +03:00
ustrcpy ( datastream , binary ) ;
2019-12-16 20:31:52 +03:00
return ;
2019-11-25 22:08:25 +03:00
}
2016-02-17 13:52:48 +03:00
2019-12-16 20:31:52 +03:00
/* Terminator */
2020-11-27 15:54:44 +03:00
termbits = 8 - bp % 8 ;
2019-12-16 20:31:52 +03:00
if ( termbits = = 8 ) {
termbits = 0 ;
}
2020-11-27 15:54:44 +03:00
current_bytes = ( bp + termbits ) / 8 ;
2019-12-16 20:31:52 +03:00
if ( termbits | | current_bytes < target_codewords ) {
int max_termbits = terminator_bits ( version ) ;
termbits = termbits < max_termbits & & current_bytes = = target_codewords ? termbits : max_termbits ;
2020-11-27 15:54:44 +03:00
bp = bin_append_posn ( 0 , termbits , binary , bp ) ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
/* Padding bits */
2020-11-27 15:54:44 +03:00
padbits = 8 - bp % 8 ;
2019-12-16 20:31:52 +03:00
if ( padbits = = 8 ) {
padbits = 0 ;
}
if ( padbits ) {
2020-11-27 15:54:44 +03:00
current_bytes = ( bp + padbits ) / 8 ;
( void ) bin_append_posn ( 0 , padbits , binary , bp ) ; /* Last use so not setting bp */
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
/* Put data into 8-bit codewords */
for ( i = 0 ; i < current_bytes ; i + + ) {
2016-02-24 10:42:15 +03:00
int p ;
2020-11-27 15:54:44 +03:00
j = i * 8 ;
2016-02-20 14:29:19 +03:00
datastream [ i ] = 0x00 ;
2016-02-24 10:42:15 +03:00
for ( p = 0 ; p < 8 ; p + + ) {
2020-11-27 15:54:44 +03:00
if ( binary [ j + p ] = = ' 1 ' ) {
datastream [ i ] | = ( 0x80 > > p ) ;
2016-02-20 14:29:19 +03:00
}
}
}
/* Add pad codewords */
toggle = 0 ;
2019-11-25 22:08:25 +03:00
for ( i = current_bytes ; i < target_codewords ; i + + ) {
2016-02-20 14:29:19 +03:00
if ( toggle = = 0 ) {
datastream [ i ] = 0xec ;
toggle = 1 ;
} else {
datastream [ i ] = 0x11 ;
toggle = 0 ;
}
}
2016-02-17 13:52:48 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2016-02-20 14:29:19 +03:00
printf ( " Resulting codewords: \n \t " ) ;
2019-11-25 22:08:25 +03:00
for ( i = 0 ; i < target_codewords ; i + + ) {
2019-12-16 20:31:52 +03:00
printf ( " 0x%02X " , datastream [ i ] ) ;
2016-02-20 14:29:19 +03:00
}
printf ( " \n " ) ;
}
2016-02-17 13:52:48 +03:00
}
2016-02-20 14:29:19 +03:00
/* Split data into blocks, add error correction and then interleave the blocks and error correction data */
2021-06-19 15:11:23 +03:00
static void add_ecc ( unsigned char fullstream [ ] , const unsigned char datastream [ ] , const int version ,
const int data_cw , const int blocks , const int debug_print ) {
2019-11-25 22:08:25 +03:00
int ecc_cw ;
2019-12-05 21:19:37 +03:00
int short_data_block_length ;
int qty_long_blocks ;
int qty_short_blocks ;
int ecc_block_length ;
2020-11-27 15:54:44 +03:00
int i , j , length_this_block , in_posn ;
rs_t rs ;
2019-12-05 21:19:37 +03:00
# ifdef _MSC_VER
2021-06-19 15:11:23 +03:00
unsigned char * data_block ;
unsigned char * ecc_block ;
unsigned char * interleaved_data ;
unsigned char * interleaved_ecc ;
2019-12-05 21:19:37 +03:00
# endif
2019-11-25 22:08:25 +03:00
if ( version < RMQR_VERSION ) {
ecc_cw = qr_total_codewords [ version - 1 ] - data_cw ;
} else {
ecc_cw = rmqr_total_codewords [ version - RMQR_VERSION ] - data_cw ;
}
2019-12-05 21:36:00 +03:00
short_data_block_length = data_cw / blocks ;
qty_long_blocks = data_cw % blocks ;
qty_short_blocks = blocks - qty_long_blocks ;
ecc_block_length = ecc_cw / blocks ;
2020-07-19 12:31:12 +03:00
/* Suppress some clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult/uninitialized.Assign warnings */
assert ( short_data_block_length > = 0 ) ;
assert ( ecc_block_length * blocks = = ecc_cw ) ;
2016-02-20 14:29:19 +03:00
2016-02-17 13:52:48 +03:00
# ifndef _MSC_VER
2020-04-28 23:10:54 +03:00
unsigned char data_block [ short_data_block_length + 1 ] ;
unsigned char ecc_block [ ecc_block_length ] ;
unsigned char interleaved_data [ data_cw ] ;
unsigned char interleaved_ecc [ ecc_cw ] ;
2016-02-17 13:52:48 +03:00
# else
2020-04-28 23:10:54 +03:00
data_block = ( unsigned char * ) _alloca ( short_data_block_length + 1 ) ;
ecc_block = ( unsigned char * ) _alloca ( ecc_block_length ) ;
interleaved_data = ( unsigned char * ) _alloca ( data_cw ) ;
interleaved_ecc = ( unsigned char * ) _alloca ( ecc_cw ) ;
2016-02-17 13:52:48 +03:00
# endif
2020-11-27 15:54:44 +03:00
rs_init_gf ( & rs , 0x11d ) ;
rs_init_code ( & rs , ecc_block_length , 0 ) ;
in_posn = 0 ;
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
for ( i = 0 ; i < blocks ; i + + ) {
if ( i < qty_short_blocks ) {
length_this_block = short_data_block_length ;
} else {
length_this_block = short_data_block_length + 1 ;
}
for ( j = 0 ; j < ecc_block_length ; j + + ) {
ecc_block [ j ] = 0 ;
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
for ( j = 0 ; j < length_this_block ; j + + ) {
2020-11-27 15:54:44 +03:00
data_block [ j ] = datastream [ in_posn + j ] ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2020-11-27 15:54:44 +03:00
rs_encode ( & rs , length_this_block , data_block , ecc_block ) ;
2016-02-17 13:52:48 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2016-02-20 14:29:19 +03:00
printf ( " Block %d: " , i + 1 ) ;
for ( j = 0 ; j < length_this_block ; j + + ) {
printf ( " %2X " , data_block [ j ] ) ;
}
if ( i < qty_short_blocks ) {
printf ( " " ) ;
}
printf ( " // " ) ;
for ( j = 0 ; j < ecc_block_length ; j + + ) {
printf ( " %2X " , ecc_block [ ecc_block_length - j - 1 ] ) ;
}
printf ( " \n " ) ;
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
for ( j = 0 ; j < short_data_block_length ; j + + ) {
2019-11-27 19:16:14 +03:00
interleaved_data [ ( j * blocks ) + i ] = data_block [ j ] ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
if ( i > = qty_short_blocks ) {
2021-06-19 15:11:23 +03:00
interleaved_data [ ( short_data_block_length * blocks ) + ( i - qty_short_blocks ) ]
= data_block [ short_data_block_length ] ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
for ( j = 0 ; j < ecc_block_length ; j + + ) {
2019-11-27 19:16:14 +03:00
interleaved_ecc [ ( j * blocks ) + i ] = ecc_block [ ecc_block_length - j - 1 ] ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2020-11-27 15:54:44 +03:00
in_posn + = length_this_block ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
for ( j = 0 ; j < data_cw ; j + + ) {
2021-06-19 15:11:23 +03:00
// NOLINTNEXTLINE suppress clang-tidy warning: interleaved_data[data_cw] fully set
fullstream [ j ] = interleaved_data [ j ] ;
2016-02-20 14:29:19 +03:00
}
for ( j = 0 ; j < ecc_cw ; j + + ) {
2021-06-19 15:11:23 +03:00
// NOLINTNEXTLINE suppress clang-tidy warning: interleaved_ecc[ecc_cw] fully set
fullstream [ j + data_cw ] = interleaved_ecc [ j ] ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2016-02-20 14:29:19 +03:00
printf ( " \n Data Stream: \n " ) ;
for ( j = 0 ; j < ( data_cw + ecc_cw ) ; j + + ) {
printf ( " %2X " , fullstream [ j ] ) ;
}
printf ( " \n " ) ;
}
2016-02-17 13:52:48 +03:00
}
2020-11-27 15:54:44 +03:00
static void place_finder ( unsigned char grid [ ] , const int size , const int x , const int y ) {
2016-02-20 14:29:19 +03:00
int xp , yp ;
2017-08-07 10:37:02 +03:00
char finder [ ] = { 0x7F , 0x41 , 0x5D , 0x5D , 0x5D , 0x41 , 0x7F } ;
2017-10-23 22:37:52 +03:00
2016-02-20 14:29:19 +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-02-20 14:29:19 +03:00
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x11 ;
} else {
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x10 ;
}
}
}
2016-02-17 13:52:48 +03:00
}
2020-11-27 15:54:44 +03:00
static void place_align ( unsigned char grid [ ] , const int size , int x , int y ) {
2016-02-20 14:29:19 +03:00
int xp , yp ;
2017-08-07 10:37:02 +03:00
char alignment [ ] = { 0x1F , 0x11 , 0x15 , 0x11 , 0x1F } ;
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
x - = 2 ;
y - = 2 ; /* Input values represent centre of pattern */
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
for ( xp = 0 ; xp < 5 ; xp + + ) {
for ( yp = 0 ; yp < 5 ; yp + + ) {
2017-08-07 10:37:02 +03:00
if ( alignment [ yp ] & 0x10 > > xp ) {
2016-02-20 14:29:19 +03:00
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x11 ;
} else {
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x10 ;
}
}
2016-02-18 15:17:50 +03:00
}
}
2020-11-27 15:54:44 +03:00
static void setup_grid ( unsigned char * grid , const int size , const int version ) {
2016-02-20 14:29:19 +03:00
int i , toggle = 1 ;
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
/* Add timing patterns */
for ( i = 0 ; i < size ; i + + ) {
if ( toggle = = 1 ) {
grid [ ( 6 * size ) + i ] = 0x21 ;
grid [ ( i * size ) + 6 ] = 0x21 ;
toggle = 0 ;
} else {
grid [ ( 6 * size ) + i ] = 0x20 ;
grid [ ( i * size ) + 6 ] = 0x20 ;
toggle = 1 ;
2016-02-18 15:17:50 +03:00
}
}
2016-02-20 14:29:19 +03:00
/* Add finder patterns */
place_finder ( grid , size , 0 , 0 ) ;
place_finder ( grid , size , 0 , size - 7 ) ;
place_finder ( grid , size , size - 7 , 0 ) ;
/* Add separators */
for ( i = 0 ; i < 7 ; i + + ) {
grid [ ( 7 * size ) + i ] = 0x10 ;
grid [ ( i * size ) + 7 ] = 0x10 ;
grid [ ( 7 * size ) + ( size - 1 - i ) ] = 0x10 ;
grid [ ( i * size ) + ( size - 8 ) ] = 0x10 ;
grid [ ( ( size - 8 ) * size ) + i ] = 0x10 ;
grid [ ( ( size - 1 - i ) * size ) + 7 ] = 0x10 ;
}
grid [ ( 7 * size ) + 7 ] = 0x10 ;
grid [ ( 7 * size ) + ( size - 8 ) ] = 0x10 ;
grid [ ( ( size - 8 ) * size ) + 7 ] = 0x10 ;
/* Add alignment patterns */
if ( version ! = 1 ) {
/* Version 1 does not have alignment patterns */
2017-09-10 18:03:09 +03:00
int loopsize = qr_align_loopsize [ version - 1 ] ;
int x , y ;
2016-02-20 14:29:19 +03:00
for ( x = 0 ; x < loopsize ; x + + ) {
for ( y = 0 ; y < loopsize ; y + + ) {
2017-09-10 18:03:09 +03:00
int xcoord = qr_table_e1 [ ( ( version - 2 ) * 7 ) + x ] ;
int ycoord = qr_table_e1 [ ( ( version - 2 ) * 7 ) + y ] ;
2016-02-20 14:29:19 +03:00
if ( ! ( grid [ ( ycoord * size ) + xcoord ] & 0x10 ) ) {
place_align ( grid , size , xcoord , ycoord ) ;
}
}
}
}
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
/* Reserve space for format information */
for ( i = 0 ; i < 8 ; i + + ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + i ] | = 0x20 ;
grid [ ( i * size ) + 8 ] | = 0x20 ;
2016-02-20 14:29:19 +03:00
grid [ ( 8 * size ) + ( size - 1 - i ) ] = 0x20 ;
grid [ ( ( size - 1 - i ) * size ) + 8 ] = 0x20 ;
}
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + 8 ] | = 0x20 ;
2016-02-20 14:29:19 +03:00
grid [ ( ( size - 1 - 7 ) * size ) + 8 ] = 0x21 ; /* Dark Module from Figure 25 */
/* Reserve space for version information */
if ( version > = 7 ) {
for ( i = 0 ; i < 6 ; i + + ) {
grid [ ( ( size - 9 ) * size ) + i ] = 0x20 ;
grid [ ( ( size - 10 ) * size ) + i ] = 0x20 ;
grid [ ( ( size - 11 ) * size ) + i ] = 0x20 ;
grid [ ( i * size ) + ( size - 9 ) ] = 0x20 ;
grid [ ( i * size ) + ( size - 10 ) ] = 0x20 ;
grid [ ( i * size ) + ( size - 11 ) ] = 0x20 ;
2016-02-18 15:17:50 +03:00
}
}
2016-02-20 14:29:19 +03:00
}
2016-02-18 15:17:50 +03:00
2021-06-19 15:11:23 +03:00
static int cwbit ( const unsigned char * fullstream , const int i ) {
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( fullstream [ ( i > > 3 ) ] & ( 0x80 > > ( i & 0x07 ) ) ) {
return 1 ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
return 0 ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
static void populate_grid ( unsigned char * grid , const int h_size , const int v_size , const unsigned char * fullstream ,
const int cw ) {
2016-02-20 14:29:19 +03:00
int direction = 1 ; /* up */
int row = 0 ; /* right hand side */
2017-09-10 18:03:09 +03:00
int i , n , y ;
2016-02-20 14:29:19 +03:00
n = cw * 8 ;
2019-11-25 22:08:25 +03:00
y = v_size - 1 ;
2016-02-20 14:29:19 +03:00
i = 0 ;
2020-04-28 23:10:54 +03:00
while ( i < n ) {
2019-11-25 22:08:25 +03:00
int x = ( h_size - 2 ) - ( row * 2 ) ;
2020-11-27 15:54:44 +03:00
int r = y * h_size ;
2019-11-27 19:16:14 +03:00
2019-11-25 22:08:25 +03:00
if ( ( x < 6 ) & & ( v_size = = h_size ) )
2016-02-20 14:29:19 +03:00
x - - ; /* skip over vertical timing pattern */
2020-11-27 15:54:44 +03:00
if ( ! ( grid [ r + ( x + 1 ) ] & 0xf0 ) ) {
grid [ r + ( x + 1 ) ] = cwbit ( fullstream , i ) ;
2016-02-20 14:29:19 +03:00
i + + ;
}
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
if ( i < n ) {
2020-11-27 15:54:44 +03:00
if ( ! ( grid [ r + x ] & 0xf0 ) ) {
grid [ r + x ] = cwbit ( fullstream , i ) ;
2016-02-20 14:29:19 +03:00
i + + ;
2016-02-18 15:17:50 +03:00
}
}
2016-02-20 14:29:19 +03:00
if ( direction ) {
y - - ;
2020-11-27 15:54:44 +03:00
if ( y = = - 1 ) {
/* reached the top */
row + + ;
y = 0 ;
direction = 0 ;
}
2016-02-20 14:29:19 +03:00
} else {
y + + ;
2020-11-27 15:54:44 +03:00
if ( y = = v_size ) {
/* reached the bottom */
row + + ;
y = v_size - 1 ;
direction = 1 ;
}
2016-02-20 14:29:19 +03:00
}
2020-04-28 23:10:54 +03:00
}
2016-02-20 14:29:19 +03:00
}
# ifdef ZINTLOG
2019-12-16 20:31:52 +03:00
static int append_log ( char log ) {
2016-02-20 14:29:19 +03:00
FILE * file ;
file = fopen ( " zintlog.txt " , " a+ " ) ;
fprintf ( file , " %c " , log ) ;
fclose ( file ) ;
return 0 ;
}
2019-12-16 20:31:52 +03:00
static int write_log ( char log [ ] ) {
2016-02-20 14:29:19 +03:00
FILE * file ;
file = fopen ( " zintlog.txt " , " a+ " ) ;
fprintf ( file , log ) ; /*writes*/
fprintf ( file , " \r \n " ) ; /*writes*/
fclose ( file ) ;
return 0 ;
}
# endif
2020-11-27 15:54:44 +03:00
static int evaluate ( unsigned char * local , const int size ) {
static const unsigned char h1011101 [ 7 ] = { 1 , 0 , 1 , 1 , 1 , 0 , 1 } ;
int x , y , r , k , block ;
2016-02-20 14:29:19 +03:00
int result = 0 ;
char state ;
int dark_mods ;
2020-11-27 15:54:44 +03:00
double percentage ;
2016-02-20 14:29:19 +03:00
int a , b , afterCount , beforeCount ;
# ifdef ZINTLOG
int result_b = 0 ;
char str [ 15 ] ;
# endif
2020-07-19 12:31:12 +03:00
/* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warnings */
assert ( size > 0 ) ;
2016-02-20 14:29:19 +03:00
# ifdef ZINTLOG
//bitmask output
for ( y = 0 ; y < size ; y + + ) {
strcpy ( str , " " ) ;
for ( x = 0 ; x < size ; x + + ) {
state = local [ ( y * size ) + x ] ;
append_log ( state ) ;
}
write_log ( " " ) ;
}
write_log ( " " ) ;
# endif
/* Test 1: Adjacent modules in row/column in same colour */
/* Vertical */
for ( x = 0 ; x < size ; x + + ) {
block = 0 ;
2020-11-27 15:54:44 +03:00
state = 0 ;
2016-02-20 14:29:19 +03:00
for ( y = 0 ; y < size ; y + + ) {
if ( local [ ( y * size ) + x ] = = state ) {
block + + ;
} else {
2020-11-27 15:54:44 +03:00
if ( block > = 5 ) {
result + = block - 2 ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
block = 1 ;
2016-02-20 14:29:19 +03:00
state = local [ ( y * size ) + x ] ;
}
}
2020-11-27 15:54:44 +03:00
if ( block > = 5 ) {
result + = block - 2 ;
2016-02-20 14:29:19 +03:00
}
}
/* Horizontal */
2020-12-10 22:48:52 +03:00
dark_mods = 0 ; /* Count dark mods simultaneously (see Test 4 below) */
2016-02-20 14:29:19 +03:00
for ( y = 0 ; y < size ; y + + ) {
2020-11-27 15:54:44 +03:00
r = y * size ;
2016-02-20 14:29:19 +03:00
block = 0 ;
2020-11-27 15:54:44 +03:00
state = 0 ;
2016-02-20 14:29:19 +03:00
for ( x = 0 ; x < size ; x + + ) {
2020-11-27 15:54:44 +03:00
if ( local [ r + x ] = = state ) {
2016-02-20 14:29:19 +03:00
block + + ;
} else {
2020-11-27 15:54:44 +03:00
if ( block > = 5 ) {
result + = block - 2 ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
block = 1 ;
state = local [ r + x ] ;
2016-02-20 14:29:19 +03:00
}
2020-12-10 22:48:52 +03:00
if ( state ) {
dark_mods + + ;
}
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
if ( block > = 5 ) {
result + = block - 2 ;
2016-02-20 14:29:19 +03:00
}
}
# ifdef ZINTLOG
/* output Test 1 */
sprintf ( str , " %d " , result ) ;
result_b = result ;
write_log ( str ) ;
# endif
/* Test 2: Block of modules in same color */
for ( x = 0 ; x < size - 1 ; x + + ) {
for ( y = 0 ; y < size - 1 ; y + + ) {
2020-11-27 15:54:44 +03:00
k = local [ ( y * size ) + x ] ;
if ( ( ( k = = local [ ( ( y + 1 ) * size ) + x ] ) & &
( k = = local [ ( y * size ) + ( x + 1 ) ] ) ) & &
( k = = local [ ( ( y + 1 ) * size ) + ( x + 1 ) ] ) ) {
2016-02-20 14:29:19 +03:00
result + = 3 ;
}
}
}
# ifdef ZINTLOG
/* output Test 2 */
sprintf ( str , " %d " , result - result_b ) ;
result_b = result ;
write_log ( str ) ;
# endif
/* Test 3: 1:1:3:1:1 ratio pattern in row/column */
/* 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 + 2 ) * size + x ] & &
local [ ( y + 3 ) * size + x ] & & local [ ( y + 4 ) * size + x ] & &
! local [ ( y + 5 ) * size + x ] & & local [ ( y + 6 ) * size + x ] ) {
2016-02-20 14:29:19 +03:00
/* Pattern found, check before and after */
beforeCount = 0 ;
2020-11-27 15:54:44 +03:00
for ( b = ( y - 1 ) ; b > = ( y - 4 ) ; b - - ) {
if ( b < 0 ) { /* Count < edge as whitespace */
beforeCount = 4 ;
break ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
if ( local [ ( b * size ) + x ] ) {
break ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
beforeCount + + ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
if ( beforeCount = = 4 ) {
/* Pattern is preceded by light area 4 modules wide */
2016-02-20 14:29:19 +03:00
result + = 40 ;
2020-11-27 15:54:44 +03:00
} else {
afterCount = 0 ;
for ( a = ( y + 7 ) ; a < = ( y + 10 ) ; a + + ) {
if ( a > = size ) { /* Count > edge as whitespace */
afterCount = 4 ;
break ;
}
if ( local [ ( a * size ) + x ] ) {
break ;
}
afterCount + + ;
}
if ( afterCount = = 4 ) {
/* Pattern is followed by light area 4 modules wide */
result + = 40 ;
}
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
y + = 3 ; /* Skip to next possible match */
2016-02-20 14:29:19 +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 , h1011101 , 7 ) = = 0 ) {
2016-02-20 14:29:19 +03:00
/* Pattern found, check before and after */
beforeCount = 0 ;
2020-11-27 15:54:44 +03:00
for ( b = ( x - 1 ) ; b > = ( x - 4 ) ; b - - ) {
if ( b < 0 ) { /* Count < edge as whitespace */
beforeCount = 4 ;
break ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
if ( local [ r + b ] ) {
break ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
beforeCount + + ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
if ( beforeCount = = 4 ) {
/* Pattern is preceded by light area 4 modules wide */
2016-02-20 14:29:19 +03:00
result + = 40 ;
2020-11-27 15:54:44 +03:00
} else {
afterCount = 0 ;
for ( a = ( x + 7 ) ; a < = ( x + 10 ) ; a + + ) {
if ( a > = size ) { /* Count > edge as whitespace */
afterCount = 4 ;
break ;
}
if ( local [ r + a ] ) {
break ;
}
afterCount + + ;
}
if ( afterCount = = 4 ) {
/* Pattern is followed by light area 4 modules wide */
result + = 40 ;
}
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
x + = 3 ; /* Skip to next possible match */
2016-02-20 14:29:19 +03:00
}
}
}
# ifdef ZINTLOG
/* output Test 3 */
sprintf ( str , " %d " , result - result_b ) ;
result_b = result ;
write_log ( str ) ;
# endif
/* Test 4: Proportion of dark modules in entire symbol */
2020-11-27 15:54:44 +03:00
percentage = ( 100.0 * dark_mods ) / ( size * size ) ;
2020-12-10 22:48:52 +03:00
k = ( int ) ( fabs ( percentage - 50.0 ) / 5.0 ) ;
2016-02-20 14:29:19 +03:00
result + = 10 * k ;
# ifdef ZINTLOG
/* output Test 4+summary */
sprintf ( str , " %d " , result - result_b ) ;
write_log ( str ) ;
write_log ( " ========== " ) ;
sprintf ( str , " %d " , result ) ;
write_log ( str ) ;
# endif
return result ;
}
2020-11-27 15:54:44 +03:00
/* Add format information to grid */
static void add_format_info ( unsigned char * grid , const int size , const int ecc_level , const int pattern ) {
2016-02-20 14:29:19 +03:00
int format = pattern ;
unsigned int seq ;
int i ;
switch ( ecc_level ) {
2020-11-27 15:54:44 +03:00
case LEVEL_L : format | = 0x08 ;
2016-02-20 14:29:19 +03:00
break ;
2020-11-27 15:54:44 +03:00
case LEVEL_Q : format | = 0x18 ;
2016-02-20 14:29:19 +03:00
break ;
2020-11-27 15:54:44 +03:00
case LEVEL_H : format | = 0x10 ;
2016-02-20 14:29:19 +03:00
break ;
}
seq = qr_annex_c [ format ] ;
for ( i = 0 ; i < 6 ; i + + ) {
2020-11-27 15:54:44 +03:00
grid [ ( i * size ) + 8 ] | = ( seq > > i ) & 0x01 ;
2016-02-20 14:29:19 +03:00
}
for ( i = 0 ; i < 8 ; i + + ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + ( size - i - 1 ) ] | = ( seq > > i ) & 0x01 ;
2016-02-20 14:29:19 +03:00
}
for ( i = 0 ; i < 6 ; i + + ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + ( 5 - i ) ] | = ( seq > > ( i + 9 ) ) & 0x01 ;
2016-02-20 14:29:19 +03:00
}
for ( i = 0 ; i < 7 ; i + + ) {
2020-11-27 15:54:44 +03:00
grid [ ( ( ( size - 7 ) + i ) * size ) + 8 ] | = ( seq > > ( i + 8 ) ) & 0x01 ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
grid [ ( 7 * size ) + 8 ] | = ( seq > > 6 ) & 0x01 ;
grid [ ( 8 * size ) + 8 ] | = ( seq > > 7 ) & 0x01 ;
grid [ ( 8 * size ) + 7 ] | = ( seq > > 8 ) & 0x01 ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
static int apply_bitmask ( unsigned char * grid , const int size , const int ecc_level , const int user_mask ,
const int debug_print ) {
2016-02-20 14:29:19 +03:00
int x , y ;
2020-11-27 15:54:44 +03:00
int r , k ;
int bit ;
2016-02-20 14:29:19 +03:00
int pattern , penalty [ 8 ] ;
2020-11-27 15:54:44 +03:00
int best_pattern ;
int size_squared = size * size ;
2016-02-20 14:29:19 +03:00
# ifndef _MSC_VER
2020-11-27 15:54:44 +03:00
unsigned char mask [ size_squared ] ;
unsigned char local [ size_squared ] ;
2016-02-20 14:29:19 +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-02-20 14:29:19 +03:00
# endif
/* 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 + + ) {
2016-02-20 14:29:19 +03:00
// all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array.
2020-11-27 15:54:44 +03:00
if ( ! ( grid [ r + x ] & 0xf0 ) ) { // exclude areas not to be masked.
2016-02-20 14:29:19 +03:00
if ( ( ( y + x ) & 1 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( ( y & 1 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x02 ;
2016-02-20 14:29:19 +03:00
}
if ( ( x % 3 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x04 ;
2016-02-20 14:29:19 +03:00
}
if ( ( ( y + x ) % 3 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x08 ;
2016-02-20 14:29:19 +03:00
}
if ( ( ( ( y / 2 ) + ( x / 3 ) ) & 1 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x10 ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
if ( ( y * x ) % 6 = = 0 ) { /* Equivalent to (y * x) % 2 + (y * x) % 3 == 0 */
mask [ r + x ] | = 0x20 ;
2016-02-20 14:29:19 +03:00
}
if ( ( ( ( ( y * x ) & 1 ) + ( ( y * x ) % 3 ) ) & 1 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x40 ;
2016-02-20 14:29:19 +03:00
}
if ( ( ( ( ( y + x ) & 1 ) + ( ( y * x ) % 3 ) ) & 1 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x80 ;
2016-02-20 14:29:19 +03:00
}
}
}
}
2020-11-27 15:54:44 +03:00
if ( user_mask ) {
best_pattern = user_mask - 1 ;
} else {
/* all eight bitmask variants have been encoded in the 8 bits of the bytes
* that make up the mask array . select them for evaluation according to the
* desired pattern . */
best_pattern = 0 ;
for ( pattern = 0 ; pattern < 8 ; 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 ;
}
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
add_format_info ( local , size , ecc_level , pattern ) ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
penalty [ pattern ] = evaluate ( local , size ) ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
if ( penalty [ pattern ] < penalty [ best_pattern ] ) {
best_pattern = pattern ;
}
}
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
printf ( " Mask: %d (%s) " , best_pattern , user_mask ? " specified " : " automatic " ) ;
if ( ! user_mask ) {
for ( pattern = 0 ; pattern < 8 ; pattern + + ) printf ( " %d:%d " , pattern , penalty [ pattern ] ) ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
printf ( " \n " ) ;
2016-02-20 14:29:19 +03:00
}
# ifdef ZINTLOG
char str [ 15 ] ;
sprintf ( str , " %d " , best_val ) ;
write_log ( " choosed pattern: " ) ;
write_log ( str ) ;
# endif
/* Apply mask */
2020-11-27 15:54:44 +03:00
if ( ! user_mask & & best_pattern = = 7 ) { /* Reuse last */
memcpy ( grid , local , size_squared ) ;
} else {
bit = 1 < < best_pattern ;
for ( y = 0 ; y < size_squared ; y + + ) {
if ( mask [ y ] & bit ) {
grid [ y ] ^ = 0x01 ;
2016-02-20 14:29:19 +03:00
}
}
}
return best_pattern ;
}
/* Add version information */
2020-11-27 15:54:44 +03:00
static void add_version_info ( unsigned char * grid , const int size , const int version ) {
2016-02-20 14:29:19 +03:00
int i ;
long int version_data = qr_annex_d [ version - 7 ] ;
for ( i = 0 ; i < 6 ; i + + ) {
grid [ ( ( size - 11 ) * size ) + i ] + = ( version_data > > ( i * 3 ) ) & 0x41 ;
grid [ ( ( size - 10 ) * size ) + i ] + = ( version_data > > ( ( i * 3 ) + 1 ) ) & 0x41 ;
grid [ ( ( size - 9 ) * size ) + i ] + = ( version_data > > ( ( i * 3 ) + 2 ) ) & 0x41 ;
grid [ ( i * size ) + ( size - 11 ) ] + = ( version_data > > ( i * 3 ) ) & 0x41 ;
grid [ ( i * size ) + ( size - 10 ) ] + = ( version_data > > ( ( i * 3 ) + 1 ) ) & 0x41 ;
grid [ ( i * size ) + ( size - 9 ) ] + = ( version_data > > ( ( i * 3 ) + 2 ) ) & 0x41 ;
}
}
2020-11-27 15:54:44 +03:00
static int blockLength ( const int start , const char inputMode [ ] , const int inputLength ) {
2016-02-20 14:29:19 +03:00
/* Find the length of the block starting from 'start' */
2020-11-27 15:54:44 +03:00
int i ;
2017-05-29 12:43:47 +03:00
int count ;
2016-02-20 14:29:19 +03:00
char mode = inputMode [ start ] ;
count = 0 ;
i = start ;
do {
count + + ;
} while ( ( ( i + count ) < inputLength ) & & ( inputMode [ i + count ] = = mode ) ) ;
return count ;
}
2020-11-27 15:54:44 +03:00
static int getBinaryLength ( const int version , char inputMode [ ] , const unsigned int inputData [ ] , const int inputLength ,
const int gs1 , const int eci , const int debug_print ) {
2016-02-20 14:29:19 +03:00
/* Calculate the actual bitlength of the proposed binary string */
2020-11-27 15:54:44 +03:00
int i , j ;
2016-02-20 14:29:19 +03:00
char currentMode ;
int count = 0 ;
2018-06-20 05:38:50 +03:00
int alphalength ;
2019-12-16 20:31:52 +03:00
int blocklength ;
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
qr_define_mode ( inputMode , inputData , inputLength , gs1 , version , debug_print ) ;
2016-02-20 14:29:19 +03:00
currentMode = ' ' ; // Null
2019-12-16 20:31:52 +03:00
if ( gs1 = = 1 ) { /* Not applicable to MICROQR */
2019-11-25 22:08:25 +03:00
if ( version < RMQR_VERSION ) {
count + = 4 ;
} else {
count + = 3 ;
}
2016-02-20 14:29:19 +03:00
}
2017-10-23 22:37:52 +03:00
2019-12-16 20:31:52 +03:00
if ( eci ! = 0 ) { // RMQR and MICROQR do not support ECI
2019-11-27 19:16:14 +03:00
count + = 4 ;
if ( eci < = 127 ) {
count + = 8 ;
} else if ( eci < = 16383 ) {
count + = 16 ;
} else {
count + = 24 ;
}
2016-08-16 14:43:41 +03:00
}
2016-02-20 14:29:19 +03:00
for ( i = 0 ; i < inputLength ; i + + ) {
if ( inputMode [ i ] ! = currentMode ) {
2019-12-16 20:31:52 +03:00
count + = mode_bits ( version ) + cci_bits ( version , inputMode [ i ] ) ;
blocklength = blockLength ( i , inputMode , inputLength ) ;
2016-02-20 14:29:19 +03:00
switch ( inputMode [ i ] ) {
case ' K ' :
2019-12-16 20:31:52 +03:00
count + = ( blocklength * 13 ) ;
2016-02-20 14:29:19 +03:00
break ;
case ' B ' :
2019-12-16 20:31:52 +03:00
for ( j = i ; j < ( i + blocklength ) ; j + + ) {
2016-02-20 14:29:19 +03:00
if ( inputData [ j ] > 0xff ) {
count + = 16 ;
} else {
count + = 8 ;
}
}
break ;
case ' A ' :
2019-12-16 20:31:52 +03:00
alphalength = blocklength ;
if ( gs1 ) {
// In alphanumeric mode % becomes %%
for ( j = i ; j < ( i + blocklength ) ; j + + ) {
if ( inputData [ j ] = = ' % ' ) {
alphalength + + ;
}
2018-06-20 05:38:50 +03:00
}
}
switch ( alphalength % 2 ) {
2016-02-20 14:29:19 +03:00
case 0 :
2018-06-20 05:38:50 +03:00
count + = ( alphalength / 2 ) * 11 ;
2016-02-20 14:29:19 +03:00
break ;
case 1 :
2018-06-20 05:38:50 +03:00
count + = ( ( alphalength - 1 ) / 2 ) * 11 ;
2016-02-20 14:29:19 +03:00
count + = 6 ;
break ;
}
break ;
case ' N ' :
2019-12-16 20:31:52 +03:00
switch ( blocklength % 3 ) {
2016-02-20 14:29:19 +03:00
case 0 :
2019-12-16 20:31:52 +03:00
count + = ( blocklength / 3 ) * 10 ;
2016-02-20 14:29:19 +03:00
break ;
case 1 :
2019-12-16 20:31:52 +03:00
count + = ( ( blocklength - 1 ) / 3 ) * 10 ;
2016-02-20 14:29:19 +03:00
count + = 4 ;
break ;
case 2 :
2019-12-16 20:31:52 +03:00
count + = ( ( blocklength - 2 ) / 3 ) * 10 ;
2016-02-20 14:29:19 +03:00
count + = 7 ;
break ;
}
break ;
}
currentMode = inputMode [ i ] ;
}
}
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2019-12-16 20:31:52 +03:00
printf ( " Estimated Binary Length: %d (version %d, eci %d, gs1 %d) \n " , count , version , eci , gs1 ) ;
2019-11-27 19:16:14 +03:00
}
2019-12-16 20:31:52 +03:00
return count ;
2019-11-27 19:16:14 +03:00
}
2020-11-27 15:54:44 +03:00
INTERNAL int qr_code ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) {
int i , j , est_binlen , prev_est_binlen ;
2019-11-25 22:08:25 +03:00
int ecc_level , autosize , version , max_cw , target_codewords , blocks , size ;
2016-02-20 14:29:19 +03:00
int bitmask , gs1 ;
2020-04-02 16:41:13 +03:00
int full_multibyte ;
2020-11-27 15:54:44 +03:00
int user_mask ;
2016-02-20 14:29:19 +03:00
int canShrink ;
2020-11-27 15:54:44 +03:00
int size_squared ;
int debug_print = symbol - > debug & ZINT_DEBUG_PRINT ;
2021-01-11 21:11:41 +03:00
int eci_length = get_eci_length ( symbol - > eci , source , length ) ;
2016-02-20 14:29:19 +03:00
# ifndef _MSC_VER
2021-01-11 21:11:41 +03:00
unsigned int jisdata [ eci_length + 1 ] ;
char mode [ eci_length ] ;
char prev_mode [ eci_length ] ;
2016-02-20 14:29:19 +03:00
# else
2021-01-11 21:11:41 +03:00
unsigned char * datastream ;
unsigned char * fullstream ;
unsigned char * grid ;
unsigned int * jisdata = ( unsigned int * ) _alloca ( ( eci_length + 1 ) * sizeof ( unsigned int ) ) ;
char * mode = ( char * ) _alloca ( eci_length ) ;
char * prev_mode = ( char * ) _alloca ( eci_length ) ;
2016-02-20 14:29:19 +03:00
# endif
2019-11-27 19:16:14 +03:00
gs1 = ( ( symbol - > input_mode & 0x07 ) = = GS1_MODE ) ;
2021-01-11 21:11:41 +03:00
/* If ZINT_FULL_MULTIBYTE use Kanji mode in DATA_MODE or for non-Shift JIS 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 <= 8 */
if ( user_mask > 8 ) {
user_mask = 0 ; /* Ignore */
}
2016-02-20 14:29:19 +03:00
2019-11-27 19:16:14 +03:00
if ( ( symbol - > input_mode & 0x07 ) = = DATA_MODE ) {
2020-04-02 16:41:13 +03:00
sjis_cpy ( source , & length , jisdata , full_multibyte ) ;
2016-08-16 14:43:41 +03:00
} else {
2019-11-27 19:16:14 +03:00
int done = 0 ;
if ( symbol - > eci ! = 20 ) { /* Unless ECI 20 (Shift JIS) */
2021-01-11 21:11:41 +03:00
/* Try other encodings (ECI 0 defaults to ISO/IEC 8859-1) */
int error_number = sjis_utf8_to_eci ( symbol - > eci , source , & length , jisdata , full_multibyte ) ;
2019-11-27 19:16:14 +03:00
if ( error_number = = 0 ) {
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 , " 575: Invalid character in input data for ECI %d " , symbol - > eci ) ;
2019-11-27 19:16:14 +03:00
return error_number ;
}
2016-08-16 14:43:41 +03:00
}
2019-11-27 19:16:14 +03:00
if ( ! done ) {
/* Try Shift-JIS */
2021-01-11 21:11:41 +03:00
int error_number = sjis_utf8 ( symbol , source , & length , jisdata ) ;
2019-11-27 19:16:14 +03:00
if ( error_number ! = 0 ) {
return error_number ;
2016-02-20 14:29:19 +03:00
}
2016-08-16 14:43:41 +03:00
}
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
est_binlen = getBinaryLength ( 40 , mode , jisdata , length , gs1 , symbol - > eci , debug_print ) ;
2016-02-20 14:29:19 +03:00
ecc_level = LEVEL_L ;
max_cw = 2956 ;
if ( ( symbol - > option_1 > = 1 ) & & ( symbol - > option_1 < = 4 ) ) {
switch ( symbol - > option_1 ) {
2019-12-16 20:31:52 +03:00
case 1 :
2016-02-20 14:29:19 +03:00
break ;
case 2 : ecc_level = LEVEL_M ;
max_cw = 2334 ;
break ;
case 3 : ecc_level = LEVEL_Q ;
max_cw = 1666 ;
break ;
case 4 : ecc_level = LEVEL_H ;
max_cw = 1276 ;
break ;
}
}
if ( est_binlen > ( 8 * max_cw ) ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 561: Input too long for selected error correction level " ) ;
2016-02-20 14:29:19 +03:00
return ZINT_ERROR_TOO_LONG ;
}
autosize = 40 ;
for ( i = 39 ; i > = 0 ; i - - ) {
switch ( ecc_level ) {
case LEVEL_L :
if ( ( 8 * qr_data_codewords_L [ i ] ) > = est_binlen ) {
autosize = i + 1 ;
}
break ;
case LEVEL_M :
if ( ( 8 * qr_data_codewords_M [ i ] ) > = est_binlen ) {
autosize = i + 1 ;
}
break ;
case LEVEL_Q :
if ( ( 8 * qr_data_codewords_Q [ i ] ) > = est_binlen ) {
autosize = i + 1 ;
}
break ;
case LEVEL_H :
if ( ( 8 * qr_data_codewords_H [ i ] ) > = est_binlen ) {
autosize = i + 1 ;
}
break ;
}
}
2019-12-16 20:31:52 +03:00
if ( autosize ! = 40 ) {
2020-11-27 15:54:44 +03:00
est_binlen = getBinaryLength ( autosize , mode , jisdata , length , gs1 , symbol - > eci , debug_print ) ;
2019-12-16 20:31:52 +03:00
}
2016-02-20 14:29:19 +03:00
// Now see if the optimised binary will fit in a smaller symbol.
canShrink = 1 ;
do {
if ( autosize = = 1 ) {
canShrink = 0 ;
} else {
2020-11-27 15:54:44 +03:00
prev_est_binlen = est_binlen ;
memcpy ( prev_mode , mode , length ) ;
est_binlen = getBinaryLength ( autosize - 1 , mode , jisdata , length , gs1 , symbol - > eci , debug_print ) ;
2016-02-20 14:29:19 +03:00
switch ( ecc_level ) {
case LEVEL_L :
if ( ( 8 * qr_data_codewords_L [ autosize - 2 ] ) < est_binlen ) {
canShrink = 0 ;
}
break ;
case LEVEL_M :
if ( ( 8 * qr_data_codewords_M [ autosize - 2 ] ) < est_binlen ) {
canShrink = 0 ;
}
break ;
case LEVEL_Q :
if ( ( 8 * qr_data_codewords_Q [ autosize - 2 ] ) < est_binlen ) {
canShrink = 0 ;
}
break ;
case LEVEL_H :
if ( ( 8 * qr_data_codewords_H [ autosize - 2 ] ) < est_binlen ) {
canShrink = 0 ;
}
break ;
}
if ( canShrink = = 1 ) {
// Optimisation worked - data will fit in a smaller symbol
autosize - - ;
} else {
// Data did not fit in the smaller symbol, revert to original size
2020-11-27 15:54:44 +03:00
est_binlen = prev_est_binlen ;
memcpy ( mode , prev_mode , length ) ;
2016-02-20 14:29:19 +03:00
}
}
} while ( canShrink = = 1 ) ;
version = autosize ;
if ( ( symbol - > option_2 > = 1 ) & & ( symbol - > option_2 < = 40 ) ) {
/* If the user has selected a larger symbol than the smallest available,
then use the size the user has selected , and re - optimise for this
symbol size .
*/
if ( symbol - > option_2 > version ) {
version = symbol - > option_2 ;
2020-11-27 15:54:44 +03:00
est_binlen = getBinaryLength ( symbol - > option_2 , mode , jisdata , length , gs1 , symbol - > eci , debug_print ) ;
2016-02-20 14:29:19 +03:00
}
2017-10-23 22:37:52 +03:00
2017-04-11 11:26:39 +03:00
if ( symbol - > option_2 < version ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 569: Input too long for selected symbol size " ) ;
2017-04-11 11:26:39 +03:00
return ZINT_ERROR_TOO_LONG ;
}
2016-02-20 14:29:19 +03:00
}
2019-11-27 19:16:14 +03:00
2019-12-16 20:31:52 +03:00
/* Ensure maxium error correction capacity unless user-specified */
if ( symbol - > option_1 = = - 1 | | symbol - > option_1 ! = ecc_level ) {
if ( est_binlen < = qr_data_codewords_M [ version - 1 ] * 8 ) {
ecc_level = LEVEL_M ;
}
if ( est_binlen < = qr_data_codewords_Q [ version - 1 ] * 8 ) {
ecc_level = LEVEL_Q ;
}
if ( est_binlen < = qr_data_codewords_H [ version - 1 ] * 8 ) {
ecc_level = LEVEL_H ;
}
2016-02-20 14:29:19 +03:00
}
2019-11-25 22:08:25 +03:00
target_codewords = qr_data_codewords_L [ version - 1 ] ;
2016-02-20 14:29:19 +03:00
blocks = qr_blocks_L [ version - 1 ] ;
switch ( ecc_level ) {
2019-11-25 22:08:25 +03:00
case LEVEL_M : target_codewords = qr_data_codewords_M [ version - 1 ] ;
2016-02-20 14:29:19 +03:00
blocks = qr_blocks_M [ version - 1 ] ;
break ;
2019-11-25 22:08:25 +03:00
case LEVEL_Q : target_codewords = qr_data_codewords_Q [ version - 1 ] ;
2016-02-20 14:29:19 +03:00
blocks = qr_blocks_Q [ version - 1 ] ;
break ;
2019-11-25 22:08:25 +03:00
case LEVEL_H : target_codewords = qr_data_codewords_H [ version - 1 ] ;
2016-02-20 14:29:19 +03:00
blocks = qr_blocks_H [ version - 1 ] ;
break ;
}
# ifndef _MSC_VER
2019-12-01 18:17:08 +03:00
unsigned char datastream [ target_codewords + 1 ] ;
2019-11-27 19:16:14 +03:00
unsigned char fullstream [ qr_total_codewords [ version - 1 ] + 1 ] ;
2016-02-20 14:29:19 +03:00
# else
2019-12-01 18:17:08 +03:00
datastream = ( unsigned char * ) _alloca ( target_codewords + 1 ) ;
2019-11-27 19:16:14 +03:00
fullstream = ( unsigned char * ) _alloca ( qr_total_codewords [ version - 1 ] + 1 ) ;
2016-02-20 14:29:19 +03:00
# endif
2021-06-19 15:11:23 +03:00
qr_binary ( datastream , version , target_codewords , mode , jisdata , length , gs1 , symbol - > eci , est_binlen ,
debug_print ) ;
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 , target_codewords ) ;
2019-12-19 03:37:55 +03:00
# endif
2020-11-27 15:54:44 +03:00
add_ecc ( fullstream , datastream , version , target_codewords , blocks , debug_print ) ;
2016-02-20 14:29:19 +03:00
size = qr_sizes [ version - 1 ] ;
2020-11-27 15:54:44 +03:00
size_squared = size * size ;
2016-02-20 14:29:19 +03:00
# ifndef _MSC_VER
2020-11-27 15:54:44 +03:00
unsigned char grid [ size_squared ] ;
2016-02-20 14:29:19 +03:00
# else
2021-06-19 15:11:23 +03:00
grid = ( unsigned char * ) _alloca ( size_squared ) ;
2016-02-20 14:29:19 +03:00
# endif
2020-11-27 15:54:44 +03:00
memset ( grid , 0 , size_squared ) ;
2016-02-20 14:29:19 +03:00
setup_grid ( grid , size , version ) ;
2019-11-25 22:08:25 +03:00
populate_grid ( grid , size , size , fullstream , qr_total_codewords [ version - 1 ] ) ;
2016-02-20 14:29:19 +03:00
if ( version > = 7 ) {
add_version_info ( grid , size , version ) ;
}
2020-11-27 15:54:44 +03:00
bitmask = apply_bitmask ( grid , size , ecc_level , user_mask , debug_print ) ;
2016-02-20 14:29:19 +03:00
add_format_info ( grid , size , ecc_level , bitmask ) ;
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-02-20 14:29:19 +03:00
for ( j = 0 ; j < size ; j + + ) {
2020-11-27 15:54:44 +03:00
if ( grid [ r + j ] & 0x01 ) {
2016-02-20 14:29:19 +03:00
set_module ( symbol , i , j ) ;
}
}
symbol - > row_height [ i ] = 1 ;
}
2021-06-19 15:11:23 +03:00
symbol - > height = size ;
2016-02-20 14:29:19 +03:00
return 0 ;
}
2019-11-27 19:16:14 +03:00
static void micro_qr_m1 ( struct zint_symbol * symbol , char binary_data [ ] ) {
2016-09-17 20:22:26 +03:00
int i , j , latch ;
2017-09-10 18:03:09 +03:00
int bits_total , bits_left ;
2016-02-20 14:29:19 +03:00
int data_codewords , ecc_codewords ;
unsigned char data_blocks [ 4 ] , ecc_blocks [ 3 ] ;
2020-11-27 15:54:44 +03:00
rs_t rs ;
2016-02-20 14:29:19 +03:00
bits_total = 20 ;
latch = 0 ;
/* Add terminator */
2017-05-29 12:43:47 +03:00
bits_left = bits_total - ( int ) strlen ( binary_data ) ;
2016-02-20 14:29:19 +03:00
if ( bits_left < = 3 ) {
for ( i = 0 ; i < bits_left ; i + + ) {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 0 " ) ;
2016-02-20 14:29:19 +03:00
}
latch = 1 ;
} else {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 000 " ) ;
2016-02-20 14:29:19 +03:00
}
if ( latch = = 0 ) {
/* Manage last (4-bit) block */
2017-05-29 12:43:47 +03:00
bits_left = bits_total - ( int ) strlen ( binary_data ) ;
2016-02-20 14:29:19 +03:00
if ( bits_left < = 4 ) {
for ( i = 0 ; i < bits_left ; i + + ) {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 0 " ) ;
2016-02-20 14:29:19 +03:00
}
latch = 1 ;
}
}
if ( latch = = 0 ) {
/* Complete current byte */
2017-09-10 18:03:09 +03:00
int remainder = 8 - ( strlen ( binary_data ) % 8 ) ;
2016-02-20 14:29:19 +03:00
if ( remainder = = 8 ) {
remainder = 0 ;
}
for ( i = 0 ; i < remainder ; i + + ) {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 0 " ) ;
2016-02-20 14:29:19 +03:00
}
/* Add padding */
2017-05-29 12:43:47 +03:00
bits_left = bits_total - ( int ) strlen ( binary_data ) ;
2016-02-20 14:29:19 +03:00
if ( bits_left > 4 ) {
remainder = ( bits_left - 4 ) / 8 ;
for ( i = 0 ; i < remainder ; i + + ) {
2017-09-10 18:03:09 +03:00
strcat ( binary_data , ( i & 1 ) ? " 00010001 " : " 11101100 " ) ;
2016-02-20 14:29:19 +03:00
}
}
2017-06-06 23:31:03 +03:00
bin_append ( 0 , 4 , binary_data ) ;
2016-02-20 14:29:19 +03:00
}
data_codewords = 3 ;
ecc_codewords = 2 ;
/* Copy data into codewords */
for ( i = 0 ; i < ( data_codewords - 1 ) ; i + + ) {
data_blocks [ i ] = 0 ;
2016-09-17 20:22:26 +03:00
for ( j = 0 ; j < 8 ; j + + ) {
if ( binary_data [ ( i * 8 ) + j ] = = ' 1 ' ) {
2020-11-27 15:54:44 +03:00
data_blocks [ i ] | = 0x80 > > j ;
2016-09-17 20:22:26 +03:00
}
2016-02-20 14:29:19 +03:00
}
}
data_blocks [ 2 ] = 0 ;
2016-09-17 20:22:26 +03:00
for ( j = 0 ; j < 4 ; j + + ) {
if ( binary_data [ 16 + j ] = = ' 1 ' ) {
2020-11-27 15:54:44 +03:00
data_blocks [ 2 ] | = 0x80 > > j ;
2016-09-17 20:22:26 +03:00
}
2016-02-20 14:29:19 +03:00
}
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 , data_blocks , data_codewords ) ;
2020-03-30 13:59:16 +03:00
# else
( void ) symbol ; /* Unused */
2019-12-19 03:37:55 +03:00
# endif
2019-11-27 19:16:14 +03:00
2016-02-20 14:29:19 +03:00
/* Calculate Reed-Solomon error codewords */
2020-11-27 15:54:44 +03:00
rs_init_gf ( & rs , 0x11d ) ;
rs_init_code ( & rs , ecc_codewords , 0 ) ;
rs_encode ( & rs , data_codewords , data_blocks , ecc_blocks ) ;
2016-02-20 14:29:19 +03:00
/* Add Reed-Solomon codewords to binary data */
for ( i = 0 ; i < ecc_codewords ; i + + ) {
2017-06-06 23:11:11 +03:00
bin_append ( ecc_blocks [ ecc_codewords - i - 1 ] , 8 , binary_data ) ;
2016-02-20 14:29:19 +03:00
}
}
2019-11-27 19:16:14 +03:00
static void micro_qr_m2 ( struct zint_symbol * symbol , char binary_data [ ] , const int ecc_mode ) {
2016-09-17 20:22:26 +03:00
int i , j , latch ;
2017-09-10 18:03:09 +03:00
int bits_total = 0 , bits_left ;
2017-05-29 12:43:47 +03:00
int data_codewords = 0 , ecc_codewords = 0 ;
2016-02-20 14:29:19 +03:00
unsigned char data_blocks [ 6 ] , ecc_blocks [ 7 ] ;
2020-11-27 15:54:44 +03:00
rs_t rs ;
2016-02-20 14:29:19 +03:00
latch = 0 ;
if ( ecc_mode = = LEVEL_L ) {
bits_total = 40 ;
}
2017-05-29 12:43:47 +03:00
else if ( ecc_mode = = LEVEL_M ) {
2016-02-20 14:29:19 +03:00
bits_total = 32 ;
}
2017-05-29 12:43:47 +03:00
else assert ( 0 ) ;
2016-02-20 14:29:19 +03:00
/* Add terminator */
2017-05-29 12:43:47 +03:00
bits_left = bits_total - ( int ) strlen ( binary_data ) ;
2016-02-20 14:29:19 +03:00
if ( bits_left < = 5 ) {
for ( i = 0 ; i < bits_left ; i + + ) {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 0 " ) ;
2016-02-20 14:29:19 +03:00
}
latch = 1 ;
} else {
2017-06-06 23:31:03 +03:00
bin_append ( 0 , 5 , binary_data ) ;
2016-02-20 14:29:19 +03:00
}
if ( latch = = 0 ) {
/* Complete current byte */
2017-09-10 18:03:09 +03:00
int remainder = 8 - ( strlen ( binary_data ) % 8 ) ;
2016-02-20 14:29:19 +03:00
if ( remainder = = 8 ) {
remainder = 0 ;
}
for ( i = 0 ; i < remainder ; i + + ) {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 0 " ) ;
2016-02-20 14:29:19 +03:00
}
/* Add padding */
2017-05-29 12:43:47 +03:00
bits_left = bits_total - ( int ) strlen ( binary_data ) ;
2016-02-20 14:29:19 +03:00
remainder = bits_left / 8 ;
for ( i = 0 ; i < remainder ; i + + ) {
2017-09-10 18:03:09 +03:00
strcat ( binary_data , ( i & 1 ) ? " 00010001 " : " 11101100 " ) ;
2016-02-20 14:29:19 +03:00
}
}
if ( ecc_mode = = LEVEL_L ) {
data_codewords = 5 ;
ecc_codewords = 5 ;
}
2017-05-29 12:43:47 +03:00
else if ( ecc_mode = = LEVEL_M ) {
2016-02-20 14:29:19 +03:00
data_codewords = 4 ;
ecc_codewords = 6 ;
}
2017-05-29 12:43:47 +03:00
else assert ( 0 ) ;
2016-02-20 14:29:19 +03:00
/* Copy data into codewords */
for ( i = 0 ; i < data_codewords ; i + + ) {
data_blocks [ i ] = 0 ;
2017-10-23 22:37:52 +03:00
2016-09-17 20:22:26 +03:00
for ( j = 0 ; j < 8 ; j + + ) {
if ( binary_data [ ( i * 8 ) + j ] = = ' 1 ' ) {
2020-11-27 15:54:44 +03:00
data_blocks [ i ] | = 0x80 > > j ;
2016-09-17 20:22:26 +03:00
}
2016-02-20 14:29:19 +03:00
}
}
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 , data_blocks , data_codewords ) ;
2020-03-30 13:59:16 +03:00
# else
( void ) symbol ; /* Unused */
2019-12-19 03:37:55 +03:00
# endif
2019-11-27 19:16:14 +03:00
2016-02-20 14:29:19 +03:00
/* Calculate Reed-Solomon error codewords */
2020-11-27 15:54:44 +03:00
rs_init_gf ( & rs , 0x11d ) ;
rs_init_code ( & rs , ecc_codewords , 0 ) ;
rs_encode ( & rs , data_codewords , data_blocks , ecc_blocks ) ;
2016-02-20 14:29:19 +03:00
/* Add Reed-Solomon codewords to binary data */
for ( i = 0 ; i < ecc_codewords ; i + + ) {
2017-06-06 23:11:11 +03:00
bin_append ( ecc_blocks [ ecc_codewords - i - 1 ] , 8 , binary_data ) ;
2016-02-20 14:29:19 +03:00
}
return ;
}
2019-11-27 19:16:14 +03:00
static void micro_qr_m3 ( struct zint_symbol * symbol , char binary_data [ ] , const int ecc_mode ) {
2016-09-17 20:22:26 +03:00
int i , j , latch ;
2017-09-10 18:03:09 +03:00
int bits_total = 0 , bits_left ;
2017-05-29 12:43:47 +03:00
int data_codewords = 0 , ecc_codewords = 0 ;
2016-02-20 14:29:19 +03:00
unsigned char data_blocks [ 12 ] , ecc_blocks [ 9 ] ;
2020-11-27 15:54:44 +03:00
rs_t rs ;
2016-02-20 14:29:19 +03:00
latch = 0 ;
if ( ecc_mode = = LEVEL_L ) {
bits_total = 84 ;
}
2017-05-29 12:43:47 +03:00
else if ( ecc_mode = = LEVEL_M ) {
2016-02-20 14:29:19 +03:00
bits_total = 68 ;
}
2017-05-29 12:43:47 +03:00
else assert ( 0 ) ;
2016-02-20 14:29:19 +03:00
/* Add terminator */
2017-05-29 12:43:47 +03:00
bits_left = bits_total - ( int ) strlen ( binary_data ) ;
2016-02-20 14:29:19 +03:00
if ( bits_left < = 7 ) {
for ( i = 0 ; i < bits_left ; i + + ) {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 0 " ) ;
2016-02-20 14:29:19 +03:00
}
latch = 1 ;
} else {
2017-06-06 23:31:03 +03:00
bin_append ( 0 , 7 , binary_data ) ;
2016-02-20 14:29:19 +03:00
}
if ( latch = = 0 ) {
/* Manage last (4-bit) block */
2017-05-29 12:43:47 +03:00
bits_left = bits_total - ( int ) strlen ( binary_data ) ;
2016-02-20 14:29:19 +03:00
if ( bits_left < = 4 ) {
for ( i = 0 ; i < bits_left ; i + + ) {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 0 " ) ;
2016-02-20 14:29:19 +03:00
}
latch = 1 ;
}
}
if ( latch = = 0 ) {
/* Complete current byte */
2017-09-10 18:03:09 +03:00
int remainder = 8 - ( strlen ( binary_data ) % 8 ) ;
2016-02-20 14:29:19 +03:00
if ( remainder = = 8 ) {
remainder = 0 ;
}
for ( i = 0 ; i < remainder ; i + + ) {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 0 " ) ;
2016-02-20 14:29:19 +03:00
}
/* Add padding */
2017-05-29 12:43:47 +03:00
bits_left = bits_total - ( int ) strlen ( binary_data ) ;
2016-02-20 14:29:19 +03:00
if ( bits_left > 4 ) {
remainder = ( bits_left - 4 ) / 8 ;
for ( i = 0 ; i < remainder ; i + + ) {
2017-09-10 18:03:09 +03:00
strcat ( binary_data , ( i & 1 ) ? " 00010001 " : " 11101100 " ) ;
2016-02-20 14:29:19 +03:00
}
}
2017-06-06 23:31:03 +03:00
bin_append ( 0 , 4 , binary_data ) ;
2016-02-20 14:29:19 +03:00
}
if ( ecc_mode = = LEVEL_L ) {
data_codewords = 11 ;
ecc_codewords = 6 ;
}
2017-05-29 12:43:47 +03:00
else if ( ecc_mode = = LEVEL_M ) {
2016-02-20 14:29:19 +03:00
data_codewords = 9 ;
ecc_codewords = 8 ;
}
2017-05-29 12:43:47 +03:00
else assert ( 0 ) ;
2016-02-20 14:29:19 +03:00
/* Copy data into codewords */
for ( i = 0 ; i < ( data_codewords - 1 ) ; i + + ) {
data_blocks [ i ] = 0 ;
2017-10-23 22:37:52 +03:00
2016-09-17 20:22:26 +03:00
for ( j = 0 ; j < 8 ; j + + ) {
if ( binary_data [ ( i * 8 ) + j ] = = ' 1 ' ) {
2020-11-27 15:54:44 +03:00
data_blocks [ i ] | = 0x80 > > j ;
2016-09-17 20:22:26 +03:00
}
2016-02-20 14:29:19 +03:00
}
}
if ( ecc_mode = = LEVEL_L ) {
data_blocks [ 10 ] = 0 ;
2016-11-26 01:21:30 +03:00
for ( j = 0 ; j < 4 ; j + + ) {
if ( binary_data [ 80 + j ] = = ' 1 ' ) {
2020-11-27 15:54:44 +03:00
data_blocks [ 10 ] | = 0x80 > > j ;
2016-11-26 01:21:30 +03:00
}
2016-02-20 14:29:19 +03:00
}
}
if ( ecc_mode = = LEVEL_M ) {
data_blocks [ 8 ] = 0 ;
2016-11-26 01:21:30 +03:00
for ( j = 0 ; j < 4 ; j + + ) {
if ( binary_data [ 64 + j ] = = ' 1 ' ) {
2020-11-27 15:54:44 +03:00
data_blocks [ 8 ] | = 0x80 > > j ;
2016-11-26 01:21:30 +03:00
}
2016-02-20 14:29:19 +03:00
}
}
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 , data_blocks , data_codewords ) ;
2020-03-30 13:59:16 +03:00
# else
( void ) symbol ; /* Unused */
2019-12-19 03:37:55 +03:00
# endif
2019-11-27 19:16:14 +03:00
2016-02-20 14:29:19 +03:00
/* Calculate Reed-Solomon error codewords */
2020-11-27 15:54:44 +03:00
rs_init_gf ( & rs , 0x11d ) ;
rs_init_code ( & rs , ecc_codewords , 0 ) ;
rs_encode ( & rs , data_codewords , data_blocks , ecc_blocks ) ;
2016-02-20 14:29:19 +03:00
/* Add Reed-Solomon codewords to binary data */
for ( i = 0 ; i < ecc_codewords ; i + + ) {
2017-06-06 23:11:11 +03:00
bin_append ( ecc_blocks [ ecc_codewords - i - 1 ] , 8 , binary_data ) ;
2016-02-20 14:29:19 +03:00
}
return ;
}
2019-11-27 19:16:14 +03:00
static void micro_qr_m4 ( struct zint_symbol * symbol , char binary_data [ ] , const int ecc_mode ) {
2016-09-17 20:22:26 +03:00
int i , j , latch ;
2017-09-10 18:03:09 +03:00
int bits_total = 0 , bits_left ;
2017-05-29 12:43:47 +03:00
int data_codewords = 0 , ecc_codewords = 0 ;
2016-02-20 14:29:19 +03:00
unsigned char data_blocks [ 17 ] , ecc_blocks [ 15 ] ;
2020-11-27 15:54:44 +03:00
rs_t rs ;
2016-02-20 14:29:19 +03:00
latch = 0 ;
if ( ecc_mode = = LEVEL_L ) {
bits_total = 128 ;
}
2017-05-29 12:43:47 +03:00
else if ( ecc_mode = = LEVEL_M ) {
2016-02-20 14:29:19 +03:00
bits_total = 112 ;
}
2017-05-29 12:43:47 +03:00
else if ( ecc_mode = = LEVEL_Q ) {
2016-02-20 14:29:19 +03:00
bits_total = 80 ;
}
2017-05-29 12:43:47 +03:00
else assert ( 0 ) ;
2016-02-20 14:29:19 +03:00
/* Add terminator */
2017-05-29 12:43:47 +03:00
bits_left = bits_total - ( int ) strlen ( binary_data ) ;
2016-02-20 14:29:19 +03:00
if ( bits_left < = 9 ) {
for ( i = 0 ; i < bits_left ; i + + ) {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 0 " ) ;
2016-02-20 14:29:19 +03:00
}
latch = 1 ;
} else {
2017-06-06 23:31:03 +03:00
bin_append ( 0 , 9 , binary_data ) ;
2016-02-20 14:29:19 +03:00
}
if ( latch = = 0 ) {
/* Complete current byte */
2017-09-10 18:03:09 +03:00
int remainder = 8 - ( strlen ( binary_data ) % 8 ) ;
2016-02-20 14:29:19 +03:00
if ( remainder = = 8 ) {
remainder = 0 ;
}
for ( i = 0 ; i < remainder ; i + + ) {
2016-03-03 00:12:38 +03:00
strcat ( binary_data , " 0 " ) ;
2016-02-20 14:29:19 +03:00
}
/* Add padding */
2017-05-29 12:43:47 +03:00
bits_left = bits_total - ( int ) strlen ( binary_data ) ;
2016-02-20 14:29:19 +03:00
remainder = bits_left / 8 ;
for ( i = 0 ; i < remainder ; i + + ) {
2017-09-10 18:03:09 +03:00
strcat ( binary_data , ( i & 1 ) ? " 00010001 " : " 11101100 " ) ;
2016-02-20 14:29:19 +03:00
}
}
if ( ecc_mode = = LEVEL_L ) {
data_codewords = 16 ;
ecc_codewords = 8 ;
}
2017-05-29 12:43:47 +03:00
else if ( ecc_mode = = LEVEL_M ) {
2016-02-20 14:29:19 +03:00
data_codewords = 14 ;
ecc_codewords = 10 ;
}
2017-05-29 12:43:47 +03:00
else if ( ecc_mode = = LEVEL_Q ) {
2016-02-20 14:29:19 +03:00
data_codewords = 10 ;
ecc_codewords = 14 ;
}
2017-05-29 12:43:47 +03:00
else assert ( 0 ) ;
2016-02-20 14:29:19 +03:00
/* Copy data into codewords */
for ( i = 0 ; i < data_codewords ; i + + ) {
data_blocks [ i ] = 0 ;
2017-10-23 22:37:52 +03:00
2016-09-17 20:22:26 +03:00
for ( j = 0 ; j < 8 ; j + + ) {
if ( binary_data [ ( i * 8 ) + j ] = = ' 1 ' ) {
2020-11-27 15:54:44 +03:00
data_blocks [ i ] | = 0x80 > > j ;
2016-09-17 20:22:26 +03:00
}
2016-02-20 14:29:19 +03:00
}
}
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 , data_blocks , data_codewords ) ;
2020-03-30 13:59:16 +03:00
# else
( void ) symbol ; /* Unused */
2019-12-19 03:37:55 +03:00
# endif
2019-11-27 19:16:14 +03:00
2016-02-20 14:29:19 +03:00
/* Calculate Reed-Solomon error codewords */
2020-11-27 15:54:44 +03:00
rs_init_gf ( & rs , 0x11d ) ;
rs_init_code ( & rs , ecc_codewords , 0 ) ;
rs_encode ( & rs , data_codewords , data_blocks , ecc_blocks ) ;
2016-02-20 14:29:19 +03:00
/* Add Reed-Solomon codewords to binary data */
for ( i = 0 ; i < ecc_codewords ; i + + ) {
2017-06-06 23:11:11 +03:00
bin_append ( ecc_blocks [ ecc_codewords - i - 1 ] , 8 , binary_data ) ;
2016-02-20 14:29:19 +03:00
}
}
2020-11-27 15:54:44 +03:00
static void micro_setup_grid ( unsigned char * grid , const int size ) {
2016-02-20 14:29:19 +03:00
int i , toggle = 1 ;
/* Add timing patterns */
for ( i = 0 ; i < size ; i + + ) {
if ( toggle = = 1 ) {
grid [ i ] = 0x21 ;
grid [ ( i * size ) ] = 0x21 ;
toggle = 0 ;
} else {
grid [ i ] = 0x20 ;
grid [ ( i * size ) ] = 0x20 ;
toggle = 1 ;
}
}
/* Add finder patterns */
place_finder ( grid , size , 0 , 0 ) ;
/* Add separators */
for ( i = 0 ; i < 7 ; i + + ) {
grid [ ( 7 * size ) + i ] = 0x10 ;
grid [ ( i * size ) + 7 ] = 0x10 ;
}
grid [ ( 7 * size ) + 7 ] = 0x10 ;
/* Reserve space for format information */
for ( i = 0 ; i < 8 ; i + + ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + i ] | = 0x20 ;
grid [ ( i * size ) + 8 ] | = 0x20 ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + 8 ] | = 20 ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
static void micro_populate_grid ( unsigned char * grid , const int size , const char full_stream [ ] ) {
2016-02-20 14:29:19 +03:00
int direction = 1 ; /* up */
int row = 0 ; /* right hand side */
2020-11-27 15:54:44 +03:00
int n , i ;
2020-03-30 13:59:16 +03:00
int y ;
2016-02-20 14:29:19 +03:00
2021-06-10 13:15:39 +03:00
n = ( int ) strlen ( full_stream ) ;
2016-02-20 14:29:19 +03:00
y = size - 1 ;
i = 0 ;
do {
2017-09-10 18:03:09 +03:00
int x = ( size - 2 ) - ( row * 2 ) ;
2016-02-20 14:29:19 +03:00
if ( ! ( grid [ ( y * size ) + ( x + 1 ) ] & 0xf0 ) ) {
if ( full_stream [ i ] = = ' 1 ' ) {
grid [ ( y * size ) + ( x + 1 ) ] = 0x01 ;
} else {
grid [ ( y * size ) + ( x + 1 ) ] = 0x00 ;
2016-02-18 15:17:50 +03:00
}
2016-02-20 14:29:19 +03:00
i + + ;
}
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
if ( i < n ) {
if ( ! ( grid [ ( y * size ) + x ] & 0xf0 ) ) {
if ( full_stream [ i ] = = ' 1 ' ) {
grid [ ( y * size ) + x ] = 0x01 ;
} else {
grid [ ( y * size ) + x ] = 0x00 ;
2016-02-18 15:17:50 +03:00
}
2016-02-20 14:29:19 +03:00
i + + ;
2016-02-18 15:17:50 +03:00
}
}
2016-02-20 14:29:19 +03:00
if ( direction ) {
y - - ;
} else {
y + + ;
}
if ( y = = 0 ) {
/* reached the top */
row + + ;
y = 1 ;
direction = 0 ;
}
if ( y = = size ) {
/* reached the bottom */
row + + ;
y = size - 1 ;
direction = 1 ;
}
} while ( i < n ) ;
}
2020-11-27 15:54:44 +03:00
static int micro_evaluate ( const unsigned char * grid , const int size , const int pattern ) {
2016-02-20 14:29:19 +03:00
int sum1 , sum2 , i , filter = 0 , retval ;
switch ( pattern ) {
case 0 : filter = 0x01 ;
break ;
case 1 : filter = 0x02 ;
break ;
case 2 : filter = 0x04 ;
break ;
case 3 : filter = 0x08 ;
break ;
2016-02-18 15:17:50 +03:00
}
2016-02-20 14:29:19 +03:00
sum1 = 0 ;
sum2 = 0 ;
for ( i = 1 ; i < size ; i + + ) {
if ( grid [ ( i * size ) + size - 1 ] & filter ) {
sum1 + + ;
2016-02-18 15:17:50 +03:00
}
2016-02-20 14:29:19 +03:00
if ( grid [ ( ( size - 1 ) * size ) + i ] & filter ) {
sum2 + + ;
}
}
if ( sum1 < = sum2 ) {
retval = ( sum1 * 16 ) + sum2 ;
} else {
retval = ( sum2 * 16 ) + sum1 ;
2016-02-18 15:17:50 +03:00
}
2016-02-20 14:29:19 +03:00
return retval ;
2016-02-18 15:17:50 +03:00
}
2020-11-27 15:54:44 +03:00
static int micro_apply_bitmask ( unsigned char * grid , const int size , const int user_mask , const int debug_print ) {
2016-02-20 14:29:19 +03:00
int x , y ;
2020-11-27 15:54:44 +03:00
int r , k ;
int bit ;
int pattern , value [ 4 ] ;
int best_pattern ;
int size_squared = size * size ;
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
# ifndef _MSC_VER
2020-11-27 15:54:44 +03:00
unsigned char mask [ size_squared ] ;
unsigned char eval [ size_squared ] ;
2016-02-20 14:29:19 +03:00
# else
2021-06-19 15:11:23 +03:00
unsigned char * mask = ( unsigned char * ) _alloca ( size_squared ) ;
unsigned char * eval = ( unsigned char * ) _alloca ( size_squared ) ;
2016-02-20 14:29:19 +03:00
# endif
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +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 + + ) {
2016-02-18 15:17:50 +03:00
2020-11-27 15:54:44 +03:00
if ( ! ( grid [ r + x ] & 0xf0 ) ) {
2016-02-20 14:29:19 +03:00
if ( ( y & 1 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
if ( ( ( ( y / 2 ) + ( x / 3 ) ) & 1 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x02 ;
2016-02-20 14:29:19 +03:00
}
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
if ( ( ( ( ( y * x ) & 1 ) + ( ( y * x ) % 3 ) ) & 1 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x04 ;
2016-02-20 14:29:19 +03:00
}
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
if ( ( ( ( ( y + x ) & 1 ) + ( ( y * x ) % 3 ) ) & 1 ) = = 0 ) {
2020-11-27 15:54:44 +03:00
mask [ r + x ] | = 0x08 ;
2016-02-20 14:29:19 +03:00
}
}
}
}
2016-02-18 15:17:50 +03:00
2020-11-27 15:54:44 +03:00
if ( user_mask ) {
best_pattern = user_mask - 1 ;
} else {
for ( k = 0 ; k < size_squared ; k + + ) {
if ( grid [ k ] & 0x01 ) {
eval [ k ] = mask [ k ] ^ 0xff ;
2016-02-20 14:29:19 +03:00
} else {
2020-11-27 15:54:44 +03:00
eval [ k ] = mask [ k ] ;
2016-02-20 14:29:19 +03:00
}
}
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
/* Evaluate result */
best_pattern = 0 ;
for ( pattern = 0 ; pattern < 4 ; pattern + + ) {
value [ pattern ] = micro_evaluate ( eval , size , pattern ) ;
if ( value [ pattern ] > value [ best_pattern ] ) {
best_pattern = pattern ;
}
}
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
if ( 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 , value [ pattern ] ) ;
2016-02-20 14:29:19 +03:00
}
2020-11-27 15:54:44 +03:00
printf ( " \n " ) ;
2016-02-20 14:29:19 +03:00
}
/* Apply mask */
2020-11-27 15:54:44 +03:00
bit = 1 < < best_pattern ;
for ( k = 0 ; k < size_squared ; k + + ) {
if ( mask [ k ] & bit ) {
if ( grid [ k ] & 0x01 ) {
grid [ k ] = 0x00 ;
} else {
grid [ k ] = 0x01 ;
2016-02-20 14:29:19 +03:00
}
2016-02-18 15:17:50 +03:00
}
}
2016-02-20 14:29:19 +03:00
return best_pattern ;
2016-02-18 15:17:50 +03:00
}
2020-11-27 15:54:44 +03:00
INTERNAL int microqr ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) {
int i , size , j ;
2016-02-20 14:29:19 +03:00
char full_stream [ 200 ] ;
2020-04-02 16:41:13 +03:00
int full_multibyte ;
2020-11-27 15:54:44 +03:00
int user_mask ;
2017-05-29 12:43:47 +03:00
2019-11-27 19:16:14 +03:00
unsigned int jisdata [ 40 ] ;
2016-02-20 14:29:19 +03:00
char mode [ 40 ] ;
2019-12-16 20:31:52 +03:00
int alpha_used = 0 , byte_or_kanji_used = 0 ;
2016-02-20 14:29:19 +03:00
int version_valid [ 4 ] ;
int binary_count [ 4 ] ;
int ecc_level , autoversion , version ;
2019-12-16 20:31:52 +03:00
int bitmask , format , format_full ;
2020-11-27 15:54:44 +03:00
int size_squared ;
int debug_print = symbol - > debug & ZINT_DEBUG_PRINT ;
2016-02-20 14:29:19 +03:00
# ifdef _MSC_VER
2021-06-19 15:11:23 +03:00
unsigned char * grid ;
2016-02-17 13:52:48 +03:00
# endif
2016-02-18 15:17:50 +03:00
2016-02-20 14:29:19 +03:00
if ( length > 35 ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 562: Input data too long " ) ;
2016-02-20 14:29:19 +03:00
return ZINT_ERROR_TOO_LONG ;
}
2016-02-17 13:52:48 +03:00
2019-09-02 13:43:14 +03:00
/* Check option 1 in combination with option 2 */
ecc_level = LEVEL_L ;
if ( symbol - > option_1 > = 1 & & symbol - > option_1 < = 4 ) {
if ( symbol - > option_1 = = 4 ) {
strcpy ( symbol - > errtxt , " 566: Error correction level H not available " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
if ( symbol - > option_2 > = 1 & & symbol - > option_2 < = 4 ) {
if ( symbol - > option_2 = = 1 & & symbol - > option_1 ! = 1 ) {
strcpy ( symbol - > errtxt , " 574: Version M1 supports error correction level L only " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
if ( symbol - > option_2 ! = 4 & & symbol - > option_1 = = 3 ) {
strcpy ( symbol - > errtxt , " 575: Error correction level Q requires Version M4 " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
}
ecc_level = symbol - > option_1 ;
}
2021-01-11 21:11:41 +03:00
/* If ZINT_FULL_MULTIBYTE use Kanji mode in DATA_MODE or for non-Shift JIS 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-11-27 19:16:14 +03:00
if ( ( symbol - > input_mode & 0x07 ) = = DATA_MODE ) {
2020-04-02 16:41:13 +03:00
sjis_cpy ( source , & length , jisdata , full_multibyte ) ;
2016-08-16 14:43:41 +03:00
} else {
2019-11-27 19:16:14 +03:00
/* Try ISO 8859-1 conversion first */
2021-01-11 21:11:41 +03:00
int error_number = sjis_utf8_to_eci ( 3 , source , & length , jisdata , full_multibyte ) ;
2016-08-16 14:43:41 +03:00
if ( error_number ! = 0 ) {
2019-11-27 19:16:14 +03:00
/* Try Shift-JIS */
2021-01-11 21:11:41 +03:00
error_number = sjis_utf8 ( symbol , source , & length , jisdata ) ;
2019-11-27 19:16:14 +03:00
if ( error_number ! = 0 ) {
return error_number ;
2016-02-18 15:17:50 +03:00
}
2016-08-16 14:43:41 +03:00
}
2016-02-20 14:29:19 +03:00
}
2019-12-16 20:31:52 +03:00
/* Determine if alpha (excluding numerics), byte or kanji used */
for ( i = 0 ; i < length & & ( alpha_used = = 0 | | byte_or_kanji_used = = 0 ) ; i + + ) {
if ( jisdata [ i ] < ' 0 ' | | jisdata [ i ] > ' 9 ' ) {
if ( is_alpha ( jisdata [ i ] , 0 /*gs1*/ ) ) {
alpha_used = 1 ;
} else {
byte_or_kanji_used = 1 ;
}
2016-02-20 14:29:19 +03:00
}
}
2016-02-17 13:52:48 +03:00
2019-12-16 20:31:52 +03:00
for ( i = 0 ; i < 4 ; i + + ) {
version_valid [ i ] = 1 ;
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2019-11-27 19:16:14 +03:00
/* Eliminate possible versions depending on type of content */
2019-12-16 20:31:52 +03:00
if ( byte_or_kanji_used ) {
2016-02-20 14:29:19 +03:00
version_valid [ 0 ] = 0 ;
version_valid [ 1 ] = 0 ;
2019-12-16 20:31:52 +03:00
} else if ( alpha_used ) {
2016-02-20 14:29:19 +03:00
version_valid [ 0 ] = 0 ;
}
2016-02-17 13:52:48 +03:00
2019-12-16 20:31:52 +03:00
/* Eliminate possible versions depending on error correction level specified */
if ( ecc_level = = LEVEL_Q ) {
2016-02-20 14:29:19 +03:00
version_valid [ 0 ] = 0 ;
version_valid [ 1 ] = 0 ;
2019-12-16 20:31:52 +03:00
version_valid [ 2 ] = 0 ;
} else if ( ecc_level = = LEVEL_M ) {
version_valid [ 0 ] = 0 ;
}
/* Determine length of binary data */
for ( i = 0 ; i < 4 ; i + + ) {
if ( version_valid [ i ] ) {
2021-06-19 15:11:23 +03:00
binary_count [ i ] = getBinaryLength ( MICROQR_VERSION + i , mode , jisdata , length , 0 /*gs1*/ , 0 /*eci*/ ,
debug_print ) ;
2019-12-16 20:31:52 +03:00
} else {
binary_count [ i ] = 128 + 1 ;
}
2016-02-20 14:29:19 +03:00
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
/* Eliminate possible versions depending on length of binary data */
if ( binary_count [ 0 ] > 20 ) {
version_valid [ 0 ] = 0 ;
}
if ( binary_count [ 1 ] > 40 ) {
version_valid [ 1 ] = 0 ;
}
if ( binary_count [ 2 ] > 84 ) {
version_valid [ 2 ] = 0 ;
}
if ( binary_count [ 3 ] > 128 ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 565: Input data too long " ) ;
2016-02-20 14:29:19 +03:00
return ZINT_ERROR_TOO_LONG ;
}
2016-02-17 13:52:48 +03:00
2019-12-16 20:31:52 +03:00
/* Eliminate possible versions depending on binary length and error correction level specified */
2016-02-20 14:29:19 +03:00
if ( ecc_level = = LEVEL_Q ) {
if ( binary_count [ 3 ] > 80 ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 567: Input data too long " ) ;
2016-02-20 14:29:19 +03:00
return ZINT_ERROR_TOO_LONG ;
}
2019-12-16 20:31:52 +03:00
} else if ( ecc_level = = LEVEL_M ) {
2016-02-20 14:29:19 +03:00
if ( binary_count [ 1 ] > 32 ) {
version_valid [ 1 ] = 0 ;
}
if ( binary_count [ 2 ] > 68 ) {
version_valid [ 2 ] = 0 ;
}
if ( binary_count [ 3 ] > 112 ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 568: Input data too long " ) ;
2016-02-20 14:29:19 +03:00
return ZINT_ERROR_TOO_LONG ;
}
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
autoversion = 3 ;
if ( version_valid [ 2 ] ) {
autoversion = 2 ;
}
if ( version_valid [ 1 ] ) {
autoversion = 1 ;
}
if ( version_valid [ 0 ] ) {
autoversion = 0 ;
}
2016-02-17 13:52:48 +03:00
2016-02-20 14:29:19 +03:00
version = autoversion ;
/* Get version from user */
if ( ( symbol - > option_2 > = 1 ) & & ( symbol - > option_2 < = 4 ) ) {
2019-09-02 13:43:14 +03:00
if ( symbol - > option_2 - 1 > = autoversion ) {
version = symbol - > option_2 - 1 ;
2017-04-11 11:26:39 +03:00
} else {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 570: Input too long for selected symbol size " ) ;
2017-04-11 11:26:39 +03:00
return ZINT_ERROR_TOO_LONG ;
2016-02-20 14:29:19 +03:00
}
}
2016-02-17 13:52:48 +03:00
2019-12-16 20:31:52 +03:00
/* If there is enough unused space then increase the error correction level, unless user-specified */
if ( symbol - > option_1 = = - 1 | | symbol - > option_1 ! = ecc_level ) {
if ( version = = 3 ) {
if ( binary_count [ 3 ] < = 112 ) {
ecc_level = LEVEL_M ;
}
if ( binary_count [ 3 ] < = 80 ) {
ecc_level = LEVEL_Q ;
}
} else if ( version = = 2 ) {
if ( binary_count [ 2 ] < = 68 ) {
ecc_level = LEVEL_M ;
}
} else if ( version = = 1 ) {
if ( binary_count [ 1 ] < = 32 ) {
ecc_level = LEVEL_M ;
}
2016-02-20 14:29:19 +03:00
}
}
2016-02-17 13:52:48 +03:00
2020-11-27 15:54:44 +03:00
qr_define_mode ( mode , jisdata , length , 0 /*gs1*/ , MICROQR_VERSION + version , debug_print ) ;
2016-02-17 13:52:48 +03:00
2020-11-27 15:54:44 +03:00
qr_binary ( ( unsigned char * ) full_stream , MICROQR_VERSION + version , 0 /*target_codewords*/ , mode , jisdata , length ,
0 /*gs1*/ , 0 /*eci*/ , binary_count [ version ] , debug_print ) ;
2016-02-20 14:29:19 +03:00
switch ( version ) {
2019-11-27 19:16:14 +03:00
case 0 : micro_qr_m1 ( symbol , full_stream ) ;
2016-02-20 14:29:19 +03:00
break ;
2019-11-27 19:16:14 +03:00
case 1 : micro_qr_m2 ( symbol , full_stream , ecc_level ) ;
2016-02-20 14:29:19 +03:00
break ;
2019-11-27 19:16:14 +03:00
case 2 : micro_qr_m3 ( symbol , full_stream , ecc_level ) ;
2016-02-20 14:29:19 +03:00
break ;
2019-11-27 19:16:14 +03:00
case 3 : micro_qr_m4 ( symbol , full_stream , ecc_level ) ;
2016-02-20 14:29:19 +03:00
break ;
}
size = micro_qr_sizes [ version ] ;
2020-11-27 15:54:44 +03:00
size_squared = size * size ;
2016-02-17 13:52:48 +03:00
# ifndef _MSC_VER
2020-11-27 15:54:44 +03:00
unsigned char grid [ size_squared ] ;
2016-02-17 13:52:48 +03:00
# else
2021-06-19 15:11:23 +03:00
grid = ( unsigned char * ) _alloca ( size_squared ) ;
2016-02-17 13:52:48 +03:00
# endif
2016-02-20 14:29:19 +03:00
2020-11-27 15:54:44 +03:00
memset ( grid , 0 , size_squared ) ;
2016-02-20 14:29:19 +03:00
micro_setup_grid ( grid , size ) ;
micro_populate_grid ( grid , size , full_stream ) ;
2020-11-27 15:54:44 +03:00
bitmask = micro_apply_bitmask ( grid , size , user_mask , debug_print ) ;
2016-02-20 14:29:19 +03:00
/* Add format data */
format = 0 ;
switch ( version ) {
case 1 : switch ( ecc_level ) {
case 1 : format = 1 ;
break ;
case 2 : format = 2 ;
break ;
}
break ;
case 2 : switch ( ecc_level ) {
case 1 : format = 3 ;
break ;
case 2 : format = 4 ;
break ;
}
break ;
case 3 : switch ( ecc_level ) {
case 1 : format = 5 ;
break ;
case 2 : format = 6 ;
break ;
case 3 : format = 7 ;
break ;
}
break ;
}
format_full = qr_annex_c1 [ ( format < < 2 ) + bitmask ] ;
if ( format_full & 0x4000 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + 1 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x2000 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + 2 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x1000 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + 3 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x800 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + 4 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x400 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + 5 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x200 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + 6 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x100 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + 7 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x80 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 8 * size ) + 8 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x40 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 7 * size ) + 8 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x20 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 6 * size ) + 8 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x10 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 5 * size ) + 8 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x08 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 4 * size ) + 8 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x04 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 3 * size ) + 8 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x02 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 2 * size ) + 8 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
if ( format_full & 0x01 ) {
2020-11-27 15:54:44 +03:00
grid [ ( 1 * size ) + 8 ] | = 0x01 ;
2016-02-20 14:29:19 +03:00
}
symbol - > width = size ;
symbol - > rows = size ;
for ( i = 0 ; i < size ; i + + ) {
for ( j = 0 ; j < size ; j + + ) {
if ( grid [ ( i * size ) + j ] & 0x01 ) {
set_module ( symbol , i , j ) ;
}
}
symbol - > row_height [ i ] = 1 ;
}
2021-06-19 15:11:23 +03:00
symbol - > height = size ;
2016-02-20 14:29:19 +03:00
return 0 ;
2016-02-17 13:52:48 +03:00
}
2017-05-21 01:37:50 +03:00
/* For UPNQR the symbol size and error correction capacity is fixed */
2020-11-27 15:54:44 +03:00
INTERNAL int upnqr ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) {
int i , j , r , est_binlen ;
2019-11-25 22:08:25 +03:00
int ecc_level , version , target_codewords , blocks , size ;
2017-05-21 11:20:03 +03:00
int bitmask , error_number ;
2020-11-27 15:54:44 +03:00
int size_squared ;
int debug_print = symbol - > debug & ZINT_DEBUG_PRINT ;
2017-05-21 01:37:50 +03:00
# ifndef _MSC_VER
2019-11-27 19:16:14 +03:00
unsigned int jisdata [ length + 1 ] ;
2017-05-21 01:37:50 +03:00
char mode [ length + 1 ] ;
# else
2021-06-19 15:11:23 +03:00
unsigned char * datastream ;
unsigned char * fullstream ;
unsigned char * grid ;
unsigned int * jisdata = ( unsigned int * ) _alloca ( ( length + 1 ) * sizeof ( unsigned int ) ) ;
char * mode = ( char * ) _alloca ( length + 1 ) ;
2017-05-21 01:37:50 +03:00
# endif
2017-10-23 22:37:52 +03:00
2017-05-21 11:20:03 +03:00
# ifndef _MSC_VER
unsigned char preprocessed [ length + 1 ] ;
# else
2021-06-19 15:11:23 +03:00
unsigned char * preprocessed = ( unsigned char * ) _alloca ( length + 1 ) ;
2017-05-21 11:20:03 +03:00
# endif
2017-05-21 01:37:50 +03:00
2019-11-27 19:16:14 +03:00
symbol - > eci = 4 ; /* Set before any processing */
switch ( symbol - > input_mode & 0x07 ) {
2017-05-21 11:20:03 +03:00
case DATA_MODE :
2017-05-21 01:37:50 +03:00
/* Input is already in ISO-8859-2 format */
2020-11-27 15:54:44 +03:00
for ( i = 0 ; i < length ; i + + ) {
2019-11-27 19:16:14 +03:00
jisdata [ i ] = source [ i ] ;
2017-05-21 01:37:50 +03:00
mode [ i ] = ' B ' ;
}
break ;
2017-05-21 11:20:03 +03:00
case GS1_MODE :
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 571: UPNQR does not support GS-1 encoding " ) ;
2017-05-21 11:20:03 +03:00
return ZINT_ERROR_INVALID_OPTION ;
break ;
case UNICODE_MODE :
2021-01-11 21:11:41 +03:00
error_number = utf8_to_eci ( 4 , source , preprocessed , & length ) ;
2017-05-21 11:20:03 +03:00
if ( error_number ! = 0 ) {
2021-07-06 21:53:31 +03:00
strcpy ( symbol - > errtxt , " 572: Invalid character in input data for ECI 4 " ) ;
2017-05-21 11:20:03 +03:00
return error_number ;
}
2020-11-27 15:54:44 +03:00
for ( i = 0 ; i < length ; i + + ) {
2019-11-27 19:16:14 +03:00
jisdata [ i ] = preprocessed [ i ] ;
2017-05-21 11:20:03 +03:00
mode [ i ] = ' B ' ;
}
2017-05-21 01:37:50 +03:00
break ;
}
2020-11-27 15:54:44 +03:00
est_binlen = getBinaryLength ( 15 , mode , jisdata , length , 0 , symbol - > eci , debug_print ) ;
2017-10-23 22:37:52 +03:00
2017-05-21 01:37:50 +03:00
ecc_level = LEVEL_M ;
2017-06-05 22:05:58 +03:00
if ( est_binlen > 3320 ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 573: Input too long for selected symbol " ) ;
2017-05-21 01:37:50 +03:00
return ZINT_ERROR_TOO_LONG ;
}
version = 15 ; // 77 x 77
2019-11-25 22:08:25 +03:00
target_codewords = qr_data_codewords_M [ version - 1 ] ;
2017-05-21 01:37:50 +03:00
blocks = qr_blocks_M [ version - 1 ] ;
# ifndef _MSC_VER
2019-12-01 18:17:08 +03:00
unsigned char datastream [ target_codewords + 1 ] ;
2019-11-27 19:16:14 +03:00
unsigned char fullstream [ qr_total_codewords [ version - 1 ] + 1 ] ;
2017-05-21 01:37:50 +03:00
# else
2019-12-01 18:17:08 +03:00
datastream = ( unsigned char * ) _alloca ( target_codewords + 1 ) ;
2019-11-27 19:16:14 +03:00
fullstream = ( unsigned char * ) _alloca ( qr_total_codewords [ version - 1 ] + 1 ) ;
2017-05-21 01:37:50 +03:00
# endif
2020-11-27 15:54:44 +03:00
qr_binary ( datastream , version , target_codewords , mode , jisdata , length , 0 , symbol - > eci , est_binlen , debug_print ) ;
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 , target_codewords ) ;
2019-12-19 03:37:55 +03:00
# endif
2020-11-27 15:54:44 +03:00
add_ecc ( fullstream , datastream , version , target_codewords , blocks , debug_print ) ;
2017-05-21 01:37:50 +03:00
size = qr_sizes [ version - 1 ] ;
2020-11-27 15:54:44 +03:00
size_squared = size * size ;
2017-05-21 01:37:50 +03:00
# ifndef _MSC_VER
2020-11-27 15:54:44 +03:00
unsigned char grid [ size_squared ] ;
2017-05-21 01:37:50 +03:00
# else
2021-06-19 15:11:23 +03:00
grid = ( unsigned char * ) _alloca ( size_squared ) ;
2017-05-21 01:37:50 +03:00
# endif
2020-11-27 15:54:44 +03:00
memset ( grid , 0 , size_squared ) ;
2017-05-21 01:37:50 +03:00
setup_grid ( grid , size , version ) ;
2019-11-25 22:08:25 +03:00
populate_grid ( grid , size , size , fullstream , qr_total_codewords [ version - 1 ] ) ;
2017-10-23 22:37:52 +03:00
2017-05-30 10:40:08 +03:00
add_version_info ( grid , size , version ) ;
2017-05-21 01:37:50 +03:00
2020-11-27 15:54:44 +03:00
bitmask = apply_bitmask ( grid , size , ecc_level , 0 /*user_mask*/ , debug_print ) ;
2017-05-21 01:37:50 +03:00
add_format_info ( grid , size , ecc_level , bitmask ) ;
2017-10-23 22:37:52 +03:00
2017-05-21 01:37:50 +03:00
symbol - > width = size ;
symbol - > rows = size ;
for ( i = 0 ; i < size ; i + + ) {
2020-11-27 15:54:44 +03:00
r = i * size ;
2017-05-21 01:37:50 +03:00
for ( j = 0 ; j < size ; j + + ) {
2020-11-27 15:54:44 +03:00
if ( grid [ r + j ] & 0x01 ) {
2017-05-21 01:37:50 +03:00
set_module ( symbol , i , j ) ;
}
}
symbol - > row_height [ i ] = 1 ;
}
2021-06-19 15:11:23 +03:00
symbol - > height = size ;
2017-05-21 01:37:50 +03:00
return 0 ;
2017-05-29 12:43:47 +03:00
}
2017-10-23 22:34:31 +03:00
2021-06-19 15:11:23 +03:00
static void setup_rmqr_grid ( unsigned char * grid , const int h_size , const int v_size ) {
2019-11-25 22:08:25 +03:00
int i , j ;
char alignment [ ] = { 0x1F , 0x11 , 0x15 , 0x11 , 0x1F } ;
int h_version , finder_position ;
2017-10-23 22:37:52 +03:00
2019-11-25 22:08:25 +03:00
/* Add timing patterns - top and bottom */
for ( i = 0 ; i < h_size ; i + + ) {
if ( i % 2 ) {
grid [ i ] = 0x20 ;
grid [ ( ( v_size - 1 ) * h_size ) + i ] = 0x20 ;
} else {
grid [ i ] = 0x21 ;
grid [ ( ( v_size - 1 ) * h_size ) + i ] = 0x21 ;
}
}
/* Add timing patterns - left and right */
for ( i = 0 ; i < v_size ; i + + ) {
if ( i % 2 ) {
grid [ i * h_size ] = 0x20 ;
grid [ ( i * h_size ) + ( h_size - 1 ) ] = 0x20 ;
} else {
grid [ i * h_size ] = 0x21 ;
grid [ ( i * h_size ) + ( h_size - 1 ) ] = 0x21 ;
}
}
/* Add finder pattern */
place_finder ( grid , h_size , 0 , 0 ) ; // This works because finder is always top left
/* Add finder sub-pattern to bottom right */
for ( i = 0 ; i < 5 ; i + + ) {
for ( j = 0 ; j < 5 ; j + + ) {
if ( alignment [ j ] & 0x10 > > i ) {
grid [ ( ( v_size - 5 ) * h_size ) + ( h_size * i ) + ( h_size - 5 ) + j ] = 0x11 ;
} else {
grid [ ( ( v_size - 5 ) * h_size ) + ( h_size * i ) + ( h_size - 5 ) + j ] = 0x10 ;
}
}
}
/* Add corner finder pattern - bottom left */
grid [ ( v_size - 2 ) * h_size ] = 0x11 ;
grid [ ( ( v_size - 2 ) * h_size ) + 1 ] = 0x10 ;
grid [ ( ( v_size - 1 ) * h_size ) + 1 ] = 0x11 ;
/* Add corner finder pattern - top right */
grid [ h_size - 2 ] = 0x11 ;
grid [ ( h_size * 2 ) - 2 ] = 0x10 ;
grid [ ( h_size * 2 ) - 1 ] = 0x11 ;
/* Add seperator */
for ( i = 0 ; i < 7 ; i + + ) {
grid [ ( i * h_size ) + 7 ] = 0x20 ;
}
if ( v_size > 7 ) {
// Note for v_size = 9 this overrides the bottom right corner finder pattern
for ( i = 0 ; i < 8 ; i + + ) {
grid [ ( 7 * h_size ) + i ] = 0x20 ;
}
}
/* Add alignment patterns */
if ( h_size > 27 ) {
2020-11-27 15:54:44 +03:00
h_version = 0 ; // Suppress compiler warning [-Wmaybe-uninitialized]
2019-11-25 22:08:25 +03:00
for ( i = 0 ; i < 5 ; i + + ) {
if ( h_size = = rmqr_width [ i ] ) {
h_version = i ;
2020-11-27 15:54:44 +03:00
break ;
2019-11-25 22:08:25 +03:00
}
}
for ( i = 0 ; i < 4 ; i + + ) {
finder_position = rmqr_table_d1 [ ( h_version * 4 ) + i ] ;
if ( finder_position ! = 0 ) {
for ( j = 0 ; j < v_size ; j + + ) {
if ( j % 2 ) {
grid [ ( j * h_size ) + finder_position ] = 0x10 ;
} else {
grid [ ( j * h_size ) + finder_position ] = 0x11 ;
}
}
// Top square
grid [ h_size + finder_position - 1 ] = 0x11 ;
grid [ ( h_size * 2 ) + finder_position - 1 ] = 0x11 ;
grid [ h_size + finder_position + 1 ] = 0x11 ;
grid [ ( h_size * 2 ) + finder_position + 1 ] = 0x11 ;
// Bottom square
grid [ ( h_size * ( v_size - 3 ) ) + finder_position - 1 ] = 0x11 ;
grid [ ( h_size * ( v_size - 2 ) ) + finder_position - 1 ] = 0x11 ;
grid [ ( h_size * ( v_size - 3 ) ) + finder_position + 1 ] = 0x11 ;
grid [ ( h_size * ( v_size - 2 ) ) + finder_position + 1 ] = 0x11 ;
}
}
}
/* Reserve space for format information */
for ( i = 0 ; i < 5 ; i + + ) {
for ( j = 0 ; j < 3 ; j + + ) {
grid [ ( h_size * ( i + 1 ) ) + j + 8 ] = 0x20 ;
grid [ ( h_size * ( v_size - 6 ) ) + ( h_size * i ) + j + ( h_size - 8 ) ] = 0x20 ;
}
}
grid [ ( h_size * 1 ) + 11 ] = 0x20 ;
grid [ ( h_size * 2 ) + 11 ] = 0x20 ;
grid [ ( h_size * 3 ) + 11 ] = 0x20 ;
grid [ ( h_size * ( v_size - 6 ) ) + ( h_size - 5 ) ] = 0x20 ;
grid [ ( h_size * ( v_size - 6 ) ) + ( h_size - 4 ) ] = 0x20 ;
grid [ ( h_size * ( v_size - 6 ) ) + ( h_size - 3 ) ] = 0x20 ;
}
/* rMQR according to 2018 draft standard */
2020-11-27 15:54:44 +03:00
INTERNAL int rmqr ( struct zint_symbol * symbol , unsigned char source [ ] , int length ) {
2019-11-25 22:08:25 +03:00
int i , j , est_binlen ;
int ecc_level , autosize , version , max_cw , target_codewords , blocks , h_size , v_size ;
int gs1 ;
2020-04-02 16:41:13 +03:00
int full_multibyte ;
2019-11-25 22:08:25 +03:00
int footprint , best_footprint , format_data ;
unsigned int left_format_info , right_format_info ;
2020-11-27 15:54:44 +03:00
int debug_print = symbol - > debug & ZINT_DEBUG_PRINT ;
2019-11-25 22:08:25 +03:00
# ifndef _MSC_VER
2019-12-01 18:17:08 +03:00
unsigned int jisdata [ length + 1 ] ;
2019-11-25 22:08:25 +03:00
char mode [ length + 1 ] ;
# else
2021-06-19 15:11:23 +03:00
unsigned char * datastream ;
unsigned char * fullstream ;
unsigned char * grid ;
unsigned int * jisdata = ( unsigned int * ) _alloca ( ( length + 1 ) * sizeof ( unsigned int ) ) ;
char * mode = ( char * ) _alloca ( length + 1 ) ;
2019-11-25 22:08:25 +03:00
# endif
2019-12-01 18:17:08 +03:00
gs1 = ( ( symbol - > input_mode & 0x07 ) = = GS1_MODE ) ;
2021-01-11 21:11:41 +03:00
/* If ZINT_FULL_MULTIBYTE use Kanji mode in DATA_MODE or for non-Shift JIS in UNICODE_MODE */
2020-11-27 15:54:44 +03:00
full_multibyte = ( symbol - > option_3 & 0xFF ) = = ZINT_FULL_MULTIBYTE ;
2017-10-23 22:37:52 +03:00
2019-12-01 18:17:08 +03:00
if ( ( symbol - > input_mode & 0x07 ) = = DATA_MODE ) {
2020-04-02 16:41:13 +03:00
sjis_cpy ( source , & length , jisdata , full_multibyte ) ;
2019-11-25 22:08:25 +03:00
} else {
2019-12-16 20:31:52 +03:00
/* Try ISO 8859-1 conversion first */
2021-01-11 21:11:41 +03:00
int error_number = sjis_utf8_to_eci ( 3 , source , & length , jisdata , full_multibyte ) ;
2019-12-16 20:31:52 +03:00
if ( error_number ! = 0 ) {
2019-12-01 18:17:08 +03:00
/* Try Shift-JIS */
2021-01-11 21:11:41 +03:00
error_number = sjis_utf8 ( symbol , source , & length , jisdata ) ;
2019-12-01 18:17:08 +03:00
if ( error_number ! = 0 ) {
return error_number ;
2019-11-25 22:08:25 +03:00
}
}
}
2020-11-27 15:54:44 +03:00
est_binlen = getBinaryLength ( RMQR_VERSION + 31 , mode , jisdata , length , gs1 , 0 /*eci*/ , debug_print ) ;
2019-11-25 22:08:25 +03:00
ecc_level = LEVEL_M ;
max_cw = 152 ;
if ( symbol - > option_1 = = 1 ) {
strcpy ( symbol - > errtxt , " 576: Error correction level L not available in rMQR " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
if ( symbol - > option_1 = = 3 ) {
strcpy ( symbol - > errtxt , " 577: Error correction level Q not available in rMQR " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
if ( symbol - > option_1 = = 4 ) {
ecc_level = LEVEL_H ;
max_cw = 76 ;
}
if ( est_binlen > ( 8 * max_cw ) ) {
strcpy ( symbol - > errtxt , " 578: Input too long for selected error correction level " ) ;
return ZINT_ERROR_TOO_LONG ;
}
if ( ( symbol - > option_2 < 0 ) | | ( symbol - > option_2 > 38 ) ) {
strcpy ( symbol - > errtxt , " 579: Invalid rMQR symbol size " ) ;
return ZINT_ERROR_INVALID_OPTION ;
}
version = 31 ; // Set default to keep compiler happy
if ( symbol - > option_2 = = 0 ) {
// Automatic symbol size
autosize = 31 ;
best_footprint = rmqr_height [ 31 ] * rmqr_width [ 31 ] ;
for ( version = 30 ; version > = 0 ; version - - ) {
2020-11-27 15:54:44 +03:00
est_binlen = getBinaryLength ( RMQR_VERSION + version , mode , jisdata , length , gs1 , 0 /*eci*/ , debug_print ) ;
2019-11-25 22:08:25 +03:00
footprint = rmqr_height [ version ] * rmqr_width [ version ] ;
if ( ecc_level = = LEVEL_M ) {
2019-11-27 22:32:40 +03:00
if ( 8 * rmqr_data_codewords_M [ version ] > = est_binlen ) {
2019-11-25 22:08:25 +03:00
if ( footprint < best_footprint ) {
autosize = version ;
best_footprint = footprint ;
}
}
} else {
2019-11-27 22:32:40 +03:00
if ( 8 * rmqr_data_codewords_H [ version ] > = est_binlen ) {
2019-11-25 22:08:25 +03:00
if ( footprint < best_footprint ) {
autosize = version ;
best_footprint = footprint ;
}
}
}
}
version = autosize ;
2020-11-27 15:54:44 +03:00
est_binlen = getBinaryLength ( RMQR_VERSION + version , mode , jisdata , length , gs1 , 0 /*eci*/ , debug_print ) ;
2019-11-25 22:08:25 +03:00
}
if ( ( symbol - > option_2 > = 1 ) & & ( symbol - > option_2 < = 32 ) ) {
// User specified symbol size
version = symbol - > option_2 - 1 ;
2020-11-27 15:54:44 +03:00
est_binlen = getBinaryLength ( RMQR_VERSION + version , mode , jisdata , length , gs1 , 0 /*eci*/ , debug_print ) ;
2019-11-25 22:08:25 +03:00
}
if ( symbol - > option_2 > = 33 ) {
// User has specified symbol height only
version = rmqr_fixed_height_upper_bound [ symbol - > option_2 - 32 ] ;
for ( i = version - 1 ; i > rmqr_fixed_height_upper_bound [ symbol - > option_2 - 33 ] ; i - - ) {
2020-11-27 15:54:44 +03:00
est_binlen = getBinaryLength ( RMQR_VERSION + i , mode , jisdata , length , gs1 , 0 /*eci*/ , debug_print ) ;
2019-11-25 22:08:25 +03:00
if ( ecc_level = = LEVEL_M ) {
2019-11-27 22:32:40 +03:00
if ( 8 * rmqr_data_codewords_M [ i ] > = est_binlen ) {
2019-11-25 22:08:25 +03:00
version = i ;
}
} else {
2019-11-27 22:32:40 +03:00
if ( 8 * rmqr_data_codewords_H [ i ] > = est_binlen ) {
2019-11-25 22:08:25 +03:00
version = i ;
}
}
}
2020-11-27 15:54:44 +03:00
est_binlen = getBinaryLength ( RMQR_VERSION + version , mode , jisdata , length , gs1 , 0 /*eci*/ , debug_print ) ;
2019-11-25 22:08:25 +03:00
}
if ( symbol - > option_1 = = - 1 ) {
// Detect if there is enough free space to increase ECC level
if ( est_binlen < ( rmqr_data_codewords_H [ version ] * 8 ) ) {
ecc_level = LEVEL_H ;
}
}
if ( ecc_level = = LEVEL_M ) {
target_codewords = rmqr_data_codewords_M [ version ] ;
blocks = rmqr_blocks_M [ version ] ;
} else {
target_codewords = rmqr_data_codewords_H [ version ] ;
blocks = rmqr_blocks_H [ version ] ;
}
if ( est_binlen > ( target_codewords * 8 ) ) {
// User has selected a symbol too small for the data
strcpy ( symbol - > errtxt , " 580: Input too long for selected symbol size " ) ;
return ZINT_ERROR_TOO_LONG ;
}
2020-11-27 15:54:44 +03:00
if ( debug_print ) {
2019-11-25 22:08:25 +03:00
printf ( " Minimum codewords = %d \n " , est_binlen / 8 ) ;
printf ( " Selected version: %d = R%dx%d- " , ( version + 1 ) , rmqr_height [ version ] , rmqr_width [ version ] ) ;
if ( ecc_level = = LEVEL_M ) {
printf ( " M \n " ) ;
} else {
printf ( " H \n " ) ;
}
printf ( " Number of data codewords in symbol = %d \n " , target_codewords ) ;
printf ( " Number of ECC blocks = %d \n " , blocks ) ;
}
# ifndef _MSC_VER
2019-12-01 18:17:08 +03:00
unsigned char datastream [ target_codewords + 1 ] ;
unsigned char fullstream [ rmqr_total_codewords [ version ] + 1 ] ;
2019-11-25 22:08:25 +03:00
# else
2021-06-19 15:11:23 +03:00
datastream = ( unsigned char * ) _alloca ( target_codewords + 1 ) ;
fullstream = ( unsigned char * ) _alloca ( rmqr_total_codewords [ version ] + 1 ) ;
2019-11-25 22:08:25 +03:00
# endif
2021-06-19 15:11:23 +03:00
qr_binary ( datastream , RMQR_VERSION + version , target_codewords , mode , jisdata , length , gs1 , 0 /*eci*/ , est_binlen ,
debug_print ) ;
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 , target_codewords ) ;
2019-12-19 03:37:55 +03:00
# endif
2020-11-27 15:54:44 +03:00
add_ecc ( fullstream , datastream , RMQR_VERSION + version , target_codewords , blocks , debug_print ) ;
2019-11-25 22:08:25 +03:00
h_size = rmqr_width [ version ] ;
v_size = rmqr_height [ version ] ;
# ifndef _MSC_VER
unsigned char grid [ h_size * v_size ] ;
# else
2021-06-19 15:11:23 +03:00
grid = ( unsigned char * ) _alloca ( h_size * v_size ) ;
2019-11-25 22:08:25 +03:00
# endif
2020-11-27 15:54:44 +03:00
memset ( grid , 0 , h_size * v_size ) ;
2019-11-25 22:08:25 +03:00
2020-03-30 13:59:16 +03:00
setup_rmqr_grid ( grid , h_size , v_size ) ;
2019-11-25 22:08:25 +03:00
populate_grid ( grid , h_size , v_size , fullstream , rmqr_total_codewords [ version ] ) ;
/* apply bitmask */
for ( i = 0 ; i < v_size ; i + + ) {
2020-11-27 15:54:44 +03:00
int r = i * h_size ;
2019-11-25 22:08:25 +03:00
for ( j = 0 ; j < h_size ; j + + ) {
2020-11-27 15:54:44 +03:00
if ( ( grid [ r + j ] & 0xf0 ) = = 0 ) {
2019-11-25 22:08:25 +03:00
// This is a data module
if ( ( ( i / 2 ) + ( j / 3 ) ) % 2 = = 0 ) { // < This is the data mask from section 7.8.2
// This module needs to be changed
2020-11-27 15:54:44 +03:00
if ( grid [ r + j ] = = 0x01 ) {
grid [ r + j ] = 0x00 ;
2019-11-25 22:08:25 +03:00
} else {
2020-11-27 15:54:44 +03:00
grid [ r + j ] = 0x01 ;
2019-11-25 22:08:25 +03:00
}
}
}
}
}
/* add format information */
format_data = version ;
if ( ecc_level = = LEVEL_H ) {
format_data + = 32 ;
}
left_format_info = rmqr_format_info_left [ format_data ] ;
right_format_info = rmqr_format_info_right [ format_data ] ;
for ( i = 0 ; i < 5 ; i + + ) {
for ( j = 0 ; j < 3 ; j + + ) {
grid [ ( h_size * ( i + 1 ) ) + j + 8 ] = ( left_format_info > > ( ( j * 5 ) + i ) ) & 0x01 ;
2021-06-19 15:11:23 +03:00
grid [ ( h_size * ( v_size - 6 ) ) + ( h_size * i ) + j + ( h_size - 8 ) ]
= ( right_format_info > > ( ( j * 5 ) + i ) ) & 0x01 ;
2019-11-25 22:08:25 +03:00
}
}
grid [ ( h_size * 1 ) + 11 ] = ( left_format_info > > 15 ) & 0x01 ;
grid [ ( h_size * 2 ) + 11 ] = ( left_format_info > > 16 ) & 0x01 ;
grid [ ( h_size * 3 ) + 11 ] = ( left_format_info > > 17 ) & 0x01 ;
grid [ ( h_size * ( v_size - 6 ) ) + ( h_size - 5 ) ] = ( right_format_info > > 15 ) & 0x01 ;
grid [ ( h_size * ( v_size - 6 ) ) + ( h_size - 4 ) ] = ( right_format_info > > 16 ) & 0x01 ;
grid [ ( h_size * ( v_size - 6 ) ) + ( h_size - 3 ) ] = ( right_format_info > > 17 ) & 0x01 ;
symbol - > width = h_size ;
symbol - > rows = v_size ;
for ( i = 0 ; i < v_size ; i + + ) {
2020-11-27 15:54:44 +03:00
int r = i * h_size ;
2019-11-25 22:08:25 +03:00
for ( j = 0 ; j < h_size ; j + + ) {
2020-11-27 15:54:44 +03:00
if ( grid [ r + j ] & 0x01 ) {
2019-11-25 22:08:25 +03:00
set_module ( symbol , i , j ) ;
}
}
symbol - > row_height [ i ] = 1 ;
}
2021-06-19 15:11:23 +03:00
symbol - > height = v_size ;
2019-11-25 22:08:25 +03:00
return 0 ;
2019-12-04 16:45:01 +03:00
}