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