XADMaster/libxad/clients/AMPK.c
2017-02-08 13:53:28 +02:00

2566 lines
71 KiB
C
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef XADMASTER_AMPK_C
#define XADMASTER_AMPK_C
/* $Id: AMPK.c,v 1.16 2005/06/23 14:54:40 stoecker Exp $
AmiPack file archiver
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 "../unix/xadClient.h"
#define XADIOGETBITSHIGH
#define XADIOGETBITSLOW
#define XADIOGETBITSLOWR
#define XADIOREADBITSLOW
#include "xadIO.c"
#include "xadIO_Compress.c"
#include "xadIO_XPK.c"
#ifndef XADMASTERVERSION
#define XADMASTERVERSION 13
#endif
XADCLIENTVERSTR("AMPK 1.16 (21.2.2004)")
#define AMPK_VERSION 1
#define AMPK_REVISION 16
#define AMPLUSUNPACK_VERSION AMPK_VERSION
#define AMPLUSUNPACK_REVISION AMPK_REVISION
#define LHWARP_VERSION AMPK_VERSION
#define LHWARP_REVISION AMPK_REVISION
#define COMPDISK_VERSION AMPK_VERSION
#define COMPDISK_REVISION AMPK_REVISION
#define COMPRESS_VERSION AMPK_VERSION
#define COMPRESS_REVISION AMPK_REVISION
#define ARC_VERSION AMPK_VERSION
#define ARC_REVISION AMPK_REVISION
#define ARCCBM_VERSION AMPK_VERSION
#define ARCCBM_REVISION AMPK_REVISION
#define ARCCBMSFX_VERSION AMPK_VERSION
#define ARCCBMSFX_REVISION AMPK_REVISION
#define WARP_VERSION AMPK_VERSION
#define WARP_REVISION AMPK_REVISION
#define SQ_VERSION AMPK_VERSION
#define SQ_REVISION AMPK_REVISION
#define CRUNCH_VERSION AMPK_VERSION
#define CRUNCH_REVISION AMPK_REVISION
#ifndef MAKE_ID
#define MAKE_ID(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d)
#endif
#define xadIOPutFuncRLE90TYPE2 ((xadPTR) 0x80000000)
/* xx9000 --> xx90 */
/* xx90yy --> xx(yy times) */
/* io->xio_PutFuncPrivate may be initialized with 0x80000000 for Type 2 mode */
/* Type 2 mode: xx9001 --> xx90 instead of xx */
static xadUINT8 xadIOPutFuncRLE90(struct xadInOut *io, xadUINT8 data)
{
xadUINT32 a, num;
a = (xadUINT32)(uintptr_t) io->xio_PutFuncPrivate;
if(a & 0x100) /* was RLE mode */
{
if(!data || (data == 1 && (a & 0x80000000))) { a = 0x90; num = 1; }
else { a &= 0xFF; num = data-1; }
}
else if(data == 0x90) { num = 0; a |= 0x100; }
else { num = 1; a = data; }
io->xio_PutFuncPrivate = (xadPTR)(uintptr_t) a;
while(num-- && !io->xio_Error)
{
if(!io->xio_OutSize && !(io->xio_Flags & XADIOF_NOOUTENDERR))
{
io->xio_Error = XADERR_DECRUNCH;
io->xio_Flags |= XADIOF_ERROR;
}
else
{
if(io->xio_OutBufferPos >= io->xio_OutBufferSize)
xadIOWriteBuf(io);
io->xio_OutBuffer[io->xio_OutBufferPos++] = a;
if(!--io->xio_OutSize)
io->xio_Flags |= XADIOF_LASTOUTBYTE;
}
}
return data;
}
#define xadIOPutFuncRLECBMSet(io,c,old) (io->xio_PutFuncPrivate = ((xadPTR)(uintptr_t) \
(((old) ? 0x80000000 : 0)|((c)<<8))))
/* xxyyzz --> zz (yy times) */
/* xx00zz --> zz (255/256 times) */
/* xx is first character of stream */
/* io->xio_PutFuncPrivate may be initialized with 0x80000000 for old mode */
static xadUINT8 xadIOPutFuncRLECBM(struct xadInOut *io, xadUINT8 data)
{
xadUINT32 a, num;
a = (xadUINT32)(uintptr_t) io->xio_PutFuncPrivate;
/* upper 16 bits == flags
mid 8 bits == rle char
lower 8 bits == count
*/
num = 0;
if(a & 0x40000) /* RLE + size found */
{
num = a&0xFF;
if(!num) num = ((a & 0x80000000) ? 255 : 256);
a &= ~(0x600FF); /* clear flags and size */
}
else if(a & 0x20000) /* RLE found */
a |= 0x40000+data;
else if(data == ((a>>8)&0xFF))
a |= 0x20000;
else
num = 1;
io->xio_PutFuncPrivate = (xadPTR)(uintptr_t) a;
while(num-- && !io->xio_Error)
{
if(!io->xio_OutSize && !(io->xio_Flags & XADIOF_NOOUTENDERR))
{
io->xio_Error = XADERR_DECRUNCH;
io->xio_Flags |= XADIOF_ERROR;
}
else
{
if(io->xio_OutBufferPos >= io->xio_OutBufferSize)
xadIOWriteBuf(io);
io->xio_OutBuffer[io->xio_OutBufferPos++] = data;
if(!--io->xio_OutSize)
io->xio_Flags |= XADIOF_LASTOUTBYTE;
}
}
return data;
}
static void xadIOChecksum(struct xadInOut *io, xadUINT32 size)
{
xadUINT32 s, i;
s = (xadUINT32)(uintptr_t) io->xio_OutFuncPrivate;
for(i = 0; i < size; i++)
s += io->xio_OutBuffer[i];
/* byte sum */
io->xio_OutFuncPrivate = (xadPTR)(uintptr_t) s;
}
/* AMPK1 ******************************************************************************************/
struct AMPK1Data {
xadUINT8 datfield[0x1000];
xadUINT16 Var7[314]; /* This separation mostly is a result */
xadUINT16 Var8[314]; /* of reassembling and not a real need */
xadUINT16 Var9[1];
xadUINT16 Var10[314];
xadUINT16 Var11[1];
xadUINT16 Var12[314];
xadUINT16 Var13[1];
xadUINT16 Var14[1];
xadUINT16 Var15[4095];
xadUINT16 Var16[1];
};
static xadINT32 DecrAMPK1(struct xadInOut *io)
{
xadUINT32 i, j, k = 0xFC4, l;
xadUINT32 u = 0, v, w = 0x20000, r, s, t;
struct xadMasterBase *xadMasterBase = io->xio_xadMasterBase;
struct AMPK1Data *dat;
if(!(dat = (struct AMPK1Data *) xadAllocVec(XADM sizeof(struct AMPK1Data), XADMEMF_CLEAR)))
return XADERR_NOMEMORY;
v = xadIOGetBitsHigh(io,17);
for(i = 314; i; --i)
{
dat->Var7[i-1] = i;
dat->Var8[i] = i-1;
dat->Var10[i] = 1;
dat->Var11[i] = dat->Var12[i] + dat->Var10[i];
}
for(i = 0x1000; i; --i)
dat->Var13[i] = dat->Var14[i] + (10000 / (i + 200));
memset(dat->datfield, ' ', k);
while(!(io->xio_Flags & (XADIOF_LASTOUTBYTE|XADIOF_ERROR)))
{
i = w - u;
r = ((dat->Var12[0] * (v - u + 1))-1)/i;
j = 1;
s = 314;
while(j < s)
{
t = (s + j)>>1;
if(dat->Var12[t] > r)
j = ++t;
else
s = t;
} /* returns j */
w = ((dat->Var11[j] * i) / dat->Var12[0]) + u;
u += (i * dat->Var12[j]) / dat->Var12[0];
for(;;)
{
if(u >= 0x10000)
{
u -= 0x10000; w -= 0x10000; v -= 0x10000;
}
else if(u >= 0x8000 && w <= 0x18000)
{
u -= 0x8000; w -= 0x8000; v -= 0x8000;
}
else if(w > 0x10000)
break;
u <<= 1; w <<= 1;
v = (v<<1) + xadIOGetBitsHigh(io, 1);
}
i = dat->Var8[j];
if(dat->Var12[0] >= 0x7FFF)
{
s = 0;
for(r = 314; r; --r)
{
dat->Var12[r] = s;
dat->Var10[r] = (dat->Var10[r] + 1)>>1;
s += dat->Var10[r];
}
dat->Var12[0] = s;
}
for(r = j; dat->Var10[r] == dat->Var9[r]; --r)
;
if(r < j)
{
s = dat->Var8[r];
t = dat->Var8[j];
dat->Var8[r] = t;
dat->Var8[j] = s;
dat->Var7[s] = j;
dat->Var7[t] = r;
}
++dat->Var10[r];
while(r--)
++dat->Var12[r];
if(i < 0x100)
{
dat->datfield[k++] = xadIOPutChar(io, i);
k &= 0xFFF;
}
else
{
l = w - u;
r = ((dat->Var14[0] * (v - u + 1)-1)/l);
j = 1;
s = 0x1000;
while(j < s)
{
t = (s + j)>>1;
if(dat->Var14[t] > r)
j = ++t;
else
s = t;
}
--j; /* return j */
w = ((dat->Var14[j] * l) / dat->Var14[0]) + u;
u += (l * dat->Var15[j]) / dat->Var14[0];
for(;;)
{
if(u >= 0x10000)
{
u -= 0x10000; w -= 0x10000; v -= 0x10000;
}
else if(u >= 0x8000 && w <= 0x18000)
{
u -= 0x8000; w -= 0x8000; v -= 0x8000;
}
else if(w > 0x10000)
break;
u <<= 1; w <<= 1;
v = (v<<1) + xadIOGetBitsHigh(io, 1);
}
l = k - j - 1;
i -= 253;
for(j = 0; j < i; ++j)
{
dat->datfield[k++] = xadIOPutChar(io, dat->datfield[(l+j)&0xFFF]);
k &= 0xFFF;
}
}
}
xadFreeObjectA(XADM dat, 0);
return io->xio_Error;
}
/* AMPK2 ******************************************************************************************/
static xadINT32 DecrAMPK2(struct xadInOut *io)
{
xadINT32 i = 0, k = 0xFEE, m, n;
struct xadMasterBase *xadMasterBase = io->xio_xadMasterBase;
xadSTRPTR datfield;
if(!(datfield = (xadSTRPTR) xadAllocVec(XADM 0x1000, XADMEMF_CLEAR)))
return XADERR_NOMEMORY;
memset(datfield, ' ', k);
while(!(io->xio_Flags & (XADIOF_LASTOUTBYTE|XADIOF_ERROR)))
{
i >>= 1;
if(!(i & 0x100))
i = xadIOGetChar(io) | 0xFF00;
if(i & 1)
{
datfield[k++] = xadIOPutChar(io, xadIOGetChar(io));
k &= 0xFFF;
}
else
{
n = xadIOGetChar(io);
m = xadIOGetChar(io);
n |= ((m&0xF0)<<4);
m = (m&0xF)+2;
while(m-- >= 0)
{
datfield[k++] = xadIOPutChar(io, datfield[n++ & 0xFFF]);
k &= 0xFFF;
}
}
}
xadFreeObjectA(XADM datfield, 0);
return io->xio_Error;
}
/* AMPK3 - LZHUF **********************************************************************************/
#ifndef XADMASTERFILE
static const xadUINT8 AMPK3_d_code[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,
10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,
12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15,
16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,
20,20,20,20,21,21,21,21,22,22,22,22,23,23,23,23,
24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,
32,32,33,33,34,34,35,35,36,36,37,37,38,38,39,39,
40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
};
static const xadUINT8 AMPK3_d_len[256] = {
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
};
#else /* save space, as this is double used */
static const xadUINT8 DMS_d_code[256];
static const xadUINT8 DMS_d_len[256];
#define AMPK3_d_code DMS_d_code
#define AMPK3_d_len DMS_d_len
#endif
/* These defines need to reflect the largest values when thinking of
the field size (lowest threshold, highest lz_f and lz_n) */
#define AMPK3_LZ_N 4096
#define AMPK3_LZ_F 60
#define AMPK3_THRESHOLD 2
#define AMPK3_N_CHAR (256 + 1 - AMPK3_THRESHOLD + AMPK3_LZ_F)
#define AMPK3_LZ_T (AMPK3_N_CHAR * 2 - 1) /* size of table */
#define AMPK3_LZ_R (AMPK3_LZ_T - 1) /* position of root */
#define AMPK3_MAX_FREQ 0x8000 /* updates tree when the */
/* root frequency comes to this value. */
struct AMPK3Data {
xadUINT8 datfield[0x1000];
xadUINT16 freq[AMPK3_LZ_T+1];
xadUINT16 son[AMPK3_LZ_T];
xadUINT16 parent[AMPK3_LZ_T+AMPK3_N_CHAR];
};
static xadINT32 DecrAMPK3(struct xadInOut *io, xadUINT32 type)
{
xadUINT32 i, j, k, l, m, n, o;
struct xadMasterBase *xadMasterBase = io->xio_xadMasterBase;
struct AMPK3Data *dat;
xadUINT32 n_char, threshold, lz_t, lz_r, bitnum;
switch(type)
{
case 2:
threshold = 2;
bitnum = 5;
break;
case 1:
threshold = 2;
bitnum = 6;
break;
default:
threshold = 3;
bitnum = 6;
break;
};
n_char = 256 + 1 - threshold + AMPK3_LZ_F;
lz_t = n_char * 2 - 1;
lz_r = lz_t - 1;
k = AMPK3_LZ_N-AMPK3_LZ_F;
if(!(dat = (struct AMPK3Data *) xadAllocVec(XADM sizeof(struct AMPK3Data), XADMEMF_CLEAR)))
return XADERR_NOMEMORY;
for(i = 0; i < n_char; ++i)
{
dat->freq[i] = 1;
dat->son[i] = lz_t+i;
dat->parent[lz_t+i] = i;
}
/* i already has correct value n_char */
for(j = 0; i <= lz_r; ++i)
{
dat->freq[i] = dat->freq[j] + dat->freq[j+1];
dat->son[i] = j;
dat->parent[j] = dat->parent[j+1] = i;
j += 2;
}
dat->freq[i] = AMPK3_MAX_FREQ;
memset(dat->datfield, ' ', k);
while(!(io->xio_Flags & (XADIOF_LASTOUTBYTE|XADIOF_ERROR)))
{
i = dat->son[lz_r];
while(i < lz_t)
i = dat->son[i+xadIOGetBitsHigh(io, 1)];
if(dat->freq[lz_r] == 0x8000)
{
j = 0;
for(n = 0; n < lz_t; ++n)
{
if(dat->son[n] >= lz_t)
{
dat->freq[j] = (dat->freq[n] + 1) >> 1;
dat->son[j++] = dat->son[n];
}
}
n = 0;
for(j = n_char; j < lz_t; ++j)
{
o = dat->freq[j] = dat->freq[n] + dat->freq[n+1];
for(l = j-1; o < dat->freq[l]; --l)
;
++l;
for(m = j-1; m >= l; --m)
dat->freq[m+1] = dat->freq[m];
dat->freq[l] = o;
for(m = j-1; m >= l; --m)
dat->son[m+1] = dat->son[m];
dat->son[l] = n;
n += 2;
}
for(n = 0; n < lz_t; ++n)
{
j = dat->son[n];
dat->parent[j] = n;
if(j < lz_t)
dat->parent[j+1] = n;
}
}
o = dat->parent[i];
do
{
j = ++dat->freq[o];
l = o+1;
if(j > dat->freq[l])
{
while(j > dat->freq[l+1])
++l;
dat->freq[o] = dat->freq[l];
dat->freq[l] = j;
j = dat->son[o];
dat->parent[j] = l;
if(j < lz_t)
dat->parent[j+1] = l;
m = dat->son[l];
dat->son[l] = j;
dat->parent[m] = o;
if(m < lz_t)
dat->parent[m+1] = o;
dat->son[o] = m;
o = l;
}
o = dat->parent[o];
} while(o);
i -= lz_t;
if(i < 0x100)
{
dat->datfield[k++] = xadIOPutChar(io, i);
k &= 0xFFF;
}
else if((io->xio_Flags & XADIOF_NOOUTENDERR) && i == 0x100) /* crunch end indicator */
break;
else
{
l = xadIOGetBitsHigh(io,8);
m = AMPK3_d_len[l] - (8-bitnum);
l = k - (AMPK3_d_code[l] << bitnum | (((l << m) | xadIOGetBitsHigh(io, m)) & ((1<<bitnum)-1))) - 1;
i -= 256-threshold;
for(j = 0; j < i; ++j)
{
dat->datfield[k++] = xadIOPutChar(io, dat->datfield[(l+j)&0xFFF]);
k &= 0xFFF;
}
}
}
xadFreeObjectA(XADM dat, 0);
return io->xio_Error;
}
/* ARC squeeze ************************************************************************************/
#define ARCSQSPEOF 256 /* special endfile token */
#define ARCSQNUMVALS 257 /* 256 data values plus SPEOF */
static xadINT32 ARCunsqueeze(struct xadInOut *io)
{
xadINT32 err;
struct xadMasterBase *xadMasterBase = io->xio_xadMasterBase;
xadINT32 i, numnodes;
xadINT16 *node;
if((node = (xadINT16 *) xadAllocVec(XADM 2*2*ARCSQNUMVALS, XADMEMF_PUBLIC|XADMEMF_CLEAR)))
{
numnodes = xadIOGetBitsLow(io, 16);
if(numnodes < 0 || numnodes >= ARCSQNUMVALS)
err = XADERR_DECRUNCH;
else
{ /* initialize for possible empty tree (SPEOF only) */
node[0] = node[1] = -(ARCSQSPEOF + 1);
numnodes *= 2; i = 0;
while(i < numnodes) /* get decoding tree from file */
{
node[i++] = xadIOGetBitsLow(io, 16);
node[i++] = xadIOGetBitsLow(io, 16);
}
do
{
/* follow bit stream in tree to a leaf */
i = 0;
while(i >= 0 && 2 * i + 1 < numnodes && !io->xio_Error)
i = node[2*i + xadIOGetBitsLow(io, 1)];
i = -(i + 1); /* decode fake node index to original data value */
if(i != ARCSQSPEOF)
xadIOPutChar(io, i);
} while(i != ARCSQSPEOF && !io->xio_Error);
err = io->xio_Error;
}
xadFreeObjectA(XADM node, 0);
}
else
err = XADERR_NOMEMORY;
return err;
}
/* CBM huffman ************************************************************************************/
struct CBMHuffmanData {
xadUINT32 hc[256]; /* Huffman codes */
xadUINT8 hl[256]; /* Lengths of huffman codes */
xadUINT8 hv[256]; /* Character associated with Huffman code */
};
static xadINT32 CBMunhuff(struct xadInOut *io)
{
struct xadMasterBase *xadMasterBase = io->xio_xadMasterBase;
struct CBMHuffmanData *cd;
if((cd = (struct CBMHuffmanData *) xadAllocVec(XADM sizeof(struct CBMHuffmanData), XADMEMF_PUBLIC|XADMEMF_CLEAR)))
{
xadINT32 hcount, i;
hcount = 255; /* Will be first code */
for(i = 0; i < 256 && !io->xio_Error; ++i) /* Fetch Huffman codes */
{
cd->hv[i] = i;
cd->hl[i] = xadIOGetBitsLow(io, 5);
if(cd->hl[i] > 24)
{
io->xio_Flags |= XADIOF_ERROR;
io->xio_Error = XADERR_DECRUNCH; /* Code too big */
}
else if(cd->hl[i])
cd->hc[i] = xadIOGetBitsLow(io, cd->hl[i]);
else
--hcount;
}
if(!io->xio_Error)
{
xadINT32 h,j,k,m;
xadUINT32 t;
xadUINT8 u;
m = sizeof(cd->hl);
while(m >>= 1)
{
k = sizeof(cd->hl) - m;
j = 1;
do
{
i = j;
do
{
h = i + m;
if(cd->hl[h - 1] > cd->hl[i - 1])
{
t = cd->hc[i - 1]; cd->hc[i - 1] = cd->hc[h - 1]; cd->hc[h - 1] = t;
u = cd->hv[i - 1]; cd->hv[i - 1] = cd->hv[h - 1]; cd->hv[h - 1] = u;
u = cd->hl[i - 1]; cd->hl[i - 1] = cd->hl[h - 1]; cd->hl[h - 1] = u;
i -= m;
}
else
break;
} while (i >= 1);
j += 1;
} while(j <= k);
}
}
while(!(io->xio_Flags & (XADIOF_LASTOUTBYTE|XADIOF_ERROR)))
{
xadINT32 hcode, size;
hcode = size = 0;
for(i = hcount; i >= 0; --i)
{
if(size != cd->hl[i])
hcode = xadIOReadBitsLow(io,(size = cd->hl[i]));
if(hcode == cd->hc[i])
{
xadIOPutChar(io, cd->hv[i]);
xadIODropBitsLow(io, size);
break;
}
}
if(i < 0)
{
io->xio_Error = XADERR_DECRUNCH;
io->xio_Flags |= XADIOF_ERROR;
}
}
xadFreeObjectA(XADM cd, 0);
}
else
io->xio_Error = XADERR_NOMEMORY;
return io->xio_Error;
}
/* CBM pack ***************************************************************************************/
struct CBM_LZ /* Lempel Zev compression string table entry */
{
xadUINT32 prefix; /* Prefix code */
xadUINT8 ext; /* Extension character */
};
#define CBMLZTABLESIZE 4096
#define CBMLZSTACKSIZE 512
struct CBMLZData {
struct CBM_LZ Table[CBMLZTABLESIZE]; /* Lempel Zev compression string table */
xadUINT8 Stack[CBMLZSTACKSIZE]; /* Lempel Zev stack */
};
/* This is pretty straight forward if you have Terry Welch's article
* "A Technique for High Performance Data Compression" from IEEE Computer
* June 1984
*
* This implemention reserves code 256 to indicate the end of a crunched
* file, and code 257 was reserved for future considerations. Codes grow
* up to 12 bits and then stay there. There is no reset of the string
* table.
*/
static xadINT32 CBMunpack(struct xadInOut *io)
{
struct xadMasterBase *xadMasterBase = io->xio_xadMasterBase;
struct CBMLZData *cd;
if((cd = (struct CBMLZData *) xadAllocVec(XADM sizeof(struct CBMLZData), XADMEMF_PUBLIC|XADMEMF_CLEAR)))
{
xadINT32 lzstack = 0; /* Lempel Zev stack pointer */
xadINT32 cdlen = 9; /* Current code size */
xadINT32 code; /* Last received code */
xadINT32 wtcl = 256; /* Bump cdlen when code reaches this value */
xadINT32 wttcl = 254-1;/* Copy of wtcl */
xadINT32 oldcode;
xadINT32 incode;
xadUINT8 finchar;
xadINT32 ncodes = 258; /* Current # of codes in table */
oldcode = xadIOGetBitsLowR(io, 9);
if(oldcode != 256) /* Code 256 is EOF for this entry (a zero length file) */
{
finchar = xadIOPutChar(io, oldcode);
while(!io->xio_Error)
{
incode = code = xadIOGetBitsLowR(io, cdlen);
/* Get ready for next time */
if((cdlen < 12))
{
if(!(--wttcl))
{
wtcl = wtcl << 1;
cdlen++;
wttcl = wtcl;
}
}
if(incode == 256)
break; /* end code */
/* code 257 is reserved */
else if(incode >= ncodes) /* Undefined code, special case */
{
cd->Stack[lzstack++] = finchar;
code = oldcode;
incode = ncodes;
}
while(code > 255) /* Decompose string */
{
if(lzstack >= CBMLZSTACKSIZE)
io->xio_Error = XADERR_DECRUNCH;
else
cd->Stack[lzstack++] = cd->Table[code].ext;
code = cd->Table[code].prefix;
}
xadIOPutChar(io, (finchar = code));
while(lzstack)
xadIOPutChar(io, cd->Stack[--lzstack]);
if(ncodes < CBMLZTABLESIZE)
{
cd->Table[ncodes].prefix = oldcode;
cd->Table[ncodes].ext = finchar;
ncodes++;
}
oldcode = incode;
}
}
xadFreeObjectA(XADM cd, 0);
}
else
io->xio_Error = XADERR_NOMEMORY;
return io->xio_Error;
}
/**************************************************************************************************/
XADRECOGDATA(AMPK)
{
if(data[0] == 'A' && data[1] == 'M' && data[2] == 'P' && data[3] == 'K')
return 1;
else
return 0;
}
struct AMPKHead {
xadUINT8 ID[4];
xadUINT8 FileVersion;
xadUINT8 pad1;
xadUINT8 NumDirs[2]; /* First entry is missing always! */
xadUINT8 NumFiles[2]; /* Buggy format */
xadUINT8 UnCrunchedSize[4];
xadUINT8 CrunchedSize[4];
xadUINT8 pad2;
xadUINT8 pad3;
};
#define AMPKHead_TRUESIZE 20
#define AMPKENTRYTYPE_FILE 2
#define AMPKENTRYTYPE_NEWDIR 1
#define AMPKENTRYTYPE_LEAVEDIR 0
struct AMPKEntry {
xadUINT8 Type;
xadUINT8 NameSize;
xadUINT8 DirSize[4];
/* DirSite matches 3 bytes more than complete directory size
including start node and leave node. */
};
#define AMPKEntry_TRUESIZE 6
/* Always followed by directory or file name. */
struct AMPKFile {
xadUINT8 Size[4];
xadUINT8 CrunchedSize[4]; /* wrong for crunchtype 0 (store) */
xadUINT8 CrunchType;
xadUINT8 pad1;
xadUINT8 Protection[4];
xadUINT8 pad2[2];
xadUINT8 CommentSize;
xadUINT8 pad3;
};
/* Always followed by comment (if there is one!). */
#define AMPKFile_TRUESIZE 18
static const xadSTRPTR ampktype[4] = {(xadSTRPTR)"stored", (xadSTRPTR)"medium", (xadSTRPTR)"fast", (xadSTRPTR)"slow"};
XADGETINFO(AMPK)
{
xadUINT8 dirname[512]; /* never 0 terminated */
xadINT32 err, i, dirnamesize = 0;
xadUINT32 skip = 0;
struct AMPKHead hd;
struct AMPKEntry et;
struct AMPKFile fl;
struct xadFileInfo *fi;
if((err = xadHookAccess(XADM XADAC_READ, AMPKHead_TRUESIZE, &hd, ai)))
return err;
while(!err && ai->xai_InPos < ai->xai_InSize)
{
if(!(err = xadHookAccess(XADM XADAC_READ, AMPKEntry_TRUESIZE, &et, ai)))
{
/* Format has problems with stored file. When a file is stored as last entry
in a directory, some useless stuff is stored behind it. */
xadUINT32 dirSize = EndGetM32(et.DirSize);
if(skip && (et.Type > AMPKENTRYTYPE_FILE ||
(et.Type == AMPKENTRYTYPE_NEWDIR && dirSize >= 0x01000000) ||
(et.Type != AMPKENTRYTYPE_NEWDIR && dirSize)))
{
if(!(err = xadHookAccess(XADM XADAC_INPUTSEEK, skip-AMPKEntry_TRUESIZE, 0, ai)))
{
if(ai->xai_InPos < ai->xai_InSize)
{
if(!(err = xadHookAccess(XADM XADAC_READ, AMPKEntry_TRUESIZE, &et, ai)))
{
if(et.Type || EndGetM32(et.DirSize)) /* a leave-dir node must follow */
err = XADERR_ILLEGALDATA;
}
}
}
}
skip = 0;
if(!err && ai->xai_InPos < ai->xai_InSize)
{
switch(et.Type)
{
default: err = XADERR_ILLEGALDATA; break;
case AMPKENTRYTYPE_LEAVEDIR:
if(dirnamesize)
{
--dirnamesize; /* skip last slash */
while(dirnamesize && dirname[dirnamesize-1] != '/')
dirnamesize--;
}
break;
case AMPKENTRYTYPE_NEWDIR:
if(dirnamesize + et.NameSize + 1 <= sizeof(dirname))
{
if(!(err = xadHookAccess(XADM XADAC_READ, et.NameSize, dirname+dirnamesize, ai)))
{
dirnamesize += et.NameSize;
if((fi = (struct xadFileInfo *) xadAllocObject(XADM XADOBJ_FILEINFO,
XAD_OBJNAMESIZE, dirnamesize+1, TAG_DONE)))
{
fi->xfi_Flags = XADFIF_DIRECTORY|XADFIF_NODATE;
xadConvertDates(XADM XAD_DATECURRENTTIME, 1, XAD_GETDATEXADDATE,
&fi->xfi_Date, TAG_DONE);
for(i = 0; i < dirnamesize; ++i)
fi->xfi_FileName[i] = dirname[i];
err = xadAddFileEntry(XADM fi, ai, XAD_SETINPOS, ai->xai_InPos, TAG_DONE);
}
else
err = XADERR_NOMEMORY;
dirname[dirnamesize++] = '/';
}
}
else
err = XADERR_SHORTBUFFER;
break;
case AMPKENTRYTYPE_FILE:
if(dirnamesize + et.NameSize <= sizeof(dirname))
{
if(!(err = xadHookAccess(XADM XADAC_READ, et.NameSize, dirname+dirnamesize, ai)))
{
if(!(err = xadHookAccess(XADM XADAC_READ, AMPKFile_TRUESIZE, &fl, ai)))
{
xadUINT32 size = EndGetM32(fl.Size);
xadUINT32 crunchedSize = EndGetM32(fl.CrunchedSize);
xadUINT32 protection = EndGetM32(fl.Protection);
if((fi = (struct xadFileInfo *) xadAllocObject(XADM XADOBJ_FILEINFO,
XAD_OBJNAMESIZE, dirnamesize+et.NameSize+1, fl.CommentSize ? XAD_OBJCOMMENTSIZE :
TAG_DONE, fl.CommentSize+1, TAG_DONE)))
{
if(!fl.CommentSize || !(err = xadHookAccess(XADM XADAC_READ, fl.CommentSize, fi->xfi_Comment, ai)))
{
fi->xfi_DataPos = ai->xai_InPos;
fi->xfi_PrivateInfo = (xadPTR)(uintptr_t) fl.CrunchType;
fi->xfi_EntryInfo = ampktype[fl.CrunchType];
for(i = 0; i < dirnamesize + et.NameSize; ++i)
fi->xfi_FileName[i] = dirname[i];
fi->xfi_CrunchSize = fl.CrunchType ? crunchedSize : size;
fi->xfi_Size = size;
fi->xfi_Flags = XADFIF_NODATE|XADFIF_SEEKDATAPOS|XADFIF_EXTRACTONBUILD;
xadConvertDates(XADM XAD_DATECURRENTTIME, 1, XAD_GETDATEXADDATE,
&fi->xfi_Date, TAG_DONE);
fi->xfi_Protection = protection;
skip = crunchedSize - (xadUINT32)fi->xfi_CrunchSize;
err = xadAddFileEntry(XADM fi, ai, XAD_SETINPOS, ai->xai_InPos+fi->xfi_CrunchSize, TAG_DONE);
}
else
xadFreeObjectA(XADM fi, 0);
}
else
err = XADERR_NOMEMORY;
}
}
}
else
err = XADERR_SHORTBUFFER;
break;
} /* switch */
}
}
}
if(err)
{
ai->xai_Flags |= XADAIF_FILECORRUPT;
ai->xai_LastError = err;
}
return ai->xai_FileInfo ? 0 : XADERR_ILLEGALDATA;
}
XADUNARCHIVE(AMPK)
{
xadINT32 err;
struct xadFileInfo *fi;
fi = ai->xai_CurFile;
if(!fi->xfi_PrivateInfo) /* private info is crunch type */
err = xadHookAccess(XADM XADAC_COPY, fi->xfi_Size, 0, ai);
else
{
struct xadInOut *io;
if((io = xadIOAlloc(XADIOF_ALLOCINBUFFER|XADIOF_ALLOCOUTBUFFER|XADIOF_NOCRC32|XADIOF_NOCRC16, ai, xadMasterBase)))
{
io->xio_InSize = fi->xfi_CrunchSize;
io->xio_OutSize = fi->xfi_Size;
switch((xadUINT32)(uintptr_t)fi->xfi_PrivateInfo)
{
case 1: io->xio_Flags |= XADIOF_NOINENDERR; err = DecrAMPK1(io); break;
case 2: err = DecrAMPK2(io); break;
case 3: err = DecrAMPK3(io,0); break;
default: err = XADERR_DATAFORMAT; break;
}
if(!err)
err = xadIOWriteBuf(io);
if(!err && io->xio_InSize)
err = XADERR_DECRUNCH;
xadFreeObjectA(XADM io, 0);
}
else
err = XADERR_NOMEMORY;
}
return err;
}
/************************************************************************************************/
XADRECOGDATA(AmPlusUnpack)
{
if(data[0] == 'F' && data[1] == 'O' && data[2] == 'R' && data[3] == 'M'
&& data[8] == 'A' && data[9] == 'P' && data[10] == 'U' && data[11] == 'P')
return 1;
else
return 0;
}
/* This archiver uses a slightly modified IFF format, where chunks are used
in other chunk body. F.e. FILE is used in HELP, DATA or PACK and NAME is used
in file or DISK chunks. */
/* FILE chunks start with that header. The chunk size includes NAME entry. */
struct AmPlusUnpackData {
xadUINT32 FileSize;
xadUINT8 Date[12];
xadUINT32 Protection;
};
/* DCYL chunk is missing in this client (never saw such a file). */
#define AMPLUSPACKMODE_INT 0
#define AMPLUSPACKMODE_XPK 1
/* PACK or DATA chunks start with a 10 Byte information header */
/* HELP chunk has same data format, but no header (starts directly with FILE) */
struct AmPlusDataHead {
xadUINT16 type; /* unknown*/
xadUINT32 crsize; /* real value (maybe 1 less than size of body) */
xadUINT32 crc; /* always -1 for XPKF files, CRC is longword sum of file data */
};
/* PACK data either uses own algorithm or XPK */
/* VERS chunk contains of following structure: */
struct AmPlusVers {
xadUINT32 Version; /* Really 4 bytes? */
xadUINT8 CreationDate[12]; /* its a DateStamp, but really creation date? */
};
/* PREF chunk contains of 6 unknown bytes */
/* DISK chunk contains of 2 unknown longwords followed by a NAME chunk for disk
name - this name is inserted in SPECIAL info field of xadArchiveInfo. */
/* MKDR chunk contains the name of a directory to be created on that disk */
struct AmUnpackIFF {
xadUINT32 ID;
xadUINT32 Size;
};
struct AmUnpackPriv {
xadUINT32 ID;
xadUINT32 CRC;
xadUINT16 Mode;
};
static const xadSTRPTR apuptype[2] = {(xadSTRPTR)"internal", (xadSTRPTR)"XPK"};
/* This Client does not scan all correct IFF file possibilities, but only
IFF-APUP file structures, which really exist. */
XADGETINFO(AmPlusUnpack)
{
xadINT32 err;
struct AmPlusUnpackData sd;
struct AmPlusDataHead dh;
struct AmUnpackIFF iff;
struct xadFileInfo *fi;
xadUINT32 id;
xadUINT32 crsize = 0;
dh.type = 0;
dh.crc = 0;
if((err = xadHookAccess(XADM XADAC_INPUTSEEK, 12, 0, ai)))
return err;
while(!err && ai->xai_InPos < ai->xai_InSize)
{
if(!(err = xadHookAccess(XADM XADAC_READ, sizeof(struct AmUnpackIFF), &iff, ai)))
{
id = iff.ID;
switch(iff.ID)
{
default: err = XADERR_ILLEGALDATA; break;
case MAKE_ID('V','E','R','S'):
case MAKE_ID('D','I','S','K'):
case MAKE_ID('P','R','E','F'):
err = xadHookAccess(XADM XADAC_INPUTSEEK, iff.Size, 0, ai);
break;
case MAKE_ID('M','K','D','R'):
if((fi = (struct xadFileInfo *) xadAllocObject(XADM XADOBJ_FILEINFO,
XAD_OBJNAMESIZE, iff.Size, TAG_DONE)))
{
fi->xfi_Flags = XADFIF_DIRECTORY|XADFIF_NODATE;
xadConvertDates(XADM XAD_DATECURRENTTIME, 1, XAD_GETDATEXADDATE,
&fi->xfi_Date, TAG_DONE);
if(!(err = xadHookAccess(XADM XADAC_READ, iff.Size, fi->xfi_FileName, ai)))
err = xadAddFileEntry(XADM fi, ai, XAD_SETINPOS, ai->xai_InPos, TAG_DONE);
else
xadFreeObjectA(XADM fi, 0);
}
else
err = XADERR_NOMEMORY;
break;
case MAKE_ID('P','A','C','K'):
case MAKE_ID('D','A','T','A'):
if(!(err = xadHookAccess(XADM XADAC_READ, sizeof(struct AmPlusDataHead), &dh, ai)))
crsize = dh.crsize;
case MAKE_ID('H','E','L','P'):
if(!err)
{
if(!(err = xadHookAccess(XADM XADAC_READ, sizeof(struct AmUnpackIFF), &iff, ai)))
{
if(iff.ID != MAKE_ID('F','I','L','E'))
{
err = XADERR_ILLEGALDATA;
}
else if(!(err = xadHookAccess(XADM XADAC_READ, sizeof(struct AmPlusUnpackData), &sd, ai)))
{
if(!(err = xadHookAccess(XADM XADAC_READ, sizeof(struct AmUnpackIFF), &iff, ai)))
{
if(iff.ID != MAKE_ID('N','A','M','E'))
{
err = XADERR_ILLEGALDATA;
}
else if((fi = (struct xadFileInfo *) xadAllocObject(XADM XADOBJ_FILEINFO,
XAD_OBJNAMESIZE, iff.Size, XAD_OBJPRIVINFOSIZE, sizeof(struct AmUnpackPriv),
TAG_DONE)))
{
((struct AmUnpackPriv *)fi->xfi_PrivateInfo)->ID = id;
if(!(err = xadHookAccess(XADM XADAC_READ, iff.Size, fi->xfi_FileName, ai)))
{
if(!(err = xadHookAccess(XADM XADAC_READ, sizeof(struct AmUnpackIFF), &iff, ai)))
{
fi->xfi_DataPos = ai->xai_InPos;
fi->xfi_Flags = XADFIF_SEEKDATAPOS|XADFIF_EXTRACTONBUILD;
((struct AmUnpackPriv *)fi->xfi_PrivateInfo)->Mode = dh.type;
fi->xfi_EntryInfo = apuptype[dh.type];
((struct AmUnpackPriv *)fi->xfi_PrivateInfo)->CRC = dh.crc;
if(id == MAKE_ID('H','E','L','P'))
{
crsize = iff.Size;
fi->xfi_Flags |= XADFIF_INFOTEXT;
}
fi->xfi_CrunchSize = crsize;
xadConvertDates(XADM XAD_DATEDATESTAMP, &sd.Date, XAD_GETDATEXADDATE,
&fi->xfi_Date, TAG_DONE);
fi->xfi_Protection = sd.Protection;
fi->xfi_Size = sd.FileSize;
err = xadAddFileEntry(XADM fi, ai, XAD_SETINPOS, (ai->xai_InPos + (iff.Size+1)) & ~1, TAG_DONE);
}
else
xadFreeObjectA(XADM fi, 0);
}
else
xadFreeObjectA(XADM fi, 0);
}
else
err = XADERR_NOMEMORY;
}
}
}
}
break;
} /* switch */
}
}
if(err)
{
ai->xai_Flags |= XADAIF_FILECORRUPT;
ai->xai_LastError = err;
}
return ai->xai_FileInfo ? 0 : XADERR_ILLEGALDATA;
}
static void AmPlusUnpCalcChecksum(struct xadInOut *io, xadUINT32 size)
{
xadUINT32 s, i;
s = (xadUINT32)(uintptr_t) io->xio_OutFuncPrivate;
for(i = 0; i < size; i++)
s += io->xio_OutBuffer[i] << ((3 - (i&3)) << 3);
/* longword sum, with remainder added at highest position */
io->xio_OutFuncPrivate = (xadPTR)(uintptr_t) s;
}
XADUNARCHIVE(AmPlusUnpack)
{
xadINT32 err = 0;
xadUINT32 i;
struct AmUnpackPriv *up;
struct xadFileInfo *fi;
struct xadInOut *io;
fi = ai->xai_CurFile;
up = (struct AmUnpackPriv *) fi->xfi_PrivateInfo;
if(up->ID == MAKE_ID('H','E','L','P'))
return xadHookAccess(XADM XADAC_COPY, fi->xfi_Size, 0, ai);
else if(up->ID == MAKE_ID('D','A','T','A'))
{
xadUINT32 bufsize, data, crc = 0;
xadUINT32 * buf;
data = (xadUINT32)fi->xfi_Size;
if((bufsize = data+3) > 51200) /* +3 to get longword rounding */
bufsize = 51200;
if((buf = (xadUINT32 *) xadAllocVec(XADM bufsize, XADMEMF_PUBLIC)))
{
while(data && !err)
{
if(data < bufsize)
bufsize = data;
if(bufsize & 3)
buf[bufsize>>2] = 0; /* clear last longword when necessary */
if(!(err = xadHookAccess(XADM XADAC_READ, bufsize, buf, ai)))
{
for(i = 0; i < ((bufsize+3) >> 2); ++i)
crc += buf[i];
err = xadHookAccess(XADM XADAC_WRITE, bufsize, buf, ai);
}
data -= bufsize;
}
xadFreeObjectA(XADM buf, 0);
}
else
err = XADERR_NOMEMORY;
if(!err && crc != up->CRC)
err = XADERR_CHECKSUM;
return err;
}
if((io = xadIOAlloc(XADIOF_ALLOCINBUFFER|XADIOF_ALLOCOUTBUFFER
|XADIOF_NOCRC32|XADIOF_NOCRC16, ai, xadMasterBase)))
{
io->xio_InSize = fi->xfi_CrunchSize;
io->xio_OutSize = fi->xfi_Size;
switch(up->Mode)
{
case AMPLUSPACKMODE_XPK:
err = xadIO_XPK(io, 0);
break;
case AMPLUSPACKMODE_INT:
io->xio_OutFunc = AmPlusUnpCalcChecksum;
err = DecrAMPK2(io);
break;
default:
err = XADERR_DATAFORMAT;
break;
}
if(!err)
err = xadIOWriteBuf(io);
if(!err && (up->Mode == AMPLUSPACKMODE_INT)
&& (xadUINT32)(uintptr_t) io->xio_OutFuncPrivate != up->CRC)
err = XADERR_CHECKSUM;
xadFreeObjectA(XADM io, 0);
}
else
err = XADERR_NOMEMORY;
return err;
}
/************************************************************************************************************************/
struct CompDisk {
xadUINT8 ID[4];
xadUINT32 Version;
xadUINT32 Compression;
xadUINT32 Flags;
};
/* Compression type 2 is either normal Lh (Zoom) or with SeqMax set to 59. */
/* Size then always (512+16)*22. */
/* CRC32 instead of CRC16 and either CRC of crunched or uncrunched data. */
/* Could not find out, what's correct, as sources showed differences. */
XADRECOGDATA(CompDisk)
{
if(data[0] == 'C' && data[1] == 'O' && data[2] == 'M' && data[3] == 'P' &&
!data[4] && !data[5] && !data[6] && data[7] == 5 && !data[8] && !data[9]
&& !data[10] && !data[11])
return 1;
else
return 0;
}
XADGETINFO(CompDisk)
{
struct xadDiskInfo *xdi;
if(!(xdi = (struct xadDiskInfo *) xadAllocObjectA(XADM XADOBJ_DISKINFO, 0)))
return XADERR_NOMEMORY;
xdi->xdi_EntryNumber = 1;
xdi->xdi_Cylinders = 80;
/* xdi->xdi_LowCyl = 0; */
xdi->xdi_HighCyl = 79;
xdi->xdi_SectorSize = 512;
xdi->xdi_TrackSectors = 11;
xdi->xdi_CylSectors = 22;
xdi->xdi_Heads = 2;
xdi->xdi_TotalSectors = 1760;
xdi->xdi_Flags = XADDIF_SEEKDATAPOS|XADDIF_EXTRACTONBUILD;
xdi->xdi_DataPos = sizeof(struct CompDisk);
return xadAddDiskEntryA(XADM xdi, ai, 0);
}
static xadUINT16 MakeOlafCRC(xadUINT8 *Mem, xadINT32 Size)
{
xadUINT16 CRC = 0, buf[256], i, j, k;
for(i = 0; i < 256; ++i)
{
k = i << 8;
for(j = 0; j < 8; ++j)
{
if(k & 0x8000)
k = (k << 1) ^ 0x1021;
else
k <<= 1;
}
buf[i] = k;
}
while(Size--)
CRC = buf[((CRC>>8) & 0xFF)] ^ ((CRC << 8) ^ *Mem++);
return CRC;
}
XADUNARCHIVE(CompDisk)
{
xadINT32 i, j, err = 0;
xadSTRPTR buf, buf2, dat[6]; /* dat == xadUINT32 compsize, xadUINT16 crc16 */
if((buf = (xadSTRPTR) xadAllocVec(XADM 512*22*2, XADMEMF_PUBLIC))) /* 2 buffers */
{
buf2 = buf + 512*22;
/* skip entries */
for(i = 0; !err && i < ai->xai_LowCyl; ++i)
{
if(!(err = xadHookAccess(XADM XADAC_READ, 6, &dat, ai)))
{
if(!(j = EndGetM32(dat)))
j = 512*22;
err = xadHookAccess(XADM XADAC_INPUTSEEK, j, 0, ai);
}
}
for(; !err && i <= ai->xai_HighCyl; ++i)
{
if(!(err = xadHookAccess(XADM XADAC_READ, 6, &dat, ai)))
{
if(!(j = EndGetM32(dat)))
err = xadHookAccess(XADM XADAC_READ, 512*22, buf, ai);
else
{
if(!(err = xadHookAccess(XADM XADAC_READ, j, buf2, ai)))
{
struct xadInOut *io;
if((io = xadIOAlloc(XADIOF_NOCRC32|XADIOF_NOCRC16, ai, xadMasterBase)))
{
io->xio_InSize = io->xio_InBufferSize = j;
io->xio_OutSize = io->xio_OutBufferSize = 512*22;
io->xio_InBuffer = (xadUINT8 *)buf2;
io->xio_OutBuffer = (xadUINT8 *)buf;
if(!(err = xadIO_Compress(io, 12|UCOMPBLOCK_MASK)) && io->xio_OutSize)
err = XADERR_DECRUNCH;
xadFreeObjectA(XADM io,0);
}
else
err = XADERR_NOMEMORY;
}
}
if(!err)
{
if(MakeOlafCRC((xadUINT8 *)buf, 512*22) != EndGetM16(dat+4))
err = XADERR_CHECKSUM;
else
err = xadHookAccess(XADM XADAC_WRITE, 512*22, buf, ai);
}
}
}
xadFreeObjectA(XADM buf, 0);
}
else
err = XADERR_NOMEMORY;
return err;
}
/************************************************************************************************************************/
struct LhWarpHead {
xadUINT8 version;
xadUINT8 revision1;
xadUINT8 revision2;
xadUINT8 empty;
xadUINT8 lowcyl[2];
xadUINT8 highcyl[2];
xadUINT8 textsize[4];
xadUINT8 crtextsize[4];
xadUINT8 filesize[4]; /* not for revision <= 2 files */
}; /* followed by crunched text */
#define LHWARPMETHOD_FREEZE 0
#define LHWARPMETHOD_STORED 1
#define LHWARPMETHOD_VAPORIZE 7
#define LHWARPMETHOD_SQUEEZE 10
struct LhWarpEntry {
xadUINT8 method;
xadUINT8 nodata; /* set to 2 for empty blocks */
xadUINT8 tracknum;
xadUINT8 pad;
xadUINT8 blocks[3]; /* [0] Bits 0..7 == blocks 1.. 7 */
/* [1] Bits 0..7 == blocks 8..15 */
/* [2] Bits 0..5 == blocks 16..22 */
xadUINT8 oldmode; /* not used by LhWarp */
xadUINT8 datasize[4];
xadUINT8 crsize[4];
xadUINT8 crc32[4];
}; /* followed by data */
/* old mode is
xadUINT8 pad1;
xadUINT8 pad2;
xadUINT8 tracknum;
xadUINT8 pad3;
xadUINT32 datasize;
xadUINT32 crsize;
xadUINT32 checksum;
*/
XADRECOGDATA(LHWARP)
{
if(data[0] == 1 && data[1] <= 3 && data[2] <= 9 && !data[3] &&
!data[4] && data[5] <= data[7] && !data[6] && data[7] <= 79 &&
data[1] + data[2] > 0 && !data[8] && !data[9] &&
EndGetM32(data+8) >= EndGetM32(data+12))
return 1;
else
return 0;
}
XADGETINFO(LHWARP)
{
xadINT32 err, cr, ucr;
struct xadDiskInfo *xdi;
struct LhWarpHead lhw;
struct xadTextInfo *ti;
if(!(err = xadHookAccess(XADM XADAC_READ, sizeof(struct LhWarpHead), &lhw, ai)))
{
if(!(xdi = (struct xadDiskInfo *) xadAllocObjectA(XADM XADOBJ_DISKINFO, 0)))
err = XADERR_NOMEMORY;
else
{
cr = EndGetM32(lhw.crtextsize);
ucr = EndGetM32(lhw.textsize);
if((xdi->xdi_PrivateInfo = (xadPTR)(uintptr_t) lhw.revision1))
xdi->xdi_Flags |= XADDIF_SECTORLABELS;
xdi->xdi_EntryNumber = 1;
xdi->xdi_Cylinders = 80;
xdi->xdi_LowCyl = EndGetM16(lhw.lowcyl);
xdi->xdi_HighCyl = EndGetM16(lhw.highcyl);
xdi->xdi_SectorSize = 512;
xdi->xdi_TrackSectors = 11;
xdi->xdi_CylSectors = 22;
xdi->xdi_Heads = 2;
xdi->xdi_TotalSectors = 1760;
xdi->xdi_Flags |= XADDIF_SEEKDATAPOS;
if(ucr && (lhw.revision1 == 3 || !xadHookAccess(XADM XADAC_INPUTSEEK, -4, 0, ai)))
{
if((ti = (struct xadTextInfo *) xadAllocObjectA(XADM XADOBJ_TEXTINFO, 0)))
{
xadINT32 ok = 0;
ti->xti_Size = ucr;
if((ti->xti_Text = (xadSTRPTR) xadAllocVec(XADM ucr+1, XADMEMF_ANY|XADMEMF_CLEAR)))
{
struct xadInOut *io;
if((io = xadIOAlloc(XADIOF_ALLOCINBUFFER|XADIOF_NOCRC32|XADIOF_NOCRC16,
ai, xadMasterBase)))
{
io->xio_InSize = cr;
io->xio_OutSize = io->xio_OutBufferSize = ucr;
io->xio_OutBuffer = (xadUINT8 *)ti->xti_Text;
if(!DecrAMPK3(io,0))
ok = 1;
xadFreeObjectA(XADM io, 0);
}
if(!ok)
xadFreeObjectA(XADM ti->xti_Text, 0);
}
if(!ok)
xadFreeObjectA(XADM ti, 0);
else
xdi->xdi_TextInfo = ti;
}
}
xdi->xdi_DataPos = sizeof(struct LhWarpHead)+cr;
if(lhw.revision1 < 3)
xdi->xdi_DataPos -= 4;
err = xadAddDiskEntryA(XADM xdi, ai, 0);
}
}
return err;
}
static xadINT32 LHWSave(xadSTRPTR data, struct LhWarpEntry *lhw, struct xadMasterBase *xadMasterBase,
struct xadArchiveInfo *ai)
{
xadINT32 bits, i, j, endpos, blksize;
bits = lhw->blocks[0]|(lhw->blocks[1]<<8)|(lhw->blocks[2]<<16);
endpos = EndGetM32(lhw->datasize);
blksize = 512+16;
if(lhw->oldmode)
{
j = EndGetM32(lhw->datasize);
for(i = endpos = 0; i < j; ++i)
endpos += data[i];
if(endpos != EndGetM32(lhw->crc32))
return XADERR_CHECKSUM;
bits = (1<<22)-1;
}
else if(xadCalcCRC32(XADM XADCRC32_ID1, 0, endpos, (xadUINT8 *) data) != EndGetM32(lhw->crc32))
return XADERR_CHECKSUM;
if(bits < (1<<22)-1) /* if equal, no copy necessary */
{
for(i = 21; i >= 0; --i)
{
if(bits&(1<<i))
{
endpos -= blksize;
if(endpos != i*blksize)
xadCopyMem(XADM data+endpos, data+(i*blksize), blksize);
}
else
memset(data+(i*blksize), 0, blksize);
}
}
if(!lhw->oldmode)
{
/* resort SectorLabels - we have an extra sectorlabel field at buffer end */
for(i = 0; i < 22; ++i)
{
xadCopyMem(XADM data+(i*blksize)+512, data+(22*(512+16))+i*16, 16);
xadCopyMem(XADM data+(i*blksize), data+(i*512), 512);
}
}
return xadHookTagAccess(XADM XADAC_WRITE, 512*22, data, ai,
lhw->oldmode ? TAG_DONE : XAD_SECTORLABELS, data+(22*(512+16)), TAG_DONE);
}
XADUNARCHIVE(LHWARP)
{
xadINT32 i, j, l, err = 0, ofs = 0;
struct LhWarpEntry lhw;
struct xadInOut *io;
xadSTRPTR data;
if(!ai->xai_CurDisk->xdi_PrivateInfo)
{
ofs = 4;
lhw.method = LHWARPMETHOD_FREEZE;
}
/* skip entries */
for(i = ai->xai_CurDisk->xdi_LowCyl; !err && i < ai->xai_LowCyl; ++i)
{
if(!(err = xadHookAccess(XADM XADAC_READ, sizeof(struct LhWarpEntry)-ofs, ((xadSTRPTR)&lhw)+ofs, ai)))
{
if(EndGetM32(lhw.crsize))
err = xadHookAccess(XADM XADAC_INPUTSEEK, EndGetM32(lhw.crsize), 0, ai);
}
}
if((data = xadAllocVec(XADM 22*(512+16) + 22*16, XADMEMF_PUBLIC))) /* including sector labels */
{
for(; !err && i <= ai->xai_HighCyl; ++i)
{
if(!(err = xadHookAccess(XADM XADAC_READ, sizeof(struct LhWarpEntry)-ofs, ((xadSTRPTR)&lhw)+ofs, ai)))
{
lhw.oldmode = ofs;
j = EndGetM32(lhw.crsize);
l = EndGetM32(lhw.datasize);
if(l > 22*(512+16) || l < 0)
err = XADERR_ILLEGALDATA;
else if(l) /* ignore empty store blocks */
{
if((io = xadIOAlloc(XADIOF_ALLOCINBUFFER|XADIOF_NOCRC32|XADIOF_NOCRC16, ai, xadMasterBase)))
{
io->xio_InSize = j;
io->xio_OutSize = io->xio_OutBufferSize = l;
io->xio_OutBuffer = (xadUINT8 *)data;
switch(lhw.method)
{
case LHWARPMETHOD_STORED:
while(!(io->xio_Flags & (XADIOF_LASTOUTBYTE|XADIOF_ERROR)))
xadIOPutChar(io, xadIOGetChar(io));
err = io->xio_Error;
break;
case LHWARPMETHOD_VAPORIZE:
if(!(err = xadIO_Compress(io, 14|UCOMPBLOCK_MASK)) && io->xio_OutSize)
err = XADERR_DECRUNCH;
break;
case LHWARPMETHOD_FREEZE:
err = DecrAMPK3(io,0);
break;
case LHWARPMETHOD_SQUEEZE:
io->xio_PutFunc = xadIOPutFuncRLE90;
err = ARCunsqueeze(io);
break;
default:
err = XADERR_DATAFORMAT;
break;
}
xadFreeObjectA(XADM io, 0);
}
else
err = XADERR_NOMEMORY;
}
if(!err)
err = LHWSave(data, &lhw, xadMasterBase, ai);
}
}
xadFreeObjectA(XADM data, 0);
}
else
err = XADERR_NOMEMORY;
return err;
}
/************************************************************************************************************************/
/*
00 - Archive version
01 = original
02 = extended header
01 - Compression mode
00 - Stored
01 - Packed
02 - Squeezed
03 - Crunched (arc version 2 only)
04 - Squeezed and packed (arc version 2 only)
05 - Crunched in 1 pass (arc version 2 only)
02-03 - Checksum
04-06 - Original file size in bytes
This value is not valid if the compression mode (from
above) is 5, a one pass crunch)
07-08 - Number of blocks compressed file takes (254 bytes/block)
09 - Filetype ("P", "S", "U", "R", uppercase in ASCII,
lowercase in PETASCII )
0A - Filename length
0B-0B+length - Filename (in PETASCII, no longer than 16 characters)
0B+length+1 - Relative file record length (only for arc version 2)
0B+length+2 - Date (2 bytes, in MSDOS format, only in arc vers. 2)
The header can also have some extra fields, depending on what version the
archive is. Version 1 archives do not have the RECORD length and DATE
fields, meaning they cannot contain REL files. The RECORD length is only
used when the filetype is REL.
Immediately following the filename (for version 1 archives) is the RLE
control byte, and then follows the LZ table and compressed data.
*/
static const xadSTRPTR arctypes[] = {
(xadSTRPTR)"stored", (xadSTRPTR)"stored", (xadSTRPTR)"packed", (xadSTRPTR)"squeezed", (xadSTRPTR)"crunched", (xadSTRPTR)"pack+crunch",
(xadSTRPTR)"fastpacked", (xadSTRPTR)"LZW packed", (xadSTRPTR)"squashed", (xadSTRPTR)"compressed"};
XADRECOGDATA(ArcCBM)
{
if(data[0] == 1) /* ARC V1 header */
{
if(data[1] <= 2 /* Compression mode */
&& (data[9] == 'P' || data[9] == 'S' || data[9] == 'U') && /* type */
(data[1] || ((EndGetI24(data+4)+253)/254 == EndGetI16(data+7)))) /* stored size */
return 1;
}
else if(data[0] == 2) /* ARC V2 header */
{
if(data[1] <= 5 /* Compression mode */
&& (data[9] == 'P' || data[9] == 'S' || data[9] == 'U' || data[9] == 'R') && /* type */
(data[1] || ((EndGetI24(data+4)+253)/254 == EndGetI16(data+7)))) /* stored size */
return 1;
}
return 0;
}
/* Header format
*
* xadINT16 BASIC load address
* xadINT8 ????
* xadINT8 ????
* xadINT16 Line number
* xadINT8 Token 'SYS' = 0x9E
* xadINT8 '('
* BYTEs address in ASCII
* xadINT8 ')'
*/
XADRECOGDATA(ArcCBMSFX)
{
if(size >= 254+11 && data[6] == 0x9E && data[7] == 0x28)
{
/* Calculate the start of the ARC data */
xadUINT32 i;
i = EndGetI16(data+4);
i = (i == 15 && data[8] == '7') ? (15-6)*254-1 : (i-6)*254; /* i == 15: SDA232.128 */
if(size >= i+11)
return ArcCBM_RecogData(size-i,data+i,xadMasterBase);
}
return 0;
}
struct ArcCBMPrivate {
xadUINT16 CRC;
xadUINT8 Method;
xadUINT8 Version;
};
#define ACBPI(a) ((struct ArcCBMPrivate *) ((a)->xfi_PrivateInfo))
static xadINT32 ArcCBMScanSize(struct xadArchiveInfo *ai,
struct xadFileInfo *fi, xadUINT8 *data, struct xadMasterBase *xadMasterBase)
{
xadINT32 i=0, err = 0;
xadSTRPTR buf;
xadUINT32 bufsize, fsize, pos;
pos = (xadUINT32)ai->xai_InPos;
fsize = (xadUINT32)(ai->xai_InSize-ai->xai_InPos);
bufsize = 254*50;
if(!(buf = xadAllocVec(XADM bufsize+254*2, XADMEMF_PUBLIC)))
return XADERR_NOMEMORY;
xadCopyMem(XADM data,buf+254,254); /* store the last 254 bytes */
/* first 254*2 bytes store older buffer and not current data */
while(!err && fsize >= 254)
{
if(fsize < bufsize)
bufsize = fsize;
fsize -= bufsize;
if(!(err = xadHookAccess(XADM XADAC_READ, bufsize, buf+254*2, ai)))
{
for(i = 254*2; i < bufsize+254; i += 254)
{
if(buf[i] == 2 && buf[i+1] <= 5 && buf[i+10] <= 16
&& (buf[i+9] == 'P' || buf[i+9] == 'S' || buf[i+9] == 'U' ||
buf[i+9] == 'R'))
{
fsize = 0;
break;
}
}
if(fsize)
{
xadCopyMem(XADM buf+bufsize,buf,254*2); /* store the last 2*254 bytes */
}
}
}
i -= 254*2;
fi->xfi_CrunchSize += (ai->xai_InPos-pos)+254-bufsize+i;
if(!fsize) /* find CRC and size */
{
xadINT32 j, k, l, m;
xadUINT32 b, r=0;
for(j = 254*2-1; j >= 254 && !buf[i+j]; --j)
; /* skip the empty chars */
if(j >= 254)
{
b = (buf[i+j]<<16)+(buf[i+j-1]<<8)+(buf[i+j-2]);
for(k = 0; k <= 10 && (b>>k) != 0x2608; ++k)
;
if((b>>k) == 0x2608) /* we found the wanted information */
{
if(k >= 8)
{
k -= 8;
++j;
}
j -= 9;
for(l = 0; l < 8; ++l)
{
b = buf[i+j++];
for(m = 0; m < 8; ++m)
{
r = (r<<1)|(b&1);
b >>= 1;
}
if(l == 4)
ACBPI(fi)->CRC = (r>>(8-k))&0xFFFF;
else if(l == 3+4)
{
fi->xfi_Size = (r>>(8-k))&0xFFFFFF;
fi->xfi_Flags &= ~(XADFIF_NOUNCRUNCHSIZE);
}
}
}
}
}
xadFreeObjectA(XADM buf, 0);
if(err)
xadAddFileEntryA(XADM fi, ai,0);
else
err = xadAddFileEntry(XADM fi, ai, XAD_SETINPOS, ai->xai_InPos-bufsize+i,
TAG_DONE);
return err;
}
XADGETINFO(ArcCBM)
{
xadUINT8 data[254]; /* One sector, minimum size of a compressed file with header */
struct xadFileInfo *fi;
struct xadSpecial *sp;
xadINT32 err = XADERR_OK, blocksize, insize;
while(!err && ai->xai_InPos < ai->xai_InSize-11)
{
/* Read archive header */
if((insize = (xadUINT32)(ai->xai_InSize-ai->xai_InPos)) > sizeof(data))
insize = sizeof(data);
if(!(err = xadHookAccess(XADM XADAC_READ, insize, data, ai)))
{
if((data[0] == 1 || data[0] == 2) && data[1] <= 5 && data[10] <= 16) /* Valid header? */
{
if((fi = (struct xadFileInfo *) xadAllocObject(XADM XADOBJ_FILEINFO,
XAD_OBJPRIVINFOSIZE, sizeof(struct ArcCBMPrivate), TAG_DONE)))
{
fi->xfi_Flags = XADFIF_SEEKDATAPOS|XADFIF_EXTRACTONBUILD|
XADFIF_XADSTRFILENAME;
blocksize = EndGetI16(data+7)*254;
fi->xfi_DataPos = ai->xai_InPos+11+data[10]-insize;
if(data[0] == 2)
fi->xfi_DataPos += 3;
if(data[1] == 5) /* Original size invalid? */
fi->xfi_Flags |= XADFIF_NOUNCRUNCHSIZE;
else
fi->xfi_Size = EndGetI24(data+4);
if(!data[1]) /* File is stored: original size == crunched size */
fi->xfi_CrunchSize = fi->xfi_Size;
else
fi->xfi_CrunchSize = blocksize-11-data[10];
fi->xfi_EntryInfo = arctypes[1+data[1]];
ACBPI(fi)->Version = data[0];
ACBPI(fi)->Method = data[1];
ACBPI(fi)->CRC = EndGetI16(data+2);
/* Set file date */
xadConvertDates(XADM XAD_DATECURRENTTIME, 1, XAD_GETDATEXADDATE,
&fi->xfi_Date, TAG_DONE);
fi->xfi_Flags |= XADFIF_NODATE;
/* The date information contained in ARC files is not very
reliable and thus ignored. */
fi->xfi_FileName = xadConvertName(XADM CHARSET_HOST,
XAD_CHARACTERSET, CHARSET_C64, XAD_PATHSEPERATOR, 0,
XAD_PSTRING, data+10, XAD_ERRORCODE, &err, TAG_DONE);
if(fi->xfi_FileName)
{
/* Set Commodore specific file information */
if((fi->xfi_Special = sp = (struct xadSpecial *)
xadAllocObjectA(XADM XADOBJ_SPECIAL, 0)))
{
sp->xfis_Type=XADSPECIALTYPE_CBM8BIT;
switch (data[9])
{
case 'P':
sp->xfis_Data.xfis_CBM8bit.xfis_FileType=XADCBM8BITTYPE_PRG;
break;
case 'S':
sp->xfis_Data.xfis_CBM8bit.xfis_FileType=XADCBM8BITTYPE_SEQ;
break;
case 'R':
sp->xfis_Data.xfis_CBM8bit.xfis_FileType=XADCBM8BITTYPE_REL;
sp->xfis_Data.xfis_CBM8bit.xfis_RecordLength=data[11+data[10]+1];
break;
case 'U':
sp->xfis_Data.xfis_CBM8bit.xfis_FileType=XADCBM8BITTYPE_USR;
break;
default:
sp->xfis_Data.xfis_CBM8bit.xfis_FileType=XADCBM8BITTYPE_UNKNOWN;
break;
}
if(data[1] != 5) /* Mode 5? */
{
blocksize = ((blocksize+253)/254)*254 + (xadUINT32)ai->xai_InPos - insize;
if(blocksize > ai->xai_InSize)
blocksize = (xadUINT32)ai->xai_InSize;
err = xadAddFileEntry(XADM fi, ai, XAD_SETINPOS, (xadSignSize)blocksize, TAG_DONE);
}
else
err = ArcCBMScanSize(ai, fi, data, xadMasterBase); /* also does addentry */
}
else
{
xadFreeObjectA(XADM fi->xfi_FileName, 0);
xadFreeObjectA(XADM fi, 0);
}
}
else
xadFreeObjectA(XADM fi, 0);
}
else
err = XADERR_NOMEMORY;
}
else if(insize == sizeof(data) && !(data[0] == 0x1A
|| (data[0] == 0x20 && data[1] == 0x20 && data[2] == 0x20))) /* not at end */
err = XADERR_ILLEGALDATA;
else
break;
} /* read header */
} /* loop */
if(err)
{
ai->xai_Flags |= XADAIF_FILECORRUPT;
ai->xai_LastError = err;
}
return (ai->xai_FileInfo ? 0 : err);
}
XADGETINFO(ArcCBMSFX)
{
xadINT8 data[9];
xadINT32 i;
/* Read the first 9 bytes of the file to calculate the start of the
decompressor code */
if((i = xadHookAccess(XADM XADAC_READ, 9, data, ai)))
return i;
i = EndGetI16(data+4);
i = (i == 15 && data[8] == '7') ? (15-6)*254-1 : (i-6)*254; /* i == 15: SDA232.128 */
if((i = xadHookAccess(XADM XADAC_INPUTSEEK, i-9, 0, ai)))
return i;
return ArcCBM_GetInfo(ai, xadMasterBase);
}
static void xadIOArcCRC(struct xadInOut *io, xadUINT32 size)
{
xadUINT16 s;
xadUINT8 s2;
xadUINT32 i;
s = (xadUINT16) (xadUINT32)(uintptr_t) io->xio_OutFuncPrivate;
s2 = (xadUINT8) (((xadUINT32)(uintptr_t) io->xio_OutFuncPrivate) >> 16);
for(i = 0; i < size; i++)
s += io->xio_OutBuffer[i] ^ (++s2);
io->xio_OutFuncPrivate = (xadPTR)(uintptr_t) ((xadUINT32)s + (((xadUINT32)s2)<<16));
}
XADUNARCHIVE(ArcCBM)
{
xadINT32 err = 0;
struct xadFileInfo *fi;
struct xadInOut *io;
fi = ai->xai_CurFile;
if((io = xadIOAlloc(XADIOF_ALLOCINBUFFER|XADIOF_ALLOCOUTBUFFER|XADIOF_NOCRC32|XADIOF_NOCRC16, ai, xadMasterBase)))
{
io->xio_InSize = fi->xfi_CrunchSize;
io->xio_OutSize = fi->xfi_Size;
io->xio_OutFunc = (ACBPI(fi)->Version == 1) ?
xadIOChecksum : xadIOArcCRC;
if(ACBPI(fi)->Method && ACBPI(fi)->Method != 2)
{
io->xio_PutFunc = xadIOPutFuncRLECBM;
xadIOPutFuncRLECBMSet(io, ACBPI(fi)->Method == 1 ?
xadIOGetChar(io) : 0xFE, ACBPI(fi)->Version == 1);
}
switch(ACBPI(fi)->Method)
{
case 0:
case 1:
while(!(io->xio_Flags & (XADIOF_LASTOUTBYTE|XADIOF_ERROR)))
xadIOPutChar(io, xadIOGetChar(io));
break;
case 4:
case 2:
err = CBMunhuff(io);
break;
case 5:
case 3:
err = CBMunpack(io);
break;
default: err = XADERR_DATAFORMAT; break;
}
if(!err)
err = xadIOWriteBuf(io);
if(!err && ((xadUINT16)((uintptr_t)io->xio_OutFuncPrivate)) != ACBPI(fi)->CRC)
{
err = XADERR_CHECKSUM;
}
xadFreeObjectA(XADM io, 0);
}
else
err = XADERR_NOMEMORY;
return err;
}
/**************************************************************************************************/
/*
Warp archives max 160 entries, where every entry is a track side.
Head 0 is indicated by TOP, head 1 by BOT.
576172702076312E3100 Warp v1.1\0
0031 Track number (example: 49)
424F5400 BOT\0 or TOP\0
0001 Fileversion (Always 1)
0003 Algorithmus 1 = Crunch, 2 = Squeeze, 3 = Pack
089A CRC16
000015F8 Crunched Size
576172702076312E3100
0000
544F5000
0002
3350 * These 8 byte are inserted for type 2 block (MFM, IBM)
1880
5100
0000
0001
0CCB
00000BAB
*/
XADRECOGDATA(Warp)
{
if(data[0] == 'W' && data[1] == 'a' && data[2] == 'r' && data[3] == 'p'
&& data[4] == ' ' && data[5] == 'v' && data[6] == '1' && data[7] == '.'
&& data[8] == '1' && !data[9] && !data[10] && !data[15] && data[13] == 'O'
&& !data[16] && data[17] == 1 && !data[18] && data[19] <= 3)
return 1;
else
return 0;
}
XADGETINFO(Warp)
{
xadUINT8 dat[26];
xadINT32 err = 0;
xadUINT32 low = 0, cur = 0, c, num = 1;
struct xadDiskInfo *xdi = 0, *xdi2;
while(!err && ai->xai_InPos < ai->xai_InSize)
{
if(!(err = xadHookAccess(XADM XADAC_READ, 26, dat, ai)))
{
if(Warp_RecogData(26, dat, xadMasterBase))
{
if(!(err = xadHookAccess(XADM XADAC_INPUTSEEK, EndGetM32(dat+22), 0, ai)))
{
c = (dat[11] << 1) + (dat[12] == 'T' ? 0 : 1);
if(!low || cur+1 != c)
{
if(!(xdi2 = (struct xadDiskInfo *) xadAllocObjectA(XADM XADOBJ_DISKINFO, 0)))
err = XADERR_NOMEMORY;
else
{
if(xdi)
{
xdi->xdi_Next = xdi2; xdi->xdi_HighCyl = cur>>1;
}
else
ai->xai_DiskInfo = xdi2;
xdi = xdi2;
xdi->xdi_EntryNumber = num++;
xdi->xdi_SectorSize = 512;
xdi->xdi_Cylinders = 80;
xdi->xdi_Heads = 2;
xdi->xdi_Flags = XADDIF_SEEKDATAPOS|XADDIF_SECTORLABELS;
xdi->xdi_DataPos = ai->xai_InPos-26-EndGetM32(dat+22);
xdi->xdi_TrackSectors = 11;
xdi->xdi_CylSectors = 22;
xdi->xdi_TotalSectors = 1760;
if(dat[12] == 'T' && dat[11] <= 80)
{
cur = c; ++low;
xdi->xdi_LowCyl = dat[11];
}
else
err = XADERR_ILLEGALDATA;
}
}
else
cur = c;
}
}
else
err = XADERR_ILLEGALDATA;
}
}
if(xdi)
xdi->xdi_HighCyl = cur>>1;
if((ai->xai_LastError = err))
ai->xai_Flags |= XADAIF_FILECORRUPT;
return low ? 0 : err;
}
XADUNARCHIVE(Warp)
{
xadUINT32 i, j;
xadINT32 err = 0;
xadUINT8 dat[34];
struct xadInOut *io;
xadSTRPTR inbuf, outbuf;
/* skip entries */
for(i = ai->xai_CurDisk->xdi_LowCyl; !err && i < ai->xai_LowCyl; ++i)
{
for(j = 0; !err && j < 2; ++j)
{
if(!(err = xadHookAccess(XADM XADAC_READ, 34, dat, ai)))
err = xadHookAccess(XADM XADAC_INPUTSEEK, EndGetM32(dat+22), 0, ai);
}
}
if((inbuf = (xadSTRPTR) xadAllocVec(XADM (512+16)*11*2, XADMEMF_PUBLIC)))
{
outbuf = inbuf+((512+16)*11);
for(; !err && i <= ai->xai_HighCyl; ++i)
{
for(j = 0; !err && j < 2; ++j)
{
if(!(err = xadHookAccess(XADM XADAC_READ, 26, dat, ai)))
{
if((io = xadIOAlloc(XADIOF_NOCRC32|XADIOF_NOCRC16, ai, xadMasterBase)))
{
if(dat[19])
io->xio_PutFunc = xadIOPutFuncRLE90;
io->xio_InBuffer = (xadUINT8 *)inbuf;
io->xio_OutBuffer = (xadUINT8 *)outbuf;
io->xio_OutSize = io->xio_OutBufferSize = (512+16)*11;
io->xio_InSize = io->xio_InBufferSize = io->xio_InBufferPos = EndGetM32(dat+22);
switch(dat[19])
{
case 1:
if(xadIOGetChar(io) != 12)
err = XADERR_DECRUNCH;
else
err = xadIO_Compress(io, 12|UCOMPBLOCK_MASK);
break;
case 2:
err = ARCunsqueeze(io);
break;
case 0: case 3:
while(!(io->xio_Flags & (XADIOF_LASTINBYTE|XADIOF_ERROR)))
xadIOPutChar(io, xadIOGetChar(io));
err = io->xio_Error;
break;
default:
err = XADERR_DATAFORMAT;
}
if(!err && xadCalcCRC16(XADM XADCRC16_ID1, 0, (512+16)*11, (xadUINT8 *) outbuf) != EndGetM16(dat+20))
err = XADERR_CHECKSUM;
if(!err)
{
err = xadHookTagAccess(XADM XADAC_WRITE, 512*11, outbuf,
ai, XAD_SECTORLABELS, outbuf+512*11, TAG_DONE);
}
xadFreeObjectA(XADM io, 0);
}
else
err = XADERR_NOMEMORY;
}
}
}
xadFreeObjectA(XADM inbuf, 0);
}
else
err = XADERR_NOMEMORY;
return err;
}
/**************************************************************************************************/
/*
All words are in Intel format
1 xadINT8 ID $76
1 xadINT8 ID $FE / $FD
1 STRING Filename + comment (optional): FILENAME.EXT[ COMMENT]\0
1 xadINT8 Cruncher version, high nibble major version, low nibble minor version
1 xadINT8 Crunched format version, high nibble major version, low nibble minor version
1 xadINT8 Checksum flag (0 = checksum can be checked)
1 xadINT8 Spare info byte (unused)
n BYTEs LZW compressed data
EOF:
1 xadINT16 Checksum (sum of all bytes in decrunched file)
n BYTEs Padding bytes (optional) (to make the file size a multiple of 128)
Minimum file size: 7 bytes + 9 bits + 2 bytes => 11 bytes
*/
XADRECOGDATA(Crunch)
{
int i;
if(size >= 11 && data[0]==0x76 && data[1]==0xFD)
{
for(i = 2; data[i] && i < size; ++i)
;
/* Check buffer size */
if(++i <= size-6)
{
/* Check format version byte */
if(data[i] >= 0x10 && data[i] <= 0x2F)
return 1;
}
}
return 0;
}
XADGETINFO(Crunch)
{
xadUINT8 data[256];
struct xadFileInfo *fi;
xadINT32 err;
int i, j;
if((i = (int)ai->xai_InSize) > 256)
i = 256;
if(!(err = xadHookAccess(XADM XADAC_READ, i, data, ai)))
{
if((fi=(struct xadFileInfo *) xadAllocObjectA(XADM XADOBJ_FILEINFO, NULL)))
{
fi->xfi_Flags = XADFIF_NODATE|XADFIF_SEEKDATAPOS|XADFIF_NOUNCRUNCHSIZE|
XADFIF_EXTRACTONBUILD|XADFIF_XADSTRFILENAME|XADFIF_XADSTRCOMMENT;
/* Calculate filename length and comment length */
i=2;
while(data[i] && data[i] != '[')
++i;
for(j = i; data[j-1] == ' '; --j)
;
if((fi->xfi_FileName=xadConvertName(XADM CHARSET_HOST, XAD_CHARACTERSET,
CHARSET_ASCII, XAD_STRINGSIZE, j-2, XAD_CSTRING, data+2,
XAD_ERRORCODE, &err, TAG_DONE)))
{
if(data[i]) /* Comment available */
{
++i;
if(data[i] == ' ') ++i; /* Skip leading space */
j=i;
while(data[i] && data[i] != ']')
++i;
fi->xfi_Comment = xadConvertName(XADM CHARSET_HOST, XAD_CHARACTERSET,
CHARSET_ASCII, XAD_STRINGSIZE, i-j, XAD_CSTRING, data+j, TAG_DONE);
}
/* Make sure to skip until the end of the string */
while(data[i])
++i;
++i;
fi->xfi_DataPos = i;
fi->xfi_CrunchSize = ai->xai_InSize-2-fi->xfi_DataPos;
fi->xfi_PrivateInfo = (xadPTR)(uintptr_t) data[1];
if((data[i+1] & 0xF0) == 0x10)
{
fi->xfi_EntryInfo = data[1] == 0xFE ? (xadSTRPTR)"LZW 1" : (xadSTRPTR)"LZHUF 1";
}
else
{
fi->xfi_EntryInfo = data[1] == 0xFE ? (xadSTRPTR)"LZW 2" : (xadSTRPTR)"LZHUF 2";
}
/* fill in today's date */
xadConvertDates(XADM XAD_DATECURRENTTIME, XADTRUE, XAD_GETDATEXADDATE,
&fi->xfi_Date, TAG_DONE);
return xadAddFileEntryA(XADM fi, ai, 0);
}
xadFreeObjectA(XADM fi, 0);
}
else err = XADERR_NOMEMORY;
}
return err;
}
XADUNARCHIVE(Crunch)
{
xadUINT8 data[4];
xadUINT16 chksum;
xadINT32 err;
/* Read 4 info bytes */
if(!(err=xadHookAccess(XADM XADAC_READ, 4, data, ai)))
{
struct xadInOut *io;
if((io = xadIOAlloc(XADIOF_ALLOCINBUFFER|XADIOF_ALLOCOUTBUFFER|
XADIOF_NOOUTENDERR|XADIOF_NOCRC32|XADIOF_NOCRC16, ai, xadMasterBase)))
{
io->xio_InSize = ai->xai_CurFile->xfi_CrunchSize;
io->xio_OutFunc = xadIOChecksum;
/* io->xio_OutSize = 0; */
err = DecrAMPK3(io, ((data[1] & 0xF0) == 0x10) ? 1 : 2);
if(!err)
err = xadIOWriteBuf(io);
if(!err && !data[2])
{
chksum = xadIOGetChar(io);
chksum += xadIOGetChar(io)<<8;
if((((xadUINT32)(uintptr_t)io->xio_OutFuncPrivate)&0xFFFF) != chksum)
err = XADERR_CHECKSUM;
}
xadFreeObjectA(XADM io, 0);
}
else
err = XADERR_NOMEMORY;
}
return err;
}
/**************************************************************************************************/
XADCLIENT(Crunch) {
(struct xadClient *)XADNEXTCLIENT,
XADCLIENT_VERSION,
XADMASTERVERSION,
CRUNCH_VERSION,
CRUNCH_REVISION,
256,
XADCF_FILEARCHIVER|XADCF_FREEFILEINFO|XADCF_NOCHECKSIZE|XADCF_FREEXADSTRINGS,
XADCID_CRUNCH,
"Crunch-LZHUF",
XADRECOGDATAP(Crunch),
XADGETINFOP(Crunch),
XADUNARCHIVEP(Crunch),
NULL
};
XADCLIENT(Warp) {
(struct xadClient *)&Crunch_Client,
XADCLIENT_VERSION,
XADMASTERVERSION,
WARP_VERSION,
WARP_REVISION,
26,
XADCF_DISKARCHIVER|XADCF_FREEDISKINFO,
XADCID_WARP,
"Warp",
XADRECOGDATAP(Warp),
XADGETINFOP(Warp),
XADUNARCHIVEP(Warp),
NULL
};
XADCLIENT(ArcCBMSFX) {
(struct xadClient *)&Warp_Client,
XADCLIENT_VERSION,
XADMASTERVERSION,
ARCCBMSFX_VERSION,
ARCCBMSFX_REVISION,
4064+11,
XADCF_FILEARCHIVER|XADCF_FREEFILEINFO|XADCF_FREESPECIALINFO
|XADCF_FREEXADSTRINGS|XADCF_NOCHECKSIZE,
XADCID_ARCCBMSFX,
"Arc CBM SFX",
XADRECOGDATAP(ArcCBMSFX),
XADGETINFOP(ArcCBMSFX),
XADUNARCHIVEP(ArcCBM),
NULL
};
XADCLIENT(ArcCBM) {
(struct xadClient *)&ArcCBMSFX_Client,
XADCLIENT_VERSION,
XADMASTERVERSION,
ARCCBM_VERSION,
ARCCBM_REVISION,
11,
XADCF_FILEARCHIVER|XADCF_FREEFILEINFO|XADCF_FREESPECIALINFO
|XADCF_FREEXADSTRINGS,
XADCID_ARCCBM,
"Arc CBM",
XADRECOGDATAP(ArcCBM),
XADGETINFOP(ArcCBM),
XADUNARCHIVEP(ArcCBM),
NULL
};
XADCLIENT(CompDisk) {
(struct xadClient *)&ArcCBM_Client,
XADCLIENT_VERSION,
XADMASTERVERSION,
COMPDISK_VERSION,
COMPDISK_REVISION,
12,
XADCF_DISKARCHIVER|XADCF_FREEDISKINFO,
XADCID_COMPDISK,
"CompDisk",
XADRECOGDATAP(CompDisk),
XADGETINFOP(CompDisk),
XADUNARCHIVEP(CompDisk),
NULL
};
XADCLIENT(LHWarp) {
(struct xadClient *)&CompDisk_Client,
XADCLIENT_VERSION,
XADMASTERVERSION,
LHWARP_VERSION,
LHWARP_REVISION,
20,
XADCF_DISKARCHIVER|XADCF_FREEDISKINFO|XADCF_FREETEXTINFO
|XADCF_FREETEXTINFOTEXT,
XADCID_LHWARP,
"LhWarp",
XADRECOGDATAP(LHWARP),
XADGETINFOP(LHWARP),
XADUNARCHIVEP(LHWARP),
NULL
};
XADCLIENT(AmPlusUnpack) {
(struct xadClient *)&LHWarp_Client,
XADCLIENT_VERSION,
XADMASTERVERSION,
AMPLUSUNPACK_VERSION,
AMPLUSUNPACK_REVISION,
12,
XADCF_FILEARCHIVER|XADCF_FREEFILEINFO,
XADCID_AMIGAPLUSUNPACK,
"Amiga Plus Unpack",
XADRECOGDATAP(AmPlusUnpack),
XADGETINFOP(AmPlusUnpack),
XADUNARCHIVEP(AmPlusUnpack),
NULL
};
XADFIRSTCLIENT(AMPK) {
(struct xadClient *)&AmPlusUnpack_Client,
XADCLIENT_VERSION,
XADMASTERVERSION,
AMPK_VERSION,
AMPK_REVISION,
12,
XADCF_FILEARCHIVER|XADCF_FREEFILEINFO,
XADCID_AMIPACK,
"AmiPack",
XADRECOGDATAP(AMPK),
XADGETINFOP(AMPK),
XADUNARCHIVEP(AMPK),
NULL
};
#undef XADNEXTCLIENT
#define XADNEXTCLIENT XADNEXTCLIENTNAME(AMPK)
#endif /* XADMASTER_AMPK_C */