Files
harbour-core/contrib/hbzebra/qrcode.c
Viktor Szakats 5a2a287752 2017-09-08 16:00 UTC Viktor Szakats (vszakats users.noreply.github.com)
* *
    * partial sync with the 3.4 fork codebase. These are the things
      synces for the most part:
      - copyright headers
      - grammar/typos in comments and some readmes
      - comment/whitespace/decorations
      - variable scoping in C files
      - DO CASE/SWITCH and some other alternate syntax usage
      - minimal amount of human readable text in strings
      - minor code updates
      - HB_TRACE() void * casts for pointers and few other changes to
        avoid C compiler warnings
      - various other, minor code cleanups
      - only Harbour/C code/headers were touched in src, utils, contrib,
        include. No 3rd party code, no make files, and with just a few
        exceptions, no 'tests' code was touched.
      - certain components were not touched were 3.4 diverged too much
        already, like f.e. hbmk2, hbssl, hbcurl, hbexpat
      - the goal was that no actual program logic should be altered by
        these changes. Except some possible minor exceptions, any such
        change is probably a bug in this patch.
      It's a massive patch, if you find anything broken after it, please
      open an Issue with the details. Build test was done on macOS.
      The goal is make it easier to see what actual code/logic was changed
      in 3.4 compared to 3.2 and to make patches easier to apply in both
      ways.
2017-09-08 16:25:13 +00:00

1300 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 ) );
/* iMaskMin = 0; */
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 );
}