Welcome to mirror list, hosted at ThFree Co, Russian Federation.

idprop.c « intern « blenkernel « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 66feaffadb7116d532b621e6f0b004dedf55cb70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#include "DNA_listBase.h"
#include "DNA_ID.h"

#include "BKE_idprop.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_utildefines.h"

#include "BLI_blenlib.h"

#include "MEM_guardedalloc.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* IDPropertyTemplate is a union in DNA_ID.h */
static char idp_size_table[] = {
	0, /*strings don't have fixed sizes :)*/
	sizeof(int),
	sizeof(float),
	sizeof(float)*3, /*Vector type*/
	sizeof(float)*16, /*Matrix type, we allocate max 4x4 even if in 3x3 mode*/
	0, /*arrays don't have a fixed size either :)*/
	sizeof(ListBase), /*Group type*/
	sizeof(void*)
};


/* ----------- Array Type ----------- */

/*this function works for strings too!*/
void IDP_ResizeArray(IDProperty *prop, int newlen)
{
	void *newarr;
	int newsize=newlen;

	/*first check if the array buffer size has room*/
	/*if newlen is 200 chars less then totallen, reallocate anyway*/
	if (newlen <= prop->totallen && prop->totallen - newlen < 200) {
		prop->len = newlen;
		return;
	}

	/* - Note: This code comes from python, here's the corrusponding comment. - */
	/* This over-allocates proportional to the list size, making room
	 * for additional growth.  The over-allocation is mild, but is
	 * enough to give linear-time amortized behavior over a long
	 * sequence of appends() in the presence of a poorly-performing
	 * system realloc().
	 * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
	 */
	newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;

	newarr = MEM_callocN(idp_size_table[prop->type]*newsize, "idproperty array resized");
	/*newlen is bigger*/
	if (newlen >= prop->len) memcpy(newarr, prop->data.pointer, prop->len*idp_size_table[prop->type]);
	/*newlen is smaller*/
	else memcpy(newarr, prop->data.pointer, newlen*prop->len*idp_size_table[prop->type]);

	MEM_freeN(prop->data.pointer);
	prop->data.pointer = newarr;
	prop->len = newlen;
	prop->totallen = newsize;
}

 void IDP_FreeArray(IDProperty *prop)
{
	if (prop->data.pointer)
		MEM_freeN(prop->data.pointer);
}

/*taken from readfile.c*/
#define SWITCH_LONGINT(a) { \
    char s_i, *p_i; \
    p_i= (char *)&(a);  \
    s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \
    s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \
    s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \
    s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; }



/* ---------- String Type ------------ */
void IDP_AssignString(IDProperty *prop, char *st)
{
	int stlen;

	stlen = strlen(st);

	IDP_ResizeArray(prop, stlen+1); /*make room for null byte :) */
	strcpy(prop->data.pointer, st);
}

void IDP_ConcatStringC(IDProperty *prop, char *st)
{
	int newlen;

	newlen = prop->len + strlen(st);
	/*we have to remember that prop->len includes the null byte for strings.
	 so there's no need to add +1 to the resize function.*/
	IDP_ResizeArray(prop, newlen);
	strcat(prop->data.pointer, st);
}

void IDP_ConcatString(IDProperty *str1, IDProperty *append)
{
	int newlen;

	/*since ->len for strings includes the NULL byte, we have to subtract one or
	 we'll get an extra null byte after each concatination operation.*/
	newlen = str1->len + append->len - 1;
	IDP_ResizeArray(str1, newlen);
	strcat(str1->data.pointer, append->data.pointer);
}

void IDP_FreeString(IDProperty *prop)
{
	MEM_freeN(prop->data.pointer);
}


/*-------- ID Type -------*/

void IDP_LinkID(IDProperty *prop, ID *id)
{
	if (prop->data.pointer) ((ID*)prop->data.pointer)->us--;
	prop->data.pointer = id;
	id_us_plus(id);
}

void IDP_UnlinkID(IDProperty *prop)
{
	((ID*)prop->data.pointer)->us--;
}

/*-------- Group Functions -------*/
void IDP_AddToGroup(IDProperty *group, IDProperty *prop)
{
	group->len++;
	BLI_addtail(&group->data.group, prop);
}

void IDP_RemFromGroup(IDProperty *group, IDProperty *prop)
{
	group->len--;
	BLI_remlink(&group->data.group, prop);
}

IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, char *name)
{
	IDProperty *loop;
	for (loop=prop->data.group.first; loop; loop=loop->next) {
		if (strcmp(prop->name, name)==0) return prop;
	}
	return NULL;
}

typedef struct IDPIter {
	void *next;
	IDProperty *parent;
} IDPIter;

