home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ANews 1
/
AnewsCD01.iso
/
Indispensables
/
Compression
/
xad
/
Developer
/
Sources
/
clients
/
LZX.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-08-09
|
26KB
|
990 lines
#ifndef XADMASTER_LZX_C
#define XADMASTER_LZX_C
/* Programmheader
Name: LZX.c
Main: xadmaster
Versionstring: $VER: LZX.c 1.3 (29.06.1999)
Author: SDI, David Tritscher
Distribution: Freeware
Description: LZX file archiver client
1.0 09.02.99 : first working version
1.1 13.03.99 : now uses register parameters
1.2 20.06.99 : removed exec.library calls
1.3 29.06.99 : now uses master free stuff
*/
/* The decrunch routines of this client are based on unlzx sources code made
by David Tritscher. Thanks guy, was a big help. A made the routines
reentrant (using a parameter structure) and developed the XAD interface
functions. */
#include <proto/xadmaster.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include "SDI_compiler.h"
#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"
#ifndef XADMASTERFILE
#define LZX_Client FirstClient
#define NEXTCLIENT 0
UBYTE version[] = "$VER: LZX 1.3 (29.06.1999) Freeware";
#endif
#define LZX_VERSION 1
#define LZX_REVISION 3
/* ---------------------------------------------------------------------- */
#define LZXINFO_DAMAGE_PROTECT 1
#define LZXINFO_FLAG_LOCKED 2
struct LZXInfo_Header
{
UBYTE ID[3]; /* "LZX" */
UBYTE Flags; /* LZXINFO_FLAG_#? */
UBYTE Unknown[6];
};
#define LZXHDR_FLAG_MERGED (1<<0)
#define LZXHDR_PROT_READ (1<<0)
#define LZXHDR_PROT_WRITE (1<<1)
#define LZXHDR_PROT_DELETE (1<<2)
#define LZXHDR_PROT_EXECUTE (1<<3)
#define LZXHDR_PROT_ARCHIVE (1<<4)
#define LZXHDR_PROT_HOLD (1<<5)
#define LZXHDR_PROT_SCRIPT (1<<6)
#define LZXHDR_PROT_PURE (1<<7)
#define LZXHDR_TYPE_MSDOS 0
#define LZXHDR_TYPE_WINDOWS 1
#define LZXHDR_TYPE_OS2 2
#define LZXHDR_TYPE_AMIGA 10
#define LZXHDR_TYPE_UNIX 20
#define LZXHDR_PACK_STORE 0
#define LZXHDR_PACK_NORMAL 2
#define LZXHDR_PACK_EOF 32
struct LZXArc_Header
{
UBYTE Attributes; /* 0 - LZXHDR_PROT_#? */
UBYTE pad1; /* 1 */
ULONG FileSize; /* 2 (little endian) */
ULONG CrSize; /* 6 (little endian) */
UBYTE MachineType; /* 10 - LZXHDR_TYPE_#? */
UBYTE PackMode; /* 11 - LZXHDR_PACK_#? */
UBYTE Flags; /* 12 - LZXHDR_FLAG_#? */
UBYTE pad2; /* 13 */
UBYTE CommentSize; /* 14 - length (0-79) */
UBYTE ExtractVersion; /* 15 - version needed to extract */
UBYTE pad3; /* 16 */
UBYTE pad4; /* 17 */
ULONG Date; /* 18 - Packed_Date */
ULONG DataCRC; /* 22 (little endian) */
ULONG HeaderCRC; /* 26 (little endian) */
UBYTE FilenameSize; /* 30 - filename length */
}; /* SIZE = 31 */
/* Header CRC includes filename and comment. */
#define LZXHEADERSIZE 31
/* Packed date [4 BYTES, bit 0 is MSB, 31 is LSB]
bit 0 - 4 Day
5 - 8 Month (January is 0)
9 - 14 Year (start 1970)
15 - 19 Hour
20 - 25 Minute
26 - 31 Second
*/
struct LZXEntryData {
ULONG CRC; /* CRC of uncrunched data */
ULONG PackMode; /* CrunchMode */
ULONG ArchivePos; /* Position is source file */
ULONG DataStart; /* Position in merged buffer */
};
#define LZXPE(a) ((struct LZXEntryData *) ((a)->xfi_PrivateInfo))
#define LZXDD(a) ((struct LZXDecrData *) ((a)->xai_PrivateClient))
struct LZXDecrData {
ULONG ArchivePos; /* The Archive-Pos to detect if it is correct buffer */
ULONG DataPos; /* must be lower or equal to current entry or reinit is necessary */
UBYTE *source;
UBYTE *destination;
UBYTE *source_end;
UBYTE *destination_end;
UBYTE *pos;
ULONG decrunch_method;
ULONG decrunch_length;
ULONG pack_size;
ULONG last_offset;
ULONG control;
LONG shift;
UBYTE offset_len[8];
UWORD offset_table[128];
UBYTE huffman20_len[20];
UWORD huffman20_table[96];
UBYTE literal_len[768];
UWORD literal_table[5120];
UBYTE read_buffer[16384]; /* have a reasonable sized read buffer */
UBYTE decrunch_buffer[258+65536+258]; /* allow overrun for speed */
};
static ULONG LZXConvEnd32(ULONG a)
{
ULONG b = 0, i;
for(i = 0; i <= 24; i += 8)
b += ((UBYTE)(a >> i))<<(24-i);
return b;
}
ASM(BOOL) LZX_RecogData(REG(d0, ULONG size), REG(a0, STRPTR data),
REG(a6, struct xadMasterBase *xadMasterBase))
{
if(data[0] == 'L' && data[1] == 'Z' && data[2] == 'X')
return 1;
else
return 0;
}
ASM(LONG) LZX_GetInfo(REG(a0, struct xadArchiveInfo *ai),
REG(a6, struct xadMasterBase *xadMasterBase))
{
LONG err, num = 1;
ULONG bufpos = 0;
struct xadFileInfo *fi = 0, *fi2, *fig = 0; /* fig - first grouped ptr */
struct LZXArc_Header head;
if(!(err = xadHookAccess(XADAC_INPUTSEEK, sizeof(struct LZXInfo_Header), 0, ai)))
{
while(!err && ai->xai_InPos < ai->xai_InSize)
{
if(!(err = xadHookAccess(XADAC_READ, LZXHEADERSIZE, &head, ai)))
{
ULONG i, j, k, l, crc;
i = head.CommentSize;
j = head.FilenameSize;
k = LZXConvEnd32(head.HeaderCRC);
head.HeaderCRC = 0; /* clear for CRC check */
if(!(fi2 = (struct xadFileInfo *) xadAllocObject(XADOBJ_FILEINFO,
XAD_OBJNAMESIZE, j+1, i ? XAD_OBJCOMMENTSIZE : TAG_IGNORE, i+1,
XAD_OBJPRIVINFOSIZE, sizeof(struct LZXEntryData), TAG_DONE)))
err = XADERR_NOMEMORY;
else if(!(err = xadHookAccess(XADAC_READ, j, fi2->xfi_FileName, ai)) &&
(!i || !(err = xadHookAccess(XADAC_READ, i, fi2->xfi_Comment, ai))))
{
l = LZXConvEnd32(head.CrSize);
if(!l || !(err = xadHookAccess(XADAC_INPUTSEEK, l, 0, ai)))
{
crc = xadCalcCRC32(XADCRC32_ID1, ~0, LZXHEADERSIZE, (STRPTR) &head);
crc = xadCalcCRC32(XADCRC32_ID1, crc, j, fi2->xfi_FileName);
if(i)
crc = xadCalcCRC32(XADCRC32_ID1, crc, i, fi2->xfi_Comment);
if(~crc != k)
err = XADERR_CHECKSUM;
else
{
if(!fig)
{
fig = fi2; bufpos = 0;
}
fi2->xfi_Size = LZXConvEnd32(head.FileSize);
fi2->xfi_EntryNumber = num++;
if(!l && !fi2->xfi_Size && fi2->xfi_FileName[--j] == '/')
{
fi2->xfi_FileName[j] = 0;
fi2->xfi_Flags |= XADFIF_DIRECTORY;
}
i = head.Attributes;
j = 0;
if(!(i & LZXHDR_PROT_READ))
j |= FIBF_READ;
if(!(i & LZXHDR_PROT_WRITE))
j |= FIBF_WRITE;
if(!(i & LZXHDR_PROT_DELETE))
j |= FIBF_DELETE;
if(!(i & LZXHDR_PROT_EXECUTE))
j |= FIBF_EXECUTE;
j |= (i & (LZXHDR_PROT_ARCHIVE|LZXHDR_PROT_SCRIPT));
if(i & LZXHDR_PROT_PURE)
j |= FIBF_PURE;
if(i & LZXHDR_PROT_HOLD)
j |= (1<<7); /* not defined in <dos/dos.h> */
fi2->xfi_Protection = j;
{ /* Make the date */
struct xadDate d;
j = head.Date;
d.xd_Second = j & 63;
j >>= 6;
d.xd_Minute = j & 63;
j >>= 6;
d.xd_Hour = j & 31;
j >>= 5;
d.xd_Year = 1970 + (j & 63);
j >>= 6;
d.xd_Month = 1 + (j & 15);
j >>= 4;
d.xd_Day = j;
d.xd_Micros = 0;
xadConvertDates(XAD_DATEXADDATE, &d, XAD_GETDATEXADDATE,
&fi2->xfi_Date, TAG_DONE);
}
LZXPE(fi2)->CRC = LZXConvEnd32(head.DataCRC);
LZXPE(fi2)->DataStart = bufpos;
bufpos += fi2->xfi_Size;
if(head.Flags & LZXHDR_FLAG_MERGED)
{
fi2->xfi_Flags |= XADFIF_GROUPED;
if(l)
{
fi2->xfi_Flags |= XADFIF_ENDOFGROUP;
fi2->xfi_GroupCrSize = l;
}
}
else
fi2->xfi_CrunchSize = l;
if(l)
{
LZXPE(fi2)->ArchivePos = ai->xai_InPos-l;
LZXPE(fi2)->PackMode = head.PackMode;
while(fig)
{
fig->xfi_GroupCrSize = l;
LZXPE(fig)->ArchivePos = ai->xai_InPos-l;
LZXPE(fig)->PackMode = head.PackMode;
fig = fig->xfi_Next;
}
}
if(!fi)
ai->xai_FileInfo = fi2;
else
fi->xfi_Next = fi2;
fi = fi2;
fi2 = 0;
} /* skip crunched data */
} /* get filename and comment */
if(fi2)
xadFreeObjectA(fi2,0);
} /* xadFileInfo Allocation */
} /* READ header */
} /* while loop */
} /* INPUTSEEK 3 bytes */
if(err && ai->xai_FileInfo)
{
ai->xai_Flags |= XADAIF_FILECORRUPT;
ai->xai_LastError = err;
err = 0;
}
return err;
}
/* ---------------------------------------------------------------------- */
static const UBYTE LZXtable_one[32]=
{
0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14
};
static const ULONG LZXtable_two[32]=
{
0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,
1536,2048,3072,4096,6144,8192,12288,16384,24576,32768,49152
};
static const ULONG LZXtable_three[16]=
{
0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767
};
static const UBYTE LZXtable_four[34]=
{
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
};
/* ---------------------------------------------------------------------- */
/* Build a fast huffman decode table from the symbol bit lengths. */
/* There is an alternate algorithm which is faster but also more complex. */
static LONG LZXmake_decode_table(LONG number_symbols, LONG LZXtable_size,
UBYTE *length, unsigned short *table)
{
register UBYTE bit_num = 0;
register LONG symbol;
ULONG leaf; /* could be a register */
ULONG LZXtable_mask, bit_mask, pos, fill, next_symbol, reverse;
LONG abort = 0;
pos = 0; /* consistantly used as the current position in the decode table */
bit_mask = LZXtable_mask = 1 << LZXtable_size;
bit_mask >>= 1; /* don't do the first number */
bit_num++;
while((!abort) && (bit_num <= LZXtable_size))
{
for(symbol = 0; symbol < number_symbols; symbol++)
{
if(length[symbol] == bit_num)
{
reverse = pos; /* reverse the order of the position's bits */
leaf = 0;
fill = LZXtable_size;
do /* reverse the position */
{
leaf = (leaf << 1) + (reverse & 1);
reverse >>= 1;
} while(--fill);
if((pos += bit_mask) > LZXtable_mask)
{
abort = 1;
break; /* we will overrun the table! abort! */
}
fill = bit_mask;
next_symbol = 1 << bit_num;
do
{
table[leaf] = symbol;
leaf += next_symbol;
} while(--fill);
}
}
bit_mask >>= 1;
bit_num++;
}
if((!abort) && (pos != LZXtable_mask))
{
for(symbol = pos; symbol < LZXtable_mask; symbol++) /* clear the rest of the table */
{
reverse = symbol; /* reverse the order of the position's bits */
leaf = 0;
fill = LZXtable_size;
do /* reverse the position */
{
leaf = (leaf << 1) + (reverse & 1);
reverse >>= 1;
} while(--fill);
table[leaf] = 0;
}
next_symbol = LZXtable_mask >> 1;
pos <<= 16;
LZXtable_mask <<= 16;
bit_mask = 32768;
while((!abort) && (bit_num <= 16))
{
for(symbol = 0; symbol < number_symbols; symbol++)
{
if(length[symbol] == bit_num)
{
reverse = pos >> 16; /* reverse the order of the position's bits */
leaf = 0;
fill = LZXtable_size;
do /* reverse the position */
{
leaf = (leaf << 1) + (reverse & 1);
reverse >>= 1;
} while(--fill);
for(fill = 0; fill < bit_num - LZXtable_size; fill++)
{
if(table[leaf] == 0)
{
table[(next_symbol << 1)] = 0;
table[(next_symbol << 1) + 1] = 0;
table[leaf] = next_symbol++;
}
leaf = table[leaf] << 1;
leaf += (pos >> (15 - fill)) & 1;
}
table[leaf] = symbol;
if((pos += bit_mask) > LZXtable_mask)
{
abort = 1;
break; /* we will overrun the table! abort! */
}
}
}
bit_mask >>= 1;
bit_num++;
}
}
if(pos != LZXtable_mask) abort = 1; /* the table is incomplete! */
return(abort);
}
/* ---------------------------------------------------------------------- */
/* Read and build the decrunch tables. There better be enough data in the */
/* source buffer or it's stuffed. */
static LONG LZX_read_literal_table(struct LZXDecrData *decr)
{
register ULONG control;
register LONG shift;
ULONG temp; /* could be a register */
ULONG symbol, pos, count, fix, max_symbol;
UBYTE *source;
LONG abort = 0;
source = decr->source;
control = decr->control;
shift = decr->shift;
if(shift < 0) /* fix the control word if necessary */
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
/* read the decrunch method */
decr->decrunch_method = control & 7;
control >>= 3;
if((shift -= 3) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
/* Read and build the offset huffman table */
if((!abort) && (decr->decrunch_method == 3))
{
for(temp = 0; temp < 8; temp++)
{
decr->offset_len[temp] = control & 7;
control >>= 3;
if((shift -= 3) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
}
abort = LZXmake_decode_table(8, 7, decr->offset_len, decr->offset_table);
}
/* read decrunch length */
if(!abort)
{
decr->decrunch_length = (control & 255) << 16;
control >>= 8;
if((shift -= 8) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
decr->decrunch_length += (control & 255) << 8;
control >>= 8;
if((shift -= 8) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
decr->decrunch_length += (control & 255);
control >>= 8;
if((shift -= 8) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
}
/* read and build the huffman literal table */
if((!abort) && (decr->decrunch_method != 1))
{
pos = 0;
fix = 1;
max_symbol = 256;
do
{
for(temp = 0; temp < 20; temp++)
{
decr->huffman20_len[temp] = control & 15;
control >>= 4;
if((shift -= 4) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
}
abort = LZXmake_decode_table(20, 6, decr->huffman20_len, decr->huffman20_table);
if(abort) break; /* argh! table is corrupt! */
do
{
if((symbol = decr->huffman20_table[control & 63]) >= 20)
{
do /* symbol is longer than 6 bits */
{
symbol = decr->huffman20_table[((control >> 6) & 1) + (symbol << 1)];
if(!shift--)
{
shift += 16;
control += *source++ << 24;
control += *source++ << 16;
}
control >>= 1;
} while(symbol >= 20);
temp = 6;
}
else
{
temp = decr->huffman20_len[symbol];
}
control >>= temp;
if((shift -= temp) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
switch(symbol)
{
case 17:
case 18:
{
if(symbol == 17)
{
temp = 4;
count = 3;
}
else /* symbol == 18 */
{
temp = 6 - fix;
count = 19;
}
count += (control & LZXtable_three[temp]) + fix;
control >>= temp;
if((shift -= temp) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
while((pos < max_symbol) && (count--))
decr->literal_len[pos++] = 0;
break;
}
case 19:
{
count = (control & 1) + 3 + fix;
if(!shift--)
{
shift += 16;
control += *source++ << 24;
control += *source++ << 16;
}
control >>= 1;
if((symbol = decr->huffman20_table[control & 63]) >= 20)
{
do /* symbol is longer than 6 bits */
{
symbol = decr->huffman20_table[((control >> 6) & 1) + (symbol << 1)];
if(!shift--)
{
shift += 16;
control += *source++ << 24;
control += *source++ << 16;
}
control >>= 1;
} while(symbol >= 20);
temp = 6;
}
else
{
temp = decr->huffman20_len[symbol];
}
control >>= temp;
if((shift -= temp) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
symbol = LZXtable_four[decr->literal_len[pos] + 17 - symbol];
while((pos < max_symbol) && (count--))
decr->literal_len[pos++] = symbol;
break;
}
default:
{
symbol = LZXtable_four[decr->literal_len[pos] + 17 - symbol];
decr->literal_len[pos++] = symbol;
break;
}
}
} while(pos < max_symbol);
fix--;
max_symbol += 512;
} while(max_symbol == 768);
if(!abort)
abort = LZXmake_decode_table(768, 12, decr->literal_len, decr->literal_table);
}
decr->control = control;
decr->shift = shift;
decr->source = source;
return(abort);
}
/* ---------------------------------------------------------------------- */
/* Fill up the decrunch buffer. Needs lots of overrun for both destination */
/* and source buffers. Most of the time is spent in this routine so it's */
/* pretty damn optimized. */
static void LZXdecrunch(struct LZXDecrData *decr)
{
register ULONG control;
register LONG shift;
ULONG temp; /* could be a register */
ULONG symbol, count;
UBYTE *string, *source, *destination;
control = decr->control;
shift = decr->shift;
source = decr->source;
destination = decr->destination;
do
{
if((symbol = decr->literal_table[control & 4095]) >= 768)
{
control >>= 12;
if((shift -= 12) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
do /* literal is longer than 12 bits */
{
symbol = decr->literal_table[(control & 1) + (symbol << 1)];
if(!shift--)
{
shift += 16;
control += *source++ << 24;
control += *source++ << 16;
}
control >>= 1;
} while(symbol >= 768);
}
else
{
temp = decr->literal_len[symbol];
control >>= temp;
if((shift -= temp) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
}
if(symbol < 256)
{
*destination++ = symbol;
}
else
{
symbol -= 256;
count = LZXtable_two[temp = symbol & 31];
temp = LZXtable_one[temp];
if((temp >= 3) && (decr->decrunch_method == 3))
{
temp -= 3;
count += ((control & LZXtable_three[temp]) << 3);
control >>= temp;
if((shift -= temp) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
count += (temp = decr->offset_table[control & 127]);
temp = decr->offset_len[temp];
}
else
{
count += control & LZXtable_three[temp];
if(!count) count = decr->last_offset;
}
control >>= temp;
if((shift -= temp) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
decr->last_offset = count;
count = LZXtable_two[temp = (symbol >> 5) & 15] + 3;
temp = LZXtable_one[temp];
count += (control & LZXtable_three[temp]);
control >>= temp;
if((shift -= temp) < 0)
{
shift += 16;
control += *source++ << (8 + shift);
control += *source++ << shift;
}
string = (decr->decrunch_buffer + decr->last_offset < destination) ?
destination - decr->last_offset : destination + 65536 - decr->last_offset;
do
{
*destination++ = *string++;
} while(--count);
}
} while((destination < decr->destination_end) && (source < decr->source_end));
decr->control = control;
decr->shift = shift;
decr->source = source;
decr->destination = destination;
}
/* ---------------------------------------------------------------------- */
static LONG LZXextract(struct xadArchiveInfo *ai, struct xadMasterBase *xadMasterBase,
ULONG unpack_size, ULONG rescrc)
{
UBYTE *temp;
ULONG count, crc = ~0;
LONG err;
struct LZXDecrData *decr;
decr = (struct LZXDecrData *) ai->xai_PrivateClient;
while(unpack_size > 0)
{
if(decr->pos == decr->destination) /* time to fill the buffer? */
{
/* check if we have enough data and read some if not */
if(decr->source >= decr->source_end) /* have we exhausted the current read buffer? */
{
temp = decr->read_buffer;
if(count = temp - decr->source + 16384)
{
do /* copy the remaining overrun to the start of the buffer */
{
*temp++ = *(decr->source++);
} while(--count);
}
decr->source = decr->read_buffer;
count = decr->source - temp + 16384;
if(decr->pack_size < count)
count = decr->pack_size; /* make sure we don't read too much */
if((err = xadHookAccess(XADAC_READ, count, temp, ai)))
return err;
decr->pack_size -= count;
temp += count;
if(decr->source >= temp)
return XADERR_DECRUNCH; /* argh! no more data! */
} /* if(decr->source >= decr->source_end) */
/* check if we need to read the tables */
if(decr->decrunch_length <= 0)
{
if(LZX_read_literal_table(decr))
return XADERR_DECRUNCH; /* argh! can't make huffman tables! */
}
/* unpack some data */
if(decr->destination >= decr->decrunch_buffer + 258 + 65536)
{
if(count = decr->destination - decr->decrunch_buffer - 65536)
{
temp = (decr->destination = decr->decrunch_buffer) + 65536;
do /* copy the overrun to the start of the buffer */
{
*(decr->destination++) = *temp++;
} while(--count);
}
decr->pos = decr->destination;
}
decr->destination_end = decr->destination + decr->decrunch_length;
if(decr->destination_end > decr->decrunch_buffer + 258 + 65536)
decr->destination_end = decr->decrunch_buffer + 258 + 65536;
temp = decr->destination;
LZXdecrunch(decr);
decr->decrunch_length -= (decr->destination - temp);
}
/* calculate amount of data we can use before we need to fill the buffer again */
count = decr->destination - decr->pos;
if(count > unpack_size)
count = unpack_size; /* take only what we need */
if(rescrc) /* when no CRC given, then skip writing */
{
crc = xadCalcCRC32(XADCRC32_ID1, crc, count, decr->pos);
if((err = xadHookAccess(XADAC_WRITE, count, decr->pos, ai)))
return err;
}
unpack_size -= count;
decr->pos += count;
decr->DataPos += count;
}
if(rescrc && ~crc != rescrc)
return XADERR_CHECKSUM;
return 0;
}
/* ---------------------------------------------------------------------- */
ASM(LONG) LZX_UnArchive(REG(a0, struct xadArchiveInfo *ai),
REG(a6, struct xadMasterBase *xadMasterBase))
{
struct xadFileInfo *fi;
LONG ret = 0, crc;
fi = ai->xai_CurFile;
if(!ai->xai_PrivateClient || LZXDD(ai)->ArchivePos != LZXPE(fi)->ArchivePos
|| LZXDD(ai)->DataPos > LZXPE(fi)->DataStart)
{
if(ai->xai_PrivateClient) /* free the unneeded client */
{
xadFreeObjectA(ai->xai_PrivateClient, 0);
ai->xai_PrivateClient = 0;
}
if((crc = LZXPE(fi)->ArchivePos - ai->xai_InPos))
{
if((ret = xadHookAccess(XADAC_INPUTSEEK, crc, 0, ai)))
return ret;
}
}
switch(LZXPE(fi)->PackMode)
{
case LZXHDR_PACK_STORE:
{
ULONG bufsize, data;
APTR buf;
crc = ~0;
data = fi->xfi_Size;
if((bufsize = data) > 51200)
bufsize = 51200;
if((buf = xadAllocVec(bufsize, MEMF_PUBLIC)))
{
while(data && !ret)
{
if(data < bufsize)
bufsize = data;
if(!(ret = xadHookAccess(XADAC_READ, bufsize, buf, ai)))
{
crc = xadCalcCRC32(XADCRC32_ID1, crc, bufsize, buf);
ret = xadHookAccess(XADAC_WRITE, bufsize, buf, ai);
}
data -= bufsize;
}
xadFreeObjectA(buf,0);
}
else
ret = XADERR_NOMEMORY;
if(!ret && ~crc != LZXPE(fi)->CRC)
ret = XADERR_CHECKSUM;
}
break;
case LZXHDR_PACK_NORMAL:
{
struct LZXDecrData *decr = 0;
if(!ai->xai_PrivateClient && !(decr = (struct LZXDecrData *)
xadAllocVec(sizeof(struct LZXDecrData), MEMF_PUBLIC|MEMF_CLEAR)))
ret = XADERR_NOMEMORY;
else
{
if(decr)
{
decr->ArchivePos = LZXPE(fi)->ArchivePos;
decr->DataPos = 0;
decr->shift = -16;
decr->last_offset = 1;
decr->source_end = (decr->source = decr->read_buffer + 16384) - 1024;
decr->pos = decr->destination_end = decr->destination = decr->decrunch_buffer + 258 + 65536;
decr->pack_size = fi->xfi_Flags & XADFIF_GROUPED ?
fi->xfi_GroupCrSize : fi->xfi_CrunchSize;
ai->xai_PrivateClient = decr;
}
if((crc = LZXPE(fi)->DataStart - LZXDD(ai)->DataPos))
ret = LZXextract(ai, xadMasterBase, crc, 0);
if(!ret)
ret = LZXextract(ai, xadMasterBase, fi->xfi_Size, LZXPE(fi)->CRC);
/* free no longer needed temporary buffer and stuff structure */
if(ret || !(fi->xfi_Flags & XADFIF_GROUPED) || (fi->xfi_Flags & XADFIF_ENDOFGROUP))
{
xadFreeObjectA(ai->xai_PrivateClient, 0);
ai->xai_PrivateClient = 0;
}
}
}
break;
default: ret = XADERR_DECRUNCH; break;
}
return ret;
}
ASM(void) LZX_Free(REG(a0, struct xadArchiveInfo *ai),
REG(a6, struct xadMasterBase *xadMasterBase))
{
if(ai->xai_PrivateClient) /* decrunch buffer */
{
xadFreeObjectA(ai->xai_PrivateClient, 0);
ai->xai_PrivateClient = 0;
}
}
struct xadClient LZX_Client = {
NEXTCLIENT, XADCLIENT_VERSION, 2, LZX_VERSION, LZX_REVISION,
10, XADCF_FILEARCHIVER|XADCF_FREEFILEINFO, XADCID_LZX, "LZX",
(BOOL (*)()) LZX_RecogData, (LONG (*)()) LZX_GetInfo,
(LONG (*)()) LZX_UnArchive, (void (*)()) LZX_Free};
#endif /* XADASTER_LZX_C */