Blender  V2.59
dna_genfile.c
Go to the documentation of this file.
00001 /* dna_genfile.c
00002  *
00003  * Functions for struct-dna, the genetic file dot c!
00004  *
00005  * $Id: dna_genfile.c 36276 2011-04-21 15:53:30Z campbellbarton $
00006  *
00007  * ***** BEGIN GPL LICENSE BLOCK *****
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License
00011  * as published by the Free Software Foundation; either version 2
00012  * of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software Foundation,
00021  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00022  *
00023  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00024  * All rights reserved.
00025  *
00026  * The Original Code is: all of this file.
00027  *
00028  * Contributor(s): none yet.
00029  *
00030  * ***** END GPL LICENSE BLOCK *****
00031  * DNA handling
00032  */
00033 
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <string.h>
00042 
00043 #include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN
00044 
00045 #include "DNA_genfile.h"
00046 #include "DNA_sdna_types.h" // for SDNA ;-)
00047 
00048 
00049 /* gcc 4.1 on mingw was complaining that __int64 was already defined
00050 actually is saw the line below as typedef long long long long... 
00051 Anyhow, since its already defined, its safe to do an ifndef here- Campbell */
00052 #ifdef FREE_WINDOWS
00053 #ifndef __int64
00054 typedef long long __int64;
00055 #endif
00056 #endif
00057 
00058 /*
00059  * - please note: no builtin security to detect input of double structs
00060  * - if you want a struct not to be in DNA file: add two hash marks above it (#<enter>#<enter>)
00061 
00062 Structure DNA data is added to each blender file and to each executable, this to detect
00063 in .blend files new veriables in structs, changed array sizes, etc. It's also used for
00064 converting endian and pointer size (32-64 bits)
00065 As an extra, Python uses a call to detect run-time the contents of a blender struct.
00066 
00067 Create a structDNA: only needed when one of the input include (.h) files change.
00068 File Syntax:
00069         SDNA (4 bytes) (magic number)
00070         NAME (4 bytes)
00071         <nr> (4 bytes) amount of names (int)
00072         <string> 
00073         <string>
00074         ...
00075         ...
00076         TYPE (4 bytes)
00077         <nr> amount of types (int)
00078         <string>
00079         <string>
00080         ...
00081         ...
00082         TLEN (4 bytes)
00083         <len> (short) the lengths of types
00084         <len>
00085         ...
00086         ...
00087         STRC (4 bytes)
00088         <nr> amount of structs (int)
00089         <typenr><nr_of_elems> <typenr><namenr> <typenr><namenr> ...
00090         
00091 !!Remember to read/write integer and short aligned!!
00092 
00093  While writing a file, the names of a struct is indicated with a type number,
00094  to be found with: type= findstruct_nr(SDNA *, char *)
00095  The value of 'type' corresponds with the the index within the structs array
00096 
00097  For the moment: the complete DNA file is included in a .blend file. For
00098  the future we can think of smarter methods, like only included the used
00099  structs. Only needed to keep a file short though...
00100 
00101 ALLOWED AND TESTED CHANGES IN STRUCTS:
00102  - type change (a char to float will be divided by 255)
00103  - location within a struct (everthing can be randomly mixed up)
00104  - struct within struct (within struct etc), this is recursive
00105  - adding new elements, will be default initialized zero
00106  - remving elements
00107  - change of array sizes
00108  - change of a pointer type: when the name doesn't change the contents is copied
00109 
00110 NOT YET:
00111  - array (vec[3]) to float struct (vec3f)
00112 
00113 DONE:
00114  - endian compatibility
00115  - pointer conversion (32-64 bits)
00116 
00117 IMPORTANT:
00118  - do not use #defines in structs for array lengths, this cannot be read by the dna functions
00119  - do not use uint, but unsigned int instead, ushort and ulong are allowed
00120  - only use a long in Blender if you want this to be the size of a pointer. so it is
00121    32 bits or 64 bits, dependant at the cpu architecture
00122  - chars are always unsigned
00123  - aligment of variables has to be done in such a way, that any system does
00124    not create 'padding' (gaps) in structures. So make sure that:
00125    - short: 2 aligned
00126    - int: 4 aligned
00127    - float: 4 aligned
00128    - double: 8 aligned
00129    - long: 8 aligned
00130    - struct: 8 aligned
00131  - the sdna functions have several error prints builtin, always check blender running from a console.
00132  
00133 */
00134 
00135 /* local */
00136 static int le_int(int temp);
00137 static short le_short(short temp);
00138 
00139 /* ************************* ENDIAN STUFF ********************** */
00140 
00141 static short le_short(short temp)
00142 {
00143         short new;
00144         char *rt=(char *)&temp, *rtn=(char *)&new;
00145 
00146         rtn[0]= rt[1];
00147         rtn[1]= rt[0];
00148 
00149         return new;
00150 }
00151 
00152 
00153 static int le_int(int temp)
00154 {
00155         int new;
00156         char *rt=(char *)&temp, *rtn=(char *)&new;
00157 
00158         rtn[0]= rt[3];
00159         rtn[1]= rt[2];
00160         rtn[2]= rt[1];
00161         rtn[3]= rt[0];
00162 
00163         return new;
00164 }
00165 
00166 
00167 /* ************************* MAKE DNA ********************** */
00168 
00169 /* allowed duplicate code from makesdna.c */
00170 int DNA_elem_array_size(const char *astr, int len)
00171 {
00172         int a, mul=1;
00173         char str[100], *cp= NULL;
00174 
00175         memcpy(str, astr, len+1);
00176 
00177         for(a=0; a<len; a++) {
00178                 if( str[a]== '[' ) {
00179                         cp= &(str[a+1]);
00180                 }
00181                 else if( str[a]==']' && cp) {
00182                         str[a]= 0;
00183                         mul*= atoi(cp);
00184                 }
00185         }
00186 
00187         return mul;
00188 }
00189 
00190 /* ************************* END MAKE DNA ********************** */
00191 
00192 /* ************************* DIV ********************** */
00193 
00194 void DNA_sdna_free(SDNA *sdna)
00195 {
00196         MEM_freeN(sdna->data);
00197         MEM_freeN((void *)sdna->names);
00198         MEM_freeN(sdna->types);
00199         MEM_freeN(sdna->structs);
00200         
00201         MEM_freeN(sdna);
00202 }
00203 
00204 static int ispointer(const char *name)
00205 {
00206         /* check if pointer or function pointer */
00207         return (name[0]=='*' || (name[0]=='(' && name[1]=='*'));
00208 }
00209 
00210 static int elementsize(SDNA *sdna, short type, short name)
00211 /* call with numbers from struct-array */
00212 {
00213         int mul, namelen, len;
00214         const char *cp;
00215         
00216         cp= sdna->names[name];
00217         len= 0;
00218         
00219         namelen= strlen(cp);
00220         /* is it a pointer or function pointer? */
00221         if(ispointer(cp)) {
00222                 /* has the naam an extra length? (array) */
00223                 mul= 1;
00224                 if( cp[namelen-1]==']') mul= DNA_elem_array_size(cp, namelen);
00225                 
00226                 len= sdna->pointerlen*mul;
00227         }
00228         else if( sdna->typelens[type] ) {
00229                 /* has the naam an extra length? (array) */
00230                 mul= 1;
00231                 if( cp[namelen-1]==']') mul= DNA_elem_array_size(cp, namelen);
00232                 
00233                 len= mul*sdna->typelens[type];
00234                 
00235         }
00236         
00237         return len;
00238 }
00239 
00240 #if 0
00241 static void printstruct(SDNA *sdna, short strnr)
00242 {
00243         /* is for debug */
00244         int b, nr;
00245         short *sp;
00246         
00247         sp= sdna->structs[strnr];
00248         
00249         printf("struct %s\n", sdna->types[ sp[0] ]);
00250         nr= sp[1];
00251         sp+= 2;
00252         
00253         for(b=0; b< nr; b++, sp+= 2) {
00254                 printf("   %s %s\n", sdna->types[sp[0]], sdna->names[sp[1]]);
00255         }
00256 }
00257 #endif
00258 
00259 static short *findstruct_name(SDNA *sdna, const char *str)
00260 {
00261         int a;
00262         short *sp= NULL;
00263 
00264 
00265         for(a=0; a<sdna->nr_structs; a++) {
00266 
00267                 sp= sdna->structs[a];
00268                 
00269                 if(strcmp( sdna->types[ sp[0] ], str )==0) return sp;
00270         }
00271         
00272         return NULL;
00273 }
00274 
00275 int DNA_struct_find_nr(SDNA *sdna, const char *str)
00276 {
00277         short *sp= NULL;
00278         int a;
00279 
00280         if(sdna->lastfind<sdna->nr_structs) {
00281                 sp= sdna->structs[sdna->lastfind];
00282                 if(strcmp( sdna->types[ sp[0] ], str )==0) return sdna->lastfind;
00283         }
00284 
00285         for(a=0; a<sdna->nr_structs; a++) {
00286 
00287                 sp= sdna->structs[a];
00288                 
00289                 if(strcmp( sdna->types[ sp[0] ], str )==0) {
00290                         sdna->lastfind= a;
00291                         return a;
00292                 }
00293         }
00294         
00295         return -1;
00296 }
00297 
00298 /* ************************* END DIV ********************** */
00299 
00300 /* ************************* READ DNA ********************** */
00301 
00302 static void init_structDNA(SDNA *sdna, int do_endian_swap)
00303 /* in sdna->data the data, now we convert that to something understandable */
00304 {
00305         int *data, *verg, gravity_fix= -1;
00306         intptr_t nr;
00307         short *sp;
00308         char str[8], *cp;
00309         
00310         verg= (int *)str;
00311         data= (int *)sdna->data;
00312 
00313         strcpy(str, "SDNA");
00314         if( *data == *verg ) {
00315         
00316                 data++;
00317                 
00318                 /* load names array */
00319                 strcpy(str, "NAME");
00320                 if( *data == *verg ) {
00321                         data++;
00322                         
00323                         if(do_endian_swap) sdna->nr_names= le_int(*data);
00324                         else sdna->nr_names= *data;
00325                         
00326                         data++;
00327                         sdna->names= MEM_callocN( sizeof(void *)*sdna->nr_names, "sdnanames");
00328                 }
00329                 else {
00330                         printf("NAME error in SDNA file\n");
00331                         return;
00332                 }
00333                 
00334                 nr= 0;
00335                 cp= (char *)data;
00336                 while(nr<sdna->nr_names) {
00337                         sdna->names[nr]= cp;
00338 
00339                         /* "float gravity [3]" was parsed wrong giving both "gravity" and
00340                            "[3]"  members. we rename "[3]", and later set the type of
00341                            "gravity" to "void" so the offsets work out correct */
00342                         if(*cp == '[' && strcmp(cp, "[3]")==0) {
00343                                 if(nr && strcmp(sdna->names[nr-1], "Cvi") == 0) {
00344                                         sdna->names[nr]= "gravity[3]";
00345                                         gravity_fix= nr;
00346                                 }
00347                         }
00348 
00349                         while( *cp) cp++;
00350                         cp++;
00351                         nr++;
00352                 }
00353                 nr= (intptr_t)cp;               /* prevent BUS error */
00354                 nr= (nr+3) & ~3;
00355                 cp= (char *)nr;
00356                 
00357                 /* load type names array */
00358                 data= (int *)cp;
00359                 strcpy(str, "TYPE");
00360                 if( *data == *verg ) {
00361                         data++;
00362                         
00363                         if(do_endian_swap) sdna->nr_types= le_int(*data);
00364                         else sdna->nr_types= *data;
00365                         
00366                         data++;
00367                         sdna->types= MEM_callocN( sizeof(void *)*sdna->nr_types, "sdnatypes");
00368                 }
00369                 else {
00370                         printf("TYPE error in SDNA file\n");
00371                         return;
00372                 }
00373                 
00374                 nr= 0;
00375                 cp= (char *)data;
00376                 while(nr<sdna->nr_types) {
00377                         sdna->types[nr]= cp;
00378                         
00379                         /* this is a patch, to change struct names without a confict with SDNA */
00380                         /* be careful to use it, in this case for a system-struct (opengl/X) */
00381                         
00382                         if( *cp == 'b') {
00383                                 /* struct Screen was already used by X, 'bScreen' replaces the old IrisGL 'Screen' struct */
00384                                 if( strcmp("bScreen", cp)==0 ) sdna->types[nr]= cp+1;
00385                         }
00386                         
00387                         while( *cp) cp++;
00388                         cp++;
00389                         nr++;
00390                 }
00391                 nr= (intptr_t)cp;               /* prevent BUS error */
00392                 nr= (nr+3) & ~3;
00393                 cp= (char *)nr;
00394                 
00395                 /* load typelen array */
00396                 data= (int *)cp;
00397                 strcpy(str, "TLEN");
00398                 if( *data == *verg ) {
00399                         data++;
00400                         sp= (short *)data;
00401                         sdna->typelens= sp;
00402                         
00403                         if(do_endian_swap) {
00404                                 short a, *spo= sp;
00405                                 
00406                                 a= sdna->nr_types;
00407                                 while(a--) {
00408                                         spo[0]= le_short(spo[0]);
00409                                         spo++;
00410                                 }
00411                         }
00412                         
00413                         sp+= sdna->nr_types;
00414                 }
00415                 else {
00416                         printf("TLEN error in SDNA file\n");
00417                         return;
00418                 }
00419                 if(sdna->nr_types & 1) sp++;    /* prevent BUS error */
00420 
00421                 /* load struct array */
00422                 data= (int *)sp;
00423                 strcpy(str, "STRC");
00424                 if( *data == *verg ) {
00425                         data++;
00426                         
00427                         if(do_endian_swap) sdna->nr_structs= le_int(*data);
00428                         else sdna->nr_structs= *data;
00429                         
00430                         data++;
00431                         sdna->structs= MEM_callocN( sizeof(void *)*sdna->nr_structs, "sdnastrcs");
00432                 }
00433                 else {
00434                         printf("STRC error in SDNA file\n");
00435                         return;
00436                 }
00437                 
00438                 nr= 0;
00439                 sp= (short *)data;
00440                 while(nr<sdna->nr_structs) {
00441                         sdna->structs[nr]= sp;
00442                         
00443                         if(do_endian_swap) {
00444                                 short a;
00445                                 
00446                                 sp[0]= le_short(sp[0]);
00447                                 sp[1]= le_short(sp[1]);
00448                                 
00449                                 a= sp[1];
00450                                 sp+= 2;
00451                                 while(a--) {
00452                                         sp[0]= le_short(sp[0]);
00453                                         sp[1]= le_short(sp[1]);
00454                                         sp+= 2;
00455                                 }
00456                         }
00457                         else {
00458                                 sp+= 2*sp[1]+2;
00459                         }
00460                         
00461                         nr++;
00462                 }
00463 
00464                 /* finally pointerlen: use struct ListBase to test it, never change the size of it! */
00465                 sp= findstruct_name(sdna, "ListBase");
00466                 /* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */
00467                 
00468                 sdna->pointerlen= sdna->typelens[ sp[0] ]/2;
00469 
00470                 if(sp[1]!=2 || (sdna->pointerlen!=4 && sdna->pointerlen!=8)) {
00471                         printf("ListBase struct error! Needs it to calculate pointerize.\n");
00472                         exit(0);
00473                         /* well, at least sizeof(ListBase) is error proof! (ton) */
00474                 }
00475                 
00476                 /* second part of gravity problem, setting "gravity" type to void */
00477                 if(gravity_fix > -1) {
00478                         for(nr=0; nr<sdna->nr_structs; nr++) {
00479                                 sp= sdna->structs[nr];
00480                                 if(strcmp(sdna->types[sp[0]], "ClothSimSettings") == 0)
00481                                         sp[10]= 9;
00482                         }
00483                 }
00484         }
00485 }
00486 
00487 SDNA *DNA_sdna_from_data(void *data, int datalen, int do_endian_swap)
00488 {
00489         SDNA *sdna= MEM_mallocN(sizeof(*sdna), "sdna");
00490         
00491         sdna->lastfind= 0;
00492 
00493         sdna->datalen= datalen;
00494         sdna->data= MEM_mallocN(datalen, "sdna_data");
00495         memcpy(sdna->data, data, datalen);
00496         
00497         init_structDNA(sdna, do_endian_swap);
00498         
00499         return sdna;
00500 }
00501 
00502 /* ******************** END READ DNA ********************** */
00503 
00504 /* ******************* HANDLE DNA ***************** */
00505 
00506 static void recurs_test_compflags(SDNA *sdna, char *compflags, int structnr)
00507 {
00508         int a, b, typenr, elems;
00509         short *sp;
00510         const char *cp;
00511         
00512         /* check all structs, test if it's inside another struct */
00513         sp= sdna->structs[structnr];
00514         typenr= sp[0];
00515         
00516         for(a=0; a<sdna->nr_structs; a++) {
00517                 if(a!=structnr && compflags[a]==1) {
00518                         sp= sdna->structs[a];
00519                         elems= sp[1];
00520                         sp+= 2;
00521                         for(b=0; b<elems; b++, sp+=2) {
00522                                 if(sp[0]==typenr) {
00523                                         cp= sdna->names[ sp[1] ];
00524                                         if(!ispointer(cp)) {
00525                                                 compflags[a]= 2;
00526                                                 recurs_test_compflags(sdna, compflags, a);
00527                                         }
00528                                 }
00529                         }
00530                 }
00531         }
00532         
00533 }
00534 
00535         /* Unsure of exact function - compares the sdna argument to
00536          * newsdna and sets up the information necessary to convert
00537          * data written with a dna of oldsdna to inmemory data with a
00538          * structure defined by the newsdna sdna (I think). -zr
00539          */
00540 
00541 /* well, the function below is just a lookup table to speed
00542  * up reading files. doh! -ton
00543  */
00544 
00545 
00546 char *DNA_struct_get_compareflags(SDNA *sdna, SDNA *newsdna)
00547 {
00548         /* flag: 0: doesn't exist anymore (or not yet)
00549          *       1: is equal
00550          *       2: is different
00551          */
00552         int a, b;
00553         short *spold, *spcur;
00554         const char *str1, *str2;
00555         char *compflags;
00556         
00557         if(sdna->nr_structs==0) {
00558                 printf("error: file without SDNA\n");
00559                 return NULL;
00560         }
00561                 
00562         compflags= MEM_callocN(sdna->nr_structs, "compflags");
00563 
00564         /* we check all structs in 'sdna' and compare them with 
00565          * the structs in 'newsdna'
00566          */
00567         
00568         for(a=0; a<sdna->nr_structs; a++) {
00569                 spold= sdna->structs[a];
00570                 
00571                 /* search for type in cur */
00572                 spcur= findstruct_name(newsdna, sdna->types[spold[0]]);
00573                 
00574                 if(spcur) {
00575                         compflags[a]= 2;
00576                         
00577                         /* compare length and amount of elems */
00578                         if( spcur[1] == spold[1]) {
00579                                 if( newsdna->typelens[spcur[0]] == sdna->typelens[spold[0]] ) {
00580 
00581                                         /* same length, same amount of elems, now per type and name */
00582                                         b= spold[1];
00583                                         spold+= 2;
00584                                         spcur+= 2;
00585                                         while(b > 0) {
00586                                                 str1= newsdna->types[spcur[0]];
00587                                                 str2= sdna->types[spold[0]];
00588                                                 if(strcmp(str1, str2)!=0) break;
00589 
00590                                                 str1= newsdna->names[spcur[1]];
00591                                                 str2= sdna->names[spold[1]];
00592                                                 if(strcmp(str1, str2)!=0) break;
00593 
00594                                                 /* same type and same name, now pointersize */
00595                                                 if(ispointer(str1)) {
00596                                                         if(sdna->pointerlen!=newsdna->pointerlen) break;
00597                                                 }
00598 
00599                                                 b--;
00600                                                 spold+= 2;
00601                                                 spcur+= 2;
00602                                         }
00603                                         if(b==0) compflags[a]= 1;
00604 
00605                                 }
00606                         }
00607                         
00608                 }
00609         }
00610 
00611         /* first struct in util.h is struct Link, this is skipped in compflags (als # 0).
00612          * was a bug, and this way dirty patched! Solve this later....
00613          */
00614         compflags[0]= 1;
00615 
00616         /* Because structs can be inside structs, we recursively
00617          * set flags when a struct is altered
00618          */
00619         for(a=0; a<sdna->nr_structs; a++) {
00620                 if(compflags[a]==2) recurs_test_compflags(sdna, compflags, a);
00621         }
00622         
00623 /*
00624         for(a=0; a<sdna->nr_structs; a++) {
00625                 if(compflags[a]==2) {
00626                         spold= sdna->structs[a];
00627                         printf("changed: %s\n", sdna->types[ spold[0] ]);
00628                 }
00629         }
00630 */
00631 
00632         return compflags;
00633 }
00634 
00635 static void cast_elem(char *ctype, char *otype, const char *name, char *curdata, char *olddata)
00636 {
00637         double val = 0.0;
00638         int arrlen, curlen=1, oldlen=1, ctypenr, otypenr;
00639         
00640         arrlen= DNA_elem_array_size(name, strlen(name));
00641         
00642         /* define otypenr */
00643         if(strcmp(otype, "char")==0 || (strcmp(otype, "const char")==0)) otypenr= 0; 
00644         else if((strcmp(otype, "uchar")==0) || (strcmp(otype, "unsigned char")==0)) otypenr= 1;
00645         else if(strcmp(otype, "short")==0) otypenr= 2; 
00646         else if((strcmp(otype, "ushort")==0)||(strcmp(otype, "unsigned short")==0)) otypenr= 3;
00647         else if(strcmp(otype, "int")==0) otypenr= 4;
00648         else if(strcmp(otype, "long")==0) otypenr= 5;
00649         else if((strcmp(otype, "ulong")==0)||(strcmp(otype, "unsigned long")==0)) otypenr= 6;
00650         else if(strcmp(otype, "float")==0) otypenr= 7;
00651         else if(strcmp(otype, "double")==0) otypenr= 8;
00652         else return;
00653         
00654         /* define ctypenr */
00655         if(strcmp(ctype, "char")==0) ctypenr= 0; 
00656         else if(strcmp(ctype, "const char")==0) ctypenr= 0; 
00657         else if((strcmp(ctype, "uchar")==0)||(strcmp(ctype, "unsigned char")==0)) ctypenr= 1;
00658         else if(strcmp(ctype, "short")==0) ctypenr= 2; 
00659         else if((strcmp(ctype, "ushort")==0)||(strcmp(ctype, "unsigned short")==0)) ctypenr= 3;
00660         else if(strcmp(ctype, "int")==0) ctypenr= 4;
00661         else if(strcmp(ctype, "long")==0) ctypenr= 5;
00662         else if((strcmp(ctype, "ulong")==0)||(strcmp(ctype, "unsigned long")==0)) ctypenr= 6;
00663         else if(strcmp(ctype, "float")==0) ctypenr= 7;
00664         else if(strcmp(ctype, "double")==0) ctypenr= 8;
00665         else return;
00666 
00667         /* define lengths */
00668         if(otypenr < 2) oldlen= 1;
00669         else if(otypenr < 4) oldlen= 2;
00670         else if(otypenr < 8) oldlen= 4;
00671         else oldlen= 8;
00672 
00673         if(ctypenr < 2) curlen= 1;
00674         else if(ctypenr < 4) curlen= 2;
00675         else if(ctypenr < 8) curlen= 4;
00676         else curlen= 8;
00677         
00678         while(arrlen>0) {
00679                 switch(otypenr) {
00680                 case 0:
00681                         val= *olddata; break;
00682                 case 1:
00683                         val= *( (unsigned char *)olddata); break;
00684                 case 2:
00685                         val= *( (short *)olddata); break;
00686                 case 3:
00687                         val= *( (unsigned short *)olddata); break;
00688                 case 4:
00689                         val= *( (int *)olddata); break;
00690                 case 5:
00691                         val= *( (int *)olddata); break;
00692                 case 6:
00693                         val= *( (unsigned int *)olddata); break;
00694                 case 7:
00695                         val= *( (float *)olddata); break;
00696                 case 8:
00697                         val= *( (double *)olddata); break;
00698                 }
00699                 
00700                 switch(ctypenr) {
00701                 case 0:
00702                         *curdata= val; break;
00703                 case 1:
00704                         *( (unsigned char *)curdata)= val; break;
00705                 case 2:
00706                         *( (short *)curdata)= val; break;
00707                 case 3:
00708                         *( (unsigned short *)curdata)= val; break;
00709                 case 4:
00710                         *( (int *)curdata)= val; break;
00711                 case 5:
00712                         *( (int *)curdata)= val; break;
00713                 case 6:
00714                         *( (unsigned int *)curdata)= val; break;
00715                 case 7:
00716                         if(otypenr<2) val/= 255;
00717                         *( (float *)curdata)= val; break;
00718                 case 8:
00719                         if(otypenr<2) val/= 255;
00720                         *( (double *)curdata)= val; break;
00721                 }
00722 
00723                 olddata+= oldlen;
00724                 curdata+= curlen;
00725                 arrlen--;
00726         }
00727 }
00728 
00729 static void cast_pointer(int curlen, int oldlen, const char *name, char *curdata, char *olddata)
00730 {
00731 #ifdef WIN32
00732         __int64 lval;
00733 #else
00734         long long lval;
00735 #endif
00736         int arrlen;
00737         
00738         arrlen= DNA_elem_array_size(name, strlen(name));
00739         
00740         while(arrlen>0) {
00741         
00742                 if(curlen==oldlen) {
00743                         memcpy(curdata, olddata, curlen);
00744                 }
00745                 else if(curlen==4 && oldlen==8) {
00746 #ifdef WIN32                    
00747                         lval= *( (__int64 *)olddata );
00748 #else
00749                         lval= *( (long long *)olddata );
00750 #endif
00751                         *((int *)curdata) = lval>>3;            /* is of course gambling! */
00752                 }
00753                 else if(curlen==8 && oldlen==4) {
00754 #ifdef WIN32
00755                          *( (__int64 *)curdata ) = *((int *)olddata);
00756 #else
00757                          *( (long long *)curdata ) = *((int *)olddata);
00758 #endif
00759                 }
00760                 else {
00761                         /* for debug */
00762                         printf("errpr: illegal pointersize! \n");
00763                 }
00764                 
00765                 olddata+= oldlen;
00766                 curdata+= curlen;
00767                 arrlen--;
00768 
00769         }
00770 }
00771 
00772 static int elem_strcmp(const char *name, const char *oname)
00773 {
00774         int a=0;
00775         
00776         /* strcmp without array part */
00777         
00778         while(1) {
00779                 if(name[a] != oname[a]) return 1;
00780                 if(name[a]=='[') break;
00781                 if(name[a]==0) break;
00782                 a++;
00783         }
00784         if(name[a] != oname[a]) return 1;
00785         return 0;
00786 }
00787 
00788 static char *find_elem(SDNA *sdna, const char *type, const char *name, short *old, char *olddata, short **sppo)
00789 {
00790         int a, elemcount, len;
00791         const char *otype, *oname;
00792         
00793         /* without arraypart, so names can differ: return old namenr and type */
00794         
00795         /* in old is the old struct */
00796         elemcount= old[1];
00797         old+= 2;
00798         for(a=0; a<elemcount; a++, old+=2) {
00799         
00800                 otype= sdna->types[old[0]];
00801                 oname= sdna->names[old[1]];
00802                 
00803                 len= elementsize(sdna, old[0], old[1]);
00804                 
00805                 if( elem_strcmp(name, oname)==0 ) {     /* naam equal */
00806                         if( strcmp(type, otype)==0 ) {  /* type equal */
00807                                 if(sppo) *sppo= old;
00808                                 return olddata;
00809                         }
00810                         
00811                         return NULL;
00812                 }
00813                 
00814                 olddata+= len;
00815         }
00816         return NULL;
00817 }
00818 
00819 static void reconstruct_elem(SDNA *newsdna, SDNA *oldsdna, char *type, const char *name, char *curdata, short *old, char *olddata)
00820 {
00821         /* rules: test for NAME:
00822                         - name equal:
00823                                 - cast type
00824                         - name partially equal (array differs)
00825                                 - type equal: memcpy
00826                                 - types casten
00827            (nzc 2-4-2001 I want the 'unsigned' bit to be parsed as well. Where
00828            can I force this?)
00829         */      
00830         int a, elemcount, len, array, oldsize, cursize, mul;
00831         char *otype;
00832         const char *oname, *cp;
00833         
00834         /* is 'name' an array? */
00835         cp= name;
00836         array= 0;
00837         while( *cp && *cp!='[') {
00838                 cp++; array++;
00839         }
00840         if( *cp!= '[' ) array= 0;
00841         
00842         /* in old is the old struct */
00843         elemcount= old[1];
00844         old+= 2;
00845         for(a=0; a<elemcount; a++, old+=2) {
00846                 otype= oldsdna->types[old[0]];
00847                 oname= oldsdna->names[old[1]];
00848                 len= elementsize(oldsdna, old[0], old[1]);
00849                 
00850                 if( strcmp(name, oname)==0 ) {  /* name equal */
00851                         
00852                         if(ispointer(name)) {   /* pointer of functionpointer afhandelen */
00853                                 cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
00854                         }
00855                         else if( strcmp(type, otype)==0 ) {     /* type equal */
00856                                 memcpy(curdata, olddata, len);
00857                         }
00858                         else cast_elem(type, otype, name, curdata, olddata);
00859 
00860                         return;
00861                 }
00862                 else if(array) {                /* name is an array */
00863 
00864                         if(oname[array]=='[' && strncmp(name, oname, array)==0 ) {                      /* basis equal */
00865                                 
00866                                 cursize= DNA_elem_array_size(name, strlen(name));
00867                                 oldsize= DNA_elem_array_size(oname, strlen(oname));
00868 
00869                                 if(ispointer(name)) {           /* handle pointer or functionpointer */
00870                                         if(cursize>oldsize) cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, oname, curdata, olddata);
00871                                         else cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
00872                                 }
00873                                 else if(name[0]=='*' || strcmp(type, otype)==0 ) {      /* type equal */
00874                                         mul= len/oldsize;
00875                                         mul*= (cursize < oldsize)? cursize: oldsize;
00876                                         memcpy(curdata, olddata, mul);
00877                                         
00878                                         /* terminate strings */
00879                                         if(oldsize > cursize && strcmp(type, "char")==0)
00880                                                 curdata[mul-1]= 0;
00881                                 }
00882                                 else {
00883                                         if(cursize>oldsize) cast_elem(type, otype, oname, curdata, olddata);
00884                                         else cast_elem(type, otype, name, curdata, olddata);
00885                                 }
00886                                 return;
00887                         }
00888                 }
00889                 olddata+= len;
00890         }
00891 }
00892 
00893 static void reconstruct_struct(SDNA *newsdna, SDNA *oldsdna, char *compflags, int oldSDNAnr, char *data, int curSDNAnr, char *cur)
00894 {
00895         /* Recursive!
00896          * Per element from cur_struct, read data from old_struct.
00897          * If element is a struct, call recursive.
00898          */
00899         int a, elemcount, elen, eleno, mul, mulo, firststructtypenr;
00900         short *spo, *spc, *sppo;
00901         char *type, *cpo, *cpc;
00902         const char *name, *nameo;
00903 
00904         if(oldSDNAnr== -1) return;
00905         if(curSDNAnr== -1) return;
00906 
00907         if( compflags[oldSDNAnr]==1 ) {         /* if recursive: test for equal */
00908         
00909                 spo= oldsdna->structs[oldSDNAnr];
00910                 elen= oldsdna->typelens[ spo[0] ];
00911                 memcpy( cur, data, elen);
00912                 
00913                 return;
00914         }
00915 
00916         firststructtypenr= *(newsdna->structs[0]);
00917 
00918         spo= oldsdna->structs[oldSDNAnr];
00919         spc= newsdna->structs[curSDNAnr];
00920 
00921         elemcount= spc[1];
00922 
00923         spc+= 2;
00924         cpc= cur;
00925         for(a=0; a<elemcount; a++, spc+=2) {
00926                 type= newsdna->types[spc[0]];
00927                 name= newsdna->names[spc[1]];
00928                 
00929                 elen= elementsize(newsdna, spc[0], spc[1]);
00930 
00931                 /* test: is type a struct? */
00932                 if(spc[0]>=firststructtypenr  &&  !ispointer(name)) {
00933                 
00934                         /* where does the old struct data start (and is there an old one?) */
00935                         cpo= find_elem(oldsdna, type, name, spo, data, &sppo);
00936                         
00937                         if(cpo) {
00938                                 oldSDNAnr= DNA_struct_find_nr(oldsdna, type);
00939                                 curSDNAnr= DNA_struct_find_nr(newsdna, type);
00940                                 
00941                                 /* array! */
00942                                 mul= DNA_elem_array_size(name, strlen(name));
00943                                 nameo= oldsdna->names[sppo[1]];
00944                                 mulo= DNA_elem_array_size(nameo, strlen(nameo));
00945                                 
00946                                 eleno= elementsize(oldsdna, sppo[0], sppo[1]);
00947                                 
00948                                 elen/= mul;
00949                                 eleno/= mulo;
00950                                 
00951                                 while(mul--) {
00952                                         reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
00953                                         cpo+= eleno;
00954                                         cpc+= elen;
00955                                         
00956                                         /* new struct array larger than old */
00957                                         mulo--;
00958                                         if(mulo<=0) break;
00959                                 }
00960                         }
00961                         else cpc+= elen;
00962                 }
00963                 else {
00964 
00965                         reconstruct_elem(newsdna, oldsdna, type, name, cpc, spo, data);
00966                         cpc+= elen;
00967 
00968                 }
00969         }
00970 }
00971 
00972 void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
00973 {
00974         /* Recursive!
00975          * If element is a struct, call recursive.
00976          */
00977         int a, mul, elemcount, elen, elena, firststructtypenr;
00978         short *spo, *spc, skip;
00979         char *type, *cpo, *cur, cval;
00980         const char *name;
00981 
00982         if(oldSDNAnr== -1) return;
00983         firststructtypenr= *(oldsdna->structs[0]);
00984         
00985         spo= spc= oldsdna->structs[oldSDNAnr];
00986 
00987         elemcount= spo[1];
00988 
00989         spc+= 2;
00990         cur= data;
00991         
00992         for(a=0; a<elemcount; a++, spc+=2) {
00993                 type= oldsdna->types[spc[0]];
00994                 name= oldsdna->names[spc[1]];
00995                 
00996                 /* elementsize = including arraysize */
00997                 elen= elementsize(oldsdna, spc[0], spc[1]);
00998 
00999                 /* test: is type a struct? */
01000                 if(spc[0]>=firststructtypenr  &&  !ispointer(name)) {
01001                         /* where does the old data start (is there one?) */
01002                         cpo= find_elem(oldsdna, type, name, spo, data, NULL);
01003                         if(cpo) {
01004                                 oldSDNAnr= DNA_struct_find_nr(oldsdna, type);
01005                                 
01006                                 mul= DNA_elem_array_size(name, strlen(name));
01007                                 elena= elen/mul;
01008 
01009                                 while(mul--) {
01010                                         DNA_struct_switch_endian(oldsdna, oldSDNAnr, cpo);
01011                                         cpo += elena;
01012                                 }
01013                         }
01014                 }
01015                 else {
01016                         
01017                         if(ispointer(name)) {
01018                                 if(oldsdna->pointerlen==8) {
01019                                         
01020                                         mul= DNA_elem_array_size(name, strlen(name));
01021                                         cpo= cur;
01022                                         while(mul--) {
01023                                                 cval= cpo[0]; cpo[0]= cpo[7]; cpo[7]= cval;
01024                                                 cval= cpo[1]; cpo[1]= cpo[6]; cpo[6]= cval;
01025                                                 cval= cpo[2]; cpo[2]= cpo[5]; cpo[5]= cval;
01026                                                 cval= cpo[3]; cpo[3]= cpo[4]; cpo[4]= cval;
01027                                                 
01028                                                 cpo+= 8;
01029                                         }
01030                                         
01031                                 }
01032                         }
01033                         else {
01034                                 
01035                                 if( spc[0]==2 || spc[0]==3 ) {  /* short-ushort */
01036                                         
01037                                         /* exception: variable called blocktype/ipowin: derived from ID_  */
01038                                         skip= 0;
01039                                         if(name[0]=='b' && name[1]=='l') {
01040                                                 if(strcmp(name, "blocktype")==0) skip= 1;
01041                                         }
01042                                         else if(name[0]=='i' && name[1]=='p') {
01043                                                 if(strcmp(name, "ipowin")==0) skip= 1;
01044                                         }
01045                                         
01046                                         if(skip==0) {
01047                                                 mul= DNA_elem_array_size(name, strlen(name));
01048                                                 cpo= cur;
01049                                                 while(mul--) {
01050                                                         cval= cpo[0];
01051                                                         cpo[0]= cpo[1];
01052                                                         cpo[1]= cval;
01053                                                         cpo+= 2;
01054                                                 }
01055                                         }
01056                                 }
01057                                 else if(spc[0]>3 && spc[0]<8) { /* int-long-ulong-float */
01058 
01059                                         mul= DNA_elem_array_size(name, strlen(name));
01060                                         cpo= cur;
01061                                         while(mul--) {
01062                                                 cval= cpo[0];
01063                                                 cpo[0]= cpo[3];
01064                                                 cpo[3]= cval;
01065                                                 cval= cpo[1];
01066                                                 cpo[1]= cpo[2];
01067                                                 cpo[2]= cval;
01068                                                 cpo+= 4;
01069                                         }
01070                                 }
01071                         }
01072                 }
01073                 cur+= elen;
01074         }
01075 }
01076 
01077 void *DNA_struct_reconstruct(SDNA *newsdna, SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data)
01078 {
01079         int a, curSDNAnr, curlen=0, oldlen;
01080         short *spo, *spc;
01081         char *cur, *type, *cpc, *cpo;
01082         
01083         /* oldSDNAnr == structnr, we're looking for the corresponding 'cur' number */
01084         spo= oldsdna->structs[oldSDNAnr];
01085         type= oldsdna->types[ spo[0] ];
01086         oldlen= oldsdna->typelens[ spo[0] ];
01087         curSDNAnr= DNA_struct_find_nr(newsdna, type);
01088 
01089         /* init data and alloc */
01090         if(curSDNAnr >= 0) {
01091                 spc= newsdna->structs[curSDNAnr];
01092                 curlen= newsdna->typelens[ spc[0] ];
01093         }
01094         if(curlen==0) {
01095                 return NULL;
01096         }
01097 
01098         cur= MEM_callocN( blocks*curlen, "reconstruct");
01099         cpc= cur;
01100         cpo= data;
01101         for(a=0; a<blocks; a++) {
01102                 reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
01103                 cpc+= curlen;
01104                 cpo+= oldlen;
01105         }
01106 
01107         return cur;
01108 }
01109 
01110 int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const char *name)
01111 {
01112         
01113         int SDNAnr= DNA_struct_find_nr(sdna, stype);
01114         short *spo= sdna->structs[SDNAnr];
01115         char *cp= find_elem(sdna, vartype, name, spo, NULL, NULL);
01116         return (int)((intptr_t)cp);
01117 }
01118