/**************************************************************/
/* $VER: FileOp.c Revison 1.0                                 */
/* This file is part of Synth Librarian v1.0                  */
/* ©1993-1994 Jean-Alexis MONTIGNIES                          */
/* This file must not be distributed modified or separatly    */
/* without my written permission                              */
/* See Synth_Librarian.guide for more details                 */
/**************************************************************/

/* Synth librarian part for I/O with files */
#include <libraries/asl.h>
#include <proto/asl.h>
#include <stdio.h>
#include <dos.h>
#include <proto/exec.h>
#include <errno.h>
#include <libraries/iffparse.h>
#include <exec/memory.h>
#include <libraries/locale.h>
#include <proto/locale.h>
#include <proto/dos.h>

#define CATCOMP_NUMBERS
#include "SynthLibLoc.h"
#include "SynthLib.h"
#include "SynthLibInt.h"

#define ID_MDDP MAKE_ID('M','D','D','P')
#define ID_HEAD MAKE_ID('H','E','A','D')
#define ID_MIDI MAKE_ID('M','I','D','I')
#define ID_DATA MAKE_ID('D','A','T','A')

extern struct LocaleInfo MLi;
extern char MainCatBlock[];
static struct FileRequester *AslFR,*DriFR;
FILE *F;

STRPTR GetString(struct LocaleInfo *li, LONG stringNum,char *CatCompBlock);
BPTR GetDriverSeg(void);
int FileOpInit(void);
void FileOpClose(void);
int SaveOne(struct DumpNode *Node1);
void SaveAll(void);
int LoadIff(ULONG *Length);


int FileOpInit(void)
 {int ReturnCode;

  AslBase=NULL;
  AslFR=NULL;
  DriFR=NULL;

  if (AslBase=OpenLibrary("asl.library",0L))
    if (AslFR=AllocAslRequestTags(ASL_FileRequest,ASL_Dir,"PROGDIR:",TAG_DONE))
      if (DriFR=AllocAslRequestTags(ASL_FileRequest,ASL_Dir,"PROGDIR:SLDrivers",TAG_DONE))
        ReturnCode=0;
       else
        ReturnCode=3;
     else
      ReturnCode=1;
   else
    ReturnCode=2;

  return(ReturnCode);
 }

void FileOpClose(void)
 {if (AslFR)
    FreeAslRequest(AslFR);
  if (DriFR)
    FreeAslRequest(DriFR);
  if (AslBase)
    CloseLibrary(AslBase);
 }

BPTR GetDriverSeg(void)
 {BPTR DSeg=NULL;

  if (AslRequestTags(DriFR,TAG_DONE))
    if (!chdir(DriFR->rf_Dir))
     {
      if (!(DSeg=LoadSeg(DriFR->rf_File)))
        NewMessage(GetString(&MLi,MG_DRIVER_IO_ERROR,MainCatBlock),1);
     }
     else
       NewMessage(GetString(&MLi,MG_FILE_NODIR,MainCatBlock),1);
  return(DSeg);
 }

int SaveDumpLib(void)
 {if (SelectedDump)
   {
    if (AslRequestTags(AslFR,ASL_FuncFlags,FILF_SAVE,TAG_DONE))
      if (!chdir(AslFR->rf_Dir))
        if (F=fopen(AslFR->rf_File,"wb"))
         {errno=SaveOne(SelectedDump);
          if (errno)
            NewMessage(GetString(&MLi,MG_FILE_IO_ERROR,MainCatBlock),1);
          fclose (F);
         }
         else
          NewMessage(GetString(&MLi,MG_FILE_NOFILE,MainCatBlock),1);
       else
        NewMessage(GetString(&MLi,MG_FILE_NODIR,MainCatBlock),1);
   }
   else
    NewMessage(GetString(&MLi,MG_FILE_NODATA,MainCatBlock),1);
  return(0);
 }

int OpenLib(void)
 {int Error;
  ULONG Dummy;

  if (AslRequestTags(AslFR,ASL_FuncFlags,0L,TAG_DONE))
    if (!chdir(AslFR->rf_Dir))
      if (F=fopen(AslFR->rf_File,"rb"))
       {Error=LoadIff(&Dummy);
        if (Error)
          NewMessage(GetString(&MLi,Error,MainCatBlock),1);
        fclose (F);
       }
       else
        NewMessage(GetString(&MLi,MG_FILE_NOFILE,MainCatBlock),1);
     else
      NewMessage(GetString(&MLi,MG_FILE_NODIR,MainCatBlock),1);
  return(0);
 }

