mirror of
https://github.com/ZDoom/Raze.git
synced 2025-03-04 16:01:25 +00:00
The EDuke32 and RedNukem frontends are working, Blood isn't yet. Notes: many of the CMake variables and its output still refer to zdoom. Before changing that I wanted to make sure to be able to commit something that works. support code for Windows XP has been entirely removed. On Windows this will only target Vista and up. the crc32.h header had to be renamed to deconflict from zlib. several Windows API calls were changed to call the A-versions directly. Weirdly enough there were places that defined their parameters as T types but in a non-working way. removed some remaining editor files and support for the native software rendering only Windows backend. in a few simple cases, replaced 'char' with 'uint8_t'. The code as-is depends on chars being unsigned which is non-portable. This needs to be carefully reviewed.
2856 lines
108 KiB
C++
2856 lines
108 KiB
C++
/**************************************************************************************************
|
|
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;
|
|
}
|
|
|
|
|
|
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]]);
|
|
}
|
|
|
|
|
|
//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};*/
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
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(0xD8FFu)) 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)) { Xfree(dctbuf); return -1; }
|
|
|
|
lnumcomponents = (int32_t)(*kfileptr++); if (!lnumcomponents) { Xfree(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]);
|
|
}
|
|
|
|
Xfree(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(0xD8FFu)) //.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(0xD8FFu)) //.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_DATAA 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 = FindFirstFileA(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 (!FindNextFileA(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)
|
|
{
|
|
Xfree((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 =========================
|