2009-09-29 13:45:46 +04:00
/* gridmtx.c - Grid Matrix
libzint - the open source barcode library
Copyright ( C ) 2009 Robin Stuart < robin @ zint . org . uk >
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 .
*/
/* This file impliments Grid Matrix as specified in
AIM Global Document Number AIMD014 Rev . 1.63 Revised 9 Dec 2008 */
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# ifdef _MSC_VER
# include <malloc.h>
# endif
# include "common.h"
# include "reedsol.h"
# include "gridmtx.h"
2009-10-21 13:08:44 +04:00
# include "gb2312.h"
int number_lat ( int gbdata [ ] , int length , int position )
{
/* Attempt to calculate the 'cost' of using numeric mode from a given position in number of bits */
/* Also ensures that numeric mode is not selected when it cannot be used: for example in
a string which has " 2.2.0 " ( cannot have more than one non - numeric character for each
block of three numeric characters ) */
int sp ;
int numb = 0 , nonum = 0 , done ;
int tally = 0 ;
sp = position ;
do {
done = 0 ;
if ( ( gbdata [ sp ] > = ' 0 ' ) & & ( gbdata [ sp ] < = ' 9 ' ) ) { numb + + ; done = 1 ; }
switch ( gbdata [ sp ] ) {
case ' ' :
case ' + ' :
case ' - ' :
case ' . ' :
case ' , ' :
nonum + + ;
done = 1 ;
}
if ( ( sp + 1 ) < length ) {
if ( ( gbdata [ sp ] = = 0x13 ) & & ( gbdata [ sp + 1 ] = = 0x10 ) ) {
nonum + + ;
done = 1 ;
sp + + ;
}
}
if ( done = = 0 ) {
tally + = 80 ;
} else {
if ( numb = = 3 ) {
if ( nonum = = 0 ) {
tally + = 10 ;
}
if ( nonum = = 1 ) {
tally + = 20 ;
}
if ( nonum > 1 ) {
tally + = 80 ;
}
numb = 0 ;
nonum = 0 ;
}
}
sp + + ;
} while ( ( sp < length ) & & ( sp < = ( position + 8 ) ) ) ;
if ( numb = = 0 ) {
tally + = 80 ;
}
if ( numb > 1 ) {
if ( nonum = = 0 ) {
tally + = 10 ;
}
if ( nonum = = 1 ) {
tally + = 20 ;
}
if ( nonum > 1 ) {
tally + = 80 ;
}
}
return tally ;
}
int seek_forward ( int gbdata [ ] , int length , int position , int current_mode )
{
/* In complete contrast to the method recommended in Annex D of the ANSI standard this
code uses a look - ahead test in the same manner as Data Matrix . This decision was made
because the " official " algorithm does not provide clear methods for dealing with all
possible combinations of input data */
int number_count , byte_count , mixed_count , upper_count , lower_count , chinese_count ;
int sp , best_mode , done ;
int best_count , last = - 1 ;
int debug = 0 ;
if ( gbdata [ position ] > 0xff ) { return GM_CHINESE ; }
switch ( current_mode ) {
case GM_CHINESE :
number_count = 13 ;
byte_count = 13 ;
mixed_count = 13 ;
upper_count = 13 ;
lower_count = 13 ;
chinese_count = 0 ;
break ;
case GM_NUMBER :
number_count = 0 ;
byte_count = 10 ;
mixed_count = 10 ;
upper_count = 10 ;
lower_count = 10 ;
chinese_count = 10 ;
break ;
case GM_LOWER :
number_count = 5 ;
byte_count = 7 ;
mixed_count = 7 ;
upper_count = 5 ;
lower_count = 0 ;
chinese_count = 5 ;
break ;
case GM_UPPER :
number_count = 5 ;
byte_count = 7 ;
mixed_count = 7 ;
upper_count = 0 ;
lower_count = 5 ;
chinese_count = 5 ;
break ;
case GM_MIXED :
number_count = 10 ;
byte_count = 10 ;
mixed_count = 0 ;
upper_count = 10 ;
lower_count = 10 ;
chinese_count = 10 ;
break ;
case GM_BYTE :
number_count = 4 ;
byte_count = 0 ;
mixed_count = 4 ;
upper_count = 4 ;
lower_count = 4 ;
chinese_count = 4 ;
default : /* Start of symbol */
number_count = 4 ;
byte_count = 4 ;
mixed_count = 4 ;
upper_count = 4 ;
lower_count = 4 ;
chinese_count = 4 ;
}
for ( sp = position ; ( sp < length ) & & ( sp < = ( position + 8 ) ) ; sp + + ) {
done = 0 ;
if ( gbdata [ sp ] > = 0xff ) {
byte_count + = 17 ;
mixed_count + = 23 ;
upper_count + = 18 ;
lower_count + = 18 ;
chinese_count + = 13 ;
done = 1 ;
}
if ( ( gbdata [ sp ] > = ' a ' ) & & ( gbdata [ sp ] < = ' z ' ) ) {
byte_count + = 8 ;
mixed_count + = 6 ;
upper_count + = 10 ;
lower_count + = 5 ;
chinese_count + = 13 ;
done = 1 ;
}
if ( ( gbdata [ sp ] > = ' A ' ) & & ( gbdata [ sp ] < = ' Z ' ) ) {
byte_count + = 8 ;
mixed_count + = 6 ;
upper_count + = 5 ;
lower_count + = 10 ;
chinese_count + = 13 ;
done = 1 ;
}
if ( ( gbdata [ sp ] > = ' 0 ' ) & & ( gbdata [ sp ] < = ' 9 ' ) ) {
byte_count + = 8 ;
mixed_count + = 6 ;
upper_count + = 8 ;
lower_count + = 8 ;
chinese_count + = 13 ;
done = 1 ;
}
if ( gbdata [ sp ] = = ' ' ) {
byte_count + = 8 ;
mixed_count + = 6 ;
upper_count + = 5 ;
lower_count + = 5 ;
chinese_count + = 13 ;
done = 1 ;
}
if ( done = = 0 ) {
/* Control character */
byte_count + = 8 ;
mixed_count + = 16 ;
upper_count + = 13 ;
lower_count + = 13 ;
chinese_count + = 13 ;
}
if ( gbdata [ sp ] > = 0x7f ) {
mixed_count + = 20 ;
upper_count + = 20 ;
lower_count + = 20 ;
}
}
/* Adjust for <end of line> */
for ( sp = position ; ( sp < ( length - 1 ) ) & & ( sp < = ( position + 7 ) ) ; sp + + ) {
if ( ( gbdata [ sp ] = = 0x13 ) & & ( gbdata [ sp ] = = 0x10 ) ) {
chinese_count - = 13 ;
}
}
/* Adjust for double digits */
for ( sp = position ; ( sp < ( length - 1 ) ) & & ( sp < = ( position + 7 ) ) ; sp + + ) {
if ( sp ! = last ) {
if ( ( ( gbdata [ sp ] > = ' 0 ' ) & & ( gbdata [ sp ] < = ' 9 ' ) ) & & ( ( gbdata [ sp + 1 ] > = ' 0 ' ) & & ( gbdata [ sp + 1 ] < = ' 9 ' ) ) ) {
chinese_count - = 13 ;
last = sp + 1 ;
}
}
}
/* Numeric mode is more complex */
number_count + = number_lat ( gbdata , length , position ) ;
if ( debug ) { printf ( " C %d / B %d / M %d / U %d / L %d / N %d \n " , chinese_count , byte_count , mixed_count , upper_count , lower_count , number_count ) ; }
best_count = chinese_count ;
best_mode = GM_CHINESE ;
if ( byte_count < = best_count ) {
best_count = byte_count ;
best_mode = GM_BYTE ;
}
if ( mixed_count < = best_count ) {
best_count = mixed_count ;
best_mode = GM_MIXED ;
}
if ( upper_count < = best_count ) {
best_count = upper_count ;
best_mode = GM_UPPER ;
}
if ( lower_count < = best_count ) {
best_count = lower_count ;
best_mode = GM_LOWER ;
}
if ( number_count < = best_count ) {
best_count = number_count ;
best_mode = GM_NUMBER ;
}
return best_mode ;
}
void add_byte_count ( char binary [ ] , int byte_count_posn , int byte_count )
{
/* Add the length indicator for byte encoded blocks */
if ( byte_count & 0x100 ) { binary [ byte_count_posn ] = ' 0 ' ; } else { binary [ byte_count_posn ] = ' 1 ' ; }
if ( byte_count & 0x80 ) { binary [ byte_count_posn + 1 ] = ' 0 ' ; } else { binary [ byte_count_posn + 1 ] = ' 1 ' ; }
if ( byte_count & 0x40 ) { binary [ byte_count_posn + 2 ] = ' 0 ' ; } else { binary [ byte_count_posn + 2 ] = ' 1 ' ; }
if ( byte_count & 0x20 ) { binary [ byte_count_posn + 3 ] = ' 0 ' ; } else { binary [ byte_count_posn + 3 ] = ' 1 ' ; }
if ( byte_count & 0x10 ) { binary [ byte_count_posn + 4 ] = ' 0 ' ; } else { binary [ byte_count_posn + 4 ] = ' 1 ' ; }
if ( byte_count & 0x08 ) { binary [ byte_count_posn + 5 ] = ' 0 ' ; } else { binary [ byte_count_posn + 5 ] = ' 1 ' ; }
if ( byte_count & 0x04 ) { binary [ byte_count_posn + 6 ] = ' 0 ' ; } else { binary [ byte_count_posn + 6 ] = ' 1 ' ; }
if ( byte_count & 0x02 ) { binary [ byte_count_posn + 7 ] = ' 0 ' ; } else { binary [ byte_count_posn + 7 ] = ' 1 ' ; }
if ( byte_count & 0x01 ) { binary [ byte_count_posn + 8 ] = ' 0 ' ; } else { binary [ byte_count_posn + 8 ] = ' 1 ' ; }
}
void add_shift_char ( char binary [ ] , int shifty )
{
/* Add a control character to the data stream */
int i , debug = 0 ;
int glyph = 0 ;
for ( i = 0 ; i < 64 ; i + + ) {
if ( shift_set [ i ] = = shifty ) {
glyph = i ;
}
}
if ( debug ) { printf ( " SHIFT [%d] " , glyph ) ; }
if ( glyph & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
}
2009-12-05 02:18:48 +03:00
int gm_encode ( int gbdata [ ] , int length , char binary [ ] , int reader )
2009-10-21 13:08:44 +04:00
{
/* Create a binary stream representation of the input data.
7 sets are defined - Chinese characters , Numerals , Lower case letters , Upper case letters ,
Mixed numerals and latters , Control characters and 8 - bit binary data */
int sp , current_mode , next_mode , last_mode , glyph = 0 ;
int c1 , c2 , done ;
int p = 0 , ppos ;
int numbuf [ 3 ] , punt = 0 ;
int number_pad_posn , debug = 0 ;
int byte_count_posn = 0 , byte_count = 0 ;
int shift , i ;
strcpy ( binary , " " ) ;
sp = 0 ;
current_mode = 0 ;
last_mode = 0 ;
number_pad_posn = 0 ;
2009-12-05 02:18:48 +03:00
if ( reader ) {
concat ( binary , " 1010 " ) ; /* FNC3 - Reader Initialisation */
}
2009-10-21 13:08:44 +04:00
do {
next_mode = seek_forward ( gbdata , length , sp , current_mode ) ;
if ( next_mode ! = current_mode ) {
switch ( current_mode ) {
case 0 :
switch ( next_mode ) {
case GM_CHINESE : concat ( binary , " 0001 " ) ; break ;
case GM_NUMBER : concat ( binary , " 0010 " ) ; break ;
case GM_LOWER : concat ( binary , " 0011 " ) ; break ;
case GM_UPPER : concat ( binary , " 0100 " ) ; break ;
case GM_MIXED : concat ( binary , " 0101 " ) ; break ;
case GM_BYTE : concat ( binary , " 0111 " ) ; break ;
}
break ;
case GM_CHINESE :
switch ( next_mode ) {
case GM_NUMBER : concat ( binary , " 1111111100001 " ) ; break ; // 8161
case GM_LOWER : concat ( binary , " 1111111100010 " ) ; break ; // 8162
case GM_UPPER : concat ( binary , " 1111111100011 " ) ; break ; // 8163
case GM_MIXED : concat ( binary , " 1111111100100 " ) ; break ; // 8164
case GM_BYTE : concat ( binary , " 1111111100101 " ) ; break ; // 8165
}
break ;
case GM_NUMBER :
/* add numeric block padding value */
switch ( p ) {
case 1 : binary [ number_pad_posn ] = ' 1 ' ; binary [ number_pad_posn + 1 ] = ' 0 ' ; break ; // 2 pad digits
case 2 : binary [ number_pad_posn ] = ' 0 ' ; binary [ number_pad_posn + 1 ] = ' 1 ' ; break ; // 1 pad digit
case 3 : binary [ number_pad_posn ] = ' 0 ' ; binary [ number_pad_posn + 1 ] = ' 0 ' ; break ; // 0 pad digits
}
switch ( next_mode ) {
case GM_CHINESE : concat ( binary , " 1111111011 " ) ; break ; // 1019
case GM_LOWER : concat ( binary , " 1111111100 " ) ; break ; // 1020
case GM_UPPER : concat ( binary , " 1111111101 " ) ; break ; // 1021
case GM_MIXED : concat ( binary , " 1111111110 " ) ; break ; // 1022
case GM_BYTE : concat ( binary , " 1111111111 " ) ; break ; // 1023
}
break ;
case GM_LOWER :
case GM_UPPER :
switch ( next_mode ) {
case GM_CHINESE : concat ( binary , " 11100 " ) ; break ; // 28
case GM_NUMBER : concat ( binary , " 11101 " ) ; break ; // 29
case GM_LOWER :
case GM_UPPER : concat ( binary , " 11110 " ) ; break ; // 30
case GM_MIXED : concat ( binary , " 1111100 " ) ; break ; // 124
case GM_BYTE : concat ( binary , " 1111110 " ) ; break ; // 126
}
break ;
case GM_MIXED :
switch ( next_mode ) {
case GM_CHINESE : concat ( binary , " 1111110001 " ) ; break ; // 1009
case GM_NUMBER : concat ( binary , " 1111110010 " ) ; break ; // 1010
case GM_LOWER : concat ( binary , " 1111110011 " ) ; break ; // 1011
case GM_UPPER : concat ( binary , " 1111110100 " ) ; break ; // 1012
case GM_BYTE : concat ( binary , " 1111110111 " ) ; break ; // 1015
}
break ;
case GM_BYTE :
/* add byte block length indicator */
add_byte_count ( binary , byte_count_posn , byte_count ) ;
byte_count = 0 ;
switch ( next_mode ) {
case GM_CHINESE : concat ( binary , " 0001 " ) ; break ; // 1
case GM_NUMBER : concat ( binary , " 0010 " ) ; break ; // 2
case GM_LOWER : concat ( binary , " 0011 " ) ; break ; // 3
case GM_UPPER : concat ( binary , " 0100 " ) ; break ; // 4
case GM_MIXED : concat ( binary , " 0101 " ) ; break ; // 5
}
break ;
}
if ( debug ) {
switch ( next_mode ) {
case GM_CHINESE : printf ( " CHIN " ) ; break ;
case GM_NUMBER : printf ( " NUMB " ) ; break ;
case GM_LOWER : printf ( " LOWR " ) ; break ;
case GM_UPPER : printf ( " UPPR " ) ; break ;
case GM_MIXED : printf ( " MIXD " ) ; break ;
case GM_BYTE : printf ( " BYTE " ) ; break ;
}
}
}
last_mode = current_mode ;
current_mode = next_mode ;
switch ( current_mode ) {
case GM_CHINESE :
done = 0 ;
if ( gbdata [ sp ] > 0xff ) {
/* GB2312 character */
c1 = ( gbdata [ sp ] & 0xff00 ) > > 8 ;
c2 = gbdata [ sp ] & 0xff ;
if ( ( c1 > = 0xa0 ) & & ( c1 < = 0xa9 ) ) {
glyph = ( 0x60 * ( c1 - 0xa1 ) ) + ( c2 - 0xa0 ) ;
}
if ( ( c1 > = 0xb0 ) & & ( c1 < = 0xf7 ) ) {
glyph = ( 0x60 * ( c1 - 0xb0 + 9 ) ) + ( c2 - 0xa0 ) ;
}
done = 1 ;
}
if ( ! ( done ) ) {
if ( sp ! = ( length - 1 ) ) {
if ( ( gbdata [ sp ] = = 0x13 ) & & ( gbdata [ sp + 1 ] = = 0x10 ) ) {
/* End of Line */
glyph = 7776 ;
sp + + ;
}
done = 1 ;
}
}
if ( ! ( done ) ) {
if ( sp ! = ( length - 1 ) ) {
if ( ( ( gbdata [ sp ] > = ' 0 ' ) & & ( gbdata [ sp ] < = ' 9 ' ) ) & &
( ( gbdata [ sp + 1 ] > = ' 0 ' ) & & ( gbdata [ sp + 1 ] < = ' 9 ' ) ) ) {
/* Two digits */
glyph = 8033 + ( 10 * ( gbdata [ sp ] - ' 0 ' ) ) + ( gbdata [ sp + 1 ] - ' 0 ' ) ;
sp + + ;
}
}
}
if ( ! ( done ) ) {
/* Byte value */
glyph = 7777 + gbdata [ sp ] ;
}
if ( debug ) { printf ( " [%d] " , glyph ) ; }
if ( glyph & 0x1000 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x800 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x400 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x200 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x100 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
sp + + ;
break ;
case GM_NUMBER :
if ( last_mode ! = current_mode ) {
/* Reserve a space for numeric digit padding value (2 bits) */
number_pad_posn = strlen ( binary ) ;
concat ( binary , " XX " ) ;
}
p = 0 ;
ppos = - 1 ;
/* Numeric compression can also include certain combinations of
non - numeric character */
numbuf [ 0 ] = ' 0 ' ;
numbuf [ 1 ] = ' 0 ' ;
numbuf [ 2 ] = ' 0 ' ;
do {
if ( ( gbdata [ sp ] > = ' 0 ' ) & & ( gbdata [ sp ] < = ' 9 ' ) ) {
numbuf [ p ] = gbdata [ sp ] ;
sp + + ;
p + + ;
}
switch ( gbdata [ sp ] ) {
case ' ' :
case ' + ' :
case ' - ' :
case ' . ' :
case ' , ' :
punt = gbdata [ sp ] ;
sp + + ;
ppos = p ;
break ;
}
if ( sp < ( length - 1 ) ) {
if ( ( gbdata [ sp ] = = 0x13 ) & & ( gbdata [ sp + 1 ] = = 0x10 ) ) {
/* <end of line> */
punt = gbdata [ sp ] ;
sp + = 2 ;
ppos = p ;
}
}
} while ( ( p < 3 ) & & ( sp < length ) ) ;
if ( ppos ! = - 1 ) {
switch ( punt ) {
case ' ' : glyph = 0 ; break ;
case ' + ' : glyph = 3 ; break ;
case ' - ' : glyph = 6 ; break ;
case ' . ' : glyph = 9 ; break ;
case ' , ' : glyph = 12 ; break ;
case 0x13 : glyph = 15 ; break ;
}
glyph + = ppos ;
glyph + = 1000 ;
if ( debug ) { printf ( " [%d] " , glyph ) ; }
if ( glyph & 0x200 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x100 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
}
glyph = ( 100 * ( numbuf [ 0 ] - ' 0 ' ) ) + ( 10 * ( numbuf [ 1 ] - ' 0 ' ) ) + ( numbuf [ 2 ] - ' 0 ' ) ;
if ( debug ) { printf ( " [%d] " , glyph ) ; }
if ( glyph & 0x200 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x100 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
break ;
case GM_BYTE :
if ( last_mode ! = current_mode ) {
/* Reserve space for byte block length indicator (9 bits) */
byte_count_posn = strlen ( binary ) ;
concat ( binary , " LLLLLLLLL " ) ;
}
if ( byte_count = = 512 ) {
/* Maximum byte block size is 512 bytes. If longer is needed then start a new block */
add_byte_count ( binary , byte_count_posn , byte_count ) ;
concat ( binary , " 0111 " ) ;
byte_count_posn = strlen ( binary ) ;
concat ( binary , " LLLLLLLLL " ) ;
byte_count = 0 ;
}
glyph = gbdata [ sp ] ;
if ( debug ) { printf ( " [%d] " , glyph ) ; }
if ( glyph & 0x80 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x40 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
sp + + ;
byte_count + + ;
break ;
case GM_MIXED :
shift = 1 ;
if ( ( gbdata [ sp ] > = ' 0 ' ) & & ( gbdata [ sp ] < = ' 9 ' ) ) { shift = 0 ; }
if ( ( gbdata [ sp ] > = ' A ' ) & & ( gbdata [ sp ] < = ' Z ' ) ) { shift = 0 ; }
if ( ( gbdata [ sp ] > = ' a ' ) & & ( gbdata [ sp ] < = ' z ' ) ) { shift = 0 ; }
if ( gbdata [ sp ] = = ' ' ) { shift = 0 ; }
if ( shift = = 0 ) {
/* Mixed Mode character */
glyph = posn ( EUROPIUM , gbdata [ sp ] ) ;
if ( debug ) { printf ( " [%d] " , glyph ) ; }
if ( glyph & 0x20 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
} else {
/* Shift Mode character */
concat ( binary , " 1111110110 " ) ; /* 1014 - shift indicator */
add_shift_char ( binary , gbdata [ sp ] ) ;
}
sp + + ;
break ;
case GM_UPPER :
shift = 1 ;
if ( ( gbdata [ sp ] > = ' A ' ) & & ( gbdata [ sp ] < = ' Z ' ) ) { shift = 0 ; }
if ( gbdata [ sp ] = = ' ' ) { shift = 0 ; }
if ( shift = = 0 ) {
/* Upper Case character */
glyph = posn ( " ABCDEFGHIJKLMNOPQRSTUVWXYZ " , gbdata [ sp ] ) ;
if ( debug ) { printf ( " [%d] " , glyph ) ; }
if ( glyph & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
} else {
/* Shift Mode character */
concat ( binary , " 1111101 " ) ; /* 127 - shift indicator */
add_shift_char ( binary , gbdata [ sp ] ) ;
}
sp + + ;
break ;
case GM_LOWER :
shift = 1 ;
if ( ( gbdata [ sp ] > = ' a ' ) & & ( gbdata [ sp ] < = ' z ' ) ) { shift = 0 ; }
if ( gbdata [ sp ] = = ' ' ) { shift = 0 ; }
if ( shift = = 0 ) {
/* Lower Case character */
glyph = posn ( " abcdefghijklmnopqrstuvwxyz " , gbdata [ sp ] ) ;
if ( debug ) { printf ( " [%d] " , glyph ) ; }
if ( glyph & 0x10 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x08 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x04 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x02 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
if ( glyph & 0x01 ) { concat ( binary , " 1 " ) ; } else { concat ( binary , " 0 " ) ; }
} else {
/* Shift Mode character */
concat ( binary , " 1111101 " ) ; /* 127 - shift indicator */
add_shift_char ( binary , gbdata [ sp ] ) ;
}
sp + + ;
break ;
}
if ( strlen ( binary ) > 9191 ) {
return ERROR_TOO_LONG ;
}
} while ( sp < length ) ;
if ( current_mode = = GM_NUMBER ) {
/* add numeric block padding value */
switch ( p ) {
case 1 : binary [ number_pad_posn ] = ' 1 ' ; binary [ number_pad_posn + 1 ] = ' 0 ' ; break ; // 2 pad digits
case 2 : binary [ number_pad_posn ] = ' 0 ' ; binary [ number_pad_posn + 1 ] = ' 1 ' ; break ; // 1 pad digit
case 3 : binary [ number_pad_posn ] = ' 0 ' ; binary [ number_pad_posn + 1 ] = ' 0 ' ; break ; // 0 pad digits
}
}
if ( current_mode = = GM_BYTE ) {
/* Add byte block length indicator */
add_byte_count ( binary , byte_count_posn , byte_count ) ;
}
/* Add "end of data" character */
switch ( current_mode ) {
case GM_CHINESE : concat ( binary , " 1111111100000 " ) ; break ; // 8160
case GM_NUMBER : concat ( binary , " 1111111010 " ) ; break ; // 1018
case GM_LOWER :
case GM_UPPER : concat ( binary , " 11011 " ) ; break ; // 27
case GM_MIXED : concat ( binary , " 1111110000 " ) ; break ; // 1008
case GM_BYTE : concat ( binary , " 0000 " ) ; break ; // 0
}
/* Add padding bits if required */
p = 7 - ( strlen ( binary ) % 7 ) ;
if ( p = = 7 ) { p = 0 ; }
for ( i = 0 ; i < p ; i + + ) {
concat ( binary , " 0 " ) ;
}
if ( strlen ( binary ) > 9191 ) {
return ERROR_TOO_LONG ;
}
return 0 ;
}
void gm_add_ecc ( char binary [ ] , int data_posn , int layers , int ecc_level , int word [ ] )
{
int total_cw , data_cw , i , j , wp ;
int n1 , b1 , n2 , b2 , e1 , b3 , e2 ;
int block_size , data_size , ecc_size , toggle ;
int data [ 1320 ] , block [ 130 ] ;
unsigned char data_block [ 115 ] , ecc_block [ 70 ] ;
total_cw = gm_total_cw [ ( layers - 1 ) ] ;
data_cw = gm_data_codewords [ ( ( layers - 1 ) * 5 ) + ( ecc_level - 1 ) ] ;
for ( i = 0 ; i < 1320 ; i + + ) {
data [ i ] = 0 ;
}
/* Convert from binary sream to 7-bit codewords */
for ( i = 0 ; i < data_posn ; i + + ) {
if ( binary [ i * 7 ] = = ' 1 ' ) { data [ i ] + = 0x40 ; }
if ( binary [ ( i * 7 ) + 1 ] = = ' 1 ' ) { data [ i ] + = 0x20 ; }
if ( binary [ ( i * 7 ) + 2 ] = = ' 1 ' ) { data [ i ] + = 0x10 ; }
if ( binary [ ( i * 7 ) + 3 ] = = ' 1 ' ) { data [ i ] + = 0x08 ; }
if ( binary [ ( i * 7 ) + 4 ] = = ' 1 ' ) { data [ i ] + = 0x04 ; }
if ( binary [ ( i * 7 ) + 5 ] = = ' 1 ' ) { data [ i ] + = 0x02 ; }
if ( binary [ ( i * 7 ) + 6 ] = = ' 1 ' ) { data [ i ] + = 0x01 ; }
}
/* Add padding codewords */
data [ data_posn ] = 0x00 ;
for ( i = ( data_posn + 1 ) ; i < data_cw ; i + + ) {
if ( i % 2 ) {
data [ i ] = 0x7e ;
toggle = 1 ;
} else {
data [ i ] = 0x00 ;
toggle = 0 ;
}
}
/* Get block sizes */
n1 = gm_n1 [ ( layers - 1 ) ] ;
b1 = gm_b1 [ ( layers - 1 ) ] ;
n2 = n1 - 1 ;
b2 = gm_b2 [ ( layers - 1 ) ] ;
e1 = gm_ebeb [ ( ( layers - 1 ) * 20 ) + ( ( ecc_level - 1 ) * 4 ) ] ;
b3 = gm_ebeb [ ( ( layers - 1 ) * 20 ) + ( ( ecc_level - 1 ) * 4 ) + 1 ] ;
e2 = gm_ebeb [ ( ( layers - 1 ) * 20 ) + ( ( ecc_level - 1 ) * 4 ) + 2 ] ;
/* Split the data into blocks */
wp = 0 ;
for ( i = 0 ; i < ( b1 + b2 ) ; i + + ) {
if ( i < b1 ) { block_size = n1 ; } else { block_size = n2 ; }
if ( i < b3 ) { ecc_size = e1 ; } else { ecc_size = e2 ; }
data_size = block_size - ecc_size ;
/* printf("block %d/%d: data %d / ecc %d\n", i + 1, (b1 + b2), data_size, ecc_size);*/
for ( j = 0 ; j < data_size ; j + + ) {
data_block [ j ] = data [ wp ] ;
wp + + ;
}
/* Calculate ECC data for this block */
rs_init_gf ( 0x89 ) ;
rs_init_code ( ecc_size , 1 ) ;
rs_encode ( data_size , data_block , ecc_block ) ;
rs_free ( ) ;
/* Correct error correction data but in reverse order */
for ( j = 0 ; j < data_size ; j + + ) {
block [ j ] = data_block [ j ] ;
}
for ( j = 0 ; j < ecc_size ; j + + ) {
block [ ( j + data_size ) ] = ecc_block [ ecc_size - j - 1 ] ;
}
for ( j = 0 ; j < n2 ; j + + ) {
word [ ( ( b1 + b2 ) * j ) + i ] = block [ j ] ;
}
if ( block_size = = n1 ) {
word [ ( ( b1 + b2 ) * ( n1 - 1 ) ) + i ] = block [ ( n1 - 1 ) ] ;
}
}
}
void place_macromodule ( char grid [ ] , int x , int y , int word1 , int word2 , int size )
{
int i , j ;
i = ( x * 6 ) + 1 ;
j = ( y * 6 ) + 1 ;
if ( word2 & 0x40 ) { grid [ ( j * size ) + i + 2 ] = ' 1 ' ; }
if ( word2 & 0x20 ) { grid [ ( j * size ) + i + 3 ] = ' 1 ' ; }
if ( word2 & 0x10 ) { grid [ ( ( j + 1 ) * size ) + i ] = ' 1 ' ; }
if ( word2 & 0x08 ) { grid [ ( ( j + 1 ) * size ) + i + 1 ] = ' 1 ' ; }
if ( word2 & 0x04 ) { grid [ ( ( j + 1 ) * size ) + i + 2 ] = ' 1 ' ; }
if ( word2 & 0x02 ) { grid [ ( ( j + 1 ) * size ) + i + 3 ] = ' 1 ' ; }
if ( word2 & 0x01 ) { grid [ ( ( j + 2 ) * size ) + i ] = ' 1 ' ; }
if ( word1 & 0x40 ) { grid [ ( ( j + 2 ) * size ) + i + 1 ] = ' 1 ' ; }
if ( word1 & 0x20 ) { grid [ ( ( j + 2 ) * size ) + i + 2 ] = ' 1 ' ; }
if ( word1 & 0x10 ) { grid [ ( ( j + 2 ) * size ) + i + 3 ] = ' 1 ' ; }
if ( word1 & 0x08 ) { grid [ ( ( j + 3 ) * size ) + i ] = ' 1 ' ; }
if ( word1 & 0x04 ) { grid [ ( ( j + 3 ) * size ) + i + 1 ] = ' 1 ' ; }
if ( word1 & 0x02 ) { grid [ ( ( j + 3 ) * size ) + i + 2 ] = ' 1 ' ; }
if ( word1 & 0x01 ) { grid [ ( ( j + 3 ) * size ) + i + 3 ] = ' 1 ' ; }
}
void place_data_in_grid ( int word [ ] , char grid [ ] , int modules , int size )
{
int x , y , macromodule , offset ;
offset = 13 - ( ( modules - 1 ) / 2 ) ;
for ( y = 0 ; y < modules ; y + + ) {
for ( x = 0 ; x < modules ; x + + ) {
macromodule = gm_macro_matrix [ ( ( y + offset ) * 27 ) + ( x + offset ) ] ;
place_macromodule ( grid , x , y , word [ macromodule * 2 ] , word [ ( macromodule * 2 ) + 1 ] , size ) ;
}
}
}
void place_layer_id ( char * grid , int size , int layers , int modules , int ecc_level )
{
/* Place the layer ID into each macromodule */
int i , j , layer , start , stop ;
# ifndef _MSC_VER
int layerid [ layers + 1 ] ;
int id [ modules * modules ] ;
# else
int * layerid = ( int * ) _alloca ( ( layers + 1 ) * sizeof ( int ) ) ;
int * id = ( int * ) _alloca ( ( modules * modules ) * sizeof ( int ) ) ;
# endif
/* Calculate Layer IDs */
for ( i = 0 ; i < = layers ; i + + ) {
if ( ecc_level = = 1 ) {
layerid [ i ] = 3 - ( i % 4 ) ;
} else {
layerid [ i ] = ( i + 5 - ecc_level ) % 4 ;
}
}
for ( i = 0 ; i < modules ; i + + ) {
for ( j = 0 ; j < modules ; j + + ) {
id [ ( i * modules ) + j ] = 0 ;
}
}
/* Calculate which value goes in each macromodule */
start = modules / 2 ;
stop = modules / 2 ;
for ( layer = 0 ; layer < = layers ; layer + + ) {
for ( i = start ; i < = stop ; i + + ) {
id [ ( start * modules ) + i ] = layerid [ layer ] ;
id [ ( i * modules ) + start ] = layerid [ layer ] ;
id [ ( ( modules - start - 1 ) * modules ) + i ] = layerid [ layer ] ;
id [ ( i * modules ) + ( modules - start - 1 ) ] = layerid [ layer ] ;
}
start - - ;
stop + + ;
}
/* Place the data in the grid */
for ( i = 0 ; i < modules ; i + + ) {
for ( j = 0 ; j < modules ; j + + ) {
if ( id [ ( i * modules ) + j ] & 0x02 ) {
grid [ ( ( ( i * 6 ) + 1 ) * size ) + ( j * 6 ) + 1 ] = ' 1 ' ;
}
if ( id [ ( i * modules ) + j ] & 0x01 ) {
grid [ ( ( ( i * 6 ) + 1 ) * size ) + ( j * 6 ) + 2 ] = ' 1 ' ;
}
}
}
}
2009-09-29 13:45:46 +04:00
2009-10-06 23:03:00 +04:00
int grid_matrix ( struct zint_symbol * symbol , unsigned char source [ ] , int length )
2009-09-29 13:45:46 +04:00
{
2009-10-21 13:08:44 +04:00
int size , modules , dark , error_number ;
2009-11-01 01:42:10 +03:00
int auto_layers , min_layers , layers , auto_ecc_level , min_ecc_level , ecc_level ;
int x , y , i , j , glyph ;
2009-10-21 13:08:44 +04:00
char binary [ 9300 ] ;
2009-11-02 18:47:08 +03:00
int data_cw , input_latch = 0 ;
2009-12-05 02:18:48 +03:00
int word [ 1460 ] , data_max , reader = 0 ;
2009-10-21 13:08:44 +04:00
# ifndef _MSC_VER
int utfdata [ length + 1 ] ;
int gbdata [ length + 1 ] ;
# else
int * utfdata = ( int * ) _alloca ( ( length + 1 ) * sizeof ( int ) ) ;
int * gbdata = ( int * ) _alloca ( ( length + 1 ) * sizeof ( int ) ) ;
# endif
for ( i = 0 ; i < 1460 ; i + + ) {
word [ i ] = 0 ;
}
switch ( symbol - > input_mode ) {
case DATA_MODE :
for ( i = 0 ; i < length ; i + + ) {
gbdata [ i ] = ( int ) source [ i ] ;
}
break ;
default :
/* Convert Unicode input to GB-2312 */
error_number = utf8toutf16 ( symbol , source , utfdata , & length ) ;
if ( error_number ! = 0 ) { return error_number ; }
for ( i = 0 ; i < length ; i + + ) {
if ( utfdata [ i ] < = 0xff ) {
gbdata [ i ] = utfdata [ i ] ;
} else {
j = 0 ;
glyph = 0 ;
do {
if ( gb2312_lookup [ j * 2 ] = = utfdata [ i ] ) {
glyph = gb2312_lookup [ ( j * 2 ) + 1 ] ;
}
j + + ;
} while ( ( j < 7445 ) & & ( glyph = = 0 ) ) ;
if ( glyph = = 0 ) {
strcpy ( symbol - > errtxt , " Invalid character in input data " ) ;
return ERROR_INVALID_DATA ;
}
gbdata [ i ] = glyph ;
}
}
break ;
}
2009-12-05 02:18:48 +03:00
if ( symbol - > output_options & READER_INIT ) reader = 1 ;
error_number = gm_encode ( gbdata , length , binary , reader ) ;
2009-10-21 13:08:44 +04:00
if ( error_number ! = 0 ) {
strcpy ( symbol - > errtxt , " Input data too long " ) ;
return error_number ;
}
/* Determine the size of the symbol */
data_cw = strlen ( binary ) / 7 ;
2009-11-01 01:42:10 +03:00
auto_layers = 13 ;
for ( i = 12 ; i > 0 ; i - - ) {
if ( gm_recommend_cw [ ( i - 1 ) ] > = data_cw ) { auto_layers = i ; }
}
min_layers = 13 ;
2009-10-21 13:08:44 +04:00
for ( i = 12 ; i > 0 ; i - - ) {
2009-11-01 01:42:10 +03:00
if ( gm_max_cw [ ( i - 1 ) ] > = data_cw ) { min_layers = i ; }
}
layers = auto_layers ;
2009-11-02 18:47:08 +03:00
auto_ecc_level = 3 ;
if ( layers = = 1 ) { auto_ecc_level = 5 ; }
if ( ( layers = = 2 ) | | ( layers = = 3 ) ) { auto_ecc_level = 4 ; }
min_ecc_level = 1 ;
if ( layers = = 1 ) { min_ecc_level = 4 ; }
if ( ( layers = = 2 ) | | ( layers = = 3 ) ) { min_ecc_level = 2 ; }
ecc_level = auto_ecc_level ;
2009-11-01 01:42:10 +03:00
if ( ( symbol - > option_2 > = 1 ) & & ( symbol - > option_2 < = 13 ) ) {
2009-11-02 18:47:08 +03:00
input_latch = 1 ;
2009-11-01 01:42:10 +03:00
if ( symbol - > option_2 > min_layers ) {
layers = symbol - > option_2 ;
} else {
layers = min_layers ;
}
2009-10-21 13:08:44 +04:00
}
2009-11-02 18:47:08 +03:00
if ( input_latch = = 1 ) {
auto_ecc_level = 3 ;
if ( layers = = 1 ) { auto_ecc_level = 5 ; }
if ( ( layers = = 2 ) | | ( layers = = 3 ) ) { auto_ecc_level = 4 ; }
ecc_level = auto_ecc_level ;
if ( data_cw > gm_data_codewords [ ( 5 * ( layers - 1 ) ) + ( ecc_level - 1 ) ] ) {
layers + + ;
}
}
2009-11-01 01:42:10 +03:00
2009-11-02 18:47:08 +03:00
if ( input_latch = = 0 ) {
if ( ( symbol - > option_1 > = 1 ) & & ( symbol - > option_1 < = 5 ) ) {
if ( symbol - > option_1 > min_ecc_level ) {
ecc_level = symbol - > option_1 ;
} else {
ecc_level = min_ecc_level ;
}
}
if ( data_cw > gm_data_codewords [ ( 5 * ( layers - 1 ) ) + ( ecc_level - 1 ) ] ) {
do {
layers + + ;
} while ( ( data_cw > gm_data_codewords [ ( 5 * ( layers - 1 ) ) + ( ecc_level - 1 ) ] ) & & ( layers < = 13 ) ) ;
2009-11-01 01:42:10 +03:00
}
}
data_max = 1313 ;
switch ( ecc_level ) {
case 2 : data_max = 1167 ; break ;
case 3 : data_max = 1021 ; break ;
case 4 : data_max = 875 ; break ;
case 5 : data_max = 729 ; break ;
}
if ( data_cw > data_max ) {
strcpy ( symbol - > errtxt , " Input data too long " ) ;
return ERROR_TOO_LONG ;
}
2009-10-21 13:08:44 +04:00
gm_add_ecc ( binary , data_cw , layers , ecc_level , word ) ;
size = 6 + ( layers * 12 ) ;
modules = 1 + ( layers * 2 ) ;
# ifndef _MSC_VER
char grid [ size * size ] ;
# else
char * grid = ( char * ) _alloca ( ( size * size ) * sizeof ( char ) ) ;
# endif
for ( x = 0 ; x < size ; x + + ) {
for ( y = 0 ; y < size ; y + + ) {
grid [ ( y * size ) + x ] = ' 0 ' ;
}
}
place_data_in_grid ( word , grid , modules , size ) ;
place_layer_id ( grid , size , layers , modules , ecc_level ) ;
/* Add macromodule frames */
for ( x = 0 ; x < modules ; x + + ) {
dark = 1 - ( x % 2 ) ;
for ( y = 0 ; y < modules ; y + + ) {
if ( dark = = 1 ) {
for ( i = 0 ; i < 5 ; i + + ) {
grid [ ( ( y * 6 ) * size ) + ( x * 6 ) + i ] = ' 1 ' ;
grid [ ( ( ( y * 6 ) + 5 ) * size ) + ( x * 6 ) + i ] = ' 1 ' ;
grid [ ( ( ( y * 6 ) + i ) * size ) + ( x * 6 ) ] = ' 1 ' ;
grid [ ( ( ( y * 6 ) + i ) * size ) + ( x * 6 ) + 5 ] = ' 1 ' ;
}
grid [ ( ( ( y * 6 ) + 5 ) * size ) + ( x * 6 ) + 5 ] = ' 1 ' ;
dark = 0 ;
} else {
dark = 1 ;
}
}
}
/* Copy values to symbol */
symbol - > width = size ;
symbol - > rows = size ;
for ( x = 0 ; x < size ; x + + ) {
for ( y = 0 ; y < size ; y + + ) {
if ( grid [ ( y * size ) + x ] = = ' 1 ' ) {
set_module ( symbol , y , x ) ;
}
}
symbol - > row_height [ x ] = 1 ;
}
2009-09-29 13:45:46 +04:00
2009-10-21 13:08:44 +04:00
return 0 ;
}