2016-08-24 21:39:39 +03:00
/* codablock.c - Handles Codablock-F and Codablock-E */
/*
libzint - the open source barcode library
Copyright ( C ) 2016 Harald Oehlmann
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
2016-09-12 16:49:17 +03:00
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2016-08-24 21:39:39 +03:00
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
2016-09-12 16:49:17 +03:00
documentation and / or other materials provided with the distribution .
2016-08-24 21:39:39 +03:00
3. Neither the name of the project nor the names of its contributors
may be used to endorse or promote products derived from this software
2016-09-12 16:49:17 +03:00
without specific prior written permission .
2016-08-24 21:39:39 +03:00
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
2016-09-12 16:49:17 +03:00
OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
2016-08-24 21:39:39 +03:00
SUCH DAMAGE .
*/
# include <stdio.h>
2016-09-04 13:04:41 +03:00
# include <math.h>
2016-08-31 17:29:21 +03:00
# include <string.h>
# include <stdlib.h>
# ifdef _MSC_VER
2016-09-12 16:49:17 +03:00
# include <malloc.h>
2016-08-31 17:29:21 +03:00
# endif
2016-08-24 21:39:39 +03:00
# include "common.h"
2016-09-04 13:04:41 +03:00
# include "gs1.h"
2016-08-31 17:29:21 +03:00
# define uchar unsigned char
2016-08-24 21:39:39 +03:00
2016-09-12 16:49:17 +03:00
/* FTab C128 flags - may be added */
2016-08-31 17:29:21 +03:00
# define CodeA 1
# define CodeB 2
# define CodeC 4
# define CEnd 8
# define CShift 16
# define CFill 32
# define CodeFNC1 64
2016-09-04 13:04:41 +03:00
# define ZTNum (CodeA+CodeB+CodeC)
# define ZTFNC1 (CodeA+CodeB+CodeC+CodeFNC1)
/* ASCII-Extension for Codablock-F */
# define aFNC1 (uchar)(128)
# define aFNC2 (uchar)(129)
# define aFNC3 (uchar)(130)
# define aFNC4 (uchar)(131)
# define aCodeA (uchar)(132)
# define aCodeB (uchar)(133)
# define aCodeC (uchar)(134)
# define aShift (uchar)(135)
static const char * C128Table [ 107 ] = {
/* Code 128 character encodation - Table 1 */
" 212222 " , " 222122 " , " 222221 " , " 121223 " , " 121322 " , " 131222 " , " 122213 " ,
" 122312 " , " 132212 " , " 221213 " , " 221312 " , " 231212 " , " 112232 " , " 122132 " , " 122231 " , " 113222 " ,
" 123122 " , " 123221 " , " 223211 " , " 221132 " , " 221231 " , " 213212 " , " 223112 " , " 312131 " , " 311222 " ,
" 321122 " , " 321221 " , " 312212 " , " 322112 " , " 322211 " , " 212123 " , " 212321 " , " 232121 " , " 111323 " ,
" 131123 " , " 131321 " , " 112313 " , " 132113 " , " 132311 " , " 211313 " , " 231113 " , " 231311 " , " 112133 " ,
" 112331 " , " 132131 " , " 113123 " , " 113321 " , " 133121 " , " 313121 " , " 211331 " , " 231131 " , " 213113 " ,
" 213311 " , " 213131 " , " 311123 " , " 311321 " , " 331121 " , " 312113 " , " 312311 " , " 332111 " , " 314111 " ,
" 221411 " , " 431111 " , " 111224 " , " 111422 " , " 121124 " , " 121421 " , " 141122 " , " 141221 " , " 112214 " ,
" 112412 " , " 122114 " , " 122411 " , " 142112 " , " 142211 " , " 241211 " , " 221114 " , " 413111 " , " 241112 " ,
" 134111 " , " 111242 " , " 121142 " , " 121241 " , " 114212 " , " 124112 " , " 124211 " , " 411212 " , " 421112 " ,
" 421211 " , " 212141 " , " 214121 " , " 412121 " , " 111143 " , " 111341 " , " 131141 " , " 114113 " , " 114311 " ,
" 411113 " , " 411311 " , " 113141 " , " 114131 " , " 311141 " , " 411131 " , " 211412 " , " 211214 " , " 211232 " ,
" 2331112 "
} ;
2016-08-31 17:29:21 +03:00
/* Code F Analysing-Chart */
typedef struct sCharacterSetTable
{
2016-09-12 16:49:17 +03:00
int CharacterSet ; /* Still possible character sets for actual*/
int AFollowing ; /* Still following Characters in Charset A */
int BFollowing ; /* Still following Characters in Charset B */
int CFollowing ; /* Still following Characters in Charset C */
2016-08-31 17:29:21 +03:00
} CharacterSetTable ;
2016-09-12 16:49:17 +03:00
/* Find the possible Code-128 Character sets for a character
2016-08-31 17:29:21 +03:00
* The result is an or of CodeA , CodeB , CodeC , CodeFNC1 in dependency of the
* possible Code 128 character sets .
*/
int GetPossibleCharacterSet ( unsigned char C )
{
2016-09-12 16:49:17 +03:00
if ( C < = ' \x19 ' ) /* Dec:31 */
return CodeA ;
if ( C > = ' 0 ' & & C < = ' 9 ' )
return ZTNum ; /* ZTNum=CodeA+CodeB+CodeC */
if ( C = = aFNC1 )
return ZTFNC1 ; /* ZTFNC1=CodeA+CodeB+CodeC+CodeFNC1 */
if ( C > = ' \x60 ' & & C < = ' \x7f ' ) /* 60 to 127 */
return CodeB ;
return CodeA + CodeB ;
2016-08-31 17:29:21 +03:00
}
/* Create a Table with the following information for each Data character:
2016-09-12 16:49:17 +03:00
* int CharacterSet is an or of CodeA , CodeB , CodeC , CodeFNC1 , in
* dependency which character set is applicable .
* ( Result of GetPossibleCharacterSet )
* int AFollowing , BFollowing The number of source characters you still may encode
* in this character set .
* int CFollowing The number of characters encodable in CodeC if we
* start here .
2016-08-31 17:29:21 +03:00
*/
2017-06-13 22:05:35 +03:00
static void CreateCharacterSetTable ( CharacterSetTable T [ ] , unsigned char * data , const size_t dataLength )
2016-08-31 17:29:21 +03:00
{
2016-09-12 16:49:17 +03:00
int charCur ;
int runChar ;
/* Treat the Data backwards */
charCur = dataLength - 1 ;
T [ charCur ] . CharacterSet = GetPossibleCharacterSet ( data [ charCur ] ) ;
T [ charCur ] . AFollowing = ( ( T [ charCur ] . CharacterSet & CodeA ) = = 0 ) ? 0 : 1 ;
T [ charCur ] . BFollowing = ( ( T [ charCur ] . CharacterSet & CodeB ) = = 0 ) ? 0 : 1 ;
T [ charCur ] . CFollowing = 0 ;
for ( charCur - - ; charCur > = 0 ; charCur - - )
{
T [ charCur ] . CharacterSet = GetPossibleCharacterSet ( data [ charCur ] ) ;
T [ charCur ] . AFollowing =
( ( T [ charCur ] . CharacterSet & CodeA ) = = 0 ) ? 0 : T [ charCur + 1 ] . AFollowing + 1 ;
T [ charCur ] . BFollowing =
( ( T [ charCur ] . CharacterSet & CodeB ) = = 0 ) ? 0 : T [ charCur + 1 ] . BFollowing + 1 ;
T [ charCur ] . CFollowing = 0 ;
}
/* Find the CodeC-chains */
for ( charCur = 0 ; charCur < dataLength ; charCur + + )
{
T [ charCur ] . CFollowing = 0 ;
if ( ( T [ charCur ] . CharacterSet & CodeC ) ! = 0 )
{
/* CodeC possible */
runChar = charCur ;
do {
/* Wether this is FNC1 wether next is */
/* numeric */
if ( T [ runChar ] . CharacterSet = = ZTFNC1 )
/* FNC1 */
+ + ( T [ charCur ] . CFollowing ) ;
else
{
+ + runChar ;
if ( runChar > = dataLength )
break ;
/* Only a Number may follow */
if ( T [ runChar ] . CharacterSet = = ZTNum )
T [ charCur ] . CFollowing + = 2 ;
else
break ;
}
+ + runChar ;
} while ( runChar < dataLength ) ;
}
}
2016-08-31 17:29:21 +03:00
}
2016-09-12 16:49:17 +03:00
/* Find the amount of numerical characters in pairs which will fit in
* one bundle into the line ( up to here ) . This is calculated online because
2016-08-31 17:29:21 +03:00
* it depends on the space in the line .
*/
int RemainingDigits ( CharacterSetTable * T , int charCur , int emptyColumns )
{
2016-09-12 16:49:17 +03:00
int digitCount ; /* Numerical digits fitting in the line */
int runChar ;
runChar = charCur ;
digitCount = 0 ;
while ( emptyColumns > 0 & & runChar < charCur + T [ charCur ] . CFollowing )
{
if ( T [ runChar ] . CharacterSet ! = ZTFNC1 )
{
/* NOT FNC1 */
digitCount + = 2 ;
runChar + + ;
}
runChar + + ;
emptyColumns - - ;
}
return digitCount ;
2016-08-31 17:29:21 +03:00
}
2016-09-12 16:49:17 +03:00
/* Find the Character distribution at a given column count.
2016-08-31 17:29:21 +03:00
* If to many rows ( > 44 ) are requested the columns is extended .
2016-09-12 16:49:17 +03:00
* A oneLigner may be choosen if shorter .
2016-08-31 17:29:21 +03:00
* Parameters :
2016-09-12 16:49:17 +03:00
* T Pointer on the Characters which fit in the row
* If a different count is calculated it is corrected
* in the callers workspace .
* pFillings Output of filling characters
* pSet Output of the character sets used , allocated by me .
* Data The Data string to encode , exceptionnally not an out
* Return value Resulting row count
2016-08-31 17:29:21 +03:00
*/
2017-06-13 22:05:35 +03:00
static int Columns2Rows ( CharacterSetTable * T , unsigned char * data , const size_t dataLength ,
2016-09-12 16:49:17 +03:00
int * pRows , int * pUseColumns , int * pSet , int * pFillings )
2016-08-31 17:29:21 +03:00
{
2016-09-12 16:49:17 +03:00
int useColumns ; /* Usable Characters per line */
int fillings ; /* Number of filling characters */
int rowsCur ;
int runChar ;
int emptyColumns ; /* Number of codes still empty in line. */
int emptyColumns2 ; /* Alternative emptyColumns to compare */
int CPaires ; /* Number of digit pairs which may fit in the line */
int characterSetCur ; /* Current Character Set */
useColumns = * pUseColumns ;
if ( useColumns < 3 )
useColumns = 3 ;
/* >>> Loop until rowsCur<44 */
do {
2017-10-23 22:34:31 +03:00
int charCur = 0 ;
int fOneLiner = 1 ; /* First try one-Liner */
2016-09-12 16:49:17 +03:00
memset ( pSet , 0 , dataLength * sizeof ( int ) ) ;
rowsCur = 0 ;
/* >>> Line and OneLiner-try Loop */
do {
/* >> Start Character */
emptyColumns = useColumns ; /* Remained place in Line */
if ( fOneLiner )
emptyColumns + = 2 ;
/* >>Choose in Set A or B */
/* (C is changed as an option later on) */
pSet [ charCur ] = characterSetCur =
( T [ charCur ] . AFollowing > T [ charCur ] . BFollowing )
? CodeA : CodeB ;
/* >> Test on Numeric Mode C */
CPaires = RemainingDigits ( T , charCur , emptyColumns ) ;
if ( CPaires > = 4 )
{
/* 4 Digits in Numeric compression ->OK */
/* > May an odd start find more ? */
/* Skip leading <FNC1>'s */
/* Typical structure : <FNC1><FNC1>12... */
/* Test if numeric after one isn't better.*/
runChar = charCur ;
emptyColumns2 = emptyColumns ;
while ( T [ runChar ] . CharacterSet = = ZTFNC1 )
{
+ + runChar ;
- - emptyColumns2 ;
}
if ( CPaires > = RemainingDigits ( T , runChar + 1 , emptyColumns2 - 1 ) )
{
/* Start odd is not better */
/* We start in C */
pSet [ charCur ] = characterSetCur = CodeC ;
/* Inkrement charCur */
if ( T [ charCur ] . CharacterSet ! = ZTFNC1 )
+ + charCur ; /* 2 Num.Digits */
}
}
+ + charCur ;
- - emptyColumns ;
/* >> Following characters */
while ( emptyColumns > 0 & & charCur < dataLength )
{
switch ( characterSetCur ) {
case CodeA :
case CodeB :
/* >> Check switching to CodeC */
/* Switch if :
* - Character not FNC1
* - 4 real Digits will fit in line
* - an odd Start will not be better
*/
if ( T [ charCur ] . CharacterSet = = ZTNum
& & ( CPaires = RemainingDigits ( T , charCur , emptyColumns - 1 ) ) > = 4
& & CPaires > RemainingDigits ( T , charCur + 1 , emptyColumns - 2 ) )
{
/* > Change to C */
pSet [ charCur ] = characterSetCur = CodeC ;
charCur + = 2 ; /* 2 Digit */
emptyColumns - = 2 ; /* <SwitchC>12 */
} else if ( characterSetCur = = CodeA )
{
if ( T [ charCur ] . AFollowing = = 0 )
{
/* Must change to B */
if ( emptyColumns = = 1 )
{
/* Can't switch: */
pSet [ charCur - 1 ] | = CEnd + CFill ;
emptyColumns = 0 ;
} else {
/* <Shift> or <switchB>? */
2017-04-03 12:47:39 +03:00
if ( T [ charCur ] . BFollowing = = 1 )
{
pSet [ charCur ] | = CShift ;
} else {
pSet [ charCur ] | = CodeB ;
characterSetCur = CodeB ;
}
2016-09-12 16:49:17 +03:00
emptyColumns - = 2 ;
+ + charCur ;
}
} else {
- - emptyColumns ;
+ + charCur ;
}
} else { /* Last possibility : CodeB */
if ( T [ charCur ] . BFollowing = = 0 )
{
/* Must change to A */
if ( emptyColumns = = 1 )
{
/* Can't switch: */
pSet [ charCur - 1 ] | = CEnd + CFill ;
emptyColumns = 0 ;
} else {
/* <Shift> or <switchA>? */
2017-04-03 12:47:39 +03:00
if ( T [ charCur ] . AFollowing = = 1 )
{
pSet [ charCur ] | = CShift ;
} else {
pSet [ charCur ] | = CodeA ;
characterSetCur = CodeA ;
}
2016-09-12 16:49:17 +03:00
emptyColumns - = 2 ;
+ + charCur ;
}
} else {
- - emptyColumns ;
+ + charCur ;
}
}
break ;
case CodeC :
if ( T [ charCur ] . CFollowing > 0 )
{
charCur + = ( T [ charCur ] . CharacterSet = = ZTFNC1 ) ? 1 : 2 ;
emptyColumns - - ;
} else {
/* Must change to A or B */
if ( emptyColumns = = 1 )
{
/* Can't switch: */
pSet [ charCur - 1 ] | = CEnd + CFill ;
emptyColumns = 0 ;
} else {
/*<SwitchA> or <switchA>?*/
characterSetCur = pSet [ charCur ] =
( T [ charCur ] . AFollowing > T [ charCur ] . BFollowing )
? CodeA : CodeB ;
emptyColumns - = 2 ;
+ + charCur ;
}
}
break ;
} /* switch */
} /* while */
/* > End of Codeline */
pSet [ charCur - 1 ] | = CEnd ;
+ + rowsCur ;
if ( fOneLiner )
{
if ( charCur < dataLength )
{
/* One line not sufficiant */
fOneLiner = 0 ;
/* Reset and Start again */
charCur = 0 ;
rowsCur = 0 ;
memset ( pSet , 0 , dataLength * sizeof ( int ) ) ;
} else {
/* Calculate real Length of OneLiner */
/* This is -2 BASED !!! */
useColumns - = emptyColumns ;
}
}
} while ( charCur < dataLength ) ; /* <= Data.Len-1 */
/* Place check characters C1,C2 */
if ( fOneLiner )
fillings = 0 ;
else {
switch ( emptyColumns ) {
case 1 :
pSet [ charCur - 1 ] | = CFill ;
/* Glide in following block without break */
case 0 :
+ + rowsCur ;
fillings = useColumns - 2 + emptyColumns ;
break ;
case 2 :
fillings = 0 ;
break ;
default :
pSet [ charCur - 1 ] | = CFill ;
fillings = emptyColumns - 2 ;
}
}
if ( rowsCur > 44 ) {
+ + useColumns ;
if ( useColumns > 62 ) {
return ZINT_ERROR_TOO_LONG ;
}
}
} while ( rowsCur > 44 ) ;
# ifdef _DEBUG
printf ( " -> out: rowsCur <%i>, useColumns <%i>, fillings <%i> \n " , rowsCur , useColumns , fillings ) ;
# endif
* pUseColumns = useColumns ;
* pRows = rowsCur ;
* pFillings = fillings ;
return 0 ;
2016-08-31 17:29:21 +03:00
}
2016-09-12 16:49:17 +03:00
/* Find columns if row count is given.
2016-08-31 17:29:21 +03:00
*/
2017-06-13 22:05:35 +03:00
static int Rows2Columns ( CharacterSetTable * T , unsigned char * data , const size_t dataLength ,
2016-09-12 16:49:17 +03:00
int * pRows , int * pUseColumns , int * pSet , int * pFillings )
2016-08-31 17:29:21 +03:00
{
2016-09-12 16:49:17 +03:00
int rowsCur ;
int rowsRequested ; /* Number of requested rows */
2016-09-13 09:16:51 +03:00
int backupRows = 0 ;
2016-09-12 16:49:17 +03:00
int fillings ;
2016-09-13 09:16:51 +03:00
int backupFillings = 0 ;
2016-09-12 16:49:17 +03:00
int useColumns ;
int testColumns ; /* To enter into Width2Rows */
2016-09-13 09:16:51 +03:00
int backupColumns = 0 ;
int fBackupOk = 0 ; /* The memorysed set is o.k. */
2016-09-12 16:49:17 +03:00
int testListSize = 0 ;
int pTestList [ 62 ] ;
2016-09-04 13:04:41 +03:00
# ifndef _MSC_VER
2016-09-12 16:49:17 +03:00
int * pBackupSet [ dataLength ] ;
2016-09-04 13:04:41 +03:00
# else
2016-09-12 16:49:17 +03:00
int * pBackupSet = ( int * ) _alloca ( dataLength * sizeof ( int ) ) ;
2016-08-31 17:29:21 +03:00
# endif
2016-09-12 16:49:17 +03:00
rowsRequested = * pRows ;
# ifdef _DEBUG
fprintf ( stderr , " Optimizer : Searching <%i> rows \n " , rowsRequested ) ;
# endif
if ( rowsRequested = = 1 )
/* OneLiners are self-calibrating */
testColumns = 32767 ;
else {
/* First guess */
testColumns = dataLength / rowsRequested ;
if ( testColumns > 62 )
testColumns = 62 ;
else if ( testColumns < 1 )
testColumns = 1 ;
}
2017-10-23 22:34:31 +03:00
for ( ; ; ) {
2017-10-16 20:26:54 +03:00
int errorCur ;
2016-09-12 16:49:17 +03:00
pTestList [ testListSize ] = testColumns ;
testListSize + + ;
useColumns = testColumns ; /* Make a copy because it may be modified */
2017-10-16 20:26:54 +03:00
errorCur = Columns2Rows ( T , data , dataLength , & rowsCur , & useColumns , pSet , & fillings ) ;
2016-09-12 16:49:17 +03:00
if ( errorCur ! = 0 )
return errorCur ;
if ( rowsCur < = rowsRequested ) {
/* Less or exactly line number found */
/* check if column count below already tested or Count = 1*/
2016-09-21 00:19:31 +03:00
int fInTestList = ( rowsCur = = 1 | | testColumns = = 1 ) ;
2016-09-12 16:49:17 +03:00
int posCur ;
for ( posCur = 0 ; posCur < testListSize & & ! fInTestList ; posCur + + ) {
if ( pTestList [ posCur ] = = testColumns - 1 )
fInTestList = 1 ;
}
if ( fInTestList ) {
/* >> Smaller Width already tested
* if rowsCur = rowsRequested - > Exit
* if rowsCur < rowsRequested and fillings > 0
* - > New search for rowsRequested : = rowsCur
*/
2016-09-21 00:19:31 +03:00
if ( rowsCur = = rowsRequested | | fillings = = 0 | | testColumns = = 1 ) {
2016-09-12 16:49:17 +03:00
/* Exit with actual */
* pFillings = fillings ;
* pRows = rowsCur ;
* pUseColumns = useColumns ;
return 0 ;
}
/* Search again for smaller Line number */
rowsRequested = rowsCur ;
pTestList [ 0 ] = testColumns ;
testListSize = 1 ;
}
/* > Test more rows (shorter CDB) */
fBackupOk = ( rowsCur = = rowsRequested ) ;
memcpy ( pBackupSet , pSet , dataLength * sizeof ( int ) ) ;
backupFillings = fillings ;
backupColumns = useColumns ;
backupRows = rowsCur ;
- - testColumns ;
} else {
/* > To many rows */
int fInTestList = fBackupOk ;
int posCur ;
for ( posCur = 0 ; posCur < testListSize & & ! fInTestList ; posCur + + ) {
if ( pTestList [ posCur ] = = testColumns + 1 )
fInTestList = 1 ;
}
if ( fInTestList ) {
/* The next less-rows (larger) code was
* already tested . So give the larger
* back .
*/
memcpy ( pSet , pBackupSet , dataLength * sizeof ( int ) ) ;
* pFillings = backupFillings ;
* pRows = backupRows ;
* pUseColumns = backupColumns ;
return 0 ;
}
/* > Test less rows (longer code) */
backupRows = rowsCur ;
memcpy ( pBackupSet , pSet , dataLength * sizeof ( int ) ) ;
backupFillings = fillings ;
backupColumns = useColumns ;
fBackupOk = 0 ;
+ + testColumns ;
}
}
2016-08-31 17:29:21 +03:00
}
2016-09-04 13:04:41 +03:00
/* Print a character in character set A
*/
void A2C128_A ( uchar * * ppOutPos , uchar c )
{
2016-09-12 16:49:17 +03:00
uchar * pOutPos = * ppOutPos ;
switch ( c ) {
case aCodeB : * pOutPos = 100 ; break ;
case aFNC4 : * pOutPos = 101 ; break ;
case aFNC1 : * pOutPos = 102 ; break ;
case aFNC2 : * pOutPos = 97 ; break ;
case aFNC3 : * pOutPos = 96 ; break ;
case aCodeC : * pOutPos = 99 ; break ;
case aShift : * pOutPos = 98 ; break ;
default :
/* +++ HaO 13.11.98 c>' ' && c < '\x1F' corrected */
if ( c > = ' ' & & c < = ' _ ' )
* pOutPos = ( uchar ) ( c - ' ' ) ;
else
* pOutPos = ( uchar ) ( c + 64 ) ;
break ;
}
( * ppOutPos ) + + ;
}
2016-09-04 13:04:41 +03:00
/* Output c in Set B
*/
void A2C128_B ( uchar * * ppOutPos , uchar c )
{
2016-09-12 16:49:17 +03:00
uchar * pOutPos = * ppOutPos ;
switch ( c ) {
case aFNC1 : * pOutPos = 102 ; break ;
case aFNC2 : * pOutPos = 97 ; break ;
case aFNC3 : * pOutPos = 96 ; break ;
case aFNC4 : * pOutPos = 100 ; break ;
case aCodeA : * pOutPos = 101 ; break ;
case aCodeC : * pOutPos = 99 ; break ;
case aShift : * pOutPos = 98 ; break ;
default : * pOutPos = ( uchar ) ( c - ' ' ) ; break ;
}
+ + ( * ppOutPos ) ;
2016-09-04 13:04:41 +03:00
}
/* Output c1, c2 in Set C
*/
void A2C128_C ( uchar * * ppOutPos , uchar c1 , uchar c2 )
{
2016-09-12 16:49:17 +03:00
uchar * pOutPos = * ppOutPos ;
switch ( c1 ) {
case aFNC1 : * pOutPos = 102 ; break ;
case aCodeB : * pOutPos = 100 ; break ;
case aCodeA : * pOutPos = 101 ; break ;
default : * pOutPos = ( char ) ( 10 * ( c1 - ' 0 ' ) + ( c2 - ' 0 ' ) ) ; break ;
}
( * ppOutPos ) + + ;
2016-09-04 13:04:41 +03:00
}
/* Output a character in Characterset
*/
void ASCIIZ128 ( uchar * * ppOutPos , int CharacterSet , uchar c1 , uchar c2 )
{
2016-09-12 16:49:17 +03:00
if ( CharacterSet = = CodeA )
A2C128_A ( ppOutPos , c1 ) ;
else if ( CharacterSet = = CodeB )
A2C128_B ( ppOutPos , c1 ) ;
else
A2C128_C ( ppOutPos , c1 , c2 ) ;
2016-09-04 13:04:41 +03:00
}
/* XLate Table A of Codablock-F Specification and call output
*/
2016-09-12 16:49:17 +03:00
void SumASCII ( uchar * * ppOutPos , int Sum , int CharacterSet )
2016-09-04 13:04:41 +03:00
{
2016-09-12 16:49:17 +03:00
switch ( CharacterSet ) {
case CodeA :
A2C128_A ( ppOutPos , ( uchar ) Sum ) ;
break ;
case CodeB :
if ( Sum < = 31 )
A2C128_B ( ppOutPos , ( uchar ) ( Sum + 96 ) ) ;
else if ( Sum < = 47 )
A2C128_B ( ppOutPos , ( uchar ) Sum ) ;
else
A2C128_B ( ppOutPos , ( uchar ) ( Sum + 10 ) ) ;
break ;
case CodeC :
A2C128_C ( ppOutPos
, ( char ) ( Sum / 10 + ' 0 ' ) , ( uchar ) ( Sum % 10 + ' 0 ' ) ) ;
break ;
}
2016-09-04 13:04:41 +03:00
}
2016-09-12 16:49:17 +03:00
/* Main function called by zint framework
*/
2017-05-29 12:43:47 +03:00
int codablock ( struct zint_symbol * symbol , const unsigned char source [ ] , const size_t length ) {
2017-06-13 22:05:35 +03:00
size_t charCur , dataLength ;
2016-09-12 16:49:17 +03:00
int Error ;
int rows , columns , useColumns ;
int fillings ;
int Sum1 , Sum2 ;
uchar * pOutPos ;
int rowCur ;
int characterSetCur ;
int emptyColumns ;
2016-09-04 13:04:41 +03:00
char dest [ 1000 ] ;
int r , c ;
# ifdef _MSC_VER
2016-09-12 16:49:17 +03:00
CharacterSetTable * T ;
unsigned char * data ;
int * pSet ;
uchar * pOutput ;
2016-09-04 13:04:41 +03:00
# endif
2016-09-12 16:49:17 +03:00
/* Parameter check */
/* option1: rows 0: automatic, 1..44 */
rows = symbol - > option_1 ;
if ( rows > 44 ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 410: Row parameter not in 0..44 " ) ;
2016-09-12 16:49:17 +03:00
return ZINT_ERROR_INVALID_OPTION ;
}
/* option_2: (usable data) columns: 0: automatic, 6..66 */
columns = symbol - > option_2 ;
if ( ! ( columns < = 0 | | ( columns > = 6 & & columns < = 66 ) ) ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 411: Columns parameter not in 0,6..66 " ) ;
2016-09-12 16:49:17 +03:00
return ZINT_ERROR_INVALID_OPTION ;
}
/* GS1 not implemented */
2016-08-24 21:39:39 +03:00
if ( symbol - > input_mode = = GS1_MODE ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 412: GS1 mode not supported " ) ;
2016-09-12 16:49:17 +03:00
return ZINT_ERROR_INVALID_OPTION ;
}
2016-09-04 13:04:41 +03:00
# ifndef _MSC_VER
2016-09-12 16:49:17 +03:00
unsigned char data [ length * 2 + 1 ] ;
2016-09-04 13:04:41 +03:00
# else
2016-09-12 16:49:17 +03:00
data = ( unsigned char * ) _alloca ( length * 2 + 1 ) ;
2016-08-31 17:29:21 +03:00
# endif
2016-09-12 16:49:17 +03:00
dataLength = 0 ;
if ( symbol - > output_options & READER_INIT ) {
data [ dataLength ] = aFNC3 ;
dataLength + + ;
}
/* Replace all Codes>127 with <fnc4>Code-128 */
for ( charCur = 0 ; charCur < length ; charCur + + ) {
if ( source [ charCur ] > 127 )
{
data [ dataLength ] = aFNC4 ;
dataLength + + ;
data [ dataLength ] = ( unsigned char ) ( source [ charCur ] & 127 ) ;
} else
data [ dataLength ] = source [ charCur ] ;
dataLength + + ;
}
/* Build character set table */
2016-09-04 13:04:41 +03:00
# ifndef _MSC_VER
2016-09-12 16:49:17 +03:00
CharacterSetTable T [ dataLength ] ;
int pSet [ dataLength ] ;
2016-09-04 13:04:41 +03:00
# else
2016-09-12 16:49:17 +03:00
T = ( CharacterSetTable * ) _alloca ( dataLength * sizeof ( CharacterSetTable ) ) ;
pSet = ( int * ) _alloca ( dataLength * sizeof ( int ) ) ;
2016-09-04 13:04:41 +03:00
# endif
2016-09-12 16:49:17 +03:00
CreateCharacterSetTable ( T , data , dataLength ) ;
/* Find final row and column count */
/* nor row nor column count given */
2016-09-21 00:19:31 +03:00
if ( rows < = 0 & & columns < = 5 ) {
2016-09-12 16:49:17 +03:00
/* Use Code128 until reasonable size */
2016-09-21 00:19:31 +03:00
if ( dataLength < 9 ) {
2016-09-12 16:49:17 +03:00
rows = 1 ;
} else {
2016-09-21 00:19:31 +03:00
/* use 1/1 aspect/ratio Codablock */
columns = ( ( int ) floor ( sqrt ( 1.0 * dataLength ) ) + 5 ) ;
if ( columns > 64 )
columns = 64 ;
2016-10-27 11:32:12 +03:00
# ifdef _DEBUG
2017-09-10 18:03:09 +03:00
printf ( " Auto column count for %zu characters:%d \n " , dataLength , columns ) ;
2016-10-27 11:32:12 +03:00
# endif
2016-09-12 16:49:17 +03:00
}
}
2016-10-27 11:32:12 +03:00
/* There are 5 Codewords for Organisation Start(2),row(1),CheckSum,Stop */
useColumns = columns - 5 ;
2016-09-12 16:49:17 +03:00
if ( rows > 0 ) {
/* row count given */
Error = Rows2Columns ( T , data , dataLength , & rows , & useColumns , pSet , & fillings ) ;
} else {
/* column count given */
Error = Columns2Rows ( T , data , dataLength , & rows , & useColumns , pSet , & fillings ) ;
}
if ( Error ! = 0 ) {
2017-07-27 18:01:53 +03:00
strcpy ( symbol - > errtxt , " 413: Data string to long " ) ;
2016-09-12 16:49:17 +03:00
return Error ;
}
/* Checksum */
Sum1 = Sum2 = 0 ;
if ( rows > 1 )
{
2017-06-13 22:05:35 +03:00
size_t charCur ;
2016-09-12 16:49:17 +03:00
for ( charCur = 0 ; charCur < dataLength ; charCur + + ) {
Sum1 = ( Sum1 + ( charCur % 86 + 1 ) * data [ charCur ] ) % 86 ;
Sum2 = ( Sum2 + ( charCur % 86 ) * data [ charCur ] ) % 86 ;
}
}
# ifdef _DEBUG
{ /* start a new level of local variables */
int DPos ;
printf ( " \n Data: " ) ;
for ( DPos = 0 ; DPos < dataLength ; DPos + + )
fputc ( data [ DPos ] , stdout ) ;
printf ( " \n Set: " ) ;
for ( DPos = 0 ; DPos < dataLength ; DPos + + ) {
switch ( pSet [ DPos ] & ( CodeA + CodeB + CodeC ) ) {
case CodeA : fputc ( ' A ' , stdout ) ; break ;
case CodeB : fputc ( ' B ' , stdout ) ; break ;
case CodeC : fputc ( ' C ' , stdout ) ; break ;
default : fputc ( ' . ' , stdout ) ; break ;
}
}
printf ( " \n FNC1: " ) ;
for ( DPos = 0 ; DPos < dataLength ; DPos + + )
fputc ( ( pSet [ DPos ] & CodeFNC1 ) = = 0 ? ' . ' : ' X ' , stdout ) ;
printf ( " \n END: " ) ;
for ( DPos = 0 ; DPos < dataLength ; DPos + + )
fputc ( ( pSet [ DPos ] & CEnd ) = = 0 ? ' . ' : ' X ' , stdout ) ;
printf ( " \n Shif: " ) ;
for ( DPos = 0 ; DPos < dataLength ; DPos + + )
fputc ( ( pSet [ DPos ] & CShift ) = = 0 ? ' . ' : ' X ' , stdout ) ;
printf ( " \n FILL: " ) ;
for ( DPos = 0 ; DPos < dataLength ; DPos + + )
fputc ( ( pSet [ DPos ] & CFill ) = = 0 ? ' . ' : ' X ' , stdout ) ;
fputc ( ' \n ' , stdout ) ;
}
# endif
columns = useColumns + 5 ;
/* >>> Build C128 code numbers */
/* The C128 column count contains Start (2CW), Row ID, Checksum, Stop */
2016-09-04 13:04:41 +03:00
# ifndef _MSC_VER
2016-09-12 16:49:17 +03:00
uchar pOutput [ columns * rows ] ;
2016-09-04 13:04:41 +03:00
# else
2016-09-12 16:49:17 +03:00
pOutput = ( unsigned char * ) _alloca ( columns * rows * sizeof ( char ) ) ;
2016-09-04 13:04:41 +03:00
# endif
2016-09-12 16:49:17 +03:00
pOutPos = pOutput ;
charCur = 0 ;
/* >> Loop over rows */
for ( rowCur = 0 ; rowCur < rows ; rowCur + + ) {
if ( charCur > = dataLength )
{
/* >> Empty line with StartCCodeBCodeC */
characterSetCur = CodeC ;
/* CDB Start C*/
* pOutPos = ' \x67 ' ;
pOutPos + + ;
* pOutPos = ' \x63 ' ;
pOutPos + + ;
SumASCII ( & pOutPos , rowCur + 42 , CodeC ) ;
emptyColumns = useColumns - 2 ;
while ( emptyColumns > 0 )
{
if ( characterSetCur = = CodeC )
{
A2C128_C ( & pOutPos , aCodeB , ' \0 ' ) ;
characterSetCur = CodeB ;
} else {
A2C128_B ( & pOutPos , aCodeC ) ;
characterSetCur = CodeC ;
}
- - emptyColumns ;
}
} else {
/* >> Normal Line */
/* > Startcode */
switch ( pSet [ charCur ] & ( CodeA + CodeB + CodeC ) ) {
case CodeA :
* pOutPos = ' \x67 ' ;
pOutPos + + ;
if ( rows > 1 ) {
* pOutPos = ' \x62 ' ;
pOutPos + + ;
}
characterSetCur = CodeA ;
break ;
case CodeB :
if ( rows = = 1 ) {
* pOutPos = ' \x68 ' ;
pOutPos + + ;
} else {
* pOutPos = ' \x67 ' ;
pOutPos + + ;
* pOutPos = ' \x64 ' ;
pOutPos + + ;
}
characterSetCur = CodeB ;
break ;
case CodeC :
2016-09-13 09:16:51 +03:00
default :
2016-09-12 16:49:17 +03:00
if ( rows = = 1 ) {
* pOutPos = ' \x69 ' ;
pOutPos + + ;
} else {
* pOutPos = ' \x67 ' ;
pOutPos + + ;
* pOutPos = ' \x63 ' ;
pOutPos + + ;
}
characterSetCur = CodeC ;
break ;
2016-09-04 13:04:41 +03:00
}
2016-09-12 16:49:17 +03:00
if ( rows > 1 )
{
/* > Set F1 */
/* In first line : # of rows */
/* In Case of CodeA we shifted to CodeB */
SumASCII ( & pOutPos
, ( rowCur = = 0 ) ? rows - 2 : rowCur + 42
, ( characterSetCur = = CodeA ) ? CodeB : characterSetCur
) ;
}
/* >>> Data */
2016-09-12 23:47:40 +03:00
emptyColumns = useColumns ;
2016-09-12 16:49:17 +03:00
/* +++ One liner don't have start/stop code */
if ( rows = = 1 )
emptyColumns + = 2 ;
/* >> Character loop */
while ( emptyColumns > 0 )
{
/* ? Change character set */
/* not at first possition (It was then the start set) */
/* +++ special case for one-ligner */
if ( emptyColumns < useColumns | | ( rows = = 1 & & charCur ! = 0 ) )
{
if ( ( pSet [ charCur ] & CodeA ) ! = 0 )
{
/* Change to A */
ASCIIZ128 ( & pOutPos , characterSetCur , aCodeA , ' \0 ' ) ;
- - emptyColumns ;
characterSetCur = CodeA ;
} else if ( ( pSet [ charCur ] & CodeB ) ! = 0 )
{
/* Change to B */
ASCIIZ128 ( & pOutPos , characterSetCur , aCodeB , ' \0 ' ) ;
- - emptyColumns ;
characterSetCur = CodeB ;
} else if ( ( pSet [ charCur ] & CodeC ) ! = 0 )
{
/* Change to C */
ASCIIZ128 ( & pOutPos , characterSetCur , aCodeC , ' \0 ' ) ;
- - emptyColumns ;
characterSetCur = CodeC ;
}
}
2017-03-30 16:23:14 +03:00
if ( ( pSet [ charCur ] & CShift ) ! = 0 )
2016-09-12 16:49:17 +03:00
{
2016-09-21 00:19:31 +03:00
/* >> Shift it and put out the shifted character */
2016-09-12 16:49:17 +03:00
ASCIIZ128 ( & pOutPos , characterSetCur , aShift , ' \0 ' ) ;
emptyColumns - = 2 ;
characterSetCur = ( characterSetCur = = CodeB ) ? CodeA : CodeB ;
ASCIIZ128 ( & pOutPos , characterSetCur , data [ charCur ] , ' \0 ' ) ;
characterSetCur = ( characterSetCur = = CodeB ) ? CodeA : CodeB ;
} else {
/* Normal Character */
if ( characterSetCur = = CodeC )
{
if ( data [ charCur ] = = aFNC1 )
A2C128_C ( & pOutPos , aFNC1 , ' \0 ' ) ;
else
{
A2C128_C ( & pOutPos , data [ charCur ] , data [ charCur + 1 ] ) ;
+ + charCur ;
/* We need this here to get the good index */
/* for the termination flags in Set. */
}
} else
ASCIIZ128 ( & pOutPos , characterSetCur , data [ charCur ] , ' \0 ' ) ;
- - emptyColumns ;
}
/* >> End Criteria */
if ( ( pSet [ charCur ] & CFill ) ! = 0 )
{
/* Fill Line but leave space for checks in last line */
if ( rowCur = = rows - 1 & & emptyColumns > = 2 )
emptyColumns - = 2 ;
while ( emptyColumns > 0 )
{
switch ( characterSetCur ) {
case CodeC :
A2C128_C ( & pOutPos , aCodeB , ' \0 ' ) ;
characterSetCur = CodeB ;
break ;
case CodeB :
A2C128_B ( & pOutPos , aCodeC ) ;
characterSetCur = CodeC ;
break ;
case CodeA :
A2C128_A ( & pOutPos , aCodeC ) ;
characterSetCur = CodeC ;
break ;
}
- - emptyColumns ;
}
}
if ( ( pSet [ charCur ] & CEnd ) ! = 0 )
emptyColumns = 0 ;
+ + charCur ;
} /* Loop over characters */
} /* if filling-Line / normal */
/* Add checksum in last line */
if ( rows > 1 & & rowCur = = rows - 1 )
{
SumASCII ( & pOutPos , Sum1 , characterSetCur ) ;
SumASCII ( & pOutPos , Sum2 , characterSetCur ) ;
}
/* Add Code 128 checksum */
{
int Sum = 0 ;
int Pos = 0 ;
for ( ; Pos < useColumns + 3 ; Pos + + )
{
Sum = ( Sum +
( ( Pos = = 0 ? 1 : Pos ) * pOutput [ columns * rowCur + Pos ] ) % 103
) % 103 ;
}
* pOutPos = ( uchar ) Sum ;
pOutPos + + ;
}
/* Add end character */
* pOutPos = 106 ;
pOutPos + + ;
} /* End Lineloop */
# ifdef _DEBUG
/* Dump the output to the screen
*/
printf ( " \n Code 128 Code Numbers: \n " ) ;
{ /* start a new level of local variables */
int DPos , DPos2 ;
for ( DPos = 0 ; DPos < rows ; DPos + + )
{
for ( DPos2 = 0 ; DPos2 < columns ; DPos2 + + )
{
2016-09-21 00:19:31 +03:00
printf ( " %3d " , ( int ) ( pOutput [ DPos * columns + DPos2 ] ) ) ;
2016-09-12 16:49:17 +03:00
}
printf ( " \n " ) ;
}
}
printf ( " rows=%i columns=%i fillings=%i \n " , rows , columns , fillings ) ;
# endif
/* Paint the C128 patterns */
for ( r = 0 ; r < rows ; r + + ) {
strcpy ( dest , " " ) ;
for ( c = 0 ; c < columns ; c + + ) {
strcat ( dest , C128Table [ pOutput [ r * columns + c ] ] ) ;
2016-09-04 13:04:41 +03:00
}
2016-09-12 16:49:17 +03:00
expand ( symbol , dest ) ;
2016-10-27 15:33:19 +03:00
symbol - > row_height [ r ] = 10 ;
2016-09-12 16:49:17 +03:00
}
if ( ! ( symbol - > output_options & BARCODE_BIND ) ) {
symbol - > output_options + = BARCODE_BIND ;
}
2016-09-12 23:47:40 +03:00
if ( symbol - > border_width < 2 ) {
symbol - > border_width = 2 ;
}
2016-09-12 16:49:17 +03:00
return 0 ;
2016-09-04 13:04:41 +03:00
}
2017-10-23 22:34:31 +03:00