
#include <ctype.h>
#include <string.h>

#include "fat.h"
#include "file.h"
#include "hardware.h"

struct Fat fat;   					// wichtige daten/variablen der fat
struct File file;					// wichtige dateibezogene daten/variablen


#if (WRITE==1)

//***************************************************************************************************************
// schreibt sektor nummer:sec auf die karte (puffer:sector) !!
// setzt bufferFlag=0 da puffer nicht dirty sein kann nach schreiben !
//***************************************************************************************************************
unsigned char fat_writeSector(unsigned long int sec){	
 
	fat.bufferDirty=0;								// buffer kann nicht dirty sein weil wird geschrieben		
	return(mmc_write_sector(sec,fat.sector));		// schreiben von sektor puffer		
}

#endif


// ***************************************************************************************************************
// umrechnung cluster auf 1.sektor des clusters (möglicherweise mehrere sektoren/cluster) !
// ***************************************************************************************************************
unsigned long int fat_clustToSec(unsigned long int clust){

	return (fat.dataDirSec+2+((clust-2) * fat.secPerClust));					// errechnet den 1. sektor der sektoren des clusters
}

// ***************************************************************************************************************
// umrechnung sektor auf cluster (nicht die position im cluster selber!!)
// ***************************************************************************************************************
unsigned long int fat_secToClust(unsigned long int sec){
 
  return ((sec-fat.dataDirSec-2+2*fat.secPerClust)/fat.secPerClust);	// umkerhrfunktion von fat_clustToSec
}


//***************************************************************************************************************
// läd sektor:sec auf puffer:sector zum bearbeiten im ram !
// setzt currentSectorNr auf richtigen wert (also den sektor der gepuffert ist). es wird geprüft
// ob der gepufferte sektor geändert wurde, wenn ja muss erst geschrieben werden, um diese daten nicht zu verlieren !
//***************************************************************************************************************
unsigned char fat_loadSector(unsigned long int sec){
	
  if(sec!=fat.currentSectorNr){					// nachladen nötig			
	#if (WRITE==1)
	if(fat.bufferDirty==1) fat_writeSector(fat.currentSectorNr);	// puffer diry, also vorher schreiben		  		  
	#endif
	mmc_read_sector(sec,fat.sector);	// neuen sektor laden						  
	fat.currentSectorNr=sec;						// aktualisiert sektor nummer (nummer des gepufferten sektors)
	return(0);	
	}	
		
  else return(0);										// alles ok, daten sind schon da (sec==fat.currentSectorNr)	

  return(1);											// fehler	
}







// datei lesen funktionen:

// fat_loadSector -> fat_loadRowOfSector -> fat_loadFileDataFromCluster -> fat_loadFileDataFromDir -> fat_loadFileDataFromDir -> fat_cd   "daten chain"

//***************************************************************************************************************
// läd die reihe:row des gepufferten sektors auf das struct:file. dort stehen dann
// alle wichgigen daten wie: 1.cluster,länge bei dateien, name des eintrags, reihen nummer (im sektor), attribut use...
//***************************************************************************************************************
unsigned char fat_loadRowOfSector(unsigned int row){

	unsigned char i;
	row=row<<5;									// multipliziert mit 32 um immer auf zeilen anfang zu kommen (zeile 0=0,zeile 1=32,zeile 2=62 usw).

	void *vsector;								// void, damit man schoen umbiegen kann :)
	
	for(i=0;i<11;i++)
		file.name[i]=fat.sector[row+i];			// datei name, ersten 10 bytes vom 32 byte eintrag.

	file.attrib=fat.sector[row+11];							// datei attribut, byte 11.

	vsector=&fat.sector[row+26];							// low word von fist.cluster
	file.firstCluster=*(unsigned short*)vsector;
	
	vsector=&fat.sector[row+20];							// high word von first.cluster
	file.firstCluster|=(*(unsigned short*)vsector)<<16;

	vsector=&fat.sector[row+28];							// 4 byte von file.length
	file.length=*(unsigned long int*)vsector;

	return(0);				
}


