#define NAME	 "xBench"
#define REVISION "1"

/* Programmheader

	Name:		xBench
	Author:		SDI (before 1.1 Urban Dominik Müller)
	Distribution:	PD
	Description:	xpk benchmark utility
	Compileropts:	-
	Linkeropts:	-l xpkmaster
	Linkeropts SAS: LIB LIB:scm.lib

 1.1   29.11.96 : added version string
*/

#include "SDI_defines.h"
#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"
#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/xpkmaster_lib.h>
#include <pragma/timer_lib.h>
#include <exec/memory.h>
#include <exec/devices.h>

#ifdef __MAXON__
  #define __asm
  #define __saveds
#endif

#define THREE_BUFS	0
#define NOCRC		0

struct timerequest timerequest;
struct Library *TimerBase = NULL;
struct Library *XpkBase = NULL;
BPTR fh = 0;

UBYTE errbuf[XPKERRMSGSIZE + 1];	/* +1 to make room for '\n'        */
STRPTR Password = 0;
STRPTR buf1 = 0, buf2 = 0, buf3 = 0;
LONG bufsize;

void end(STRPTR str)
{
  if(fh)		Close(fh);
  if(buf3)		FreeMem(buf3, bufsize);
  if(buf2)		FreeMem(buf2, bufsize);
  if(buf1)		FreeMem(buf1, bufsize);
  if(TimerBase)		CloseDevice((struct IORequest *) & timerequest);
  if(XpkBase)		CloseLibrary(XpkBase);
  if(str)		printf ("%s\n", str);

  exit (0);
}

void init(void)
{
  if(OpenDevice("timer.device", 0, (struct IORequest *) & timerequest, 0))
    end("Can't open timer.device");

  TimerBase = &timerequest.tr_node.io_Device->dd_Library;

  if(!(XpkBase = OpenLibrary (XPKNAME, 0)))
    end("Can't open " XPKNAME);
}

void testfile(STRPTR packer, STRPTR file)
{
  struct EClockVal eval1, eval2;
  struct FileInfoBlock fib;
  ULONG freq, ulen, ulen2, clen, ctime, utime;
  LONG cf;

  if(!(fh = Open(file, MODE_OLDFILE)))
    end("Cannot open input file");

  if(!(ExamineFH (fh, &fib)))
    end("Failed to ExamineFH input file");

  bufsize = fib.fib_Size + fib.fib_Size / 32 + 2 * XPK_MARGIN;

  if(!(buf1 = (STRPTR) AllocMem(bufsize, MEMF_FAST)))
    end("Out of memory");

  if(!(buf2 = (STRPTR) AllocMem(bufsize, MEMF_FAST)))
    end("Out of memory");

#if THREE_BUFS
  if(!(buf3 = (STRPTR) AllocMem(bufsize, MEMF_FAST)))
    end("Out of memory");
#endif

  ulen = Read(fh, buf1, fib.fib_Size);

  if(ulen != fib.fib_Size)
    end("Could not read whole file with one Read()");

  Close(fh);
  fh = 0;

  /*--------------------------------------------------------*/

  Forbid ();
  freq = ReadEClock (&eval1);
  if(XpkPackTags(XPK_InBuf, buf1,
		 XPK_InLen, ulen,
		 XPK_OutBuf, buf2,
		 XPK_OutBufLen, bufsize,
		 XPK_GetOutLen, &clen,
		 XPK_GetError, errbuf,
		 XPK_Password, Password,
		 XPK_PackMethod, packer,
		 TAG_DONE))
  {
    Permit();
    end(errbuf);
  }

  ReadEClock(&eval2);
  Permit();
  ctime = eval2.ev_lo - eval1.ev_lo;

  /*--------------------------------------------------------*/

  Forbid();
  ReadEClock(&eval1);

  if(XpkUnpackTags(XPK_InBuf, buf2,
		   XPK_InLen, clen,
#if THREE_BUFS
		   XPK_OutBuf, buf3,
#else
		   XPK_OutBuf, buf1,
#endif
		   XPK_OutBufLen, bufsize,
		   XPK_GetOutLen, &ulen2,
		   XPK_GetError, errbuf,
#if NOCRC
		   XPK_NoCRC, TRUE,
#endif
		   XPK_Password, Password,
		   TAG_DONE))
  {
    Permit();
    end(errbuf);
  }

  ReadEClock(&eval2);
  Permit();
  utime = eval2.ev_lo - eval1.ev_lo;

  /*--------------------------------------------------------*/

  cf = 1000 - 1000 * clen / ulen;

  if(cf < 0)
    cf = 0;

  printf("%-8s   %6ld %6ld %2ld.%ld%%    %3ld.%02ld %7ld     %2ld.%02ld %7ld\n",
	  packer,
	  ulen, clen, cf / 10, cf % 10,
	  ctime / freq, (100 * (ctime % freq)) / freq, (int) ((double) freq * (double) ulen / (double) ctime),
	  utime / freq, (100 * (utime % freq)) / freq, (int) ((double) freq * (double) ulen / (double) utime)
    );

  if(ulen != ulen2)
  {
    printf("decompressed length is %ld !!!\n", ulen2);
  }

#if THREE_BUFS
  if(buf3)
  {
    FreeMem(buf3, bufsize);
    buf3 = 0;
  }
#endif
  if(buf2)
  {
    FreeMem(buf2, bufsize);
    buf2 = 0;
  }
  if(buf1)
  {
    FreeMem (buf1, bufsize);
    buf1 = 0;
  }
}

main(int argc, char *argv[])
{
  LONG i = 1;

  if(!strcmp (argv[1], "-p"))
    Password = "testpw", i++;

  init();

  printf("Warning: Have to Forbid() task rescheduling for accurate measurements.\n");
  printf("Packer      UComp   Comp    CF     CTime    CSpd     UTime    USpd\n");
  for(; i < argc - 1; i++)
    testfile (argv[i], argv[argc - 1]);

  end(NULL);
}
