/**
 * $Id:$
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * The contents of this file may be used under the terms of either the GNU
 * General Public License Version 2 or later (the "GPL", see
 * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or
 * later (the "BL", see http://www.blender.org/BL/ ) which has to be
 * bought from the Blender Foundation to become active, in which case the
 * above mentioned GPL option does not apply.
 *
 * The Original Code is Copyright (C) 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 *****
 */

/**
 * $Id:$
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * The contents of this file may be used under the terms of either the GNU
 * General Public License Version 2 or later (the "GPL", see
 * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or
 * later (the "BL", see http://www.blender.org/BL/ ) which has to be
 * bought from the Blender Foundation to become active, in which case the
 * above mentioned GPL option does not apply.
 *
 * The Original Code is Copyright (C) 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 *****
 */


/*  genfile.c   juni 94     MIXED MODEL
 * 
 *	- pas op: geen beveiling tegen dubbele structen
 *  - struct niet in DNA file: twee hekjes erboven (#<enter>#<enter>)
 * 
 */


#include "blender.h"
#include "screen.h"
#include "file.h"

/* Internal prototypes */
void calculate_structlens(void);

/*  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.
 */

struct SDNA cur_sdna={0, 0, }, old_sdna={0, 0, };
int maxdata= 100000, maxnr= 5000;
int switch_endian= 0;
int nr_names=0;
int nr_types=0;
int nr_structs=0;
char **names, *namedata;		/* op adres names[a] staat string a */
char **types, *typedata;		/* op adres types[a] staat string a */
short *typelens;				/* op typelens[a] staat de lengte van type a */
short **structs, *structdata;	/* op sp= structs[a] staat eerste adres structdefinitie
								   sp[0] is typenummer
								   sp[1] is aantal elementen
								   sp[2] sp[3] is typenr,  namenr (enz) */

char *compflags=0;

/* ************************* MAKEN DNA ********************** */


int add_type(char *str, int len)
{
	int nr;
	char *cp;
	
	if(str[0]==0) return -1;
	
	/* zoek typearray door */
	for(nr=0; nr<nr_types; nr++) {
		if(strcmp(str, types[nr])==0) {
			if(len) typelens[nr]= len;
			return nr;
		}
	}
	
	/* nieuw type appenden */
	if(nr_types==0) cp= typedata;
	else {
		cp= types[nr_types-1]+strlen(types[nr_types-1])+1;
	}
	strcpy(cp, str);
	types[nr_types]= cp;
	typelens[nr_types]= len;
	
	if(nr_types>=maxnr) {
		printf("too many types\n");
		return nr_types-1;;
	}
	nr_types++;
	
	return nr_types-1;
}

int add_name(char *str)
{
	int nr;
	char *cp;
	
	if(str[0]==0) return -1;
	
	/* zoek name array door */
	for(nr=0; nr<nr_names; nr++) {
		if(strcmp(str, names[nr])==0) {
			return nr;
		}
	}
	
	/* nieuw type appenden */
	if(nr_names==0) cp= namedata;
	else {
		cp= names[nr_names-1]+strlen(names[nr_names-1])+1;
	}
	strcpy(cp, str);
	names[nr_names]= cp;
	
	if(nr_names>=maxnr) {
		printf("too many names\n");
		return nr_names-1;
	}
	nr_names++;
	
	return nr_names-1;
}

short *add_struct(int namecode)
{
	int len;
	short *sp;

	if(nr_structs==0) {
		structs[0]= structdata;
	}
	else {
		sp= structs[nr_structs-1];
		len= sp[1];
		structs[nr_structs]= sp+ 2*len+2;
	}
	
	sp= structs[nr_structs];
	sp[0]= namecode;
	
	if(nr_structs>=maxnr) {
		printf("too many structs\n");
		return sp;
	}
	nr_structs++;
	
	return sp;
}