//***************************************************************************************************************
// geht reihen weise durch sektoren des clusters mit dem startsektor:sec, und sucht nach der datei mit dem 
// namen:name. es werden die einzelnen sektoren nachgeladen auf puffer:sector vor dem bearbeiten.
// wird die datei in dem cluster gefunden ist return 0 , sonst return1.
//***************************************************************************************************************
unsigned char fat_loadFileDataFromCluster(unsigned long int sec , char name[]){
	
  unsigned char r;  
  unsigned char s=0;

  do{										// sektoren des clusters prüfen
	r=0;									// neuer sektor, dann reihen von 0 an.
	mmc_read_sector(sec+s,fat.sector);		// läd den sektor sec auf den puffer fat.sector
	fat.currentSectorNr=sec+s;				// setzen des aktuellen sektors
	  do{									// reihen des sektors prüfen
		fat_loadRowOfSector(r);				// zeile 0-15 auf struct file laden
		if(file.name[0]==0){				// wenn man auf erste 0 stößt müsste der rest auch leer sein!
			file.row=r;						// zeile sichern.
			return(1);
			}
		if(0==strncmp((char*)file.name,name,10)){		// zeile r ist gesuchte		
		  file.row=r;					// zeile sichern.
		  return(0);			
		  }
		r++;
	  }while(r<16);					// zählt zeilennummer (16(zeilen) * 32(spalten) == 512 bytes des sektors)
	s++;
	}while(s<fat.secPerClust);			// geht durch sektoren des clusters

	return (1);						// fehler (datei nicht gefunden, oder fehler beim lesen)
}


//***************************************************************************************************************
// wenn dir == 0 dann wird das root direktory durchsucht, wenn nicht wird der ordner cluster-chain gefolgt, um
// die datei zu finden. es wird das komplette directory in dem man sich befindet durchsucht.
// bei fat16 wird der rootDir berreich durchsucht, bei fat32 die cluster chain des rootDir.
//***************************************************************************************************************
unsigned char fat_loadFileDataFromDir(char name[]){ 

  unsigned int s;

  if(fat.dir==0 && fat.fatType==16){									// IM ROOTDIR.	fat16	
	for(s=0;s<(unsigned int)(fat.dataDirSec+2-fat.rootDir);s++){		// zählt durch RootDir sektoren (errechnet anzahl rootDir sektoren).
	  if(0==fat_loadFileDataFromCluster(fat.rootDir+s,name))return(0);// sucht die datei, wenn da, läd daten (1.cluster usw)
	  }
	}		
	
  else {		
	unsigned long int i;
	if(fat.dir==0 && fat.fatType==32)i=fat.rootDir;					// IM ROOTDIR.	fat32		
	else i=fat.dir;															// NICHT ROOTDIR																											
	while(!((i==0xfffffff&&fat.fatType==32)||(i==0xffff&&fat.fatType==16))){	// prüft ob weitere sektoren zum lesen da sind (fat32||fat16)
	  if(0==fat_loadFileDataFromCluster(fat_clustToSec(i),name))return(0);	// lät die daten der datei auf struct:file. datei gefunden (umrechnung auf absoluten sektor)
	  i=fat_getNextCluster(i);													// liest nächsten cluster des dir-eintrags (unterverzeichniss größer 16 einträge)
	  }
	}

  return(1);																	// datei/verzeichniss nicht gefunden
}


#if (SMALL_FILE_SYSTEM==0)

//***************************************************************************************************************
// start immer im root Dir. start in root dir (dir==0).
// es MUSS in das direktory gewechselt werden, in dem die datei zum lesen/anhängen ist (außer root, da startet mann)!
//***************************************************************************************************************
unsigned char fat_cd(char name[]){

  if(name[0]==0){								// ZUM ROOTDIR FAT16/32
	fat.dir=0;										// root dir 
	return(0);
	}

  if(0==fat_loadFileDataFromDir(name)){			// NICHT ROOTDIR	(fat16/32)
	fat.dir=file.firstCluster;						// zeigt auf 1.cluster des dir	(fat16/32)	
	return(0);
	}

  return(1);									// dir nicht gewechselt (nicht da?) !!
}

#endif





#if (WRITE==1)

// datei anlegen funktionen :

