2008-07-14 01:15:55 +04:00
/* medical.c - Handles 1 track and 2 track pharmacode and Codabar */
/*
libzint - the open source barcode library
2008-11-17 11:47:42 +03:00
Copyright ( C ) 2008 Robin Stuart < robin @ zint . org . uk >
2008-07-14 01:15:55 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License along
with this program ; if not , write to the Free Software Foundation , Inc . ,
51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include "common.h"
/* Codabar table checked against EN 798:1995 */
# define CASET "0123456789-$: / .+ABCD"
2008-09-02 23:44:41 +04:00
2008-07-14 01:15:55 +04:00
static char * CodaTable [ 20 ] = { " 11111221 " , " 11112211 " , " 11121121 " , " 22111111 " , " 11211211 " , " 21111211 " ,
" 12111121 " , " 12112111 " , " 12211111 " , " 21121111 " , " 11122111 " , " 11221111 " , " 21112121 " , " 21211121 " ,
" 21212111 " , " 11212121 " , " 11221211 " , " 12121121 " , " 11121221 " , " 11122211 " } ;
2008-10-03 12:22:08 +04:00
int c39 ( struct zint_symbol * symbol , unsigned char source [ ] ) ;
2008-07-14 01:15:55 +04:00
int pharma_one ( struct zint_symbol * symbol , unsigned char source [ ] )
{
/* "Pharmacode can represent only a single integer from 3 to 131070. Unlike other
commonly used one - dimensional barcode schemes , pharmacode does not store the data in a
form corresponding to the human - readable digits ; the number is encoded in binary , rather
than decimal . Pharmacode is read from right to left : with n as the bar position starting
at 0 on the right , each narrow bar adds 2 n to the value and each wide bar adds 2 ( 2 ^ n ) .
The minimum barcode is 2 bars and the maximum 16 , so the smallest number that could
be encoded is 3 ( 2 narrow bars ) and the biggest is 131070 ( 16 wide bars ) . "
- http : //en.wikipedia.org/wiki/Pharmacode */
/* This code uses the One Track Pharamacode calculating algorithm as recommended by
the specification at http : //www.laetus.com/laetus.php?request=file&id=69 */
unsigned long int tester ;
int counter ;
char inter [ 17 ] ;
2008-09-02 23:44:41 +04:00
int error_number ;
2008-07-14 01:15:55 +04:00
char dest [ 1000 ] ;
2008-09-02 23:44:41 +04:00
error_number = 0 ;
2008-07-14 01:15:55 +04:00
strcpy ( dest , " " ) ;
2008-09-30 19:05:53 +04:00
if ( ustrlen ( source ) > 6 ) {
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Input too long [511] " ) ;
2008-07-14 01:15:55 +04:00
return ERROR_TOO_LONG ;
}
2008-09-02 23:44:41 +04:00
error_number = is_sane ( NESET , source ) ;
if ( error_number = = ERROR_INVALID_DATA ) {
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Invalid characters in data [512] " ) ;
2008-09-02 23:44:41 +04:00
return error_number ;
2008-07-14 01:15:55 +04:00
}
strcpy ( inter , " " ) ;
2008-10-03 12:22:08 +04:00
tester = atoi ( ( char * ) source ) ;
2008-07-14 01:15:55 +04:00
if ( ( tester < 3 ) | | ( tester > 131070 ) ) {
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Data out of range [513] " ) ;
2008-07-14 01:15:55 +04:00
return ERROR_INVALID_DATA ;
}
do
{
if ( tester % 2 = = 0 ) {
concat ( inter , " W " ) ;
tester = ( tester - 2 ) / 2 ;
} else {
concat ( inter , " N " ) ;
tester = ( tester - 1 ) / 2 ;
}
}
while ( tester ! = 0 ) ;
for ( counter = ( strlen ( inter ) - 1 ) ; counter > = 0 ; counter - - ) {
if ( inter [ counter ] = = ' W ' ) {
concat ( dest , " 32 " ) ;
} else {
concat ( dest , " 12 " ) ;
}
}
expand ( symbol , dest ) ;
2009-02-19 22:09:57 +03:00
2008-09-02 23:44:41 +04:00
return error_number ;
2008-07-14 01:15:55 +04:00
}
int pharma_two_calc ( struct zint_symbol * symbol , unsigned char source [ ] , char dest [ ] )
{
/* This code uses the Two Track Pharamacode defined in the document at
http : //www.laetus.com/laetus.php?request=file&id=69 and using a modified
algorithm from the One Track system . This standard accepts integet values
from 4 to 64570080. */
unsigned long int tester ;
int counter ;
char inter [ 17 ] ;
2008-09-02 23:44:41 +04:00
int error_number ;
2008-07-14 01:15:55 +04:00
2008-09-02 23:44:41 +04:00
error_number = 0 ;
2008-07-14 01:15:55 +04:00
strcpy ( dest , " " ) ;
strcpy ( inter , " " ) ;
2008-10-03 12:22:08 +04:00
tester = atoi ( ( char * ) source ) ;
2008-07-14 01:15:55 +04:00
if ( ( tester < 4 ) | | ( tester > 64570080 ) )
{
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Data out of range [533] " ) ;
2008-07-14 01:15:55 +04:00
return ERROR_INVALID_DATA ;
}
do
{
switch ( tester % 3 ) {
case 0 :
concat ( inter , " 3 " ) ;
tester = ( tester - 3 ) / 3 ;
break ;
case 1 :
concat ( inter , " 1 " ) ;
tester = ( tester - 1 ) / 3 ;
break ;
case 2 :
concat ( inter , " 2 " ) ;
tester = ( tester - 2 ) / 3 ;
break ;
}
}
while ( tester ! = 0 ) ;
for ( counter = ( strlen ( inter ) - 1 ) ; counter > = 0 ; counter - - )
{
dest [ ( strlen ( inter ) - 1 ) - counter ] = inter [ counter ] ;
}
dest [ strlen ( inter ) ] = ' \0 ' ;
2008-09-02 23:44:41 +04:00
return error_number ;
2008-07-14 01:15:55 +04:00
}
int pharma_two ( struct zint_symbol * symbol , unsigned char source [ ] )
{
/* Draws the patterns for two track pharmacode */
char height_pattern [ 200 ] ;
unsigned int loopey ;
int writer ;
2008-09-02 23:44:41 +04:00
int error_number = 0 ;
2008-07-14 01:15:55 +04:00
strcpy ( height_pattern , " " ) ;
2008-09-30 19:05:53 +04:00
if ( ustrlen ( source ) > 8 ) {
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Input too long [531] " ) ;
2008-07-14 01:15:55 +04:00
return ERROR_TOO_LONG ;
}
2008-09-02 23:44:41 +04:00
error_number = is_sane ( NESET , source ) ;
if ( error_number = = ERROR_INVALID_DATA ) {
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Invalid characters in data [532] " ) ;
2008-09-02 23:44:41 +04:00
return error_number ;
2008-07-14 01:15:55 +04:00
}
2008-09-02 23:44:41 +04:00
error_number = pharma_two_calc ( symbol , source , height_pattern ) ;
if ( error_number ! = 0 ) {
return error_number ;
2008-07-14 01:15:55 +04:00
}
writer = 0 ;
for ( loopey = 0 ; loopey < strlen ( height_pattern ) ; loopey + + )
{
if ( ( height_pattern [ loopey ] = = ' 2 ' ) | | ( height_pattern [ loopey ] = = ' 3 ' ) )
{
symbol - > encoded_data [ 0 ] [ writer ] = ' 1 ' ;
}
if ( ( height_pattern [ loopey ] = = ' 1 ' ) | | ( height_pattern [ loopey ] = = ' 3 ' ) )
{
symbol - > encoded_data [ 1 ] [ writer ] = ' 1 ' ;
}
writer + = 2 ;
}
symbol - > rows = 2 ;
symbol - > width = writer - 1 ;
2009-02-19 22:09:57 +03:00
2008-09-02 23:44:41 +04:00
return error_number ;
2008-07-14 01:15:55 +04:00
}
int codabar ( struct zint_symbol * symbol , unsigned char source [ ] )
{ /* The Codabar system consisting of simple substitution */
2008-09-02 23:44:41 +04:00
int i , error_number ;
2008-07-14 01:15:55 +04:00
char dest [ 1000 ] ;
2008-09-02 23:44:41 +04:00
error_number = 0 ;
2008-07-14 01:15:55 +04:00
strcpy ( dest , " " ) ;
2008-09-30 19:05:53 +04:00
if ( ustrlen ( source ) > 60 ) { /* No stack smashing please */
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Input too long [181] " ) ;
2008-07-14 01:15:55 +04:00
return ERROR_TOO_LONG ;
}
to_upper ( source ) ;
2008-09-02 23:44:41 +04:00
error_number = is_sane ( CASET , source ) ;
if ( error_number = = ERROR_INVALID_DATA ) {
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Invalid characters in data [182] " ) ;
2008-09-02 23:44:41 +04:00
return error_number ;
2008-07-14 01:15:55 +04:00
}
/* Codabar must begin and end with the characters A, B, C or D */
if ( ( ( source [ 0 ] ! = ' A ' ) & & ( source [ 0 ] ! = ' B ' ) ) & &
( ( source [ 0 ] ! = ' C ' ) & & ( source [ 0 ] ! = ' D ' ) ) )
{
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Invalid characters in data [183] " ) ;
2008-07-14 01:15:55 +04:00
return 6 ;
}
2008-09-30 19:05:53 +04:00
if ( ( ( source [ ustrlen ( source ) - 1 ] ! = ' A ' ) & & ( source [ ustrlen ( source ) - 1 ] ! = ' B ' ) ) & &
( ( source [ ustrlen ( source ) - 1 ] ! = ' C ' ) & & ( source [ ustrlen ( source ) - 1 ] ! = ' D ' ) ) )
2008-07-14 01:15:55 +04:00
{
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Invalid characters in data [184] " ) ;
2008-07-14 01:15:55 +04:00
return 6 ;
}
2008-09-30 19:05:53 +04:00
for ( i = 0 ; i < = ustrlen ( source ) ; i + + )
2008-07-14 01:15:55 +04:00
{
lookup ( CASET , CodaTable , source [ i ] , dest ) ;
}
expand ( symbol , dest ) ;
2009-02-19 22:09:57 +03:00
ustrcpy ( symbol - > text , source ) ;
2008-09-02 23:44:41 +04:00
return error_number ;
}
int code32 ( struct zint_symbol * symbol , unsigned char source [ ] )
{ /* Italian Pharmacode */
int i , zeroes , error_number , checksum , checkpart , checkdigit ;
char localstr [ 10 ] , tempstr [ 2 ] , risultante [ 7 ] ;
long int pharmacode , remainder , devisor ;
int codeword [ 6 ] ;
char tabella [ 34 ] ;
/* Validate the input */
2008-09-30 19:05:53 +04:00
if ( ustrlen ( source ) > 8 ) {
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Input too long [C91] " ) ;
2008-09-02 23:44:41 +04:00
return ERROR_TOO_LONG ;
}
error_number = is_sane ( NESET , source ) ;
if ( error_number = = ERROR_INVALID_DATA ) {
2008-10-05 09:51:58 +04:00
strcpy ( symbol - > errtxt , " Invalid characters in data [C92] " ) ;
2008-09-02 23:44:41 +04:00
return error_number ;
}
/* Add leading zeros as required */
strcpy ( localstr , " " ) ;
2008-09-30 19:05:53 +04:00
zeroes = 8 - ustrlen ( source ) ;
2008-09-02 23:44:41 +04:00
for ( i = 0 ; i < zeroes ; i + + ) {
concat ( localstr , " 0 " ) ;
}
2008-10-03 12:22:08 +04:00
concat ( localstr , ( char * ) source ) ;
2008-09-02 23:44:41 +04:00
/* Calculate the check digit */
checksum = 0 ;
checkpart = 0 ;
for ( i = 0 ; i < 4 ; i + + ) {
checkpart = ctoi ( localstr [ i * 2 ] ) ;
checksum + = checkpart ;
checkpart = 2 * ( ctoi ( localstr [ ( i * 2 ) + 1 ] ) ) ;
if ( checkpart > = 10 ) {
checksum + = ( checkpart - 10 ) + 1 ;
} else {
checksum + = checkpart ;
}
}
/* Add check digit to data string */
checkdigit = checksum % 10 ;
tempstr [ 0 ] = itoc ( checkdigit ) ;
tempstr [ 1 ] = ' \0 ' ;
concat ( localstr , tempstr ) ;
/* Convert string into an integer value */
pharmacode = 0 ;
for ( i = 0 ; i < 9 ; i + + ) {
pharmacode * = 10 ;
pharmacode + = ctoi ( localstr [ i ] ) ;
}
/* Convert from decimal to base-32 */
devisor = 33554432 ;
for ( i = 5 ; i > = 0 ; i - - ) {
codeword [ i ] = pharmacode / devisor ;
remainder = pharmacode % devisor ;
pharmacode = remainder ;
devisor / = 32 ;
}
/* Look up values in 'Tabella di conversione' */
strcpy ( tabella , " 0123456789BCDFGHJKLMNPQRSTUVWXYZ " ) ;
strcpy ( risultante , " " ) ;
for ( i = 5 ; i > = 0 ; i - - ) {
tempstr [ 0 ] = tabella [ codeword [ i ] ] ;
concat ( risultante , tempstr ) ;
}
/* Plot the barcode using Code 39 */
2008-10-03 12:22:08 +04:00
error_number = c39 ( symbol , ( unsigned char * ) risultante ) ;
2008-09-02 23:44:41 +04:00
if ( error_number ! = 0 ) { return error_number ; }
/* Override the normal text output with the Pharmacode number */
2009-02-19 22:09:57 +03:00
ustrcpy ( symbol - > text , ( unsigned char * ) " A " ) ;
uconcat ( symbol - > text , ( unsigned char * ) localstr ) ;
2008-09-02 23:44:41 +04:00
return error_number ;
2008-07-14 01:15:55 +04:00
}