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