#ifndef XADMASTER_SUPERDUPER3_C
#define XADMASTER_SUPERDUPER3_C

/* Programmheader

	Name:		SuperDuper3.c
	Main:		xadmaster
	Versionstring:	$VER: SuperDuper3.c 1.0 (07.09.1998)
	Author:		SDI
	Distribution:	Freeware
	Description:	SuperDuper3 disk image client

 1.0   07.09.98 : first version
*/

#include <proto/xadmaster.h>
#include <exec/memory.h>
#include "SDI_compiler.h"
#include "xpkstuff.c"

#ifndef XADMASTERFILE
#define SuperDuper3_Client	FirstClient
#define NEXTCLIENT		0
UBYTE version[] = "$VER: SuperDuper3 1.0 (07.09.1998)";
#endif
#define SUPERDUPER3_VERSION	1
#define SUPERDUPER3_REVISION	0

ASM(BOOL) SuperDuper3_RecogData(REG(d0, ULONG size), REG(a0, STRPTR data),
REG(a6, struct xadMasterBase *xadMasterBase))
{
  if(((ULONG *) data)[0] == 0x464F524D &&
  (((ULONG *) data)[2] == 0x53444444 ||
  ((ULONG *) data)[2] == 0x53444844))
    return 1;
  else
    return 0;
}

ASM(LONG) SuperDuper3_GetInfo(REG(a0, struct xadArchiveInfo *ai),
REG(a6, struct xadMasterBase *xadMasterBase))
{
  LONG err;
  ULONG dat[9], num = 0;
  struct xadDiskInfo *xdi;

  if(!(xdi = (struct xadDiskInfo *) xadAllocObjectA(XADOBJ_DISKINFO, 0)))
    return XADERR_NOMEMORY;
  ai->xai_DiskInfo = xdi;

  if((err = xadHookAccess(XADAC_READ, 12, dat, ai)))
    return err;

  xdi->xdi_EntryNumber = 1;
  xdi->xdi_SectorSize = 512;
  xdi->xdi_Cylinders = 80;
  xdi->xdi_Heads = 2;
  xdi->xdi_Flags = XADDIF_GUESSLOWCYL|XADDIF_GUESSHIGHCYL;
/*xdi->xdi_LowCyl = 0; */
  xdi->xdi_TrackSectors = dat[2] == 0x53444844 ? 22 : 11;
  xdi->xdi_CylSectors = 2 * xdi->xdi_TrackSectors;
  xdi->xdi_TotalSectors = 80 * xdi->xdi_CylSectors;

  while(ai->xai_InPos < ai->xai_InSize)
  {
    if((err = xadHookAccess(XADAC_READ, 36, dat, ai)))
      return err;
    if((err = xadHookAccess(XADAC_INPUTSEEK, dat[1]-28, 0, ai)))
      return err;
    ++num;
    if(dat[0] == 0x58504B46 && (dat[8] & (1<<25)))
    { /* check for password flag in every entry */
      ai->xai_Flags |= XADAIF_CRYPTED;
      xdi->xdi_Flags |= XADDIF_CRYPTED;
    }
  }
  if((err = xadHookAccess(XADAC_INPUTSEEK, 12 - ai->xai_InPos, 0, ai)))
    return err;

  if(num > 80)
    return XADERR_ILLEGALDATA;

  xdi->xdi_HighCyl = num-1;

  return 0;
}

ASM(LONG) SuperDuper3_UnArchive(REG(a0, struct xadArchiveInfo *ai),
REG(a6, struct xadMasterBase *xadMasterBase))
{
  LONG i, err = 0, u;
  struct {
    STRPTR a;
    ULONG  s;
  } dat;
  struct ExecBase * SysBase = xadMasterBase->xmb_SysBase;

  u = ai->xai_InPos;

  /* skip entries */
  for(i = ai->xai_CurDisk->xdi_LowCyl; !err && i < ai->xai_LowCyl; ++i)
  {
    if(!(err = xadHookAccess(XADAC_READ, 8, &dat, ai)))
      err = xadHookAccess(XADAC_INPUTSEEK, dat.s, 0, ai);
  }

  for(; !err && i <= ai->xai_HighCyl; ++i)
  {
    if(!(err = xadHookAccess(XADAC_READ, 8, &dat, ai)))
    {
      if(dat.a == (STRPTR) 0x58504B46)
      {
        if(!(err = xadHookAccess(XADAC_INPUTSEEK, -8, 0, ai)))
        {
          if(!(err = xpkDecrunch(&dat.a, &dat.s, ai, xadMasterBase)))
          {
            err = xadHookAccess(XADAC_WRITE, dat.s, dat.a, ai);
            FreeVec(dat.a);
          }
        }
      }
      else /* normal BODY chunk */
        err = xadHookAccess(XADAC_COPY, dat.s, 0, ai);
    }
  }

  /* seek back to start */
  if(!err)
    err = xadHookAccess(XADAC_INPUTSEEK, u-ai->xai_InPos, 0, ai);

  return err;
}

ASM(void) SuperDuper3_Free(REG(a0, struct xadArchiveInfo *ai),
REG(a6, struct xadMasterBase *xadMasterBase))
{
  if(ai->xai_DiskInfo)
  {
    xadFreeObjectA(ai->xai_DiskInfo, 0);
    ai->xai_DiskInfo = 0; /* clear the entry */
  }
}

struct xadClient SuperDuper3_Client = {
NEXTCLIENT, XADCLIENT_VERSION, 1, SUPERDUPER3_VERSION, SUPERDUPER3_REVISION,
12, XADCF_DISKARCHIVER, XADCID_SUPERDUPER3, "SuperDuper3",
(BOOL (*)()) SuperDuper3_RecogData, (LONG (*)()) SuperDuper3_GetInfo,
(LONG (*)()) SuperDuper3_UnArchive, (void (*)()) SuperDuper3_Free};

#endif /* XADASTER_SUPERDUPER3_C */
