A streamlined version (for embedded use) of Jeff Brown's ZBar library. Visit <http://zbar.sourceforge.net> for more details.
Dependents: BarcodeReader_F103
decoder/ean.c@0:e33621169e44, 2020-01-10 (annotated)
- Committer:
- hudakz
- Date:
- Fri Jan 10 20:29:52 2020 +0000
- Revision:
- 0:e33621169e44
Streamlined barcode reader library.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 0:e33621169e44 | 1 | /*------------------------------------------------------------------------ |
hudakz | 0:e33621169e44 | 2 | * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> |
hudakz | 0:e33621169e44 | 3 | * |
hudakz | 0:e33621169e44 | 4 | * This file is part of the ZBar Bar Code Reader. |
hudakz | 0:e33621169e44 | 5 | * |
hudakz | 0:e33621169e44 | 6 | * The ZBar Bar Code Reader is free software; you can redistribute it |
hudakz | 0:e33621169e44 | 7 | * and/or modify it under the terms of the GNU Lesser Public License as |
hudakz | 0:e33621169e44 | 8 | * published by the Free Software Foundation; either version 2.1 of |
hudakz | 0:e33621169e44 | 9 | * the License, or (at your option) any later version. |
hudakz | 0:e33621169e44 | 10 | * |
hudakz | 0:e33621169e44 | 11 | * The ZBar Bar Code Reader is distributed in the hope that it will be |
hudakz | 0:e33621169e44 | 12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
hudakz | 0:e33621169e44 | 13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
hudakz | 0:e33621169e44 | 14 | * GNU Lesser Public License for more details. |
hudakz | 0:e33621169e44 | 15 | * |
hudakz | 0:e33621169e44 | 16 | * You should have received a copy of the GNU Lesser Public License |
hudakz | 0:e33621169e44 | 17 | * along with the ZBar Bar Code Reader; if not, write to the Free |
hudakz | 0:e33621169e44 | 18 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
hudakz | 0:e33621169e44 | 19 | * Boston, MA 02110-1301 USA |
hudakz | 0:e33621169e44 | 20 | * |
hudakz | 0:e33621169e44 | 21 | * http://sourceforge.net/projects/zbar |
hudakz | 0:e33621169e44 | 22 | *------------------------------------------------------------------------*/ |
hudakz | 0:e33621169e44 | 23 | |
hudakz | 0:e33621169e44 | 24 | #include "../config.h" |
hudakz | 0:e33621169e44 | 25 | #include <zbar.h> |
hudakz | 0:e33621169e44 | 26 | #include "../decoder.h" |
hudakz | 0:e33621169e44 | 27 | |
hudakz | 0:e33621169e44 | 28 | #ifdef ENABLE_EAN |
hudakz | 0:e33621169e44 | 29 | |
hudakz | 0:e33621169e44 | 30 | #ifdef DEBUG_EAN |
hudakz | 0:e33621169e44 | 31 | # define DEBUG_LEVEL (DEBUG_EAN) |
hudakz | 0:e33621169e44 | 32 | #endif |
hudakz | 0:e33621169e44 | 33 | #include "../debug.h" |
hudakz | 0:e33621169e44 | 34 | |
hudakz | 0:e33621169e44 | 35 | /* partial decode symbol location */ |
hudakz | 0:e33621169e44 | 36 | typedef enum symbol_partial_e { |
hudakz | 0:e33621169e44 | 37 | EAN_LEFT = 0x0000, |
hudakz | 0:e33621169e44 | 38 | EAN_RIGHT = 0x1000, |
hudakz | 0:e33621169e44 | 39 | } symbol_partial_t; |
hudakz | 0:e33621169e44 | 40 | |
hudakz | 0:e33621169e44 | 41 | /* convert compact encoded D2E1E2 to character (bit4 is parity) */ |
hudakz | 0:e33621169e44 | 42 | static const unsigned char digits[] = { /* E1 E2 */ |
hudakz | 0:e33621169e44 | 43 | 0x06, 0x10, 0x04, 0x13, /* 2 2-5 */ |
hudakz | 0:e33621169e44 | 44 | 0x19, 0x08, 0x11, 0x05, /* 3 2-5 (d2 <= thr) */ |
hudakz | 0:e33621169e44 | 45 | 0x09, 0x12, 0x07, 0x15, /* 4 2-5 (d2 <= thr) */ |
hudakz | 0:e33621169e44 | 46 | 0x16, 0x00, 0x14, 0x03, /* 5 2-5 */ |
hudakz | 0:e33621169e44 | 47 | 0x18, 0x01, 0x02, 0x17, /* E1E2=43,44,33,34 (d2 > thr) */ |
hudakz | 0:e33621169e44 | 48 | }; |
hudakz | 0:e33621169e44 | 49 | |
hudakz | 0:e33621169e44 | 50 | static const unsigned char parity_decode[] = { |
hudakz | 0:e33621169e44 | 51 | 0xf0, /* [xx] BBBBBB = RIGHT half EAN-13 */ |
hudakz | 0:e33621169e44 | 52 | |
hudakz | 0:e33621169e44 | 53 | /* UPC-E check digit encoding */ |
hudakz | 0:e33621169e44 | 54 | 0xff, |
hudakz | 0:e33621169e44 | 55 | 0xff, |
hudakz | 0:e33621169e44 | 56 | 0x0f, /* [07] BBBAAA = 0 */ |
hudakz | 0:e33621169e44 | 57 | 0xff, |
hudakz | 0:e33621169e44 | 58 | 0x1f, /* [0b] BBABAA = 1 */ |
hudakz | 0:e33621169e44 | 59 | 0x2f, /* [0d] BBAABA = 2 */ |
hudakz | 0:e33621169e44 | 60 | 0xf3, /* [0e] BBAAAB = 3 */ |
hudakz | 0:e33621169e44 | 61 | 0xff, |
hudakz | 0:e33621169e44 | 62 | 0x4f, /* [13] BABBAA = 4 */ |
hudakz | 0:e33621169e44 | 63 | 0x7f, /* [15] BABABA = 7 */ |
hudakz | 0:e33621169e44 | 64 | 0xf8, /* [16] BABAAB = 8 */ |
hudakz | 0:e33621169e44 | 65 | 0x5f, /* [19] BAABBA = 5 */ |
hudakz | 0:e33621169e44 | 66 | 0xf9, /* [1a] BAABAB = 9 */ |
hudakz | 0:e33621169e44 | 67 | 0xf6, /* [1c] BAAABB = 6 */ |
hudakz | 0:e33621169e44 | 68 | 0xff, |
hudakz | 0:e33621169e44 | 69 | |
hudakz | 0:e33621169e44 | 70 | /* LEFT half EAN-13 leading digit */ |
hudakz | 0:e33621169e44 | 71 | 0xff, |
hudakz | 0:e33621169e44 | 72 | 0x6f, /* [23] ABBBAA = 6 */ |
hudakz | 0:e33621169e44 | 73 | 0x9f, /* [25] ABBABA = 9 */ |
hudakz | 0:e33621169e44 | 74 | 0xf5, /* [26] ABBAAB = 5 */ |
hudakz | 0:e33621169e44 | 75 | 0x8f, /* [29] ABABBA = 8 */ |
hudakz | 0:e33621169e44 | 76 | 0xf7, /* [2a] ABABAB = 7 */ |
hudakz | 0:e33621169e44 | 77 | 0xf4, /* [2c] ABAABB = 4 */ |
hudakz | 0:e33621169e44 | 78 | 0xff, |
hudakz | 0:e33621169e44 | 79 | 0x3f, /* [31] AABBBA = 3 */ |
hudakz | 0:e33621169e44 | 80 | 0xf2, /* [32] AABBAB = 2 */ |
hudakz | 0:e33621169e44 | 81 | 0xf1, /* [34] AABABB = 1 */ |
hudakz | 0:e33621169e44 | 82 | 0xff, |
hudakz | 0:e33621169e44 | 83 | 0xff, |
hudakz | 0:e33621169e44 | 84 | 0xff, |
hudakz | 0:e33621169e44 | 85 | 0xff, |
hudakz | 0:e33621169e44 | 86 | 0x0f, /* [3f] AAAAAA = 0 */ |
hudakz | 0:e33621169e44 | 87 | }; |
hudakz | 0:e33621169e44 | 88 | |
hudakz | 0:e33621169e44 | 89 | #ifdef DEBUG_EAN |
hudakz | 0:e33621169e44 | 90 | static unsigned char debug_buf[0x18]; |
hudakz | 0:e33621169e44 | 91 | |
hudakz | 0:e33621169e44 | 92 | static inline const unsigned char *dsprintbuf(ean_decoder_t *ean) |
hudakz | 0:e33621169e44 | 93 | { |
hudakz | 0:e33621169e44 | 94 | int i; |
hudakz | 0:e33621169e44 | 95 | for(i = 0; i < 7; i++) |
hudakz | 0:e33621169e44 | 96 | debug_buf[i] = ((ean->buf[0] < 0 || ean->buf[i] < 0) |
hudakz | 0:e33621169e44 | 97 | ? '-' |
hudakz | 0:e33621169e44 | 98 | : ean->buf[i] + '0'); |
hudakz | 0:e33621169e44 | 99 | debug_buf[i] = ' '; |
hudakz | 0:e33621169e44 | 100 | for(; i < 13; i++) |
hudakz | 0:e33621169e44 | 101 | debug_buf[i + 1] = ((ean->buf[7] < 0 || ean->buf[i] < 0) |
hudakz | 0:e33621169e44 | 102 | ? '-' |
hudakz | 0:e33621169e44 | 103 | : ean->buf[i] + '0'); |
hudakz | 0:e33621169e44 | 104 | debug_buf[i + 1] = ' '; |
hudakz | 0:e33621169e44 | 105 | for(; i < 18; i++) |
hudakz | 0:e33621169e44 | 106 | debug_buf[i + 2] = ((ean->buf[13] < 0 || ean->buf[i] < 0) |
hudakz | 0:e33621169e44 | 107 | ? '-' |
hudakz | 0:e33621169e44 | 108 | : ean->buf[i] + '0'); |
hudakz | 0:e33621169e44 | 109 | debug_buf[i + 2] = '\0'; |
hudakz | 0:e33621169e44 | 110 | return(debug_buf); |
hudakz | 0:e33621169e44 | 111 | } |
hudakz | 0:e33621169e44 | 112 | #endif |
hudakz | 0:e33621169e44 | 113 | |
hudakz | 0:e33621169e44 | 114 | /* evaluate previous N (>= 2) widths as auxiliary pattern, |
hudakz | 0:e33621169e44 | 115 | * using preceding 4 as character width |
hudakz | 0:e33621169e44 | 116 | */ |
hudakz | 0:e33621169e44 | 117 | static inline signed char aux_end (zbar_decoder_t *dcode, |
hudakz | 0:e33621169e44 | 118 | unsigned char fwd) |
hudakz | 0:e33621169e44 | 119 | { |
hudakz | 0:e33621169e44 | 120 | /* reference width from previous character */ |
hudakz | 0:e33621169e44 | 121 | unsigned s = calc_s(dcode, 4 + fwd, 4); |
hudakz | 0:e33621169e44 | 122 | |
hudakz | 0:e33621169e44 | 123 | /* check quiet zone */ |
hudakz | 0:e33621169e44 | 124 | unsigned qz = get_width(dcode, 0); |
hudakz | 0:e33621169e44 | 125 | if(!fwd && qz && qz < s * 3 / 4) { |
hudakz | 0:e33621169e44 | 126 | dprintf(2, " [invalid quiet]"); |
hudakz | 0:e33621169e44 | 127 | return(-1); |
hudakz | 0:e33621169e44 | 128 | } |
hudakz | 0:e33621169e44 | 129 | |
hudakz | 0:e33621169e44 | 130 | dprintf(2, " ("); |
hudakz | 0:e33621169e44 | 131 | signed char code = 0; |
hudakz | 0:e33621169e44 | 132 | unsigned char i; |
hudakz | 0:e33621169e44 | 133 | for(i = 1 - fwd; i < 3 + fwd; i++) { |
hudakz | 0:e33621169e44 | 134 | unsigned e = get_width(dcode, i) + get_width(dcode, i + 1); |
hudakz | 0:e33621169e44 | 135 | dprintf(2, " %d", e); |
hudakz | 0:e33621169e44 | 136 | code = (code << 2) | decode_e(e, s, 7); |
hudakz | 0:e33621169e44 | 137 | if(code < 0) { |
hudakz | 0:e33621169e44 | 138 | dprintf(2, " [invalid end guard]"); |
hudakz | 0:e33621169e44 | 139 | return(-1); |
hudakz | 0:e33621169e44 | 140 | } |
hudakz | 0:e33621169e44 | 141 | } |
hudakz | 0:e33621169e44 | 142 | dprintf(2, ") s=%d aux=%x", s, code); |
hudakz | 0:e33621169e44 | 143 | return(code); |
hudakz | 0:e33621169e44 | 144 | } |
hudakz | 0:e33621169e44 | 145 | |
hudakz | 0:e33621169e44 | 146 | /* determine possible auxiliary pattern |
hudakz | 0:e33621169e44 | 147 | * using current 4 as possible character |
hudakz | 0:e33621169e44 | 148 | */ |
hudakz | 0:e33621169e44 | 149 | static inline signed char aux_start (zbar_decoder_t *dcode) |
hudakz | 0:e33621169e44 | 150 | { |
hudakz | 0:e33621169e44 | 151 | /* FIXME NB add-on has no guard in reverse */ |
hudakz | 0:e33621169e44 | 152 | unsigned e2 = get_width(dcode, 5) + get_width(dcode, 6); |
hudakz | 0:e33621169e44 | 153 | if(decode_e(e2, dcode->ean.s4, 7)) { |
hudakz | 0:e33621169e44 | 154 | dprintf(2, " [invalid any]"); |
hudakz | 0:e33621169e44 | 155 | return(/*FIXME (get_color(dcode) == ZBAR_SPACE) ? STATE_ADDON : */-1); |
hudakz | 0:e33621169e44 | 156 | } |
hudakz | 0:e33621169e44 | 157 | |
hudakz | 0:e33621169e44 | 158 | unsigned e1 = get_width(dcode, 4) + get_width(dcode, 5); |
hudakz | 0:e33621169e44 | 159 | unsigned char E1 = decode_e(e1, dcode->ean.s4, 7); |
hudakz | 0:e33621169e44 | 160 | |
hudakz | 0:e33621169e44 | 161 | if(get_color(dcode) == ZBAR_BAR) { |
hudakz | 0:e33621169e44 | 162 | /* check for quiet-zone */ |
hudakz | 0:e33621169e44 | 163 | unsigned qz = get_width(dcode, 7); |
hudakz | 0:e33621169e44 | 164 | if(!qz || qz >= dcode->ean.s4 * 3 / 4) { |
hudakz | 0:e33621169e44 | 165 | if(!E1) { |
hudakz | 0:e33621169e44 | 166 | dprintf(2, " [valid normal]"); |
hudakz | 0:e33621169e44 | 167 | return(0); /* normal symbol start */ |
hudakz | 0:e33621169e44 | 168 | } |
hudakz | 0:e33621169e44 | 169 | else if(E1 == 1) { |
hudakz | 0:e33621169e44 | 170 | dprintf(2, " [valid add-on]"); |
hudakz | 0:e33621169e44 | 171 | return(STATE_ADDON); /* add-on symbol start */ |
hudakz | 0:e33621169e44 | 172 | } |
hudakz | 0:e33621169e44 | 173 | } |
hudakz | 0:e33621169e44 | 174 | dprintf(2, " [invalid start]"); |
hudakz | 0:e33621169e44 | 175 | return(-1); |
hudakz | 0:e33621169e44 | 176 | } |
hudakz | 0:e33621169e44 | 177 | |
hudakz | 0:e33621169e44 | 178 | if(!E1) { |
hudakz | 0:e33621169e44 | 179 | /* attempting decode from SPACE => validate center guard */ |
hudakz | 0:e33621169e44 | 180 | unsigned e3 = get_width(dcode, 6) + get_width(dcode, 7); |
hudakz | 0:e33621169e44 | 181 | if(!decode_e(e3, dcode->ean.s4, 7)) { |
hudakz | 0:e33621169e44 | 182 | dprintf(2, " [valid center]"); |
hudakz | 0:e33621169e44 | 183 | return(0); /* start after center guard */ |
hudakz | 0:e33621169e44 | 184 | } |
hudakz | 0:e33621169e44 | 185 | } |
hudakz | 0:e33621169e44 | 186 | dprintf(2, " [invalid center]"); |
hudakz | 0:e33621169e44 | 187 | return(/*STATE_ADDON*/-1); |
hudakz | 0:e33621169e44 | 188 | } |
hudakz | 0:e33621169e44 | 189 | |
hudakz | 0:e33621169e44 | 190 | /* attempt to decode previous 4 widths (2 bars and 2 spaces) as a character */ |
hudakz | 0:e33621169e44 | 191 | static inline signed char decode4 (zbar_decoder_t *dcode) |
hudakz | 0:e33621169e44 | 192 | { |
hudakz | 0:e33621169e44 | 193 | /* calculate similar edge measurements */ |
hudakz | 0:e33621169e44 | 194 | unsigned e1 = ((get_color(dcode) == ZBAR_BAR) |
hudakz | 0:e33621169e44 | 195 | ? get_width(dcode, 0) + get_width(dcode, 1) |
hudakz | 0:e33621169e44 | 196 | : get_width(dcode, 2) + get_width(dcode, 3)); |
hudakz | 0:e33621169e44 | 197 | unsigned e2 = get_width(dcode, 1) + get_width(dcode, 2); |
hudakz | 0:e33621169e44 | 198 | dprintf(2, "\n e1=%d e2=%d", e1, e2); |
hudakz | 0:e33621169e44 | 199 | |
hudakz | 0:e33621169e44 | 200 | /* create compacted encoding for direct lookup */ |
hudakz | 0:e33621169e44 | 201 | signed char code = ((decode_e(e1, dcode->ean.s4, 7) << 2) | |
hudakz | 0:e33621169e44 | 202 | decode_e(e2, dcode->ean.s4, 7)); |
hudakz | 0:e33621169e44 | 203 | if(code < 0) |
hudakz | 0:e33621169e44 | 204 | return(-1); |
hudakz | 0:e33621169e44 | 205 | dprintf(2, " code=%x", code); |
hudakz | 0:e33621169e44 | 206 | |
hudakz | 0:e33621169e44 | 207 | /* 4 combinations require additional determinant (D2) |
hudakz | 0:e33621169e44 | 208 | E1E2 == 34 (0110) |
hudakz | 0:e33621169e44 | 209 | E1E2 == 43 (1001) |
hudakz | 0:e33621169e44 | 210 | E1E2 == 33 (0101) |
hudakz | 0:e33621169e44 | 211 | E1E2 == 44 (1010) |
hudakz | 0:e33621169e44 | 212 | */ |
hudakz | 0:e33621169e44 | 213 | if((1 << code) & 0x0660) { |
hudakz | 0:e33621169e44 | 214 | /* use sum of bar widths */ |
hudakz | 0:e33621169e44 | 215 | unsigned d2 = ((get_color(dcode) == ZBAR_BAR) |
hudakz | 0:e33621169e44 | 216 | ? get_width(dcode, 0) + get_width(dcode, 2) |
hudakz | 0:e33621169e44 | 217 | : get_width(dcode, 1) + get_width(dcode, 3)); |
hudakz | 0:e33621169e44 | 218 | d2 *= 7; |
hudakz | 0:e33621169e44 | 219 | unsigned char mid = (((1 << code) & 0x0420) |
hudakz | 0:e33621169e44 | 220 | ? 3 /* E1E2 in 33,44 */ |
hudakz | 0:e33621169e44 | 221 | : 4); /* E1E2 in 34,43 */ |
hudakz | 0:e33621169e44 | 222 | unsigned char alt = d2 > (mid * dcode->ean.s4); |
hudakz | 0:e33621169e44 | 223 | if(alt) |
hudakz | 0:e33621169e44 | 224 | code = ((code >> 1) & 3) | 0x10; /* compress code space */ |
hudakz | 0:e33621169e44 | 225 | dprintf(2, " (d2=%d(%d) alt=%d)", d2, mid * dcode->ean.s4, alt); |
hudakz | 0:e33621169e44 | 226 | } |
hudakz | 0:e33621169e44 | 227 | dprintf(2, " char=%02x", digits[(unsigned char)code]); |
hudakz | 0:e33621169e44 | 228 | zassert(code < 0x14, -1, "code=%02x e1=%x e2=%x s4=%x color=%x\n", |
hudakz | 0:e33621169e44 | 229 | code, e1, e2, dcode->ean.s4, get_color(dcode)); |
hudakz | 0:e33621169e44 | 230 | return(code); |
hudakz | 0:e33621169e44 | 231 | } |
hudakz | 0:e33621169e44 | 232 | |
hudakz | 0:e33621169e44 | 233 | static inline zbar_symbol_type_t ean_part_end4 (ean_pass_t *pass, |
hudakz | 0:e33621169e44 | 234 | unsigned char fwd) |
hudakz | 0:e33621169e44 | 235 | { |
hudakz | 0:e33621169e44 | 236 | /* extract parity bits */ |
hudakz | 0:e33621169e44 | 237 | unsigned char par = ((pass->raw[1] & 0x10) >> 1 | |
hudakz | 0:e33621169e44 | 238 | (pass->raw[2] & 0x10) >> 2 | |
hudakz | 0:e33621169e44 | 239 | (pass->raw[3] & 0x10) >> 3 | |
hudakz | 0:e33621169e44 | 240 | (pass->raw[4] & 0x10) >> 4); |
hudakz | 0:e33621169e44 | 241 | |
hudakz | 0:e33621169e44 | 242 | dprintf(2, " par=%x", par); |
hudakz | 0:e33621169e44 | 243 | if(par && par != 0xf) |
hudakz | 0:e33621169e44 | 244 | /* invalid parity combination */ |
hudakz | 0:e33621169e44 | 245 | return(ZBAR_NONE); |
hudakz | 0:e33621169e44 | 246 | |
hudakz | 0:e33621169e44 | 247 | if(!par == fwd) { |
hudakz | 0:e33621169e44 | 248 | /* reverse sampled digits */ |
hudakz | 0:e33621169e44 | 249 | unsigned char tmp = pass->raw[1]; |
hudakz | 0:e33621169e44 | 250 | pass->raw[1] = pass->raw[4]; |
hudakz | 0:e33621169e44 | 251 | pass->raw[4] = tmp; |
hudakz | 0:e33621169e44 | 252 | tmp = pass->raw[2]; |
hudakz | 0:e33621169e44 | 253 | pass->raw[2] = pass->raw[3]; |
hudakz | 0:e33621169e44 | 254 | pass->raw[3] = tmp; |
hudakz | 0:e33621169e44 | 255 | } |
hudakz | 0:e33621169e44 | 256 | |
hudakz | 0:e33621169e44 | 257 | dprintf(2, "\n"); |
hudakz | 0:e33621169e44 | 258 | dprintf(1, "decode4=%x%x%x%x\n", |
hudakz | 0:e33621169e44 | 259 | pass->raw[1] & 0xf, pass->raw[2] & 0xf, |
hudakz | 0:e33621169e44 | 260 | pass->raw[3] & 0xf, pass->raw[4] & 0xf); |
hudakz | 0:e33621169e44 | 261 | if(!par) |
hudakz | 0:e33621169e44 | 262 | return(ZBAR_EAN8 | EAN_RIGHT); |
hudakz | 0:e33621169e44 | 263 | return(ZBAR_EAN8 | EAN_LEFT); |
hudakz | 0:e33621169e44 | 264 | } |
hudakz | 0:e33621169e44 | 265 | |
hudakz | 0:e33621169e44 | 266 | static inline zbar_symbol_type_t ean_part_end7 (ean_decoder_t *ean, |
hudakz | 0:e33621169e44 | 267 | ean_pass_t *pass, |
hudakz | 0:e33621169e44 | 268 | unsigned char fwd) |
hudakz | 0:e33621169e44 | 269 | { |
hudakz | 0:e33621169e44 | 270 | /* calculate parity index */ |
hudakz | 0:e33621169e44 | 271 | unsigned char par = ((fwd) |
hudakz | 0:e33621169e44 | 272 | ? ((pass->raw[1] & 0x10) << 1 | |
hudakz | 0:e33621169e44 | 273 | (pass->raw[2] & 0x10) | |
hudakz | 0:e33621169e44 | 274 | (pass->raw[3] & 0x10) >> 1 | |
hudakz | 0:e33621169e44 | 275 | (pass->raw[4] & 0x10) >> 2 | |
hudakz | 0:e33621169e44 | 276 | (pass->raw[5] & 0x10) >> 3 | |
hudakz | 0:e33621169e44 | 277 | (pass->raw[6] & 0x10) >> 4) |
hudakz | 0:e33621169e44 | 278 | : ((pass->raw[1] & 0x10) >> 4 | |
hudakz | 0:e33621169e44 | 279 | (pass->raw[2] & 0x10) >> 3 | |
hudakz | 0:e33621169e44 | 280 | (pass->raw[3] & 0x10) >> 2 | |
hudakz | 0:e33621169e44 | 281 | (pass->raw[4] & 0x10) >> 1 | |
hudakz | 0:e33621169e44 | 282 | (pass->raw[5] & 0x10) | |
hudakz | 0:e33621169e44 | 283 | (pass->raw[6] & 0x10) << 1)); |
hudakz | 0:e33621169e44 | 284 | |
hudakz | 0:e33621169e44 | 285 | /* lookup parity combination */ |
hudakz | 0:e33621169e44 | 286 | pass->raw[0] = parity_decode[par >> 1]; |
hudakz | 0:e33621169e44 | 287 | if(par & 1) |
hudakz | 0:e33621169e44 | 288 | pass->raw[0] >>= 4; |
hudakz | 0:e33621169e44 | 289 | pass->raw[0] &= 0xf; |
hudakz | 0:e33621169e44 | 290 | dprintf(2, " par=%02x(%x)", par, pass->raw[0]); |
hudakz | 0:e33621169e44 | 291 | |
hudakz | 0:e33621169e44 | 292 | if(pass->raw[0] == 0xf) |
hudakz | 0:e33621169e44 | 293 | /* invalid parity combination */ |
hudakz | 0:e33621169e44 | 294 | return(ZBAR_NONE); |
hudakz | 0:e33621169e44 | 295 | |
hudakz | 0:e33621169e44 | 296 | if(!par == fwd) { |
hudakz | 0:e33621169e44 | 297 | /* reverse sampled digits */ |
hudakz | 0:e33621169e44 | 298 | unsigned char i; |
hudakz | 0:e33621169e44 | 299 | for(i = 1; i < 4; i++) { |
hudakz | 0:e33621169e44 | 300 | unsigned char tmp = pass->raw[i]; |
hudakz | 0:e33621169e44 | 301 | pass->raw[i] = pass->raw[7 - i]; |
hudakz | 0:e33621169e44 | 302 | pass->raw[7 - i] = tmp; |
hudakz | 0:e33621169e44 | 303 | } |
hudakz | 0:e33621169e44 | 304 | } |
hudakz | 0:e33621169e44 | 305 | |
hudakz | 0:e33621169e44 | 306 | dprintf(2, "\n"); |
hudakz | 0:e33621169e44 | 307 | dprintf(1, "decode=%x%x%x%x%x%x%x(%02x)\n", |
hudakz | 0:e33621169e44 | 308 | pass->raw[0] & 0xf, pass->raw[1] & 0xf, |
hudakz | 0:e33621169e44 | 309 | pass->raw[2] & 0xf, pass->raw[3] & 0xf, |
hudakz | 0:e33621169e44 | 310 | pass->raw[4] & 0xf, pass->raw[5] & 0xf, |
hudakz | 0:e33621169e44 | 311 | pass->raw[6] & 0xf, par); |
hudakz | 0:e33621169e44 | 312 | |
hudakz | 0:e33621169e44 | 313 | if(TEST_CFG(ean->ean13_config, ZBAR_CFG_ENABLE)) { |
hudakz | 0:e33621169e44 | 314 | if(!par) |
hudakz | 0:e33621169e44 | 315 | return(ZBAR_EAN13 | EAN_RIGHT); |
hudakz | 0:e33621169e44 | 316 | if(par & 0x20) |
hudakz | 0:e33621169e44 | 317 | return(ZBAR_EAN13 | EAN_LEFT); |
hudakz | 0:e33621169e44 | 318 | } |
hudakz | 0:e33621169e44 | 319 | if(par && !(par & 0x20)) |
hudakz | 0:e33621169e44 | 320 | return(ZBAR_UPCE); |
hudakz | 0:e33621169e44 | 321 | |
hudakz | 0:e33621169e44 | 322 | return(ZBAR_NONE); |
hudakz | 0:e33621169e44 | 323 | } |
hudakz | 0:e33621169e44 | 324 | |
hudakz | 0:e33621169e44 | 325 | /* update state for one of 4 parallel passes */ |
hudakz | 0:e33621169e44 | 326 | static inline zbar_symbol_type_t decode_pass (zbar_decoder_t *dcode, |
hudakz | 0:e33621169e44 | 327 | ean_pass_t *pass) |
hudakz | 0:e33621169e44 | 328 | { |
hudakz | 0:e33621169e44 | 329 | pass->state++; |
hudakz | 0:e33621169e44 | 330 | unsigned char idx = pass->state & STATE_IDX; |
hudakz | 0:e33621169e44 | 331 | unsigned char fwd = pass->state & 1; |
hudakz | 0:e33621169e44 | 332 | |
hudakz | 0:e33621169e44 | 333 | if(get_color(dcode) == ZBAR_SPACE && |
hudakz | 0:e33621169e44 | 334 | (idx == 0x10 || idx == 0x11) && |
hudakz | 0:e33621169e44 | 335 | TEST_CFG(dcode->ean.ean8_config, ZBAR_CFG_ENABLE) && |
hudakz | 0:e33621169e44 | 336 | !aux_end(dcode, fwd)) { |
hudakz | 0:e33621169e44 | 337 | dprintf(2, " fwd=%x", fwd); |
hudakz | 0:e33621169e44 | 338 | zbar_symbol_type_t part = ean_part_end4(pass, fwd); |
hudakz | 0:e33621169e44 | 339 | pass->state = -1; |
hudakz | 0:e33621169e44 | 340 | return(part); |
hudakz | 0:e33621169e44 | 341 | } |
hudakz | 0:e33621169e44 | 342 | |
hudakz | 0:e33621169e44 | 343 | if(!(idx & 0x03) && idx <= 0x14) { |
hudakz | 0:e33621169e44 | 344 | if(!dcode->ean.s4) |
hudakz | 0:e33621169e44 | 345 | return(0); |
hudakz | 0:e33621169e44 | 346 | /* validate guard bars before decoding first char of symbol */ |
hudakz | 0:e33621169e44 | 347 | if(!pass->state) { |
hudakz | 0:e33621169e44 | 348 | pass->state = aux_start(dcode); |
hudakz | 0:e33621169e44 | 349 | if(pass->state < 0) |
hudakz | 0:e33621169e44 | 350 | return(0); |
hudakz | 0:e33621169e44 | 351 | idx = pass->state & STATE_IDX; |
hudakz | 0:e33621169e44 | 352 | } |
hudakz | 0:e33621169e44 | 353 | signed char code = decode4(dcode); |
hudakz | 0:e33621169e44 | 354 | if(code < 0) |
hudakz | 0:e33621169e44 | 355 | pass->state = -1; |
hudakz | 0:e33621169e44 | 356 | else { |
hudakz | 0:e33621169e44 | 357 | dprintf(2, "\n raw[%x]=%02x =>", idx >> 2, |
hudakz | 0:e33621169e44 | 358 | digits[(unsigned char)code]); |
hudakz | 0:e33621169e44 | 359 | pass->raw[(idx >> 2) + 1] = digits[(unsigned char)code]; |
hudakz | 0:e33621169e44 | 360 | dprintf(2, " raw=%d%d%d%d%d%d%d", |
hudakz | 0:e33621169e44 | 361 | pass->raw[0] & 0xf, pass->raw[1] & 0xf, |
hudakz | 0:e33621169e44 | 362 | pass->raw[2] & 0xf, pass->raw[3] & 0xf, |
hudakz | 0:e33621169e44 | 363 | pass->raw[4] & 0xf, pass->raw[5] & 0xf, |
hudakz | 0:e33621169e44 | 364 | pass->raw[6] & 0xf); |
hudakz | 0:e33621169e44 | 365 | } |
hudakz | 0:e33621169e44 | 366 | } |
hudakz | 0:e33621169e44 | 367 | |
hudakz | 0:e33621169e44 | 368 | if(get_color(dcode) == ZBAR_SPACE && |
hudakz | 0:e33621169e44 | 369 | (idx == 0x18 || idx == 0x19)) { |
hudakz | 0:e33621169e44 | 370 | zbar_symbol_type_t part = ZBAR_NONE; |
hudakz | 0:e33621169e44 | 371 | dprintf(2, " fwd=%x", fwd); |
hudakz | 0:e33621169e44 | 372 | if(!aux_end(dcode, fwd)) |
hudakz | 0:e33621169e44 | 373 | part = ean_part_end7(&dcode->ean, pass, fwd); |
hudakz | 0:e33621169e44 | 374 | pass->state = -1; |
hudakz | 0:e33621169e44 | 375 | return(part); |
hudakz | 0:e33621169e44 | 376 | } |
hudakz | 0:e33621169e44 | 377 | return(0); |
hudakz | 0:e33621169e44 | 378 | } |
hudakz | 0:e33621169e44 | 379 | |
hudakz | 0:e33621169e44 | 380 | static inline signed char ean_verify_checksum (ean_decoder_t *ean, |
hudakz | 0:e33621169e44 | 381 | int n) |
hudakz | 0:e33621169e44 | 382 | { |
hudakz | 0:e33621169e44 | 383 | unsigned char chk = 0; |
hudakz | 0:e33621169e44 | 384 | unsigned char i; |
hudakz | 0:e33621169e44 | 385 | for(i = 0; i < n; i++) { |
hudakz | 0:e33621169e44 | 386 | unsigned char d = ean->buf[i]; |
hudakz | 0:e33621169e44 | 387 | zassert(d < 10, -1, "i=%x d=%x chk=%x %s\n", i, d, chk, |
hudakz | 0:e33621169e44 | 388 | _zbar_decoder_buf_dump((void*)ean->buf, 18)); |
hudakz | 0:e33621169e44 | 389 | chk += d; |
hudakz | 0:e33621169e44 | 390 | if((i ^ n) & 1) { |
hudakz | 0:e33621169e44 | 391 | chk += d << 1; |
hudakz | 0:e33621169e44 | 392 | if(chk >= 20) |
hudakz | 0:e33621169e44 | 393 | chk -= 20; |
hudakz | 0:e33621169e44 | 394 | } |
hudakz | 0:e33621169e44 | 395 | if(chk >= 10) |
hudakz | 0:e33621169e44 | 396 | chk -= 10; |
hudakz | 0:e33621169e44 | 397 | } |
hudakz | 0:e33621169e44 | 398 | zassert(chk < 10, -1, "chk=%x n=%x %s", chk, n, |
hudakz | 0:e33621169e44 | 399 | _zbar_decoder_buf_dump((void*)ean->buf, 18)); |
hudakz | 0:e33621169e44 | 400 | if(chk) |
hudakz | 0:e33621169e44 | 401 | chk = 10 - chk; |
hudakz | 0:e33621169e44 | 402 | unsigned char d = ean->buf[n]; |
hudakz | 0:e33621169e44 | 403 | zassert(d < 10, -1, "n=%x d=%x chk=%x %s\n", n, d, chk, |
hudakz | 0:e33621169e44 | 404 | _zbar_decoder_buf_dump((void*)ean->buf, 18)); |
hudakz | 0:e33621169e44 | 405 | if(chk != d) { |
hudakz | 0:e33621169e44 | 406 | dprintf(1, "\nchecksum mismatch %d != %d (%s)\n", |
hudakz | 0:e33621169e44 | 407 | chk, d, dsprintbuf(ean)); |
hudakz | 0:e33621169e44 | 408 | return(-1); |
hudakz | 0:e33621169e44 | 409 | } |
hudakz | 0:e33621169e44 | 410 | return(0); |
hudakz | 0:e33621169e44 | 411 | } |
hudakz | 0:e33621169e44 | 412 | |
hudakz | 0:e33621169e44 | 413 | static inline unsigned char isbn10_calc_checksum (ean_decoder_t *ean) |
hudakz | 0:e33621169e44 | 414 | { |
hudakz | 0:e33621169e44 | 415 | unsigned int chk = 0; |
hudakz | 0:e33621169e44 | 416 | unsigned char w; |
hudakz | 0:e33621169e44 | 417 | for(w = 10; w > 1; w--) { |
hudakz | 0:e33621169e44 | 418 | unsigned char d = ean->buf[13 - w]; |
hudakz | 0:e33621169e44 | 419 | zassert(d < 10, '?', "w=%x d=%x chk=%x %s\n", w, d, chk, |
hudakz | 0:e33621169e44 | 420 | _zbar_decoder_buf_dump((void*)ean->buf, 18)); |
hudakz | 0:e33621169e44 | 421 | chk += d * w; |
hudakz | 0:e33621169e44 | 422 | } |
hudakz | 0:e33621169e44 | 423 | chk = chk % 11; |
hudakz | 0:e33621169e44 | 424 | if(!chk) |
hudakz | 0:e33621169e44 | 425 | return('0'); |
hudakz | 0:e33621169e44 | 426 | chk = 11 - chk; |
hudakz | 0:e33621169e44 | 427 | if(chk < 10) |
hudakz | 0:e33621169e44 | 428 | return(chk + '0'); |
hudakz | 0:e33621169e44 | 429 | return('X'); |
hudakz | 0:e33621169e44 | 430 | } |
hudakz | 0:e33621169e44 | 431 | |
hudakz | 0:e33621169e44 | 432 | static inline void ean_expand_upce (ean_decoder_t *ean, |
hudakz | 0:e33621169e44 | 433 | ean_pass_t *pass) |
hudakz | 0:e33621169e44 | 434 | { |
hudakz | 0:e33621169e44 | 435 | int i = 0; |
hudakz | 0:e33621169e44 | 436 | /* parity encoded digit is checksum */ |
hudakz | 0:e33621169e44 | 437 | ean->buf[12] = pass->raw[i++]; |
hudakz | 0:e33621169e44 | 438 | |
hudakz | 0:e33621169e44 | 439 | unsigned char decode = pass->raw[6] & 0xf; |
hudakz | 0:e33621169e44 | 440 | ean->buf[0] = 0; |
hudakz | 0:e33621169e44 | 441 | ean->buf[1] = 0; |
hudakz | 0:e33621169e44 | 442 | ean->buf[2] = pass->raw[i++] & 0xf; |
hudakz | 0:e33621169e44 | 443 | ean->buf[3] = pass->raw[i++] & 0xf; |
hudakz | 0:e33621169e44 | 444 | ean->buf[4] = (decode < 3) ? decode : pass->raw[i++] & 0xf; |
hudakz | 0:e33621169e44 | 445 | ean->buf[5] = (decode < 4) ? 0 : pass->raw[i++] & 0xf; |
hudakz | 0:e33621169e44 | 446 | ean->buf[6] = (decode < 5) ? 0 : pass->raw[i++] & 0xf; |
hudakz | 0:e33621169e44 | 447 | ean->buf[7] = 0; |
hudakz | 0:e33621169e44 | 448 | ean->buf[8] = 0; |
hudakz | 0:e33621169e44 | 449 | ean->buf[9] = (decode < 3) ? pass->raw[i++] & 0xf : 0; |
hudakz | 0:e33621169e44 | 450 | ean->buf[10] = (decode < 4) ? pass->raw[i++] & 0xf : 0; |
hudakz | 0:e33621169e44 | 451 | ean->buf[11] = (decode < 5) ? pass->raw[i++] & 0xf : decode; |
hudakz | 0:e33621169e44 | 452 | } |
hudakz | 0:e33621169e44 | 453 | |
hudakz | 0:e33621169e44 | 454 | static inline zbar_symbol_type_t integrate_partial (ean_decoder_t *ean, |
hudakz | 0:e33621169e44 | 455 | ean_pass_t *pass, |
hudakz | 0:e33621169e44 | 456 | zbar_symbol_type_t part) |
hudakz | 0:e33621169e44 | 457 | { |
hudakz | 0:e33621169e44 | 458 | /* copy raw data into holding buffer */ |
hudakz | 0:e33621169e44 | 459 | /* if same partial is not consistent, reset others */ |
hudakz | 0:e33621169e44 | 460 | dprintf(2, " integrate part=%x (%s)", part, dsprintbuf(ean)); |
hudakz | 0:e33621169e44 | 461 | signed char i, j; |
hudakz | 0:e33621169e44 | 462 | if(part & ZBAR_ADDON) { |
hudakz | 0:e33621169e44 | 463 | /* FIXME TBD */ |
hudakz | 0:e33621169e44 | 464 | for(i = (part == ZBAR_ADDON5) ? 4 : 1; i >= 0; i--) { |
hudakz | 0:e33621169e44 | 465 | unsigned char digit = pass->raw[i] & 0xf; |
hudakz | 0:e33621169e44 | 466 | if(ean->addon && ean->buf[i + 13] != digit) { |
hudakz | 0:e33621169e44 | 467 | /* partial mismatch - reset collected parts */ |
hudakz | 0:e33621169e44 | 468 | ean->left = ean->right = ean->addon = ZBAR_NONE; |
hudakz | 0:e33621169e44 | 469 | } |
hudakz | 0:e33621169e44 | 470 | ean->buf[i + 13] = digit; |
hudakz | 0:e33621169e44 | 471 | } |
hudakz | 0:e33621169e44 | 472 | ean->addon = part; |
hudakz | 0:e33621169e44 | 473 | } |
hudakz | 0:e33621169e44 | 474 | else { |
hudakz | 0:e33621169e44 | 475 | if((ean->left && ((part & ZBAR_SYMBOL) != ean->left)) || |
hudakz | 0:e33621169e44 | 476 | (ean->right && ((part & ZBAR_SYMBOL) != ean->right))) { |
hudakz | 0:e33621169e44 | 477 | /* partial mismatch - reset collected parts */ |
hudakz | 0:e33621169e44 | 478 | dprintf(2, " rst(type %x %x)", ean->left, ean->right); |
hudakz | 0:e33621169e44 | 479 | ean->left = ean->right = ean->addon = ZBAR_NONE; |
hudakz | 0:e33621169e44 | 480 | } |
hudakz | 0:e33621169e44 | 481 | |
hudakz | 0:e33621169e44 | 482 | if(part & EAN_RIGHT) { |
hudakz | 0:e33621169e44 | 483 | part &= ZBAR_SYMBOL; |
hudakz | 0:e33621169e44 | 484 | j = (part == ZBAR_EAN13) ? 12 : 7; |
hudakz | 0:e33621169e44 | 485 | for(i = (part == ZBAR_EAN13) ? 6 : 4; i; i--, j--) { |
hudakz | 0:e33621169e44 | 486 | unsigned char digit = pass->raw[i] & 0xf; |
hudakz | 0:e33621169e44 | 487 | if(ean->right && ean->buf[j] != digit) { |
hudakz | 0:e33621169e44 | 488 | /* partial mismatch - reset collected parts */ |
hudakz | 0:e33621169e44 | 489 | dprintf(2, " rst(right)"); |
hudakz | 0:e33621169e44 | 490 | ean->left = ean->right = ean->addon = ZBAR_NONE; |
hudakz | 0:e33621169e44 | 491 | } |
hudakz | 0:e33621169e44 | 492 | ean->buf[j] = digit; |
hudakz | 0:e33621169e44 | 493 | } |
hudakz | 0:e33621169e44 | 494 | ean->right = part; |
hudakz | 0:e33621169e44 | 495 | } |
hudakz | 0:e33621169e44 | 496 | else if(part != ZBAR_UPCE) /* EAN_LEFT */ { |
hudakz | 0:e33621169e44 | 497 | j = (part == ZBAR_EAN13) ? 6 : 3; |
hudakz | 0:e33621169e44 | 498 | for(i = (part == ZBAR_EAN13) ? 6 : 4; j >= 0; i--, j--) { |
hudakz | 0:e33621169e44 | 499 | unsigned char digit = pass->raw[i] & 0xf; |
hudakz | 0:e33621169e44 | 500 | if(ean->left && ean->buf[j] != digit) { |
hudakz | 0:e33621169e44 | 501 | /* partial mismatch - reset collected parts */ |
hudakz | 0:e33621169e44 | 502 | dprintf(2, " rst(left)"); |
hudakz | 0:e33621169e44 | 503 | ean->left = ean->right = ean->addon = ZBAR_NONE; |
hudakz | 0:e33621169e44 | 504 | } |
hudakz | 0:e33621169e44 | 505 | ean->buf[j] = digit; |
hudakz | 0:e33621169e44 | 506 | } |
hudakz | 0:e33621169e44 | 507 | ean->left = part; |
hudakz | 0:e33621169e44 | 508 | } |
hudakz | 0:e33621169e44 | 509 | else /* ZBAR_UPCE */ |
hudakz | 0:e33621169e44 | 510 | ean_expand_upce(ean, pass); |
hudakz | 0:e33621169e44 | 511 | } |
hudakz | 0:e33621169e44 | 512 | |
hudakz | 0:e33621169e44 | 513 | if((part & ZBAR_SYMBOL) != ZBAR_UPCE) { |
hudakz | 0:e33621169e44 | 514 | part = (ean->left & ean->right); |
hudakz | 0:e33621169e44 | 515 | if(!part) |
hudakz | 0:e33621169e44 | 516 | part = ZBAR_PARTIAL; |
hudakz | 0:e33621169e44 | 517 | } |
hudakz | 0:e33621169e44 | 518 | |
hudakz | 0:e33621169e44 | 519 | if(((part == ZBAR_EAN13 || |
hudakz | 0:e33621169e44 | 520 | part == ZBAR_UPCE) && ean_verify_checksum(ean, 12)) || |
hudakz | 0:e33621169e44 | 521 | (part == ZBAR_EAN8 && ean_verify_checksum(ean, 7))) |
hudakz | 0:e33621169e44 | 522 | /* invalid parity */ |
hudakz | 0:e33621169e44 | 523 | part = ZBAR_NONE; |
hudakz | 0:e33621169e44 | 524 | |
hudakz | 0:e33621169e44 | 525 | if(part == ZBAR_EAN13) { |
hudakz | 0:e33621169e44 | 526 | /* special case EAN-13 subsets */ |
hudakz | 0:e33621169e44 | 527 | if(!ean->buf[0] && TEST_CFG(ean->upca_config, ZBAR_CFG_ENABLE)) |
hudakz | 0:e33621169e44 | 528 | part = ZBAR_UPCA; |
hudakz | 0:e33621169e44 | 529 | else if(ean->buf[0] == 9 && ean->buf[1] == 7) { |
hudakz | 0:e33621169e44 | 530 | /* ISBN-10 has priority over ISBN-13(?) */ |
hudakz | 0:e33621169e44 | 531 | if(ean->buf[2] == 8 && |
hudakz | 0:e33621169e44 | 532 | TEST_CFG(ean->isbn10_config, ZBAR_CFG_ENABLE)) |
hudakz | 0:e33621169e44 | 533 | part = ZBAR_ISBN10; |
hudakz | 0:e33621169e44 | 534 | else if((ean->buf[2] == 8 || ean->buf[2] == 9) && |
hudakz | 0:e33621169e44 | 535 | TEST_CFG(ean->isbn13_config, ZBAR_CFG_ENABLE)) |
hudakz | 0:e33621169e44 | 536 | part = ZBAR_ISBN13; |
hudakz | 0:e33621169e44 | 537 | } |
hudakz | 0:e33621169e44 | 538 | } |
hudakz | 0:e33621169e44 | 539 | else if(part == ZBAR_UPCE) { |
hudakz | 0:e33621169e44 | 540 | if(TEST_CFG(ean->upce_config, ZBAR_CFG_ENABLE)) { |
hudakz | 0:e33621169e44 | 541 | /* UPC-E was decompressed for checksum verification, |
hudakz | 0:e33621169e44 | 542 | * but user requested compressed result |
hudakz | 0:e33621169e44 | 543 | */ |
hudakz | 0:e33621169e44 | 544 | ean->buf[0] = ean->buf[1] = 0; |
hudakz | 0:e33621169e44 | 545 | for(i = 2; i < 8; i++) |
hudakz | 0:e33621169e44 | 546 | ean->buf[i] = pass->raw[i - 1] & 0xf; |
hudakz | 0:e33621169e44 | 547 | ean->buf[i] = pass->raw[0] & 0xf; |
hudakz | 0:e33621169e44 | 548 | } |
hudakz | 0:e33621169e44 | 549 | else if(TEST_CFG(ean->upca_config, ZBAR_CFG_ENABLE)) |
hudakz | 0:e33621169e44 | 550 | /* UPC-E reported as UPC-A has priority over EAN-13 */ |
hudakz | 0:e33621169e44 | 551 | part = ZBAR_UPCA; |
hudakz | 0:e33621169e44 | 552 | else if(TEST_CFG(ean->ean13_config, ZBAR_CFG_ENABLE)) |
hudakz | 0:e33621169e44 | 553 | part = ZBAR_EAN13; |
hudakz | 0:e33621169e44 | 554 | else |
hudakz | 0:e33621169e44 | 555 | part = ZBAR_NONE; |
hudakz | 0:e33621169e44 | 556 | } |
hudakz | 0:e33621169e44 | 557 | |
hudakz | 0:e33621169e44 | 558 | if(part > ZBAR_PARTIAL) |
hudakz | 0:e33621169e44 | 559 | part |= ean->addon; |
hudakz | 0:e33621169e44 | 560 | |
hudakz | 0:e33621169e44 | 561 | dprintf(2, " %x/%x=%x", ean->left, ean->right, part); |
hudakz | 0:e33621169e44 | 562 | return(part); |
hudakz | 0:e33621169e44 | 563 | } |
hudakz | 0:e33621169e44 | 564 | |
hudakz | 0:e33621169e44 | 565 | /* copy result to output buffer */ |
hudakz | 0:e33621169e44 | 566 | static inline void postprocess (zbar_decoder_t *dcode, |
hudakz | 0:e33621169e44 | 567 | zbar_symbol_type_t sym) |
hudakz | 0:e33621169e44 | 568 | { |
hudakz | 0:e33621169e44 | 569 | ean_decoder_t *ean = &dcode->ean; |
hudakz | 0:e33621169e44 | 570 | zbar_symbol_type_t base = sym & ZBAR_SYMBOL; |
hudakz | 0:e33621169e44 | 571 | int i = 0, j = 0; |
hudakz | 0:e33621169e44 | 572 | if(base > ZBAR_PARTIAL) { |
hudakz | 0:e33621169e44 | 573 | if(base == ZBAR_UPCA) |
hudakz | 0:e33621169e44 | 574 | i = 1; |
hudakz | 0:e33621169e44 | 575 | else if(base == ZBAR_UPCE) { |
hudakz | 0:e33621169e44 | 576 | i = 1; |
hudakz | 0:e33621169e44 | 577 | base--; |
hudakz | 0:e33621169e44 | 578 | } |
hudakz | 0:e33621169e44 | 579 | else if(base == ZBAR_ISBN13) |
hudakz | 0:e33621169e44 | 580 | base = ZBAR_EAN13; |
hudakz | 0:e33621169e44 | 581 | else if(base == ZBAR_ISBN10) |
hudakz | 0:e33621169e44 | 582 | i = 3; |
hudakz | 0:e33621169e44 | 583 | |
hudakz | 0:e33621169e44 | 584 | if(base == ZBAR_ISBN10 || |
hudakz | 0:e33621169e44 | 585 | !TEST_CFG(ean_get_config(ean, sym), ZBAR_CFG_EMIT_CHECK)) |
hudakz | 0:e33621169e44 | 586 | base--; |
hudakz | 0:e33621169e44 | 587 | |
hudakz | 0:e33621169e44 | 588 | for(; j < base && ean->buf[i] >= 0; i++, j++) |
hudakz | 0:e33621169e44 | 589 | dcode->buf[j] = ean->buf[i] + '0'; |
hudakz | 0:e33621169e44 | 590 | |
hudakz | 0:e33621169e44 | 591 | if((sym & ZBAR_SYMBOL) == ZBAR_ISBN10 && j == 9 && |
hudakz | 0:e33621169e44 | 592 | TEST_CFG(ean->isbn10_config, ZBAR_CFG_EMIT_CHECK)) |
hudakz | 0:e33621169e44 | 593 | /* recalculate ISBN-10 check digit */ |
hudakz | 0:e33621169e44 | 594 | dcode->buf[j++] = isbn10_calc_checksum(ean); |
hudakz | 0:e33621169e44 | 595 | } |
hudakz | 0:e33621169e44 | 596 | if(sym & ZBAR_ADDON) |
hudakz | 0:e33621169e44 | 597 | for(i = 13; ean->buf[i] >= 0; i++, j++) |
hudakz | 0:e33621169e44 | 598 | dcode->buf[j] = ean->buf[i] + '0'; |
hudakz | 0:e33621169e44 | 599 | dcode->buflen = j; |
hudakz | 0:e33621169e44 | 600 | dcode->buf[j] = '\0'; |
hudakz | 0:e33621169e44 | 601 | } |
hudakz | 0:e33621169e44 | 602 | |
hudakz | 0:e33621169e44 | 603 | zbar_symbol_type_t _zbar_decode_ean (zbar_decoder_t *dcode) |
hudakz | 0:e33621169e44 | 604 | { |
hudakz | 0:e33621169e44 | 605 | /* process upto 4 separate passes */ |
hudakz | 0:e33621169e44 | 606 | zbar_symbol_type_t sym = ZBAR_NONE; |
hudakz | 0:e33621169e44 | 607 | unsigned char pass_idx = dcode->idx & 3; |
hudakz | 0:e33621169e44 | 608 | |
hudakz | 0:e33621169e44 | 609 | /* update latest character width */ |
hudakz | 0:e33621169e44 | 610 | dcode->ean.s4 -= get_width(dcode, 4); |
hudakz | 0:e33621169e44 | 611 | dcode->ean.s4 += get_width(dcode, 0); |
hudakz | 0:e33621169e44 | 612 | |
hudakz | 0:e33621169e44 | 613 | unsigned char i; |
hudakz | 0:e33621169e44 | 614 | for(i = 0; i < 4; i++) { |
hudakz | 0:e33621169e44 | 615 | ean_pass_t *pass = &dcode->ean.pass[i]; |
hudakz | 0:e33621169e44 | 616 | if(pass->state >= 0 || |
hudakz | 0:e33621169e44 | 617 | i == pass_idx) |
hudakz | 0:e33621169e44 | 618 | { |
hudakz | 0:e33621169e44 | 619 | dprintf(2, " ean[%x/%x]: idx=%x st=%d s=%d", |
hudakz | 0:e33621169e44 | 620 | pass_idx, i, dcode->idx, pass->state, dcode->ean.s4); |
hudakz | 0:e33621169e44 | 621 | zbar_symbol_type_t part = decode_pass(dcode, pass); |
hudakz | 0:e33621169e44 | 622 | if(part) { |
hudakz | 0:e33621169e44 | 623 | /* update accumulated data from new partial decode */ |
hudakz | 0:e33621169e44 | 624 | sym = integrate_partial(&dcode->ean, pass, part); |
hudakz | 0:e33621169e44 | 625 | if(sym) { |
hudakz | 0:e33621169e44 | 626 | /* this pass valid => _reset_ all passes */ |
hudakz | 0:e33621169e44 | 627 | dprintf(2, " sym=%x", sym); |
hudakz | 0:e33621169e44 | 628 | dcode->ean.pass[0].state = dcode->ean.pass[1].state = -1; |
hudakz | 0:e33621169e44 | 629 | dcode->ean.pass[2].state = dcode->ean.pass[3].state = -1; |
hudakz | 0:e33621169e44 | 630 | if(sym > ZBAR_PARTIAL) { |
hudakz | 0:e33621169e44 | 631 | if(!get_lock(dcode, ZBAR_EAN13)) |
hudakz | 0:e33621169e44 | 632 | postprocess(dcode, sym); |
hudakz | 0:e33621169e44 | 633 | else { |
hudakz | 0:e33621169e44 | 634 | dprintf(1, " [locked %d]", dcode->lock); |
hudakz | 0:e33621169e44 | 635 | sym = ZBAR_PARTIAL; |
hudakz | 0:e33621169e44 | 636 | } |
hudakz | 0:e33621169e44 | 637 | } |
hudakz | 0:e33621169e44 | 638 | } |
hudakz | 0:e33621169e44 | 639 | } |
hudakz | 0:e33621169e44 | 640 | dprintf(2, "\n"); |
hudakz | 0:e33621169e44 | 641 | } |
hudakz | 0:e33621169e44 | 642 | } |
hudakz | 0:e33621169e44 | 643 | return(sym); |
hudakz | 0:e33621169e44 | 644 | } |
hudakz | 0:e33621169e44 | 645 | |
hudakz | 0:e33621169e44 | 646 | #endif |