#ifndef XPKMASTER_HOOK_FH_C
#define XPKMASTER_HOOK_FH_C

/* Routinesheader

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

 1.0   06.10.96 : first real version
 1.1   01.01.97 : work around for sub library caused MungWall hits
 1.2   10.01.97 : removed work around, because I found problem
 1.3   29.03.97 : TOTSIZE now also in inhook
*/

#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, epos;

  switch(msg->xmm_Type)
  {
  case XIO_SEEK:
    if((msg->xmm_Size = Seek(msg->xmm_FH, msg->xmm_Size, OFFSET_CURRENT))<0)
      return XPKERR_IOERRIN;
    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;
  case XIO_TOTSIZE:
    if((wanted = Seek(msg->xmm_FH, 0, OFFSET_END)) < 0 ||
    (epos = Seek(msg->xmm_FH, wanted, OFFSET_BEGINNING)) < 0)
      return XPKERR_IOERRIN;
    msg->xmm_Size = epos-wanted;
    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;
    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 fhouthook = { {0}, (ULONG (*) ()) fhoutfunc,0 ,0};

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

/**************** alloc fh I/O buf ***************/
static LONG allociobuf(struct XpkMasterMsg *msg)
{
  ULONG buflen = msg->xmm_Size;

  if(msg->xmm_BufLen >= buflen) /* buffer is large enough */
    return 0;

  freeiobuf(msg); /* clear old buffer */

  if(!(msg->xmm_Buf = (STRPTR) AllocMem(buflen, msg->xmm_MemType)))
    return XPKERR_NOMEM; /* get new one */

  msg->xmm_BufLen = buflen; /* set correct data */

#ifdef DEBUG
  DebugRunTime("allociobuf: allocated buffer at %lx of size %ld",
  msg->xmm_Buf, msg->xmm_BufLen);
#endif

  return 0; /* all ok */
}

#endif /* XPKMASTER_HOOK_FH_C */
