mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-19 02:31:25 +00:00
b3639ae8e7
I have commented out the versions of these functions that perform bitmasks and shifts and replaced them with versions that cast to and from integral types, pending performance and compatibility research across platforms. git-svn-id: https://svn.eduke32.com/eduke32@5174 1a8010ca-5511-0410-912e-c29ae57300e0
3088 lines
113 KiB
C
3088 lines
113 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 "kplib.h"
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "pragmas.h"
|
|
|
|
#if !defined(_WIN32)
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
typedef long long __int64;
|
|
static __inline int32_t _lrotl(int32_t i, int sh)
|
|
{ return((i>>(-sh))|(i<<sh)); }
|
|
/*__inline*/ int32_t filelength(int h)
|
|
{
|
|
struct stat st;
|
|
if (fstat(h,&st) < 0) return(-1);
|
|
return(st.st_size);
|
|
}
|
|
#define _fileno fileno
|
|
#else
|
|
#include <io.h>
|
|
#include <intrin.h>
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0
|
|
#endif
|
|
#if !defined(max)
|
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
|
#endif
|
|
#if !defined(min)
|
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
#if defined(__GNUC__)
|
|
#undef _inline
|
|
#define _inline inline
|
|
#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 frameplace;
|
|
static int32_t bytesperline, xres, yres;
|
|
|
|
static 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 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 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], *nfilptr;
|
|
static int32_t nbitpos;
|
|
static void suckbitsnextblock()
|
|
{
|
|
if (zipfilmode)
|
|
{
|
|
//NOTE: should only read bytes inside compsize, not 64K!!! :/
|
|
int32_t n;
|
|
B_BUF32(&olinbuf[0], B_UNBUF32(&olinbuf[sizeof(olinbuf)-4]));
|
|
n = min((unsigned) (kzfs.compleng-kzfs.comptell), sizeof(olinbuf)-4);
|
|
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 = (uint8_t *)&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, 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(int32_t *hitab, 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(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 = (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*bytesperline + (i<<2) + frameplace;
|
|
|
|
//Precalculate x-clipping to screen borders (speeds up putbuf)
|
|
//Equation: (0 <= xr <= ixsiz) && (0 <= xr*ixstp+globxoffs+ixoff <= xres)
|
|
xr0 = max((-ixoff+(1<<j)-1)>>j,0);
|
|
xr1 = min((xres-ixoff+(1<<j)-1)>>j,ixsiz);
|
|
xr0 = ixsiz-xr0;
|
|
xr1 = ixsiz-xr1;
|
|
|
|
if (kcoltype == 4) { xr0 = xr0*2; xr1 = xr1*2; }
|
|
else if (kcoltype == 2) { xr0 = xr0*3-2; xr1 = xr1*3-2; }
|
|
else if (kcoltype == 6) { xr0 = xr0*4-2; xr1 = xr1*4-2; }
|
|
else
|
|
{
|
|
switch (bitdepth)
|
|
{
|
|
case 1: xr0 += ((-ixsiz)&7)+7;
|
|
xr1 += ((-ixsiz)&7)+7; break;
|
|
case 2: xr0 = ((xr0+((-ixsiz)&3)+3)<<1);
|
|
xr1 = ((xr1+((-ixsiz)&3)+3)<<1); break;
|
|
case 4: xr0 = ((xr0+((-ixsiz)&1)+1)<<2);
|
|
xr1 = ((xr1+((-ixsiz)&1)+1)<<2); break;
|
|
}
|
|
}
|
|
ixstp <<= 2;
|
|
return(0);
|
|
}
|
|
|
|
#if defined(_MSC_VER) && !defined(NOASM)
|
|
|
|
static _inline int32_t Paeth686(int32_t a, int32_t b, int32_t c)
|
|
{
|
|
_asm
|
|
{
|
|
push ebx
|
|
push esi
|
|
push edi
|
|
mov eax, a
|
|
mov ebx, b
|
|
mov ecx, c
|
|
mov edx, ecx
|
|
sub edx, eax
|
|
sub edx, ebx
|
|
lea edx, abstab10[edx*4+2048]
|
|
mov esi, [ebx*4+edx]
|
|
mov edi, [ecx*4+edx]
|
|
cmp edi, esi
|
|
cmovge edi, esi
|
|
cmovge ecx, ebx
|
|
cmp edi, [eax*4+edx]
|
|
cmovl eax, ecx
|
|
pop edi
|
|
pop esi
|
|
pop ebx
|
|
}
|
|
}
|
|
|
|
static _inline void rgbhlineasm(int32_t c, int32_t d, int32_t t, int32_t b)
|
|
{
|
|
_asm
|
|
{
|
|
push ebx
|
|
push edi
|
|
|
|
mov ecx, c
|
|
mov edx, d
|
|
mov edi, t
|
|
mov ebx, b
|
|
sub ecx, edx
|
|
jle short endit
|
|
add edx, offset olinbuf
|
|
cmp dword ptr trnsrgb, 0
|
|
jz short begit2
|
|
begit:
|
|
mov eax, dword ptr [ecx+edx]
|
|
or eax, 0xff000000
|
|
cmp eax, dword ptr trnsrgb
|
|
jne short skipit
|
|
and eax, 0xffffff
|
|
skipit:
|
|
sub ecx, 3
|
|
mov [edi], eax
|
|
lea edi, [edi+ebx]
|
|
jnz short begit
|
|
jmp short endit
|
|
begit2:
|
|
mov eax, dword ptr [ecx+edx]
|
|
or eax, 0xff000000
|
|
sub ecx, 3
|
|
mov [edi], eax
|
|
lea edi, [edi+ebx]
|
|
jnz short begit2
|
|
endit:
|
|
pop edi
|
|
pop ebx
|
|
}
|
|
}
|
|
|
|
static _inline void pal8hlineasm(int32_t c, int32_t d, int32_t t, int32_t b)
|
|
{
|
|
_asm
|
|
{
|
|
mov ecx, c
|
|
mov edx, d
|
|
sub ecx, edx
|
|
jle short endit
|
|
|
|
push ebx
|
|
push edi
|
|
mov edi, t
|
|
mov ebx, b
|
|
add edx, offset olinbuf
|
|
begit:movzx eax, byte ptr [ecx+edx]
|
|
mov eax, dword ptr palcol[eax*4]
|
|
sub ecx, 1
|
|
mov [edi], eax
|
|
lea edi, [edi+ebx]
|
|
jnz short begit
|
|
pop edi
|
|
pop ebx
|
|
endit:
|
|
}
|
|
}
|
|
|
|
#elif defined(__GNUC__) && defined(__i386__) && !defined(NOASM)
|
|
|
|
static inline int32_t Paeth686(int32_t a, int32_t b, int32_t c)
|
|
{
|
|
__asm__ __volatile__(
|
|
"movl %%ecx, %%edx \n"
|
|
"subl %%eax, %%edx \n"
|
|
"subl %%ebx, %%edx \n"
|
|
"leal (abstab10+2048)(,%%edx,4), %%edx \n"
|
|
"movl (%%edx,%%ebx,4), %%esi \n"
|
|
"movl (%%edx,%%ecx,4), %%edi \n"
|
|
"cmpl %%esi, %%edi \n"
|
|
"cmovgel %%esi, %%edi \n"
|
|
"cmovgel %%ebx, %%ecx \n"
|
|
"cmpl (%%edx,%%eax,4), %%edi \n"
|
|
"cmovgel %%eax, %%ecx \n"
|
|
: "+c"(c) : "a"(a), "b"(b) : "edx","esi","edi","memory","cc"
|
|
);
|
|
return c;
|
|
}
|
|
|
|
//Note: "cmove eax,?" may be faster than "jne ?:and eax,?" but who cares
|
|
static inline void rgbhlineasm(int32_t c, int32_t d, int32_t t, int32_t b)
|
|
{
|
|
__asm__ __volatile__(
|
|
"subl %%edx, %%ecx \n"
|
|
"jle 3f \n"
|
|
"addl $olinbuf, %%edx \n"
|
|
"cmpl $0, trnsrgb(,1) \n"
|
|
"jz 2f \n"
|
|
"0: movl (%%ecx,%%edx,1), %%eax \n"
|
|
"orl $0xff000000, %%eax \n"
|
|
"cmpl trnsrgb(,1), %%eax \n"
|
|
"jne 1f \n"
|
|
"andl $0xffffff, %%eax \n"
|
|
"1: subl $3, %%ecx \n"
|
|
"movl %%eax, (%%edi) \n"
|
|
"leal (%%edi,%%ebx,1), %%edi \n"
|
|
"jnz 0b \n"
|
|
"jmp 3f \n"
|
|
"2: movl (%%ecx,%%edx,1), %%eax \n"
|
|
"orl $0xff000000, %%eax \n"
|
|
"subl $3, %%ecx \n"
|
|
"movl %%eax, (%%edi) \n"
|
|
"leal (%%edi,%%ebx,1), %%edi \n"
|
|
"jnz 2b \n"
|
|
"3: \n"
|
|
: "+c"(c), "+d"(d), "+D"(t) : "b"(b) : "eax","memory","cc"
|
|
);
|
|
}
|
|
|
|
static inline void pal8hlineasm(int32_t c, int32_t d, int32_t t, int32_t b)
|
|
{
|
|
__asm__ __volatile__(
|
|
"subl %%edx, %%ecx \n"
|
|
"jle 1f \n"
|
|
"addl $olinbuf, %%edx \n"
|
|
"0: movzbl (%%ecx,%%edx,1), %%eax \n"
|
|
"movl palcol(,%%eax,4), %%eax \n"
|
|
"subl $1, %%ecx \n"
|
|
"movl %%eax, (%%edi) \n"
|
|
"leal (%%edi,%%ebx,1), %%edi \n"
|
|
"jnz 0b \n"
|
|
"1: \n"
|
|
: "+c"(c), "+d"(d), "+D"(t) : "b"(b) : "eax","memory","cc"
|
|
);
|
|
}
|
|
|
|
#else
|
|
|
|
static inline int32_t Paeth686(int32_t const a, int32_t const b, int32_t c)
|
|
{
|
|
int32_t const * const ptr = &abstab10[(c - a) - (b - 512)];
|
|
int32_t const esi = *(ptr + b);
|
|
int32_t edi = *(ptr + c);
|
|
if (edi >= esi) edi = esi, c = b;
|
|
return (edi < *(ptr + a)) ? c : a;
|
|
}
|
|
|
|
static inline void rgbhlineasm(int32_t x, int32_t xr1, intptr_t p, int32_t ixstp)
|
|
{
|
|
int32_t i;
|
|
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)
|
|
{
|
|
i = (B_UNBUF32(&olinbuf[x]))|B_LITTLE32(0xff000000);
|
|
if (i == trnsrgb) i &= B_LITTLE32(0xffffff);
|
|
B_BUF32((void *) p, i);
|
|
}
|
|
}
|
|
|
|
static inline void pal8hlineasm(int32_t x, int32_t xr1, intptr_t p, int32_t ixstp)
|
|
{
|
|
for (; x>xr1; p+=ixstp,x--) B_BUF32((void *) p, palcol[olinbuf[x]]);
|
|
}
|
|
|
|
#endif
|
|
|
|
//Autodetect filter
|
|
// /f0: 0000000...
|
|
// /f1: 1111111...
|
|
// /f2: 2222222...
|
|
// /f3: 1333333...
|
|
// /f3: 3333333...
|
|
// /f4: 4444444...
|
|
// /f5: 0142321...
|
|
static int32_t filter1st, filterest;
|
|
static void putbuf(const uint8_t *buf, int32_t leng)
|
|
{
|
|
int32_t i, x;
|
|
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)
|
|
{
|
|
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)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 daframeplace, int32_t dabytesperline, 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 *)&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?
|
|
|
|
frameplace = daframeplace;
|
|
bytesperline = dabytesperline;
|
|
xres = daxres;
|
|
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 >= 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 >= yres) && (intlac < 2)) goto kpngrend_goodret;
|
|
}
|
|
|
|
k = peekbits(LOGQHUFSIZ0);
|
|
if (qhufbit0[k]) { i = qhufval0[k]; suckbits((int32_t)qhufbit0[k]); }
|
|
else i = hufgetsym(ibuf0,nbuf0);
|
|
//else i = hufgetsym_skipb(ibuf0,nbuf0,LOGQHUFSIZ0,qhuf0v); //hufgetsym_skipb related code
|
|
|
|
if (i < 256) { slidebuf[(slidew++)&32767] = (uint8_t)i; continue; }
|
|
if (i == 256) break;
|
|
i = getbits(hxbit[i+30-257][0]) + hxbit[i+30-257][1];
|
|
|
|
k = peekbits(LOGQHUFSIZ1);
|
|
if (qhufbit1[k]) { j = qhufval1[k]; suckbits((int32_t)qhufbit1[k]); }
|
|
else j = hufgetsym(ibuf1,nbuf1);
|
|
//else j = hufgetsym_skipb(ibuf1,nbuf1,LOGQHUFSIZ1,qhuf1v); //hufgetsym_skipb related code
|
|
|
|
j = getbits(hxbit[j][0]) + hxbit[j][1];
|
|
i += slidew; do { slidebuf[slidew&32767] = slidebuf[(slidew-j)&32767]; slidew++; }
|
|
while (slidew < i);
|
|
}
|
|
}
|
|
while (!bfinal);
|
|
|
|
slider -= 16384;
|
|
if (!((slider^slidew)&32768))
|
|
putbuf(&slidebuf[slider&32767],slidew-slider);
|
|
else
|
|
{
|
|
putbuf(&slidebuf[slider&32767],(-slider)&32767);
|
|
putbuf(slidebuf,slidew&32767);
|
|
}
|
|
|
|
kpngrend_goodret:
|
|
if (!(filterest&~(1<<filter1st))) filtype = (int8_t)filter1st;
|
|
else if ((filter1st == 1) && (!(filterest&~(1<<3)))) filtype = 3;
|
|
else filtype = 5;
|
|
if (kcoltype == 4) paleng = 0; //For /c4, palcol/paleng used as LUT for "*0x10101": alpha is invalid!
|
|
return(0);
|
|
}
|
|
|
|
//============================= KPNGILIB ends ================================
|
|
//============================ KPEGILIB begins ===============================
|
|
|
|
//11/01/2000: This code was originally from KPEG.C
|
|
// All non 32-bit color drawing was removed
|
|
// "Motion" JPG code was removed
|
|
// A lot of parameters were added to kpeg() for library usage
|
|
static int32_t kpeginited = 0;
|
|
static int32_t clipxdim, clipydim;
|
|
|
|
static int32_t hufmaxatbit[8][20], hufvalatbit[8][20], hufcnt[8];
|
|
static uint8_t hufnumatbit[8][20], huftable[8][256];
|
|
static int32_t hufquickval[8][1024], hufquickbits[8][1024], hufquickcnt[8];
|
|
static int32_t quantab[4][64], dct[12][64], lastdc[4], unzig[64], zigit[64]; //dct:10=MAX (says spec);+2 for hacks
|
|
static uint8_t gnumcomponents, dcflagor[64];
|
|
static int32_t gcompid[4], gcomphsamp[4], gcompvsamp[4], gcompquantab[4], gcomphsampshift[4], gcompvsampshift[4];
|
|
static int32_t lnumcomponents, lcompid[4], lcompdc[4], lcompac[4], lcomphsamp[4], lcompvsamp[4], lcompquantab[4];
|
|
static int32_t lcomphvsamp0, lcomphsampshift0, lcompvsampshift0;
|
|
static int32_t colclip[1024], colclipup8[1024], colclipup16[1024];
|
|
/*static uint8_t pow2char[8] = {1,2,4,8,16,32,64,128};*/
|
|
|
|
#if defined(_MSC_VER) && !defined(NOASM)
|
|
|
|
static _inline int32_t mulshr24(int32_t a, int32_t d)
|
|
{
|
|
_asm
|
|
{
|
|
mov eax, a
|
|
imul d
|
|
shrd eax, edx, 24
|
|
}
|
|
}
|
|
|
|
static _inline int32_t mulshr32(int32_t a, int32_t d)
|
|
{
|
|
_asm
|
|
{
|
|
mov eax, a
|
|
imul d
|
|
mov eax, edx
|
|
}
|
|
}
|
|
|
|
#elif defined(__GNUC__) && defined(__i386__) && !defined(NOASM)
|
|
|
|
#define mulshr24(a,d) \
|
|
({ int32_t __a=(a), __d=(d); \
|
|
__asm__ __volatile__ ("imull %%edx; shrdl $24, %%edx, %%eax" \
|
|
: "+a" (__a), "+d" (__d) : : "cc"); \
|
|
__a; })
|
|
|
|
#define mulshr32(a,d) \
|
|
({ int32_t __a=(a), __d=(d); \
|
|
__asm__ __volatile__ ("imull %%edx" \
|
|
: "+a" (__a), "+d" (__d) : : "cc"); \
|
|
__d; })
|
|
|
|
#else
|
|
|
|
static inline int32_t mulshr24(int32_t a, int32_t b)
|
|
{
|
|
return((int32_t)((((__int64)a)*((__int64)b))>>24));
|
|
}
|
|
|
|
static inline int32_t mulshr32(int32_t a, int32_t b)
|
|
{
|
|
return((int32_t)((((__int64)a)*((__int64)b))>>32));
|
|
}
|
|
|
|
#endif
|
|
|
|
static int32_t cosqr16[8] = //cosqr16[i] = ((cos(PI*i/16)*sqrt(2))<<24);
|
|
{23726566,23270667,21920489,19727919,16777216,13181774,9079764,4628823};
|
|
static int32_t crmul[4096], cbmul[4096];
|
|
|
|
static void initkpeg()
|
|
{
|
|
int32_t i, j, x, y;
|
|
|
|
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*bytesperline + ((x)<<2) + 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 += 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 += 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 += 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 daframeplace, int32_t dabytesperline, 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 *)kfilebuf;
|
|
kfileend = &kfileptr[kfilength];
|
|
|
|
if (B_UNBUF16(kfileptr) == B_LITTLE16(0xd8ff)) kfileptr += 2;
|
|
else return(-1); //"%s is not a JPEG file\n",filename
|
|
|
|
restartinterval = 0;
|
|
for (i=0; i<4; i++) lastdc[i] = 0;
|
|
for (i=0; i<8; i++) hufcnt[i] = 0;
|
|
|
|
kcoltype = 0; bitdepth = 8; //For PNGOUT
|
|
do
|
|
{
|
|
ch = *kfileptr++; if (ch != 255) continue;
|
|
do { marker = *kfileptr++; }
|
|
while (marker == 255);
|
|
if (marker != 0xd9) //Don't read past end of buffer
|
|
{
|
|
leng = ((intptr_t)kfileptr[0]<<8)+(intptr_t)kfileptr[1]-2;
|
|
kfileptr += 2;
|
|
}
|
|
//printf("fileoffs=%08x, marker=%02x,leng=%d",((int32_t)kfileptr)-((int32_t)kfilebuf)-2,marker,leng);
|
|
switch (marker)
|
|
{
|
|
case 0xc0: case 0xc1: case 0xc2:
|
|
//processit!
|
|
kfileptr++; //numbits = *kfileptr++;
|
|
|
|
ydim = B_BIG16(B_UNBUF16(&kfileptr[0]));
|
|
xdim = B_BIG16(B_UNBUF16(&kfileptr[2]));
|
|
//printf("%s: %ld / %ld = %ld\n",filename,xdim*ydim*3,kfilength,(xdim*ydim*3)/kfilength);
|
|
|
|
frameplace = daframeplace;
|
|
bytesperline = dabytesperline;
|
|
xres = daxres;
|
|
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 *)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 *)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)) { if (dctbuf) Bfree(dctbuf); return(-1); }
|
|
|
|
lnumcomponents = (int32_t)(*kfileptr++); if (!lnumcomponents) { if (dctbuf) Bfree(dctbuf); return(-1); }
|
|
if (lnumcomponents > 1) kcoltype = 2;
|
|
for (z=0; z<lnumcomponents; z++)
|
|
{
|
|
lcompid[z] = kfileptr[0];
|
|
lcompdc[z] = (kfileptr[1]>>4);
|
|
lcompac[z] = (kfileptr[1]&15);
|
|
kfileptr += 2;
|
|
}
|
|
|
|
Ss = kfileptr[0];
|
|
Se = kfileptr[1];
|
|
Ah = (kfileptr[2]>>4);
|
|
Al = (kfileptr[2]&15);
|
|
kfileptr += 3;
|
|
//printf("passcnt=%d, Ss=%d, Se=%d, Ah=%d, Al=%d\n",passcnt,Ss,Se,Ah,Al);
|
|
|
|
if ((!passcnt) && ((Ss) || (Se != 63) || (Ah) || (Al)))
|
|
{
|
|
for (z=zz=0; z<gnumcomponents; z++)
|
|
{
|
|
dctx[z] = ((xdim+(ghsampmax<<3)-1)>>(glhsampmax+3)) << gcomphsampshift[z];
|
|
dcty[z] = ((ydim+(gvsampmax<<3)-1)>>(glvsampmax+3)) << gcompvsampshift[z];
|
|
zz += dctx[z]*dcty[z];
|
|
}
|
|
z = zz*64*sizeof(int16_t);
|
|
dctbuf = (int16_t *)Bmalloc(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,xres);
|
|
clipydim = min(ydim,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 *)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 *)kfilebuf < kfilength);
|
|
|
|
if (!dctbuf) return(0);
|
|
|
|
lnumcomponents = gnumcomponents;
|
|
for (i=0; i<gnumcomponents; i++)
|
|
{
|
|
lcomphsamp[i] = gcomphsamp[i]; gcomphsamp[i] <<= 3;
|
|
lcompvsamp[i] = gcompvsamp[i]; gcompvsamp[i] <<= 3;
|
|
lshx[i] = glhsampmax-gcomphsampshift[i]+3;
|
|
lshy[i] = glvsampmax-gcompvsampshift[i]+3;
|
|
}
|
|
lcomphsampshift0 = gcomphsampshift[0];
|
|
lcompvsampshift0 = gcompvsampshift[0];
|
|
lcomphvsamp0 = (lcomphsamp[0]<<lcompvsampshift0);
|
|
for (y=0; y<ydim; y+=gcompvsamp[0])
|
|
for (x=0; x<xdim; x+=gcomphsamp[0])
|
|
{
|
|
dc = dct[0];
|
|
for (c=0; c<gnumcomponents; c++)
|
|
for (yy=0; yy<gcompvsamp[c]; yy+=8)
|
|
for (xx=0; xx<gcomphsamp[c]; xx+=8,dc+=64)
|
|
{
|
|
dcs = &dctptr[c][(((y+yy)>>lshy[c])*dctx[c] + ((x+xx)>>lshx[c]))<<6];
|
|
quanptr = &quantab[gcompquantab[c]][0];
|
|
for (z=0; z<64; z++) dc[z] = ((int32_t)dcs[zigit[z]])*quanptr[z];
|
|
invdct8x8(dc,0xff);
|
|
}
|
|
kplib_yrbrend_func(x,y,&dct[0][0]);
|
|
}
|
|
|
|
Bfree(dctbuf); return(0);
|
|
}
|
|
|
|
//============================== KPEGILIB ends ==============================
|
|
//================================ GIF begins ================================
|
|
|
|
static uint8_t suffix[4100], filbuffer[768], tempstack[4096];
|
|
static int32_t prefix[4100];
|
|
|
|
static int32_t kgifrend(const char *kfilebuf, int32_t kfilelength,
|
|
intptr_t daframeplace, int32_t dabytesperline, 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 *)&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*dabytesperline+daframeplace; 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*dabytesperline+daframeplace; 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 daframeplace, int32_t dabytesperline, 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*dabytesperline+x*4+daframeplace, palcol[cptr[0]]);
|
|
cptr++;
|
|
}
|
|
return(0);
|
|
}
|
|
#endif
|
|
|
|
//=============================== CEL ends ==================================
|
|
//============================= TARGA begins ================================
|
|
|
|
static int32_t ktgarend(const char *header, int32_t fleng,
|
|
intptr_t daframeplace, int32_t dabytesperline, 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 *)&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 = dabytesperline; }
|
|
else { y0 = ysiz-1; y1 = -1; yi =-1; pi =-dabytesperline; }
|
|
if (header[2] < 8) rlestat = -2; else rlestat = -1;
|
|
|
|
p = y0*dabytesperline+daframeplace;
|
|
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 daframeplace, int32_t dabytesperline, 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 ((x0 >= daxres) || (x1 <= 0) || (y0 >= dayres) || (y1 <= 0)) return(0);
|
|
if (x0 < 0) x0 = 0;
|
|
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*dabytesperline+daframeplace);
|
|
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] = (_lrotl(i,palcol[0])&palcol[3]) +
|
|
(_lrotl(i,palcol[1])&palcol[4]) +
|
|
(_lrotl(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] = (_lrotl(i,palcol[0])&palcol[3]) +
|
|
(_lrotl(i,palcol[1])&palcol[4]) +
|
|
(_lrotl(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 daframeplace, int32_t dabytesperline, 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, *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 *)&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*dabytesperline + daframeplace+3;
|
|
for (y=y0; y<y1; y++,i+=dabytesperline)
|
|
for (x=x0; x<x1; x++) *(char *)((x<<2)+i) = 255;
|
|
}
|
|
|
|
x = x0 = 0; x1 = xsiz;
|
|
y = y0 = 0; y1 = ysiz;
|
|
cptr = (uint8_t *)&buf[128];
|
|
p = y*dabytesperline+daframeplace;
|
|
|
|
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 += dabytesperline; }
|
|
}
|
|
}
|
|
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 += dabytesperline; } 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 *lptr;
|
|
const uint8_t *cptr;
|
|
const uint8_t *ubuf = (uint8_t *)buf;
|
|
|
|
(*xsiz) = (*ysiz) = 0; if (leng < 16) return;
|
|
if (B_UNBUF16(&ubuf[0]) == B_LITTLE16(0x5089)) //.PNG
|
|
{
|
|
lptr = (int32_t *)buf;
|
|
if ((lptr[0] != (int32_t)B_LITTLE32(0x474e5089)) || (lptr[1] != (int32_t)B_LITTLE32(0x0a1a0a0d))) return;
|
|
lptr = &lptr[2];
|
|
while (((uintptr_t)lptr-(uintptr_t)buf) < (uintptr_t)(leng-16))
|
|
{
|
|
if (lptr[1] == (int32_t)B_LITTLE32(0x52444849)) //IHDR
|
|
{(*xsiz) = B_BIG32(lptr[2]); (*ysiz) = B_BIG32(lptr[3]); break; }
|
|
lptr = (int32_t *)((intptr_t)lptr + B_BIG32(lptr[0]) + 12);
|
|
}
|
|
}
|
|
else if (B_UNBUF16(&ubuf[0]) == B_LITTLE16(0xd8ff)) //.JPG
|
|
{
|
|
cptr = (uint8_t *)&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 *ubuf = (uint8_t *)buf;
|
|
|
|
paleng = 0; bakcol = 0; numhufblocks = zlibcompflags = 0; filtype = -1;
|
|
|
|
if (B_UNBUF16(&ubuf[0]) == B_LITTLE16(0x5089)) //.PNG
|
|
return(kpngrend(buf,leng,frameptr,bpl,xdim,ydim));
|
|
else if (B_UNBUF16(&ubuf[0]) == B_LITTLE16(0xd8ff)) //.JPG
|
|
return(kpegrend(buf,leng,frameptr,bpl,xdim,ydim));
|
|
else
|
|
{
|
|
if ((ubuf[0] == 'G') && (ubuf[1] == 'I') && (ubuf[2] == 'F')) //.GIF
|
|
return(kgifrend(buf, leng, frameptr, bpl, xdim, ydim));
|
|
else if ((ubuf[0] == 'B') && (ubuf[1] == 'M')) //.BMP
|
|
return(kbmprend(buf, leng, frameptr, bpl, xdim, ydim));
|
|
else if (B_UNBUF32(ubuf) == B_LITTLE32(0x0801050a)) //.PCX
|
|
return(kpcxrend(buf, leng, frameptr, bpl, xdim, ydim));
|
|
#ifdef KPCEL
|
|
else if ((ubuf[0] == 0x19) && (ubuf[1] == 0x91) && (ubuf[10] == 8) && (ubuf[11] == 0)) //old .CEL/.PIC
|
|
return(kcelrend(buf, leng, frameptr, bpl, xdim, ydim, xoff, yoff));
|
|
#endif
|
|
#ifdef KPDDS
|
|
else if ((B_UNBUF32(ubuf) == B_LITTLE32(0x20534444)) && (B_UNBUF32(&ubuf[4]) == B_LITTLE32(124))) //.DDS
|
|
return(kddsrend(buf, leng, frameptr, bpl, xdim, ydim, xoff, yoff));
|
|
#endif
|
|
//Unreliable .TGA identification - this MUST be final case!
|
|
else if (istarga(ubuf, leng))
|
|
return(ktgarend(buf, leng, frameptr, bpl, xdim, ydim));
|
|
else return -1;
|
|
}
|
|
}
|
|
|
|
//==================== External picture interface ends =======================
|
|
|
|
//Brute-force case-insensitive, slash-insensitive, * and ? wildcard matcher
|
|
//Given: string i and string j. string j can have wildcards
|
|
//Returns: 1:matches, 0:doesn't match
|
|
|
|
extern char toupperlookup[256];
|
|
|
|
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)
|
|
{
|
|
int32_t i;
|
|
|
|
if (!kzhashbuf) //Initialize hash table on first call
|
|
{
|
|
Bmemset(kzhashead,-1,sizeof(kzhashead));
|
|
kzhashbuf = (char *)Bmalloc(KZHASHINITSIZE); if (!kzhashbuf) return(0);
|
|
kzhashpos = 0; kzlastfnam = -1; kzhashsiz = KZHASHINITSIZE; kzdirnamhead = -1;
|
|
}
|
|
if (kzhashpos+siz > kzhashsiz) //Make sure string fits in kzhashbuf
|
|
{
|
|
i = kzhashsiz; do { i <<= 1; }
|
|
while (kzhashpos+siz > i);
|
|
kzhashbuf = (char *)Brealloc(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()
|
|
{
|
|
if (kzhashbuf) { Bfree(kzhashbuf); kzhashbuf = 0; }
|
|
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)
|
|
{
|
|
FILE *fil;
|
|
int32_t i, j, k, leng, hashind, zipnamoffs, numfiles;
|
|
char tempbuf[260+46];
|
|
|
|
fil = fopen(filnam,"rb");
|
|
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)) { fclose(fil); return(-1); }
|
|
strcpy(&kzhashbuf[kzhashpos],filnam);
|
|
zipnamoffs = kzhashpos; kzhashpos += i;
|
|
|
|
fread(&i,4,1,fil);
|
|
if (i == (int32_t)B_LITTLE32(0x04034b50)) //'PK\3\4' is ZIP file id
|
|
{
|
|
fseek(fil,-22,SEEK_END);
|
|
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]));
|
|
fseek(fil,B_LITTLE32(B_UNBUF32(&tempbuf[16])),SEEK_SET);
|
|
}
|
|
else //Slow way of finding dir info (used when ZIP has junk at end)
|
|
{
|
|
fseek(fil,0,SEEK_SET); numfiles = 0;
|
|
while (1)
|
|
{
|
|
if (!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; }
|
|
fread(tempbuf,26,1,fil);
|
|
fseek(fil,B_LITTLE32(B_UNBUF32(&tempbuf[14])) + B_LITTLE16(B_UNBUF16(&tempbuf[24])) + B_LITTLE16(B_UNBUF16(&tempbuf[22])),SEEK_CUR);
|
|
numfiles++;
|
|
}
|
|
if (numfiles < 0) { fclose(fil); return(-1); }
|
|
fseek(fil,-4,SEEK_CUR);
|
|
}
|
|
for (i=0; i<numfiles; i++)
|
|
{
|
|
fread(tempbuf,46,1,fil);
|
|
if (B_UNBUF32(&tempbuf[0]) != B_LITTLE32(0x02014b50)) { fclose(fil); return(0); }
|
|
|
|
j = B_LITTLE16(B_UNBUF16(&tempbuf[28])); //filename length
|
|
fread(&tempbuf[46],j,1,fil);
|
|
tempbuf[j+46] = 0;
|
|
|
|
//Write information into hash
|
|
j = strlen(&tempbuf[46])+22; if (!kzcheckhashsiz(j)) { 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
|
|
fseek(fil,j,SEEK_CUR);
|
|
}
|
|
}
|
|
else if (i == (int32_t)B_LITTLE32(0x536e654b)) //'KenS' is GRP file id
|
|
{
|
|
fread(tempbuf,12,1,fil);
|
|
if ((B_UNBUF32(&tempbuf[0]) != B_LITTLE32(0x65766c69)) || //'ilve'
|
|
(B_UNBUF32(&tempbuf[4]) != B_LITTLE32(0x6e616d72))) //'rman'
|
|
{ fclose(fil); return(0); }
|
|
numfiles = B_LITTLE32(B_UNBUF32(&tempbuf[8])); k = ((numfiles+1)<<4);
|
|
for (i=0; i<numfiles; i++,k+=leng)
|
|
{
|
|
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)) { 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;
|
|
}
|
|
}
|
|
fclose(fil);
|
|
return(0);
|
|
}
|
|
|
|
//this allows the use of kplib.c with a file that is already open
|
|
void kzsetfil(FILE *fil)
|
|
{
|
|
kzfs.fil = fil;
|
|
kzfs.comptyp = 0;
|
|
kzfs.seek0 = 0;
|
|
kzfs.leng = filelength(_fileno(kzfs.fil));
|
|
kzfs.pos = 0;
|
|
kzfs.i = 0;
|
|
}
|
|
|
|
intptr_t kzopen(const char *filnam)
|
|
{
|
|
FILE *fil;
|
|
int32_t i, j, fileoffs, fileleng;
|
|
char tempbuf[46+260], *zipnam, iscomp;
|
|
|
|
//kzfs.fil = 0;
|
|
if (filnam[0] != '|') //Search standalone file first
|
|
{
|
|
kzfs.fil = fopen(filnam,"rb");
|
|
if (kzfs.fil)
|
|
{
|
|
kzfs.comptyp = 0;
|
|
kzfs.seek0 = 0;
|
|
kzfs.leng = filelength(_fileno(kzfs.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 = fopen(zipnam,"rb"); if (!fil) return(0);
|
|
fseek(fil,fileoffs,SEEK_SET);
|
|
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
|
|
{
|
|
fread(tempbuf,30,1,fil);
|
|
if (B_UNBUF32(&tempbuf[0]) != B_LITTLE32(0x04034b50)) { fclose(fil); return(0); }
|
|
fseek(fil,B_LITTLE16(B_UNBUF16(&tempbuf[26]))+B_LITTLE16(B_UNBUF16(&tempbuf[28])),SEEK_CUR);
|
|
|
|
kzfs.fil = fil;
|
|
kzfs.comptyp = B_LITTLE16(B_UNBUF16(&tempbuf[8]));
|
|
kzfs.seek0 = 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: fclose(kzfs.fil); kzfs.fil = 0; return(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Finally, check mounted dirs
|
|
for (i=kzdirnamhead; i>=0; i=B_UNBUF32(&kzhashbuf[i]))
|
|
{
|
|
strcpy(tempbuf,&kzhashbuf[i+4]);
|
|
j = strlen(tempbuf);
|
|
if (strlen(filnam)+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 = fopen(tempbuf,"rb");
|
|
if (kzfs.fil)
|
|
{
|
|
kzfs.comptyp = 0;
|
|
kzfs.seek0 = 0;
|
|
kzfs.leng = filelength(_fileno(kzfs.fil));
|
|
kzfs.pos = 0;
|
|
kzfs.i = 0;
|
|
return((intptr_t)kzfs.fil);
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
#if defined(_WIN32)
|
|
static HANDLE hfind = INVALID_HANDLE_VALUE;
|
|
static WIN32_FIND_DATA findata;
|
|
#else
|
|
#define MAX_PATH 260
|
|
static DIR *hfind = NULL;
|
|
static struct dirent *findata = NULL;
|
|
#endif
|
|
|
|
//File find state variables. Example sequence (read top->bot, left->right):
|
|
// srchstat srchzoff srchdoff
|
|
// 0,1,2,3
|
|
// 500,200,-1
|
|
// 4 300
|
|
// 0,1,2,3,4 100
|
|
// 0,1,2,3,4 -1
|
|
static int32_t srchstat = -1, srchzoff = 0, srchdoff = -1, wildstpathleng;
|
|
static char wildst[MAX_PATH] = "", newildst[MAX_PATH] = "";
|
|
|
|
void kzfindfilestart(const char *st)
|
|
{
|
|
#if defined(_WIN32)
|
|
if (hfind != INVALID_HANDLE_VALUE)
|
|
{ FindClose(hfind); hfind = INVALID_HANDLE_VALUE; }
|
|
#else
|
|
if (hfind) { closedir(hfind); hfind = NULL; }
|
|
#endif
|
|
strcpy(wildst,st); strcpy(newildst,st);
|
|
srchstat = 0; srchzoff = kzlastfnam; srchdoff = kzdirnamhead;
|
|
}
|
|
|
|
int32_t kzfindfile(char *filnam)
|
|
{
|
|
int32_t i;
|
|
|
|
kzfindfile_beg:;
|
|
filnam[0] = 0;
|
|
if (srchstat == 0)
|
|
{
|
|
if (!newildst[0]) { srchstat = -1; return(0); }
|
|
do
|
|
{
|
|
srchstat = 1;
|
|
|
|
//Extract directory from wildcard string for pre-pending
|
|
wildstpathleng = 0;
|
|
for (i=0; newildst[i]; i++)
|
|
if ((newildst[i] == '/') || (newildst[i] == '\\'))
|
|
wildstpathleng = i+1;
|
|
|
|
Bmemcpy(filnam,newildst,wildstpathleng);
|
|
|
|
#if defined(_WIN32)
|
|
hfind = FindFirstFile(newildst,&findata);
|
|
if (hfind == INVALID_HANDLE_VALUE)
|
|
{ if (!kzhashbuf) return(0); srchstat = 2; continue; }
|
|
if (findata.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) continue;
|
|
i = wildstpathleng;
|
|
if (findata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
|
|
if ((findata.cFileName[0] == '.') && (!findata.cFileName[1])) continue;
|
|
strcpy(&filnam[i],findata.cFileName);
|
|
if (findata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) strcat(&filnam[i],"\\");
|
|
#else
|
|
if (!hfind)
|
|
{
|
|
char *s = ".";
|
|
if (wildstpathleng > 0)
|
|
{
|
|
filnam[wildstpathleng] = 0;
|
|
s = filnam;
|
|
}
|
|
hfind = opendir(s);
|
|
if (!hfind) { if (!kzhashbuf) return 0; srchstat = 2; continue; }
|
|
}
|
|
break; // process srchstat == 1
|
|
#endif
|
|
return(1);
|
|
}
|
|
while (0);
|
|
}
|
|
if (srchstat == 1)
|
|
{
|
|
while (1)
|
|
{
|
|
Bmemcpy(filnam,newildst,wildstpathleng);
|
|
#if defined(_WIN32)
|
|
if (!FindNextFile(hfind,&findata))
|
|
{ FindClose(hfind); hfind = INVALID_HANDLE_VALUE; if (!kzhashbuf) return(0); srchstat = 2; break; }
|
|
if (findata.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) continue;
|
|
i = wildstpathleng;
|
|
if (findata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
|
|
if ((findata.cFileName[0] == '.') && (!findata.cFileName[1])) continue;
|
|
strcpy(&filnam[i],findata.cFileName);
|
|
if (findata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) strcat(&filnam[i],"\\");
|
|
#else
|
|
if ((findata = readdir(hfind)) == NULL)
|
|
{ closedir(hfind); hfind = NULL; if (!kzhashbuf) return 0; srchstat = 2; break; }
|
|
i = wildstpathleng;
|
|
if (findata->d_type == DT_DIR)
|
|
{ if (findata->d_name[0] == '.' && !findata->d_name[1]) continue; } //skip .
|
|
else if ((findata->d_type == DT_REG) || (findata->d_type == DT_LNK))
|
|
{ if (findata->d_name[0] == '.') continue; } //skip hidden (dot) files
|
|
else continue; //skip devices and fifos and such
|
|
if (!wildmatch(findata->d_name,&newildst[wildstpathleng])) continue;
|
|
strcpy(&filnam[i],findata->d_name);
|
|
if (findata->d_type == DT_DIR) strcat(&filnam[i],"/");
|
|
#endif
|
|
return(1);
|
|
}
|
|
}
|
|
while (srchstat == 2)
|
|
{
|
|
if (srchzoff < 0) { srchstat = 3; break; }
|
|
if (wildmatch(&kzhashbuf[srchzoff+21],newildst))
|
|
{
|
|
//strcpy(filnam,&kzhashbuf[srchzoff+21]);
|
|
filnam[0] = '|'; strcpy(&filnam[1],&kzhashbuf[srchzoff+21]);
|
|
srchzoff = B_UNBUF32(&kzhashbuf[srchzoff+4]);
|
|
return(1);
|
|
}
|
|
srchzoff = B_UNBUF32(&kzhashbuf[srchzoff+4]);
|
|
}
|
|
while (srchstat == 3)
|
|
{
|
|
if (srchdoff < 0) { srchstat = -1; break; }
|
|
strcpy(newildst,&kzhashbuf[srchdoff+4]);
|
|
i = strlen(newildst);
|
|
if ((i) && (newildst[i-1] != '/') && (newildst[i-1] != '\\') && (filnam[0] != '/') && (filnam[0] != '\\'))
|
|
#if defined(_WIN32)
|
|
strcat(newildst,"\\");
|
|
#else
|
|
strcat(newildst,"/");
|
|
#endif
|
|
strcat(newildst,wildst);
|
|
srchdoff = B_UNBUF32(&kzhashbuf[srchdoff]);
|
|
srchstat = 0; goto kzfindfile_beg;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
//File searching code (supports inside ZIP files!) How to use this code:
|
|
// char filnam[MAX_PATH];
|
|
// kzfindfilestart("vxl/*.vxl");
|
|
// while (kzfindfile(filnam)) puts(filnam);
|
|
//NOTES:
|
|
// * Directory names end with '\' or '/' (depending on system)
|
|
// * Files inside zip begin with '|'
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
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
|
|
{ fseek(kzfs.fil,kzfs.seek0+kzfs.pos,SEEK_SET); kzfs.i = kzfs.pos; }
|
|
i = min(kzfs.leng-kzfs.pos,leng);
|
|
fread(buffer,i,1,kzfs.fil);
|
|
kzfs.i += i; //kzfs.i is a local copy of 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) fseek(kzfs.fil,kzfs.seek0,SEEK_SET);
|
|
|
|
gslidew = 0; gslider = 16384;
|
|
kzfs.jmpplc = 0;
|
|
|
|
//Initialize for suckbits/peekbits/getbits
|
|
kzfs.comptell = min((unsigned)kzfs.compleng,sizeof(olinbuf));
|
|
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 kpzload(const char *filnam, intptr_t *pic, int32_t *bpl, int32_t *xsiz, int32_t *ysiz)
|
|
{
|
|
int32_t leng;
|
|
int32_t handle = kopen4load((char *)filnam, 0);
|
|
|
|
(*pic) = 0;
|
|
if (handle < 0) return;
|
|
leng = kfilelength(handle);
|
|
|
|
if (leng+1 > kpzbufsiz)
|
|
{
|
|
kpzbuf = (char *) Xrealloc(kpzbuf, leng+1);
|
|
kpzbufsiz = leng+1;
|
|
if (!kpzbuf) { kclose(handle); return; }
|
|
}
|
|
kpzbuf[leng]=0; // FIXME: buf[leng] read in kpegrend(), see BUF_LENG_READ
|
|
kread(handle,kpzbuf,leng);
|
|
kclose(handle);
|
|
|
|
kpgetdim(kpzbuf,leng,xsiz,ysiz);
|
|
(*bpl) = ((*xsiz)<<2);
|
|
(*pic) = (intptr_t)Xmalloc((*ysiz)*(*bpl)); if (!(*pic)) { return; }
|
|
if (kprender(kpzbuf, leng, *pic, *bpl, *xsiz, *ysiz) < 0) { if (*pic) { Bfree((void *) *pic), *pic = 0; return; } }
|
|
}
|
|
//====================== HANDY PICTURE function ends =========================
|