/*
 * Sanity Operating System (SOS) filesystem client for XAD.
 * Copyright (C) 2000 Stuart Caie <kyzer@4u.net>
 *
 * Dirk Stoecker, author of the XAD library, is expressly permitted to
 * include this software in his library without conditions or restrictions.
 *
 * For everyone else:
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* This XAD client reads 'Sanity Operating System' disks - trackdisk demos
 * written by Sanity with a standard disk layout.
 *
 * The SOS disk structure is (C) 1992-1995 Dierk Ohlerich (Chaos/Sanity)
 *
 * $VER: SOS.c 1.2 (01.03.2000)
 */

#include <libraries/xadmaster.h>
#include <proto/xadmaster.h>
#include <inline/xadmaster.h>
#include <string.h>

#include "SDI_compiler.h"
#include "ConvertE.c"


#ifndef XADMASTERFILE
#define SOS_Client		FirstClient
#define NEXTCLIENT		0
const UBYTE version[] = "$VER: SOS 1.2 (01.03.2000)";
#endif
#define SOS_VERSION		1
#define SOS_REVISION		2



/* SOS disk structure:
 * Block size = 512
 *
 * Block    0: bootblock - longword 'SOS1' at offset 16
 * Blocks 1-n: SOS operating system code
 * Block    n: first directory block. first file is always "loader"
 *
 * The array of SOSfile structures is terminated with an entry whose
 * offset is 0 (and whose length is 0 and name is "")
 */

struct SOSfile {
  ULONG offset, size;
  char name[24];
};

/* SOS bootblock ids: dostype='DOS\0', id = 'SOS1' */
struct SOSboot {
  ULONG dostype, cksum, magic, branch, id;
};


#define FILESIZE (sizeof(struct SOSfile))
#define BOOTSIZE (sizeof(struct SOSboot))

/* FILESEEK = 'having read a SOSfile, seek back onto a block boundary'
 * BOOTSEEK = 'having read some bootblock data, seek enough such that a
 *             subsequent FILESEEK will seek back onto a block boundary'
 */
#define FILESEEK (512 - FILESIZE)
#define BOOTSEEK (512 - BOOTSIZE + FILESIZE)


ASM(LONG) SOS_GetInfo(REG(a0, struct xadArchiveInfo *ai),
REG(a6, struct xadMasterBase *xadMasterBase)) {

  struct TagItem tags[]  = {
    { XAD_OBJNAMESIZE, 25 },
    { TAG_DONE, 0 }
  };

  struct TagItem datetags[] = {
    { XAD_DATECURRENTTIME, 1 },
    { XAD_GETDATEXADDATE,  0 },
    { TAG_DONE, 0 }
  };

  struct xadFileInfo *link, *fi;
  struct SOSfile file;
  struct SOSboot boot;
  LONG err;
  int n;

  /* check the image */
  if (ai->xai_ImageInfo->xii_SectorSize != 512) return XADERR_FILESYSTEM;


  /* check the bootblock */
  if ((err = xadHookAccess(XADAC_READ, BOOTSIZE, &boot, ai))) return err;
  if ((err = xadHookAccess(XADAC_INPUTSEEK, BOOTSEEK, 0, ai))) return err;
  if (EndConvM32(boot.dostype) != 0x444f5300
  ||  EndConvM32(boot.id)      != 0x534f5331) return XADERR_FILESYSTEM;


  /* search blocks 2-29 for the first directory block */
  for (n = 2; n < 30; n++) {
    if ((err = xadHookAccess(XADAC_INPUTSEEK, FILESEEK, 0, ai))) return err;
    if ((err = xadHookAccess(XADAC_READ, FILESIZE, &file, ai)))  return err;
    if (strncmp("loader", file.name, 24) == 0) break;
  }
  if (n == 30) return XADERR_FILESYSTEM;

  /* main directory entry loop */
  link = NULL; n = 1;

  /* loop ends on entry where offset = 0 */
  while (!err && file.offset != 0) {
    fi = (struct xadFileInfo *) xadAllocObjectA(XADOBJ_FILEINFO, tags);
    if (fi) {
      fi->xfi_EntryNumber = n++;
      fi->xfi_Flags       = XADFIF_NODATE | XADFIF_SEEKDATAPOS;
      fi->xfi_Size        = fi->xfi_CrunchSize = EndConvM32(file.size);
      fi->xfi_DataPos     = EndConvM32(file.offset);
      xadCopyMem(file.name, fi->xfi_FileName, 24);

      /* fill in today's date */
      datetags[1].ti_Data = (ULONG) &fi->xfi_Date;
      xadConvertDatesA(datetags);

      if (link) link->xfi_Next   = fi;    /* link into list */
      else      ai->xai_FileInfo = fi;    /* write head of list */
      link = fi;

      /* read next entry */
      err = xadHookAccess(XADAC_READ, FILESIZE, &file, ai);
    }
    else {
      err = XADERR_NOMEMORY;
    }
  }

  /* handle errors */
  if (err) {
    if (!ai->xai_FileInfo) return err;
    ai->xai_Flags |= XADAIF_FILECORRUPT;
    ai->xai_LastError = err;
  }
  return XADERR_OK;
}


ASM(LONG) SOS_UnArchive(REG(a0, struct xadArchiveInfo *ai),
REG(a6, struct xadMasterBase *xadMasterBase)) {
  return xadHookAccess(XADAC_COPY, ai->xai_CurFile->xfi_Size, NULL, ai);
}


const struct xadClient SOS_Client = {
  NEXTCLIENT, XADCLIENT_VERSION, 5, SOS_VERSION, SOS_REVISION,

  0,						/* minimum archive size     */
  XADCF_FILESYSTEM | XADCF_FREEFILEINFO,	/* type of client and flags */
  0,						/* internal ID (not needed) */
  "SanityOS FS",				/* name of client           */

  /* client functions */
  (BOOL (*)()) NULL,
  (LONG (*)()) SOS_GetInfo,
  (LONG (*)()) SOS_UnArchive,
  (void (*)()) NULL
};