int preprocess_include(char *maindata, int len)
{
	int a, newlen, comment;
	char *cp, *temp, *md;
	
	temp= mallocN(len, "preprocess_include");
	memcpy(temp, maindata, len);
	
	/* alle enters/tabs/etc vervangen door spaties */
	cp= temp;
	a= len;
	while(a--) {
		if( *cp<32 || *cp>128 ) *cp= 32;
		cp++;
	}
	
	/* data uit temp naar maindata kopieeren, verwijder commentaar en dubbele spaties */
	cp= temp;
	md= maindata;
	newlen= 0;
	comment= 0;
	a= len;
	while(a--) {
		
		if(cp[0]=='/' && cp[1]=='*') {
			comment= 1;
			cp[0]=cp[1]= 32;
		}
		if(cp[0]=='*' && cp[1]=='/') {
			comment= 0;
			cp[0]=cp[1]= 32;
		}

		/* niet kopieeren als: */
		if(comment);
		else if( cp[0]==' ' && cp[1]==' ' );
		else if( cp[-1]=='*' && cp[0]==' ' );	/* pointers met spatie */
		else {
			md[0]= cp[0];
			md++;
			newlen++;
		}
		cp++;
	}
	
	freeN(temp);
	return newlen;
}

void convert_include(char *filename)
{
	/* lees includefile, sla structen over die op regel ervoor '#' hebben.
	   sla alle data op in tijdelijke arrays.
	*/
	int a, file, filelen, count, overslaan, slen, type, name, strct;
	short *structpoin, *sp;
	char *maindata, *mainend, *md, *md1;


	file= open(filename, O_BINARY|O_RDONLY);
	if(file== -1) {
		printf("Can't read file %s\n", filename);
	}
	else {
		filelen= filesize(file);
		
		md= maindata= mallocN(filelen, "convert_include");
		read(file, maindata, filelen);
		close(file);

		filelen= preprocess_include(maindata, filelen);
		mainend= maindata+filelen-1;

		/* we zoeken naar '{' en dan terug naar 'struct' */
		count= 0;
		overslaan= 0;
		while(count<filelen) {
			
			/* code voor struct overslaan: twee hekjes. (voor spatie zorgt preprocess) */
			if(md[0]=='#' && md[1]==' ' && md[2]=='#') {
				overslaan= 1;
			}
			
			if(md[0]=='{') {
				md[0]= 0;
				if(overslaan) {
					overslaan= 0;
				}
				else {
					if(md[-1]==' ') md[-1]= 0;
					md1= md-2;
					while( *md1!=32) md1--;		/* naar begin woord */
					md1++;
					
					/* structnaam te pakken, als... */
					if( strncmp(md1-7, "struct", 6)==0 ) {
						
						strct= add_type(md1, 0);
						structpoin= add_struct(strct);
						sp= structpoin+2;
						
						/* eerst overal keurige strings van maken */
						md1= md+1;
						while(*md1 != '}') {
							if( ((long)md1) > ((long)mainend) ) break;
							
							if(*md1==',' || *md1==' ') *md1= 0;
							md1++;
						}
						
						/* types en namen lezen tot eerste karakter niet '}' */
						md1= md+1;
						while( *md1 != '}' ) {
							if( ((long)md1) > ((long)mainend) ) break;
							
							/* als er 'struct' of 'unsigned' staat, overslaan */
							if(*md1) {
								if( strncmp(md1, "struct", 6)==0 ) md1+= 7;
								if( strncmp(md1, "unsigned", 6)==0 ) md1+= 9;
								
								/* type te pakken! */
								type= add_type(md1, 0);
								
								md1+= strlen(md1);
								
								/* doorlezen tot ';' */
								while( *md1 != ';' ) {
									if( ((long)md1) > ((long)mainend) ) break;
									
									if(*md1) {
										/* name te pakken */
										slen= strlen(md1);
										if( md1[slen-1]==';' ) {
											md1[slen-1]= 0;

											name= add_name(md1);
											sp[0]= type;
											sp[1]= name;
											structpoin[1]++;
											sp+= 2;
											
											md1+= slen;
											break;
										}
										
										name= add_name(md1);
										sp[0]= type;
										sp[1]= name;
										structpoin[1]++;
										sp+= 2;
										
										md1+= slen;
									}
									md1++;
								}
							}
							md1++;
						}
					}
				}
			}
			count++;
			md++;
		}
		
		freeN(maindata);	
	}	
}

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;
}

