mirror of
https://github.com/MacPaw/XADMaster.git
synced 2025-08-29 03:23:48 +02:00
2566 lines
71 KiB
C
Executable file
2566 lines
71 KiB
C
Executable file
#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 */
|