#ifndef XPKMASTER_XPKMASTER_C
#define XPKMASTER_XPKMASTER_C

/* Routinesheader

	Name:		xpkmaster.c
	Main:		xpkmaster
	Versionstring:	$VER: xpkmaster.c 1.10 (01.04.97)
	Author:		SDI
	Distribution:	PD
	Description:	the main xpk functions

 1.0   09.10.96 : first real version
 1.1   27.12.96 : removed 1.3 specific functions
 1.2   10.01.97 : corrected XpkPack's abort
 1.3   11.01.97 : corrected mem bug (reported by Laurent Kempe)
 1.4   30.01.97 : hopefully fixed mem bug finally
 1.5   31.01.97 : bug still occured
 1.6   01.03.97 : added NoPack stuff to XpkWrite and XpkPack
 1.7   24.03.97 : fixed XpkPack
 1.8   25.03.97 : added AutoPasswd
 1.9   28.03.97 : moved autopassword into xpkopen
 1.10  01.04.97 : fixed NoPack error
*/

#include <pragma/exec_lib.h>
#include <pragma/intuition_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/utility_lib.h>
#include <pragma/xpkmaster_lib.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <libraries/ppbase.h>
#include <dos/dos.h>
#include "xpkmaster.h"
#include "xpk_strings.h"

#ifdef SUPPORT_A4
  LONG XpkOpenA4NAME(struct XpkFib **xfh, struct TagItem *tags, ULONG a4);
  #ifdef __SASC
    #pragma libcall XpkBase XpkOpenA4NAME 036 C9803
  #else
    #pragma amicall(XpkBase,0x36,XpkOpenA4NAME(a0,a1,a4))
  #endif
#else
  #define XpkOpenA4NAME XpkOpen
#endif

/**************************************************************************
 *
 *   XpkPack() - pack a file
 *
 */

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm LIBXpkPack(register __a0 struct TagItem *tags A4PROTO)
{
  struct XpkBuffer *xbuf = 0;
  STRPTR buf;
  LONG totlen, res, chunklen;

  if(!FindTagItem(XPK_PackMethod, tags))
    return XPKERR_BADPARAMS;

  if((res = XpkOpenA4NAME((struct XpkFib **) &xbuf, tags A4SUPP)))
    return res;

  totlen = xbuf->xb_InLen;

  CurrentTime(&xbuf->xb_Secs, &xbuf->xb_Mics); /* Start the clock */

  xbuf->xb_Prog.xp_Type = XPKPROG_START;
  xbuf->xb_Prog.xp_ULen = totlen;
  if(callprogress(xbuf))
    return XpkClose((struct XpkFib *) xbuf);

  while(totlen > 0)
  {
    chunklen = xbuf->xb_Fib.xf_NLen;

    if(!(buf = (STRPTR) hookread(xbuf, XIO_READ, NULL, chunklen)))
      break;

    if(XpkWrite((struct XpkFib *) xbuf, buf, chunklen))
      break;

    totlen -= chunklen;

    xbuf->xb_Prog.xp_Type = XPKPROG_MID;	/* Progress report     */
    xbuf->xb_Prog.xp_UCur += chunklen;
    xbuf->xb_Prog.xp_CCur = xbuf->xb_Fib.xf_CCur;
    if(callprogress(xbuf))
      return XpkClose((struct XpkFib *) xbuf);
  }

  if(xbuf->xb_Prog.xp_Type)
  {
    xbuf->xb_Prog.xp_Type = XPKPROG_END;
    xbuf->xb_Prog.xp_CCur += xbuf->xb_Headers.h_LocSize;
    xbuf->xb_Prog.xp_Activity = xbuf->xb_Result ?
      strings[TXT_ABORTED] : xbuf->xb_LastMsg;
    callprogress(xbuf); 	/* Call the hook one last time */
  }

  return XpkClose((struct XpkFib *) xbuf);
}

