XADMaster/libxad/clients/LhF.c

584 lines
13 KiB
C
Executable file

#ifndef XADMASTER_LHF_C
#define XADMASTER_LHF_C
/* $Id: LhF.c,v 1.7 2005/06/23 14:54:41 stoecker Exp $
LhF file archiver client
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"
#ifndef XADMASTERVERSION
#define XADMASTERVERSION 8
#endif
XADCLIENTVERSTR("LhF 1.1 (22.2.2004)")
#define LHF_VERSION 1
#define LHF_REVISION 1
struct LhFData {
xadUINT8 Comment;
xadUINT8 Protection;
xadUINT16 NameSize;
xadUINT32 CrunchSize;
xadUINT32 Size;
xadUINT32 Date;
};
XADGETINFO(LhF)
{
xadINT32 err, num = 1, i;
xadUINT32 data[2];
struct LhFData ld;
struct xadFileInfo *fi = 0, *fi2;
if((err = xadHookAccess(XADM XADAC_READ, 8, data, ai)))
return err;
while(!err && ai->xai_InPos < ai->xai_InSize && ai->xai_InPos < data[1])
{
if(!(err = xadHookAccess(XADM XADAC_READ, sizeof(struct LhFData), &ld, ai)))
{
if((fi2 = (struct xadFileInfo *) xadAllocObject(XADM XADOBJ_FILEINFO,
XAD_OBJNAMESIZE, ld.NameSize+1, TAG_DONE)))
{
if(!(err = xadHookAccess(XADM XADAC_READ, ld.NameSize, fi2->xfi_FileName, ai)))
{
struct xadDate xd;
if(ld.Comment)
{
xadSTRPTR a;
for(a = fi2->xfi_FileName; *a; ++a)
;
fi2->xfi_Comment = ++a;
}
fi2->xfi_DataPos = ai->xai_InPos;
fi2->xfi_EntryNumber = num++;
if(ld.Size == 0xFFFFFFFF)
fi2->xfi_Flags |= XADFIF_DIRECTORY;
else if(!ld.Size)
{
fi2->xfi_Size = fi2->xfi_CrunchSize = ld.CrunchSize;
fi2->xfi_PrivateInfo = (xadPTR) 1;
}
else
{
fi2->xfi_Size = ld.Size;
fi2->xfi_CrunchSize = ld.CrunchSize;
}
fi2->xfi_Protection = ld.Protection;
fi2->xfi_Flags |= XADFIF_SEEKDATAPOS;
i = ld.Date;
xd.xd_Second = i&63; i >>= 6;
xd.xd_Minute = i&63; i >>= 6;
xd.xd_Hour = i&31; i >>= 5;
xd.xd_Day = (1 + i)&31; i >>= 5;
xd.xd_Month = i&15; i >>= 4;
xd.xd_Year = 1976 + i;
xd.xd_Micros = 0;
xadConvertDates(XADM XAD_DATEXADDATE, &xd, XAD_GETDATEXADDATE,
&fi2->xfi_Date, TAG_DONE);
err = xadHookAccess(XADM XADAC_INPUTSEEK, ld.CrunchSize, 0, ai);
}
if(!err)
{
if(fi)
fi->xfi_Next = fi2;
else
ai->xai_FileInfo = fi2;
fi = fi2;
}
else
xadFreeObjectA(XADM fi2, 0);
}
else
err = XADERR_NOMEMORY;
}
}
if(err)
{
ai->xai_Flags |= XADAIF_FILECORRUPT;
ai->xai_LastError = err;
}
return fi ? 0 : XADERR_ILLEGALDATA;
}
XADRECOGDATA(LhF)
{
if(((xadUINT32 *)data)[0] == 0x4C684600)
return 1;
else
return 0;
}
/****************************************************************************/
#define LHFWINDOWSIZE 0x8000
struct LhFDecrunch {
xadINT16 backstack[20];
xadINT16 stackdata[256];
xadINT32 leftwinsize;
xadSTRPTR windowpos;
xadSTRPTR sourcebuf;
xadUINT32 sourcelen;
xadINT16 data0[16];
xadINT8 data1[20];
xadINT8 data2[2560];
xadINT16 data3[4098];
xadINT32 numbits;
xadUINT32 bitbuf;
xadUINT16 err;
struct xadArchiveInfo *ai;
struct xadMasterBase *xadMasterBase;
xadUINT8 inbuffer[LHFWINDOWSIZE];
xadINT8 outbuffer[256*2+LHFWINDOWSIZE+6];
};
static xadUINT16 LHFgetc(struct LhFDecrunch *lhd)
{
xadUINT16 a;
if(lhd->sourcelen < 2 || lhd->err)
return 0;
if(lhd->sourcebuf == (xadSTRPTR) lhd->inbuffer + LHFWINDOWSIZE)
{
xadUINT32 i;
struct xadMasterBase *xadMasterBase = lhd->xadMasterBase;
if((i = lhd->sourcelen) > LHFWINDOWSIZE)
i = LHFWINDOWSIZE;
if((lhd->err = xadHookAccess(XADM XADAC_READ, i, lhd->inbuffer, lhd->ai)))
return 0;
lhd->sourcebuf = (xadSTRPTR) lhd->inbuffer;
}
lhd->sourcelen -= 2;
a = *(lhd->sourcebuf++) << 8;
a += *(lhd->sourcebuf++);
return a;
}
/* Neue Bytes von rechts herein, Daten links abgreifen */
static xadUINT16 LHFgetbits(struct LhFDecrunch *lhd, xadUINT32 bits)
{
xadUINT16 r;
r = lhd->bitbuf >> (32-bits);
lhd->numbits += bits;
if(lhd->numbits < 0)
lhd->bitbuf <<= bits;
else
{
bits -= lhd->numbits;
lhd->bitbuf <<= bits;
lhd->bitbuf |= LHFgetc(lhd);
lhd->bitbuf <<= lhd->numbits;
lhd->numbits -= 16;
}
return r;
}
static xadINT32 LHFflush(struct LhFDecrunch *lhd)
{
xadINT32 i, j, err;
struct xadMasterBase *xadMasterBase = lhd->xadMasterBase;
lhd->leftwinsize = LHFWINDOWSIZE-1;
j = LHFWINDOWSIZE;
if((i = ((uintptr_t)lhd->windowpos - (uintptr_t)(lhd->outbuffer+256)) - j) < 0)
j += i;
lhd->windowpos -= j;
if((err = xadHookAccess(XADM XADAC_WRITE, (xadUINT32) j, lhd->outbuffer+256, lhd->ai)) && !lhd->err)
lhd->err = err;
if(i >= 0) /* copy the overworked buffer back */
{
lhd->leftwinsize -= i;
i += 256 - 1;
do
{
lhd->outbuffer[i] = lhd->outbuffer[LHFWINDOWSIZE+i];
} while(i--);
}
return lhd->err;
}
static xadINT32 LHFsub1(struct LhFDecrunch *lhd, xadINT16 *p, xadINT8 *q, xadINT16 rounds, xadINT16 maxbits)
{
xadINT16 data[32], *r = data+16, *s = data, *t = lhd->data0, *u;
xadINT16 i = 0, j = 0, k = 0, l = maxbits-1, m, n, o;
m = (1<<l);
n = (m<<1);
do
{
*(s++) = m;
m >>= 1;
*(r++) = k;
o = *(t++);
o = (o<<l)|(o>>(16-l));
k += o;
if(k < 0)
return XADERR_ILLEGALDATA;
} while(l--);
if(k > n)
return XADERR_ILLEGALDATA;
else if(k != n)
{
u = p + n;
n -= k;
l += (n&1) + (n>>1);
do
{
*(--u) = m;
*(--u) = 0;
} while(l--);
o = 16 - maxbits;
k = (k<<o)|(k>>(16-o));
l += o;
m |= (1<<l);
do
{
*(s++) = m;
m >>= 1;
*(r++) = k;
o = *(t++);
o = (o<<l)|(o>>(16-l));
k += o;
} while(k < 0 && l--);
if(k)
return XADERR_ILLEGALDATA;
}
t = p;
do
{
if((k = *(q++)) > 0)
{
s = data+15+k;
o = *s;
m = *(s-16);
*s += m;
k -= maxbits;
if(k <= 0 && m--)
{
s = p+o;
do
{
*(s++) = i;
} while(m--);
}
else
{
s = p + (((xadUINT16) o) >> (16-maxbits));
o <<= maxbits;
do
{
if(!(m = *s))
{
do
{
j -= 4;
*s = j;
*(--t) = m;
*(--t) = 0;
s = t;
if(o & 0x8000)
++s;
o <<= 1;
} while(--k > 0);
*(s) = i;
}
else
{
s = p + (m/2);
if(o & 0x8000)
++s;
o <<= 1;
--k;
}
} while(k > 0);
*s = i;
}
}
++i;
} while(rounds--);
return 0;
}
static xadINT32 LHFsub2(struct LhFDecrunch *lhd, xadINT16 bits, xadINT16 maxbits)
{
xadINT16 i, j, k, l;
xadINT8 *d = lhd->data1;
memset(lhd->data0, 0, 32);
if(!(i = LHFgetbits(lhd, (xadUINT32) bits)))
{
if((i = LHFgetbits(lhd, (xadUINT32)bits)) >= maxbits)
return XADERR_ILLEGALDATA;
lhd->data1[i] = 0;
for(bits = 0; bits < 256; ++bits)
lhd->stackdata[i] = i;
return 0;
}
else if(i >= maxbits)
return XADERR_ILLEGALDATA;
l = i;
do
{
if((k = LHFgetbits(lhd, 3)) == 7)
{
j = k;
do
{
k = LHFgetbits(lhd, 1);
j += k;
} while(k);
k = j;
}
*d = k;
if(*(d++) > 0)
++lhd->data0[k-1];
} while(i--);
return LHFsub1(lhd, lhd->stackdata, lhd->data1, l, 8);
}
static xadINT32 DecrunchLhF(struct LhFDecrunch *lhd)
{
xadINT32 i, j, k, l, m, n;
xadINT8 *p;
lhd->numbits = -16; /* init getbits */
lhd->bitbuf = LHFgetc(lhd) << 16;
lhd->bitbuf += LHFgetc(lhd); /* end init */
// lhd->windowpos = lhd->outbuffer + 254;
// *(lhd->windowpos++) = 0;
// *(lhd->windowpos++) = 0;
lhd->windowpos = (xadSTRPTR) lhd->outbuffer + 256;
lhd->leftwinsize = LHFWINDOWSIZE-1;
do
{
if(!(i = LHFgetbits(lhd, 16)))
return XADERR_ILLEGALDATA;
if((j = LHFgetbits(lhd, 9)))
{
if(LHFsub2(lhd, 5, 20))
return XADERR_ILLEGALDATA;
memset(lhd->data0, 0, 32);
p = lhd->data2;
do
{
k = lhd->bitbuf >> 24;
if((k = lhd->stackdata[k]) < 0)
{
l = lhd->bitbuf >> 16;
do
{
if(l & 0x80)
k += 2;
l <<= 1;
} while((k = lhd->stackdata[k>>1]) < 0);
}
LHFgetbits(lhd, (xadUINT32) lhd->data1[k]);
k -= 3;
if(k < 0)
{
l = 0;
k += 2;
if(!k)
k = LHFgetbits(lhd, 2) + 3;
else if(k > 0)
k = LHFgetbits(lhd, 7) + 7;
else
{
k = LHFgetbits(lhd, 3) + 3;
l = *(p-1);
lhd->data0[l-1] += k--;
}
do
{
*(p++) = l;
} while(k--);
}
else
{
*p = k;
if(*(p++) > 0)
++lhd->data0[k-1];
}
} while(j--);
while(!*(--p))
;
n = p-lhd->data2;
if((k = LHFsub1(lhd, lhd->data3, lhd->data2, n, 12)))
return k;
}
else
{
xadUINT16 temp;
n = LHFgetbits(lhd, 9);
lhd->data2[n] = 0;
for(temp = 0; temp < 0x1000; ++temp)
lhd->data3[temp] = n;
}
if(n >= 256 && (k = LHFsub2(lhd, 4, 16)))
return k;
--i;
do
{
do
{
if((k = lhd->data3[lhd->bitbuf>>20]) < 0)
{
l = lhd->bitbuf >> 16;
if(l & (1<<3))
k += 2;
if((k = lhd->data3[k>>1]) < 0)
{
if(l & (1<<2))
k += 2;
if((k = lhd->data3[k>>1]) < 0)
{
if(l & (1<<1))
k += 2;
if((k = lhd->data3[k>>1]) < 0)
{
if(l & (1<<0))
k += 2;
k = lhd->data3[k>>1];
}
}
}
}
LHFgetbits(lhd, (xadUINT32) lhd->data2[k]);
k -= 256;
if(k >= 0)
{
if((l = lhd->stackdata[lhd->bitbuf >> 24]) < 0)
{
m = lhd->bitbuf >> 16;
do
{
m <<= 1;
if(m & 0x100)
l = lhd->stackdata[(l/2)+1];
else
{
do
{
m <<= 1;
l = lhd->stackdata[l/2];
} while(l < 0 && !(m & 0x100));
}
} while(l < 0);
}
m = lhd->data1[l];
LHFgetbits(lhd, (xadUINT32) m);
m = l;
if(--m > 0)
l = LHFgetbits(lhd, (xadUINT32) m) + (1<<m);
p = (xadINT8 *) lhd->windowpos-l-1;
l = 256 - k;
if(p < lhd->outbuffer)
p += LHFWINDOWSIZE;
while(l++ < 257+2)
*(lhd->windowpos++) = *(p++);
k += 3;
lhd->leftwinsize -= k;
}
else
{
*(lhd->windowpos++) = k;
--lhd->leftwinsize;
}
} while(i-- && lhd->leftwinsize >= 0);
if(lhd->leftwinsize < 0 && LHFflush(lhd))
return lhd->err;
} while(i >= 0);
} while(LHFgetbits(lhd, 1));
return LHFflush(lhd);
}
/****************************************************************************/
XADUNARCHIVE(LhF)
{
xadINT32 err;
struct xadFileInfo *fi;
fi = ai->xai_CurFile;
if(fi->xfi_PrivateInfo)
err = xadHookAccess(XADM XADAC_COPY, fi->xfi_Size, 0, ai);
else
{
struct LhFDecrunch *d;
if((d = (struct LhFDecrunch *) xadAllocVec(XADM sizeof(struct LhFDecrunch), XADMEMF_CLEAR)))
{
d->ai = ai;
d->xadMasterBase = xadMasterBase;
d->sourcelen = (xadUINT32)fi->xfi_CrunchSize;
d->sourcebuf = (xadSTRPTR) d->inbuffer+LHFWINDOWSIZE;
err = DecrunchLhF(d);
xadFreeObjectA(XADM d, 0);
}
else
err = XADERR_NOMEMORY;
}
return err;
}
/****************************************************************************/
XADFIRSTCLIENT(LhF) {
XADNEXTCLIENT,
XADCLIENT_VERSION,
XADMASTERVERSION,
LHF_VERSION,
LHF_REVISION,
8,
XADCF_FILEARCHIVER|XADCF_FREEFILEINFO,
XADCID_LHF,
"LhF",
XADRECOGDATAP(LhF),
XADGETINFOP(LhF),
XADUNARCHIVEP(LhF),
NULL
};
#undef XADNEXTCLIENT
#define XADNEXTCLIENT XADNEXTCLIENTNAME(LhF)
#endif /* XADMASTER_LHF_C */