]> git.sur5r.net Git - glabels/blob - barcode-0.98/codabar.c
Imported Upstream version 2.2.8
[glabels] / barcode-0.98 / codabar.c
1 /*
2  * codabar.c -- encoding for Codabar
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 /* this is ordered in decades to simplify encoding */
31 static char alphabet[] = 
32    "0123456789" "-$:/.+ABCD";
33
34 #define CODE_A  16
35 #define CODE_B  17
36
37 #define NARROW  12
38 #define WIDE    14
39
40 /* Patterns */
41 static char *patterns[] = {
42 "1111133","1111331","1113113","3311111","1131131",
43 "3111131","1311113","1311311","1331111","3113111",
44 "1113311","1133111","3111313","3131113","3131311",
45 "1131313","1133131","1313113","1113133","1113331" };
46
47 /*
48  * Check that the text can be encoded. Returns 0 or -1.
49  * If it's all lowecase convert to uppercase and accept it.
50  * If the first character is a letter (A to D), the last one must be too;
51  * no other character should be a letter.
52  */
53 int Barcode_cbr_verify(unsigned char *text)
54 {
55     int i, lower=0, upper=0;
56     int startpresent = 0;
57
58     if (!strlen(text))
59         return -1;
60     for (i=0; text[i]; i++) {
61         char * pos;
62         if (isupper(text[i])) upper++;
63         if (islower(text[i])) lower++;
64         pos = strchr(alphabet,toupper(text[i]));
65         if (!pos)
66             return -1;
67         if (i == 0 && pos - alphabet >= CODE_A)
68             startpresent = 1;
69         else if (pos - alphabet >= CODE_A &&
70                  (!startpresent || i != strlen(text) - 1))
71             return -1;  
72     }
73     if (lower && upper)
74         return -1;
75     return 0;
76 }
77
78 static int add_one(char *ptr, int code)
79 {
80     sprintf(ptr,"1%s", /* separator */ patterns[code]);
81     return 0;
82 }
83
84 /*
85  * The encoding functions fills the "partial" and "textinfo" fields.
86  * Lowercase chars are converted to uppercase
87  */
88 int Barcode_cbr_encode(struct Barcode_Item *bc)
89 {
90     static char *text;
91     static char *partial;  /* dynamic */
92     static char *textinfo; /* dynamic */
93     char *c, *ptr, *textptr;
94     int i, code, textpos, usesum, checksum = 0, startpresent;
95
96     if (bc->partial)
97         free(bc->partial);
98     if (bc->textinfo)
99         free(bc->textinfo);
100     bc->partial = bc->textinfo = NULL; /* safe */
101
102     if (!bc->encoding)
103         bc->encoding = strdup("codabar");
104
105     text = bc->ascii;
106     if (!text) {
107         bc->error = EINVAL;
108         return -1;
109     }
110     /* the partial code is 8 * (head + text + check + tail) + margin + term. */
111     partial = malloc( (strlen(text) + 3) * 8 + 2);
112     if (!partial) {
113         bc->error = errno;
114         return -1;
115     }
116
117     /* the text information is at most "nnn:fff:c " * (strlen + check) +term */
118     textinfo = malloc(10*(strlen(text) + 1) + 2);
119     if (!textinfo) {
120         bc->error = errno;
121         free(partial);
122         return -1;
123     }
124
125     ptr = partial;
126     textptr = textinfo;
127     textpos = 0;
128     usesum = bc->flags & BARCODE_NO_CHECKSUM ? 0 : 1;
129     /* if no start character specified, A is used as a start character */
130     if (!isalpha(text[0])) {
131         add_one(ptr, CODE_A);
132         ptr += strlen(ptr);
133         textpos = WIDE;
134         checksum = CODE_A;
135         startpresent = 0;
136     } else {
137         startpresent = 1;
138     }
139     for (i=0; i<strlen(text); i++) {
140         c = strchr(alphabet, toupper(text[i]));
141         if (!c) {
142             bc->error = EINVAL; /* impossible if text is verified */
143             free(partial);
144             free(textinfo);
145             return -1;
146         }
147         code = c - alphabet;
148         add_one(ptr, code);
149         sprintf(textptr, "%i:12:%c ", textpos, toupper(text[i]));
150         textpos += code < 12 ? NARROW : WIDE;
151         textptr += strlen(textptr);
152         ptr += strlen(ptr); 
153         checksum += code;
154         if (startpresent && usesum && i == strlen(text) - 2) {
155             /* stuff a check symbol before the stop */
156             c = strchr(alphabet, toupper(text[i+1]));
157             if (!c) /* impossible */
158                 continue;
159             code = c - alphabet;
160             checksum += code;
161
162             /* Complement to a multiple of 16 */
163             checksum = (checksum + 15) / 16 * 16 - checksum;
164             add_one(ptr, checksum);
165             ptr += strlen(ptr);
166         }
167     }
168     if (!startpresent) {
169         if (usesum) {
170             /* if no start character specified, B is used as a stop char */
171             checksum += CODE_B;
172             checksum = (checksum + 15) / 16 * 16 - checksum;
173             add_one(ptr, checksum);
174             ptr += strlen(ptr);
175         }
176         add_one(ptr, CODE_B);
177     }
178     bc->partial = partial;
179     bc->textinfo = textinfo;
180
181     return 0;
182 }