int SaveAsLib(void)
 {if (DumpList.lh_Head->ln_Succ)
   {
    if (AslRequestTags(AslFR,ASL_FuncFlags,FILF_SAVE,TAG_DONE))
     {Flags|=MAIN_FLAGS_NAMED;
      SaveAll();
     }
   }
   else
    NewMessage(GetString(&MLi,MG_FILE_NODATA,MainCatBlock),1);
  return(0);
 }

int SaveLib(void)
 {if (Flags & MAIN_FLAGS_NAMED)
    SaveAll();
   else
    SaveAsLib();
  return(0);
 }

void SaveAll(void)
 {errno=0;
  if (DumpList.lh_Head->ln_Succ)
    if (!chdir(AslFR->rf_Dir))
      if (F=fopen(AslFR->rf_File,"wb"))
       {/* Evaluation de la taille du fichier */
        ULONG Total=0;
        ULONG Number=0;

        struct DumpNode *Node1,*Node2;
        errno=0;

        Node1=(struct DumpNode *)DumpList.lh_Head;

        while (Node2=(struct DumpNode *)Node1->DNode.ln_Succ)
         {Number++;
          Total+=12+58;
          Total+=8+Node1->DumpLength;
          if (Total & 1)
            Total++;
          if (Node1->Data)
           {
            Total+=8+Node1->DataLength;
            if (Total & 1)
              Total++;
           }
          Node1=Node2;
         }

        if (Number>1)
         {
          fwrite("LIST",1,4,F);
          if (!errno)
            fwrite(&Total,4,1,F);
          if (!errno)
            fwrite("MDDP",1,4,F);
         }

        Node1=(struct DumpNode *)DumpList.lh_Head;

        while ((Node2=(struct DumpNode *)Node1->DNode.ln_Succ) && !errno)
         {
          errno=SaveOne(Node1);
          Node1=Node2;
         }

        if (errno)
          NewMessage(GetString(&MLi,MG_FILE_IO_ERROR,MainCatBlock),1);
        fclose (F);
       }
       else
        NewMessage(GetString(&MLi,MG_FILE_NOFILE,MainCatBlock),1);
     else
      NewMessage(GetString(&MLi,MG_FILE_NODIR,MainCatBlock),1);
   else
    NewMessage(GetString(&MLi,MG_FILE_NODATA,MainCatBlock),1);
 }

int SaveOne(struct DumpNode *Node1)
 {ULONG Length,BLength;
  Length=58;

  BLength=Node1->DumpLength;
  if (BLength & 1)
    BLength++;

  Length+=8+BLength;

  BLength=Node1->DataLength;
  if (BLength & 1)
    BLength++;

  if (BLength)
    Length+=8+BLength;

  fwrite("FORM",4,1,F);
  if (!errno)
    fwrite(&Length,4,1,F);
  if (!errno)
    fwrite("MDDP",4,1,F);

  if (!errno)
    fwrite("HEAD\0\0\0\x32",4,2,F);
  if (!errno)
    fwrite(&Node1->Flags,50,1,F);

  if (!errno)
    fwrite("MIDI",4,1,F);
  if (!errno)
    fwrite(&Node1->DumpLength,4,1,F);
  if (!errno)
    fwrite(Node1->Dump,1,Node1->DumpLength,F);
  if (!errno && (Node1->DumpLength & 1))
    fputc(0,F);

  if (Node1->DataLength)
   {
    if (!errno)
      fwrite("DRIV",4,1,F);
    if (!errno)
      fwrite(&Node1->DataLength,4,1,F);
    if (!errno)
      fwrite(Node1->Data,1,Node1->DataLength,F);
    if (!errno && (Node1->DataLength & 1))
      fputc(0,F);
   }
  return (errno);
 }

