2 * ean.c -- encoding for ean, upc and isbn
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>
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.
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.
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.
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.
40 * These following static arrays are used to describe the barcode.
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"};
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:
57 static char *ean_mirrortab[] = {
58 "------","--1-11","--11-1","--111-","-1--11",
59 "-11--1","-111--","-1-1-1","-1-11-","-11-1-"
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)
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-"
74 * UPC-E mirroring for encoding "1"
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"
81 /* UPC-2 has just two digits to mirror */
82 static char *upc_mirrortab2[] = {
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.
90 static char *guard[] = {"0a1a","1a1a1","a1a"};
92 /* initial, final guard bars for UPC-E*/
93 static char *guardE[] = {"0a1a","1a1a1a"};
95 /* initial and inter-char guard bars for supplementals (first is space) */
96 static char *guardS[] = {"9112","11"};
99 * These functions are shortcuts I use in the encoding engine
101 static int ean_make_checksum(char *text, int mode)
103 int esum = 0, osum = 0, i;
104 int even=1; /* last char is even */
106 if (strchr(text, ' '))
107 i = strchr(text, ' ') - text; /* end of first part */
109 i = strlen(text); /* end of all */
112 if (even) esum += text[i]-'0';
113 else osum += text[i]-'0';
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);
126 * Check that the text can be encoded. Returns 0 or -1.
128 * 13 or 12 digits: EAN-13 w/ or w/o checksum
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,
134 int Barcode_ean_verify(unsigned char *text)
136 int i, len0, len, addon;
137 unsigned char tmp[24], *spc;
140 spc = strchr(text, ' ');
143 addon = len - len0 - 1;
144 if (addon != 2 && addon != 5)
146 for (i=len0+1; i<len; i++)
147 if (!isdigit(text[i]))
152 for (i=0; i<len0; i++)
153 if (!isdigit(text[i]))
158 strncpy(tmp, text, 7);
160 if (text[7] != (ean_make_checksum(tmp, 0) + '0'))
165 strncpy(tmp, text, 12);
167 if (text[12] != (ean_make_checksum(tmp, 0) + '0'))
177 /* Expand the middle part of UPC-E to UPC-A */
178 static char *upc_e_to_a0(unsigned char *text)
180 static char result[16];
181 strcpy(result, "00000000000"); /* 11 0's */
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 */
189 memcpy(result+1, text, 3); /* Manufacturer */
190 memcpy(result+9, text+3, 2); /* Product */
193 memcpy(result+1, text, 4); /* Manufacturer */
194 memcpy(result+10, text+4, 1); /* Product */
197 memcpy(result+1, text, 5); /* Manufacturer */
198 memcpy(result+10, text+5, 1); /* Product */
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
209 * the middle part, encoding "0" or "1" prepended
210 * 8: fully qualified UPC-E with checksum.
212 * Returns a 11 digit UPC-A (w/o checksum) for valid EPC-E barcode
213 * or an empty string for an invalid one.
215 * The checksum for UPC-E is calculated using its UPC-A equivalent.
217 static char *upc_e_to_a(unsigned char *text)
219 static unsigned char result[16], *spc;
222 spc = strchr(text, ' ');
230 strcpy(result, upc_e_to_a0(text));
233 /* the first char is '0' or '1':
234 * valid number system for UPC-E and no checksum
236 if (text[0] == '0' || text[0] == '1') {
237 strcpy(result, upc_e_to_a0(text+1));
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);
246 if (chk == (text[len-1] - '0'))
248 /* Invalid 7 digit representation for UPC-E. */
251 if (text[0] == '0' || text[0] == '1') {
252 strcpy(result, upc_e_to_a0(text+1));
254 chk = ean_make_checksum(result, 0);
255 if (chk == (text[len-1] - '0'))
259 /* Invalid representation for UPC-E. */
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.
269 static unsigned char *upc_a_to_e(unsigned char *text)
271 static unsigned char result[16];
277 strcpy(result, text);
279 chksum = ean_make_checksum(result, 0);
280 if (text[11] != (chksum - '0'))
284 chksum = ean_make_checksum(text, 0);
290 strcpy(result, "00000000"); /* 8 0's*/
292 /* UPC-E can only be used with number system 0 or 1 */
293 if (text[0] != '0' && text[0] != '1')
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);
303 } else if (!strncmp(text+4, "00000", 5)) {
304 memcpy(&result[1], text+1, 3);
305 memcpy(&result[4], text+9, 2);
307 } else if (!strncmp(text+5, "00000", 5)) {
308 memcpy(&result[1], text+1, 4);
309 result[5] = text[10];
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];
318 result[7] = chksum + '0';
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
332 int Barcode_upc_verify(unsigned char *text)
334 int i, len0, len, addon;
335 unsigned char tmp[24], *spc;
338 spc = strchr(text, ' ');
341 addon = len - len0 - 1;
342 if (addon != 2 && addon != 5)
344 for (i=len0+1; i<len; i++)
345 if (!isdigit(text[i]))
350 for (i=0; i<len0; i++)
351 if (!isdigit(text[i]))
355 case 6: case 7: case 8:
356 strncpy(tmp, text, len0);
358 if (!upc_e_to_a(tmp))
362 strncpy(tmp, text, 11);
364 if (text[11] != (ean_make_checksum(tmp, 0) + '0'))
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.
379 int Barcode_isbn_verify(unsigned char *text)
383 for (i=0; text[i]; i++) {
386 if (isdigit(text[i])) {
388 if (ndigit == 9) { /* got it all */
393 return -1; /* found non-digit */
395 if (ndigit!=9) return -1; /* too short */
397 /* skip an hyphen, if any */
400 /* accept one more char if any (the checksum) */
401 if (isdigit(text[i]) || toupper(text[i])=='X')
406 /* and accept the extra price tag (blank + 5 digits), if any */
407 if (strlen(text+i) != 6)
411 i++; /* skip the blank */
413 if (!isdigit(text[i]))
417 return 0; /* Ok: isbn + 5-digit addon */
420 static int width_of_partial(unsigned char *partial)
424 if (isdigit(*partial))
426 else if (islower(*partial))
427 i += *partial - 'a' + 1;
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).
437 int Barcode_ean_encode(struct Barcode_Item *bc)
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 */
445 enum {UPCA, UPCE, EAN13, EAN8, ISBN} encoding = ISBN;
446 int i, xpos, checksum, len, len0, addon;
453 /* Find out whether the barcode has addon and
454 * the length of the barcode w/o the addon.
456 len = strlen(bc->ascii);
457 spc = strchr(bc->ascii, ' ');
459 len0 = spc - bc->ascii;
460 addon = strlen(spc + 1);
461 if (addon != 2 && addon != 5) {
462 bc->error = EINVAL; /* impossible, actually */
471 /* ISBN already wrote what it is; if unknown, find it out */
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.
478 switch(bc->flags & BARCODE_ENCODING_MASK) {
482 bc->encoding = strdup("EAN-8");
486 bc->encoding = strdup("EAN-13");
497 case 6: case 7: case 8:
498 bc->encoding = strdup("UPC-E");
502 bc->encoding = strdup("UPC-A");
511 /* else, it's wrong (impossible, as the text is checked) */
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;
521 if (encoding == UPCA) { /* add the leading 0 (not printed) */
523 strcpy(text+1, bc->ascii);
524 } else if (encoding == UPCE) {
525 strcpy(text, upc_a_to_e(upc_e_to_a(bc->ascii)));
527 strcpy(text, bc->ascii);
531 * build the checksum and the bars: any encoding is slightly different
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 */
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'];
553 ptr1 = partial + strlen(partial); /* target */
554 ptr2 = digits[text[i]-'0']; /* source */
556 if (mirror[i-1] == '1') {
564 * Write the ascii digit. UPC has a special case
565 * for the first digit, which is out of the bars
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 */
573 sprintf(tptr, "%i:12:%c ", xpos, text[i]);
574 tptr += strlen(tptr);
576 /* count the width of the symbol */
577 xpos += 7; /* width_of_partial(ptr2) */
580 strcat(partial, guard[1]); /* middle */
581 xpos += width_of_partial(guard[1]);
585 ptr1 = partial + strlen(partial); /* target */
586 ptr2 = digits[text[i]-'0']; /* source */
589 * Ascii digit. Once again, UPC has a special
590 * case for the last digit
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 */
598 sprintf(tptr, "%i:12:%c ", xpos, text[i]);
599 tptr += strlen(tptr);
601 xpos += 7; /* width_of_partial(ptr2) */
603 tptr[-1] = '\0'; /* overwrite last space */
604 strcat(partial, guard[2]); /* end */
605 xpos += width_of_partial(guard[2]);
607 } else if (encoding == UPCE) {
608 checksum = text[7] - '0';
610 strcpy(partial, guardE[0]);
611 partial[0] = '9'; /* UPC-A has one digit before the symbol, too */
612 xpos = width_of_partial(partial);
614 /* UPC-E has the number system written before the bars. */
615 sprintf(tptr, "0:10:%c ", text[0]);
616 tptr += strlen(tptr);
619 mirror = upc_mirrortab[checksum];
621 mirror = upc_mirrortab1[checksum];
624 ptr1 = partial + strlen(partial); /* target */
625 ptr2 = digits[text[i+1]-'0']; /* source */
627 if (mirror[i] != '1') { /* negated wrt EAN13 */
634 sprintf(tptr, "%i:12:%c ", xpos, text[i+1]);
635 tptr += strlen(tptr);
636 xpos += 7; /* width_of_partial(ptr2) */
639 sprintf(tptr, "%i:10:%c ", xpos+10, text[7]);
640 tptr += strlen(tptr);
641 ptr1[0] += 'a'-'1'; /* bars are long */
644 tptr[-1] = '\0'; /* overwrite last space */
645 strcat(partial, guardE[1]); /* end */
647 } else { /* EAN-8 almost identical to EAN-13 but no mirroring */
650 checksum = ean_make_checksum(text, 0);
651 text[7] = '0' + checksum; /* add it to the text */
655 strcpy(partial, guard[0]);
656 xpos = width_of_partial(partial);
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' */
665 strcat(partial, guard[1]); /* middle */
666 xpos += width_of_partial(guard[1]);
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' */
675 tptr[-1] = '\0'; /* overwrite last space */
676 strcat(partial, guard[2]); /* end */
680 * And that's it. Now, in case some add-on is specified it
681 * must be encoded too. Look for it.
683 if ( (ptr1 = spc) ) {
686 if (strlen(ptr1)==5) {
687 checksum = ean_make_checksum(text, 1 /* special way */);
688 mirror = upc_mirrortab[checksum]+1; /* only last 5 digits */
690 checksum = atoi(text)%4;
691 mirror = upc_mirrortab2[checksum];
693 strcat(textinfo, " +"); strcat(partial, "+");
694 tptr = textinfo + strlen(textinfo);
695 for (i=0; i<strlen(text); i++) {
697 strcat(partial, guardS[0]); /* separation and head */
698 xpos += width_of_partial(guardS[0]);
700 strcat(partial, guardS[1]);
701 xpos += width_of_partial(guardS[1]);
703 ptr1 = partial + strlen(partial); /* target */
704 ptr2 = digits[text[i]-'0']; /* source */
706 if (mirror[i] != '1') { /* negated wrt EAN13 */
714 sprintf(tptr, " %i:12:%c", xpos, text[i]);
715 tptr += strlen(tptr);
716 xpos += 7; /* width_of_partial(ptr2) */
720 /* all done, copy results to the data structure */
721 bc->partial = strdup(partial);
726 bc->textinfo = strdup(textinfo);
734 bc->width = width_of_partial(partial);
736 return 0; /* success */
739 int Barcode_upc_encode(struct Barcode_Item *bc)
741 return Barcode_ean_encode(bc); /* UPC is folded into EAN */
744 int Barcode_isbn_encode(struct Barcode_Item *bc)
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;
755 strcpy(text, "978"); j=3;
758 for (i=0; otext[i]; i++) {
759 if (isdigit(otext[i]))
760 text[j++] = otext[i];
761 if (j == 12) /* checksum added later */
765 if (strchr(otext, ' '))
766 strcat(text, strchr(otext, ' '));
768 bc->encoding = strdup("ISBN");
769 retval = Barcode_ean_encode(bc);
770 bc->ascii = otext; /* restore ascii for the ps comments */