// ***************************************************************************************************************
// sucht leeren eintrag (zeile) im cluster mit dem startsektor:secStart.
// wird dort kein freier eintrag gefunden ist return (1).
// wird ein freier eintrag gefunden, ist die position der freien reihe auf file.row abzulesen und return (0).
// der sektor mit der freien reihe ist auf dem puffer:sector gepuffert.
// ****************************************************************************************************************
unsigned char fat_getFreeRowOfCluster(unsigned long secStart){
    
  unsigned int b;								// zum durchgenen der sektor bytes
  unsigned char s=0;							// sektoren des clusters.
  
  do{
	file.row=0;									// neuer sektor(oder 1.sektor), reihen von vorne.
	if(0==fat_loadSector(secStart+s)){			// laed sektor auf puffer fat.sector
	  for(b=0;b<512;b=b+32){					// zaehlt durch zeilen (0-15).
		if(fat.sector[b]==0x00||fat.sector[b]==0xE5)return(0);	// prueft auf freihen eintrag (leer oder geloescht == OK!).
		file.row++;								// zählt reihe hoch (nächste reihe im sektor).
		}
	  }
	s++;										// sektoren des clusters ++ weil einen geprüft.
	}while(s<fat.secPerClust);					// geht die sektoren des clusters durch (moeglicherweise auch nur 1. sektor).
  return (1);									// nicht gefunden in diesem cluster (== nicht OK!).
}


// ***************************************************************************************************************
// sucht leeren eintrag (zeile) im directory mit dem startcluster:dir.
// geht die cluster chain des direktories durch. dabei werden auch alle sektoren der cluster geprüft.
// wird dort kein freier eintrag gefunden, wird ein neuer leerer cluster gesucht, verkettet und der 
// 1. sektor des freien clusters geladen. die reihe wird auf den ersten eintrag gesetzt, da frei.
// anhand der reihe kann man nun den direktory eintrag vornehmen, und auf die karte schreiben.
// ****************************************************************************************************************
void fat_getFreeRowOfDir(unsigned long int dir){
  
  unsigned long int start=dir;
 
  // solange bis ende cluster chain.
  while( !((dir==0xfffffff&&fat.fatType==32)||(dir==0xffff&&fat.fatType==16)) ){		  
	if(0==fat_getFreeRowOfCluster(fat_clustToSec(dir)))return;	// freien eintrag in clustern, des dir gefunden !!
	start=dir;		
	dir=fat_getNextCluster(dir);	
	}									// wenn aus schleife raus, kein freier eintrag da -> neuer cluster nötig.

  dir=fat_secToClust(fat.startSectors);	// dir ist jetzt neuer cluster zum verketten !
  fat_setCluster(start,dir);			// cluster-chain mit neuem cluster verketten
  fat_setCluster(dir,0x0fffffff);		// cluster-chain ende markieren

  //es muessen neue gesucht werden, weil der bekannte aus file.c ja grade verkettet wurden. datei eintrag passte nicht mehr ins dir...
  fat_getFreeClustersInRow(2);							// neue freie cluster suchen, für datei.
  file.firstCluster=fat_secToClust(fat.startSectors);	// 1. cluster der datei
  file.lastCluster=fat_secToClust(fat.endSectors);		// letzter bekannter cluster der datei

  fat.currentSectorNr=fat_clustToSec(dir);	// setzen des richtigen sektors, also auf den 1. der neu verketteten

  unsigned int j=511;
  do{
    fat.sector[j]=0x00;						//schreibt puffer fat.sector voll mit 0x00==leer
  	}while(j--);

  unsigned char i=1;						// ab 1 weil der 1.sektor des clusters eh noch beschrieben wird...
  do{
	fat_writeSector(fat.currentSectorNr+i);	// löschen des cluster (überschreibt mit 0x00), wichtig bei ffls,
	i++;
	}while(i<fat.secPerClust);

  file.row=0;								// erste reihe frei, weil grad neuen cluster verkettet !
}