int LoadIff(ULONG *Length)
 {ULONG ID,BR,FSize,FLength,CSize;
  int ReturnCode=0;
  struct DumpNode* Node;

  BR=fread(&ID,4,1,F);
  *Length+=4;

  if (BR==1)
   {BR=fread(&FSize,4,1,F);
    *Length+=4;
   }
   else
    BR=0;

  if (BR==1)
    switch(ID)
     {case ID_FORM:

        BR=fread(&ID,4,1,F);
        *Length+=4;
        FLength=4;

        if (BR==1)
          if (ID==ID_MDDP)
           {
            if (Node=AllocMem(sizeof(struct DumpNode),MEMF_CLEAR))
              do
               {
                BR=fread(&ID,4,1,F);
                *Length+=4;
                FLength+=4;

                if (BR==1)
                  switch(ID)
                   {case ID_HEAD:
                      BR=fread(&CSize,4,1,F);
                      *Length+=4;
                      FLength+=4;
                      if ((BR==1) && (CSize>=0x32))
                       {BR=fread(&(Node->Flags),50,1,F);
                        if (BR==1)
                         {*Length+=CSize;
                          FLength+=CSize;
                          if (CSize & 1)
                            CSize++;
                          if (CSize>0x32)
                            if (fseek(F,CSize-0x32,SEEK_CUR))
                              BR=0;
                         }
                         else
                           BR=0;
                       }
                       else
                         BR=0;
                      break;

                    case ID_MIDI:
                      BR=fread(&CSize,4,1,F);
                      if (BR==1)
                       {
                        *Length+=4;
                        FLength+=4;
                        if (Node->Dump)
                         {if (CSize & 1)
                            CSize++;
                          *Length+=CSize;
                          FLength+=CSize;
                          if (fseek(F,CSize,SEEK_CUR))
                            BR=0;
                         }
                         else
                          if (Node->Dump=AllocMem(CSize,0L))
                           {
                            Node->DumpLength=CSize;
                            BR=fread(Node->Dump,1,CSize,F);
                            if (BR==CSize)
                             {*Length+=CSize;
                              FLength+=CSize;
                              if (CSize & 1)
                               {CSize++;
                                *Length++;
                                FLength++;
                                if (fseek(F,1,SEEK_CUR))
                                  BR=0;
                               }
                             }
                             else
                              BR=0;
                           }
                           else
                           {ReturnCode=MG_FI_OUT_OF_MEMORY;
                            BR=0;
                           }
                       }
                      break;

                    case ID_DATA:
                      BR=fread(&CSize,4,1,F);
                      if (BR==1)
                       {
                        *Length+=4;
                        FLength+=4;
                        if (Node->Data)
                         {if (CSize & 1)
                            CSize++;
                          *Length+=CSize;
                          FLength+=CSize;
                          if (fseek(F,CSize,SEEK_CUR))
                            BR=0;
                         }
                         else
                          if (Node->Data=AllocMem(CSize,0L))
                           {Node->DataLength=CSize;
                            BR=fread(Node->Data,1,CSize,F);
                            if (BR==CSize)
                             {*Length+=CSize;
                              FLength+=CSize;
                              if (CSize & 1)
                               {CSize++;
                                *Length++;
                                FLength++;
                                if (fseek(F,1,SEEK_CUR))
                                  BR=0;
                               }
                             }
                             else
                              BR=0;
                           }
                           else
                           {ReturnCode=MG_FI_OUT_OF_MEMORY;
                            BR=0;
                           }
                       }
                      break;

                    default:
                      BR=fread(&CSize,4,1,F);
                      if (BR==1)
                       {
                        if (CSize & 1)
                          CSize++;
                        *Length+=4+CSize;
                        FLength+=4+CSize;
                        if (fseek(F,CSize,SEEK_CUR))
                          BR=0;
                       }
                   }
               }
              while (BR && (FLength<FSize));
             else
             {ReturnCode=MG_FI_OUT_OF_MEMORY;
              BR=0;
             }
            if (!BR && Node)
             {if (Node->Dump)
                FreeMem(Node->Dump,Node->DumpLength);
              if (Node->Data)
                FreeMem(Node->Data,Node->DataLength);
              FreeMem(Node,sizeof(struct DumpNode));
             }
            if (Node)
              AddDumpToList(Node);
           }
           else
           {
            if (FSize & 1)
              FSize++;
            if (fseek(F,FSize-4,SEEK_CUR))
              BR=0;
           }
         else
          BR=0;

        break;

      case ID_LIST:
      case ID_CAT:

        BR=fread(&ID,4,1,F);
        *Length+=4;
        FLength=4;

        if (BR==1)
          if ((ID==ID_MDDP) || (ID==ID_NULL))
            do
              if (ReturnCode=LoadIff(&FLength))
                BR=0;
            while ((FLength<FSize) && BR);
           else
           {
            if (FSize & 1)
              FSize++;
            if (fseek(F,FSize-4,SEEK_CUR))
              BR=0;
           }
         else
          BR=0;
        break;

      default:

        ReturnCode=MG_FI_NOTIFF;

        break;

     }
  if (!BR && ReturnCode)
    ReturnCode=MG_FILE_IO_ERROR;

  return(ReturnCode);
 }
