Files
harbour-core/contrib/hbzebra/qrcode.c
2017-09-11 19:56:57 +00:00

1302 lines
43 KiB
C

/*
* Zebra barcode library
*
* Copyright 2011 Mindaugas Kavaliauskas <dbtopas at dbtopas.lt>
*
* 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 2, 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; see the file LICENSE.txt. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
/*
QR Code is ISO/IEC18004
JIS-X-0510 QR Code standard in Japanese language :)
https://osdn.jp/projects/qrcode/docs/qrcode_specification_ja/en/1/qrcode_specification_ja.pdf
https://en.wikipedia.org/wiki/QR_Code
http://www.qrcode.com/
https://foxdesignsstudio.com/uploads/pdf/Three_QR_Code.pdf
https://web.archive.org/web/www.qrme.co.uk/qr-code-resources/understanding-a-qr-code.html
http://www.swetake.com/qrcode/index-e.html
https://www.codeproject.com/Articles/20574/Open-Source-QRCode-Library
https://osdn.jp/projects/reedsolomon/
https://web.archive.org/web/twit88.com/platform/projects/show/mt-qrcode
https://qrcode.osdn.jp/
https://zxing.org/w/decode.jspx Online decoder
http://blog.qr4.nl/Online-QR-Code_Decoder.aspx Online decoder (not all codes are decoded)
http://www.thonky.com/qr-code-tutorial/ Tutorial
https://github.com/zxing/zxing Java library
http://goqr.me/ Online encode
http://www.pclviewer.com/rs2/calculator.html Reed-Solomon ECC calculator
https://web.archive.org/web/raidenii.net/files/datasheets/misc/qr_code.pdf
*/
#include "hbzebra.h"
/* #define DEBUG_CODE */
typedef struct
{
unsigned char uiCount;
unsigned char uiData;
unsigned char uiECC;
} QRBLOCKPARAM;
typedef struct
{
unsigned int uiECC;
QRBLOCKPARAM block[ 2 ];
} QRLEVEL, * PQRLEVEL;
typedef struct
{
unsigned int uiTotal; /* total number of codewords */
QRLEVEL level[ 4 ];
} QRVERSION, * PQRVERSION;
static const QRVERSION s_version[] =
{
{ 26, {{ 7, {{ 1, 19, 7}, { 0, 0, 0}}}, /* 1 2 * 2 */
{ 10, {{ 1, 16, 10}, { 0, 0, 0}}}, /* 4 * 2 */
{ 13, {{ 1, 13, 13}, { 0, 0, 0}}}, /* 6 * 2 */
{ 17, {{ 1, 9, 17}, { 0, 0, 0}}}}}, /* 8 * 2 */
{ 44, {{ 10, {{ 1, 34, 10}, { 0, 0, 0}}}, /* 2 4 * 2 */
{ 16, {{ 1, 28, 16}, { 0, 0, 0}}},
{ 22, {{ 1, 22, 22}, { 0, 0, 0}}},
{ 28, {{ 1, 16, 28}, { 0, 0, 0}}}}},
{ 70, {{ 15, {{ 1, 55, 15}, { 0, 0, 0}}}, /* 3 7 * 2 */
{ 26, {{ 1, 44, 26}, { 0, 0, 0}}},
{ 36, {{ 2, 17, 18}, { 0, 0, 0}}},
{ 44, {{ 2, 13, 22}, { 0, 0, 0}}}}},
{ 100, {{ 20, {{ 1, 80, 20}, { 0, 0, 0}}}, /* 4 */
{ 36, {{ 2, 32, 18}, { 0, 0, 0}}},
{ 52, {{ 2, 24, 26}, { 0, 0, 0}}},
{ 64, {{ 4, 9, 16}, { 0, 0, 0}}}}},
{ 134, {{ 26, {{ 1, 108, 26}, { 0, 0, 0}}}, /* 5 */
{ 48, {{ 2, 43, 24}, { 0, 0, 0}}},
{ 72, {{ 2, 15, 18}, { 2, 16, 18}}},
{ 88, {{ 2, 11, 22}, { 2, 12, 22}}}}},
{ 172, {{ 36, {{ 2, 68, 18}, { 0, 0, 0}}}, /* 6 */
{ 64, {{ 4, 27, 16}, { 0, 0, 0}}},
{ 96, {{ 4, 19, 24}, { 0, 0, 0}}},
{ 112, {{ 4, 15, 28}, { 0, 0, 0}}}}},
{ 196, {{ 40, {{ 2, 78, 20}, { 0, 0, 0}}}, /* 7 */
{ 72, {{ 4, 31, 18}, { 0, 0, 0}}},
{ 108, {{ 2, 14, 18}, { 4, 15, 18}}},
{ 130, {{ 4, 13, 26}, { 1, 14, 26}}}}},
{ 242, {{ 48, {{ 2, 97, 24}, { 0, 0, 0}}}, /* 8 */
{ 88, {{ 2, 38, 22}, { 2, 39, 22}}},
{ 132, {{ 4, 18, 22}, { 2, 19, 22}}},
{ 156, {{ 4, 14, 26}, { 2, 15, 26}}}}},
{ 292, {{ 60, {{ 2, 116, 30}, { 0, 0, 0}}}, /* 9 */
{ 110, {{ 3, 36, 22}, { 2, 37, 22}}},
{ 160, {{ 4, 16, 20}, { 4, 17, 20}}},
{ 192, {{ 4, 12, 24}, { 4, 13, 24}}}}},
{ 346, {{ 72, {{ 2, 68, 18}, { 2, 69, 18}}}, /* 10 */
{ 130, {{ 4, 43, 26}, { 1, 44, 26}}},
{ 192, {{ 6, 19, 24}, { 2, 20, 24}}},
{ 224, {{ 6, 15, 28}, { 2, 16, 28}}}}},
{ 404, {{ 80, {{ 4, 81, 20}, { 0, 0, 0}}}, /* 11 */
{ 150, {{ 1, 50, 30}, { 4, 51, 30}}},
{ 224, {{ 4, 22, 28}, { 4, 23, 28}}},
{ 264, {{ 3, 12, 24}, { 8, 13, 24}}}}},
{ 466, {{ 96, {{ 2, 92, 24}, { 2, 93, 24}}}, /* 12 */
{ 176, {{ 6, 36, 22}, { 2, 37, 22}}},
{ 260, {{ 4, 20, 26}, { 6, 21, 26}}},
{ 308, {{ 7, 14, 28}, { 4, 15, 28}}}}},
{ 532, {{ 104, {{ 4, 107, 26}, { 0, 0, 0}}}, /* 13 */
{ 198, {{ 8, 37, 22}, { 1, 38, 22}}},
{ 288, {{ 8, 20, 24}, { 4, 21, 24}}},
{ 352, {{12, 11, 22}, { 4, 12, 22}}}}},
{ 581, {{ 120, {{ 3, 115, 30}, { 1, 116, 30}}}, /* 14 */
{ 216, {{ 4, 40, 24}, { 5, 41, 24}}},
{ 320, {{11, 16, 20}, { 5, 17, 20}}},
{ 384, {{11, 12, 24}, { 5, 13, 24}}}}},
{ 655, {{ 132, {{ 5, 87, 22}, { 1, 88, 22}}}, /* 15 */
{ 240, {{ 5, 41, 24}, { 5, 42, 24}}},
{ 360, {{ 5, 24, 30}, { 7, 25, 30}}},
{ 432, {{11, 12, 24}, { 7, 13, 24}}}}},
{ 733, {{ 144, {{ 5, 98, 24}, { 1, 99, 24}}}, /* 16 */
{ 280, {{ 7, 45, 28}, { 3, 46, 28}}},
{ 408, {{15, 19, 24}, { 2, 20, 24}}},
{ 480, {{ 3, 15, 30}, {13, 16, 30}}}}},
{ 815, {{ 168, {{ 1, 107, 28}, { 5, 108, 28}}}, /* 17 */
{ 308, {{10, 46, 28}, { 1, 47, 28}}},
{ 448, {{ 1, 22, 28}, {15, 23, 28}}},
{ 532, {{ 2, 14, 28}, {17, 15, 28}}}}},
{ 901, {{ 180, {{ 5, 120, 30}, { 1, 121, 30}}}, /* 18 */
{ 338, {{ 9, 43, 26}, { 4, 44, 26}}},
{ 504, {{17, 22, 28}, { 1, 23, 28}}},
{ 588, {{ 2, 14, 28}, {19, 15, 28}}}}},
{ 991, {{ 196, {{ 3, 113, 28}, { 4, 114, 28}}}, /* 19 */
{ 364, {{ 3, 44, 26}, {11, 45, 26}}},
{ 546, {{17, 21, 26}, { 4, 22, 26}}},
{ 650, {{ 9, 13, 26}, {16, 14, 26}}}}},
{1085, {{ 224, {{ 3, 107, 28}, { 5, 108, 28}}}, /* 20 */
{ 416, {{ 3, 41, 26}, {13, 42, 26}}},
{ 600, {{15, 24, 30}, { 5, 25, 30}}},
{ 700, {{15, 15, 28}, {10, 16, 28}}}}},
{1156, {{ 224, {{ 4, 116, 28}, { 4, 117, 28}}}, /* 21 */
{ 442, {{17, 42, 26}, { 0, 0, 0}}},
{ 644, {{17, 22, 28}, { 6, 23, 28}}},
{ 750, {{19, 16, 30}, { 6, 17, 30}}}}},
{1258, {{ 252, {{ 2, 111, 28}, { 7, 112, 28}}}, /* 22 */
{ 476, {{17, 46, 28}, { 0, 0, 0}}},
{ 690, {{ 7, 24, 30}, {16, 25, 30}}},
{ 816, {{34, 13, 24}, { 0, 0, 0}}}}},
{1364, {{ 270, {{ 4, 121, 30}, { 5, 122, 30}}}, /* 23 */
{ 504, {{ 4, 47, 28}, {14, 48, 28}}},
{ 750, {{11, 24, 30}, {14, 25, 30}}},
{ 900, {{16, 15, 30}, {14, 16, 30}}}}},
{1474, {{ 300, {{ 6, 117, 30}, { 4, 118, 30}}}, /* 24 */
{ 560, {{ 6, 45, 28}, {14, 46, 28}}},
{ 810, {{11, 24, 30}, {16, 25, 30}}},
{ 960, {{30, 16, 30}, { 2, 17, 30}}}}},
{1588, {{ 312, {{ 8, 106, 26}, { 4, 107, 26}}}, /* 25 */
{ 588, {{ 8, 47, 28}, {13, 48, 28}}},
{ 870, {{ 7, 24, 30}, {22, 25, 30}}},
{1050, {{22, 15, 30}, {13, 16, 30}}}}},
{1706, {{ 336, {{10, 114, 28}, { 2, 115, 28}}}, /* 26 */
{ 644, {{19, 46, 28}, { 4, 47, 28}}},
{ 952, {{28, 22, 28}, { 6, 23, 28}}},
{1110, {{33, 16, 30}, { 4, 17, 30}}}}},
{1828, {{ 360, {{ 8, 122, 30}, { 4, 123, 30}}}, /* 27 */
{ 700, {{22, 45, 28}, { 3, 46, 28}}},
{1020, {{ 8, 23, 30}, {26, 24, 30}}},
{1200, {{12, 15, 30}, {28, 16, 30}}}}},
{1921, {{ 390, {{ 3, 117, 30}, {10, 118, 30}}}, /* 28 */
{ 728, {{ 3, 45, 28}, {23, 46, 28}}},
{1050, {{ 4, 24, 30}, {31, 25, 30}}},
{1260, {{11, 15, 30}, {31, 16, 30}}}}},
{2051, {{ 420, {{ 7, 116, 30}, { 7, 117, 30}}}, /* 29 */
{ 784, {{21, 45, 28}, { 7, 46, 28}}},
{1140, {{ 1, 23, 30}, {37, 24, 30}}},
{1350, {{19, 15, 30}, {26, 16, 30}}}}},
{2185, {{ 450, {{ 5, 115, 30}, {10, 116, 30}}}, /* 30 */
{ 812, {{19, 47, 28}, {10, 48, 28}}},
{1200, {{15, 24, 30}, {25, 25, 30}}},
{1440, {{23, 15, 30}, {25, 16, 30}}}}},
{2323, {{ 480, {{13, 115, 30}, { 3, 116, 30}}}, /* 31 */
{ 868, {{ 2, 46, 28}, {29, 47, 28}}},
{1290, {{42, 24, 30}, { 1, 25, 30}}},
{1530, {{23, 15, 30}, {28, 16, 30}}}}},
{2465, {{ 510, {{17, 115, 30}, { 0, 0, 0}}}, /* 32 */
{ 924, {{10, 46, 28}, {23, 47, 28}}},
{1350, {{10, 24, 30}, {35, 25, 30}}},
{1620, {{19, 15, 30}, {35, 16, 30}}}}},
{2611, {{ 540, {{17, 115, 30}, { 1, 116, 30}}}, /* 33 */
{ 980, {{14, 46, 28}, {21, 47, 28}}},
{1440, {{29, 24, 30}, {19, 25, 30}}},
{1710, {{11, 15, 30}, {46, 16, 30}}}}},
{2761, {{ 570, {{13, 115, 30}, { 6, 116, 30}}}, /* 34 */
{1036, {{14, 46, 28}, {23, 47, 28}}},
{1530, {{44, 24, 30}, { 7, 25, 30}}},
{1800, {{59, 16, 30}, { 1, 17, 30}}}}},
{2876, {{ 570, {{12, 121, 30}, { 7, 122, 30}}}, /* 35 */
{1064, {{12, 47, 28}, {26, 48, 28}}},
{1590, {{39, 24, 30}, {14, 25, 30}}},
{1890, {{22, 15, 30}, {41, 16, 30}}}}},
{3034, {{ 600, {{ 6, 121, 30}, {14, 122, 30}}}, /* 36 */
{1120, {{ 6, 47, 28}, {34, 48, 28}}},
{1680, {{46, 24, 30}, {10, 25, 30}}},
{1980, {{ 2, 15, 30}, {64, 16, 30}}}}},
{3196, {{ 630, {{17, 122, 30}, { 4, 123, 30}}}, /* 37 */
{1204, {{29, 46, 28}, {14, 47, 28}}},
{1770, {{49, 24, 30}, {10, 25, 30}}},
{2100, {{24, 15, 30}, {46, 16, 30}}}}},
{3362, {{ 660, {{ 4, 122, 30}, {18, 123, 30}}}, /* 38 */
{1260, {{13, 46, 28}, {32, 47, 28}}},
{1860, {{48, 24, 30}, {14, 25, 30}}},
{2220, {{42, 15, 30}, {32, 16, 30}}}}},
{3532, {{ 720, {{20, 117, 30}, { 4, 118, 30}}}, /* 39 */
{1316, {{40, 47, 28}, { 7, 48, 28}}},
{1950, {{43, 24, 30}, {22, 25, 30}}},
{2310, {{10, 15, 30}, {67, 16, 30}}}}},
{3706, {{ 750, {{19, 118, 30}, { 6, 119, 30}}}, /* 40 */
{1372, {{18, 47, 28}, {31, 48, 28}}},
{2040, {{34, 24, 30}, {34, 25, 30}}},
{2430, {{20, 15, 30}, {61, 16, 30}}}}}
};
static const unsigned char s_rev[ 256 ] =
{
#define R2( n ) n, n + 2 * 64, n + 1 * 64, n + 3 * 64
#define R4( n ) R2( n ), R2( n + 2 * 16 ), R2( n + 1 * 16 ), R2( n + 3 * 16 )
#define R6( n ) R4( n ), R4( n + 2 * 4 ), R4( n + 1 * 4 ), R4( n + 3 * 4 )
R6( 0 ), R6( 2 ), R6( 1 ), R6( 3 )
};
/* zero terminated align patterns positions */
static unsigned char s_align01[] = { 0 };
static unsigned char s_align02[] = { 6, 18, 0 };
static unsigned char s_align03[] = { 6, 22, 0 };
static unsigned char s_align04[] = { 6, 26, 0 };
static unsigned char s_align05[] = { 6, 30, 0 };
static unsigned char s_align06[] = { 6, 34, 0 };
static unsigned char s_align07[] = { 6, 22, 38, 0 };
static unsigned char s_align08[] = { 6, 24, 42, 0 };
static unsigned char s_align09[] = { 6, 26, 46, 0 };
static unsigned char s_align00[] = { 6, 28, 50, 0 };
static unsigned char s_align11[] = { 6, 30, 54, 0 };
static unsigned char s_align12[] = { 6, 32, 58, 0 };
static unsigned char s_align13[] = { 6, 34, 62, 0 };
static unsigned char s_align14[] = { 6, 26, 46, 66, 0 };
static unsigned char s_align15[] = { 6, 26, 48, 70, 0 };
static unsigned char s_align16[] = { 6, 26, 50, 74, 0 };
static unsigned char s_align17[] = { 6, 30, 54, 78, 0 };
static unsigned char s_align18[] = { 6, 30, 56, 82, 0 };
static unsigned char s_align19[] = { 6, 30, 58, 86, 0 };
static unsigned char s_align10[] = { 6, 34, 62, 90, 0 };
static unsigned char s_align21[] = { 6, 28, 50, 72, 94, 0 };
static unsigned char s_align22[] = { 6, 26, 50, 74, 98, 0 };
static unsigned char s_align23[] = { 6, 30, 54, 78, 102, 0 };
static unsigned char s_align24[] = { 6, 28, 54, 80, 106, 0 };
static unsigned char s_align25[] = { 6, 32, 58, 84, 110, 0 };
static unsigned char s_align26[] = { 6, 30, 58, 86, 114, 0 };
static unsigned char s_align27[] = { 6, 34, 62, 90, 118, 0 };
static unsigned char s_align28[] = { 6, 26, 50, 74, 98, 122, 0 };
static unsigned char s_align29[] = { 6, 30, 54, 78, 102, 126, 0 };
static unsigned char s_align20[] = { 6, 26, 52, 78, 104, 130, 0 };
static unsigned char s_align31[] = { 6, 30, 56, 82, 108, 134, 0 };
static unsigned char s_align32[] = { 6, 34, 60, 86, 112, 138, 0 };
static unsigned char s_align33[] = { 6, 30, 58, 86, 114, 142, 0 };
static unsigned char s_align34[] = { 6, 34, 62, 90, 118, 146, 0 };
static unsigned char s_align35[] = { 6, 30, 54, 78, 102, 126, 150, 0 };
static unsigned char s_align36[] = { 6, 24, 50, 76, 102, 128, 154, 0 };
static unsigned char s_align37[] = { 6, 28, 54, 80, 106, 132, 158, 0 };
static unsigned char s_align38[] = { 6, 32, 58, 84, 110, 136, 162, 0 };
static unsigned char s_align39[] = { 6, 26, 54, 82, 110, 138, 166, 0 };
static unsigned char s_align40[] = { 6, 30, 58, 86, 114, 142, 170, 0 };
static unsigned char * s_align[ 40 ] = {
s_align01,
s_align02,
s_align03,
s_align04,
s_align05,
s_align06,
s_align07,
s_align08,
s_align09,
s_align00,
s_align11,
s_align12,
s_align13,
s_align14,
s_align15,
s_align16,
s_align17,
s_align18,
s_align19,
s_align10,
s_align21,
s_align22,
s_align23,
s_align24,
s_align25,
s_align26,
s_align27,
s_align28,
s_align29,
s_align20,
s_align31,
s_align32,
s_align33,
s_align34,
s_align35,
s_align36,
s_align37,
s_align38,
s_align39,
s_align40
};
#ifdef DEBUG_CODE
static int _qr_check_version_table( void )
{
int iV, iL;
unsigned int uiSumD, uiSumE;
for( iV = 1; iV <= 40; iV++ )
{
const QRVERSION * pQRVersion = &s_version[ iV - 1 ];
for( iL = 0; iL < 4; iL++ )
{
uiSumE = ( unsigned int ) ( pQRVersion->level[ iL ].block[ 0 ].uiCount ) * ( pQRVersion->level[ iL ].block[ 0 ].uiECC ) +
( unsigned int ) ( pQRVersion->level[ iL ].block[ 1 ].uiCount ) * ( pQRVersion->level[ iL ].block[ 1 ].uiECC );
if( uiSumE != pQRVersion->level[ iL ].uiECC )
return iV + 10000 + ( iL + 1 ) * 1000;
uiSumD = ( unsigned int ) ( pQRVersion->level[ iL ].block[ 0 ].uiCount ) * ( pQRVersion->level[ iL ].block[ 0 ].uiData ) +
( unsigned int ) ( pQRVersion->level[ iL ].block[ 1 ].uiCount ) * ( pQRVersion->level[ iL ].block[ 1 ].uiData );
if( uiSumD + uiSumE != pQRVersion->uiTotal )
return iV + 20000 + ( iL + 1 ) * 1000;
if( pQRVersion->level[ iL ].block[ 1 ].uiCount > 0 )
{
if( pQRVersion->level[ iL ].block[ 0 ].uiData > pQRVersion->level[ iL ].block[ 1 ].uiData )
return iV + 30000 + ( iL + 1 ) * 1000;
if( pQRVersion->level[ iL ].block[ 0 ].uiECC != pQRVersion->level[ iL ].block[ 1 ].uiECC )
return iV + 40000 + ( iL + 1 ) * 1000;
}
}
}
return 0;
}
HB_FUNC( _QR_CHECK_VERSION_TABLE )
{
hb_retni( _qr_check_version_table() );
}
#endif
static int _qr_version_crc( int iVersion )
{
int i, iValue, iVersionRev;
iVersionRev = 0;
for( i = 0; i < 6; i++ )
{
iVersionRev <<= 1;
if( iVersion & 1 )
iVersionRev |= 1;
iVersion >>= 1;
}
iValue = iVersionRev;
for( i = 0; i < 6; i++ )
{
if( iValue & 1 )
iValue ^= 0x149F; /* 0x149F - reversed 12-bit polynom */
iValue >>= 1;
}
iValue <<= 6;
iValue |= iVersionRev;
return iValue; /* 18-bit return value */
}
static int _qr_format_crc( int iLevel, int iMask )
{
int i, iValue, iRev;
iRev = ( ( iLevel & 1 ) ? 0 : 2 ) | ( ( iLevel & 2 ) ? 1 : 0 ); /* 0->1, 1->0, 2->3, 3->2 + reverse bits */
iRev |= ( ( iMask & 1 ) ? 16 : 0 ) | ( ( iMask & 2 ) ? 8 : 0 ) | ( ( iMask & 4 ) ? 4 : 0 ); /* reverse bits */
iValue = iRev;
for( i = 0; i < 5; i++ )
{
if( iValue & 1 )
iValue ^= 0x765; /* 0x765 - reversed 10-bit polynom */
iValue >>= 1;
}
iValue <<= 5;
iValue |= iRev;
return iValue ^ 0x2415; /* 15-bit return value */
}
#ifdef DEBUG_CODE
HB_FUNC( _QR_VERSION_CRC )
{
hb_retni( _qr_version_crc( hb_parni( 1 ) ) );
}
HB_FUNC( _QR_FORMAT_CRC )
{
hb_retni( _qr_format_crc( hb_parni( 1 ), hb_parni( 2 ) ) );
}
#endif
static int _qr_versionlength( int iVersion )
{
return iVersion * 4 + 17;
}
static int _qr_fixed( int iVersion, int iRow, int iCol )
{
int iLength = _qr_versionlength( iVersion );
const unsigned char * pi;
/* position detection markers and version info */
if( iRow < 9 && iCol < 9 )
return 1;
if( iRow < 9 && iCol >= iLength - 8 )
return 1;
if( iRow >= iLength - 8 && iCol < 9 )
return 1;
/* timing patterns */
if( iRow == 6 || iCol == 6 )
return 1;
/* alignment patterns */
pi = s_align[ iVersion - 1 ];
for( ; *pi; pi++ )
{
const unsigned char * pj = s_align[ iVersion - 1 ];
for( ; *pj; pj++ )
{
if( iRow - 2 <= ( int ) *pi && ( int ) *pi <= iRow + 2 &&
iCol - 2 <= ( int ) *pj && ( int ) *pj <= iCol + 2 )
{
if( ( *pi == 6 && ( int ) *pj > iLength - 10 ) ||
( ( int ) *pi > iLength - 10 && *pj == 6 ) )
break;
return 1;
}
}
}
/* format info */
if( iVersion >= 7 &&
( ( iCol < 6 && iRow >= iLength - 11 ) || ( iCol >= iLength - 11 && iRow < 6 ) ) )
return 1;
return 0;
}
static PHB_BITBUFFER _qr_interlace( PHB_BITBUFFER pData, unsigned char * pECC, int iVersion, int iLevel )
{
const QRVERSION * pVersion = &s_version[ iVersion - 1 ];
const QRLEVEL * pLevel = &( pVersion->level[ iLevel ] );
PHB_BITBUFFER pRet;
HB_BYTE * pDataBuf, * pRetBuf;
unsigned int uiDst, uiSrc, uiPos, uiBlock;
pRet = hb_bitbuffer_create();
hb_bitbuffer_set( pRet, pVersion->uiTotal * 8, HB_FALSE ); /* Allocate */
pRetBuf = hb_bitbuffer_buffer( pRet );
pDataBuf = hb_bitbuffer_buffer( pData );
uiDst = 0;
for( uiPos = 0; uiPos < ( unsigned int ) pLevel->block[ 0 ].uiData || uiPos < ( unsigned int ) pLevel->block[ 1 ].uiData; uiPos++ )
{
uiSrc = 0;
for( uiBlock = 0; uiBlock < ( unsigned int ) pLevel->block[ 0 ].uiCount; uiBlock++ )
{
if( uiPos < ( unsigned int ) pLevel->block[ 0 ].uiData )
{
pRetBuf[ uiDst++ ] = pDataBuf[ uiPos + uiSrc ];
}
uiSrc += pLevel->block[ 0 ].uiData;
}
if( pLevel->block[ 1 ].uiCount )
{
for( uiBlock = 0; uiBlock < ( unsigned int ) pLevel->block[ 1 ].uiCount; uiBlock++ )
{
pRetBuf[ uiDst++ ] = pDataBuf[ uiPos + uiSrc ];
uiSrc += pLevel->block[ 1 ].uiData;
}
}
}
for( uiPos = 0; uiPos < ( unsigned int ) pLevel->block[ 0 ].uiECC; uiPos++ )
{
uiSrc = 0;
for( uiBlock = 0; uiBlock < ( unsigned int ) pLevel->block[ 0 ].uiCount; uiBlock++ )
{
if( uiPos < ( unsigned int ) pLevel->block[ 0 ].uiECC )
{
pRetBuf[ uiDst++ ] = s_rev[ pECC[ uiPos + uiSrc ] ];
}
uiSrc += pLevel->block[ 0 ].uiECC;
}
if( pLevel->block[ 1 ].uiCount )
{
for( uiBlock = 0; uiBlock < ( unsigned int ) pLevel->block[ 1 ].uiCount; uiBlock++ )
{
pRetBuf[ uiDst++ ] = s_rev[ pECC[ uiPos + uiSrc ] ];
uiSrc += pLevel->block[ 1 ].uiECC;
}
}
}
#ifdef DEBUG_CODE
if( uiDst != pVersion->uiTotal )
HB_TRACE( HB_TR_ALWAYS, ( "ERROR!!! uiDst:%d pVersion->uiTotal:%d", uiDst, pVersion->uiTotal ) );
for( uiPos = 0; uiPos < pVersion->uiTotal; uiPos++ )
HB_TRACE( HB_TR_ALWAYS, ( "interlaced:%3d %02X", ( int ) s_rev[ ( unsigned char ) pRetBuf[ uiPos ] ], ( int ) s_rev[ ( unsigned char ) pRetBuf[ uiPos ] ] ) );
#endif
return pRet;
}
static int _qr_alphanumeric_no( char ch )
{
if( '0' <= ch && ch <= '9' )
return ch - '0';
if( 'A' <= ch && ch <= 'Z' )
return ch - 'A' + 10;
switch( ch )
{
case ' ':
return 36;
case '$':
return 37;
case '%':
return 38;
case '*':
return 39;
case '+':
return 40;
case '-':
return 41;
case '.':
return 42;
case '/':
return 43;
case ':':
return 44;
}
return -1;
}
static int _qr_cci_len( int iVersion, int iMode ) /* Character Count Indicator */
{
if( iMode == 1 )
return iVersion <= 9 ? 10 : ( iVersion <= 26 ? 12 : 14 );
if( iMode == 2 )
return iVersion <= 9 ? 9 : ( iVersion <= 26 ? 11 : 13 );
if( iMode == 4 )
return iVersion <= 9 ? 8 : 16;
return 0;
}
static int _qr_dataencode( const char * szCode, HB_SIZE nSize, PHB_BITBUFFER pData, int iLevel )
{
int i, iVersion, iMode;
HB_ISIZ iLen, iDataLen, m;
HB_SIZE n;
/* Select encoding mode */
iMode = 1; /* 1=Numeric, 2=Alphanumeric, 4=8-bit, 8=Kanji. Not modes: 0=terminator, 3=Structured append, 7=ECI, 5=FNC1(1), 9=FNC1(2)*/
for( n = 0; n < nSize; n++ )
{
char ch = szCode[ n ];
if( '0' <= ch && ch <= '9' )
{
}
else if( ( 'A' <= ch && ch <= 'Z' ) ||
ch == ' ' || ch == '$' || ch == '%' || ch == '*' || ch == '+' || ch == '-' || ch == '.' || ch == '/' || ch == ':' )
iMode = 2;
else
{
iMode = 4;
break;
}
}
/* Calculate data length in bits */
if( iMode == 1 )
iLen = ( nSize / 3 ) * 10 + ( ( nSize % 3 ) == 0 ? 0 : ( ( nSize % 3 ) == 1 ? 4 : 7 ) );
else if( iMode == 2 )
iLen = ( nSize / 2 ) * 11 + ( nSize % 2 ) * 6;
else /* if( iMode == 4 ) */
iLen = nSize * 8;
iLen += 4; /* Mode indicator length */
/* Select version */
iDataLen = 0; /* to pacify warning with some C compilers (MSVS 2010) */
iVersion = 0; /* to pacify warning */
for( i = 1; i <= 40; i++ )
{
iDataLen = ( int ) ( s_version[ i - 1 ].uiTotal - s_version[ i - 1 ].level[ iLevel ].uiECC );
if( iDataLen * 8 >= iLen + _qr_cci_len( i, iMode ) )
{
iVersion = i;
break;
}
}
if( i > 40 )
return 0; /* Too large */
#ifdef DEBUG_CODE
HB_TRACE( HB_TR_ALWAYS, ( "iMode:%d iLen:%" HB_PFS "d iDataLen:%d iVersion:%d", iMode, iLen, iDataLen, iVersion ) );
#endif
/* Encode */
hb_bitbuffer_cat_int_rev( pData, iMode, 4 );
hb_bitbuffer_cat_int_rev( pData, ( int ) nSize, _qr_cci_len( iVersion, iMode ) );
if( iMode == 1 )
{
for( n = 0; n + 2 < nSize; n += 3 )
{
hb_bitbuffer_cat_int_rev( pData, 100 * ( int )( unsigned char ) ( szCode[ n ] - '0' ) +
10 * ( int )( unsigned char ) ( szCode[ n + 1 ] - '0' ) +
( int )( unsigned char ) ( szCode[ n + 2 ] - '0' ), 10 );
}
if( n + 1 == nSize )
hb_bitbuffer_cat_int_rev( pData, ( int )( unsigned char ) ( szCode[ n ] - '0' ), 4 );
else
hb_bitbuffer_cat_int_rev( pData, 10 * ( int )( unsigned char ) ( szCode[ n ] - '0' ) +
( int )( unsigned char ) ( szCode[ n + 1 ] - '0' ), 7 );
}
else if( iMode == 2 )
{
for( n = 0; n + 1 < nSize; n += 2 )
{
hb_bitbuffer_cat_int_rev( pData, 45 * _qr_alphanumeric_no( szCode[ n ] ) + _qr_alphanumeric_no( szCode[ n + 1 ] ), 11 );
}
if( n != nSize )
{
hb_bitbuffer_cat_int_rev( pData, _qr_alphanumeric_no( szCode[ n ] ), 6 );
}
}
else if( iMode == 4 )
{
for( n = 0; n < nSize; n++ )
hb_bitbuffer_cat_int_rev( pData, ( int ) ( unsigned char ) szCode[ n ], 8 );
}
/* Terminator */
if( iDataLen * 8 >= ( int ) hb_bitbuffer_len( pData ) + 4 )
hb_bitbuffer_cat_int_rev( pData, 0, 4 );
/* Padding */
if( hb_bitbuffer_len( pData ) & 7 )
hb_bitbuffer_cat_int_rev( pData, 0, 8 - ( hb_bitbuffer_len( pData ) & 7 ) );
iLen = iDataLen - hb_bitbuffer_len( pData ) / 8;
for( m = 0; m < iLen; m++ )
{
hb_bitbuffer_cat_int_rev( pData, ( m & 1 ) ? 0x11 : 0xEC, 8 );
}
#ifdef DEBUG_CODE
for( m = 0; m < iDataLen; m++ )
HB_TRACE( HB_TR_ALWAYS, ( "data:%3d %02X", s_rev[ *( hb_bitbuffer_buffer( pData ) + m ) ], s_rev[ *( hb_bitbuffer_buffer( pData ) + m ) ] ) );
#endif
return iVersion;
}
static void _reed_solomon_encode( unsigned char * pData, int iDataLen, unsigned char * pECC, int iECCLen, int * pPoly, int * pExp, int * pLog, int iMod )
{
int i, j;
for( i = 0; i < iECCLen; i++ )
pECC[ i ] = 0;
for( i = 0; i < iDataLen; i++ )
{
unsigned char iM = s_rev[ pData[ i ] ] ^ pECC[ iECCLen - 1 ];
for( j = iECCLen - 1; j > 0; j-- )
{
if( iM && pPoly[ j ] )
pECC[ j ] = ( unsigned char ) ( pECC[ j - 1 ] ^ pExp[ ( pLog[ iM ] + pLog[ pPoly[ j ] ] ) % iMod ] );
else
pECC[ j ] = pECC[ j - 1 ];
}
if( iM && pPoly[ 0 ] )
pECC[ 0 ] = ( unsigned char ) ( pExp[ ( pLog[ iM ] + pLog[ pPoly[ 0 ] ] ) % iMod ] );
else
pECC[ 0 ] = 0;
}
}
static unsigned char * _qr_checksum( PHB_BITBUFFER pData, int iVersion, int iLevel )
{
const QRVERSION * pVersion = &s_version[ iVersion - 1 ];
const QRLEVEL * pLevel = &( pVersion->level[ iLevel ] );
HB_BYTE * pDataBuf = hb_bitbuffer_buffer( pData );
int * pPoly, * pExp, * pLog;
int i, j, iBits, iMod, iPoly, iECCLen, iIndex;
unsigned char * pECC, * pECCPtr, ui, ui2;
/* Init Galois field. Parameters: iPoly */
iPoly = 0x11D;
j = iPoly;
for( iBits = 0; j > 1; iBits++ )
j >>= 1;
iMod = ( 1 << iBits ) - 1;
pExp = ( int * ) hb_xgrab( sizeof( int ) * iMod ); /* exponent function */
pLog = ( int * ) hb_xgrab( sizeof( int ) * ( iMod + 1 ) ); /* logarithm function */
j = 1;
pLog[ 0 ] = iMod;
for( i = 0; i < iMod; i++ )
{
pExp[ i ] = j;
pLog[ j ] = i;
j <<= 1;
if( j & ( 1 << iBits ) )
j ^= iPoly;
}
/* Init Reed-Solomon encode. Parameters: iECCLen, iIndex */
iECCLen = pLevel->block[ 0 ].uiECC;
iIndex = 0; /* why this parameter is different from DataMatrix ??? */
pPoly = ( int * ) hb_xgrab( sizeof( int ) * ( iECCLen + 1 ) );
pPoly[ 0 ] = 1;
for( i = 1; i <= iECCLen; i++ )
{
pPoly[ i ] = 1;
for( j = i - 1; j > 0; j-- )
{
if( pPoly[ j ] )
pPoly[ j ] = pExp[ ( pLog[ pPoly[ j ] ] + iIndex ) % iMod ];
pPoly[ j ] ^= pPoly[ j - 1 ];
}
pPoly[ 0 ] = pExp[ ( pLog[ pPoly[ 0 ] ] + iIndex ) % iMod ];
iIndex++;
}
#ifdef DEBUG_CODE
for( i = 0; i <= iECCLen; i++ )
HB_TRACE( HB_TR_ALWAYS, ( "POLY[%3d %02X]:%3d %02X", i, i, pPoly[ i ], pPoly[ i ] ) );
#endif
pECC = ( unsigned char * ) hb_xgrab( pLevel->block[ 0 ].uiECC * ( pLevel->block[ 0 ].uiCount + pLevel->block[ 1 ].uiCount ) );
pECCPtr = pECC;
/* Divide data into blocks and do Reed-Solomon encoding for each block */
for( ui = 0; ui < pLevel->block[ 0 ].uiCount; ui++ )
{
/* Calculate Reed-Solomon ECC for one block */
_reed_solomon_encode( pDataBuf, pLevel->block[ 0 ].uiData, pECCPtr, iECCLen, pPoly, pExp, pLog, iMod );
pDataBuf += pLevel->block[ 0 ].uiData;
for( i = 0; i < iECCLen / 2; i++ )
{
ui2 = pECCPtr[ i ];
pECCPtr[ i ] = pECCPtr[ iECCLen - 1 - i ];
pECCPtr[ iECCLen - 1 - i ] = ui2;
}
pECCPtr += iECCLen;
}
for( ui = 0; ui < pLevel->block[ 1 ].uiCount; ui++ )
{
/* Calculate Reed-Solomon ECC for one block */
_reed_solomon_encode( pDataBuf, pLevel->block[ 1 ].uiData, pECCPtr, iECCLen, pPoly, pExp, pLog, iMod );
pDataBuf += pLevel->block[ 1 ].uiData;
for( i = 0; i < iECCLen / 2; i++ )
{
ui2 = pECCPtr[ i ];
pECCPtr[ i ] = pECCPtr[ iECCLen - 1 - i ];
pECCPtr[ iECCLen - 1 - i ] = ui2;
}
pECCPtr += iECCLen;
}
hb_xfree( pExp );
hb_xfree( pLog );
hb_xfree( pPoly );
#ifdef DEBUG_CODE
iECCLen = pLevel->block[ 0 ].uiECC * ( pLevel->block[ 0 ].uiCount + pLevel->block[ 1 ].uiCount );
for( i = 0; i < iECCLen; i++ )
HB_TRACE( HB_TR_ALWAYS, ( "ecc:%3d %02X", ( int ) ( unsigned char ) pECC[ i ], ( int ) ( unsigned char ) pECC[ i ] ) );
#endif
return pECC;
}
static void _qr_draw( PHB_BITBUFFER pBits, PHB_BITBUFFER pCWBits, int iVersion )
{
int i, j, iLength;
const unsigned char * pi;
HB_SYMBOL_UNUSED( pCWBits );
iLength = _qr_versionlength( iVersion );
/* draw position detection markers */
for( i = 0; i < 7; i++ )
{
hb_bitbuffer_set( pBits, i, 1 );
hb_bitbuffer_set( pBits, i + 6 * iLength, 1 );
hb_bitbuffer_set( pBits, i * iLength, 1 );
hb_bitbuffer_set( pBits, i * iLength + 6, 1 );
hb_bitbuffer_set( pBits, i + ( iLength - 7 ) * iLength, 1 );
hb_bitbuffer_set( pBits, i + ( iLength - 1 ) * iLength, 1 );
hb_bitbuffer_set( pBits, ( iLength - 7 + i ) * iLength, 1 );
hb_bitbuffer_set( pBits, ( iLength - 7 + i ) * iLength + 6, 1 );
hb_bitbuffer_set( pBits, iLength - 7 + i, 1 );
hb_bitbuffer_set( pBits, iLength - 7 + i + 6 * iLength, 1 );
hb_bitbuffer_set( pBits, iLength - 7 + i * iLength, 1 );
hb_bitbuffer_set( pBits, iLength - 1 + i * iLength, 1 );
}
for( i = 2; i < 5; i++ )
{
for( j = 2; j < 5; j++ )
{
hb_bitbuffer_set( pBits, i * iLength + j, 1 );
hb_bitbuffer_set( pBits, i * iLength + j + iLength - 7, 1 );
hb_bitbuffer_set( pBits, ( i + iLength - 7 ) * iLength + j, 1 );
}
}
/* draw timing patterns */
for( i = 8; i < iLength - 8; i += 2 )
{
hb_bitbuffer_set( pBits, i + 6 * iLength, 1 );
hb_bitbuffer_set( pBits, i * iLength + 6, 1 );
}
/* draw alignment patterns */
pi = s_align[ iVersion - 1 ];
for( ; *pi; pi++ )
{
const unsigned char * pj = s_align[ iVersion - 1 ];
for( ; *pj; pj++ )
{
if( ( *pi > 10 && *pi < iLength - 10 ) ||
( *pj > 10 && *pj < iLength - 10 ) ||
( *pi > 10 && *pj > 10 ))
{
hb_bitbuffer_set( pBits, iLength * *pi + *pj - 1, 0 );
hb_bitbuffer_set( pBits, iLength * *pi + *pj + 1, 0 );
hb_bitbuffer_set( pBits, iLength * ( *pi - 1 ) + *pj, 0 );
hb_bitbuffer_set( pBits, iLength * ( *pi + 1 ) + *pj, 0 );
hb_bitbuffer_set( pBits, iLength * *pi + *pj, 1 );
hb_bitbuffer_set( pBits, iLength * ( *pi - 2 ) + *pj - 2, 1 );
hb_bitbuffer_set( pBits, iLength * ( *pi - 2 ) + *pj - 1, 1 );
hb_bitbuffer_set( pBits, iLength * ( *pi - 2 ) + *pj , 1 );
hb_bitbuffer_set( pBits, iLength * ( *pi - 2 ) + *pj + 1, 1 );
hb_bitbuffer_set( pBits, iLength * ( *pi - 2 ) + *pj + 2, 1 );
hb_bitbuffer_set( pBits, ( *pi - 1 ) * iLength + *pj - 2, 1 );
hb_bitbuffer_set( pBits, *pi * iLength + *pj - 2, 1 );
hb_bitbuffer_set( pBits, ( *pi + 1 ) * iLength + *pj - 2, 1 );
hb_bitbuffer_set( pBits, ( *pi - 1 ) * iLength + *pj + 2, 1 );
hb_bitbuffer_set( pBits, *pi * iLength + *pj + 2, 1 );
hb_bitbuffer_set( pBits, ( *pi + 1 ) * iLength + *pj + 2, 1 );
hb_bitbuffer_set( pBits, iLength * ( *pi + 2 ) + *pj - 2, 1 );
hb_bitbuffer_set( pBits, iLength * ( *pi + 2 ) + *pj - 1, 1 );
hb_bitbuffer_set( pBits, iLength * ( *pi + 2 ) + *pj , 1 );
hb_bitbuffer_set( pBits, iLength * ( *pi + 2 ) + *pj + 1, 1 );
hb_bitbuffer_set( pBits, iLength * ( *pi + 2 ) + *pj + 2, 1 );
}
}
}
/* Dark module */
hb_bitbuffer_set( pBits, 8 + iLength * ( iLength - 8 ), 1 );
/* Draw data. Note: pCWBits == NULL is used only for debugging */
if( pCWBits )
{
int no, up, right;
i = j = iLength - 1;
right = 1;
up = 1;
no = 0;
while( i >= 0 && j >= 0 )
{
if( ! _qr_fixed( iVersion, i, j ) )
hb_bitbuffer_set( pBits, i * iLength + j, hb_bitbuffer_get( pCWBits, no++ ) );
if( right )
{
j--;
}
else
{
if( up )
{
if( i > 0 )
{
i--;
j++;
}
else
{
up = 0;
j--;
}
}
else
{
if( i < iLength - 1 )
{
i++;
j++;
}
else
{
up = 1;
j--;
}
}
}
right = ! right;
if( j == 6 )
j--;
}
}
}
static int _qr_penalty( PHB_BITBUFFER pBits, int iVersion )
{
int i, j, k, iPenalty = 0, iLen = _qr_versionlength( iVersion );
HB_BOOL bBit;
/* 1. Same color modules in row/column */
for( i = 0; i < iLen; i++ )
{
/* Row */
HB_BOOL bBitLast = hb_bitbuffer_get( pBits, i * iLen );
k = 1;
for( j = 1; j < iLen; j++ )
{
bBit = hb_bitbuffer_get( pBits, i * iLen + j );
if( bBit != bBitLast )
{
if( k >= 5 )
iPenalty += 3 + ( k - 5 );
bBitLast = bBit;
k = 1;
}
else
k++;
}
if( k >= 5 )
iPenalty = 3 + ( k - 5 );
/* Col */
bBitLast = hb_bitbuffer_get( pBits, i );
k = 1;
for( j = 1; j < iLen; j++ )
{
bBit = hb_bitbuffer_get( pBits, i + iLen * j );
if( bBit != bBitLast )
{
if( k >= 5 )
iPenalty += 3 + ( k - 5 );
bBitLast = bBit;
k = 1;
}
else
k++;
}
if( k >= 5 )
iPenalty = 3 + ( k - 5 );
}
/* 2. Block of same color modules */
/* Instead of looking for non-overlapped MxN block, we can search for 2x2 overlapping blocks,
penalty value is the same for both of these methods */
for( i = 0; i < iLen - 1; i++ )
{
for( j = 0; j < iLen - 1; j++ )
{
bBit = hb_bitbuffer_get( pBits, i * iLen + j );
if( hb_bitbuffer_get( pBits, i * iLen + j + 1 ) == bBit &&
hb_bitbuffer_get( pBits, ( i + 1 ) * iLen + j ) == bBit &&
hb_bitbuffer_get( pBits, ( i + 1 ) * iLen + j + 1 ) == bBit )
iPenalty += 3;
}
}
/* 3. Black-White-Black-Black-Black-White-Black modules */
for( i = 0; i < iLen - 6; i++ )
{
for( j = 0; j < iLen - 6; j++ )
{
if( hb_bitbuffer_get( pBits, i * iLen + j ) &&
! hb_bitbuffer_get( pBits, i * iLen + j + 1 ) &&
hb_bitbuffer_get( pBits, i * iLen + j + 2 ) &&
hb_bitbuffer_get( pBits, i * iLen + j + 3 ) &&
hb_bitbuffer_get( pBits, i * iLen + j + 4 ) &&
! hb_bitbuffer_get( pBits, i * iLen + j + 5 ) &&
hb_bitbuffer_get( pBits, i * iLen + j + 6 ) )
iPenalty += 40;
if( hb_bitbuffer_get( pBits, i * iLen + j ) &&
! hb_bitbuffer_get( pBits, ( i + 1 ) * iLen + j ) &&
hb_bitbuffer_get( pBits, ( i + 2 ) * iLen + j ) &&
hb_bitbuffer_get( pBits, ( i + 3 ) * iLen + j ) &&
hb_bitbuffer_get( pBits, ( i + 4 ) * iLen + j ) &&
! hb_bitbuffer_get( pBits, ( i + 5 ) * iLen + j ) &&
hb_bitbuffer_get( pBits, ( i + 6 ) * iLen + j ) )
iPenalty += 40;
}
}
/* 4. Proportion of color modules */
k = 0;
for( i = 0; i < iLen; i++ )
for( j = 0; j < iLen; j++ )
if( hb_bitbuffer_get( pBits, i * iLen + j ) )
k++;
k = k * 100 / ( iLen * iLen );
if( k < 50 )
k = 100 - k;
iPenalty += ( k / 5 ) * 10;
return iPenalty;
}
static void _qr_mask_pattern( PHB_BITBUFFER pBits, int iVersion, int iMask )
{
int i, j, k = 0, iLen = _qr_versionlength( iVersion );
for( i = 0; i < iLen; i++ )
{
for( j = 0; j < iLen; j++ )
{
if( ! _qr_fixed( iVersion, i, j ) )
{
switch( iMask )
{
case 0:
k = ( i + j ) % 2 == 0;
break;
case 1:
k = i % 2 == 0;
break;
case 2:
k = j % 3 == 0;
break;
case 3:
k = ( i + j ) % 3 == 0;
break;
case 4:
k = ( i / 2 + j / 3 ) % 2 == 0;
break;
case 5:
k = ( i * j ) % 2 + ( i * j ) % 3 == 0;
break;
case 6:
k = ( ( i * j ) % 2 + ( i * j ) % 3 ) % 2 == 0;
break;
case 7:
k = ( ( i * j ) % 3 + ( i + j ) % 2 ) % 2 == 0;
break;
}
if( k )
hb_bitbuffer_not( pBits, i * iLen + j );
}
}
}
}
static int _qr_mask( PHB_BITBUFFER pBits, int iVersion )
{
int i, iPenaltyMin = 0, iMaskMin = 0;
for( i = 0; i < 8; i++ )
{
int iPenalty;
_qr_mask_pattern( pBits, iVersion, i );
iPenalty = _qr_penalty( pBits, iVersion );
#ifdef DEBUG_CODE
HB_TRACE( HB_TR_ALWAYS, ( "mask:%d penalty:%d", i, iPenalty ) );
#endif
if( i == 0 || iPenalty < iPenaltyMin )
{
iPenaltyMin = iPenalty;
iMaskMin = i;
}
_qr_mask_pattern( pBits, iVersion, i );
}
#ifdef DEBUG_CODE
HB_TRACE( HB_TR_ALWAYS, ( "mask:%d", iMaskMin ) );
#if 0
iMaskMin = 0;
#endif
HB_TRACE( HB_TR_ALWAYS, ( "mask applied:%d", iMaskMin ) );
#endif
_qr_mask_pattern( pBits, iVersion, iMaskMin );
return iMaskMin;
}
static void _qr_draw_version_format( PHB_BITBUFFER pBits, int iVersion, int iLevel, int iMask )
{
int i, iCRC, iLen = _qr_versionlength( iVersion );
if( iVersion >= 7 )
{
iCRC = _qr_version_crc( iVersion );
for( i = 0; i < 18; i++ )
{
if( iCRC & ( 1 << 17 ) )
{
hb_bitbuffer_set( pBits, iLen - 11 + ( i % 3 ) + iLen * ( i / 3 ), 1 );
hb_bitbuffer_set( pBits, ( iLen - 11 + ( i % 3 ) ) * iLen + ( i / 3 ), 1 );
}
iCRC <<= 1;
}
}
iCRC = _qr_format_crc( iLevel, iMask );
for( i = 0; i < 15; i++ )
{
if( iCRC & ( 1 << 14 ) )
{
/* Top left */
if( i <= 7 )
hb_bitbuffer_set( pBits, ( i + ( i >= 6 ? 1 : 0 ) ) * iLen + 8, 1 );
else
hb_bitbuffer_set( pBits, ( 14 - i ) + ( i == 8 ? 1 : 0 ) + iLen * 8, 1 );
/* Top right and bottom left */
if( i <= 7 )
hb_bitbuffer_set( pBits, iLen - 1 - i + iLen * 8, 1 );
else
hb_bitbuffer_set( pBits, ( iLen - 15 + i ) * iLen + 8, 1 );
}
iCRC <<= 1;
}
#if 0
/* _qr_fixed() test code */
for( i = 0; i < iLen; i++ )
{
int j;
for( j = 0; j < iLen; j++ )
hb_bitbuffer_set( pBits, i * iLen + j, _qr_fixed( iVersion, i, j ) );
}
#endif
}
PHB_ZEBRA hb_zebra_create_qrcode( const char * szCode, HB_SIZE nLen, int iFlags )
{
PHB_ZEBRA pZebra;
PHB_BITBUFFER pData, pFinal;
unsigned char * pECC;
int iVersion, iLevel, iMask;
pZebra = hb_zebra_create();
pZebra->iType = HB_ZEBRA_TYPE_QRCODE;
if( nLen > 7089 )
{
pZebra->iError = HB_ZEBRA_ERROR_TOOLARGE;
return pZebra;
}
switch( iFlags & HB_ZEBRA_FLAG_QR_LEVEL_MASK )
{
case HB_ZEBRA_FLAG_QR_LEVEL_M:
iLevel = 1;
break;
case HB_ZEBRA_FLAG_QR_LEVEL_Q:
iLevel = 2;
break;
case HB_ZEBRA_FLAG_QR_LEVEL_H:
iLevel = 3;
break;
default:
iLevel = 0;
break;
}
#ifdef DEBUG_CODE
HB_TRACE( HB_TR_ALWAYS, ( "qr1 iLevel:%d", iLevel ) );
#endif
pData = hb_bitbuffer_create();
iVersion = _qr_dataencode( szCode, nLen, pData, iLevel );
#ifdef DEBUG_CODE
HB_TRACE( HB_TR_ALWAYS, ( "qr3 iVersion:%d", iVersion ) );
#endif
if( iVersion == 0 )
{
hb_bitbuffer_destroy( pData );
pZebra->iError = HB_ZEBRA_ERROR_TOOLARGE;
return pZebra;
}
pZebra->iCol = _qr_versionlength( iVersion );
pZebra->szCode = hb_strdup( szCode );
pECC = _qr_checksum( pData, iVersion, iLevel );
pFinal = _qr_interlace( pData, pECC, iVersion, iLevel );
hb_bitbuffer_destroy( pData );
hb_xfree( pECC );
pZebra->pBits = hb_bitbuffer_create();
_qr_draw( pZebra->pBits, pFinal, iVersion );
hb_bitbuffer_destroy( pFinal );
iMask = _qr_mask( pZebra->pBits, iVersion );
_qr_draw_version_format( pZebra->pBits, iVersion, iLevel, iMask );
return pZebra;
}
HB_FUNC( HB_ZEBRA_CREATE_QRCODE )
{
PHB_ITEM pItem = hb_param( 1, HB_IT_STRING );
if( pItem )
hb_zebra_ret( hb_zebra_create_qrcode( hb_itemGetCPtr( pItem ), hb_itemGetCLen( pItem ), hb_parni( 2 ) ) );
else
hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}