//***************************************************************************************************************
// erstellt 32 byte eintrag einer datei, oder verzeichnisses im puffer:sector.
// erstellt eintrag in reihe:row, mit namen:name usw... !!  
// muss noch auf die karte geschrieben werden ! nicht optimiert auf geschwindigkeit.
//***************************************************************************************************************
void fat_makeRowDataEntry(unsigned int row,char name[],unsigned char attrib,unsigned long int cluster,unsigned long int length){

  fat.bufferDirty=1;								// puffer beschrieben, also neue daten darin(vor lesen muss geschrieben werden)
  
  row=row<<5;										// multipliziert mit 32 um immer auf zeilen anfang zu kommen (zeile 0=0,zeile 1=32,zeile 2=62 ... zeile 15=480)	

  unsigned char i;								// byte zähler in reihe von sektor (32byte eintrag)
  unsigned char	*bytesOfSec=&fat.sector[row];	// zeiger auf sector bytes
  void *vsector;

  for(i=0;i<11;i++) *bytesOfSec++=name[i];				// namen schreiben

  *bytesOfSec++=attrib;									// attrib schreiben

  vsector=&fat.sector[row+12];
  *(unsigned long int*)vsector++=0x01010101;			// 	unnoetige felder beschreiben
  *(unsigned long int*)vsector=0x01010101;

  vsector=&fat.sector[row+20];
  *(unsigned short*)vsector=(cluster&0xffff0000)>>16;// low word	von cluster
  
  vsector=&fat.sector[row+22];
  *(unsigned long int*)vsector=0x01010101;			// unnoetige felder beschreiben
  
  vsector=&fat.sector[row+26];
  *(unsigned short*)vsector=(cluster&0x0000ffff);	// high word von cluster
  
  vsector=&fat.sector[row+28];
  *(unsigned long int*)vsector=length;				// laenge
}


//***************************************************************************************************************
// macht den datei eintrag im jetzigen verzeichniss (fat.dir).
// file.row enthält die reihen nummer des leeren eintrags, der vorher gesucht wurde, auf puffer:sector ist der gewünschte
// sektor gepuffert. für fat16 im root dir muss andere funktion genutzt werden, als fat_getFreeRowOfDir (durchsucht nur dirs).
// fat.rootDir enthält bei fat32 den start cluster des directory, bei fat16 den 1. sektor des rootDir bereichs!
//***************************************************************************************************************
void fat_makeFileEntry(char name[],unsigned char attrib,unsigned long int length){
  
  unsigned int s;													// zähler für root dir sektoren fat16
 
  if(fat.dir==0&&fat.fatType==32)fat_getFreeRowOfDir(fat.rootDir);	// IM ROOT DIR (fat32)

  else if(fat.dir==0 && fat.fatType==16){							// IM ROOT DIR (fat16)		
	for(s=0;s<(unsigned int)(fat.dataDirSec+2-fat.rootDir);s++){	// zählt durch RootDir sektoren (errechnet anzahl rootDir sektoren).								
	  if(0==fat_getFreeRowOfCluster(fat.rootDir+s))break;			// geht durch sektoren des root dir.
	  }
	}  

  else fat_getFreeRowOfDir(fat.dir);									// NICHT ROOT DIR fat32/fat16
		
  fat_makeRowDataEntry(file.row,name,attrib,file.firstCluster,length);	// schreibt file eintrag auf puffer
  fat_writeSector(fat.currentSectorNr);									// schreibt puffer auf karte
}

#endif





// fat funktionen:

//***************************************************************************************************************
// sucht nötige folge Cluster aus der fat ! 
// erster daten cluster = 2, ende einer cluster chain 0xFFFF (fat16) oder 0xFFFFFFF, 0xFFFFFF8 (fat32), 
// stelle des clusters in der fat, hat als wert, den nächsten cluster. (1:1 gemapt)!
//***************************************************************************************************************
unsigned long int fat_getNextCluster(unsigned long int oneCluster){	
  
  // FAT 16**************FAT 16	
  if(fat.fatType==16){																	
	unsigned long int i=oneCluster>>8;;			// (i=oneCluster/256)errechnet den sektor der fat in dem oneCluster ist (rundet immer ab)
	unsigned long int j=(oneCluster<<1)-(i<<9);	// (j=(oneCluster-256*i)*2 == 2*oneCluster-512*i)errechnet das low byte von oneCluster
			
	if(0==fat_loadSector(i+fat.fatSec)){			// ob neu laden nötig, wird von fat_loadSector geprüft
	  void *bytesOfSec=&fat.sector[j];	  			// zeiger auf puffer
	  return *(unsigned short*)bytesOfSec;		// da der ram auch little endian ist, kann einfach gecastet werden und gut :)
	  }	
	}

  // FAT 32**************FAT 32	
  else{												
	unsigned long int i=oneCluster>>7;			// (i=oneCluster/128)errechnet den sektor der fat in dem oneCluster ist (rundet immer ab)
	unsigned long int j=(oneCluster<<2)-(i<<9);	// (j=(oneCluster-128*i)*4 == oneCluster*4-512*i)errechnet das low byte von oneCluster
		
	if(0==fat_loadSector(i+fat.fatSec)){			// ob neu laden nötig wird von fat_loadSector geprüft
	  void *bytesOfSec=&fat.sector[j];				// zeiger auf puffer
	  return *(unsigned long int*)bytesOfSec;	// da der ram auch little endian ist, kann einfach gecastet werden und gut :)
	  }	
  }

  return(0);
}


//***************************************************************************************************************
// sucht verkettete cluster einer datei, die in einer reihe liegen. worst case: nur ein cluster.
// sieht in der fat ab dem cluster offsetCluster nach. sucht die anzahl von MAX_CLUSTERS_IN_ROW,
// am stück,falls möglich. prüft ob der cluster neben offsetCluster dazu gehört...
// setzt dann fat.endSectors und fat.startSectors. das -1 weil z.b. [95,98] = {95,96,97,98} = 4 sektoren
//***************************************************************************************************************
void fat_getFatChainClustersInRow(unsigned long int offsetCluster){

  unsigned int i=0;
  fat.startSectors=fat_clustToSec(offsetCluster);	// setzen des 1. sektors der datei
  fat.endSectors=fat.startSectors;
  do{
	 if( (offsetCluster+1+i)==fat_getNextCluster(offsetCluster+i) ) fat.endSectors+=fat.secPerClust; // zählen der zusammenhängenden sektoren					
	 else {
		file.lastCluster=offsetCluster+i;			// cluster daneben gehört nicht dazu, somit ist offset+i der letzte bekannte
		break;											
		}		
	 }while(i++<MAX_CLUSTERS_IN_ROW);	 
  fat.endSectors+=fat.secPerClust-1;
}


#if (WRITE==1)

//***************************************************************************************************************
// sucht freie zusammenhängende cluster aus der fat. maximal MAX_CLUSTERS_IN_ROW am stück.
// erst wir der erste frei cluster gesucht, ab offsetCluster(iklusive) und dann wird geschaut, ob der
// daneben auch frei ist. setzt dann fat.endSectors und fat.startSectors. das -1 weil z.b. [95,98] = {95,96,97,98} = 4 sektoren
//***************************************************************************************************************
void fat_getFreeClustersInRow(unsigned long int offsetCluster){

  unsigned int i=1; 															// variable für anzahl der zu suchenden sektoren
  while(fat_getNextCluster(offsetCluster)) offsetCluster++;		// suche des 1. freien clusters																					
		
  fat.startSectors=fat_clustToSec(offsetCluster);	// setzen des startsektors der freien sektoren (umrechnen von cluster zu sektoren)	 
  fat.endSectors=fat.startSectors;

  do{																// suche der nächsten freien
	 if(0==fat_getNextCluster(offsetCluster+i) ) fat.endSectors+=fat.secPerClust;	// zählen der zusammenhängenden sektoren			
	 else break;												// cluster daneben ist nicht frei				
	 }while(i++<MAX_CLUSTERS_IN_ROW);	

  fat.endSectors+=fat.secPerClust-1;					// -1 weil der erste sektor schon mit zählt z.b. [95,98] = 4 sektoren  
}

 
//***************************************************************************************************************
// verkettet ab startCluster bis einschließlich endCluster. verkettet auch den letzten bekannten mit den neu übergebenen !
// es ist wegen der fragmentierung der fat nötig, sich den letzten bekannten cluster zu merken, 
// damit man bei weiteren cluster in einer reihe die alten cluster noch dazu verketten kann (so sind lücken im verketten möglich).
//***************************************************************************************************************
void fat_setClusterChain(unsigned long int startCluster,unsigned int endCluster){

  fat_setCluster(file.lastCluster,startCluster);		// ende der chain setzen, bzw verketten der ketten
  
  while(startCluster!=endCluster){  
	 startCluster++;
	 fat_setCluster( startCluster-1 ,startCluster );	// verketten der cluster der neuen kette									
	 }
	 
  fat_setCluster(startCluster,0xfffffff);				// ende der chain setzen
  file.lastCluster=endCluster;							// ende cluster der kette updaten
  fat_writeSector(fat.currentSectorNr);					// schreiben des fat sektors auf die karte

}


