gbarcode 0.98.16-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -0
- data/COPYING +0 -0
- data/README +199 -0
- data/Rakefile +109 -0
- data/ext/barcode.h +119 -0
- data/ext/barcode_wrap.c +3192 -0
- data/ext/codabar.c +182 -0
- data/ext/code128.c +607 -0
- data/ext/code39.c +173 -0
- data/ext/code93.c +213 -0
- data/ext/ean.c +774 -0
- data/ext/extconf.rb +6 -0
- data/ext/i25.c +164 -0
- data/ext/library.c +244 -0
- data/ext/msi.c +155 -0
- data/ext/pcl.c +200 -0
- data/ext/plessey.c +164 -0
- data/ext/ps.c +272 -0
- data/ext/svg.c +174 -0
- data/extras/mingw-rbconfig.rb +176 -0
- data/lib/gbarcode.so +0 -0
- data/test/assets/gb-code128b.eps +44 -0
- data/test/gbarcode_test.rb +48 -0
- data/test/test_helper.rb +2 -0
- metadata +77 -0
data/ext/code39.c
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
/*
|
2
|
+
* code39.c -- encoding for code39
|
3
|
+
*
|
4
|
+
* Copyright (c) 1999 Alessandro Rubini (rubini@gnu.org)
|
5
|
+
* Copyright (c) 1999 Prosa Srl. (prosa@prosa.it)
|
6
|
+
*
|
7
|
+
* This program is free software; you can redistribute it and/or modify
|
8
|
+
* it under the terms of the GNU General Public License as published by
|
9
|
+
* the Free Software Foundation; either version 2 of the License, or
|
10
|
+
* (at your option) any later version.
|
11
|
+
*
|
12
|
+
* This program is distributed in the hope that it will be useful,
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
* GNU General Public License for more details.
|
16
|
+
*
|
17
|
+
* You should have received a copy of the GNU General Public License
|
18
|
+
* along with this program; if not, write to the Free Software
|
19
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
20
|
+
*/
|
21
|
+
|
22
|
+
#include <stdio.h>
|
23
|
+
#include <stdlib.h>
|
24
|
+
#include <string.h>
|
25
|
+
#include <ctype.h>
|
26
|
+
#include <errno.h>
|
27
|
+
|
28
|
+
#include "barcode.h"
|
29
|
+
|
30
|
+
|
31
|
+
/* this is ordered in decades to simplify encoding */
|
32
|
+
static char alphabet[] =
|
33
|
+
"1234567890" "ABCDEFGHIJ" "KLMNOPQRST" "UVWXYZ-. *" "$/+%";
|
34
|
+
|
35
|
+
/* the checksum alphabet has a different order */
|
36
|
+
static char checkbet[] =
|
37
|
+
"0123456789" "ABCDEFGHIJ" "KLMNOPQRST" "UVWXYZ-. $" "/+%";
|
38
|
+
|
39
|
+
/* The first 40 symbols repeat this bar pattern */
|
40
|
+
static char *bars[] = {
|
41
|
+
"31113","13113","33111","11313","31311",
|
42
|
+
"13311","11133","31131","13131","11331"};
|
43
|
+
|
44
|
+
/* The first 4 decades use these space patterns */
|
45
|
+
static char *spaces[] = {"1311","1131","1113","3111"};
|
46
|
+
|
47
|
+
/* the last four symbols are special */
|
48
|
+
static char *specialbars[] = {
|
49
|
+
"11111","11111","11111","11111"};
|
50
|
+
|
51
|
+
static char *specialspaces[] = {
|
52
|
+
"3331","3313","3133","1333"};
|
53
|
+
|
54
|
+
static char *fillers[]= {
|
55
|
+
"0a3a1c1c1a",
|
56
|
+
"1a3a1c1c1a"
|
57
|
+
};
|
58
|
+
|
59
|
+
|
60
|
+
/*
|
61
|
+
* Check that the text can be encoded. Returns 0 or -1.
|
62
|
+
* If it's all lowecase convert to uppercase and accept it
|
63
|
+
*/
|
64
|
+
int Barcode_39_verify(unsigned char *text)
|
65
|
+
{
|
66
|
+
int i, lower=0, upper=0;
|
67
|
+
|
68
|
+
if (text[0] == '\0')
|
69
|
+
return -1;
|
70
|
+
for (i=0; text[i]; i++) {
|
71
|
+
if (isupper(text[i])) upper++;
|
72
|
+
if (islower(text[i])) lower++;
|
73
|
+
if (!strchr(alphabet,toupper(text[i])))
|
74
|
+
return -1;
|
75
|
+
}
|
76
|
+
if (lower && upper)
|
77
|
+
return -1;
|
78
|
+
return 0;
|
79
|
+
}
|
80
|
+
|
81
|
+
static int add_one(char *ptr, int code)
|
82
|
+
{
|
83
|
+
char *b, *s;
|
84
|
+
|
85
|
+
if (code < 40) {
|
86
|
+
b = bars[code%10];
|
87
|
+
s = spaces[code/10];
|
88
|
+
} else {
|
89
|
+
b = specialbars[code-40];
|
90
|
+
s = specialspaces[code-40];
|
91
|
+
}
|
92
|
+
sprintf(ptr,"1%c%c%c%c%c%c%c%c%c", /* separator */
|
93
|
+
b[0], s[0], b[1], s[1], b[2], s[2],
|
94
|
+
b[3], s[3], b[4]);
|
95
|
+
return 0;
|
96
|
+
}
|
97
|
+
|
98
|
+
/*
|
99
|
+
* The encoding functions fills the "partial" and "textinfo" fields.
|
100
|
+
* Lowercase chars are converted to uppercase
|
101
|
+
*/
|
102
|
+
int Barcode_39_encode(struct Barcode_Item *bc)
|
103
|
+
{
|
104
|
+
static char *text;
|
105
|
+
static char *partial; /* dynamic */
|
106
|
+
static char *textinfo; /* dynamic */
|
107
|
+
char *c, *ptr, *textptr;
|
108
|
+
int i, code, textpos, checksum = 0;
|
109
|
+
|
110
|
+
if (bc->partial)
|
111
|
+
free(bc->partial);
|
112
|
+
if (bc->textinfo)
|
113
|
+
free(bc->textinfo);
|
114
|
+
bc->partial = bc->textinfo = NULL; /* safe */
|
115
|
+
|
116
|
+
if (!bc->encoding)
|
117
|
+
bc->encoding = strdup("code 39");
|
118
|
+
|
119
|
+
text = bc->ascii;
|
120
|
+
if (!text) {
|
121
|
+
bc->error = EINVAL;
|
122
|
+
return -1;
|
123
|
+
}
|
124
|
+
/* the partial code is 10* (head + text + check + tail) + margin + term. */
|
125
|
+
partial = malloc( (strlen(text) + 3) * 10 +2);
|
126
|
+
if (!partial) {
|
127
|
+
bc->error = errno;
|
128
|
+
return -1;
|
129
|
+
}
|
130
|
+
|
131
|
+
/* the text information is at most "nnn:fff:c " * strlen +term */
|
132
|
+
textinfo = malloc(10*strlen(text) + 2);
|
133
|
+
if (!textinfo) {
|
134
|
+
bc->error = errno;
|
135
|
+
free(partial);
|
136
|
+
return -1;
|
137
|
+
}
|
138
|
+
|
139
|
+
strcpy(partial, fillers[0]);
|
140
|
+
ptr = partial + strlen(partial);
|
141
|
+
textptr = textinfo;
|
142
|
+
textpos = 22;
|
143
|
+
|
144
|
+
for (i=0; text[i]; i++) {
|
145
|
+
c = strchr(alphabet, toupper(text[i]));
|
146
|
+
if (!c) {
|
147
|
+
bc->error = EINVAL; /* impossible if text is verified */
|
148
|
+
free(partial);
|
149
|
+
free(textinfo);
|
150
|
+
return -1;
|
151
|
+
}
|
152
|
+
code = c - alphabet;
|
153
|
+
add_one(ptr, code);
|
154
|
+
c = strchr(checkbet,*c);
|
155
|
+
if (c) /* the '*' is not there */
|
156
|
+
checksum += (c-checkbet);
|
157
|
+
sprintf(textptr, "%i:12:%c ", textpos, toupper(text[i]));
|
158
|
+
|
159
|
+
textpos += 16; /* width of each code */
|
160
|
+
textptr += strlen(textptr);
|
161
|
+
ptr += strlen(ptr);
|
162
|
+
}
|
163
|
+
/* Add the checksum */
|
164
|
+
if ( (bc->flags & BARCODE_NO_CHECKSUM)==0 ) {
|
165
|
+
code = (strchr(alphabet, checkbet[checksum % 43]) - alphabet);
|
166
|
+
add_one(ptr, code);
|
167
|
+
}
|
168
|
+
strcat(ptr, fillers[1]); /* end */
|
169
|
+
bc->partial = partial;
|
170
|
+
bc->textinfo = textinfo;
|
171
|
+
|
172
|
+
return 0;
|
173
|
+
}
|
data/ext/code93.c
ADDED
@@ -0,0 +1,213 @@
|
|
1
|
+
/*
|
2
|
+
* code39.c -- encoding for code39
|
3
|
+
*
|
4
|
+
* Copyright (c) 1999 Alessandro Rubini (rubini@gnu.org)
|
5
|
+
* Copyright (c) 1999 Prosa Srl. (prosa@prosa.it)
|
6
|
+
* Copyright (c) 2001 Nathan D. Holmes / FedEx Services (ndholmes@fedex.com)
|
7
|
+
*
|
8
|
+
* This program is free software; you can redistribute it and/or modify
|
9
|
+
* it under the terms of the GNU General Public License as published by
|
10
|
+
* the Free Software Foundation; either version 2 of the License, or
|
11
|
+
* (at your option) any later version.
|
12
|
+
*
|
13
|
+
* This program is distributed in the hope that it will be useful,
|
14
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
* GNU General Public License for more details.
|
17
|
+
*
|
18
|
+
* You should have received a copy of the GNU General Public License
|
19
|
+
* along with this program; if not, write to the Free Software
|
20
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
21
|
+
*/
|
22
|
+
|
23
|
+
#include <stdio.h>
|
24
|
+
#include <stdlib.h>
|
25
|
+
#include <string.h>
|
26
|
+
#include <ctype.h>
|
27
|
+
#include <errno.h>
|
28
|
+
|
29
|
+
#include "barcode.h"
|
30
|
+
|
31
|
+
|
32
|
+
/* this is ordered in decades to simplify encoding */
|
33
|
+
static char alphabet[] =
|
34
|
+
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%";
|
35
|
+
|
36
|
+
static char *codeset[] = {
|
37
|
+
"131112", "111213", "111312", "111411", "121113", /* 0 - 4 */
|
38
|
+
"121212", "121311", "111114", "131211", "141111", /* 5 - 9 */
|
39
|
+
"211113", "211212", "211311", "221112", "221211", /* A - E */
|
40
|
+
"231111", "112113", "112212", "112311", "122112", /* F - J */
|
41
|
+
"132111", "111123", "111222", "111321", "121122", /* K - O */
|
42
|
+
"131121", "212112", "212211", "211122", "211221", /* P - T */
|
43
|
+
"221121", "222111", "112122", "112221", "122121", /* U - Y */
|
44
|
+
"123111", "121131", "311112", "311211", "321111", /* Z - $ */
|
45
|
+
"112131", "113121", "211131", "121221", "312111", /* / - (%) */
|
46
|
+
"311121", "122211", "111141" /* (/) - (terminator) */
|
47
|
+
};
|
48
|
+
|
49
|
+
|
50
|
+
/* 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111 */
|
51
|
+
/* 00000000001111111111222222222233333333334444444444555555555566666666667777777777888888888899999999990000000000111111111122222222 */
|
52
|
+
/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567 */
|
53
|
+
static char shiftset[] =
|
54
|
+
"%$$$$$$$$$$$$$$$$$$$$$$$$$$%%%%% /// ///// / /%%%%%% %%%%%%++++++++++++++++++++++++++%%%%%";
|
55
|
+
static char shiftset2[] =
|
56
|
+
"UABCDEFGHIJKLMNOPQRSTUVWXYZABCDE ABC FGHIJ L ZFGHIJV KLMNOWABCDEFGHIJLKMNOPQRSTUVWXYZPQRST";
|
57
|
+
|
58
|
+
#define START_STOP 47
|
59
|
+
#define EXTEND_DOLLAR 43
|
60
|
+
#define EXTEND_PERCENT 44
|
61
|
+
#define EXTEND_SLASH 45
|
62
|
+
#define EXTEND_PLUS 46
|
63
|
+
|
64
|
+
/*
|
65
|
+
* Check that the text can be encoded. Returns 0 or -1.
|
66
|
+
* All of ASCII-7 is accepted.
|
67
|
+
*/
|
68
|
+
int Barcode_93_verify(unsigned char *text)
|
69
|
+
{
|
70
|
+
int i;
|
71
|
+
|
72
|
+
if (!strlen(text))
|
73
|
+
return -1;
|
74
|
+
for (i=0; text[i]; i++) {
|
75
|
+
|
76
|
+
/* Test if beyond the range of 7-bit ASCII */
|
77
|
+
if ((int)text[i] > 127)
|
78
|
+
return -1;
|
79
|
+
}
|
80
|
+
return 0;
|
81
|
+
}
|
82
|
+
|
83
|
+
/*
|
84
|
+
* The encoding functions fills the "partial" and "textinfo" fields.
|
85
|
+
* Lowercase chars are converted to uppercase
|
86
|
+
*/
|
87
|
+
int Barcode_93_encode(struct Barcode_Item *bc)
|
88
|
+
{
|
89
|
+
static unsigned char *text;
|
90
|
+
static char *partial; /* dynamic */
|
91
|
+
static char *textinfo; /* dynamic */
|
92
|
+
char *c, *textptr;
|
93
|
+
int *checksum_str;
|
94
|
+
int i, code, textpos, checksum_len=0;
|
95
|
+
int c_checksum = 0;
|
96
|
+
int k_checksum = 0;
|
97
|
+
|
98
|
+
if (bc->partial)
|
99
|
+
free(bc->partial);
|
100
|
+
if (bc->textinfo)
|
101
|
+
free(bc->textinfo);
|
102
|
+
bc->partial = bc->textinfo = NULL; /* safe */
|
103
|
+
|
104
|
+
if (!bc->encoding)
|
105
|
+
bc->encoding = strdup("code 93");
|
106
|
+
|
107
|
+
text = bc->ascii;
|
108
|
+
if (!text) {
|
109
|
+
bc->error = EINVAL;
|
110
|
+
return -1;
|
111
|
+
}
|
112
|
+
|
113
|
+
/* the partial code is 6 * (head + 2* text + 2* check + tail) + margin + term. */
|
114
|
+
partial = malloc( (strlen(text) *2 + 4) * 6 +2);
|
115
|
+
if (!partial) {
|
116
|
+
bc->error = errno;
|
117
|
+
return -1;
|
118
|
+
}
|
119
|
+
|
120
|
+
checksum_str = (int *)malloc( (strlen(text) + 3) * 2 * sizeof(int));
|
121
|
+
if (!checksum_str) {
|
122
|
+
free(partial);
|
123
|
+
bc->error = errno;
|
124
|
+
return -1;
|
125
|
+
}
|
126
|
+
|
127
|
+
/* the text information is at most "nnn:fff:c " * strlen +term */
|
128
|
+
textinfo = malloc(10*strlen(text) + 2);
|
129
|
+
if (!textinfo) {
|
130
|
+
bc->error = errno;
|
131
|
+
free(partial);
|
132
|
+
free(checksum_str);
|
133
|
+
return -1;
|
134
|
+
}
|
135
|
+
|
136
|
+
textptr = textinfo;
|
137
|
+
textpos = 22;
|
138
|
+
strcpy(partial, "0");
|
139
|
+
strcat(partial, codeset[START_STOP]);
|
140
|
+
|
141
|
+
for (i=0; i<strlen(text); i++) {
|
142
|
+
c = strchr(alphabet, text[i]);
|
143
|
+
if (!c) {
|
144
|
+
/* Encode the shift character */
|
145
|
+
switch(shiftset[text[i]])
|
146
|
+
{
|
147
|
+
case '$':
|
148
|
+
code = EXTEND_DOLLAR;
|
149
|
+
break;
|
150
|
+
case '%':
|
151
|
+
code = EXTEND_PERCENT;
|
152
|
+
break;
|
153
|
+
case '/':
|
154
|
+
code = EXTEND_SLASH;
|
155
|
+
break;
|
156
|
+
case '+':
|
157
|
+
code = EXTEND_PLUS;
|
158
|
+
break;
|
159
|
+
default:
|
160
|
+
code = 0;
|
161
|
+
break;
|
162
|
+
}
|
163
|
+
|
164
|
+
strcat(partial, codeset[code]);
|
165
|
+
checksum_str[checksum_len++] = code;
|
166
|
+
|
167
|
+
/* Encode the second character */
|
168
|
+
code = strchr(alphabet, shiftset2[text[i]]) - alphabet;
|
169
|
+
strcat(partial, codeset[code]);
|
170
|
+
checksum_str[checksum_len++] = code;
|
171
|
+
} else {
|
172
|
+
/* Character is natively supported by the symbology, encode directly */
|
173
|
+
code = c - alphabet;
|
174
|
+
strcat(partial, codeset[c -alphabet]);
|
175
|
+
checksum_str[checksum_len++] = code;
|
176
|
+
}
|
177
|
+
sprintf(textptr, "%i:12:%c ", textpos, text[i]);
|
178
|
+
textptr += strlen(textptr);
|
179
|
+
/*
|
180
|
+
* width of each code is 9; composed codes are 18, but aligning
|
181
|
+
* the text behind the right bars would be ugly, so use 9 anyways
|
182
|
+
*/
|
183
|
+
textpos += 9;
|
184
|
+
}
|
185
|
+
c_checksum=0;
|
186
|
+
k_checksum=0;
|
187
|
+
|
188
|
+
/* Add the checksum */
|
189
|
+
if ( (bc->flags & BARCODE_NO_CHECKSUM)==0 )
|
190
|
+
{
|
191
|
+
for(i=1; i<=checksum_len; i++)
|
192
|
+
{
|
193
|
+
c_checksum += i * (int)checksum_str[checksum_len - i];
|
194
|
+
k_checksum += (i+1) * (int)checksum_str[checksum_len - i];
|
195
|
+
}
|
196
|
+
|
197
|
+
c_checksum = c_checksum % 47;
|
198
|
+
k_checksum += c_checksum;
|
199
|
+
k_checksum = k_checksum % 47;
|
200
|
+
|
201
|
+
strcat(partial, codeset[c_checksum]);
|
202
|
+
strcat(partial, codeset[k_checksum]);
|
203
|
+
|
204
|
+
}
|
205
|
+
strcat(partial, codeset[START_STOP]); /* end */
|
206
|
+
|
207
|
+
/* Encodes final 1-unit width bar to turn the start character into a stop char */
|
208
|
+
strcat(partial, "1");
|
209
|
+
bc->partial = partial;
|
210
|
+
bc->textinfo = textinfo;
|
211
|
+
|
212
|
+
return 0;
|
213
|
+
}
|
data/ext/ean.c
ADDED
@@ -0,0 +1,774 @@
|
|
1
|
+
/*
|
2
|
+
* ean.c -- encoding for ean, upc and isbn
|
3
|
+
*
|
4
|
+
* Copyright (c) 1999 Alessandro Rubini <rubini@gnu.org>
|
5
|
+
* Copyright (c) 1999 Prosa Srl. <prosa@prosa.it>
|
6
|
+
* Copyright (c) 2001 Boszormenyi Zoltan <zboszor@mail.externet.hu>
|
7
|
+
*
|
8
|
+
* This program is free software; you can redistribute it and/or modify
|
9
|
+
* it under the terms of the GNU General Public License as published by
|
10
|
+
* the Free Software Foundation; either version 2 of the License, or
|
11
|
+
* (at your option) any later version.
|
12
|
+
*
|
13
|
+
* This program is distributed in the hope that it will be useful,
|
14
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
* GNU General Public License for more details.
|
17
|
+
*
|
18
|
+
* You should have received a copy of the GNU General Public License
|
19
|
+
* along with this program; if not, write to the Free Software
|
20
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
21
|
+
*/
|
22
|
+
|
23
|
+
#include <stdio.h>
|
24
|
+
#include <stdlib.h>
|
25
|
+
#include <string.h>
|
26
|
+
#include <ctype.h>
|
27
|
+
#include <errno.h>
|
28
|
+
|
29
|
+
#include "barcode.h"
|
30
|
+
|
31
|
+
/*
|
32
|
+
* IMPORTANT NOTE: if you are reading this file to learn how to add a
|
33
|
+
* new encoding type, this is the wrong place as there are too many
|
34
|
+
* special cases. Please refer to code39.c instead. If you want to
|
35
|
+
* learn how UPC, EAN, ISBN work, on the other hand, I did my best to
|
36
|
+
* commend things and hope you enjoy it.
|
37
|
+
*/
|
38
|
+
|
39
|
+
/*
|
40
|
+
* These following static arrays are used to describe the barcode.
|
41
|
+
*
|
42
|
+
* The various forms of UPC and EAN are documented as using three
|
43
|
+
* different alphabets to encode the ten digits. However, each digit
|
44
|
+
* has exactly one encoding; only, it is sometimes mirrored. Moreover,
|
45
|
+
* if you represent the width of each symbol (bar/space) instead of
|
46
|
+
* the sequence of 1's and 0's, you find that even-parity and odd-parity
|
47
|
+
* encoding are exactly the same. So, here are the digits: */
|
48
|
+
static char *digits[] = {
|
49
|
+
"3211","2221","2122","1411","1132",
|
50
|
+
"1231","1114","1312","1213","3112"};
|
51
|
+
|
52
|
+
/*
|
53
|
+
* What EAN encoding does is adding a leading digit (the 13th digit).
|
54
|
+
* Such an extra digit is encoded by mirroring three of the six digits that
|
55
|
+
* appear in the left half of the UPC code. Here how mirroring works:
|
56
|
+
*/
|
57
|
+
static char *ean_mirrortab[] = {
|
58
|
+
"------","--1-11","--11-1","--111-","-1--11",
|
59
|
+
"-11--1","-111--","-1-1-1","-1-11-","-11-1-"
|
60
|
+
};
|
61
|
+
|
62
|
+
/*
|
63
|
+
* UPC-E (the 6-digit one), instead, encodes the check character as
|
64
|
+
* a mirroring of the symbols. This is similar, but the encoding for "0" is
|
65
|
+
* different (EAN uses no mirroring for "0" to be compatible with UPC).
|
66
|
+
* The same rule is used for UPC-5 (the supplemental digits for ISBN)
|
67
|
+
*/
|
68
|
+
static char *upc_mirrortab[] = {
|
69
|
+
"---111","--1-11","--11-1","--111-","-1--11",
|
70
|
+
"-11--1","-111--","-1-1-1","-1-11-","-11-1-"
|
71
|
+
};
|
72
|
+
|
73
|
+
/*
|
74
|
+
* UPC-E mirroring for encoding "1"
|
75
|
+
*/
|
76
|
+
static char *upc_mirrortab1[] = {
|
77
|
+
"111---","11-1--","11--1-","11---1","1-11--",
|
78
|
+
"1--11-","1---11","1-1-1-","1-1--1","1--1-1"
|
79
|
+
};
|
80
|
+
|
81
|
+
/* UPC-2 has just two digits to mirror */
|
82
|
+
static char *upc_mirrortab2[] = {
|
83
|
+
"11","1-","-1","--"
|
84
|
+
};
|
85
|
+
|
86
|
+
/*
|
87
|
+
* initial, middle, final guard bars (first symbol is a a space).
|
88
|
+
* EAN-13 overwrites the first "0" with "9" to make space for the extra digit.
|
89
|
+
*/
|
90
|
+
static char *guard[] = {"0a1a","1a1a1","a1a"};
|
91
|
+
|
92
|
+
/* initial, final guard bars for UPC-E*/
|
93
|
+
static char *guardE[] = {"0a1a","1a1a1a"};
|
94
|
+
|
95
|
+
/* initial and inter-char guard bars for supplementals (first is space) */
|
96
|
+
static char *guardS[] = {"9112","11"};
|
97
|
+
|
98
|
+
/*
|
99
|
+
* These functions are shortcuts I use in the encoding engine
|
100
|
+
*/
|
101
|
+
static int ean_make_checksum(char *text, int mode)
|
102
|
+
{
|
103
|
+
int esum = 0, osum = 0, i;
|
104
|
+
int even=1; /* last char is even */
|
105
|
+
|
106
|
+
if (strchr(text, ' '))
|
107
|
+
i = strchr(text, ' ') - text; /* end of first part */
|
108
|
+
else
|
109
|
+
i = strlen(text); /* end of all */
|
110
|
+
|
111
|
+
while (i-- > 0) {
|
112
|
+
if (even) esum += text[i]-'0';
|
113
|
+
else osum += text[i]-'0';
|
114
|
+
even = !even;
|
115
|
+
}
|
116
|
+
if (!mode) { /* standard upc/ean checksum */
|
117
|
+
i = (3*esum + osum) % 10;
|
118
|
+
return (10-i) % 10; /* complement to 10 */
|
119
|
+
} else { /* add-5 checksum */
|
120
|
+
i = (3*esum + 9*osum);
|
121
|
+
return i%10;
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
/*
|
126
|
+
* Check that the text can be encoded. Returns 0 or -1.
|
127
|
+
* Accept:
|
128
|
+
* 13 or 12 digits: EAN-13 w/ or w/o checksum
|
129
|
+
* or
|
130
|
+
* 8 or 7 digits: EAN-8 w/ or w/o checksum.
|
131
|
+
* For both EAN-13 and EAN-8, accept an addon of 2 or 5 digits,
|
132
|
+
* separated by ' '
|
133
|
+
*/
|
134
|
+
int Barcode_ean_verify(unsigned char *text)
|
135
|
+
{
|
136
|
+
int i, len0, len, addon;
|
137
|
+
unsigned char tmp[24], *spc;
|
138
|
+
|
139
|
+
len = strlen(text);
|
140
|
+
spc = strchr(text, ' ');
|
141
|
+
if (spc) {
|
142
|
+
len0 = spc - text;
|
143
|
+
addon = len - len0 - 1;
|
144
|
+
if (addon != 2 && addon != 5)
|
145
|
+
return -1;
|
146
|
+
for (i=len0+1; i<len; i++)
|
147
|
+
if (!isdigit(text[i]))
|
148
|
+
return -1;
|
149
|
+
} else
|
150
|
+
len0 = len;
|
151
|
+
|
152
|
+
for (i=0; i<len0; i++)
|
153
|
+
if (!isdigit(text[i]))
|
154
|
+
return -1;
|
155
|
+
|
156
|
+
switch (len0) {
|
157
|
+
case 8:
|
158
|
+
strncpy(tmp, text, 7);
|
159
|
+
tmp[7] = '\0';
|
160
|
+
if (text[7] != (ean_make_checksum(tmp, 0) + '0'))
|
161
|
+
return -1;
|
162
|
+
case 7:
|
163
|
+
break;
|
164
|
+
case 13:
|
165
|
+
strncpy(tmp, text, 12);
|
166
|
+
tmp[12] = '\0';
|
167
|
+
if (text[12] != (ean_make_checksum(tmp, 0) + '0'))
|
168
|
+
return -1;
|
169
|
+
case 12:
|
170
|
+
break;
|
171
|
+
default:
|
172
|
+
return -1;
|
173
|
+
}
|
174
|
+
return 0;
|
175
|
+
}
|
176
|
+
|
177
|
+
/* Expand the middle part of UPC-E to UPC-A */
|
178
|
+
static char *upc_e_to_a0(unsigned char *text)
|
179
|
+
{
|
180
|
+
static char result[16];
|
181
|
+
strcpy(result, "00000000000"); /* 11 0's */
|
182
|
+
|
183
|
+
switch(text[5]) { /* last char */
|
184
|
+
case '0': case '1': case '2':
|
185
|
+
strncpy(result+1, text, 2); result[3]=text[5]; /* Manuf. */
|
186
|
+
memcpy(result+8, text+2, 3); /* Product */
|
187
|
+
break;
|
188
|
+
case '3':
|
189
|
+
memcpy(result+1, text, 3); /* Manufacturer */
|
190
|
+
memcpy(result+9, text+3, 2); /* Product */
|
191
|
+
break;
|
192
|
+
case '4':
|
193
|
+
memcpy(result+1, text, 4); /* Manufacturer */
|
194
|
+
memcpy(result+10, text+4, 1); /* Product */
|
195
|
+
break;
|
196
|
+
default:
|
197
|
+
memcpy(result+1, text, 5); /* Manufacturer */
|
198
|
+
memcpy(result+10, text+5, 1); /* Product */
|
199
|
+
break;
|
200
|
+
}
|
201
|
+
return result;
|
202
|
+
}
|
203
|
+
|
204
|
+
/* Try to expand an UPC-E barcode to its UPC-A equivalent.
|
205
|
+
* Accept 6, 7 or 8-digit sequence (not counting the addon):
|
206
|
+
* 6: only the middle part, encoding "0", w/o checksum.
|
207
|
+
* 7: the middle part, encoding "0" with a correct checksum
|
208
|
+
* or
|
209
|
+
* the middle part, encoding "0" or "1" prepended
|
210
|
+
* 8: fully qualified UPC-E with checksum.
|
211
|
+
*
|
212
|
+
* Returns a 11 digit UPC-A (w/o checksum) for valid EPC-E barcode
|
213
|
+
* or an empty string for an invalid one.
|
214
|
+
*
|
215
|
+
* The checksum for UPC-E is calculated using its UPC-A equivalent.
|
216
|
+
*/
|
217
|
+
static char *upc_e_to_a(unsigned char *text)
|
218
|
+
{
|
219
|
+
static unsigned char result[16], *spc;
|
220
|
+
int len, chk;
|
221
|
+
|
222
|
+
spc = strchr(text, ' ');
|
223
|
+
if (spc)
|
224
|
+
len = spc - text;
|
225
|
+
else
|
226
|
+
len = strlen(text);
|
227
|
+
|
228
|
+
switch (len) {
|
229
|
+
case 6:
|
230
|
+
strcpy(result, upc_e_to_a0(text));
|
231
|
+
return result;
|
232
|
+
case 7:
|
233
|
+
/* the first char is '0' or '1':
|
234
|
+
* valid number system for UPC-E and no checksum
|
235
|
+
*/
|
236
|
+
if (text[0] == '0' || text[0] == '1') {
|
237
|
+
strcpy(result, upc_e_to_a0(text+1));
|
238
|
+
result[0] = text[0];
|
239
|
+
return result;
|
240
|
+
}
|
241
|
+
|
242
|
+
/* Find out whether the 7th char is correct checksum */
|
243
|
+
strcpy(result, upc_e_to_a0(text));
|
244
|
+
chk = ean_make_checksum(result, 0);
|
245
|
+
|
246
|
+
if (chk == (text[len-1] - '0'))
|
247
|
+
return result;
|
248
|
+
/* Invalid 7 digit representation for UPC-E. */
|
249
|
+
return NULL;
|
250
|
+
case 8:
|
251
|
+
if (text[0] == '0' || text[0] == '1') {
|
252
|
+
strcpy(result, upc_e_to_a0(text+1));
|
253
|
+
result[0] = text[0];
|
254
|
+
chk = ean_make_checksum(result, 0);
|
255
|
+
if (chk == (text[len-1] - '0'))
|
256
|
+
return result;
|
257
|
+
}
|
258
|
+
default:
|
259
|
+
/* Invalid representation for UPC-E. */
|
260
|
+
return NULL;
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
264
|
+
/*
|
265
|
+
* Accept a 11 or 12 digit UPC-A barcode and
|
266
|
+
* shrink it into an 8-digit UPC-E equivalent if possible.
|
267
|
+
* Return NULL if impossible, the UPC-E barcode if possible.
|
268
|
+
*/
|
269
|
+
static unsigned char *upc_a_to_e(unsigned char *text)
|
270
|
+
{
|
271
|
+
static unsigned char result[16];
|
272
|
+
int len, chksum;
|
273
|
+
|
274
|
+
len = strlen(text);
|
275
|
+
switch (len) {
|
276
|
+
case 12:
|
277
|
+
strcpy(result, text);
|
278
|
+
result[11] = '\0';
|
279
|
+
chksum = ean_make_checksum(result, 0);
|
280
|
+
if (text[11] != (chksum - '0'))
|
281
|
+
return NULL;
|
282
|
+
break;
|
283
|
+
case 11:
|
284
|
+
chksum = ean_make_checksum(text, 0);
|
285
|
+
break;
|
286
|
+
default:
|
287
|
+
return NULL;
|
288
|
+
}
|
289
|
+
|
290
|
+
strcpy(result, "00000000"); /* 8 0's*/
|
291
|
+
|
292
|
+
/* UPC-E can only be used with number system 0 or 1 */
|
293
|
+
if (text[0] != '0' && text[0] != '1')
|
294
|
+
return NULL;
|
295
|
+
|
296
|
+
result[0] = text[0];
|
297
|
+
|
298
|
+
if ((text[3] == '0' || text[3] == '1' || text[3] == '2')
|
299
|
+
&& !strncmp(text+4, "0000", 4)) {
|
300
|
+
memcpy(&result[1], text+1, 2);
|
301
|
+
memcpy(&result[3], text+8, 3);
|
302
|
+
result[6] = text[3];
|
303
|
+
} else if (!strncmp(text+4, "00000", 5)) {
|
304
|
+
memcpy(&result[1], text+1, 3);
|
305
|
+
memcpy(&result[4], text+9, 2);
|
306
|
+
result[6] = '3';
|
307
|
+
} else if (!strncmp(text+5, "00000", 5)) {
|
308
|
+
memcpy(&result[1], text+1, 4);
|
309
|
+
result[5] = text[10];
|
310
|
+
result[6] = '4';
|
311
|
+
} else if ((text[5] != '0') && !strncmp(text+6, "0000", 4)
|
312
|
+
&& text[10] >= '5' && text[10] <= '9') {
|
313
|
+
memcpy(&result[1], text+1, 5);
|
314
|
+
result[6] = text[10];
|
315
|
+
} else {
|
316
|
+
return NULL;
|
317
|
+
}
|
318
|
+
result[7] = chksum + '0';
|
319
|
+
|
320
|
+
return result;
|
321
|
+
}
|
322
|
+
|
323
|
+
/*
|
324
|
+
* UPC-A is the same as EAN, but accept
|
325
|
+
* 12 or 11 digits (UPC-A w/ or w/o checksum)
|
326
|
+
* or accept UPC-E as:
|
327
|
+
* 6 digits (w/o number system and checksum): number system '0' assumed,
|
328
|
+
* 7 digits (either w/o number system or checksum),
|
329
|
+
* 8 digits (w/ number system and checksum)
|
330
|
+
* plus the 2 or 5-digit add-on
|
331
|
+
*/
|
332
|
+
int Barcode_upc_verify(unsigned char *text)
|
333
|
+
{
|
334
|
+
int i, len0, len, addon;
|
335
|
+
unsigned char tmp[24], *spc;
|
336
|
+
|
337
|
+
len = strlen(text);
|
338
|
+
spc = strchr(text, ' ');
|
339
|
+
if (spc) {
|
340
|
+
len0 = spc - text;
|
341
|
+
addon = len - len0 - 1;
|
342
|
+
if (addon != 2 && addon != 5)
|
343
|
+
return -1;
|
344
|
+
for (i=len0+1; i<len; i++)
|
345
|
+
if (!isdigit(text[i]))
|
346
|
+
return -1;
|
347
|
+
} else
|
348
|
+
len0 = len;
|
349
|
+
|
350
|
+
for (i=0; i<len0; i++)
|
351
|
+
if (!isdigit(text[i]))
|
352
|
+
return -1;
|
353
|
+
|
354
|
+
switch (len0) {
|
355
|
+
case 6: case 7: case 8:
|
356
|
+
strncpy(tmp, text, len0);
|
357
|
+
tmp[len0] = '\0';
|
358
|
+
if (!upc_e_to_a(tmp))
|
359
|
+
return -1;
|
360
|
+
break;
|
361
|
+
case 12:
|
362
|
+
strncpy(tmp, text, 11);
|
363
|
+
tmp[11] = '\0';
|
364
|
+
if (text[11] != (ean_make_checksum(tmp, 0) + '0'))
|
365
|
+
return -1;
|
366
|
+
case 11:
|
367
|
+
break;
|
368
|
+
default:
|
369
|
+
return -1;
|
370
|
+
}
|
371
|
+
return 0;
|
372
|
+
}
|
373
|
+
|
374
|
+
/*
|
375
|
+
* Isbn is the same as EAN, just shorter. Dashes are accepted, the
|
376
|
+
* check character (if specified) is skipped, the extra 5 digits are
|
377
|
+
* accepted after a blank.
|
378
|
+
*/
|
379
|
+
int Barcode_isbn_verify(unsigned char *text)
|
380
|
+
{
|
381
|
+
int i, ndigit=0;
|
382
|
+
|
383
|
+
for (i=0; text[i]; i++) {
|
384
|
+
if (text[i] == '-')
|
385
|
+
continue;
|
386
|
+
if (isdigit(text[i])) {
|
387
|
+
ndigit++;
|
388
|
+
if (ndigit == 9) { /* got it all */
|
389
|
+
i++; break;
|
390
|
+
}
|
391
|
+
continue;
|
392
|
+
}
|
393
|
+
return -1; /* found non-digit */
|
394
|
+
}
|
395
|
+
if (ndigit!=9) return -1; /* too short */
|
396
|
+
|
397
|
+
/* skip an hyphen, if any */
|
398
|
+
if (text[i] == '-')
|
399
|
+
i++;
|
400
|
+
/* accept one more char if any (the checksum) */
|
401
|
+
if (isdigit(text[i]) || toupper(text[i])=='X')
|
402
|
+
i++;
|
403
|
+
if (text[i] == '\0')
|
404
|
+
return 0; /* Ok */
|
405
|
+
|
406
|
+
/* and accept the extra price tag (blank + 5 digits), if any */
|
407
|
+
if (strlen(text+i) != 6)
|
408
|
+
return -1;
|
409
|
+
if (text[i] != ' ')
|
410
|
+
return -1;
|
411
|
+
i++; /* skip the blank */
|
412
|
+
while (text[i]) {
|
413
|
+
if (!isdigit(text[i]))
|
414
|
+
return -1;
|
415
|
+
i++;
|
416
|
+
}
|
417
|
+
return 0; /* Ok: isbn + 5-digit addon */
|
418
|
+
}
|
419
|
+
|
420
|
+
static int width_of_partial(unsigned char *partial)
|
421
|
+
{
|
422
|
+
int i=0;
|
423
|
+
while (*partial) {
|
424
|
+
if (isdigit(*partial))
|
425
|
+
i += *partial - '0';
|
426
|
+
else if (islower(*partial))
|
427
|
+
i += *partial - 'a' + 1;
|
428
|
+
partial++;
|
429
|
+
}
|
430
|
+
return i;
|
431
|
+
}
|
432
|
+
|
433
|
+
/*
|
434
|
+
* The encoding functions fills the "partial" and "textinfo" fields.
|
435
|
+
* This one deals with both upc (-A and -E) and ean (13 and 8).
|
436
|
+
*/
|
437
|
+
int Barcode_ean_encode(struct Barcode_Item *bc)
|
438
|
+
{
|
439
|
+
static char text[24];
|
440
|
+
static char partial[256];
|
441
|
+
static char textinfo[256];
|
442
|
+
char *mirror, *ptr1, *ptr2, *tptr = textinfo; /* where text is written */
|
443
|
+
char *spc;
|
444
|
+
|
445
|
+
enum {UPCA, UPCE, EAN13, EAN8, ISBN} encoding = ISBN;
|
446
|
+
int i, xpos, checksum, len, len0, addon;
|
447
|
+
|
448
|
+
if (!bc->ascii) {
|
449
|
+
bc->error = EINVAL;
|
450
|
+
return -1;
|
451
|
+
}
|
452
|
+
|
453
|
+
/* Find out whether the barcode has addon and
|
454
|
+
* the length of the barcode w/o the addon.
|
455
|
+
*/
|
456
|
+
len = strlen(bc->ascii);
|
457
|
+
spc = strchr(bc->ascii, ' ');
|
458
|
+
if (spc) {
|
459
|
+
len0 = spc - bc->ascii;
|
460
|
+
addon = strlen(spc + 1);
|
461
|
+
if (addon != 2 && addon != 5) {
|
462
|
+
bc->error = EINVAL; /* impossible, actually */
|
463
|
+
return -1;
|
464
|
+
}
|
465
|
+
} else {
|
466
|
+
len0 = len;
|
467
|
+
addon = 0;
|
468
|
+
}
|
469
|
+
|
470
|
+
if (!bc->encoding) {
|
471
|
+
/* ISBN already wrote what it is; if unknown, find it out */
|
472
|
+
|
473
|
+
/*
|
474
|
+
* Do not decide only by barcode length, it may be ambiguous.
|
475
|
+
* Anyway, either the user specified the barcode type or
|
476
|
+
* we already found a fitting one.
|
477
|
+
*/
|
478
|
+
switch(bc->flags & BARCODE_ENCODING_MASK) {
|
479
|
+
case BARCODE_EAN:
|
480
|
+
switch (len0) {
|
481
|
+
case 7: case 8:
|
482
|
+
bc->encoding = strdup("EAN-8");
|
483
|
+
encoding = EAN8;
|
484
|
+
break;
|
485
|
+
case 12: case 13:
|
486
|
+
bc->encoding = strdup("EAN-13");
|
487
|
+
encoding = EAN13;
|
488
|
+
break;
|
489
|
+
default:
|
490
|
+
bc->error = -EINVAL;
|
491
|
+
return -1;
|
492
|
+
}
|
493
|
+
break;
|
494
|
+
|
495
|
+
case BARCODE_UPC:
|
496
|
+
switch (len0) {
|
497
|
+
case 6: case 7: case 8:
|
498
|
+
bc->encoding = strdup("UPC-E");
|
499
|
+
encoding = UPCE;
|
500
|
+
break;
|
501
|
+
case 11: case 12:
|
502
|
+
bc->encoding = strdup("UPC-A");
|
503
|
+
encoding = UPCA;
|
504
|
+
break;
|
505
|
+
default:
|
506
|
+
bc->error = -EINVAL;
|
507
|
+
return -1;
|
508
|
+
}
|
509
|
+
break;
|
510
|
+
default:
|
511
|
+
/* else, it's wrong (impossible, as the text is checked) */
|
512
|
+
bc->error = -EINVAL;
|
513
|
+
return -1;
|
514
|
+
}
|
515
|
+
}
|
516
|
+
|
517
|
+
/* better safe than sorry */
|
518
|
+
if (bc->partial) free(bc->partial); bc->partial = NULL;
|
519
|
+
if (bc->textinfo) free(bc->textinfo); bc->textinfo = NULL;
|
520
|
+
|
521
|
+
if (encoding == UPCA) { /* add the leading 0 (not printed) */
|
522
|
+
text[0] = '0';
|
523
|
+
strcpy(text+1, bc->ascii);
|
524
|
+
} else if (encoding == UPCE) {
|
525
|
+
strcpy(text, upc_a_to_e(upc_e_to_a(bc->ascii)));
|
526
|
+
} else {
|
527
|
+
strcpy(text, bc->ascii);
|
528
|
+
}
|
529
|
+
|
530
|
+
/*
|
531
|
+
* build the checksum and the bars: any encoding is slightly different
|
532
|
+
*/
|
533
|
+
if (encoding == UPCA || encoding == EAN13 || encoding == ISBN) {
|
534
|
+
if (!(encoding == UPCA && len0 == 12) &&
|
535
|
+
!(encoding == EAN13 && len0 == 13)) {
|
536
|
+
checksum = ean_make_checksum(text, 0);
|
537
|
+
text[12] = '0' + checksum; /* add it to the text */
|
538
|
+
text[13] = '\0';
|
539
|
+
}
|
540
|
+
|
541
|
+
strcpy(partial, guard[0]);
|
542
|
+
if (encoding == EAN13 || encoding == ISBN) { /* The first digit */
|
543
|
+
sprintf(tptr,"0:12:%c ",text[0]);
|
544
|
+
tptr += strlen(tptr);
|
545
|
+
partial[0] = '9'; /* extra space for the digit */
|
546
|
+
} else if (encoding == UPCA)
|
547
|
+
partial[0] = '9'; /* UPC has one digit before the symbol, too */
|
548
|
+
xpos = width_of_partial(partial);
|
549
|
+
mirror = ean_mirrortab[text[0]-'0'];
|
550
|
+
|
551
|
+
/* left part */
|
552
|
+
for (i=1;i<7;i++) {
|
553
|
+
ptr1 = partial + strlen(partial); /* target */
|
554
|
+
ptr2 = digits[text[i]-'0']; /* source */
|
555
|
+
strcpy(ptr1, ptr2);
|
556
|
+
if (mirror[i-1] == '1') {
|
557
|
+
/* mirror this */
|
558
|
+
ptr1[0] = ptr2[3];
|
559
|
+
ptr1[1] = ptr2[2];
|
560
|
+
ptr1[2] = ptr2[1];
|
561
|
+
ptr1[3] = ptr2[0];
|
562
|
+
}
|
563
|
+
/*
|
564
|
+
* Write the ascii digit. UPC has a special case
|
565
|
+
* for the first digit, which is out of the bars
|
566
|
+
*/
|
567
|
+
if (encoding == UPCA && i==1) {
|
568
|
+
sprintf(tptr, "0:10:%c ", text[i]);
|
569
|
+
tptr += strlen(tptr);
|
570
|
+
ptr1[1] += 'a'-'1'; /* bars are long */
|
571
|
+
ptr1[3] += 'a'-'1';
|
572
|
+
} else {
|
573
|
+
sprintf(tptr, "%i:12:%c ", xpos, text[i]);
|
574
|
+
tptr += strlen(tptr);
|
575
|
+
}
|
576
|
+
/* count the width of the symbol */
|
577
|
+
xpos += 7; /* width_of_partial(ptr2) */
|
578
|
+
}
|
579
|
+
|
580
|
+
strcat(partial, guard[1]); /* middle */
|
581
|
+
xpos += width_of_partial(guard[1]);
|
582
|
+
|
583
|
+
/* right part */
|
584
|
+
for (i=7;i<13;i++) {
|
585
|
+
ptr1 = partial + strlen(partial); /* target */
|
586
|
+
ptr2 = digits[text[i]-'0']; /* source */
|
587
|
+
strcpy(ptr1, ptr2);
|
588
|
+
/*
|
589
|
+
* Ascii digit. Once again, UPC has a special
|
590
|
+
* case for the last digit
|
591
|
+
*/
|
592
|
+
if (encoding == UPCA && i==12) {
|
593
|
+
sprintf(tptr, "%i:10:%c ", xpos+13, text[i]);
|
594
|
+
tptr += strlen(tptr);
|
595
|
+
ptr1[0] += 'a'-'1'; /* bars are long */
|
596
|
+
ptr1[2] += 'a'-'1';
|
597
|
+
} else {
|
598
|
+
sprintf(tptr, "%i:12:%c ", xpos, text[i]);
|
599
|
+
tptr += strlen(tptr);
|
600
|
+
}
|
601
|
+
xpos += 7; /* width_of_partial(ptr2) */
|
602
|
+
}
|
603
|
+
tptr[-1] = '\0'; /* overwrite last space */
|
604
|
+
strcat(partial, guard[2]); /* end */
|
605
|
+
xpos += width_of_partial(guard[2]);
|
606
|
+
|
607
|
+
} else if (encoding == UPCE) {
|
608
|
+
checksum = text[7] - '0';
|
609
|
+
|
610
|
+
strcpy(partial, guardE[0]);
|
611
|
+
partial[0] = '9'; /* UPC-A has one digit before the symbol, too */
|
612
|
+
xpos = width_of_partial(partial);
|
613
|
+
|
614
|
+
/* UPC-E has the number system written before the bars. */
|
615
|
+
sprintf(tptr, "0:10:%c ", text[0]);
|
616
|
+
tptr += strlen(tptr);
|
617
|
+
|
618
|
+
if (text[0] == '0')
|
619
|
+
mirror = upc_mirrortab[checksum];
|
620
|
+
else
|
621
|
+
mirror = upc_mirrortab1[checksum];
|
622
|
+
|
623
|
+
for (i=0;i<6;i++) {
|
624
|
+
ptr1 = partial + strlen(partial); /* target */
|
625
|
+
ptr2 = digits[text[i+1]-'0']; /* source */
|
626
|
+
strcpy(ptr1, ptr2);
|
627
|
+
if (mirror[i] != '1') { /* negated wrt EAN13 */
|
628
|
+
/* mirror this */
|
629
|
+
ptr1[0] = ptr2[3];
|
630
|
+
ptr1[1] = ptr2[2];
|
631
|
+
ptr1[2] = ptr2[1];
|
632
|
+
ptr1[3] = ptr2[0];
|
633
|
+
}
|
634
|
+
sprintf(tptr, "%i:12:%c ", xpos, text[i+1]);
|
635
|
+
tptr += strlen(tptr);
|
636
|
+
xpos += 7; /* width_of_partial(ptr2) */
|
637
|
+
}
|
638
|
+
|
639
|
+
sprintf(tptr, "%i:10:%c ", xpos+10, text[7]);
|
640
|
+
tptr += strlen(tptr);
|
641
|
+
ptr1[0] += 'a'-'1'; /* bars are long */
|
642
|
+
ptr1[2] += 'a'-'1';
|
643
|
+
|
644
|
+
tptr[-1] = '\0'; /* overwrite last space */
|
645
|
+
strcat(partial, guardE[1]); /* end */
|
646
|
+
|
647
|
+
} else { /* EAN-8 almost identical to EAN-13 but no mirroring */
|
648
|
+
|
649
|
+
if (len0 != 8) {
|
650
|
+
checksum = ean_make_checksum(text, 0);
|
651
|
+
text[7] = '0' + checksum; /* add it to the text */
|
652
|
+
text[8] = '\0';
|
653
|
+
}
|
654
|
+
|
655
|
+
strcpy(partial, guard[0]);
|
656
|
+
xpos = width_of_partial(partial);
|
657
|
+
|
658
|
+
/* left part */
|
659
|
+
for (i=0;i<4;i++) {
|
660
|
+
strcpy(partial + strlen(partial), digits[text[i]-'0']);
|
661
|
+
sprintf(tptr, "%i:12:%c ", xpos, text[i]);
|
662
|
+
tptr += strlen(tptr);
|
663
|
+
xpos += 7; /* width_of_partial(digits[text[i]-'0' */
|
664
|
+
}
|
665
|
+
strcat(partial, guard[1]); /* middle */
|
666
|
+
xpos += width_of_partial(guard[1]);
|
667
|
+
|
668
|
+
/* right part */
|
669
|
+
for (i=4;i<8;i++) {
|
670
|
+
strcpy(partial + strlen(partial), digits[text[i]-'0']);
|
671
|
+
sprintf(tptr, "%i:12:%c ", xpos, text[i]);
|
672
|
+
tptr += strlen(tptr);
|
673
|
+
xpos += 7; /* width_of_partial(digits[text[i]-'0' */
|
674
|
+
}
|
675
|
+
tptr[-1] = '\0'; /* overwrite last space */
|
676
|
+
strcat(partial, guard[2]); /* end */
|
677
|
+
}
|
678
|
+
|
679
|
+
/*
|
680
|
+
* And that's it. Now, in case some add-on is specified it
|
681
|
+
* must be encoded too. Look for it.
|
682
|
+
*/
|
683
|
+
if ( (ptr1 = spc) ) {
|
684
|
+
ptr1++;
|
685
|
+
strcpy(text, ptr1);
|
686
|
+
if (strlen(ptr1)==5) {
|
687
|
+
checksum = ean_make_checksum(text, 1 /* special way */);
|
688
|
+
mirror = upc_mirrortab[checksum]+1; /* only last 5 digits */
|
689
|
+
} else {
|
690
|
+
checksum = atoi(text)%4;
|
691
|
+
mirror = upc_mirrortab2[checksum];
|
692
|
+
}
|
693
|
+
strcat(textinfo, " +"); strcat(partial, "+");
|
694
|
+
tptr = textinfo + strlen(textinfo);
|
695
|
+
for (i=0; i<strlen(text); i++) {
|
696
|
+
if (!i) {
|
697
|
+
strcat(partial, guardS[0]); /* separation and head */
|
698
|
+
xpos += width_of_partial(guardS[0]);
|
699
|
+
} else {
|
700
|
+
strcat(partial, guardS[1]);
|
701
|
+
xpos += width_of_partial(guardS[1]);
|
702
|
+
}
|
703
|
+
ptr1 = partial + strlen(partial); /* target */
|
704
|
+
ptr2 = digits[text[i]-'0']; /* source */
|
705
|
+
strcpy(ptr1, ptr2);
|
706
|
+
if (mirror[i] != '1') { /* negated wrt EAN13 */
|
707
|
+
/* mirror this */
|
708
|
+
ptr1[0] = ptr2[3];
|
709
|
+
ptr1[1] = ptr2[2];
|
710
|
+
ptr1[2] = ptr2[1];
|
711
|
+
ptr1[3] = ptr2[0];
|
712
|
+
}
|
713
|
+
/* and the text */
|
714
|
+
sprintf(tptr, " %i:12:%c", xpos, text[i]);
|
715
|
+
tptr += strlen(tptr);
|
716
|
+
xpos += 7; /* width_of_partial(ptr2) */
|
717
|
+
}
|
718
|
+
}
|
719
|
+
|
720
|
+
/* all done, copy results to the data structure */
|
721
|
+
bc->partial = strdup(partial);
|
722
|
+
if (!bc->partial) {
|
723
|
+
bc->error = errno;
|
724
|
+
return -1;
|
725
|
+
}
|
726
|
+
bc->textinfo = strdup(textinfo);
|
727
|
+
if (!bc->textinfo) {
|
728
|
+
bc->error = errno;
|
729
|
+
free(bc->partial);
|
730
|
+
bc->partial = NULL;
|
731
|
+
return -1;
|
732
|
+
}
|
733
|
+
if (!bc->width)
|
734
|
+
bc->width = width_of_partial(partial);
|
735
|
+
|
736
|
+
return 0; /* success */
|
737
|
+
}
|
738
|
+
|
739
|
+
int Barcode_upc_encode(struct Barcode_Item *bc)
|
740
|
+
{
|
741
|
+
return Barcode_ean_encode(bc); /* UPC is folded into EAN */
|
742
|
+
}
|
743
|
+
|
744
|
+
int Barcode_isbn_encode(struct Barcode_Item *bc)
|
745
|
+
{
|
746
|
+
/* For ISBN we must normalize the string and prefix "978" */
|
747
|
+
unsigned char *text = malloc(24); /* 13 + ' ' + 5 plus some slack */
|
748
|
+
unsigned char *otext;
|
749
|
+
int i, j, retval;
|
750
|
+
|
751
|
+
if (!text) {
|
752
|
+
bc->error = ENOMEM;
|
753
|
+
return -1;
|
754
|
+
}
|
755
|
+
strcpy(text, "978"); j=3;
|
756
|
+
|
757
|
+
otext = bc->ascii;
|
758
|
+
for (i=0; otext[i]; i++) {
|
759
|
+
if (isdigit(otext[i]))
|
760
|
+
text[j++] = otext[i];
|
761
|
+
if (j == 12) /* checksum added later */
|
762
|
+
break;
|
763
|
+
}
|
764
|
+
text[j]='\0';
|
765
|
+
if (strchr(otext, ' '))
|
766
|
+
strcat(text, strchr(otext, ' '));
|
767
|
+
bc->ascii = text;
|
768
|
+
bc->encoding = strdup("ISBN");
|
769
|
+
retval = Barcode_ean_encode(bc);
|
770
|
+
bc->ascii = otext; /* restore ascii for the ps comments */
|
771
|
+
free(text);
|
772
|
+
return retval;
|
773
|
+
}
|
774
|
+
|