]> git.sur5r.net Git - glabels/blob - glabels2/barcode-0.98/msi.c
2007-04-30 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / barcode-0.98 / msi.c
1 /*
2  * msi.c -- encoding for MSI-Plessey
3  *
4  * Copyright (c) 2000 Leonid A. Broukhis (leob@mailcom.com)
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <errno.h>
26
27 #include "barcode.h"
28
29
30 /* Patterns */
31 static char *patterns[] = { "13", "31" };
32
33 static char *fillers[] = { "031", "131" };
34
35 static int width = 16 /* each character uses 4 patterns */,
36         startpos = 6 /* length of the first filler */;
37
38 /*
39  * Check that the text can be encoded. Returns 0 or -1.
40  */
41 int Barcode_msi_verify(unsigned char *text)
42 {
43     int i;
44
45     if (!strlen(text))
46         return -1;
47     for (i=0; text[i]; i++) {
48         if (!isdigit(text[i]))
49             return -1;
50     }
51     return 0;
52 }
53
54 static int add_one(char *ptr, int code)
55 {
56     sprintf(ptr, "%s%s%s%s", 
57         patterns[(code >> 3) & 1],
58         patterns[(code >> 2) & 1],
59         patterns[(code >> 1) & 1],
60         patterns[code & 1]);
61     return 0;
62 }
63
64 /*
65  * The encoding functions fills the "partial" and "textinfo" fields.
66  * Lowercase chars are converted to uppercase
67  */
68 int Barcode_msi_encode(struct Barcode_Item *bc)
69 {
70     static char *text;
71     static char *partial;  /* dynamic */
72     static char *textinfo; /* dynamic */
73     char *ptr, *textptr;
74     int i, code, textpos, usesum, checksum = 0;
75
76     if (bc->partial)
77         free(bc->partial);
78     if (bc->textinfo)
79         free(bc->textinfo);
80     bc->partial = bc->textinfo = NULL; /* safe */
81
82     if (!bc->encoding)
83         bc->encoding = strdup("msi");
84
85     if ((bc->flags & BARCODE_NO_CHECKSUM))
86         usesum = 0;
87     else
88         usesum = 1;
89
90     text = bc->ascii;
91
92     /* the partial code is head + 8 * (text + check) + tail + margin + term. */
93     partial = malloc( 3 + 8 * (strlen(text) + 1) + 3 + 2 );
94     if (!partial) {
95         bc->error = errno;
96         return -1;
97     }
98
99     /* the text information is at most "nnn:fff:c " * strlen +term */
100     textinfo = malloc(10*strlen(text) + 2);
101     if (!textinfo) {
102         bc->error = errno;
103         free(partial);
104         return -1;
105     }
106
107     strcpy(partial, fillers[0]);
108     ptr = partial + strlen(partial);
109     textptr = textinfo;
110     textpos = startpos;
111     
112     for (i=0; i<strlen(text); i++) {
113         code = text[i] - '0';
114         add_one(ptr, code);
115         sprintf(textptr, "%i:12:%c ", textpos, text[i]);
116         
117         textpos += width; /* width of each code */
118         textptr += strlen(textptr);
119         ptr += strlen(ptr); 
120         if (usesum) {
121         /* For a code ...FEDCBA the checksum is computed
122          * as the sum of digits of the number ...FDB plus
123          * the sum of digits of the number ...ECA * 2.
124          * Which is equivalent to the sum of each digit of ...ECA doubled
125          * plus carry.
126          */
127             if ((i ^ strlen(text)) & 1) {
128                 /* a last digit, 2 away from last, etc. */
129                 checksum += 2 * code + (2 * code) / 10;
130             } else {
131                 checksum += code;
132             }
133         }
134     }
135     /* Some implementations use a double checksum. Currently the only way
136      * to print a barcode with double checksum is to put the checksum
137      * digit printed below at the end of a code in the command line
138      * and re-run the program.
139      */
140     if (usesum) {
141         /* the check digit is the complement of the checksum
142          * to a multiple of 10.
143          */
144         checksum = (checksum + 9) / 10 * 10 - checksum;
145         /* fprintf(stderr, "Checksum: %d\n", checksum); */
146         add_one(ptr, checksum);
147         ptr += strlen(ptr);
148     }
149
150     strcpy(ptr, fillers[1]);
151     bc->partial = partial;
152     bc->textinfo = textinfo;
153
154     return 0;
155 }