void calculate_structlens()
{
	int a, b, len, unknown= nr_structs, lastunknown, structtype, type, mul, namelen;
	short *sp, *structpoin;
	char *cp;
	
	cur_sdna.pointerlen= sizeof(void *);
	
	while(unknown) {
		lastunknown= unknown;
		unknown= 0;
		
		/* loop alle structen af... */
		for(a=0; a<nr_structs; a++) {
			structpoin= structs[a];
			structtype= structpoin[0];

			/* als lengte nog niet bekend */
			if(typelens[structtype]==0) {
				
				sp= structpoin+2;
				len= 0;
				
				/* loop alle elementen in struct af */
				for(b=0; b<structpoin[1]; b++, sp+=2) {
					type= sp[0];
					cp= names[sp[1]];
					
					namelen= strlen(cp);
					/* is het een pointer of functiepointer? */
					if(cp[0]=='*' || cp[1]=='*') {
						/* heeft de naam een extra lengte? (array) */
						mul= 1;
						if( cp[namelen-1]==']') mul= arraysize(cp, namelen);
						
						/* 4-8 aligned/ */
						if(cur_sdna.pointerlen==4) {
							if(len % 4) {
								printf("Align pointer error in struct: %s %s\n", types[structtype], cp);
							}
						}
						else {
							if(len % 8) {
								printf("Align pointer error in struct: %s %s\n", types[structtype], cp);
							}
						}
						len+= cur_sdna.pointerlen*mul;
					}
					else if( typelens[type] ) {
						/* heeft de naam een extra lente? (array) */
						mul= 1;
						if( cp[namelen-1]==']') mul= arraysize(cp, namelen);
						
						/* 2-4 aligned/ */
						if(typelens[type]>3 && (len % 4) ) {
							printf("Align 4 error in struct: %s %s\n", types[structtype], cp);
						}
						else if(typelens[type]==2 && (len % 2) ) {
							printf("Align 2 error in struct: %s %s\n", types[structtype], cp);
						}

						len+= mul*typelens[type];
						
					}
					else {
						len= 0;
						break;
					}
				}
				
				if(len==0) unknown++;
				else {
					typelens[structtype]= len;
				}
			}
		}
		
		if(unknown==lastunknown) break;
	}
	
	if(unknown) {
		printf("error: still %d structs unknown\n", unknown);
		
		for(a=0; a<nr_structs; a++) {
			structpoin= structs[a];
			structtype= structpoin[0];

			/* lengte nog niet bekend */
			if(typelens[structtype]==0) {
				printf("  %s\n", types[structtype]);
			}
		}
	}
}

