pure sdk for main

This commit is contained in:
divadiow
2025-08-27 09:51:58 +01:00
parent f0d033f1c9
commit 0571416e7c
3283 changed files with 1577720 additions and 1 deletions
+437
View File
@@ -0,0 +1,437 @@
/*------------------------------------------------------------------------
* Copyright 2011 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#include <zbar_config.h>
#include <string.h> /* memmove */
#include <zbar.h>
#ifdef DEBUG_CODABAR
# define DEBUG_LEVEL (DEBUG_CODABAR)
#endif
#include "debug.h"
#include "decoder.h"
#define NIBUF 6 /* initial scan buffer size */
static const signed char codabar_lo[12] = {
0x0, 0x1, 0x4, 0x5, 0x2, 0xa, 0xb, 0x9,
0x6, 0x7, 0x8, 0x3
};
static const unsigned char codabar_hi[8] = {
0x1, 0x4, 0x7, 0x6, 0x2, 0x3, 0x0, 0x5
};
static const unsigned char codabar_characters[20] =
"0123456789-$:/.+ABCD";
static inline int
check_width (unsigned ref,
unsigned w)
{
unsigned dref = ref;
ref *= 4;
w *= 4;
return(ref - dref <= w && w <= ref + dref);
}
static inline signed char
codabar_decode7 (zbar_decoder_t *dcode)
{
codabar_decoder_t *codabar = &dcode->codabar;
unsigned s = codabar->s7;
dbprintf(2, " s=%d", s);
if(s < 7)
return(-1);
/* check width */
if(!check_width(codabar->width, s)) {
dbprintf(2, " [width]");
return(-1);
}
/* extract min/max bar */
unsigned ibar = decode_sortn(dcode, 4, 1);
dbprintf(2, " bar=%04x", ibar);
unsigned wbmax = get_width(dcode, ibar & 0xf);
unsigned wbmin = get_width(dcode, ibar >> 12);
if(8 * wbmin < wbmax ||
3 * wbmin > 2 * wbmax)
{
dbprintf(2, " [bar outer ratio]");
return(-1);
}
unsigned wb1 = get_width(dcode, (ibar >> 8) & 0xf);
unsigned wb2 = get_width(dcode, (ibar >> 4) & 0xf);
unsigned long b0b3 = wbmin * wbmax;
unsigned long b1b2 = wb1 * wb2;
if(b1b2 + b1b2 / 8 < b0b3) {
/* single wide bar combinations */
if(8 * wbmin < 5 * wb1 ||
8 * wb1 < 5 * wb2 ||
4 * wb2 > 3 * wbmax ||
wb2 * wb2 >= wb1 * wbmax)
{
dbprintf(2, " [1bar inner ratios]");
return(-1);
}
ibar = (ibar >> 1) & 0x3;
}
else if(b1b2 > b0b3 + b0b3 / 8) {
/* three wide bars, no wide spaces */
if(4 * wbmin > 3 * wb1 ||
8 * wb1 < 5 * wb2 ||
8 * wb2 < 5 * wbmax ||
wbmin * wb2 >= wb1 * wb1)
{
dbprintf(2, " [3bar inner ratios]");
return(-1);
}
ibar = (ibar >> 13) + 4;
}
else {
dbprintf(2, " [bar inner ratios]");
return(-1);
}
unsigned ispc = decode_sort3(dcode, 2);
dbprintf(2, "(%x) spc=%03x", ibar, ispc);
unsigned wsmax = get_width(dcode, ispc & 0xf);
unsigned wsmid = get_width(dcode, (ispc >> 4) & 0xf);
unsigned wsmin = get_width(dcode, (ispc >> 8) & 0xf);
if(ibar >> 2) {
/* verify no wide spaces */
if(8 * wsmin < wsmax ||
8 * wsmin < 5 * wsmid ||
8 * wsmid < 5 * wsmax)
{
dbprintf(2, " [0space inner ratios]");
return(-1);
}
ibar &= 0x3;
if(codabar->direction)
ibar = 3 - ibar;
int c = (0xfcde >> (ibar << 2)) & 0xf;
dbprintf(2, " ex[%d]=%x", ibar, c);
return(c);
}
else if(8 * wsmin < wsmax ||
3 * wsmin > 2 * wsmax)
{
dbprintf(2, " [space outer ratio]");
return(-1);
}
unsigned long s0s2 = wsmin * wsmax;
unsigned long s1s1 = wsmid * wsmid;
if(s1s1 + s1s1 / 8 < s0s2) {
/* single wide space */
if(8 * wsmin < 5 * wsmid ||
4 * wsmid > 3 * wsmax)
{
dbprintf(2, " [1space inner ratios]");
return(-1);
}
ispc = ((ispc & 0xf) >> 1) - 1;
unsigned ic = (ispc << 2) | ibar;
if(codabar->direction)
ic = 11 - ic;
int c = codabar_lo[ic];
dbprintf(2, "(%d) lo[%d]=%x", ispc, ic, c);
return(c);
}
else if(s1s1 > s0s2 + s0s2 / 8) {
/* two wide spaces, check start/stop */
if(4 * wsmin > 3 * wsmid ||
8 * wsmid < 5 * wsmax)
{
dbprintf(2, " [2space inner ratios]");
return(-1);
}
if((ispc >> 8) == 4) {
dbprintf(2, " [space comb]");
return(-1);
}
ispc >>= 10;
dbprintf(2, "(%d)", ispc);
unsigned ic = ispc * 4 + ibar;
zassert(ic < 8, -1, "ic=%d ispc=%d ibar=%d", ic, ispc, ibar);
unsigned char c = codabar_hi[ic];
if(c >> 2 != codabar->direction) {
dbprintf(2, " [invalid stop]");
return(-1);
}
c = (c & 0x3) | 0x10;
dbprintf(2, " hi[%d]=%x", ic, c);
return(c);
}
else {
dbprintf(2, " [space inner ratios]");
return(-1);
}
}
static inline signed char
codabar_decode_start (zbar_decoder_t *dcode)
{
codabar_decoder_t *codabar = &dcode->codabar;
unsigned s = codabar->s7;
if(s < 8)
return(ZBAR_NONE);
dbprintf(2, " codabar: s=%d", s);
/* check leading quiet zone - spec is 10x */
unsigned qz = get_width(dcode, 8);
if((qz && qz * 2 < s) ||
4 * get_width(dcode, 0) > 3 * s)
{
dbprintf(2, " [invalid qz/ics]\n");
return(ZBAR_NONE);
}
/* check space ratios first */
unsigned ispc = decode_sort3(dcode, 2);
dbprintf(2, " spc=%03x", ispc);
if((ispc >> 8) == 4) {
dbprintf(2, " [space comb]\n");
return(ZBAR_NONE);
}
/* require 2 wide and 1 narrow spaces */
unsigned wsmax = get_width(dcode, ispc & 0xf);
unsigned wsmin = get_width(dcode, ispc >> 8);
unsigned wsmid = get_width(dcode, (ispc >> 4) & 0xf);
if(8 * wsmin < wsmax ||
3 * wsmin > 2 * wsmax ||
4 * wsmin > 3 * wsmid ||
8 * wsmid < 5 * wsmax ||
wsmid * wsmid <= wsmax * wsmin)
{
dbprintf(2, " [space ratio]\n");
return(ZBAR_NONE);
}
ispc >>= 10;
dbprintf(2, "(%d)", ispc);
/* check bar ratios */
unsigned ibar = decode_sortn(dcode, 4, 1);
dbprintf(2, " bar=%04x", ibar);
unsigned wbmax = get_width(dcode, ibar & 0xf);
unsigned wbmin = get_width(dcode, ibar >> 12);
if(8 * wbmin < wbmax ||
3 * wbmin > 2 * wbmax)
{
dbprintf(2, " [bar outer ratio]\n");
return(ZBAR_NONE);
}
/* require 1 wide & 3 narrow bars */
unsigned wb1 = get_width(dcode, (ibar >> 8) & 0xf);
unsigned wb2 = get_width(dcode, (ibar >> 4) & 0xf);
if(8 * wbmin < 5 * wb1 ||
8 * wb1 < 5 * wb2 ||
4 * wb2 > 3 * wbmax ||
wb1 * wb2 >= wbmin * wbmax ||
wb2 * wb2 >= wb1 * wbmax)
{
dbprintf(2, " [bar inner ratios]\n");
return(ZBAR_NONE);
}
ibar = ((ibar & 0xf) - 1) >> 1;
dbprintf(2, "(%d)", ibar);
/* decode combination */
int ic = ispc * 4 + ibar;
zassert(ic < 8, ZBAR_NONE, "ic=%d ispc=%d ibar=%d", ic, ispc, ibar);
int c = codabar_hi[ic];
codabar->buf[0] = (c & 0x3) | 0x10;
/* set character direction */
codabar->direction = c >> 2;
codabar->element = 4;
codabar->character = 1;
codabar->width = codabar->s7;
dbprintf(1, " start=%c dir=%x [valid start]\n",
codabar->buf[0] + 0x31, codabar->direction);
return(ZBAR_PARTIAL);
}
static inline int
codabar_checksum (zbar_decoder_t *dcode,
unsigned n)
{
unsigned chk = 0;
unsigned char *buf = dcode->buf;
while(n--)
chk += *(buf++);
return(!!(chk & 0xf));
}
static inline zbar_symbol_type_t
codabar_postprocess (zbar_decoder_t *dcode)
{
codabar_decoder_t *codabar = &dcode->codabar;
int dir = codabar->direction;
dcode->direction = 1 - 2 * dir;
int i, n = codabar->character;
for(i = 0; i < NIBUF; i++)
dcode->buf[i] = codabar->buf[i];
if(dir)
/* reverse buffer */
for(i = 0; i < n / 2; i++) {
unsigned j = n - 1 - i;
char code = dcode->buf[i];
dcode->buf[i] = dcode->buf[j];
dcode->buf[j] = code;
}
if(TEST_CFG(codabar->config, ZBAR_CFG_ADD_CHECK)) {
/* validate checksum */
if(codabar_checksum(dcode, n))
return(ZBAR_NONE);
if(!TEST_CFG(codabar->config, ZBAR_CFG_EMIT_CHECK)) {
dcode->buf[n - 2] = dcode->buf[n - 1];
n--;
}
}
for(i = 0; i < n; i++) {
unsigned c = dcode->buf[i];
dcode->buf[i] = ((c < 0x14)
? codabar_characters[c]
: '?');
}
dcode->buflen = i;
dcode->buf[i] = '\0';
dcode->modifiers = 0;
codabar->character = -1;
return(ZBAR_CODABAR);
}
zbar_symbol_type_t
_zbar_decode_codabar (zbar_decoder_t *dcode)
{
codabar_decoder_t *codabar = &dcode->codabar;
/* update latest character width */
codabar->s7 -= get_width(dcode, 8);
codabar->s7 += get_width(dcode, 1);
if(get_color(dcode) != ZBAR_SPACE)
return(ZBAR_NONE);
if(codabar->character < 0)
return(codabar_decode_start(dcode));
if(codabar->character < 2 &&
codabar_decode_start(dcode))
return(ZBAR_PARTIAL);
if(--codabar->element)
return(ZBAR_NONE);
codabar->element = 4;
dbprintf(1, " codabar[%c%02d+%x]",
(codabar->direction) ? '<' : '>',
codabar->character, codabar->element);
signed char c = codabar_decode7(dcode);
dbprintf(1, " %d", c);
if(c < 0) {
dbprintf(1, " [aborted]\n");
goto reset;
}
unsigned char *buf;
if(codabar->character < NIBUF)
buf = codabar->buf;
else {
if(codabar->character >= BUFFER_MIN &&
size_buf(dcode, codabar->character + 1))
{
dbprintf(1, " [overflow]\n");
goto reset;
}
buf = dcode->buf;
}
buf[codabar->character++] = c;
/* lock shared resources */
if(codabar->character == NIBUF &&
acquire_lock(dcode, ZBAR_CODABAR))
{
codabar->character = -1;
return(ZBAR_PARTIAL);
}
unsigned s = codabar->s7;
if(c & 0x10) {
unsigned qz = get_width(dcode, 0);
if(qz && qz * 2 < s) {
dbprintf(2, " [invalid qz]\n");
goto reset;
}
unsigned n = codabar->character;
if(n < CFG(*codabar, ZBAR_CFG_MIN_LEN) ||
(CFG(*codabar, ZBAR_CFG_MAX_LEN) > 0 &&
n > CFG(*codabar, ZBAR_CFG_MAX_LEN)))
{
dbprintf(2, " [invalid len]\n");
goto reset;
}
if(codabar->character < NIBUF &&
acquire_lock(dcode, ZBAR_CODABAR))
{
codabar->character = -1;
return(ZBAR_PARTIAL);
}
dbprintf(2, " stop=%c", c + 0x31);
zbar_symbol_type_t sym = codabar_postprocess(dcode);
if(sym > ZBAR_PARTIAL)
dbprintf(2, " [valid stop]");
else {
release_lock(dcode, ZBAR_CODABAR);
codabar->character = -1;
}
dbprintf(2, "\n");
return(sym);
}
else if(4 * get_width(dcode, 0) > 3 * s) {
dbprintf(2, " [ics]\n");
goto reset;
}
dbprintf(2, "\n");
return(ZBAR_NONE);
reset:
if(codabar->character >= NIBUF)
release_lock(dcode, ZBAR_CODABAR);
codabar->character = -1;
return(ZBAR_NONE);
}
+51
View File
@@ -0,0 +1,51 @@
/*------------------------------------------------------------------------
* Copyright 2011 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#ifndef _CODABAR_H_
#define _CODABAR_H_
/* Codabar specific decode state */
typedef struct codabar_decoder_s {
unsigned direction : 1; /* scan direction: 0=fwd, 1=rev */
unsigned element : 4; /* element offset 0-7 */
int character : 12; /* character position in symbol */
unsigned s7; /* current character width */
unsigned width; /* last character width */
unsigned char buf[6]; /* initial scan buffer */
unsigned config;
int configs[NUM_CFGS]; /* int valued configurations */
} codabar_decoder_t;
/* reset Codabar specific state */
static inline void codabar_reset (codabar_decoder_t *codabar)
{
codabar->direction = 0;
codabar->element = 0;
codabar->character = -1;
codabar->s7 = 0;
}
/* decode Codabar symbols */
zbar_symbol_type_t _zbar_decode_codabar(zbar_decoder_t *dcode);
#endif
+569
View File
@@ -0,0 +1,569 @@
/*------------------------------------------------------------------------
* Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#include <zbar_config.h>
#include <string.h> /* memmove */
#include <zbar.h>
#ifdef DEBUG_CODE128
# define DEBUG_LEVEL (DEBUG_CODE128)
#endif
#include "debug.h"
#include "decoder.h"
#define NUM_CHARS 108 /* total number of character codes */
typedef enum code128_char_e {
FNC3 = 0x60,
FNC2 = 0x61,
SHIFT = 0x62,
CODE_C = 0x63,
CODE_B = 0x64,
CODE_A = 0x65,
FNC1 = 0x66,
START_A = 0x67,
START_B = 0x68,
START_C = 0x69,
STOP_FWD = 0x6a,
STOP_REV = 0x6b,
FNC4 = 0x6c,
} code128_char_t;
static const unsigned char characters[NUM_CHARS] = {
0x5c, 0xbf, 0xa1, /* [00] 00 */
0x2a, 0xc5, 0x0c, 0xa4, /* [03] 01 */
0x2d, 0xe3, 0x0f, /* [07] 02 */
0x5f, 0xe4, /* [0a] 03 */
0x6b, 0xe8, 0x69, 0xa7, 0xe7, /* [0c] 10 */
0xc1, 0x51, 0x1e, 0x83, 0xd9, 0x00, 0x84, 0x1f, /* [11] 11 */
0xc7, 0x0d, 0x33, 0x86, 0xb5, 0x0e, 0x15, 0x87, /* [19] 12 */
0x10, 0xda, 0x11, /* [21] 13 */
0x36, 0xe5, 0x18, 0x37, /* [24] 20 */
0xcc, 0x13, 0x39, 0x89, 0x97, 0x14, 0x1b, 0x8a, 0x3a, 0xbd, /* [28] 21 */
0xa2, 0x5e, 0x01, 0x85, 0xb0, 0x02, 0xa3, /* [32] 22 */
0xa5, 0x2c, 0x16, 0x88, 0xbc, 0x12, 0xa6, /* [39] 23 */
0x61, 0xe6, 0x56, 0x62, /* [40] 30 */
0x19, 0xdb, 0x1a, /* [44] 31 */
0xa8, 0x32, 0x1c, 0x8b, 0xcd, 0x1d, 0xa9, /* [47] 32 */
0xc3, 0x20, 0xc4, /* [4e] 33 */
0x50, 0x5d, 0xc0, /* [51] 0014 0025 0034 */
0x2b, 0xc6, /* [54] 0134 0143 */
0x2e, /* [56] 0243 */
0x53, 0x60, /* [57] 0341 0352 */
0x31, /* [59] 1024 */
0x52, 0xc2, /* [5a] 1114 1134 */
0x34, 0xc8, /* [5c] 1242 1243 */
0x55, /* [5e] 1441 */
0x57, 0x3e, 0xce, /* [5f] 4100 5200 4300 */
0x3b, 0xc9, /* [62] 4310 3410 */
0x6a, /* [64] 3420 */
0x54, 0x4f, /* [65] 1430 2530 */
0x38, /* [67] 4201 */
0x58, 0xcb, /* [68] 4111 4311 */
0x2f, 0xca, /* [6a] 2421 3421 */
};
static const unsigned char lo_base[8] = {
0x00, 0x07, 0x0c, 0x19, 0x24, 0x32, 0x40, 0x47
};
static const unsigned char lo_offset[0x80] = {
0xff, 0xf0, 0xff, 0x1f, 0xff, 0xf2, 0xff, 0xff, /* 00 [00] */
0xff, 0xff, 0xff, 0x3f, 0xf4, 0xf5, 0xff, 0x6f, /* 01 */
0xff, 0xff, 0xff, 0xff, 0xf0, 0xf1, 0xff, 0x2f, /* 02 [07] */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x4f, /* 03 */
0xff, 0x0f, 0xf1, 0xf2, 0xff, 0x3f, 0xff, 0xf4, /* 10 [0c] */
0xf5, 0xf6, 0xf7, 0x89, 0xff, 0xab, 0xff, 0xfc, /* 11 */
0xff, 0xff, 0x0f, 0x1f, 0x23, 0x45, 0xf6, 0x7f, /* 12 [19] */
0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xf9, 0xaf, /* 13 */
0xf0, 0xf1, 0xff, 0x2f, 0xff, 0xf3, 0xff, 0xff, /* 20 [24] */
0x4f, 0x5f, 0x67, 0x89, 0xfa, 0xbf, 0xff, 0xcd, /* 21 */
0xf0, 0xf1, 0xf2, 0x3f, 0xf4, 0x56, 0xff, 0xff, /* 22 [32] */
0xff, 0xff, 0x7f, 0x8f, 0x9a, 0xff, 0xbc, 0xdf, /* 23 */
0x0f, 0x1f, 0xf2, 0xff, 0xff, 0x3f, 0xff, 0xff, /* 30 [40] */
0xf4, 0xff, 0xf5, 0x6f, 0xff, 0xff, 0xff, 0xff, /* 31 */
0x0f, 0x1f, 0x23, 0xff, 0x45, 0x6f, 0xff, 0xff, /* 32 [47] */
0xf7, 0xff, 0xf8, 0x9f, 0xff, 0xff, 0xff, 0xff, /* 33 */
};
static inline signed char decode_lo (int sig)
{
unsigned char offset = (((sig >> 1) & 0x01) |
((sig >> 3) & 0x06) |
((sig >> 5) & 0x18) |
((sig >> 7) & 0x60));
unsigned char idx = lo_offset[offset];
unsigned char base, c;
if(sig & 1)
idx &= 0xf;
else
idx >>= 4;
if(idx == 0xf)
return(-1);
base = (sig >> 11) | ((sig >> 9) & 1);
zassert(base < 8, -1, "sig=%x offset=%x idx=%x base=%x\n",
sig, offset, idx, base);
idx += lo_base[base];
zassert(idx <= 0x50, -1, "sig=%x offset=%x base=%x idx=%x\n",
sig, offset, base, idx);
c = characters[idx];
dbprintf(2, " %02x(%x(%02x)/%x(%02x)) => %02x",
idx, base, lo_base[base], offset, lo_offset[offset],
(unsigned char)c);
return(c);
}
static inline signed char decode_hi (int sig)
{
unsigned char rev = (sig & 0x4400) != 0;
unsigned char idx, c;
if(rev)
sig = (((sig >> 12) & 0x000f) |
((sig >> 4) & 0x00f0) |
((sig << 4) & 0x0f00) |
((sig << 12) & 0xf000));
dbprintf(2, " rev=%x", rev != 0);
switch(sig) {
case 0x0014: idx = 0x0; break;
case 0x0025: idx = 0x1; break;
case 0x0034: idx = 0x2; break;
case 0x0134: idx = 0x3; break;
case 0x0143: idx = 0x4; break;
case 0x0243: idx = 0x5; break;
case 0x0341: idx = 0x6; break;
case 0x0352: idx = 0x7; break;
case 0x1024: idx = 0x8; break;
case 0x1114: idx = 0x9; break;
case 0x1134: idx = 0xa; break;
case 0x1242: idx = 0xb; break;
case 0x1243: idx = 0xc; break;
case 0x1441: idx = 0xd; rev = 0; break;
default: return(-1);
}
if(rev)
idx += 0xe;
c = characters[0x51 + idx];
dbprintf(2, " %02x => %02x", idx, c);
return(c);
}
static inline unsigned char calc_check (unsigned char c)
{
if(!(c & 0x80))
return(0x18);
c &= 0x7f;
if(c < 0x3d)
return((c < 0x30 && c != 0x17) ? 0x10 : 0x20);
if(c < 0x50)
return((c == 0x4d) ? 0x20 : 0x10);
return((c < 0x67) ? 0x20 : 0x10);
}
static inline signed char decode6 (zbar_decoder_t *dcode)
{
int sig;
signed char c, chk;
unsigned bars;
/* build edge signature of character */
unsigned s = dcode->code128.s6;
dbprintf(2, " s=%d", s);
if(s < 5)
return(-1);
/* calculate similar edge measurements */
sig = (get_color(dcode) == ZBAR_BAR)
? ((decode_e(get_width(dcode, 0) + get_width(dcode, 1), s, 11) << 12) |
(decode_e(get_width(dcode, 1) + get_width(dcode, 2), s, 11) << 8) |
(decode_e(get_width(dcode, 2) + get_width(dcode, 3), s, 11) << 4) |
(decode_e(get_width(dcode, 3) + get_width(dcode, 4), s, 11)))
: ((decode_e(get_width(dcode, 5) + get_width(dcode, 4), s, 11) << 12) |
(decode_e(get_width(dcode, 4) + get_width(dcode, 3), s, 11) << 8) |
(decode_e(get_width(dcode, 3) + get_width(dcode, 2), s, 11) << 4) |
(decode_e(get_width(dcode, 2) + get_width(dcode, 1), s, 11)));
if(sig < 0)
return(-1);
dbprintf(2, " sig=%04x", sig);
/* lookup edge signature */
c = (sig & 0x4444) ? decode_hi(sig) : decode_lo(sig);
if(c == -1)
return(-1);
/* character validation */
bars = (get_color(dcode) == ZBAR_BAR)
? (get_width(dcode, 0) + get_width(dcode, 2) + get_width(dcode, 4))
: (get_width(dcode, 1) + get_width(dcode, 3) + get_width(dcode, 5));
bars = bars * 11 * 4 / s;
chk = calc_check(c);
dbprintf(2, " bars=%d chk=%d", bars, chk);
if(chk - 7 > bars || bars > chk + 7)
return(-1);
return(c & 0x7f);
}
static inline unsigned char validate_checksum (zbar_decoder_t *dcode)
{
unsigned idx, sum, i, acc = 0;
unsigned char check, err;
code128_decoder_t *dcode128 = &dcode->code128;
if(dcode128->character < 3)
return(1);
/* add in irregularly weighted start character */
idx = (dcode128->direction) ? dcode128->character - 1 : 0;
sum = dcode->buf[idx];
if(sum >= 103)
sum -= 103;
/* calculate sum in reverse to avoid multiply operations */
for(i = dcode128->character - 3; i; i--) {
zassert(sum < 103, -1, "dir=%x i=%x sum=%x acc=%x %s\n",
dcode128->direction, i, sum, acc,
_zbar_decoder_buf_dump(dcode->buf, dcode128->character));
idx = (dcode128->direction) ? dcode128->character - 1 - i : i;
acc += dcode->buf[idx];
if(acc >= 103)
acc -= 103;
zassert(acc < 103, -1, "dir=%x i=%x sum=%x acc=%x %s\n",
dcode128->direction, i, sum, acc,
_zbar_decoder_buf_dump(dcode->buf, dcode128->character));
sum += acc;
if(sum >= 103)
sum -= 103;
}
/* and compare to check character */
idx = (dcode128->direction) ? 1 : dcode128->character - 2;
check = dcode->buf[idx];
dbprintf(2, " chk=%02x(%02x)", sum, check);
err = (sum != check);
if(err)
dbprintf(1, " [checksum error]\n");
return(err);
}
/* expand and decode character set C */
static inline unsigned postprocess_c (zbar_decoder_t *dcode,
unsigned start,
unsigned end,
unsigned dst)
{
unsigned i, j;
/* expand buffer to accomodate 2x set C characters (2 digits per-char) */
unsigned delta = end - start;
unsigned newlen = dcode->code128.character + delta;
if (size_buf(dcode, newlen)) {
dbprintf(2, " [overflow]\n");
return ZBAR_NONE;
}
/* relocate unprocessed data to end of buffer */
memmove(dcode->buf + start + delta, dcode->buf + start,
dcode->code128.character - start);
dcode->code128.character = newlen;
for(i = 0, j = dst; i < delta; i++, j += 2) {
/* convert each set C character into two ASCII digits */
unsigned char code = dcode->buf[start + delta + i];
dcode->buf[j] = '0';
if(code >= 50) {
code -= 50;
dcode->buf[j] += 5;
}
if(code >= 30) {
code -= 30;
dcode->buf[j] += 3;
}
if(code >= 20) {
code -= 20;
dcode->buf[j] += 2;
}
if(code >= 10) {
code -= 10;
dcode->buf[j] += 1;
}
zassert(dcode->buf[j] <= '9', delta,
"start=%x end=%x i=%x j=%x %s\n", start, end, i, j,
_zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
zassert(code <= 9, delta,
"start=%x end=%x i=%x j=%x %s\n", start, end, i, j,
_zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
dcode->buf[j + 1] = '0' + code;
}
return(delta);
}
/* resolve scan direction and convert to ASCII */
static inline unsigned char postprocess (zbar_decoder_t *dcode)
{
unsigned i, j, cexp;
unsigned char code = 0, charset;
code128_decoder_t *dcode128 = &dcode->code128;
dbprintf(2, "\n postproc len=%d", dcode128->character);
dcode->modifiers = 0;
dcode->direction = 1 - 2 * dcode128->direction;
if(dcode128->direction) {
/* reverse buffer */
dbprintf(2, " (rev)");
for(i = 0; i < dcode128->character / 2; i++) {
unsigned j = dcode128->character - 1 - i;
code = dcode->buf[i];
dcode->buf[i] = dcode->buf[j];
dcode->buf[j] = code;
}
zassert(dcode->buf[dcode128->character - 1] == STOP_REV, 1,
"dir=%x %s\n", dcode128->direction,
_zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
}
else
zassert(dcode->buf[dcode128->character - 1] == STOP_FWD, 1,
"dir=%x %s\n", dcode128->direction,
_zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
code = dcode->buf[0];
zassert(code >= START_A && code <= START_C, 1, "%s\n",
_zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
charset = code - START_A;
cexp = (code == START_C) ? 1 : 0;
dbprintf(2, " start=%c", 'A' + charset);
for(i = 1, j = 0; i < dcode128->character - 2; i++) {
unsigned char code = dcode->buf[i];
zassert(!(code & 0x80), 1,
"i=%x j=%x code=%02x charset=%x cexp=%x %s\n",
i, j, code, charset, cexp,
_zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
if((charset & 0x2) && (code < 100))
/* defer character set C for expansion */
continue;
else if(code < 0x60) {
/* convert character set B to ASCII */
code = code + 0x20;
if((!charset || (charset == 0x81)) && (code >= 0x60))
/* convert character set A to ASCII */
code -= 0x60;
dcode->buf[j++] = code;
if(charset & 0x80)
charset &= 0x7f;
}
else {
dbprintf(2, " %02x", code);
if(charset & 0x2) {
unsigned delta;
/* expand character set C to ASCII */
zassert(cexp, 1, "i=%x j=%x code=%02x charset=%x cexp=%x %s\n",
i, j, code, charset, cexp,
_zbar_decoder_buf_dump(dcode->buf,
dcode->code128.character));
delta = postprocess_c(dcode, cexp, i, j);
i += delta;
j += delta * 2;
cexp = 0;
}
if(code < CODE_C) {
if(code == SHIFT)
charset |= 0x80;
else if(code == FNC2) {
/* FIXME FNC2 - message append */
}
else if(code == FNC3) {
/* FIXME FNC3 - initialize */
}
}
else if(code == FNC1) {
/* FNC1 - Code 128 subsets or ASCII 0x1d */
if(i == 1)
dcode->modifiers |= MOD(ZBAR_MOD_GS1);
else if(i == 2)
dcode->modifiers |= MOD(ZBAR_MOD_AIM);
else if(i < dcode->code128.character - 3)
dcode->buf[j++] = 0x1d;
/*else drop trailing FNC1 */
}
else if(code >= START_A) {
dbprintf(1, " [truncated]\n");
return(1);
}
else {
unsigned char newset = CODE_A - code;
zassert(code >= CODE_C && code <= CODE_A, 1,
"i=%x j=%x code=%02x charset=%x cexp=%x %s\n",
i, j, code, charset, cexp,
_zbar_decoder_buf_dump(dcode->buf,
dcode->code128.character));
if(newset != charset)
charset = newset;
else {
/* FIXME FNC4 - extended ASCII */
}
}
if(charset & 0x2)
cexp = i + 1;
}
}
if(charset & 0x2) {
zassert(cexp, 1, "i=%x j=%x code=%02x charset=%x cexp=%x %s\n",
i, j, code, charset, cexp,
_zbar_decoder_buf_dump(dcode->buf,
dcode->code128.character));
j += postprocess_c(dcode, cexp, i, j) * 2;
}
zassert(j < dcode->buf_alloc, 1, "j=%02x %s\n", j,
_zbar_decoder_buf_dump(dcode->buf, dcode->code128.character));
dcode->buflen = j;
dcode->buf[j] = '\0';
dcode->code128.character = j;
return(0);
}
zbar_symbol_type_t _zbar_decode_code128 (zbar_decoder_t *dcode)
{
code128_decoder_t *dcode128 = &dcode->code128;
signed char c;
/* update latest character width */
dcode128->s6 -= get_width(dcode, 6);
dcode128->s6 += get_width(dcode, 0);
if((dcode128->character < 0)
? get_color(dcode) != ZBAR_SPACE
: (/* process every 6th element of active symbol */
++dcode128->element != 6 ||
/* decode color based on direction */
get_color(dcode) != dcode128->direction))
return(0);
dcode128->element = 0;
dbprintf(2, " code128[%c%02d+%x]:",
(dcode128->direction) ? '<' : '>',
dcode128->character, dcode128->element);
c = decode6(dcode);
if(dcode128->character < 0) {
unsigned qz;
dbprintf(2, " c=%02x", c);
if(c < START_A || c > STOP_REV || c == STOP_FWD) {
dbprintf(2, " [invalid]\n");
return(0);
}
qz = get_width(dcode, 6);
if(qz && qz < (dcode128->s6 * 3) / 4) {
dbprintf(2, " [invalid qz %d]\n", qz);
return(0);
}
/* decoded valid start/stop */
/* initialize state */
dcode128->character = 1;
if(c == STOP_REV) {
dcode128->direction = ZBAR_BAR;
dcode128->element = 7;
}
else
dcode128->direction = ZBAR_SPACE;
dcode128->start = c;
dcode128->width = dcode128->s6;
dbprintf(2, " dir=%x [valid start]\n", dcode128->direction);
return(0);
}
else if(c < 0 || size_buf(dcode, dcode128->character + 1)) {
dbprintf(1, (c < 0) ? " [aborted]\n" : " [overflow]\n");
if(dcode128->character > 1)
release_lock(dcode, ZBAR_CODE128);
dcode128->character = -1;
return(0);
}
else {
unsigned dw;
if(dcode128->width > dcode128->s6)
dw = dcode128->width - dcode128->s6;
else
dw = dcode128->s6 - dcode128->width;
dw *= 4;
if(dw > dcode128->width) {
dbprintf(1, " [width var]\n");
if(dcode128->character > 1)
release_lock(dcode, ZBAR_CODE128);
dcode128->character = -1;
return(0);
}
}
dcode128->width = dcode128->s6;
zassert(dcode->buf_alloc > dcode128->character, 0,
"alloc=%x idx=%x c=%02x %s\n",
dcode->buf_alloc, dcode128->character, c,
_zbar_decoder_buf_dump(dcode->buf, dcode->buf_alloc));
if(dcode128->character == 1) {
/* lock shared resources */
if(acquire_lock(dcode, ZBAR_CODE128)) {
dcode128->character = -1;
return(0);
}
dcode->buf[0] = dcode128->start;
}
dcode->buf[dcode128->character++] = c;
if(dcode128->character > 2 &&
((dcode128->direction)
? c >= START_A && c <= START_C
: c == STOP_FWD)) {
/* FIXME STOP_FWD should check extra bar (and QZ!) */
zbar_symbol_type_t sym = ZBAR_CODE128;
if(validate_checksum(dcode) || postprocess(dcode))
sym = ZBAR_NONE;
else if(dcode128->character < CFG(*dcode128, ZBAR_CFG_MIN_LEN) ||
(CFG(*dcode128, ZBAR_CFG_MAX_LEN) > 0 &&
dcode128->character > CFG(*dcode128, ZBAR_CFG_MAX_LEN))) {
dbprintf(2, " [invalid len]\n");
sym = ZBAR_NONE;
}
else
dbprintf(2, " [valid end]\n");
dcode128->character = -1;
if(!sym)
release_lock(dcode, ZBAR_CODE128);
return(sym);
}
dbprintf(2, "\n");
return(0);
}
+51
View File
@@ -0,0 +1,51 @@
/*------------------------------------------------------------------------
* Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#ifndef _CODE128_H_
#define _CODE128_H_
/* Code 128 specific decode state */
typedef struct code128_decoder_s {
unsigned direction : 1; /* scan direction: 0=fwd/space, 1=rev/bar */
unsigned element : 3; /* element offset 0-5 */
int character : 12; /* character position in symbol */
unsigned char start; /* start character */
unsigned s6; /* character width */
unsigned width; /* last character width */
unsigned config;
int configs[NUM_CFGS]; /* int valued configurations */
} code128_decoder_t;
/* reset Code 128 specific state */
static inline void code128_reset (code128_decoder_t *dcode128)
{
dcode128->direction = 0;
dcode128->element = 0;
dcode128->character = -1;
dcode128->s6 = 0;
}
/* decode Code 128 symbols */
zbar_symbol_type_t _zbar_decode_code128(zbar_decoder_t *dcode);
#endif
+344
View File
@@ -0,0 +1,344 @@
/*------------------------------------------------------------------------
* Copyright 2008-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#include <zbar_config.h>
#include <string.h> /* memmove */
#include <zbar.h>
#ifdef DEBUG_CODE39
# define DEBUG_LEVEL (DEBUG_CODE39)
#endif
#include "debug.h"
#include "decoder.h"
#define NUM_CHARS (0x2c)
static const unsigned char code39_hi[32] = {
0x80 | 0x00, /* 2 next */
0x40 | 0x02, /* 4 */
0x80 | 0x06, /* 2 next */
0xc0 | 0x08, /* 2 skip */
0x40 | 0x0a, /* 4 */
0x80 | 0x0e, /* 2 next */
0xc0 | 0x10, /* 2 skip */
0x00 | 0x12, /* direct */
0x80 | 0x13, /* 2 next */
0xc0 | 0x15, /* 2 skip */
0x80 | 0x17, /* 2 next */
0xff,
0xc0 | 0x19, /* 2 skip */
0x00 | 0x1b, /* direct */
0xff,
0xff,
0x40 | 0x1c, /* 4 */
0x80 | 0x20, /* 2 next */
0xc0 | 0x22, /* 2 skip */
0x00 | 0x24, /* direct */
0x80 | 0x25, /* 2 next */
0xff,
0x00 | 0x27, /* direct */
0xff,
0xc0 | 0x28, /* 2 skip */
0x00 | 0x2a, /* direct */
0xff,
0xff,
0x00 | 0x2b, /* direct */
0xff,
0xff,
0xff,
};
typedef struct char39_s {
unsigned char chk, rev, fwd;
} char39_t;
static const char39_t code39_encodings[NUM_CHARS] = {
{ 0x07, 0x1a, 0x20 }, /* 00 */
{ 0x0d, 0x10, 0x03 }, /* 01 */
{ 0x13, 0x17, 0x22 }, /* 02 */
{ 0x16, 0x1d, 0x23 }, /* 03 */
{ 0x19, 0x0d, 0x05 }, /* 04 */
{ 0x1c, 0x13, 0x06 }, /* 05 */
{ 0x25, 0x07, 0x0c }, /* 06 */
{ 0x2a, 0x2a, 0x27 }, /* 07 */
{ 0x31, 0x04, 0x0e }, /* 08 */
{ 0x34, 0x00, 0x0f }, /* 09 */
{ 0x43, 0x15, 0x25 }, /* 0a */
{ 0x46, 0x1c, 0x26 }, /* 0b */
{ 0x49, 0x0b, 0x08 }, /* 0c */
{ 0x4c, 0x12, 0x09 }, /* 0d */
{ 0x52, 0x19, 0x2b }, /* 0e */
{ 0x58, 0x0f, 0x00 }, /* 0f */
{ 0x61, 0x02, 0x11 }, /* 10 */
{ 0x64, 0x09, 0x12 }, /* 11 */
{ 0x70, 0x06, 0x13 }, /* 12 */
{ 0x85, 0x24, 0x16 }, /* 13 */
{ 0x8a, 0x29, 0x28 }, /* 14 */
{ 0x91, 0x21, 0x18 }, /* 15 */
{ 0x94, 0x2b, 0x19 }, /* 16 */
{ 0xa2, 0x28, 0x29 }, /* 17 */
{ 0xa8, 0x27, 0x2a }, /* 18 */
{ 0xc1, 0x1f, 0x1b }, /* 19 */
{ 0xc4, 0x26, 0x1c }, /* 1a */
{ 0xd0, 0x23, 0x1d }, /* 1b */
{ 0x03, 0x14, 0x1e }, /* 1c */
{ 0x06, 0x1b, 0x1f }, /* 1d */
{ 0x09, 0x0a, 0x01 }, /* 1e */
{ 0x0c, 0x11, 0x02 }, /* 1f */
{ 0x12, 0x18, 0x21 }, /* 20 */
{ 0x18, 0x0e, 0x04 }, /* 21 */
{ 0x21, 0x01, 0x0a }, /* 22 */
{ 0x24, 0x08, 0x0b }, /* 23 */
{ 0x30, 0x05, 0x0d }, /* 24 */
{ 0x42, 0x16, 0x24 }, /* 25 */
{ 0x48, 0x0c, 0x07 }, /* 26 */
{ 0x60, 0x03, 0x10 }, /* 27 */
{ 0x81, 0x1e, 0x14 }, /* 28 */
{ 0x84, 0x25, 0x15 }, /* 29 */
{ 0x90, 0x22, 0x17 }, /* 2a */
{ 0xc0, 0x20, 0x1a }, /* 2b */
};
static const unsigned char code39_characters[NUM_CHARS] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%*";
static inline unsigned char code39_decode1 (unsigned char enc,
unsigned e,
unsigned s)
{
unsigned char E = decode_e(e, s, 72);
if(E > 18)
return(0xff);
enc <<= 1;
if(E > 6) {
enc |= 1;
dbprintf(2, "1");
}
else
dbprintf(2, "0");
return(enc);
}
static inline signed char code39_decode9 (zbar_decoder_t *dcode)
{
code39_decoder_t *dcode39 = &dcode->code39;
if(dcode39->s9 < 9)
return(-1);
/* threshold bar width ratios */
unsigned char i, enc = 0;
for(i = 0; i < 5; i++) {
enc = code39_decode1(enc, get_width(dcode, i), dcode39->s9);
if(enc == 0xff)
return(-1);
}
zassert(enc < 0x20, -1, " enc=%x s9=%x\n", enc, dcode39->s9);
/* lookup first 5 encoded widths for coarse decode */
unsigned char idx = code39_hi[enc];
if(idx == 0xff)
return(-1);
/* encode remaining widths (NB first encoded width is lost) */
for(; i < 9; i++) {
enc = code39_decode1(enc, get_width(dcode, i), dcode39->s9);
if(enc == 0xff)
return(-1);
}
if((idx & 0xc0) == 0x80)
idx = (idx & 0x3f) + ((enc >> 3) & 1);
else if((idx & 0xc0) == 0xc0)
idx = (idx & 0x3f) + ((enc >> 2) & 1);
else if(idx & 0xc0)
idx = (idx & 0x3f) + ((enc >> 2) & 3);
zassert(idx < 0x2c, -1, " idx=%x enc=%x s9=%x\n", idx, enc, dcode39->s9);
const char39_t *c = &code39_encodings[idx];
dbprintf(2, " i=%02x chk=%02x c=%02x/%02x", idx, c->chk, c->fwd, c->rev);
if(enc != c->chk)
return(-1);
dcode39->width = dcode39->s9;
return((dcode39->direction) ? c->rev : c->fwd);
}
static inline signed char code39_decode_start (zbar_decoder_t *dcode)
{
code39_decoder_t *dcode39 = &dcode->code39;
dbprintf(2, " s=%d ", dcode39->s9);
signed char c = code39_decode9(dcode);
if(c != 0x19 && c != 0x2b) {
dbprintf(2, "\n");
return(ZBAR_NONE);
}
dcode39->direction ^= (c == 0x19);
/* check leading quiet zone - spec is 10x */
unsigned quiet = get_width(dcode, 9);
if(quiet && quiet < dcode39->s9 / 2) {
dbprintf(2, " [invalid quiet]\n");
return(ZBAR_NONE);
}
dcode39->element = 9;
dcode39->character = 0;
dbprintf(1, " dir=%x [valid start]\n", dcode39->direction);
return(ZBAR_PARTIAL);
}
static inline int code39_postprocess (zbar_decoder_t *dcode)
{
code39_decoder_t *dcode39 = &dcode->code39;
dcode->direction = 1 - 2 * dcode39->direction;
int i;
if(dcode39->direction) {
/* reverse buffer */
dbprintf(2, " (rev)");
for(i = 0; i < dcode39->character / 2; i++) {
unsigned j = dcode39->character - 1 - i;
char code = dcode->buf[i];
dcode->buf[i] = dcode->buf[j];
dcode->buf[j] = code;
}
}
for(i = 0; i < dcode39->character; i++)
dcode->buf[i] = ((dcode->buf[i] < 0x2b)
? code39_characters[(unsigned)dcode->buf[i]]
: '?');
zassert(i < dcode->buf_alloc, -1, "i=%02x %s\n", i,
_zbar_decoder_buf_dump(dcode->buf, dcode39->character));
dcode->buflen = i;
dcode->buf[i] = '\0';
dcode->modifiers = 0;
return(0);
}
static inline int
check_width (unsigned ref,
unsigned w)
{
unsigned dref = ref;
ref *= 4;
w *= 4;
return(ref - dref <= w && w <= ref + dref);
}
zbar_symbol_type_t _zbar_decode_code39 (zbar_decoder_t *dcode)
{
code39_decoder_t *dcode39 = &dcode->code39;
/* update latest character width */
dcode39->s9 -= get_width(dcode, 9);
dcode39->s9 += get_width(dcode, 0);
if(dcode39->character < 0) {
if(get_color(dcode) != ZBAR_BAR)
return(ZBAR_NONE);
dbprintf(2, " code39:");
return(code39_decode_start(dcode));
}
if(++dcode39->element < 9)
return(ZBAR_NONE);
dbprintf(2, " code39[%c%02d+%x]",
(dcode39->direction) ? '<' : '>',
dcode39->character, dcode39->element);
if(dcode39->element == 10) {
unsigned space = get_width(dcode, 0);
if(dcode39->character &&
dcode->buf[dcode39->character - 1] == 0x2b) { /* STOP */
/* trim STOP character */
dcode39->character--;
zbar_symbol_type_t sym = ZBAR_NONE;
/* trailing quiet zone check */
if(space && space < dcode39->width / 2)
dbprintf(2, " [invalid qz]\n");
else if(dcode39->character < CFG(*dcode39, ZBAR_CFG_MIN_LEN) ||
(CFG(*dcode39, ZBAR_CFG_MAX_LEN) > 0 &&
dcode39->character > CFG(*dcode39, ZBAR_CFG_MAX_LEN)))
dbprintf(2, " [invalid len]\n");
else if(!code39_postprocess(dcode)) {
/* FIXME checksum */
dbprintf(2, " [valid end]\n");
sym = ZBAR_CODE39;
}
dcode39->character = -1;
if(!sym)
release_lock(dcode, ZBAR_CODE39);
return(sym);
}
if(space > dcode39->width / 2) {
/* inter-character space check failure */
dbprintf(2, " ics>%d [invalid ics]", dcode39->width);
if(dcode39->character)
release_lock(dcode, ZBAR_CODE39);
dcode39->character = -1;
}
dcode39->element = 0;
dbprintf(2, "\n");
return(ZBAR_NONE);
}
dbprintf(2, " s=%d ", dcode39->s9);
if(!check_width(dcode39->width, dcode39->s9)) {
dbprintf(2, " [width]\n");
if(dcode39->character)
release_lock(dcode, ZBAR_CODE39);
dcode39->character = -1;
return(ZBAR_NONE);
}
signed char c = code39_decode9(dcode);
dbprintf(2, " c=%d", c);
/* lock shared resources */
if(!dcode39->character && acquire_lock(dcode, ZBAR_CODE39)) {
dcode39->character = -1;
return(ZBAR_PARTIAL);
}
if(c < 0 || size_buf(dcode, dcode39->character + 1)) {
dbprintf(1, (c < 0) ? " [aborted]\n" : " [overflow]\n");
release_lock(dcode, ZBAR_CODE39);
dcode39->character = -1;
return(ZBAR_NONE);
}
else {
zassert(c < 0x2c, ZBAR_NONE, "c=%02x s9=%x\n", c, dcode39->s9);
dbprintf(2, "\n");
}
dcode->buf[dcode39->character++] = c;
return(ZBAR_NONE);
}
+50
View File
@@ -0,0 +1,50 @@
/*------------------------------------------------------------------------
* Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#ifndef _CODE39_H_
#define _CODE39_H_
/* Code 39 specific decode state */
typedef struct code39_decoder_s {
unsigned direction : 1; /* scan direction: 0=fwd, 1=rev */
unsigned element : 4; /* element offset 0-8 */
int character : 12; /* character position in symbol */
unsigned s9; /* current character width */
unsigned width; /* last character width */
unsigned config;
int configs[NUM_CFGS]; /* int valued configurations */
} code39_decoder_t;
/* reset Code 39 specific state */
static inline void code39_reset (code39_decoder_t *dcode39)
{
dcode39->direction = 0;
dcode39->element = 0;
dcode39->character = -1;
dcode39->s9 = 0;
}
/* decode Code 39 symbols */
zbar_symbol_type_t _zbar_decode_code39(zbar_decoder_t *dcode);
#endif
+400
View File
@@ -0,0 +1,400 @@
/*------------------------------------------------------------------------
* Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#include <zbar_config.h>
#include <zbar.h>
#ifdef DEBUG_CODE93
# define DEBUG_LEVEL (DEBUG_CODE93)
#endif
#include "debug.h"
#include "decoder.h"
static const signed char code93_hash[0x40] = {
0x0f, 0x2b, 0x30, 0x38, 0x13, 0x1b, 0x11, 0x2a,
0x0a, -1, 0x2f, 0x0f, 0x38, 0x38, 0x2f, 0x37,
0x24, 0x3a, 0x1b, 0x36, 0x18, 0x26, 0x02, 0x2c,
0x2b, 0x05, 0x21, 0x3b, 0x04, 0x15, 0x12, 0x0c,
0x00, 0x26, 0x23, 0x00, -1, 0x2e, 0x3f, 0x13,
0x2e, 0x36, -1, 0x08, 0x09, -1, 0x15, 0x14,
-1, 0x00, 0x21, 0x3b, -1, 0x33, 0x00, -1,
0x2d, 0x0c, 0x1b, 0x0a, 0x3f, 0x3f, 0x29, 0x1c,
};
static inline int
check_width (unsigned cur,
unsigned prev)
{
unsigned dw;
if(prev > cur)
dw = prev - cur;
else
dw = cur - prev;
dw *= 4;
return(dw > prev);
}
static inline int
encode6 (zbar_decoder_t *dcode)
{
/* build edge signature of character */
unsigned s = dcode->s6;
int sig = 0, i;
dbprintf(2, " s=%d ", s);
if(s < 9)
return(-1);
for(i = 6; --i > 0; ) {
unsigned c = decode_e(pair_width(dcode, i), s, 9);
if(c > 3)
return(-1);
sig = (sig << 2) | c;
dbprintf(2, "%d", c);
}
dbprintf(2, " sig=%03x", sig);
return(sig);
}
static inline int
validate_sig (int sig)
{
int i, sum = 0, emin = 0, sig0 = 0, sig1 = 0;
dbprintf(3, " sum=0");
for(i = 3; --i >= 0; ) {
int e = sig & 3;
sig >>= 2;
sum = e - sum;
sig1 <<= 4;
sig1 += sum;
dbprintf(3, "%d", sum);
if(!i)
break;
e = sig & 3;
sig >>= 2;
sum = e - sum;
sig0 <<= 4;
if(emin > sum)
emin = sum;
sig0 += sum;
dbprintf(3, "%d", sum);
}
dbprintf(3, " emin=%d sig=%03x/%03x", emin, sig1 & 0xfff, sig0 & 0xfff);
emin = emin + (emin << 4) + (emin << 8);
sig0 -= emin;
sig1 += emin;
dbprintf(3, "=%03x/%03x", sig1 & 0xfff, sig0 & 0xfff);
return((sig0 | sig1) & 0x888);
}
static inline int
decode6 (zbar_decoder_t *dcode)
{
int sig = encode6(dcode);
int g0, g1, c;
if(sig < 0 ||
(sig & 0x3) + ((sig >> 4) & 0x3) + ((sig >> 8) & 0x3) != 3 ||
validate_sig(sig))
return(-1);
if(dcode->code93.direction) {
/* reverse signature */
unsigned tmp = sig & 0x030;
sig = ((sig & 0x3c0) >> 6) | ((sig & 0x00f) << 6);
sig = ((sig & 0x30c) >> 2) | ((sig & 0x0c3) << 2) | tmp;
}
g0 = code93_hash[(sig - (sig >> 4)) & 0x3f];
g1 = code93_hash[((sig >> 2) - (sig >> 7)) & 0x3f];
zassert(g0 >= 0 && g1 >= 0, -1,
"dir=%x sig=%03x g0=%03x g1=%03x %s\n",
dcode->code93.direction, sig, g0, g1,
_zbar_decoder_buf_dump(dcode->buf, dcode->code93.character));
c = (g0 + g1) & 0x3f;
dbprintf(2, " g0=%x g1=%x c=%02x", g0, g1, c);
return(c);
}
static inline zbar_symbol_type_t
decode_start (zbar_decoder_t *dcode)
{
code93_decoder_t *dcode93 = &dcode->code93;
unsigned dir, qz, s = dcode->s6;
int c;
dbprintf(2, " code93:");
c = encode6(dcode);
if(c < 0 || (c != 0x00f && c != 0x0f0))
return(ZBAR_NONE);
dir = (c >> 7);
if(dir) {
if(decode_e(pair_width(dcode, 0), s, 9))
return(ZBAR_NONE);
qz = get_width(dcode, 8);
}
qz = get_width(dcode, 7);
if(qz && qz < (s * 3) / 4) {
dbprintf(2, " [invalid qz %d]", qz);
return(ZBAR_NONE);
}
/* decoded valid start/stop - initialize state */
dcode93->direction = dir;
dcode93->element = (!dir) ? 0 : 7;
dcode93->character = 0;
dcode93->width = s;
dbprintf(2, " dir=%x [valid start]", dir);
return(ZBAR_PARTIAL);
}
static inline zbar_symbol_type_t
decode_abort (zbar_decoder_t *dcode,
const char *reason)
{
code93_decoder_t *dcode93 = &dcode->code93;
if(dcode93->character > 1)
release_lock(dcode, ZBAR_CODE93);
dcode93->character = -1;
if(reason)
dbprintf(1, " [%s]\n", reason);
return(ZBAR_NONE);
}
static inline zbar_symbol_type_t
check_stop (zbar_decoder_t *dcode)
{
code93_decoder_t *dcode93 = &dcode->code93;
unsigned n = dcode93->character, s = dcode->s6;
int max_len = CFG(*dcode93, ZBAR_CFG_MAX_LEN);
if(n < 2 ||
n < CFG(*dcode93, ZBAR_CFG_MIN_LEN) ||
(max_len && n > max_len))
return(decode_abort(dcode, "invalid len"));
if(dcode93->direction) {
unsigned qz = get_width(dcode, 0);
if(qz && qz < (s * 3) / 4)
return(decode_abort(dcode, "invalid qz"));
}
else if(decode_e(pair_width(dcode, 0), s, 9))
/* FIXME forward-trailing QZ check */
return(decode_abort(dcode, "invalid stop"));
return(ZBAR_CODE93);
}
#define CHKMOD (47)
static inline int
plusmod47 (int acc,
int add)
{
acc += add;
if(acc >= CHKMOD)
acc -= CHKMOD;
return(acc);
}
static inline int
validate_checksums (zbar_decoder_t *dcode)
{
code93_decoder_t *dcode93 = &dcode->code93;
unsigned d, i, n = dcode93->character;
unsigned sum_c = 0, acc_c = 0, i_c = (n - 2) % 20;
unsigned sum_k = 0, acc_k = 0, i_k = (n - 1) % 15;
for(i = 0; i < n - 2; i++) {
d = dcode->buf[(dcode93->direction) ? n - 1 - i : i];
if(!i_c--) {
acc_c = 0;
i_c = 19;
}
acc_c = plusmod47(acc_c, d);
sum_c = plusmod47(sum_c, acc_c);
if(!i_k--) {
acc_k = 0;
i_k = 14;
}
acc_k = plusmod47(acc_k, d);
sum_k = plusmod47(sum_k, acc_k);
}
d = dcode->buf[(dcode93->direction) ? 1 : n - 2];
dbprintf(2, " C=%02x?=%02x", d, sum_c);
if(d != sum_c)
return(1);
acc_k = plusmod47(acc_k, sum_c);
sum_k = plusmod47(sum_k, acc_k);
d = dcode->buf[(dcode93->direction) ? 0 : n - 1];
dbprintf(2, " K=%02x?=%02x", d, sum_k);
if(d != sum_k)
return(1);
return(0);
}
/* resolve scan direction and convert to ASCII */
static inline int
postprocess (zbar_decoder_t *dcode)
{
code93_decoder_t *dcode93 = &dcode->code93;
unsigned i, j, n = dcode93->character;
static const unsigned char code93_graph[] = "-. $/+%";
static const unsigned char code93_s2[] =
"\x1b\x1c\x1d\x1e\x1f;<=>?[\\]^_{|}~\x7f\x00\x40`\x7f\x7f\x7f";
dbprintf(2, "\n postproc len=%d", n);
dcode->direction = 1 - 2 * dcode93->direction;
if(dcode93->direction) {
/* reverse buffer */
dbprintf(2, " (rev)");
for(i = 0; i < n / 2; i++) {
unsigned j = n - 1 - i;
unsigned char d = dcode->buf[i];
dcode->buf[i] = dcode->buf[j];
dcode->buf[j] = d;
}
}
n -= 2;
for(i = 0, j = 0; i < n; ) {
unsigned char d = dcode->buf[i++];
if(d < 0xa)
d = '0' + d;
else if(d < 0x24)
d = 'A' + d - 0xa;
else if(d < 0x2b)
d = code93_graph[d - 0x24];
else {
unsigned shift = d;
zassert(shift < 0x2f, -1, "%s\n",
_zbar_decoder_buf_dump(dcode->buf, dcode93->character));
d = dcode->buf[i++];
if(d < 0xa || d >= 0x24)
return(1);
d -= 0xa;
switch(shift)
{
case 0x2b: d++; break;
case 0x2c: d = code93_s2[d]; break;
case 0x2d: d += 0x21; break;
case 0x2e: d += 0x61; break;
default: return(1);
}
}
dcode->buf[j++] = d;
}
zassert(j < dcode->buf_alloc, 1,
"j=%02x %s\n", j,
_zbar_decoder_buf_dump(dcode->buf, dcode->code93.character));
dcode->buflen = j;
dcode->buf[j] = '\0';
dcode->modifiers = 0;
return(0);
}
zbar_symbol_type_t
_zbar_decode_code93 (zbar_decoder_t *dcode)
{
code93_decoder_t *dcode93 = &dcode->code93;
int c;
if(dcode93->character < 0) {
zbar_symbol_type_t sym;
if(get_color(dcode) != ZBAR_BAR)
return(ZBAR_NONE);
sym = decode_start(dcode);
dbprintf(2, "\n");
return(sym);
}
if(/* process every 6th element of active symbol */
++dcode93->element != 6 ||
/* decode color based on direction */
get_color(dcode) == dcode93->direction)
return(ZBAR_NONE);
dcode93->element = 0;
dbprintf(2, " code93[%c%02d+%x]:",
(dcode93->direction) ? '<' : '>',
dcode93->character, dcode93->element);
if(check_width(dcode->s6, dcode93->width))
return(decode_abort(dcode, "width var"));
c = decode6(dcode);
if(c < 0)
return(decode_abort(dcode, "aborted"));
if(c == 0x2f) {
if(!check_stop(dcode))
return(ZBAR_NONE);
if(validate_checksums(dcode))
return(decode_abort(dcode, "checksum error"));
if(postprocess(dcode))
return(decode_abort(dcode, "invalid encoding"));
dbprintf(2, " [valid end]\n");
dbprintf(3, " %s\n",
_zbar_decoder_buf_dump(dcode->buf, dcode93->character));
dcode93->character = -1;
return(ZBAR_CODE93);
}
if(size_buf(dcode, dcode93->character + 1))
return(decode_abort(dcode, "overflow"));
dcode93->width = dcode->s6;
if(dcode93->character == 1) {
/* lock shared resources */
if(acquire_lock(dcode, ZBAR_CODE93))
return(decode_abort(dcode, NULL));
dcode->buf[0] = dcode93->buf;
}
if(!dcode93->character)
dcode93->buf = c;
else
dcode->buf[dcode93->character] = c;
dcode93->character++;
dbprintf(2, "\n");
return(ZBAR_NONE);
}
+49
View File
@@ -0,0 +1,49 @@
/*------------------------------------------------------------------------
* Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#ifndef _CODE93_H_
#define _CODE93_H_
/* Code 93 specific decode state */
typedef struct code93_decoder_s {
unsigned direction : 1; /* scan direction: 0=fwd/space, 1=rev/bar */
unsigned element : 3; /* element offset 0-5 */
int character : 12; /* character position in symbol */
unsigned width; /* last character width */
unsigned char buf; /* first character */
unsigned config;
int configs[NUM_CFGS]; /* int valued configurations */
} code93_decoder_t;
/* reset Code 93 specific state */
static inline void code93_reset (code93_decoder_t *dcode93)
{
dcode93->direction = 0;
dcode93->element = 0;
dcode93->character = -1;
}
/* decode Code 93 symbols */
zbar_symbol_type_t _zbar_decode_code93(zbar_decoder_t *dcode);
#endif
File diff suppressed because it is too large Load Diff
+80
View File
@@ -0,0 +1,80 @@
/*------------------------------------------------------------------------
* Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#ifndef _DATABAR_H_
#define _DATABAR_H_
#define DATABAR_MAX_SEGMENTS 32
/* active DataBar (partial) segment entry */
typedef struct databar_segment_s {
signed finder : 5; /* finder pattern */
unsigned exp : 1; /* DataBar expanded finder */
unsigned color : 1; /* finder coloring */
unsigned side : 1; /* data character side of finder */
unsigned partial : 1; /* unpaired partial segment */
unsigned count : 7; /* times encountered */
unsigned epoch : 8; /* age, in characters scanned */
unsigned check : 8; /* bar checksum */
signed short data; /* decoded character data */
unsigned short width; /* measured width of finder (14 modules) */
} databar_segment_t;
/* DataBar specific decode state */
typedef struct databar_decoder_s {
unsigned config; /* decoder configuration flags */
unsigned config_exp;
unsigned csegs : 8; /* allocated segments */
unsigned epoch : 8; /* current scan */
databar_segment_t *segs; /* active segment list */
signed char chars[16]; /* outstanding character indices */
} databar_decoder_t;
/* reset DataBar segment decode state */
static inline void databar_new_scan (databar_decoder_t *db)
{
int i;
for(i = 0; i < 16; i++)
if(db->chars[i] >= 0) {
databar_segment_t *seg = db->segs + db->chars[i];
if(seg->partial)
seg->finder = -1;
db->chars[i] = -1;
}
}
/* reset DataBar accumulated segments */
static inline void databar_reset (databar_decoder_t *db)
{
int i, n = db->csegs;
databar_new_scan(db);
for(i = 0; i < n; i++)
db->segs[i].finder = -1;
}
/* decode DataBar symbols */
zbar_symbol_type_t _zbar_decode_databar(zbar_decoder_t *dcode);
#endif
+784
View File
@@ -0,0 +1,784 @@
/*------------------------------------------------------------------------
* Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#include <zbar_config.h>
#include <zbar.h>
#ifdef DEBUG_EAN
# define DEBUG_LEVEL (DEBUG_EAN)
#endif
#include "debug.h"
#include "decoder.h"
/* partial decode symbol location */
typedef enum symbol_partial_e {
EAN_LEFT = 0x0000,
EAN_RIGHT = 0x1000,
} symbol_partial_t;
/* convert compact encoded D2E1E2 to character (bit4 is parity) */
static const unsigned char digits[] = { /* E1 E2 */
0x06, 0x10, 0x04, 0x13, /* 2 2-5 */
0x19, 0x08, 0x11, 0x05, /* 3 2-5 (d2 <= thr) */
0x09, 0x12, 0x07, 0x15, /* 4 2-5 (d2 <= thr) */
0x16, 0x00, 0x14, 0x03, /* 5 2-5 */
0x18, 0x01, 0x02, 0x17, /* E1E2=43,44,33,34 (d2 > thr) */
};
static const unsigned char parity_decode[] = {
0xf0, /* [xx] BBBBBB = RIGHT half EAN-13 */
/* UPC-E check digit encoding */
0xff,
0xff,
0x0f, /* [07] BBBAAA = 0 */
0xff,
0x1f, /* [0b] BBABAA = 1 */
0x2f, /* [0d] BBAABA = 2 */
0xf3, /* [0e] BBAAAB = 3 */
0xff,
0x4f, /* [13] BABBAA = 4 */
0x7f, /* [15] BABABA = 7 */
0xf8, /* [16] BABAAB = 8 */
0x5f, /* [19] BAABBA = 5 */
0xf9, /* [1a] BAABAB = 9 */
0xf6, /* [1c] BAAABB = 6 */
0xff,
/* LEFT half EAN-13 leading digit */
0xff,
0x6f, /* [23] ABBBAA = 6 */
0x9f, /* [25] ABBABA = 9 */
0xf5, /* [26] ABBAAB = 5 */
0x8f, /* [29] ABABBA = 8 */
0xf7, /* [2a] ABABAB = 7 */
0xf4, /* [2c] ABAABB = 4 */
0xff,
0x3f, /* [31] AABBBA = 3 */
0xf2, /* [32] AABBAB = 2 */
0xf1, /* [34] AABABB = 1 */
0xff,
0xff,
0xff,
0xff,
0x0f, /* [3f] AAAAAA = 0 */
};
#ifdef DEBUG_EAN
static unsigned char debug_buf[0x18];
static inline const unsigned char *dsprintbuf(ean_decoder_t *ean)
{
int i;
for(i = 0; i < 7; i++)
debug_buf[i] = ((ean->buf[0] < 0 || ean->buf[i] < 0)
? '-'
: ean->buf[i] + '0');
debug_buf[i] = ' ';
for(; i < 13; i++)
debug_buf[i + 1] = ((ean->buf[7] < 0 || ean->buf[i] < 0)
? '-'
: ean->buf[i] + '0');
debug_buf[i + 1] = ' ';
for(; i < 18; i++)
debug_buf[i + 2] = ((ean->buf[13] < 0 || ean->buf[i] < 0)
? '-'
: ean->buf[i] + '0');
debug_buf[i + 2] = '\0';
return(debug_buf);
}
#endif
static inline int check_width (unsigned w0,
unsigned w1)
{
unsigned dw0 = w0;
w0 *= 8;
w1 *= 8;
return(w0 - dw0 <= w1 && w1 <= w0 + dw0);
}
/* evaluate previous N (>= 2) widths as auxiliary pattern,
* using preceding 4 as character width
*/
static inline signed char aux_end (zbar_decoder_t *dcode,
unsigned char fwd)
{
signed char code, i;
/* reference width from previous character */
unsigned s = calc_s(dcode, 4 + fwd, 4);
/* check quiet zone */
unsigned qz = get_width(dcode, 0);
if(!fwd && qz && qz <= s * 3 / 4) {
dbprintf(2, " [invalid quiet]");
return(-1);
}
dbprintf(2, " (");
code = 0;
for(i = 1 - fwd; i < 3 + fwd; i++) {
unsigned e = get_width(dcode, i) + get_width(dcode, i + 1);
dbprintf(2, " %d", e);
code = (code << 2) | decode_e(e, s, 7);
if(code < 0) {
dbprintf(2, " [invalid end guard]");
return(-1);
}
}
dbprintf(2, ") s=%d aux=%x", s, code);
return(code);
}
/* determine possible auxiliary pattern
* using current 4 as possible character
*/
static inline signed char aux_start (zbar_decoder_t *dcode)
{
/* FIXME NB add-on has no guard in reverse */
unsigned e1, e2 = get_width(dcode, 5) + get_width(dcode, 6);
unsigned char E1;
if(dcode->ean.s4 < 6)
return(-1);
if(decode_e(e2, dcode->ean.s4, 7)) {
dbprintf(2, " [invalid any]");
return(-1);
}
e1 = get_width(dcode, 4) + get_width(dcode, 5);
E1 = decode_e(e1, dcode->ean.s4, 7);
if(get_color(dcode) == ZBAR_BAR) {
/* check for quiet-zone */
unsigned qz = get_width(dcode, 7);
if(!qz || qz > dcode->ean.s4 * 3 / 4) {
if(!E1) {
dbprintf(2, " [valid normal]");
return(0); /* normal symbol start */
}
else if(E1 == 1) {
dbprintf(2, " [valid add-on]");
return(STATE_ADDON); /* add-on symbol start */
}
}
dbprintf(2, " [invalid start]");
return(-1);
}
if(!E1) {
/* attempting decode from SPACE => validate center guard */
unsigned e3 = get_width(dcode, 6) + get_width(dcode, 7);
unsigned e4 = get_width(dcode, 7) + get_width(dcode, 8);
if(!decode_e(e3, dcode->ean.s4, 7) &&
!decode_e(e4, dcode->ean.s4, 7)) {
dbprintf(2, " [valid center]");
return(0); /* start after center guard */
}
}
dbprintf(2, " [invalid center]");
return(-1);
}
/* check addon delimiter using current 4 as character
*/
static inline signed char aux_mid (zbar_decoder_t *dcode)
{
unsigned e = get_width(dcode, 4) + get_width(dcode, 5);
return(decode_e(e, dcode->ean.s4, 7));
}
/* attempt to decode previous 4 widths (2 bars and 2 spaces) as a character */
static inline signed char decode4 (zbar_decoder_t *dcode)
{
signed char code;
/* calculate similar edge measurements */
unsigned e1 = ((get_color(dcode) == ZBAR_BAR)
? get_width(dcode, 0) + get_width(dcode, 1)
: get_width(dcode, 2) + get_width(dcode, 3));
unsigned e2 = get_width(dcode, 1) + get_width(dcode, 2);
dbprintf(2, "\n e1=%d e2=%d", e1, e2);
if(dcode->ean.s4 < 6)
return(-1);
/* create compacted encoding for direct lookup */
code = ((decode_e(e1, dcode->ean.s4, 7) << 2) |
decode_e(e2, dcode->ean.s4, 7));
if(code < 0)
return(-1);
dbprintf(2, " code=%x", code);
/* 4 combinations require additional determinant (D2)
E1E2 == 34 (0110)
E1E2 == 43 (1001)
E1E2 == 33 (0101)
E1E2 == 44 (1010)
*/
if((1 << code) & 0x0660) {
unsigned char mid, alt;
/* use sum of bar widths */
unsigned d2 = ((get_color(dcode) == ZBAR_BAR)
? get_width(dcode, 0) + get_width(dcode, 2)
: get_width(dcode, 1) + get_width(dcode, 3));
d2 *= 7;
mid = (((1 << code) & 0x0420)
? 3 /* E1E2 in 33,44 */
: 4); /* E1E2 in 34,43 */
alt = d2 > (mid * dcode->ean.s4);
if(alt)
code = ((code >> 1) & 3) | 0x10; /* compress code space */
dbprintf(2, " (d2=%d(%d) alt=%d)", d2, mid * dcode->ean.s4, alt);
}
dbprintf(2, " char=%02x", digits[(unsigned char)code]);
zassert(code < 0x14, -1, "code=%02x e1=%x e2=%x s4=%x color=%x\n",
code, e1, e2, dcode->ean.s4, get_color(dcode));
return(code);
}
static inline char ean_part_end2 (ean_decoder_t *ean,
ean_pass_t *pass)
{
if(!TEST_CFG(ean->ean2_config, ZBAR_CFG_ENABLE))
return(ZBAR_NONE);
/* extract parity bits */
unsigned char par = ((pass->raw[1] & 0x10) >> 3 |
(pass->raw[2] & 0x10) >> 4);
/* calculate "checksum" */
unsigned char chk = ~((pass->raw[1] & 0xf) * 10 +
(pass->raw[2] & 0xf)) & 0x3;
dbprintf(2, " par=%x chk=%x", par, chk);
if(par != chk)
return(ZBAR_NONE);
dbprintf(2, "\n");
dbprintf(1, "decode2=%x%x\n",
pass->raw[1] & 0xf, pass->raw[2] & 0xf);
return(ZBAR_EAN2);
}
static inline zbar_symbol_type_t ean_part_end4 (ean_pass_t *pass,
unsigned char fwd)
{
/* extract parity bits */
unsigned char par = ((pass->raw[1] & 0x10) >> 1 |
(pass->raw[2] & 0x10) >> 2 |
(pass->raw[3] & 0x10) >> 3 |
(pass->raw[4] & 0x10) >> 4);
dbprintf(2, " par=%x", par);
if(par && par != 0xf)
/* invalid parity combination */
return(ZBAR_NONE);
if((!par) == fwd) {
/* reverse sampled digits */
unsigned char tmp = pass->raw[1];
pass->state |= STATE_REV;
pass->raw[1] = pass->raw[4];
pass->raw[4] = tmp;
tmp = pass->raw[2];
pass->raw[2] = pass->raw[3];
pass->raw[3] = tmp;
}
dbprintf(2, "\n");
dbprintf(1, "decode4=%x%x%x%x\n",
pass->raw[1] & 0xf, pass->raw[2] & 0xf,
pass->raw[3] & 0xf, pass->raw[4] & 0xf);
if(!par)
return(ZBAR_EAN8 | EAN_RIGHT);
return(ZBAR_EAN8 | EAN_LEFT);
}
static inline char ean_part_end5 (ean_decoder_t *ean,
ean_pass_t *pass)
{
if(!TEST_CFG(ean->ean5_config, ZBAR_CFG_ENABLE))
return(ZBAR_NONE);
/* extract parity bits */
unsigned char par = ((pass->raw[1] & 0x10) |
(pass->raw[2] & 0x10) >> 1 |
(pass->raw[3] & 0x10) >> 2 |
(pass->raw[4] & 0x10) >> 3 |
(pass->raw[5] & 0x10) >> 4);
/* calculate checksum */
unsigned char chk = (((pass->raw[1] & 0x0f) +
(pass->raw[2] & 0x0f) * 3 +
(pass->raw[3] & 0x0f) +
(pass->raw[4] & 0x0f) * 3 +
(pass->raw[5] & 0x0f)) * 3) % 10;
unsigned char parchk = parity_decode[par >> 1];
if(par & 1)
parchk >>= 4;
parchk &= 0xf;
dbprintf(2, " par=%x(%d) chk=%d", par, parchk, chk);
if(parchk != chk)
return(ZBAR_NONE);
dbprintf(2, "\n");
dbprintf(1, "decode5=%x%x%x%x%x\n",
pass->raw[1] & 0xf, pass->raw[2] & 0xf,
pass->raw[3] & 0xf, pass->raw[4] & 0xf,
pass->raw[5] & 0xf);
return(ZBAR_EAN5);
}
static inline zbar_symbol_type_t ean_part_end7 (ean_decoder_t *ean,
ean_pass_t *pass,
unsigned char fwd)
{
/* calculate parity index */
unsigned char par = ((fwd)
? ((pass->raw[1] & 0x10) << 1 |
(pass->raw[2] & 0x10) |
(pass->raw[3] & 0x10) >> 1 |
(pass->raw[4] & 0x10) >> 2 |
(pass->raw[5] & 0x10) >> 3 |
(pass->raw[6] & 0x10) >> 4)
: ((pass->raw[1] & 0x10) >> 4 |
(pass->raw[2] & 0x10) >> 3 |
(pass->raw[3] & 0x10) >> 2 |
(pass->raw[4] & 0x10) >> 1 |
(pass->raw[5] & 0x10) |
(pass->raw[6] & 0x10) << 1));
/* lookup parity combination */
pass->raw[0] = parity_decode[par >> 1];
if(par & 1)
pass->raw[0] >>= 4;
pass->raw[0] &= 0xf;
dbprintf(2, " par=%02x(%x)", par, pass->raw[0]);
if(pass->raw[0] == 0xf)
/* invalid parity combination */
return(ZBAR_NONE);
if((!par) == fwd) {
unsigned char i;
pass->state |= STATE_REV;
/* reverse sampled digits */
for(i = 1; i < 4; i++) {
unsigned char tmp = pass->raw[i];
pass->raw[i] = pass->raw[7 - i];
pass->raw[7 - i] = tmp;
}
}
dbprintf(2, "\n");
dbprintf(1, "decode=%x%x%x%x%x%x%x(%02x)\n",
pass->raw[0] & 0xf, pass->raw[1] & 0xf,
pass->raw[2] & 0xf, pass->raw[3] & 0xf,
pass->raw[4] & 0xf, pass->raw[5] & 0xf,
pass->raw[6] & 0xf, par);
if(TEST_CFG(ean->ean13_config, ZBAR_CFG_ENABLE)) {
if(!par)
return(ZBAR_EAN13 | EAN_RIGHT);
if(par & 0x20)
return(ZBAR_EAN13 | EAN_LEFT);
}
if(par && !(par & 0x20))
return(ZBAR_UPCE);
return(ZBAR_NONE);
}
/* update state for one of 4 parallel passes */
static inline zbar_symbol_type_t decode_pass (zbar_decoder_t *dcode,
ean_pass_t *pass)
{
unsigned char idx, fwd;
pass->state++;
idx = pass->state & STATE_IDX;
fwd = pass->state & 1;
if(get_color(dcode) == ZBAR_SPACE) {
if(pass->state & STATE_ADDON) {
dbprintf(2, " i=%d", idx);
if(idx == 0x09 || idx == 0x21) {
unsigned qz = get_width(dcode, 0);
unsigned s = calc_s(dcode, 1, 4);
zbar_symbol_type_t part = !qz || (qz >= s * 3 / 4);
if(part && idx == 0x09)
part = ean_part_end2(&dcode->ean, pass);
else if(part)
part = ean_part_end5(&dcode->ean, pass);
if(part || idx == 0x21) {
dcode->ean.direction = 0;
pass->state = -1;
return(part);
}
}
if((idx & 7) == 1) {
dbprintf(2, " +");
pass->state += 2;
idx += 2;
}
}
else if((idx == 0x10 || idx == 0x11) &&
TEST_CFG(dcode->ean.ean8_config, ZBAR_CFG_ENABLE) &&
!aux_end(dcode, fwd)) {
dbprintf(2, " fwd=%x", fwd);
zbar_symbol_type_t part = ean_part_end4(pass, fwd);
if(part)
dcode->ean.direction = (pass->state & STATE_REV) != 0;
pass->state = -1;
return(part);
}
else if((idx == 0x18 || idx == 0x19)) {
zbar_symbol_type_t part = ZBAR_NONE;
dbprintf(2, " fwd=%x", fwd);
if(!aux_end(dcode, fwd) && pass->raw[5] != 0xff)
part = ean_part_end7(&dcode->ean, pass, fwd);
if(part)
dcode->ean.direction = (pass->state & STATE_REV) != 0;
pass->state = -1;
return(part);
}
}
if(pass->state & STATE_ADDON)
idx >>= 1;
if(!(idx & 0x03) && idx <= 0x14) {
signed char code = -1;
unsigned w = pass->width;
if(!dcode->ean.s4)
return(0);
/* validate guard bars before decoding first char of symbol */
if(!pass->state) {
pass->state = aux_start(dcode);
pass->width = dcode->ean.s4;
if(pass->state < 0)
return(0);
idx = pass->state & STATE_IDX;
}
else {
w = check_width(w, dcode->ean.s4);
if(w)
pass->width = (pass->width + dcode->ean.s4 * 3) / 4;
}
if(w)
code = decode4(dcode);
else
dbprintf(2, " [bad width]");
if((code < 0 && idx != 0x10) ||
(idx > 0 && (pass->state & STATE_ADDON) && aux_mid(dcode)))
pass->state = -1;
else if(code < 0)
pass->raw[5] = 0xff;
else {
dbprintf(2, "\n raw[%x]=%02x =>", idx >> 2,
digits[(unsigned char)code]);
pass->raw[(idx >> 2) + 1] = digits[(unsigned char)code];
dbprintf(2, " raw=%d%d%d%d%d%d%d",
pass->raw[0] & 0xf, pass->raw[1] & 0xf,
pass->raw[2] & 0xf, pass->raw[3] & 0xf,
pass->raw[4] & 0xf, pass->raw[5] & 0xf,
pass->raw[6] & 0xf);
}
}
return(0);
}
static inline signed char ean_verify_checksum (ean_decoder_t *ean,
int n)
{
unsigned char chk = 0;
unsigned char i, d;
for(i = 0; i < n; i++) {
unsigned char d = ean->buf[i];
zassert(d < 10, -1, "i=%x d=%x chk=%x %s\n", i, d, chk,
_zbar_decoder_buf_dump((void*)ean->buf, 18));
chk += d;
if((i ^ n) & 1) {
chk += d << 1;
if(chk >= 20)
chk -= 20;
}
if(chk >= 10)
chk -= 10;
}
zassert(chk < 10, -1, "chk=%x n=%x %s", chk, n,
_zbar_decoder_buf_dump((void*)ean->buf, 18));
if(chk)
chk = 10 - chk;
d = ean->buf[n];
zassert(d < 10, -1, "n=%x d=%x chk=%x %s\n", n, d, chk,
_zbar_decoder_buf_dump((void*)ean->buf, 18));
if(chk != d) {
dbprintf(1, "\nchecksum mismatch %d != %d (%s)\n",
chk, d, dsprintbuf(ean));
return(-1);
}
return(0);
}
static inline unsigned char isbn10_calc_checksum (ean_decoder_t *ean)
{
unsigned int chk = 0;
unsigned char w;
for(w = 10; w > 1; w--) {
unsigned char d = ean->buf[13 - w];
zassert(d < 10, '?', "w=%x d=%x chk=%x %s\n", w, d, chk,
_zbar_decoder_buf_dump((void*)ean->buf, 18));
chk += d * w;
}
chk = chk % 11;
if(!chk)
return('0');
chk = 11 - chk;
if(chk < 10)
return(chk + '0');
return('X');
}
static inline void ean_expand_upce (ean_decoder_t *ean,
ean_pass_t *pass)
{
int i = 0;
unsigned char decode;
/* parity encoded digit is checksum */
ean->buf[12] = pass->raw[i++];
decode = pass->raw[6] & 0xf;
ean->buf[0] = 0;
ean->buf[1] = 0;
ean->buf[2] = pass->raw[i++] & 0xf;
ean->buf[3] = pass->raw[i++] & 0xf;
ean->buf[4] = (decode < 3) ? decode : pass->raw[i++] & 0xf;
ean->buf[5] = (decode < 4) ? 0 : pass->raw[i++] & 0xf;
ean->buf[6] = (decode < 5) ? 0 : pass->raw[i++] & 0xf;
ean->buf[7] = 0;
ean->buf[8] = 0;
ean->buf[9] = (decode < 3) ? pass->raw[i++] & 0xf : 0;
ean->buf[10] = (decode < 4) ? pass->raw[i++] & 0xf : 0;
ean->buf[11] = (decode < 5) ? pass->raw[i] & 0xf : decode;
}
static inline zbar_symbol_type_t integrate_partial (ean_decoder_t *ean,
ean_pass_t *pass,
zbar_symbol_type_t part)
{
/* copy raw data into holding buffer */
/* if same partial is not consistent, reset others */
dbprintf(2, " integrate part=%x (%s)", part, dsprintbuf(ean));
signed char i, j;
if((ean->left && ((part & ZBAR_SYMBOL) != ean->left)) ||
(ean->right && ((part & ZBAR_SYMBOL) != ean->right))) {
/* partial mismatch - reset collected parts */
dbprintf(2, " rst(type %x %x)", ean->left, ean->right);
ean->left = ean->right = ZBAR_NONE;
}
if((ean->left || ean->right) &&
!check_width(ean->width, pass->width)) {
dbprintf(2, " rst(width %d)", pass->width);
ean->left = ean->right = ZBAR_NONE;
}
if(part & EAN_RIGHT) {
part &= ZBAR_SYMBOL;
j = part - 1;
for(i = part >> 1; i; i--, j--) {
unsigned char digit = pass->raw[i] & 0xf;
if(ean->right && ean->buf[j] != digit) {
/* partial mismatch - reset collected parts */
dbprintf(2, " rst(right)");
ean->left = ean->right = ZBAR_NONE;
}
ean->buf[j] = digit;
}
ean->right = part;
part &= ean->left; /* FIXME!? */
}
else if(part == ZBAR_EAN13 || part == ZBAR_EAN8) /* EAN_LEFT */ {
j = (part - 1) >> 1;
for(i = part >> 1; j >= 0; i--, j--) {
unsigned char digit = pass->raw[i] & 0xf;
if(ean->left && ean->buf[j] != digit) {
/* partial mismatch - reset collected parts */
dbprintf(2, " rst(left)");
ean->left = ean->right = ZBAR_NONE;
}
ean->buf[j] = digit;
}
ean->left = part;
part &= ean->right; /* FIXME!? */
}
else if(part != ZBAR_UPCE) /* add-ons */ {
for(i = part; i > 0; i--)
ean->buf[i - 1] = pass->raw[i] & 0xf;
ean->left = part;
}
else
ean_expand_upce(ean, pass);
ean->width = pass->width;
if(!part)
part = ZBAR_PARTIAL;
if(((part == ZBAR_EAN13 ||
part == ZBAR_UPCE) && ean_verify_checksum(ean, 12)) ||
(part == ZBAR_EAN8 && ean_verify_checksum(ean, 7))) {
/* invalid checksum */
if(ean->right)
ean->left = ZBAR_NONE;
else
ean->right = ZBAR_NONE;
part = ZBAR_NONE;
}
if(part == ZBAR_EAN13) {
/* special case EAN-13 subsets */
if(!ean->buf[0] && TEST_CFG(ean->upca_config, ZBAR_CFG_ENABLE))
part = ZBAR_UPCA;
else if(ean->buf[0] == 9 && ean->buf[1] == 7) {
/* ISBN-10 has priority over ISBN-13(?) */
if(ean->buf[2] == 8 &&
TEST_CFG(ean->isbn10_config, ZBAR_CFG_ENABLE))
part = ZBAR_ISBN10;
else if((ean->buf[2] == 8 || ean->buf[2] == 9) &&
TEST_CFG(ean->isbn13_config, ZBAR_CFG_ENABLE))
part = ZBAR_ISBN13;
}
}
else if(part == ZBAR_UPCE) {
if(TEST_CFG(ean->upce_config, ZBAR_CFG_ENABLE)) {
/* UPC-E was decompressed for checksum verification,
* but user requested compressed result
*/
ean->buf[0] = ean->buf[1] = 0;
for(i = 2; i < 8; i++)
ean->buf[i] = pass->raw[i - 1] & 0xf;
ean->buf[i] = pass->raw[0] & 0xf;
}
else if(TEST_CFG(ean->upca_config, ZBAR_CFG_ENABLE))
/* UPC-E reported as UPC-A has priority over EAN-13 */
part = ZBAR_UPCA;
else if(TEST_CFG(ean->ean13_config, ZBAR_CFG_ENABLE))
part = ZBAR_EAN13;
else
part = ZBAR_NONE;
}
dbprintf(2, " dir=%d %x/%x=%x",
ean->direction, ean->left, ean->right, part);
return(part);
}
/* copy result to output buffer */
static inline void postprocess (zbar_decoder_t *dcode,
zbar_symbol_type_t sym)
{
ean_decoder_t *ean = &dcode->ean;
zbar_symbol_type_t base = sym;
int i = 0, j = 0;
if(base > ZBAR_PARTIAL) {
if(base == ZBAR_UPCA)
i = 1;
else if(base == ZBAR_UPCE) {
i = 1;
base--;
}
else if(base == ZBAR_ISBN13)
base = ZBAR_EAN13;
else if(base == ZBAR_ISBN10)
i = 3;
if(base == ZBAR_ISBN10 ||
(base > ZBAR_EAN5 &&
!TEST_CFG(ean_get_config(ean, sym), ZBAR_CFG_EMIT_CHECK)))
base--;
for(; j < base && ean->buf[i] >= 0; i++, j++)
dcode->buf[j] = ean->buf[i] + '0';
if(sym == ZBAR_ISBN10 && j == 9 &&
TEST_CFG(ean->isbn10_config, ZBAR_CFG_EMIT_CHECK))
/* recalculate ISBN-10 check digit */
dcode->buf[j++] = isbn10_calc_checksum(ean);
}
dcode->buflen = j;
dcode->buf[j] = '\0';
dcode->direction = 1 - 2 * ean->direction;
dcode->modifiers = 0;
dbprintf(2, " base=%d j=%d (%s)", base, j, dcode->buf);
}
zbar_symbol_type_t _zbar_decode_ean (zbar_decoder_t *dcode)
{
/* process upto 4 separate passes */
zbar_symbol_type_t sym = ZBAR_NONE;
unsigned char pass_idx = dcode->idx & 3;
unsigned char i;
/* update latest character width */
dcode->ean.s4 -= get_width(dcode, 4);
dcode->ean.s4 += get_width(dcode, 0);
for(i = 0; i < 4; i++) {
ean_pass_t *pass = &dcode->ean.pass[i];
if(pass->state >= 0 ||
i == pass_idx)
{
zbar_symbol_type_t part;
dbprintf(2, " ean[%x/%x]: idx=%x st=%d s=%d",
i, pass_idx, dcode->idx, pass->state, dcode->ean.s4);
part = decode_pass(dcode, pass);
if(part) {
/* update accumulated data from new partial decode */
sym = integrate_partial(&dcode->ean, pass, part);
if(sym) {
/* this pass valid => _reset_ all passes */
dbprintf(2, " sym=%x", sym);
dcode->ean.pass[0].state = dcode->ean.pass[1].state = -1;
dcode->ean.pass[2].state = dcode->ean.pass[3].state = -1;
if(sym > ZBAR_PARTIAL) {
if(!acquire_lock(dcode, sym))
postprocess(dcode, sym);
else {
dbprintf(1, " [locked %d]", dcode->lock);
sym = ZBAR_PARTIAL;
}
}
}
}
dbprintf(2, "\n");
}
}
return(sym);
}
+90
View File
@@ -0,0 +1,90 @@
/*------------------------------------------------------------------------
* Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#ifndef _EAN_H_
#define _EAN_H_
/* state of each parallel decode attempt */
typedef struct ean_pass_s {
signed char state; /* module position of w[idx] in symbol */
#define STATE_REV 0x80 /* scan direction reversed */
#define STATE_ADDON 0x40 /* scanning add-on */
#define STATE_IDX 0x3f /* element offset into symbol */
unsigned width; /* width of last character */
unsigned char raw[7]; /* decode in process */
} ean_pass_t;
/* EAN/UPC specific decode state */
typedef struct ean_decoder_s {
ean_pass_t pass[4]; /* state of each parallel decode attempt */
zbar_symbol_type_t left; /* current holding buffer contents */
zbar_symbol_type_t right;
int direction; /* scan direction */
unsigned s4, width; /* character width */
signed char buf[18]; /* holding buffer */
signed char enable;
unsigned ean13_config;
unsigned ean8_config;
unsigned upca_config;
unsigned upce_config;
unsigned isbn10_config;
unsigned isbn13_config;
unsigned ean5_config;
unsigned ean2_config;
} ean_decoder_t;
/* reset EAN/UPC pass specific state */
static inline void ean_new_scan (ean_decoder_t *ean)
{
ean->pass[0].state = ean->pass[1].state = -1;
ean->pass[2].state = ean->pass[3].state = -1;
ean->s4 = 0;
}
/* reset all EAN/UPC state */
static inline void ean_reset (ean_decoder_t *ean)
{
ean_new_scan(ean);
ean->left = ean->right = ZBAR_NONE;
}
static inline unsigned ean_get_config (ean_decoder_t *ean,
zbar_symbol_type_t sym)
{
switch(sym) {
case ZBAR_EAN2: return(ean->ean2_config);
case ZBAR_EAN5: return(ean->ean5_config);
case ZBAR_EAN8: return(ean->ean8_config);
case ZBAR_UPCE: return(ean->upce_config);
case ZBAR_ISBN10: return(ean->isbn10_config);
case ZBAR_UPCA: return(ean->upca_config);
case ZBAR_EAN13: return(ean->ean13_config);
case ZBAR_ISBN13: return(ean->isbn13_config);
default: return(0);
}
}
/* decode EAN/UPC symbols */
zbar_symbol_type_t _zbar_decode_ean(zbar_decoder_t *dcode);
#endif
+265
View File
@@ -0,0 +1,265 @@
/*------------------------------------------------------------------------
* Copyright 2008-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#include <zbar_config.h>
#include <string.h> /* memmove */
#include <zbar.h>
#ifdef DEBUG_I25
# define DEBUG_LEVEL (DEBUG_I25)
#endif
#include "debug.h"
#include "decoder.h"
static inline unsigned char i25_decode1 (unsigned char enc,
unsigned e,
unsigned s)
{
unsigned char E = decode_e(e, s, 45);
if(E > 7)
return(0xff);
enc <<= 1;
if(E > 2)
enc |= 1;
return(enc);
}
static inline unsigned char i25_decode10 (zbar_decoder_t *dcode,
unsigned char offset)
{
i25_decoder_t *dcode25 = &dcode->i25;
dbprintf(2, " s=%d", dcode25->s10);
if(dcode25->s10 < 10)
return(0xff);
/* threshold bar width ratios */
unsigned char enc = 0, par = 0;
signed char i;
for(i = 8; i >= 0; i -= 2) {
unsigned char j = offset + ((dcode25->direction) ? i : 8 - i);
enc = i25_decode1(enc, get_width(dcode, j), dcode25->s10);
if(enc == 0xff)
return(0xff);
if(enc & 1)
par++;
}
dbprintf(2, " enc=%02x par=%x", enc, par);
/* parity check */
if(par != 2) {
dbprintf(2, " [bad parity]");
return(0xff);
}
/* decode binary weights */
enc &= 0xf;
if(enc & 8) {
if(enc == 12)
enc = 0;
else if(--enc > 9) {
dbprintf(2, " [invalid encoding]");
return(0xff);
}
}
dbprintf(2, " => %x", enc);
return(enc);
}
static inline signed char i25_decode_start (zbar_decoder_t *dcode)
{
i25_decoder_t *dcode25 = &dcode->i25;
if(dcode25->s10 < 10)
return(ZBAR_NONE);
unsigned char enc = 0;
unsigned char i = 10;
enc = i25_decode1(enc, get_width(dcode, i++), dcode25->s10);
enc = i25_decode1(enc, get_width(dcode, i++), dcode25->s10);
enc = i25_decode1(enc, get_width(dcode, i++), dcode25->s10);
if((get_color(dcode) == ZBAR_BAR)
? enc != 4
: (enc = i25_decode1(enc, get_width(dcode, i++), dcode25->s10))) {
dbprintf(4, " i25: s=%d enc=%x [invalid]\n", dcode25->s10, enc);
return(ZBAR_NONE);
}
/* check leading quiet zone - spec is 10n(?)
* we require 5.25n for w=2n to 6.75n for w=3n
* (FIXME should really factor in w:n ratio)
*/
unsigned quiet = get_width(dcode, i);
if(quiet && quiet < dcode25->s10 * 3 / 8) {
dbprintf(3, " i25: s=%d enc=%x q=%d [invalid qz]\n",
dcode25->s10, enc, quiet);
return(ZBAR_NONE);
}
dcode25->direction = get_color(dcode);
dcode25->element = 1;
dcode25->character = 0;
return(ZBAR_PARTIAL);
}
static inline int i25_acquire_lock (zbar_decoder_t *dcode)
{
int i;
/* lock shared resources */
if(acquire_lock(dcode, ZBAR_I25)) {
dcode->i25.character = -1;
return(1);
}
/* copy holding buffer */
for(i = 4; --i >= 0; )
dcode->buf[i] = dcode->i25.buf[i];
return(0);
}
static inline signed char i25_decode_end (zbar_decoder_t *dcode)
{
i25_decoder_t *dcode25 = &dcode->i25;
/* check trailing quiet zone */
unsigned quiet = get_width(dcode, 0);
if((quiet && quiet < dcode25->width * 3 / 8) ||
decode_e(get_width(dcode, 1), dcode25->width, 45) > 2 ||
decode_e(get_width(dcode, 2), dcode25->width, 45) > 2) {
dbprintf(3, " i25: s=%d q=%d [invalid qz]\n",
dcode25->width, quiet);
return(ZBAR_NONE);
}
/* check exit condition */
unsigned char E = decode_e(get_width(dcode, 3), dcode25->width, 45);
if((!dcode25->direction)
? E - 3 > 4
: (E > 2 ||
decode_e(get_width(dcode, 4), dcode25->width, 45) > 2))
return(ZBAR_NONE);
if(dcode25->character <= 4 &&
i25_acquire_lock(dcode))
return(ZBAR_PARTIAL);
dcode->direction = 1 - 2 * dcode25->direction;
if(dcode25->direction) {
/* reverse buffer */
dbprintf(2, " (rev)");
int i;
for(i = 0; i < dcode25->character / 2; i++) {
unsigned j = dcode25->character - 1 - i;
char c = dcode->buf[i];
dcode->buf[i] = dcode->buf[j];
dcode->buf[j] = c;
}
}
if(dcode25->character < CFG(*dcode25, ZBAR_CFG_MIN_LEN) ||
(CFG(*dcode25, ZBAR_CFG_MAX_LEN) > 0 &&
dcode25->character > CFG(*dcode25, ZBAR_CFG_MAX_LEN))) {
dbprintf(2, " [invalid len]\n");
release_lock(dcode, ZBAR_I25);
dcode25->character = -1;
return(ZBAR_NONE);
}
zassert(dcode25->character < dcode->buf_alloc, ZBAR_NONE, "i=%02x %s\n",
dcode25->character,
_zbar_decoder_buf_dump(dcode->buf, dcode25->character));
dcode->buflen = dcode25->character;
dcode->buf[dcode25->character] = '\0';
dcode->modifiers = 0;
dbprintf(2, " [valid end]\n");
dcode25->character = -1;
return(ZBAR_I25);
}
zbar_symbol_type_t _zbar_decode_i25 (zbar_decoder_t *dcode)
{
i25_decoder_t *dcode25 = &dcode->i25;
/* update latest character width */
dcode25->s10 -= get_width(dcode, 10);
dcode25->s10 += get_width(dcode, 0);
if(dcode25->character < 0 &&
!i25_decode_start(dcode))
return(ZBAR_NONE);
if(--dcode25->element == 6 - dcode25->direction)
return(i25_decode_end(dcode));
else if(dcode25->element)
return(ZBAR_NONE);
/* FIXME check current character width against previous */
dcode25->width = dcode25->s10;
dbprintf(2, " i25[%c%02d+%x]",
(dcode25->direction) ? '<' : '>',
dcode25->character, dcode25->element);
if(dcode25->character == 4 && i25_acquire_lock(dcode))
return(ZBAR_PARTIAL);
unsigned char c = i25_decode10(dcode, 1);
dbprintf(2, " c=%x", c);
if(c > 9) {
dbprintf(2, " [aborted]\n");
goto reset;
}
if(size_buf(dcode, dcode25->character + 3)) {
dbprintf(2, " [overflow]\n");
goto reset;
}
unsigned char *buf;
if(dcode25->character >= 4)
buf = dcode->buf;
else
buf = dcode25->buf;
buf[dcode25->character++] = c + '0';
c = i25_decode10(dcode, 0);
dbprintf(2, " c=%x", c);
if(c > 9) {
dbprintf(2, " [aborted]\n");
goto reset;
}
else
dbprintf(2, "\n");
buf[dcode25->character++] = c + '0';
dcode25->element = 10;
return((dcode25->character == 2) ? ZBAR_PARTIAL : ZBAR_NONE);
reset:
if(dcode25->character >= 4)
release_lock(dcode, ZBAR_I25);
dcode25->character = -1;
return(ZBAR_NONE);
}
+51
View File
@@ -0,0 +1,51 @@
/*------------------------------------------------------------------------
* Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#ifndef _I25_H_
#define _I25_H_
/* interleaved 2 of 5 specific decode state */
typedef struct i25_decoder_s {
unsigned direction : 1; /* scan direction: 0=fwd/space, 1=rev/bar */
unsigned element : 4; /* element offset 0-8 */
int character : 12; /* character position in symbol */
unsigned s10; /* current character width */
unsigned width; /* last character width */
unsigned char buf[4]; /* initial scan buffer */
unsigned config;
int configs[NUM_CFGS]; /* int valued configurations */
} i25_decoder_t;
/* reset interleaved 2 of 5 specific state */
static inline void i25_reset (i25_decoder_t *i25)
{
i25->direction = 0;
i25->element = 0;
i25->character = -1;
i25->s10 = 0;
}
/* decode interleaved 2 of 5 symbols */
zbar_symbol_type_t _zbar_decode_i25(zbar_decoder_t *dcode);
#endif
+222
View File
@@ -0,0 +1,222 @@
/*------------------------------------------------------------------------
* Copyright 2008-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#include <zbar_config.h>
#include <zbar.h>
#ifdef DEBUG_PDF417
# define DEBUG_LEVEL (DEBUG_PDF417)
#endif
#include "debug.h"
#include "decoder.h"
#include "pdf417_hash.h"
#define PDF417_STOP 0xbff
static inline signed short pdf417_decode8 (zbar_decoder_t *dcode)
{
/* build edge signature of character
* from similar edge measurements
*/
unsigned s = dcode->pdf417.s8;
dbprintf(2, " s=%d ", s);
if(s < 8)
return(-1);
long sig = 0;
signed char e;
unsigned char i;
for(i = 0; i < 7; i++) {
if(get_color(dcode) == ZBAR_SPACE)
e = decode_e(get_width(dcode, i) +
get_width(dcode, i + 1), s, 17);
else
e = decode_e(get_width(dcode, 7 - i) +
get_width(dcode, 6 - i), s, 17);
dbprintf(4, "%x", e);
if(e < 0 || e > 8)
return(-1);
sig = (sig << 3) ^ e;
}
dbprintf(2, " sig=%06lx", sig);
/* determine cluster number */
int clst = ((sig & 7) - ((sig >> 3) & 7) +
((sig >> 12) & 7) - ((sig >> 15) & 7));
if(clst < 0)
clst += 9;
dbprintf(2, " k=%d", clst);
zassert(clst >= 0 && clst < 9, -1, "dir=%x sig=%lx k=%x %s\n",
dcode->pdf417.direction, sig, clst,
_zbar_decoder_buf_dump(dcode->buf, dcode->pdf417.character));
if(clst != 0 && clst != 3 && clst != 6) {
if(get_color(dcode) && clst == 7 && sig == 0x080007)
return(PDF417_STOP);
return(-1);
}
signed short g[3];
sig &= 0x3ffff;
g[0] = pdf417_hash[(sig - (sig >> 10)) & PDF417_HASH_MASK];
g[1] = pdf417_hash[((sig >> 8) - sig) & PDF417_HASH_MASK];
g[2] = pdf417_hash[((sig >> 14) - (sig >> 1)) & PDF417_HASH_MASK];
zassert(g[0] >= 0 && g[1] >= 0 && g[2] >= 0, -1,
"dir=%x sig=%lx k=%x g0=%03x g1=%03x g2=%03x %s\n",
dcode->pdf417.direction, sig, clst, g[0], g[1], g[2],
_zbar_decoder_buf_dump(dcode->buf, dcode->pdf417.character));
unsigned short c = (g[0] + g[1] + g[2]) & PDF417_HASH_MASK;
dbprintf(2, " g0=%x g1=%x g2=%x c=%03d(%d)",
g[0], g[1], g[2], c & 0x3ff, c >> 10);
return(c);
}
static inline signed char pdf417_decode_start(zbar_decoder_t *dcode)
{
unsigned s = dcode->pdf417.s8;
if(s < 8)
return(0);
int ei = decode_e(get_width(dcode, 0) + get_width(dcode, 1), s, 17);
int ex = (get_color(dcode) == ZBAR_SPACE) ? 2 : 6;
if(ei != ex)
return(0);
ei = decode_e(get_width(dcode, 1) + get_width(dcode, 2), s, 17);
if(ei)
return(0);
ei = decode_e(get_width(dcode, 2) + get_width(dcode, 3), s, 17);
ex = (get_color(dcode) == ZBAR_SPACE) ? 0 : 2;
if(ei != ex)
return(0);
ei = decode_e(get_width(dcode, 3) + get_width(dcode, 4), s, 17);
ex = (get_color(dcode) == ZBAR_SPACE) ? 0 : 2;
if(ei != ex)
return(0);
ei = decode_e(get_width(dcode, 4) + get_width(dcode, 5), s, 17);
if(ei)
return(0);
ei = decode_e(get_width(dcode, 5) + get_width(dcode, 6), s, 17);
if(ei)
return(0);
ei = decode_e(get_width(dcode, 6) + get_width(dcode, 7), s, 17);
ex = (get_color(dcode) == ZBAR_SPACE) ? 7 : 1;
if(ei != ex)
return(0);
ei = decode_e(get_width(dcode, 7) + get_width(dcode, 8), s, 17);
ex = (get_color(dcode) == ZBAR_SPACE) ? 8 : 1;
if(get_color(dcode) == ZBAR_BAR) {
/* stop character has extra bar */
if(ei != 1)
return(0);
ei = decode_e(get_width(dcode, 8) + get_width(dcode, 9), s, 17);
}
dbprintf(2, " pdf417[%c]: s=%d",
(get_color(dcode)) ? '<' : '>', s);
/* check quiet zone */
if(ei >= 0 && ei < ex) {
dbprintf(2, " [invalid quiet]\n");
return(0);
}
/* lock shared resources */
if(acquire_lock(dcode, ZBAR_PDF417)) {
dbprintf(2, " [locked %d]\n", dcode->lock);
return(0);
}
pdf417_decoder_t *dcode417 = &dcode->pdf417;
dcode417->direction = get_color(dcode);
dcode417->element = 0;
dcode417->character = 0;
dbprintf(2, " [valid start]\n");
return(ZBAR_PARTIAL);
}
zbar_symbol_type_t _zbar_decode_pdf417 (zbar_decoder_t *dcode)
{
pdf417_decoder_t *dcode417 = &dcode->pdf417;
/* update latest character width */
dcode417->s8 -= get_width(dcode, 8);
dcode417->s8 += get_width(dcode, 0);
if(dcode417->character < 0) {
pdf417_decode_start(dcode);
dbprintf(4, "\n");
return(0);
}
/* process every 8th element of active symbol */
if(++dcode417->element)
return(0);
dcode417->element = 0;
dbprintf(2, " pdf417[%c%02d]:",
(dcode417->direction) ? '<' : '>', dcode417->character);
if(get_color(dcode) != dcode417->direction) {
int c = dcode417->character;
release_lock(dcode, ZBAR_PDF417);
dcode417->character = -1;
zassert(get_color(dcode) == dcode417->direction, ZBAR_NONE,
"color=%x dir=%x char=%d elem=0 %s\n",
get_color(dcode), dcode417->direction, c,
_zbar_decoder_buf_dump(dcode->buf, c));
}
signed short c = pdf417_decode8(dcode);
if(c < 0 || size_buf(dcode, dcode417->character + 1)) {
dbprintf(1, (c < 0) ? " [aborted]\n" : " [overflow]\n");
release_lock(dcode, ZBAR_PDF417);
dcode417->character = -1;
return(0);
}
/* FIXME TBD infer dimensions, save codewords */
if(c == PDF417_STOP) {
dbprintf(1, " [valid stop]");
/* FIXME check trailing bar and qz */
dcode->direction = 1 - 2 * dcode417->direction;
dcode->modifiers = 0;
release_lock(dcode, ZBAR_PDF417);
dcode417->character = -1;
}
dbprintf(2, "\n");
return(0);
}
+49
View File
@@ -0,0 +1,49 @@
/*------------------------------------------------------------------------
* Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#ifndef _PDF417_H_
#define _PDF417_H_
/* PDF417 specific decode state */
typedef struct pdf417_decoder_s {
unsigned direction : 1; /* scan direction: 0=fwd/space, 1=rev/bar */
unsigned element : 3; /* element offset 0-7 */
int character : 12; /* character position in symbol */
unsigned s8; /* character width */
unsigned config;
int configs[NUM_CFGS]; /* int valued configurations */
} pdf417_decoder_t;
/* reset PDF417 specific state */
static inline void pdf417_reset (pdf417_decoder_t *pdf417)
{
pdf417->direction = 0;
pdf417->element = 0;
pdf417->character = -1;
pdf417->s8 = 0;
}
/* decode PDF417 symbols */
zbar_symbol_type_t _zbar_decode_pdf417(zbar_decoder_t *dcode);
#endif
+545
View File
@@ -0,0 +1,545 @@
/*------------------------------------------------------------------------
* Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#ifndef _PDF417_HASH_H_
#define _PDF417_HASH_H_
/* PDF417 bar to codeword decode table */
#define PDF417_HASH_MASK 0xfff
static const signed short pdf417_hash[PDF417_HASH_MASK + 1] = {
0x170, 0xd8e, 0x02e, 0x000, 0xa21, 0xc99, 0x000, 0xf06,
0xdaa, 0x7a1, 0xc5f, 0x7ff, 0xbcf, 0xac8, 0x000, 0xc51,
0x49a, 0x5c7, 0x000, 0xef2, 0x000, 0x7dd, 0x9ee, 0xe32,
0x1b7, 0x489, 0x3b7, 0xe70, 0x9c8, 0xe5e, 0xdf4, 0x599,
0x4e0, 0x608, 0x639, 0xead, 0x0ac, 0x57c, 0x000, 0x20d,
0x61b, 0x000, 0x7d1, 0x80f, 0x803, 0x000, 0x946, 0x093,
0x79c, 0xf9c, 0xb34, 0x6d8, 0x4f1, 0x975, 0x886, 0x313,
0xe8a, 0xf20, 0x3c9, 0xa92, 0xb90, 0xa1d, 0x091, 0x0ac,
0xb50, 0x3af, 0x90a, 0x45a, 0x815, 0xf29, 0xb20, 0xb6d,
0xc5c, 0x1cd, 0x1e2, 0x1bf, 0x963, 0x80b, 0xa7c, 0x9b7,
0xb65, 0x6b7, 0x117, 0xc04, 0x000, 0x18e, 0x000, 0x77f,
0xe0e, 0xf48, 0x370, 0x818, 0x379, 0x000, 0x090, 0xe77,
0xd99, 0x8b8, 0xb95, 0x8a9, 0x94c, 0xc48, 0x679, 0x000,
0x41a, 0x9ea, 0xb0e, 0x9c1, 0x1b4, 0x000, 0x630, 0x811,
0x4b1, 0xc05, 0x98f, 0xa68, 0x485, 0x706, 0xfff, 0x0d9,
0xddc, 0x000, 0x83f, 0x54e, 0x290, 0xfe7, 0x64f, 0xf36,
0x000, 0x151, 0xb9b, 0x5cd, 0x961, 0x690, -1, 0xa7a,
0x328, 0x707, 0xe6d, 0xe1f, -1, 0x6a0, 0xf3e, 0xb27,
0x315, 0xc8c, 0x6de, 0x996, 0x2f9, 0xc4c, 0x90f, -1,
0xaa7, 0x9e9, 0xfff, 0x0bb, 0x33b, 0xbc6, 0xe17, 0x000,
0x85d, 0x912, 0x5f7, 0x000, 0xff1, 0xba1, 0x086, 0xa1e,
0x85a, 0x4cf, 0xd47, 0x5a9, 0x5dc, 0x0bc, -1, 0x544,
0x522, 0x1ff, 0xfa6, 0xa83, 0xc7d, 0x545, 0xd75, 0xb6f,
0x284, 0xf11, 0xe46, -1, 0x900, 0x0f3, 0xe31, 0x705,
0x06d, 0xd59, 0x67b, 0xe56, -1, 0xde2, 0x000, 0xd42,
-1, 0x24b, 0x000, 0xf87, 0x842, -1, 0xbb9, 0x065,
0x626, 0x86a, 0x9f8, -1, 0x7ac, 0xe20, 0xbe9, 0x357,
0xfff, 0xf82, 0x219, 0x9d4, 0x269, 0x8a6, 0x251, 0x0af,
0xd02, 0x09a, 0x803, 0x0a5, 0xfed, 0x278, -1, 0x338,
0x1e5, 0xcad, 0xf9e, 0x73e, 0xb39, 0xe48, 0x754, -1,
0x680, 0xd99, 0x4d4, 0x80b, 0x4be, 0xb0d, 0x5f2, -1,
0x4b1, 0x38a, 0xff5, 0x000, 0xa1b, 0xece, 0xa06, 0x8e6,
0xdcb, 0xcb8, 0xc63, 0x98c, 0x346, 0x69c, 0x299, 0xa52,
0xfff, 0x000, -1, 0x7b2, 0xbf8, 0x2d1, 0xaff, 0x2f2,
0xd69, 0xf20, -1, 0xdcf, 0x9fb, 0x68f, 0x24e, 0xfd7,
0xfdb, 0x894, 0xc8f, 0x615, 0xa25, 0x36d, 0x1bb, 0x064,
0xb80, 0x280, 0xd7a, -1, 0xd75, 0xc90, 0xdce, 0xdce,
0x011, 0x869, 0xb2f, 0xd24, 0xe26, 0x492, 0xe0a, 0xcae,
-1, 0x2ac, 0x38c, 0x0b9, 0xc4f, -1, 0x32b, 0x415,
0x49c, 0x11c, 0x816, 0xd08, 0xf5c, 0x356, 0x2b3, 0xfbf,
0x7ff, 0x35d, 0x276, 0x292, 0x4f5, 0x0e2, 0xc68, 0x4c4,
0x000, 0xb5e, 0xd0b, 0xca7, 0x624, 0x247, 0xf0d, 0x017,
0x7ec, 0x2a6, 0x62c, 0x192, 0x610, 0xd98, 0x7a4, 0xfa3,
0x80b, 0x043, 0xd7b, 0x301, 0x69d, 0x7e4, 0x10c, 0xacb,
0x6eb, 0xea7, 0xe65, 0x75d, 0x4f5, 0x5b0, 0xa50, 0x7b6,
0x0ec, -1, 0xcf9, 0x4b4, 0x639, 0x111, 0xbdf, 0xe89,
0x9fa, 0x76b, 0xdf6, 0x2d0, 0x857, 0x3a3, 0x000, 0xa3e,
0x8cb, 0x35f, 0x4f0, 0x022, 0xb38, 0xc12, 0x93c, 0x2fc,
0x546, 0xe6e, 0x91f, 0x145, 0xfff, 0x1af, 0x957, 0xbde,
0x09d, 0xfd2, 0x9df, 0x2dc, 0x07f, 0x115, 0x7bf, 0xa35,
0x061, 0x9bf, 0xc85, 0x918, 0x0c8, 0x317, 0xce5, 0xf28,
0x108, 0x51b, 0x621, 0x188, 0x000, 0x28c, 0xf67, 0x6ef,
0x000, 0xd72, 0xce2, 0x1be, 0x000, 0x000, 0x282, 0x357,
-1, 0x4e5, 0x246, 0x859, 0x66c, 0x5d3, 0x9fd, 0x000,
0x000, 0x82f, 0xc29, 0x331, 0xa93, 0x000, 0xae4, 0x48a,
0x254, 0x000, 0x0ba, 0xe83, 0x7c7, 0xb6e, 0x88e, 0x774,
0xf6f, 0x85d, 0x47f, 0xcd6, 0xe41, 0xdb6, 0x000, 0x0f4,
0xb4d, 0x77f, 0x000, 0x901, 0x1a2, 0x44a, 0x482, 0x000,
0xe99, 0xa75, 0x000, 0x7ab, 0x000, 0x0b6, 0x35c, 0x306,
0x11c, 0x08e, 0x6eb, 0x11c, 0x771, 0xff9, 0x1c8, 0x63b,
0x58b, 0x9d2, 0x250, 0x198, 0xfe7, 0xebc, 0x000, 0xa97,
0xacc, 0xd4b, 0x28b, 0x892, 0x150, 0xcf4, 0xbc1, 0x000,
0x662, 0xdd8, 0x61f, 0x903, 0x083, 0x000, 0xc55, 0x02f,
0xc29, 0x4f5, 0xbcf, 0xe27, 0x9e3, 0xb13, 0xadc, 0x845,
0x415, 0x0ae, 0x000, 0xe30, 0x931, 0x84a, 0xb09, 0x250,
0x631, 0x7aa, 0x026, 0xdc9, 0x486, 0x3a7, 0xab0, 0xe04,
0xe1a, 0xe17, 0x611, 0x556, 0xfac, 0x3c6, 0x5ab, 0x002,
0xc16, 0xe60, -1, 0xc51, 0x772, 0x67f, 0xfa9, 0x83c,
0x974, 0x96a, 0xe94, 0x250, 0xa20, 0xc95, 0x65b, 0x479,
0xe48, 0xa35, 0x23f, 0x5cf, 0x40a, 0xcf0, 0xe82, 0x1da,
0x390, 0xc86, 0xa92, 0x433, 0xbed, 0x4a7, 0x09a, 0x15a,
0xb8d, 0x9c7, 0x5fb, 0x8a0, 0x000, 0xf9a, 0xf3c, 0x11c,
0x20c, 0xf23, 0x79d, 0xc79, 0xb71, 0x7af, 0xc5b, 0x771,
0x629, 0x834, 0xb34, 0x20c, 0x940, 0x2ca, 0x60b, 0x000,
0x4cb, 0x70b, 0x000, 0x000, 0x9e8, 0x000, 0xdca, 0x000,
0x1ae, 0xb21, 0xfe3, 0x191, 0x9e1, 0x7f6, 0x04f, 0x64a,
0xba2, 0x59e, 0x1ae, 0x000, 0x728, 0x000, 0x081, 0xecd,
0x946, 0x000, 0xdee, 0x3ff, 0xdf9, 0x1bf, 0x01a, 0x1a9,
0xc58, 0xe05, 0x3bf, 0x5e8, 0x39d, 0xbfa, 0x23f, 0xb8d,
-1, 0x000, 0x779, 0x540, 0xf2c, 0x7cc, 0x340, 0x77a,
0xa8e, 0xe8d, 0x2fd, 0xfed, 0x5d1, 0x308, 0x00f, 0xf4a,
0x39b, 0xbe2, 0x0e5, -1, 0xf4d, 0x1fe, 0xf00, 0x867,
0x195, 0x2de, 0x712, 0x000, 0x00c, 0x0a3, 0x1f3, 0x4ee,
0x317, 0x665, 0x000, 0x5d8, 0x291, 0x6c4, 0xa46, 0x492,
0x8d4, 0x647, 0x57f, 0x000, 0x259, 0xd87, 0x5c2, 0x1d8,
0xfad, -1, -1, 0x79f, 0x43a, 0xfd1, 0x164, 0x6e1,
0x350, 0xf00, 0x0e9, 0xac4, 0xe35, 0x307, 0xfff, 0xabb,
0xc1a, 0x768, 0x000, 0x372, 0x839, 0xf4b, 0x1c3, 0xab0,
0xcb6, 0x943, 0xbe9, 0x20f, 0xddc, 0xe18, 0x4eb, 0x21d,
0x530, 0x24c, 0x000, 0xf79, -1, 0x1bd, -1, 0x155,
0x435, -1, 0x132, 0x5c2, 0xb3d, 0x802, 0x733, -1,
0x336, 0xf19, 0xfea, 0xd2a, 0x07f, 0x8e9, 0x000, 0xdab,
-1, 0x088, 0x4b1, 0x7ac, 0x000, 0xe66, 0xde0, 0x73c,
0xfff, 0x02f, -1, 0x000, -1, 0x000, 0x562, 0x389,
0xb20, 0x9ea, -1, 0x3f8, 0x567, 0x035, 0xa55, 0x255,
0xc98, 0x65f, -1, 0x1ac, 0x571, 0x13d, 0xf57, 0x32a,
0xbdb, 0x0ec, 0x47d, 0x43a, -1, 0x1aa, 0x9d6, 0x843,
-1, 0x244, 0xb03, 0xd0d, 0x579, 0x1b1, 0xea7, 0x000,
0x062, -1, 0x533, 0x1db, 0xf1f, 0x2f7, 0x2df, 0x3e5,
0xdec, 0xc5c, 0x55a, 0xf6c, 0x4c1, 0x5a8, 0xcd4, 0x6fd,
0x1a6, 0x4b8, 0x98a, 0xe17, 0xeb9, 0xfd1, -1, 0x175,
0x4d6, 0xba2, 0x000, 0x614, 0x147, 0x429, 0xfee, -1,
0x0d8, -1, 0x98a, 0xdd2, 0xedd, 0x255, 0xef3, 0x345,
0x000, 0xf3e, -1, -1, 0x210, 0x88a, 0x699, -1,
0x02c, 0xfee, 0x1c1, 0xb38, 0x000, 0x7cc, 0x165, 0x536,
-1, 0x1ae, 0xefb, 0x734, -1, 0x1a4, 0x984, 0x804,
0x487, -1, -1, 0x31e, 0x9f2, 0x966, 0x000, 0xcb0,
0x552, 0x0c9, -1, 0x750, 0x650, 0x064, 0xffe, 0xe84,
0x537, 0xee7, 0x834, -1, 0x998, 0xa03, -1, 0xcdf,
0x4be, 0x310, 0x051, 0xf3f, 0x040, 0x973, 0x925, 0x000,
0x000, 0xe51, 0x8b1, 0x468, 0xe11, 0xd4f, 0x374, 0x33a,
0x126, 0x88b, 0x43a, 0xc9b, 0xdb9, 0x3c2, 0x3bd, 0x1ae,
0x000, 0xc4a, 0x000, 0x4c4, 0x859, 0xe5a, 0x000, 0xeb4,
0xd40, 0x87d, 0xc79, 0xe13, 0x50b, -1, 0x724, 0x000,
0x7be, 0x062, 0xe7f, 0xad0, 0x5f3, 0x69e, 0x381, 0x272,
0x50f, 0xac8, 0x053, 0x55e, 0xf19, 0xd71, 0x75b, 0xbf2,
0x000, 0x3ac, 0xdf0, 0xd75, 0x7e3, 0xe75, 0xa13, 0xfd8,
0xbdc, 0x1d9, 0x15f, 0x8cc, 0xba4, 0xb79, 0xb7f, 0x812,
0xfe6, 0x000, 0x2d3, 0xd7b, 0x5d4, 0xad2, 0x316, 0x908,
0x323, 0x758, 0xb0b, 0x965, 0x1a9, 0xdce, 0x660, 0x625,
0xeff, 0x0ed, 0x000, 0x323, 0x986, 0x831, 0x5c5, 0x22f,
0xd49, 0xec6, 0x90e, 0x234, 0x000, 0x80f, 0x16c, 0x528,
0x1f8, 0x2bd, 0x97d, 0xe20, 0xf29, 0x97d, 0x3a0, 0x7fc,
0x086, 0x720, 0x1f9, 0x3eb, 0xf67, 0x423, 0xa55, 0x69e,
0xede, 0x206, 0x7fa, 0x809, 0xfa8, 0xe22, 0x15e, 0x2a0,
0x04a, 0xf7b, 0x4ea, 0xd9a, -1, 0x1d8, 0x0b4, 0xb87,
0x406, -1, 0xcdf, 0x187, 0xf6d, 0x914, 0x4b1, 0x000,
0x104, 0x67e, 0xc74, 0x6da, 0xe67, 0x7d2, 0xd1f, 0x64c,
0x19d, 0x000, 0xa17, 0xfd5, 0x000, 0x8ad, 0xf38, 0xd65,
0xabd, 0x75e, 0x667, 0x632, 0x346, 0xc48, 0xa77, 0x45e,
0x2b5, 0xded, 0x7da, 0x160, 0x560, -1, 0xf4e, 0xb0c,
0xdb0, 0x287, 0x34a, 0x065, 0x439, 0x2ec, 0x679, 0xefa,
0x208, 0xeb1, 0x1b0, 0x8c8, 0xca6, 0x62c, 0xa10, 0x673,
0x000, 0x000, 0xc6a, 0x7b2, 0xbd7, 0xb2b, 0x17a, 0x6f3,
0x1ab, 0xffa, 0x5e0, 0x1fa, 0xb8f, 0xe5c, 0xcab, 0xdbc,
0x10f, 0x000, 0x000, 0xefe, 0x34b, 0x1d9, 0x834, 0x52f,
0xb58, 0x82b, 0x6e8, 0x1f3, 0x719, 0x64e, 0xf55, 0xccd,
0x531, 0x0de, 0x3aa, 0x150, 0x89a, 0x3b9, 0x26e, 0xebc,
0x7ae, 0x670, 0x315, 0x8a9, 0x03b, 0x896, 0x247, 0x2f4,
0x450, 0xd10, 0xb79, 0x0ed, 0x041, -1, 0x707, 0x9e1,
0xed6, 0x6d2, 0x000, 0xfff, 0xb1a, 0x084, 0xaf3, 0x47f,
0x02f, 0xac3, 0x751, 0x8c4, 0x291, 0xadd, 0x000, 0xea1,
0x8ec, 0xf9f, 0x5c2, 0x000, 0xd6b, 0x71e, 0x000, 0xcea,
0x971, 0x5f8, 0x4b9, 0x7c6, 0xb7e, 0x353, 0xd25, 0x423,
0x6ec, 0xb71, 0xf93, 0x000, 0x795, 0xc43, 0xaa2, 0x96a,
0xcbd, 0xb55, 0x184, 0xdf0, 0x3d9, 0xbfe, 0xf79, 0x8f0,
0x22c, 0xeeb, 0x000, 0xa4b, 0xe07, 0xf34, 0xc9d, 0x4be,
0x95b, 0x371, 0x78c, 0x9e9, 0xde6, 0x072, 0xf0d, 0x60b,
0x5a5, 0xab1, 0x000, 0x260, 0x000, 0xd2a, 0xd90, 0x154,
0x4c6, 0x438, 0x5d9, 0x736, 0x062, 0x000, 0x000, 0xb84,
0x72e, 0x0b7, 0x000, 0x050, 0x063, 0xa95, 0x89b, 0x917,
0x049, 0xb14, 0x9a0, 0x734, 0x0c3, 0xd50, 0x917, 0xb02,
0x8cf, 0x453, 0x0af, 0x8e5, 0x000, 0x7aa, 0x5d5, 0x81b,
0x788, 0xb9c, 0x01a, 0x974, 0x000, 0x000, 0x37f, 0xd9f,
0x000, 0xec4, 0x4f4, 0xbff, 0x4fe, 0x860, 0x11c, 0x74e,
0x34a, 0x281, 0x52f, 0xb05, 0xa89, 0xbee, 0x6ad, 0x9fc,
0x9ba, 0xb0b, 0x515, 0x1c7, 0x330, 0xfde, 0x97e, 0x6e7,
0xc45, -1, 0x658, 0x710, 0x28a, 0x921, 0x1de, 0x4a1,
0x9d7, 0xe32, 0xa2d, 0xb0f, 0x545, 0xd6f, 0x329, 0x9b8,
0xb4d, 0x9a0, 0x938, 0x783, 0xfa7, 0xd0a, 0xdc9, 0x0fe,
0x000, 0x249, 0x000, 0x8cd, 0x922, 0x7cd, 0x021, 0xa89,
0x3d5, 0xcee, 0x0a1, 0x6d6, 0x000, -1, 0x48b, 0x000,
0x87a, 0x8bb, 0x9ed, 0x01f, 0xe20, 0xb7f, -1, 0xe95,
0x593, 0x1da, 0x57a, -1, 0xf3a, 0x000, 0x000, -1,
-1, 0x160, 0x501, 0x7a3, 0xb59, -1, -1, 0xc7f,
-1, 0xf79, -1, -1, 0x48d, 0x781, -1, -1,
0xb74, -1, 0x3c4, 0xbe9, -1, -1, 0x9a4, 0x9ae,
0xa75, -1, -1, 0x9cd, 0x000, -1, -1, -1,
0xc3c, 0x2d4, -1, 0x173, 0xf38, 0x000, -1, 0xee9,
-1, 0xb91, 0xcc1, 0x86d, 0x8ab, 0xeb0, 0xec7, 0x687,
0xd98, 0xa95, 0x744, 0xe7c, 0x826, 0x80e, 0x599, 0x3d9,
0xf2f, -1, 0x96a, 0xfd1, 0x174, -1, 0x000, 0x1aa,
0x50e, -1, 0x5a2, 0xbcd, 0x000, -1, 0x019, 0x588,
0x18d, 0x470, 0x812, 0xeec, 0xf63, 0x05c, -1, 0x000,
0xb7f, 0x357, 0x436, 0xbb4, 0x1fb, 0x425, 0x1ed, 0xe13,
0x66c, 0x555, 0xb11, 0x7b5, 0x48d, 0x38d, 0xf72, 0x000,
0x000, 0xa66, 0x4fa, 0xf36, 0x1eb, 0x000, 0x95f, 0x000,
0xd9a, 0x82f, 0x07f, 0x253, 0x70f, 0x915, -1, 0x12d,
0x040, 0x2ca, 0x446, 0x90a, 0x7a8, 0x687, 0x000, 0x04e,
0x74f, 0x1ca, 0x793, 0x3c7, 0x3f0, 0x4c7, 0x000, 0xc30,
0x533, 0x889, 0x9ef, 0xebd, 0x984, 0x18f, 0xfe1, 0x8ea,
0x185, 0x410, 0x107, 0x000, 0x73e, 0xd4b, 0x8fc, 0xd34,
0x1e6, 0x4bf, 0xbac, 0x7c3, 0x000, 0x7c8, 0xb2f, 0x02c,
0xa46, 0x000, 0x0f9, 0x680, 0x94d, 0x6ad, 0x767, 0xfeb,
0x6c7, 0x2d5, 0x43f, 0x9af, 0x261, 0xe83, 0xfa7, 0xb7b,
0xf2d, 0x2f5, 0x4d7, 0x494, 0xbc2, 0x45b, 0x000, 0x17d,
0x5c6, 0xe2b, 0xb20, 0x19e, 0x6ba, 0x973, 0xedd, 0xea8,
0x000, 0x9f3, 0xd9a, 0x7fa, 0xb78, 0x556, 0xbb6, 0xc58,
0x210, 0x000, 0xf9a, 0x56d, 0x48b, 0xf12, 0x000, 0x54d,
0x5f4, 0x1ad, 0x86e, 0xe16, 0x6ff, 0xa35, 0x47e, 0x4c7,
0x93c, -1, -1, 0xc98, 0xd3f, 0x000, 0x788, 0x6ef,
0x959, 0xec2, 0x45e, 0xa4d, 0xa90, 0x000, 0x768, 0x8bb,
0x6ee, 0x7f5, 0x770, 0xfa8, 0xba4, 0xf49, 0x7b8, 0x616,
0x2bd, 0x23f, 0xe8c, 0x9fa, 0xa49, 0x213, 0x98a, 0x2c1,
0x595, 0x885, 0x6de, 0x057, 0x1bc, 0x000, 0xc58, 0x7a8,
0x5c1, 0x3d0, 0xa78, 0xb80, 0x000, 0xc06, -1, 0x428,
0xe92, 0xfa3, 0x341, -1, 0x000, 0x000, 0x1ca, 0x27c,
0xdeb, 0x835, 0x4c8, 0xdb3, 0x000, 0xf9d, 0x000, 0xe81,
0xc22, 0xfce, -1, 0xe6e, 0x96e, 0x161, -1, 0x3b9,
0x945, 0xa95, 0x13d, 0x748, 0x184, 0x588, 0x636, 0xf7e,
0xb44, 0x2b7, 0x217, 0xee5, 0x65a, 0xc47, -1, 0xca3,
0x83e, 0x431, 0xc64, 0x636, 0x06e, 0x404, 0x993, -1,
0xeb3, 0x134, 0x8a3, 0xca9, -1, -1, 0x2ab, 0x000,
0x8ed, 0x877, 0x1a8, 0xc89, 0x000, 0x000, 0xf94, 0x000,
0x709, 0x249, 0x9ac, 0x22a, 0x605, 0x000, 0x000, 0x6b4,
0x00c, 0xc53, 0xf23, 0x005, 0x29f, 0x865, 0xf79, 0x000,
0x5fa, 0x764, 0xe51, 0xbdc, 0xb64, 0x0f3, 0xf29, 0x2f7,
0x5da, 0x000, 0x16f, 0xb8b, 0x255, 0x9cc, 0xe43, 0x279,
0x2c2, 0x483, -1, 0xf7d, 0x7bb, 0x000, 0x9e3, 0xd84,
0xe36, 0x6e6, 0x000, -1, 0x33f, 0x41d, 0x5b5, 0x83e,
0x2f4, 0xf5b, 0x9fc, 0xb1e, -1, 0x8f4, 0xb26, 0x856,
0x3b6, 0x126, 0x4c2, 0x274, 0x0c1, 0xfa9, 0x57d, 0x000,
0x100, 0x7af, 0xc62, 0x000, 0xa55, 0x416, 0x93f, 0x78c,
0xfba, 0x5a2, 0x0c2, 0x4d4, 0xa3e, 0xcc3, 0xe73, 0xd02,
0x8df, 0x3e9, 0xe9a, 0x0f6, 0x32c, 0x23d, 0xdab, 0xf50,
0xfc2, 0x000, 0x065, 0xc23, 0xd3d, 0xc84, 0x35e, 0x000,
0xa24, 0x634, 0x4b4, 0xa52, 0x098, 0xb39, 0x9a4, 0xe71,
0x8aa, 0x741, 0x000, 0xb16, 0x5c2, 0xea1, 0xc01, 0x5c1,
0x30d, 0xca4, 0x201, 0xc9c, 0x717, 0x000, 0xba0, 0x537,
0x619, 0x000, 0xfd9, 0x6dc, 0xdaa, 0x1da, 0xe51, 0xd39,
0xb4c, 0x8a1, 0x098, 0x2f8, 0x191, 0x9dc, 0xdb0, 0x5e1,
0x000, 0xe97, 0xef1, 0x8d3, 0xb0d, 0xfce, 0x336, 0xee1,
0x7a2, 0xbc8, 0x494, 0x580, 0xba7, 0x000, 0x62a, 0x96a,
0x527, 0x859, 0x811, 0xef0, 0x429, 0xef4, 0xf3d, 0x000,
0x9d6, 0xb71, 0x000, 0x14b, 0xf3d, 0xb16, 0x204, 0x0c1,
0xcd4, 0x339, 0x39d, 0xfe3, 0x837, 0x8c7, 0x955, 0x69a,
0x5f6, 0x4c6, -1, 0x3d5, 0x000, 0x0e7, 0x4b1, -1,
0xa3e, 0xb03, 0x1ea, 0xac8, -1, 0x000, 0xed8, -1,
0x4e0, 0x9f7, 0xc91, 0x6b3, -1, -1, 0xa53, 0x290,
0xa64, 0x0e3, 0x3dc, 0xed3, 0xf2f, 0x000, 0xd7c, 0xf44,
-1, 0x205, 0x900, 0x864, -1, -1, 0xed3, 0x7d2,
0x000, -1, 0xdd2, 0x79b, 0x000, -1, 0xae6, 0x5cf,
0xde8, 0x000, 0x1f2, -1, 0x2f3, 0x000, -1, 0x2ce,
0xcf2, 0x8f4, 0xee8, 0x165, 0x309, 0x15f, -1, 0x714,
0xbfc, 0x532, 0xad0, 0x151, 0x2d5, 0x0a4, 0x391, -1,
0x0dc, 0x0c1, 0x451, -1, -1, 0x6a0, 0x250, -1,
0xab8, 0x977, 0xa86, 0x407, 0x72f, -1, 0x05f, 0x000,
0xefe, 0x950, 0x4f4, 0x957, -1, 0xd68, 0x26c, 0xa30,
0x4f1, 0x279, 0x584, 0xb34, -1, 0x4d7, 0x258, 0x000,
0x518, 0x685, 0x91c, 0x3ac, 0x0fa, -1, 0x979, 0x40c,
0x506, 0x000, -1, 0x7bd, 0xb97, 0x87f, 0xc06, 0x050,
0x7bf, 0xe3e, 0xc81, 0x000, 0x65e, 0x000, -1, 0xb76,
0xc37, 0x4c4, 0xfc9, 0x336, 0x9fa, 0xaa2, 0x32c, 0xb8b,
0xaa9, 0xc95, 0x85a, 0xa9a, 0x260, 0x4cd, 0x8fe, 0xd3c,
0x982, 0x0d7, 0xbc1, 0xdcf, 0xe62, 0xe0d, 0xf8f, 0xd7b,
0x91a, 0x3e0, 0x33a, 0x1c5, 0xf00, 0xde5, 0xad1, 0xebc,
0xebc, 0x942, 0xd86, 0x3bf, 0x8ce, 0xb8c, 0x000, 0x8d6,
0x784, 0xb74, -1, 0x818, 0x000, 0xfff, 0x07e, 0x029,
0xf48, 0xb65, 0xd81, 0x220, 0x095, 0x21f, 0xac4, 0xb31,
-1, 0x864, 0x000, 0x3bd, 0xf85, 0x237, 0x369, 0x2d9,
0xfdf, 0x25a, 0x782, 0x7b8, 0xabd, 0x5e3, 0x438, 0x230,
0xbc4, 0x7ad, 0x00a, 0x441, 0x6dc, 0x2c4, 0xf16, 0x0b3,
0x04c, 0xfd2, 0x8aa, 0xad8, 0x3e4, 0x142, 0x585, 0xc8f,
0x9bf, 0x29b, 0xac9, 0x743, 0xfb5, 0x7fc, 0x05e, 0xd38,
0x002, -1, 0xb4e, 0xd0c, 0x84c, 0xf93, 0x91f, 0xcd2,
0x04f, 0x569, 0xd1b, 0xfc6, 0x630, 0x6f6, 0x1d8, 0x91a,
0x4da, 0x9f5, 0x07a, 0xcf5, 0x634, 0x42f, 0xfff, 0x951,
0x0f9, 0xc01, 0x491, 0xbd6, 0x730, 0xfea, 0x9f4, 0xbfc,
0xf1a, 0x413, 0xa2a, 0xdc6, 0xc87, 0x9db, 0xc2c, 0x30f,
0xdb5, 0x785, 0xbaa, 0x000, 0x000, 0xa49, 0x000, 0x61d,
0xf6f, -1, 0x031, -1, 0x441, 0x7bf, 0x53e, -1,
0x6fd, 0x0f6, -1, 0xadb, -1, 0x000, 0x432, 0x187,
0xd37, 0x154, 0x539, 0xc08, 0xe51, 0x219, 0x1e9, 0x897,
0xa0e, 0x201, 0x447, 0x89f, 0x000, 0x463, 0x726, 0xa05,
0xab9, 0xd01, 0x1e4, 0xfea, 0x895, 0x816, 0x313, 0xae3,
0x3a4, -1, 0x70f, -1, 0xa42, 0x5e9, 0x78e, -1,
0x317, 0x6c8, 0x000, 0xbf7, 0xefd, -1, 0xb17, 0x382,
0xd26, 0x5ff, 0xf81, 0x20b, 0x373, 0x774, 0x081, 0xaae,
0xfdb, 0xe5d, -1, -1, 0xcb7, 0x738, 0x919, 0x933,
0x398, 0x000, 0x14e, -1, 0xe14, 0xbf8, 0x11c, 0x94b,
0x031, -1, 0x000, 0x2d4, 0xd41, 0xdc6, 0x9f6, 0xea7,
0x9e8, 0x2ec, 0x10a, 0x50d, 0xeae, 0xdb0, 0xef0, 0x9c8,
0x000, -1, 0x82e, 0x9d3, 0xdb7, 0x46d, -1, 0x230,
0x73b, 0x45b, -1, -1, 0x000, 0x4a7, -1, -1,
0x47c, 0x10e, 0x4b4, -1, -1, -1, 0x1d7, 0xa5d,
0x233, 0x6b2, 0x6bd, 0x387, 0x7ca, 0xb1a, 0xf75, 0xea4,
0xdc9, 0x98b, 0x80c, 0x702, 0xe22, 0xa6e, 0x6f8, 0x05b,
0x17c, -1, 0x000, 0xebe, 0xc8e, 0xaec, -1, 0x42b,
0xdce, -1, -1, -1, 0xef3, 0xc52, 0x31b, -1,
0xdff, 0xbd0, 0x000, 0xa72, 0x525, 0x9cf, 0x2ff, 0xfc8,
0x37c, 0xbce, 0xd8c, 0xd88, 0x3a6, 0xed8, 0x4ab, 0x000,
0x449, 0x9d7, -1, -1, 0x9be, 0x59f, 0x000, 0x882,
-1, 0x742, 0x000, -1, -1, -1, 0xe8b, 0x0f3,
0x771, -1, 0x3ea, 0x8f9, 0xcbb, 0x548, 0x46d, 0x000,
-1, 0xf74, 0xa23, 0x15b, -1, 0xaeb, 0x7f8, 0xbe2,
0x000, -1, 0x023, 0x61e, 0x95d, 0x7ac, 0x024, 0x141,
0x561, 0x9fe, 0xb10, -1, 0x623, 0xc47, 0x413, 0x0e7,
0x663, 0xcdf, 0xebe, 0x5c9, 0x573, 0x21d, 0xb28, 0x280,
0xb9f, 0xd1a, 0xecf, 0xff0, 0x000, 0xfc0, 0x085, 0x9c4,
0x48c, 0x000, 0xb0b, 0x43d, -1, 0x73b, 0x802, 0x633,
0x6ef, -1, -1, 0x5c1, 0xea6, 0x0a9, 0xab4, 0xacd,
0xb81, 0xa32, -1, -1, 0xa26, 0x9d5, 0xf7c, -1,
0xf69, 0xdbb, 0x6d5, 0x405, -1, 0xd0a, 0xfe0, 0xf5e,
0xbd7, -1, 0x89a, 0x868, 0xeb2, 0x792, 0x7fe, 0x115,
0x000, 0x8bb, 0xdd1, 0xc40, 0x453, 0xbb3, 0x7cc, 0x3e6,
0x071, 0x0f1, 0xbae, 0xf67, 0x896, 0x38e, 0x86e, 0xfaa,
0xccc, -1, 0x411, 0x8e5, 0x699, 0x2ef, 0x785, 0x9d4,
0xe30, 0xb2e, 0x976, 0x203, 0x035, 0x75d, 0x8f1, 0x144,
0x092, 0x1a5, -1, 0x55f, 0x000, 0xa43, 0x5be, 0x68d,
0x852, 0xb87, 0x9af, 0x0c0, -1, 0xa50, 0x9ca, 0x15f,
0xf06, 0x869, 0x0f3, -1, 0x000, -1, 0x9a9, -1,
-1, -1, -1, 0xf05, 0x000, -1, 0x000, 0x4a9,
0xf9d, -1, 0x000, 0xab1, 0x04c, -1, 0xd17, 0x893,
0x763, 0x332, -1, 0xc41, 0x5bd, 0xa72, 0x67c, 0xb78,
0x973, 0x6c7, 0x569, -1, 0x96a, 0xc68, 0x48c, -1,
0x6fa, -1, 0xa2a, 0x44f, -1, 0x73f, 0x28f, 0x536,
0xd91, 0xc86, 0xef8, 0x1f5, 0xfb4, 0x060, 0x230, 0xe10,
-1, 0x000, 0x305, 0x0e6, 0xb19, 0x1e2, 0x7fc, 0xf35,
-1, 0x7d9, 0x000, 0x000, 0xd2f, 0xb3a, 0x0a2, 0x7c9,
0xda6, 0x37c, 0xe43, -1, 0x7da, 0x0d6, 0x000, -1,
0xd40, -1, 0x156, 0xee9, -1, 0x239, 0x10f, 0x60c,
0x9d4, 0x663, 0x565, 0x603, 0x38b, -1, 0x606, 0x13c,
0x681, 0x436, 0xc29, 0x9c7, 0x1d9, 0x000, 0x0a6, 0x996,
0x231, 0x055, 0x01f, 0x0a3, 0xd96, 0x7c8, 0x0f3, 0xaa7,
0xd99, -1, 0x3be, 0x476, 0x25f, 0x38c, 0xdf3, 0x6d5,
0xcb5, 0xadd, 0x000, 0x136, 0x64d, 0xc0d, 0xe61, 0xd0b,
-1, 0x000, 0x535, 0x9c3, 0x279, 0x00c, 0xa87, 0xa31,
0xc4a, 0x167, 0x423, 0xec8, -1, 0x926, 0xa4d, 0x5ba,
-1, -1, 0x9bf, 0x000, 0x47f, 0x8f3, 0xd5b, 0xc3b,
0xa18, -1, 0x548, 0x8f7, 0x8cf, 0x000, 0x9bd, 0xaa2,
0x7ec, 0x000, 0xfb8, 0xafd, 0xe68, -1, 0xfa7, 0x31c,
0xef3, 0x288, 0xdf0, 0x1bc, 0xfe9, 0x1ea, 0xa9f, 0x000,
0x53f, 0x000, 0xda6, 0x09c, 0x1bf, 0x09c, 0x31c, 0x0c8,
0x31c, -1, 0x689, 0x211, -1, 0x77f, 0x723, 0xb8f,
0x683, 0x351, -1, 0xb33, 0xce0, -1, 0x61c, 0x073,
0x783, 0x6b2, 0x6a8, 0x729, 0x81b, 0xabf, 0xd15, 0x563,
0x433, -1, 0x823, 0xf99, 0x2c5, -1, 0x367, 0xcc4,
0x934, 0x6f2, 0xdf0, 0xa1f, 0x579, 0x012, -1, 0x508,
0x070, -1, 0x018, 0x270, 0xa6f, -1, 0x7a7, -1,
0x826, 0x4b5, -1, 0x7d8, 0xb20, -1, 0xc28, 0x463,
-1, 0xdf9, 0x22c, 0xe17, 0x4f2, 0xe13, 0x4ff, 0x40a,
0xdcb, 0x9ed, 0x34a, 0xeb8, 0xa0e, 0x5f2, 0x594, 0x60d,
0x4b6, 0xd3c, 0x675, 0x1c4, 0xbb5, 0xc73, 0xfad, 0xead,
-1, 0xfb6, -1, 0x146, 0xd40, 0x02f, 0x000, 0x302,
-1, -1, 0x6e5, 0x000, 0xed7, 0xd8c, 0x7a3, 0x0fc,
0x259, 0x34b, 0xa1b, 0x882, -1, 0x211, 0x000, 0xd30,
0xe02, 0x5cd, 0x53e, 0x11b, 0xa16, -1, 0x24e, -1,
0xace, 0xe9a, -1, 0x5c6, 0x9be, 0x000, 0x169, 0x982,
-1, 0x3fd, 0x457, 0x06f, 0x7e7, 0xed1, 0x5ee, 0xcef,
0x62b, 0x26c, 0xc9f, 0xe68, 0x59f, 0x0b5, 0x000, 0x0bc,
0x086, 0x890, 0x005, 0xc42, 0x939, 0xaca, 0xdd9, -1,
-1, 0x6e5, 0x0dd, 0x434, 0x297, 0xe21, 0x0f5, -1,
0xa6c, 0x4ad, 0x978, 0x433, 0xa41, 0xd6f, 0x8bf, 0xfb8,
-1, 0x928, 0x85e, 0xfb6, 0x5c7, 0x99a, 0x8ec, 0xebc,
0x226, 0x7d4, 0xdcd, 0xc0b, 0x000, 0x7f4, 0xc6f, 0x000,
0x3ad, 0x5b2, -1, 0x67b, -1, 0x568, 0x6e2, -1,
-1, -1, 0x3f3, 0xaf5, 0x33f, -1, 0x022, 0x1bd,
0xae5, -1, 0x9c3, 0x000, 0x92b, 0xee5, 0x29c, 0x000,
0x15e, 0xe71, 0xacb, 0x9d2, 0x1a3, 0xb7f, 0xa5b, 0x095,
-1, 0xb6e, 0x79f, 0x3d1, 0x7d0, 0x131, 0xcd7, -1,
0x2c3, -1, 0x396, 0x4d2, 0x297, 0x405, 0x634, -1,
-1, -1, 0x928, 0xbca, 0xb6c, 0x011, 0xfc0, 0xbaf,
0xbd2, -1, 0x585, 0x000, 0xb8a, 0x7f9, 0xd6b, 0x4eb,
0x9a3, 0x000, -1, 0xaeb, 0xa47, 0xcef, 0x9c6, -1,
0x000, -1, 0x2a9, 0x371, 0xca6, -1, 0xb7d, 0x15f,
0x2a9, -1, 0xe80, 0x7a7, 0x23a, 0x000, 0x000, 0xcc9,
0x60e, -1, 0x130, 0x9cd, 0x498, 0xe25, 0x366, 0x34b,
0x899, 0xe49, 0x1a8, 0xc93, 0x94d, 0x05e, -1, 0x0c2,
0x757, 0xb9d, 0xaa3, 0x086, 0x395, 0x3c3, 0xa2e, 0xf77,
0xcb1, 0x45e, 0x169, 0xbba, 0x367, 0x8cb, 0x260, 0x5a0,
0x8cb, 0x737, 0xa1f, 0xaaf, 0xf92, 0x430, 0x97d, 0x542,
0xb09, -1, 0x774, 0x084, 0x4c0, 0x2b3, 0xaf6, 0x93c,
0x32d, 0xee2, -1, 0x605, 0xece, 0x8eb, 0xc62, 0x01d,
0x000, 0xaba, 0xfc5, 0xb8e, 0xc07, 0xfb6, 0xbca, 0x8f0,
0xd33, -1, 0x283, 0x6d6, 0x6ad, 0x678, 0x51a, 0xc95,
0xda4, 0x962, 0x9ed, 0x307, 0x94a, 0x052, 0xf4e, 0x3bd,
0x210, 0x71a, 0x3c7, 0x5a4, 0x6e7, 0x23a, 0x523, 0x1dc,
0x6b2, 0x5e0, 0xbb0, 0xae4, 0xdb1, 0xd40, 0xc0d, 0x59e,
0x21b, 0x4e6, 0x8be, 0x3b1, 0xc71, 0x5e4, 0x4aa, 0xaf3,
0xa27, 0x43c, 0x9ea, 0x2ee, 0x6b2, 0xd51, 0x59d, 0xd3a,
0xd43, 0x59d, 0x405, 0x2d4, 0x05b, 0x1b9, 0x68b, 0xbfa,
0xbb9, 0x77a, 0xf91, 0xfcb, -1, 0x949, 0x177, 0x68d,
0xcc3, 0xcf2, 0x000, 0xa87, 0x2e6, 0xd2f, 0x111, 0x168,
0x94c, 0x54c, 0x000, 0x0c5, 0x829, 0xcbc, 0xc0b, 0x1ed,
0x836, 0x9d8, 0xbdc, 0xc5e, 0x4e5, 0xb94, 0x6f2, 0x74f,
0x878, 0x3b2, 0x48d, 0xc72, 0xcff, 0xccb, 0x8f9, 0x7ee,
0x869, 0x228, 0x035, 0x81e, 0xcf9, 0x309, 0xdf2, -1,
0x047, 0xdd3, 0xcab, 0x11d, 0xe76, 0xb52, 0xbbd, 0x12d,
0xf37, 0x552, 0x61d, 0xdd8, 0x2cd, 0x298, 0x9e2, 0xf2c,
0x9f7, 0xf41, 0xcb4, 0x277, 0xfde, 0xe7e, 0x82a, 0x86b,
0x9cc, 0x580, 0xfcc, 0x33a, 0x438, 0xd6e, 0x000, 0xc04,
0xd50, 0x681, 0x1b3, 0x322, 0x86c, 0x4a6, 0x000, 0xa17,
0xd53, 0xdc0, 0xb61, 0x323, 0x3d1, 0x3fb, 0x929, 0xa6e,
0x919, 0xae0, 0x283, 0xe6a, 0xed3, 0x371, 0xd51, 0x309,
0x510, 0xd50, 0x6f4, 0xc84, 0x566, 0xba7, 0x75b, 0xbeb,
0x793, 0x58f, 0x974, 0xe77, 0x52c, 0xcef, 0x942, 0xa7c,
0x56a, 0xaa0, 0x784, 0x0ec, 0xad3, 0xccf, 0xecf, 0xc3f,
0x846, 0x1b2, 0x112, 0x4ee, 0x18b, 0xa76, 0xe14, -1,
0xfb1, 0xb4c, -1, 0xd54, 0x0e0, 0x72d, 0xdf0, 0xf0c,
0x881, 0xc60, 0xe1b, 0x000, 0x453, 0xe21, 0xb2a, 0x6df,
0x84f, 0x000, 0x12a, 0x991, 0x587, 0xa4e, 0x522, 0x000,
0xe17, 0xc64, 0x994, 0x4cc, 0x0e5, 0xc2b, 0x8cf, 0x458,
0x992, 0xec0, 0xc80, 0xefb, 0x7b7, 0x863, 0xc0a, 0x250,
0x338, 0xa44, 0x8ab, 0x873, 0x134, 0x23c, 0x4f6, 0x066,
0xd0f, 0xdd6, 0x93d, 0xf20, 0x000, 0x9bb, 0x255, 0xe7b,
0x916, 0x4f3, 0x68e, 0xb82, 0x2b4, 0x9d7, 0xfd1, 0x0fb,
0x11e, 0x204, 0x241, 0x67f, 0x1c4, 0xe91, 0xf41, 0xb4a,
-1, 0x6d2, 0xce6, 0xdfb, -1, 0xdd0, 0xb8d, 0x8db,
0x86c, 0x224, 0xdeb, 0x7bb, 0x50e, 0x000, 0xb79, 0x11e,
0x486, 0xd4c, 0x000, 0xa54, 0x946, 0x83a, 0x537, 0x875,
0x000, 0x8e4, 0x95a, 0xdd5, 0x9d5, 0x910, 0x95b, 0x8c8,
0xd22, 0x07c, 0xac0, 0x000, 0x048, 0x170, 0x9b2, 0xcea,
0xb0f, 0x958, 0x0f9, 0xa9e, 0x87a, 0x166, 0x69c, 0x112,
0xde0, 0x487, 0xeca, 0x639, 0x4ee, 0x7fa, 0x2cc, 0x709,
0x87a, 0x5bb, 0xf64, 0x173, 0xdc6, 0xaaf, 0xbff, 0xf2a,
0x8fb, 0xd44, 0x0ca, 0xf34, 0xb3a, 0xeb3, 0xfc5, 0x61d,
0x92f, 0x6fb, 0x1a1, 0xd85, 0x8fe, 0xb6a, 0x0a1, 0x44f,
0x89a, 0xc5d, 0x13b, 0x5cc, 0x000, 0x9ac, 0x9e6, 0xf95,
0x511, 0xf2e, 0xf3c, 0x707, 0xec5, 0xaec, 0xc72, 0xeb1,
0x105, 0xda3, 0xbcb, 0x1d6, 0xf16, 0xd50, 0x306, 0x03f,
0xe6a, 0x25c, 0x9fe, 0xd3f, 0x8a4, 0x7bc, 0x0bc, 0x532,
0x62e, 0x111, 0x797, 0xc2c, 0x9d0, 0x338, 0xbc7, 0xd64,
0xb09, 0x4d6, 0xcba, 0x62c, 0xef2, 0x32b, 0x9c5, 0xc06,
0x38b, 0xbb2, 0x8b7, 0x6f2, 0x7ec, 0xa77, -1, 0x7a3,
0xc95, 0xa91, 0x5d3, 0xffc, -1, 0xe27, 0xa0a, 0x071,
0x9da, 0x000, 0xba3, 0x3fd, 0x120, 0x845, 0x151, 0xb5f,
0x193, 0xe99, 0x0f6, 0x640, 0xef4, 0xe17, 0x46b, 0x432,
0x8a4, 0x415, 0x252, 0x79c, 0xbe5, 0x3f0, 0xb64, 0x984,
0x5a7, 0x1be, 0xedc, -1, 0xd7e, 0x5b4, -1, 0xd27,
0x03e, 0x136, 0xb30, 0xfff, 0x1dc, 0xc32, 0x84a, 0x392,
0xf4f, 0x911, 0x501, 0x836, 0x700, 0x9ac, 0x000, 0xdb5,
0xfa3, 0x5d3, 0x1f8, 0x888, -1, 0xfa4, 0xfe7, 0xd87,
0x9fe, 0x6af, 0x9a5, 0xfd5, 0xf49, 0xded, 0x416, 0x2fc,
0x078, 0xd2e, 0xbf1, 0xcd9, 0x733, -1, 0xb50, 0xd57,
0xaa1, -1, 0x9b0, 0x874, 0x18f, -1, -1, 0x2f9,
0xfbb, 0xf73, 0x646, 0x868, 0x000, 0x000, 0xba2, 0xd74,
0xc8f, 0xe36, 0xcfd, 0x5b8, 0x850, 0x48a, 0x689, 0x7ad,
0xefd, 0x7e1, 0xf45, 0xd9e, 0x0f0, 0x7c0, 0x675, -1,
0xf26, 0x3c0, 0xe2d, 0xb62, 0x276, -1, 0xf90, 0x837,
0xc7c, 0x8ed, 0x08d, 0x1d6, 0x506, 0xac9, 0xd81, 0x1be,
0xf7e, 0x1a3, 0xb2a, 0x5e2, 0x217, 0x1df, 0x5a3, 0x498,
0xfb1, 0x432, 0x2ca, 0x5a1, 0x5d5, 0x135, 0x6f0, -1,
0xf70, 0x000, 0xd4c, 0x634, -1, 0x8ca, 0x198, -1,
0x7b9, 0x629, 0xc16, 0x68c, 0xea2, -1, 0xba0, 0x6d9,
0xce9, 0x7b2, 0x000, 0xf59, 0x252, 0x575, 0x0a8, 0x894,
0x000, 0x824, 0xf63, 0xd70, 0xdd8, 0x856, 0xc77, 0x334,
0xeb2, 0x2b8, 0x307, 0xc34, 0x2e7, 0xa74, 0x6b9, 0x0e1,
0x20f, 0x3ee, 0xf80, 0xa1f, 0x6e6, 0xa03, 0x3c7, 0x72f,
0xfff, 0x156, 0x273, 0x1b7, 0xd90, 0x998, 0x474, 0xf1b,
0x80f, 0xe4c, 0x0ba, 0xfff, 0x85e, 0x3af, 0x58f, 0x000,
0xf6b, 0x71c, 0x4ed, 0xec3, 0x4cb, 0x000, 0xa68, 0x6ca,
0x086, 0x000, 0x6e4, 0xab3, 0xff5, 0x281, 0xf0a, 0xc92,
0x8d5, 0x486, 0xdd1, 0x903, 0x8e3, 0x9df, 0x2ab, 0xd08,
0x144, 0xdcd, 0x281, 0x046, 0x161, 0xe83, 0xf24, 0xce7,
0x30a, 0xf89, 0xf01, 0x308, 0x142, 0x9df, 0x44d, 0x9dd,
0x3ed, 0x81b, 0xd9d, 0x000, 0x8c2, 0xe01, 0xfe6, 0xa20,
0x167, 0xedd, 0xdb1, 0x470, 0xe70, 0x3aa, 0x0ff, 0x4d1,
0xd30, 0x67a, 0xc56, 0x3d8, 0xf2e, 0x86a, 0x18b, 0x3f5,
0x1a7, 0xd97, 0x652, 0x000, 0x00d, 0xbc7, 0xed3, 0x39e,
0xb0d, 0xd8d, 0xc49, 0x2db, 0x44e, 0x820, 0x189, 0xd51,
0x523, 0x161, 0x2eb, 0x41c, 0x951, -1, 0xbb7, -1,
-1, 0x0a7, 0x3ed, 0xfaa, 0x18e, 0xa34, 0x820, 0x2b4,
-1, 0x8c2, 0x3ee, 0x59d, 0x97b, 0x209, 0x3a2, 0x102,
0x351, 0x6bf, 0xd3f, 0x4fc, 0x55f, 0x4b5, 0xe22, 0xf13,
0x53a, 0x08a, 0x38d, 0xf4b, 0x424, 0xea6, 0x48e, 0x11c,
0x339, 0x5bd, 0xf7c, 0x3bd, 0x15a, 0x35c, 0x854, 0x71b,
0x30f, 0x065, 0x97e, 0x354, 0x28e, 0x344, 0x926, 0xc0b,
0xae0, 0x5db, 0xb3e, 0x661, 0x432, 0x3c8, 0xf5e, 0x368,
0xc85, 0xfff, 0x7f5, 0x0b6, 0x98b, -1, 0x28c, 0x784,
0xb78, 0x50a, 0x696, 0x47c, 0x40d, -1, 0xe4d, 0x5fc,
-1, -1, 0xadb, 0x1db, 0x830, 0xd48, -1, 0xf3a,
0xee4, 0xed4, 0xb1a, 0xa14, 0x36d, 0xf1c, 0x774, 0x000,
0x942, 0x278, 0x7ee, 0x000, 0x550, 0x57c, 0x343, 0x22b,
0x324, 0xa34, 0x0ea, 0x230, 0x51b, 0x2d1, 0x500, 0x59f,
0xd56, 0x540, 0x2f4, 0x87d, 0x9e5, 0x9c5, 0x5ea, 0x771,
0x491, 0x206, 0xa4b, 0x4bf, 0xdaf, 0x308, 0xb25, 0x261,
0x991, 0x000, 0x88e, 0x7e8, 0x3d6, 0x15d, 0xebc, 0x6c2,
0xd45, 0x000, 0x3c6, 0x48d, 0x622, 0x758, 0xfa9, 0x3cf,
0x401, 0xcdb, 0xe3f, 0x544, 0xf1f, 0x000, -1, 0x4d4,
0x000, 0x7f1, 0xba4, 0x81c, 0x92f, 0x7d1, 0xa83, 0xa31,
0xe74, 0xa20, 0x475, 0x489, 0xf20, 0x3d1, 0xac1, 0xb2d,
0x6b2, 0x1b6, 0x063, 0xd00, 0xfeb, 0x5ca, 0xb2c, 0xcb2,
0x1cb, 0x251, 0x82b, 0x8ba, 0x40b, 0xf1e, 0xa8a, 0xd24,
0x880, 0x84e, 0x8cb, 0x0a3, 0x000, 0xaf7, 0xf99, 0x6a1,
0x156, 0x382, 0x0a0, 0x000, 0xed1, 0xd07, 0xbf5, 0x000,
0x295, 0xe48, 0x760, 0x019, 0x97f, 0xb46, 0xff5, 0x7c9,
0x1cf, 0xba4, 0x630, 0xe58, 0xda6, 0xd4b, 0xc02, 0xf9f,
0x11c, 0x000, 0xb99, 0x51f, 0x43e, 0x199, 0xdfb, 0x72f,
0x913, 0x509, 0xac5, 0xa2e, 0xcdb, 0x348, 0xb15, 0x472,
0x95d, 0x67f, 0x000, 0x4b9, 0xd78, 0xc87, 0x0f6, 0x281,
0x0bd, 0x924, 0x35e, 0x129, 0xffd, 0xe24, 0x000, 0x640,
0x09b, 0xd10, 0xa0d, 0x000, 0x474, 0x189, 0x49f, 0x62d,
0xcba, 0x561, 0x000, 0x58a, 0xaa1, 0x603, 0x5ab, 0x0c7,
0x00a, 0x784, 0x5e4, 0x7e4, 0xe4d, -1, 0x276, 0x465,
0xee9, 0xe51, 0xdae, 0xbb1, 0x51f, 0xcba, 0x1c3, 0xd70,
0x000, 0x5be, 0x4ea, 0x3cc, 0xf13, 0x811, 0x813, 0x234,
0x7e4, 0xbae, 0xd97, 0xb74, 0x000, 0x76a, 0xda1, 0x000,
0xd8c, 0x53a, 0xc5a, 0x000, 0x000, 0x61b, 0xd87, 0x141,
0x383, 0xe06, 0x6a3, 0x6c3, 0xbcc, 0xc44, 0xf63, 0xd8b,
0x58d, 0x000, 0x839, 0x77a, 0x000, 0x8e4, 0x000, 0xdbe,
0x483, 0xd5b, 0xa9d, 0xca5, 0x431, 0x491, 0x29a, 0x27d,
0x2d2, 0x691, 0x000, 0x19a, 0xa0d, 0xb0b, 0xf32, 0xe49,
0xfbf, 0x399, 0xd20, 0x000, 0x66a, 0x000, 0x447, 0xb20,
0x894, 0x038, 0xc9c, 0xff0, 0x000, 0x0d4, 0xad4, 0x768,
0x65c, 0x000, 0x27b, 0x6c6, 0x9be, 0xd35, 0xc6a, 0xdd3,
0x000, 0x2a7, 0x158, 0x38d, 0x8ef, 0x7b6, 0xd49, 0x30c,
0xec3, 0x211, 0x17c, 0xcd0, 0x61f, 0x000, 0xe6e, 0x1d4,
0x6e9, 0x000, 0xc2d, 0x5c3, 0xcd4, 0x760, 0x532, 0xc94,
0x590, 0x000, 0x4a3, 0xc33, 0x000, 0x426, 0x604, 0xa06,
0xa99, 0x917, 0x0c4, 0xc8d, 0x9e5, 0xcc7, 0x415, 0xf79,
0x000, 0xaf4, 0x622, 0x756, 0x9c2, 0xa51, 0xb0f, 0x4ef,
0xbc4, 0xe15, 0x29e, 0x055, 0x6c9, 0x695, 0x94f, 0x9d6,
0x000, 0xb9f, 0xd46, 0x1d4, 0x000, 0xcb2, 0x9e8, 0x000,
0xa5e, 0xce0, 0x000, 0x098, 0xa98, 0x6d9, 0x5e2, 0x95f,
0x791, 0xeb8, 0x5fa, 0x60a, 0xacc, 0x3d3, 0x4df, 0x0df,
0x9ca, 0x972, 0x3cc, 0x583, 0xca5, 0xe1a, 0x000, 0x2d3,
0x266, 0x000, 0x06c, 0xfff, 0x62d, 0x64e, 0x40c, 0x599,
0x475, 0xaa9, 0xba6, 0x96f, 0xe32, 0x059, 0x342, 0x36d,
0xfd1, 0x09b, 0x878, 0x9f8, 0x000, 0x3ad, 0xdba, 0x000,
0x544, 0xc1a, 0x000, 0xee8, 0x492, 0xa6b, 0x447, 0xd2a,
0xb4e, 0x02c, 0xadb, 0xde2, 0x904, 0x62d, 0xf01, 0xbb8,
0x255, 0x382, 0xfff, 0x29e, 0x000, 0x000, 0x011, 0xfff,
};
#endif
+106
View File
@@ -0,0 +1,106 @@
/*------------------------------------------------------------------------
* Copyright 2009-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
#include <zbar_config.h>
#include <assert.h>
#include <zbar.h>
#ifdef DEBUG_QR_FINDER
# define DEBUG_LEVEL (DEBUG_QR_FINDER)
#endif
#include "debug.h"
#include "decoder.h"
/* at this point lengths are all decode unit offsets from the decode edge
* NB owned by finder
*/
qr_finder_line *_zbar_decoder_get_qr_finder_line (zbar_decoder_t *dcode)
{
return(&dcode->qrf.line);
}
zbar_symbol_type_t _zbar_find_qr (zbar_decoder_t *dcode)
{
qr_finder_t *qrf = &dcode->qrf;
unsigned s, qz, w;
int ei;
/* update latest finder pattern width */
qrf->s5 -= get_width(dcode, 6);
qrf->s5 += get_width(dcode, 1);
s = qrf->s5;
/*TODO: The 2005 standard allows reflectance-reversed codes (light on dark
instead of dark on light).
If we find finder patterns with the opposite polarity, we should invert
the final binarized image and use them to search for QR codes in that.*/
if(get_color(dcode) != ZBAR_SPACE || s < 7)
return(0);
dbprintf(2, " qrf: s=%d", s);
ei = decode_e(pair_width(dcode, 1), s, 7);
dbprintf(2, " %d", ei);
if(ei)
goto invalid;
ei = decode_e(pair_width(dcode, 2), s, 7);
dbprintf(2, "%d", ei);
if(ei != 2)
goto invalid;
ei = decode_e(pair_width(dcode, 3), s, 7);
dbprintf(2, "%d", ei);
if(ei != 2)
goto invalid;
ei = decode_e(pair_width(dcode, 4), s, 7);
dbprintf(2, "%d", ei);
if(ei)
goto invalid;
/* valid QR finder symbol
* mark positions needed by decoder
*/
qz = get_width(dcode, 0);
w = get_width(dcode, 1);
qrf->line.eoffs = qz + (w + 1) / 2;
qrf->line.len = qz + w + get_width(dcode, 2);
qrf->line.pos[0] = qrf->line.len + get_width(dcode, 3);
qrf->line.pos[1] = qrf->line.pos[0];
w = get_width(dcode, 5);
qrf->line.boffs = qrf->line.pos[0] + get_width(dcode, 4) + (w + 1) / 2;
dbprintf(2, " boff=%d pos=%d len=%d eoff=%d [valid]\n",
qrf->line.boffs, qrf->line.pos[0], qrf->line.len,
qrf->line.eoffs);
dcode->direction = 0;
dcode->buflen = 0;
return(ZBAR_QRCODE);
invalid:
dbprintf(2, " [invalid]\n");
return(0);
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef _DECODER_QR_FINDER_H_
#define _DECODER_QR_FINDER_H_
#include "qrcode.h"
/* QR Code symbol finder state */
typedef struct qr_finder_s {
unsigned s5; /* finder pattern width */
qr_finder_line line; /* position info needed by decoder */
unsigned config;
} qr_finder_t;
/* reset QR finder specific state */
static inline void qr_finder_reset (qr_finder_t *qrf)
{
qrf->s5 = 0;
}
/* find QR Code symbols */
zbar_symbol_type_t _zbar_find_qr (zbar_decoder_t *dcode);
#endif