/*------------------------------------------------------------------------ * Copyright 2009-2010 (c) Jeff Brown * * 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 "zbarmodule.h" static char enumitem_doc[] = PyDoc_STR("simple enumeration item.\n" "\n" "associates an int value with a name for printing."); static zbarEnumItem *enumitem_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { int val = 0; PyObject *name = NULL; static char *kwlist[] = { "value", "name", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, "iS", kwlist, &val, &name)) return (NULL); zbarEnumItem *self = (zbarEnumItem *)type->tp_alloc(type, 0); if (!self) return (NULL); #if PY_MAJOR_VERSION >= 3 PyLongObject *longval = (PyLongObject *)PyLong_FromLong(val); if (!longval) { Py_DECREF(self); return (NULL); } /* we assume the "fast path" for a single-digit ints (see longobject.c) */ /* this also holds if we get a small_int preallocated long */ #if PY_VERSION_HEX >= 0x030900A4 Py_SET_SIZE(&self->val, Py_SIZE(longval)); #else Py_SIZE(&self->val) = Py_SIZE(longval); #endif #if PY_VERSION_HEX >= 0x030c0000 self->val.long_value.ob_digit[0] = longval->long_value.ob_digit[0]; #else self->val.ob_digit[0] = longval->ob_digit[0]; #endif Py_DECREF(longval); #else self->val.ob_ival = val; #endif self->name = name; return (self); } static void enumitem_dealloc(zbarEnumItem *self) { Py_CLEAR(self->name); ((PyObject *)self)->ob_type->tp_free((PyObject *)self); } static PyObject *enumitem_str(zbarEnumItem *self) { Py_INCREF(self->name); return (self->name); } #if PY_MAJOR_VERSION < 3 /* tp_print was dropped on Python 3.9 */ static int enumitem_print(zbarEnumItem *self, FILE *fp, int flags) { return (self->name->ob_type->tp_print(self->name, fp, flags)); } #endif static PyObject *enumitem_repr(zbarEnumItem *self) { PyObject *name = PyObject_Repr(self->name); if (!name) return (NULL); #if PY_MAJOR_VERSION >= 3 PyObject *repr = PyUnicode_FromFormat("%s(%ld, %U)", ((PyObject *)self)->ob_type->tp_name, PyLong_AsLong((PyObject *)self), name); #else char *namestr = PyString_AsString(name); PyObject *repr = PyString_FromFormat("%s(%ld, %s)", ((PyObject *)self)->ob_type->tp_name, self->val.ob_ival, namestr); #endif Py_DECREF(name); return ((PyObject *)repr); } PyTypeObject zbarEnumItem_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.EnumItem", .tp_doc = enumitem_doc, .tp_basicsize = sizeof(zbarEnumItem), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_new = (newfunc)enumitem_new, .tp_dealloc = (destructor)enumitem_dealloc, .tp_str = (reprfunc)enumitem_str, #if PY_MAJOR_VERSION < 3 .tp_print = (printfunc)enumitem_print, #endif .tp_repr = (reprfunc)enumitem_repr, }; zbarEnumItem *zbarEnumItem_New(PyObject *byname, PyObject *byvalue, int val, const char *name) { zbarEnumItem *self = PyObject_New(zbarEnumItem, &zbarEnumItem_Type); if (!self) return (NULL); #if PY_MAJOR_VERSION >= 3 PyLongObject *longval = (PyLongObject *)PyLong_FromLong(val); if (!longval) { Py_DECREF(self); return (NULL); } /* we assume the "fast path" for a single-digit ints (see longobject.c) */ /* this also holds if we get a small_int preallocated long */ #if PY_VERSION_HEX >= 0x030900A4 Py_SET_SIZE(&self->val, Py_SIZE(longval)); #else Py_SIZE(&self->val) = Py_SIZE(longval); #endif #if PY_VERSION_HEX >= 0x030c0000 self->val.long_value.ob_digit[0] = longval->long_value.ob_digit[0]; #else self->val.ob_digit[0] = longval->ob_digit[0]; #endif Py_DECREF(longval); self->name = PyUnicode_FromString(name); #else self->val.ob_ival = val; self->name = PyString_FromString(name); #endif if (!self->name || (byname && PyDict_SetItem(byname, self->name, (PyObject *)self)) || (byvalue && PyDict_SetItem(byvalue, (PyObject *)self, (PyObject *)self))) { Py_DECREF((PyObject *)self); return (NULL); } return (self); } static char enum_doc[] = PyDoc_STR("enumeration container for EnumItems.\n" "\n" "exposes items as read-only attributes"); /* FIXME add iteration */ static int enum_traverse(zbarEnum *self, visitproc visit, void *arg) { Py_VISIT(self->byname); Py_VISIT(self->byvalue); return (0); } static int enum_clear(zbarEnum *self) { Py_CLEAR(self->byname); Py_CLEAR(self->byvalue); return (0); } static void enum_dealloc(zbarEnum *self) { enum_clear(self); ((PyObject *)self)->ob_type->tp_free((PyObject *)self); } PyTypeObject zbarEnum_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.Enum", .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, .tp_doc = enum_doc, .tp_basicsize = sizeof(zbarEnum), .tp_dictoffset = offsetof(zbarEnum, byname), .tp_traverse = (traverseproc)enum_traverse, .tp_clear = (inquiry)enum_clear, .tp_dealloc = (destructor)enum_dealloc, }; zbarEnum *zbarEnum_New() { zbarEnum *self = PyObject_GC_New(zbarEnum, &zbarEnum_Type); if (!self) return (NULL); self->byname = PyDict_New(); self->byvalue = PyDict_New(); if (!self->byname || !self->byvalue) { Py_DECREF(self); return (NULL); } return (self); } int zbarEnum_Add(zbarEnum *self, int val, const char *name) { zbarEnumItem *item; item = zbarEnumItem_New(self->byname, self->byvalue, val, name); if (!item) return (-1); return (0); } zbarEnumItem *zbarEnum_LookupValue(zbarEnum *self, int val) { #if PY_MAJOR_VERSION >= 3 PyObject *key = PyLong_FromLong(val); #else PyObject *key = PyInt_FromLong(val); #endif zbarEnumItem *e = (zbarEnumItem *)PyDict_GetItem(self->byvalue, key); if (!e) return ((zbarEnumItem *)key); Py_INCREF((PyObject *)e); Py_DECREF(key); return (e); } PyObject *zbarEnum_SetFromMask(zbarEnum *self, unsigned int mask) { PyObject *result = PySet_New(NULL); PyObject *key, *item; Py_ssize_t i = 0; while (PyDict_Next(self->byvalue, &i, &key, &item)) { #if PY_MAJOR_VERSION >= 3 unsigned long val = (unsigned long)PyLong_AsLong(item); #else int val = PyInt_AsLong(item); #endif if (val < sizeof(mask) * 8 && ((mask >> val) & 1)) PySet_Add(result, item); } return (result); }