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