void make_structDNA()
{
	int a, b, file, len;
	short *sp, elem;
	char str[40], *cp;
	
	/* de allerlangst bekende struct is 50k, 100k is ruimte genoeg! */
	namedata= callocN(maxdata, "namedata");
	typedata= callocN(maxdata, "typedata");
	structdata= callocN(maxdata, "structdata");
	
	/* maximaal 5000 variablen, vast voldoende? */
	names= callocN(sizeof(char *)*maxnr, "names");
	types= callocN(sizeof(char *)*maxnr, "types");
	typelens= callocN(sizeof(short)*maxnr, "typelens");
	structs= callocN(sizeof(short)*maxnr, "structs");
	
	/* inserten alle bekende types */
	/* let op: uint komt niet voor! gebruik in structen unsigned int */
	add_type("char", 1);	/* 0 */
	add_type("uchar", 1);	/* 1 */
	add_type("short", 2);	/* 2 */
	add_type("ushort", 2);	/* 3 */
	add_type("int", 4);		/* 4 */
	add_type("long", 4);	/* 5 */
	add_type("ulong", 4);	/* 6 */
	add_type("float", 4);	/* 7 */
	add_type("double", 8);	/* 8 */
	
	/* eerste struct in util.h is struct Link, deze wordt in de compflags overgeslagen (als # 0).
	 * Vuile patch! Nog oplossen....
	 */

#ifdef IRISGL

#ifdef NINCLUDES
#define BASE_HEADER "../include/"
#else
#ifdef MIPS1
#define BASE_HEADER "./"
#else
#define BASE_HEADER "../"
#endif
#endif

#else

#ifdef WIN32
#define BASE_HEADER "p:\\blend\\opengl\\include\\"
#else
#define BASE_HEADER "../include/"
#endif

#endif

	convert_include(BASE_HEADER "util.h");
	convert_include(BASE_HEADER "blender.h");
	convert_include(BASE_HEADER "screen.h");
	convert_include(BASE_HEADER "file.h");
	convert_include(BASE_HEADER "sequence.h");
	convert_include(BASE_HEADER "effect.h");
	convert_include(BASE_HEADER "sector.h");
	convert_include(BASE_HEADER "ika.h");
	convert_include(BASE_HEADER "oops.h");
	convert_include(BASE_HEADER "imasel.h");

	calculate_structlens();

	/* DIT DEEL VOOR DEBUG */
	/*
	printf("nr_names %d nr_types %d nr_structs %d\n", nr_names, nr_types, nr_structs);
	for(a=0; a<nr_names; a++) { 
		printf(" %s \n", names[a]);
	}
	printf("\n");
	
	sp= typelens;
	for(a=0; a<nr_types; a++, sp++) { 
		printf(" %s %d\n", types[a], *sp);
	}
	printf("\n");
	
	for(a=0; a<nr_structs; a++) {
		sp= structs[a];
		printf(" struct %s elems: %d \n", types[sp[0]], sp[1]);
		elem= sp[1];
		sp+= 2;
		for(b=0; b< elem; b++, sp+= 2) {
			printf("   %s %s\n", types[sp[0]], names[sp[1]]);
		}
	}
	*/
	
	/* file schrijven */
	
	if(nr_names==0 || nr_structs==0);
	else {
		
		file= open("DNA", O_BINARY|O_WRONLY+O_CREAT+O_TRUNC, 0666);
		
		if(file== -1) {
			printf("Can't write file\n");
		}
		else {
	
			strcpy(str, "SDNA");
			write(file, str, 4);
			
			/* SCHRIJF NAMEN */
			strcpy(str, "NAME");
			write(file, str, 4);
			len= nr_names;
			write(file, &len, 4);
			
			/* lengte berekenen datablok met strings */
			cp= names[nr_names-1];
			cp+= strlen(names[nr_names-1]) + 1;			/* +1: nul-terminator */
			len= (long)cp - (long)(names[0]);
			len= (len+3) & ~3;
			write(file, names[0], len);
			
			/* SCHRIJF TYPES */
			strcpy(str, "TYPE");
			write(file, str, 4);
			len= nr_types;
			write(file, &len, 4);
	
			/* lengte berekenen datablok */
			cp= types[nr_types-1];
			cp+= strlen(types[nr_types-1]) + 1;		/* +1: nul-terminator */
			len= (long)cp - (long)(types[0]);
			len= (len+3) & ~3;
			
			write(file, types[0], len);
			
			/* SCHRIJF TYPELENGTES */
			strcpy(str, "TLEN");
			write(file, str, 4);
			
			len= 2*nr_types;
			if(nr_types & 1) len+= 2;
			write(file, typelens, len);
			
			/* SCHRIJF STRUCTEN */
			strcpy(str, "STRC");
			write(file, str, 4);
			len= nr_structs;
			write(file, &len, 4);
	
			/* lengte berekenen datablok */
			sp= structs[nr_structs-1];
			sp+= 2+ 2*( sp[1] );
			len= (long)sp - (long)(structs[0]);
			len= (len+3) & ~3;
			
			write(file, structs[0], len);
			
			
			close(file);
			
			printf("saved: DNA\n");
		}
		
		/* dna padding test */
		/*
		{
			FILE *fp;
			
			fp= fopen("rt", "w");
			if(fp==NULL);
			else {

				sp= typelens;
				for(a=0; a<nr_types; a++, sp++) { 
					fprintf(fp, "printf(\" ");
					fprintf(fp, " %s %d ", types[a], *sp);
					fprintf(fp, "%cd \\n\",  sizeof(struct %s) );\n", '%', types[a]);
				}
				fclose(fp);
			}
		}
		*/
	}
	
	
	freeN(namedata);
	freeN(typedata);
	freeN(structdata);
	freeN(names);
	freeN(types);
	freeN(typelens);
	freeN(structs);
}