/*********************************************************************
 *
 * XpkUnpack - unpack a file
 *
 */

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm LIBXpkUnpack(register __a0 struct TagItem *tags A4PROTO)
{
  struct XpkBuffer *xbuf = NULL;
  STRPTR pointer;
  LONG len, res;

  if((res = XpkOpenA4NAME((struct XpkFib **) &xbuf, tags A4SUPP)))
    return res;

  if(xbuf->xb_Flags & XMF_PACKING)
  {
    xbuf->xb_Result = XPKERR_BADPARAMS;
    goto Abort;
  }

  CurrentTime(&xbuf->xb_Secs, &xbuf->xb_Mics); /* Start the clock */

  xbuf->xb_Prog.xp_Type = XPKPROG_START;	/* Initialize progress */
  xbuf->xb_Prog.xp_ULen = xbuf->xb_ULen;
  if(callprogress(xbuf))
    goto Abort;

  if(!hookwrite(xbuf, XIO_TOTSIZE, NULL, xbuf->xb_Fib.xf_ULen + XPK_MARGIN))
  {
#ifdef DEBUG
    DebugError("XpkUnpack: XIO_TOTSIZE failed");
#endif
    goto Abort;
  }

  if(!(pointer = (STRPTR) hookwrite(xbuf, XIO_GETBUF, 0, xbuf->xb_Fib.xf_NLen)))
  {
#ifdef DEBUG
    DebugError("XpkUnpack: XIO_GETBUF failed (a)");
#endif
    goto Abort;
  }

#ifdef DEBUG
  if(xbuf->xb_Result)
    DebugError("XpkUnpack: failure before unpackloop");
#endif

  while((len = XpkRead((struct XpkFib *) xbuf, pointer, XPKLEN_ONECHUNK)) > 0)
  {
    if(!hookwrite(xbuf, XIO_WRITE, pointer, len))
    {
#ifdef DEBUG
      DebugError("XpkUnpack: XIO_WRITE failed");
#endif
      goto Abort;
    }

    xbuf->xb_Prog.xp_Type = XPKPROG_MID;	/* Progress report     */
    xbuf->xb_Prog.xp_CCur = xbuf->xb_Fib.xf_CCur;
    xbuf->xb_Prog.xp_UCur = xbuf->xb_Fib.xf_UCur;
    if(callprogress(xbuf))
      goto Abort;

    if(!(pointer = (STRPTR) hookwrite(xbuf, XIO_GETBUF, NULL, xbuf->xb_Fib.xf_NLen)))
    {
#ifdef DEBUG
      DebugError("XpkUnpack: XIO_GETBUF failed (b)");
#endif
      goto Abort;
    }
  }

  xbuf->xb_Result = len;
#ifdef DEBUG
  if(xbuf->xb_Result)
    DebugError("XpkUnpack: XpkRead failed with %ld", xbuf->xb_Result);
#endif

  if(xbuf->xb_Prog.xp_Type)
  {
    xbuf->xb_Prog.xp_Type = XPKPROG_END;
    xbuf->xb_Prog.xp_Activity = xbuf->xb_Result ? strings[TXT_ABORTED] : xbuf->xb_LastMsg;
    callprogress (xbuf);	/* Call the hook one last time */
  }
Abort:
  return XpkClose((struct XpkFib *) xbuf);
}

/*********************************************************************
 *
 * XpkOpen - open a file for packing/unpacking
 *
 */

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm LIBXpkOpen(register __a0 struct XpkBuffer **xbufp,
	register __a1 struct TagItem *tags A4PROTO)
{
#if defined(DEBUG) && defined(SUPPORT_A4)
  DebugRunTime("XpkOpen: A4 = %ld", a4);
#elif defined(DEBUG)
  DebugRunTime("XpkOpen");
#endif
  return xpkopen(xbufp, tags, 0 A4SUPP);
}

/**************************************************************************
 *
 *   XpkExamine() - inspect a compressed file
 *
 */

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm LIBXpkExamine(register __a0 struct XpkFib *fib,
	register __a1 struct TagItem *tags A4PROTO)
{
  struct XpkBuffer *dummy;
  LONG res;

#if defined(DEBUG) && defined(SUPPORT_A4)
  DebugRunTime("XpkExamine: A4 = %ld", a4);
#elif defined(DEBUG)
  DebugRunTime("XpkExamine");
#endif

  if((res = xpkopen(&dummy, tags, 1 A4SUPP)))
    return res;

  CopyMem(dummy, fib, sizeof(struct XpkFib));
  // copies the entries of XpkFib
  // *fib = dummy->Fib works too, but calls it's own copy-function

  return XpkClose((struct XpkFib *) dummy);
}

