raze-gles/source/build/src/kplib.cpp

3062 lines
113 KiB
C++
Raw Normal View History

/**************************************************************************************************
KPLIB.C: Ken's Picture LIBrary written by Ken Silverman
Copyright (c) 1998-2008 Ken Silverman
Ken Silverman's official web site: http://advsys.net/ken
Features of KPLIB.C:
* Routines for decoding JPG/PNG/GIF/PCX/TGA/BMP/DDS/CEL.
See kpgetdim(), kprender(), and optional helper function: kpzload().
* Routines for reading files out of ZIP/GRP files. All ZIP/GRP functions start with "kz".
* Multi-platform support: Dos/Windows/Linux/Mac/etc..
* Compact code, all in a single source file. Yeah, bad design on my part... but makes life
easier for everyone else - you simply add a single C file to your project, throw a few
externs in there, add the function calls, and you're done!
Brief history:
1998?: Wrote KPEG, a JPEG viewer for DOS
2000: Wrote KPNG, a PNG viewer for DOS
2001: Combined KPEG & KPNG, ported to Visual C, and made it into a library called KPLIB.C
2002: Added support for TGA,GIF,CEL,ZIP
2003: Added support for BMP
05/18/2004: Added support for 8&24 bit PCX
12/09/2005: Added support for progressive JPEG
01/05/2006: Added support for DDS
07/28/2007: Added support for GRP (Build Engine archive)
I offer this code to the community for free use - all I ask is that my name be included in the
credits.
-Ken S.
**************************************************************************************************/
#include "compat.h"
#include "baselayer.h"
#include "kplib.h"
#include "pragmas.h"
#include "vfs.h"
#if !defined(_WIN32)
static FORCE_INLINE CONSTEXPR int32_t klrotl(int32_t i, int sh) { return (i >> (-sh)) | (i << sh); }
#else
# define klrotl(i, sh) _lrotl(i, sh)
# ifdef __clang__
# include <emmintrin.h>
# else
# include <intrin.h>
# endif
#endif
//use GCC-specific extension to force symbol name to be something in particular to override underscoring.
#if defined(__GNUC__) && defined(__i386__) && !defined(NOASM)
#define ASMNAME(x) asm(x)
#else
#define ASMNAME(x)
#endif
static intptr_t kp_frameplace;
static int32_t kp_bytesperline, kp_xres, kp_yres;
static CONSTEXPR const int32_t pow2mask[32] =
{
0x00000000,0x00000001,0x00000003,0x00000007,
0x0000000f,0x0000001f,0x0000003f,0x0000007f,
0x000000ff,0x000001ff,0x000003ff,0x000007ff,
0x00000fff,0x00001fff,0x00003fff,0x00007fff,
0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
0x000fffff,0x001fffff,0x003fffff,0x007fffff,
0x00ffffff,0x01ffffff,0x03ffffff,0x07ffffff,
0x0fffffff,0x1fffffff,0x3fffffff,0x7fffffff,
};
static CONSTEXPR const int32_t pow2long[32] =
{
0x00000001,0x00000002,0x00000004,0x00000008,
0x00000010,0x00000020,0x00000040,0x00000080,
0x00000100,0x00000200,0x00000400,0x00000800,
0x00001000,0x00002000,0x00004000,0x00008000,
0x00010000,0x00020000,0x00040000,0x00080000,
0x00100000,0x00200000,0x00400000,0x00800000,
0x01000000,0x02000000,0x04000000,0x08000000,
0x10000000,0x20000000,0x40000000,(int32_t)0x80000000,
};
//Hack for peekbits,getbits,suckbits (to prevent lots of duplicate code)
// 0: PNG: do 12-byte chunk_header removal hack
// !=0: ZIP: use 64K buffer (olinbuf)
static int32_t zipfilmode;
kzfilestate kzfs;
// GCC 4.6 LTO build fix
#ifdef USING_LTO
# define B_KPLIB_STATIC
#else
# define B_KPLIB_STATIC static
#endif
//Initialized tables (can't be in union)
//jpg: png:
// crmul 16384 abstab10 4096
// cbmul 16384 hxbit 472
// dct 4608 pow2mask 128*
// colclip 4096
// colclipup8 4096
// colclipup16 4096
// unzig 256
// pow2mask 128*
// dcflagor 64
B_KPLIB_STATIC int32_t ATTRIBUTE((used)) palcol[256] ASMNAME("palcol");
static int32_t paleng, bakcol, numhufblocks, zlibcompflags;
static int8_t kcoltype, filtype, bitdepth;
//============================ KPNGILIB begins ===============================
//07/31/2000: KPNG.C first ported to C from READPNG.BAS
//10/11/2000: KPNG.C split into 2 files: KPNG.C and PNGINLIB.C
//11/24/2000: Finished adding support for coltypes 4&6
//03/31/2001: Added support for Adam7-type interlaced images
//Currently, there is no support for:
// * 16-bit color depth
// * Some useless ancillary chunks, like: gAMA(gamma) & pHYs(aspect ratio)
//.PNG specific variables:
static int32_t bakr = 0x80, bakg = 0x80, bakb = 0x80; //this used to be public...
static int32_t gslidew = 0, gslider = 0, xm, xmn[4], xr0, xr1, xplc, yplc;
static intptr_t nfplace;
static int32_t clen[320], cclen[19], bitpos, filt, xsiz, ysiz;
int32_t xsizbpl, ixsiz, ixoff, iyoff, ixstp, iystp, intlac, nbpl;
B_KPLIB_STATIC int32_t ATTRIBUTE((used)) trnsrgb ASMNAME("trnsrgb");
static int32_t ccind[19] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
static int32_t hxbit[59][2], ibuf0[288], nbuf0[32], ibuf1[32], nbuf1[32];
static const uint8_t *filptr;
static uint8_t slidebuf[32768], opixbuf0[4], opixbuf1[4];
static uint8_t pnginited = 0;
B_KPLIB_STATIC uint8_t olinbuf[131072] ASMNAME("olinbuf"); //WARNING:max kp_xres is: 131072/bpp-1
B_KPLIB_STATIC int32_t ATTRIBUTE((used)) abstab10[1024] ASMNAME("abstab10");
//Variables to speed up dynamic Huffman decoding:
#define LOGQHUFSIZ0 9
#define LOGQHUFSIZ1 6
static int32_t qhufval0[1<<LOGQHUFSIZ0], qhufval1[1<<LOGQHUFSIZ1];
static uint8_t qhufbit0[1<<LOGQHUFSIZ0], qhufbit1[1<<LOGQHUFSIZ1];
#if defined(_MSC_VER) && !defined(NOASM)
static inline int32_t bitrev(int32_t b, int32_t c)
{
_asm
{
mov edx, b
mov ecx, c
xor eax, eax
beg: shr edx, 1
adc eax, eax
sub ecx, 1
jnz short beg
}
}
#elif defined(__GNUC__) && defined(__i386__) && !defined(NOASM)
static inline int32_t bitrev(int32_t b, int32_t c)
{
int32_t a = 0;
__asm__ __volatile__(
"xorl %%eax, %%eax\n\t0:\n\tshrl $1, %%ebx\n\tadcl %%eax, %%eax\n\tsubl $1, %%ecx\n\tjnz 0b"
: "+a"(a), "+b"(b), "+c"(c) : : "cc");
return a;
}
#else
static inline int32_t bitrev(int32_t b, int32_t c)
{
int32_t i, j;
for (i=1,j=0,c=(1<<c); i<c; i+=i) { j += j; if (b&i) j++; }
return j;
}
#endif
static uint8_t fakebuf[8];
static uint8_t const *nfilptr;
static int32_t nbitpos;
static void suckbitsnextblock()
{
if (zipfilmode)
{
//NOTE: should only read bytes inside compsize, not 64K!!! :/
B_BUF32(&olinbuf[0], B_UNBUF32(&olinbuf[sizeof(olinbuf)-4]));
uint32_t n = min<uint32_t>(kzfs.compleng-kzfs.comptell, sizeof(olinbuf)-4);
buildvfs_fread(&olinbuf[4], n, 1, kzfs.fil);
kzfs.comptell += n;
bitpos -= ((sizeof(olinbuf)-4)<<3);
return;
}
if (nfilptr)
{
filptr = nfilptr; nfilptr = 0;
bitpos -= ((nbitpos-4)<<3);
return;
}
//if (n_from_suckbits < 4) will it crash?
//|===|===|crc|lng|typ|===|===|
// \ fakebuf: /
// |===|===|
//----x O---x O--------
nbitpos = B_BIG32(B_UNBUF32(&filptr[8]));
nfilptr = &filptr[nbitpos+12];
B_BUF32(&fakebuf[0], B_UNBUF32(&filptr[0])); //Copy last dword of IDAT chunk
if (B_UNBUF32(&filptr[12]) == B_LITTLE32(0x54414449)) //Copy 1st dword of next IDAT chunk
B_BUF32(&fakebuf[4], B_UNBUF32(&filptr[16]));
filptr = &fakebuf[4]; bitpos -= 32;
}
static inline int32_t peekbits(int32_t n) { return (B_LITTLE32(B_UNBUF32(&filptr[bitpos>>3]))>>(bitpos&7))&pow2mask[n]; }
static inline void suckbits(int32_t n) { bitpos += n; if (bitpos < 0) return; suckbitsnextblock(); }
static inline int32_t getbits(int32_t n) { int32_t i = peekbits(n); suckbits(n); return i; }
static int32_t hufgetsym(int32_t *hitab, const int32_t *hbmax)
{
int32_t v, n;
v = n = 0;
do { v = (v<<1)+getbits(1)+hbmax[n]-hbmax[n+1]; n++; }
while (v >= 0);
return hitab[hbmax[n]+v];
}
//This did not result in a speed-up on P4-3.6Ghz (02/22/2005)
//static int32_t hufgetsym_skipb (int32_t *hitab, int32_t *hbmax, int32_t n, int32_t addit)
//{
// int32_t v;
//
// v = bitrev(getbits(n),n)+addit;
// do { v = (v<<1)+getbits(1)+hbmax[n]-hbmax[n+1]; n++; } while (v >= 0);
// return hitab[hbmax[n]+v];
//}
static void qhufgencode(const int32_t *hitab, const int32_t *hbmax, int32_t *qhval, uint8_t *qhbit, int32_t numbits)
{
int32_t i, j, k, n, r;
//r is the bit reverse of i. Ex: if: i = 1011100111, r = 1110011101
i = r = 0;
for (n=1; n<=numbits; n++)
for (k=hbmax[n-1]; k<hbmax[n]; k++)
for (j=i+pow2mask[numbits-n]; i<=j; i++)
{
r = bitrev(i,numbits);
qhval[r] = hitab[k];
qhbit[r] = (uint8_t)n;
}
for (j=pow2mask[numbits]; i<=j; i++)
{
r = bitrev(i,numbits);
//k = 0;
//for(n=0;n<numbits;n++)
// k = (k<<1) + ((r>>n)&1) + hbmax[n]-hbmax[n+1];
//
//n = numbits;
//k = hbmax[n]-r;
//
//j = peekbits(LOGQHUFSIZ); i = qhufval[j]; j = qhufbit[j];
//
//i = j = 0;
//do
//{
// i = (i<<1)+getbits(1)+nbuf0[j]-nbuf0[j+1]; j++;
//} while (i >= 0);
//i = ibuf0[nbuf0[j]+i];
//qhval[r] = k;
qhbit[r] = 0; //n-32;
}
// //hufgetsym_skipb related code:
//for(k=n=0;n<numbits;n++) k = (k<<1)+hbmax[n]-hbmax[n+1];
//return k;
}
//inbuf[inum] : Bit length of each symbol
//inum : Number of indices
//hitab[inum] : Indices from size-ordered list to original symbol
//hbmax[0-31] : Highest index (+1) of n-bit symbol
static void hufgencode(const int32_t *inbuf, int32_t inum, int32_t *hitab, int32_t *hbmax)
{
int32_t i, tbuf[31], *tbufptr, *hbmaxptr;
Bmemset(tbuf, 0, sizeof(tbuf));
for (i=inum-1; i>=0; i--) tbuf[inbuf[i]]++;
tbuf[0] = hbmax[0] = 0; //Hack to remove symbols of length 0?
for (i=0; i<28; i += 4)
{
tbufptr = &tbuf[i];
hbmaxptr = &hbmax[i];
*(hbmaxptr+1) = *hbmaxptr + *tbufptr;
*(hbmaxptr+2) = *(hbmaxptr+1) + *(tbufptr+1);
*(hbmaxptr+3) = *(hbmaxptr+2) + *(tbufptr+2);
*(hbmaxptr+4) = *(hbmaxptr+3) + *(tbufptr+3);
}
tbufptr = &tbuf[i];
hbmaxptr = &hbmax[i];
*(hbmaxptr+1) = *hbmaxptr + *tbufptr;
*(hbmaxptr+2) = *(hbmaxptr+1) + *(tbufptr+1);
*(hbmaxptr+3) = *(hbmaxptr+2) + *(tbufptr+2);
for (i=0; i<inum; i++) if (inbuf[i]) hitab[hbmax[inbuf[i]]++] = i;
}
static int32_t initpass() //Interlaced images have 7 "passes", non-interlaced have 1
{
int32_t i, j, k;
do
{
i = (intlac<<2);
ixoff = ((0x04020100>>i)&15);
iyoff = ((0x00402010>>i)&15);
if (((ixoff >= xsiz) || (iyoff >= ysiz)) && (intlac >= 2)) { i = -1; intlac--; }
}
while (i < 0);
j = ((0x33221100>>i)&15); ixstp = (1<<j);
k = ((0x33322110>>i)&15); iystp = (1<<k);
//xsiz=12 0123456789ab
//j=3,ixoff=0 0 1 ((12+(1<<3)-1 - 0)>>3) = 2
//j=3,ixoff=4 2 ((12+(1<<3)-1 - 4)>>3) = 1
//j=2,ixoff=2 3 4 5 ((12+(1<<2)-1 - 2)>>2) = 3
//j=1,ixoff=1 6 7 8 9 a b ((12+(1<<1)-1 - 1)>>1) = 6
ixsiz = ((xsiz+ixstp-1-ixoff)>>j); //It's confusing! See the above example.
nbpl = (kp_bytesperline<<k);
//Initialize this to make filters fast:
xsizbpl = ((0x04021301>>(kcoltype<<2))&15)*ixsiz;
switch (bitdepth)
{
case 1: xsizbpl = ((xsizbpl+7)>>3); break;
case 2: xsizbpl = ((xsizbpl+3)>>2); break;
case 4: xsizbpl = ((xsizbpl+1)>>1); break;
}
Bmemset(olinbuf,0,(xsizbpl+1)*sizeof(olinbuf[0]));
B_BUF32(&opixbuf0[0], 0);
B_BUF32(&opixbuf1[0], 0);
xplc = xsizbpl; yplc = iyoff; xm = 0; filt = -1;
i = ixoff; i = (((-(i>=0))|(ixstp-1))&i);
k = (((-(yplc>=0))|(iystp-1))&yplc);
nfplace = k*kp_bytesperline + (i<<2) + kp_frameplace;
//Precalculate x-clipping to screen borders (speeds up putbuf)
//Equation: (0 <= xr <= ixsiz) && (0 <= xr*ixstp+globxoffs+ixoff <= kp_xres)
xr0 = max((-ixoff+(1<<j)-1)>>j,0);
xr1 = min((kp_xres-ixoff+(1<<j)-1)>>j,ixsiz);
xr0 = ixsiz-xr0;
xr1 = ixsiz-xr1;
if (kcoltype == 4) { xr0 = xr0*2; xr1 = xr1*2; }
else if (kcoltype == 2) { xr0 = xr0*3-2; xr1 = xr1*3-2; }
else if (kcoltype == 6) { xr0 = xr0*4-2; xr1 = xr1*4-2; }
else
{
switch (bitdepth)
{
case 1: xr0 += ((-ixsiz)&7)+7;
xr1 += ((-ixsiz)&7)+7; break;
case 2: xr0 = ((xr0+((-ixsiz)&3)+3)<<1);
xr1 = ((xr1+((-ixsiz)&3)+3)<<1); break;
case 4: xr0 = ((xr0+((-ixsiz)&1)+1)<<2);
xr1 = ((xr1+((-ixsiz)&1)+1)<<2); break;
}
}
ixstp <<= 2;
return 0;
}
#if defined(_MSC_VER) && !defined(NOASM)
static inline int32_t Paeth686(int32_t a, int32_t b, int32_t c)
{
_asm
{
push ebx
push esi
push edi
mov eax, a
mov ebx, b
mov ecx, c
mov edx, ecx
sub edx, eax
sub edx, ebx
lea edx, abstab10[edx*4+2048]
mov esi, [ebx*4+edx]
mov edi, [ecx*4+edx]
cmp edi, esi
cmovge edi, esi
cmovge ecx, ebx
cmp edi, [eax*4+edx]
cmovl eax, ecx
pop edi
pop esi
pop ebx
}
}
static inline void rgbhlineasm(int32_t c, int32_t d, int32_t t, int32_t b)
{
_asm
{
push ebx
push edi
mov ecx, c
mov edx, d
mov edi, t
mov ebx, b
sub ecx, edx
jle short endit
add edx, offset olinbuf
cmp dword ptr trnsrgb, 0
jz short begit2
begit:
mov eax, dword ptr [ecx+edx]
or eax, 0xff000000
cmp eax, dword ptr trnsrgb
jne short skipit
and eax, 0xffffff
skipit:
sub ecx, 3
mov [edi], eax
lea edi, [edi+ebx]
jnz short begit
jmp short endit
begit2:
mov eax, dword ptr [ecx+edx]
or eax, 0xff000000
sub ecx, 3
mov [edi], eax
lea edi, [edi+ebx]
jnz short begit2
endit:
pop edi
pop ebx
}
}
static inline void pal8hlineasm(int32_t c, int32_t d, int32_t t, int32_t b)
{
_asm
{
mov ecx, c
mov edx, d
sub ecx, edx
jle short endit
push ebx
push edi
mov edi, t
mov ebx, b
add edx, offset olinbuf
begit:movzx eax, byte ptr [ecx+edx]
mov eax, dword ptr palcol[eax*4]
sub ecx, 1
mov [edi], eax
lea edi, [edi+ebx]
jnz short begit
pop edi
pop ebx
endit:
}
}
#elif defined(__GNUC__) && defined(__i386__) && !defined(NOASM)
static inline int32_t Paeth686(int32_t a, int32_t b, int32_t c)
{
__asm__ __volatile__(
"movl %%ecx, %%edx \n"
"subl %%eax, %%edx \n"
"subl %%ebx, %%edx \n"
"leal (abstab10+2048)(,%%edx,4), %%edx \n"
"movl (%%edx,%%ebx,4), %%esi \n"
"movl (%%edx,%%ecx,4), %%edi \n"
"cmpl %%esi, %%edi \n"
"cmovgel %%esi, %%edi \n"
"cmovgel %%ebx, %%ecx \n"
"cmpl (%%edx,%%eax,4), %%edi \n"
"cmovgel %%eax, %%ecx \n"
: "+c"(c) : "a"(a), "b"(b) : "edx","esi","edi","memory","cc"
);
return c;
}
//Note: "cmove eax,?" may be faster than "jne ?:and eax,?" but who cares
static inline void rgbhlineasm(int32_t c, int32_t d, int32_t t, int32_t b)
{
__asm__ __volatile__(
"subl %%edx, %%ecx \n"
"jle 3f \n"
"addl $olinbuf, %%edx \n"
"cmpl $0, trnsrgb(,1) \n"
"jz 2f \n"
"0: movl (%%ecx,%%edx,1), %%eax \n"
"orl $0xff000000, %%eax \n"
"cmpl trnsrgb(,1), %%eax \n"
"jne 1f \n"
"andl $0xffffff, %%eax \n"
"1: subl $3, %%ecx \n"
"movl %%eax, (%%edi) \n"
"leal (%%edi,%%ebx,1), %%edi \n"
"jnz 0b \n"
"jmp 3f \n"
"2: movl (%%ecx,%%edx,1), %%eax \n"
"orl $0xff000000, %%eax \n"
"subl $3, %%ecx \n"
"movl %%eax, (%%edi) \n"
"leal (%%edi,%%ebx,1), %%edi \n"
"jnz 2b \n"
"3: \n"
: "+c"(c), "+d"(d), "+D"(t) : "b"(b) : "eax","memory","cc"
);
}
static inline void pal8hlineasm(int32_t c, int32_t d, int32_t t, int32_t b)
{
__asm__ __volatile__(
"subl %%edx, %%ecx \n"
"jle 1f \n"
"addl $olinbuf, %%edx \n"
"0: movzbl (%%ecx,%%edx,1), %%eax \n"
"movl palcol(,%%eax,4), %%eax \n"
"subl $1, %%ecx \n"
"movl %%eax, (%%edi) \n"
"leal (%%edi,%%ebx,1), %%edi \n"
"jnz 0b \n"
"1: \n"
: "+c"(c), "+d"(d), "+D"(t) : "b"(b) : "eax","memory","cc"
);
}
#else
static inline int32_t Paeth686(int32_t const a, int32_t const b, int32_t c)
{
int32_t const * const ptr = &abstab10[(c - a) - (b - 512)];
int32_t const esi = *(ptr + b);
int32_t edi = *(ptr + c);
if (edi >= esi) edi = esi, c = b;
return (edi < *(ptr + a)) ? c : a;
}
static inline void rgbhlineasm(int32_t x, int32_t xr1, intptr_t p, int32_t ixstp)
{
if (!trnsrgb)
{
for (; x>xr1; p+=ixstp,x-=3) B_BUF32((void *) p, (B_UNBUF32(&olinbuf[x]))|B_LITTLE32(0xff000000));
return;
}
for (; x>xr1; p+=ixstp,x-=3)
{
int32_t i = (B_UNBUF32(&olinbuf[x]))|B_LITTLE32(0xff000000);
if (i == trnsrgb) i &= B_LITTLE32(0xffffff);
B_BUF32((void *) p, i);
}
}
static inline void pal8hlineasm(int32_t x, int32_t xr1, intptr_t p, int32_t ixstp)
{
for (; x>xr1; p+=ixstp,x--) B_BUF32((void *) p, palcol[olinbuf[x]]);
}
#endif
//Autodetect filter
// /f0: 0000000...
// /f1: 1111111...
// /f2: 2222222...
// /f3: 1333333...
// /f3: 3333333...
// /f4: 4444444...
// /f5: 0142321...
static int32_t filter1st, filterest;
static void putbuf(const uint8_t *buf, int32_t leng)
{
int32_t i;
intptr_t p;
if (filt < 0)
{
if (leng <= 0) return;
filt = buf[0];
if (filter1st < 0) filter1st = filt; else filterest |= (1<<filt);
i = 1;
}
else i = 0;
while (i < leng)
{
int32_t x = i+xplc; if (x > leng) x = leng;
switch (filt)
{
case 0:
while (i < x) { olinbuf[xplc--] = buf[i++]; }
break;
case 1:
while (i < x)
{
olinbuf[xplc--] = (uint8_t)(opixbuf1[xm] += buf[i++]);
xm = xmn[xm];
}
break;
case 2:
while (i < x) { olinbuf[xplc--] += (uint8_t)buf[i++]; }
break;
case 3:
while (i < x)
{
opixbuf1[xm] = olinbuf[xplc] = (uint8_t)(((opixbuf1[xm]+olinbuf[xplc])>>1)+buf[i++]);
xm = xmn[xm]; xplc--;
}
break;
case 4:
while (i < x)
{
opixbuf1[xm] = (uint8_t)(Paeth686(opixbuf1[xm],olinbuf[xplc],opixbuf0[xm])+buf[i++]);
opixbuf0[xm] = olinbuf[xplc];
olinbuf[xplc--] = opixbuf1[xm];
xm = xmn[xm];
}
break;
}
if (xplc > 0) return;
//Draw line!
if ((uint32_t)yplc < (uint32_t)kp_yres)
{
x = xr0; p = nfplace;
switch (kcoltype)
{
case 2: rgbhlineasm(x,xr1,p,ixstp); break;
case 4:
for (; x>xr1; p+=ixstp,x-=2)
B_BUF32((void *) p, (palcol[olinbuf[x]]&B_LITTLE32(0xffffff))|B_BIG32((int32_t)olinbuf[x-1]));
break;
case 6:
for (; x>xr1; p+=ixstp,x-=4)
{
*(char *)(p) = olinbuf[x ]; //B
*(char *)(p+1) = olinbuf[x+1]; //G
*(char *)(p+2) = olinbuf[x+2]; //R
*(char *)(p+3) = olinbuf[x-1]; //A
}
break;
default:
switch (bitdepth)
{
case 1: for (; x>xr1; p+=ixstp,x--) B_BUF32((void *) p, palcol[olinbuf[x>>3]>>(x&7)]); break;
case 2: for (; x>xr1; p+=ixstp,x-=2) B_BUF32((void *) p, palcol[olinbuf[x>>3]>>(x&6)]); break;
case 4: for (; x>xr1; p+=ixstp,x-=4) B_BUF32((void *) p, palcol[olinbuf[x>>3]>>(x&4)]); break;
case 8: pal8hlineasm(x,xr1,p,ixstp); break; //for(;x>xr1;p+=ixstp,x-- ) B_BUF32((void *) p, palcol[olinbuf[x]]); break;
}
break;
}
nfplace += nbpl;
}
B_BUF32(&opixbuf0[0], 0);
B_BUF32(&opixbuf1[0], 0);
xplc = xsizbpl; yplc += iystp;
if ((intlac) && (yplc >= ysiz)) { intlac--; initpass(); }
if (i < leng)
{
filt = buf[i++];
if (filter1st < 0) filter1st = filt; else filterest |= (1<<filt);
}
else filt = -1;
}
}
static void initpngtables()
{
int32_t i, j, k;
//hxbit[0-58][0-1] is a combination of 4 different tables:
// 1st parameter: [0-29] are distances, [30-58] are lengths
// 2nd parameter: [0]: extra bits, [1]: base number
j = 1; k = 0;
for (i=0; i<30; i++)
{
hxbit[i][1] = j; j += (1<<k);
hxbit[i][0] = k; k += ((i&1) && (i >= 2));
}
j = 3; k = 0;
for (i=257; i<285; i++)
{
hxbit[i+30-257][1] = j; j += (1<<k);
hxbit[i+30-257][0] = k; k += ((!(i&3)) && (i >= 264));
}
hxbit[285+30-257][1] = 258; hxbit[285+30-257][0] = 0;
for (i=0; i<512; i++) abstab10[512+i] = abstab10[512-i] = i;
}
static int32_t kpngrend(const char *kfilebuf, int32_t kfilength,
intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres)
{
int32_t i, j, k, bfinal, btype, hlit, hdist, leng;
int32_t slidew, slider;
//int32_t qhuf0v, qhuf1v;
UNREFERENCED_PARAMETER(kfilength);
if (!pnginited) { pnginited = 1; initpngtables(); }
if ((B_UNBUF32(&kfilebuf[0]) != B_LITTLE32(0x474e5089)) || (B_UNBUF32(&kfilebuf[4]) != B_LITTLE32(0x0a1a0a0d)))
return -1; //"Invalid PNG file signature"
filptr = (uint8_t const *)&kfilebuf[8];
trnsrgb = 0; filter1st = -1; filterest = 0;
while (1)
{
leng = B_BIG32(B_UNBUF32(&filptr[0])); i = B_UNBUF32(&filptr[4]);
filptr = &filptr[8];
if (i == (int32_t)B_LITTLE32(0x52444849)) //IHDR (must be first)
{
xsiz = B_BIG32(B_UNBUF32(&filptr[0])); if (xsiz <= 0) return -1;
ysiz = B_BIG32(B_UNBUF32(&filptr[4])); if (ysiz <= 0) return -1;
bitdepth = filptr[8]; if (!((1<<bitdepth)&0x116)) return -1; //"Bit depth not supported"
kcoltype = filptr[9]; if (!((1<<kcoltype)&0x5d)) return -1; //"Color type not supported"
if (filptr[10]) return -1; //"Only *flate is supported"
if (filptr[11]) return -1; //"Filter not supported"
if (filptr[12] >= 2) return -1; //"Unsupported interlace type"
intlac = filptr[12]*7; //0=no interlace/1=Adam7 interlace
//Save code by making grayscale look like a palette color scheme
if ((!kcoltype) || (kcoltype == 4))
{
j = 0xff000000; k = (tabledivide32(255, ((1<<bitdepth)-1)))*0x10101;
paleng = (1<<bitdepth);
for (i=0; i<paleng; i++,j+=k) palcol[i] = B_LITTLE32(j);
}
}
else if (i == (int32_t)B_LITTLE32(0x45544c50)) //PLTE (must be before IDAT)
{
paleng = leng/3;
for (i=paleng-1; i>=0; i--) palcol[i] = B_LITTLE32((B_BIG32(B_UNBUF32(&filptr[i*3]))>>8)|0xff000000);
}
else if (i == (int32_t)B_LITTLE32(0x44474b62)) //bKGD (must be after PLTE and before IDAT)
{
switch (kcoltype)
{
case 0: case 4:
bakcol = (((int32_t)filptr[0]<<8)+(int32_t)filptr[1])*tabledivide32(255, ((1<<bitdepth)-1));
bakcol = bakcol*0x10101+0xff000000; break;
case 2: case 6:
if (bitdepth == 8)
{ bakcol = (((int32_t)filptr[1])<<16)+(((int32_t)filptr[3])<<8)+((int32_t)filptr[5])+0xff000000; }
else
{
for (i=0,bakcol=0xff000000; i<3; i++)
bakcol += tabledivide32(((((int32_t)filptr[i<<1])<<8)+((int32_t)filptr[(i<<1)+1])), 257)<<(16-(i<<3));
}
break;
case 3:
bakcol = palcol[filptr[0]]; break;
}
bakr = ((bakcol>>16)&255);
bakg = ((bakcol>>8)&255);
bakb = (bakcol&255);
bakcol = B_LITTLE32(bakcol);
}
else if (i == (int32_t)B_LITTLE32(0x534e5274)) //tRNS (must be after PLTE and before IDAT)
{
switch (kcoltype)
{
case 0:
if (bitdepth <= 8)
palcol[(int32_t)filptr[1]] &= B_LITTLE32(0xffffff);
//else {} // /c0 /d16 not yet supported
break;
case 2:
if (bitdepth == 8)
{ trnsrgb = B_LITTLE32((((int32_t)filptr[1])<<16)+(((int32_t)filptr[3])<<8)+((int32_t)filptr[5])+0xff000000); }
//else {} //WARNING: PNG docs say: MUST compare all 48 bits :(
break;
case 3:
for (i=min(leng,paleng)-1; i>=0; i--)
palcol[i] &= B_LITTLE32((((int32_t)filptr[i])<<24)|0xffffff);
break;
default:;
EDUKE32_UNREACHABLE_SECTION();
}
}
else if (i == (int32_t)B_LITTLE32(0x54414449)) { break; } //IDAT
filptr = &filptr[leng+4]; //crc = B_BIG32(B_UNBUF32(&filptr[-4]));
}
//Initialize this for the getbits() function
zipfilmode = 0;
filptr = &filptr[leng-4]; bitpos = -((leng-4)<<3); nfilptr = 0;
//if (leng < 4) will it crash?
kp_frameplace = dakpframeplace;
kp_bytesperline = dakpbytesperline;
kp_xres = daxres;
kp_yres = dayres;
switch (kcoltype)
{
case 4: xmn[0] = 1; xmn[1] = 0; break;
case 2: xmn[0] = 1; xmn[1] = 2; xmn[2] = 0; break;
case 6: xmn[0] = 1; xmn[1] = 2; xmn[2] = 3; xmn[3] = 0; break;
default: xmn[0] = 0; break;
}
switch (bitdepth)
{
case 1: for (i=2; i<256; i++) palcol[i] = palcol[i&1]; break;
case 2: for (i=4; i<256; i++) palcol[i] = palcol[i&3]; break;
case 4: for (i=16; i<256; i++) palcol[i] = palcol[i&15]; break;
}
//coltype: bitdepth: format:
// 0 1,2,4,8,16 I
// 2 8,16 RGB
// 3 1,2,4,8 P
// 4 8,16 IA
// 6 8,16 RGBA
xsizbpl = ((0x04021301>>(kcoltype<<2))&15)*xsiz;
switch (bitdepth)
{
case 1: xsizbpl = ((xsizbpl+7)>>3); break;
case 2: xsizbpl = ((xsizbpl+3)>>2); break;
case 4: xsizbpl = ((xsizbpl+1)>>1); break;
}
//Tests to see if xsiz > allocated space in olinbuf
//Note: xsizbpl gets re-written inside initpass()
if ((xsizbpl+1)*sizeof(olinbuf[0]) > sizeof(olinbuf)) return -1;
initpass();
slidew = 0; slider = 16384;
zlibcompflags = getbits(16); //Actually 2 fields: 8:compmethflags, 8:addflagscheck
do
{
bfinal = getbits(1); btype = getbits(2);
if (btype == 0)
{
//Raw (uncompressed)
suckbits((-bitpos)&7); //Synchronize to start of next byte
i = getbits(16); if ((getbits(16)^i) != 0xffff) return -1;
for (; i; i--)
{
if (slidew >= slider)
{
putbuf(&slidebuf[(slider-16384)&32767],16384); slider += 16384;
if ((yplc >= kp_yres) && (intlac < 2)) goto kpngrend_goodret;
}
slidebuf[(slidew++)&32767] = (uint8_t)getbits(8);
}
continue;
}
if (btype == 3) continue;
if (btype == 1) //Fixed Huffman
{
hlit = 288; hdist = 32; i = 0;
for (; i<144; i++) clen[i] = 8; //Fixed bit sizes (literals)
for (; i<256; i++) clen[i] = 9; //Fixed bit sizes (literals)
for (; i<280; i++) clen[i] = 7; //Fixed bit sizes (EOI,lengths)
for (; i<288; i++) clen[i] = 8; //Fixed bit sizes (lengths)
for (; i<320; i++) clen[i] = 5; //Fixed bit sizes (distances)
}
else //Dynamic Huffman
{
numhufblocks++;
hlit = getbits(5)+257; hdist = getbits(5)+1; j = getbits(4)+4;
for (i=0; i<j; i++) cclen[ccind[i]] = getbits(3);
for (; i<19; i++) cclen[ccind[i]] = 0;
hufgencode(cclen,19,ibuf0,nbuf0);
j = 0; k = hlit+hdist;
while (j < k)
{
i = hufgetsym(ibuf0,nbuf0);
if (i < 16) { clen[j++] = i; continue; }
if (i == 16)
{ for (i=getbits(2)+3; i; i--) { clen[j] = clen[j-1]; j++; } }
else
{
if (i == 17) i = getbits(3)+3; else i = getbits(7)+11;
for (; i; i--) clen[j++] = 0;
}
}
}
hufgencode(clen,hlit,ibuf0,nbuf0);
//qhuf0v = //hufgetsym_skipb related code
qhufgencode(ibuf0,nbuf0,qhufval0,qhufbit0,LOGQHUFSIZ0);
hufgencode(&clen[hlit],hdist,ibuf1,nbuf1);
//qhuf1v = //hufgetsym_skipb related code
qhufgencode(ibuf1,nbuf1,qhufval1,qhufbit1,LOGQHUFSIZ1);
while (1)
{
if (slidew >= slider)
{
putbuf(&slidebuf[(slider-16384)&32767],16384); slider += 16384;
if ((yplc >= kp_yres) && (intlac < 2)) goto kpngrend_goodret;
}
k = peekbits(LOGQHUFSIZ0);
if (qhufbit0[k]) { i = qhufval0[k]; suckbits((int32_t)qhufbit0[k]); }
else i = hufgetsym(ibuf0,nbuf0);
//else i = hufgetsym_skipb(ibuf0,nbuf0,LOGQHUFSIZ0,qhuf0v); //hufgetsym_skipb related code
if (i < 256) { slidebuf[(slidew++)&32767] = (uint8_t)i; continue; }
if (i == 256) break;
i = getbits(hxbit[i+30-257][0]) + hxbit[i+30-257][1];
k = peekbits(LOGQHUFSIZ1);
if (qhufbit1[k]) { j = qhufval1[k]; suckbits((int32_t)qhufbit1[k]); }
else j = hufgetsym(ibuf1,nbuf1);
//else j = hufgetsym_skipb(ibuf1,nbuf1,LOGQHUFSIZ1,qhuf1v); //hufgetsym_skipb related code
j = getbits(hxbit[j][0]) + hxbit[j][1];
i += slidew; do { slidebuf[slidew&32767] = slidebuf[(slidew-j)&32767]; slidew++; }
while (slidew < i);
}
}
while (!bfinal);
slider -= 16384;
if (!((slider^slidew)&32768))
putbuf(&slidebuf[slider&32767],slidew-slider);
else
{
putbuf(&slidebuf[slider&32767],(-slider)&32767);
putbuf(slidebuf,slidew&32767);
}
kpngrend_goodret:
if (!(filterest&~(1<<filter1st))) filtype = (int8_t)filter1st;
else if ((filter1st == 1) && (!(filterest&~(1<<3)))) filtype = 3;
else filtype = 5;
if (kcoltype == 4) paleng = 0; //For /c4, palcol/paleng used as LUT for "*0x10101": alpha is invalid!
return 0;
}
//============================= KPNGILIB ends ================================
//============================ KPEGILIB begins ===============================
//11/01/2000: This code was originally from KPEG.C
// All non 32-bit color drawing was removed
// "Motion" JPG code was removed
// A lot of parameters were added to kpeg() for library usage
static int32_t kpeginited = 0;
static int32_t clipxdim, clipydim;
static int32_t hufmaxatbit[8][20], hufvalatbit[8][20], hufcnt[8];
static uint8_t hufnumatbit[8][20], huftable[8][256];
static int32_t hufquickval[8][1024], hufquickbits[8][1024], hufquickcnt[8];
static int32_t quantab[4][64], dct[12][64], lastdc[4], unzig[64], zigit[64]; //dct:10=MAX (says spec);+2 for hacks
static uint8_t gnumcomponents, dcflagor[64];
static int32_t gcompid[4], gcomphsamp[4], gcompvsamp[4], gcompquantab[4], gcomphsampshift[4], gcompvsampshift[4];
static int32_t lnumcomponents, lcompid[4], lcompdc[4], lcompac[4], lcomphsamp[4], lcompvsamp[4], lcompquantab[4];
static int32_t lcomphvsamp0, lcomphsampshift0, lcompvsampshift0;
static int32_t colclip[1024], colclipup8[1024], colclipup16[1024];
/*static uint8_t pow2char[8] = {1,2,4,8,16,32,64,128};*/
#if defined(_MSC_VER) && !defined(NOASM)
static inline int32_t mulshr24(int32_t a, int32_t d)
{
_asm
{
mov eax, a
imul d
shrd eax, edx, 24
}
}
static inline int32_t mulshr32(int32_t a, int32_t d)
{
_asm
{
mov eax, a
imul d
mov eax, edx
}
}
#elif defined(__GNUC__) && defined(__i386__) && !defined(NOASM)
#define mulshr24(a,d) \
({ int32_t __a=(a), __d=(d); \
__asm__ __volatile__ ("imull %%edx; shrdl $24, %%edx, %%eax" \
: "+a" (__a), "+d" (__d) : : "cc"); \
__a; })
#define mulshr32(a,d) \
({ int32_t __a=(a), __d=(d); \
__asm__ __volatile__ ("imull %%edx" \
: "+a" (__a), "+d" (__d) : : "cc"); \
__d; })
#else
static inline int32_t mulshr24(int32_t a, int32_t b)
{
return (int32_t)((((int64_t)a)*((int64_t)b))>>24);
}
static inline int32_t mulshr32(int32_t a, int32_t b)
{
return (int32_t)((((int64_t)a)*((int64_t)b))>>32);
}
#endif
static int32_t cosqr16[8] = //cosqr16[i] = ((cos(PI*i/16)*sqrt(2))<<24);
{23726566,23270667,21920489,19727919,16777216,13181774,9079764,4628823};
static int32_t crmul[4096], cbmul[4096];
static void initkpeg()
{
int32_t i, j, y;
int32_t x = 0; //Back & forth diagonal pattern (aligning bytes for best compression)
for (i=0; i<16; i+=2)
{
for (y=8-1; y>=0; y--)
if ((unsigned)(i-y) < (unsigned)8) unzig[x++] = (y<<3)+i-y;
for (y=0; y<8; y++)
if ((unsigned)(i+1-y) < (unsigned)8) unzig[x++] = (y<<3)+i+1-y;
}
for (i=64-1; i>=0; i--) zigit[unzig[i]] = i;
for (i=64-1; i>=0; i--) dcflagor[i] = (uint8_t)(1<<(unzig[i]>>3));
for (i=0; i<128; i++) colclip[i] = i+128;
for (i=128; i<512; i++) colclip[i] = 255;
for (i=512; i<896; i++) colclip[i] = 0;
for (i=896; i<1024; i++) colclip[i] = i-896;
for (i=0; i<1024; i++)
{
colclipup8[i] = (colclip[i]<<8);
colclipup16[i] = (colclip[i]<<16)+0xff000000; //Hack: set alphas to 255
}
#if B_BIG_ENDIAN == 1
for (i=0; i<1024; i++)
{
colclip[i] = B_SWAP32(colclip[i]);
colclipup8[i] = B_SWAP32(colclipup8[i]);
colclipup16[i] = B_SWAP32(colclipup16[i]);
}
#endif
for (i=0; i<2048; i++)
{
j = i-1024;
crmul[(i<<1)+0] = j*1470104; //1.402*1048576
crmul[(i<<1)+1] = j*-748830; //-0.71414*1048576
cbmul[(i<<1)+0] = j*-360857; //-0.34414*1048576
cbmul[(i<<1)+1] = j*1858077; //1.772*1048576
}
Bmemset((void *)&dct[10][0],0,64*2*sizeof(dct[0][0]));
}
static void huffgetval(int32_t index, int32_t curbits, int32_t num, int32_t *daval, int32_t *dabits)
{
int32_t b, v, pow2, *hmax;
hmax = &hufmaxatbit[index][0];
pow2 = pow2long[curbits-1];
if (num&pow2) v = 1; else v = 0;
for (b=1; b<=16; b++)
{
if (v < hmax[b])
{
*dabits = b;
*daval = huftable[index][hufvalatbit[index][b]+v];
return;
}
pow2 >>= 1; v <<= 1;
if (num&pow2) v++;
}
*dabits = 16; *daval = 0;
}
static void invdct8x8(int32_t *dc, uint8_t dcflag)
{
#define SQRT2 23726566 //(sqrt(2))<<24
#define C182 31000253 //(cos(PI/8)*2)<<24
#define C18S22 43840978 //(cos(PI/8)*sqrt(2)*2)<<24
#define C38S22 18159528 //(cos(PI*3/8)*sqrt(2)*2)<<24
int32_t *edc, t0, t1, t2, t3, t4, t5, t6, t7;
edc = dc+64;
do
{
if (dcflag&1) //pow2char[z])
{
t3 = dc[2] + dc[6];
t2 = (mulshr32(dc[2]-dc[6],SQRT2<<6)<<2) - t3;
t4 = dc[0] + dc[4]; t5 = dc[0] - dc[4];
t0 = t4+t3; t3 = t4-t3; t1 = t5+t2; t2 = t5-t2;
t4 = (mulshr32(dc[5]-dc[3]+dc[1]-dc[7],C182<<6)<<2);
t7 = dc[1] + dc[7] + dc[5] + dc[3];
t6 = (mulshr32(dc[3]-dc[5],C18S22<<5)<<3) + t4 - t7;
t5 = (mulshr32(dc[1]+dc[7]-dc[5]-dc[3],SQRT2<<6)<<2) - t6;
t4 = (mulshr32(dc[1]-dc[7],C38S22<<6)<<2) - t4 + t5;
dc[0] = t0+t7; dc[7] = t0-t7; dc[1] = t1+t6; dc[6] = t1-t6;
dc[2] = t2+t5; dc[5] = t2-t5; dc[4] = t3+t4; dc[3] = t3-t4;
}
dc += 8; dcflag >>= 1;
}
while (dc < edc);
dc -= 32; edc -= 24;
do
{
t3 = dc[2*8-32] + dc[6*8-32];
t2 = (mulshr32(dc[2*8-32]-dc[6*8-32],SQRT2<<6)<<2) - t3;
t4 = dc[0*8-32] + dc[4*8-32]; t5 = dc[0*8-32] - dc[4*8-32];
t0 = t4+t3; t3 = t4-t3; t1 = t5+t2; t2 = t5-t2;
t4 = (mulshr32(dc[5*8-32]-dc[3*8-32]+dc[1*8-32]-dc[7*8-32],C182<<6)<<2);
t7 = dc[1*8-32] + dc[7*8-32] + dc[5*8-32] + dc[3*8-32];
t6 = (mulshr32(dc[3*8-32]-dc[5*8-32],C18S22<<5)<<3) + t4 - t7;
t5 = (mulshr32(dc[1*8-32]+dc[7*8-32]-dc[5*8-32]-dc[3*8-32],SQRT2<<6)<<2) - t6;
t4 = (mulshr32(dc[1*8-32]-dc[7*8-32],C38S22<<6)<<2) - t4 + t5;
dc[0*8-32] = t0+t7; dc[7*8-32] = t0-t7; dc[1*8-32] = t1+t6; dc[6*8-32] = t1-t6;
dc[2*8-32] = t2+t5; dc[5*8-32] = t2-t5; dc[4*8-32] = t3+t4; dc[3*8-32] = t3-t4;
dc++;
}
while (dc < edc);
}
static void yrbrend(int32_t x, int32_t y, int32_t *ldct)
{
int32_t i, j, ox, oy, xx, yy, xxx, yyy, xxxend, yyyend, yv, cr = 0, cb = 0, *odc, *dc, *dc2;
intptr_t p, pp;
odc = ldct; dc2 = &ldct[10<<6];
for (yy=0; yy<(lcompvsamp[0]<<3); yy+=8)
{
oy = y+yy; if ((unsigned)oy >= (unsigned)clipydim) { odc += (lcomphsamp[0]<<6); continue; }
pp = oy*kp_bytesperline + ((x)<<2) + kp_frameplace;
for (xx=0; xx<(lcomphsamp[0]<<3); xx+=8,odc+=64)
{
ox = x+xx; if ((unsigned)ox >= (unsigned)clipxdim) continue;
p = pp+(xx<<2);
dc = odc;
if (lnumcomponents > 1) dc2 = &ldct[(lcomphvsamp0<<6)+((yy>>lcompvsampshift0)<<3)+(xx>>lcomphsampshift0)];
xxxend = min(clipxdim-ox,8);
yyyend = min(clipydim-oy,8);
if ((lcomphsamp[0] == 1) && (xxxend == 8))
{
for (yyy=0; yyy<yyyend; yyy++)
{
for (xxx=0; xxx<8; xxx++)
{
yv = dc[xxx];
cr = (dc2[xxx+64]>>(20-1))&~1;
cb = (dc2[xxx ]>>(20-1))&~1;
((int32_t *)p)[xxx] = colclipup16[(unsigned)(yv+crmul[cr+2048])>>22]+
colclipup8[(unsigned)(yv+crmul[cr+2049]+cbmul[cb+2048])>>22]+
colclip[(unsigned)(yv+cbmul[cb+2049])>>22];
}
p += kp_bytesperline;
dc += 8;
if (!((yyy+1)&(lcompvsamp[0]-1))) dc2 += 8;
}
}
else if ((lcomphsamp[0] == 2) && (xxxend == 8))
{
for (yyy=0; yyy<yyyend; yyy++)
{
for (xxx=0; xxx<8; xxx+=2)
{
yv = dc[xxx];
cr = (dc2[(xxx>>1)+64]>>(20-1))&~1;
cb = (dc2[(xxx>>1)]>>(20-1))&~1;
i = crmul[cr+2049]+cbmul[cb+2048];
cr = crmul[cr+2048];
cb = cbmul[cb+2049];
((int32_t *)p)[xxx] = colclipup16[(unsigned)(yv+cr)>>22]+
colclipup8[(unsigned)(yv+ i)>>22]+
colclip[(unsigned)(yv+cb)>>22];
yv = dc[xxx+1];
((int32_t *)p)[xxx+1] = colclipup16[(unsigned)(yv+cr)>>22]+
colclipup8[(unsigned)(yv+ i)>>22]+
colclip[(unsigned)(yv+cb)>>22];
}
p += kp_bytesperline;
dc += 8;
if (!((yyy+1)&(lcompvsamp[0]-1))) dc2 += 8;
}
}
else
{
for (yyy=0; yyy<yyyend; yyy++)
{
i = 0; j = 1;
for (xxx=0; xxx<xxxend; xxx++)
{
yv = dc[xxx];
j--;
if (!j)
{
j = lcomphsamp[0];
cr = (dc2[i+64]>>(20-1))&~1;
cb = (dc2[i ]>>(20-1))&~1;
i++;
}
((int32_t *)p)[xxx] = colclipup16[(unsigned)(yv+crmul[cr+2048])>>22]+
colclipup8[(unsigned)(yv+crmul[cr+2049]+cbmul[cb+2048])>>22]+
colclip[(unsigned)(yv+cbmul[cb+2049])>>22];
}
p += kp_bytesperline;
dc += 8;
if (!((yyy+1)&(lcompvsamp[0]-1))) dc2 += 8;
}
}
}
}
}
void (*kplib_yrbrend_func)(int32_t,int32_t,int32_t *) = yrbrend;
#define KPEG_GETBITS(curbits, minbits, num, kfileptr, kfileend)\
while (curbits < minbits)\
{\
ch = *kfileptr++; num = (num<<8)+((int)ch); curbits += 8;\
if (ch == 255) { kfileptr++; if (kfileptr >= kfileend) { num <<= 8; curbits += 8; /*Hack to prevent read overrun on valid JPG by stuffing extra byte*/ } }\
}
static int32_t kpegrend(const char *kfilebuf, int32_t kfilength,
intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres)
{
int32_t i, j, v, leng = 0, xdim = 0, ydim = 0, index, prec, restartcnt, restartinterval;
int32_t x, y, z, xx, yy, zz, *dc = NULL, num, curbits, c, daval, dabits, *hqval, *hqbits, hqcnt, *quanptr = NULL;
int32_t passcnt = 0, ghsampmax = 0, gvsampmax = 0, glhsampmax = 0, glvsampmax = 0, glhstep, glvstep;
int32_t eobrun, Ss, Se, Ah, Al, Alut[2], dctx[12], dcty[12], ldctx[12], /* ldcty[12], */ lshx[4], lshy[4];
int16_t *dctbuf = 0, *dctptr[12], *ldctptr[12], *dcs = NULL;
uint8_t ch, marker, dcflag;
const uint8_t *kfileptr, *kfileend;
if (!kpeginited) { kpeginited = 1; initkpeg(); }
kfileptr = (uint8_t const *)kfilebuf;
kfileend = &kfileptr[kfilength];
if (B_UNBUF16(kfileptr) == B_LITTLE16(0xd8ff)) kfileptr += 2;
else return -1; //"%s is not a JPEG file\n",filename
restartinterval = 0;
for (i=0; i<4; i++) lastdc[i] = 0;
for (i=0; i<8; i++) hufcnt[i] = 0;
kcoltype = 0; bitdepth = 8; //For PNGOUT
do
{
ch = *kfileptr++; if (ch != 255) continue;
do { marker = *kfileptr++; }
while (marker == 255);
if (marker != 0xd9) //Don't read past end of buffer
{
leng = ((intptr_t)kfileptr[0]<<8)+(intptr_t)kfileptr[1]-2;
kfileptr += 2;
}
//printf("fileoffs=%08x, marker=%02x,leng=%d",((int32_t)kfileptr)-((int32_t)kfilebuf)-2,marker,leng);
switch (marker)
{
case 0xc0: case 0xc1: case 0xc2:
//processit!
kfileptr++; //numbits = *kfileptr++;
ydim = B_BIG16(B_UNBUF16(&kfileptr[0]));
xdim = B_BIG16(B_UNBUF16(&kfileptr[2]));
//printf("%s: %ld / %ld = %ld\n",filename,xdim*ydim*3,kfilength,(xdim*ydim*3)/kfilength);
kp_frameplace = dakpframeplace;
kp_bytesperline = dakpbytesperline;
kp_xres = daxres;
kp_yres = dayres;
gnumcomponents = kfileptr[4];
kfileptr += 5;
ghsampmax = gvsampmax = glhsampmax = glvsampmax = 0;
for (z=0; z<gnumcomponents; z++)
{
gcompid[z] = kfileptr[0];
gcomphsamp[z] = (kfileptr[1]>>4);
gcompvsamp[z] = (kfileptr[1]&15);
gcompquantab[z] = kfileptr[2];
for (i=0; i<8; i++) if (gcomphsamp[z] == pow2long[i]) { gcomphsampshift[z] = i; break; }
for (i=0; i<8; i++) if (gcompvsamp[z] == pow2long[i]) { gcompvsampshift[z] = i; break; }
if (gcomphsamp[z] > ghsampmax) { ghsampmax = gcomphsamp[z]; glhsampmax = gcomphsampshift[z]; }
if (gcompvsamp[z] > gvsampmax) { gvsampmax = gcompvsamp[z]; glvsampmax = gcompvsampshift[z]; }
kfileptr += 3;
}
break;
case 0xc4: //Huffman table
do
{
ch = *kfileptr++; leng--;
if (ch >= 16) { index = ch-12; }
else { index = ch; }
Bmemcpy((void *)&hufnumatbit[index][1],(void const *)kfileptr,16); kfileptr += 16;
leng -= 16;
v = 0; hufcnt[index] = 0;
hufquickcnt[index] = 0;
for (i=1; i<=16; i++)
{
hufmaxatbit[index][i] = v+hufnumatbit[index][i];
hufvalatbit[index][i] = hufcnt[index]-v;
Bmemcpy((void *)&huftable[index][hufcnt[index]],(void const *)kfileptr,(int32_t)hufnumatbit[index][i]);
if (i <= 10)
for (c=0; c<hufnumatbit[index][i]; c++)
for (j=(1<<(10-i)); j>0; j--)
{
hufquickval[index][hufquickcnt[index]] = huftable[index][hufcnt[index]+c];
hufquickbits[index][hufquickcnt[index]] = i;
hufquickcnt[index]++;
}
kfileptr += hufnumatbit[index][i];
leng -= hufnumatbit[index][i];
hufcnt[index] += hufnumatbit[index][i];
v = ((v+hufnumatbit[index][i])<<1);
}
}
while (leng > 0);
break;
case 0xdb:
do
{
ch = *kfileptr++; leng--;
index = (ch&15);
prec = (ch>>4);
for (z=0; z<64; z++)
{
v = (int32_t)(*kfileptr++);
if (prec) v = (v<<8)+((int32_t)(*kfileptr++));
v <<= 19;
if (unzig[z]&7) v = mulshr24(v,cosqr16[unzig[z]&7 ]);
if (unzig[z]>>3) v = mulshr24(v,cosqr16[unzig[z]>>3]);
quantab[index][unzig[z]] = v;
}
leng -= 64;
if (prec) leng -= 64;
}
while (leng > 0);
break;
case 0xdd:
restartinterval = B_BIG16(B_UNBUF16(&kfileptr[0]));
kfileptr += leng;
break;
case 0xda:
if ((xdim <= 0) || (ydim <= 0)) { Bfree(dctbuf); return -1; }
lnumcomponents = (int32_t)(*kfileptr++); if (!lnumcomponents) { Bfree(dctbuf); return -1; }
if (lnumcomponents > 1) kcoltype = 2;
for (z=0; z<lnumcomponents; z++)
{
lcompid[z] = kfileptr[0];
lcompdc[z] = (kfileptr[1]>>4);
lcompac[z] = (kfileptr[1]&15);
kfileptr += 2;
}
Ss = kfileptr[0];
Se = kfileptr[1];
Ah = (kfileptr[2]>>4);
Al = (kfileptr[2]&15);
kfileptr += 3;
//printf("passcnt=%d, Ss=%d, Se=%d, Ah=%d, Al=%d\n",passcnt,Ss,Se,Ah,Al);
if ((!passcnt) && ((Ss) || (Se != 63) || (Ah) || (Al)))
{
for (z=zz=0; z<gnumcomponents; z++)
{
dctx[z] = ((xdim+(ghsampmax<<3)-1)>>(glhsampmax+3)) << gcomphsampshift[z];
dcty[z] = ((ydim+(gvsampmax<<3)-1)>>(glvsampmax+3)) << gcompvsampshift[z];
zz += dctx[z]*dcty[z];
}
z = zz*64*sizeof(int16_t);
dctbuf = (int16_t *)Xmalloc(z); if (!dctbuf) return -1;
Bmemset(dctbuf,0,z);
for (z=zz=0; z<gnumcomponents; z++) { dctptr[z] = &dctbuf[zz*64]; zz += dctx[z]*dcty[z]; }
}
glhstep = glvstep = 0x7fffffff;
for (z=0; z<lnumcomponents; z++)
for (zz=0; zz<gnumcomponents; zz++)
if (lcompid[z] == gcompid[zz])
{
ldctptr[z] = dctptr[zz];
ldctx[z] = dctx[zz];
// ldcty[z] = dcty[zz];
lcomphsamp[z] = gcomphsamp[zz];
lcompvsamp[z] = gcompvsamp[zz];
lcompquantab[z] = gcompquantab[zz];
if (!z)
{
lcomphsampshift0 = gcomphsampshift[zz];
lcompvsampshift0 = gcompvsampshift[zz];
}
lshx[z] = glhsampmax-gcomphsampshift[zz]+3;
lshy[z] = glvsampmax-gcompvsampshift[zz]+3;
if (gcomphsampshift[zz] < glhstep) glhstep = gcomphsampshift[zz];
if (gcompvsampshift[zz] < glvstep) glvstep = gcompvsampshift[zz];
}
glhstep = (ghsampmax>>glhstep); lcomphsamp[0] = min(lcomphsamp[0],glhstep); glhstep <<= 3;
glvstep = (gvsampmax>>glvstep); lcompvsamp[0] = min(lcompvsamp[0],glvstep); glvstep <<= 3;
lcomphvsamp0 = lcomphsamp[0]*lcompvsamp[0];
clipxdim = min(xdim,kp_xres);
clipydim = min(ydim,kp_yres);
Alut[0] = (1<<Al); Alut[1] = -Alut[0];
restartcnt = restartinterval; eobrun = 0; marker = 0xd0;
num = 0; curbits = 0;
for (y=0; y<ydim; y+=glvstep)
for (x=0; x<xdim; x+=glhstep)
{
if (kfileptr-4-(uint8_t const *)kfilebuf >= kfilength) goto kpegrend_break2; //rest of file is missing!
if (!dctbuf) dc = dct[0];
for (c=0; c<lnumcomponents; c++)
{
hqval = &hufquickval[lcompac[c]+4][0];
hqbits = &hufquickbits[lcompac[c]+4][0];
hqcnt = hufquickcnt[lcompac[c]+4];
if (!dctbuf) quanptr = &quantab[lcompquantab[c]][0];
for (yy=0; yy<(lcompvsamp[c]<<3); yy+=8)
for (xx=0; xx<(lcomphsamp[c]<<3); xx+=8)
{
//NOTE: Might help to split this code into firstime vs. refinement (!Ah vs. Ah!=0)
if (dctbuf) dcs = &ldctptr[c][(((y+yy)>>lshy[c])*ldctx[c] + ((x+xx)>>lshx[c]))<<6];
//Get DC
if (!Ss)
{
KPEG_GETBITS(curbits, 16, num, kfileptr, kfileend);
if (!Ah)
{
i = ((num>>(curbits-10))&1023);
if (i < hufquickcnt[lcompdc[c]])
{ daval = hufquickval[lcompdc[c]][i]; curbits -= hufquickbits[lcompdc[c]][i]; }
else { huffgetval(lcompdc[c],curbits,num,&daval,&dabits); curbits -= dabits; }
if (daval)
{
KPEG_GETBITS(curbits, daval, num, kfileptr, kfileend);
curbits -= daval; v = ((unsigned)num >> curbits) & pow2mask[daval];
if (v <= pow2mask[daval-1]) v -= pow2mask[daval];
lastdc[c] += v;
}
if (!dctbuf) dc[0] = lastdc[c]; else dcs[0] = (int16_t)(lastdc[c]<<Al);
}
else if (num&(pow2long[--curbits])) dcs[0] |= ((int16_t)Alut[0]);
}
//Get AC
if (!dctbuf) Bmemset((void *)&dc[1],0,63*4);
z = max(Ss,1); dcflag = 1;
if (eobrun <= 0)
{
for (; z<=Se; z++)
{
KPEG_GETBITS(curbits, 16, num, kfileptr, kfileend);
i = ((num>>(curbits-10))&1023);
if (i < hqcnt)
{ daval = hqval[i]; curbits -= hqbits[i]; }
else { huffgetval(lcompac[c]+4,curbits,num,&daval,&dabits); curbits -= dabits; }
zz = (daval>>4); daval &= 15;
if (daval)
{
if (Ah)
{
KPEG_GETBITS(curbits, 8, num, kfileptr, kfileend);
if (num&(pow2long[--curbits])) daval = Alut[0]; else daval = Alut[1];
}
}
else if (zz < 15)
{
eobrun = pow2long[zz];
if (zz)
{
KPEG_GETBITS(curbits, zz, num, kfileptr, kfileend);
curbits -= zz; eobrun += ((unsigned)num >> curbits) & pow2mask[zz];
}
if (!Ah) eobrun--;
break;
}
if (Ah)
{
do
{
if (dcs[z])
{
KPEG_GETBITS(curbits, 8, num, kfileptr, kfileend);
if (num&(pow2long[--curbits])) dcs[z] += (int16_t)Alut[dcs[z] < 0];
}
else if (--zz < 0) break;
z++;
}
while (z <= Se);
if (daval) dcs[z] = (int16_t)daval;
}
else
{
z += zz; if (z > Se) break;
KPEG_GETBITS(curbits, daval, num, kfileptr, kfileend);
curbits -= daval; v = ((unsigned)num >> curbits) & pow2mask[daval];
if (daval>=1 /* FIXME ? */ && v <= pow2mask[daval-1]) v -= pow2mask[daval];
dcflag |= dcflagor[z];
if (!dctbuf) dc[unzig[z]] = v; else dcs[z] = (int16_t)(v<<Al);
}
}
}
else if (!Ah) eobrun--;
if ((Ah) && (eobrun > 0))
{
eobrun--;
for (; z<=Se; z++)
{
if (!dcs[z]) continue;
KPEG_GETBITS(curbits, 8, num, kfileptr, kfileend);
if (num&(pow2long[--curbits])) dcs[z] += ((int16_t)Alut[dcs[z] < 0]);
}
}
if (!dctbuf)
{
for (z=64-1; z>=0; z--) dc[z] *= quanptr[z];
invdct8x8(dc,dcflag); dc += 64;
}
}
}
if (!dctbuf) kplib_yrbrend_func(x,y,&dct[0][0]);
restartcnt--;
if (!restartcnt)
{
kfileptr += 1-(curbits>>3); curbits = 0;
if ((kfileptr[-2] != 255) || (kfileptr[-1] != marker)) kfileptr--;
marker++; if (marker >= 0xd8) marker = 0xd0;
restartcnt = restartinterval;
for (i=0; i<4; i++) lastdc[i] = 0;
eobrun = 0;
}
}
kpegrend_break2:;
if (!dctbuf) return 0;
passcnt++; kfileptr -= ((curbits>>3)+1); break;
case 0xd9: break;
default: kfileptr += leng; break;
}
}
while (kfileptr-(uint8_t const *)kfilebuf < kfilength);
if (!dctbuf) return 0;
lnumcomponents = gnumcomponents;
for (i=0; i<gnumcomponents; i++)
{
lcomphsamp[i] = gcomphsamp[i]; gcomphsamp[i] <<= 3;
lcompvsamp[i] = gcompvsamp[i]; gcompvsamp[i] <<= 3;
lshx[i] = glhsampmax-gcomphsampshift[i]+3;
lshy[i] = glvsampmax-gcompvsampshift[i]+3;
}
lcomphsampshift0 = gcomphsampshift[0];
lcompvsampshift0 = gcompvsampshift[0];
lcomphvsamp0 = (lcomphsamp[0]<<lcompvsampshift0);
for (y=0; y<ydim; y+=gcompvsamp[0])
for (x=0; x<xdim; x+=gcomphsamp[0])
{
dc = dct[0];
for (c=0; c<gnumcomponents; c++)
for (yy=0; yy<gcompvsamp[c]; yy+=8)
for (xx=0; xx<gcomphsamp[c]; xx+=8,dc+=64)
{
dcs = &dctptr[c][(((y+yy)>>lshy[c])*dctx[c] + ((x+xx)>>lshx[c]))<<6];
quanptr = &quantab[gcompquantab[c]][0];
for (z=0; z<64; z++) dc[z] = ((int32_t)dcs[zigit[z]])*quanptr[z];
invdct8x8(dc,0xff);
}
kplib_yrbrend_func(x,y,&dct[0][0]);
}
Bfree(dctbuf); return 0;
}
//============================== KPEGILIB ends ==============================
//================================ GIF begins ================================
static uint8_t suffix[4100], filbuffer[768], tempstack[4096];
static int32_t prefix[4100];
static int32_t kgifrend(const char *kfilebuf, int32_t kfilelength,
intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres)
{
int32_t i, x, y, xsiz, ysiz, yinc, xend, xspan, yspan, currstr, numbitgoal;
int32_t lzcols, dat, blocklen, bitcnt, xoff, transcol;
intptr_t yoff;
char numbits, startnumbits, chunkind, ilacefirst;
const uint8_t *ptr, *cptr = NULL;
int32_t daglobxoffs = 0, daglobyoffs = 0;
UNREFERENCED_PARAMETER(kfilelength);
kcoltype = 3; bitdepth = 8; //For PNGOUT
if ((kfilebuf[0] != 'G') || (kfilebuf[1] != 'I') || (kfilebuf[2] != 'F')) return -1;
paleng = (1<<((kfilebuf[10]&7)+1));
ptr = (uint8_t const *)&kfilebuf[13];
if (kfilebuf[10]&128) { cptr = ptr; ptr += paleng*3; }
transcol = -1;
while ((chunkind = *ptr++) == '!')
{
//! 0xf9 leng flags ? ? transcol
if (ptr[0] == 0xf9) { if (ptr[2]&1) transcol = (int32_t)(((uint8_t)ptr[5])); }
ptr++;
do { i = *ptr++; ptr += i; }
while (i);
}
if (chunkind != ',') return -1;
xoff = B_LITTLE16(B_UNBUF16(&ptr[0]));
yoff = B_LITTLE16(B_UNBUF16(&ptr[2]));
xspan = B_LITTLE16(B_UNBUF16(&ptr[4]));
yspan = B_LITTLE16(B_UNBUF16(&ptr[6])); ptr += 9;
if (ptr[-1]&64) { yinc = 8; ilacefirst = 1; }
else { yinc = 1; ilacefirst = 0; }
if (ptr[-1]&128)
{
paleng = (1<<((ptr[-1]&7)+1));
cptr = ptr; ptr += paleng*3;
}
for (i=0; i<paleng; i++)
palcol[i] = B_LITTLE32((((int32_t)cptr[i*3])<<16) + (((int32_t)cptr[i*3+1])<<8) + ((int32_t)cptr[i*3+2]) + 0xff000000);
for (; i<256; i++) palcol[i] = B_LITTLE32(0xff000000);
if (transcol >= 0) palcol[transcol] &= B_LITTLE32(~0xff000000);
//Handle GIF files with different logical&image sizes or non-0 offsets (added 05/15/2004)
xsiz = B_LITTLE16(B_UNBUF16(&kfilebuf[6]));
ysiz = B_LITTLE16(B_UNBUF16(&kfilebuf[8]));
if ((xoff != 0) || (yoff != 0) || (xsiz != xspan) || (ysiz != yspan))
{
daglobxoffs += xoff; //Offset bitmap image by extra amount
daglobyoffs += yoff;
}
xspan += daglobxoffs;
yspan += daglobyoffs; //UGLY HACK
y = daglobyoffs;
if ((uint32_t)y < (uint32_t)dayres)
{ yoff = y*dakpbytesperline+dakpframeplace; x = daglobxoffs; xend = xspan; }
else
{ x = daglobxoffs+0x80000000; xend = xspan+0x80000000; }
lzcols = (1<<(*ptr)); startnumbits = (uint8_t)((*ptr)+1); ptr++;
for (i=lzcols-1; i>=0; i--) { suffix[i] = (uint8_t)(prefix[i] = i); }
currstr = lzcols+2; numbits = startnumbits; numbitgoal = (lzcols<<1);
blocklen = *ptr++;
Bmemcpy(filbuffer,ptr,blocklen); ptr += blocklen;
bitcnt = 0;
while (1)
{
dat = (B_LITTLE32(B_UNBUF32(&filbuffer[bitcnt>>3]))>>(bitcnt&7)) & (numbitgoal-1);
bitcnt += numbits;
if ((bitcnt>>3) > blocklen-3)
{
B_BUF16(filbuffer, B_UNBUF16(&filbuffer[bitcnt>>3]));
i = blocklen-(bitcnt>>3);
blocklen = (int32_t)*ptr++;
Bmemcpy(&filbuffer[i],ptr,blocklen); ptr += blocklen;
bitcnt &= 7; blocklen += i;
}
if (dat == lzcols)
{
currstr = lzcols+2; numbits = startnumbits; numbitgoal = (lzcols<<1);
continue;
}
if ((currstr == numbitgoal) && (numbits < 12))
{ numbits++; numbitgoal <<= 1; }
prefix[currstr] = dat;
for (i=0; dat>=lzcols; dat=prefix[dat]) tempstack[i++] = suffix[dat];
tempstack[i] = (uint8_t)prefix[dat];
suffix[currstr-1] = suffix[currstr] = (uint8_t)dat;
for (; i>=0; i--)
{
if ((uint32_t)x < (uint32_t)daxres)
B_BUF32((void *) (yoff+(x<<2)), palcol[(int32_t)tempstack[i]]);
x++;
if (x == xend)
{
y += yinc;
if (y >= yspan)
switch (yinc)
{
case 8: if (!ilacefirst) { y = daglobyoffs+2; yinc = 4; break; }
ilacefirst = 0; y = daglobyoffs+4; yinc = 8; break;
case 4: y = daglobyoffs+1; yinc = 2; break;
case 2: case 1: return 0;
}
if ((uint32_t)y < (uint32_t)dayres)
{ yoff = y*dakpbytesperline+dakpframeplace; x = daglobxoffs; xend = xspan; }
else
{ x = daglobxoffs+0x80000000; xend = xspan+0x80000000; }
}
}
currstr++;
}
}
//=============================== GIF ends ==================================
//============================== CEL begins =================================
// //old .CEL format:
//int16_t id = 0x9119, xdim, ydim, xoff, yoff, id = 0x0008;
//int32_t imagebytes, filler[4];
//char pal6bit[256][3], image[ydim][xdim];
#ifdef KPCEL
static int32_t kcelrend(const char *buf, int32_t fleng,
intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres)
{
int32_t i, x, y, x0, x1, y0, y1, xsiz, ysiz;
const char *cptr;
UNREFERENCED_PARAMETER(fleng);
kcoltype = 3; bitdepth = 8; paleng = 256; //For PNGOUT
xsiz = (int32_t)B_LITTLE16(B_UNBUF16(&buf[2])); if (xsiz <= 0) return -1;
ysiz = (int32_t)B_LITTLE16(B_UNBUF16(&buf[4])); if (ysiz <= 0) return -1;
cptr = &buf[32];
for (i=0; i<256; i++)
{
palcol[i] = (((int32_t)cptr[0])<<18) +
(((int32_t)cptr[1])<<10) +
(((int32_t)cptr[2])<< 2) + B_LITTLE32(0xff000000);
cptr += 3;
}
x0 = 0; x1 = xsiz;
y0 = 0; y1 = ysiz;
for (y=y0; y<y1; y++)
for (x=x0; x<x1; x++)
{
if (((uint32_t)x < (uint32_t)daxres) && ((uint32_t)y < (uint32_t)dayres))
B_BUF32(y*dakpbytesperline+x*4+dakpframeplace, palcol[cptr[0]]);
cptr++;
}
return 0;
}
#endif
//=============================== CEL ends ==================================
//============================= TARGA begins ================================
static int32_t ktgarend(const char *header, int32_t fleng,
intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres)
{
int32_t i = 0, x, y, pi, xi, yi, x0, x1, y0, y1, xsiz, ysiz, rlestat, colbyte, pixbyte;
intptr_t p;
const uint8_t *fptr, *cptr = NULL, *nptr;
//Ugly and unreliable identification for .TGA!
if ((fleng < 19) || (header[1]&0xfe)) return -1;
if ((header[2] >= 12) || (!((1<<header[2])&0xe0e))) return -1;
if ((header[16]&7) || (header[16] == 0) || (header[16] > 32)) return -1;
if (header[17]&0xc0) return -1;
fptr = (uint8_t const *)&header[header[0]+18];
xsiz = (int32_t)B_LITTLE16(B_UNBUF16(&header[12])); if (xsiz <= 0) return -1;
ysiz = (int32_t)B_LITTLE16(B_UNBUF16(&header[14])); if (ysiz <= 0) return -1;
colbyte = ((((int32_t)header[16])+7)>>3);
if (header[1] == 1)
{
pixbyte = ((((int32_t)header[7])+7)>>3);
cptr = &fptr[-B_LITTLE16(B_UNBUF16(&header[3]))*pixbyte];
fptr += B_LITTLE16(B_UNBUF16(&header[5]))*pixbyte;
}
else pixbyte = colbyte;
switch (pixbyte) // For PNGOUT
{
case 1:
kcoltype = 0;
bitdepth = 8;
palcol[0] = B_LITTLE32(0xff000000);
for (i = 1; i < 256; i++) palcol[i] = palcol[i - 1] + B_LITTLE32(0x10101);
break;
case 2:
case 3: kcoltype = 2; break;
case 4: kcoltype = 6; break;
}
if (!(header[17]&16)) { x0 = 0; x1 = xsiz; xi = 1; }
else { x0 = xsiz-1; x1 = -1; xi =-1; }
if (header[17]&32) { y0 = 0; y1 = ysiz; yi = 1; pi = dakpbytesperline; }
else { y0 = ysiz-1; y1 = -1; yi =-1; pi =-dakpbytesperline; }
if (header[2] < 8) rlestat = -2; else rlestat = -1;
p = y0*dakpbytesperline+dakpframeplace;
for (y=y0; y!=y1; y+=yi,p+=pi)
for (x=x0; x!=x1; x+=xi)
{
if (rlestat < 128)
{
if ((rlestat&127) == 127) { rlestat = (int32_t)fptr[0]; fptr++; }
if (header[1] == 1)
{
if (colbyte == 1) i = fptr[0];
else i = (int32_t)B_LITTLE16(B_UNBUF16(&fptr[0]));
nptr = &cptr[i*pixbyte];
}
else nptr = fptr;
switch (pixbyte)
{
case 1: i = palcol[(int32_t)nptr[0]]; break;
case 2: i = (int32_t)B_LITTLE16(B_UNBUF16(&nptr[0]));
i = B_LITTLE32(((i&0x7c00)<<9) + ((i&0x03e0)<<6) + ((i&0x001f)<<3) + 0xff000000);
break;
case 3: i = (B_UNBUF32(&nptr[0])) | B_LITTLE32(0xff000000); break;
case 4: i = (B_UNBUF32(&nptr[0])); break;
}
fptr += colbyte;
}
if (rlestat >= 0) rlestat--;
if (((uint32_t)x < (uint32_t)daxres) && ((uint32_t)y < (uint32_t)dayres))
B_BUF32((void *) (x*4+p), i);
}
return 0;
}
//============================== TARGA ends =================================
//============================== BMP begins =================================
//TODO: handle BI_RLE8 and BI_RLE4 (compression types 1&2 respectively)
// +---------------+
// | 0(2): "BM" |
// +---------------------+| 10(4): rastoff| +------------------+
// |headsiz=12 (OS/2 1.x)|| 14(4): headsiz| | All new formats: |
//++---------------------++-------------+-+-+------------------+-----------------------+
//| 18(2): xsiz | 18(4): xsiz |
//| 20(2): ysiz | 22(4): ysiz |
//| 22(2): planes (always 1) | 26(2): planes (always 1) |
//| 24(2): cdim (1,4,8,24) | 28(2): cdim (1,4,8,16,24,32) |
//| if (cdim < 16) | 30(4): compression (0,1,2,3!?,4) |
//| 26(rastoff-14-headsiz): pal(bgr) | 34(4): (bitmap data size+3)&3 |
//| | 46(4): N colors (0=2^cdim) |
//| | if (cdim < 16) |
//| | 14+headsiz(rastoff-14-headsiz): pal(bgr0) |
//+---------------------+---------------+---------+------------------------------------+
// | rastoff(?): bitmap data |
// +-------------------------+
static int32_t kbmprend(const char *buf, int32_t fleng,
intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres)
{
int32_t i, j, x, y, x0, x1, y0, y1, rastoff, headsiz, xsiz, ysiz, cdim, comp, cptrinc, *lptr;
const char *cptr;
UNREFERENCED_PARAMETER(fleng);
headsiz = B_UNBUF32(&buf[14]);
if (headsiz == (int32_t)B_LITTLE32(12)) //OS/2 1.x (old format)
{
if (B_UNBUF16(&buf[22]) != B_LITTLE16(1)) return -1;
xsiz = (int32_t)B_LITTLE16(B_UNBUF16(&buf[18]));
ysiz = (int32_t)B_LITTLE16(B_UNBUF16(&buf[20]));
cdim = (int32_t)B_LITTLE16(B_UNBUF16(&buf[24]));
comp = 0;
}
else //All newer formats...
{
if (B_UNBUF16(&buf[26]) != B_LITTLE16(1)) return -1;
xsiz = B_LITTLE32(B_UNBUF32(&buf[18]));
ysiz = B_LITTLE32(B_UNBUF32(&buf[22]));
cdim = (int32_t)B_LITTLE16(B_UNBUF16(&buf[28]));
comp = B_LITTLE32(B_UNBUF32(&buf[30]));
}
if ((xsiz <= 0) || (!ysiz)) return -1;
//cdim must be: (1,4,8,16,24,32)
if (((uint32_t)(cdim-1) >= (uint32_t)32) || (!((1<<cdim)&0x1010113))) return -1;
if ((comp != 0) && (comp != 3)) return -1;
rastoff = B_LITTLE32(B_UNBUF32(&buf[10]));
if (cdim < 16)
{
if (cdim == 2) { palcol[0] = 0xffffffff; palcol[1] = B_LITTLE32(0xff000000); }
if (headsiz == (int32_t)B_LITTLE32(12)) j = 3; else j = 4;
for (i=0,cptr=&buf[headsiz+14]; cptr<&buf[rastoff]; i++,cptr+=j)
palcol[i] = ((B_UNBUF32(&cptr[0]))|B_LITTLE32(0xff000000));
kcoltype = 3; bitdepth = (int8_t)cdim; paleng = i; //For PNGOUT
}
else if (!(cdim&15))
{
kcoltype = 2;
switch (cdim)
{
case 16: palcol[0] = 10; palcol[1] = 5; palcol[2] = 0; palcol[3] = 5; palcol[4] = 5; palcol[5] = 5; break;
case 32: palcol[0] = 16; palcol[1] = 8; palcol[2] = 0; palcol[3] = 8; palcol[4] = 8; palcol[5] = 8; break;
}
if (comp == 3) //BI_BITFIELD (RGB masks)
{
for (i=0; i<3; i++)
{
j = B_UNBUF32(&buf[headsiz+(i<<2)+14]);
for (palcol[i]=0; palcol[i]<32; palcol[i]++)
{
if (j&1) break;
j = (((uint32_t)j)>>1);
}
for (palcol[i+3]=0; palcol[i+3]<32; palcol[i+3]++)
{
if (!(j&1)) break;
j = (((uint32_t)j)>>1);
}
}
}
palcol[0] = 24-(palcol[0]+palcol[3]);
palcol[1] = 16-(palcol[1]+palcol[4]);
palcol[2] = 8-(palcol[2]+palcol[5]);
palcol[3] = (-(1<<(24-palcol[3]))&0x00ff0000);
palcol[4] = (-(1<<(16-palcol[4]))&0x0000ff00);
palcol[5] = (-(1<<(8-palcol[5]))&0x000000ff);
}
cptrinc = (((xsiz*cdim+31)>>3)&~3); cptr = &buf[rastoff];
if (ysiz < 0) { ysiz = -ysiz; }
else { cptr = &cptr[(ysiz-1)*cptrinc]; cptrinc = -cptrinc; }
x0 = 0; x1 = xsiz;
y0 = 0; y1 = ysiz;
if (x1 > daxres) x1 = daxres;
for (y=y0; y<y1; y++,cptr=&cptr[cptrinc])
{
if ((uint32_t)y >= (uint32_t)dayres) continue;
lptr = (int32_t *)(y*dakpbytesperline+dakpframeplace);
switch (cdim)
{
case 1: for (x=x0; x<x1; x++) lptr[x] = palcol[(int32_t)((cptr[x>>3]>>((x&7)^7))&1)]; break;
case 4: for (x=x0; x<x1; x++) lptr[x] = palcol[(int32_t)((cptr[x>>1]>>(((x&1)^1)<<2))&15)]; break;
case 8: for (x=x0; x<x1; x++) lptr[x] = palcol[(int32_t)(cptr[x])]; break;
case 16: for (x=x0; x<x1; x++)
{
i = ((int32_t)(B_UNBUF16(&cptr[x<<1])));
lptr[x] = (klrotl(i,palcol[0])&palcol[3]) +
(klrotl(i,palcol[1])&palcol[4]) +
(klrotl(i,palcol[2])&palcol[5]) + B_LITTLE32(0xff000000);
} break;
case 24: for (x=x0; x<x1; x++) lptr[x] = ((B_UNBUF32(&cptr[x*3]))|B_LITTLE32(0xff000000)); break;
case 32: for (x=x0; x<x1; x++)
{
i = (B_UNBUF32(&cptr[x<<2]));
lptr[x] = (klrotl(i,palcol[0])&palcol[3]) +
(klrotl(i,palcol[1])&palcol[4]) +
(klrotl(i,palcol[2])&palcol[5]) + B_LITTLE32(0xff000000);
} break;
}
}
return 0;
}
//=============================== BMP ends ==================================
//============================== PCX begins =================================
//Note: currently only supports 8 and 24 bit PCX
static int32_t kpcxrend(const char *buf, int32_t fleng,
intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres)
{
int32_t j, x, y, nplanes, x0, x1, y0, y1, bpl, xsiz, ysiz;
intptr_t p,i;
uint8_t c;
uint8_t const *cptr;
if (B_UNBUF32(buf) != B_LITTLE32(0x0801050a)) return -1;
xsiz = B_LITTLE16(B_UNBUF16(&buf[ 8]))-B_LITTLE16(B_UNBUF16(&buf[4]))+1; if (xsiz <= 0) return -1;
ysiz = B_LITTLE16(B_UNBUF16(&buf[10]))-B_LITTLE16(B_UNBUF16(&buf[6]))+1; if (ysiz <= 0) return -1;
//buf[3]: bpp/plane:{1,2,4,8}
nplanes = buf[65]; //nplanes*bpl bytes per scanline; always be decoding break at the end of scan line
bpl = B_LITTLE16(B_UNBUF16(&buf[66])); //#bytes per scanline. Must be EVEN. May have unused data.
if (nplanes == 1)
{
//if (buf[fleng-769] != 12) return -1; //Some PCX are buggy!
cptr = (uint8_t const *)&buf[fleng-768];
for (i=0; i<256; i++)
{
palcol[i] = (((int32_t)cptr[0])<<16) +
(((int32_t)cptr[1])<< 8) +
(((int32_t)cptr[2])) + B_LITTLE32(0xff000000);
cptr += 3;
}
kcoltype = 3; bitdepth = 8; paleng = 256; //For PNGOUT
}
else if (nplanes == 3)
{
kcoltype = 2;
//Make sure background is opaque (since 24-bit PCX renderer doesn't do it)
x0 = 0; x1 = min(xsiz,daxres);
y0 = 0; y1 = min(ysiz,dayres);
i = y0*dakpbytesperline + dakpframeplace+3;
for (y=y0; y<y1; y++,i+=dakpbytesperline)
for (x=x0; x<x1; x++) *(char *)((x<<2)+i) = 255;
}
x = x0 = 0; x1 = xsiz;
y = y0 = 0; y1 = ysiz;
cptr = (uint8_t const *)&buf[128];
p = y*dakpbytesperline+dakpframeplace;
if (bpl > xsiz) { daxres = min(daxres,x1); x1 += bpl-xsiz; }
j = nplanes-1; daxres <<= 2; x0 <<= 2; x1 <<= 2; x <<= 2; x += j;
if (nplanes == 1) //8-bit PCX
{
do
{
c = *cptr++; if (c < 192) i = 1; else { i = (c&63); c = *cptr++; }
j = palcol[(int32_t)c];
for (; i; i--)
{
if ((uint32_t)y < (uint32_t)dayres)
if ((uint32_t)x < (uint32_t)daxres) B_BUF32((void *) (x+p), j);
x += 4; if (x >= x1) { x = x0; y++; p += dakpbytesperline; }
}
}
while (y < y1);
}
else if (nplanes == 3) //24-bit PCX
{
do
{
c = *cptr++; if (c < 192) i = 1; else { i = (c&63); c = *cptr++; }
for (; i; i--)
{
if ((uint32_t)y < (uint32_t)dayres)
if ((uint32_t)x < (uint32_t)daxres) *(char *)(x+p) = c;
x += 4; if (x >= x1) { j--; if (j < 0) { j = 3-1; y++; p += dakpbytesperline; } x = x0+j; }
}
}
while (y < y1);
}
return 0;
}
//=============================== PCX ends ==================================
//============================== DDS begins =================================
//Note:currently supports: DXT1,DXT2,DXT3,DXT4,DXT5,A8R8G8B8
#ifdef KPDDS
static int32_t kddsrend(const char *buf, int32_t leng,
intptr_t frameptr, int32_t bpl, int32_t xdim, int32_t ydim, int32_t xoff, int32_t yoff)
{
int32_t x, y, z = 0, xx, yy, xsiz, ysiz, dxt, al[2], ai, k, v, c0, c1, stride;
intptr_t j;
uint32_t lut[256], r[4], g[4], b[4], a[8], rr, gg, bb;
uint8_t *uptr, *wptr;
UNREFERENCED_PARAMETER(leng);
xsiz = B_LITTLE32(B_UNBUF32(&buf[16]));
ysiz = B_LITTLE32(B_UNBUF32(&buf[12]));
if ((B_UNBUF32(&buf[80]))&B_LITTLE32(64)) //Uncompressed supports only A8R8G8B8 for now
{
if ((B_UNBUF32(&buf[88])) != B_LITTLE32(32)) return -1;
if ((B_UNBUF32(&buf[92])) != B_LITTLE32(0x00ff0000)) return -1;
if ((B_UNBUF32(&buf[96])) != B_LITTLE32(0x0000ff00)) return -1;
if ((B_UNBUF32(&buf[100])) != B_LITTLE32(0x000000ff)) return -1;
if ((B_UNBUF32(&buf[104])) != B_LITTLE32(0xff000000)) return -1;
buf += 128;
j = yoff*bpl + (xoff<<2) + frameptr; xx = (xsiz<<2);
if (xoff < 0) { j -= (xoff<<2); buf -= (xoff<<2); xsiz += xoff; }
xsiz = (min(xsiz,xdim-xoff)<<2); ysiz = min(ysiz,ydim);
for (y=0; y<ysiz; y++,j+=bpl,buf+=xx)
{
if ((uint32_t)(y+yoff) >= (uint32_t)ydim) continue;
Bmemcpy((void *)j,(void *)buf,xsiz);
}
return 0;
}
if (!((B_UNBUF32(&buf[80]))&B_LITTLE32(4))) return -1; //FOURCC invalid
dxt = buf[87]-'0';
if ((buf[84] != 'D') || (buf[85] != 'X') || (buf[86] != 'T') || (dxt < 1) || (dxt > 5)) return -1;
buf += 128;
if (!(dxt&1))
{
for (z=256-1; z>0; z--) lut[z] = tabledivide32_noinline(255<<16, z);
lut[0] = (1<<16);
}
if (dxt == 1) stride = (xsiz<<1); else stride = (xsiz<<2);
for (y=0; y<ysiz; y+=4,buf+=stride)
for (x=0; x<xsiz; x+=4)
{
if (dxt == 1) uptr = (uint8_t *)(((intptr_t)buf)+(x<<1));
else uptr = (uint8_t *)(((intptr_t)buf)+(x<<2)+8);
c0 = B_LITTLE16(B_UNBUF16(&uptr[0]));
r[0] = ((c0>>8)&0xf8); g[0] = ((c0>>3)&0xfc); b[0] = ((c0<<3)&0xfc); a[0] = 255;
c1 = B_LITTLE16(B_UNBUF16(&uptr[2]));
r[1] = ((c1>>8)&0xf8); g[1] = ((c1>>3)&0xfc); b[1] = ((c1<<3)&0xfc); a[1] = 255;
if ((c0 > c1) || (dxt != 1))
{
r[2] = (((r[0]*2 + r[1] + 1)*(65536/3))>>16);
g[2] = (((g[0]*2 + g[1] + 1)*(65536/3))>>16);
b[2] = (((b[0]*2 + b[1] + 1)*(65536/3))>>16); a[2] = 255;
r[3] = (((r[0] + r[1]*2 + 1)*(65536/3))>>16);
g[3] = (((g[0] + g[1]*2 + 1)*(65536/3))>>16);
b[3] = (((b[0] + b[1]*2 + 1)*(65536/3))>>16); a[3] = 255;
}
else
{
r[2] = (r[0] + r[1])>>1;
g[2] = (g[0] + g[1])>>1;
b[2] = (b[0] + b[1])>>1; a[2] = 255;
r[3] = g[3] = b[3] = a[3] = 0; //Transparent
}
v = B_LITTLE32(B_UNBUF32(&uptr[4]));
if (dxt >= 4)
{
a[0] = uptr[-8]; a[1] = uptr[-7]; k = a[1]-a[0];
if (k < 0)
{
z = a[0]*6 + a[1] + 3;
for (j=2; j<8; j++) { a[j] = ((z*(65536/7))>>16); z += k; }
}
else
{
z = a[0]*4 + a[1] + 2;
for (j=2; j<6; j++) { a[j] = ((z*(65536/5))>>16); z += k; }
a[6] = 0; a[7] = 255;
}
al[0] = B_LITTLE32(B_UNBUF32(&uptr[-6]));
al[1] = B_LITTLE32(B_UNBUF32(&uptr[-3]));
}
wptr = (uint8_t *)((y+yoff)*bpl + ((x+xoff)<<2) + frameptr);
ai = 0;
for (yy=0; yy<4; yy++,wptr+=bpl)
{
if ((uint32_t)(y+yy+yoff) >= (uint32_t)ydim) { ai += 4; continue; }
for (xx=0; xx<4; xx++,ai++)
{
if ((uint32_t)(x+xx+xoff) >= (uint32_t)xdim) continue;
j = ((v>>(ai<<1))&3);
switch (dxt)
{
case 1: z = a[j]; break;
case 2: case 3: z = ((uptr[(ai>>1)-8] >> ((xx&1)<<2))&15)*17; break;
case 4: case 5: z = a[(al[yy>>1] >> ((ai&7)*3))&7]; break;
}
rr = r[j]; gg = g[j]; bb = b[j];
if (!(dxt&1))
{
bb = min((bb*lut[z])>>16,255);
gg = min((gg*lut[z])>>16,255);
rr = min((rr*lut[z])>>16,255);
}
wptr[(xx<<2)+0] = (uint8_t)bb;
wptr[(xx<<2)+1] = (uint8_t)gg;
wptr[(xx<<2)+2] = (uint8_t)rr;
wptr[(xx<<2)+3] = (uint8_t)z;
}
}
}
return 0;
}
#endif
//=============================== DDS ends ==================================
//=================== External picture interface begins ======================
static int32_t istarga(const uint8_t *buf, int32_t leng)
{
return ((leng >= 19) && (!(buf[1]&0xfe)) && (buf[2] < 12) && ((1<<buf[2])&0xe0e) &&
(!(buf[16]&7)) && (buf[16] != 0) && (buf[16] <= 32) && !(buf[17]&0xc0));
}
void kpgetdim(const char *buf, int32_t leng, int32_t *xsiz, int32_t *ysiz)
{
int32_t const *lptr;
const uint8_t *cptr;
const uint8_t *ubuf = (uint8_t const *)buf;
(*xsiz) = (*ysiz) = 0; if (leng < 16) return;
if (B_UNBUF16(&ubuf[0]) == B_LITTLE16(0x5089)) //.PNG
{
lptr = (int32_t const *)buf;
if ((lptr[0] != (int32_t)B_LITTLE32(0x474e5089)) || (lptr[1] != (int32_t)B_LITTLE32(0x0a1a0a0d))) return;
lptr = &lptr[2];
while (((uintptr_t)lptr-(uintptr_t)buf) < (uintptr_t)(leng-16))
{
if (lptr[1] == (int32_t)B_LITTLE32(0x52444849)) //IHDR
{(*xsiz) = B_BIG32(lptr[2]); (*ysiz) = B_BIG32(lptr[3]); break; }
lptr = (int32_t *)((intptr_t)lptr + B_BIG32(lptr[0]) + 12);
}
}
else if (B_UNBUF16(&ubuf[0]) == B_LITTLE16(0xd8ff)) //.JPG
{
cptr = (uint8_t const *)&buf[2];
while (((uintptr_t)cptr-(uintptr_t)buf) < (uintptr_t)(leng-8))
{
if ((cptr[0] != 0xff) || (cptr[1] == 0xff)) { cptr++; continue; }
if ((uint32_t)(cptr[1]-0xc0) < 3)
{
(*ysiz) = B_BIG16(B_UNBUF16(&cptr[5]));
(*xsiz) = B_BIG16(B_UNBUF16(&cptr[7]));
break;
}
cptr = &cptr[B_BIG16(B_UNBUF16(&cptr[2]))+2];
}
}
else
{
if ((ubuf[0] == 'G') && (ubuf[1] == 'I') && (ubuf[2] == 'F')) //.GIF
{
(*xsiz) = (int32_t) B_LITTLE16(B_UNBUF16(&buf[6]));
(*ysiz) = (int32_t) B_LITTLE16(B_UNBUF16(&buf[8]));
}
else if ((ubuf[0] == 'B') && (ubuf[1] == 'M')) //.BMP
{
if (B_UNBUF32(&buf[14]) == B_LITTLE32(12)) //OS/2 1.x (old format)
{
if (B_UNBUF16(&buf[22]) != B_LITTLE16(1)) return;
(*xsiz) = (int32_t) B_LITTLE16(B_UNBUF16(&buf[18]));
(*ysiz) = (int32_t) B_LITTLE16(B_UNBUF16(&buf[20]));
}
else //All newer formats...
{
if (B_UNBUF16(&buf[26]) != B_LITTLE16(1)) return;
(*xsiz) = B_LITTLE32(B_UNBUF32(&buf[18]));
(*ysiz) = B_LITTLE32(B_UNBUF32(&buf[22]));
}
}
else if (B_UNBUF32(ubuf) == B_LITTLE32(0x0801050a)) //.PCX
{
(*xsiz) = B_LITTLE16(B_UNBUF16(&buf[8]))-B_LITTLE16(B_UNBUF16(&buf[4]))+1;
(*ysiz) = B_LITTLE16(B_UNBUF16(&buf[10]))-B_LITTLE16(B_UNBUF16(&buf[6]))+1;
}
#ifdef KPCEL
else if ((ubuf[0] == 0x19) && (ubuf[1] == 0x91) && (ubuf[10] == 8) && (ubuf[11] == 0)) //old .CEL/.PIC
{
(*xsiz) = (int32_t) B_LITTLE16(B_UNBUF16(&buf[2]));
(*ysiz) = (int32_t) B_LITTLE16(B_UNBUF16(&buf[4]));
}
#endif
#ifdef KPDDS
else if ((B_UNBUF32(ubuf) == B_LITTLE32(0x20534444)) && (B_UNBUF32(&ubuf[4]) == B_LITTLE32(124))) //.DDS
{
(*xsiz) = B_LITTLE32(B_UNBUF32(&buf[16]));
(*ysiz) = B_LITTLE32(B_UNBUF32(&buf[12]));
}
#endif
else if (istarga(ubuf, leng))
{
//Unreliable .TGA identification - this MUST be final case!
(*xsiz) = (int32_t) B_LITTLE16(B_UNBUF16(&buf[12]));
(*ysiz) = (int32_t) B_LITTLE16(B_UNBUF16(&buf[14]));
}
}
}
int32_t kprender(const char *buf, int32_t leng, intptr_t frameptr, int32_t bpl,
int32_t xdim, int32_t ydim)
{
uint8_t const *ubuf = (uint8_t const *)buf;
paleng = 0; bakcol = 0; numhufblocks = zlibcompflags = 0; filtype = -1;
if (B_UNBUF16(&ubuf[0]) == B_LITTLE16(0x5089)) //.PNG
return kpngrend(buf,leng,frameptr,bpl,xdim,ydim);
else if (B_UNBUF16(&ubuf[0]) == B_LITTLE16(0xd8ff)) //.JPG
return kpegrend(buf,leng,frameptr,bpl,xdim,ydim);
else
{
if ((ubuf[0] == 'G') && (ubuf[1] == 'I') && (ubuf[2] == 'F')) //.GIF
return kgifrend(buf, leng, frameptr, bpl, xdim, ydim);
else if ((ubuf[0] == 'B') && (ubuf[1] == 'M')) //.BMP
return kbmprend(buf, leng, frameptr, bpl, xdim, ydim);
else if (B_UNBUF32(ubuf) == B_LITTLE32(0x0801050a)) //.PCX
return kpcxrend(buf, leng, frameptr, bpl, xdim, ydim);
#ifdef KPCEL
else if ((ubuf[0] == 0x19) && (ubuf[1] == 0x91) && (ubuf[10] == 8) && (ubuf[11] == 0)) //old .CEL/.PIC
return kcelrend(buf, leng, frameptr, bpl, xdim, ydim, xoff, yoff);
#endif
#ifdef KPDDS
else if ((B_UNBUF32(ubuf) == B_LITTLE32(0x20534444)) && (B_UNBUF32(&ubuf[4]) == B_LITTLE32(124))) //.DDS
return kddsrend(buf, leng, frameptr, bpl, xdim, ydim, xoff, yoff);
#endif
//Unreliable .TGA identification - this MUST be final case!
else if (istarga(ubuf, leng))
return ktgarend(buf, leng, frameptr, bpl, xdim, ydim);
else return -1;
}
}
//==================== External picture interface ends =======================
//Brute-force case-insensitive, slash-insensitive, * and ? wildcard matcher
//Given: string i and string j. string j can have wildcards
//Returns: 1:matches, 0:doesn't match
int32_t wildmatch(const char *match, const char *wild)
{
do
{
int const match_deref = *match, wild_deref = *wild;
if (match_deref && (toupperlookup[wild_deref] == toupperlookup[match_deref] || wild_deref == '?'))
{
wild++, match++;
continue;
}
else if ((match_deref|wild_deref) == '\0')
return 1;
else if (wild_deref == '*')
{
do { wild++; } while (*wild == '*');
int const wild_deref = *wild;
do
{
if (wild_deref == '\0')
return 1;
while (*match && toupperlookup[*match] != toupperlookup[wild_deref]) match++;
if (*match && *(match+1) && toupperlookup[*(match+1)] != toupperlookup[*(wild+1)])
{
match++;
continue;
}
break;
}
while (1);
if (toupperlookup[*match] == toupperlookup[wild_deref])
continue;
}
return 0;
}
while (1);
}
//===================== ZIP decompression code begins ========================
//format: (used by kzaddstack/kzopen to cache file name&start info)
//[char zipnam[?]\0]
//[next hashindex/-1][next index/-1][zipnam index][fileoffs][fileleng][iscomp][char filnam[?]\0]
//[next hashindex/-1][next index/-1][zipnam index][fileoffs][fileleng][iscomp][char filnam[?]\0]
//...
//[char zipnam[?]\0]
//[next hashindex/-1][next index/-1][zipnam index][fileoffs][fileleng][iscomp][char filnam[?]\0]
//[next hashindex/-1][next index/-1][zipnam index][fileoffs][fileleng][iscomp][char filnam[?]\0]
//...
#define KZHASHINITSIZE 8192
static char *kzhashbuf = 0;
static int32_t kzhashead[256], kzhashpos, kzlastfnam = -1, kzhashsiz, kzdirnamhead = -1;
static int32_t kzcheckhashsiz(int32_t siz)
{
if (!kzhashbuf) //Initialize hash table on first call
{
Bmemset(kzhashead,-1,sizeof(kzhashead));
kzhashbuf = (char *)Xmalloc(KZHASHINITSIZE); if (!kzhashbuf) return 0;
kzhashpos = 0; kzlastfnam = -1; kzhashsiz = KZHASHINITSIZE; kzdirnamhead = -1;
}
if (kzhashpos+siz > kzhashsiz) //Make sure string fits in kzhashbuf
{
int32_t i = kzhashsiz; do { i <<= 1; }
while (kzhashpos+siz > i);
kzhashbuf = (char *)Xrealloc(kzhashbuf,i); if (!kzhashbuf) return 0;
kzhashsiz = i;
}
return 1;
}
static int32_t kzcalchash(const char *st)
{
int32_t i, hashind;
for (i=0,hashind=0; st[i]; i++)
hashind = toupperlookup[st[i]]-((hashind<<1)+hashind);
return hashind%ARRAY_SIZE(kzhashead);
}
static int32_t kzcheckhash(const char *filnam, char **zipnam, int32_t *fileoffs, int32_t *fileleng, char *iscomp)
{
int32_t i;
if (!kzhashbuf) return 0;
if (filnam[0] == '|') filnam++;
for (i=kzhashead[kzcalchash(filnam)]; i>=0; i=(B_UNBUF32(&kzhashbuf[i])))
if (!filnamcmp(filnam,&kzhashbuf[i+21]))
{
(*zipnam) = &kzhashbuf[B_UNBUF32(&kzhashbuf[i+8])];
(*fileoffs) = B_UNBUF32(&kzhashbuf[i+12]);
(*fileleng) = B_UNBUF32(&kzhashbuf[i+16]);
(*iscomp) = kzhashbuf[i+20];
return 1;
}
return 0;
}
void kzuninit()
{
DO_FREE_AND_NULL(kzhashbuf);
kzhashpos = kzhashsiz = 0; kzdirnamhead = -1;
}
//If file found, loads internal directory from ZIP/GRP into memory (hash) to allow faster access later
//If file not found, assumes it's a directory and adds it to an internal list
int32_t kzaddstack(const char *filnam)
{
buildvfs_FILE fil;
int32_t i, j, k, leng, hashind, zipnamoffs, numfiles;
char tempbuf[260+46];
fil = buildvfs_fopen_read(filnam);
if (!fil) //if file not found, assume it's a directory
{
//Add directory name to internal list (using kzhashbuf for convenience of dynamic allocation)
i = strlen(filnam)+5; if (!kzcheckhashsiz(i)) return -1;
B_BUF32(&kzhashbuf[kzhashpos], kzdirnamhead); kzdirnamhead = kzhashpos;
strcpy(&kzhashbuf[kzhashpos+4],filnam);
kzhashpos += i;
return -1;
}
//Write ZIP/GRP filename to hash
i = strlen(filnam)+1; if (!kzcheckhashsiz(i)) { buildvfs_fclose(fil); return -1; }
strcpy(&kzhashbuf[kzhashpos],filnam);
zipnamoffs = kzhashpos; kzhashpos += i;
buildvfs_fread(&i,4,1,fil);
if (i == (int32_t)B_LITTLE32(0x04034b50)) //'PK\3\4' is ZIP file id
{
buildvfs_fseek_abs(fil,buildvfs_flength(fil)-22);
buildvfs_fread(tempbuf,22,1,fil);
if (B_UNBUF32(&tempbuf[0]) == B_LITTLE32(0x06054b50)) //Fast way of finding dir info
{
numfiles = B_LITTLE16(B_UNBUF16(&tempbuf[10]));
buildvfs_fseek_abs(fil,B_LITTLE32(B_UNBUF32(&tempbuf[16])));
}
else //Slow way of finding dir info (used when ZIP has junk at end)
{
buildvfs_fseek_abs(fil,0); numfiles = 0;
while (1)
{
if (!buildvfs_fread(&j,4,1,fil)) { numfiles = -1; break; }
if (j == (int32_t)B_LITTLE32(0x02014b50)) break; //Found central file header :)
if (j != (int32_t)B_LITTLE32(0x04034b50)) { numfiles = -1; break; }
buildvfs_fread(tempbuf,26,1,fil);
buildvfs_fseek_rel(fil,B_LITTLE32(B_UNBUF32(&tempbuf[14])) + B_LITTLE16(B_UNBUF16(&tempbuf[24])) + B_LITTLE16(B_UNBUF16(&tempbuf[22])));
numfiles++;
}
if (numfiles < 0) { buildvfs_fclose(fil); return -1; }
buildvfs_fseek_rel(fil,-4);
}
for (i=0; i<numfiles; i++)
{
buildvfs_fread(tempbuf,46,1,fil);
if (B_UNBUF32(&tempbuf[0]) != B_LITTLE32(0x02014b50)) { buildvfs_fclose(fil); return 0; }
j = B_LITTLE16(B_UNBUF16(&tempbuf[28])); //filename length
buildvfs_fread(&tempbuf[46],j,1,fil);
tempbuf[j+46] = 0;
//Write information into hash
j = strlen(&tempbuf[46])+22; if (!kzcheckhashsiz(j)) { buildvfs_fclose(fil); return -1; }
hashind = kzcalchash(&tempbuf[46]);
B_BUF32(&kzhashbuf[kzhashpos], kzhashead[hashind]);
B_BUF32(&kzhashbuf[kzhashpos+4], kzlastfnam);
B_BUF32(&kzhashbuf[kzhashpos+8], zipnamoffs);
B_BUF32(&kzhashbuf[kzhashpos+12], B_LITTLE32(B_UNBUF32(&tempbuf[42]))); //fileoffs
B_BUF32(&kzhashbuf[kzhashpos+16], 0); //fileleng not used for ZIPs (reserve space for simplicity)
kzhashbuf[kzhashpos+20] = 1; //iscomp
strcpy(&kzhashbuf[kzhashpos+21],&tempbuf[46]);
kzhashead[hashind] = kzhashpos; kzlastfnam = kzhashpos; kzhashpos += j;
j = B_LITTLE16(B_UNBUF16(&tempbuf[30])); //extra field length
j += B_LITTLE16(B_UNBUF16(&tempbuf[32])); //file comment length
buildvfs_fseek_rel(fil,j);
}
}
else if (i == (int32_t)B_LITTLE32(0x536e654b)) //'KenS' is GRP file id
{
buildvfs_fread(tempbuf,12,1,fil);
if ((B_UNBUF32(&tempbuf[0]) != B_LITTLE32(0x65766c69)) || //'ilve'
(B_UNBUF32(&tempbuf[4]) != B_LITTLE32(0x6e616d72))) //'rman'
{ buildvfs_fclose(fil); return 0; }
numfiles = B_LITTLE32(B_UNBUF32(&tempbuf[8])); k = ((numfiles+1)<<4);
for (i=0; i<numfiles; i++,k+=leng)
{
buildvfs_fread(tempbuf,16,1,fil);
leng = B_LITTLE32(B_UNBUF32(&tempbuf[12])); //File length
tempbuf[12] = 0;
//Write information into hash
j = strlen(tempbuf)+22; if (!kzcheckhashsiz(j)) { buildvfs_fclose(fil); return -1; }
hashind = kzcalchash(tempbuf);
B_BUF32(&kzhashbuf[kzhashpos], kzhashead[hashind]);
B_BUF32(&kzhashbuf[kzhashpos+4], kzlastfnam);
B_BUF32(&kzhashbuf[kzhashpos+8], zipnamoffs);
B_BUF32(&kzhashbuf[kzhashpos+12], k); //fileoffs
B_BUF32(&kzhashbuf[kzhashpos+16], leng); //fileleng
kzhashbuf[kzhashpos+20] = 0; //iscomp
strcpy(&kzhashbuf[kzhashpos+21],tempbuf);
kzhashead[hashind] = kzhashpos; kzlastfnam = kzhashpos; kzhashpos += j;
}
}
buildvfs_fclose(fil);
return 0;
}
//this allows the use of kplib.c with a file that is already open
void kzsetfil(buildvfs_FILE fil)
{
kzfs.fil = fil;
kzfs.comptyp = 0;
kzfs.seek0 = 0;
kzfs.leng = buildvfs_flength(fil);
kzfs.pos = 0;
kzfs.i = 0;
}
intptr_t kzopen(const char *filnam)
{
buildvfs_FILE fil{};
int32_t i, fileoffs, fileleng;
char tempbuf[46+260], *zipnam, iscomp;
//kzfs.fil = 0;
if (filnam[0] != '|') //Search standalone file first
{
kzfs.fil = buildvfs_fopen_read(filnam);
if (kzfs.fil)
{
kzfs.comptyp = 0;
kzfs.seek0 = 0;
kzfs.leng = buildvfs_flength(fil);
kzfs.pos = 0;
kzfs.i = 0;
return (intptr_t)kzfs.fil;
}
}
if (kzcheckhash(filnam,&zipnam,&fileoffs,&fileleng,&iscomp)) //Then check mounted ZIP/GRP files
{
fil = buildvfs_fopen_read(zipnam); if (!fil) return 0;
buildvfs_fseek_abs(fil,fileoffs);
if (!iscomp) //Must be from GRP file
{
kzfs.fil = fil;
kzfs.comptyp = 0;
kzfs.seek0 = fileoffs;
kzfs.leng = fileleng;
kzfs.pos = 0;
kzfs.i = 0;
return (intptr_t)kzfs.fil;
}
else
{
buildvfs_fread(tempbuf,30,1,fil);
if (B_UNBUF32(&tempbuf[0]) != B_LITTLE32(0x04034b50)) { buildvfs_fclose(fil); return 0; }
buildvfs_fseek_rel(fil,B_LITTLE16(B_UNBUF16(&tempbuf[26]))+B_LITTLE16(B_UNBUF16(&tempbuf[28])));
kzfs.fil = fil;
kzfs.comptyp = B_LITTLE16(B_UNBUF16(&tempbuf[8]));
kzfs.seek0 = buildvfs_ftell(fil);
kzfs.leng = B_LITTLE32(B_UNBUF32(&tempbuf[22]));
kzfs.pos = 0;
switch (kzfs.comptyp) //Compression method
{
case 0: kzfs.i = 0; return (intptr_t)kzfs.fil;
case 8:
if (!pnginited) { pnginited = 1; initpngtables(); }
kzfs.comptell = 0;
kzfs.compleng = (int32_t)B_LITTLE32(B_UNBUF32(&tempbuf[18]));
//WARNING: No file in ZIP can be > 2GB-32K bytes
gslidew = 0x7fffffff; //Force reload at beginning
return (intptr_t)kzfs.fil;
default: buildvfs_fclose(kzfs.fil); kzfs.fil = 0; return 0;
}
}
}
//Finally, check mounted dirs
int const namlen = strlen(filnam);
for (i=kzdirnamhead; i>=0; i=B_UNBUF32(&kzhashbuf[i]))
{
strcpy(tempbuf,&kzhashbuf[i+4]);
uint32_t const j = strlen(tempbuf);
if (namlen+1+j >= sizeof(tempbuf)) continue; //don't allow int32_t filenames to buffer overrun
if ((j) && (tempbuf[j-1] != '/') && (tempbuf[j-1] != '\\') && (filnam[0] != '/') && (filnam[0] != '\\'))
#if defined(_WIN32)
strcat(tempbuf,"\\");
#else
strcat(tempbuf,"/");
#endif
strcat(tempbuf,filnam);
kzfs.fil = buildvfs_fopen_read(tempbuf);
if (kzfs.fil)
{
kzfs.comptyp = 0;
kzfs.seek0 = 0;
kzfs.leng = buildvfs_flength(fil);
kzfs.pos = 0;
kzfs.i = 0;
return (intptr_t)kzfs.fil;
}
}
return 0;
}
#ifndef USE_PHYSFS
// --------------------------------------------------------------------------
#if defined(_WIN32)
static HANDLE hfind = INVALID_HANDLE_VALUE;
static WIN32_FIND_DATA findata;
#else
#include <dirent.h>
#define MAX_PATH 260
static DIR *hfind = NULL;
static struct dirent *findata = NULL;
#endif
//File find state variables. Example sequence (read top->bot, left->right):
// srchstat srchzoff srchdoff
// 0,1,2,3
// 500,200,-1
// 4 300
// 0,1,2,3,4 100
// 0,1,2,3,4 -1
static int32_t srchstat = -1, srchzoff = 0, srchdoff = -1, wildstpathleng;
static char wildst[MAX_PATH] = "", newildst[MAX_PATH] = "";
void kzfindfilestart(const char *st)
{
#if defined(_WIN32)
if (hfind != INVALID_HANDLE_VALUE)
{ FindClose(hfind); hfind = INVALID_HANDLE_VALUE; }
#else
if (hfind) { closedir(hfind); hfind = NULL; }
#endif
strcpy(wildst,st); strcpy(newildst,st);
srchstat = 0; srchzoff = kzlastfnam; srchdoff = kzdirnamhead;
}
int32_t kzfindfile(char *filnam)
{
int32_t i;
kzfindfile_beg:;
filnam[0] = 0;
if (srchstat == 0)
{
if (!newildst[0]) { srchstat = -1; return 0; }
do
{
srchstat = 1;
//Extract directory from wildcard string for pre-pending
wildstpathleng = 0;
for (i=0; newildst[i]; i++)
if ((newildst[i] == '/') || (newildst[i] == '\\'))
wildstpathleng = i+1;
Bmemcpy(filnam,newildst,wildstpathleng);
#if defined(_WIN32)
hfind = FindFirstFile(newildst,&findata);
if (hfind == INVALID_HANDLE_VALUE)
{ if (!kzhashbuf) return 0; srchstat = 2; continue; }
if (findata.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) continue;
i = wildstpathleng;
if (findata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
if ((findata.cFileName[0] == '.') && (!findata.cFileName[1])) continue;
strcpy(&filnam[i],findata.cFileName);
if (findata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) strcat(&filnam[i],"\\");
#else
if (!hfind)
{
char const *s = ".";
if (wildstpathleng > 0)
{
filnam[wildstpathleng] = 0;
s = filnam;
}
hfind = opendir(s);
if (!hfind) { if (!kzhashbuf) return 0; srchstat = 2; continue; }
}
break; // process srchstat == 1
#endif
return 1;
}
while (0);
}
if (srchstat == 1)
{
while (1)
{
Bmemcpy(filnam,newildst,wildstpathleng);
#if defined(_WIN32)
if (!FindNextFile(hfind,&findata))
{ FindClose(hfind); hfind = INVALID_HANDLE_VALUE; if (!kzhashbuf) return 0; srchstat = 2; break; }
if (findata.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) continue;
i = wildstpathleng;
if (findata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
if ((findata.cFileName[0] == '.') && (!findata.cFileName[1])) continue;
strcpy(&filnam[i],findata.cFileName);
if (findata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) strcat(&filnam[i],"\\");
#else
if ((findata = readdir(hfind)) == NULL)
{ closedir(hfind); hfind = NULL; if (!kzhashbuf) return 0; srchstat = 2; break; }
i = wildstpathleng;
if (findata->d_type == DT_DIR)
{ if (findata->d_name[0] == '.' && !findata->d_name[1]) continue; } //skip .
else if ((findata->d_type == DT_REG) || (findata->d_type == DT_LNK))
{ if (findata->d_name[0] == '.') continue; } //skip hidden (dot) files
else continue; //skip devices and fifos and such
if (!wildmatch(findata->d_name,&newildst[wildstpathleng])) continue;
strcpy(&filnam[i],findata->d_name);
if (findata->d_type == DT_DIR) strcat(&filnam[i],"/");
#endif
return 1;
}
}
while (srchstat == 2)
{
if (srchzoff < 0) { srchstat = 3; break; }
if (wildmatch(&kzhashbuf[srchzoff+21],newildst))
{
//strcpy(filnam,&kzhashbuf[srchzoff+21]);
filnam[0] = '|'; strcpy(&filnam[1],&kzhashbuf[srchzoff+21]);
srchzoff = B_UNBUF32(&kzhashbuf[srchzoff+4]);
return 1;
}
srchzoff = B_UNBUF32(&kzhashbuf[srchzoff+4]);
}
while (srchstat == 3)
{
if (srchdoff < 0) { srchstat = -1; break; }
strcpy(newildst,&kzhashbuf[srchdoff+4]);
i = strlen(newildst);
if ((i) && (newildst[i-1] != '/') && (newildst[i-1] != '\\') && (filnam[0] != '/') && (filnam[0] != '\\'))
#if defined(_WIN32)
strcat(newildst,"\\");
#else
strcat(newildst,"/");
#endif
strcat(newildst,wildst);
srchdoff = B_UNBUF32(&kzhashbuf[srchdoff]);
srchstat = 0; goto kzfindfile_beg;
}
return 0;
}
//File searching code (supports inside ZIP files!) How to use this code:
// char filnam[MAX_PATH];
// kzfindfilestart("vxl/*.vxl");
// while (kzfindfile(filnam)) puts(filnam);
//NOTES:
// * Directory names end with '\' or '/' (depending on system)
// * Files inside zip begin with '|'
#endif
// --------------------------------------------------------------------------
static char *gzbufptr;
static void putbuf4zip(const uint8_t *buf, int32_t uncomp0, int32_t uncomp1)
{
int32_t i0, i1;
// uncomp0 ... uncomp1
// &gzbufptr[kzfs.pos] ... &gzbufptr[kzfs.endpos];
i0 = max(uncomp0,kzfs.pos);
i1 = min(uncomp1,kzfs.endpos);
if (i0 < i1) Bmemcpy(&gzbufptr[i0],&buf[i0-uncomp0],i1-i0);
}
//returns number of bytes copied
int32_t kzread(void *buffer, int32_t leng)
{
int32_t i, j, k, bfinal, btype, hlit, hdist;
if ((!kzfs.fil) || (leng <= 0)) return 0;
if (kzfs.comptyp == 0)
{
if (kzfs.pos != kzfs.i) //Seek only when position changes
{ buildvfs_fseek_abs(kzfs.fil,kzfs.seek0+kzfs.pos); kzfs.i = kzfs.pos; }
i = min(kzfs.leng-kzfs.pos,leng);
buildvfs_fread(buffer,i,1,kzfs.fil);
kzfs.i += i; //kzfs.i is a local copy of buildvfs_ftell(kzfs.fil);
}
else if (kzfs.comptyp == 8)
{
zipfilmode = 1;
//Initialize for putbuf4zip
gzbufptr = (char *)buffer; gzbufptr = &gzbufptr[-kzfs.pos];
kzfs.endpos = min(kzfs.pos+leng,kzfs.leng);
if (kzfs.endpos == kzfs.pos) return 0; //Guard against reading 0 length
if (kzfs.pos < gslidew-32768) // Must go back to start :(
{
if (kzfs.comptell) buildvfs_fseek_abs(kzfs.fil,kzfs.seek0);
gslidew = 0; gslider = 16384;
kzfs.jmpplc = 0;
//Initialize for suckbits/peekbits/getbits
kzfs.comptell = min<int32_t>(kzfs.compleng,sizeof(olinbuf));
buildvfs_fread(&olinbuf[0],kzfs.comptell,1,kzfs.fil);
//Make it re-load when there are < 32 bits left in FIFO
bitpos = -(((int32_t)sizeof(olinbuf)-4)<<3);
//Identity: filptr + (bitpos>>3) = &olinbuf[0]
filptr = &olinbuf[-(bitpos>>3)];
}
else
{
i = max(gslidew-32768,0); j = gslider-16384;
//HACK: Don't unzip anything until you have to...
// (keeps file pointer as low as possible)
if (kzfs.endpos <= gslidew) j = kzfs.endpos;
//write uncompoffs on slidebuf from: i to j
if (!((i^j)&32768))
putbuf4zip(&slidebuf[i&32767],i,j);
else
{
putbuf4zip(&slidebuf[i&32767],i,j&~32767);
putbuf4zip(slidebuf,j&~32767,j);
}
//HACK: Don't unzip anything until you have to...
// (keeps file pointer as low as possible)
if (kzfs.endpos <= gslidew) goto retkzread;
}
switch (kzfs.jmpplc)
{
case 0: goto kzreadplc0;
case 1: goto kzreadplc1;
case 2: goto kzreadplc2;
case 3: goto kzreadplc3;
}
kzreadplc0:;
do
{
bfinal = getbits(1); btype = getbits(2);
#if 0
//Display Huffman block offsets&lengths of input file - for debugging only!
{
static int32_t ouncomppos = 0, ocomppos = 0;
if (kzfs.comptell == sizeof(olinbuf)) i = 0;
else if (kzfs.comptell < kzfs.compleng) i = kzfs.comptell-(sizeof(olinbuf)-4);
else i = kzfs.comptell-(kzfs.comptell%(sizeof(olinbuf)-4));
i += ((int32_t)&filptr[bitpos>>3])-((int32_t)(&olinbuf[0]));
i = (i<<3)+(bitpos&7)-3;
if (gslidew) printf(" ULng:0x%08x CLng:0x%08x.%x",gslidew-ouncomppos,(i-ocomppos)>>3,((i-ocomppos)&7)<<1);
printf("\ntype:%d, Uoff:0x%08x Coff:0x%08x.%x",btype,gslidew,i>>3,(i&7)<<1);
if (bfinal)
{
printf(" ULng:0x%08x CLng:0x%08x.%x",kzfs.leng-gslidew,((kzfs.compleng<<3)-i)>>3,(((kzfs.compleng<<3)-i)&7)<<1);
printf("\n Uoff:0x%08x Coff:0x%08x.0",kzfs.leng,kzfs.compleng);
ouncomppos = ocomppos = 0;
}
else { ouncomppos = gslidew; ocomppos = i; }
}
#endif
if (btype == 0)
{
//Raw (uncompressed)
suckbits((-bitpos)&7); //Synchronize to start of next byte
i = getbits(16); if ((getbits(16)^i) != 0xffff) return -1;
for (; i; i--)
{
if (gslidew >= gslider)
{
putbuf4zip(&slidebuf[(gslider-16384)&32767],gslider-16384,gslider); gslider += 16384;
if (gslider-16384 >= kzfs.endpos)
{
kzfs.jmpplc = 1; kzfs.i = i; kzfs.bfinal = bfinal;
goto retkzread;
kzreadplc1:; i = kzfs.i; bfinal = kzfs.bfinal;
}
}
slidebuf[(gslidew++)&32767] = (uint8_t)getbits(8);
}
continue;
}
if (btype == 3) continue;
if (btype == 1) //Fixed Huffman
{
hlit = 288; hdist = 32; i = 0;
for (; i<144; i++) clen[i] = 8; //Fixed bit sizes (literals)
for (; i<256; i++) clen[i] = 9; //Fixed bit sizes (literals)
for (; i<280; i++) clen[i] = 7; //Fixed bit sizes (EOI,lengths)
for (; i<288; i++) clen[i] = 8; //Fixed bit sizes (lengths)
for (; i<320; i++) clen[i] = 5; //Fixed bit sizes (distances)
}
else //Dynamic Huffman
{
hlit = getbits(5)+257; hdist = getbits(5)+1; j = getbits(4)+4;
for (i=0; i<j; i++) cclen[ccind[i]] = getbits(3);
for (; i<19; i++) cclen[ccind[i]] = 0;
hufgencode(cclen,19,ibuf0,nbuf0);
j = 0; k = hlit+hdist;
while (j < k)
{
i = hufgetsym(ibuf0,nbuf0);
if (i < 16) { clen[j++] = i; continue; }
if (i == 16)
{ for (i=getbits(2)+3; i; i--) { clen[j] = clen[j-1]; j++; } }
else
{
if (i == 17) i = getbits(3)+3; else i = getbits(7)+11;
for (; i; i--) clen[j++] = 0;
}
}
}
hufgencode(clen,hlit,ibuf0,nbuf0);
qhufgencode(ibuf0,nbuf0,qhufval0,qhufbit0,LOGQHUFSIZ0);
hufgencode(&clen[hlit],hdist,ibuf1,nbuf1);
qhufgencode(ibuf1,nbuf1,qhufval1,qhufbit1,LOGQHUFSIZ1);
while (1)
{
if (gslidew >= gslider)
{
putbuf4zip(&slidebuf[(gslider-16384)&32767],gslider-16384,gslider); gslider += 16384;
if (gslider-16384 >= kzfs.endpos)
{
kzfs.jmpplc = 2; kzfs.bfinal = bfinal; goto retkzread;
kzreadplc2:; bfinal = kzfs.bfinal;
}
}
k = peekbits(LOGQHUFSIZ0);
if (qhufbit0[k]) { i = qhufval0[k]; suckbits((int32_t)qhufbit0[k]); }
else i = hufgetsym(ibuf0,nbuf0);
if (i < 256) { slidebuf[(gslidew++)&32767] = (uint8_t)i; continue; }
if (i == 256) break;
i = getbits(hxbit[i+30-257][0]) + hxbit[i+30-257][1];
k = peekbits(LOGQHUFSIZ1);
if (qhufbit1[k]) { j = qhufval1[k]; suckbits((int32_t)qhufbit1[k]); }
else j = hufgetsym(ibuf1,nbuf1);
j = getbits(hxbit[j][0]) + hxbit[j][1];
for (; i; i--,gslidew++) slidebuf[gslidew&32767] = slidebuf[(gslidew-j)&32767];
}
}
while (!bfinal);
gslider -= 16384;
if (!((gslider^gslidew)&32768))
putbuf4zip(&slidebuf[gslider&32767],gslider,gslidew);
else
{
putbuf4zip(&slidebuf[gslider&32767],gslider,gslidew&~32767);
putbuf4zip(slidebuf,gslidew&~32767,gslidew);
}
kzreadplc3:; kzfs.jmpplc = 3;
}
retkzread:;
i = kzfs.pos;
kzfs.pos += leng; if (kzfs.pos > kzfs.leng) kzfs.pos = kzfs.leng;
return kzfs.pos-i;
}
//WARNING: kzseek(<-32768,SEEK_CUR); or:
// kzseek(0,SEEK_END); can make next kzread very slow!!!
int32_t kzseek(int32_t offset, int32_t whence)
{
if (!kzfs.fil) return -1;
switch (whence)
{
case SEEK_CUR: kzfs.pos += offset; break;
case SEEK_END: kzfs.pos = kzfs.leng+offset; break;
case SEEK_SET: default: kzfs.pos = offset;
}
if (kzfs.pos < 0) kzfs.pos = 0;
if (kzfs.pos > kzfs.leng) kzfs.pos = kzfs.leng;
return kzfs.pos;
}
//====================== ZIP decompression code ends =========================
//===================== HANDY PICTURE function begins ========================
#include "cache1d.h"
void kpzdecode(int32_t const leng, intptr_t * const pic, int32_t * const xsiz, int32_t * const ysiz)
{
*pic = 0;
kpgetdim(kpzbuf, leng, xsiz, ysiz);
*pic = (intptr_t)Xmalloc(*ysiz * ((*xsiz)<<2));
if (!*pic)
return;
if (kprender(kpzbuf, leng, *pic, ((*xsiz)<<2), *xsiz, *ysiz) < 0)
{
Bfree((void *) *pic);
*pic = (intptr_t)NULL;
}
}
void kpzload(const char * const filnam, intptr_t * const pic, int32_t * const xsiz, int32_t * const ysiz)
{
kpzdecode(kpzbufload(filnam), pic, xsiz, ysiz);
}
//====================== HANDY PICTURE function ends =========================