#ifndef XPKMASTER_TAGS_C
#define XPKMASTER_TAGS_C

/* Routinesheader

	Name:		tags.c
	Main:		xpkmaster
	Versionstring:	$VER: tags.c 1.0 (09.10.96)
	Author:		SDI
	Distribution:	PD
	Description:	Tag handling functions

 1.0   09.10.96 : first real version
*/

#include <pragma/dos_lib.h>
#include <pragma/exec_lib.h>
#include <pragma/utility_lib.h>
#include <exec/types.h>
#include "xpkmaster.h"
#include "xpk_strings.h"

static LONG findmethod(struct XpkBuffer *xbuf, STRPTR name);

/* Parse input/output buffer specification tags before an operation */
LONG parsebuftags(struct XpkBuffer *xbuf, struct TagItem *tags,
	ULONG readonly)
{
  struct TagItem *ti, *scan = tags;
//  LONG i = 0, o = 0;
  ULONG data, fh;
  STRPTR inname = NULL, outname = NULL;

  xbuf->xb_Prog.xp_FileName = NULL;

  /* Pass 1 */

  while((ti = MyNextTagItem(&scan)))
  {
    data = ti->ti_Data;

#ifdef BUGGY_SASC
    /* if ti->ti_Tag is 0x40000000 the code produced by SAS jumps to dragonland. */
    /* This together with buggy applications which forget the TAG_END gurus. */
    if((ti->ti_Tag>=XPK_TagBase) && (ti->ti_Tag<=XPK_NoCRC))
#endif
    switch(ti->ti_Tag)
    {
    case XPK_NoClobber:
      if(data) xbuf->xb_Flags |= XMF_NOCLOBBER; break;
    case XPK_FileName:
      xbuf->xb_Prog.xp_FileName = basename((STRPTR) data); break;
    case XPK_GetOutLen:
      xbuf->xb_GetOutLen = (ULONG *) data; break;
    case XPK_GetOutBufLen:
      xbuf->xb_GetOutBufLen = (ULONG *) data; break;
    case XPK_GetError:
      xbuf->xb_ErrBuf = (STRPTR) data; xbuf->xb_ErrBuf[0] = 0; break;
    case XPK_GetOutBuf:
      xbuf->xb_Flags |= XMF_GETOUTBUF;
      xbuf->xb_WMsg.xmm_Flags |= XIO_GETOUTBUF;
      xbuf->xb_WMsg.xmm_BufOfs = 0;
      xbuf->xb_PackParam.xsp_Flags |= XSF_PREVCHUNK;
      xbuf->xb_WHook = &memouthook;
      xbuf->xb_GetOutBuf = (STRPTR *) data;
//      o++;
      break;
    }
  }

  /* Pass 2 */

  while((ti = MyNextTagItem(&tags)))
  {
    data = ti->ti_Data;
#ifdef BUGGY_SASC
    /* if ti->ti_Tag is 0x40000000 the code produced by SAS jumps to dragonland. */
    /* This together with buggy applications which forget the TAG_END gurus. */
    if((ti->ti_Tag>=XPK_TagBase) && (ti->ti_Tag<=XPK_NoCRC))
#endif
    switch(ti->ti_Tag)
    {
      /* Ways to specify input data */
    case XPK_InName:
      inname = basename((STRPTR) data);		/* ??? Why ??? CvR */
      if(!(data = Open((STRPTR) data, MODE_OLDFILE)))
      {
        xbuf->xb_Result = XPKERR_IOERRIN; xbuf->xb_Result2 = IoErr();
	return xbuf->xb_Result;
      }
      xbuf->xb_RMsg.xmm_Flags |= XMF_PRIVFH;
    case XPK_InFH:
      xbuf->xb_RMsg.xmm_FH = data;
      xbuf->xb_RHook = &fhinhook;
//      i++;
      break;
    case XPK_InBuf:
      xbuf->xb_RMsg.xmm_Buf = (STRPTR) data;
      xbuf->xb_RMsg.xmm_BufOfs = 0;
      xbuf->xb_RHook = &meminhook;
//      i++;
      break;
    case XPK_InLen:
      xbuf->xb_InLen = xbuf->xb_RMsg.xmm_Len = data; break;
    case XPK_InHook:
      xbuf->xb_RHook = (struct Hook *) data;
//      i++;
      break;

      /* Ways to specify output data */
    case XPK_OutName:
      outname = basename((STRPTR) data);	/* ??? Why ??? CvR */
      if(xbuf->xb_Flags & XMF_NOCLOBBER)
	if((fh = Open((STRPTR) data, MODE_OLDFILE)))
	  return Close(fh), xbuf->xb_Result = XPKERR_FILEEXISTS;
      xbuf->xb_OutName = (STRPTR) data;
      if(!(data = Open((STRPTR) data, MODE_NEWFILE)))
      {
        xbuf->xb_Result = XPKERR_IOERROUT; xbuf->xb_Result2 = IoErr();
        return xbuf->xb_Result;
      }
      xbuf->xb_WMsg.xmm_Flags |= XMF_PRIVFH;
    case XPK_OutFH:
      xbuf->xb_WMsg.xmm_FH = data;
      xbuf->xb_WHook = &fhouthook;
//      o++;
      break;
    case XPK_OutBuf:
      xbuf->xb_WMsg.xmm_Buf = (STRPTR) data;
      xbuf->xb_WMsg.xmm_BufOfs = 0;
      xbuf->xb_WHook = &memouthook;
      xbuf->xb_PackParam.xsp_Flags |= XSF_PREVCHUNK;
//      o++;
      break;
    case XPK_OutBufLen:
      xbuf->xb_WMsg.xmm_BufLen = data;
      break;
    case XPK_OutHook:
      xbuf->xb_WHook = (struct Hook *) data;
//      o++;
      break;

      /* Other junk */
    case XPK_PackMethod:
      xbuf->xb_Flags |= XMF_PACKING;
      if(findmethod(xbuf, (STRPTR) data))
	  return xbuf->xb_Result;
      break;
    case XPK_Password:
      xbuf->xb_Password = (STRPTR) data;
      break;
    case XPK_PassThru:
      if (data)
	xbuf->xb_Flags |= XMF_PASSTHRU;
      break;
    case XPK_OutMemType:
      xbuf->xb_WMsg.xmm_MemType = data;
      break;
    case XPK_ChunkHook:
      xbuf->xb_ChunkHook = (struct Hook *) data;
      break;
    case XPK_ChunkSize:
      xbuf->xb_ChunkSize = ROUNDLONG(data);	/* This may get adjusted later */
      break;
    case XPK_PackMode:
      xbuf->xb_PackingMode = data;
      break;
    case XPK_TaskPri:
      SetTaskPri(FindTask(NULL), data);
      xbuf->xb_Flags |= XMF_OWNTASKPRI;
      break;
    case XPK_ShortError:
      xbuf->xb_Flags |= XMF_SHORTERR;
      break;
    case XPK_StepDown:
      xbuf->xb_PackParam.xsp_Flags |= XSF_STEPDOWN;
      break;
    case XPK_LossyOK:
      xbuf->xb_Flags |= XMF_LOSSYOK;
      break;
    case XPK_NoCRC:
      xbuf->xb_Flags |= XMF_NOCRC;
      break;
    }
  }

  if(xbuf->xb_Flags & XMF_PACKING)
    xbuf->xb_PackParam.xsp_Flags &= ~XSF_PREVCHUNK;

  if(xbuf->xb_Password && !*xbuf->xb_Password)
    xbuf->xb_Password = NULL;

  if(!inname)
    inname = outname;
  if(!outname)
    outname = inname;

  if(!xbuf->xb_Prog.xp_FileName)
    if(xbuf->xb_Flags & XMF_PACKING)
      xbuf->xb_Prog.xp_FileName = inname;
    else
      xbuf->xb_Prog.xp_FileName = outname;

  if(!xbuf->xb_Prog.xp_FileName)
    xbuf->xb_Prog.xp_FileName = "";

  /* Make sure we got ONE input and ONE output */
//  if(i != 1 || (!readonly && o != 1))
//  {
//    xbuf->xb_Result = XPKERR_BADPARAMS;
//    return xbuf->xb_Result;
//  }

  return (xbuf->xb_Result = 0);
}

