Esempio n. 1
0
/* Given an array property, creates an N-dimensional tuple of values. */
static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop, int dim, int *index)
{
	PyObject *tuple;
	int i, len;
	int totdim = RNA_property_array_dimension(ptr, prop, NULL);

	len = RNA_property_multi_array_length(ptr, prop, dim);

	tuple = PyTuple_New(len);

	for (i = 0; i < len; i++) {
		PyObject *item;

		if (dim + 1 < totdim)
			item = pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
		else {
			item = pyrna_array_index(ptr, prop, *index);
			*index = *index + 1;
		}

		if (!item) {
			Py_DECREF(tuple);
			return NULL;
		}

		PyTuple_SET_ITEM(tuple, i, item);
	}

	return tuple;
}
Esempio n. 2
0
static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop,
                          int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *totitem,
                          const char *error_prefix)
{
	int dimsize[MAX_ARRAY_DIMENSION];
	int totdim = RNA_property_array_dimension(ptr, prop, dimsize);

	/* validate type first because length validation may modify property array length */


#ifdef USE_MATHUTILS
	if (lvalue_dim == 0) { /* only valid for first level array */
		if (MatrixObject_Check(rvalue)) {
			MatrixObject *pymat = (MatrixObject *)rvalue;

			if (BaseMath_ReadCallback(pymat) == -1)
				return -1;

			if (RNA_property_type(prop) != PROP_FLOAT) {
				PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign to non float array",
				             error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop));
				return -1;
			}
			else if (totdim != 2) {
				PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign array with %d dimensions",
				             error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), totdim);
				return -1;
			}
			else if (pymat->num_col != dimsize[0] || pymat->num_row != dimsize[1]) {
				PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign dimension size mismatch, "
				             "is %dx%d, expected be %dx%d",
				             error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop),
				             pymat->num_col, pymat->num_row, dimsize[0], dimsize[1]);
				return -1;
			}
			else {
				*totitem = dimsize[0] * dimsize[1];
				return 0;
			}
		}
	}
