/*------------------------------------------
   DRUMFILE.C -- File I/O Routines for DRUM
                 (c) Charles Petzold, 1992
  ------------------------------------------*/

#include <windows.h>
extern "C" {
#include <mmsystem.h>
#include <commdlg.h>
}
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "drumdll.h"
#include "drumfile.h"

OPENFILENAME ofn = { sizeof (OPENFILENAME) } ;

char * szFilter[] = { "Drum Files (*.DRM)",  "*.drm", "" } ;

char szDrumID [] = "DRUM" ;
char szListID [] = "LIST" ;
char szInfoID [] = "INFO" ;
char szSoftID [] = "ISFT" ;
char szDateID [] = "ISCD" ;
char szFmtID  [] = "fmt " ;
char szDataID [] = "data" ;

char szSoftware [] = "DRUM by Charles Petzold, "
                     "PC Magazine, Vol. 11, Nos. 9-12" ;

char szErrorNoCreate    [] = "File %s could not be opened for writing." ;
char szErrorCannotWrite [] = "File %s could not be written to. Disk full." ;
char szErrorNotFound    [] = "File %s not found or cannot be opened." ;
char szErrorNotDrum     [] = "File %s is not a standard DRUM file." ;
char szErrorUnsupported [] = "File %s is not a supported DRUM file." ;
char szErrorCannotRead  [] = "File %s cannot be read." ;

BOOL DrumFileParse (char * szFileName, char * szTitleName)
     {
     static char szBuffer [_MAX_PATH] ;

     if (_fullpath (szBuffer, szFileName, _MAX_PATH))
          {
          strcpy (szFileName, szBuffer) ;

          if (!GetFileTitle (szFileName, szTitleName, _MAX_FNAME + _MAX_EXT))
               return TRUE ;
          }

     return FALSE ;
     }

BOOL DrumFileOpenDlg (HWND hwnd, char * szFileName, char * szTitleName)
     {
     ofn.hwndOwner         = hwnd ;
     ofn.lpstrFilter       = szFilter [0] ;
     ofn.lpstrFile         = szFileName ;
     ofn.nMaxFile          = _MAX_PATH ;
     ofn.lpstrFileTitle    = szTitleName ;
     ofn.nMaxFileTitle     = _MAX_FNAME + _MAX_EXT ;
     ofn.Flags             = OFN_CREATEPROMPT ;
     ofn.lpstrDefExt       = "drm" ;

     return GetOpenFileName (&ofn) ;
     }

BOOL DrumFileSaveDlg (HWND hwnd, char * szFileName, char * szTitleName)
     {
     ofn.hwndOwner         = hwnd ;
     ofn.lpstrFilter       = szFilter [0] ;
     ofn.lpstrFile         = szFileName ;
     ofn.nMaxFile          = _MAX_PATH ;
     ofn.lpstrFileTitle    = szTitleName ;
     ofn.nMaxFileTitle     = _MAX_FNAME + _MAX_EXT ;
     ofn.Flags             = OFN_OVERWRITEPROMPT ;
     ofn.lpstrDefExt       = "drm" ;

     return GetSaveFileName (&ofn) ;
     }