#ifndef XPK_MINOS_37
ULONG findtag (struct TagItem *tags, ULONG tag)
{
  struct TagItem *ti;

  while((ti = MyNextTagItem(&tags)))
    if(ti->ti_Tag == tag)
      return ti->ti_Data;
  return 0;
}
#endif

void parseerrortags (struct TagItem *tags)
{
  struct TagItem *ti;

  while((ti = MyNextTagItem(&tags)))
  {
    if(ti->ti_Tag == XPK_GetError)
      sprintf((STRPTR) ti->ti_Data, TXT_OUT_OF_MEMORY);
  }
}

/* Parse XPK_Get... tags after an operation is finished */
void parsegettags(struct XpkBuffer *xbuf)
{
  if(xbuf->xb_GetOutBuf)
    *xbuf->xb_GetOutBuf = xbuf->xb_WMsg.xmm_Buf;

  if(xbuf->xb_GetOutLen)
    if(xbuf->xb_Flags & XMF_PACKING)
      *xbuf->xb_GetOutLen = xbuf->xb_Fib.xf_CLen;
    else
      *xbuf->xb_GetOutLen = xbuf->xb_Fib.xf_ULen;

  if(xbuf->xb_GetOutBufLen)
    *xbuf->xb_GetOutBufLen = xbuf->xb_WMsg.xmm_BufLen;

  if(xbuf->xb_ErrBuf)
    geterror(xbuf);
}

#ifndef XPK_MINOS_37
/* Routines to emulate utility.library routines on pre-2.0 machines */
/* should be killed next time */
struct TagItem *MyNextTagItem(struct TagItem **listpt)
{
  if(UtilityBase)
    return (struct TagItem *) NextTagItem(listpt);
  else
  {
    if((listpt) && (*listpt) && ((*listpt)->ti_Tag != TAG_DONE))
      return ((*listpt)++);
    else
      return (0L);
  }
}
#endif

/* Find a compression library/method given a name */
static LONG findmethod(struct XpkBuffer *xbuf, STRPTR name)
{
  struct Library *XpkSubBase;
  struct XpkInfo *subinfo;
  STRPTR t;

  /* Try to use the first four letters as the ID */
  xbuf->xb_PackingMode = 0;
  if((XpkSubBase = opensub(xbuf, idfromname(name))))
  {
    subinfo = XpksPackerInfo();
    xbuf->xb_PackingMode = subinfo->xi_DefMode;
    if(name[4] == '.' && name[5])
      xbuf->xb_PackingMode = strtol(name + 5, 0, 10);
    if((t = strchr(name, '/')))
      xbuf->xb_Password = t + 1;
    return 0;
  }
  return xbuf->xb_Result;
}
#endif /* XPKMASTER_TAGS_C */
