GPU Framebuffer: simplify gpu_framebuffer_update_attachments_and_fill_empty_slots...
[blender.git] / source / blender / makesdna / intern / dna_genfile.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  * DNA handling
27  */
28
29 /** \file blender/makesdna/intern/dna_genfile.c
30  *  \ingroup DNA
31  *
32  * Lowest-level functions for decoding the parts of a saved .blend
33  * file, including interpretation of its SDNA block and conversion of
34  * contents of other parts according to the differences between that
35  * SDNA and the SDNA of the current (running) version of Blender.
36  */
37
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <limits.h>
43
44 #include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN
45
46 #include "BLI_utildefines.h"
47 #include "BLI_endian_switch.h"
48
49 #ifdef WITH_DNA_GHASH
50 #  include "BLI_ghash.h"
51 #endif
52
53 #include "DNA_genfile.h"
54 #include "DNA_sdna_types.h" // for SDNA ;-)
55
56 /**
57  * \section dna_genfile Overview
58  *
59  * - please note: no builtin security to detect input of double structs
60  * - if you want a struct not to be in DNA file: add two hash marks above it `(#<enter>#<enter>)`.
61  *
62  * Structure DNA data is added to each blender file and to each executable, this to detect
63  * in .blend files new variables in structs, changed array sizes, etc. It's also used for
64  * converting endian and pointer size (32-64 bits)
65  * As an extra, Python uses a call to detect run-time the contents of a blender struct.
66  *
67  * Create a structDNA: only needed when one of the input include (.h) files change.
68  * File Syntax:
69  * \code{.unparsed}
70  *     SDNA (4 bytes) (magic number)
71  *     NAME (4 bytes)
72  *     <nr> (4 bytes) amount of names (int)
73  *     <string>
74  *     <string>
75  *     ...
76  *     ...
77  *     TYPE (4 bytes)
78  *     <nr> amount of types (int)
79  *     <string>
80  *     <string>
81  *     ...
82  *     ...
83  *     TLEN (4 bytes)
84  *     <len> (short) the lengths of types
85  *     <len>
86  *     ...
87  *     ...
88  *     STRC (4 bytes)
89  *     <nr> amount of structs (int)
90  *     <typenr><nr_of_elems> <typenr><namenr> <typenr><namenr> ...
91  * \endcode
92  *
93  *  **Remember to read/write integer and short aligned!**
94  *
95  *  While writing a file, the names of a struct is indicated with a type number,
96  *  to be found with: ``type = DNA_struct_find_nr(SDNA *, const char *)``
97  *  The value of ``type`` corresponds with the index within the structs array
98  *
99  *  For the moment: the complete DNA file is included in a .blend file. For
100  *  the future we can think of smarter methods, like only included the used
101  *  structs. Only needed to keep a file short though...
102  *
103  * ALLOWED AND TESTED CHANGES IN STRUCTS:
104  *  - type change (a char to float will be divided by 255)
105  *  - location within a struct (everything can be randomly mixed up)
106  *  - struct within struct (within struct etc), this is recursive
107  *  - adding new elements, will be default initialized zero
108  *  - removing elements
109  *  - change of array sizes
110  *  - change of a pointer type: when the name doesn't change the contents is copied
111  *
112  * NOT YET:
113  *  - array (``vec[3]``) to float struct (``vec3f``)
114  *
115  * DONE:
116  *  - endian compatibility
117  *  - pointer conversion (32-64 bits)
118  *
119  * IMPORTANT:
120  *  - do not use #defines in structs for array lengths, this cannot be read by the dna functions
121  *  - do not use uint, but unsigned int instead, ushort and ulong are allowed
122  *  - only use a long in Blender if you want this to be the size of a pointer. so it is
123  *    32 bits or 64 bits, dependent at the cpu architecture
124  *  - chars are always unsigned
125  *  - alignment of variables has to be done in such a way, that any system does
126  *    not create 'padding' (gaps) in structures. So make sure that:
127  *    - short: 2 aligned
128  *    - int: 4 aligned
129  *    - float: 4 aligned
130  *    - double: 8 aligned
131  *    - long: 8 aligned
132  *    - struct: 8 aligned
133  *  - the sdna functions have several error prints builtin, always check blender running from a console.
134  *
135  */
136
137 /* ************************* MAKE DNA ********************** */
138
139 /* allowed duplicate code from makesdna.c */
140
141 /**
142  * parses the "[n]" on the end of an array name and returns the number of array elements n.
143  */
144 int DNA_elem_array_size(const char *str)
145 {
146         int a, mul = 1;
147         const char *cp = NULL;
148
149         for (a = 0; str[a]; a++) {
150                 if (str[a] == '[') {
151                         cp = &(str[a + 1]);
152                 }
153                 else if (str[a] == ']' && cp) {
154                         mul *= atoi(cp);
155                 }
156         }
157
158         return mul;
159 }
160
161 /* ************************* END MAKE DNA ********************** */
162
163 /* ************************* DIV ********************** */
164
165 void DNA_sdna_free(SDNA *sdna)
166 {
167         if (sdna->data_alloc) {
168                 MEM_freeN((void *)sdna->data);
169         }
170
171         MEM_freeN((void *)sdna->names);
172         MEM_freeN((void *)sdna->types);
173         MEM_freeN(sdna->structs);
174
175 #ifdef WITH_DNA_GHASH
176         if (sdna->structs_map) {
177                 BLI_ghash_free(sdna->structs_map, NULL, NULL);
178         }
179 #endif
180
181         MEM_freeN(sdna);
182 }
183
184 /**
185  * Return true if the name indicates a pointer of some kind.
186  */
187 static bool ispointer(const char *name)
188 {
189         /* check if pointer or function pointer */
190         return (name[0] == '*' || (name[0] == '(' && name[1] == '*'));
191 }
192
193 /**
194  * Returns the size of struct fields of the specified type and name.
195  *
196  * \param type  Index into sdna->types/typelens
197  * \param name  Index into sdna->names,
198  * needed to extract possible pointer/array information.
199  */
200 static int elementsize(const SDNA *sdna, short type, short name)
201 {
202         int mul, namelen, len;
203         const char *cp;
204
205         cp = sdna->names[name];
206         len = 0;
207
208         namelen = strlen(cp);
209         /* is it a pointer or function pointer? */
210         if (ispointer(cp)) {
211                 /* has the name an extra length? (array) */
212                 mul = 1;
213                 if (cp[namelen - 1] == ']') {
214                         mul = DNA_elem_array_size(cp);
215                 }
216
217                 len = sdna->pointerlen * mul;
218         }
219         else if (sdna->typelens[type]) {
220                 /* has the name an extra length? (array) */
221                 mul = 1;
222                 if (cp[namelen - 1] == ']') {
223                         mul = DNA_elem_array_size(cp);
224                 }
225
226                 len = mul * sdna->typelens[type];
227
228         }
229
230         return len;
231 }
232
233 #if 0
234 static void printstruct(SDNA *sdna, short strnr)
235 {
236         /* is for debug */
237         int b, nr;
238         short *sp;
239
240         sp = sdna->structs[strnr];
241
242         printf("struct %s\n", sdna->types[sp[0]]);
243         nr = sp[1];
244         sp += 2;
245
246         for (b = 0; b < nr; b++, sp += 2) {
247                 printf("   %s %s\n", sdna->types[sp[0]], sdna->names[sp[1]]);
248         }
249 }
250 #endif
251
252 /**
253  * Returns the index of the struct info for the struct with the specified name.
254  */
255 int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
256 {
257         const short *sp = NULL;
258
259         if (*index_last < sdna->nr_structs) {
260                 sp = sdna->structs[*index_last];
261                 if (strcmp(sdna->types[sp[0]], str) == 0) {
262                         return *index_last;
263                 }
264         }
265
266 #ifdef WITH_DNA_GHASH
267         {
268                 void **index_p;
269                 int a;
270
271                 index_p = BLI_ghash_lookup_p(sdna->structs_map, str);
272
273                 if (index_p) {
274                         a = POINTER_AS_INT(*index_p);
275                         *index_last = a;
276                 }
277                 else {
278                         a = -1;
279                 }
280                 return a;
281         }
282 #else
283         {
284                 int a;
285
286                 for (a = 0; a < sdna->nr_structs; a++) {
287
288                         sp = sdna->structs[a];
289
290                         if (strcmp(sdna->types[sp[0]], str) == 0) {
291                                 *index_last = a;
292                                 return a;
293                         }
294                 }
295         }
296         return -1;
297 #endif
298 }
299
300 int DNA_struct_find_nr(const SDNA *sdna, const char *str)
301 {
302         unsigned int index_last_dummy = UINT_MAX;
303         return DNA_struct_find_nr_ex(sdna, str, &index_last_dummy);
304 }
305
306 /* ************************* END DIV ********************** */
307
308 /* ************************* READ DNA ********************** */
309
310 BLI_INLINE const char *pad_up_4(const char *ptr)
311 {
312         return (const char *)((((uintptr_t)ptr) + 3) & ~3);
313 }
314
315 /**
316  * Temporary DNA doversion for files that were created with Blender 2.80
317  * between October 2016, and November 2017 (>=280.0 and < 280.2).
318  *
319  * /note This would be way more efficient if we can get the version from SDNA
320  * So we could return true if version == 280 && subversion < 2.
321  *
322  * Returns true if we need to do the DNA renaming.
323  */
324 static bool need_doversion_280(SDNA *sdna, int *data, const bool data_alloc)
325 {
326         if (data_alloc == false) {
327                 return false;
328         }
329
330         bool active_layer = false, render_layers = false;
331
332         const char *cp = (char *)data;
333         for (int nr = 0; nr < sdna->nr_names; nr++) {
334                 if (strcmp(cp, "active_layer") == 0) {
335                         active_layer = true;
336                         if (active_layer && render_layers) {
337                                 return true;
338                         }
339                 }
340                 else if (strcmp(cp, "render_layers") == 0) {
341                         render_layers = true;
342                         if (active_layer && render_layers) {
343                                 return true;
344                         }
345                 }
346
347                 while (*cp) cp++;
348                 cp++;
349         }
350
351         /* If someone adds only one of them to the DNA, don't! */
352         BLI_assert(!(active_layer || render_layers));
353         return false;
354 }
355
356 /**
357  * In sdna->data the data, now we convert that to something understandable
358  */
359 static bool init_structDNA(
360         SDNA *sdna, bool do_endian_swap,
361         bool data_alloc,
362         const char **r_error_message)
363 {
364         int *data, *verg, gravity_fix = -1;
365         short *sp;
366         char str[8];
367
368         verg = (int *)str;
369         data = (int *)sdna->data;
370
371         /* clear pointers incase of error */
372         sdna->names = NULL;
373         sdna->types = NULL;
374         sdna->structs = NULL;
375 #ifdef WITH_DNA_GHASH
376         sdna->structs_map = NULL;
377 #endif
378
379         strcpy(str, "SDNA");
380         if (*data != *verg) {
381                 *r_error_message = "SDNA error in SDNA file";
382                 return false;
383         }
384         else {
385                 const char *cp;
386
387                 data++;
388
389                 /* load names array */
390                 strcpy(str, "NAME");
391                 if (*data == *verg) {
392                         data++;
393
394                         sdna->nr_names = *data;
395                         if (do_endian_swap) {
396                                 BLI_endian_switch_int32(&sdna->nr_names);
397                         }
398
399                         data++;
400                         sdna->names = MEM_callocN(sizeof(void *) * sdna->nr_names, "sdnanames");
401                 }
402                 else {
403                         *r_error_message = "NAME error in SDNA file";
404                         return false;
405                 }
406
407                 /* Temporary DNA doversion for files that were created with Blender 2.80
408                  * between 280.0 and 280.2. */
409                 const bool doversion_280 = need_doversion_280(sdna, data, data_alloc);
410
411                 cp = (char *)data;
412                 for (int nr = 0; nr < sdna->nr_names; nr++) {
413                         sdna->names[nr] = cp;
414
415                         /* "float gravity [3]" was parsed wrong giving both "gravity" and
416                          * "[3]"  members. we rename "[3]", and later set the type of
417                          * "gravity" to "void" so the offsets work out correct */
418                         if (*cp == '[' && strcmp(cp, "[3]") == 0) {
419                                 if (nr && strcmp(sdna->names[nr - 1], "Cvi") == 0) {
420                                         sdna->names[nr] = "gravity[3]";
421                                         gravity_fix = nr;
422                                 }
423                         }
424                         else if (doversion_280) {
425                                 if (strcmp(cp, "*render_layer") == 0) {
426                                         /* WorkSpace. */
427                                         sdna->names[nr] = "*view_layer";
428                                 }
429                                 else if (strcmp(cp, "*scene_layer") == 0) {
430                                         /* ParticleEditSettings. */
431                                         sdna->names[nr] = "*view_layer";
432                                 }
433                                 else if (strcmp(cp, "render_layers") == 0) {
434                                         /* Scene. */
435                                         sdna->names[nr] = "view_layers";
436                                 }
437                                 else if (strcmp(cp, "active_layer") == 0) {
438                                         /* Scene. */
439                                         sdna->names[nr] = "active_view_layer";
440                                 }
441                                 else if (strcmp(cp, "*cur_render_layer") == 0) {
442                                         /* FileGlobal. */
443                                         sdna->names[nr] = "*cur_view_layer";
444                                 }
445                         }
446
447                         while (*cp) cp++;
448                         cp++;
449                 }
450
451                 cp = pad_up_4(cp);
452
453                 /* load type names array */
454                 data = (int *)cp;
455                 strcpy(str, "TYPE");
456                 if (*data == *verg) {
457                         data++;
458
459                         sdna->nr_types = *data;
460                         if (do_endian_swap) {
461                                 BLI_endian_switch_int32(&sdna->nr_types);
462                         }
463
464                         data++;
465                         sdna->types = MEM_callocN(sizeof(void *) * sdna->nr_types, "sdnatypes");
466                 }
467                 else {
468                         *r_error_message = "TYPE error in SDNA file";
469                         return false;
470                 }
471
472                 cp = (char *)data;
473                 for (int nr = 0; nr < sdna->nr_types; nr++) {
474                         sdna->types[nr] = cp;
475
476                         /* this is a patch, to change struct names without a conflict with SDNA */
477                         /* be careful to use it, in this case for a system-struct (opengl/X) */
478
479                         /* struct Screen was already used by X, 'bScreen' replaces the old IrisGL 'Screen' struct */
480                         if (strcmp("bScreen", cp) == 0) {
481                                 sdna->types[nr] = cp + 1;
482                         }
483                         /* Groups renamed to collections in 2.8 */
484                         else if (strcmp("Collection", cp) == 0) {
485                                 sdna->types[nr] = "Group";
486                         }
487                         else if (strcmp("CollectionObject", cp) == 0) {
488                                 sdna->types[nr] = "GroupObject";
489                         }
490                         else if (doversion_280) {
491                                 if (strcmp(cp, "SceneLayer") == 0) {
492                                         sdna->types[nr] = "ViewLayer";
493                                 }
494                                 else if (strcmp(cp, "SceneLayerEngineData") == 0) {
495                                         sdna->types[nr] = "ViewLayerEngineData";
496                                 }
497                         }
498
499                         while (*cp) cp++;
500                         cp++;
501                 }
502
503                 cp = pad_up_4(cp);
504
505                 /* load typelen array */
506                 data = (int *)cp;
507                 strcpy(str, "TLEN");
508                 if (*data == *verg) {
509                         data++;
510                         sp = (short *)data;
511                         sdna->typelens = sp;
512
513                         if (do_endian_swap) {
514                                 BLI_endian_switch_int16_array(sp, sdna->nr_types);
515                         }
516
517                         sp += sdna->nr_types;
518                 }
519                 else {
520                         *r_error_message = "TLEN error in SDNA file";
521                         return false;
522                 }
523                 if (sdna->nr_types & 1) sp++;   /* prevent BUS error */
524
525                 /* load struct array */
526                 data = (int *)sp;
527                 strcpy(str, "STRC");
528                 if (*data == *verg) {
529                         data++;
530
531                         sdna->nr_structs = *data;
532                         if (do_endian_swap) {
533                                 BLI_endian_switch_int32(&sdna->nr_structs);
534                         }
535
536                         data++;
537                         sdna->structs = MEM_callocN(sizeof(void *) * sdna->nr_structs, "sdnastrcs");
538                 }
539                 else {
540                         *r_error_message = "STRC error in SDNA file";
541                         return false;
542                 }
543
544                 sp = (short *)data;
545                 for (int nr = 0; nr < sdna->nr_structs; nr++) {
546                         sdna->structs[nr] = sp;
547
548                         if (do_endian_swap) {
549                                 short a;
550
551                                 BLI_endian_switch_int16(&sp[0]);
552                                 BLI_endian_switch_int16(&sp[1]);
553
554                                 a = sp[1];
555                                 sp += 2;
556                                 while (a--) {
557                                         BLI_endian_switch_int16(&sp[0]);
558                                         BLI_endian_switch_int16(&sp[1]);
559                                         sp += 2;
560                                 }
561                         }
562                         else {
563                                 sp += 2 * sp[1] + 2;
564                         }
565                 }
566         }
567
568         {
569                 /* second part of gravity problem, setting "gravity" type to void */
570                 if (gravity_fix > -1) {
571                         for (int nr = 0; nr < sdna->nr_structs; nr++) {
572                                 sp = sdna->structs[nr];
573                                 if (strcmp(sdna->types[sp[0]], "ClothSimSettings") == 0)
574                                         sp[10] = SDNA_TYPE_VOID;
575                         }
576                 }
577         }
578
579 #ifdef WITH_DNA_GHASH
580         {
581                 /* create a ghash lookup to speed up */
582                 sdna->structs_map = BLI_ghash_str_new_ex("init_structDNA gh", sdna->nr_structs);
583
584                 for (intptr_t nr = 0; nr < sdna->nr_structs; nr++) {
585                         sp = sdna->structs[nr];
586                         BLI_ghash_insert(sdna->structs_map, (void *)sdna->types[sp[0]], POINTER_FROM_INT(nr));
587                 }
588         }
589 #endif
590
591         /* Calculate 'sdna->pointerlen' */
592         {
593                 intptr_t nr = DNA_struct_find_nr(sdna, "ListBase");
594
595                 /* should never happen, only with corrupt file for example */
596                 if (UNLIKELY(nr == -1)) {
597                         *r_error_message = "ListBase struct error! Not found.";
598                         return false;
599                 }
600
601                 /* finally pointerlen: use struct ListBase to test it, never change the size of it! */
602                 sp = sdna->structs[nr];
603                 /* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */
604
605                 sdna->pointerlen = sdna->typelens[sp[0]] / 2;
606
607                 if (sp[1] != 2 || (sdna->pointerlen != 4 && sdna->pointerlen != 8)) {
608                         *r_error_message = "ListBase struct error! Needs it to calculate pointerize.";
609                         /* well, at least sizeof(ListBase) is error proof! (ton) */
610                         return false;
611                 }
612         }
613
614         return true;
615 }
616
617 /**
618  * Constructs and returns a decoded SDNA structure from the given encoded SDNA data block.
619  */
620 SDNA *DNA_sdna_from_data(
621         const void *data, const int datalen,
622         bool do_endian_swap, bool data_alloc,
623         const char **r_error_message)
624 {
625         SDNA *sdna = MEM_mallocN(sizeof(*sdna), "sdna");
626         const char *error_message = NULL;
627
628         sdna->datalen = datalen;
629         if (data_alloc) {
630                 char *data_copy = MEM_mallocN(datalen, "sdna_data");
631                 memcpy(data_copy, data, datalen);
632                 sdna->data = data_copy;
633         }
634         else {
635                 sdna->data = data;
636         }
637         sdna->data_alloc = data_alloc;
638
639
640         if (init_structDNA(sdna, do_endian_swap, data_alloc, &error_message)) {
641                 return sdna;
642         }
643         else {
644                 if (r_error_message == NULL) {
645                         fprintf(stderr, "Error decoding blend file SDNA: %s\n", error_message);
646                 }
647                 else {
648                         *r_error_message = error_message;
649                 }
650                 DNA_sdna_free(sdna);
651                 return NULL;
652         }
653 }
654
655 /**
656  * Using globals is acceptable here, the data is read-only and only changes between Blender versions.
657  *
658  * So it is safe to create once and reuse.
659  */
660 static SDNA *g_sdna = NULL;
661
662 void DNA_sdna_current_init(void)
663 {
664         g_sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false, NULL);
665 }
666
667 const struct SDNA *DNA_sdna_current_get(void)
668 {
669         BLI_assert(g_sdna != NULL);
670         return g_sdna;
671 }
672
673 void DNA_sdna_current_free(void)
674 {
675         DNA_sdna_free(g_sdna);
676         g_sdna = NULL;
677 }
678
679 /* ******************** END READ DNA ********************** */
680
681 /* ******************* HANDLE DNA ***************** */
682
683 /**
684  * Used by #DNA_struct_get_compareflags (below) to recursively mark all structs
685  * containing a field of type structnr as changed between old and current SDNAs.
686  */
687 static void recurs_test_compflags(const SDNA *sdna, char *compflags, int structnr)
688 {
689         int a, b, typenr, elems;
690         const short *sp;
691         const char *cp;
692
693         /* check all structs, test if it's inside another struct */
694         sp = sdna->structs[structnr];
695         typenr = sp[0];
696
697         for (a = 0; a < sdna->nr_structs; a++) {
698                 if ((a != structnr) && (compflags[a] == SDNA_CMP_EQUAL)) {
699                         sp = sdna->structs[a];
700                         elems = sp[1];
701                         sp += 2;
702                         for (b = 0; b < elems; b++, sp += 2) {
703                                 if (sp[0] == typenr) {
704                                         cp = sdna->names[sp[1]];
705                                         if (!ispointer(cp)) {
706                                                 compflags[a] = SDNA_CMP_NOT_EQUAL;
707                                                 recurs_test_compflags(sdna, compflags, a);
708                                         }
709                                 }
710                         }
711                 }
712         }
713
714 }
715
716
717 /**
718  * Constructs and returns an array of byte flags with one element for each struct in oldsdna,
719  * indicating how it compares to newsdna:
720  */
721 const char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna)
722 {
723         int a, b;
724         const short *sp_old, *sp_new;
725         const char *str1, *str2;
726         char *compflags;
727
728         if (oldsdna->nr_structs == 0) {
729                 printf("error: file without SDNA\n");
730                 return NULL;
731         }
732
733         compflags = MEM_callocN(oldsdna->nr_structs, "compflags");
734
735         /* we check all structs in 'oldsdna' and compare them with
736          * the structs in 'newsdna'
737          */
738         unsigned int newsdna_index_last = 0;
739
740         for (a = 0; a < oldsdna->nr_structs; a++) {
741                 sp_old = oldsdna->structs[a];
742
743                 /* search for type in cur */
744                 int sp_new_index = DNA_struct_find_nr_ex(newsdna, oldsdna->types[sp_old[0]], &newsdna_index_last);
745
746                 /* The next indices will almost always match */
747                 newsdna_index_last++;
748
749                 if (sp_new_index != -1) {
750                         sp_new = newsdna->structs[sp_new_index];
751                         /* initial assumption */
752                         compflags[a] = SDNA_CMP_NOT_EQUAL;
753
754                         /* compare length and amount of elems */
755                         if (sp_new[1] == sp_old[1]) {
756                                 if (newsdna->typelens[sp_new[0]] == oldsdna->typelens[sp_old[0]]) {
757
758                                         /* same length, same amount of elems, now per type and name */
759                                         b = sp_old[1];
760                                         sp_old += 2;
761                                         sp_new += 2;
762                                         while (b > 0) {
763                                                 str1 = newsdna->types[sp_new[0]];
764                                                 str2 = oldsdna->types[sp_old[0]];
765                                                 if (strcmp(str1, str2) != 0) break;
766
767                                                 str1 = newsdna->names[sp_new[1]];
768                                                 str2 = oldsdna->names[sp_old[1]];
769                                                 if (strcmp(str1, str2) != 0) break;
770
771                                                 /* same type and same name, now pointersize */
772                                                 if (ispointer(str1)) {
773                                                         if (oldsdna->pointerlen != newsdna->pointerlen) break;
774                                                 }
775
776                                                 b--;
777                                                 sp_old += 2;
778                                                 sp_new += 2;
779                                         }
780                                         if (b == 0) {
781                                                 /* no differences found */
782                                                 compflags[a] = SDNA_CMP_EQUAL;
783                                         }
784
785                                 }
786                         }
787
788                 }
789         }
790
791         /* first struct in util.h is struct Link, this is skipped in compflags (als # 0).
792          * was a bug, and this way dirty patched! Solve this later....
793          */
794         compflags[0] = SDNA_CMP_EQUAL;
795
796         /* Because structs can be inside structs, we recursively
797          * set flags when a struct is altered
798          */
799         for (a = 0; a < oldsdna->nr_structs; a++) {
800                 if (compflags[a] == SDNA_CMP_NOT_EQUAL) {
801                         recurs_test_compflags(oldsdna, compflags, a);
802                 }
803         }
804
805 #if 0
806         for (a = 0; a < oldsdna->nr_structs; a++) {
807                 if (compflags[a] == SDNA_CMP_NOT_EQUAL) {
808                         spold = oldsdna->structs[a];
809                         printf("changed: %s\n", oldsdna->types[spold[0]]);
810                 }
811         }
812 #endif
813
814         return compflags;
815 }
816
817 /**
818  * Converts the name of a primitive type to its enumeration code.
819  */
820 static eSDNA_Type sdna_type_nr(const char *dna_type)
821 {
822         if     ((strcmp(dna_type, "char") == 0) || (strcmp(dna_type, "const char") == 0))          return SDNA_TYPE_CHAR;
823         else if ((strcmp(dna_type, "uchar") == 0) || (strcmp(dna_type, "unsigned char") == 0))     return SDNA_TYPE_UCHAR;
824         else if ( strcmp(dna_type, "short") == 0)                                                  return SDNA_TYPE_SHORT;
825         else if ((strcmp(dna_type, "ushort") == 0) || (strcmp(dna_type, "unsigned short") == 0))   return SDNA_TYPE_USHORT;
826         else if ( strcmp(dna_type, "int") == 0)                                                    return SDNA_TYPE_INT;
827         else if ( strcmp(dna_type, "float") == 0)                                                  return SDNA_TYPE_FLOAT;
828         else if ( strcmp(dna_type, "double") == 0)                                                 return SDNA_TYPE_DOUBLE;
829         else if ( strcmp(dna_type, "int64_t") == 0)                                                return SDNA_TYPE_INT64;
830         else if ( strcmp(dna_type, "uint64_t") == 0)                                               return SDNA_TYPE_UINT64;
831         else                                                                                       return -1; /* invalid! */
832 }
833
834 /**
835  * Converts a value of one primitive type to another.
836  * Note there is no optimization for the case where otype and ctype are the same:
837  * assumption is that caller will handle this case.
838  *
839  * \param ctype  Name of type to convert to
840  * \param otype  Name of type to convert from
841  * \param name  Field name to extract array-size information
842  * \param curdata  Where to put converted data
843  * \param olddata  Data of type otype to convert
844  */
845 static void cast_elem(
846         const char *ctype, const char *otype, const char *name,
847         char *curdata, const char *olddata)
848 {
849         double val = 0.0;
850         int arrlen, curlen = 1, oldlen = 1;
851
852         eSDNA_Type ctypenr, otypenr;
853
854         arrlen = DNA_elem_array_size(name);
855
856         if ( (otypenr = sdna_type_nr(otype)) == -1 ||
857              (ctypenr = sdna_type_nr(ctype)) == -1)
858         {
859                 return;
860         }
861
862         /* define lengths */
863         oldlen = DNA_elem_type_size(otypenr);
864         curlen = DNA_elem_type_size(ctypenr);
865
866         while (arrlen > 0) {
867                 switch (otypenr) {
868                         case SDNA_TYPE_CHAR:
869                                 val = *olddata; break;
870                         case SDNA_TYPE_UCHAR:
871                                 val = *( (unsigned char *)olddata); break;
872                         case SDNA_TYPE_SHORT:
873                                 val = *( (short *)olddata); break;
874                         case SDNA_TYPE_USHORT:
875                                 val = *( (unsigned short *)olddata); break;
876                         case SDNA_TYPE_INT:
877                                 val = *( (int *)olddata); break;
878                         case SDNA_TYPE_FLOAT:
879                                 val = *( (float *)olddata); break;
880                         case SDNA_TYPE_DOUBLE:
881                                 val = *( (double *)olddata); break;
882                         case SDNA_TYPE_INT64:
883                                 val = *( (int64_t *)olddata); break;
884                         case SDNA_TYPE_UINT64:
885                                 val = *( (uint64_t *)olddata); break;
886                 }
887
888                 switch (ctypenr) {
889                         case SDNA_TYPE_CHAR:
890                                 *curdata = val; break;
891                         case SDNA_TYPE_UCHAR:
892                                 *( (unsigned char *)curdata) = val; break;
893                         case SDNA_TYPE_SHORT:
894                                 *( (short *)curdata) = val; break;
895                         case SDNA_TYPE_USHORT:
896                                 *( (unsigned short *)curdata) = val; break;
897                         case SDNA_TYPE_INT:
898                                 *( (int *)curdata) = val; break;
899                         case SDNA_TYPE_FLOAT:
900                                 if (otypenr < 2) val /= 255;
901                                 *( (float *)curdata) = val; break;
902                         case SDNA_TYPE_DOUBLE:
903                                 if (otypenr < 2) val /= 255;
904                                 *( (double *)curdata) = val; break;
905                         case SDNA_TYPE_INT64:
906                                 *( (int64_t *)curdata) = val; break;
907                         case SDNA_TYPE_UINT64:
908                                 *( (uint64_t *)curdata) = val; break;
909                 }
910
911                 olddata += oldlen;
912                 curdata += curlen;
913                 arrlen--;
914         }
915 }
916
917 /**
918  * Converts pointer values between different sizes. These are only used
919  * as lookup keys to identify data blocks in the saved .blend file, not
920  * as actual in-memory pointers.
921  *
922  * \param curlen  Pointer length to conver to
923  * \param oldlen  Length of pointers in olddata
924  * \param name  Field name to extract array-size information
925  * \param curdata  Where to put converted data
926  * \param olddata  Data to convert
927  */
928 static void cast_pointer(int curlen, int oldlen, const char *name, char *curdata, const char *olddata)
929 {
930         int64_t lval;
931         int arrlen;
932
933         arrlen = DNA_elem_array_size(name);
934
935         while (arrlen > 0) {
936
937                 if (curlen == oldlen) {
938                         memcpy(curdata, olddata, curlen);
939                 }
940                 else if (curlen == 4 && oldlen == 8) {
941                         lval = *((int64_t *)olddata);
942
943                         /* WARNING: 32-bit Blender trying to load file saved by 64-bit Blender,
944                          * pointers may lose uniqueness on truncation! (Hopefully this wont
945                          * happen unless/until we ever get to multi-gigabyte .blend files...) */
946                         *((int *)curdata) = lval >> 3;
947                 }
948                 else if (curlen == 8 && oldlen == 4) {
949                         *((int64_t *)curdata) = *((int *)olddata);
950                 }
951                 else {
952                         /* for debug */
953                         printf("errpr: illegal pointersize!\n");
954                 }
955
956                 olddata += oldlen;
957                 curdata += curlen;
958                 arrlen--;
959
960         }
961 }
962
963 /**
964  * Equality test on name and oname excluding any array-size suffix.
965  */
966 static int elem_strcmp(const char *name, const char *oname)
967 {
968         int a = 0;
969
970         while (1) {
971                 if (name[a] != oname[a]) return 1;
972                 if (name[a] == '[' || oname[a] == '[') break;
973                 if (name[a] == 0 || oname[a] == 0) break;
974                 a++;
975         }
976         return 0;
977 }
978
979 /**
980  * Returns whether the specified field exists according to the struct format
981  * pointed to by old.
982  *
983  * \param sdna  Old SDNA
984  * \param type  Current field type name
985  * \param name  Current field name
986  * \param old  Pointer to struct information in sdna
987  * \return true when existing, false otherwise.
988  */
989 static bool elem_exists(
990         const SDNA *sdna,
991         const char *type,
992         const char *name,
993         const short *old)
994 {
995         int a, elemcount;
996         const char *otype, *oname;
997
998         /* in old is the old struct */
999         elemcount = old[1];
1000         old += 2;
1001         for (a = 0; a < elemcount; a++, old += 2) {
1002                 otype = sdna->types[old[0]];
1003                 oname = sdna->names[old[1]];
1004
1005                 if (elem_strcmp(name, oname) == 0) {  /* name equal */
1006                         return strcmp(type, otype) == 0;  /* type equal */
1007                 }
1008         }
1009         return false;
1010 }
1011
1012 /**
1013  * Returns the address of the data for the specified field within olddata
1014  * according to the struct format pointed to by old, or NULL if no such
1015  * field can be found.
1016  *
1017  * Passing olddata=NULL doesn't work reliably for existence checks; it will
1018  * return NULL both when the field is found at offset 0 and when it is not
1019  * found at all. For field existence checks, use elem_exists() instead.
1020  *
1021  * \param sdna  Old SDNA
1022  * \param type  Current field type name
1023  * \param name  Current field name
1024  * \param old  Pointer to struct information in sdna
1025  * \param olddata  Struct data
1026  * \param sppo  Optional place to return pointer to field info in sdna
1027  * \return Data address.
1028  */
1029 static const char *find_elem(
1030         const SDNA *sdna,
1031         const char *type,
1032         const char *name,
1033         const short *old,
1034         const char *olddata,
1035         const short **sppo)
1036 {
1037         int a, elemcount, len;
1038         const char *otype, *oname;
1039
1040         /* without arraypart, so names can differ: return old namenr and type */
1041
1042         /* in old is the old struct */
1043         elemcount = old[1];
1044         old += 2;
1045         for (a = 0; a < elemcount; a++, old += 2) {
1046
1047                 otype = sdna->types[old[0]];
1048                 oname = sdna->names[old[1]];
1049
1050                 len = elementsize(sdna, old[0], old[1]);
1051
1052                 if (elem_strcmp(name, oname) == 0) {  /* name equal */
1053                         if (strcmp(type, otype) == 0) {   /* type equal */
1054                                 if (sppo) *sppo = old;
1055                                 return olddata;
1056                         }
1057
1058                         return NULL;
1059                 }
1060
1061                 olddata += len;
1062         }
1063         return NULL;
1064 }
1065
1066 /**
1067  * Converts the contents of a single field of a struct, of a non-struct type,
1068  * from oldsdna to newsdna format.
1069  *
1070  * \param newsdna  SDNA of current Blender
1071  * \param oldsdna  SDNA of Blender that saved file
1072  * \param type  current field type name
1073  * \param name  current field name
1074  * \param curdata  put field data converted to newsdna here
1075  * \param old  pointer to struct info in oldsdna
1076  * \param olddata  struct contents laid out according to oldsdna
1077  */
1078 static void reconstruct_elem(
1079         const SDNA *newsdna,
1080         const SDNA *oldsdna,
1081         const char *type,
1082         const char *name,
1083         char *curdata,
1084         const short *old,
1085         const char *olddata)
1086 {
1087         /* rules: test for NAME:
1088          *      - name equal:
1089          *          - cast type
1090          *      - name partially equal (array differs)
1091          *          - type equal: memcpy
1092          *          - types casten
1093          * (nzc 2-4-2001 I want the 'unsigned' bit to be parsed as well. Where
1094          * can I force this?)
1095          */
1096         int a, elemcount, len, countpos, oldsize, cursize, mul;
1097         const char *otype, *oname, *cp;
1098
1099         /* is 'name' an array? */
1100         cp = name;
1101         countpos = 0;
1102         while (*cp && *cp != '[') {
1103                 cp++; countpos++;
1104         }
1105         if (*cp != '[') countpos = 0;
1106
1107         /* in old is the old struct */
1108         elemcount = old[1];
1109         old += 2;
1110         for (a = 0; a < elemcount; a++, old += 2) {
1111                 otype = oldsdna->types[old[0]];
1112                 oname = oldsdna->names[old[1]];
1113                 len = elementsize(oldsdna, old[0], old[1]);
1114
1115                 if (strcmp(name, oname) == 0) { /* name equal */
1116
1117                         if (ispointer(name)) {  /* pointer of functionpointer afhandelen */
1118                                 cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
1119                         }
1120                         else if (strcmp(type, otype) == 0) {    /* type equal */
1121                                 memcpy(curdata, olddata, len);
1122                         }
1123                         else {
1124                                 cast_elem(type, otype, name, curdata, olddata);
1125                         }
1126
1127                         return;
1128                 }
1129                 else if (countpos != 0) {  /* name is an array */
1130
1131                         if (oname[countpos] == '[' && strncmp(name, oname, countpos) == 0) {  /* basis equal */
1132
1133                                 cursize = DNA_elem_array_size(name);
1134                                 oldsize = DNA_elem_array_size(oname);
1135
1136                                 if (ispointer(name)) {  /* handle pointer or functionpointer */
1137                                         cast_pointer(newsdna->pointerlen, oldsdna->pointerlen,
1138                                                      cursize > oldsize ? oname : name,
1139                                                      curdata, olddata);
1140                                 }
1141                                 else if (strcmp(type, otype) == 0) {  /* type equal */
1142                                         mul = len / oldsize; /* size of single old array element */
1143                                         mul *= (cursize < oldsize) ? cursize : oldsize; /* smaller of sizes of old and new arrays */
1144                                         memcpy(curdata, olddata, mul);
1145
1146                                         if (oldsize > cursize && strcmp(type, "char") == 0) {
1147                                                 /* string had to be truncated, ensure it's still null-terminated */
1148                                                 curdata[mul - 1] = '\0';
1149                                         }
1150                                 }
1151                                 else {
1152                                         cast_elem(type, otype,
1153                                                   cursize > oldsize ? oname : name,
1154                                                   curdata, olddata);
1155                                 }
1156                                 return;
1157                         }
1158                 }
1159                 olddata += len;
1160         }
1161 }
1162
1163 /**
1164  * Converts the contents of an entire struct from oldsdna to newsdna format.
1165  *
1166  * \param newsdna  SDNA of current Blender
1167  * \param oldsdna  SDNA of Blender that saved file
1168  * \param compflags
1169  *
1170  * Result from DNA_struct_get_compareflags to avoid needless conversions.
1171  * \param oldSDNAnr  Index of old struct definition in oldsdna
1172  * \param data  Struct contents laid out according to oldsdna
1173  * \param curSDNAnr  Index of current struct definition in newsdna
1174  * \param cur  Where to put converted struct contents
1175  */
1176 static void reconstruct_struct(
1177         const SDNA *newsdna,
1178         const SDNA *oldsdna,
1179         const char *compflags,
1180
1181         int oldSDNAnr,
1182         const char *data,
1183         int curSDNAnr,
1184         char *cur)
1185 {
1186         /* Recursive!
1187          * Per element from cur_struct, read data from old_struct.
1188          * If element is a struct, call recursive.
1189          */
1190         int a, elemcount, elen, eleno, mul, mulo, firststructtypenr;
1191         const short *spo, *spc, *sppo;
1192         const char *type;
1193         const char *cpo;
1194         char *cpc;
1195         const char *name, *nameo;
1196
1197         unsigned int oldsdna_index_last = UINT_MAX;
1198         unsigned int cursdna_index_last = UINT_MAX;
1199
1200
1201         if (oldSDNAnr == -1) return;
1202         if (curSDNAnr == -1) return;
1203
1204         if (compflags[oldSDNAnr] == SDNA_CMP_EQUAL) {
1205                 /* if recursive: test for equal */
1206                 spo = oldsdna->structs[oldSDNAnr];
1207                 elen = oldsdna->typelens[spo[0]];
1208                 memcpy(cur, data, elen);
1209
1210                 return;
1211         }
1212
1213         firststructtypenr = *(newsdna->structs[0]);
1214
1215         spo = oldsdna->structs[oldSDNAnr];
1216         spc = newsdna->structs[curSDNAnr];
1217
1218         elemcount = spc[1];
1219
1220         spc += 2;
1221         cpc = cur;
1222         for (a = 0; a < elemcount; a++, spc += 2) {  /* convert each field */
1223                 type = newsdna->types[spc[0]];
1224                 name = newsdna->names[spc[1]];
1225
1226                 elen = elementsize(newsdna, spc[0], spc[1]);
1227
1228                 /* test: is type a struct? */
1229                 if (spc[0] >= firststructtypenr && !ispointer(name)) {
1230                         /* struct field type */
1231                         /* where does the old struct data start (and is there an old one?) */
1232                         cpo = (char *)find_elem(oldsdna, type, name, spo, data, &sppo);
1233
1234                         if (cpo) {
1235                                 oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last);
1236                                 curSDNAnr = DNA_struct_find_nr_ex(newsdna, type, &cursdna_index_last);
1237
1238                                 /* array! */
1239                                 mul = DNA_elem_array_size(name);
1240                                 nameo = oldsdna->names[sppo[1]];
1241                                 mulo = DNA_elem_array_size(nameo);
1242
1243                                 eleno = elementsize(oldsdna, sppo[0], sppo[1]);
1244
1245                                 elen /= mul;
1246                                 eleno /= mulo;
1247
1248                                 while (mul--) {
1249                                         reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
1250                                         cpo += eleno;
1251                                         cpc += elen;
1252
1253                                         /* new struct array larger than old */
1254                                         mulo--;
1255                                         if (mulo <= 0) break;
1256                                 }
1257                         }
1258                         else {
1259                                 cpc += elen;  /* skip field no longer present */
1260                         }
1261                 }
1262                 else {
1263                         /* non-struct field type */
1264                         reconstruct_elem(newsdna, oldsdna, type, name, cpc, spo, data);
1265                         cpc += elen;
1266                 }
1267         }
1268 }
1269
1270 /**
1271  * Does endian swapping on the fields of a struct value.
1272  *
1273  * \param oldsdna  SDNA of Blender that saved file
1274  * \param oldSDNAnr  Index of struct info within oldsdna
1275  * \param data  Struct data
1276  */
1277 void DNA_struct_switch_endian(const SDNA *oldsdna, int oldSDNAnr, char *data)
1278 {
1279         /* Recursive!
1280          * If element is a struct, call recursive.
1281          */
1282         int a, mul, elemcount, elen, elena, firststructtypenr;
1283         const short *spo, *spc;
1284         char *cur;
1285         const char *type, *name;
1286         unsigned int oldsdna_index_last = UINT_MAX;
1287
1288         if (oldSDNAnr == -1) return;
1289         firststructtypenr = *(oldsdna->structs[0]);
1290
1291         spo = spc = oldsdna->structs[oldSDNAnr];
1292
1293         elemcount = spo[1];
1294
1295         spc += 2;
1296         cur = data;
1297
1298         for (a = 0; a < elemcount; a++, spc += 2) {
1299                 type = oldsdna->types[spc[0]];
1300                 name = oldsdna->names[spc[1]];
1301
1302                 /* elementsize = including arraysize */
1303                 elen = elementsize(oldsdna, spc[0], spc[1]);
1304
1305                 /* test: is type a struct? */
1306                 if (spc[0] >= firststructtypenr && !ispointer(name)) {
1307                         /* struct field type */
1308                         /* where does the old data start (is there one?) */
1309                         char *cpo = (char *)find_elem(oldsdna, type, name, spo, data, NULL);
1310                         if (cpo) {
1311                                 oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last);
1312
1313                                 mul = DNA_elem_array_size(name);
1314                                 elena = elen / mul;
1315
1316                                 while (mul--) {
1317                                         DNA_struct_switch_endian(oldsdna, oldSDNAnr, cpo);
1318                                         cpo += elena;
1319                                 }
1320                         }
1321                 }
1322                 else {
1323                         /* non-struct field type */
1324                         if (ispointer(name)) {
1325                                 if (oldsdna->pointerlen == 8) {
1326                                         BLI_endian_switch_int64_array((int64_t *)cur, DNA_elem_array_size(name));
1327                                 }
1328                         }
1329                         else {
1330                                 if (ELEM(spc[0], SDNA_TYPE_SHORT, SDNA_TYPE_USHORT)) {
1331
1332                                         /* exception: variable called blocktype: derived from ID_  */
1333                                         bool skip = false;
1334                                         if (name[0] == 'b' && name[1] == 'l') {
1335                                                 if (strcmp(name, "blocktype") == 0) skip = true;
1336                                         }
1337
1338                                         if (skip == false) {
1339                                                 BLI_endian_switch_int16_array((int16_t *)cur, DNA_elem_array_size(name));
1340                                         }
1341                                 }
1342                                 else if (ELEM(spc[0], SDNA_TYPE_INT, SDNA_TYPE_FLOAT)) {
1343                                         /* note, intentionally ignore long/ulong here these could be 4 or 8 bits,
1344                                          * but turns out we only used for runtime vars and
1345                                          * only once for a struct type that's no longer used. */
1346
1347                                         BLI_endian_switch_int32_array((int32_t *)cur, DNA_elem_array_size(name));
1348                                 }
1349                                 else if (ELEM(spc[0], SDNA_TYPE_INT64, SDNA_TYPE_UINT64, SDNA_TYPE_DOUBLE)) {
1350                                         BLI_endian_switch_int64_array((int64_t *)cur, DNA_elem_array_size(name));
1351                                 }
1352                         }
1353                 }
1354                 cur += elen;
1355         }
1356 }
1357
1358 /**
1359  * \param newsdna  SDNA of current Blender
1360  * \param oldsdna  SDNA of Blender that saved file
1361  * \param compflags
1362  *
1363  * Result from DNA_struct_get_compareflags to avoid needless conversions
1364  * \param oldSDNAnr  Index of struct info within oldsdna
1365  * \param blocks  The number of array elements
1366  * \param data  Array of struct data
1367  * \return An allocated reconstructed struct
1368  */
1369 void *DNA_struct_reconstruct(
1370         const SDNA *newsdna, const SDNA *oldsdna,
1371         const char *compflags, int oldSDNAnr, int blocks, const void *data)
1372 {
1373         int a, curSDNAnr, curlen = 0, oldlen;
1374         const short *spo, *spc;
1375         char *cur, *cpc;
1376         const char *cpo;
1377         const char *type;
1378
1379         /* oldSDNAnr == structnr, we're looking for the corresponding 'cur' number */
1380         spo = oldsdna->structs[oldSDNAnr];
1381         type = oldsdna->types[spo[0]];
1382         oldlen = oldsdna->typelens[spo[0]];
1383         curSDNAnr = DNA_struct_find_nr(newsdna, type);
1384
1385         /* init data and alloc */
1386         if (curSDNAnr != -1) {
1387                 spc = newsdna->structs[curSDNAnr];
1388                 curlen = newsdna->typelens[spc[0]];
1389         }
1390         if (curlen == 0) {
1391                 return NULL;
1392         }
1393
1394         cur = MEM_callocN(blocks * curlen, "reconstruct");
1395         cpc = cur;
1396         cpo = data;
1397         for (a = 0; a < blocks; a++) {
1398                 reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
1399                 cpc += curlen;
1400                 cpo += oldlen;
1401         }
1402
1403         return cur;
1404 }
1405
1406 /**
1407  * Returns the offset of the field with the specified name and type within the specified
1408  * struct type in sdna.
1409  */
1410 int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const char *name)
1411 {
1412         const int SDNAnr = DNA_struct_find_nr(sdna, stype);
1413         const short * const spo = sdna->structs[SDNAnr];
1414         const char * const cp = find_elem(sdna, vartype, name, spo, NULL, NULL);
1415         BLI_assert(SDNAnr != -1);
1416         return (int)((intptr_t)cp);
1417 }
1418
1419 bool DNA_struct_find(const SDNA *sdna, const char *stype)
1420 {
1421         return DNA_struct_find_nr(sdna, stype) != -1;
1422 }
1423
1424 bool DNA_struct_elem_find(const SDNA *sdna, const char *stype, const char *vartype, const char *name)
1425 {
1426         const int SDNAnr = DNA_struct_find_nr(sdna, stype);
1427
1428         if (SDNAnr != -1) {
1429                 const short * const spo = sdna->structs[SDNAnr];
1430                 const bool found = elem_exists(sdna, vartype, name, spo);
1431
1432                 if (found) {
1433                         return true;
1434                 }
1435         }
1436         return false;
1437 }
1438
1439
1440 /**
1441  * Returns the size in bytes of a primitive type.
1442  */
1443 int DNA_elem_type_size(const eSDNA_Type elem_nr)
1444 {
1445         /* should contain all enum types */
1446         switch (elem_nr) {
1447                 case SDNA_TYPE_CHAR:
1448                 case SDNA_TYPE_UCHAR:
1449                         return 1;
1450                 case SDNA_TYPE_SHORT:
1451                 case SDNA_TYPE_USHORT:
1452                         return 2;
1453                 case SDNA_TYPE_INT:
1454                 case SDNA_TYPE_FLOAT:
1455                         return 4;
1456                 case SDNA_TYPE_DOUBLE:
1457                 case SDNA_TYPE_INT64:
1458                 case SDNA_TYPE_UINT64:
1459                         return 8;
1460         }
1461
1462         /* weak */
1463         return 8;
1464 }