char * DrumFileWrite (DRUM * pdrum, char * szFileName)
     {
     char        szDateBuf [16] ;
     HMMIO       hmmio ;
     long        lFormat = 1L ;
     MMCKINFO    mmckinfo [3] ;
     struct tm * tmTime ;
     time_t      lTime ;
     WORD        wError = 0 ;

     memset (mmckinfo, 0, 3 * sizeof (MMCKINFO)) ;

               // Recreate the file for writing

     if ((hmmio = mmioOpen (szFileName, NULL,
                            MMIO_CREATE | MMIO_WRITE | MMIO_ALLOCBUF)) == NULL)
          return szErrorNoCreate ;

               // Create a "RIFF" chunk with a "CPDR" type

     mmckinfo[0].fccType = mmioStringToFOURCC (szDrumID, 0) ;

     wError |= mmioCreateChunk (hmmio, &mmckinfo[0], MMIO_CREATERIFF) ;

               // Create "LIST" sub-chunk with an "INFO" type

     mmckinfo[1].fccType = mmioStringToFOURCC (szInfoID, 0) ;

     wError |= mmioCreateChunk (hmmio, &mmckinfo[1], MMIO_CREATELIST) ;

               // Create "ISFT" sub-sub-chunk

     mmckinfo[2].ckid = mmioStringToFOURCC (szSoftID, 0) ;

     wError |= mmioCreateChunk (hmmio, &mmckinfo[2], 0) ;
     wError |= (mmioWrite (hmmio, szSoftware, sizeof (szSoftware)) !=
                                              sizeof (szSoftware)) ;
     wError |= mmioAscend (hmmio, &mmckinfo[2], 0) ;

               // Create a time string

     time (&lTime) ;
     tmTime = localtime (&lTime) ;

     wsprintf (szDateBuf, "%04d-%02d-%02d",
               tmTime->tm_year + 1900, tmTime->tm_mon + 1, tmTime->tm_mday) ;

               // Create "ISCD" sub-sub-chunk

     mmckinfo[2].ckid = mmioStringToFOURCC (szDateID, 0) ;

     wError |= mmioCreateChunk (hmmio, &mmckinfo[2], 0) ;
     wError |= (mmioWrite (hmmio, szDateBuf, strlen (szDateBuf) + 1) !=
                                      (long) strlen (szDateBuf) + 1) ;
     wError |= mmioAscend (hmmio, &mmckinfo[2], 0) ;
     wError |= mmioAscend (hmmio, &mmckinfo[1], 0) ;

               // Create "fmt " sub-chunk

     mmckinfo[1].ckid = mmioStringToFOURCC (szFmtID, 0) ;

     wError |= mmioCreateChunk (hmmio, &mmckinfo[1], 0) ;
     wError |= (mmioWrite (hmmio, (LPSTR) &lFormat, sizeof (long)) !=
                                                    sizeof (long)) ;
     wError |= mmioAscend (hmmio, &mmckinfo[1], 0) ;

               // Create the "data" sub-chunk

     mmckinfo[1].ckid = mmioStringToFOURCC (szDataID, 0) ;

     wError |= mmioCreateChunk (hmmio, &mmckinfo[1], 0) ;
     wError |= (mmioWrite (hmmio, (LPSTR) pdrum, sizeof (DRUM)) !=
                                                 sizeof (DRUM)) ;
     wError |= mmioAscend (hmmio, &mmckinfo[1], 0) ;
     wError |= mmioAscend (hmmio, &mmckinfo[0], 0) ;

               // Clean up and return

     wError |= mmioClose (hmmio, 0) ;

     if (wError)
          {
          mmioOpen (szFileName, NULL, MMIO_DELETE) ;
          return szErrorCannotWrite ;
          }

     return NULL ;
     }

char * DrumFileRead (DRUM * pdrum, char * szFileName)
     {
     DRUM     drum ;
     HMMIO    hmmio ;
     long     lFormat ;
     MMCKINFO mmckinfo [3] ;

     memset (mmckinfo, 0, 2 * sizeof (MMCKINFO)) ;

               // Open the file

     if ((hmmio = mmioOpen (szFileName, NULL, MMIO_READ)) == NULL)
          return szErrorNotFound ;

               // Locate a "RIFF" chunk with a "DRUM" form-type

     mmckinfo[0].ckid = mmioStringToFOURCC (szDrumID, 0) ;

     if (mmioDescend (hmmio, &mmckinfo[0], NULL, MMIO_FINDRIFF))
          {
          mmioClose (hmmio, 0) ;
          return szErrorNotDrum ;
          }

               // Locate, read, and verify the "fmt " sub-chunk

     mmckinfo[1].ckid = mmioStringToFOURCC (szFmtID, 0) ;

     if (mmioDescend (hmmio, &mmckinfo[1], &mmckinfo[0], MMIO_FINDCHUNK))
          {
          mmioClose (hmmio, 0) ;
          return szErrorNotDrum ;
          }

     if (mmckinfo[1].cksize != sizeof (long))
          {
          mmioClose (hmmio, 0) ;
          return szErrorUnsupported ;
          }

     if (mmioRead (hmmio, (LPSTR) &lFormat, sizeof (long)) != sizeof (long))
          {
          mmioClose (hmmio, 0) ;
          return szErrorCannotRead ;
          }

     if (lFormat != 1)
          {
          mmioClose (hmmio, 0) ;
          return szErrorUnsupported ;
          }

               // Go to end of "fmt " sub-chunk

     mmioAscend (hmmio, &mmckinfo[1], 0) ;

               // Locate, read, and verify the "data" sub-chunk

     mmckinfo[1].ckid = mmioStringToFOURCC (szDataID, 0) ;

     if (mmioDescend (hmmio, &mmckinfo[1], &mmckinfo[0], MMIO_FINDCHUNK))
          {
          mmioClose (hmmio, 0) ;
          return szErrorNotDrum ;
          }

     if (mmckinfo[1].cksize != sizeof (DRUM))
          {
          mmioClose (hmmio, 0) ;
          return szErrorUnsupported ;
          }

     if (mmioRead (hmmio, (LPSTR) &drum, sizeof (DRUM)) != sizeof (DRUM))
          {
          mmioClose (hmmio, 0) ;
          return szErrorCannotRead ;
          }

               // Close the file and copy the DRUM structure data

     mmioClose (hmmio, 0) ;

     memcpy (pdrum, &drum, sizeof (DRUM)) ;
     return NULL ;
     }
