/*****************************************************************************\
* dir2fd.c - Utilitaires de conversion des fichiers .fd exelvision        *
* Auteur : Daniel Coulom & Fabrice Jouanot                             *
* Creation :Octobre 2009                                                        *
\*****************************************************************************/
/*
dir2df DiskImage.fd FolderName
*/
#include <shlobj.h>
#include <stdio.h>
#include <dirent.h>
#include "dcexeldisk.h"

#define TITRE " Directory to Floppy Disk Converter - Version 2009.10"

//Variables globales

FILE *f1;
char *diskfilename;
char *folder;
char fullname[MAX_PATH + 1];
char dvib[16];          //Disk Volume Information Block = AU 0
char abm[240];          //Allocation Bit Map = AU 1
char fdr[256];          //File Descriptor Record
char flags[10];         //attributs d'un fichier
int nrec;               //nombre d'enregistrements d'un fichier
int recsize;            //taille des enregistrements d'un fichier
int nau;                //nombre d'unites d'allocation d'un fichier
int nextau;             //prochaine au disponible pour un fichier
char message[255];      //message a afficher dans la listbox
char directory[32768];  //catalogue
int directorysize;      //taille du catalogue

//Affichage d'une ligne dans la LISTBOX////////////////////////////////////////
int Display(char *string)
{
 printf(string);
 printf("\n");
 return(0);
}


//Affichage d'un message d'erreur//////////////////////////////////////////////
void Erreur(int r)
{
 switch(r)
 {
  case  1: Display("Erreur: sélectionnez un fichier image"); break;
  case  2: Display("Erreur: ouverture fichier image impossible"); break;
  case  3: Display("Erreur: format disquette incorrect"); break;
  case  4: Display("Erreur: allocation des blocs incorrecte"); break;
  case  5: Display("Erreur: catalogue incorrect"); break;
  case  6: Display("Erreur: création du fichier impossible"); break;
  case  7: Display("Erreur: impossible d'ouvrir le dossier"); break;
  case  8: Display("Erreur: taille des fichiers > capacité disquette"); break;
  case  9: Display("Erreur: ouverture du fichier impossible"); break;
 }
}

//lecture DVIB/////////////////////////////////////////////////////////////////
int Getdvib()
{
 fseek(f1, 0, SEEK_SET);
 fread(dvib, 1, 16, f1); //lecture DVIB
 if(dvib[0] != (char)0xa5) return(-1);
 if(dvib[1] != (char)0x5a) return(-1);
 if(dvib[2] != (char)0x55) return(-1);
 if(dvib[3] != (char)0xaa) return(-1);
 if(dvib[4] != (char)0x00) return(-1);
 if(dvib[5] != (char)0xff) return(-1);
 return(0);
}

//lecture ABM//////////////////////////////////////////////////////////////////
int Getabm()
{
 fseek(f1, 16, SEEK_SET);
 fread(abm, 1, 240, f1); //lecture ABM
 return(0);
}

//lecture catalogue////////////////////////////////////////////////////////////
int Getdir()
{
 int i, next;
 fseek(f1, 512, SEEK_SET);
 fread(directory, 1, 512, f1); //première unité d'allocation
 if((directory[0] & 0xff) != 0xd0) return(-1);
 if((directory[1] & 0xff) != 0x0d) return(-1);
 directorysize = 512;
 i = 0;
 while(i < 100)
 {
  next = 256 * (directory[512 * i + 510] & 0xff);
  next += (directory[512 * i + 511] & 0xff);
  if(next > 0x7fff) break;
  fseek(f1, next * 512, SEEK_SET);
  fread(directory + 512 * i + 512, 1, 512, f1); //nouvelle unité d'allocation
  if((directory[512 * i + 512] & 0xff) != 0xd0) return(-1);
  if((directory[512 * i + 513] & 0xff) != 0x0d) return(-1);
  i++;
  directorysize += 512;
  if(directorysize >= sizeof(directory)) return(-1);
 }
 return(0);
}