void *IDP_GetGroupIterator(IDProperty *prop)
{
	IDPIter *iter = MEM_callocN(sizeof(IDPIter), "IDPIter");
	iter->next = prop->data.group.first;
	iter->parent = prop;
	return (void*) iter;
}

void *IDP_GroupIterNext(void *vself)
{
	IDPIter *self = (IDPIter*) vself;
	Link *next = (Link*) self->next;
	if (self->next == NULL) {
		MEM_freeN(self);
		return NULL;
	}

	self->next = next->next;
	return (void*) next;
}

void IDP_FreeIterBeforeEnd(void *vself)
{
	MEM_freeN(vself);
}

/*Ok, the way things work, Groups free the ID Property structs of their children.
  This is because all ID Property freeing functions free only direct data (not the ID Property
  struct itself), but for Groups the child properties *are* considered
  direct data.*/
void IDP_FreeGroup(IDProperty *prop)
{
	IDProperty *loop, *next;
	for (loop=prop->data.group.first; loop; loop=next)
	{
		next = loop->next;
		IDP_FreeProperty(loop);
		MEM_freeN(loop);
	}
}


/*-------- Main Functions --------*/

IDProperty *IDP_GetProperties(ID *id, int create_if_needed)
{
	if (id->properties) return id->properties;
	else {
		if (create_if_needed) {
			id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty");
			id->properties->type = IDP_GROUP;
		}
		return id->properties;
	}
}

IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name)
{
	IDProperty *prop=NULL;

	switch (type) {
		case IDP_INT:
			prop = MEM_callocN(sizeof(IDProperty), "IDProperty int");
			prop->data.val = val.i;
			break;
		case IDP_FLOAT:
			prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
			*(float*)&prop->data.val = val.f;
			break;
		case IDP_ARRAY:
		{
			/*for now, we only support float and int arrays*/
			if (val.array.type == IDP_FLOAT || val.array.type == IDP_INT) {
				prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
				prop->len = prop->totallen = val.array.len;
				prop->subtype = val.array.type;
				prop->data.pointer = MEM_callocN(idp_size_table[val.array.type]*val.array.len, "id property array");
				break;
			} else {
				return NULL;
			}
		}
		case IDP_STRING:
		{
			char *st = val.str;
			int stlen;

			prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
			if (st == NULL) {
				prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
				prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
				prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
			} else {
				stlen = strlen(st) + 1;
				prop->data.pointer = MEM_callocN(stlen, "id property string 2");
				prop->len = prop->totallen = stlen;
				strcpy(prop->data.pointer, st);
			}
			break;
		}
		case IDP_GROUP:
		{
			prop = MEM_callocN(sizeof(IDProperty), "IDProperty group");
			/* heh I think all needed values are set properly by calloc anyway :) */
			break;
		}
		case IDP_MATRIX:
			prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
			if (val.matrix_or_vector.matvec_size == IDP_MATRIX4X4)
				prop->data.pointer = MEM_callocN(sizeof(float)*4*4, "matrix 4x4 idproperty");
			else
				prop->data.pointer = MEM_callocN(sizeof(float)*3*3, "matrix 3x3 idproperty");
		case IDP_VECTOR:
			prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
			switch (val.matrix_or_vector.matvec_size) {
				case IDP_VECTOR4D:
					prop->data.pointer = MEM_callocN(sizeof(float)*4, "vector 4d idproperty");
					break;
				case IDP_VECTOR3D:
					prop->data.pointer = MEM_callocN(sizeof(float)*3, "vector 3d idproperty");
					break;
				case IDP_VECTOR2D:
					prop->data.pointer = MEM_callocN(sizeof(float)*2, "vector 2d idproperty");
					break;

			}
		default:
		{
			prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
			break;
		}
	}

	prop->type = type;
	strncpy(prop->name, name, MAX_IDPROP_NAME);
	return prop;
}

/*NOTE: this will free all child properties of list arrays and groups!
  Also, note that this does NOT unlink anything!  Plus it doesn't free
  the actual IDProperty struct either.*/
void IDP_FreeProperty(IDProperty *prop)
{
	switch (prop->type) {
		case IDP_ARRAY:
			IDP_FreeArray(prop);
			break;
		case IDP_STRING:
			IDP_FreeString(prop);
			break;
		case IDP_GROUP:
			IDP_FreeGroup(prop);
			break;
		case IDP_VECTOR:
		case IDP_MATRIX:
			MEM_freeN(prop->data.pointer);
			break;
	}
}

/*Unlinks any IDProperty<->ID linkage that might be going on.*/
void IDP_UnlinkProperty(IDProperty *prop)
{
	switch (prop->type) {
		case IDP_ID:
			IDP_UnlinkID(prop);
	}
}