#ifndef XPKMASTER_XPKMASTER_C
#define XPKMASTER_XPKMASTER_C

/* Routinesheader

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

 1.0   09.10.96 : first real version
*/

#include <pragma/exec_lib.h>
#include <pragma/intuition_lib.h>
#include <pragma/dos_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"

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

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm XpkPack(register __a0 struct TagItem *tags A4PROTO)
{

  struct XpkBuffer *xbuf = NULL;
  STRPTR buf;
  LONG totlen, chunklen, res;

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

  if(findtag(tags, XPK_PackMethod) == -1)
    return XPKERR_BADPARAMS;

  if((res = XpkOpen(&xbuf, tags A4SUPP)))
    return res;

  totlen = xbuf->xb_InLen;

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

  xbuf->xb_Prog.xp_Type = XPKPROG_START;
  xbuf->xb_Prog.xp_ULen = totlen;
  if(callprogress(xbuf))
    goto Abort;

  while(totlen > 0)
  {
    chunklen = xbuf->xb_Fib.xf_NLen;
    if(!(buf = (STRPTR) hookread (xbuf, XIO_READ, NULL, chunklen)))
      goto Abort;

    if(XpkWrite(xbuf, buf, chunklen))
      goto Abort;

    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))
      goto Abort;
  }

/* Abort: Here or below? CvR */
  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 */
  }
Abort:
  return XpkClose(xbuf);
}

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

#ifdef __cplusplus
  extern "C"
#endif

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

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

  if((res = XpkOpen(&xbuf, tags A4SUPP)))
    return res;

#ifdef DEBUG
  if(xbuf->xb_Result)
    DebugError("XpkUnpack: XpkOpen failed?");
#endif

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

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

  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;
  }

#ifdef DEBUG
  DebugRunTime("XpkUnpack:after hookwrite.XIO_TOTSIZE, %ld, %ld, %ld",
  xbuf->xb_WMsg.xmm_BufOfs, xbuf->xb_WMsg.xmm_Size,
  xbuf->xb_WMsg.xmm_BufLen);
#endif

  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
  DebugRunTime("XpkUnpack:after hookwrite.XIO_GETBUF, %ld, %ld, %ld, %ld, %ld, %ld",
  xbuf->xb_WMsg.xmm_BufOfs, xbuf->xb_WMsg.xmm_Size, xbuf->xb_WMsg.xmm_BufLen, xbuf->xb_Fib.xf_CCur,
  xbuf->xb_Fib.xf_UCur, xbuf->xb_Fib.xf_NLen);
#endif

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

  while((len = XpkRead(xbuf, pointer, XPKLEN_ONECHUNK)) > 0)
  {
#ifdef DEBUG
  DebugRunTime("XpkUnpack:in unpack loop - before hookwrite XIO_WRITE, %ld, %ld, %ld, %ld, %ld, %ld, %ld",
  xbuf->xb_WMsg.xmm_BufOfs, xbuf->xb_WMsg.xmm_Size, xbuf->xb_WMsg.xmm_BufLen, xbuf->xb_Fib.xf_CCur,
  xbuf->xb_Fib.xf_UCur, xbuf->xb_Fib.xf_NLen, len);
#endif
    if(!hookwrite(xbuf, XIO_WRITE, pointer, len))
    {
#ifdef DEBUG
      DebugError("XpkUnpack: XIO_WRITE failed");
#endif
      goto Abort;
    }

#ifdef DEBUG
  DebugRunTime("XpkUnpack:in unpack loop - after hookwrite.XIO_WRITE, %ld, %ld, %ld, %ld, %ld, %ld",
  xbuf->xb_WMsg.xmm_BufOfs, xbuf->xb_WMsg.xmm_Size, xbuf->xb_WMsg.xmm_BufLen, xbuf->xb_Fib.xf_CCur,
  xbuf->xb_Fib.xf_UCur, xbuf->xb_Fib.xf_NLen);
#endif

    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;
    }
  }

#ifdef DEBUG
  DebugRunTime("XpkUnpack:after hookwrite.XIO_GETBUF 2nd time, %ld, %ld, %ld",
  xbuf->xb_WMsg.xmm_BufOfs, xbuf->xb_WMsg.xmm_Size, xbuf->xb_WMsg.xmm_BufLen);
#endif

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

/* Abort: Here or below? CvR */
  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 (xbuf);
}

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

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm XpkOpen (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 XpkExamine(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(dummy);
}

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

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm XpkRead(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)))
      {
#ifdef DEBUG
	DebugError("XpkRead: XpksUnpackChunk failed with %ld", xbuf->xb_Result);
#endif
	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_buf 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 XpkWrite(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;
  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);

  /******************* 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 = (ulen + ulen / 32 & ~3) + XPK_MARGIN;
  if(!(outbuf = (STRPTR) hookwrite (xbuf, XIO_GETBUF, NULL, outbuflen)))
    return xbuf->xb_Result;
  outbuf += head->h_LocSize; /* compress to behind local header. */

  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;
  }

  /* zeropad upto next longword */
  for(rclen = clen; rclen & 3; ++rclen) outbuf[rclen] = 0;  

  head->h_Loc.xch_Word.xchw_CChk = cchecksum ((ULONG *) outbuf, rclen / 4);
  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, rclen)))
    return xbuf->xb_Result;

  head->h_Glob.xsh_ULen += ulen;
  
  xbuf->xb_Fib.xf_UCur += ulen;
  xbuf->xb_Fib.xf_CCur += head->h_LocSize + rclen;
  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 XpkSeek(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 XpkClose(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_UPSTD:
    if(xbuf->xb_Flags & XMF_INITED)
      XpksUnpackFree (&xbuf->xb_PackParam);

  case XPKMODE_UPPP:
    break;

  case XPKMODE_PKSTD:
    if(!xbuf->xb_Result && !(xbuf->xb_Flags & XMF_GLOBHDR))
    {
      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)
    {
      /******************* 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);
  }

  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
  if(xbuf->xb_Result)
    DebugError("XpkClose: failed freebufs?");
#endif
  return freebufs(xbuf);
}

#endif /* XPKMASTER_XPKMASTER_C */

