0ffc170a5aa65e3d6696469ebf91eb4a58a5a0d6
[blender.git] / source / blender / makesdna / intern / dna_genfile.c
1 /* dna_genfile.c
2  *
3  * Functions for struct-dna, the genetic file dot c!
4  *
5  * $Id$
6  *
7  * ***** BEGIN GPL LICENSE BLOCK *****
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL LICENSE BLOCK *****
31  * DNA handling
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN
39
40 #include "DNA_genfile.h"
41 #include "DNA_sdna_types.h" // for SDNA ;-)
42
43
44 /* gcc 4.1 on mingw was complaining that __int64 was alredy defined
45 actually is saw the line below as typedef long long long long... 
46 Anyhow, since its alredy defined, its safe to do an ifndef here- Cambpell*/
47 #ifdef FREE_WINDOWS
48 #ifndef __int64
49 typedef long long __int64;
50 #endif
51 #endif
52
53 /*
54  * - please note: no builtin security to detect input of double structs
55  * - if you want a struct not to be in DNA file: add two hash marks above it (#<enter>#<enter>)
56
57 Structure DNA data is added to each blender file and to each executable, this to detect
58 in .blend files new veriables in structs, changed array sizes, etc. It's also used for
59 converting endian and pointer size (32-64 bits)
60 As an extra, Python uses a call to detect run-time the contents of a blender struct.
61
62 Create a structDNA: only needed when one of the input include (.h) files change.
63 File Syntax:
64         SDNA (4 bytes) (magic number)
65         NAME (4 bytes)
66         <nr> (4 bytes) amount of names (int)
67         <string> 
68         <string>
69         ...
70         ...
71         TYPE (4 bytes)
72         <nr> amount of types (int)
73         <string>
74         <string>
75         ...
76         ...
77         TLEN (4 bytes)
78         <len> (short) the lengths of types
79         <len>
80         ...
81         ...
82         STRC (4 bytes)
83         <nr> amount of structs (int)
84         <typenr><nr_of_elems> <typenr><namenr> <typenr><namenr> ...
85         
86 !!Remember to read/write integer and short aligned!!
87
88  While writing a file, the names of a struct is indicated with a type number,
89  to be found with: type= findstruct_nr(SDNA *, char *)
90  The value of 'type' corresponds with the the index within the structs array
91
92  For the moment: the complete DNA file is included in a .blend file. For
93  the future we can think of smarter methods, like only included the used
94  structs. Only needed to keep a file short though...
95
96 ALLOWED AND TESTED CHANGES IN STRUCTS:
97  - type change (a char to float will be divided by 255)
98  - location within a struct (everthing can be randomly mixed up)
99  - struct within struct (within struct etc), this is recursive
100  - adding new elements, will be default initialized zero
101  - remving elements
102  - change of array sizes
103  - change of a pointer type: when the name doesn't change the contents is copied
104
105 NOT YET:
106  - array (vec[3]) to float struct (vec3f)
107
108 DONE:
109  - endian compatibility
110  - pointer conversion (32-64 bits)
111
112 IMPORTANT:
113  - do not use #defines in structs for array lenghts, this cannot be read by the dna functions
114  - do not use uint, but unsigned int instead, ushort and ulong are allowed
115  - only use a long in Blender if you want this to be the size of a pointer. so it is
116    32 bits or 64 bits, dependant at the cpu architecture
117  - chars are always unsigned
118  - aligment of variables has to be done in such a way, that any system does
119    not create 'padding' (gaps) in structures. So make sure that:
120    - short: 2 aligned
121    - int: 4 aligned
122    - float: 4 aligned
123    - double: 8 aligned
124    - long: 8 aligned
125    - struct: 8 aligned
126  - the sdna functions have several error prints builtin, always check blender running from a console.
127  
128 */
129
130 /* local */
131 static int le_int(int temp);
132 static short le_short(short temp);
133
134 /* ************************* ENDIAN STUFF ********************** */
135
136 static short le_short(short temp)
137 {
138         short new;
139         char *rt=(char *)&temp, *rtn=(char *)&new;
140
141         rtn[0]= rt[1];
142         rtn[1]= rt[0];
143
144         return new;
145 }
146
147
148 static int le_int(int temp)
149 {
150         int new;
151         char *rt=(char *)&temp, *rtn=(char *)&new;
152
153         rtn[0]= rt[3];
154         rtn[1]= rt[2];
155         rtn[2]= rt[1];
156         rtn[3]= rt[0];
157
158         return new;
159 }
160
161
162 /* ************************* MAKE DNA ********************** */
163
164 /* allowed duplicate code from makesdna.c */
165 int DNA_elem_array_size(const char *astr, int len)
166 {
167         int a, mul=1;
168         char str[100], *cp=0;
169
170         memcpy(str, astr, len+1);
171
172         for(a=0; a<len; a++) {
173                 if( str[a]== '[' ) {
174                         cp= &(str[a+1]);
175                 }
176                 else if( str[a]==']' && cp) {
177                         str[a]= 0;
178                         mul*= atoi(cp);
179                 }
180         }
181
182         return mul;
183 }
184
185 /* ************************* END MAKE DNA ********************** */
186
187 /* ************************* DIV ********************** */
188
189 void DNA_sdna_free(SDNA *sdna)
190 {
191         MEM_freeN(sdna->data);
192         MEM_freeN(sdna->names);
193         MEM_freeN(sdna->types);
194         MEM_freeN(sdna->structs);
195         
196         MEM_freeN(sdna);
197 }
198
199 static int ispointer(char *name)
200 {
201         /* check if pointer or function pointer */
202         return (name[0]=='*' || (name[0]=='(' && name[1]=='*'));
203 }
204
205 static int elementsize(SDNA *sdna, short type, short name)
206 /* call with numbers from struct-array */
207 {
208         int mul, namelen, len;
209         char *cp;
210         
211         cp= sdna->names[name];
212         len= 0;
213         
214         namelen= strlen(cp);
215         /* is it a pointer or function pointer? */
216         if(ispointer(cp)) {
217                 /* has the naam an extra length? (array) */
218                 mul= 1;
219                 if( cp[namelen-1]==']') mul= DNA_elem_array_size(cp, namelen);
220                 
221                 len= sdna->pointerlen*mul;
222         }
223         else if( sdna->typelens[type] ) {
224                 /* has the naam an extra length? (array) */
225                 mul= 1;
226                 if( cp[namelen-1]==']') mul= DNA_elem_array_size(cp, namelen);
227                 
228                 len= mul*sdna->typelens[type];
229                 
230         }
231         
232         return len;
233 }
234
235 #if 0
236 static void printstruct(SDNA *sdna, short strnr)
237 {
238         /* is for debug */
239         int b, nr;
240         short *sp;
241         
242         sp= sdna->structs[strnr];
243         
244         printf("struct %s\n", sdna->types[ sp[0] ]);
245         nr= sp[1];
246         sp+= 2;
247         
248         for(b=0; b< nr; b++, sp+= 2) {
249                 printf("   %s %s\n", sdna->types[sp[0]], sdna->names[sp[1]]);
250         }
251 }
252 #endif
253
254 static short *findstruct_name(SDNA *sdna, char *str)
255 {
256         int a;
257         short *sp=0;
258
259
260         for(a=0; a<sdna->nr_structs; a++) {
261
262                 sp= sdna->structs[a];
263                 
264                 if(strcmp( sdna->types[ sp[0] ], str )==0) return sp;
265         }
266         
267         return 0;
268 }
269
270 int DNA_struct_find_nr(SDNA *sdna, const char *str)
271 {
272         short *sp=0;
273         int a;
274
275         if(sdna->lastfind<sdna->nr_structs) {
276                 sp= sdna->structs[sdna->lastfind];
277                 if(strcmp( sdna->types[ sp[0] ], str )==0) return sdna->lastfind;
278         }
279
280         for(a=0; a<sdna->nr_structs; a++) {
281
282                 sp= sdna->structs[a];
283                 
284                 if(strcmp( sdna->types[ sp[0] ], str )==0) {
285                         sdna->lastfind= a;
286                         return a;
287                 }
288         }
289         
290         return -1;
291 }
292
293 /* ************************* END DIV ********************** */
294
295 /* ************************* READ DNA ********************** */
296
297 static void init_structDNA(SDNA *sdna, int do_endian_swap)
298 /* in sdna->data the data, now we convert that to something understandable */
299 {
300         int *data, *verg;
301         long nr; /* intptr_t 2.48 XXX */
302         short *sp;
303         char str[8], *cp;
304         
305         verg= (int *)str;
306         data= (int *)sdna->data;
307
308         strcpy(str, "SDNA");
309         if( *data == *verg ) {
310         
311                 data++;
312                 
313                 /* load names array */
314                 strcpy(str, "NAME");
315                 if( *data == *verg ) {
316                         data++;
317                         
318                         if(do_endian_swap) sdna->nr_names= le_int(*data);
319                         else sdna->nr_names= *data;
320                         
321                         data++;
322                         sdna->names= MEM_callocN( sizeof(void *)*sdna->nr_names, "sdnanames");
323                 }
324                 else {
325                         printf("NAME error in SDNA file\n");
326                         return;
327                 }
328                 
329                 nr= 0;
330                 cp= (char *)data;
331                 while(nr<sdna->nr_names) {
332                         sdna->names[nr]= cp;
333                         while( *cp) cp++;
334                         cp++;
335                         nr++;
336                 }
337                 nr= (long)cp;           /* prevent BUS error */ /* intptr_t 2.48 XXX */
338                 nr= (nr+3) & ~3;
339                 cp= (char *)nr;
340                 
341                 /* load type names array */
342                 data= (int *)cp;
343                 strcpy(str, "TYPE");
344                 if( *data == *verg ) {
345                         data++;
346                         
347                         if(do_endian_swap) sdna->nr_types= le_int(*data);
348                         else sdna->nr_types= *data;
349                         
350                         data++;
351                         sdna->types= MEM_callocN( sizeof(void *)*sdna->nr_types, "sdnatypes");
352                 }
353                 else {
354                         printf("TYPE error in SDNA file\n");
355                         return;
356                 }
357                 
358                 nr= 0;
359                 cp= (char *)data;
360                 while(nr<sdna->nr_types) {
361                         sdna->types[nr]= cp;
362                         
363                         /* this is a patch, to change struct names without a confict with SDNA */
364                         /* be careful to use it, in this case for a system-struct (opengl/X) */
365                         
366                         if( *cp == 'b') {
367                                 /* struct Screen was already used by X, 'bScreen' replaces the old IrisGL 'Screen' struct */
368                                 if( strcmp("bScreen", cp)==0 ) sdna->types[nr]= cp+1;
369                         }
370                         
371                         while( *cp) cp++;
372                         cp++;
373                         nr++;
374                 }
375                 nr= (long)cp;           /* prevent BUS error */ /* intptr_t 2.48 XXX */
376                 nr= (nr+3) & ~3;
377                 cp= (char *)nr;
378                 
379                 /* load typelen array */
380                 data= (int *)cp;
381                 strcpy(str, "TLEN");
382                 if( *data == *verg ) {
383                         data++;
384                         sp= (short *)data;
385                         sdna->typelens= sp;
386                         
387                         if(do_endian_swap) {
388                                 short a, *spo= sp;
389                                 
390                                 a= sdna->nr_types;
391                                 while(a--) {
392                                         spo[0]= le_short(spo[0]);
393                                         spo++;
394                                 }
395                         }
396                         
397                         sp+= sdna->nr_types;
398                 }
399                 else {
400                         printf("TLEN error in SDNA file\n");
401                         return;
402                 }
403                 if(sdna->nr_types & 1) sp++;    /* prevent BUS error */
404
405                 /* load struct array */
406                 data= (int *)sp;
407                 strcpy(str, "STRC");
408                 if( *data == *verg ) {
409                         data++;
410                         
411                         if(do_endian_swap) sdna->nr_structs= le_int(*data);
412                         else sdna->nr_structs= *data;
413                         
414                         data++;
415                         sdna->structs= MEM_callocN( sizeof(void *)*sdna->nr_structs, "sdnastrcs");
416                 }
417                 else {
418                         printf("STRC error in SDNA file\n");
419                         return;
420                 }
421                 
422                 nr= 0;
423                 sp= (short *)data;
424                 while(nr<sdna->nr_structs) {
425                         sdna->structs[nr]= sp;
426                         
427                         if(do_endian_swap) {
428                                 short a;
429                                 
430                                 sp[0]= le_short(sp[0]);
431                                 sp[1]= le_short(sp[1]);
432                                 
433                                 a= sp[1];
434                                 sp+= 2;
435                                 while(a--) {
436                                         sp[0]= le_short(sp[0]);
437                                         sp[1]= le_short(sp[1]);
438                                         sp+= 2;
439                                 }
440                         }
441                         else {
442                                 sp+= 2*sp[1]+2;
443                         }
444                         
445                         nr++;
446                 }
447                 
448                 /* finally pointerlen: use struct ListBase to test it, never change the size of it! */
449                 sp= findstruct_name(sdna, "ListBase");
450                 /* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */
451                 
452                 sdna->pointerlen= sdna->typelens[ sp[0] ]/2;
453
454                 if(sp[1]!=2 || (sdna->pointerlen!=4 && sdna->pointerlen!=8)) {
455                         printf("ListBase struct error! Needs it to calculate pointerize.\n");
456                         exit(0);
457                         /* well, at least sizeof(ListBase) is error proof! (ton) */
458                 }
459                 
460         }
461 }
462
463 SDNA *DNA_sdna_from_data(void *data, int datalen, int do_endian_swap)
464 {
465         SDNA *sdna= MEM_mallocN(sizeof(*sdna), "sdna");
466         
467         sdna->lastfind= 0;
468
469         sdna->datalen= datalen;
470         sdna->data= MEM_mallocN(datalen, "sdna_data");
471         memcpy(sdna->data, data, datalen);
472         
473         init_structDNA(sdna, do_endian_swap);
474         
475         return sdna;
476 }
477
478 /* ******************** END READ DNA ********************** */
479
480 /* ******************* HANDLE DNA ***************** */
481
482 static void recurs_test_compflags(SDNA *sdna, char *compflags, int structnr)
483 {
484         int a, b, typenr, elems;
485         short *sp;
486         char *cp;
487         
488         /* check all structs, test if it's inside another struct */
489         sp= sdna->structs[structnr];
490         typenr= sp[0];
491         
492         for(a=0; a<sdna->nr_structs; a++) {
493                 if(a!=structnr && compflags[a]==1) {
494                         sp= sdna->structs[a];
495                         elems= sp[1];
496                         sp+= 2;
497                         for(b=0; b<elems; b++, sp+=2) {
498                                 if(sp[0]==typenr) {
499                                         cp= sdna->names[ sp[1] ];
500                                         if(!ispointer(cp)) {
501                                                 compflags[a]= 2;
502                                                 recurs_test_compflags(sdna, compflags, a);
503                                         }
504                                 }
505                         }
506                 }
507         }
508         
509 }
510
511         /* Unsure of exact function - compares the sdna argument to
512          * newsdna and sets up the information necessary to convert
513          * data written with a dna of oldsdna to inmemory data with a
514          * structure defined by the newsdna sdna (I think). -zr
515          */
516
517 /* well, the function below is just a lookup table to speed
518  * up reading files. doh! -ton
519  */
520
521
522 char *DNA_struct_get_compareflags(SDNA *sdna, SDNA *newsdna)
523 {
524         /* flag: 0: doesn't exist anymore (or not yet)
525          *       1: is equal
526          *       2: is different
527          */
528         int a, b;
529         short *spold, *spcur;
530         char *str1, *str2;
531         char *compflags;
532         
533         if(sdna->nr_structs==0) {
534                 printf("error: file without SDNA\n");
535                 return NULL;
536         }
537                 
538         compflags= MEM_callocN(sdna->nr_structs, "compflags");
539
540         /* we check all structs in 'sdna' and compare them with 
541          * the structs in 'newsdna'
542          */
543         
544         for(a=0; a<sdna->nr_structs; a++) {
545                 spold= sdna->structs[a];
546                 
547                 /* search for type in cur */
548                 spcur= findstruct_name(newsdna, sdna->types[spold[0]]);
549                 
550                 if(spcur) {
551                         compflags[a]= 2;
552                         
553                         /* compare length and amount of elems */
554                         if( spcur[1] == spold[1]) {
555                                  if( newsdna->typelens[spcur[0]] == sdna->typelens[spold[0]] ) {
556                                          
557                                          /* same length, same amount of elems, now per type and name */
558                                          b= spold[1];
559                                          spold+= 2;
560                                          spcur+= 2;
561                                          while(b > 0) {
562                                                  str1= newsdna->types[spcur[0]];
563                                                  str2= sdna->types[spold[0]];
564                                                  if(strcmp(str1, str2)!=0) break;
565
566                                                  str1= newsdna->names[spcur[1]];
567                                                  str2= sdna->names[spold[1]];
568                                                  if(strcmp(str1, str2)!=0) break;
569                                                  
570                                                  /* same type and same name, now pointersize */
571                                                  if(ispointer(str1)) {
572                                                          if(sdna->pointerlen!=newsdna->pointerlen) break;
573                                                  }
574                                                  
575                                                  b--;
576                                                  spold+= 2;
577                                                  spcur+= 2;
578                                          }
579                                          if(b==0) compflags[a]= 1;
580
581                                  }
582                         }
583                         
584                 }
585         }
586
587         /* first struct in util.h is struct Link, this is skipped in compflags (als # 0).
588          * was a bug, and this way dirty patched! Solve this later....
589          */
590         compflags[0]= 1;
591
592         /* Because structs can be inside structs, we recursively
593          * set flags when a struct is altered
594          */
595         for(a=0; a<sdna->nr_structs; a++) {
596                 if(compflags[a]==2) recurs_test_compflags(sdna, compflags, a);
597         }
598         
599 /*
600         for(a=0; a<sdna->nr_structs; a++) {
601                 if(compflags[a]==2) {
602                         spold= sdna->structs[a];
603                         printf("changed: %s\n", sdna->types[ spold[0] ]);
604                 }
605         }
606 */
607
608         return compflags;
609 }
610
611 static void cast_elem(char *ctype, char *otype, char *name, char *curdata, char *olddata)
612 {
613         double val = 0.0;
614         int arrlen, curlen=1, oldlen=1, ctypenr, otypenr;
615         
616         arrlen= DNA_elem_array_size(name, strlen(name));
617         
618         /* define otypenr */
619         if(strcmp(otype, "char")==0) otypenr= 0; 
620         else if((strcmp(otype, "uchar")==0)||(strcmp(otype, "unsigned char")==0)) otypenr= 1;
621         else if(strcmp(otype, "short")==0) otypenr= 2; 
622         else if((strcmp(otype, "ushort")==0)||(strcmp(otype, "unsigned short")==0)) otypenr= 3;
623         else if(strcmp(otype, "int")==0) otypenr= 4;
624         else if(strcmp(otype, "long")==0) otypenr= 5;
625         else if((strcmp(otype, "ulong")==0)||(strcmp(otype, "unsigned long")==0)) otypenr= 6;
626         else if(strcmp(otype, "float")==0) otypenr= 7;
627         else if(strcmp(otype, "double")==0) otypenr= 8;
628         else return;
629         
630         /* define ctypenr */
631         if(strcmp(ctype, "char")==0) ctypenr= 0; 
632         else if((strcmp(ctype, "uchar")==0)||(strcmp(ctype, "unsigned char")==0)) ctypenr= 1;
633         else if(strcmp(ctype, "short")==0) ctypenr= 2; 
634         else if((strcmp(ctype, "ushort")==0)||(strcmp(ctype, "unsigned short")==0)) ctypenr= 3;
635         else if(strcmp(ctype, "int")==0) ctypenr= 4;
636         else if(strcmp(ctype, "long")==0) ctypenr= 5;
637         else if((strcmp(ctype, "ulong")==0)||(strcmp(ctype, "unsigned long")==0)) ctypenr= 6;
638         else if(strcmp(ctype, "float")==0) ctypenr= 7;
639         else if(strcmp(ctype, "double")==0) ctypenr= 8;
640         else return;
641
642         /* define lengths */
643         if(otypenr < 2) oldlen= 1;
644         else if(otypenr < 4) oldlen= 2;
645         else if(otypenr < 8) oldlen= 4;
646         else oldlen= 8;
647
648         if(ctypenr < 2) curlen= 1;
649         else if(ctypenr < 4) curlen= 2;
650         else if(ctypenr < 8) curlen= 4;
651         else curlen= 8;
652         
653         while(arrlen>0) {
654                 switch(otypenr) {
655                 case 0:
656                         val= *olddata; break;
657                 case 1:
658                         val= *( (unsigned char *)olddata); break;
659                 case 2:
660                         val= *( (short *)olddata); break;
661                 case 3:
662                         val= *( (unsigned short *)olddata); break;
663                 case 4:
664                         val= *( (int *)olddata); break;
665                 case 5:
666                         val= *( (int *)olddata); break;
667                 case 6:
668                         val= *( (unsigned int *)olddata); break;
669                 case 7:
670                         val= *( (float *)olddata); break;
671                 case 8:
672                         val= *( (double *)olddata); break;
673                 }
674                 
675                 switch(ctypenr) {
676                 case 0:
677                         *curdata= val; break;
678                 case 1:
679                         *( (unsigned char *)curdata)= val; break;
680                 case 2:
681                         *( (short *)curdata)= val; break;
682                 case 3:
683                         *( (unsigned short *)curdata)= val; break;
684                 case 4:
685                         *( (int *)curdata)= val; break;
686                 case 5:
687                         *( (int *)curdata)= val; break;
688                 case 6:
689                         *( (unsigned int *)curdata)= val; break;
690                 case 7:
691                         if(otypenr<2) val/= 255;
692                         *( (float *)curdata)= val; break;
693                 case 8:
694                         if(otypenr<2) val/= 255;
695                         *( (double *)curdata)= val; break;
696                 }
697
698                 olddata+= oldlen;
699                 curdata+= curlen;
700                 arrlen--;
701         }
702 }
703
704 static void cast_pointer(int curlen, int oldlen, char *name, char *curdata, char *olddata)
705 {
706 #ifdef WIN32
707         __int64 lval;
708 #else
709         long long lval;
710 #endif
711         int arrlen;
712         
713         arrlen= DNA_elem_array_size(name, strlen(name));
714         
715         while(arrlen>0) {
716         
717                 if(curlen==oldlen) {
718                         memcpy(curdata, olddata, curlen);
719                 }
720                 else if(curlen==4 && oldlen==8) {
721 #ifdef WIN32                    
722                         lval= *( (__int64 *)olddata );
723 #else
724                         lval= *( (long long *)olddata );
725 #endif
726                         *((int *)curdata) = lval>>3;            /* is of course gambling! */
727                 }
728                 else if(curlen==8 && oldlen==4) {
729 #ifdef WIN32
730                          *( (__int64 *)curdata ) = *((int *)olddata);
731 #else
732                          *( (long long *)curdata ) = *((int *)olddata);
733 #endif
734                 }
735                 else {
736                         /* for debug */
737                         printf("errpr: illegal pointersize! \n");
738                 }
739                 
740                 olddata+= oldlen;
741                 curdata+= curlen;
742                 arrlen--;
743
744         }
745 }
746
747 static int elem_strcmp(char *name, char *oname)
748 {
749         int a=0;
750         
751         /* strcmp without array part */
752         
753         while(1) {
754                 if(name[a] != oname[a]) return 1;
755                 if(name[a]=='[') break;
756                 if(name[a]==0) break;
757                 a++;
758         }
759         if(name[a] != oname[a]) return 1;
760         return 0;
761 }
762
763 static char *find_elem(SDNA *sdna, char *type, char *name, short *old, char *olddata, short **sppo)
764 {
765         int a, elemcount, len;
766         char *otype, *oname;
767         
768         /* without arraypart, so names can differ: return old namenr and type */
769         
770         /* in old is the old struct */
771         elemcount= old[1];
772         old+= 2;
773         for(a=0; a<elemcount; a++, old+=2) {
774         
775                 otype= sdna->types[old[0]];
776                 oname= sdna->names[old[1]];
777                 
778                 len= elementsize(sdna, old[0], old[1]);
779                 
780                 if( elem_strcmp(name, oname)==0 ) {     /* naam equal */
781                         if( strcmp(type, otype)==0 ) {  /* type equal */
782                                 if(sppo) *sppo= old;
783                                 return olddata;
784                         }
785                         
786                         return 0;
787                 }
788                 
789                 olddata+= len;
790         }
791         return 0;
792 }
793
794 static void reconstruct_elem(SDNA *newsdna, SDNA *oldsdna, char *type, char *name, char *curdata, short *old, char *olddata)
795 {
796         /* rules: test for NAME:
797                         - name equal:
798                                 - cast type
799                         - name partially equal (array differs)
800                                 - type equal: memcpy
801                                 - types casten
802            (nzc 2-4-2001 I want the 'unsigned' bit to be parsed as well. Where
803            can I force this?)
804         */      
805         int a, elemcount, len, array, oldsize, cursize, mul;
806         char *otype, *oname, *cp;
807         
808         /* is 'name' an array? */
809         cp= name;
810         array= 0;
811         while( *cp && *cp!='[') {
812                 cp++; array++;
813         }
814         if( *cp!= '[' ) array= 0;
815         
816         /* in old is the old struct */
817         elemcount= old[1];
818         old+= 2;
819         for(a=0; a<elemcount; a++, old+=2) {
820                 otype= oldsdna->types[old[0]];
821                 oname= oldsdna->names[old[1]];
822                 len= elementsize(oldsdna, old[0], old[1]);
823                 
824                 if( strcmp(name, oname)==0 ) {  /* name equal */
825                         
826                         if(ispointer(name)) {   /* pointer of functionpointer afhandelen */
827                                 cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
828                         }
829                         else if( strcmp(type, otype)==0 ) {     /* type equal */
830                                 memcpy(curdata, olddata, len);
831                         }
832                         else cast_elem(type, otype, name, curdata, olddata);
833
834                         return;
835                 }
836                 else if(array) {                /* name is an array */
837
838                         if(oname[array]=='[' && strncmp(name, oname, array)==0 ) {                      /* basis equal */
839                                 
840                                 cursize= DNA_elem_array_size(name, strlen(name));
841                                 oldsize= DNA_elem_array_size(oname, strlen(oname));
842
843                                 if(ispointer(name)) {           /* handle pointer or functionpointer */
844                                         if(cursize>oldsize) cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, oname, curdata, olddata);
845                                         else cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
846                                 }
847                                 else if(name[0]=='*' || strcmp(type, otype)==0 ) {      /* type equal */
848                                         mul= len/oldsize;
849                                         mul*= (cursize < oldsize)? cursize: oldsize;
850                                         memcpy(curdata, olddata, mul);
851                                 }
852                                 else {
853                                         if(cursize>oldsize) cast_elem(type, otype, oname, curdata, olddata);
854                                         else cast_elem(type, otype, name, curdata, olddata);
855                                 }
856                                 return;
857                         }
858                 }
859                 olddata+= len;
860         }
861 }
862
863 static void reconstruct_struct(SDNA *newsdna, SDNA *oldsdna, char *compflags, int oldSDNAnr, char *data, int curSDNAnr, char *cur)
864 {
865         /* Recursive!
866          * Per element from cur_struct, read data from old_struct.
867          * If element is a struct, call recursive.
868          */
869         int a, elemcount, elen, eleno, mul, mulo, firststructtypenr;
870         short *spo, *spc, *sppo;
871         char *name, *nameo, *type, *cpo, *cpc;
872
873         if(oldSDNAnr== -1) return;
874         if(curSDNAnr== -1) return;
875
876         if( compflags[oldSDNAnr]==1 ) {         /* if recursive: test for equal */
877         
878                 spo= oldsdna->structs[oldSDNAnr];
879                 elen= oldsdna->typelens[ spo[0] ];
880                 memcpy( cur, data, elen);
881                 
882                 return;
883         }
884
885         firststructtypenr= *(newsdna->structs[0]);
886
887         spo= oldsdna->structs[oldSDNAnr];
888         spc= newsdna->structs[curSDNAnr];
889
890         elemcount= spc[1];
891
892         spc+= 2;
893         cpc= cur;
894         for(a=0; a<elemcount; a++, spc+=2) {
895                 type= newsdna->types[spc[0]];
896                 name= newsdna->names[spc[1]];
897                 
898                 elen= elementsize(newsdna, spc[0], spc[1]);
899
900                 /* test: is type a struct? */
901                 if(spc[0]>=firststructtypenr  &&  !ispointer(name)) {
902                 
903                         /* where does the old struct data start (and is there an old one?) */
904                         cpo= find_elem(oldsdna, type, name, spo, data, &sppo);
905                         
906                         if(cpo) {
907                                 oldSDNAnr= DNA_struct_find_nr(oldsdna, type);
908                                 curSDNAnr= DNA_struct_find_nr(newsdna, type);
909                                 
910                                 /* array! */
911                                 mul= DNA_elem_array_size(name, strlen(name));
912                                 nameo= oldsdna->names[sppo[1]];
913                                 mulo= DNA_elem_array_size(nameo, strlen(nameo));
914                                 
915                                 eleno= elementsize(oldsdna, sppo[0], sppo[1]);
916                                 
917                                 elen/= mul;
918                                 eleno/= mulo;
919                                 
920                                 while(mul--) {
921                                         reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
922                                         cpo+= eleno;
923                                         cpc+= elen;
924                                         
925                                         /* new struct array larger than old */
926                                         mulo--;
927                                         if(mulo<=0) break;
928                                 }
929                         }
930                         else cpc+= elen;
931                 }
932                 else {
933
934                         reconstruct_elem(newsdna, oldsdna, type, name, cpc, spo, data);
935                         cpc+= elen;
936
937                 }
938         }
939 }
940
941 void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
942 {
943         /* Recursive!
944          * If element is a struct, call recursive.
945          */
946         int a, mul, elemcount, elen, elena, firststructtypenr;
947         short *spo, *spc, skip;
948         char *name, *type, *cpo, *cur, cval;
949
950         if(oldSDNAnr== -1) return;
951         firststructtypenr= *(oldsdna->structs[0]);
952         
953         spo= spc= oldsdna->structs[oldSDNAnr];
954
955         elemcount= spo[1];
956
957         spc+= 2;
958         cur= data;
959         
960         for(a=0; a<elemcount; a++, spc+=2) {
961                 type= oldsdna->types[spc[0]];
962                 name= oldsdna->names[spc[1]];
963                 
964                 /* elementsize = including arraysize */
965                 elen= elementsize(oldsdna, spc[0], spc[1]);
966
967                 /* test: is type a struct? */
968                 if(spc[0]>=firststructtypenr  &&  !ispointer(name)) {
969                         /* where does the old data start (is there one?) */
970                         cpo= find_elem(oldsdna, type, name, spo, data, 0);
971                         if(cpo) {
972                                 oldSDNAnr= DNA_struct_find_nr(oldsdna, type);
973                                 
974                                 mul= DNA_elem_array_size(name, strlen(name));
975                                 elena= elen/mul;
976
977                                 while(mul--) {
978                                         DNA_struct_switch_endian(oldsdna, oldSDNAnr, cpo);
979                                         cpo += elena;
980                                 }
981                         }
982                 }
983                 else {
984                         
985                         if(ispointer(name)) {
986                                 if(oldsdna->pointerlen==8) {
987                                         
988                                         mul= DNA_elem_array_size(name, strlen(name));
989                                         cpo= cur;
990                                         while(mul--) {
991                                                 cval= cpo[0]; cpo[0]= cpo[7]; cpo[7]= cval;
992                                                 cval= cpo[1]; cpo[1]= cpo[6]; cpo[6]= cval;
993                                                 cval= cpo[2]; cpo[2]= cpo[5]; cpo[5]= cval;
994                                                 cval= cpo[3]; cpo[3]= cpo[4]; cpo[4]= cval;
995                                                 
996                                                 cpo+= 8;
997                                         }
998                                         
999                                 }
1000                         }
1001                         else {
1002                                 
1003                                 if( spc[0]==2 || spc[0]==3 ) {  /* short-ushort */
1004                                         
1005                                         /* exception: variable called blocktype/ipowin: derived from ID_  */
1006                                         skip= 0;
1007                                         if(name[0]=='b' && name[1]=='l') {
1008                                                 if(strcmp(name, "blocktype")==0) skip= 1;
1009                                         }
1010                                         else if(name[0]=='i' && name[1]=='p') {
1011                                                 if(strcmp(name, "ipowin")==0) skip= 1;
1012                                         }
1013                                         
1014                                         if(skip==0) {
1015                                                 mul= DNA_elem_array_size(name, strlen(name));
1016                                                 cpo= cur;
1017                                                 while(mul--) {
1018                                                         cval= cpo[0];
1019                                                         cpo[0]= cpo[1];
1020                                                         cpo[1]= cval;
1021                                                         cpo+= 2;
1022                                                 }
1023                                         }
1024                                 }
1025                                 else if(spc[0]>3 && spc[0]<8) { /* int-long-ulong-float */
1026
1027                                         mul= DNA_elem_array_size(name, strlen(name));
1028                                         cpo= cur;
1029                                         while(mul--) {
1030                                                 cval= cpo[0];
1031                                                 cpo[0]= cpo[3];
1032                                                 cpo[3]= cval;
1033                                                 cval= cpo[1];
1034                                                 cpo[1]= cpo[2];
1035                                                 cpo[2]= cval;
1036                                                 cpo+= 4;
1037                                         }
1038                                 }
1039                         }
1040                 }
1041                 cur+= elen;
1042         }
1043 }
1044
1045 void *DNA_struct_reconstruct(SDNA *newsdna, SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data)
1046 {
1047         int a, curSDNAnr, curlen=0, oldlen;
1048         short *spo, *spc;
1049         char *cur, *type, *cpc, *cpo;
1050         
1051         /* oldSDNAnr == structnr, we're looking for the corresponding 'cur' number */
1052         spo= oldsdna->structs[oldSDNAnr];
1053         type= oldsdna->types[ spo[0] ];
1054         oldlen= oldsdna->typelens[ spo[0] ];
1055         curSDNAnr= DNA_struct_find_nr(newsdna, type);
1056
1057         /* init data and alloc */
1058         if(curSDNAnr >= 0) {
1059                 spc= newsdna->structs[curSDNAnr];
1060                 curlen= newsdna->typelens[ spc[0] ];
1061         }
1062         if(curlen==0) {
1063                 return NULL;
1064         }
1065
1066         cur= MEM_callocN( blocks*curlen, "reconstruct");
1067         cpc= cur;
1068         cpo= data;
1069         for(a=0; a<blocks; a++) {
1070                 reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
1071                 cpc+= curlen;
1072                 cpo+= oldlen;
1073         }
1074
1075         return cur;
1076 }
1077
1078 int DNA_elem_offset(SDNA *sdna, char *stype, char *vartype, char *name)
1079 {
1080         
1081         int SDNAnr= DNA_struct_find_nr(sdna, stype);
1082         short *spo= sdna->structs[SDNAnr];
1083         char *cp= find_elem(sdna, vartype, name, spo, NULL, NULL);
1084         return (int)((long)cp); /* intptr_t 2.48 XXX */
1085 }
1086