/**************************************************************************
 *
 *   XpkRead() - read one chunk from a compressed file
 *
 */

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm LIBXpkRead(register __a0 struct XpkBuffer *xbuf,
	register __a1 STRPTR buf, register __d0 ULONG len)
{
  struct XpkSubParams *xpar;
  struct Library *XpkSubBase = xbuf->xb_SubBase;
  XpkChunkHeader *lochdr = &(xbuf->xb_Headers.h_Loc);
  LONG ulen, clen, rclen, lochdrsize = xbuf->xb_Headers.h_LocSize;
  ULONG csum;
  ULONG maxon_bug; // remove later all assigns to this var - only workaround
		   // for MaxonC++ bug

#ifdef DEBUG
  DebugRunTime("XpkRead");
#endif

  if(!xbuf)
    return XPKERR_NOFUNC;

  if(xbuf->xb_Flags & XMF_EOF)
    return 0;

  switch(xbuf->xb_Format) 
  {
    /*********************** Unpack standard XPK *******************/
  case XPKMODE_UPSTD:
    if(lochdr->xch_Word.xchw_Type == XPKCHUNK_END)
      return 0;

// remove (maxon_bug = ..) later, when Maxon removed the bug!
    if((maxon_bug = hchecksum((STRPTR) lochdr, lochdrsize)))
    {
#ifdef DEBUG
      DebugError("XpkRead: hchecksum(,%ld) failed", lochdrsize);
#endif
      return(xbuf->xb_Result = XPKERR_CHECKSUM);
    }

    if(xbuf->xb_Headers.h_Glob.xsh_Flags & XPKSTREAMF_LONGHEADERS)
      ulen = lochdr->xch_Long.xchl_ULen, clen = lochdr->xch_Long.xchl_CLen;
    else
      ulen = lochdr->xch_Word.xchw_ULen, clen = lochdr->xch_Word.xchw_CLen;
    rclen = ROUNDLONG(clen);

    if(lochdr->xch_Word.xchw_Type == XPKCHUNK_RAW)
    {
// remove later assignment
      if(!(maxon_bug = (ULONG) hookread(xbuf, XIO_READ, buf, rclen + lochdrsize)))
	return xbuf->xb_Result;

      if(!(xbuf->xb_Flags & XMF_NOCRC))
	if((csum=cchecksum((ULONG *) buf, rclen >>2)) != lochdr->xch_Word.xchw_CChk)
	{
#ifdef DEBUG
	  DebugError("XpkRead: cchecksum(,%ld) = %lx != %lx failed", rclen >> 2, csum, (ULONG) lochdr->xch_Word.xchw_CChk);
#endif
	  return (xbuf->xb_Result = XPKERR_CHECKSUM);
        }

      CopyMem(buf + rclen, lochdr, lochdrsize);
    }
    else if(lochdr->xch_Word.xchw_Type == XPKCHUNK_PACKED)
    {
      xpar = &xbuf->xb_PackParam;
      if(!(xpar->xsp_InBuf = hookread(xbuf, XIO_READ, NULL, rclen + lochdrsize)))
	return xbuf->xb_Result;

      if(!(xbuf->xb_Flags & XMF_NOCRC))
	if((csum=cchecksum((ULONG *)xpar->xsp_InBuf, rclen >> 2)) != lochdr->xch_Word.xchw_CChk)
	{
#ifdef DEBUG
	  DebugError("XpkRead: cchecksum(,%ld) = %lx != %lx failed", rclen >>2 , csum, (ULONG) lochdr->xch_Word.xchw_CChk);
#endif
	  return (xbuf->xb_Result = XPKERR_CHECKSUM);
        }
      xbuf->xb_Flags |= XMF_INITED;

      xpar->xsp_InLen = clen;
      xpar->xsp_OutLen = ulen;
      xpar->xsp_OutBufLen = ulen;
      xpar->xsp_Number = 0;
      xpar->xsp_OutBuf = buf;
      xpar->xsp_Password = xbuf->xb_Password;
      xpar->xsp_LibVersion = xbuf->xb_Headers.h_Glob.xsh_SubVrs;

      if((xbuf->xb_Result = XpksUnpackChunk(xpar)))
      {
	return xbuf->xb_Result;
      }

      CopyMem((STRPTR) xpar->xsp_InBuf + rclen, lochdr, lochdrsize);
    }
    else
      return (xbuf->xb_Result = XPKERR_CORRUPTPKD);

    updatefib(xbuf);
    return ulen;

    /********************* Unpack powerpacked file ****************/
  case XPKMODE_UPPP:
    {
#ifdef USE_POWERPACKER
      struct Library *PPBase = xbuf->xb_SubBase;
      STRPTR inbuf, inbufend;

      if(!(inbuf = (STRPTR) hookread(xbuf, XIO_READ, NULL, xbuf->xb_InLen - 4)))
        return xbuf->xb_Result;
      inbufend = inbuf + xbuf->xb_InLen - 4;

      ppDecrunchBuffer(inbufend, buf, (ULONG *) inbuf, DECR_NONE);

      xbuf->xb_Fib.xf_CCur = xbuf->xb_InLen;
      xbuf->xb_Fib.xf_UCur = xbuf->xb_Fib.xf_ULen;
      xbuf->xb_Fib.xf_NLen = 0;
      xbuf->xb_Flags |= XMF_EOF;

      return (LONG) xbuf->xb_ULen;
#else
      return (xbuf->xb_Result = XPKERR_NOFUNC);
#endif /* USE_POWERPACKER */
    }

    /********************* Unpack unpacked file *******************/
  case XPKMODE_UPUP:
    {
      ULONG len = xbuf->xb_Fib.xf_ULen - xbuf->xb_Fib.xf_CCur;

      if(len > CHUNKSIZE)
        len = CHUNKSIZE;
      else
        xbuf->xb_Flags |= XMF_EOF;

// maxon_bug later should be removed
      if(!(maxon_bug = (ULONG)hookread(xbuf, XIO_READ, buf, len)))
        return xbuf->xb_Result;

      xbuf->xb_Fib.xf_CCur += len;
      xbuf->xb_Fib.xf_UCur += len;
      xbuf->xb_Fib.xf_NLen = Min(xbuf->xb_InLen - xbuf->xb_Fib.xf_UCur, CHUNKSIZE) + XPK_MARGIN;

      return (LONG) len;
    }
  }

  return xbuf->xb_Result;
}

