#ifndef XPKMASTER_HOOK_FH_C
#define XPKMASTER_HOOK_FH_C

/* Routinesheader

	Name:		hook_fh.c
	Main:		xpkmaster
	Versionstring:	$VER: hook_fh.c 1.0 (06.10.96)
	Author:		SDI
	Distribution:	PD
	Description:	File IO hooks

 1.0   06.10.96 : first real version
*/

#include <exec/types.h>
#include <pragma/dos_lib.h>
#include <pragma/exec_lib.h>
#include "xpkmaster.h"

static LONG allociobuf(struct XpkMasterMsg *msg);
static void freeiobuf(struct XpkMasterMsg *msg);

#ifdef __MAXON__
  #define __asm
#endif

/****************************** read-from-fh hook **************************/
static LONG __asm fhinfunc(register __a1 struct XpkMasterMsg *msg)
{
  LONG wanted;

  switch(msg->xmm_Type)
  {
  case XIO_SEEK:
    if((msg->xmm_Size = Seek(msg->xmm_FH, msg->xmm_Size, OFFSET_CURRENT))<0)
      return XPKERR_IOERRIN;
    msg->xmm_Ptr = (STRPTR) 42;	/* something > 0 */
    break;
  case XIO_GETBUF:
    if(allociobuf(msg))
      return XPKERR_NOMEM;
    msg->xmm_Ptr = msg->xmm_Buf;
    break;
  case XIO_READ:
    if(!msg->xmm_Ptr)
    {
      if(allociobuf(msg))
        return XPKERR_NOMEM;
      msg->xmm_Ptr = msg->xmm_Buf;
    }
    wanted = msg->xmm_Size;
    if((msg->xmm_Size = Read(msg->xmm_FH, msg->xmm_Ptr, wanted)) != wanted)
      return msg->xmm_Size >= 0 ? XPKERR_TRUNCATED : XPKERR_IOERRIN;
    break;
  case XIO_ABORT:
  case XIO_FREE:
    freeiobuf(msg);
    if(msg->xmm_Flags & XMF_PRIVFH)
      Close(msg->xmm_FH),
	msg->xmm_FH = 0;
    break;
  }
  return 0;
}

struct Hook fhinhook = { {0}, (ULONG (*) ()) fhinfunc, 0, 0};

/****************************** write-to-fh hook **************************/

static LONG __asm fhoutfunc(register __a1 struct XpkMasterMsg *msg)
{
  LONG wanted;

  switch(msg->xmm_Type)
  {
  case XIO_GETBUF:
    if(allociobuf(msg))
      return XPKERR_NOMEM;
    msg->xmm_Ptr = msg->xmm_Buf;
    break;
  case XIO_WRITE:
    wanted = msg->xmm_Size;
    if((msg->xmm_Size = Write(msg->xmm_FH, msg->xmm_Ptr, wanted)) != wanted)
      return XPKERR_IOERROUT;
    break;
  case XIO_SEEK:
    if((msg->xmm_Size = Seek(msg->xmm_FH, msg->xmm_Size, OFFSET_CURRENT))<0)
      return XPKERR_IOERROUT;
    msg->xmm_Ptr = (STRPTR) 42;	/* something > 0 */
    break;
  case XIO_ABORT:
  case XIO_FREE:
    freeiobuf (msg);
    if(msg->xmm_Flags & XMF_PRIVFH)
    {
      Close(msg->xmm_FH);
      msg->xmm_FH = 0L;
    }
    break;
  }
  return 0;
}

struct Hook fhouthook = { {0}, (ULONG (*) ()) fhoutfunc,0 ,0};

/**************** free fh I/O buf ***************/
static void freeiobuf(struct XpkMasterMsg *msg)
{
  if(msg->xmm_BufLen)
  {
    FreeMem(msg->xmm_Buf, msg->xmm_BufLen);
    msg->xmm_BufLen = 0;
  }
}

/**************** alloc fh I/O buf ***************/
static LONG allociobuf(struct XpkMasterMsg *msg)
{
  if(msg->xmm_BufLen >= msg->xmm_Size)
    return 0;
  freeiobuf(msg);
  if(!(msg->xmm_Buf = (STRPTR) AllocMem(msg->xmm_Size, msg->xmm_MemType)))
    return XPKERR_NOMEM;
  msg->xmm_BufLen = msg->xmm_Size;
  return 0;
}

#endif /* XPKMASTER_HOOK_FH_C */
