コード例 #1
0
/* sequence slice (set): idparr[a:b] = value */
static int BPy_IDArray_ass_slice(BPy_IDArray *self, int begin, int end, PyObject *seq)
{
    IDProperty *prop = self->prop;
    short is_double = 0;
    const PyTypeObject *py_type = idp_array_py_type(self, &is_double);
    const size_t elem_size = is_double ? sizeof(double) : sizeof(float);
    size_t alloc_len;
    size_t size;
    void *vec;

    CLAMP(begin, 0, prop->len);
    CLAMP(end, 0, prop->len);
    begin = MIN2(begin, end);

    size = (end - begin);
    alloc_len = size * elem_size;

    vec = MEM_mallocN(alloc_len, "array assignment"); /* NOTE: we count on int/float being the same size here */
    if (PyC_AsArray(vec, seq, size, py_type, is_double, "slice assignment: ") == -1) {
        MEM_freeN(vec);
        return -1;
    }

    memcpy((void *)(((char *)IDP_Array(prop)) + (begin * elem_size)), vec, alloc_len);

    MEM_freeN(vec);
    return 0;
}
コード例 #2
0
/* sequence slice (get): idparr[a:b] */
static PyObject *BPy_IDArray_slice(BPy_IDArray *self, int begin, int end)
{
    IDProperty *prop = self->prop;
    PyObject *tuple;
    int count;

    CLAMP(begin, 0, prop->len);
    if (end < 0) end = prop->len + end + 1;
    CLAMP(end, 0, prop->len);
    begin = MIN2(begin, end);

    tuple = PyTuple_New(end - begin);

    switch (prop->subtype) {
    case IDP_FLOAT:
    {
        float *array = (float *)IDP_Array(prop);
        for (count = begin; count < end; count++) {
            PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
        }
        break;
    }
    case IDP_DOUBLE:
    {
        double *array = (double *)IDP_Array(prop);
        for (count = begin; count < end; count++) {
            PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
        }
        break;
    }
    case IDP_INT:
    {
        int *array = (int *)IDP_Array(prop);
        for (count = begin; count < end; count++) {
            PyTuple_SET_ITEM(tuple, count - begin, PyLong_FromLong(array[count]));
        }
        break;
    }
    }

    return tuple;
}
コード例 #3
0
static PyObject *idprop_py_from_idp_string(const IDProperty *prop)
{
    if (prop->subtype == IDP_STRING_SUB_BYTE) {
        return PyBytes_FromStringAndSize(IDP_String(prop), prop->len);
    }
    else {
#ifdef USE_STRING_COERCE
        return PyC_UnicodeFromByteAndSize(IDP_Array(prop), prop->len - 1);
#else
        return PyUnicode_FromStringAndSize(IDP_String(prop), prop->len - 1);
#endif
    }
}
コード例 #4
0
static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
{
    if (index < 0 || index >= self->prop->len) {
        PyErr_SetString(PyExc_RuntimeError, "index out of range!");
        return -1;
    }

    switch (self->prop->subtype) {
    case IDP_FLOAT:
    {
        const float f = (float)PyFloat_AsDouble(value);
        if (f == -1 && PyErr_Occurred()) {
            return -1;
        }
        ((float *)IDP_Array(self->prop))[index] = f;
        break;
    }
    case IDP_DOUBLE:
    {
        const double d = PyFloat_AsDouble(value);
        if (d == -1 && PyErr_Occurred()) {
            return -1;
        }
        ((double *)IDP_Array(self->prop))[index] = d;
        break;
    }
    case IDP_INT:
    {
        const int i = _PyLong_AsInt(value);
        if (i == -1 && PyErr_Occurred()) {
            return -1;
        }

        ((int *)IDP_Array(self->prop))[index] = i;
        break;
    }
    }
    return 0;
}
コード例 #5
0
static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
{
    if (index < 0 || index >= self->prop->len) {
        PyErr_SetString(PyExc_IndexError, "index out of range!");
        return NULL;
    }

    switch (self->prop->subtype) {
    case IDP_FLOAT:
        return PyFloat_FromDouble(((float *)IDP_Array(self->prop))[index]);
    case IDP_DOUBLE:
        return PyFloat_FromDouble(((double *)IDP_Array(self->prop))[index]);
    case IDP_INT:
        return PyLong_FromLong((long)((int *)IDP_Array(self->prop))[index]);
    }

    PyErr_Format(PyExc_RuntimeError,
                 "%s: invalid/corrupt array type '%d'!",
                 __func__, self->prop->subtype);

    return NULL;
}
コード例 #6
0
ファイル: idprop_py_api.c プロジェクト: wchargin/blender
static IDProperty *idp_from_PySequence_Buffer(const char *name, Py_buffer *buffer)
{
	IDProperty *prop;
	IDPropertyTemplate val = {0};

	int format = idp_array_type_from_format_char(*buffer->format);
	if (format == -1) {
		/* should never happen as the type has been checked before */
		return NULL;
	}
	else {
		val.array.type = format;
		val.array.len = buffer->len / buffer->itemsize;
	}
	prop = IDP_New(IDP_ARRAY, &val, name);
	memcpy(IDP_Array(prop), buffer->buf, buffer->len);
	return prop;
}
コード例 #7
0
ファイル: idprop_py_api.c プロジェクト: wchargin/blender
static int BPy_IDArray_getbuffer(BPy_IDArray *self, Py_buffer *view, int flags)
{
	IDProperty *prop = self->prop;
	int itemsize = itemsize_by_idarray_type(prop->subtype);
	int length = itemsize * prop->len;

	if (PyBuffer_FillInfo(view, (PyObject *)self, IDP_Array(prop), length, false, flags) == -1) {
		return -1;
	}

	view->itemsize = itemsize;
	view->format = (char *)idp_format_from_array_type(prop->subtype);

	Py_ssize_t *shape = MEM_mallocN(sizeof(Py_ssize_t), __func__);
	shape[0] = prop->len;
	view->shape = shape;

	return 0;
}
コード例 #8
0
/* for simple, non nested types this is the same as BPy_IDGroup_WrapData */
static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
{
    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_ARRAY:
    {
        PyObject *seq = PyList_New(prop->len);
        int i;

        if (!seq) {
            PyErr_Format(PyExc_RuntimeError,
                         "%s: IDP_ARRAY: PyList_New(%d) failed",
                         __func__, prop->len);
            return NULL;
        }

        switch (prop->subtype) {
        case IDP_FLOAT:
        {
            float *array = (float *)IDP_Array(prop);
            for (i = 0; i < prop->len; i++) {
                PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
            }
            break;
        }
        case IDP_DOUBLE:
        {
            double *array = (double *)IDP_Array(prop);
            for (i = 0; i < prop->len; i++) {
                PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
            }
            break;
        }
        case IDP_INT:
        {
            int *array = (int *)IDP_Array(prop);
            for (i = 0; i < prop->len; i++) {
                PyList_SET_ITEM(seq, i, PyLong_FromLong(array[i]));
            }
            break;
        }
        default:
            PyErr_Format(PyExc_RuntimeError,
                         "%s: invalid/corrupt array type '%d'!",
                         __func__, prop->subtype);
            Py_DECREF(seq);
            return NULL;
        }

        return seq;
    }
    case IDP_IDPARRAY:
    {
        PyObject *seq = PyList_New(prop->len), *wrap;
        IDProperty *array = IDP_IDPArray(prop);
        int i;

        if (!seq) {
            PyErr_Format(PyExc_RuntimeError,
                         "%s: IDP_IDPARRAY: PyList_New(%d) failed",
                         __func__, prop->len);
            return NULL;
        }

        for (i = 0; i < prop->len; i++) {
            wrap = BPy_IDGroup_MapDataToPy(array++);

            if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
                return NULL;

            PyList_SET_ITEM(seq, i, wrap);
        }
        return seq;
    }
    case IDP_GROUP:
    {
        PyObject *dict = PyDict_New(), *wrap;
        IDProperty *loop;

        for (loop = prop->data.group.first; loop; loop = loop->next) {
            wrap = BPy_IDGroup_MapDataToPy(loop);

            if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
                return NULL;

            PyDict_SetItemString(dict, loop->name, wrap);
            Py_DECREF(wrap);
        }
        return dict;
    }
    }

    PyErr_Format(PyExc_RuntimeError,
                 "%s ERROR: '%s' property exists with a bad type code '%d'!",
                 __func__, prop->name, prop->type);
    return NULL;
}
コード例 #9
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;
}
コード例 #10
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;
}
コード例 #11
0
ファイル: idprop_py_api.c プロジェクト: wchargin/blender
static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob)
{
	IDProperty *prop;
	IDPropertyTemplate val = {0};

	PyObject **ob_seq_fast_items;
	PyObject *item;
	int i;

	ob_seq_fast_items = PySequence_Fast_ITEMS(ob);

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

	/* 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);

	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 = ob_seq_fast_items[i];
				if (((prop_data[i] = PyFloat_AsDouble(item)) == -1.0) && PyErr_Occurred()) {
					return NULL;
				}
			}
			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 = ob_seq_fast_items[i];
				if (((prop_data[i] = PyC_Long_AsI32(item)) == -1) && PyErr_Occurred()) {
					return NULL;
				}
			}
			break;
		}
		case IDP_IDPARRAY:
		{
			prop = IDP_NewIDPArray(name);
			for (i = 0; i < val.array.len; i++) {
				item = ob_seq_fast_items[i];
				if (BPy_IDProperty_Map_ValidateAndCreate(NULL, prop, item) == false) {
					return NULL;
				}
			}
			break;
		}
		default:
			/* should never happen */
			PyErr_SetString(PyExc_RuntimeError, "internal error with idp array.type");
			return NULL;
	}
	return prop;
}