395 lines
12 KiB
C
395 lines
12 KiB
C
/*
|
|
* Zebra barcode library
|
|
*
|
|
* Copyright 2010 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.
|
|
*
|
|
*/
|
|
|
|
#include "hbzebra.h"
|
|
|
|
|
|
static const unsigned short s_code[] = {
|
|
00633, /* 00 */
|
|
00663, /* ! ! 01 */
|
|
01463, /* " " 02 */
|
|
00311, /* # # 03 */
|
|
00611, /* $ $ 04 */
|
|
00621, /* % % 05 */
|
|
00231, /* & & 06 */
|
|
00431, /* ' ' 07 */
|
|
00461, /* ( ( 08 */
|
|
00223, /* ) ) 09 */
|
|
00423, /* * * 10 */
|
|
00443, /* + + 11 */
|
|
00715, /* , , 12 */
|
|
00731, /* - - 13 */
|
|
01631, /* . . 14 */
|
|
00635, /* / / 15 */
|
|
00671, /* 0 0 16 */
|
|
01471, /* 1 1 17 */
|
|
01163, /* 2 2 18 */
|
|
00723, /* 3 3 19 */
|
|
01623, /* 4 4 20 */
|
|
00473, /* 5 5 21 */
|
|
00563, /* 6 6 22 */
|
|
01667, /* 7 7 23 */
|
|
00627, /* 8 8 24 */
|
|
00647, /* 9 9 25 */
|
|
01447, /* : : 26 */
|
|
00467, /* ; ; 27 */
|
|
00547, /* < < 28 */
|
|
01147, /* = = 29 */
|
|
00333, /* > > 30 */
|
|
01433, /* ? ? 31 */
|
|
01543, /* @ @ 32 */
|
|
00305, /* A A 33 */
|
|
00321, /* B B 34 */
|
|
01421, /* C C 35 */
|
|
00215, /* D D 36 */
|
|
00261, /* E E 37 */
|
|
01061, /* F F 38 */
|
|
00213, /* G G 39 */
|
|
00243, /* H H 40 */
|
|
01043, /* I I 41 */
|
|
00355, /* J J 42 */
|
|
01615, /* K K 43 */
|
|
01661, /* L L 44 */
|
|
00335, /* M M 45 */
|
|
01435, /* N N 46 */
|
|
01561, /* O O 47 */
|
|
01567, /* P P 48 */
|
|
01613, /* Q Q 49 */
|
|
01643, /* R R 50 */
|
|
00273, /* S S 51 */
|
|
01073, /* T T 52 */
|
|
01673, /* U U 53 */
|
|
00327, /* V V 54 */
|
|
01427, /* W W 55 */
|
|
01507, /* X X 56 */
|
|
00267, /* Y Y 57 */
|
|
01067, /* Z Z 58 */
|
|
01307, /* [ [ 59 */
|
|
01367, /* \ \ 60 */
|
|
01023, /* ] ] 61 */
|
|
01217, /* ^ ^ 62 */
|
|
00145, /* _ _ 63 */
|
|
00605, /* NUL ` 64 */
|
|
00151, /* SOH a 65 */
|
|
01411, /* STX b 66 */
|
|
00641, /* ETX c 67 */
|
|
01441, /* EOT d 68 */
|
|
00115, /* ENQ e 69 */
|
|
00415, /* ACK f 70 */
|
|
00131, /* BEL g 71 */
|
|
01031, /* BS h 72 */
|
|
00541, /* HT i 73 */
|
|
01141, /* LF j 74 */
|
|
01103, /* VT k 75 */
|
|
00123, /* FF l 76 */
|
|
01357, /* CR m 77 */
|
|
00503, /* SO n 78 */
|
|
01361, /* SI o 79 */
|
|
00745, /* DLE p 80 */
|
|
00751, /* DC1 q 81 */
|
|
01711, /* DC2 r 82 */
|
|
00475, /* DC3 s 83 */
|
|
00571, /* DC4 t 84 */
|
|
01171, /* NAK u 85 */
|
|
00457, /* SYN v 86 */
|
|
00517, /* ETB w 87 */
|
|
01117, /* CAN x 88 */
|
|
01733, /* EM y 89 */
|
|
01573, /* SUB z 90 */
|
|
01557, /* ESC { 91 */
|
|
00365, /* FS | 92 */
|
|
01705, /* GS } 93 */
|
|
01721, /* RS ~ 94 */
|
|
00275, /* US DEL 95 */
|
|
01075, /* FNC3 FNC3 96 */
|
|
00257, /* FNC2 FNC2 97 */
|
|
01057, /* ShiB ShiA 98 */
|
|
01735, /* CodC CodC 99 */
|
|
01675, /* CodB FNC4 CodB 100 */
|
|
01727, /* FNC4 CodA CodA 101 */
|
|
01657, /* FNC1 FNC1 FNC1 102 */
|
|
00413, /* Start Code A 103 */
|
|
00113, /* Start Code B 104 */
|
|
00713 /* Start Code C 105 */
|
|
};
|
|
|
|
#define CODESET_A 0
|
|
#define CODESET_B 1
|
|
|
|
#define START_A 103
|
|
#define START_B 104
|
|
#define START_C 105
|
|
|
|
#define SELECT_A 101
|
|
#define SELECT_B 100
|
|
#define SELECT_C 99
|
|
|
|
#define SHIFT_AB 98
|
|
|
|
|
|
static int _code128_charno( char ch, int iCodeSet )
|
|
{
|
|
if( iCodeSet == CODESET_A )
|
|
{
|
|
if( ch >= ' ' && ch <= '_' )
|
|
return ch - ' ';
|
|
else if( ( unsigned char ) ch <= 31 )
|
|
return ch + 64;
|
|
else
|
|
return -1;
|
|
}
|
|
else if( iCodeSet == CODESET_B )
|
|
{
|
|
if( ch >= ' ' && ( unsigned char ) ch <= 127 )
|
|
return ch - ' ';
|
|
else
|
|
return -1;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
PHB_ZEBRA hb_zebra_create_code128( const char * szCode, HB_SIZE nLen, int iFlags )
|
|
{
|
|
PHB_ZEBRA pZebra;
|
|
int i, j, k, csum, iCodeSet, iCodeLen, iLen = ( int ) nLen;
|
|
int * pCode;
|
|
|
|
HB_SYMBOL_UNUSED( iFlags );
|
|
|
|
pZebra = hb_zebra_create();
|
|
pZebra->iType = HB_ZEBRA_TYPE_CODE128;
|
|
|
|
j = 0;
|
|
for( i = 0; i < iLen; i++ )
|
|
{
|
|
if( ( unsigned char ) szCode[ i ] >= 128 )
|
|
{
|
|
pZebra->iError = HB_ZEBRA_ERROR_INVALIDCODE;
|
|
return pZebra;
|
|
}
|
|
if( szCode[ i ] >= ' ' && szCode[ i ] <= 126 )
|
|
j++;
|
|
}
|
|
|
|
/* make print string */
|
|
pZebra->szCode = ( char * ) hb_xgrab( j + 1 );
|
|
j = 0;
|
|
for( i = 0; i < iLen; i++ )
|
|
{
|
|
if( szCode[ i ] >= 32 && szCode[ i ] <= 126 )
|
|
pZebra->szCode[ j++ ] = szCode[ i ];
|
|
}
|
|
pZebra->szCode[ j ] = '\0';
|
|
|
|
/* generate code set switch characters */
|
|
pCode = ( int * ) hb_xgrab( sizeof( int ) * iLen * 2 );
|
|
iCodeSet = CODESET_B; /* to pacify MSVC warning only. It will be assigned later */
|
|
iCodeLen = 0;
|
|
/* determine the first optimal codeset */
|
|
for( i = 0; i < iLen; i++ )
|
|
{
|
|
if( _code128_charno( szCode[ i ], CODESET_A ) == -1 )
|
|
{
|
|
iCodeSet = CODESET_B;
|
|
pCode[ iCodeLen++ ] = START_B;
|
|
break;
|
|
}
|
|
else if( _code128_charno( szCode[ i ], CODESET_B ) == -1 )
|
|
{
|
|
iCodeSet = CODESET_A;
|
|
pCode[ iCodeLen++ ] = START_A;
|
|
break;
|
|
}
|
|
}
|
|
if( iCodeLen == 0 )
|
|
{
|
|
iCodeSet = CODESET_B;
|
|
pCode[ iCodeLen++ ] = START_B;
|
|
}
|
|
|
|
/* encode source data */
|
|
/* Warning: digit optimizer works in optimal way with this encoder code. Be careful
|
|
if you'll change encoder code, digit optimizer can require adjustment also [Mindaugas] */
|
|
for( i = 0; i < iLen; i++ )
|
|
{
|
|
int iCode = _code128_charno( szCode[ i ], iCodeSet );
|
|
|
|
if( iCode != -1 )
|
|
pCode[ iCodeLen++ ] = iCode;
|
|
else
|
|
{
|
|
/* We should generate codeset switch instead of shift for the last character.
|
|
This will help digit optimizer to do its job [Mindaugas] */
|
|
if( i + 1 < iLen &&
|
|
_code128_charno( szCode[ i + 1 ], iCodeSet == CODESET_A ? CODESET_B : CODESET_A ) == -1 )
|
|
{
|
|
pCode[ iCodeLen++ ] = SHIFT_AB;
|
|
pCode[ iCodeLen++ ] = _code128_charno( szCode[ i ], iCodeSet == CODESET_A ? CODESET_B : CODESET_A );
|
|
}
|
|
else
|
|
{
|
|
if( iCodeSet == CODESET_A )
|
|
{
|
|
iCodeSet = CODESET_B;
|
|
pCode[ iCodeLen++ ] = SELECT_B;
|
|
}
|
|
else
|
|
{
|
|
iCodeSet = CODESET_A;
|
|
pCode[ iCodeLen++ ] = SELECT_A;
|
|
}
|
|
pCode[ iCodeLen++ ] = _code128_charno( szCode[ i ], iCodeSet );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* optimize digits */
|
|
iCodeSet = pCode[ 0 ] == START_A ? CODESET_A : CODESET_B;
|
|
for( i = 1; i < iCodeLen; i++ )
|
|
{
|
|
if( iCodeSet == CODESET_A && pCode[ i ] == SELECT_B )
|
|
iCodeSet = CODESET_B;
|
|
else if( iCodeSet == CODESET_B && pCode[ i ] == SELECT_A )
|
|
iCodeSet = CODESET_A;
|
|
|
|
if( 16 <= pCode[ i ] && pCode[ i ] <= 25 )
|
|
{
|
|
for( j = i + 1; j < iCodeLen && 16 <= pCode[ j ] && pCode[ j ] <= 25; j++ )
|
|
;
|
|
|
|
if( j - i == 2 && i == 1 && j == iCodeLen )
|
|
{
|
|
/* [StartB] 1 2 --> [StartC] [12] */
|
|
pCode[ 0 ] = START_C;
|
|
pCode[ 1 ] = ( pCode[ 1 ] - 16 ) * 10 + pCode[ 2 ] - 16;
|
|
iCodeLen = 2;
|
|
break;
|
|
}
|
|
else if( ( j - i >= 4 && ( i == 1 || j == iCodeLen || pCode[ j ] == SELECT_A || pCode[ j ] == SELECT_B ) ) ||
|
|
j - i >= 6 )
|
|
{
|
|
if( i == 1 )
|
|
{
|
|
/* [StartN] 1 2 3 4 --> [StartC] [12] [34] */
|
|
/* [StartN] 1 2 3 4 5 --> [StartC] [12] [34] [CodeN] 5 */
|
|
/* [StartN] 1 2 3 4 X ... --> [StartC] [12] [34] [CodeN] X ... */
|
|
/* [StartN] 1 2 3 4 5 X ... --> [StartC] [12] [34] [CodeN] 5 X ... */
|
|
pCode[ 0 ] = START_C;
|
|
for( k = 1; k < j - 1; k += 2 )
|
|
pCode[ i++ ] = ( pCode[ k ] - 16 ) * 10 + pCode[ k + 1 ] - 16;
|
|
|
|
if( k < iCodeLen )
|
|
{
|
|
j = i;
|
|
pCode[ i++ ] = iCodeSet == CODESET_A ? SELECT_A : SELECT_B;
|
|
for( ; k < iCodeLen; k++ )
|
|
pCode[ i++ ] = pCode[ k ];
|
|
}
|
|
iCodeLen = i;
|
|
}
|
|
else
|
|
{
|
|
/* ... X 1 2 3 4 --> ... X [CodeC] [12] [34] */
|
|
/* ... X 1 2 3 4 [CodeN] ... --> ... X [CodeC] [12] [34] [CodeN] ... */
|
|
/* ... X 1 2 3 4 5 --> ... X 1 [CodeC] [23] [45] */
|
|
/* ... X 1 2 3 4 5 [CodeN] ... --> ... X 1 [CodeC] [23] [45] [CodeN] ... */
|
|
/* ... X 1 2 3 4 5 6 Y ... --> ... X [CodeC] [12] [34] [56] [CodeN] Y ... */
|
|
/* ... X 1 2 3 4 5 6 7 Y ... --> ... X 1 [CodeC] [23] [45] [67] [CodeN] Y ... */
|
|
|
|
if( ( j - i ) & 1 )
|
|
{
|
|
/* digit count is odd */
|
|
i++;
|
|
}
|
|
|
|
pCode[ i + 1 ] = ( pCode[ i ] - 16 ) * 10 + pCode[ i + 1 ] - 16;
|
|
pCode[ i ] = SELECT_C;
|
|
i += 2;
|
|
for( k = i; k < j; k += 2 )
|
|
pCode[ i++ ] = ( pCode[ k ] - 16 ) * 10 + pCode[ k + 1 ] - 16;
|
|
j = i;
|
|
if( k < iCodeLen )
|
|
{
|
|
if( pCode[ k ] != SELECT_A && pCode[ k ] != SELECT_B )
|
|
pCode[ i++ ] = iCodeSet == CODESET_A ? SELECT_A : SELECT_B;
|
|
|
|
for( ; k < iCodeLen; k++ )
|
|
pCode[ i++ ] = pCode[ k ];
|
|
}
|
|
iCodeLen = i;
|
|
}
|
|
}
|
|
i = j - 1;
|
|
}
|
|
}
|
|
|
|
pZebra->pBits = hb_bitbuffer_create();
|
|
csum = pCode[ 0 ];
|
|
for( i = 0; i < iCodeLen; i++ )
|
|
{
|
|
hb_bitbuffer_cat_int( pZebra->pBits, s_code[ pCode[ i ] ], 11 );
|
|
csum += i * pCode[ i ];
|
|
}
|
|
|
|
hb_xfree( pCode );
|
|
/* checksum */
|
|
hb_bitbuffer_cat_int( pZebra->pBits, s_code[ csum % 103 ], 11 );
|
|
|
|
hb_bitbuffer_cat_int( pZebra->pBits, 0x1AE3, 13 );
|
|
return pZebra;
|
|
}
|
|
|
|
|
|
HB_FUNC( HB_ZEBRA_CREATE_CODE128 )
|
|
{
|
|
PHB_ITEM pItem = hb_param( 1, HB_IT_STRING );
|
|
|
|
if( pItem )
|
|
hb_zebra_ret( hb_zebra_create_code128( hb_itemGetCPtr( pItem ), hb_itemGetCLen( pItem ), hb_parni( 2 ) ) );
|
|
else
|
|
hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
}
|