#endif /* USE_MATHUTILS */


	{
		if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix) == -1)
			return -1;

		return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix);
	}
}
Esempio n. 3
0
static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop,
                             int lvalue_dim, int arrayoffset, int index,
                             ItemTypeCheckFunc check_item_type, const char *item_type_str,
                             ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
{
	int totdim, dimsize[MAX_ARRAY_DIMENSION];
	int totitem, i;

	totdim = RNA_property_array_dimension(ptr, prop, dimsize);

	/* convert index */

	/* arr[3][4][5]
	 *
	 *    arr[2] = x
	 *    lvalue_dim = 0, index = 0 + 2 * 4 * 5
	 *
	 *    arr[2][3] = x
	 *    lvalue_dim = 1, index = 40 + 3 * 5 */

	lvalue_dim++;

	for (i = lvalue_dim; i < totdim; i++)
		index *= dimsize[i];

	index += arrayoffset;

	if (lvalue_dim == totdim) { /* single item, assign directly */
		if (!check_item_type(py)) {
			PyErr_Format(PyExc_TypeError, "%s %.200s.%.200s, expected a %s type, not %s",
			             error_prefix, RNA_struct_identifier(ptr->type),
			             RNA_property_identifier(prop), item_type_str,
			             Py_TYPE(py)->tp_name);
			return -1;
		}
		copy_value_single(py, ptr, prop, NULL, 0, &index, convert_item, rna_set_index);
	}
	else {
		if (validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix) == -1) {
			return -1;
		}

		if (totitem) {
			copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index);
		}
	}
	return 0;
}
PyObject *pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index)
{
	int totdim, arraydim, arrayoffset, dimsize[MAX_ARRAY_DIMENSION], i, len;
	BPy_PropertyArrayRNA *ret = NULL;

	arraydim = self ? self->arraydim : 0;
	arrayoffset = self ? self->arrayoffset : 0;

	/* just in case check */
	len = RNA_property_multi_array_length(ptr, prop, arraydim);
	if (index >= len || index < 0) {
		/* this shouldn't happen because higher level funcs must check for invalid index */
		if (G.debug & G_DEBUG_PYTHON)
			printf("%s: invalid index %d for array with length=%d\n", __func__, index, len);

		PyErr_SetString(PyExc_IndexError, "out of range");
		return NULL;
	}

	totdim = RNA_property_array_dimension(ptr, prop, dimsize);

	if (arraydim + 1 < totdim) {
		ret = (BPy_PropertyArrayRNA *)pyrna_prop_CreatePyObject(ptr, prop);
		ret->arraydim = arraydim + 1;

		/* arr[3][4][5]
		 *
		 *    x = arr[2]
		 *    index = 0 + 2 * 4 * 5
		 * 
		 *    x = arr[2][3]
		 *    index = offset + 3 * 5 */

		for (i = arraydim + 1; i < totdim; i++)
			index *= dimsize[i];

		ret->arrayoffset = arrayoffset + index;
	}
	else {
		index = arrayoffset + index;
		ret = (BPy_PropertyArrayRNA *)pyrna_array_index(ptr, prop, index);
	}

	return (PyObject *)ret;
}
Esempio n. 5
0
/* TODO, multi-dimensional arrays */
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
{
	int len = RNA_property_array_length(ptr, prop);
	int type;
	int i;

	if (len == 0) /* possible with dynamic arrays */
		return 0;

	if (RNA_property_array_dimension(ptr, prop, NULL) > 1) {
		PyErr_SetString(PyExc_TypeError, "PropertyRNA - multi dimensional arrays not supported yet");
		return -1;
	}

	type = RNA_property_type(prop);

	switch (type) {
		case PROP_FLOAT:
		{
			float value_f = PyFloat_AsDouble(value);
			if (value_f == -1 && PyErr_Occurred()) {
				PyErr_Clear();
				return 0;
			}
			else {
				float tmp[32];
				float *tmp_arr;

				if (len * sizeof(float) > sizeof(tmp)) {
					tmp_arr = PyMem_MALLOC(len * sizeof(float));
				}
				else {
					tmp_arr = tmp;
				}

				RNA_property_float_get_array(ptr, prop, tmp_arr);

				for (i = 0; i < len; i++) {
					if (tmp_arr[i] == value_f) {
						break;
					}
				}

				if (tmp_arr != tmp)
					PyMem_FREE(tmp_arr);

				return i < len ? 1 : 0;
			}
			break;
		}
		case PROP_BOOLEAN:
		case PROP_INT:
		{
			int value_i = PyLong_AsSsize_t(value);
			if (value_i == -1 && PyErr_Occurred()) {
				PyErr_Clear();
				return 0;
			}
			else {
				int tmp[32];
				int *tmp_arr;

				if (len * sizeof(int) > sizeof(tmp)) {
					tmp_arr = PyMem_MALLOC(len * sizeof(int));
				}
				else {
					tmp_arr = tmp;
				}

				if (type == PROP_BOOLEAN)
					RNA_property_boolean_get_array(ptr, prop, tmp_arr);
				else
					RNA_property_int_get_array(ptr, prop, tmp_arr);

				for (i = 0; i < len; i++) {
					if (tmp_arr[i] == value_i) {
						break;
					}
				}

				if (tmp_arr != tmp)
					PyMem_FREE(tmp_arr);

				return i < len ? 1 : 0;
			}
			break;
		}
	}

	/* should never reach this */
	PyErr_SetString(PyExc_TypeError, "PropertyRNA - type not in float/bool/int");
	return -1;
}
Esempio n. 6
0
static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
                         int dim, char *data, unsigned int item_size, int *index,
                         ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
{
	int totdim = RNA_property_array_dimension(ptr, prop, NULL);
	const Py_ssize_t seq_size = PySequence_Size(seq);
	Py_ssize_t i;

	/* Regarding PySequence_GetItem() failing.
	 *
	 * This should never be NULL since we validated it, _but_ some tricky python
	 * developer could write their own sequence type which succeeds on
	 * validating but fails later somehow, so include checks for safety.
	 */

	/* Note that 'data can be NULL' */

	if (seq_size == -1) {
		return NULL;
	}


#ifdef USE_MATHUTILS
	if (dim == 0) {
		if (MatrixObject_Check(seq)) {
			MatrixObject *pymat = (MatrixObject *)seq;
			size_t allocsize = pymat->num_col * pymat->num_row * sizeof(float);

			/* read callback already done by validate */
			/* since this is the first iteration we can assume data is allocated */
			memcpy(data, pymat->matrix, allocsize);

			/* not really needed but do for completeness */
			data += allocsize;

			return data;
		}
	}
#endif /* USE_MATHUTILS */


	for (i = 0; i < seq_size; i++) {
		PyObject *item = PySequence_GetItem(seq, i);
		if (item) {
			if (dim + 1 < totdim) {
				data = copy_values(item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
			}
			else {
				data = copy_value_single(item, ptr, prop, data, item_size, index, convert_item, rna_set_index);
			}

			Py_DECREF(item);

			/* data may be NULL, but the for loop checks */
		}
		else {
			return NULL;
		}
	}

	return data;
}
Esempio n. 7
0
/* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop,
                                 int lvalue_dim, int *totitem, const char *error_prefix)
{
	int dimsize[MAX_ARRAY_DIMENSION];
	int tot, totdim, len;

	totdim = RNA_property_array_dimension(ptr, prop, dimsize);
	tot = count_items(rvalue, totdim - lvalue_dim);

	if (tot == -1) {
		PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, error validating the sequence length",
		             error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop));
		return -1;
	}
	else if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
		if (RNA_property_array_length(ptr, prop) != tot) {
#if 0
			/* length is flexible */
			if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) {
				/* BLI_snprintf(error_str, error_str_size,
				 *              "%s.%s: array length cannot be changed to %d",
				 *              RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */
				PyErr_Format(PyExc_ValueError, "%s %s.%s: array length cannot be changed to %d",
				             error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot);
				return -1;
			}
#else
			*totitem = tot;
			return 0;

#endif
		}

		len = tot;
	}
	else {
		/* length is a constraint */
		if (!lvalue_dim) {
			len = RNA_property_array_length(ptr, prop);
		}
		/* array item assignment */
		else {
			int i;

			len = 1;

			/* arr[3][4][5]
			 *
			 *    arr[2] = x
			 *    dimsize = {4, 5}
			 *    dimsize[1] = 4
			 *    dimsize[2] = 5
			 *    lvalue_dim = 0, totdim = 3
			 * 
			 *    arr[2][3] = x
			 *    lvalue_dim = 1
			 * 
			 *    arr[2][3][4] = x
			 *    lvalue_dim = 2 */
			for (i = lvalue_dim; i < totdim; i++)
				len *= dimsize[i];
		}

		if (tot != len) {
			/* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */
			PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, sequence must have %d items total, not %d",
			             error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), len, tot);
			return -1;
		}
	}

	*totitem = len;

	return 0;
}