multi_encoder 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }
@@ -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
+ }
@@ -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
+