//Calcul espace disponible/////////////////////////////////////////////////////
int Freespace()
{
 int i, j, x;
 x = 0;
 Getabm();
 for(i = 0; i < 240; i++)
 for(j = 1; j < 256; j *= 2)
 if((abm[i] & j) == 0) x += 512;
 return x;
}

//Determination des caracteristiques d'un fichier//////////////////////////////
void Fdr(int au)
{
 int i, x;
 flags[0] = 0;
 nrec = 0;
 recsize = 0;
 nau = 1; //une unite d'allocation pour le fdr
 fseek(f1, au * 512, SEEK_SET);
 fread(fdr, 1, 256, f1);
 if((fdr[0] & 0xff) != 0xfd) return;
 //flags
 if(fdr[1] & 0x01) strcat(flags, "W");
 if(fdr[1] & 0x02) strcat(flags, "D");
 if(fdr[1] & 0x20) strcat(flags, "R");
 //nombre et longueur des enregistrements
 nrec = 256 * (fdr[2] & 0xff) + (fdr[3] & 0xff);
 recsize = 256 * (fdr[4] & 0xff) + (fdr[5] & 0xff);
 //allocation des blocs
 for(i = 0; i < 81; i++)
 {
  x = 256 * (fdr[3 * i + 13] & 0xff) + (fdr[3 * i + 14] & 0xff); //n° d'au
  if(x == 0) break;
  x = fdr[3 * i + 15] & 0xff; //nombre d'au's
  nau += x;
 }
}


//initialisation nouvelle disquette////////////////////////////////////////////
void Initdisk(int dos)
{
 int i;
 //initialisation des secteurs
 for(i = 0; i < 0xa0000; i++) fputc(0xe5, f1);
 Display("Initialisation des secteurs");
 //initialisation du systeme de fichiers
 fseek(f1, 0, SEEK_SET);
 fwrite(vierge, 1, 0x400, f1);
 Display("Initialisation du système de fichiers");
 //transfert du DOS
 if(dos)
 {
  fseek(f1, 0, SEEK_SET);
  fwrite(dos0, 1, 0x1000, f1);
  fseek(f1, 0x2000, SEEK_SET);
  fwrite(dos1, 1, 0x1000, f1);
  Display("Transfert du DOS 1.4");
 }
}


//copie d'un fichier dans la disquette/////////////////////////////////////////
int Copyfile(char *name)
{
 FILE *f2; //fichier a copier
 int i;
 char buffer[512];
 //ouverture du fichier
 Display(name);
 strcpy(fullname, folder);
 strcat(fullname, name);
 f2 = fopen(fullname, "rb");
 if(f2 == NULL) {Erreur(9); return 0;}
 //allocation des unites et mise a jour du catalogue
 fread(fdr, 1, 256, f2);
 nau = fdr[15] & 0xff;  //nombre d'au necessaires (hors fdr)
 if((nextau + nau + 1) > 1280) return -1; //allocation impossible
 fdr[13] = (nextau + 1) / 256;
 fdr[14] = (nextau + 1) & 0xff;
 //copie des unites d'allocation
 fseek(f1, 512 * nextau, SEEK_SET);
 fwrite(fdr, 1, 256, f1);
 fread(buffer, 1, 256, f2);
 fwrite(buffer, 1, 256, f1);
 for(i = 0; i < nau; i++)
 {
  fread(buffer, 1, 512, f2);
  fwrite(buffer, 1, 512, f1);
 }
 nau++;  //nombre d'au ecrites (y compris fdr)
 nextau += nau;
 //fin de traitement
 fclose(f2);
 return 0;
}

