summaryrefslogtreecommitdiffstats
path: root/zbar/decoder/i25.c
diff options
context:
space:
mode:
Diffstat (limited to 'zbar/decoder/i25.c')
-rw-r--r--zbar/decoder/i25.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/zbar/decoder/i25.c b/zbar/decoder/i25.c
new file mode 100644
index 0000000..8fdea25
--- /dev/null
+++ b/zbar/decoder/i25.c
@@ -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 "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)
+{
+ unsigned char enc = 0, par = 0;
+ signed char i;
+
+ i25_decoder_t *dcode25 = &dcode->i25;
+ dbprintf(2, " s=%d", dcode25->s10);
+ if (dcode25->s10 < 10)
+ return (0xff);
+
+ /* threshold bar width ratios */
+ 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)
+{
+ unsigned char enc = 0;
+ unsigned char i = 10;
+ unsigned quiet;
+
+ i25_decoder_t *dcode25 = &dcode->i25;
+ if (dcode25->s10 < 10)
+ return (ZBAR_NONE);
+
+ 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)
+ */
+ 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)
+{
+ unsigned char E;
+ 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 */
+ 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) {
+ int i;
+ /* reverse buffer */
+ dbprintf(2, " (rev)");
+ 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)
+{
+ unsigned char c;
+ unsigned char *buf;
+
+ 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);
+
+ 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;
+ }
+
+ 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);
+}