2009-10-06 19:03:00 +00:00
/* qr.c Handles QR Code */
2008-07-13 21:15:55 +00:00
/*
libzint - the open source barcode library
2009-10-06 19:03:00 +00:00
Copyright ( C ) 2009 Robin Stuart < robin @ zint . org . uk >
2008-07-13 21:15:55 +00:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License along
with this program ; if not , write to the Free Software Foundation , Inc . ,
51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
# include <string.h>
# include "common.h"
2009-08-09 08:45:58 +00:00
# include <stdio.h>
2009-10-06 19:03:00 +00:00
# include "sjis.h"
# include "qr.h"
# include "qrrs.h"
2008-09-02 19:49:08 +00:00
2009-10-06 19:03:00 +00:00
int in_alpha ( int glyph ) {
/* Returns true if input glyph is in the Alphanumeric set */
int retval = 0 ;
char cglyph = ( char ) glyph ;
if ( ( cglyph > = ' 0 ' ) & & ( cglyph < = ' 9 ' ) ) {
retval = 1 ;
}
if ( ( cglyph > = ' A ' ) & & ( cglyph < = ' Z ' ) ) {
retval = 1 ;
}
switch ( cglyph ) {
case ' ' :
case ' $ ' :
case ' % ' :
case ' * ' :
case ' + ' :
case ' - ' :
case ' . ' :
case ' / ' :
case ' : ' :
retval = 1 ;
break ;
}
return retval ;
}
2008-07-13 21:15:55 +00:00
2009-10-06 19:03:00 +00:00
void define_mode ( char mode [ ] , int jisdata [ ] , int length )
{
/* Values placed into mode[] are: K = Kanji, B = Binary, A = Alphanumeric, N = Numeric */
int i , mlen , j ;
for ( i = 0 ; i < length ; i + + ) {
if ( jisdata [ i ] > 0xff ) {
mode [ i ] = ' K ' ;
} else {
mode [ i ] = ' B ' ;
if ( in_alpha ( jisdata [ i ] ) ) { mode [ i ] = ' A ' ; }
if ( ( jisdata [ i ] > = ' 0 ' ) & & ( jisdata [ i ] < = ' 9 ' ) ) { mode [ i ] = ' N ' ; }
}
}
/* If less than 6 numeric digits together then don't use numeric mode */
for ( i = 0 ; i < length ; i + + ) {
if ( mode [ i ] = = ' N ' ) {
if ( ( ( i ! = 0 ) & & ( mode [ i - 1 ] ! = ' N ' ) ) | | ( i = = 0 ) ) {
mlen = 0 ;
while ( ( ( mlen + i ) < length ) & & ( mode [ mlen + i ] = = ' N ' ) ) {
mlen + + ;
} ;
if ( mlen < 6 ) {
for ( j = 0 ; j < mlen ; j + + ) {
mode [ i + j ] = ' A ' ;
}
}
}
}
}
/* If less than 4 alphanumeric characters together then don't use alphanumeric mode */
for ( i = 0 ; i < length ; i + + ) {
if ( mode [ i ] = = ' A ' ) {
if ( ( ( i ! = 0 ) & & ( mode [ i - 1 ] ! = ' A ' ) ) | | ( i = = 0 ) ) {
mlen = 0 ;
while ( ( ( mlen + i ) < length ) & & ( mode [ mlen + i ] = = ' A ' ) ) {
mlen + + ;
} ;
if ( mlen < 6 ) {
for ( j = 0 ; j < mlen ; j + + ) {
mode [ i + j ] = ' B ' ;
}
}
}
}
}
}
2009-08-09 08:45:58 +00:00
2009-10-06 19:03:00 +00:00
int estimate_binary_length ( char mode [ ] , int length )
{
/* Make an estimate (worst case scenario) of how long the binary string will be */
int i , count = 0 ;
char current = 0 ;
int a_count = 0 ;
int n_count = 0 ;
switch ( mode [ 0 ] ) {
case ' K ' : count = 12 + 4 ; current = ' K ' ; break ;
case ' B ' : count = 16 + 4 ; current = ' B ' ; break ;
case ' A ' : count = 13 + 4 ; current = ' A ' ; break ;
case ' N ' : count = 14 + 4 ; current = ' N ' ; break ;
2009-08-09 08:45:58 +00:00
}
2009-10-06 19:03:00 +00:00
for ( i = 0 ; i < length ; i + + ) {
if ( mode [ i ] ! = current ) {
if ( current = = ' N ' ) {
switch ( n_count ) {
case 1 : count + = 4 ; break ;
case 2 : count + = 7 ; break ;
}
}
switch ( mode [ i ] ) {
case ' K ' : count + = 12 + 4 ; current = ' K ' ; break ;
case ' B ' : count + = 16 + 4 ; current = ' B ' ; break ;
case ' A ' : count + = 13 + 4 ; current = ' A ' ; break ;
case ' N ' : count + = 14 + 4 ; current = ' N ' ; break ;
}
}
switch ( mode [ i ] ) {
case ' K ' : count + = 13 ; break ;
case ' B ' : count + = 8 ; break ;
case ' A ' : a_count + + ; if ( ( a_count % 2 ) = = 0 ) { count + = 11 ; a_count = 0 ; } break ;
case ' N ' : n_count + + ; if ( ( n_count % 3 ) = = 0 ) { count + = 10 ; n_count = 0 ; } break ;
}
2008-07-13 21:15:55 +00:00
}
2009-10-06 19:03:00 +00:00
return count ;
}
2008-07-13 21:15:55 +00:00
2009-10-06 19:03:00 +00:00
void qr_binary ( int datastream [ ] , int version , int target_binlen , char mode [ ] , int jisdata [ ] , int length )
{
/* Convert input data to a binary stream and add padding */
int position = 0 , debug = 1 ;
int short_data_block_length , i , scheme ;
char data_block , padbits ;
int current_binlen , current_bytes ;
int toggle ;
# ifndef _MSC_VER
char binary [ target_binlen * 8 ] ;
# else
char binary = ( char * ) _alloca ( target_binlen * 8 ) ;
# endif
strcpy ( binary , " " ) ;
if ( version < = 9 ) {
scheme = 1 ;
}
if ( ( version > = 10 ) & & ( version < = 26 ) ) {
scheme = 2 ;
}
if ( version > = 27 ) {
scheme = 3 ;
}
if ( debug ) {
for ( i = 0 ; i < length ; i + + ) {
printf ( " %c " , mode [ i ] ) ;
2008-07-13 21:15:55 +00:00
}
2009-10-06 19:03:00 +00:00
printf ( " \n " ) ;
2008-07-13 21:15:55 +00:00
}
2009-10-06 19:03:00 +00:00
do {
data_block = mode [ position ] ;
short_data_block_length = 0 ;
do {
short_data_block_length + + ;
} while ( ( ( short_data_block_length + position ) < length ) & & ( mode [ position + short_data_block_length ] = = data_block ) ) ;
switch ( data_block ) {
case ' K ' :
/* Kanji mode */
/* Mode indicator */
concat ( binary , " 1000 " ) ;
/* Character count indicator */
switch ( scheme ) {
case 3 :
if ( short_data_block_length & 0x800 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x400 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
case 2 :
if ( short_data_block_length & 0x200 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x100 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
case 1 :
if ( short_data_block_length & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
break ;
}
if ( debug ) { printf ( " Kanji block (length %d) \n \t " , short_data_block_length ) ; }
/* Character representation */
for ( i = 0 ; i < short_data_block_length ; i + + ) {
int jis = jisdata [ position + i ] ;
int msb , lsb , prod ;
if ( jis > 0x9fff ) { jis - = 0xc140 ; }
msb = ( jis & 0xff00 ) > > 4 ;
lsb = ( jis & 0xff ) ;
prod = ( msb * 0xc0 ) + lsb ;
if ( prod & 0x1000 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x800 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x400 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x200 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x100 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( debug ) { printf ( " 0x%4X " , prod ) ; }
}
if ( debug ) { printf ( " \n " ) ; }
break ;
case ' B ' :
/* Byte mode */
/* Mode indicator */
concat ( binary , " 0100 " ) ;
/* Character count indicator */
switch ( scheme ) {
case 3 :
case 2 :
if ( short_data_block_length & 0x8000 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x4000 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x2000 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x1000 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x800 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x400 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x200 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x100 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
case 1 :
if ( short_data_block_length & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
break ;
}
if ( debug ) { printf ( " Byte block (length %d) \n \t " , short_data_block_length ) ; }
/* Character representation */
for ( i = 0 ; i < short_data_block_length ; i + + ) {
int byte = jisdata [ position + i ] ;
if ( byte & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( byte & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( byte & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( byte & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( byte & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( byte & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( byte & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( byte & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( debug ) { printf ( " 0x%4X " , byte ) ; }
}
if ( debug ) { printf ( " \n " ) ; }
break ;
case ' A ' :
/* Alphanumeric mode */
/* Mode indicator */
concat ( binary , " 0010 " ) ;
/* Character count indicator */
switch ( scheme ) {
case 3 :
if ( short_data_block_length & 0x1000 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x800 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
case 2 :
if ( short_data_block_length & 0x400 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x200 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
case 1 :
if ( short_data_block_length & 0x100 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
break ;
}
if ( debug ) { printf ( " Alpha block (length %d) \n \t " , short_data_block_length ) ; }
/* Character representation */
i = 0 ;
while ( i < short_data_block_length ) {
int count ;
int first = 0 , second = 0 , prod ;
first = posn ( RHODIUM , ( char ) jisdata [ position + i ] ) ;
count = 1 ;
prod = first ;
if ( mode [ position + i + 1 ] = = ' A ' ) {
second = posn ( RHODIUM , ( char ) jisdata [ position + i + 1 ] ) ;
count = 2 ;
prod = ( first * 45 ) + second ;
}
switch ( count ) {
case 2 :
if ( prod & 0x400 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x200 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x100 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
case 1 :
if ( prod & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
break ;
}
if ( debug ) { printf ( " 0x%4X " , prod ) ; }
i + = 2 ;
} ;
if ( debug ) { printf ( " \n " ) ; }
break ;
case ' N ' :
/* Numeric mode */
/* Mode indicator */
concat ( binary , " 0001 " ) ;
/* Character count indicator */
switch ( scheme ) {
case 3 :
if ( short_data_block_length & 0x2000 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x1000 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
case 2 :
if ( short_data_block_length & 0x800 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x400 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
case 1 :
if ( short_data_block_length & 0x200 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x100 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( short_data_block_length & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
break ;
}
if ( debug ) { printf ( " Number block (length %d) \n \t " , short_data_block_length ) ; }
/* Character representation */
i = 0 ;
while ( i < short_data_block_length ) {
int count ;
int first = 0 , second = 0 , third = 0 , prod ;
first = posn ( NEON , ( char ) jisdata [ position + i ] ) ;
count = 1 ;
prod = first ;
if ( mode [ position + i + 1 ] = = ' N ' ) {
second = posn ( NEON , ( char ) jisdata [ position + i + 1 ] ) ;
count = 2 ;
prod = ( prod * 10 ) + second ;
}
if ( mode [ position + i + 2 ] = = ' N ' ) {
third = posn ( NEON , ( char ) jisdata [ position + i + 2 ] ) ;
count = 3 ;
prod = ( prod * 10 ) + third ;
}
switch ( count ) {
case 3 :
if ( prod & 0x200 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x100 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
case 2 :
if ( prod & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
case 1 :
if ( prod & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( prod & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
break ;
}
if ( debug ) { printf ( " 0x%4X (%d) " , prod , prod ) ; }
i + = 3 ;
} ;
if ( debug ) { printf ( " \n " ) ; }
break ;
}
position + = short_data_block_length ;
} while ( position < length - 1 ) ;
/* Terminator */
concat ( binary , " 0000 " ) ;
current_binlen = strlen ( binary ) ;
padbits = 8 - ( current_binlen % 8 ) ;
if ( padbits = = 8 ) { padbits = 0 ; }
current_bytes = ( current_binlen + padbits ) / 8 ;
/* Padding bits */
for ( i = 0 ; i < padbits ; i + + ) {
concat ( binary , " 0 " ) ;
2008-07-13 21:15:55 +00:00
}
2009-10-06 19:03:00 +00:00
/* Put data into 8-bit codewords */
for ( i = 0 ; i < current_bytes ; i + + ) {
datastream [ i ] = 0x00 ;
if ( binary [ i * 8 ] = = ' 1 ' ) { datastream [ i ] + = 0x80 ; }
if ( binary [ i * 8 + 1 ] = = ' 1 ' ) { datastream [ i ] + = 0x40 ; }
if ( binary [ i * 8 + 2 ] = = ' 1 ' ) { datastream [ i ] + = 0x20 ; }
if ( binary [ i * 8 + 3 ] = = ' 1 ' ) { datastream [ i ] + = 0x10 ; }
if ( binary [ i * 8 + 4 ] = = ' 1 ' ) { datastream [ i ] + = 0x08 ; }
if ( binary [ i * 8 + 5 ] = = ' 1 ' ) { datastream [ i ] + = 0x04 ; }
if ( binary [ i * 8 + 6 ] = = ' 1 ' ) { datastream [ i ] + = 0x02 ; }
if ( binary [ i * 8 + 7 ] = = ' 1 ' ) { datastream [ i ] + = 0x01 ; }
}
/* Add pad codewords */
toggle = 0 ;
for ( i = current_bytes ; i < target_binlen ; i + + ) {
if ( toggle = = 0 ) {
datastream [ i ] = 0xec ;
toggle = 1 ;
} else {
datastream [ i ] = 0x11 ;
toggle = 0 ;
}
}
2008-07-13 21:15:55 +00:00
2009-10-06 19:03:00 +00:00
if ( debug ) {
for ( i = 0 ; i < target_binlen ; i + + ) {
printf ( " 0x%2X " , datastream [ i ] ) ;
}
printf ( " \n " ) ;
}
2008-07-13 21:15:55 +00:00
}
2009-10-06 19:03:00 +00:00
void add_ecc ( int fullstream [ ] , int datastream [ ] , int version , int data_cw , int blocks )
2008-07-13 21:15:55 +00:00
{
2009-10-06 19:03:00 +00:00
/* Split data into blocks, add error correction and then interleave the blocks and error correction data */
int ecc_cw = qr_total_codewords [ version - 1 ] - data_cw ;
int short_data_block_length = data_cw / blocks ;
int qty_long_blocks = data_cw % blocks ;
int qty_short_blocks = blocks - qty_long_blocks ;
int ecc_block_length = ecc_cw / blocks ;
int i , j , length_this_block , posn , debug = 1 ;
RS * rs ;
2009-09-29 09:45:46 +00:00
# ifndef _MSC_VER
2009-10-06 19:03:00 +00:00
unsigned char data_block [ short_data_block_length + 2 ] ;
unsigned char ecc_block [ ecc_block_length + 2 ] ;
int interleaved_data [ data_cw + 2 ] ;
int interleaved_ecc [ ecc_cw + 2 ] ;
2009-09-29 09:45:46 +00:00
# else
2009-10-06 19:03:00 +00:00
unsigned char data_block = ( unsigned char * ) _alloca ( short_data_block_length + 2 ) ;
unsigned char ecc_block = ( unsigned char * ) _alloca ( ecc_block_length + 2 ) ;
int interleaved_data = ( int * ) _alloca ( data_cw + 2 ) ;
int interleaved_ecc = ( int * ) _alloca ( ecc_cw + 2 ) ;
2009-09-29 09:45:46 +00:00
# endif
2009-01-11 09:11:03 +00:00
2009-10-06 19:03:00 +00:00
posn = 0 ;
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 ;
}
for ( j = 0 ; j < length_this_block ; j + + ) {
data_block [ j ] = ( unsigned char ) datastream [ posn + j ] ;
}
rs = init_rs ( 8 , 0x11d , 0 , 1 , ecc_block_length , 255 - length_this_block - ecc_block_length ) ;
encode_rs_char ( rs , data_block , ecc_block ) ;
if ( debug ) {
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 [ j ] ) ;
}
printf ( " \n " ) ;
}
for ( j = 0 ; j < short_data_block_length ; j + + ) {
interleaved_data [ ( j * blocks ) + i ] = ( int ) data_block [ j ] ;
}
if ( i > = qty_short_blocks ) {
interleaved_data [ ( short_data_block_length * blocks ) + ( i - qty_short_blocks ) ] = ( int ) data_block [ short_data_block_length ] ;
}
for ( j = 0 ; j < ecc_block_length ; j + + ) {
interleaved_ecc [ ( j * blocks ) + i ] = ( int ) ecc_block [ j ] ;
}
posn + = length_this_block ;
2009-09-29 09:45:46 +00:00
}
2009-10-06 19:03:00 +00:00
free_rs_cache ( ) ;
2009-09-29 09:45:46 +00:00
2009-10-06 19:03:00 +00:00
for ( j = 0 ; j < data_cw ; j + + ) {
fullstream [ j ] = interleaved_data [ j ] ;
}
for ( j = 0 ; j < ecc_cw ; j + + ) {
fullstream [ j + data_cw ] = interleaved_ecc [ j ] ;
}
if ( debug ) {
printf ( " \n Data Stream: \n " ) ;
for ( j = 0 ; j < ( data_cw + ecc_cw ) ; j + + ) {
printf ( " %2X " , fullstream [ j ] ) ;
}
printf ( " \n " ) ;
}
}
void place_finder ( unsigned char grid [ ] , int size , int x , int y )
{
int xp , yp ;
int finder [ ] = {
1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1 , 0 , 0 , 0 , 0 , 0 , 1 ,
1 , 0 , 1 , 1 , 1 , 0 , 1 ,
1 , 0 , 1 , 1 , 1 , 0 , 1 ,
1 , 0 , 1 , 1 , 1 , 0 , 1 ,
1 , 0 , 0 , 0 , 0 , 0 , 1 ,
1 , 1 , 1 , 1 , 1 , 1 , 1
} ;
for ( xp = 0 ; xp < 7 ; xp + + ) {
for ( yp = 0 ; yp < 7 ; yp + + ) {
if ( finder [ xp + ( 7 * yp ) ] = = 1 ) {
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x11 ;
} else {
grid [ ( ( yp + y ) * size ) + ( xp + x ) ] = 0x10 ;
}
2009-08-08 15:25:17 +00:00
}
}
2009-10-06 19:03:00 +00:00
}
void setup_grid ( unsigned char * grid , int size )
{
int i , toggle = 1 ;
for ( i = 0 ; i < size ; i + + ) {
if ( toggle = = 1 ) {
grid [ ( 6 * size ) + i ] = 0x11 ;
grid [ ( i * size ) + 6 ] = 0x11 ;
toggle = 0 ;
} else {
grid [ ( 6 * size ) + i ] = 0x10 ;
grid [ ( i * size ) + 6 ] = 0x10 ;
toggle = 1 ;
}
}
place_finder ( grid , size , 0 , 0 ) ;
place_finder ( grid , size , 0 , size - 7 ) ;
place_finder ( grid , size , size - 7 , 0 ) ;
}
int qr_code ( struct zint_symbol * symbol , unsigned char source [ ] , int length )
{
int error_number , i , j , glyph , est_binlen ;
int ecc_level , autosize , version , max_cw , target_binlen , blocks , size ;
# ifndef _MSC_VER
int utfdata [ length + 1 ] ;
int jisdata [ length + 1 ] ;
char mode [ length + 1 ] ;
# else
int utfdata = ( int * ) _alloca ( ( length + 1 ) * sizeof ( int ) ) ;
int jisdata = ( int * ) _alloca ( ( length + 1 ) * sizeof ( int ) ) ;
char mode = ( char * ) _alloca ( ( length + 1 ) * sizeof ( int ) ) ;
# endif
2009-09-29 09:45:46 +00:00
switch ( symbol - > input_mode ) {
case DATA_MODE :
for ( i = 0 ; i < length ; i + + ) {
2009-10-06 19:03:00 +00:00
jisdata [ i ] = ( int ) source [ i ] ;
2009-09-29 09:45:46 +00:00
}
break ;
2009-10-06 19:03:00 +00:00
default :
/* Convert Unicode input to Shift-JIS */
error_number = utf8toutf16 ( symbol , source , utfdata , & length ) ;
2009-09-29 09:45:46 +00:00
if ( error_number ! = 0 ) { return error_number ; }
2009-10-06 19:03:00 +00:00
for ( i = 0 ; i < length ; i + + ) {
if ( utfdata [ i ] < = 0xff ) {
jisdata [ i ] = utfdata [ i ] ;
} else {
j = 0 ;
glyph = 0 ;
do {
if ( sjis_lookup [ j * 2 ] = = utfdata [ i ] ) {
glyph = sjis_lookup [ ( j * 2 ) + 1 ] ;
}
j + + ;
} while ( ( j < 6843 ) & & ( glyph = = 0 ) ) ;
if ( glyph = = 0 ) {
strcpy ( symbol - > errtxt , " Invalid character in input data " ) ;
return ERROR_INVALID_DATA ;
}
jisdata [ i ] = glyph ;
}
}
2009-09-29 09:45:46 +00:00
break ;
2009-08-08 15:25:17 +00:00
}
2009-10-06 19:03:00 +00:00
define_mode ( mode , jisdata , length ) ;
est_binlen = estimate_binary_length ( mode , length ) ;
ecc_level = LEVEL_L ;
max_cw = 2956 ;
if ( ( symbol - > option_1 > = 1 ) & & ( symbol - > option_1 < = 4 ) ) {
switch ( symbol - > option_1 ) {
case 1 : ecc_level = LEVEL_L ; max_cw = 2956 ; 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 ) ) {
strcpy ( symbol - > errtxt , " Input too long for selected error correction level " ) ;
return 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 ;
}
}
if ( ( symbol - > option_2 > = 1 ) & & ( symbol - > option_2 < = 40 ) ) {
if ( symbol - > option_2 > autosize ) {
version = symbol - > option_2 ;
} else {
version = autosize ;
}
} else {
version = autosize ;
}
target_binlen = qr_data_codewords_L [ version - 1 ] ; blocks = qr_blocks_L [ version - 1 ] ;
switch ( ecc_level ) {
case LEVEL_M : target_binlen = qr_data_codewords_M [ version - 1 ] ; blocks = qr_blocks_M [ version - 1 ] ; break ;
case LEVEL_Q : target_binlen = qr_data_codewords_Q [ version - 1 ] ; blocks = qr_blocks_Q [ version - 1 ] ; break ;
case LEVEL_H : target_binlen = qr_data_codewords_H [ version - 1 ] ; blocks = qr_blocks_H [ version - 1 ] ; break ;
}
# ifndef _MSC_VER
int datastream [ target_binlen + 1 ] ;
int fullstream [ qr_total_codewords [ version - 1 ] + 1 ] ;
# else
int datastream = ( int * ) _alloca ( ( target_binlen + 1 ) * sizeof ( int ) ) ;
int fullstream = ( int * ) _alloca ( ( qr_total_codewords [ version - 1 ] + 1 ) * sizeof ( int ) ) ;
# endif
2009-08-08 15:25:17 +00:00
2009-10-06 19:03:00 +00:00
qr_binary ( datastream , version , target_binlen , mode , jisdata , length ) ;
add_ecc ( fullstream , datastream , version , target_binlen , blocks ) ;
size = qr_sizes [ version - 1 ] ;
# ifndef _MSC_VER
unsigned char grid [ size * size ] ;
# else
unsigned char grid = ( unsigned char * ) _alloca ( ( size * size ) * sizeof ( unsigned char ) ) ;
# endif
for ( i = 0 ; i < size ; i + + ) {
for ( j = 0 ; j < size ; j + + ) {
grid [ ( i * size ) + j ] = 0 ;
}
2008-07-13 21:15:55 +00:00
}
2009-10-06 19:03:00 +00:00
setup_grid ( grid , size ) ;
2008-07-13 21:15:55 +00:00
2009-10-06 19:03:00 +00: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 ) {
2009-05-31 20:33:54 +00:00
set_module ( symbol , i , j ) ;
2008-07-13 21:15:55 +00:00
}
}
symbol - > row_height [ i ] = 1 ;
}
2009-10-06 19:03:00 +00:00
printf ( " Version %d: target %d bytes \n " , version , target_binlen ) ;
2008-07-13 21:15:55 +00:00
2009-06-02 20:23:38 +00:00
return 0 ;
2008-07-13 21:15:55 +00:00
}
2008-09-02 19:49:08 +00:00