Beispiel #1
0
/* use for both array and group */
static Py_hash_t BPy_IDGroup_hash(BPy_IDProperty *self)
{
    return _Py_HashPointer(self->prop);
}

static PyObject *BPy_IDGroup_repr(BPy_IDProperty *self)
{
    return PyUnicode_FromFormat("<bpy id prop: owner=\"%s\", name=\"%s\", address=%p>",
                                self->id ? self->id->name : "<NONE>", self->prop->name, self->prop);
}

PyObject *BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent)
{
    switch (prop->type) {
    case IDP_STRING:
        return idprop_py_from_idp_string(prop);
    case IDP_INT:
        return idprop_py_from_idp_int(prop);
    case IDP_FLOAT:
        return idprop_py_from_idp_float(prop);
    case IDP_DOUBLE:
        return idprop_py_from_idp_double(prop);
    case IDP_GROUP:
        return idprop_py_from_idp_group(id, prop, parent);
    case IDP_ARRAY:
        return idprop_py_from_idp_array(id, prop);
    case IDP_IDPARRAY:
        return idprop_py_from_idp_idparray(id, prop); /* this could be better a internal type */
    default:
        Py_RETURN_NONE;
    }
}

#if 0 /* UNUSED, currently assignment overwrites into new properties, rather than setting in-place */
static int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
{
    switch (prop->type) {
    case IDP_STRING:
    {
        char *st;
        if (!PyUnicode_Check(value)) {
            PyErr_SetString(PyExc_TypeError, "expected a string!");
            return -1;
        }
        /* NOTE: if this code is enabled, bytes support needs to be added */
#ifdef USE_STRING_COERCE
        {
            int alloc_len;
            PyObject *value_coerce = NULL;

            st = (char *)PyC_UnicodeAsByte(value, &value_coerce);
            alloc_len = strlen(st) + 1;

            st = _PyUnicode_AsString(value);
            IDP_ResizeArray(prop, alloc_len);
            memcpy(IDP_Array(prop), st, alloc_len);
            Py_XDECREF(value_coerce);
        }
#else
        st = _PyUnicode_AsString(value);
        IDP_ResizeArray(prop, strlen(st) + 1);
        strcpy(IDP_Array(prop), st);
#endif

        return 0;
    }

    case IDP_INT:
    {
        int ivalue = PyLong_AsSsize_t(value);
        if (ivalue == -1 && PyErr_Occurred()) {
            PyErr_SetString(PyExc_TypeError, "expected an int type");
            return -1;
        }
        IDP_Int(prop) = ivalue;
        break;
    }
    case IDP_FLOAT:
    {
        float fvalue = (float)PyFloat_AsDouble(value);
        if (fvalue == -1 && PyErr_Occurred()) {
            PyErr_SetString(PyExc_TypeError, "expected a float");
            return -1;
        }
        IDP_Float(self->prop) = fvalue;
        break;
    }
    case IDP_DOUBLE:
    {
        double dvalue = PyFloat_AsDouble(value);
        if (dvalue == -1 && PyErr_Occurred()) {
            PyErr_SetString(PyExc_TypeError, "expected a float");
            return -1;
        }
        IDP_Double(self->prop) = dvalue;
        break;
    }
    default:
        PyErr_SetString(PyExc_AttributeError, "attempt to set read-only attribute!");
        return -1;
    }
    return 0;
}
Beispiel #2
0
/**
 * \note group can be a pointer array or a group.
 * assume we already checked key is a string.
 *
 * \return success.
 */
bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group, PyObject *ob)
{
    IDProperty *prop = NULL;
    IDPropertyTemplate val = {0};

    const char *name;

    if (name_obj) {
        Py_ssize_t name_size;
        name = _PyUnicode_AsStringAndSize(name_obj, &name_size);

        if (name == NULL) {
            PyErr_Format(PyExc_KeyError,
                         "invalid id-property key, expected a string, not a %.200s",
                         Py_TYPE(name_obj)->tp_name);
            return false;
        }

        if (name_size > MAX_IDPROP_NAME) {
            PyErr_SetString(PyExc_KeyError, "the length of IDProperty names is limited to 63 characters");
            return false;
        }
    }
    else {
        name = "";
    }

    if (PyFloat_Check(ob)) {
        val.d = PyFloat_AsDouble(ob);
        prop = IDP_New(IDP_DOUBLE, &val, name);
    }
    else if (PyLong_Check(ob)) {
        val.i = _PyLong_AsInt(ob);
        if (val.i == -1 && PyErr_Occurred()) {
            return false;
        }
        prop = IDP_New(IDP_INT, &val, name);
    }
    else if (PyUnicode_Check(ob)) {
#ifdef USE_STRING_COERCE
        PyObject *value_coerce = NULL;
        val.string.str = (char *)PyC_UnicodeAsByte(ob, &value_coerce);
        val.string.subtype = IDP_STRING_SUB_UTF8;
        prop = IDP_New(IDP_STRING, &val, name);
        Py_XDECREF(value_coerce);
#else
        val.str = _PyUnicode_AsString(ob);
        prop = IDP_New(IDP_STRING, val, name);
#endif
    }
    else if (PyBytes_Check(ob)) {
        val.string.str = PyBytes_AS_STRING(ob);
        val.string.len = PyBytes_GET_SIZE(ob);
        val.string.subtype = IDP_STRING_SUB_BYTE;

        prop = IDP_New(IDP_STRING, &val, name);
        //prop = IDP_NewString(PyBytes_AS_STRING(ob), name, PyBytes_GET_SIZE(ob));
        //prop->subtype = IDP_STRING_SUB_BYTE;
    }
    else if (PySequence_Check(ob)) {
        PyObject *ob_seq_fast = PySequence_Fast(ob, "py -> idprop");
        PyObject *item;
        int i;

        if (ob_seq_fast == NULL) {
            return false;
        }

        if ((val.array.type = idp_sequence_type(ob_seq_fast)) == -1) {
            Py_DECREF(ob_seq_fast);
            PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays");
            return false;
        }

        /* validate sequence and derive type.
         * we assume IDP_INT unless we hit a float
         * number; then we assume it's */

        val.array.len = PySequence_Fast_GET_SIZE(ob_seq_fast);

        switch (val.array.type) {
        case IDP_DOUBLE:
        {
            double *prop_data;

            prop = IDP_New(IDP_ARRAY, &val, name);
            prop_data = IDP_Array(prop);
            for (i = 0; i < val.array.len; i++) {
                item = PySequence_Fast_GET_ITEM(ob_seq_fast, i);
                if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
                    Py_DECREF(ob_seq_fast);
                    return false;
                }
            }
            break;
        }
        case IDP_INT:
        {
            int *prop_data;
            prop = IDP_New(IDP_ARRAY, &val, name);
            prop_data = IDP_Array(prop);
            for (i = 0; i < val.array.len; i++) {
                item = PySequence_Fast_GET_ITEM(ob_seq_fast, i);
                if (((prop_data[i] = _PyLong_AsInt(item)) == -1) && PyErr_Occurred()) {
                    Py_DECREF(ob_seq_fast);
                    return false;
                }
            }
            break;
        }
        case IDP_IDPARRAY:
        {
            prop = IDP_NewIDPArray(name);
            for (i = 0; i < val.array.len; i++) {
                item = PySequence_Fast_GET_ITEM(ob_seq_fast, i);

                if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
                    Py_DECREF(ob_seq_fast);
                    return false;
                }
            }
            break;
        }
        default:
            /* should never happen */
            Py_DECREF(ob_seq_fast);
            PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type");
            return false;
        }

        Py_DECREF(ob_seq_fast);
    }
    else if (PyMapping_Check(ob)) {
        PyObject *keys, *vals, *key, *pval;
        int i, len;
        /*yay! we get into recursive stuff now!*/
        keys = PyMapping_Keys(ob);
        vals = PyMapping_Values(ob);

        /* we allocate the group first; if we hit any invalid data,
         * we can delete it easily enough.*/
        prop = IDP_New(IDP_GROUP, &val, name);
        len = PyMapping_Length(ob);
        for (i = 0; i < len; i++) {
            key = PySequence_GetItem(keys, i);
            pval = PySequence_GetItem(vals, i);
            if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
                IDP_FreeProperty(prop);
                MEM_freeN(prop);
                Py_XDECREF(keys);
                Py_XDECREF(vals);
                Py_XDECREF(key);
                Py_XDECREF(pval);
                /* error is already set */
                return false;
            }
            Py_XDECREF(key);
            Py_XDECREF(pval);
        }
        Py_XDECREF(keys);
        Py_XDECREF(vals);
    }
    else {
        PyErr_Format(PyExc_TypeError,
                     "invalid id-property type %.200s not supported",
                     Py_TYPE(ob)->tp_name);
        return false;
    }

    if (group->type == IDP_IDPARRAY) {
        IDP_AppendArray(group, prop);
        // IDP_FreeProperty(item);  /* IDP_AppendArray does a shallow copy (memcpy), only free memory */
        MEM_freeN(prop);
    }
    else {
        IDP_ReplaceInGroup(group, prop);
    }

    return true;
}
Beispiel #3
0
/* note: group can be a pointer array or a group */
const char *BPy_IDProperty_Map_ValidateAndCreate(const char *name, IDProperty *group, PyObject *ob)
{
    IDProperty *prop = NULL;
    IDPropertyTemplate val = {0};

    if(strlen(name) >= sizeof(group->name))
        return "the length of IDProperty names is limited to 31 characters";

    if (PyFloat_Check(ob)) {
        val.d = PyFloat_AsDouble(ob);
        prop = IDP_New(IDP_DOUBLE, val, name);
    } else if (PyLong_Check(ob)) {
        val.i = (int) PyLong_AsSsize_t(ob);
        prop = IDP_New(IDP_INT, val, name);
    } else if (PyUnicode_Check(ob)) {
#ifdef USE_STRING_COERCE
        PyObject *value_coerce= NULL;
        val.str = (char *)PyC_UnicodeAsByte(ob, &value_coerce);
        prop = IDP_New(IDP_STRING, val, name);
        Py_XDECREF(value_coerce);
#else
        val.str = _PyUnicode_AsString(ob);
        prop = IDP_New(IDP_STRING, val, name);
#endif
    } else if (PySequence_Check(ob)) {
        PyObject *item;
        int i;

        if((val.array.type= idp_sequence_type(ob)) == -1)
            return "only floats, ints and dicts are allowed in ID property arrays";

        /*validate sequence and derive type.
        we assume IDP_INT unless we hit a float
        number; then we assume it's */

        val.array.len = PySequence_Size(ob);

        switch(val.array.type) {
        case IDP_DOUBLE:
            prop = IDP_New(IDP_ARRAY, val, name);
            for (i=0; i<val.array.len; i++) {
                item = PySequence_GetItem(ob, i);
                ((double*)prop->data.pointer)[i] = (float)PyFloat_AsDouble(item);
                Py_DECREF(item);
            }
            break;
        case IDP_INT:
            prop = IDP_New(IDP_ARRAY, val, name);
            for (i=0; i<val.array.len; i++) {
                item = PySequence_GetItem(ob, i);
                ((int*)prop->data.pointer)[i] = (int)PyLong_AsSsize_t(item);
                Py_DECREF(item);
            }
            break;
        case IDP_IDPARRAY:
            prop= IDP_NewIDPArray(name);
            for (i=0; i<val.array.len; i++) {
                const char *error;
                item = PySequence_GetItem(ob, i);
                error= BPy_IDProperty_Map_ValidateAndCreate("", prop, item);
                Py_DECREF(item);

                if(error)
                    return error;
            }
            break;
        }
    } else if (PyMapping_Check(ob)) {
        PyObject *keys, *vals, *key, *pval;
        int i, len;
        /*yay! we get into recursive stuff now!*/
        keys = PyMapping_Keys(ob);
        vals = PyMapping_Values(ob);

        /*we allocate the group first; if we hit any invalid data,
          we can delete it easily enough.*/
        prop = IDP_New(IDP_GROUP, val, name);
        len = PyMapping_Length(ob);
        for (i=0; i<len; i++) {
            key = PySequence_GetItem(keys, i);
            pval = PySequence_GetItem(vals, i);
            if (!PyUnicode_Check(key)) {
                IDP_FreeProperty(prop);
                MEM_freeN(prop);
                Py_XDECREF(keys);
                Py_XDECREF(vals);
                Py_XDECREF(key);
                Py_XDECREF(pval);
                return "invalid element in subgroup dict template!";
            }
            if (BPy_IDProperty_Map_ValidateAndCreate(_PyUnicode_AsString(key), prop, pval)) {
                IDP_FreeProperty(prop);
                MEM_freeN(prop);
                Py_XDECREF(keys);
                Py_XDECREF(vals);
                Py_XDECREF(key);
                Py_XDECREF(pval);
                return "invalid element in subgroup dict template!";
            }
            Py_XDECREF(key);
            Py_XDECREF(pval);
        }
        Py_XDECREF(keys);
        Py_XDECREF(vals);
    } else return "invalid property value";

    if(group->type==IDP_IDPARRAY) {
        IDP_AppendArray(group, prop);
        // IDP_FreeProperty(item); // IDP_AppendArray does a shallow copy (memcpy), only free memory
        MEM_freeN(prop);
    } else {
        IDP_ReplaceInGroup(group, prop);
    }

    return NULL;
}