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