//creation d'une disquette/////////////////////////////////////////////////////
void Createdisk(int dos)
{
 DIR *dp;
 struct dirent *ep;
 int i, j, n;
 int fileallocation;
 Display("Création d'une disquette avec les fichiers d'un dossier :");
 Display("---------------------------------------------------------");
 if(diskfilename[0] == 0) {Erreur(1); return;}
 if(folder[0] == 0) {Erreur(7); return;}
 f1 = fopen(diskfilename, "wb+");
 if(f1 == NULL) {Erreur(2); return;}
   //initialisation
 Initdisk(dos);
 if(Getdvib() < 0) {Erreur(3); return;}
 if(Getabm() < 0) {Erreur(4); return;}
 if(Getdir() < 0) {Erreur(5); return;}
 //copie des fichiers
 n = 0;
 nextau = 24;
 fileallocation = 0;
 dp = opendir(folder);
 if(dp == NULL) {Erreur(7); return;}
 Display("Copie des fichiers");
 while((ep = readdir(dp)))
 {
  char *dosname;
  dosname = ep->d_name;
  if(dosname[0] == '.') continue;
  //mise a jour du catalogue
  for(i = 18 * n + 2; i < 18 * n + 18; i++) directory[i] = 0x20;
  i = 18 * n + 2; //nom du fichier
  j = 0; while(dosname[j] != '.') directory[i++] = dosname[j++];
  i = 18 * n + 15; //extension
  j++; while(dosname[j] != 0) directory[i++] = dosname[j++];
  i = 18 * n + 18; //premiere unite d'allocation
  directory[i++] = nextau / 256;
  directory[i++] = nextau & 0xff;
  if(Copyfile(dosname) < 0) {Erreur(8); return;}
  n++;
  fileallocation += nau; //nombre d'unite d'allocation pour les fichiers
 }
 closedir(dp);
 //mise a jour du catalogue
 fseek(f1, 0x200, SEEK_SET);
 fwrite(directory, 1, 20, f1); j = 20; //j est l'index dans la directory
 for(i = 1; i < n; i++)
 {
  if((i % 28) == 0) //creation nouvelle unite d'allocation pour le catalogue
  {
   nextau = 7 + n / 28;
   fputc(0, f1); fputc(0, f1); fputc(0, f1); fputc(0, f1);
   fputc(nextau / 256, f1); fputc(nextau & 0xff, f1);
   fseek(f1, nextau * 512, SEEK_SET);
   fputc(0xd0, f1); fputc(0x0d, f1);
  }
  fwrite(directory + j, 1, 18, f1); j += 18;
 }
 for(i = 2 + 18 * (n % 28); i < 510; i++) fputc(0, f1); //completer a zero
 fputc(0x80, f1); fputc(0x00, f1);                      //fin du catalogue
 //mise a jour de l'allocation bit map pour le catalogue
 j = 1;
 for(i = 0; i < (n / 28); i++) j <<= 1;
 abm[1] = j - 1;
 //mise a jour de l'allocation bit map pour les fichiers
 for(i = 0; i < (fileallocation / 8); i++) abm[3 + i] = 0xff;
 j = 1;
 for(i = 0; i < (fileallocation % 8); i++) j <<= 1;
 abm[3 + (fileallocation / 8)] = j - 1;
 //ecriture de l'allocation bit map
 fseek(f1, 16, SEEK_SET);
 fwrite(abm, 1, 240, f1);
 //fin de l'extraction
 Display("");
 sprintf(message, "%i fichiers copiés dans la disquette", n);
 Display(message);
 sprintf(message, "%i octets alloués aux fichiers", fileallocation * 512);
 Display(message);
 Display("Fin de la création de la disquette");
 fclose(f1);
}


// main program //////////////////////////////////////////////////////////////
int main (int argc, char *argv[])
{
	printf("Dir2FD 2010.01 (c) Daniel Coulom, Jester\n");
	if (argc<3) 
	{ Erreur(1);
		exit(1);
	}
	diskfilename=argv[1];
	folder=argv[2];
	Createdisk(1);
	exit(0);
}
