XADMaster/libxad/clientfunc.c
2011-05-12 00:35:43 +03:00

614 lines
18 KiB
C
Executable file

#ifndef XADMASTER_CLIENTFUNC_C
#define XADMASTER_CLIENTFUNC_C
/* $Id: clientfunc.c,v 1.19 2005/06/23 14:54:36 stoecker Exp $
the client support functions
XAD library system for archive handling
Copyright (C) 1998 and later by Dirk Stöcker <soft@dstoecker.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "include/functions.h"
#include "include/version.h"
#include <ctype.h> /* needed for isprint() */
FUNCxadGetClientInfo /* no args */
{
return xadMasterBase->xmb_FirstClient;
}
ENDFUNC
FUNCxadAddDiskEntry /* struct xadDiskInfo *di, struct xadArchiveInfoP *ai,
xadTAGPTR tags */
{
struct xadDiskInfo *ldi;
xadTAGPTR ti;
xadUINT32 i;
xadERROR ret = 0;
#ifdef DEBUG
DebugHookTagList("xadAddDiskEntry()", tags);
#endif
di->xdi_EntryNumber = ++ai->xaip_LastEntryNumber;
if((ldi = ai->xaip_LastDiskEntry))
ldi->xdi_Next = di;
else
ai->xaip_ArchiveInfo.xai_DiskInfo = di;
ai->xaip_LastDiskEntry = di;
di->xdi_Next = 0;
/* never return errors before this point! */
ldi = ai->xaip_ArchiveInfo.xai_CurDisk;
ai->xaip_ArchiveInfo.xai_CurDisk = di;
if(!((i = callprogress(ai, 0, XADPMODE_NEWENTRY, xadMasterBase)) & XADPIF_OK))
ret = XADERR_BREAK;
ai->xaip_ArchiveInfo.xai_CurDisk = ldi; /* reset */
if(!ret && (ti = FindTagItem(XAD_SETINPOS, tags)) &&
(ai->xaip_ArchiveInfo.xai_InPos != ti->ti_Data
|| FindTagItem(XAD_USESKIPINFO, tags)))
{
ret = xadHookTagAccessA(XADM_PRIV XADAC_INPUTSEEK,
ti->ti_Data-ai->xaip_ArchiveInfo.xai_InPos, 0, XADM_AI(ai), tags);
}
return ret;
}
ENDFUNC
FUNCxadAddFileEntry /* struct xadFileInfo *fi, struct xadArchiveInfoP *ai,
xadTAGPTR tags */
{
struct xadFileInfo *lfi;
xadTAGPTR ti;
xadUINT32 i;
xadERROR ret = 0;
#ifdef DEBUG
DebugHookTagList("xadAddFileEntry()", tags);
if(fi->xfi_Special)
DebugRunTime("LIBxadAddFileEntry: entry '%s' has special info",
fi->xfi_FileName);
#endif
lfi = ai->xaip_LastFileEntry;
fi->xfi_EntryNumber = ++ai->xaip_LastEntryNumber;
if(lfi && (fi->xfi_Flags & XADFIF_DIRECTORY)
&& GetTagData(XAD_INSERTDIRSFIRST, 0, tags))
{
struct xadFileInfo *lfi2 = 0;
lfi = ai->xaip_ArchiveInfo.xai_FileInfo;
while(lfi && (lfi->xfi_Flags & XADFIF_DIRECTORY) &&
stricmp(lfi->xfi_FileName, fi->xfi_FileName) <= 0)
{
lfi2 = lfi; lfi = lfi->xfi_Next;
}
if(lfi2)
lfi2->xfi_Next = fi;
else
ai->xaip_ArchiveInfo.xai_FileInfo = fi;
if(!(fi->xfi_Next = lfi))
ai->xaip_LastFileEntry = fi;
}
else
{
if(lfi)
lfi->xfi_Next = fi;
else
ai->xaip_ArchiveInfo.xai_FileInfo = fi;
fi->xfi_Next = 0;
ai->xaip_LastFileEntry = fi;
}
/* never return errors before this point! */
lfi = ai->xaip_ArchiveInfo.xai_CurFile;
ai->xaip_ArchiveInfo.xai_CurFile = fi;
if(!((i = callprogress(ai, 0, XADPMODE_NEWENTRY, xadMasterBase))
& XADPIF_OK))
ret = XADERR_BREAK;
ai->xaip_ArchiveInfo.xai_CurFile = lfi; /* reset */
if(!ret && (ti = FindTagItem(XAD_SETINPOS, tags)) &&
(ai->xaip_ArchiveInfo.xai_InPos != ti->ti_Data
|| FindTagItem(XAD_USESKIPINFO, tags)))
ret = xadHookTagAccessA(XADM XADAC_INPUTSEEK,
ti->ti_Data-ai->xaip_ArchiveInfo.xai_InPos, 0,
XADM_AI(ai), tags);
return ret;
}
ENDFUNC
FUNCxadHookAccess /* xadUINT32 command, xadSignSize data, xadPTR buffer,
struct xadArchiveInfoP *ai */
{
return xadHookTagAccessA(XADM_PRIV command, data, buffer, XADM_AI(ai), 0);
}
ENDFUNC
static xadERROR skipread(xadUINT8 *buf, xadSize size,
struct xadArchiveInfoP *ai, xadUINT32 skip)
{
#ifdef AMIGA
struct xadMasterBaseP *xadMasterBase = (struct xadMasterBaseP *) ai->xaip_MasterBase;
struct UtilityBase *UtilityBase = xadMasterBase->xmb_UtilityBase;
#endif
struct xadHookParam *ihp;
struct Hook *ih;
const struct xadSkipInfo *si, *si2;
xadERROR ret = 0;
xadSize s;
ihp = &(ai->xaip_InHookParam);
ih = ai->xaip_InHook;
if(ai->xaip_ArchiveInfo.xai_SkipInfo && skip)
{
while(!ret && size)
{
si2 = 0;
for(si = ai->xaip_ArchiveInfo.xai_SkipInfo; si; si = si->xsi_Next)
{
/* skip buffer at start */
if(si->xsi_Position <= ai->xaip_ArchiveInfo.xai_InPos &&
si->xsi_Position+si->xsi_SkipSize > ai->xaip_ArchiveInfo.xai_InPos)
{
ihp->xhp_Command = XADHC_SEEK;
ihp->xhp_CommandData = si->xsi_Position+si->xsi_SkipSize
- ai->xaip_ArchiveInfo.xai_InPos;
ret = CallHookPkt(ih, ai, ihp);
ai->xaip_ArchiveInfo.xai_InPos = ihp->xhp_DataPos;
}
else if(si->xsi_Position > ai->xaip_ArchiveInfo.xai_InPos &&
(!si2 || si2->xsi_Position > si->xsi_Position))
si2 = si;
}
if(!ret)
{
if(!si2 || (s = si2->xsi_Position - ai->xaip_ArchiveInfo.xai_InPos)
> size)
s = size;
ihp->xhp_Command = XADHC_READ;
ihp->xhp_BufferPtr = buf;
ihp->xhp_BufferSize = s;
ret = CallHookPkt(ih, ai, ihp);
buf += s;
ai->xaip_ArchiveInfo.xai_InPos = ihp->xhp_DataPos;
size -= s;
}
}
}
else
{
ihp->xhp_Command = XADHC_READ;
ihp->xhp_BufferPtr = buf;
ihp->xhp_BufferSize = size;
ret = CallHookPkt(ih, ai, ihp);
ai->xaip_ArchiveInfo.xai_InPos = ihp->xhp_DataPos;
}
return ret;
}
xadSignSize getskipsize(xadSignSize data, const struct xadArchiveInfoP *ai)
{
const struct xadSkipInfo *si, *silo, *sihi, *sit;
#ifdef DEBUG
xadSignSize sdata;
sdata = data;
#endif
for(si = silo = sihi = ai->xaip_ArchiveInfo.xai_SkipInfo; si;
si = si->xsi_Next)
{
if(si->xsi_Position > sihi->xsi_Position)
sihi = si;
if(si->xsi_Position < silo->xsi_Position)
silo = si;
}
if(data < 0) /* skip when entries are at buffer start or in buffer */
{
for(;;)
{
if(sihi->xsi_Position < ai->xaip_ArchiveInfo.xai_InPos)
{
if(sihi->xsi_Position + sihi->xsi_SkipSize
> ai->xaip_ArchiveInfo.xai_InPos)
data -= ai->xaip_ArchiveInfo.xai_InPos - sihi->xsi_Position;
else if(sihi->xsi_Position + sihi->xsi_SkipSize
> ai->xaip_ArchiveInfo.xai_InPos+data)
data -= sihi->xsi_SkipSize;
}
if(silo == sihi)
break;
else
{
sit = silo;
for(si = ai->xaip_ArchiveInfo.xai_SkipInfo; si; si = si->xsi_Next)
{
if(si->xsi_Position > sit->xsi_Position && si->xsi_Position
< sihi->xsi_Position)
sit = si;
}
sihi = sit;
}
}
}
else
{
for(;;)
{
if(silo->xsi_Position >= ai->xaip_ArchiveInfo.xai_InPos) /* in buffer */
{
if(silo->xsi_Position <= ai->xaip_ArchiveInfo.xai_InPos+data)
data += silo->xsi_SkipSize;
}
else if(silo->xsi_Position+silo->xsi_SkipSize
> ai->xaip_ArchiveInfo.xai_InPos) /* first border partial */
data += silo->xsi_Position+silo->xsi_SkipSize
-ai->xaip_ArchiveInfo.xai_InPos;
if(silo == sihi)
break;
else
{
sit = sihi;
for(si = ai->xaip_ArchiveInfo.xai_SkipInfo; si; si = si->xsi_Next)
{
if(si->xsi_Position < sit->xsi_Position && si->xsi_Position
> silo->xsi_Position)
sit = si;
}
silo = sit;
}
}
}
#ifdef DEBUG
if(sdata != data)
DebugRunTime("getskipsize: changed seeksize from %ld to %ld", sdata, data);
#endif
return data;
}
FUNCxadHookTagAccess /* xadUINT32 command, xadSignSize data, xadPTR buffer,
struct xadArchiveInfo *ai, xadTAGPTR tags */
{
xadERROR ret = 0;
xadUINT32 skip = 0;
struct xadHookParam *ihp, *ohp;
struct Hook *ih, *oh;
xadTAGPTR ti;
struct TagItem tis[2];
xadUINT32 *crc32 = 0, crc32ID = XADCRC32_ID1;
xadUINT16 *crc16 = 0, crc16ID = XADCRC16_ID1;
#ifdef DEBUG
static const xadSTRPTR comname[] = {"XADAC_READ", "XADAC_WRITE",
"XADAC_COPY", "XADAC_INPUTSEEK", "XADAC_OUTPUTSEEK"};
DebugHookTagList("xadHookAccess(%-16s, %7lld, %08lx, .) pos(%6lld|%6lld)", tags,
comname[command-XADAC_READ], data, buffer, ai->xaip_ArchiveInfo.xai_InPos,
ai->xaip_ArchiveInfo.xai_OutPos);
#endif
tis[0].ti_Tag = XAD_SECTORLABELS;
tis[0].ti_Data = 0;
tis[1].ti_Tag = TAG_DONE;
ihp = &(ai->xaip_InHookParam);
ohp = &(ai->xaip_OutHookParam);
ih = ai->xaip_InHook;
oh = ai->xaip_OutHook;
if((!ih && (command == XADAC_READ || command == XADAC_INPUTSEEK
|| command == XADAC_COPY)) || (!oh && (command == XADAC_WRITE
|| command == XADAC_OUTPUTSEEK || command == XADAC_COPY)))
return XADERR_BADPARAMS;
ti = tags;
while((tags = NextTagItem(&ti)))
{
switch(tags->ti_Tag)
{
case XAD_USESKIPINFO: skip = (xadUINT32) tags->ti_Data; break;
case XAD_SECTORLABELS: tis[0].ti_Data = tags->ti_Data; break;
case XAD_GETCRC32: crc32 = (xadUINT32 *)(uintptr_t) tags->ti_Data; break;
case XAD_GETCRC16: crc16 = (xadUINT16 *)(uintptr_t) tags->ti_Data; break;
case XAD_CRC32ID: crc32ID = (xadUINT32) tags->ti_Data; break;
case XAD_CRC16ID: crc16ID = (xadUINT16) tags->ti_Data; break;
}
}
if(tis[0].ti_Data && (data&(512-1)))
return XADERR_BADPARAMS;
switch(command)
{
case XADAC_READ:
ret = skipread(buffer, data, ai, skip);
if(crc32)
*crc32 = xadCalcCRC32(XADM_PRIV crc32ID, *crc32, data, buffer);
if(crc16)
*crc16 = xadCalcCRC16(XADM_PRIV crc16ID, *crc16, data, buffer);
break;
case XADAC_WRITE:
ohp->xhp_Command = XADHC_WRITE;
ohp->xhp_BufferPtr = buffer;
ohp->xhp_BufferSize = data;
if(tis[0].ti_Data)
{
#ifdef DEBUG
xadINT32 i, j;
xadUINT8 r[16*2+1+16+1], *s;
s = (xadUINT8 *) tis[0].ti_Data;
for(i = 0; i < data; i += 512)
{
for(j = 0; j < 16; ++j)
{
r[j*2] = (*s/16 >= 10) ? (*s/16+'A'-10) : (*s/16+'0');
r[j*2+1] = (*s%16 >= 10) ? (*s%16+'A'-10) : (*s%16+'0');
r[32] = ' ';
r[33+j] = isprint(*s) ? *s : '.';
++s;
r[33+16] = 0;
}
DebugOther("SectorLabel: %s", r);
}
#endif
ohp->xhp_TagList = tis;
}
ret = CallHookPkt(oh, ai, ohp);
ai->xaip_ArchiveInfo.xai_OutPos = ohp->xhp_DataPos;
if(ohp->xhp_DataPos > ai->xaip_ArchiveInfo.xai_OutSize)
{
ai->xaip_ArchiveInfo.xai_OutSize = ohp->xhp_DataPos;
if(!ret)
{
xadUINT32 i;
if(!((i = callprogress(ai, 0, XADPMODE_PROGRESS, xadMasterBase))
& XADPIF_OK))
ret = XADERR_BREAK;
else if(i & XADPIF_SKIP)
ret = XADERR_SKIP;
}
}
if(crc32)
*crc32 = xadCalcCRC32(XADM crc32ID, *crc32, data, buffer);
if(crc16)
*crc16 = xadCalcCRC16(XADM crc16ID, *crc16, data, buffer);
break;
case XADAC_COPY:
{
xadSize bufsize;
xadPTR buf;
if((bufsize = data) > 51200)
bufsize = 51200;
if((buf = xadAllocVec(XADM bufsize, XADMEMF_PUBLIC)))
{
ohp->xhp_Command = XADHC_WRITE;
ohp->xhp_BufferPtr = buf;
while(data > 0 && !ret)
{
ohp->xhp_BufferSize = data > bufsize ? bufsize : data;
if(!(ret = skipread(buf, ohp->xhp_BufferSize, ai, skip)))
ret = CallHookPkt(oh, ai, ohp);
if(crc32)
*crc32 = xadCalcCRC32(XADM crc32ID, *crc32, ohp->xhp_BufferSize,
ohp->xhp_BufferPtr);
if(crc16)
*crc16 = xadCalcCRC16(XADM crc16ID, *crc16, ohp->xhp_BufferSize,
ohp->xhp_BufferPtr);
ai->xaip_ArchiveInfo.xai_OutPos = ohp->xhp_DataPos;
if(ohp->xhp_DataPos > ai->xaip_ArchiveInfo.xai_OutSize)
{
ai->xaip_ArchiveInfo.xai_OutSize = ohp->xhp_DataPos;
if(!ret)
{
xadUINT32 i;
if(!((i = callprogress(ai, 0, XADPMODE_PROGRESS,
xadMasterBase)) & XADPIF_OK))
ret = XADERR_BREAK;
else if(i & XADPIF_SKIP)
ret = XADERR_SKIP;
}
}
data -= ohp->xhp_BufferSize;
}
xadFreeObjectA(XADM buf, 0);
}
else
ret = XADERR_NOMEMORY;
}
break;
case XADAC_INPUTSEEK:
if(skip)
data = getskipsize(data, ai);
ihp->xhp_Command = XADHC_SEEK;
ihp->xhp_CommandData = data;
ret = CallHookPkt(ih, ai, ihp);
ai->xaip_ArchiveInfo.xai_InPos = ihp->xhp_DataPos;
break;
case XADAC_OUTPUTSEEK:
ohp->xhp_Command = XADHC_SEEK;
ohp->xhp_CommandData = data;
ret = CallHookPkt(oh, ai, ohp);
ai->xaip_ArchiveInfo.xai_OutPos = ohp->xhp_DataPos;
break;
default: ret = XADERR_NOTSUPPORTED; break;
}
#ifdef DEBUG
if(ret)
DebugError("xadHookAccess returns \"%s\" (%ld)", xadGetErrorText(XADM ret), ret);
#endif
return ret;
}
ENDFUNC
xadUINT32 callprogress(const struct xadArchiveInfoP *ai, xadUINT32 stat,
xadUINT32 mode, struct xadMasterBaseP * xadMasterBase)
{
xadUINT32 ret = XADPIF_OK;
struct xadProgressInfo *pi;
#ifdef AMIGA
struct UtilityBase *UtilityBase = xadMasterBase->xmb_UtilityBase;
#endif
#ifdef DEBUG
DebugRunTime("callprogress: hook = $%08lx", ai->xaip_ProgressHook);
#endif
if(ai->xaip_ProgressHook)
{
if((pi = (struct xadProgressInfo *) xadAllocObjectA(XADM
XADOBJ_PROGRESSINFO, 0)))
{
pi->xpi_Mode = mode;
pi->xpi_Client = ai->xaip_ArchiveInfo.xai_Client;
pi->xpi_DiskInfo = ai->xaip_ArchiveInfo.xai_CurDisk;
pi->xpi_FileInfo = ai->xaip_ArchiveInfo.xai_CurFile;
pi->xpi_CurrentSize = ai->xaip_ArchiveInfo.xai_OutSize;
pi->xpi_LowCyl = ai->xaip_ArchiveInfo.xai_LowCyl;
pi->xpi_HighCyl = ai->xaip_ArchiveInfo.xai_HighCyl;
if(mode == XADPMODE_ERROR)
{
pi->xpi_Error = stat; stat = 0;
}
pi->xpi_Status = stat;
ret = CallHookPkt(ai->xaip_ProgressHook, 0, pi);
xadFreeObjectA(XADM pi, 0);
}
}
return ret;
}
xadUINT32 callprogressFN(const struct xadArchiveInfoP *ai, xadUINT32 stat,
xadUINT32 mode, xadSTRPTR *filename, struct xadMasterBaseP * xadMasterBase)
{
xadUINT32 ret = XADPIF_OK;
struct xadProgressInfo *pi;
#ifdef AMIGA
struct UtilityBase *UtilityBase = xadMasterBase->xmb_UtilityBase;
#endif
#ifdef DEBUG
DebugRunTime("callprogressFN: hook = $%08lx", ai->xaip_ProgressHook);
#endif
if(ai->xaip_ProgressHook)
{
if((pi = (struct xadProgressInfo *) xadAllocObjectA(XADM
XADOBJ_PROGRESSINFO, 0)))
{
pi->xpi_FileName = *filename;
pi->xpi_Mode = mode;
pi->xpi_Client = ai->xaip_ArchiveInfo.xai_Client;
pi->xpi_DiskInfo = ai->xaip_ArchiveInfo.xai_CurDisk;
pi->xpi_FileInfo = ai->xaip_ArchiveInfo.xai_CurFile;
pi->xpi_CurrentSize = ai->xaip_ArchiveInfo.xai_OutSize;
pi->xpi_LowCyl = ai->xaip_ArchiveInfo.xai_LowCyl;
pi->xpi_HighCyl = ai->xaip_ArchiveInfo.xai_HighCyl;
if(mode == XADPMODE_ERROR)
{
pi->xpi_Error = stat; stat = 0;
}
pi->xpi_Status = stat;
ret = CallHookPkt(ai->xaip_ProgressHook, 0, pi);
*filename = pi->xpi_NewName;
xadFreeObjectA(XADM pi, 0);
}
}
return ret;
}
/* Copies all clients given to the central list in xadMasterBase. If any
* entries have xc_Identifier set, searches the list and overwrites the
* first entry with the same identifier. The xc_Flags and add_flags are
* ORed in any new entry. Returns XADTRUE if any client could be added,
* XADFALSE if no client could be added.
*/
xadBOOL xadAddClients(struct xadMasterBaseP *xadMasterBase,
const struct xadClient *clients,
xadUINT32 add_flags)
{
const struct xadClient *xc;
struct xadClient *xc2, *new_xc, *tail;
xadBOOL ok = XADFALSE;
/* go to tail of client list */
tail = xadMasterBase->xmb_FirstClient;
while (tail && tail->xc_Next) tail = tail->xc_Next;
/* for all clients */
for (xc = clients; xc; xc = xc->xc_Next) {
/* reject client if it is too new to be used */
if (xc->xc_MasterVersion > XADMASTERVERSION) continue;
/* if client has an ID, try and find if a client with that ID already
* exists in the list, and overwrite it */
if (xc->xc_Identifier) {
/* loop through all clients */
for (xc2 = xadMasterBase->xmb_FirstClient; xc2; xc2 = xc2->xc_Next) {
/* if a matching ID is found */
if (xc2->xc_Identifier == xc->xc_Identifier) {
/* copy over existing client, but don't lose the list link */
new_xc = xc2->xc_Next;
xadCopyMem(XADM xc, xc2, sizeof(struct xadClient));
xc2->xc_Next = new_xc;
xc2->xc_Flags |= add_flags;
ok = XADTRUE;
break;
}
}
/* if we found a match, this client has been added */
if (xc2) continue;
}
/* there was no identifier or no match, so we have to add this client */
if ((new_xc = xadAllocVec(XADM sizeof(struct xadClient), XADMEMF_PUBLIC))) {
xadCopyMem(XADM xc, new_xc, sizeof(struct xadClient));
new_xc->xc_Next = NULL;
new_xc->xc_Flags |= add_flags;
if (tail) tail->xc_Next = new_xc;
else xadMasterBase->xmb_FirstClient = new_xc;
tail = new_xc;
ok = XADTRUE;
}
}
return ok;
}
/* Removes all clients from the central list in xadMasterBase */
void xadFreeClients(struct xadMasterBaseP *xadMasterBase)
{
struct xadClient *xc, *next;
for (xc = xadMasterBase->xmb_FirstClient; xc; xc = next) {
next = xc->xc_Next;
xadFreeObjectA(XADM xc, 0);
}
xadMasterBase->xmb_FirstClient = NULL;
}
#endif /* XADMASTER_CLIENTFUNC_C */