//***************************************************************************************************************
// setzt den cluster inhalt. errechnet den sektor der fat in dem cluster ist, errechnet das low byte von
// cluster und setzt dann byteweise den inhalt:content.
// prüft ob buffer dirty (zu setztender cluster nicht in jetzt gepuffertem).
// prüfung erfolgt in fat_loadSector, dann wird alter vorher geschrieben, sonst gehen dort daten verloren !!
//***************************************************************************************************************
void fat_setCluster(unsigned long int cluster, unsigned long int content){  

	// FAT 16**************FAT 16	
	if(fat.fatType==16){					
		unsigned long int i=cluster>>8;			// (i=cluster/256)errechnet den sektor der fat in dem cluster ist (rundet immer ab)
		unsigned long int j=(cluster<<1)-(i<<9);	// (j=(cluster-256*i)*2 == 2*cluster-512*i)errechnet das low byte von cluster
		
		if(0==fat_loadSector(i+fat.fatSec)){		//	neu laden (fat_loadSector prüft ob schon gepuffert)
			void *bytesOfSec=&fat.sector[j];		// init des zeigers auf unterste adresse
			*(unsigned short*)bytesOfSec=content;// weil ram auch little endian geht das so :)
			fat.bufferDirty=1;						// zeigt an, dass im aktuellen sector geschrieben wurde
			}	
		}

	// FAT 32**************FAT 32	
	else{													
		unsigned long int i=cluster>>7;			// (i=cluster/128)errechnet den sektor der fat in dem cluster ist (rundet immer ab)
		unsigned long int j=(cluster<<2)-(i<<9);	//(j=(cluster-128*i)*4 == cluster*4-512*i)errechnet das low byte von cluster		
		
		if(0==fat_loadSector(i+fat.fatSec)){		//	neu laden (fat_loadSector prüft ob schon gepuffert)
			void *bytesOfSec=&fat.sector[j];		// init des zeigers auf unterste adresse
			*(unsigned long int*)bytesOfSec=content;		// weil ram auch little endian geht das so :)
			fat.bufferDirty=1;						// zeigt an, dass im aktuellen sector geschrieben wurde
			}	
		}		
}


//***************************************************************************************************************
// löscht cluster chain, beginnend ab dem startCluster.
// sucht cluster, setzt inhalt usw.. abschließend noch den cluster-chain ende markierten cluster löschen.
//***************************************************************************************************************
void fat_delClusterChain(unsigned long int startCluster){

  unsigned long int nextCluster=startCluster;		// tmp variable, wegen verketteter cluster..  
	
  do{
	 startCluster=nextCluster;
	 nextCluster=fat_getNextCluster(startCluster);
	 fat_setCluster(startCluster,0x00000000);  	
  }while(!((nextCluster==0xfffffff&&fat.fatType==32)||(nextCluster==0xffff&&fat.fatType==16)));	
  fat_writeSector(fat.currentSectorNr);
}
 
#endif


