Blender V2.61 - r43446

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