/**************************************************************************
 *
 *   XpkWrite() - write a chunk to a compressed file
 *
 */

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm LIBXpkWrite(register __a0 struct XpkBuffer *xbuf,
	register __a1 STRPTR buf, register __d0 ULONG ulen)
{
  struct Library *XpkSubBase = xbuf->xb_SubBase;
  struct XpkSubParams *xpar;
  struct Headers *head = &xbuf->xb_Headers;
  LONG clen, rclen, outbuflen;
  UWORD end[2] = {0,0}; /* last ULONG of buffer, when not longword bounded */
  UBYTE type;
  STRPTR outbuf;
  ULONG maxon_bug; //remove later after correction of bug

  if(!xbuf->xb_FirstChunk)
    xbuf->xb_FirstChunk = ulen;
  if(ulen > xbuf->xb_FirstChunk)
    return (xbuf->xb_Result = XPKERR_BADPARAMS);

  if(xbuf->xb_Flags & XMF_NOPACK) // no packing
  {
    hookwrite(xbuf, XIO_WRITE, buf, ulen);
    xbuf->xb_Fib.xf_UCur += ulen;
    xbuf->xb_Fib.xf_CCur += ulen;
    xbuf->xb_Fib.xf_NLen = Min(xbuf->xb_InLen - xbuf->xb_Fib.xf_UCur,
      (LONG) xbuf->xb_ChunkSize);
    return xbuf->xb_Result;
  }

  /******************* Write the GlobHdr ********************/
  if(!(xbuf->xb_Flags & XMF_GLOBHDR))
  {
    if(!xbuf->xb_Password)
      CopyMem(buf, head->h_Glob.xsh_Initial, Min(16, ulen));
    xbuf->xb_Flags |= XMF_GLOBHDR;
// maxon_bug later should be removed
    if(!(maxon_bug = (ULONG) hookwrite(xbuf, XIO_WRITE, &head->h_Glob,
    sizeof(struct XpkStreamHeader))))
      return xbuf->xb_Result;
    xbuf->xb_Fib.xf_CCur += sizeof(struct XpkStreamHeader);
  }

  /******************* Allocate the buffer *****************/
  outbuflen = ROUNDLONG(ulen + (ulen>>5) + head->h_LocSize) + XPK_MARGIN;
  if(!(outbuf = (STRPTR) hookwrite(xbuf, XIO_GETBUF, NULL, outbuflen)))
    return xbuf->xb_Result;

  outbuf += head->h_LocSize;
  /* compress to behind local header. This is needed by mem-out hook! */

  if(ulen < xbuf->xb_MinChunk)
    goto copychunk;

  /******************* Pack the chunk **********************/
  xpar = &xbuf->xb_PackParam;
  xpar->xsp_InBuf = buf;
  xpar->xsp_InLen = ulen;
  xpar->xsp_OutBuf = outbuf;
  xpar->xsp_OutBufLen = outbuflen - head->h_LocSize;
  xpar->xsp_Number += 1;
  xpar->xsp_Mode = xbuf->xb_PackingMode;
  xpar->xsp_Password = xbuf->xb_Password;
  xpar->xsp_LibVersion = xbuf->xb_SubInfo->xi_LibVersion;

  xbuf->xb_Result = XpksPackChunk(xpar);
  xbuf->xb_Flags |= XMF_INITED;

  type = XPKCHUNK_PACKED;
  clen = xpar->xsp_OutLen;

  if(xbuf->xb_Result == XPKERR_EXPANSION)
  {
    xbuf->xb_Result = 0;
copychunk:
    type = XPKCHUNK_RAW;
    clen = ulen;
    outbuf = buf;
  }

  if(xbuf->xb_Result)
    return xbuf->xb_Result;

  /******************* Write the chunk **********************/
  head->h_Loc.xch_Word.xchw_Type = type;
  if(head->h_Glob.xsh_Flags & XPKSTREAMF_LONGHEADERS)
  {
    head->h_Loc.xch_Long.xchl_ULen = ulen;
    head->h_Loc.xch_Long.xchl_CLen = clen;
  }
  else
  {
    head->h_Loc.xch_Word.xchw_ULen = (WORD) ulen;
    head->h_Loc.xch_Word.xchw_CLen = (WORD) clen;
  }

  if((rclen = clen&3))
  {
    clen -= rclen;
    CopyMem(outbuf+clen, &end, rclen); /* copy the remaining bytes (max 3) */
  }

  head->h_Loc.xch_Word.xchw_CChk = cchecksum((ULONG *) outbuf, clen >> 2)
    ^ end[0] ^ end[1];
  /* add the rest bytes to the checksum */
  
  head->h_Loc.xch_Word.xchw_HChk = 0;
  head->h_Loc.xch_Word.xchw_HChk = hchecksum((STRPTR) &head->h_Loc, head->h_LocSize);

// maxon_bug later should be removed
  if(!(maxon_bug = (ULONG) hookwrite(xbuf, XIO_WRITE, &head->h_Loc, head->h_LocSize)))
    return xbuf->xb_Result;

// remove
  if(!(maxon_bug = (ULONG) hookwrite(xbuf, XIO_WRITE, outbuf, clen)))
    return xbuf->xb_Result;

  if(rclen)
  {
// remove maxon_bug
    if(!(maxon_bug = (ULONG) hookwrite(xbuf, XIO_WRITE, &end, 4)))
      return xbuf->xb_Result;
    clen += 4;
  }

  head->h_Glob.xsh_ULen += ulen;
  
  xbuf->xb_Fib.xf_UCur += ulen;
  xbuf->xb_Fib.xf_CCur += head->h_LocSize + clen;
  xbuf->xb_Fib.xf_NLen = Min(max(xbuf->xb_InLen, head->h_Glob.xsh_ULen) -
    xbuf->xb_Fib.xf_UCur, (LONG) xbuf->xb_ChunkSize);

  return xbuf->xb_Result;
}