/* ************************* END MAKEN DNA ********************** */
/* ************************* DIV ********************** */

void freestructDNA(struct SDNA *sdna)
{
	if(sdna->data) {
		freeN(sdna->data);
		sdna->data= 0;
		freeN(sdna->names);
		sdna->names= 0;
		freeN(sdna->types);
		sdna->types= 0;
		freeN(sdna->structs);
		sdna->structs= 0;
	}
}

void freestructDNA_all()
{

	freestructDNA(&old_sdna);

	if(cur_sdna.data) {
		freeN(cur_sdna.names);
		cur_sdna.names= 0;
		freeN(cur_sdna.types);
		cur_sdna.types= 0;
		freeN(cur_sdna.structs);
		cur_sdna.structs= 0;
	}

	if(compflags) freeN(compflags);
	compflags= 0;
}

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;
}

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]]);
	}
}


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 findstruct_nr(struct SDNA *sdna, char *str)
{
	static int lasta=0;
	int a;
	short *sp=0;

	if(lasta<sdna->nr_structs) {
		sp= sdna->structs[lasta];
		if(strcmp( sdna->types[ sp[0] ], str )==0) return lasta;
	}

	for(a=0; a<sdna->nr_structs; a++) {

		sp= sdna->structs[a];
		
		if(strcmp( sdna->types[ sp[0] ], str )==0) {
			lasta= a;
			return a;
		}
	}
	
	return -1;
}


/* ************************* END DIV ********************** */
/* ************************* LEZEN DNA ********************** */



void init_structDNA(struct SDNA *sdna)
/* in sdna->data staat de data, uit elkaar pulken */
{
	int *data, *verg;
	long nr;
	short *sp;
	static char str[8], *cp;
	
	if(sdna->data==0) {
		bzero(sdna, sizeof(struct SDNA));
		return;
	}
	
	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(switch_endian) sdna->nr_names= le_int(*data);
			else sdna->nr_names= *data;
			
			data++;
			sdna->names= 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(switch_endian) sdna->nr_types= le_int(*data);
			else sdna->nr_types= *data;
			
			data++;
			sdna->types= 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(switch_endian) {
				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(switch_endian) sdna->nr_structs= le_int(*data);
			else sdna->nr_structs= *data;
			
			data++;
			sdna->structs= callocN( sizeof(void *)*sdna->nr_types, "sdnatypes");
		}
		else {
			printf("STRC error in SDNA file\n");
			return;
		}
		
		nr= 0;
		sp= (short *)data;
		while(nr<sdna->nr_structs) {
			sdna->structs[nr]= sp;
			
			if(switch_endian) {
				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! */
		/* the global pointerlen from readfile.c can't be used here... */
		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);
		}
		
	}
}

void read_structDNA(struct SDNA *sdna, char *filename)
{
	int file, filelen;
	
	file= open(filename, O_BINARY|O_RDONLY);
	if(file== -1) {
		printf("Can't read DNA file\n");
	}
	else {
		filelen= filesize(file);
		sdna->datalen= filelen;

		sdna->data= mallocN(filelen, "convert_include");
		read(file, sdna->data, filelen);
		close(file);
		
		init_structDNA(sdna);
	}
}


