This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/blenloader/intern/genfile.c

1103 lines
25 KiB
C
Raw Normal View History

2002-10-12 11:37:38 +00:00
/**
* $Id$
*
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version. The Blender
* Foundation also sells licenses for use in proprietary software under
* the Blender License. See http://www.blender.org/BL/ for information
* about this.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
* DNA handling
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
2002-10-12 11:37:38 +00:00
#ifndef WIN32
#include <unistd.h> // for read close
#else
#include <io.h> // for open close read
#endif
#include <string.h> // strncmp
#include <stdio.h> // for printf
#include <stdlib.h> // for atoi
#include <fcntl.h> // for open O_RDONLY
#include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN
#include "BLI_blenlib.h" // for BLI_filesize
#include "BKE_utildefines.h" // for O_BINARY TRUE MIN2
#include "DNA_sdna_types.h" // for SDNA ;-)
#include "BLO_writefile.h"
#include "BLO_genfile.h"
#include "genfile.h"
/*
* - pas op: geen beveiling tegen dubbele structen
* - struct niet in DNA file: twee hekjes erboven (#<enter>#<enter>)
Aanmaken structDNA: alleen wanneer includes wijzigen.
File Syntax:
SDNA (4 bytes) (voor fileherkenning)
NAME (4 bytes)
<nr> (4 bytes) aantal namen (int)
<string>
<string>
...
...
TYPE (4 bytes)
<nr> aantal types (int)
<string>
<string>
...
...
TLEN (4 bytes)
<len> (short)
<len>
...
...
STRC (4 bytes)
<nr> aantal structen (int)
<typenr><nr_of_elems> <typenr><namenr> <typenr><namenr> ...
!!Denk aan integer en short aligned schrijven/lezen!!
Bij het wegschrijven van files worden namen structen aangegeven
met type= findstruct_nr(SDNA *, char *), 'type' correspondeert met nummer
structarray in structDNA.
Voor het moment: complete DNA file appenden achter blenderfile.
In toekomst nadenken over slimmere methode (alleen gebruikte
structen?, voorgeprepareerde DNA files? (TOT, OB, MAT )
TOEGESTANE EN GETESTE WIJZIGINGEN IN STRUCTS:
- type verandering (bij chars naar float wordt door 255 gedeeld)
- plek in struct (alles kan door elkaar)
- struct in struct (in struct etc, is recursief)
- nieuwe elementen toevoegen (standaard op 0)
- elementen eruit (worden niet meer ingelezen)
- array's groter/kleiner
- verschillende typepointers met zelfde naam worden altijd gekopieerd.
(NOG) NIET:
- float-array (vec[3]) naar struct van floats (vec3f)
GEDAAN:
- DNA file in (achter) blender-executable plakken voor upward
compatibility Gebruikte methode: het makesdna programma schrijft
een c-file met een met spaties gevuld char-array van de juiste
lengte. Makesdna maakt er een .o van en vult de spaties met de
DNA file.
- endian compatibility
- 32 bits en 64 bits pointers
LET OP:
- uint mag niet in een struct, gebruik unsigned int. (backwards
compatibility vanwege 64 bits code!)
- structen moeten altijd (intern) 4/8-aligned en short-aligned zijn.
de SDNA routine test hierop en print duidelijke errors.
DNA files met align errors zijn onbruikbaar!
- switch_endian doet alleen long long pointers,
zodat ze veilig gecast kunnen worden naar 32 bits
- casten van 64 naar 32 bits poinetrs: >>3.
*/
/* local */
static int le_int(int temp);
static short le_short(short temp);
/* ************************* ENDIAN STUFF ********************** */
static short le_short(short temp)
{
short new;
char *rt=(char *)&temp, *rtn=(char *)&new;
rtn[0]= rt[1];
rtn[1]= rt[0];
return new;
}
static int le_int(int temp)
{
int new;
char *rt=(char *)&temp, *rtn=(char *)&new;
rtn[0]= rt[3];
rtn[1]= rt[2];
rtn[2]= rt[1];
rtn[3]= rt[0];
return new;
}
/* ************************* MAKEN DNA ********************** */
/* allowed duplicate code from makesdna.c */
static int arraysize(char *astr, int len)
{
int a, mul=1;
char str[100], *cp=0;
memcpy(str, astr, len+1);
for(a=0; a<len; a++) {
if( str[a]== '[' ) {
cp= &(str[a+1]);
}
else if( str[a]==']' && cp) {
str[a]= 0;
mul*= atoi(cp);
}
}
return mul;
}
/* ************************* END MAKEN DNA ********************** */
/* ************************* DIV ********************** */
void dna_freestructDNA(struct SDNA *sdna)
{
MEM_freeN(sdna->data);
MEM_freeN(sdna->names);
MEM_freeN(sdna->types);
MEM_freeN(sdna->structs);
MEM_freeN(sdna);
}
static int elementsize(struct SDNA *sdna, short type, short name)
/* aanroepen met nummers uit struct-array */
{
int mul, namelen, len;
char *cp;
cp= sdna->names[name];
len= 0;
namelen= strlen(cp);
/* is het een pointer of functiepointer? */
if(cp[0]=='*' || cp[1]=='*') {
/* heeft de naam een extra lente? (array) */
mul= 1;
if( cp[namelen-1]==']') mul= arraysize(cp, namelen);
len= sdna->pointerlen*mul;
}
else if( sdna->typelens[type] ) {
/* heeft de naam een extra lente? (array) */
mul= 1;
if( cp[namelen-1]==']') mul= arraysize(cp, namelen);
len= mul*sdna->typelens[type];
}
return len;
}
#if 0
static void printstruct(struct SDNA *sdna, short strnr)
{
/* geef het structnummer door, is voor debug */
int b, nr;
short *sp;
sp= sdna->structs[strnr];
printf("struct %s\n", sdna->types[ sp[0] ]);
nr= sp[1];
sp+= 2;
for(b=0; b< nr; b++, sp+= 2) {
printf(" %s %s\n", sdna->types[sp[0]], sdna->names[sp[1]]);
}
}
#endif
static short *findstruct_name(struct SDNA *sdna, char *str)
{
int a;
short *sp=0;
for(a=0; a<sdna->nr_structs; a++) {
sp= sdna->structs[a];
if(strcmp( sdna->types[ sp[0] ], str )==0) return sp;
}
return 0;
}
int dna_findstruct_nr(struct SDNA *sdna, char *str)
{
short *sp=0;
int a;
if(sdna->lastfind<sdna->nr_structs) {
sp= sdna->structs[sdna->lastfind];
if(strcmp( sdna->types[ sp[0] ], str )==0) return sdna->lastfind;
}
for(a=0; a<sdna->nr_structs; a++) {
sp= sdna->structs[a];
if(strcmp( sdna->types[ sp[0] ], str )==0) {
sdna->lastfind= a;
return a;
}
}
return -1;
}
/* ************************* END DIV ********************** */
/* ************************* LEZEN DNA ********************** */
static void init_structDNA(struct SDNA *sdna, int do_endian_swap)
/* in sdna->data staat de data, uit elkaar pulken */
{
int *data, *verg;
long nr;
short *sp;
char str[8], *cp;
verg= (int *)str;
data= (int *)sdna->data;
strcpy(str, "SDNA");
if( *data == *verg ) {
data++;
/* laad namen array */
strcpy(str, "NAME");
if( *data == *verg ) {
data++;
if(do_endian_swap) sdna->nr_names= le_int(*data);
else sdna->nr_names= *data;
data++;
sdna->names= MEM_callocN( sizeof(void *)*sdna->nr_names, "sdnanames");
}
else {
printf("NAME error in SDNA file\n");
return;
}
nr= 0;
cp= (char *)data;
while(nr<sdna->nr_names) {
sdna->names[nr]= cp;
while( *cp) cp++;
cp++;
nr++;
}
nr= (long)cp; /* BUS error voorkomen */
nr= (nr+3) & ~3;
cp= (char *)nr;
/* laad typenamen array */
data= (int *)cp;
strcpy(str, "TYPE");
if( *data == *verg ) {
data++;
if(do_endian_swap) sdna->nr_types= le_int(*data);
else sdna->nr_types= *data;
data++;
sdna->types= MEM_callocN( sizeof(void *)*sdna->nr_types, "sdnatypes");
}
else {
printf("TYPE error in SDNA file\n");
return;
}
nr= 0;
cp= (char *)data;
while(nr<sdna->nr_types) {
sdna->types[nr]= cp;
/* met deze patch kunnen structnamen gewijzigd worden */
/* alleen gebruiken voor conflicten met systeem-structen (opengl/X) */
if( *cp == 'b') {
/* struct Screen was already used by X, 'bScreen' replaces the old IrisGL 'Screen' struct */
if( strcmp("bScreen", cp)==0 ) sdna->types[nr]= cp+1;
}
while( *cp) cp++;
cp++;
nr++;
}
nr= (long)cp; /* BUS error voorkomen */
nr= (nr+3) & ~3;
cp= (char *)nr;
/* laad typelen array */
data= (int *)cp;
strcpy(str, "TLEN");
if( *data == *verg ) {
data++;
sp= (short *)data;
sdna->typelens= sp;
if(do_endian_swap) {
short a, *spo= sp;
a= sdna->nr_types;
while(a--) {
spo[0]= le_short(spo[0]);
spo++;
}
}
sp+= sdna->nr_types;
}
else {
printf("TLEN error in SDNA file\n");
return;
}
if(sdna->nr_types & 1) sp++; /* BUS error voorkomen */
/* laad structen array */
data= (int *)sp;
strcpy(str, "STRC");
if( *data == *verg ) {
data++;
if(do_endian_swap) sdna->nr_structs= le_int(*data);
else sdna->nr_structs= *data;
data++;
sdna->structs= MEM_callocN( sizeof(void *)*sdna->nr_structs, "sdnastrcs");
}
else {
printf("STRC error in SDNA file\n");
return;
}
nr= 0;
sp= (short *)data;
while(nr<sdna->nr_structs) {
sdna->structs[nr]= sp;
if(do_endian_swap) {
short a;
sp[0]= le_short(sp[0]);
sp[1]= le_short(sp[1]);
a= sp[1];
sp+= 2;
while(a--) {
sp[0]= le_short(sp[0]);
sp[1]= le_short(sp[1]);
sp+= 2;
}
}
else {
sp+= 2*sp[1]+2;
}
nr++;
}
/* finally pointerlen: use struct ListBase to test it, never change the size of it! */
sp= findstruct_name(sdna, "ListBase");
sdna->pointerlen= sdna->typelens[ sp[0] ]/2;
if(sp[1]!=2 || (sdna->pointerlen!=4 && sdna->pointerlen!=8)) {
printf("ListBase struct error! Needs it to calculate pointerize.\n");
exit(0);
}
}
}
struct SDNA *dna_sdna_from_data(void *data, int datalen, int do_endian_swap)
{
struct SDNA *sdna= MEM_mallocN(sizeof(*sdna), "sdna");
sdna->lastfind= 0;
sdna->datalen= datalen;
sdna->data= MEM_mallocN(datalen, "sdna_data");
memcpy(sdna->data, data, datalen);
init_structDNA(sdna, do_endian_swap);
return sdna;
}
/* XXX, this routine was added because at one
* point I thought using the dna more would be
* nice, but really thats a flawed idea, you
* already know about your memory structures when
* you are compiling no need to redirect that
* through the DNA, the python stuff should be
* changed to not use this routine (a bit
* o' work). - zr
*/
int BLO_findstruct_offset(char *structname, char *member)
{
extern char DNAstr[]; /* DNA.c */
extern int DNAlen;
struct SDNA *sdna;
int a, offset;
short *sp;
sdna= dna_sdna_from_data(DNAstr, DNAlen, 0);
sp= findstruct_name(sdna, structname);
if(sp) {
a= sp[1]; /* aantal elems */
sp+= 2;
offset= 0;
while(a--) {
if(strcmp(sdna->names[sp[1]], member)==0) {
dna_freestructDNA(sdna);
return offset;
}
offset+= elementsize(sdna, sp[0], sp[1]);
sp+= 2;
}
}
dna_freestructDNA(sdna);
return -1;
}
/* ******************** END LEZEN DNA ********************** */
/* ******************* AFHANDELEN DNA ***************** */
static void recurs_test_compflags(struct SDNA *sdna, char *compflags, int structnr)
{
int a, b, typenr, elems;
short *sp;
char *cp;
/* loop alle structen af en test of deze struct in andere zit */
sp= sdna->structs[structnr];
typenr= sp[0];
for(a=0; a<sdna->nr_structs; a++) {
if(a!=structnr && compflags[a]==1) {
sp= sdna->structs[a];
elems= sp[1];
sp+= 2;
for(b=0; b<elems; b++, sp+=2) {
if(sp[0]==typenr) {
cp= sdna->names[ sp[1] ];
if(cp[0]!= '*') {
compflags[a]= 2;
recurs_test_compflags(sdna, compflags, a);
}
}
}
}
}
}
/* Unsure of exact function - compares the sdna argument to
* newsdna and sets up the information necessary to convert
* data written with a dna of oldsdna to inmemory data with a
* structure defined by the newsdna sdna (I think). -zr
*/
char *dna_get_structDNA_compareflags(struct SDNA *sdna, struct SDNA *newsdna)
{
/* flag: 0:bestaat niet meer (of nog niet)
* 1: is gelijk
* 2: is anders
*/
int a, b;
short *spold, *spcur;
char *str1, *str2;
char *compflags;
if(sdna->nr_structs==0) {
printf("error: file without SDNA\n");
return NULL;
}
compflags= MEM_callocN(sdna->nr_structs, "compflags");
/* We lopen alle structs in 'sdna' af, vergelijken ze met
* de structs in 'newsdna'
*/
for(a=0; a<sdna->nr_structs; a++) {
spold= sdna->structs[a];
/* type zoeken in cur */
spcur= findstruct_name(newsdna, sdna->types[spold[0]]);
if(spcur) {
compflags[a]= 2;
/* lengte en aantal elems vergelijken */
if( spcur[1] == spold[1]) {
if( newsdna->typelens[spcur[0]] == sdna->typelens[spold[0]] ) {
/* evenlang en evenveel elems, nu per type en naam */
b= spold[1];
spold+= 2;
spcur+= 2;
while(b > 0) {
str1= newsdna->types[spcur[0]];
str2= sdna->types[spold[0]];
if(strcmp(str1, str2)!=0) break;
str1= newsdna->names[spcur[1]];
str2= sdna->names[spold[1]];
if(strcmp(str1, str2)!=0) break;
/* naam gelijk, type gelijk, nu nog pointersize, dit geval komt haast nooit voor! */
if(str1[0]=='*') {
if(sdna->pointerlen!=newsdna->pointerlen) break;
}
b--;
spold+= 2;
spcur+= 2;
}
if(b==0) compflags[a]= 1;
}
}
}
}
/* eerste struct in util.h is struct Link, deze wordt in de compflags overgeslagen (als # 0).
* Vuile patch! Nog oplossen....
*/
compflags[0]= 1;
/* Aangezien structen in structen kunnen zitten gaan we recursief
* vlaggen zetten als er een struct veranderd is
*/
for(a=0; a<sdna->nr_structs; a++) {
if(compflags[a]==2) recurs_test_compflags(sdna, compflags, a);
}
/*
for(a=0; a<sdna->nr_structs; a++) {
if(compflags[a]==2) {
spold= sdna->structs[a];
printf("changed: %s\n", sdna->types[ spold[0] ]);
}
}
*/
return compflags;
}
static void cast_elem(char *ctype, char *otype, char *name, char *curdata, char *olddata)
{
double val = 0.0;
int arrlen, curlen=1, oldlen=1, ctypenr, otypenr;
arrlen= arraysize(name, strlen(name));
/* otypenr bepalen */
if(strcmp(otype, "char")==0) otypenr= 0;
else if((strcmp(otype, "uchar")==0)||(strcmp(otype, "unsigned char")==0)) otypenr= 1;
else if(strcmp(otype, "short")==0) otypenr= 2;
else if((strcmp(otype, "ushort")==0)||(strcmp(otype, "unsigned short")==0)) otypenr= 3;
else if(strcmp(otype, "int")==0) otypenr= 4;
else if(strcmp(otype, "long")==0) otypenr= 5;
else if((strcmp(otype, "ulong")==0)||(strcmp(otype, "unsigned long")==0)) otypenr= 6;
else if(strcmp(otype, "float")==0) otypenr= 7;
else if(strcmp(otype, "double")==0) otypenr= 8;
else return;
/* ctypenr bepalen */
if(strcmp(ctype, "char")==0) ctypenr= 0;
else if((strcmp(ctype, "uchar")==0)||(strcmp(ctype, "unsigned char")==0)) ctypenr= 1;
else if(strcmp(ctype, "short")==0) ctypenr= 2;
else if((strcmp(ctype, "ushort")==0)||(strcmp(ctype, "unsigned short")==0)) ctypenr= 3;
else if(strcmp(ctype, "int")==0) ctypenr= 4;
else if(strcmp(ctype, "long")==0) ctypenr= 5;
else if((strcmp(ctype, "ulong")==0)||(strcmp(ctype, "unsigned long")==0)) ctypenr= 6;
else if(strcmp(ctype, "float")==0) ctypenr= 7;
else if(strcmp(ctype, "double")==0) ctypenr= 8;
else return;
/* lengtes bepalen */
if(otypenr < 2) oldlen= 1;
else if(otypenr < 4) oldlen= 2;
else if(otypenr < 8) oldlen= 4;
else oldlen= 8;
if(ctypenr < 2) curlen= 1;
else if(ctypenr < 4) curlen= 2;
else if(ctypenr < 8) curlen= 4;
else curlen= 8;
while(arrlen>0) {
switch(otypenr) {
case 0:
val= *olddata; break;
case 1:
val= *( (unsigned char *)olddata); break;
case 2:
val= *( (short *)olddata); break;
case 3:
val= *( (unsigned short *)olddata); break;
case 4:
val= *( (int *)olddata); break;
case 5:
val= *( (int *)olddata); break;
case 6:
val= *( (unsigned int *)olddata); break;
case 7:
val= *( (float *)olddata); break;
case 8:
val= *( (double *)olddata); break;
}
switch(ctypenr) {
case 0:
*curdata= val; break;
case 1:
*( (unsigned char *)curdata)= val; break;
case 2:
*( (short *)curdata)= val; break;
case 3:
*( (unsigned short *)curdata)= val; break;
case 4:
*( (int *)curdata)= val; break;
case 5:
*( (int *)curdata)= val; break;
case 6:
*( (unsigned int *)curdata)= val; break;
case 7:
if(otypenr<2) val/= 255;
*( (float *)curdata)= val; break;
case 8:
if(otypenr<2) val/= 255;
*( (double *)curdata)= val; break;
}
olddata+= oldlen;
curdata+= curlen;
arrlen--;
}
}
static void cast_pointer(int curlen, int oldlen, char *name, char *curdata, char *olddata)
{
#ifdef WIN32
__int64 lval;
#else
long long lval;
#endif
int arrlen;
arrlen= arraysize(name, strlen(name));
while(arrlen>0) {
if(curlen==oldlen) {
memcpy(curdata, olddata, curlen);
}
else if(curlen==4 && oldlen==8) {
#ifdef WIN32
lval= *( (__int64 *)olddata );
#else
lval= *( (long long *)olddata );
#endif
*((int *)curdata) = lval>>3; /* is natuurlijk een beetje een gok! */
}
else if(curlen==8 && oldlen==4) {
#ifdef WIN32
*( (__int64 *)curdata ) = *((int *)olddata);
#else
*( (long long *)curdata ) = *((int *)olddata);
#endif
}
else {
/* voor debug */
printf("errpr: illegal pointersize! \n");
}
olddata+= oldlen;
curdata+= curlen;
arrlen--;
}
}
static int elem_strcmp(char *name, char *oname)
{
int a=0;
/* strcmp without array part */
while(TRUE) {
if(name[a] != oname[a]) return 1;
if(name[a]=='[') break;
if(name[a]==0) break;
a++;
}
if(name[a] != oname[a]) return 1;
return 0;
}
static char *find_elem(struct SDNA *sdna, char *type, char *name, short *old, char *olddata, short **sppo)
{
int a, elemcount, len;
char *otype, *oname;
/* without arraypart, so names can differ: return old namenr and type */
/* in old staat de oude struct */
elemcount= old[1];
old+= 2;
for(a=0; a<elemcount; a++, old+=2) {
otype= sdna->types[old[0]];
oname= sdna->names[old[1]];
len= elementsize(sdna, old[0], old[1]);
if( elem_strcmp(name, oname)==0 ) { /* naam gelijk */
if( strcmp(type, otype)==0 ) { /* type gelijk */
if(sppo) *sppo= old;
return olddata;
}
return 0;
}
olddata+= len;
}
return 0;
}
static void reconstruct_elem(struct SDNA *newsdna, struct SDNA *oldsdna, char *type, char *name, char *curdata, short *old, char *olddata)
{
/* regels: testen op NAAM:
- naam volledig gelijk:
- type casten
- naam gedeeltelijk gelijk (array anders)
- type gelijk: memcpy
- types casten
(nzc 2-4-2001 I want the 'unsigned' bit to be parsed as well. Where
can I force this?
*/
int a, elemcount, len, array, oldsize, cursize, mul;
char *otype, *oname, *cp;
/* is 'name' een array? */
cp= name;
array= 0;
while( *cp && *cp!='[') {
cp++; array++;
}
if( *cp!= '[' ) array= 0;
/* in old staat de oude struct */
elemcount= old[1];
old+= 2;
for(a=0; a<elemcount; a++, old+=2) {
otype= oldsdna->types[old[0]];
oname= oldsdna->names[old[1]];
len= elementsize(oldsdna, old[0], old[1]);
if( strcmp(name, oname)==0 ) { /* naam gelijk */
if( name[0]=='*') { /* pointer afhandelen */
cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
}
else if( strcmp(type, otype)==0 ) { /* type gelijk */
memcpy(curdata, olddata, len);
}
else cast_elem(type, otype, name, curdata, olddata);
return;
}
else if(array) { /* de naam is een array */
if( strncmp(name, oname, array)==0 ) { /* basis gelijk */
cursize= arraysize(name, strlen(name));
oldsize= arraysize(oname, strlen(oname));
if( name[0]=='*') { /* pointer afhandelen */
if(cursize>oldsize) cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, oname, curdata, olddata);
else cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
}
else if(name[0]=='*' || strcmp(type, otype)==0 ) { /* type gelijk */
mul= len/oldsize;
mul*= MIN2(cursize, oldsize);
memcpy(curdata, olddata, mul);
}
else {
if(cursize>oldsize) cast_elem(type, otype, oname, curdata, olddata);
else cast_elem(type, otype, name, curdata, olddata);
}
return;
}
}
olddata+= len;
}
}
static void reconstruct_struct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, char *data, int curSDNAnr, char *cur)
{
/* Recursief!
* Per element van cur_struct data lezen uit old_struct.
* Als element een struct is, recursief aanroepen.
*/
int a, elemcount, elen, eleno, mul, mulo, firststructtypenr;
short *spo, *spc, *sppo;
char *name, *nameo, *type, *cpo, *cpc;
if(oldSDNAnr== -1) return;
if(curSDNAnr== -1) return;
if( compflags[oldSDNAnr]==1 ) { /* bij recurs: testen op gelijk */
spo= oldsdna->structs[oldSDNAnr];
elen= oldsdna->typelens[ spo[0] ];
memcpy( cur, data, elen);
return;
}
firststructtypenr= *(newsdna->structs[0]);
spo= oldsdna->structs[oldSDNAnr];
spc= newsdna->structs[curSDNAnr];
elemcount= spc[1];
spc+= 2;
cpc= cur;
for(a=0; a<elemcount; a++, spc+=2) {
type= newsdna->types[spc[0]];
name= newsdna->names[spc[1]];
elen= elementsize(newsdna, spc[0], spc[1]);
/* testen: is type een struct? */
if(spc[0]>=firststructtypenr && name[0]!='*') {
/* waar start de oude struct data (is ie er wel?) */
cpo= find_elem(oldsdna, type, name, spo, data, &sppo);
if(cpo) {
oldSDNAnr= dna_findstruct_nr(oldsdna, type);
curSDNAnr= dna_findstruct_nr(newsdna, type);
/* array! */
mul= arraysize(name, strlen(name));
nameo= oldsdna->names[sppo[1]];
mulo= arraysize(nameo, strlen(nameo));
eleno= elementsize(oldsdna, sppo[0], sppo[1]);
elen/= mul;
eleno/= mulo;
while(mul--) {
reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
cpo+= eleno;
cpc+= elen;
/* new struct array larger than old */
mulo--;
if(mulo<=0) break;
}
}
else cpc+= elen;
}
else {
reconstruct_elem(newsdna, oldsdna, type, name, cpc, spo, data);
cpc+= elen;
}
}
}
void dna_switch_endian_struct(struct SDNA *oldsdna, int oldSDNAnr, char *data)
{
/* Recursief!
* Als element een struct is, recursief aanroepen.
*/
int a, mul, elemcount, elen, elena, firststructtypenr;
short *spo, *spc, skip;
char *name, *type, *cpo, *cur, cval;
if(oldSDNAnr== -1) return;
firststructtypenr= *(oldsdna->structs[0]);
spo= spc= oldsdna->structs[oldSDNAnr];
elemcount= spo[1];
spc+= 2;
cur= data;
for(a=0; a<elemcount; a++, spc+=2) {
type= oldsdna->types[spc[0]];
name= oldsdna->names[spc[1]];
/* elementsize = including arraysize */
elen= elementsize(oldsdna, spc[0], spc[1]);
/* testen: is type een struct? */
if(spc[0]>=firststructtypenr && name[0]!='*') {
/* waar start de oude struct data (is ie er wel?) */
cpo= find_elem(oldsdna, type, name, spo, data, 0);
if(cpo) {
oldSDNAnr= dna_findstruct_nr(oldsdna, type);
mul= arraysize(name, strlen(name));
elena= elen/mul;
while(mul--) {
dna_switch_endian_struct(oldsdna, oldSDNAnr, cpo);
cpo += elena;
}
}
}
else {
if( name[0]=='*' ) {
if(oldsdna->pointerlen==8) {
mul= arraysize(name, strlen(name));
cpo= cur;
while(mul--) {
cval= cpo[0]; cpo[0]= cpo[7]; cpo[7]= cval;
cval= cpo[1]; cpo[1]= cpo[6]; cpo[6]= cval;
cval= cpo[2]; cpo[2]= cpo[5]; cpo[5]= cval;
cval= cpo[3]; cpo[3]= cpo[4]; cpo[4]= cval;
cpo+= 8;
}
}
}
else {
if( spc[0]==2 || spc[0]==3 ) { /* short-ushort */
/* uitzondering: variable die blocktype/ipowin heet: van ID_ afgeleid */
skip= 0;
if(name[0]=='b' && name[1]=='l') {
if(strcmp(name, "blocktype")==0) skip= 1;
}
else if(name[0]=='i' && name[1]=='p') {
if(strcmp(name, "ipowin")==0) skip= 1;
}
if(skip==0) {
mul= arraysize(name, strlen(name));
cpo= cur;
while(mul--) {
cval= cpo[0];
cpo[0]= cpo[1];
cpo[1]= cval;
cpo+= 2;
}
}
}
else if(spc[0]>3 && spc[0]<8) { /* int-long-ulong-float */
mul= arraysize(name, strlen(name));
cpo= cur;
while(mul--) {
cval= cpo[0];
cpo[0]= cpo[3];
cpo[3]= cval;
cval= cpo[1];
cpo[1]= cpo[2];
cpo[2]= cval;
cpo+= 4;
}
}
}
}
cur+= elen;
}
}
void *dna_reconstruct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data)
{
int a, curSDNAnr, curlen=0, oldlen;
short *spo, *spc;
char *cur, *type, *cpc, *cpo;
/* oldSDNAnr == structnr, we zoeken het corresponderende 'cur' nummer */
spo= oldsdna->structs[oldSDNAnr];
type= oldsdna->types[ spo[0] ];
oldlen= oldsdna->typelens[ spo[0] ];
curSDNAnr= dna_findstruct_nr(newsdna, type);
/* data goedzetten en nieuwe calloc doen */
if(curSDNAnr >= 0) {
spc= newsdna->structs[curSDNAnr];
curlen= newsdna->typelens[ spc[0] ];
}
if(curlen==0) {
return NULL;
}
cur= MEM_callocN( blocks*curlen, "reconstruct");
cpc= cur;
cpo= data;
for(a=0; a<blocks; a++) {
reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
cpc+= curlen;
cpo+= oldlen;
}
return cur;
}