Rev 4634 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/**************************************************************************************************
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>
#if defined(__POWERPC__) || defined(GEKKO)
#define BIGENDIAN 1
#endif
#ifdef BIGENDIAN
static uint32_t LSWAPIB
(uint32_t a
) { return(((a
>>8)&0xff00)+((a
&0xff00)<<8)+(a
<<24)+(a
>>24)); }
static uint16_t SSWAPIB
(uint16_t a
) { return((a
>>8)+(a
<<8)); }
#define LSWAPIL(a) (a)
#define SSWAPIL(a) (a)
#else
#define LSWAPIB(a) (a)
#define SSWAPIB(a) (a)
static uint32_t LSWAPIL
(uint32_t a
) { return(((a
>>8)&0xff00)+((a
&0xff00)<<8)+(a
<<24)+(a
>>24)); }
static uint16_t SSWAPIL
(uint16_t a
) { return((a
>>8)+(a
<<8)); }
#endif
#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>
#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 __clang__ && __clang_major__==3
// clang 3.1 SVN r149129, assertion failure with inline asm
# define NOASM 1
#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)
#if defined(BIGENDIAN)
static _inline
uint32_t bswap
(uint32_t a
)
{
_asm
{
mov eax
, a
bswap eax
}
}
#endif
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)
#if defined(BIGENDIAN)
static inline uint32_t bswap
(uint32_t a
)
{
__asm__ __volatile__
("bswap %0" : "+r"(a
) : : "cc");
return a
;
}
#endif
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
#if defined(BIGENDIAN)
static inline uint32_t bswap
(uint32_t a
)
{
return(((a
&0xff0000)>>8) + ((a
&0xff00)<<8) + (a
<<24) + (a
>>24));
}
#endif
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
;
*(int32_t *) &olinbuf
[0] = *(int32_t *) &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
= LSWAPIL
(*(int32_t *)&filptr
[8]);
nfilptr
= (uint8_t *)&filptr
[nbitpos
+12];
*(int32_t *)&fakebuf
[0] = *(int32_t *)&filptr
[0]; //Copy last dword of IDAT chunk
if (*(int32_t *)&filptr
[12] == (int32_t)LSWAPIB
(0x54414449)) //Copy 1st dword of next IDAT chunk
*(int32_t *)&fakebuf
[4] = *(int32_t *)&filptr
[16];
filptr
= &fakebuf
[4]; bitpos
-= 32;
}
static _inline
int32_t peekbits
(int32_t n
) { return((LSWAPIB
(*(int32_t *)&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]));
*(int32_t *)&opixbuf0
[0] = *(int32_t *)&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 a
, int32_t b
, int32_t c
)
{
const int32_t *ptr
= &abstab10
[(c
-a
)-(b
-512)];
const int32_t 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) *(int32_t *)p
= (*(int32_t *)&olinbuf
[x
])|LSWAPIB
(0xff000000);
return;
}
for (; x
>xr1
; p
+=ixstp
,x
-=3)
{
i
= (*(int32_t *)&olinbuf
[x
])|LSWAPIB
(0xff000000);
if (i
== trnsrgb
) i
&= LSWAPIB
(0xffffff);
*(int32_t *)p
= i
;
}
}
static inline void pal8hlineasm
(int32_t x
, int32_t xr1
, intptr_t p
, int32_t ixstp
)
{
for (; x
>xr1
; p
+=ixstp
,x
--) *(int32_t *)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
]; xplc
--; i
++; }
break;
case 1:
while (i
< x
)
{
olinbuf
[xplc
] = (uint8_t)(opixbuf1
[xm
] += buf
[i
]);
xm
= xmn
[xm
]; xplc
--; i
++;
}
break;
case 2:
while (i
< x
) { olinbuf
[xplc
] += (uint8_t)buf
[i
]; xplc
--; i
++; }
break;
case 3:
while (i
< x
)
{
opixbuf1
[xm
] = olinbuf
[xplc
] = (uint8_t)(((opixbuf1
[xm
]+olinbuf
[xplc
])>>1)+buf
[i
]);
xm
= xmn
[xm
]; xplc
--; i
++;
}
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
]; xplc
--; i
++;
}
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)
*(int32_t *)p
= (palcol
[olinbuf
[x
]]&LSWAPIB
(0xffffff))|LSWAPIL
((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
--) *(int32_t *)p
= palcol
[olinbuf
[x
>>3]>>(x
&7)]; break;
case 2: for (; x
>xr1
; p
+=ixstp
,x
-=2) *(int32_t *)p
= palcol
[olinbuf
[x
>>3]>>(x
&6)]; break;
case 4: for (; x
>xr1
; p
+=ixstp
,x
-=4) *(int32_t *)p
= palcol
[olinbuf
[x
>>3]>>(x
&4)]; break;
case 8: pal8hlineasm
(x
,xr1
,p
,ixstp
); break; //for(;x>xr1;p+=ixstp,x-- ) *(int32_t *)p = palcol[olinbuf[x]]; break;
}
break;
}
nfplace
+= nbpl
;
}
*(int32_t *)&opixbuf0
[0] = *(int32_t *)&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 ((*(int32_t *)&kfilebuf
[0] != (int32_t)LSWAPIB
(0x474e5089)) || (*(int32_t *)&kfilebuf
[4] != (int32_t)LSWAPIB
(0x0a1a0a0d)))
return(-1); //"Invalid PNG file signature"
filptr
= (uint8_t *)&kfilebuf
[8];
trnsrgb
= 0; filter1st
= -1; filterest
= 0;
while (1)
{
leng
= LSWAPIL
(*(int32_t *)&filptr
[0]); i
= *(int32_t *)&filptr
[4];
filptr
= &filptr
[8];
if (i
== (int32_t)LSWAPIB
(0x52444849)) //IHDR (must be first)
{
xsiz
= LSWAPIL
(*(int32_t *)&filptr
[0]); if (xsiz
<= 0) return(-1);
ysiz
= LSWAPIL
(*(int32_t *)&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
= (255 / ((1<<bitdepth
)-1))*0x10101;
paleng
= (1<<bitdepth
);
for (i
=0; i
<paleng
; i
++,j
+=k
) palcol
[i
] = LSWAPIB
(j
);
}
}
else if (i
== (int32_t)LSWAPIB
(0x45544c50)) //PLTE (must be before IDAT)
{
paleng
= leng
/3;
for (i
=paleng
-1; i
>=0; i
--) palcol
[i
] = LSWAPIB
((LSWAPIL
(*(int32_t *)&filptr
[i
*3])>>8)|0xff000000);
}
else if (i
== (int32_t)LSWAPIB
(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])*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
+= ((((((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
= LSWAPIB
(bakcol
);
}
else if (i
== (int32_t)LSWAPIB
(0x534e5274)) //tRNS (must be after PLTE and before IDAT)
{
switch (kcoltype
)
{
case 0:
if (bitdepth
<= 8)
palcol
[(int32_t)filptr
[1]] &= LSWAPIB
(0xffffff);
//else {} // /c0 /d16 not yet supported
break;
case 2:
if (bitdepth
== 8)
{ trnsrgb
= LSWAPIB
((((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
] &= LSWAPIB
((((int32_t)filptr
[i
])<<24)|0xffffff);
break;
default:;
}
}
else if (i
== (int32_t)LSWAPIB
(0x54414449)) { break; } //IDAT
filptr
= &filptr
[leng
+4]; //crc = LSWAPIL(*(int32_t *)&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 defined(BIGENDIAN)
for (i
=0; i
<1024; i
++)
{
colclip
[i
] = bswap
(colclip
[i
]);
colclipup8
[i
] = bswap
(colclipup8
[i
]);
colclipup16
[i
] = bswap
(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 (*(uint16_t *)kfileptr
== SSWAPIB
(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
= SSWAPIL
(*(uint16_t *)&kfileptr
[0]);
xdim
= SSWAPIL
(*(uint16_t *)&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
= SSWAPIL
(*(uint16_t *)&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
, backcol
, *lptr
;
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
= SSWAPIB
(*(uint16_t *)&ptr
[0]);
yoff
= SSWAPIB
(*(uint16_t *)&ptr
[2]);
xspan
= SSWAPIB
(*(uint16_t *)&ptr
[4]);
yspan
= SSWAPIB
(*(uint16_t *)&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
] = LSWAPIB
((((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
] = LSWAPIB
(0xff000000);
if (transcol
>= 0) palcol
[transcol
] &= LSWAPIB
(~
0xff000000);
//Handle GIF files with different logical&image sizes or non-0 offsets (added 05/15/2004)
xsiz
= SSWAPIB
(*(uint16_t *)&kfilebuf
[6]);
ysiz
= SSWAPIB
(*(uint16_t *)&kfilebuf
[8]);
if ((xoff
!= 0) || (yoff
!= 0) || (xsiz
!= xspan
) || (ysiz
!= yspan
))
{
int32_t xx
[4], yy
[4];
if (kfilebuf
[10]&128) backcol
= palcol
[(uint8_t)kfilebuf
[11]]; else backcol
= 0;
//Fill border to backcol
lptr
= (int32_t *)(yy
[0]*dabytesperline
+daframeplace
);
for (y
=yy
[0]; y
<yy
[1]; y
++,lptr
=(int32_t *)(((intptr_t)lptr
)+dabytesperline
))
for (x
=xx
[0]; x
<xx
[3]; x
++) lptr
[x
] = backcol
;
for (; y
<yy
[2]; y
++,lptr
=(int32_t *)(((intptr_t)lptr
)+dabytesperline
))
{
for (x
=xx
[0]; x
<xx
[1]; x
++) lptr
[x
] = backcol
;
for (x
=xx
[2]; x
<xx
[3]; x
++) lptr
[x
] = backcol
;
}
for (; y
<yy
[3]; y
++,lptr
=(int32_t *)(((intptr_t)lptr
)+dabytesperline
))
for (x
=xx
[0]; x
<xx
[3]; x
++) lptr
[x
] = backcol
;
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
= (LSWAPIB
(*(int32_t *)&filbuffer
[bitcnt
>>3])>>(bitcnt
&7)) & (numbitgoal
-1);
bitcnt
+= numbits
;
if ((bitcnt
>>3) > blocklen
-3)
{
*(int16_t *)filbuffer
= *(int16_t *)&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
)
*(int32_t *)(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)SSWAPIB
(*(uint16_t *)&buf
[2]); if (xsiz
<= 0) return(-1);
ysiz
= (int32_t)SSWAPIB
(*(uint16_t *)&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) + LSWAPIB
(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
))
*(int32_t *)(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)SSWAPIB
(*(uint16_t *)&header
[12]); if (xsiz
<= 0) return(-1);
ysiz
= (int32_t)SSWAPIB
(*(uint16_t *)&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
[-SSWAPIB
(*(uint16_t *)&header
[3])*pixbyte
];
fptr
+= SSWAPIB
(*(uint16_t *)&header
[5])*pixbyte
;
}
else pixbyte
= colbyte
;
switch (pixbyte
) //For PNGOUT
{
case 1: kcoltype
= 0; bitdepth
= 8; palcol
[0] = LSWAPIB
(0xff000000);
for (i
=1; i
<256; i
++) palcol
[i
] = palcol
[i
-1]+LSWAPIB
(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)SSWAPIB
(*(uint16_t *)&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)SSWAPIB
(*(uint16_t *)&nptr
[0]);
i
= LSWAPIB
(((i
&0x7c00)<<9) + ((i
&0x03e0)<<6) + ((i
&0x001f)<<3) + 0xff000000);
break;
case 3: i
= (*(int32_t *)&nptr
[0]) | LSWAPIB
(0xff000000); break;
case 4: i
= (*(int32_t *)&nptr
[0]); break;
}
fptr
+= colbyte
;
}
if (rlestat
>= 0) rlestat
--;
if (((uint32_t)x
< (uint32_t)daxres
) && ((uint32_t)y
< (uint32_t)dayres
))
*(int32_t *)(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
= *(int32_t *)&buf
[14];
if (headsiz
== (int32_t)LSWAPIB
(12)) //OS/2 1.x (old format)
{
if (*(int16_t *)(&buf
[22]) != SSWAPIB
(1)) return(-1);
xsiz
= (int32_t)SSWAPIB
(*(uint16_t *)&buf
[18]);
ysiz
= (int32_t)SSWAPIB
(*(uint16_t *)&buf
[20]);
cdim
= (int32_t)SSWAPIB
(*(uint16_t *)&buf
[24]);
comp
= 0;
}
else //All newer formats...
{
if (*(int16_t *)(&buf
[26]) != SSWAPIB
(1)) return(-1);
xsiz
= LSWAPIB
(*(int32_t *)&buf
[18]);
ysiz
= LSWAPIB
(*(int32_t *)&buf
[22]);
cdim
= (int32_t)SSWAPIB
(*(uint16_t *)&buf
[28]);
comp
= LSWAPIB
(*(int32_t *)&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
= LSWAPIB
(*(int32_t *)&buf
[10]);
if (cdim
< 16)
{
if (cdim
== 2) { palcol
[0] = 0xffffffff; palcol
[1] = LSWAPIB
(0xff000000); }
if (headsiz
== (int32_t)LSWAPIB
(12)) j
= 3; else j
= 4;
for (i
=0,cptr
=&buf
[headsiz
+14]; cptr
<&buf
[rastoff
]; i
++,cptr
+=j
)
palcol
[i
] = ((*(int32_t *)&cptr
[0])|LSWAPIB
(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
= *(int32_t *)&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)(*(int16_t *)&cptr
[x
<<1]));
lptr
[x
] = (_lrotl
(i
,palcol
[0])&palcol
[3]) +
(_lrotl
(i
,palcol
[1])&palcol
[4]) +
(_lrotl
(i
,palcol
[2])&palcol
[5]) + LSWAPIB
(0xff000000);
} break;
case 24: for (x
=x0
; x
<x1
; x
++) lptr
[x
] = ((*(int32_t *)&cptr
[x
*3])|LSWAPIB
(0xff000000)); break;
case 32: for (x
=x0
; x
<x1
; x
++)
{
i
= (*(int32_t *)&cptr
[x
<<2]);
lptr
[x
] = (_lrotl
(i
,palcol
[0])&palcol
[3]) +
(_lrotl
(i
,palcol
[1])&palcol
[4]) +
(_lrotl
(i
,palcol
[2])&palcol
[5]) + LSWAPIB
(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 (*(int32_t *)buf
!= (int32_t)LSWAPIB
(0x0801050a)) return(-1);
xsiz
= SSWAPIB
(*(int16_t *)&buf
[ 8])-SSWAPIB
(*(int16_t *)&buf
[4])+1; if (xsiz
<= 0) return(-1);
ysiz
= SSWAPIB
(*(int16_t *)&buf
[10])-SSWAPIB
(*(int16_t *)&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
= SSWAPIB
(*(int16_t *)&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])) + LSWAPIB
(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
) *(int32_t *)(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
= LSWAPIB
(*(int32_t *)&buf
[16]);
ysiz
= LSWAPIB
(*(int32_t *)&buf
[12]);
if ((*(int32_t *)&buf
[80])&LSWAPIB
(64)) //Uncompressed supports only A8R8G8B8 for now
{
if ((*(int32_t *)&buf
[88]) != LSWAPIB
(32)) return(-1);
if ((*(int32_t *)&buf
[92]) != LSWAPIB
(0x00ff0000)) return(-1);
if ((*(int32_t *)&buf
[96]) != LSWAPIB
(0x0000ff00)) return(-1);
if ((*(int32_t *)&buf
[100]) != LSWAPIB
(0x000000ff)) return(-1);
if ((*(uint32_t *)&buf
[104]) != LSWAPIB
(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 (!((*(int32_t *)&buf
[80])&LSWAPIB
(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
] = (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
= SSWAPIB
(*(uint16_t *)&uptr
[0]);
r
[0] = ((c0
>>8)&0xf8); g
[0] = ((c0
>>3)&0xfc); b
[0] = ((c0
<<3)&0xfc); a
[0] = 255;
c1
= SSWAPIB
(*(uint16_t *)&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
= LSWAPIB
(*(int32_t *)&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] = LSWAPIB
(*(int32_t *)&uptr
[-6]);
al
[1] = LSWAPIB
(*(int32_t *)&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 (*(uint16_t *)&ubuf
[0] == SSWAPIB
(0x5089)) //.PNG
{
lptr
= (int32_t *)buf
;
if ((lptr
[0] != (int32_t)LSWAPIB
(0x474e5089)) || (lptr
[1] != (int32_t)LSWAPIB
(0x0a1a0a0d))) return;
lptr
= &lptr
[2];
while (((uintptr_t)lptr
-(uintptr_t)buf
) < (uintptr_t)(leng
-16))
{
if (lptr
[1] == (int32_t)LSWAPIB
(0x52444849)) //IHDR
{(*xsiz
) = LSWAPIL
(lptr
[2]); (*ysiz
) = LSWAPIL
(lptr
[3]); break; }
lptr
= (int32_t *)((intptr_t)lptr
+ LSWAPIL
(lptr
[0]) + 12);
}
}
else if (*(uint16_t *)&ubuf
[0] == SSWAPIB
(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
) = SSWAPIL
(*(uint16_t *)&cptr
[5]);
(*xsiz
) = SSWAPIL
(*(uint16_t *)&cptr
[7]);
break;
}
cptr
= &cptr
[SSWAPIL
(*(uint16_t *)&cptr
[2])+2];
}
}
else
{
if ((ubuf
[0] == 'G') && (ubuf
[1] == 'I') && (ubuf
[2] == 'F')) //.GIF
{
(*xsiz
) = (int32_t) SSWAPIB
(*(uint16_t *) &buf
[6]);
(*ysiz
) = (int32_t) SSWAPIB
(*(uint16_t *) &buf
[8]);
}
else if ((ubuf
[0] == 'B') && (ubuf
[1] == 'M')) //.BMP
{
if (*(int32_t *) (&buf
[14]) == (int32_t)LSWAPIB
(12)) //OS/2 1.x (old format)
{
if (*(int16_t *) (&buf
[22]) != SSWAPIB
(1)) return;
(*xsiz
) = (int32_t) SSWAPIB
(*(uint16_t *) &buf
[18]);
(*ysiz
) = (int32_t) SSWAPIB
(*(uint16_t *) &buf
[20]);
}
else //All newer formats...
{
if (*(int16_t *) (&buf
[26]) != SSWAPIB
(1)) return;
(*xsiz
) = LSWAPIB
(*(int32_t *) &buf
[18]);
(*ysiz
) = LSWAPIB
(*(int32_t *) &buf
[22]);
}
}
else if (*(int32_t *) ubuf
== (int32_t)LSWAPIB
(0x0801050a)) //.PCX
{
(*xsiz
) = SSWAPIB
(*(int16_t *) &buf
[8])-SSWAPIB
(*(int16_t *) &buf
[4])+1;
(*ysiz
) = SSWAPIB
(*(int16_t *) &buf
[10])-SSWAPIB
(*(int16_t *) &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) SSWAPIB
(*(uint16_t *) &buf
[2]);
(*ysiz
) = (int32_t) SSWAPIB
(*(uint16_t *) &buf
[4]);
}
#endif
#ifdef KPDDS
else if ((*(int32_t *) ubuf
== LSWAPIB
(0x20534444)) && (*(int32_t *) &ubuf
[4] == LSWAPIB
(124))) //.DDS
{
(*xsiz
) = LSWAPIB
(*(int32_t *) &buf
[16]);
(*ysiz
) = LSWAPIB
(*(int32_t *) &buf
[12]);
}
#endif
else if (istarga
(ubuf
, leng
))
{
//Unreliable .TGA identification - this MUST be final case!
(*xsiz
) = (int32_t) SSWAPIB
(*(uint16_t *) &buf
[12]);
(*ysiz
) = (int32_t) SSWAPIB
(*(uint16_t *) &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 (*(uint16_t *)&ubuf
[0] == SSWAPIB
(0x5089)) //.PNG
return(kpngrend
(buf
,leng
,frameptr
,bpl
,xdim
,ydim
));
else if (*(uint16_t *)&ubuf
[0] == SSWAPIB
(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 (*(int32_t *) ubuf
== (int32_t)LSWAPIB
(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 ((*(int32_t *) ubuf
== LSWAPIB
(0x20534444)) && (*(int32_t *) &ubuf
[4] == LSWAPIB
(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];
static int32_t wildmatch
(const char *match
, const char *wild
)
{
do
{
if (*match
&& (toupperlookup
[*wild
] == toupperlookup
[*match
] || *wild
== '?'))
{
wild
++, match
++;
continue;
}
else if (*match
+ *wild
== '\0')
return 1;
else if (*wild
== '*')
{
while (*wild
== '*') wild
++;
if (*wild
== '\0') return 1;
while (toupperlookup
[*match
] != toupperlookup
[*wild
] && *match
) match
++;
if (toupperlookup
[*match
] == toupperlookup
[*wild
])
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
=(*(int32_t *)&kzhashbuf
[i
]))
if (!filnamcmp
(filnam
,&kzhashbuf
[i
+21]))
{
(*zipnam
) = &kzhashbuf
[*(int32_t *)&kzhashbuf
[i
+8]];
(*fileoffs
) = *(int32_t *)&kzhashbuf
[i
+12];
(*fileleng
) = *(int32_t *)&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);
*(int32_t *)&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)LSWAPIB
(0x04034b50)) //'PK\3\4' is ZIP file id
{
fseek(fil
,-22,SEEK_END
);
fread(tempbuf
,22,1,fil
);
if (*(int32_t *)&tempbuf
[0] == (int32_t)LSWAPIB
(0x06054b50)) //Fast way of finding dir info
{
numfiles
= SSWAPIB
(*(int16_t *)&tempbuf
[10]);
fseek(fil
,LSWAPIB
(*(int32_t *)&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)LSWAPIB
(0x02014b50)) break; //Found central file header :)
if (j
!= (int32_t)LSWAPIB
(0x04034b50)) { numfiles
= -1; break; }
fread(tempbuf
,26,1,fil
);
fseek(fil
,LSWAPIB
(*(int32_t *)&tempbuf
[14]) + SSWAPIB
(*(int16_t *)&tempbuf
[24]) + SSWAPIB
(*(int16_t *)&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 (*(int32_t *)&tempbuf
[0] != (int32_t)LSWAPIB
(0x02014b50)) { fclose(fil
); return(0); }
j
= SSWAPIB
(*(int16_t *)&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]);
*(int32_t *)&kzhashbuf
[kzhashpos
] = kzhashead
[hashind
];
*(int32_t *)&kzhashbuf
[kzhashpos
+4] = kzlastfnam
;
*(int32_t *)&kzhashbuf
[kzhashpos
+8] = zipnamoffs
;
*(int32_t *)&kzhashbuf
[kzhashpos
+12] = LSWAPIB
(*(int32_t *)&tempbuf
[42]); //fileoffs
*(int32_t *)&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
= SSWAPIB
(*(int16_t *)&tempbuf
[30]); //extra field length
j
+= SSWAPIB
(*(int16_t *)&tempbuf
[32]); //file comment length
fseek(fil
,j
,SEEK_CUR
);
}
}
else if (i
== (int32_t)LSWAPIB
(0x536e654b)) //'KenS' is GRP file id
{
fread(tempbuf
,12,1,fil
);
if ((*(int32_t *)&tempbuf
[0] != (int32_t)LSWAPIB
(0x65766c69)) || //'ilve'
(*(int32_t *)&tempbuf
[4] != (int32_t)LSWAPIB
(0x6e616d72))) //'rman'
{ fclose(fil
); return(0); }
numfiles
= LSWAPIB
(*(int32_t *)&tempbuf
[8]); k
= ((numfiles
+1)<<4);
for (i
=0; i
<numfiles
; i
++,k
+=leng
)
{
fread(tempbuf
,16,1,fil
);
leng
= LSWAPIB
(*(int32_t *)&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
);
*(int32_t *)&kzhashbuf
[kzhashpos
] = kzhashead
[hashind
];
*(int32_t *)&kzhashbuf
[kzhashpos
+4] = kzlastfnam
;
*(int32_t *)&kzhashbuf
[kzhashpos
+8] = zipnamoffs
;
*(int32_t *)&kzhashbuf
[kzhashpos
+12] = k
; //fileoffs
*(int32_t *)&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 (*(int32_t *)&tempbuf
[0] != (int32_t)LSWAPIB
(0x04034b50)) { fclose(fil
); return(0); }
fseek(fil
,SSWAPIB
(*(int16_t *)&tempbuf
[26])+SSWAPIB
(*(int16_t *)&tempbuf
[28]),SEEK_CUR
);
kzfs.
fil = fil
;
kzfs.
comptyp = SSWAPIB
(*(int16_t *)&tempbuf
[8]);
kzfs.
seek0 = ftell(fil
);
kzfs.
leng = LSWAPIB
(*(int32_t *)&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)LSWAPIB
(*(int32_t *)&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
=*(int32_t *)&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
= *(int32_t *)&kzhashbuf
[srchzoff
+4];
return(1);
}
srchzoff
= *(int32_t *)&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
= *(int32_t *)&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 =========================