void findstruct_ext(char *str1, char *str2)
{
	int a, offset;
	short *sp;
	
	/* eerst inlezen DNA file */
	
	read_structDNA(&cur_sdna, "DNA");
	
	sp= findstruct_name(&cur_sdna, str1);
	
	if(sp) {
		a= sp[1];	/* aantal elems */
		sp+= 2;
		offset= 0;
		
		while(a--) {
			if( strcmp( cur_sdna.names[ sp[1] ], str2 )==0 ) {
				printf("type %s offset %d\n", cur_sdna.types[ sp[0] ], offset);
				return;
			}
			offset+= elementsize(&cur_sdna, sp[0], sp[1]);
			
			sp+= 2;
		}
		printf("Element bestaat niet\n");
	}
	else printf("Struct bestaat niet\n");
	
}

int findstruct_offset(char *structname, char *member)
{
	int a, offset;
	short *sp;
	
	sp= findstruct_name(&cur_sdna, structname);
	
	if(sp) {
		a= sp[1];	/* aantal elems */
		sp+= 2;
		offset= 0;
		
		while(a--) {
			if(strcmp(cur_sdna.names[sp[1]], member)==0) return offset;

			offset+= elementsize(&cur_sdna, sp[0], sp[1]);			
			sp+= 2;
		}
	}
	
	return -1;
}

/* ******************** END LEZEN DNA ********************** */
/* ******************* AFHANDELEN DNA ***************** */

int struct_compare(char *stype, void *one, void *two)
/* van struct 'stype' worden one en two vergeleken: pointers detecteren!!! */
{
	int namelen, a, nr, elemcount, elen, firststructtypenr;
	short *spc;
	char *type, *p1, *p2, *name;
	
	if(one==0 || two==0) return 0;
	
	nr= findstruct_nr(&cur_sdna, stype);
	if(nr == -1) return 0;
	
	firststructtypenr= *(cur_sdna.structs[0]);
	spc= cur_sdna.structs[nr];

	elemcount= spc[1];

	spc+= 2;
	p1= one;
	p2= two;

	for(a=0; a<elemcount; a++, spc+=2) {
		
		type= cur_sdna.types[spc[0]];
		name= cur_sdna.names[spc[1]];
		elen= elementsize(&cur_sdna, spc[0], spc[1]);
		namelen= strlen(name);
		
		if(name[0]=='*') {
			if( strncmp(type, "void", 4) ) {
				if( *((long *)p1)==0 && *((long *)p2)==0);
				else if( *((long *)p1) && *((long *)p2));
				else return 0;
			}
		}
		else if(strncmp(type, "char", 4)==0 && name[namelen-1]==']') {
			;
		}
		else {

			/* testen: is type een struct? */
			if(spc[0]>=firststructtypenr) {
				if( struct_compare(type, p1, p2)==0) return 0;
			}
			else {
				if(memcmp(p1, p2, elen)) return 0;
				
				
			}
		}
		
		p1+= elen;
		p2+= elen;
	}
	
	return 1;
}


void recurs_test_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= old_sdna.structs[structnr];
	typenr= sp[0];
	
	for(a=0; a<old_sdna.nr_structs; a++) {
		if(a!=structnr && compflags[a]==1) {
			sp= old_sdna.structs[a];
			elems= sp[1];
			sp+= 2;
			for(b=0; b<elems; b++, sp+=2) {
				if(sp[0]==typenr) {
					cp= old_sdna.names[ sp[1] ];
					if(cp[0]!= '*') {
						compflags[a]= 2;
						recurs_test_compflags(a);
					}
				}
			}
		}
	}
	
}

