#ifndef XPKMASTER_TAGS_C
#define XPKMASTER_TAGS_C

/* Routinesheader

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

 1.0   09.10.96 : first real version
 1.1   27.12.96 : removed 1.3 specific functions
 1.2   06.01.97 : added DEBUG info
 1.3   01.03.97 : added new tags
 1.4   07.03.97 : corrected some of the new stuff
 1.5   23.03.97 : fixed enforcer hits of version 1.4
 1.6   24.03.97 : fixed some errors
 1.7   06.06.97 : now only 1 request, when no outfile
*/

#include <pragma/dos_lib.h>
#include <pragma/exec_lib.h>
#include <pragma/utility_lib.h>
#include <xpk/xpkprefs.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;
  ULONG data, fh;

#ifdef DEBUG
  DebugTagList("parsebuftags", tags);
#endif

  /* Pass 1 */

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

    switch(ti->ti_Tag)
    {
    case XPK_Preferences:
      if(!data) xbuf->xb_Flags |= XMF_NOPREFS; break;
    case XPK_ChunkHook:
      xbuf->xb_ChunkHook = (struct Hook *) data;
      break;
    case XPK_NoClobber:
      if(data) xbuf->xb_Flags |= XMF_NOCLOBBER; break;
    case XPK_FileName:
      xbuf->xb_Prog.xp_FileName = FilePart((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; 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;
      break;
    }
  }

  /* get default preferences settings */
  xbuf->xb_Flags |= XMF_EXTERNALS;
  if(!(xbuf->xb_Flags & XMF_NOPREFS))
  {
    struct XpkPrefsSemaphore *sem;

    if((sem = GetPrefsSem()))
    {
      if(sem->xps_MainPrefs)
      {
	if(sem->xps_MainPrefs->xmp_Flags & XPKM_UseXFD)
	  xbuf->xb_Flags |= XMF_XFD;
	if(!(sem->xps_MainPrefs->xmp_Flags & XPKM_UseExternals))
	  xbuf->xb_Flags &= ~XMF_EXTERNALS;
	if(sem->xps_MainPrefs->xmp_Flags & XPKM_AutoPassword)
	  xbuf->xb_Flags |= XMF_AUTOPASSWD;
      }
      ReleaseSemaphore((struct SignalSemaphore *) sem);
    }
  }

  /* Pass 2 */

  while((ti = NextTagItem(&tags)))
  {
    data = ti->ti_Data;

    switch(ti->ti_Tag)
    {
      /* Ways to specify input data */
    case XPK_InName:
      xbuf->xb_InName = FilePart((STRPTR) data);
      if(!(data = Open((STRPTR) data, MODE_OLDFILE)))
      {
//      xbuf->xb_Result2 = IoErr();
 	return (xbuf->xb_Result = XPKERR_IOERRIN);
      }
      xbuf->xb_RMsg.xmm_Flags |= XMF_PRIVFH;
      /* no break, as following is needed too */
    case XPK_InFH:
      xbuf->xb_RMsg.xmm_FH = data;
      xbuf->xb_RHook = &fhinhook;
      break;
    case XPK_InBuf:
      xbuf->xb_RMsg.xmm_Buf = (STRPTR) data;
      xbuf->xb_RMsg.xmm_BufOfs = 0;
      xbuf->xb_RHook = &meminhook;
      break;
    case XPK_InLen:
      xbuf->xb_InLen = xbuf->xb_RMsg.xmm_Len = data; break;
    case XPK_InHook:
      xbuf->xb_RHook = (struct Hook *) data;
      break;

      /* Ways to specify output data */
    case XPK_OutName:
      if(xbuf->xb_Flags & XMF_NOCLOBBER)
	if((fh = Open((STRPTR) data, MODE_OLDFILE)))
	{
	  Close(fh);
	  return (xbuf->xb_Result = XPKERR_FILEEXISTS);
	}
      xbuf->xb_OutName = (STRPTR) data;
      if(!(data = Open((STRPTR) data, MODE_NEWFILE)))
      {
        xbuf->xb_OutName = 0;
//      xbuf->xb_Result2 = IoErr();
 	return (xbuf->xb_Result = XPKERR_IOERROUT);
      }
      xbuf->xb_WMsg.xmm_Flags |= XMF_PRIVFH;
    case XPK_OutFH:
      xbuf->xb_WMsg.xmm_FH = data;
      xbuf->xb_WHook = &fhouthook;
      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;
      break;
    case XPK_OutBufLen:
      xbuf->xb_WMsg.xmm_BufLen = data;
      break;
    case XPK_OutHook:
      xbuf->xb_WHook = (struct Hook *) data;
      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_UseXfdMaster:
      if(data)
        xbuf->xb_Flags |= XMF_XFD;
      else
        xbuf->xb_Flags &= ~XMF_XFD;
      break;
    case XPK_UseExternals:
      if(data)
        xbuf->xb_Flags |= XMF_EXTERNALS;
      else
        xbuf->xb_Flags &= ~XMF_EXTERNALS;
      break;
    case XPK_PassRequest:
      if(data)
        xbuf->xb_Flags |= XMF_AUTOPASSWD;
      else
        xbuf->xb_Flags &= ~XMF_AUTOPASSWD;
      break;
    case XPK_ChunkReport:
      if(data && !xbuf->xb_ChunkHook && !(xbuf->xb_Flags & XMF_NOPREFS))
        xbuf->xb_Flags |= XMF_AUTOPRHOOK;
      break;
    case XPK_OutMemType:
      xbuf->xb_WMsg.xmm_MemType = 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_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 = 0;

  if(!xbuf->xb_Prog.xp_FileName)
  {
    xbuf->xb_Prog.xp_FileName = xbuf->xb_InName;
    if(!(xbuf->xb_Flags & XMF_PACKING) && xbuf->xb_OutName)
      xbuf->xb_Prog.xp_FileName = FilePart(xbuf->xb_OutName);
  }

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

  return (xbuf->xb_Result = 0);
}

void parseerrortags(struct TagItem *tags)
{
  struct TagItem *ti;
  while((ti = NextTagItem(&tags)))
  {
    if(ti->ti_Tag == XPK_GetError)
      XpkFault(XPKERR_NOMEM, 0, (STRPTR) ti->ti_Data, XPKERRMSGSIZE);
  }
}

/* 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)
    XpkFault(xbuf->xb_Result, 0, xbuf->xb_ErrBuf, XPKERRMSGSIZE);
}

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

  /* Try to use the first four letters as the ID */
  xbuf->xb_PackingMode = 0;
  if(!strnicmp(name, "USER", 4) || !name || !*name) /* prefs call */
    return 0;
  else if((XpkSubBase = opensub(xbuf, idfromname(name))))
  {
    subinfo = XpksPackerInfo();
    xbuf->xb_PackingMode = subinfo->xi_DefMode;
    if(name[4] == '.' && name[5])
      xbuf->xb_PackingMode = strtoul(name + 5, 0, 10);
    return 0;
  }
  return xbuf->xb_Result;
}
#endif /* XPKMASTER_TAGS_C */
