1 /*------------------------------------------------------------------------
2 * Copyright 2011 (c) Jeff Brown <spadix@users.sourceforge.net>
3 *
4 * This file is part of the ZBar Bar Code Reader.
5 *
6 * The ZBar Bar Code Reader is free software; you can redistribute it
7 * and/or modify it under the terms of the GNU Lesser Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * The ZBar Bar Code Reader is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser Public License
17 * along with the ZBar Bar Code Reader; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301 USA
20 *
21 * http://sourceforge.net/projects/zbar
22 *------------------------------------------------------------------------*/
23
24 #include <config.h>
25 #include <string.h> /* memmove */
26
27 #include <zbar.h>
28
29 #ifdef DEBUG_CODABAR
30 # define DEBUG_LEVEL (DEBUG_CODABAR)
31 #endif
32 #include "debug.h"
33 #include "decoder.h"
34
35 #define NIBUF 6 /* initial scan buffer size */
36
37 static const signed char codabar_lo[12] = {
38 0x0, 0x1, 0x4, 0x5, 0x2, 0xa, 0xb, 0x9,
39 0x6, 0x7, 0x8, 0x3
40 };
41
42 static const unsigned char codabar_hi[8] = {
43 0x1, 0x4, 0x7, 0x6, 0x2, 0x3, 0x0, 0x5
44 };
45
46 static const unsigned char codabar_characters[20] =
47 "0123456789-$:/.+ABCD";
48
49 static inline int
check_width(unsigned ref,unsigned w)50 check_width (unsigned ref,
51 unsigned w)
52 {
53 unsigned dref = ref;
54 ref *= 4;
55 w *= 4;
56 return(ref - dref <= w && w <= ref + dref);
57 }
58
59 static inline signed char
codabar_decode7(zbar_decoder_t * dcode)60 codabar_decode7 (zbar_decoder_t *dcode)
61 {
62 codabar_decoder_t *codabar = &dcode->codabar;
63 unsigned s = codabar->s7;
64 dbprintf(2, " s=%d", s);
65 if(s < 7)
66 return(-1);
67
68 /* check width */
69 if(!check_width(codabar->width, s)) {
70 dbprintf(2, " [width]");
71 return(-1);
72 }
73
74 /* extract min/max bar */
75 unsigned ibar = decode_sortn(dcode, 4, 1);
76 dbprintf(2, " bar=%04x", ibar);
77
78 unsigned wbmax = get_width(dcode, ibar & 0xf);
79 unsigned wbmin = get_width(dcode, ibar >> 12);
80 if(8 * wbmin < wbmax ||
81 3 * wbmin > 2 * wbmax)
82 {
83 dbprintf(2, " [bar outer ratio]");
84 return(-1);
85 }
86
87 unsigned wb1 = get_width(dcode, (ibar >> 8) & 0xf);
88 unsigned wb2 = get_width(dcode, (ibar >> 4) & 0xf);
89 unsigned long b0b3 = wbmin * wbmax;
90 unsigned long b1b2 = wb1 * wb2;
91 if(b1b2 + b1b2 / 8 < b0b3) {
92 /* single wide bar combinations */
93 if(8 * wbmin < 5 * wb1 ||
94 8 * wb1 < 5 * wb2 ||
95 4 * wb2 > 3 * wbmax ||
96 wb2 * wb2 >= wb1 * wbmax)
97 {
98 dbprintf(2, " [1bar inner ratios]");
99 return(-1);
100 }
101 ibar = (ibar >> 1) & 0x3;
102 }
103 else if(b1b2 > b0b3 + b0b3 / 8) {
104 /* three wide bars, no wide spaces */
105 if(4 * wbmin > 3 * wb1 ||
106 8 * wb1 < 5 * wb2 ||
107 8 * wb2 < 5 * wbmax ||
108 wbmin * wb2 >= wb1 * wb1)
109 {
110 dbprintf(2, " [3bar inner ratios]");
111 return(-1);
112 }
113 ibar = (ibar >> 13) + 4;
114 }
115 else {
116 dbprintf(2, " [bar inner ratios]");
117 return(-1);
118 }
119
120 unsigned ispc = decode_sort3(dcode, 2);
121 dbprintf(2, "(%x) spc=%03x", ibar, ispc);
122
123 unsigned wsmax = get_width(dcode, ispc & 0xf);
124 unsigned wsmid = get_width(dcode, (ispc >> 4) & 0xf);
125 unsigned wsmin = get_width(dcode, (ispc >> 8) & 0xf);
126 if(ibar >> 2) {
127 /* verify no wide spaces */
128 if(8 * wsmin < wsmax ||
129 8 * wsmin < 5 * wsmid ||
130 8 * wsmid < 5 * wsmax)
131 {
132 dbprintf(2, " [0space inner ratios]");
133 return(-1);
134 }
135 ibar &= 0x3;
136 if(codabar->direction)
137 ibar = 3 - ibar;
138 int c = (0xfcde >> (ibar << 2)) & 0xf;
139 dbprintf(2, " ex[%d]=%x", ibar, c);
140 return(c);
141 }
142 else if(8 * wsmin < wsmax ||
143 3 * wsmin > 2 * wsmax)
144 {
145 dbprintf(2, " [space outer ratio]");
146 return(-1);
147 }
148
149 unsigned long s0s2 = wsmin * wsmax;
150 unsigned long s1s1 = wsmid * wsmid;
151 if(s1s1 + s1s1 / 8 < s0s2) {
152 /* single wide space */
153 if(8 * wsmin < 5 * wsmid ||
154 4 * wsmid > 3 * wsmax)
155 {
156 dbprintf(2, " [1space inner ratios]");
157 return(-1);
158 }
159 ispc = ((ispc & 0xf) >> 1) - 1;
160 unsigned ic = (ispc << 2) | ibar;
161 if(codabar->direction)
162 ic = 11 - ic;
163 int c = codabar_lo[ic];
164 dbprintf(2, "(%d) lo[%d]=%x", ispc, ic, c);
165 return(c);
166 }
167 else if(s1s1 > s0s2 + s0s2 / 8) {
168 /* two wide spaces, check start/stop */
169 if(4 * wsmin > 3 * wsmid ||
170 8 * wsmid < 5 * wsmax)
171 {
172 dbprintf(2, " [2space inner ratios]");
173 return(-1);
174 }
175 if((ispc >> 8) == 4) {
176 dbprintf(2, " [space comb]");
177 return(-1);
178 }
179 ispc >>= 10;
180 dbprintf(2, "(%d)", ispc);
181 unsigned ic = ispc * 4 + ibar;
182 zassert(ic < 8, -1, "ic=%d ispc=%d ibar=%d", ic, ispc, ibar);
183 unsigned char c = codabar_hi[ic];
184 if(c >> 2 != codabar->direction) {
185 dbprintf(2, " [invalid stop]");
186 return(-1);
187 }
188 c = (c & 0x3) | 0x10;
189 dbprintf(2, " hi[%d]=%x", ic, c);
190 return(c);
191 }
192 else {
193 dbprintf(2, " [space inner ratios]");
194 return(-1);
195 }
196 }
197
198 static inline signed char
codabar_decode_start(zbar_decoder_t * dcode)199 codabar_decode_start (zbar_decoder_t *dcode)
200 {
201 codabar_decoder_t *codabar = &dcode->codabar;
202 unsigned s = codabar->s7;
203 if(s < 8)
204 return(ZBAR_NONE);
205 dbprintf(2, " codabar: s=%d", s);
206
207 /* check leading quiet zone - spec is 10x */
208 unsigned qz = get_width(dcode, 8);
209 if((qz && qz * 2 < s) ||
210 4 * get_width(dcode, 0) > 3 * s)
211 {
212 dbprintf(2, " [invalid qz/ics]\n");
213 return(ZBAR_NONE);
214 }
215
216 /* check space ratios first */
217 unsigned ispc = decode_sort3(dcode, 2);
218 dbprintf(2, " spc=%03x", ispc);
219 if((ispc >> 8) == 4) {
220 dbprintf(2, " [space comb]\n");
221 return(ZBAR_NONE);
222 }
223
224 /* require 2 wide and 1 narrow spaces */
225 unsigned wsmax = get_width(dcode, ispc & 0xf);
226 unsigned wsmin = get_width(dcode, ispc >> 8);
227 unsigned wsmid = get_width(dcode, (ispc >> 4) & 0xf);
228 if(8 * wsmin < wsmax ||
229 3 * wsmin > 2 * wsmax ||
230 4 * wsmin > 3 * wsmid ||
231 8 * wsmid < 5 * wsmax ||
232 wsmid * wsmid <= wsmax * wsmin)
233 {
234 dbprintf(2, " [space ratio]\n");
235 return(ZBAR_NONE);
236 }
237 ispc >>= 10;
238 dbprintf(2, "(%d)", ispc);
239
240 /* check bar ratios */
241 unsigned ibar = decode_sortn(dcode, 4, 1);
242 dbprintf(2, " bar=%04x", ibar);
243
244 unsigned wbmax = get_width(dcode, ibar & 0xf);
245 unsigned wbmin = get_width(dcode, ibar >> 12);
246 if(8 * wbmin < wbmax ||
247 3 * wbmin > 2 * wbmax)
248 {
249 dbprintf(2, " [bar outer ratio]\n");
250 return(ZBAR_NONE);
251 }
252
253 /* require 1 wide & 3 narrow bars */
254 unsigned wb1 = get_width(dcode, (ibar >> 8) & 0xf);
255 unsigned wb2 = get_width(dcode, (ibar >> 4) & 0xf);
256 if(8 * wbmin < 5 * wb1 ||
257 8 * wb1 < 5 * wb2 ||
258 4 * wb2 > 3 * wbmax ||
259 wb1 * wb2 >= wbmin * wbmax ||
260 wb2 * wb2 >= wb1 * wbmax)
261 {
262 dbprintf(2, " [bar inner ratios]\n");
263 return(ZBAR_NONE);
264 }
265 ibar = ((ibar & 0xf) - 1) >> 1;
266 dbprintf(2, "(%d)", ibar);
267
268 /* decode combination */
269 int ic = ispc * 4 + ibar;
270 zassert(ic < 8, ZBAR_NONE, "ic=%d ispc=%d ibar=%d", ic, ispc, ibar);
271 int c = codabar_hi[ic];
272 codabar->buf[0] = (c & 0x3) | 0x10;
273
274 /* set character direction */
275 codabar->direction = c >> 2;
276
277 codabar->element = 4;
278 codabar->character = 1;
279 codabar->width = codabar->s7;
280 dbprintf(1, " start=%c dir=%x [valid start]\n",
281 codabar->buf[0] + 0x31, codabar->direction);
282 return(ZBAR_PARTIAL);
283 }
284
285 static inline int
codabar_checksum(zbar_decoder_t * dcode,unsigned n)286 codabar_checksum (zbar_decoder_t *dcode,
287 unsigned n)
288 {
289 unsigned chk = 0;
290 unsigned char *buf = dcode->buf;
291 while(n--)
292 chk += *(buf++);
293 return(!!(chk & 0xf));
294 }
295
296 static inline zbar_symbol_type_t
codabar_postprocess(zbar_decoder_t * dcode)297 codabar_postprocess (zbar_decoder_t *dcode)
298 {
299 codabar_decoder_t *codabar = &dcode->codabar;
300 int dir = codabar->direction;
301 dcode->direction = 1 - 2 * dir;
302 int i, n = codabar->character;
303 for(i = 0; i < NIBUF; i++)
304 dcode->buf[i] = codabar->buf[i];
305 if(dir)
306 /* reverse buffer */
307 for(i = 0; i < n / 2; i++) {
308 unsigned j = n - 1 - i;
309 char code = dcode->buf[i];
310 dcode->buf[i] = dcode->buf[j];
311 dcode->buf[j] = code;
312 }
313
314 if(TEST_CFG(codabar->config, ZBAR_CFG_ADD_CHECK)) {
315 /* validate checksum */
316 if(codabar_checksum(dcode, n))
317 return(ZBAR_NONE);
318 if(!TEST_CFG(codabar->config, ZBAR_CFG_EMIT_CHECK)) {
319 dcode->buf[n - 2] = dcode->buf[n - 1];
320 n--;
321 }
322 }
323
324 for(i = 0; i < n; i++) {
325 unsigned c = dcode->buf[i];
326 dcode->buf[i] = ((c < 0x14)
327 ? codabar_characters[c]
328 : '?');
329 }
330 dcode->buflen = i;
331 dcode->buf[i] = '\0';
332 dcode->modifiers = 0;
333
334 codabar->character = -1;
335 return(ZBAR_CODABAR);
336 }
337
338 zbar_symbol_type_t
_zbar_decode_codabar(zbar_decoder_t * dcode)339 _zbar_decode_codabar (zbar_decoder_t *dcode)
340 {
341 codabar_decoder_t *codabar = &dcode->codabar;
342
343 /* update latest character width */
344 codabar->s7 -= get_width(dcode, 8);
345 codabar->s7 += get_width(dcode, 1);
346
347 if(get_color(dcode) != ZBAR_SPACE)
348 return(ZBAR_NONE);
349 if(codabar->character < 0)
350 return(codabar_decode_start(dcode));
351 if(codabar->character < 2 &&
352 codabar_decode_start(dcode))
353 return(ZBAR_PARTIAL);
354 if(--codabar->element)
355 return(ZBAR_NONE);
356 codabar->element = 4;
357
358 dbprintf(1, " codabar[%c%02d+%x]",
359 (codabar->direction) ? '<' : '>',
360 codabar->character, codabar->element);
361
362 signed char c = codabar_decode7(dcode);
363 dbprintf(1, " %d", c);
364 if(c < 0) {
365 dbprintf(1, " [aborted]\n");
366 goto reset;
367 }
368
369 unsigned char *buf;
370 if(codabar->character < NIBUF)
371 buf = codabar->buf;
372 else {
373 if(codabar->character >= BUFFER_MIN &&
374 size_buf(dcode, codabar->character + 1))
375 {
376 dbprintf(1, " [overflow]\n");
377 goto reset;
378 }
379 buf = dcode->buf;
380 }
381 buf[codabar->character++] = c;
382
383 /* lock shared resources */
384 if(codabar->character == NIBUF &&
385 acquire_lock(dcode, ZBAR_CODABAR))
386 {
387 codabar->character = -1;
388 return(ZBAR_PARTIAL);
389 }
390
391 unsigned s = codabar->s7;
392 if(c & 0x10) {
393 unsigned qz = get_width(dcode, 0);
394 if(qz && qz * 2 < s) {
395 dbprintf(2, " [invalid qz]\n");
396 goto reset;
397 }
398 unsigned n = codabar->character;
399 if(n < CFG(*codabar, ZBAR_CFG_MIN_LEN) ||
400 (CFG(*codabar, ZBAR_CFG_MAX_LEN) > 0 &&
401 n > CFG(*codabar, ZBAR_CFG_MAX_LEN)))
402 {
403 dbprintf(2, " [invalid len]\n");
404 goto reset;
405 }
406 if(codabar->character < NIBUF &&
407 acquire_lock(dcode, ZBAR_CODABAR))
408 {
409 codabar->character = -1;
410 return(ZBAR_PARTIAL);
411 }
412 dbprintf(2, " stop=%c", c + 0x31);
413
414 zbar_symbol_type_t sym = codabar_postprocess(dcode);
415 if(sym > ZBAR_PARTIAL)
416 dbprintf(2, " [valid stop]");
417 else {
418 release_lock(dcode, ZBAR_CODABAR);
419 codabar->character = -1;
420 }
421 dbprintf(2, "\n");
422 return(sym);
423 }
424 else if(4 * get_width(dcode, 0) > 3 * s) {
425 dbprintf(2, " [ics]\n");
426 goto reset;
427 }
428
429 dbprintf(2, "\n");
430 return(ZBAR_NONE);
431
432 reset:
433 if(codabar->character >= NIBUF)
434 release_lock(dcode, ZBAR_CODABAR);
435 codabar->character = -1;
436 return(ZBAR_NONE);
437 }
438