Zoltan Hudak / zbar

Dependents:   BarcodeReader_F103

Files at this revision

API Documentation at this revision

Comitter:
hudakz
Date:
Fri Jan 10 20:29:52 2020 +0000
Child:
1:4f5c042a2d34
Commit message:
Streamlined barcode reader library.

Changed in this revision

config.c Show annotated file Show diff for this revision Revisions of this file
config.h Show annotated file Show diff for this revision Revisions of this file
debug.h Show annotated file Show diff for this revision Revisions of this file
decoder.c Show annotated file Show diff for this revision Revisions of this file
decoder.h Show annotated file Show diff for this revision Revisions of this file
decoder/code128.c Show annotated file Show diff for this revision Revisions of this file
decoder/code128.h Show annotated file Show diff for this revision Revisions of this file
decoder/code39.c Show annotated file Show diff for this revision Revisions of this file
decoder/code39.h Show annotated file Show diff for this revision Revisions of this file
decoder/ean.c Show annotated file Show diff for this revision Revisions of this file
decoder/ean.h Show annotated file Show diff for this revision Revisions of this file
decoder/i25.c Show annotated file Show diff for this revision Revisions of this file
decoder/i25.h Show annotated file Show diff for this revision Revisions of this file
include/zbar.h Show annotated file Show diff for this revision Revisions of this file
include/zbar/Decoder.h Show annotated file Show diff for this revision Revisions of this file
include/zbar/Scanner.h Show annotated file Show diff for this revision Revisions of this file
include/zbar/Symbol.h Show annotated file Show diff for this revision Revisions of this file
refcnt.c Show annotated file Show diff for this revision Revisions of this file
refcnt.h Show annotated file Show diff for this revision Revisions of this file
scanner.c Show annotated file Show diff for this revision Revisions of this file
symbol.c Show annotated file Show diff for this revision Revisions of this file
symbol.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config.c	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,148 @@
+/*------------------------------------------------------------------------
+ *  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
+ *------------------------------------------------------------------------*/
+
+#include <config.h>
+#include <stdlib.h>     /* strtol */
+#include <string.h>     /* strchr, strncmp, strlen */
+#include <errno.h>
+#include <assert.h>
+
+#include <zbar.h>
+
+int zbar_parse_config (const char *cfgstr,
+                        zbar_symbol_type_t *sym,
+                        zbar_config_t *cfg,
+                        int *val)
+{
+    if(!cfgstr)
+        return(1);
+
+    const char *dot = strchr(cfgstr, '.');
+    if(dot) {
+        int len = dot - cfgstr;
+        if(!len || (len == 1 && !strncmp(cfgstr, "*", len)))
+            *sym = ZBAR_NONE;
+        else if(len < 2)
+            return(1);
+        else if(!strncmp(cfgstr, "qrcode", len))
+            *sym = ZBAR_QRCODE;
+        else if(len < 3)
+            return(1);
+        else if(!strncmp(cfgstr, "upca", len))
+            *sym = ZBAR_UPCA;
+        else if(!strncmp(cfgstr, "upce", len))
+            *sym = ZBAR_UPCE;
+        else if(!strncmp(cfgstr, "ean13", len))
+            *sym = ZBAR_EAN13;
+        else if(!strncmp(cfgstr, "ean8", len))
+            *sym = ZBAR_EAN8;
+        else if(!strncmp(cfgstr, "i25", len))
+            *sym = ZBAR_I25;
+        else if(len < 4)
+            return(1);
+        else if(!strncmp(cfgstr, "scanner", len))
+            *sym = ZBAR_PARTIAL; /* FIXME lame */
+        else if(!strncmp(cfgstr, "isbn13", len))
+            *sym = ZBAR_ISBN13;
+        else if(!strncmp(cfgstr, "isbn10", len))
+            *sym = ZBAR_ISBN10;
+#if 0
+        /* FIXME addons are configured per-main symbol type */
+        else if(!strncmp(cfgstr, "addon2", len))
+            *sym = ZBAR_ADDON2;
+        else if(!strncmp(cfgstr, "addon5", len))
+            *sym = ZBAR_ADDON5;
+#endif
+        else if(len < 6)
+            return(1);
+        else if(!strncmp(cfgstr, "code39", len))
+            *sym = ZBAR_CODE39;
+        else if(!strncmp(cfgstr, "pdf417", len))
+            *sym = ZBAR_PDF417;
+        else if(len < 7)
+            return(1);
+        else if(!strncmp(cfgstr, "code128", len))
+            *sym = ZBAR_CODE128;
+        else
+            return(1);
+        cfgstr = dot + 1;
+    }
+    else
+        *sym = ZBAR_NONE;
+
+    int len = strlen(cfgstr);
+    const char *eq = strchr(cfgstr, '=');
+    if(eq)
+        len = eq - cfgstr;
+    else
+        *val = 1;  /* handle this here so we can override later */
+    char negate = 0;
+
+    if(len > 3 && !strncmp(cfgstr, "no-", 3)) {
+        negate = 1;
+        cfgstr += 3;
+        len -= 3;
+    }
+
+    if(len < 1)
+        return(1);
+    else if(!strncmp(cfgstr, "y-density", len))
+        *cfg = ZBAR_CFG_Y_DENSITY;
+    else if(!strncmp(cfgstr, "x-density", len))
+        *cfg = ZBAR_CFG_X_DENSITY;
+    else if(len < 2)
+        return(1);
+    else if(!strncmp(cfgstr, "enable", len))
+        *cfg = ZBAR_CFG_ENABLE;
+    else if(len < 3)
+        return(1);
+    else if(!strncmp(cfgstr, "disable", len)) {
+        *cfg = ZBAR_CFG_ENABLE;
+        negate = !negate; /* no-disable ?!? */
+    }
+    else if(!strncmp(cfgstr, "min-length", len))
+        *cfg = ZBAR_CFG_MIN_LEN;
+    else if(!strncmp(cfgstr, "max-length", len))
+        *cfg = ZBAR_CFG_MAX_LEN;
+    else if(!strncmp(cfgstr, "ascii", len))
+        *cfg = ZBAR_CFG_ASCII;
+    else if(!strncmp(cfgstr, "add-check", len))
+        *cfg = ZBAR_CFG_ADD_CHECK;
+    else if(!strncmp(cfgstr, "emit-check", len))
+        *cfg = ZBAR_CFG_EMIT_CHECK;
+    else if(!strncmp(cfgstr, "position", len))
+        *cfg = ZBAR_CFG_POSITION;
+    else 
+        return(1);
+
+    if(eq) {
+        errno = 0;
+        *val = strtol(eq + 1, NULL, 0);
+        if(errno)
+            return(1);
+    }
+    if(negate)
+        *val = !*val;
+
+    return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,232 @@
+/* include/config.h.  Generated from config.h.in by configure.  */
+
+/* include/config.h.in.  Generated from configure.ac by autoheader.  */
+
+
+/* whether to build support for Code 128 symbology */
+#define ENABLE_CODE128 1
+
+/* whether to build support for Code 39 symbology */
+#define ENABLE_CODE39 1
+//#define DEBUG_CODE39 1
+
+/* whether to build support for EAN symbologies */
+#define ENABLE_EAN 1
+
+/* whether to build support for Interleaved 2 of 5 symbology */
+#define ENABLE_I25 1
+
+/* whether to build support for PDF417 symbology */
+/* #undef ENABLE_PDF417 */
+
+/* whether to build support for QR Code */
+//#define ENABLE_QRCODE 1
+
+/* Define to 1 if you have the `atexit' function. */
+#define HAVE_ATEXIT 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the <features.h> header file. */
+#define HAVE_FEATURES_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+//#define HAVE_GETPAGESIZE 1
+
+/* Define if you have the iconv() function and it works. */
+#define HAVE_ICONV 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <jpeglib.h> header file. */
+/* #undef HAVE_JPEGLIB_H */
+
+/* Define to 1 if you have the `jpeg' library (-ljpeg). */
+/* #undef HAVE_LIBJPEG */
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+/* #undef HAVE_LIBPTHREAD */
+
+/* Define to 1 if you have the <linux/videodev2.h> header file. */
+/* #undef HAVE_LINUX_VIDEODEV2_H */
+
+/* Define to 1 if you have the <linux/videodev.h> header file. */
+/* #undef HAVE_LINUX_VIDEODEV_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+/* #undef HAVE_MMAP */
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the <pthread.h> header file. */
+/* #undef HAVE_PTHREAD_H */
+
+/* Define to 1 if you have the `setenv' function. */
+#define HAVE_SETENV 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#define HAVE_SYS_IPC_H 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/shm.h> header file. */
+#define HAVE_SYS_SHM_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#define HAVE_SYS_TIMES_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#define HAVE_UINTPTR_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <vfw.h> header file. */
+#define HAVE_VFW_H 1
+
+/* Define to 1 if you have the <X11/extensions/XShm.h> header file. */
+/* #undef HAVE_X11_EXTENSIONS_XSHM_H */
+
+/* Define to 1 if you have the <X11/extensions/Xvlib.h> header file. */
+/* #undef HAVE_X11_EXTENSIONS_XVLIB_H */
+
+/* Define as const if the declaration of iconv() needs const. */
+#define ICONV_CONST
+
+/* Library major version */
+#define LIB_VERSION_MAJOR 0
+
+/* Library minor version */
+#define LIB_VERSION_MINOR 2
+
+/* Library revision */
+#define LIB_VERSION_REVISION 0
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if assertions should be disabled. */
+/* #undef NDEBUG */
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "zbar"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "spadix@users.sourceforge.net"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "zbar"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "zbar 0.10"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "zbar"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.10"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.10"
+
+/* Define to 1 if the X Window System is missing or not being used. */
+/* #undef X_DISPLAY_MISSING */
+
+/* Program major version (before the '.') as a number */
+#define ZBAR_VERSION_MAJOR 0
+
+/* Program minor version (after '.') as a number */
+#define ZBAR_VERSION_MINOR 10
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT8_T */
+
+/* Minimum Windows API version */
+#define _WIN32_WINNT 0x0500
+
+/* used only for pthread debug attributes */
+/* #undef __USE_UNIX98 */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the type of a signed integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef int32_t */
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint32_t */
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint8_t */
+
+/* Define to the type of an unsigned integer type wide enough to hold a
+   pointer, if such a type exists, and if the system does not define it. */
+/* #undef uintptr_t */
+
+#ifndef X_DISPLAY_MISSING
+# define HAVE_X
+#endif
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debug.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,87 @@
+/*------------------------------------------------------------------------
+ *  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
+ *------------------------------------------------------------------------*/
+
+/* varargs variations on compile time debug spew */
+
+#ifndef DEBUG_LEVEL
+
+# ifdef __GNUC__
+    /* older versions of gcc (< 2.95) require a named varargs parameter */
+#  define dprintf(args...)
+# else
+    /* unfortunately named vararg parameter is a gcc-specific extension */
+#  define dprintf(...)
+# endif
+
+#else
+
+# include <stdio.h>
+
+# ifdef __GNUC__
+#  define dprintf(level, args...) \
+    if((level) <= DEBUG_LEVEL)    \
+        fprintf(stderr, args)
+# else
+#  define dprintf(level, ...)     \
+    if((level) <= DEBUG_LEVEL)    \
+        fprintf(stderr, __VA_ARGS__)
+# endif
+
+#endif /* DEBUG_LEVEL */
+
+/* spew warnings for non-fatal assertions.
+ * returns specified error code if assertion fails.
+ * NB check/return is still performed for NDEBUG
+ * only the message is inhibited
+ * FIXME don't we need varargs hacks here?
+ */
+#ifndef NDEBUG
+
+# include <stdio.h>
+
+#if __STDC_VERSION__ < 199901L && !defined(__func__)
+# if __GNUC__ >= 2
+#  define __func__ __FUNCTION__
+# else
+#  define __func__ "<unknown>"
+# endif
+#endif
+
+# define zassert(condition, retval, format, ...) do {                   \
+        if(!(condition)) {                                              \
+            fprintf(stderr, "WARNING: %s:%d: %s:"                       \
+                    " Assertion \"%s\" failed.\n\t" format,             \
+                    __FILE__, __LINE__, __func__, #condition ,          \
+                    ##__VA_ARGS__);                                     \
+            return(retval);                                             \
+        }                                                               \
+    } while(0)
+
+#else
+
+# define zassert(condition, retval, format, ...) do {   \
+        if(!(condition))                                \
+            return(retval);                             \
+    } while(0)
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder.c	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,481 @@
+/*------------------------------------------------------------------------
+ *  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
+ *------------------------------------------------------------------------*/
+#include <config.h>
+#include <stdlib.h> /* malloc, calloc, free */
+
+#include <stdio.h>  /* snprintf */
+
+#include <string.h> /* memset, strlen */
+
+#include <zbar.h>
+#include "decoder.h"
+
+#if defined(DEBUG_DECODER) || defined(DEBUG_EAN) || defined(DEBUG_CODE39) || defined(DEBUG_I25) || defined \
+        (DEBUG_CODE128) || defined(DEBUG_QR_FINDER) || (defined(DEBUG_PDF417) && (DEBUG_PDF417 >= 4))
+#define DEBUG_LEVEL 1
+#endif
+#include "debug.h"
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+zbar_decoder_t* zbar_decoder_create()
+{
+    zbar_decoder_t*     dcode = calloc(1, sizeof(zbar_decoder_t));
+    dcode->buf_alloc = BUFFER_MIN;
+    dcode->buf = malloc(dcode->buf_alloc);
+
+    /* initialize default configs */
+#ifdef ENABLE_EAN
+    dcode->ean.enable = 1;
+    dcode->ean.ean13_config = ((1 << ZBAR_CFG_ENABLE) | (1 << ZBAR_CFG_EMIT_CHECK));
+    dcode->ean.ean8_config = ((1 << ZBAR_CFG_ENABLE) | (1 << ZBAR_CFG_EMIT_CHECK));
+    dcode->ean.upca_config = 1 << ZBAR_CFG_EMIT_CHECK;
+    dcode->ean.upce_config = 1 << ZBAR_CFG_EMIT_CHECK;
+    dcode->ean.isbn10_config = 1 << ZBAR_CFG_EMIT_CHECK;
+    dcode->ean.isbn13_config = 1 << ZBAR_CFG_EMIT_CHECK;
+#endif
+#ifdef ENABLE_I25
+    dcode->i25.config = 1 << ZBAR_CFG_ENABLE;
+    CFG(dcode->i25, ZBAR_CFG_MIN_LEN) = 6;
+#endif
+#ifdef ENABLE_CODE39
+    dcode->code39.config = 1 << ZBAR_CFG_ENABLE;
+    CFG(dcode->code39, ZBAR_CFG_MIN_LEN) = 1;
+#endif
+#ifdef ENABLE_CODE128
+    dcode->code128.config = 1 << ZBAR_CFG_ENABLE;
+#endif
+#ifdef ENABLE_PDF417
+    dcode->pdf417.config = 1 << ZBAR_CFG_ENABLE;
+#endif
+#ifdef ENABLE_QRCODE
+    dcode->qrf.config = 1 << ZBAR_CFG_ENABLE;
+#endif
+    zbar_decoder_reset(dcode);
+    return(dcode);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void zbar_decoder_destroy(zbar_decoder_t* dcode)
+{
+    if (dcode->buf)
+        free(dcode->buf);
+    free(dcode);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void zbar_decoder_reset(zbar_decoder_t* dcode)
+{
+    memset(dcode, 0, (long) &dcode->buf_alloc - (long)dcode);
+#ifdef ENABLE_EAN
+    ean_reset(&dcode->ean);
+#endif
+#ifdef ENABLE_I25
+    i25_reset(&dcode->i25);
+#endif
+#ifdef ENABLE_CODE39
+    code39_reset(&dcode->code39);
+#endif
+#ifdef ENABLE_CODE128
+    code128_reset(&dcode->code128);
+#endif
+#ifdef ENABLE_PDF417
+    pdf417_reset(&dcode->pdf417);
+#endif
+#ifdef ENABLE_QRCODE
+    qr_finder_reset(&dcode->qrf);
+#endif
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void zbar_decoder_new_scan(zbar_decoder_t* dcode)
+{
+    /* soft reset decoder */
+
+    memset(dcode->w, 0, sizeof(dcode->w));
+    dcode->lock = 0;
+    dcode->idx = 0;
+#ifdef ENABLE_EAN
+    ean_new_scan(&dcode->ean);
+#endif
+#ifdef ENABLE_I25
+    i25_reset(&dcode->i25);
+#endif
+#ifdef ENABLE_CODE39
+    code39_reset(&dcode->code39);
+#endif
+#ifdef ENABLE_CODE128
+    code128_reset(&dcode->code128);
+#endif
+#ifdef ENABLE_PDF417
+    pdf417_reset(&dcode->pdf417);
+#endif
+#ifdef ENABLE_QRCODE
+    qr_finder_reset(&dcode->qrf);
+#endif
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+zbar_color_t zbar_decoder_get_color(const zbar_decoder_t* dcode)
+{
+    return(get_color(dcode));
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+const char* zbar_decoder_get_data(const zbar_decoder_t* dcode)
+{
+    return((char*)dcode->buf);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+unsigned int zbar_decoder_get_data_length(const zbar_decoder_t* dcode)
+{
+    return(dcode->buflen);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+zbar_decoder_handler_t* zbar_decoder_set_handler(zbar_decoder_t* dcode, zbar_decoder_handler_t handler)
+{
+    zbar_decoder_handler_t*     result = dcode->handler;
+    dcode->handler = handler;
+    return(result);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void zbar_decoder_set_userdata(zbar_decoder_t* dcode, void* userdata)
+{
+    dcode->userdata = userdata;
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+void* zbar_decoder_get_userdata(const zbar_decoder_t* dcode)
+{
+    return(dcode->userdata);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+zbar_symbol_type_t zbar_decoder_get_type(const zbar_decoder_t* dcode)
+{
+    return(dcode->type);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+zbar_symbol_type_t zbar_decode_width(zbar_decoder_t* dcode, unsigned w)
+{
+    dcode->w[dcode->idx & (DECODE_WINDOW - 1)] = w;
+    dprintf(1, "    decode[%x]: w=%d (%g)\n", dcode->idx, w, (w / 32.));
+
+    /* each decoder processes width stream in parallel */
+    zbar_symbol_type_t  sym = dcode->type = ZBAR_NONE;
+
+#ifdef ENABLE_EAN
+    if ((dcode->ean.enable) && (sym = _zbar_decode_ean(dcode)))
+        dcode->type = sym;
+#endif
+#ifdef ENABLE_CODE39
+    if (TEST_CFG(dcode->code39.config, ZBAR_CFG_ENABLE) && (sym = _zbar_decode_code39(dcode)) > ZBAR_PARTIAL)
+        dcode->type = sym;
+#endif
+#ifdef ENABLE_CODE128
+    if (TEST_CFG(dcode->code128.config, ZBAR_CFG_ENABLE) && (sym = _zbar_decode_code128(dcode)) > ZBAR_PARTIAL)
+        dcode->type = sym;
+#endif
+#ifdef ENABLE_I25
+    if (TEST_CFG(dcode->i25.config, ZBAR_CFG_ENABLE) && (sym = _zbar_decode_i25(dcode)) > ZBAR_PARTIAL)
+        dcode->type = sym;
+#endif
+#ifdef ENABLE_PDF417
+    if (TEST_CFG(dcode->pdf417.config, ZBAR_CFG_ENABLE) && (sym = _zbar_decode_pdf417(dcode)) > ZBAR_PARTIAL)
+        dcode->type = sym;
+#endif
+#ifdef ENABLE_QRCODE
+    if (TEST_CFG(dcode->qrf.config, ZBAR_CFG_ENABLE) && (sym = _zbar_find_qr(dcode)) > ZBAR_PARTIAL)
+        dcode->type = sym;
+#endif
+    dcode->idx++;
+    if (dcode->type) {
+        if (dcode->handler)
+            dcode->handler(dcode);
+        if (dcode->lock && dcode->type > ZBAR_PARTIAL)
+            dcode->lock = 0;
+    }
+
+    return(dcode->type);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+static inline int decoder_set_config_bool(zbar_decoder_t* dcode, zbar_symbol_type_t sym, zbar_config_t cfg, int val)
+{
+    unsigned*   config = NULL;
+    switch (sym) {
+    #ifdef ENABLE_EAN
+
+        case ZBAR_EAN13:
+            config = &dcode->ean.ean13_config;
+            break;
+
+        case ZBAR_EAN8:
+            config = &dcode->ean.ean8_config;
+            break;
+
+        case ZBAR_UPCA:
+            config = &dcode->ean.upca_config;
+            break;
+
+        case ZBAR_UPCE:
+            config = &dcode->ean.upce_config;
+            break;
+
+        case ZBAR_ISBN10:
+            config = &dcode->ean.isbn10_config;
+            break;
+
+        case ZBAR_ISBN13:
+            config = &dcode->ean.isbn13_config;
+            break;
+    #endif
+    #ifdef ENABLE_I25
+
+        case ZBAR_I25:
+            config = &dcode->i25.config;
+            break;
+    #endif
+    #ifdef ENABLE_CODE39
+
+        case ZBAR_CODE39:
+            config = &dcode->code39.config;
+            break;
+    #endif
+    #ifdef ENABLE_CODE128
+
+        case ZBAR_CODE128:
+            config = &dcode->code128.config;
+            break;
+    #endif
+    #ifdef ENABLE_PDF417
+
+        case ZBAR_PDF417:
+            config = &dcode->pdf417.config;
+            break;
+    #endif
+    #ifdef ENABLE_QRCODE
+
+        case ZBAR_QRCODE:
+            config = &dcode->qrf.config;
+            break;
+    #endif
+
+        /* FIXME handle addons */
+
+        default:
+            return(1);
+    }
+
+    if (!config || cfg >= ZBAR_CFG_NUM)
+        return(1);
+
+    if (!val)
+        *config &= ~(1 << cfg);
+    else
+    if (val == 1)
+        *config |= (1 << cfg);
+    else
+        return(1);
+
+#ifdef ENABLE_EAN
+    dcode->ean.enable = TEST_CFG
+        (
+            dcode->ean.ean13_config |
+                dcode->ean.ean8_config |
+                dcode->ean.upca_config |
+                dcode->ean.upce_config |
+                dcode->ean.isbn10_config |
+                dcode->ean.isbn13_config,
+            ZBAR_CFG_ENABLE
+        );
+#endif
+    return(0);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+static inline int decoder_set_config_int(zbar_decoder_t* dcode, zbar_symbol_type_t sym, zbar_config_t cfg, int val)
+{
+    switch (sym) {
+    #ifdef ENABLE_I25
+
+        case ZBAR_I25:
+            CFG(dcode->i25, cfg) = val;
+            break;
+    #endif
+    #ifdef ENABLE_CODE39
+
+        case ZBAR_CODE39:
+            CFG(dcode->code39, cfg) = val;
+            break;
+    #endif
+    #ifdef ENABLE_CODE128
+
+        case ZBAR_CODE128:
+            CFG(dcode->code128, cfg) = val;
+            break;
+    #endif
+    #ifdef ENABLE_PDF417
+
+        case ZBAR_PDF417:
+            CFG(dcode->pdf417, cfg) = val;
+            break;
+    #endif
+
+        default:
+            return(1);
+    }
+
+    return(0);
+}
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+int zbar_decoder_set_config(zbar_decoder_t* dcode, zbar_symbol_type_t sym, zbar_config_t cfg, int val)
+{
+    if (sym == ZBAR_NONE) {
+        zbar_decoder_set_config(dcode, ZBAR_EAN13, cfg, val);
+        zbar_decoder_set_config(dcode, ZBAR_EAN8, cfg, val);
+        zbar_decoder_set_config(dcode, ZBAR_UPCA, cfg, val);
+        zbar_decoder_set_config(dcode, ZBAR_UPCE, cfg, val);
+        zbar_decoder_set_config(dcode, ZBAR_ISBN10, cfg, val);
+        zbar_decoder_set_config(dcode, ZBAR_ISBN13, cfg, val);
+        zbar_decoder_set_config(dcode, ZBAR_I25, cfg, val);
+        zbar_decoder_set_config(dcode, ZBAR_CODE39, cfg, val);
+        zbar_decoder_set_config(dcode, ZBAR_CODE128, cfg, val);
+        zbar_decoder_set_config(dcode, ZBAR_PDF417, cfg, val);
+        zbar_decoder_set_config(dcode, ZBAR_QRCODE, cfg, val);
+        return(0);
+    }
+
+    if (cfg >= 0 && cfg < ZBAR_CFG_NUM)
+        return(decoder_set_config_bool(dcode, sym, cfg, val));
+    else
+    if (cfg >= ZBAR_CFG_MIN_LEN && cfg <= ZBAR_CFG_MAX_LEN)
+        return(decoder_set_config_int(dcode, sym, cfg, val));
+    else
+        return(1);
+}
+
+static char*    decoder_dump = NULL;
+static unsigned decoder_dumplen = 0;
+
+/**
+ * @brief
+ * @note
+ * @param
+ * @retval
+ */
+const char* _zbar_decoder_buf_dump(unsigned char* buf, unsigned int buflen)
+{
+    int dumplen = (buflen * 3) + 12;
+    if (!decoder_dump || dumplen > decoder_dumplen) {
+        if (decoder_dump)
+            free(decoder_dump);
+        decoder_dump = malloc(dumplen);
+        decoder_dumplen = dumplen;
+    }
+
+    char*   p = decoder_dump + snprintf(decoder_dump, 12, "buf[%04x]=", (buflen > 0xffff) ? 0xffff : buflen);
+    int     i;
+    for (i = 0; i < buflen; i++)
+        p += snprintf(p, 4, "%s%02x", (i) ? " " : "", buf[i]);
+    return(decoder_dump);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,205 @@
+/*------------------------------------------------------------------------
+ *  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 _DECODER_H_
+#define _DECODER_H_
+
+#include "config.h"
+#include <stdlib.h>     /* realloc */
+
+#include <zbar.h>
+
+#define NUM_CFGS (ZBAR_CFG_MAX_LEN - ZBAR_CFG_MIN_LEN + 1)
+
+#ifdef ENABLE_EAN
+# include "decoder/ean.h"
+#endif
+#ifdef ENABLE_I25
+# include "decoder/i25.h"
+#endif
+#ifdef ENABLE_CODE39
+# include "decoder/code39.h"
+#endif
+#ifdef ENABLE_CODE128
+# include "decoder/code128.h"
+#endif
+#ifdef ENABLE_PDF417
+# include "decoder/pdf417.h"
+#endif
+#ifdef ENABLE_QRCODE
+# include "decoder/qr_finder.h"
+#endif
+
+/* size of bar width history (implementation assumes power of two) */
+#ifndef DECODE_WINDOW
+# define DECODE_WINDOW  16
+#endif
+
+/* initial data buffer allocation */
+#ifndef BUFFER_MIN
+# define BUFFER_MIN   0x20
+#endif
+
+/* maximum data buffer allocation
+ * (longer symbols are rejected)
+ */
+#ifndef BUFFER_MAX
+# define BUFFER_MAX  0x100
+#endif
+
+/* buffer allocation increment */
+#ifndef BUFFER_INCR
+# define BUFFER_INCR  0x10
+#endif
+
+#define CFG(dcode, cfg) ((dcode).configs[(cfg) - ZBAR_CFG_MIN_LEN])
+#define TEST_CFG(config, cfg) (((config) >> (cfg)) & 1)
+
+/* symbology independent decoder state */
+struct zbar_decoder_s {
+    unsigned char idx;                  /* current width index */
+    unsigned w[DECODE_WINDOW];          /* window of last N bar widths */
+    zbar_symbol_type_t type;            /* type of last decoded data */
+    zbar_symbol_type_t lock;            /* buffer lock */
+
+    /* everything above here is automatically reset */
+    unsigned buf_alloc;                 /* dynamic buffer allocation */
+    unsigned buflen;                    /* binary data length */
+    unsigned char *buf;                 /* decoded characters */
+    void *userdata;                     /* application data */
+    zbar_decoder_handler_t *handler;    /* application callback */
+
+    /* symbology specific state */
+#ifdef ENABLE_EAN
+    ean_decoder_t ean;                  /* EAN/UPC parallel decode attempts */
+#endif
+#ifdef ENABLE_I25
+    i25_decoder_t i25;                  /* Interleaved 2 of 5 decode state */
+#endif
+#ifdef ENABLE_CODE39
+    code39_decoder_t code39;            /* Code 39 decode state */
+#endif
+#ifdef ENABLE_CODE128
+    code128_decoder_t code128;          /* Code 128 decode state */
+#endif
+#ifdef ENABLE_PDF417
+    pdf417_decoder_t pdf417;            /* PDF417 decode state */
+#endif
+#ifdef ENABLE_QRCODE
+    qr_finder_t qrf;                    /* QR Code finder state */
+#endif
+};
+
+/* return current element color */
+static inline char get_color (const zbar_decoder_t *dcode)
+{
+    return(dcode->idx & 1);
+}
+
+/* retrieve i-th previous element width */
+static inline unsigned get_width (const zbar_decoder_t *dcode,
+                                  unsigned char offset)
+{
+    return(dcode->w[(dcode->idx - offset) & (DECODE_WINDOW - 1)]);
+}
+
+/* retrieve bar+space pair width starting at offset i */
+static inline unsigned pair_width (const zbar_decoder_t *dcode,
+                                   unsigned char offset)
+{
+    return(get_width(dcode, offset) + get_width(dcode, offset + 1));
+}
+
+/* calculate total character width "s"
+ *   - start of character identified by context sensitive offset
+ *     (<= DECODE_WINDOW - n)
+ *   - size of character is n elements
+ */
+static inline unsigned calc_s (const zbar_decoder_t *dcode,
+                               unsigned char offset,
+                               unsigned char n)
+{
+    /* FIXME check that this gets unrolled for constant n */
+    unsigned s = 0;
+    while(n--)
+        s += get_width(dcode, offset++);
+    return(s);
+}
+
+/* fixed character width decode assist
+ * bar+space width are compared as a fraction of the reference dimension "x"
+ *   - +/- 1/2 x tolerance
+ *   - measured total character width (s) compared to symbology baseline (n)
+ *     (n = 7 for EAN/UPC, 11 for Code 128)
+ *   - bar+space *pair width* "e" is used to factor out bad "exposures"
+ *     ("blooming" or "swelling" of dark or light areas)
+ *     => using like-edge measurements avoids these issues
+ *   - n should be > 3
+ */
+static inline int decode_e (unsigned e,
+                            unsigned s,
+                            unsigned n)
+{
+    /* result is encoded number of units - 2
+     * (for use as zero based index)
+     * or -1 if invalid
+     */
+    unsigned char E = ((e * n * 2 + 1) / s - 3) / 2;
+    return((E >= n - 3) ? -1 : E);
+}
+
+/* acquire shared state lock */
+static inline char get_lock (zbar_decoder_t *dcode,
+                             zbar_symbol_type_t req)
+{
+    if(dcode->lock)
+        return(1);
+    dcode->lock = req;
+    return(0);
+}
+
+/* ensure output buffer has sufficient allocation for request */
+static inline char size_buf (zbar_decoder_t *dcode,
+                             unsigned len)
+{
+    if(len < dcode->buf_alloc)
+        /* FIXME size reduction heuristic? */
+        return(0);
+    if(len > BUFFER_MAX)
+        return(1);
+    if(len < dcode->buf_alloc + BUFFER_INCR) {
+        len = dcode->buf_alloc + BUFFER_INCR;
+        if(len > BUFFER_MAX)
+            len = BUFFER_MAX;
+    }
+    unsigned char *buf = realloc(dcode->buf, len);
+    if(!buf)
+        return(1);
+    dcode->buf = buf;
+    dcode->buf_alloc = len;
+    return(0);
+}
+
+extern const char *_zbar_decoder_buf_dump (unsigned char *buf,
+                                            unsigned int buflen);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder/code128.c	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,518 @@
+/*------------------------------------------------------------------------
+ *  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
+ *------------------------------------------------------------------------*/
+
+#include "../config.h"
+#include <string.h>     /* memmove */
+
+#ifdef ENABLE_CODE128
+
+#include <zbar.h>
+#include "../decoder.h"
+
+#ifdef DEBUG_CODE128
+# define DEBUG_LEVEL (DEBUG_CODE128)
+#endif
+#include "../debug.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];
+    if(sig & 1)
+        idx &= 0xf;
+    else
+        idx >>= 4;
+    if(idx == 0xf)
+        return(-1);
+
+    unsigned char 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);
+    unsigned char c = characters[idx];
+    dprintf(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;
+    if(rev)
+        sig = (((sig >> 12) & 0x000f) |
+               ((sig >>  4) & 0x00f0) |
+               ((sig <<  4) & 0x0f00) |
+               ((sig << 12) & 0xf000));
+    dprintf(2, " rev=%x", rev != 0);
+
+    unsigned char idx;
+    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;
+    unsigned char c = characters[0x51 + idx];
+    dprintf(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)
+{
+    /* build edge signature of character */
+    unsigned s = dcode->code128.s6;
+    dprintf(2, " s=%d", s);
+    if(s < 5)
+        return(-1);
+    /* calculate similar edge measurements */
+    int 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);
+    dprintf(2, " sig=%04x", sig);
+    /* lookup edge signature */
+    signed char c = (sig & 0x4444) ? decode_hi(sig) : decode_lo(sig);
+    if(c == -1)
+        return(-1);
+
+    /* character validation */
+    unsigned 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;
+    unsigned char chk = calc_check(c);
+    dprintf(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)
+{
+    code128_decoder_t *dcode128 = &dcode->code128;
+    if(dcode128->character < 3)
+        return(1);
+
+    /* add in irregularly weighted start character */
+    unsigned idx = (dcode128->direction) ? dcode128->character - 1 : 0;
+    unsigned sum = dcode->buf[idx];
+    if(sum >= 103)
+        sum -= 103;
+
+    /* calculate sum in reverse to avoid multiply operations */
+    unsigned i, acc = 0;
+    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;
+    unsigned char check = dcode->buf[idx];
+    dprintf(2, " chk=%02x(%02x)", sum, check);
+    unsigned char err = (sum != check);
+    if(err)
+        dprintf(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)
+{
+    /* expand buffer to accomodate 2x set C characters (2 digits per-char) */
+    unsigned delta = end - start;
+    unsigned newlen = dcode->code128.character + delta;
+    size_buf(dcode, newlen);
+
+    /* relocate unprocessed data to end of buffer */
+    memmove(dcode->buf + start + delta, dcode->buf + start,
+            dcode->code128.character - start);
+    dcode->code128.character = newlen;
+
+    unsigned i, j;
+    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)
+{
+    code128_decoder_t *dcode128 = &dcode->code128;
+    dprintf(2, "\n    postproc len=%d", dcode128->character);
+    unsigned i, j;
+    unsigned char code = 0;
+    if(dcode128->direction) {
+        /* reverse buffer */
+        dprintf(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));
+
+    unsigned char charset = code - START_A;
+    unsigned cexp = (code == START_C) ? 1 : 0;
+    dprintf(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 {
+            dprintf(2, " %02x", code);
+            if(charset & 0x2) {
+                /* 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));
+                unsigned 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)
+                /* FIXME FNC1 - Code 128 subsets or ASCII 0x1d */;
+            else if(code >= START_A) {
+                dprintf(1, " [truncated]\n");
+                return(1);
+            }
+            else {
+                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));
+                unsigned char newset = CODE_A - code;
+                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;
+    }
+    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;
+
+    /* update latest character width */
+    dcode128->s6 -= get_width(dcode, 6);
+    dcode128->s6 += get_width(dcode, 0);
+
+    if(/* process every 6th element of active symbol */
+       (dcode128->character >= 0 &&
+        (++dcode128->element) != 6) ||
+       /* decode color based on direction */
+       (get_color(dcode) != dcode128->direction))
+        return(0);
+    dcode128->element = 0;
+
+    dprintf(2, "      code128[%c%02d+%x]:",
+            (dcode128->direction) ? '<' : '>',
+            dcode128->character, dcode128->element);
+
+    signed char c = decode6(dcode);
+    if(dcode128->character < 0) {
+        dprintf(2, " c=%02x", c);
+        if(c < START_A || c > STOP_REV || c == STOP_FWD) {
+            dprintf(2, " [invalid]\n");
+            return(0);
+        }
+        unsigned qz = get_width(dcode, 6);
+        if(qz && qz < (dcode->code128.s6 * 3) / 4) {
+            dprintf(2, " [invalid qz %d]\n", qz);
+            return(0);
+        }
+        /* lock shared resources */
+        if(get_lock(dcode, ZBAR_CODE128)) {
+            dprintf(2, " [locked %d]\n", dcode->lock);
+            dcode128->character = -1;
+            return(0);
+        }
+        /* decoded valid start/stop */
+        /* initialize state */
+        dcode128->character = 0;
+        if(c == STOP_REV) {
+            dcode128->direction = ZBAR_BAR;
+            dcode128->element = 7;
+        }
+        else
+            dcode128->direction = ZBAR_SPACE;
+        dprintf(2, " dir=%x [valid start]", dcode128->direction);
+    }
+    else if((c < 0) ||
+            ((dcode128->character >= BUFFER_MIN) &&
+             size_buf(dcode, dcode128->character + 1))) {
+        dprintf(1, (c < 0) ? " [aborted]\n" : " [overflow]\n");
+        dcode->lock = 0;
+        dcode128->character = -1;
+        return(0);
+    }
+
+    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));
+
+    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))) {
+            dprintf(2, " [invalid len]\n");
+            sym = ZBAR_NONE;
+        }
+        else
+            dprintf(2, " [valid end]\n");
+        dcode128->character = -1;
+        if(!sym)
+            dcode->lock = 0;
+        return(sym);
+    }
+
+    dprintf(2, "\n");
+    return(0);
+}
+ #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder/code128.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,61 @@
+/*------------------------------------------------------------------------
+ *  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 s6;                /* character width */
+
+//    unsigned config;
+//    int configs[NUM_CFGS];      /* int valued configurations */
+//} code128_decoder_t;
+
+#include <stdint.h>
+
+typedef struct code128_decoder_s {
+    uint8_t direction;          /* scan direction: 0=fwd/space, 1=rev/bar */
+    uint8_t element;            /* element offset 0-5 */
+    int16_t character;          /* character position in symbol */
+    uint16_t s6;                /* 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder/code39.c	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,331 @@
+/*------------------------------------------------------------------------
+ *  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
+ *------------------------------------------------------------------------*/
+
+#include "../config.h"
+#include <string.h>     /* memmove */
+
+#ifdef ENABLE_CODE39
+
+#include <zbar.h>
+#include "../decoder.h"
+
+#ifdef DEBUG_CODE39
+# define DEBUG_LEVEL DEBUG_CODE39
+#endif
+#include "../debug.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, 36);
+    if(E > 7)
+        return(0xff);
+    enc <<= 1;
+    if(E > 2) {
+        enc |= 1;
+        dprintf(2, "1");
+    }
+    else
+        dprintf(2, "0");
+    return(enc);
+}
+
+static inline signed char code39_decode9 (zbar_decoder_t *dcode)
+{
+    code39_decoder_t *dcode39 = &dcode->code39;
+
+    dprintf(2, " s=%d ", dcode39->s9);
+    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];
+    dprintf(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;
+
+    signed char c = code39_decode9(dcode);
+    if(c == 0x19)
+        dcode39->direction ^= 1;
+    else if(c != 0x2b) {
+        dprintf(2, "\n");
+        return(ZBAR_NONE);
+    }
+
+    /* check leading quiet zone - spec is 10x */
+    unsigned quiet = get_width(dcode, 9);
+    if(quiet && quiet < dcode39->s9 / 2) {
+        dprintf(2, " [invalid quiet]\n");
+        return(ZBAR_NONE);
+    }
+
+    dcode39->element = 9;
+    dcode39->character = 0;
+    dprintf(1, " dir=%x [valid start]\n", dcode39->direction);
+    return(ZBAR_PARTIAL);
+}
+
+static inline void code39_postprocess (zbar_decoder_t *dcode)
+{
+    code39_decoder_t *dcode39 = &dcode->code39;
+    int i;
+    if(dcode39->direction) {
+        /* reverse buffer */
+        dprintf(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]]
+                         : '?');
+    dcode->buflen = i;
+    dcode->buf[i] = '\0';
+}
+
+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);
+        dprintf(2, "      code39:");
+        return((zbar_symbol_type_t)code39_decode_start(dcode));
+    }
+
+    if(++dcode39->element < 9)
+        return(ZBAR_NONE);
+
+    dprintf(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_CODE39;
+
+            /* trailing quiet zone check */
+            if(space && space < dcode39->width / 2) {
+                dprintf(2, " [invalid qz]\n");
+                sym = ZBAR_NONE;
+            }
+            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))) {
+                dprintf(2, " [invalid len]\n");
+                sym = ZBAR_NONE;
+            }
+            else {
+                /* FIXME checksum (needs config enable) */
+                code39_postprocess(dcode);
+                dprintf(2, " [valid end]\n");
+            }
+            dcode39->character = -1;
+            if(!sym)
+                dcode->lock = ZBAR_NONE;
+            return(sym);
+        }
+        if(space > dcode39->width / 2) {
+            /* inter-character space check failure */
+            dcode->lock = ZBAR_NONE;
+            dcode39->character = -1;
+            dprintf(2, " ics>%d [invalid ics]", dcode39->width);
+        }
+        dcode39->element = ZBAR_NONE;
+        dprintf(2, "\n");
+        return(ZBAR_NONE);
+    }
+
+    signed char c = code39_decode9(dcode);
+    dprintf(2, " c=%d", c);
+
+    /* lock shared resources */
+    if(!dcode39->character && get_lock(dcode, ZBAR_CODE39)) {
+        dcode39->character = -1;
+        dprintf(1, " [locked %d]\n", dcode->lock);
+        return(ZBAR_PARTIAL);
+    }
+
+    if(c < 0 ||
+       ((dcode39->character >= BUFFER_MIN) &&
+        size_buf(dcode, dcode39->character + 1))) {
+        dprintf(1, (c < 0) ? " [aborted]\n" : " [overflow]\n");
+        dcode->lock = ZBAR_NONE;
+        dcode39->character = -1;
+        return(ZBAR_NONE);
+    }
+    else {
+        zassert(c < 0x2c, ZBAR_NONE, "c=%02x s9=%x\n", c, dcode39->s9);
+        dprintf(2, "\n");
+    }
+
+    dcode->buf[dcode39->character++] = c;
+
+    return(ZBAR_NONE);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder/code39.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,64 @@
+/*------------------------------------------------------------------------
+ *  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_
+
+#include <stdint.h>
+
+/* Code 39 specific decode state */
+/* 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;
+
+typedef struct code39_decoder_s {
+    uint8_t direction;     /* scan direction: 0=fwd, 1=rev */
+    uint8_t element;       /* element offset 0-8 */
+    int16_t character;         /* character position in symbol */
+    uint16_t s9;                /* current character width */
+    uint16_t 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder/ean.c	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,646 @@
+/*------------------------------------------------------------------------
+ *  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
+ *------------------------------------------------------------------------*/
+
+#include "../config.h"
+#include <zbar.h>
+#include "../decoder.h"
+
+#ifdef ENABLE_EAN
+
+#ifdef DEBUG_EAN
+# define DEBUG_LEVEL (DEBUG_EAN)
+#endif
+#include "../debug.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
+
+/* 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)
+{
+    /* 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) {
+        dprintf(2, " [invalid quiet]");
+        return(-1);
+    }
+
+    dprintf(2, " (");
+    signed char code = 0;
+    unsigned char i;
+    for(i = 1 - fwd; i < 3 + fwd; i++) {
+        unsigned e = get_width(dcode, i) + get_width(dcode, i + 1);
+        dprintf(2, " %d", e);
+        code = (code << 2) | decode_e(e, s, 7);
+        if(code < 0) {
+            dprintf(2, " [invalid end guard]");
+            return(-1);
+        }
+    }
+    dprintf(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 e2 = get_width(dcode, 5) + get_width(dcode, 6);
+    if(decode_e(e2, dcode->ean.s4, 7)) {
+        dprintf(2, " [invalid any]");
+        return(/*FIXME (get_color(dcode) == ZBAR_SPACE) ? STATE_ADDON : */-1);
+    }
+
+    unsigned e1 = get_width(dcode, 4) + get_width(dcode, 5);
+    unsigned char 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) {
+                dprintf(2, " [valid normal]");
+                return(0); /* normal symbol start */
+            }
+            else if(E1 == 1) {
+                dprintf(2, " [valid add-on]");
+                return(STATE_ADDON); /* add-on symbol start */
+            }
+        }
+        dprintf(2, " [invalid start]");
+        return(-1);
+    }
+
+    if(!E1) {
+        /* attempting decode from SPACE => validate center guard */
+        unsigned e3 = get_width(dcode, 6) + get_width(dcode, 7);
+        if(!decode_e(e3, dcode->ean.s4, 7)) {
+            dprintf(2, " [valid center]");
+            return(0); /* start after center guard */
+        }
+    }
+    dprintf(2, " [invalid center]");
+    return(/*STATE_ADDON*/-1);
+}
+
+/* attempt to decode previous 4 widths (2 bars and 2 spaces) as a character */
+static inline signed char decode4 (zbar_decoder_t *dcode)
+{
+    /* 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);
+    dprintf(2, "\n        e1=%d e2=%d", e1, e2);
+
+    /* create compacted encoding for direct lookup */
+    signed char code = ((decode_e(e1, dcode->ean.s4, 7) << 2) |
+                        decode_e(e2, dcode->ean.s4, 7));
+    if(code < 0)
+        return(-1);
+    dprintf(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) {
+        /* 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;
+        unsigned char mid = (((1 << code) & 0x0420)
+                             ? 3     /* E1E2 in 33,44 */
+                             : 4);   /* E1E2 in 34,43 */
+        unsigned char alt = d2 > (mid * dcode->ean.s4);
+        if(alt)
+            code = ((code >> 1) & 3) | 0x10; /* compress code space */
+        dprintf(2, " (d2=%d(%d) alt=%d)", d2, mid * dcode->ean.s4, alt);
+    }
+    dprintf(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 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);
+
+    dprintf(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->raw[1] = pass->raw[4];
+        pass->raw[4] = tmp;
+        tmp = pass->raw[2];
+        pass->raw[2] = pass->raw[3];
+        pass->raw[3] = tmp;
+    }
+
+    dprintf(2, "\n");
+    dprintf(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 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;
+    dprintf(2, " par=%02x(%x)", par, pass->raw[0]);
+
+    if(pass->raw[0] == 0xf)
+        /* invalid parity combination */
+        return(ZBAR_NONE);
+
+    if(!par == fwd) {
+        /* reverse sampled digits */
+        unsigned char i;
+        for(i = 1; i < 4; i++) {
+            unsigned char tmp = pass->raw[i];
+            pass->raw[i] = pass->raw[7 - i];
+            pass->raw[7 - i] = tmp;
+        }
+    }
+
+    dprintf(2, "\n");
+    dprintf(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)
+{
+    pass->state++;
+    unsigned char idx = pass->state & STATE_IDX;
+    unsigned char fwd = pass->state & 1;
+
+    if(get_color(dcode) == ZBAR_SPACE &&
+       (idx == 0x10 || idx == 0x11) &&
+       TEST_CFG(dcode->ean.ean8_config, ZBAR_CFG_ENABLE) &&
+       !aux_end(dcode, fwd)) {
+        dprintf(2, " fwd=%x", fwd);
+        zbar_symbol_type_t part = ean_part_end4(pass, fwd);
+        pass->state = -1;
+        return(part);
+    }
+
+    if(!(idx & 0x03) && idx <= 0x14) {
+        if(!dcode->ean.s4)
+            return(0);
+        /* validate guard bars before decoding first char of symbol */
+        if(!pass->state) {
+            pass->state = aux_start(dcode);
+            if(pass->state < 0)
+                return(0);
+            idx = pass->state & STATE_IDX;
+        }
+        signed char code = decode4(dcode);
+        if(code < 0)
+            pass->state = -1;
+        else {
+            dprintf(2, "\n        raw[%x]=%02x =>", idx >> 2,
+                    digits[(unsigned char)code]);
+            pass->raw[(idx >> 2) + 1] = digits[(unsigned char)code];
+            dprintf(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);
+        }
+    }
+
+    if(get_color(dcode) == ZBAR_SPACE &&
+       (idx == 0x18 || idx == 0x19)) {
+        zbar_symbol_type_t part = ZBAR_NONE;
+        dprintf(2, " fwd=%x", fwd);
+        if(!aux_end(dcode, fwd))
+            part = ean_part_end7(&dcode->ean, pass, fwd);
+        pass->state = -1;
+        return(part);
+    }
+    return(0);
+}
+
+static inline signed char ean_verify_checksum (ean_decoder_t *ean,
+                                               int n)
+{
+    unsigned char chk = 0;
+    unsigned char i;
+    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;
+    unsigned char 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) {
+        dprintf(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;
+    /* parity encoded digit is checksum */
+    ean->buf[12] = pass->raw[i++];
+
+    unsigned char 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 */
+    dprintf(2, " integrate part=%x (%s)", part, dsprintbuf(ean));
+    signed char i, j;
+    if(part & ZBAR_ADDON) {
+        /* FIXME TBD */
+        for(i = (part == ZBAR_ADDON5) ? 4 : 1; i >= 0; i--) {
+            unsigned char digit = pass->raw[i] & 0xf;
+            if(ean->addon && ean->buf[i + 13] != digit) {
+                /* partial mismatch - reset collected parts */
+                ean->left = ean->right = ean->addon = ZBAR_NONE;
+            }
+            ean->buf[i + 13] = digit;
+        }
+        ean->addon = part;
+    }
+    else {
+        if((ean->left && ((part & ZBAR_SYMBOL) != ean->left)) ||
+           (ean->right && ((part & ZBAR_SYMBOL) != ean->right))) {
+            /* partial mismatch - reset collected parts */
+            dprintf(2, " rst(type %x %x)", ean->left, ean->right);
+            ean->left = ean->right = ean->addon = ZBAR_NONE;
+        }
+
+        if(part & EAN_RIGHT) {
+            part &= ZBAR_SYMBOL;
+            j = (part == ZBAR_EAN13) ? 12 : 7;
+            for(i = (part == ZBAR_EAN13) ? 6 : 4; i; i--, j--) {
+                unsigned char digit = pass->raw[i] & 0xf;
+                if(ean->right && ean->buf[j] != digit) {
+                    /* partial mismatch - reset collected parts */
+                    dprintf(2, " rst(right)");
+                    ean->left = ean->right = ean->addon = ZBAR_NONE;
+                }
+                ean->buf[j] = digit;
+            }
+            ean->right = part;
+        }
+        else if(part != ZBAR_UPCE) /* EAN_LEFT */ {
+            j = (part == ZBAR_EAN13) ? 6 : 3;
+            for(i = (part == ZBAR_EAN13) ? 6 : 4; j >= 0; i--, j--) {
+                unsigned char digit = pass->raw[i] & 0xf;
+                if(ean->left && ean->buf[j] != digit) {
+                    /* partial mismatch - reset collected parts */
+                    dprintf(2, " rst(left)");
+                    ean->left = ean->right = ean->addon = ZBAR_NONE;
+                }
+                ean->buf[j] = digit;
+            }
+            ean->left = part;
+        }
+        else /* ZBAR_UPCE */
+            ean_expand_upce(ean, pass);
+    }
+
+    if((part & ZBAR_SYMBOL) != ZBAR_UPCE) {
+        part = (ean->left & ean->right);
+        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 parity */
+        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;
+    }
+
+    if(part > ZBAR_PARTIAL)
+        part |= ean->addon;
+
+    dprintf(2, " %x/%x=%x", 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 & ZBAR_SYMBOL;
+    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 ||
+           !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_SYMBOL) == 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);
+    }
+    if(sym & ZBAR_ADDON)
+        for(i = 13; ean->buf[i] >= 0; i++, j++)
+            dcode->buf[j] = ean->buf[i] + '0';
+    dcode->buflen = j;
+    dcode->buf[j] = '\0';
+}
+
+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;
+
+    /* update latest character width */
+    dcode->ean.s4 -= get_width(dcode, 4);
+    dcode->ean.s4 += get_width(dcode, 0);
+
+    unsigned char i;
+    for(i = 0; i < 4; i++) {
+        ean_pass_t *pass = &dcode->ean.pass[i];
+        if(pass->state >= 0 ||
+           i == pass_idx)
+        {
+            dprintf(2, "      ean[%x/%x]: idx=%x st=%d s=%d",
+                    pass_idx, i, dcode->idx, pass->state, dcode->ean.s4);
+            zbar_symbol_type_t 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 */
+                    dprintf(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(!get_lock(dcode, ZBAR_EAN13))
+                            postprocess(dcode, sym);
+                        else {
+                            dprintf(1, " [locked %d]", dcode->lock);
+                            sym = ZBAR_PARTIAL;
+                        }
+                    }
+                }
+            }
+            dprintf(2, "\n");
+        }
+    }
+    return(sym);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder/ean.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,84 @@
+/*------------------------------------------------------------------------
+ *  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 _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_ADDON 0x40        /*   scanning add-on */
+#define STATE_IDX   0x1f        /*   element offset into symbol */
+    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;
+    zbar_symbol_type_t addon;
+    unsigned s4;                /* 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;
+} 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 = ean->addon = ZBAR_NONE;
+}
+
+static inline unsigned ean_get_config (ean_decoder_t *ean,
+                                       zbar_symbol_type_t sym)
+{
+    switch(sym & ZBAR_SYMBOL) {
+    case ZBAR_EAN13:  return(ean->ean13_config);
+    case ZBAR_EAN8:   return(ean->ean8_config);
+    case ZBAR_UPCA:   return(ean->upca_config);
+    case ZBAR_UPCE:   return(ean->upce_config);
+    case ZBAR_ISBN10: return(ean->isbn10_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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder/i25.c	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,238 @@
+/*------------------------------------------------------------------------
+ *  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
+ *------------------------------------------------------------------------*/
+
+#include "../config.h"
+#include <string.h>     /* memmove */
+
+#ifdef ENABLE_I25
+
+#include <zbar.h>
+#include "../decoder.h"
+
+#ifdef DEBUG_I25
+# define DEBUG_LEVEL (DEBUG_I25)
+#endif
+#include "../debug.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;
+    dprintf(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++;
+    }
+
+    dprintf(2, " enc=%02x par=%x", enc, par);
+
+    /* parity check */
+    if(par != 2) {
+        dprintf(2, " [bad parity]");
+        return(0xff);
+    }
+
+    /* decode binary weights */
+    enc &= 0xf;
+    if(enc & 8) {
+        if(enc == 12)
+            enc = 0;
+        else if(--enc > 9) {
+            dprintf(2, " [invalid encoding]");
+            return(0xff);
+        }
+    }
+
+    dprintf(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))) {
+        dprintf(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) {
+        dprintf(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 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) {
+        dprintf(3, " 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->direction) {
+        /* reverse buffer */
+        dprintf(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))) {
+        dprintf(2, " [invalid len]\n");
+        dcode->lock = 0;
+        dcode25->character = -1;
+        return(ZBAR_NONE);
+    }
+
+    dcode->buflen = dcode25->character;
+    dcode->buf[dcode25->character] = '\0';
+    dprintf(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;
+
+    dprintf(2, "      i25[%c%02d+%x]",
+            (dcode25->direction) ? '<' : '>',
+            dcode25->character, dcode25->element);
+
+    /* lock shared resources */
+    if(!dcode25->character && get_lock(dcode, ZBAR_I25)) {
+        dcode25->character = -1;
+        dprintf(2, " [locked %d]\n", dcode->lock);
+        return(ZBAR_PARTIAL);
+    }
+
+    unsigned char c = i25_decode10(dcode, 1);
+    dprintf(2, " c=%x", c);
+
+    if(c > 9 ||
+       ((dcode25->character >= BUFFER_MIN) &&
+        size_buf(dcode, dcode25->character + 2))) {
+        dprintf(2, (c > 9) ? " [aborted]\n" : " [overflow]\n");
+        dcode->lock = 0;
+        dcode25->character = -1;
+        return(ZBAR_NONE);
+    }
+    dcode->buf[dcode25->character++] = c + '0';
+
+    c = i25_decode10(dcode, 0);
+    dprintf(2, " c=%x", c);
+    if(c > 9) {
+        dprintf(2, " [aborted]\n");
+        dcode->lock = 0;
+        dcode25->character = -1;
+        return(ZBAR_NONE);
+    }
+    else
+        dprintf(2, "\n");
+
+    dcode->buf[dcode25->character++] = c + '0';
+    dcode25->element = 10;
+    return((dcode25->character == 2) ? ZBAR_PARTIAL : ZBAR_NONE);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoder/i25.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,63 @@
+/*------------------------------------------------------------------------
+ *  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 config;
+//    int configs[NUM_CFGS];      /* int valued configurations */
+//} i25_decoder_t;
+
+#include <stdint.h>
+
+typedef struct i25_decoder_s {
+    uint8_t direction;          /* scan direction: 0=fwd/space, 1=rev/bar */
+    uint8_t element;            /* element offset 0-8 */
+    int16_t character;          /* character position in symbol */
+    uint16_t s10;               /* current character width */
+    uint16_t width;             /* last character width */
+
+    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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/zbar.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,1312 @@
+/*------------------------------------------------------------------------
+ *  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 _ZBAR_H_
+#define _ZBAR_H_
+
+/** @file
+ * ZBar Barcode Reader C API definition
+ */
+
+/** @mainpage
+ *
+ * interface to the barcode reader is available at several levels.
+ * most applications will want to use the high-level interfaces:
+ *
+ * @section high-level High-Level Interfaces
+ *
+ * these interfaces wrap all library functionality into an easy-to-use
+ * package for a specific toolkit:
+ * - the "GTK+ 2.x widget" may be used with GTK GUI applications.  a
+ *   Python wrapper is included for PyGtk
+ * - the @ref zbar::QZBar "Qt4 widget" may be used with Qt GUI
+ *   applications
+ * - the Processor interface (in @ref c-processor "C" or @ref
+ *   zbar::Processor "C++") adds a scanning window to an application
+ *   with no GUI.
+ *
+ * @section mid-level Intermediate Interfaces
+ *
+ * building blocks used to construct high-level interfaces:
+ * - the ImageScanner (in @ref c-imagescanner "C" or @ref
+ *   zbar::ImageScanner "C++") looks for barcodes in a library defined
+ *   image object
+ * - the Window abstraction (in @ref c-window "C" or @ref
+ *   zbar::Window "C++") sinks library images, displaying them on the
+ *   platform display
+ * - the Video abstraction (in @ref c-video "C" or @ref zbar::Video
+ *   "C++") sources library images from a video device
+ *
+ * @section low-level Low-Level Interfaces
+ *
+ * direct interaction with barcode scanning and decoding:
+ * - the Scanner (in @ref c-scanner "C" or @ref zbar::Scanner "C++")
+ *   looks for barcodes in a linear intensity sample stream
+ * - the Decoder (in @ref c-decoder "C" or @ref zbar::Decoder "C++")
+ *   extracts barcodes from a stream of bar and space widths
+ */
+
+#ifdef __cplusplus
+
+/** C++ namespace for library interfaces */
+namespace zbar {
+    extern "C" {
+#endif
+
+
+/** @name Global library interfaces */
+/*@{*/
+
+/** "color" of element: bar or space. */
+typedef enum zbar_color_e {
+    ZBAR_SPACE = 0,    /**< light area or space between bars */
+    ZBAR_BAR = 1,      /**< dark area or colored bar segment */
+} zbar_color_t;
+
+/** decoded symbol type. */
+typedef enum zbar_symbol_type_e {
+    ZBAR_NONE        =      0,  /**< no symbol decoded */
+    ZBAR_PARTIAL     =      1,  /**< intermediate status */
+    ZBAR_EAN8        =      8,  /**< EAN-8 */
+    ZBAR_UPCE        =      9,  /**< UPC-E */
+    ZBAR_ISBN10      =     10,  /**< ISBN-10 (from EAN-13). @since 0.4 */
+    ZBAR_UPCA        =     12,  /**< UPC-A */
+    ZBAR_EAN13       =     13,  /**< EAN-13 */
+    ZBAR_ISBN13      =     14,  /**< ISBN-13 (from EAN-13). @since 0.4 */
+    ZBAR_I25         =     25,  /**< Interleaved 2 of 5. @since 0.4 */
+    ZBAR_CODE39      =     39,  /**< Code 39. @since 0.4 */
+    ZBAR_PDF417      =     57,  /**< PDF417. @since 0.6 */
+    ZBAR_QRCODE      =     64,  /**< QR Code. @since 0.10 */
+    ZBAR_CODE128     =    128,  /**< Code 128 */
+    ZBAR_SYMBOL      = 0x00ff,  /**< mask for base symbol type */
+    ZBAR_ADDON2      = 0x0200,  /**< 2-digit add-on flag */
+    ZBAR_ADDON5      = 0x0500,  /**< 5-digit add-on flag */
+    ZBAR_ADDON       = 0x0700,  /**< add-on flag mask */
+} zbar_symbol_type_t;
+
+/** error codes. */
+typedef enum zbar_error_e {
+    ZBAR_OK = 0,                /**< no error */
+    ZBAR_ERR_NOMEM,             /**< out of memory */
+    ZBAR_ERR_INTERNAL,          /**< internal library error */
+    ZBAR_ERR_UNSUPPORTED,       /**< unsupported request */
+    ZBAR_ERR_INVALID,           /**< invalid request */
+    ZBAR_ERR_SYSTEM,            /**< system error */
+    ZBAR_ERR_LOCKING,           /**< locking error */
+    ZBAR_ERR_BUSY,              /**< all resources busy */
+    ZBAR_ERR_XDISPLAY,          /**< X11 display error */
+    ZBAR_ERR_XPROTO,            /**< X11 protocol error */
+    ZBAR_ERR_CLOSED,            /**< output window is closed */
+    ZBAR_ERR_WINAPI,            /**< windows system error */
+    ZBAR_ERR_NUM                /**< number of error codes */
+} zbar_error_t;
+
+/** decoder configuration options.
+ * @since 0.4
+ */
+typedef enum zbar_config_e {
+    ZBAR_CFG_ENABLE = 0,        /**< enable symbology/feature */
+    ZBAR_CFG_ADD_CHECK,         /**< enable check digit when optional */
+    ZBAR_CFG_EMIT_CHECK,        /**< return check digit when present */
+    ZBAR_CFG_ASCII,             /**< enable full ASCII character set */
+    ZBAR_CFG_NUM,               /**< number of boolean decoder configs */
+
+    ZBAR_CFG_MIN_LEN = 0x20,    /**< minimum data length for valid decode */
+    ZBAR_CFG_MAX_LEN,           /**< maximum data length for valid decode */
+
+    ZBAR_CFG_POSITION = 0x80,   /**< enable scanner to collect position data */
+
+    ZBAR_CFG_X_DENSITY = 0x100, /**< image scanner vertical scan density */
+    ZBAR_CFG_Y_DENSITY,         /**< image scanner horizontal scan density */
+} zbar_config_t;
+
+/** retrieve runtime library version information.
+ * @param major set to the running major version (unless NULL)
+ * @param minor set to the running minor version (unless NULL)
+ * @returns 0
+ */
+extern int zbar_version(unsigned *major,
+                        unsigned *minor);
+
+/** set global library debug level.
+ * @param verbosity desired debug level.  higher values create more spew
+ */
+extern void zbar_set_verbosity(int verbosity);
+
+/** increase global library debug level.
+ * eg, for -vvvv
+ */
+extern void zbar_increase_verbosity(void);
+
+/** retrieve string name for symbol encoding.
+ * @param sym symbol type encoding
+ * @returns the static string name for the specified symbol type,
+ * or "UNKNOWN" if the encoding is not recognized
+ */
+extern const char *zbar_get_symbol_name(zbar_symbol_type_t sym);
+
+/** retrieve string name for addon encoding.
+ * @param sym symbol type encoding
+ * @returns static string name for any addon, or the empty string
+ * if no addons were decoded
+ */
+extern const char *zbar_get_addon_name(zbar_symbol_type_t sym);
+
+/** parse a configuration string of the form "[symbology.]config[=value]".
+ * the config must match one of the recognized names.
+ * the symbology, if present, must match one of the recognized names.
+ * if symbology is unspecified, it will be set to 0.
+ * if value is unspecified it will be set to 1.
+ * @returns 0 if the config is parsed successfully, 1 otherwise
+ * @since 0.4
+ */
+extern int zbar_parse_config(const char *config_string,
+                             zbar_symbol_type_t *symbology,
+                             zbar_config_t *config,
+                             int *value);
+
+/** @internal type unsafe error API (don't use) */
+extern int _zbar_error_spew(const void *object,
+                            int verbosity);
+extern const char *_zbar_error_string(const void *object,
+                                      int verbosity);
+extern zbar_error_t _zbar_get_error_code(const void *object);
+
+/*@}*/
+
+struct zbar_symbol_s;
+typedef struct zbar_symbol_s zbar_symbol_t;
+
+struct zbar_symbol_set_s;
+typedef struct zbar_symbol_set_s zbar_symbol_set_t;
+
+
+/*------------------------------------------------------------*/
+/** @name Symbol interface
+ * decoded barcode symbol result object.  stores type, data, and image
+ * location of decoded symbol.  all memory is owned by the library
+ */
+/*@{*/
+
+/** @typedef zbar_symbol_t
+ * opaque decoded symbol object.
+ */
+
+/** symbol reference count manipulation.
+ * increment the reference count when you store a new reference to the
+ * symbol.  decrement when the reference is no longer used.  do not
+ * refer to the symbol once the count is decremented and the
+ * containing image has been recycled or destroyed.
+ * @note the containing image holds a reference to the symbol, so you
+ * only need to use this if you keep a symbol after the image has been
+ * destroyed or reused.
+ * @since 0.9
+ */
+extern void zbar_symbol_ref(const zbar_symbol_t *symbol,
+                            int refs);
+
+/** retrieve type of decoded symbol.
+ * @returns the symbol type
+ */
+extern zbar_symbol_type_t zbar_symbol_get_type(const zbar_symbol_t *symbol);
+
+/** retrieve data decoded from symbol.
+ * @returns the data string
+ */
+extern const char *zbar_symbol_get_data(const zbar_symbol_t *symbol);
+
+/** retrieve length of binary data.
+ * @returns the length of the decoded data
+ */
+extern unsigned int zbar_symbol_get_data_length(const zbar_symbol_t *symbol);
+
+/** retrieve a symbol confidence metric.
+ * @returns an unscaled, relative quantity: larger values are better
+ * than smaller values, where "large" and "small" are application
+ * dependent.
+ * @note expect the exact definition of this quantity to change as the
+ * metric is refined.  currently, only the ordered relationship
+ * between two values is defined and will remain stable in the future
+ * @since 0.9
+ */
+extern int zbar_symbol_get_quality(const zbar_symbol_t *symbol);
+
+/** retrieve current cache count.  when the cache is enabled for the
+ * image_scanner this provides inter-frame reliability and redundancy
+ * information for video streams.
+ * @returns < 0 if symbol is still uncertain.
+ * @returns 0 if symbol is newly verified.
+ * @returns > 0 for duplicate symbols
+ */
+extern int zbar_symbol_get_count(const zbar_symbol_t *symbol);
+
+/** retrieve the number of points in the location polygon.  the
+ * location polygon defines the image area that the symbol was
+ * extracted from.
+ * @returns the number of points in the location polygon
+ * @note this is currently not a polygon, but the scan locations
+ * where the symbol was decoded
+ */
+extern unsigned zbar_symbol_get_loc_size(const zbar_symbol_t *symbol);
+
+/** retrieve location polygon x-coordinates.
+ * points are specified by 0-based index.
+ * @returns the x-coordinate for a point in the location polygon.
+ * @returns -1 if index is out of range
+ */
+extern int zbar_symbol_get_loc_x(const zbar_symbol_t *symbol,
+                                 unsigned index);
+
+/** retrieve location polygon y-coordinates.
+ * points are specified by 0-based index.
+ * @returns the y-coordinate for a point in the location polygon.
+ * @returns -1 if index is out of range
+ */
+extern int zbar_symbol_get_loc_y(const zbar_symbol_t *symbol,
+                                 unsigned index);
+
+/** iterate the set to which this symbol belongs (there can be only one).
+ * @returns the next symbol in the set, or
+ * @returns NULL when no more results are available
+ */
+extern const zbar_symbol_t *zbar_symbol_next(const zbar_symbol_t *symbol);
+
+/** retrieve components of a composite result.
+ * @returns the symbol set containing the components
+ * @returns NULL if the symbol is already a physical symbol
+ * @since 0.10
+ */
+extern const zbar_symbol_set_t*
+zbar_symbol_get_components(const zbar_symbol_t *symbol);
+
+/** iterate components of a composite result.
+ * @returns the first physical component symbol of a composite result
+ * @returns NULL if the symbol is already a physical symbol
+ * @since 0.10
+ */
+extern const zbar_symbol_t*
+zbar_symbol_first_component(const zbar_symbol_t *symbol);
+
+/** print XML symbol element representation to user result buffer.
+ * @see http://zbar.sourceforge.net/2008/barcode.xsd for the schema.
+ * @param symbol is the symbol to print
+ * @param buffer is the inout result pointer, it will be reallocated
+ * with a larger size if necessary.
+ * @param buflen is inout length of the result buffer.
+ * @returns the buffer pointer
+ * @since 0.6
+ */
+extern char *zbar_symbol_xml(const zbar_symbol_t *symbol,
+                             char **buffer,
+                             unsigned *buflen);
+
+/*@}*/
+
+/*------------------------------------------------------------*/
+/** @name Symbol Set interface
+ * container for decoded result symbols associated with an image
+ * or a composite symbol.
+ * @since 0.10
+ */
+/*@{*/
+
+/** @typedef zbar_symbol_set_t
+ * opaque symbol iterator object.
+ * @since 0.10
+ */
+
+/** reference count manipulation.
+ * increment the reference count when you store a new reference.
+ * decrement when the reference is no longer used.  do not refer to
+ * the object any longer once references have been released.
+ * @since 0.10
+ */
+extern void zbar_symbol_set_ref(const zbar_symbol_set_t *symbols,
+                                int refs);
+
+/** retrieve set size.
+ * @returns the number of symbols in the set.
+ * @since 0.10
+ */
+extern int zbar_symbol_set_get_size(const zbar_symbol_set_t *symbols);
+
+/** set iterator.
+ * @returns the first decoded symbol result in a set
+ * @returns NULL if the set is empty
+ * @since 0.10
+ */
+extern const zbar_symbol_t*
+zbar_symbol_set_first_symbol(const zbar_symbol_set_t *symbols);
+
+/*@}*/
+
+/*------------------------------------------------------------*/
+/** @name Image interface
+ * stores image data samples along with associated format and size
+ * metadata
+ */
+/*@{*/
+
+struct zbar_image_s;
+/** opaque image object. */
+typedef struct zbar_image_s zbar_image_t;
+
+/** cleanup handler callback function.
+ * called to free sample data when an image is destroyed.
+ */
+typedef void (zbar_image_cleanup_handler_t)(zbar_image_t *image);
+
+/** data handler callback function.
+ * called when decoded symbol results are available for an image
+ */
+typedef void (zbar_image_data_handler_t)(zbar_image_t *image,
+                                         const void *userdata);
+
+/** new image constructor.
+ * @returns a new image object with uninitialized data and format.
+ * this image should be destroyed (using zbar_image_destroy()) as
+ * soon as the application is finished with it
+ */
+extern zbar_image_t *zbar_image_create(void);
+
+/** image destructor.  all images created by or returned to the
+ * application should be destroyed using this function.  when an image
+ * is destroyed, the associated data cleanup handler will be invoked
+ * if available
+ * @note make no assumptions about the image or the data buffer.
+ * they may not be destroyed/cleaned immediately if the library
+ * is still using them.  if necessary, use the cleanup handler hook
+ * to keep track of image data buffers
+ */
+extern void zbar_image_destroy(zbar_image_t *image);
+
+/** image reference count manipulation.
+ * increment the reference count when you store a new reference to the
+ * image.  decrement when the reference is no longer used.  do not
+ * refer to the image any longer once the count is decremented.
+ * zbar_image_ref(image, -1) is the same as zbar_image_destroy(image)
+ * @since 0.5
+ */
+extern void zbar_image_ref(zbar_image_t *image,
+                           int refs);
+
+/** image format conversion.  refer to the documentation for supported
+ * image formats
+ * @returns a @em new image with the sample data from the original image
+ * converted to the requested format.  the original image is
+ * unaffected.
+ * @note the converted image size may be rounded (up) due to format
+ * constraints
+ */
+extern zbar_image_t *zbar_image_convert(const zbar_image_t *image,
+                                        unsigned long format);
+
+/** image format conversion with crop/pad.
+ * if the requested size is larger than the image, the last row/column
+ * are duplicated to cover the difference.  if the requested size is
+ * smaller than the image, the extra rows/columns are dropped from the
+ * right/bottom.
+ * @returns a @em new image with the sample data from the original
+ * image converted to the requested format and size.
+ * @note the image is @em not scaled
+ * @see zbar_image_convert()
+ * @since 0.4
+ */
+extern zbar_image_t *zbar_image_convert_resize(const zbar_image_t *image,
+                                               unsigned long format,
+                                               unsigned width,
+                                               unsigned height);
+
+/** retrieve the image format.
+ * @returns the fourcc describing the format of the image sample data
+ */
+extern unsigned long zbar_image_get_format(const zbar_image_t *image);
+
+/** retrieve a "sequence" (page/frame) number associated with this image.
+ * @since 0.6
+ */
+extern unsigned zbar_image_get_sequence(const zbar_image_t *image);
+
+/** retrieve the width of the image.
+ * @returns the width in sample columns
+ */
+extern unsigned zbar_image_get_width(const zbar_image_t *image);
+
+/** retrieve the height of the image.
+ * @returns the height in sample rows
+ */
+extern unsigned zbar_image_get_height(const zbar_image_t *image);
+
+/** return the image sample data.  the returned data buffer is only
+ * valid until zbar_image_destroy() is called
+ */
+extern const void *zbar_image_get_data(const zbar_image_t *image);
+
+/** return the size of image data.
+ * @since 0.6
+ */
+extern unsigned long zbar_image_get_data_length(const zbar_image_t *img);
+
+/** retrieve the decoded results.
+ * @returns the (possibly empty) set of decoded symbols
+ * @returns NULL if the image has not been scanned
+ * @since 0.10
+ */
+extern const zbar_symbol_set_t*
+zbar_image_get_symbols(const zbar_image_t *image);
+
+/** associate the specified symbol set with the image, replacing any
+ * existing results.  use NULL to release the current results from the
+ * image.
+ * @see zbar_image_scanner_recycle_image()
+ * @since 0.10
+ */
+extern void zbar_image_set_symbols(zbar_image_t *image,
+                                   const zbar_symbol_set_t *symbols);
+
+/** image_scanner decode result iterator.
+ * @returns the first decoded symbol result for an image
+ * or NULL if no results are available
+ */
+extern const zbar_symbol_t*
+zbar_image_first_symbol(const zbar_image_t *image);
+
+/** specify the fourcc image format code for image sample data.
+ * refer to the documentation for supported formats.
+ * @note this does not convert the data!
+ * (see zbar_image_convert() for that)
+ */
+extern void zbar_image_set_format(zbar_image_t *image,
+                                  unsigned long format);
+
+/** associate a "sequence" (page/frame) number with this image.
+ * @since 0.6
+ */
+extern void zbar_image_set_sequence(zbar_image_t *image,
+                                    unsigned sequence_num);
+
+/** specify the pixel size of the image.
+ * @note this does not affect the data!
+ */
+extern void zbar_image_set_size(zbar_image_t *image,
+                                unsigned width,
+                                unsigned height);
+
+/** specify image sample data.  when image data is no longer needed by
+ * the library the specific data cleanup handler will be called
+ * (unless NULL)
+ * @note application image data will not be modified by the library
+ */
+extern void zbar_image_set_data(zbar_image_t *image,
+                                const void *data,
+                                unsigned long data_byte_length,
+                                zbar_image_cleanup_handler_t *cleanup_hndlr);
+
+/** built-in cleanup handler.
+ * passes the image data buffer to free()
+ */
+extern void zbar_image_free_data(zbar_image_t *image);
+
+/** associate user specified data value with an image.
+ * @since 0.5
+ */
+extern void zbar_image_set_userdata(zbar_image_t *image,
+                                    void *userdata);
+
+/** return user specified data value associated with the image.
+ * @since 0.5
+ */
+extern void *zbar_image_get_userdata(const zbar_image_t *image);
+
+/** dump raw image data to a file for debug.
+ * the data will be prefixed with a 16 byte header consisting of:
+ *   - 4 bytes uint = 0x676d697a ("zimg")
+ *   - 4 bytes format fourcc
+ *   - 2 bytes width
+ *   - 2 bytes height
+ *   - 4 bytes size of following image data in bytes
+ * this header can be dumped w/eg:
+ * @verbatim
+       od -Ax -tx1z -N16 -w4 [file]
+@endverbatim
+ * for some formats the image can be displayed/converted using
+ * ImageMagick, eg:
+ * @verbatim
+       display -size 640x480+16 [-depth ?] [-sampling-factor ?x?] \
+           {GRAY,RGB,UYVY,YUV}:[file]
+@endverbatim
+ *
+ * @param image the image object to dump
+ * @param filebase base filename, appended with ".XXXX.zimg" where
+ * XXXX is the format fourcc
+ * @returns 0 on success or a system error code on failure
+ */
+extern int zbar_image_write(const zbar_image_t *image,
+                            const char *filebase);
+
+/** read back an image in the format written by zbar_image_write()
+ * @note TBD
+ */
+extern zbar_image_t *zbar_image_read(char *filename);
+
+/*@}*/
+
+/*------------------------------------------------------------*/
+/** @name Processor interface
+ * @anchor c-processor
+ * high-level self-contained image processor.
+ * processes video and images for barcodes, optionally displaying
+ * images to a library owned output window
+ */
+/*@{*/
+
+struct zbar_processor_s;
+/** opaque standalone processor object. */
+typedef struct zbar_processor_s zbar_processor_t;
+
+/** constructor.
+ * if threaded is set and threading is available the processor
+ * will spawn threads where appropriate to avoid blocking and
+ * improve responsiveness
+ */
+extern zbar_processor_t *zbar_processor_create(int threaded);
+
+/** destructor.  cleans up all resources associated with the processor
+ */
+extern void zbar_processor_destroy(zbar_processor_t *processor);
+
+/** (re)initialization.
+ * opens a video input device and/or prepares to display output
+ */
+extern int zbar_processor_init(zbar_processor_t *processor,
+                               const char *video_device,
+                               int enable_display);
+
+/** request a preferred size for the video image from the device.
+ * the request may be adjusted or completely ignored by the driver.
+ * @note must be called before zbar_processor_init()
+ * @since 0.6
+ */
+extern int zbar_processor_request_size(zbar_processor_t *processor,
+                                       unsigned width,
+                                       unsigned height);
+
+/** request a preferred video driver interface version for
+ * debug/testing.
+ * @note must be called before zbar_processor_init()
+ * @since 0.6
+ */
+extern int zbar_processor_request_interface(zbar_processor_t *processor,
+                                            int version);
+
+/** request a preferred video I/O mode for debug/testing.  You will
+ * get errors if the driver does not support the specified mode.
+ * @verbatim
+    0 = auto-detect
+    1 = force I/O using read()
+    2 = force memory mapped I/O using mmap()
+    3 = force USERPTR I/O (v4l2 only)
+@endverbatim
+ * @note must be called before zbar_processor_init()
+ * @since 0.7
+ */
+extern int zbar_processor_request_iomode(zbar_processor_t *video,
+                                         int iomode);
+
+/** force specific input and output formats for debug/testing.
+ * @note must be called before zbar_processor_init()
+ */
+extern int zbar_processor_force_format(zbar_processor_t *processor,
+                                       unsigned long input_format,
+                                       unsigned long output_format);
+
+/** setup result handler callback.
+ * the specified function will be called by the processor whenever
+ * new results are available from the video stream or a static image.
+ * pass a NULL value to disable callbacks.
+ * @param processor the object on which to set the handler.
+ * @param handler the function to call when new results are available.
+ * @param userdata is set as with zbar_processor_set_userdata().
+ * @returns the previously registered handler
+ */
+extern zbar_image_data_handler_t*
+zbar_processor_set_data_handler(zbar_processor_t *processor,
+                                zbar_image_data_handler_t *handler,
+                                const void *userdata);
+
+/** associate user specified data value with the processor.
+ * @since 0.6
+ */
+extern void zbar_processor_set_userdata(zbar_processor_t *processor,
+                                        void *userdata);
+
+/** return user specified data value associated with the processor.
+ * @since 0.6
+ */
+extern void *zbar_processor_get_userdata(const zbar_processor_t *processor);
+
+/** set config for indicated symbology (0 for all) to specified value.
+ * @returns 0 for success, non-0 for failure (config does not apply to
+ * specified symbology, or value out of range)
+ * @see zbar_decoder_set_config()
+ * @since 0.4
+ */
+extern int zbar_processor_set_config(zbar_processor_t *processor,
+                                     zbar_symbol_type_t symbology,
+                                     zbar_config_t config,
+                                     int value);
+
+/** parse configuration string using zbar_parse_config()
+ * and apply to processor using zbar_processor_set_config().
+ * @returns 0 for success, non-0 for failure
+ * @see zbar_parse_config()
+ * @see zbar_processor_set_config()
+ * @since 0.4
+ */
+static inline int zbar_processor_parse_config (zbar_processor_t *processor,
+                                               const char *config_string)
+{
+    zbar_symbol_type_t sym;
+    zbar_config_t cfg;
+    int val;
+    return(zbar_parse_config(config_string, &sym, &cfg, &val) ||
+           zbar_processor_set_config(processor, sym, cfg, val));
+}
+
+/** retrieve the current state of the ouput window.
+ * @returns 1 if the output window is currently displayed, 0 if not.
+ * @returns -1 if an error occurs
+ */
+extern int zbar_processor_is_visible(zbar_processor_t *processor);
+
+/** show or hide the display window owned by the library.
+ * the size will be adjusted to the input size
+ */
+extern int zbar_processor_set_visible(zbar_processor_t *processor,
+                                      int visible);
+
+/** control the processor in free running video mode.
+ * only works if video input is initialized. if threading is in use,
+ * scanning will occur in the background, otherwise this is only
+ * useful wrapping calls to zbar_processor_user_wait(). if the
+ * library output window is visible, video display will be enabled.
+ */
+extern int zbar_processor_set_active(zbar_processor_t *processor,
+                                     int active);
+
+/** retrieve decode results for last scanned image/frame.
+ * @returns the symbol set result container or NULL if no results are
+ * available
+ * @note the returned symbol set has its reference count incremented;
+ * ensure that the count is decremented after use
+ * @since 0.10
+ */
+extern const zbar_symbol_set_t*
+zbar_processor_get_results(const zbar_processor_t *processor);
+
+/** wait for input to the display window from the user
+ * (via mouse or keyboard).
+ * @returns >0 when input is received, 0 if timeout ms expired
+ * with no input or -1 in case of an error
+ */
+extern int zbar_processor_user_wait(zbar_processor_t *processor,
+                                    int timeout);
+
+/** process from the video stream until a result is available,
+ * or the timeout (in milliseconds) expires.
+ * specify a timeout of -1 to scan indefinitely
+ * (zbar_processor_set_active() may still be used to abort the scan
+ * from another thread).
+ * if the library window is visible, video display will be enabled.
+ * @note that multiple results may still be returned (despite the
+ * name).
+ * @returns >0 if symbols were successfully decoded,
+ * 0 if no symbols were found (ie, the timeout expired)
+ * or -1 if an error occurs
+ */
+extern int zbar_process_one(zbar_processor_t *processor,
+                            int timeout);
+
+/** process the provided image for barcodes.
+ * if the library window is visible, the image will be displayed.
+ * @returns >0 if symbols were successfully decoded,
+ * 0 if no symbols were found or -1 if an error occurs
+ */
+extern int zbar_process_image(zbar_processor_t *processor,
+                              zbar_image_t *image);
+
+/** display detail for last processor error to stderr.
+ * @returns a non-zero value suitable for passing to exit()
+ */
+static inline int
+zbar_processor_error_spew (const zbar_processor_t *processor,
+                           int verbosity)
+{
+    return(_zbar_error_spew(processor, verbosity));
+}
+
+/** retrieve the detail string for the last processor error. */
+static inline const char*
+zbar_processor_error_string (const zbar_processor_t *processor,
+                             int verbosity)
+{
+    return(_zbar_error_string(processor, verbosity));
+}
+
+/** retrieve the type code for the last processor error. */
+static inline zbar_error_t
+zbar_processor_get_error_code (const zbar_processor_t *processor)
+{
+    return(_zbar_get_error_code(processor));
+}
+
+/*@}*/
+
+/*------------------------------------------------------------*/
+/** @name Video interface
+ * @anchor c-video
+ * mid-level video source abstraction.
+ * captures images from a video device
+ */
+/*@{*/
+
+struct zbar_video_s;
+/** opaque video object. */
+typedef struct zbar_video_s zbar_video_t;
+
+/** constructor. */
+extern zbar_video_t *zbar_video_create(void);
+
+/** destructor. */
+extern void zbar_video_destroy(zbar_video_t *video);
+
+/** open and probe a video device.
+ * the device specified by platform specific unique name
+ * (v4l device node path in *nix eg "/dev/video",
+ *  DirectShow DevicePath property in windows).
+ * @returns 0 if successful or -1 if an error occurs
+ */
+extern int zbar_video_open(zbar_video_t *video,
+                           const char *device);
+
+/** retrieve file descriptor associated with open *nix video device
+ * useful for using select()/poll() to tell when new images are
+ * available (NB v4l2 only!!).
+ * @returns the file descriptor or -1 if the video device is not open
+ * or the driver only supports v4l1
+ */
+extern int zbar_video_get_fd(const zbar_video_t *video);
+
+/** request a preferred size for the video image from the device.
+ * the request may be adjusted or completely ignored by the driver.
+ * @returns 0 if successful or -1 if the video device is already
+ * initialized
+ * @since 0.6
+ */
+extern int zbar_video_request_size(zbar_video_t *video,
+                                   unsigned width,
+                                   unsigned height);
+
+/** request a preferred driver interface version for debug/testing.
+ * @note must be called before zbar_video_open()
+ * @since 0.6
+ */
+extern int zbar_video_request_interface(zbar_video_t *video,
+                                        int version);
+
+/** request a preferred I/O mode for debug/testing.  You will get
+ * errors if the driver does not support the specified mode.
+ * @verbatim
+    0 = auto-detect
+    1 = force I/O using read()
+    2 = force memory mapped I/O using mmap()
+    3 = force USERPTR I/O (v4l2 only)
+@endverbatim
+ * @note must be called before zbar_video_open()
+ * @since 0.7
+ */
+extern int zbar_video_request_iomode(zbar_video_t *video,
+                                     int iomode);
+
+/** retrieve current output image width.
+ * @returns the width or 0 if the video device is not open
+ */
+extern int zbar_video_get_width(const zbar_video_t *video);
+
+/** retrieve current output image height.
+ * @returns the height or 0 if the video device is not open
+ */
+extern int zbar_video_get_height(const zbar_video_t *video);
+
+/** initialize video using a specific format for debug.
+ * use zbar_negotiate_format() to automatically select and initialize
+ * the best available format
+ */
+extern int zbar_video_init(zbar_video_t *video,
+                           unsigned long format);
+
+/** start/stop video capture.
+ * all buffered images are retired when capture is disabled.
+ * @returns 0 if successful or -1 if an error occurs
+ */
+extern int zbar_video_enable(zbar_video_t *video,
+                             int enable);
+
+/** retrieve next captured image.  blocks until an image is available.
+ * @returns NULL if video is not enabled or an error occurs
+ */
+extern zbar_image_t *zbar_video_next_image(zbar_video_t *video);
+
+/** display detail for last video error to stderr.
+ * @returns a non-zero value suitable for passing to exit()
+ */
+static inline int zbar_video_error_spew (const zbar_video_t *video,
+                                         int verbosity)
+{
+    return(_zbar_error_spew(video, verbosity));
+}
+
+/** retrieve the detail string for the last video error. */
+static inline const char *zbar_video_error_string (const zbar_video_t *video,
+                                                   int verbosity)
+{
+    return(_zbar_error_string(video, verbosity));
+}
+
+/** retrieve the type code for the last video error. */
+static inline zbar_error_t
+zbar_video_get_error_code (const zbar_video_t *video)
+{
+    return(_zbar_get_error_code(video));
+}
+
+/*@}*/
+
+/*------------------------------------------------------------*/
+/** @name Window interface
+ * @anchor c-window
+ * mid-level output window abstraction.
+ * displays images to user-specified platform specific output window
+ */
+/*@{*/
+
+struct zbar_window_s;
+/** opaque window object. */
+typedef struct zbar_window_s zbar_window_t;
+
+/** constructor. */
+extern zbar_window_t *zbar_window_create(void);
+
+/** destructor. */
+extern void zbar_window_destroy(zbar_window_t *window);
+
+/** associate reader with an existing platform window.
+ * This can be any "Drawable" for X Windows or a "HWND" for windows.
+ * input images will be scaled into the output window.
+ * pass NULL to detach from the resource, further input will be
+ * ignored
+ */
+extern int zbar_window_attach(zbar_window_t *window,
+                              void *x11_display_w32_hwnd,
+                              unsigned long x11_drawable);
+
+/** control content level of the reader overlay.
+ * the overlay displays graphical data for informational or debug
+ * purposes.  higher values increase the level of annotation (possibly
+ * decreasing performance). @verbatim
+    0 = disable overlay
+    1 = outline decoded symbols (default)
+    2 = also track and display input frame rate
+@endverbatim
+ */
+extern void zbar_window_set_overlay(zbar_window_t *window,
+                                    int level);
+
+/** retrieve current content level of reader overlay.
+ * @see zbar_window_set_overlay()
+ * @since 0.10
+ */
+extern int zbar_window_get_overlay(const zbar_window_t *window);
+
+/** draw a new image into the output window. */
+extern int zbar_window_draw(zbar_window_t *window,
+                            zbar_image_t *image);
+
+/** redraw the last image (exposure handler). */
+extern int zbar_window_redraw(zbar_window_t *window);
+
+/** resize the image window (reconfigure handler).
+ * this does @em not update the contents of the window
+ * @since 0.3, changed in 0.4 to not redraw window
+ */
+extern int zbar_window_resize(zbar_window_t *window,
+                              unsigned width,
+                              unsigned height);
+
+/** display detail for last window error to stderr.
+ * @returns a non-zero value suitable for passing to exit()
+ */
+static inline int zbar_window_error_spew (const zbar_window_t *window,
+                                          int verbosity)
+{
+    return(_zbar_error_spew(window, verbosity));
+}
+
+/** retrieve the detail string for the last window error. */
+static inline const char*
+zbar_window_error_string (const zbar_window_t *window,
+                          int verbosity)
+{
+    return(_zbar_error_string(window, verbosity));
+}
+
+/** retrieve the type code for the last window error. */
+static inline zbar_error_t
+zbar_window_get_error_code (const zbar_window_t *window)
+{
+    return(_zbar_get_error_code(window));
+}
+
+
+/** select a compatible format between video input and output window.
+ * the selection algorithm attempts to use a format shared by
+ * video input and window output which is also most useful for
+ * barcode scanning.  if a format conversion is necessary, it will
+ * heuristically attempt to minimize the cost of the conversion
+ */
+extern int zbar_negotiate_format(zbar_video_t *video,
+                                 zbar_window_t *window);
+
+/*@}*/
+
+/*------------------------------------------------------------*/
+/** @name Image Scanner interface
+ * @anchor c-imagescanner
+ * mid-level image scanner interface.
+ * reads barcodes from 2-D images
+ */
+/*@{*/
+
+struct zbar_image_scanner_s;
+/** opaque image scanner object. */
+typedef struct zbar_image_scanner_s zbar_image_scanner_t;
+
+/** constructor. */
+extern zbar_image_scanner_t *zbar_image_scanner_create(void);
+
+/** destructor. */
+extern void zbar_image_scanner_destroy(zbar_image_scanner_t *scanner);
+
+/** setup result handler callback.
+ * the specified function will be called by the scanner whenever
+ * new results are available from a decoded image.
+ * pass a NULL value to disable callbacks.
+ * @returns the previously registered handler
+ */
+extern zbar_image_data_handler_t*
+zbar_image_scanner_set_data_handler(zbar_image_scanner_t *scanner,
+                                    zbar_image_data_handler_t *handler,
+                                    const void *userdata);
+
+
+/** set config for indicated symbology (0 for all) to specified value.
+ * @returns 0 for success, non-0 for failure (config does not apply to
+ * specified symbology, or value out of range)
+ * @see zbar_decoder_set_config()
+ * @since 0.4
+ */
+extern int zbar_image_scanner_set_config(zbar_image_scanner_t *scanner,
+                                         zbar_symbol_type_t symbology,
+                                         zbar_config_t config,
+                                         int value);
+
+/** parse configuration string using zbar_parse_config()
+ * and apply to image scanner using zbar_image_scanner_set_config().
+ * @returns 0 for success, non-0 for failure
+ * @see zbar_parse_config()
+ * @see zbar_image_scanner_set_config()
+ * @since 0.4
+ */
+static inline int
+zbar_image_scanner_parse_config (zbar_image_scanner_t *scanner,
+                                 const char *config_string)
+{
+    zbar_symbol_type_t sym;
+    zbar_config_t cfg;
+    int val;
+    return(zbar_parse_config(config_string, &sym, &cfg, &val) ||
+           zbar_image_scanner_set_config(scanner, sym, cfg, val));
+}
+
+/** enable or disable the inter-image result cache (default disabled).
+ * mostly useful for scanning video frames, the cache filters
+ * duplicate results from consecutive images, while adding some
+ * consistency checking and hysteresis to the results.
+ * this interface also clears the cache
+ */
+extern void zbar_image_scanner_enable_cache(zbar_image_scanner_t *scanner,
+                                            int enable);
+
+/** remove any previously decoded results from the image scanner and the
+ * specified image.  somewhat more efficient version of
+ * zbar_image_set_symbols(image, NULL) which may retain memory for
+ * subsequent decodes
+ * @since 0.10
+ */
+extern void zbar_image_scanner_recycle_image(zbar_image_scanner_t *scanner,
+                                             zbar_image_t *image);
+
+/** retrieve decode results for last scanned image.
+ * @returns the symbol set result container or NULL if no results are
+ * available
+ * @note the symbol set does not have its reference count adjusted;
+ * ensure that the count is incremented if the results may be kept
+ * after the next image is scanned
+ * @since 0.10
+ */
+extern const zbar_symbol_set_t*
+zbar_image_scanner_get_results(const zbar_image_scanner_t *scanner);
+
+/** scan for symbols in provided image.  The image format must be
+ * "Y800" or "GRAY".
+ * @returns >0 if symbols were successfully decoded from the image,
+ * 0 if no symbols were found or -1 if an error occurs
+ * @see zbar_image_convert()
+ * @since 0.9 - changed to only accept grayscale images
+ */
+extern int zbar_scan_image(zbar_image_scanner_t *scanner,
+                           zbar_image_t *image);
+
+/*@}*/
+
+/*------------------------------------------------------------*/
+/** @name Decoder interface
+ * @anchor c-decoder
+ * low-level bar width stream decoder interface.
+ * identifies symbols and extracts encoded data
+ */
+/*@{*/
+
+struct zbar_decoder_s;
+/** opaque decoder object. */
+typedef struct zbar_decoder_s zbar_decoder_t;
+
+/** decoder data handler callback function.
+ * called by decoder when new data has just been decoded
+ */
+typedef void (zbar_decoder_handler_t)(zbar_decoder_t *decoder);
+
+/** constructor. */
+extern zbar_decoder_t *zbar_decoder_create(void);
+
+/** destructor. */
+extern void zbar_decoder_destroy(zbar_decoder_t *decoder);
+
+/** set config for indicated symbology (0 for all) to specified value.
+ * @returns 0 for success, non-0 for failure (config does not apply to
+ * specified symbology, or value out of range)
+ * @since 0.4
+ */
+extern int zbar_decoder_set_config(zbar_decoder_t *decoder,
+                                   zbar_symbol_type_t symbology,
+                                   zbar_config_t config,
+                                   int value);
+
+/** parse configuration string using zbar_parse_config()
+ * and apply to decoder using zbar_decoder_set_config().
+ * @returns 0 for success, non-0 for failure
+ * @see zbar_parse_config()
+ * @see zbar_decoder_set_config()
+ * @since 0.4
+ */
+static inline int zbar_decoder_parse_config (zbar_decoder_t *decoder,
+                                             const char *config_string)
+{
+    zbar_symbol_type_t sym;
+    zbar_config_t cfg;
+    int val;
+    return(zbar_parse_config(config_string, &sym, &cfg, &val) ||
+           zbar_decoder_set_config(decoder, sym, cfg, val));
+}
+
+/** clear all decoder state.
+ * any partial symbols are flushed
+ */
+extern void zbar_decoder_reset(zbar_decoder_t *decoder);
+
+/** mark start of a new scan pass.
+ * clears any intra-symbol state and resets color to ::ZBAR_SPACE.
+ * any partially decoded symbol state is retained
+ */
+extern void zbar_decoder_new_scan(zbar_decoder_t *decoder);
+
+/** process next bar/space width from input stream.
+ * the width is in arbitrary relative units.  first value of a scan
+ * is ::ZBAR_SPACE width, alternating from there.
+ * @returns appropriate symbol type if width completes
+ * decode of a symbol (data is available for retrieval)
+ * @returns ::ZBAR_PARTIAL as a hint if part of a symbol was decoded
+ * @returns ::ZBAR_NONE (0) if no new symbol data is available
+ */
+extern zbar_symbol_type_t zbar_decode_width(zbar_decoder_t *decoder,
+                                            unsigned width);
+
+/** retrieve color of @em next element passed to
+ * zbar_decode_width(). */
+extern zbar_color_t zbar_decoder_get_color(const zbar_decoder_t *decoder);
+
+/** retrieve last decoded data.
+ * @returns the data string or NULL if no new data available.
+ * the returned data buffer is owned by library, contents are only
+ * valid between non-0 return from zbar_decode_width and next library
+ * call
+ */
+extern const char *zbar_decoder_get_data(const zbar_decoder_t *decoder);
+
+/** retrieve length of binary data.
+ * @returns the length of the decoded data or 0 if no new data
+ * available.
+ */
+extern unsigned int
+zbar_decoder_get_data_length(const zbar_decoder_t *decoder);
+
+/** retrieve last decoded symbol type.
+ * @returns the type or ::ZBAR_NONE if no new data available
+ */
+extern zbar_symbol_type_t
+zbar_decoder_get_type(const zbar_decoder_t *decoder);
+
+/** setup data handler callback.
+ * the registered function will be called by the decoder
+ * just before zbar_decode_width() returns a non-zero value.
+ * pass a NULL value to disable callbacks.
+ * @returns the previously registered handler
+ */
+extern zbar_decoder_handler_t*
+zbar_decoder_set_handler(zbar_decoder_t *decoder,
+                         zbar_decoder_handler_t *handler);
+
+/** associate user specified data value with the decoder. */
+extern void zbar_decoder_set_userdata(zbar_decoder_t *decoder,
+                                      void *userdata);
+
+/** return user specified data value associated with the decoder. */
+extern void *zbar_decoder_get_userdata(const zbar_decoder_t *decoder);
+
+/*@}*/
+
+/*------------------------------------------------------------*/
+/** @name Scanner interface
+ * @anchor c-scanner
+ * low-level linear intensity sample stream scanner interface.
+ * identifies "bar" edges and measures width between them.
+ * optionally passes to bar width decoder
+ */
+/*@{*/
+
+struct zbar_scanner_s;
+/** opaque scanner object. */
+typedef struct zbar_scanner_s zbar_scanner_t;
+
+/** constructor.
+ * if decoder is non-NULL it will be attached to scanner
+ * and called automatically at each new edge
+ * current color is initialized to ::ZBAR_SPACE
+ * (so an initial BAR->SPACE transition may be discarded)
+ */
+extern zbar_scanner_t *zbar_scanner_create(zbar_decoder_t *decoder);
+
+/** destructor. */
+extern void zbar_scanner_destroy(zbar_scanner_t *scanner);
+
+/** clear all scanner state.
+ * also resets an associated decoder
+ */
+extern zbar_symbol_type_t zbar_scanner_reset(zbar_scanner_t *scanner);
+
+/** mark start of a new scan pass. resets color to ::ZBAR_SPACE.
+ * also updates an associated decoder.
+ * @returns any decode results flushed from the pipeline
+ * @note when not using callback handlers, the return value should
+ * be checked the same as zbar_scan_y()
+ * @note call zbar_scanner_flush() at least twice before calling this
+ * method to ensure no decode results are lost
+ */
+extern zbar_symbol_type_t zbar_scanner_new_scan(zbar_scanner_t *scanner);
+
+/** flush scanner processing pipeline.
+ * forces current scanner position to be a scan boundary.
+ * call multiple times (max 3) to completely flush decoder.
+ * @returns any decode/scan results flushed from the pipeline
+ * @note when not using callback handlers, the return value should
+ * be checked the same as zbar_scan_y()
+ * @since 0.9
+ */
+extern zbar_symbol_type_t zbar_scanner_flush(zbar_scanner_t *scanner);
+
+/** process next sample intensity value.
+ * intensity (y) is in arbitrary relative units.
+ * @returns result of zbar_decode_width() if a decoder is attached,
+ * otherwise @returns (::ZBAR_PARTIAL) when new edge is detected
+ * or 0 (::ZBAR_NONE) if no new edge is detected
+ */
+extern zbar_symbol_type_t zbar_scan_y(zbar_scanner_t *scanner,
+                                      int y);
+
+/** process next sample from RGB (or BGR) triple. */
+static inline zbar_symbol_type_t zbar_scan_rgb24 (zbar_scanner_t *scanner,
+                                                    unsigned char *rgb)
+{
+    return(zbar_scan_y(scanner, rgb[0] + rgb[1] + rgb[2]));
+}
+
+/** retrieve last scanned width. */
+extern unsigned zbar_scanner_get_width(const zbar_scanner_t *scanner);
+
+/** retrieve sample position of last edge.
+ * @since 0.10
+ */
+extern unsigned zbar_scanner_get_edge(const zbar_scanner_t *scn,
+                                      unsigned offset,
+                                      int prec);
+
+/** retrieve last scanned color. */
+extern zbar_color_t zbar_scanner_get_color(const zbar_scanner_t *scanner);
+
+/*@}*/
+
+#ifdef __cplusplus
+    }
+}
+
+//# include "zbar/Exception.h"
+# include "zbar/Decoder.h"
+# include "zbar/Scanner.h"
+# include "zbar/Symbol.h"
+//# include "zbar/Image.h"
+//# include "zbar/ImageScanner.h"
+//# include "zbar/Video.h"
+//# include "zbar/Window.h"
+//# include "zbar/Processor.h"
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/zbar/Decoder.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,193 @@
+//------------------------------------------------------------------------
+//  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 _ZBAR_DECODER_H_
+#define _ZBAR_DECODER_H_
+
+/// @file
+/// Decoder C++ wrapper
+
+#ifndef _ZBAR_H_
+# error "include zbar.h in your application, **not** zbar/Decoder.h"
+#endif
+
+#include <string>
+
+namespace zbar {
+
+/// low-level bar width stream decoder interface.
+/// identifies symbols and extracts encoded data
+
+class Decoder {
+ public:
+
+    /// Decoder result handler.
+    /// applications should subtype this and pass an instance to
+    /// set_handler() to implement result processing
+    class Handler {
+    public:
+        virtual ~Handler() { }
+
+        /// invoked by the Decoder as decode results become available.
+        virtual void decode_callback(Decoder &decoder) = 0;
+    };
+
+    /// constructor.
+    Decoder ()
+        : _handler(NULL)
+    {
+        _decoder = zbar_decoder_create();
+    }
+
+    ~Decoder ()
+    {
+        zbar_decoder_destroy(_decoder);
+    }
+
+    /// clear all decoder state.
+    /// see zbar_decoder_reset()
+    void reset ()
+    {
+        zbar_decoder_reset(_decoder);
+    }
+
+    /// mark start of a new scan pass.
+    /// see zbar_decoder_new_scan()
+    void new_scan ()
+    {
+        zbar_decoder_new_scan(_decoder);
+    }
+
+    /// process next bar/space width from input stream.
+    /// see zbar_decode_width()
+    zbar_symbol_type_t decode_width (unsigned width)
+    {
+        return(zbar_decode_width(_decoder, width));
+    }
+
+    /// process next bar/space width from input stream.
+    /// see zbar_decode_width()
+    Decoder& operator<< (unsigned width)
+    {
+        zbar_decode_width(_decoder, width);
+        return(*this);
+    }
+
+    /// retrieve color of @em next element passed to Decoder.
+    /// see zbar_decoder_get_color()
+    zbar_color_t get_color () const
+    {
+        return(zbar_decoder_get_color(_decoder));
+    }
+
+    /// retrieve last decoded symbol type.
+    /// see zbar_decoder_get_type()
+    zbar_symbol_type_t get_type () const
+    {
+        return(zbar_decoder_get_type(_decoder));
+    }
+
+    /// retrieve string name of last decoded symbol type.
+    /// see zbar_get_symbol_name()
+    const char *get_symbol_name () const
+    {
+        return(zbar_get_symbol_name(zbar_decoder_get_type(_decoder)));
+    }
+
+    /// retrieve string name for last decode addon.
+    /// see zbar_get_addon_name()
+    const char *get_addon_name () const
+    {
+        return(zbar_get_addon_name(zbar_decoder_get_type(_decoder)));
+    }
+
+    /// retrieve last decoded data in ASCII format as a char array.
+    /// see zbar_decoder_get_data()
+    const char *get_data_chars() const
+    {
+        return(zbar_decoder_get_data(_decoder));
+    }
+
+    /// retrieve last decoded data as a std::string.
+    /// see zbar_decoder_get_data()
+    const std::string get_data_string() const
+    {
+        return(std::string(zbar_decoder_get_data(_decoder),
+                           zbar_decoder_get_data_length(_decoder)));
+    }
+
+    /// retrieve last decoded data as a std::string.
+    /// see zbar_decoder_get_data()
+    const std::string get_data() const
+    {
+        return(get_data_string());
+    }
+
+    /// retrieve length of decoded binary data.
+    /// see zbar_decoder_get_data_length()
+    int get_data_length() const
+    {
+        return(zbar_decoder_get_data_length(_decoder));
+    }
+
+    /// setup callback to handle result data.
+    void set_handler (Handler &handler)
+    {
+        _handler = &handler;
+        zbar_decoder_set_handler(_decoder, _cb);
+        zbar_decoder_set_userdata(_decoder, this);
+    }
+
+    /// set config for indicated symbology (0 for all) to specified value.
+    /// @see zbar_decoder_set_config()
+    /// @since 0.4
+    int set_config (zbar_symbol_type_t symbology,
+                    zbar_config_t config,
+                    int value)
+    {
+        return(zbar_decoder_set_config(_decoder, symbology, config, value));
+    }
+
+    /// set config parsed from configuration string.
+    /// @see zbar_decoder_parse_config()
+    /// @since 0.4
+    int set_config (std::string cfgstr)
+    {
+        return(zbar_decoder_parse_config(_decoder, cfgstr.c_str()));
+    }
+
+ private:
+    friend class Scanner;
+    zbar_decoder_t *_decoder;
+    Handler *_handler;
+
+    static void _cb (zbar_decoder_t *cdcode)
+    {
+        Decoder *dcode = (Decoder*)zbar_decoder_get_userdata(cdcode);
+        if(dcode && dcode->_handler)
+            dcode->_handler->decode_callback(*dcode);
+    }
+};
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/zbar/Scanner.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,162 @@
+//------------------------------------------------------------------------
+//  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 _ZBAR_SCANNER_H_
+#define _ZBAR_SCANNER_H_
+
+/// @file
+/// Scanner C++ wrapper
+
+#ifndef _ZBAR_H_
+# error "include zbar.h in your application, **not** zbar/Scanner.h"
+#endif
+
+#include <stdio.h>
+
+namespace zbar {
+
+/// low-level linear intensity sample stream scanner interface.
+/// identifies "bar" edges and measures width between them.
+/// optionally passes to bar width Decoder
+
+class Scanner {
+ public:
+
+    /// constructor.
+    /// @param decoder reference to a Decoder instance which will
+    /// be passed scan results automatically
+    Scanner (Decoder& decoder)
+    {
+        _scanner = zbar_scanner_create(decoder._decoder);
+    }
+
+    /// constructor.
+    /// @param decoder pointer to a Decoder instance which will
+    /// be passed scan results automatically
+    Scanner (Decoder* decoder = NULL)
+    {
+        zbar_decoder_t *zdcode = NULL;
+        if(decoder)
+            zdcode = decoder->_decoder;
+        _scanner = zbar_scanner_create(zdcode);
+    }
+
+    ~Scanner ()
+    {
+        zbar_scanner_destroy(_scanner);
+    }
+
+    /// clear all scanner state.
+    /// see zbar_scanner_reset()
+    void reset ()
+    {
+        zbar_scanner_reset(_scanner);
+    }
+
+    /// mark start of a new scan pass.
+    /// see zbar_scanner_new_scan()
+    zbar_symbol_type_t new_scan ()
+    {
+        _type = zbar_scanner_new_scan(_scanner);
+        return(_type);
+    }
+
+    /// flush scanner pipeline.
+    /// see zbar_scanner_flush()
+    zbar_symbol_type_t flush ()
+    {
+        _type = zbar_scanner_flush(_scanner);
+        return(_type);
+    }
+
+    /// process next sample intensity value.
+    /// see zbar_scan_y()
+    zbar_symbol_type_t scan_y (int y)
+    {
+        _type = zbar_scan_y(_scanner, y);
+        return(_type);
+    }
+
+    /// process next sample intensity value.
+    /// see zbar_scan_y()
+    Scanner& operator<< (int y)
+    {
+        _type = zbar_scan_y(_scanner, y);
+        return(*this);
+    }
+
+    /// process next sample from RGB (or BGR) triple.
+    /// see zbar_scan_rgb24()
+    zbar_symbol_type_t scan_rgb24 (unsigned char *rgb)
+    {
+        _type = zbar_scan_rgb24(_scanner, rgb);
+        return(_type);
+    }
+
+    /// process next sample from RGB (or BGR) triple.
+    /// see zbar_scan_rgb24()
+    Scanner& operator<< (unsigned char *rgb)
+    {
+        _type = zbar_scan_rgb24(_scanner, rgb);
+        return(*this);
+    }
+
+    /// retrieve last scanned width.
+    /// see zbar_scanner_get_width()
+    unsigned get_width () const
+    {
+        return(zbar_scanner_get_width(_scanner));
+    }
+
+    /// retrieve last scanned color.
+    /// see zbar_scanner_get_color()
+    zbar_color_t get_color () const
+    {
+        return(zbar_scanner_get_color(_scanner));
+    }
+
+    /// retrieve last scan result.
+    zbar_symbol_type_t get_type () const
+    {
+        return(_type);
+    }
+
+    /// cast to C scanner
+    operator zbar_scanner_t* () const
+    {
+        return(_scanner);
+    }
+
+    /// retrieve C scanner
+    const zbar_scanner_t *get_c_scanner () const
+    {
+        return(_scanner);
+    }
+
+ private:
+    zbar_scanner_t *_scanner;
+    zbar_symbol_type_t _type;
+};
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/zbar/Symbol.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,451 @@
+//------------------------------------------------------------------------
+//  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 _ZBAR_SYMBOL_H_
+#define _ZBAR_SYMBOL_H_
+
+/// @file
+/// Symbol C++ wrapper
+
+#ifndef _ZBAR_H_
+# error "include zbar.h in your application, **not** zbar/Symbol.h"
+#endif
+
+#include <stdlib.h>
+#include <string>
+#include <ostream>
+#include <assert.h>
+
+namespace zbar {
+
+class SymbolIterator;
+
+/// container for decoded result symbols associated with an image
+/// or a composite symbol.
+
+class SymbolSet {
+public:
+    /// constructor.
+    SymbolSet (const zbar_symbol_set_t *syms = NULL)
+        : _syms(syms)
+    {
+        ref();
+    }
+
+    /// copy constructor.
+    SymbolSet (const SymbolSet& syms)
+        : _syms(syms._syms)
+    {
+        ref();
+    }
+
+    /// destructor.
+    ~SymbolSet ()
+    {
+        ref(-1);
+    }
+
+    /// manipulate reference count.
+    void ref (int delta = 1) const
+    {
+        if(_syms)
+            zbar_symbol_set_ref((zbar_symbol_set_t*)_syms, delta);
+    }
+
+    /// cast to C symbol set.
+    operator const zbar_symbol_set_t* () const
+    {
+        return(_syms);
+    }
+
+    int get_size ()
+    {
+        return((_syms) ? zbar_symbol_set_get_size(_syms) : 0);
+    }
+
+    /// create a new SymbolIterator over decoded results.
+    SymbolIterator symbol_begin() const;
+
+    /// return a SymbolIterator suitable for ending iteration.
+    const SymbolIterator symbol_end() const;
+
+private:
+    const zbar_symbol_set_t *_syms;
+};
+
+/// decoded barcode symbol result object.  stores type, data, and
+/// image location of decoded symbol
+
+class Symbol {
+public:
+
+    /// image pixel location (x, y) coordinate tuple.
+    class Point {
+    public:
+        int x;  ///< x-coordinate.
+        int y;  ///< y-coordinate.
+
+        Point () { }
+
+        Point(int x, int y)
+            : x(x), y(y)
+        { }
+
+        /// copy constructor.
+        Point (const Point& pt)
+        {
+            x = pt.x;
+            y = pt.y;
+        }
+    };
+
+    /// iteration over Point objects in a symbol location polygon.
+    class PointIterator
+        : public std::iterator<std::input_iterator_tag, Point> {
+
+    public:
+        /// constructor.
+        PointIterator (const Symbol *sym = NULL,
+                       int index = 0)
+            : _sym(sym),
+              _index(index)
+        {
+            sym->ref(1);
+            if(!sym ||
+               (unsigned)_index >= zbar_symbol_get_loc_size(*_sym))
+                _index = -1;
+        }
+
+        /// constructor.
+        PointIterator (const PointIterator& iter)
+            : _sym(iter._sym),
+              _index(iter._index)
+        {
+            _sym->ref();
+        }
+
+        /// destructor.
+        ~PointIterator ()
+        {
+            _sym->ref(-1);
+        }
+
+        /// advance iterator to next Point.
+        PointIterator& operator++ ()
+        {
+            unsigned int i = ++_index;
+            if(i >= zbar_symbol_get_loc_size(*_sym))
+                _index = -1;
+            return(*this);
+        }
+
+        /// retrieve currently referenced Point.
+        const Point operator* () const
+        {
+            assert(_index >= 0);
+            return(Point(zbar_symbol_get_loc_x(*_sym, _index),
+                         zbar_symbol_get_loc_y(*_sym, _index)));
+        }
+
+        /// test if two iterators refer to the same Point in the same
+        /// Symbol.
+        bool operator== (const PointIterator& iter) const
+        {
+            return(_index == iter._index &&
+                   ((_index < 0) || _sym == iter._sym));
+        }
+
+        /// test if two iterators refer to the same Point in the same
+        /// Symbol.
+        bool operator!= (const PointIterator& iter) const
+        {
+            return(!(*this == iter));
+        }
+
+    private:
+        const Symbol *_sym;
+        int _index;
+    };
+
+    /// constructor.
+    Symbol (const zbar_symbol_t *sym = NULL)
+        : _xmlbuf(NULL),
+          _xmllen(0)
+    {
+        init(sym);
+        ref();
+    }
+
+    /// copy constructor.
+    Symbol (const Symbol& sym)
+        : _sym(sym._sym),
+          _type(sym._type),
+          _data(sym._data),
+          _xmlbuf(NULL),
+          _xmllen(0)
+    {
+        ref();
+    }
+
+    /// destructor.
+    ~Symbol () {
+        if(_xmlbuf)
+            free(_xmlbuf);
+        ref(-1);
+    }
+
+    void ref (int delta = 1) const
+    {
+        if(_sym)
+            zbar_symbol_ref((zbar_symbol_t*)_sym, delta);
+    }
+
+    /// cast to C symbol.
+    operator const zbar_symbol_t* () const
+    {
+        return(_sym);
+    }
+
+    /// test if two Symbol objects refer to the same C symbol.
+    bool operator== (const Symbol& sym) const
+    {
+        return(_sym == sym._sym);
+    }
+
+    /// test if two Symbol objects refer to the same C symbol.
+    bool operator!= (const Symbol& sym) const
+    {
+        return(!(*this == sym));
+    }
+
+    /// retrieve type of decoded symbol.
+    zbar_symbol_type_t get_type () const
+    {
+        return(_type);
+    }
+
+    /// retrieve the string name of the symbol type.
+    const std::string get_type_name () const
+    {
+        return(zbar_get_symbol_name(_type));
+    }
+
+    /// retrieve the string name for any addon.
+    const std::string get_addon_name () const
+    {
+        return(zbar_get_addon_name(_type));
+    }
+
+    /// retrieve data decoded from symbol.
+    const std::string get_data () const
+    {
+        return(_data);
+    }
+
+    /// retrieve length of binary data
+    unsigned get_data_length () const
+    {
+        return((_sym) ? zbar_symbol_get_data_length(_sym) : 0);
+    }
+
+    /// retrieve inter-frame coherency count.
+    /// see zbar_symbol_get_count()
+    /// @since 1.5
+    int get_count () const
+    {
+        return((_sym) ? zbar_symbol_get_count(_sym) : -1);
+    }
+
+    SymbolSet get_components () const
+    {
+        return(SymbolSet((_sym) ? zbar_symbol_get_components(_sym) : NULL));
+    }
+
+    /// create a new PointIterator at the start of the location
+    /// polygon.
+    PointIterator point_begin() const
+    {
+        return(PointIterator(this));
+    }
+
+    /// return a PointIterator suitable for ending iteration.
+    const PointIterator point_end() const
+    {
+        return(PointIterator());
+    }
+
+    /// see zbar_symbol_get_loc_size().
+    int get_location_size () const
+    {
+        return((_sym) ? zbar_symbol_get_loc_size(_sym) : 0);
+    }
+
+    /// see zbar_symbol_get_loc_x().
+    int get_location_x (unsigned index) const
+    {
+        return((_sym) ? zbar_symbol_get_loc_x(_sym, index) : -1);
+    }
+
+    /// see zbar_symbol_get_loc_y().
+    int get_location_y (unsigned index) const
+    {
+        return((_sym) ? zbar_symbol_get_loc_y(_sym, index) : -1);
+    }
+
+    /// see zbar_symbol_xml().
+    const std::string xml () const
+    {
+        if(!_sym)
+            return("");
+        return(zbar_symbol_xml(_sym, (char**)&_xmlbuf, (unsigned*)&_xmllen));
+    }
+
+protected:
+
+    friend class SymbolIterator;
+
+    /// (re)initialize Symbol from C symbol object.
+    void init (const zbar_symbol_t *sym = NULL)
+    {
+        _sym = sym;
+        if(sym) {
+            _type = zbar_symbol_get_type(sym);
+            _data = std::string(zbar_symbol_get_data(sym),
+                                zbar_symbol_get_data_length(sym));
+        }
+        else {
+            _type = ZBAR_NONE;
+            _data = "";
+        }
+    }
+
+private:
+    const zbar_symbol_t *_sym;
+    zbar_symbol_type_t _type;
+    std::string _data;
+    char *_xmlbuf;
+    unsigned _xmllen;
+};
+
+/// iteration over Symbol result objects in a scanned Image or SymbolSet.
+class SymbolIterator
+    : public std::iterator<std::input_iterator_tag, Symbol> {
+
+public:
+    /// default constructor.
+    SymbolIterator ()
+    { }
+
+    /// constructor.
+    SymbolIterator (const SymbolSet &syms)
+        : _syms(syms)
+    {
+        const zbar_symbol_set_t *zsyms = _syms;
+        if(zsyms)
+            _sym.init(zbar_symbol_set_first_symbol(zsyms));
+    }
+
+    /// copy constructor.
+    SymbolIterator (const SymbolIterator& iter)
+        : _syms(iter._syms)
+    {
+        const zbar_symbol_set_t *zsyms = _syms;
+        if(zsyms)
+            _sym.init(zbar_symbol_set_first_symbol(zsyms));
+    }
+
+    ~SymbolIterator ()
+    {
+        _sym.init();
+    }
+
+    /// advance iterator to next Symbol.
+    SymbolIterator& operator++ ()
+    {
+        const zbar_symbol_t *zsym = _sym;
+        if(zsym)
+            _sym.init(zbar_symbol_next(zsym));
+        else {
+            const zbar_symbol_set_t *zsyms = _syms;
+            if(zsyms)
+                _sym.init(zbar_symbol_set_first_symbol(zsyms));
+        }
+        return(*this);
+    }
+
+    /// retrieve currently referenced Symbol.
+    const Symbol operator* () const
+    {
+        return(_sym);
+    }
+
+    /// access currently referenced Symbol.
+    const Symbol* operator-> () const
+    {
+        return(&_sym);
+    }
+
+    /// test if two iterators refer to the same Symbol
+    bool operator== (const SymbolIterator& iter) const
+    {
+        // it is enough to test the symbols, as they belong
+        // to only one set (also simplifies invalid case)
+        return(_sym == iter._sym);
+    }
+
+    /// test if two iterators refer to the same Symbol
+    bool operator!= (const SymbolIterator& iter) const
+    {
+        return(!(*this == iter));
+    }
+
+    const SymbolIterator end () const {
+        return(SymbolIterator());
+    }
+
+private:
+    SymbolSet _syms;
+    Symbol _sym;
+};
+
+inline SymbolIterator SymbolSet::symbol_begin () const {
+    return(SymbolIterator(*this));
+}
+
+inline const SymbolIterator SymbolSet::symbol_end () const {
+    return(SymbolIterator());
+}
+
+/// @relates Symbol
+/// stream the string representation of a Symbol.
+static inline std::ostream& operator<< (std::ostream& out,
+                                        const Symbol& sym)
+{
+    out << sym.get_type_name()
+        << sym.get_addon_name()
+        << ":" << sym.get_data();
+    return(out);
+}
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/refcnt.c	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,48 @@
+/*------------------------------------------------------------------------
+ *  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
+ *------------------------------------------------------------------------*/
+
+#include "refcnt.h"
+
+#ifdef HAVE_LIBPTHREAD
+
+pthread_once_t initialized = PTHREAD_ONCE_INIT;
+pthread_mutex_t _zbar_reflock;
+
+static void initialize (void)
+{
+    pthread_mutex_init(&_zbar_reflock, NULL);
+}
+
+void _zbar_refcnt_init ()
+{
+    pthread_once(&initialized, initialize);
+}
+
+
+#else
+
+void _zbar_refcnt_init ()
+{
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/refcnt.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,84 @@
+/*------------------------------------------------------------------------
+ *  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 _REFCNT_H_
+#define _REFCNT_H_
+
+#include <config.h>
+#include <assert.h>
+
+#if defined(_WIN32)
+# include <windows.h>
+
+typedef volatile LONG refcnt_t;  /* FIXME where did volatile come from? */
+
+static inline int _zbar_refcnt (refcnt_t *cnt,
+                                int delta)
+{
+    int rc = -1;
+    if(delta > 0)
+        while(delta--)
+            rc = InterlockedIncrement(cnt);
+    else if(delta < 0)
+        while(delta++)
+            rc = InterlockedDecrement(cnt);
+    assert(rc >= 0);
+    return(rc);
+}
+
+
+#elif defined(HAVE_LIBPTHREAD)
+# include <pthread.h>
+
+typedef int refcnt_t;
+
+extern pthread_mutex_t _zbar_reflock;
+
+static inline int _zbar_refcnt (refcnt_t *cnt,
+                                int delta)
+{
+    pthread_mutex_lock(&_zbar_reflock);
+    int rc = (*cnt += delta);
+    pthread_mutex_unlock(&_zbar_reflock);
+    assert(rc >= 0);
+    return(rc);
+}
+
+
+#else
+
+typedef int refcnt_t;
+
+static inline int _zbar_refcnt (refcnt_t *cnt,
+                                int delta)
+{
+    int rc = (*cnt += delta);
+    assert(rc >= 0);
+    return(rc);
+}
+
+#endif
+
+
+void _zbar_refcnt_init(void);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scanner.c	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,311 @@
+/*------------------------------------------------------------------------
+ *  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
+ *------------------------------------------------------------------------*/
+
+#include <config.h>
+#include <stdlib.h>     /* malloc, free, abs */
+#include <string.h>     /* memset */
+
+#include <zbar.h>
+//#include "svg.h"
+
+#ifdef DEBUG_SCANNER
+# define DEBUG_LEVEL (DEBUG_SCANNER)
+#endif
+#include "debug.h"
+
+#ifndef ZBAR_FIXED
+# define ZBAR_FIXED 5
+#endif
+#define ROUND (1 << (ZBAR_FIXED - 1))
+
+/* FIXME add runtime config API for these */
+#ifndef ZBAR_SCANNER_THRESH_MIN
+# define ZBAR_SCANNER_THRESH_MIN  4
+#endif
+
+#ifndef ZBAR_SCANNER_THRESH_INIT_WEIGHT
+# define ZBAR_SCANNER_THRESH_INIT_WEIGHT .44
+#endif
+#define THRESH_INIT ((unsigned)((ZBAR_SCANNER_THRESH_INIT_WEIGHT       \
+                                 * (1 << (ZBAR_FIXED + 1)) + 1) / 2))
+
+#ifndef ZBAR_SCANNER_THRESH_FADE
+# define ZBAR_SCANNER_THRESH_FADE 8
+#endif
+
+#ifndef ZBAR_SCANNER_EWMA_WEIGHT
+# define ZBAR_SCANNER_EWMA_WEIGHT .78
+#endif
+#define EWMA_WEIGHT ((unsigned)((ZBAR_SCANNER_EWMA_WEIGHT              \
+                                 * (1 << (ZBAR_FIXED + 1)) + 1) / 2))
+
+/* scanner state */
+struct zbar_scanner_s {
+    zbar_decoder_t *decoder; /* associated bar width decoder */
+    unsigned y1_min_thresh; /* minimum threshold */
+
+    unsigned x;             /* relative scan position of next sample */
+    int y0[4];              /* short circular buffer of average intensities */
+
+    int y1_sign;            /* slope at last crossing */
+    unsigned y1_thresh;     /* current slope threshold */
+
+    unsigned cur_edge;      /* interpolated position of tracking edge */
+    unsigned last_edge;     /* interpolated position of last located edge */
+    unsigned width;         /* last element width */
+};
+
+zbar_scanner_t *zbar_scanner_create (zbar_decoder_t *dcode)
+{
+    zbar_scanner_t *scn = malloc(sizeof(zbar_scanner_t));
+    scn->decoder = dcode;
+    scn->y1_min_thresh = ZBAR_SCANNER_THRESH_MIN;
+    zbar_scanner_reset(scn);
+    return(scn);
+}
+
+void zbar_scanner_destroy (zbar_scanner_t *scn)
+{
+    free(scn);
+}
+
+zbar_symbol_type_t zbar_scanner_reset (zbar_scanner_t *scn)
+{
+    memset(&scn->x, 0, sizeof(zbar_scanner_t) + (void*)scn - (void*)&scn->x);
+    scn->y1_thresh = scn->y1_min_thresh;
+    if(scn->decoder)
+        zbar_decoder_reset(scn->decoder);
+    return(ZBAR_NONE);
+}
+
+unsigned zbar_scanner_get_width (const zbar_scanner_t *scn)
+{
+    return(scn->width);
+}
+
+unsigned zbar_scanner_get_edge (const zbar_scanner_t *scn,
+                                unsigned offset,
+                                int prec)
+{
+    unsigned edge = scn->last_edge - offset - (1 << ZBAR_FIXED) - ROUND;
+    prec = ZBAR_FIXED - prec;
+    if(prec > 0)
+        return(edge >> prec);
+    else if(!prec)
+        return(edge);
+    else
+        return(edge << -prec);
+}
+
+zbar_color_t zbar_scanner_get_color (const zbar_scanner_t *scn)
+{
+    return((scn->y1_sign <= 0) ? ZBAR_SPACE : ZBAR_BAR);
+}
+
+static inline unsigned calc_thresh (zbar_scanner_t *scn)
+{
+    /* threshold 1st to improve noise rejection */
+    unsigned thresh = scn->y1_thresh;
+    if((thresh <= scn->y1_min_thresh) || !scn->width) {
+        dprintf(1, " tmin=%d", scn->y1_min_thresh);
+        return(scn->y1_min_thresh);
+    }
+    /* slowly return threshold to min */
+    unsigned dx = (scn->x << ZBAR_FIXED) - scn->last_edge;
+    unsigned long t = thresh * dx;
+    t /= scn->width;
+    t /= ZBAR_SCANNER_THRESH_FADE;
+    dprintf(1, " thr=%d t=%ld x=%d last=%d.%d (%d)",
+            thresh, t, scn->x, scn->last_edge >> ZBAR_FIXED,
+            scn->last_edge & ((1 << ZBAR_FIXED) - 1), dx);
+    if(thresh > t) {
+        thresh -= t;
+        if(thresh > scn->y1_min_thresh)
+            return(thresh);
+    }
+    scn->y1_thresh = scn->y1_min_thresh;
+    return(scn->y1_min_thresh);
+}
+
+static inline zbar_symbol_type_t process_edge (zbar_scanner_t *scn,
+                                               int y1)
+{
+    if(!scn->y1_sign)
+        scn->last_edge = scn->cur_edge = (1 << ZBAR_FIXED) + ROUND;
+    else if(!scn->last_edge)
+        scn->last_edge = scn->cur_edge;
+
+    scn->width = scn->cur_edge - scn->last_edge;
+    dprintf(1, " sgn=%d cur=%d.%d w=%d (%s)\n",
+            scn->y1_sign, scn->cur_edge >> ZBAR_FIXED,
+            scn->cur_edge & ((1 << ZBAR_FIXED) - 1), scn->width,
+            ((y1 > 0) ? "SPACE" : "BAR"));
+    scn->last_edge = scn->cur_edge;
+
+#if DEBUG_SVG > 1
+    svg_path_moveto(SVG_ABS, scn->last_edge - (1 << ZBAR_FIXED) - ROUND, 0);
+#endif
+
+    /* pass to decoder */
+    if(scn->decoder)
+        return(zbar_decode_width(scn->decoder, scn->width));
+    return(ZBAR_PARTIAL);
+}
+
+inline zbar_symbol_type_t zbar_scanner_flush (zbar_scanner_t *scn)
+{
+    if(!scn->y1_sign)
+        return(ZBAR_NONE);
+
+    unsigned x = (scn->x << ZBAR_FIXED) + ROUND;
+
+    if(scn->cur_edge != x || scn->y1_sign > 0) {
+        dprintf(1, "flush0:");
+        zbar_symbol_type_t edge = process_edge(scn, -scn->y1_sign);
+        scn->cur_edge = x;
+        scn->y1_sign = -scn->y1_sign;
+        return(edge);
+    }
+
+    scn->y1_sign = scn->width = 0;
+    if(scn->decoder)
+        return(zbar_decode_width(scn->decoder, 0));
+    return(ZBAR_PARTIAL);
+}
+
+zbar_symbol_type_t zbar_scanner_new_scan (zbar_scanner_t *scn)
+{
+    zbar_symbol_type_t edge = ZBAR_NONE;
+    while(scn->y1_sign) {
+        zbar_symbol_type_t tmp = zbar_scanner_flush(scn);
+        if(tmp < 0 || tmp > edge)
+            edge = tmp;
+    }
+
+    /* reset scanner and associated decoder */
+    memset(&scn->x, 0, sizeof(zbar_scanner_t) + (void*)scn - (void*)&scn->x);
+    scn->y1_thresh = scn->y1_min_thresh;
+    if(scn->decoder)
+        zbar_decoder_new_scan(scn->decoder);
+    return(edge);
+}
+
+zbar_symbol_type_t zbar_scan_y (zbar_scanner_t *scn,
+                                int y)
+{
+    /* FIXME calc and clip to max y range... */
+    /* retrieve short value history */
+    register int x = scn->x;
+    register int y0_1 = scn->y0[(x - 1) & 3];
+    register int y0_0 = y0_1;
+    if(x) {
+        /* update weighted moving average */
+        y0_0 += ((int)((y - y0_1) * EWMA_WEIGHT)) >> ZBAR_FIXED;
+        scn->y0[x & 3] = y0_0;
+    }
+    else
+        y0_0 = y0_1 = scn->y0[0] = scn->y0[1] = scn->y0[2] = scn->y0[3] = y;
+    register int y0_2 = scn->y0[(x - 2) & 3];
+    register int y0_3 = scn->y0[(x - 3) & 3];
+    /* 1st differential @ x-1 */
+    register int y1_1 = y0_1 - y0_2;
+    {
+        register int y1_2 = y0_2 - y0_3;
+        if((abs(y1_1) < abs(y1_2)) &&
+           ((y1_1 >= 0) == (y1_2 >= 0)))
+            y1_1 = y1_2;
+    }
+
+    /* 2nd differentials @ x-1 & x-2 */
+    register int y2_1 = y0_0 - (y0_1 * 2) + y0_2;
+    register int y2_2 = y0_1 - (y0_2 * 2) + y0_3;
+
+    dprintf(1, "scan: x=%d y=%d y0=%d y1=%d y2=%d",
+            x, y, y0_1, y1_1, y2_1);
+
+    zbar_symbol_type_t edge = ZBAR_NONE;
+    /* 2nd zero-crossing is 1st local min/max - could be edge */
+    if((!y2_1 ||
+        ((y2_1 > 0) ? y2_2 < 0 : y2_2 > 0)) &&
+       (calc_thresh(scn) <= abs(y1_1)))
+    {
+        /* check for 1st sign change */
+        char y1_rev = (scn->y1_sign > 0) ? y1_1 < 0 : y1_1 > 0;
+        if(y1_rev)
+            /* intensity change reversal - finalize previous edge */
+            edge = process_edge(scn, y1_1);
+
+        if(y1_rev || (abs(scn->y1_sign) < abs(y1_1))) {
+            scn->y1_sign = y1_1;
+
+            /* adaptive thresholding */
+            /* start at multiple of new min/max */
+            scn->y1_thresh = (abs(y1_1) * THRESH_INIT + ROUND) >> ZBAR_FIXED;
+            dprintf(1, "\tthr=%d", scn->y1_thresh);
+            if(scn->y1_thresh < scn->y1_min_thresh)
+                scn->y1_thresh = scn->y1_min_thresh;
+
+            /* update current edge */
+            int d = y2_1 - y2_2;
+            scn->cur_edge = 1 << ZBAR_FIXED;
+            if(!d)
+                scn->cur_edge >>= 1;
+            else if(y2_1)
+                /* interpolate zero crossing */
+                scn->cur_edge -= ((y2_1 << ZBAR_FIXED) + 1) / d;
+            scn->cur_edge += x << ZBAR_FIXED;
+            dprintf(1, "\n");
+        }
+    }
+    else
+        dprintf(1, "\n");
+    /* FIXME add fall-thru pass to decoder after heuristic "idle" period
+       (eg, 6-8 * last width) */
+    scn->x = x + 1;
+    return(edge);
+}
+
+/* undocumented API for drawing cutesy debug graphics */
+void zbar_scanner_get_state (const zbar_scanner_t *scn,
+                             unsigned *x,
+                             unsigned *cur_edge,
+                             unsigned *last_edge,
+                             int *y0,
+                             int *y1,
+                             int *y2,
+                             int *y1_thresh)
+{
+    register int y0_0 = scn->y0[(scn->x - 1) & 3];
+    register int y0_1 = scn->y0[(scn->x - 2) & 3];
+    register int y0_2 = scn->y0[(scn->x - 3) & 3];
+    if(x) *x = scn->x - 1;
+    if(cur_edge) *cur_edge = scn->cur_edge;
+    if(last_edge) *last_edge = scn->last_edge;
+    if(y0) *y0 = y0_1;
+    if(y1) *y1 = y0_1 - y0_2;
+    if(y2) *y2 = y0_0 - (y0_1 * 2) + y0_2;
+    /* NB not quite accurate (uses updated x) */
+    zbar_scanner_t *mut_scn = (zbar_scanner_t*)scn;
+    if(y1_thresh) *y1_thresh = calc_thresh(mut_scn);
+    dprintf(1, "\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbol.c	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,244 @@
+/*------------------------------------------------------------------------
+ *  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
+ *------------------------------------------------------------------------*/
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <zbar.h>
+#include "symbol.h"
+
+const char *zbar_get_symbol_name (zbar_symbol_type_t sym)
+{
+    switch(sym & ZBAR_SYMBOL) {
+    case ZBAR_EAN8: return("EAN-8");
+    case ZBAR_UPCE: return("UPC-E");
+    case ZBAR_ISBN10: return("ISBN-10");
+    case ZBAR_UPCA: return("UPC-A");
+    case ZBAR_EAN13: return("EAN-13");
+    case ZBAR_ISBN13: return("ISBN-13");
+    case ZBAR_I25: return("I2/5");
+    case ZBAR_CODE39: return("CODE-39");
+    case ZBAR_CODE128: return("CODE-128");
+    case ZBAR_PDF417: return("PDF417");
+    case ZBAR_QRCODE: return("QR-Code");
+    default: return("UNKNOWN");
+    }
+}
+
+const char *zbar_get_addon_name (zbar_symbol_type_t sym)
+{
+    switch(sym & ZBAR_ADDON) {
+    case ZBAR_ADDON2: return("+2");
+    case ZBAR_ADDON5: return("+5");
+    default: return("");
+    }
+}
+
+
+void _zbar_symbol_free (zbar_symbol_t *sym)
+{
+    if(sym->syms) {
+        zbar_symbol_set_ref(sym->syms, -1);
+        sym->syms = NULL;
+    }
+    if(sym->pts)
+        free(sym->pts);
+    if(sym->data_alloc && sym->data)
+        free(sym->data);
+    free(sym);
+}
+
+void zbar_symbol_ref (const zbar_symbol_t *sym,
+                      int refs)
+{
+    zbar_symbol_t *ncsym = (zbar_symbol_t*)sym;
+    _zbar_symbol_refcnt(ncsym, refs);
+}
+
+zbar_symbol_type_t zbar_symbol_get_type (const zbar_symbol_t *sym)
+{
+    return(sym->type);
+}
+
+const char *zbar_symbol_get_data (const zbar_symbol_t *sym)
+{
+    return(sym->data);
+}
+
+unsigned int zbar_symbol_get_data_length (const zbar_symbol_t *sym)
+{
+    return(sym->datalen);
+}
+
+int zbar_symbol_get_count (const zbar_symbol_t *sym)
+{
+    return(sym->cache_count);
+}
+
+int zbar_symbol_get_quality (const zbar_symbol_t *sym)
+{
+    return(sym->quality);
+}
+
+unsigned zbar_symbol_get_loc_size (const zbar_symbol_t *sym)
+{
+    return(sym->npts);
+}
+
+int zbar_symbol_get_loc_x (const zbar_symbol_t *sym,
+                           unsigned idx)
+{
+    if(idx < sym->npts)
+        return(sym->pts[idx].x);
+    else
+        return(-1);
+}
+
+int zbar_symbol_get_loc_y (const zbar_symbol_t *sym,
+                           unsigned idx)
+{
+    if(idx < sym->npts)
+        return(sym->pts[idx].y);
+    else
+        return(-1);
+}
+
+const zbar_symbol_t *zbar_symbol_next (const zbar_symbol_t *sym)
+{
+    return((sym) ? sym->next : NULL);
+}
+
+const zbar_symbol_set_t*
+zbar_symbol_get_components (const zbar_symbol_t *sym)
+{
+    return(sym->syms);
+}
+
+const zbar_symbol_t *zbar_symbol_first_component (const zbar_symbol_t *sym)
+{
+    return((sym && sym->syms) ? sym->syms->head : NULL);
+}
+
+
+static const char *xmlfmt[] = {
+    "<symbol type='%s' quality='%d'",
+    " count='%d'",
+    "><data><![CDATA[",
+    "]]></data></symbol>",
+};
+
+/* FIXME suspect... */
+#define MAX_INT_DIGITS 10
+
+char *zbar_symbol_xml (const zbar_symbol_t *sym,
+                       char **buf,
+                       unsigned *len)
+{
+    const char *type = zbar_get_symbol_name(sym->type);
+    /* FIXME binary data */
+    unsigned datalen = strlen(sym->data);
+    unsigned maxlen = (strlen(xmlfmt[0]) + strlen(xmlfmt[1]) +
+                       strlen(xmlfmt[2]) + strlen(xmlfmt[3]) +
+                       strlen(type) + datalen + MAX_INT_DIGITS + 1);
+    if(!*buf || (*len < maxlen)) {
+        if(*buf)
+            free(*buf);
+        *buf = malloc(maxlen);
+        /* FIXME check OOM */
+        *len = maxlen;
+    }
+
+    int n = snprintf(*buf, maxlen, xmlfmt[0], type, sym->quality);
+    assert(n > 0);
+    assert(n <= maxlen);
+
+    if(sym->cache_count) {
+        int i = snprintf(*buf + n, maxlen - n, xmlfmt[1], sym->cache_count);
+        assert(i > 0);
+        n += i;
+        assert(n <= maxlen);
+    }
+
+    int i = strlen(xmlfmt[2]);
+    memcpy(*buf + n, xmlfmt[2], i + 1);
+    n += i;
+    assert(n <= maxlen);
+
+    /* FIXME binary data */
+    /* FIXME handle "]]>" */
+    strncpy(*buf + n, sym->data, datalen + 1);
+    n += datalen;
+    assert(n <= maxlen);
+
+    i = strlen(xmlfmt[3]);
+    memcpy(*buf + n, xmlfmt[3], i + 1);
+    n += i;
+    assert(n <= maxlen);
+
+    *len = n;
+    return(*buf);
+}
+
+
+zbar_symbol_set_t *_zbar_symbol_set_create ()
+{
+    zbar_symbol_set_t *syms = calloc(1, sizeof(*syms));
+    _zbar_refcnt(&syms->refcnt, 1);
+    return(syms);
+}
+
+inline void _zbar_symbol_set_free (zbar_symbol_set_t *syms)
+{
+    zbar_symbol_t *sym, *next;
+    for(sym = syms->head; sym; sym = next) {
+        next = sym->next;
+        sym->next = NULL;
+        _zbar_symbol_refcnt(sym, -1);
+    }
+    syms->head = NULL;
+    free(syms);
+}
+
+void zbar_symbol_set_ref (const zbar_symbol_set_t *syms,
+                          int delta)
+{
+    zbar_symbol_set_t *ncsyms = (zbar_symbol_set_t*)syms;
+    if(!_zbar_refcnt(&ncsyms->refcnt, delta) && delta <= 0)
+        _zbar_symbol_set_free(ncsyms);
+}
+
+int zbar_symbol_set_get_size (const zbar_symbol_set_t *syms)
+{
+    return(syms->nsyms);
+}
+
+const zbar_symbol_t*
+zbar_symbol_set_first_symbol (const zbar_symbol_set_t *syms)
+{
+    zbar_symbol_t *sym = syms->tail;
+    if(sym)
+        return(sym->next);
+    return(syms->head);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbol.h	Fri Jan 10 20:29:52 2020 +0000
@@ -0,0 +1,92 @@
+/*------------------------------------------------------------------------
+ *  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 _SYMBOL_H_
+#define _SYMBOL_H_
+
+#include <stdlib.h>
+#include <zbar.h>
+#include "refcnt.h"
+
+typedef struct point_s {
+    int x, y;
+} point_t;
+
+struct zbar_symbol_set_s {
+    refcnt_t refcnt;
+    int nsyms;                  /* number of filtered symbols */
+    zbar_symbol_t *head;        /* first of decoded symbol results */
+    zbar_symbol_t *tail;        /* last of unfiltered symbol results */
+};
+
+struct zbar_symbol_s {
+    zbar_symbol_type_t type;    /* symbol type */
+    unsigned int data_alloc;    /* allocation size of data */
+    unsigned int datalen;       /* length of binary symbol data */
+    char *data;                 /* symbol data */
+
+    unsigned pts_alloc;         /* allocation size of pts */
+    unsigned npts;              /* number of points in location polygon */
+    point_t *pts;               /* list of points in location polygon */
+
+    refcnt_t refcnt;            /* reference count */
+    zbar_symbol_t *next;        /* linked list of results (or siblings) */
+    zbar_symbol_set_t *syms;    /* components of composite result */
+    unsigned long time;         /* relative symbol capture time */
+    int cache_count;            /* cache state */
+    int quality;                /* relative symbol reliability metric */
+};
+
+extern void _zbar_symbol_free(zbar_symbol_t*);
+
+extern zbar_symbol_set_t *_zbar_symbol_set_create(void);
+extern void _zbar_symbol_set_free(zbar_symbol_set_t*);
+
+static inline void sym_add_point (zbar_symbol_t *sym,
+                                  int x,
+                                  int y)
+{
+    int i = sym->npts;
+    if(++sym->npts >= sym->pts_alloc)
+        sym->pts = realloc(sym->pts, ++sym->pts_alloc * sizeof(point_t));
+    sym->pts[i].x = x;
+    sym->pts[i].y = y;
+}
+
+static inline void _zbar_symbol_refcnt (zbar_symbol_t *sym,
+                                        int delta)
+{
+    if(!_zbar_refcnt(&sym->refcnt, delta) && delta <= 0)
+        _zbar_symbol_free(sym);
+}
+
+static inline void _zbar_symbol_set_add (zbar_symbol_set_t *syms,
+                                         zbar_symbol_t *sym)
+{
+    sym->next = syms->head;
+    syms->head = sym;
+    syms->nsyms++;
+
+    _zbar_symbol_refcnt(sym, 1);
+}
+
+#endif