/**************************************************************************
 *
 *   XpkSeek() - move around on a compressed file
 *
 */

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm LIBXpkSeek(register __a0 struct XpkBuffer *xbuf,
	register __d0 LONG dist, register __d1 LONG mode)
{
  xbuf->xb_Result = XPKERR_NOFUNC;
  parsegettags(xbuf);

  return xbuf->xb_Result;
}

/**************************************************************************
 *
 *   XpkClose() - finish (de)compressing an XPK file
 *
 */

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm LIBXpkClose(register __a0 struct XpkBuffer *xbuf)
{
  struct Library *XpkSubBase = xbuf->xb_SubBase;
  struct Headers *head = &xbuf->xb_Headers;
  LONG outlen;

  if(!xbuf)
    return 0;

#ifdef DEBUG
  if(xbuf->xb_Result)
    DebugError("XpkClose: failed (%ld) before XpkClose", xbuf->xb_Result);
#endif

  switch(xbuf->xb_Format)
  {
//  case XPKMODE_UPPP:
//    break;
  case XPKMODE_PKSTD:
    {
      if(!xbuf->xb_Result && !(xbuf->xb_Flags & XMF_GLOBHDR|XMF_NOPACK))
      {

        hookwrite(xbuf, XIO_WRITE, &head->h_Glob, sizeof(struct XpkStreamHeader));
#ifdef DEBUG
        if(xbuf->xb_Result) DebugError("XpkClose: failed to write globhdr");
#endif
        xbuf->xb_Fib.xf_CCur += sizeof(struct XpkStreamHeader);
      }
      if(!xbuf->xb_Result && !(xbuf->xb_Flags & XMF_NOPACK))
      {
        /******************* Write final chunk header *****************/
        memset(&head->h_Loc, 0, head->h_LocSize);
        head->h_Loc.xch_Word.xchw_Type = XPKCHUNK_END;
        head->h_Loc.xch_Word.xchw_HChk = 0;
        head->h_Loc.xch_Word.xchw_HChk =
          hchecksum((STRPTR) &head->h_Loc, head->h_LocSize);

        hookwrite(xbuf, XIO_WRITE, &head->h_Loc, head->h_LocSize);
#ifdef DEBUG
        if(xbuf->xb_Result) DebugError("XpkClose: failed to write lochdr");
#endif
        xbuf->xb_Fib.xf_CCur += head->h_LocSize;
        outlen = xbuf->xb_Fib.xf_CCur;

        /********************** Write global header *******************/
        hookwrite(xbuf, XIO_SEEK, NULL, -outlen);
#ifdef DEBUG
        if(xbuf->xb_Result) DebugError("XpkClose: failed to reset output");
#endif

        head->h_Glob.xsh_Pack = XPK_COOKIE;
        head->h_Glob.xsh_CLen = outlen - 8;
        head->h_Glob.xsh_HChk = 0;
        head->h_Glob.xsh_HChk =
          hchecksum((STRPTR) &head->h_Glob, sizeof(struct XpkStreamHeader));

        hookwrite(xbuf, XIO_WRITE, &head->h_Glob, sizeof(struct XpkStreamHeader));
#ifdef DEBUG
        if(xbuf->xb_Result) DebugError("XpkClose: failed updating globalhdr");
#endif

        hookwrite(xbuf, XIO_SEEK, 0, outlen - sizeof(struct XpkStreamHeader));
#ifdef DEBUG
        if(xbuf->xb_Result) DebugError("XpkClose: failed to SEEK to end of output");
#endif
      }
      xbuf->xb_Fib.xf_CLen = xbuf->xb_Fib.xf_CCur;
      xbuf->xb_Fib.xf_ULen = xbuf->xb_Fib.xf_UCur;

      /*************************** Shut down *************************/
      if(xbuf->xb_Flags & XMF_INITED)
        XpksPackFree(&xbuf->xb_PackParam);
    }
    break;
  case XPKMODE_UPSTD:
    if(xbuf->xb_Flags & XMF_INITED)
      XpksUnpackFree(&xbuf->xb_PackParam);
    break;
  }

  hookread(xbuf, xbuf->xb_Result ? XIO_ABORT : XIO_FREE, NULL, 0);
#ifdef DEBUG
  if(xbuf->xb_Result) DebugError("XpkClose: failed read ABORT/FREE");
#endif

  hookwrite(xbuf, xbuf->xb_Result ? XIO_ABORT : XIO_FREE, NULL, 0);
#ifdef DEBUG
  if(xbuf->xb_Result) DebugError("XpkClose: failed write ABORT/FREE");
#endif

  if(xbuf->xb_Result && xbuf->xb_Result != XPKERR_CHECKSUM && xbuf->xb_OutName)
    DeleteFile(xbuf->xb_OutName);

  parsegettags(xbuf);		/* Send information to the user */

#ifdef DEBUG
    DebugRunTime("XpkClose: InLen %ld, CLen %ld, ULen %ld, ID %.4s", xbuf->xb_InLen,
    xbuf->xb_Fib.xf_CLen, xbuf->xb_Fib.xf_ULen, &xbuf->xb_SubID);
#endif

  return freebufs(xbuf);
}

#endif /* XPKMASTER_XPKMASTER_C */