//***************************************************************************************************************
// Initialisiert die Fat(16/32) daten, wie: root directory sektor, daten sektor, fat sektor...
// siehe auch Fatgen103.pdf. ist NICHT auf performance optimiert!
// byte/sector, byte/cluster, anzahl der fats, sector/fat ... (halt alle wichtigen daten zum lesen ders datei systems!)
//*****************************************************************<**********************************************
unsigned char fat_loadFatData(unsigned long int sec){

										// offset,size
  unsigned int  		rootEntCnt;		// 17,2				größe die eine fat belegt
  unsigned int  		fatSz16;		// 22,2				sectors occupied by one fat16
  unsigned long int 	fatSz32;		// 36,4				sectors occupied by one fat32

  void *vsector;

  if(0==mmc_read_sector(sec,fat.sector)){	// lesen von fat sector und bestimmen der wichtigen berreiche 

	fat.bufferDirty = 0;				// init wert des flags
		
	fat.secPerClust=fat.sector[13];		// fat.secPerClust, 13 only (power of 2)

	vsector=&fat.sector[14];
	fat.fatSec=*(unsigned short*)vsector;

	vsector=&fat.sector[17];
	rootEntCnt=*(unsigned short*)vsector;

	vsector=&fat.sector[22];
	fatSz16=*(unsigned short*)vsector;

	fat.rootDir	 = (((rootEntCnt <<5) + 512) /512)-1;	// ist 0 bei fat 32, sonst der root dir sektor

	if(fat.rootDir==0){									// FAT32 spezifisch (die prüfung so, ist nicht spezifikation konform !).

		vsector=&fat.sector[36];
		fatSz32=*(unsigned long int *)vsector;

		vsector=&fat.sector[44];
		fat.rootDir=*(unsigned long int *)vsector;

		fat.dataDirSec = fat.fatSec + (fatSz32 * fat.sector[16]);	// data sector (beginnt mit cluster 2)
		fat.fatType=32;									// fat typ
	  }

	else{												// FAT16	spezifisch
		fat.dataDirSec = fat.fatSec + (fatSz16 * fat.sector[16]) + fat.rootDir;		// data sektor (beginnt mit cluster 2)
		fat.rootDir=fat.dataDirSec-fat.rootDir;			// root dir sektor, da nicht im datenbereich (cluster)	
		fat.rootDir+=sec;								// addiert den startsektor auf 	"
		fat.fatType=16;									// fat typ
		}		

	fat.fatSec+=sec;									// addiert den startsektor auf
	fat.dataDirSec+=sec;								// addiert den startsektor auf (umrechnung von absolut auf real)
	fat.dataDirSec-=2;									// zeigt auf 1. cluster
	fat.dir=0;											// dir auf '0'==root dir, sonst 1.Cluster des dir
	return (0);
	}


  return (1);			// sector nicht gelesen, fat nicht initialisiert!!
}


//************************************************************************************************<<***************
// int fat sucht den 1. cluster des dateisystems (fat16/32) auch VBR genannt,  
//************************************************************************************************<<***************
unsigned char fat_initfat(void){					
  
   unsigned long int secOfFirstPartition=0;					// ist 1. sektor der 1. partition aus dem MBR  
  
	if(0==mmc_read_sector(0,fat.sector)){

	  void *vsector=&fat.sector[454];								//startsektor bestimmen
	  secOfFirstPartition=*(unsigned long int*)vsector;

	  //prüfung ob man schon im VBR gelesen hat (0x6964654d = "Medi")
	  if(secOfFirstPartition==0x6964654d)  return fat_loadFatData(0);  //ist superfloppy

	  else {return fat_loadFatData(secOfFirstPartition);}				 // ist partitioniert...
	 }

  return (1);
}


#if (SMALL_FILE_SYSTEM==0)

// *****************************************************************************************************************
// bereitet str so auf, dass man es auf die mmc/sd karte schreiben kann.
// wandelt z.b. "t.txt" -> "T        TXT" oder "main.c" in "MAIN    C  " => also immer 8.3 und upper case letter
// VORSICHT es werden keine Prüfungen gemacht !
// *****************************************************************************************************************
char * fat_str(char *str){

  unsigned char i;
  unsigned char j=0;
  unsigned char c;
  char tmp[12];					// tmp string zum einfacheren umwandeln
  
  strcpy(tmp,str);

  for(i=0;i<11;i++)str[i]=' ';	// als vorbereitung alles mit leerzeichen füllen
  str[11]='\0';

  i=0;

  do{
	c=toupper(tmp[j]);
	if(c=='\0')return str;
	if(c!='.')str[i]=c;
	else i=7;
	i++;
	j++;
	}while(i<12);

  return str;
  
}

#endif

