/***********************************************************************
***
*** CDTV - Read a File Directly from CD-ROM
***
***     Copyright (C) 1990 Commodore-Amiga, Inc.
***     Permission granted for use in CDTV applications.
***     Author: Carl Sassenrath, Ukiah, CA  (30-DEC-90)
***
************************************************************************
***
***     What:
***       Sometimes you may want to read a file directly from
***       disk without passing through the file system. This
***       example illustrates a simple technique for doing so.
***
***     Notes:
***       1. This example deals with CDFS file locks.  These
***          structures are not entirely public, and you should
***          not attempt to copy them elsewhere nor access any
***          non-public fields within them.
***       2. This example only works if you know the sector size
***          of the disk you are reading.  Normally they are 2048
***          bytes in length, but other sizes are possible. You
***          should limit your use of this code to your disks only.
***       3. You should think about what happens when the disk is
***          ejected... see the note below.
***       4. Currently tested with Manx C compiler only.
***
***
***********************************************************************/

#include <exec/types.h>
#include <exec/io.h>
#include <devices/cdtv.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>

extern  struct  IOStdReq *CreateStdIO();
extern  struct  MsgPort  *CreatePort();
struct  IOStdReq *IOReq1 = NULL;
struct  MsgPort  *IOPort = NULL;

char    Buffer[10*2048];

char    AssertFail[] = "Assertion failed (MUST)";
#define MUST(expr)  if (!(expr)) Quit(AssertFail);


/***********************************************************************
***
***  Main
***
***********************************************************************/
main(argc,argv)
        int argc;
        char *argv[];
{
        ULONG l;
        ULONG sector;
        struct FileLock *lock;

        printf("CDTV Direct File Read Example (30-Dec-90)\n");

        Init();

        /* Convert path/file name into something the FS understands: */
        l = Lock("s:startup-sequence",ACCESS_READ);
        if (!l) Quit("Cannot lock the file");
        lock = (struct FileLock *)BADDR(l); /* Convert to address */

        /* Pluck the sector right out of public part of the structure */
        sector = lock->fl_Key;
        UnLock(l); /* Lock freed - "l" & "lock" not valid anymore. */

        /* Now simply read the sectors needed... HOWEVER, you may want
        ** to keep an eye out for a disk change since the file system
        ** can no longer do so for you!  The longer you wait after the
        ** lock has been made, the better the chance that the disk has
        ** been changed, and your read may be successful, but on the
        ** wrong disk.  Use the AmigaDOS packet ACTION_INFO to check
        ** what disk is present.
        */
        DoIOR(IOReq1, CD_READ, sector*2048, 2048, Buffer);
        puts(Buffer);
        /*
        ** This READ must begin at an even offset (word aligned)
        ** and be an even number of bytes in length. Also the buffer
        ** must be word aligned. Another example might be:
        */
        DoIOR(IOReq1, CD_READ, sector*2048+5632, 12320, Buffer);
        /* For best performance, make the read as long as possible. */

        Quit(0);
}

/***********************************************************************
***
***  Init -- initialize program and structures
***
***********************************************************************/
Init()
{
        MUST(IOPort = CreatePort(0,0));
        MUST(IOReq1 = CreateStdIO(IOPort));

        if (OpenDevice("cdtv.device",0,IOReq1,0))
                Quit("CDTV Device will not open");
}

/***********************************************************************
***
***  Quit -- exit program and clean-up.  Return an error if needed.
***
***********************************************************************/
Quit(s)
        char *s;        /* error message */
{
        if (IOReq1)
        {
                if (IOReq1->io_Device) CloseDevice(IOReq1);
                DeleteStdIO(IOReq1);
        }
        if (IOPort)     DeletePort(IOPort);
        if (s) {printf("\nERROR: %s\n",s); exit(40);}
        else exit(0);
}

/***********************************************************************
***
***  DoIOR -- execute a device command
***
***********************************************************************/
DoIOR(req,cmd,off,len,data)
        struct IOStdReq *req;
        int cmd;
        long off;
        long len;
        APTR data;
{
        req->io_Command = cmd;
        req->io_Offset = off;
        req->io_Length = len;
        req->io_Data   = data;
        if (DoIO(req)) Quit("DoIO command error");
}