void set_compareflags_structDNA()
{
	/* flag: 0:bestaat niet meer (of nog niet)
	 *       1: is gelijk
	 *       2: is anders
	 */
	int a, b;
	short *spold, *spcur;
	char *str1, *str2;
	
	if(old_sdna.nr_structs==0) {
		printf("error: file without SDNA\n");
		return;
	}
		
	if(compflags) freeN(compflags);
	compflags= callocN(old_sdna.nr_structs, "compflags");

	/* We lopen alle structs in 'old_sdna' af, vergelijken ze met 
	 * de structs in 'cur_sdna'
	 */
	
	for(a=0; a<old_sdna.nr_structs; a++) {
		spold= old_sdna.structs[a];
		
		/* type zoeken in cur */
		spcur= findstruct_name(&cur_sdna, old_sdna.types[spold[0]]);
		
		if(spcur) {
			compflags[a]= 2;
			
			/* lengte en aantal elems vergelijken */
			if( spcur[1] == spold[1]) {
				 if( cur_sdna.typelens[spcur[0]] == old_sdna.typelens[spold[0]] ) {
					 
					 /* evenlang en evenveel elems, nu per type en naam */
					 b= spold[1];
					 spold+= 2;
					 spcur+= 2;
					 while(b > 0) {
						 str1= cur_sdna.types[spcur[0]];
						 str2= old_sdna.types[spold[0]];
						 if(strcmp(str1, str2)!=0) break;

						 str1= cur_sdna.names[spcur[1]];
						 str2= old_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(old_sdna.pointerlen!=cur_sdna.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<old_sdna.nr_structs; a++) {
		if(compflags[a]==2) recurs_test_compflags(a);
	}
	
	for(a=0; a<old_sdna.nr_structs; a++) {
		if(compflags[a]==2) {
			spold= old_sdna.structs[a];
			#ifndef FREE
			printf("changed: %s\n", old_sdna.types[ spold[0] ]);
			#endif
		}
	}
	
	
}

void cast_elem(char *ctype, char *otype, char *name, char *curdata, char *olddata)
{
	double val;
	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) otypenr= 1;
	else if(strcmp(otype, "short")==0) otypenr= 2; 
	else if(strcmp(otype, "ushort")==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) 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) ctypenr= 1;
	else if(strcmp(ctype, "short")==0) ctypenr= 2; 
	else if(strcmp(ctype, "ushort")==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) 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= *( (uchar *)olddata); break;
		case 2:
			val= *( (short *)olddata); break;
		case 3:
			val= *( (ushort *)olddata); break;
		case 4:
			val= *( (int *)olddata); break;
		case 5:
			val= *( (int *)olddata); break;
		case 6:
			val= *( (uint *)olddata); break;
		case 7:
			val= *( (float *)olddata); break;
		case 8:
			val= *( (double *)olddata); break;
		}
		
		switch(ctypenr) {
		case 0:
			*curdata= val; break;
		case 1:
			*( (uchar *)curdata)= val; break;
		case 2:
			*( (short *)curdata)= val; break;
		case 3:
			*( (ushort *)curdata)= val; break;
		case 4:
			*( (int *)curdata)= val; break;
		case 5:
			*( (int *)curdata)= val; break;
		case 6:
			*( (uint *)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--;
	}
}

void cast_pointer(int curlen, int oldlen, char *name, char *curdata, char *olddata)
{
#ifdef WIN32
	DWORDLONG 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= *( (DWORDLONG *)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
			 *( (DWORDLONG *)curdata ) = *((int *)olddata);
#else
			 *( (long long *)curdata ) = *((int *)olddata);
#endif
		}
		else {
			/* voor debug */
			printf("errpr: illegal pointersize! \n");
		}
		
		olddata+= oldlen;
		curdata+= curlen;
		arrlen--;

	}
}

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;
}

char *find_elem(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= old_sdna.types[old[0]];
		oname= old_sdna.names[old[1]];
		
		len= elementsize(&old_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;
}

void reconstruct_elem(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
	*/	
	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= old_sdna.types[old[0]];
		oname= old_sdna.names[old[1]];
		len= elementsize(&old_sdna, old[0], old[1]);
		
		if( strcmp(name, oname)==0 ) {	/* naam gelijk */
			
			if( name[0]=='*') {		/* pointer afhandelen */
				cast_pointer(cur_sdna.pointerlen, old_sdna.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(cur_sdna.pointerlen, old_sdna.pointerlen, oname, curdata, olddata);
					else cast_pointer(cur_sdna.pointerlen, old_sdna.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;
	}
	
}

void reconstruct_struct(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= old_sdna.structs[oldSDNAnr];
		elen= old_sdna.typelens[ spo[0] ];
		memcpy( cur, data, elen);
		
		return;
	}

	firststructtypenr= *(cur_sdna.structs[0]);

	spo= old_sdna.structs[oldSDNAnr];
	spc= cur_sdna.structs[curSDNAnr];

	elemcount= spc[1];

	spc+= 2;
	cpc= cur;
	for(a=0; a<elemcount; a++, spc+=2) {
		type= cur_sdna.types[spc[0]];
		name= cur_sdna.names[spc[1]];
		
		elen= elementsize(&cur_sdna, 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(type, name, spo, data, &sppo);
			
			if(cpo) {
				oldSDNAnr= findstruct_nr(&old_sdna, type);
				curSDNAnr= findstruct_nr(&cur_sdna, type);
				
				/* array! */
				mul= arraysize(name, strlen(name));
				nameo= old_sdna.names[sppo[1]];
				mulo= arraysize(nameo, strlen(nameo));
				
				eleno= elementsize(&old_sdna, sppo[0], sppo[1]);
				
				elen/= mul;
				eleno/= mulo;
				
				while(mul--) {
					reconstruct_struct(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(type, name, cpc, spo, data);
			cpc+= elen;

		}
	}
	
}

void switch_endian_struct(int oldSDNAnr, char *data)
{
	/* Recursief!
	 * Als element een struct is, recursief aanroepen.
	 */
	int a, mul, elemcount, elen, elena, firststructtypenr, curSDNAnr;
	short *spo, *spc, skip;
	char *name, *type, *cpo, *cur, cval;

	if(oldSDNAnr== -1) return;
	firststructtypenr= *(old_sdna.structs[0]);
	
	spo= spc= old_sdna.structs[oldSDNAnr];

	elemcount= spo[1];

	spc+= 2;
	cur= data;
	
	for(a=0; a<elemcount; a++, spc+=2) {
		type= old_sdna.types[spc[0]];
		name= old_sdna.names[spc[1]];
		
		/* elementsize = including arraysize */
		elen= elementsize(&old_sdna, 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(type, name, spo, data, 0);
			if(cpo) {
				oldSDNAnr= findstruct_nr(&old_sdna, type);
				
				mul= arraysize(name, strlen(name));
				elena= elen/mul;

				while(mul--) {
					switch_endian_struct(oldSDNAnr, cpo);
					cpo += elena;
				}
			}
		}
		else {
			
			if( name[0]=='*' ) {
				if(old_sdna.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 reconstruct(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= old_sdna.structs[oldSDNAnr];
	type= old_sdna.types[ spo[0] ];
	oldlen= old_sdna.typelens[ spo[0] ];
	curSDNAnr= findstruct_nr(&cur_sdna, type);

	/* data goedzetten en nieuwe calloc doen */
	if(curSDNAnr >= 0) {
		spc= cur_sdna.structs[curSDNAnr];
		curlen= cur_sdna.typelens[ spc[0] ];
	}
	if(curlen==0) {
		freeN(*data);
		*data= 0;
		return;
	}
	cur= callocN( blocks*curlen, "reconstruct");
	
	cpc= cur;
	cpo= *data;
	for(a=0; a<blocks; a++) {
		reconstruct_struct(oldSDNAnr, cpo, curSDNAnr, cpc);
		cpc+= curlen;
		cpo+= oldlen;
	}
	freeN(*data);
	*data= cur;
}