/************************************************************************************************** KPLIB.C: Ken's Picture LIBrary written by Ken Silverman Copyright (c) 1998-2008 Ken Silverman Ken Silverman's official web site: http://advsys.net/ken Features of KPLIB.C: * Routines for decoding JPG/PNG/GIF/PCX/TGA/BMP/DDS/CEL. See kpgetdim(), kprender(), and optional helper function: kpzload(). * Routines for reading files out of ZIP/GRP files. All ZIP/GRP functions start with "kz". * Multi-platform support: Dos/Windows/Linux/Mac/etc.. * Compact code, all in a single source file. Yeah, bad design on my part... but makes life easier for everyone else - you simply add a single C file to your project, throw a few externs in there, add the function calls, and you're done! Brief history: 1998?: Wrote KPEG, a JPEG viewer for DOS 2000: Wrote KPNG, a PNG viewer for DOS 2001: Combined KPEG & KPNG, ported to Visual C, and made it into a library called KPLIB.C 2002: Added support for TGA,GIF,CEL,ZIP 2003: Added support for BMP 05/18/2004: Added support for 8&24 bit PCX 12/09/2005: Added support for progressive JPEG 01/05/2006: Added support for DDS 07/28/2007: Added support for GRP (Build Engine archive) I offer this code to the community for free use - all I ask is that my name be included in the credits. -Ken S. **************************************************************************************************/ #include "compat.h" #include "baselayer.h" #include "kplib.h" #include "pragmas.h" #if !defined(_WIN32) #include 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 #ifdef __clang__ #include #else #include #endif #endif //use GCC-specific extension to force symbol name to be something in particular to override underscoring. #if defined(__GNUC__) && defined(__i386__) && !defined(NOASM) #define ASMNAME(x) asm(x) #else #define ASMNAME(x) #endif static intptr_t kp_frameplace; static int32_t kp_bytesperline, kp_xres, kp_yres; static 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 kp_xres is: 131072/bpp-1 B_KPLIB_STATIC int32_t ATTRIBUTE((used)) abstab10[1024] ASMNAME("abstab10"); //Variables to speed up dynamic Huffman decoding: #define LOGQHUFSIZ0 9 #define LOGQHUFSIZ1 6 static int32_t qhufval0[1<(kzfs.compleng-kzfs.comptell, sizeof(olinbuf)-4); fread(&olinbuf[4], n, 1, kzfs.fil); kzfs.comptell += n; bitpos -= ((sizeof(olinbuf)-4)<<3); return; } if (nfilptr) { filptr = nfilptr; nfilptr = 0; bitpos -= ((nbitpos-4)<<3); return; } //if (n_from_suckbits < 4) will it crash? //|===|===|crc|lng|typ|===|===| // \ fakebuf: / // |===|===| //----x O---x O-------- nbitpos = B_BIG32(B_UNBUF32(&filptr[8])); nfilptr = &filptr[nbitpos+12]; B_BUF32(&fakebuf[0], B_UNBUF32(&filptr[0])); //Copy last dword of IDAT chunk if (B_UNBUF32(&filptr[12]) == B_LITTLE32(0x54414449)) //Copy 1st dword of next IDAT chunk B_BUF32(&fakebuf[4], B_UNBUF32(&filptr[16])); filptr = &fakebuf[4]; bitpos -= 32; } static inline int32_t peekbits(int32_t n) { return (B_LITTLE32(B_UNBUF32(&filptr[bitpos>>3]))>>(bitpos&7))&pow2mask[n]; } static inline void suckbits(int32_t n) { bitpos += n; if (bitpos < 0) return; suckbitsnextblock(); } static inline int32_t getbits(int32_t n) { int32_t i = peekbits(n); suckbits(n); return i; } static int32_t hufgetsym(int32_t *hitab, const int32_t *hbmax) { int32_t v, n; v = n = 0; do { v = (v<<1)+getbits(1)+hbmax[n]-hbmax[n+1]; n++; } while (v >= 0); return hitab[hbmax[n]+v]; } //This did not result in a speed-up on P4-3.6Ghz (02/22/2005) //static int32_t hufgetsym_skipb (int32_t *hitab, int32_t *hbmax, int32_t n, int32_t addit) //{ // int32_t v; // // v = bitrev(getbits(n),n)+addit; // do { v = (v<<1)+getbits(1)+hbmax[n]-hbmax[n+1]; n++; } while (v >= 0); // return hitab[hbmax[n]+v]; //} static void qhufgencode(const int32_t *hitab, const int32_t *hbmax, int32_t *qhval, uint8_t *qhbit, int32_t numbits) { int32_t i, j, k, n, r; //r is the bit reverse of i. Ex: if: i = 1011100111, r = 1110011101 i = r = 0; for (n=1; n<=numbits; n++) for (k=hbmax[n-1]; k>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=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>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<>i)&15); iystp = (1<>3) = 2 //j=3,ixoff=4 2 ((12+(1<<3)-1 - 4)>>3) = 1 //j=2,ixoff=2 3 4 5 ((12+(1<<2)-1 - 2)>>2) = 3 //j=1,ixoff=1 6 7 8 9 a b ((12+(1<<1)-1 - 1)>>1) = 6 ixsiz = ((xsiz+ixstp-1-ixoff)>>j); //It's confusing! See the above example. nbpl = (kp_bytesperline<>(kcoltype<<2))&15)*ixsiz; switch (bitdepth) { case 1: xsizbpl = ((xsizbpl+7)>>3); break; case 2: xsizbpl = ((xsizbpl+3)>>2); break; case 4: xsizbpl = ((xsizbpl+1)>>1); break; } Bmemset(olinbuf,0,(xsizbpl+1)*sizeof(olinbuf[0])); B_BUF32(&opixbuf0[0], 0); B_BUF32(&opixbuf1[0], 0); xplc = xsizbpl; yplc = iyoff; xm = 0; filt = -1; i = ixoff; i = (((-(i>=0))|(ixstp-1))&i); k = (((-(yplc>=0))|(iystp-1))&yplc); nfplace = k*kp_bytesperline + (i<<2) + kp_frameplace; //Precalculate x-clipping to screen borders (speeds up putbuf) //Equation: (0 <= xr <= ixsiz) && (0 <= xr*ixstp+globxoffs+ixoff <= kp_xres) xr0 = max((-ixoff+(1<>j,0); xr1 = min((kp_xres-ixoff+(1<>j,ixsiz); xr0 = ixsiz-xr0; xr1 = ixsiz-xr1; if (kcoltype == 4) { xr0 = xr0*2; xr1 = xr1*2; } else if (kcoltype == 2) { xr0 = xr0*3-2; xr1 = xr1*3-2; } else if (kcoltype == 6) { xr0 = xr0*4-2; xr1 = xr1*4-2; } else { switch (bitdepth) { case 1: xr0 += ((-ixsiz)&7)+7; xr1 += ((-ixsiz)&7)+7; break; case 2: xr0 = ((xr0+((-ixsiz)&3)+3)<<1); xr1 = ((xr1+((-ixsiz)&3)+3)<<1); break; case 4: xr0 = ((xr0+((-ixsiz)&1)+1)<<2); xr1 = ((xr1+((-ixsiz)&1)+1)<<2); break; } } ixstp <<= 2; return 0; } #if defined(_MSC_VER) && !defined(NOASM) static inline int32_t Paeth686(int32_t a, int32_t b, int32_t c) { _asm { push ebx push esi push edi mov eax, a mov ebx, b mov ecx, c mov edx, ecx sub edx, eax sub edx, ebx lea edx, abstab10[edx*4+2048] mov esi, [ebx*4+edx] mov edi, [ecx*4+edx] cmp edi, esi cmovge edi, esi cmovge ecx, ebx cmp edi, [eax*4+edx] cmovl eax, ecx pop edi pop esi pop ebx } } static inline void rgbhlineasm(int32_t c, int32_t d, int32_t t, int32_t b) { _asm { push ebx push edi mov ecx, c mov edx, d mov edi, t mov ebx, b sub ecx, edx jle short endit add edx, offset olinbuf cmp dword ptr trnsrgb, 0 jz short begit2 begit: mov eax, dword ptr [ecx+edx] or eax, 0xff000000 cmp eax, dword ptr trnsrgb jne short skipit and eax, 0xffffff skipit: sub ecx, 3 mov [edi], eax lea edi, [edi+ebx] jnz short begit jmp short endit begit2: mov eax, dword ptr [ecx+edx] or eax, 0xff000000 sub ecx, 3 mov [edi], eax lea edi, [edi+ebx] jnz short begit2 endit: pop edi pop ebx } } static inline void pal8hlineasm(int32_t c, int32_t d, int32_t t, int32_t b) { _asm { mov ecx, c mov edx, d sub ecx, edx jle short endit push ebx push edi mov edi, t mov ebx, b add edx, offset olinbuf begit:movzx eax, byte ptr [ecx+edx] mov eax, dword ptr palcol[eax*4] sub ecx, 1 mov [edi], eax lea edi, [edi+ebx] jnz short begit pop edi pop ebx endit: } } #elif defined(__GNUC__) && defined(__i386__) && !defined(NOASM) static inline int32_t Paeth686(int32_t a, int32_t b, int32_t c) { __asm__ __volatile__( "movl %%ecx, %%edx \n" "subl %%eax, %%edx \n" "subl %%ebx, %%edx \n" "leal (abstab10+2048)(,%%edx,4), %%edx \n" "movl (%%edx,%%ebx,4), %%esi \n" "movl (%%edx,%%ecx,4), %%edi \n" "cmpl %%esi, %%edi \n" "cmovgel %%esi, %%edi \n" "cmovgel %%ebx, %%ecx \n" "cmpl (%%edx,%%eax,4), %%edi \n" "cmovgel %%eax, %%ecx \n" : "+c"(c) : "a"(a), "b"(b) : "edx","esi","edi","memory","cc" ); return c; } //Note: "cmove eax,?" may be faster than "jne ?:and eax,?" but who cares static inline void rgbhlineasm(int32_t c, int32_t d, int32_t t, int32_t b) { __asm__ __volatile__( "subl %%edx, %%ecx \n" "jle 3f \n" "addl $olinbuf, %%edx \n" "cmpl $0, trnsrgb(,1) \n" "jz 2f \n" "0: movl (%%ecx,%%edx,1), %%eax \n" "orl $0xff000000, %%eax \n" "cmpl trnsrgb(,1), %%eax \n" "jne 1f \n" "andl $0xffffff, %%eax \n" "1: subl $3, %%ecx \n" "movl %%eax, (%%edi) \n" "leal (%%edi,%%ebx,1), %%edi \n" "jnz 0b \n" "jmp 3f \n" "2: movl (%%ecx,%%edx,1), %%eax \n" "orl $0xff000000, %%eax \n" "subl $3, %%ecx \n" "movl %%eax, (%%edi) \n" "leal (%%edi,%%ebx,1), %%edi \n" "jnz 2b \n" "3: \n" : "+c"(c), "+d"(d), "+D"(t) : "b"(b) : "eax","memory","cc" ); } static inline void pal8hlineasm(int32_t c, int32_t d, int32_t t, int32_t b) { __asm__ __volatile__( "subl %%edx, %%ecx \n" "jle 1f \n" "addl $olinbuf, %%edx \n" "0: movzbl (%%ecx,%%edx,1), %%eax \n" "movl palcol(,%%eax,4), %%eax \n" "subl $1, %%ecx \n" "movl %%eax, (%%edi) \n" "leal (%%edi,%%ebx,1), %%edi \n" "jnz 0b \n" "1: \n" : "+c"(c), "+d"(d), "+D"(t) : "b"(b) : "eax","memory","cc" ); } #else static inline int32_t Paeth686(int32_t const a, int32_t const b, int32_t c) { int32_t const * const ptr = &abstab10[(c - a) - (b - 512)]; int32_t const esi = *(ptr + b); int32_t edi = *(ptr + c); if (edi >= esi) edi = esi, c = b; return (edi < *(ptr + a)) ? c : a; } static inline void rgbhlineasm(int32_t x, int32_t xr1, intptr_t p, int32_t ixstp) { if (!trnsrgb) { for (; x>xr1; p+=ixstp,x-=3) B_BUF32((void *) p, (B_UNBUF32(&olinbuf[x]))|B_LITTLE32(0xff000000)); return; } for (; x>xr1; p+=ixstp,x-=3) { int32_t i = (B_UNBUF32(&olinbuf[x]))|B_LITTLE32(0xff000000); if (i == trnsrgb) i &= B_LITTLE32(0xffffff); B_BUF32((void *) p, i); } } static inline void pal8hlineasm(int32_t x, int32_t xr1, intptr_t p, int32_t ixstp) { for (; x>xr1; p+=ixstp,x--) B_BUF32((void *) p, palcol[olinbuf[x]]); } #endif //Autodetect filter // /f0: 0000000... // /f1: 1111111... // /f2: 2222222... // /f3: 1333333... // /f3: 3333333... // /f4: 4444444... // /f5: 0142321... static int32_t filter1st, filterest; static void putbuf(const uint8_t *buf, int32_t leng) { int32_t i; intptr_t p; if (filt < 0) { if (leng <= 0) return; filt = buf[0]; if (filter1st < 0) filter1st = filt; else filterest |= (1< leng) x = leng; switch (filt) { case 0: while (i < x) { olinbuf[xplc--] = buf[i++]; } break; case 1: while (i < x) { olinbuf[xplc--] = (uint8_t)(opixbuf1[xm] += buf[i++]); xm = xmn[xm]; } break; case 2: while (i < x) { olinbuf[xplc--] += (uint8_t)buf[i++]; } break; case 3: while (i < x) { opixbuf1[xm] = olinbuf[xplc] = (uint8_t)(((opixbuf1[xm]+olinbuf[xplc])>>1)+buf[i++]); xm = xmn[xm]; xplc--; } break; case 4: while (i < x) { opixbuf1[xm] = (uint8_t)(Paeth686(opixbuf1[xm],olinbuf[xplc],opixbuf0[xm])+buf[i++]); opixbuf0[xm] = olinbuf[xplc]; olinbuf[xplc--] = opixbuf1[xm]; xm = xmn[xm]; } break; } if (xplc > 0) return; //Draw line! if ((uint32_t)yplc < (uint32_t)kp_yres) { x = xr0; p = nfplace; switch (kcoltype) { case 2: rgbhlineasm(x,xr1,p,ixstp); break; case 4: for (; x>xr1; p+=ixstp,x-=2) B_BUF32((void *) p, (palcol[olinbuf[x]]&B_LITTLE32(0xffffff))|B_BIG32((int32_t)olinbuf[x-1])); break; case 6: for (; x>xr1; p+=ixstp,x-=4) { *(char *)(p) = olinbuf[x ]; //B *(char *)(p+1) = olinbuf[x+1]; //G *(char *)(p+2) = olinbuf[x+2]; //R *(char *)(p+3) = olinbuf[x-1]; //A } break; default: switch (bitdepth) { case 1: for (; x>xr1; p+=ixstp,x--) B_BUF32((void *) p, palcol[olinbuf[x>>3]>>(x&7)]); break; case 2: for (; x>xr1; p+=ixstp,x-=2) B_BUF32((void *) p, palcol[olinbuf[x>>3]>>(x&6)]); break; case 4: for (; x>xr1; p+=ixstp,x-=4) B_BUF32((void *) p, palcol[olinbuf[x>>3]>>(x&4)]); break; case 8: pal8hlineasm(x,xr1,p,ixstp); break; //for(;x>xr1;p+=ixstp,x-- ) B_BUF32((void *) p, palcol[olinbuf[x]]); break; } break; } nfplace += nbpl; } B_BUF32(&opixbuf0[0], 0); B_BUF32(&opixbuf1[0], 0); xplc = xsizbpl; yplc += iystp; if ((intlac) && (yplc >= ysiz)) { intlac--; initpass(); } if (i < leng) { filt = buf[i++]; if (filter1st < 0) filter1st = filt; else filterest |= (1<= 2)); } j = 3; k = 0; for (i=257; i<285; i++) { hxbit[i+30-257][1] = j; j += (1<= 264)); } hxbit[285+30-257][1] = 258; hxbit[285+30-257][0] = 0; for (i=0; i<512; i++) abstab10[512+i] = abstab10[512-i] = i; } static int32_t kpngrend(const char *kfilebuf, int32_t kfilength, intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres) { int32_t i, j, k, bfinal, btype, hlit, hdist, leng; int32_t slidew, slider; //int32_t qhuf0v, qhuf1v; UNREFERENCED_PARAMETER(kfilength); if (!pnginited) { pnginited = 1; initpngtables(); } if ((B_UNBUF32(&kfilebuf[0]) != B_LITTLE32(0x474e5089)) || (B_UNBUF32(&kfilebuf[4]) != B_LITTLE32(0x0a1a0a0d))) return -1; //"Invalid PNG file signature" filptr = (uint8_t const *)&kfilebuf[8]; trnsrgb = 0; filter1st = -1; filterest = 0; while (1) { leng = B_BIG32(B_UNBUF32(&filptr[0])); i = B_UNBUF32(&filptr[4]); filptr = &filptr[8]; if (i == (int32_t)B_LITTLE32(0x52444849)) //IHDR (must be first) { xsiz = B_BIG32(B_UNBUF32(&filptr[0])); if (xsiz <= 0) return -1; ysiz = B_BIG32(B_UNBUF32(&filptr[4])); if (ysiz <= 0) return -1; bitdepth = filptr[8]; if (!((1<= 2) return -1; //"Unsupported interlace type" intlac = filptr[12]*7; //0=no interlace/1=Adam7 interlace //Save code by making grayscale look like a palette color scheme if ((!kcoltype) || (kcoltype == 4)) { j = 0xff000000; k = (tabledivide32(255, ((1<=0; i--) palcol[i] = B_LITTLE32((B_BIG32(B_UNBUF32(&filptr[i*3]))>>8)|0xff000000); } else if (i == (int32_t)B_LITTLE32(0x44474b62)) //bKGD (must be after PLTE and before IDAT) { switch (kcoltype) { case 0: case 4: bakcol = (((int32_t)filptr[0]<<8)+(int32_t)filptr[1])*tabledivide32(255, ((1<>16)&255); bakg = ((bakcol>>8)&255); bakb = (bakcol&255); bakcol = B_LITTLE32(bakcol); } else if (i == (int32_t)B_LITTLE32(0x534e5274)) //tRNS (must be after PLTE and before IDAT) { switch (kcoltype) { case 0: if (bitdepth <= 8) palcol[(int32_t)filptr[1]] &= B_LITTLE32(0xffffff); //else {} // /c0 /d16 not yet supported break; case 2: if (bitdepth == 8) { trnsrgb = B_LITTLE32((((int32_t)filptr[1])<<16)+(((int32_t)filptr[3])<<8)+((int32_t)filptr[5])+0xff000000); } //else {} //WARNING: PNG docs say: MUST compare all 48 bits :( break; case 3: for (i=min(leng,paleng)-1; i>=0; i--) palcol[i] &= B_LITTLE32((((int32_t)filptr[i])<<24)|0xffffff); break; default:; EDUKE32_UNREACHABLE_SECTION(); } } else if (i == (int32_t)B_LITTLE32(0x54414449)) { break; } //IDAT filptr = &filptr[leng+4]; //crc = B_BIG32(B_UNBUF32(&filptr[-4])); } //Initialize this for the getbits() function zipfilmode = 0; filptr = &filptr[leng-4]; bitpos = -((leng-4)<<3); nfilptr = 0; //if (leng < 4) will it crash? kp_frameplace = dakpframeplace; kp_bytesperline = dakpbytesperline; kp_xres = daxres; kp_yres = dayres; switch (kcoltype) { case 4: xmn[0] = 1; xmn[1] = 0; break; case 2: xmn[0] = 1; xmn[1] = 2; xmn[2] = 0; break; case 6: xmn[0] = 1; xmn[1] = 2; xmn[2] = 3; xmn[3] = 0; break; default: xmn[0] = 0; break; } switch (bitdepth) { case 1: for (i=2; i<256; i++) palcol[i] = palcol[i&1]; break; case 2: for (i=4; i<256; i++) palcol[i] = palcol[i&3]; break; case 4: for (i=16; i<256; i++) palcol[i] = palcol[i&15]; break; } //coltype: bitdepth: format: // 0 1,2,4,8,16 I // 2 8,16 RGB // 3 1,2,4,8 P // 4 8,16 IA // 6 8,16 RGBA xsizbpl = ((0x04021301>>(kcoltype<<2))&15)*xsiz; switch (bitdepth) { case 1: xsizbpl = ((xsizbpl+7)>>3); break; case 2: xsizbpl = ((xsizbpl+3)>>2); break; case 4: xsizbpl = ((xsizbpl+1)>>1); break; } //Tests to see if xsiz > allocated space in olinbuf //Note: xsizbpl gets re-written inside initpass() if ((xsizbpl+1)*sizeof(olinbuf[0]) > sizeof(olinbuf)) return -1; initpass(); slidew = 0; slider = 16384; zlibcompflags = getbits(16); //Actually 2 fields: 8:compmethflags, 8:addflagscheck do { bfinal = getbits(1); btype = getbits(2); if (btype == 0) { //Raw (uncompressed) suckbits((-bitpos)&7); //Synchronize to start of next byte i = getbits(16); if ((getbits(16)^i) != 0xffff) return -1; for (; i; i--) { if (slidew >= slider) { putbuf(&slidebuf[(slider-16384)&32767],16384); slider += 16384; if ((yplc >= kp_yres) && (intlac < 2)) goto kpngrend_goodret; } slidebuf[(slidew++)&32767] = (uint8_t)getbits(8); } continue; } if (btype == 3) continue; if (btype == 1) //Fixed Huffman { hlit = 288; hdist = 32; i = 0; for (; i<144; i++) clen[i] = 8; //Fixed bit sizes (literals) for (; i<256; i++) clen[i] = 9; //Fixed bit sizes (literals) for (; i<280; i++) clen[i] = 7; //Fixed bit sizes (EOI,lengths) for (; i<288; i++) clen[i] = 8; //Fixed bit sizes (lengths) for (; i<320; i++) clen[i] = 5; //Fixed bit sizes (distances) } else //Dynamic Huffman { numhufblocks++; hlit = getbits(5)+257; hdist = getbits(5)+1; j = getbits(4)+4; for (i=0; i= slider) { putbuf(&slidebuf[(slider-16384)&32767],16384); slider += 16384; if ((yplc >= kp_yres) && (intlac < 2)) goto kpngrend_goodret; } k = peekbits(LOGQHUFSIZ0); if (qhufbit0[k]) { i = qhufval0[k]; suckbits((int32_t)qhufbit0[k]); } else i = hufgetsym(ibuf0,nbuf0); //else i = hufgetsym_skipb(ibuf0,nbuf0,LOGQHUFSIZ0,qhuf0v); //hufgetsym_skipb related code if (i < 256) { slidebuf[(slidew++)&32767] = (uint8_t)i; continue; } if (i == 256) break; i = getbits(hxbit[i+30-257][0]) + hxbit[i+30-257][1]; k = peekbits(LOGQHUFSIZ1); if (qhufbit1[k]) { j = qhufval1[k]; suckbits((int32_t)qhufbit1[k]); } else j = hufgetsym(ibuf1,nbuf1); //else j = hufgetsym_skipb(ibuf1,nbuf1,LOGQHUFSIZ1,qhuf1v); //hufgetsym_skipb related code j = getbits(hxbit[j][0]) + hxbit[j][1]; i += slidew; do { slidebuf[slidew&32767] = slidebuf[(slidew-j)&32767]; slidew++; } while (slidew < i); } } while (!bfinal); slider -= 16384; if (!((slider^slidew)&32768)) putbuf(&slidebuf[slider&32767],slidew-slider); else { putbuf(&slidebuf[slider&32767],(-slider)&32767); putbuf(slidebuf,slidew&32767); } kpngrend_goodret: if (!(filterest&~(1<>24); } static inline int32_t mulshr32(int32_t a, int32_t b) { return (int32_t)((((int64_t)a)*((int64_t)b))>>32); } #endif static int32_t cosqr16[8] = //cosqr16[i] = ((cos(PI*i/16)*sqrt(2))<<24); {23726566,23270667,21920489,19727919,16777216,13181774,9079764,4628823}; static int32_t crmul[4096], cbmul[4096]; static void initkpeg() { int32_t i, j, y; int32_t x = 0; //Back & forth diagonal pattern (aligning bytes for best compression) for (i=0; i<16; i+=2) { for (y=8-1; y>=0; y--) if ((unsigned)(i-y) < (unsigned)8) unzig[x++] = (y<<3)+i-y; for (y=0; y<8; y++) if ((unsigned)(i+1-y) < (unsigned)8) unzig[x++] = (y<<3)+i+1-y; } for (i=64-1; i>=0; i--) zigit[unzig[i]] = i; for (i=64-1; i>=0; i--) dcflagor[i] = (uint8_t)(1<<(unzig[i]>>3)); for (i=0; i<128; i++) colclip[i] = i+128; for (i=128; i<512; i++) colclip[i] = 255; for (i=512; i<896; i++) colclip[i] = 0; for (i=896; i<1024; i++) colclip[i] = i-896; for (i=0; i<1024; i++) { colclipup8[i] = (colclip[i]<<8); colclipup16[i] = (colclip[i]<<16)+0xff000000; //Hack: set alphas to 255 } #if B_BIG_ENDIAN == 1 for (i=0; i<1024; i++) { colclip[i] = B_SWAP32(colclip[i]); colclipup8[i] = B_SWAP32(colclipup8[i]); colclipup16[i] = B_SWAP32(colclipup16[i]); } #endif for (i=0; i<2048; i++) { j = i-1024; crmul[(i<<1)+0] = j*1470104; //1.402*1048576 crmul[(i<<1)+1] = j*-748830; //-0.71414*1048576 cbmul[(i<<1)+0] = j*-360857; //-0.34414*1048576 cbmul[(i<<1)+1] = j*1858077; //1.772*1048576 } Bmemset((void *)&dct[10][0],0,64*2*sizeof(dct[0][0])); } static void huffgetval(int32_t index, int32_t curbits, int32_t num, int32_t *daval, int32_t *dabits) { int32_t b, v, pow2, *hmax; hmax = &hufmaxatbit[index][0]; pow2 = pow2long[curbits-1]; if (num&pow2) v = 1; else v = 0; for (b=1; b<=16; b++) { if (v < hmax[b]) { *dabits = b; *daval = huftable[index][hufvalatbit[index][b]+v]; return; } pow2 >>= 1; v <<= 1; if (num&pow2) v++; } *dabits = 16; *daval = 0; } static void invdct8x8(int32_t *dc, uint8_t dcflag) { #define SQRT2 23726566 //(sqrt(2))<<24 #define C182 31000253 //(cos(PI/8)*2)<<24 #define C18S22 43840978 //(cos(PI/8)*sqrt(2)*2)<<24 #define C38S22 18159528 //(cos(PI*3/8)*sqrt(2)*2)<<24 int32_t *edc, t0, t1, t2, t3, t4, t5, t6, t7; edc = dc+64; do { if (dcflag&1) //pow2char[z]) { t3 = dc[2] + dc[6]; t2 = (mulshr32(dc[2]-dc[6],SQRT2<<6)<<2) - t3; t4 = dc[0] + dc[4]; t5 = dc[0] - dc[4]; t0 = t4+t3; t3 = t4-t3; t1 = t5+t2; t2 = t5-t2; t4 = (mulshr32(dc[5]-dc[3]+dc[1]-dc[7],C182<<6)<<2); t7 = dc[1] + dc[7] + dc[5] + dc[3]; t6 = (mulshr32(dc[3]-dc[5],C18S22<<5)<<3) + t4 - t7; t5 = (mulshr32(dc[1]+dc[7]-dc[5]-dc[3],SQRT2<<6)<<2) - t6; t4 = (mulshr32(dc[1]-dc[7],C38S22<<6)<<2) - t4 + t5; dc[0] = t0+t7; dc[7] = t0-t7; dc[1] = t1+t6; dc[6] = t1-t6; dc[2] = t2+t5; dc[5] = t2-t5; dc[4] = t3+t4; dc[3] = t3-t4; } dc += 8; dcflag >>= 1; } while (dc < edc); dc -= 32; edc -= 24; do { t3 = dc[2*8-32] + dc[6*8-32]; t2 = (mulshr32(dc[2*8-32]-dc[6*8-32],SQRT2<<6)<<2) - t3; t4 = dc[0*8-32] + dc[4*8-32]; t5 = dc[0*8-32] - dc[4*8-32]; t0 = t4+t3; t3 = t4-t3; t1 = t5+t2; t2 = t5-t2; t4 = (mulshr32(dc[5*8-32]-dc[3*8-32]+dc[1*8-32]-dc[7*8-32],C182<<6)<<2); t7 = dc[1*8-32] + dc[7*8-32] + dc[5*8-32] + dc[3*8-32]; t6 = (mulshr32(dc[3*8-32]-dc[5*8-32],C18S22<<5)<<3) + t4 - t7; t5 = (mulshr32(dc[1*8-32]+dc[7*8-32]-dc[5*8-32]-dc[3*8-32],SQRT2<<6)<<2) - t6; t4 = (mulshr32(dc[1*8-32]-dc[7*8-32],C38S22<<6)<<2) - t4 + t5; dc[0*8-32] = t0+t7; dc[7*8-32] = t0-t7; dc[1*8-32] = t1+t6; dc[6*8-32] = t1-t6; dc[2*8-32] = t2+t5; dc[5*8-32] = t2-t5; dc[4*8-32] = t3+t4; dc[3*8-32] = t3-t4; dc++; } while (dc < edc); } static void yrbrend(int32_t x, int32_t y, int32_t *ldct) { int32_t i, j, ox, oy, xx, yy, xxx, yyy, xxxend, yyyend, yv, cr = 0, cb = 0, *odc, *dc, *dc2; intptr_t p, pp; odc = ldct; dc2 = &ldct[10<<6]; for (yy=0; yy<(lcompvsamp[0]<<3); yy+=8) { oy = y+yy; if ((unsigned)oy >= (unsigned)clipydim) { odc += (lcomphsamp[0]<<6); continue; } pp = oy*kp_bytesperline + ((x)<<2) + kp_frameplace; for (xx=0; xx<(lcomphsamp[0]<<3); xx+=8,odc+=64) { ox = x+xx; if ((unsigned)ox >= (unsigned)clipxdim) continue; p = pp+(xx<<2); dc = odc; if (lnumcomponents > 1) dc2 = &ldct[(lcomphvsamp0<<6)+((yy>>lcompvsampshift0)<<3)+(xx>>lcomphsampshift0)]; xxxend = min(clipxdim-ox,8); yyyend = min(clipydim-oy,8); if ((lcomphsamp[0] == 1) && (xxxend == 8)) { for (yyy=0; yyy>(20-1))&~1; cb = (dc2[xxx ]>>(20-1))&~1; ((int32_t *)p)[xxx] = colclipup16[(unsigned)(yv+crmul[cr+2048])>>22]+ colclipup8[(unsigned)(yv+crmul[cr+2049]+cbmul[cb+2048])>>22]+ colclip[(unsigned)(yv+cbmul[cb+2049])>>22]; } p += kp_bytesperline; dc += 8; if (!((yyy+1)&(lcompvsamp[0]-1))) dc2 += 8; } } else if ((lcomphsamp[0] == 2) && (xxxend == 8)) { for (yyy=0; yyy>1)+64]>>(20-1))&~1; cb = (dc2[(xxx>>1)]>>(20-1))&~1; i = crmul[cr+2049]+cbmul[cb+2048]; cr = crmul[cr+2048]; cb = cbmul[cb+2049]; ((int32_t *)p)[xxx] = colclipup16[(unsigned)(yv+cr)>>22]+ colclipup8[(unsigned)(yv+ i)>>22]+ colclip[(unsigned)(yv+cb)>>22]; yv = dc[xxx+1]; ((int32_t *)p)[xxx+1] = colclipup16[(unsigned)(yv+cr)>>22]+ colclipup8[(unsigned)(yv+ i)>>22]+ colclip[(unsigned)(yv+cb)>>22]; } p += kp_bytesperline; dc += 8; if (!((yyy+1)&(lcompvsamp[0]-1))) dc2 += 8; } } else { for (yyy=0; yyy>(20-1))&~1; cb = (dc2[i ]>>(20-1))&~1; i++; } ((int32_t *)p)[xxx] = colclipup16[(unsigned)(yv+crmul[cr+2048])>>22]+ colclipup8[(unsigned)(yv+crmul[cr+2049]+cbmul[cb+2048])>>22]+ colclip[(unsigned)(yv+cbmul[cb+2049])>>22]; } p += kp_bytesperline; dc += 8; if (!((yyy+1)&(lcompvsamp[0]-1))) dc2 += 8; } } } } } void (*kplib_yrbrend_func)(int32_t,int32_t,int32_t *) = yrbrend; #define KPEG_GETBITS(curbits, minbits, num, kfileptr, kfileend)\ while (curbits < minbits)\ {\ ch = *kfileptr++; num = (num<<8)+((int)ch); curbits += 8;\ if (ch == 255) { kfileptr++; if (kfileptr >= kfileend) { num <<= 8; curbits += 8; /*Hack to prevent read overrun on valid JPG by stuffing extra byte*/ } }\ } static int32_t kpegrend(const char *kfilebuf, int32_t kfilength, intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres) { int32_t i, j, v, leng = 0, xdim = 0, ydim = 0, index, prec, restartcnt, restartinterval; int32_t x, y, z, xx, yy, zz, *dc = NULL, num, curbits, c, daval, dabits, *hqval, *hqbits, hqcnt, *quanptr = NULL; int32_t passcnt = 0, ghsampmax = 0, gvsampmax = 0, glhsampmax = 0, glvsampmax = 0, glhstep, glvstep; int32_t eobrun, Ss, Se, Ah, Al, Alut[2], dctx[12], dcty[12], ldctx[12], /* ldcty[12], */ lshx[4], lshy[4]; int16_t *dctbuf = 0, *dctptr[12], *ldctptr[12], *dcs = NULL; uint8_t ch, marker, dcflag; const uint8_t *kfileptr, *kfileend; if (!kpeginited) { kpeginited = 1; initkpeg(); } kfileptr = (uint8_t const *)kfilebuf; kfileend = &kfileptr[kfilength]; if (B_UNBUF16(kfileptr) == B_LITTLE16(0xd8ff)) kfileptr += 2; else return -1; //"%s is not a JPEG file\n",filename restartinterval = 0; for (i=0; i<4; i++) lastdc[i] = 0; for (i=0; i<8; i++) hufcnt[i] = 0; kcoltype = 0; bitdepth = 8; //For PNGOUT do { ch = *kfileptr++; if (ch != 255) continue; do { marker = *kfileptr++; } while (marker == 255); if (marker != 0xd9) //Don't read past end of buffer { leng = ((intptr_t)kfileptr[0]<<8)+(intptr_t)kfileptr[1]-2; kfileptr += 2; } //printf("fileoffs=%08x, marker=%02x,leng=%d",((int32_t)kfileptr)-((int32_t)kfilebuf)-2,marker,leng); switch (marker) { case 0xc0: case 0xc1: case 0xc2: //processit! kfileptr++; //numbits = *kfileptr++; ydim = B_BIG16(B_UNBUF16(&kfileptr[0])); xdim = B_BIG16(B_UNBUF16(&kfileptr[2])); //printf("%s: %ld / %ld = %ld\n",filename,xdim*ydim*3,kfilength,(xdim*ydim*3)/kfilength); kp_frameplace = dakpframeplace; kp_bytesperline = dakpbytesperline; kp_xres = daxres; kp_yres = dayres; gnumcomponents = kfileptr[4]; kfileptr += 5; ghsampmax = gvsampmax = glhsampmax = glvsampmax = 0; for (z=0; z>4); gcompvsamp[z] = (kfileptr[1]&15); gcompquantab[z] = kfileptr[2]; for (i=0; i<8; i++) if (gcomphsamp[z] == pow2long[i]) { gcomphsampshift[z] = i; break; } for (i=0; i<8; i++) if (gcompvsamp[z] == pow2long[i]) { gcompvsampshift[z] = i; break; } if (gcomphsamp[z] > ghsampmax) { ghsampmax = gcomphsamp[z]; glhsampmax = gcomphsampshift[z]; } if (gcompvsamp[z] > gvsampmax) { gvsampmax = gcompvsamp[z]; glvsampmax = gcompvsampshift[z]; } kfileptr += 3; } break; case 0xc4: //Huffman table do { ch = *kfileptr++; leng--; if (ch >= 16) { index = ch-12; } else { index = ch; } Bmemcpy((void *)&hufnumatbit[index][1],(void const *)kfileptr,16); kfileptr += 16; leng -= 16; v = 0; hufcnt[index] = 0; hufquickcnt[index] = 0; for (i=1; i<=16; i++) { hufmaxatbit[index][i] = v+hufnumatbit[index][i]; hufvalatbit[index][i] = hufcnt[index]-v; Bmemcpy((void *)&huftable[index][hufcnt[index]],(void const *)kfileptr,(int32_t)hufnumatbit[index][i]); if (i <= 10) for (c=0; c0; j--) { hufquickval[index][hufquickcnt[index]] = huftable[index][hufcnt[index]+c]; hufquickbits[index][hufquickcnt[index]] = i; hufquickcnt[index]++; } kfileptr += hufnumatbit[index][i]; leng -= hufnumatbit[index][i]; hufcnt[index] += hufnumatbit[index][i]; v = ((v+hufnumatbit[index][i])<<1); } } while (leng > 0); break; case 0xdb: do { ch = *kfileptr++; leng--; index = (ch&15); prec = (ch>>4); for (z=0; z<64; z++) { v = (int32_t)(*kfileptr++); if (prec) v = (v<<8)+((int32_t)(*kfileptr++)); v <<= 19; if (unzig[z]&7) v = mulshr24(v,cosqr16[unzig[z]&7 ]); if (unzig[z]>>3) v = mulshr24(v,cosqr16[unzig[z]>>3]); quantab[index][unzig[z]] = v; } leng -= 64; if (prec) leng -= 64; } while (leng > 0); break; case 0xdd: restartinterval = B_BIG16(B_UNBUF16(&kfileptr[0])); kfileptr += leng; break; case 0xda: if ((xdim <= 0) || (ydim <= 0)) { Bfree(dctbuf); return -1; } lnumcomponents = (int32_t)(*kfileptr++); if (!lnumcomponents) { Bfree(dctbuf); return -1; } if (lnumcomponents > 1) kcoltype = 2; for (z=0; z>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>(glhsampmax+3)) << gcomphsampshift[z]; dcty[z] = ((ydim+(gvsampmax<<3)-1)>>(glvsampmax+3)) << gcompvsampshift[z]; zz += dctx[z]*dcty[z]; } z = zz*64*sizeof(int16_t); dctbuf = (int16_t *)Xmalloc(z); if (!dctbuf) return -1; Bmemset(dctbuf,0,z); for (z=zz=0; z>glhstep); lcomphsamp[0] = min(lcomphsamp[0],glhstep); glhstep <<= 3; glvstep = (gvsampmax>>glvstep); lcompvsamp[0] = min(lcompvsamp[0],glvstep); glvstep <<= 3; lcomphvsamp0 = lcomphsamp[0]*lcompvsamp[0]; clipxdim = min(xdim,kp_xres); clipydim = min(ydim,kp_yres); Alut[0] = (1<= kfilength) goto kpegrend_break2; //rest of file is missing! if (!dctbuf) dc = dct[0]; for (c=0; c>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]<>(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< 0)) { eobrun--; for (; z<=Se; z++) { if (!dcs[z]) continue; KPEG_GETBITS(curbits, 8, num, kfileptr, kfileend); if (num&(pow2long[--curbits])) dcs[z] += ((int16_t)Alut[dcs[z] < 0]); } } if (!dctbuf) { for (z=64-1; z>=0; z--) dc[z] *= quanptr[z]; invdct8x8(dc,dcflag); dc += 64; } } } if (!dctbuf) kplib_yrbrend_func(x,y,&dct[0][0]); restartcnt--; if (!restartcnt) { kfileptr += 1-(curbits>>3); curbits = 0; if ((kfileptr[-2] != 255) || (kfileptr[-1] != marker)) kfileptr--; marker++; if (marker >= 0xd8) marker = 0xd0; restartcnt = restartinterval; for (i=0; i<4; i++) lastdc[i] = 0; eobrun = 0; } } kpegrend_break2:; if (!dctbuf) return 0; passcnt++; kfileptr -= ((curbits>>3)+1); break; case 0xd9: break; default: kfileptr += leng; break; } } while (kfileptr-(uint8_t const *)kfilebuf < kfilength); if (!dctbuf) return 0; lnumcomponents = gnumcomponents; for (i=0; i>lshy[c])*dctx[c] + ((x+xx)>>lshx[c]))<<6]; quanptr = &quantab[gcompquantab[c]][0]; for (z=0; z<64; z++) dc[z] = ((int32_t)dcs[zigit[z]])*quanptr[z]; invdct8x8(dc,0xff); } kplib_yrbrend_func(x,y,&dct[0][0]); } Bfree(dctbuf); return 0; } //============================== KPEGILIB ends ============================== //================================ GIF begins ================================ static uint8_t suffix[4100], filbuffer[768], tempstack[4096]; static int32_t prefix[4100]; static int32_t kgifrend(const char *kfilebuf, int32_t kfilelength, intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres) { int32_t i, x, y, xsiz, ysiz, yinc, xend, xspan, yspan, currstr, numbitgoal; int32_t lzcols, dat, blocklen, bitcnt, xoff, transcol; intptr_t yoff; char numbits, startnumbits, chunkind, ilacefirst; const uint8_t *ptr, *cptr = NULL; int32_t daglobxoffs = 0, daglobyoffs = 0; UNREFERENCED_PARAMETER(kfilelength); kcoltype = 3; bitdepth = 8; //For PNGOUT if ((kfilebuf[0] != 'G') || (kfilebuf[1] != 'I') || (kfilebuf[2] != 'F')) return -1; paleng = (1<<((kfilebuf[10]&7)+1)); ptr = (uint8_t const *)&kfilebuf[13]; if (kfilebuf[10]&128) { cptr = ptr; ptr += paleng*3; } transcol = -1; while ((chunkind = *ptr++) == '!') { //! 0xf9 leng flags ? ? transcol if (ptr[0] == 0xf9) { if (ptr[2]&1) transcol = (int32_t)(((uint8_t)ptr[5])); } ptr++; do { i = *ptr++; ptr += i; } while (i); } if (chunkind != ',') return -1; xoff = B_LITTLE16(B_UNBUF16(&ptr[0])); yoff = B_LITTLE16(B_UNBUF16(&ptr[2])); xspan = B_LITTLE16(B_UNBUF16(&ptr[4])); yspan = B_LITTLE16(B_UNBUF16(&ptr[6])); ptr += 9; if (ptr[-1]&64) { yinc = 8; ilacefirst = 1; } else { yinc = 1; ilacefirst = 0; } if (ptr[-1]&128) { paleng = (1<<((ptr[-1]&7)+1)); cptr = ptr; ptr += paleng*3; } for (i=0; i= 0) palcol[transcol] &= B_LITTLE32(~0xff000000); //Handle GIF files with different logical&image sizes or non-0 offsets (added 05/15/2004) xsiz = B_LITTLE16(B_UNBUF16(&kfilebuf[6])); ysiz = B_LITTLE16(B_UNBUF16(&kfilebuf[8])); if ((xoff != 0) || (yoff != 0) || (xsiz != xspan) || (ysiz != yspan)) { daglobxoffs += xoff; //Offset bitmap image by extra amount daglobyoffs += yoff; } xspan += daglobxoffs; yspan += daglobyoffs; //UGLY HACK y = daglobyoffs; if ((uint32_t)y < (uint32_t)dayres) { yoff = y*dakpbytesperline+dakpframeplace; x = daglobxoffs; xend = xspan; } else { x = daglobxoffs+0x80000000; xend = xspan+0x80000000; } lzcols = (1<<(*ptr)); startnumbits = (uint8_t)((*ptr)+1); ptr++; for (i=lzcols-1; i>=0; i--) { suffix[i] = (uint8_t)(prefix[i] = i); } currstr = lzcols+2; numbits = startnumbits; numbitgoal = (lzcols<<1); blocklen = *ptr++; Bmemcpy(filbuffer,ptr,blocklen); ptr += blocklen; bitcnt = 0; while (1) { dat = (B_LITTLE32(B_UNBUF32(&filbuffer[bitcnt>>3]))>>(bitcnt&7)) & (numbitgoal-1); bitcnt += numbits; if ((bitcnt>>3) > blocklen-3) { B_BUF16(filbuffer, B_UNBUF16(&filbuffer[bitcnt>>3])); i = blocklen-(bitcnt>>3); blocklen = (int32_t)*ptr++; Bmemcpy(&filbuffer[i],ptr,blocklen); ptr += blocklen; bitcnt &= 7; blocklen += i; } if (dat == lzcols) { currstr = lzcols+2; numbits = startnumbits; numbitgoal = (lzcols<<1); continue; } if ((currstr == numbitgoal) && (numbits < 12)) { numbits++; numbitgoal <<= 1; } prefix[currstr] = dat; for (i=0; dat>=lzcols; dat=prefix[dat]) tempstack[i++] = suffix[dat]; tempstack[i] = (uint8_t)prefix[dat]; suffix[currstr-1] = suffix[currstr] = (uint8_t)dat; for (; i>=0; i--) { if ((uint32_t)x < (uint32_t)daxres) B_BUF32((void *) (yoff+(x<<2)), palcol[(int32_t)tempstack[i]]); x++; if (x == xend) { y += yinc; if (y >= yspan) switch (yinc) { case 8: if (!ilacefirst) { y = daglobyoffs+2; yinc = 4; break; } ilacefirst = 0; y = daglobyoffs+4; yinc = 8; break; case 4: y = daglobyoffs+1; yinc = 2; break; case 2: case 1: return 0; } if ((uint32_t)y < (uint32_t)dayres) { yoff = y*dakpbytesperline+dakpframeplace; x = daglobxoffs; xend = xspan; } else { x = daglobxoffs+0x80000000; xend = xspan+0x80000000; } } } currstr++; } } //=============================== GIF ends ================================== //============================== CEL begins ================================= // //old .CEL format: //int16_t id = 0x9119, xdim, ydim, xoff, yoff, id = 0x0008; //int32_t imagebytes, filler[4]; //char pal6bit[256][3], image[ydim][xdim]; #ifdef KPCEL static int32_t kcelrend(const char *buf, int32_t fleng, intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres) { int32_t i, x, y, x0, x1, y0, y1, xsiz, ysiz; const char *cptr; UNREFERENCED_PARAMETER(fleng); kcoltype = 3; bitdepth = 8; paleng = 256; //For PNGOUT xsiz = (int32_t)B_LITTLE16(B_UNBUF16(&buf[2])); if (xsiz <= 0) return -1; ysiz = (int32_t)B_LITTLE16(B_UNBUF16(&buf[4])); if (ysiz <= 0) return -1; cptr = &buf[32]; for (i=0; i<256; i++) { palcol[i] = (((int32_t)cptr[0])<<18) + (((int32_t)cptr[1])<<10) + (((int32_t)cptr[2])<< 2) + B_LITTLE32(0xff000000); cptr += 3; } x0 = 0; x1 = xsiz; y0 = 0; y1 = ysiz; for (y=y0; y= 12) || (!((1< 32)) return -1; if (header[17]&0xc0) return -1; fptr = (uint8_t const *)&header[header[0]+18]; xsiz = (int32_t)B_LITTLE16(B_UNBUF16(&header[12])); if (xsiz <= 0) return -1; ysiz = (int32_t)B_LITTLE16(B_UNBUF16(&header[14])); if (ysiz <= 0) return -1; colbyte = ((((int32_t)header[16])+7)>>3); if (header[1] == 1) { pixbyte = ((((int32_t)header[7])+7)>>3); cptr = &fptr[-B_LITTLE16(B_UNBUF16(&header[3]))*pixbyte]; fptr += B_LITTLE16(B_UNBUF16(&header[5]))*pixbyte; } else pixbyte = colbyte; switch (pixbyte) // For PNGOUT { case 1: kcoltype = 0; bitdepth = 8; palcol[0] = B_LITTLE32(0xff000000); for (i = 1; i < 256; i++) palcol[i] = palcol[i - 1] + B_LITTLE32(0x10101); break; case 2: case 3: kcoltype = 2; break; case 4: kcoltype = 6; break; } if (!(header[17]&16)) { x0 = 0; x1 = xsiz; xi = 1; } else { x0 = xsiz-1; x1 = -1; xi =-1; } if (header[17]&32) { y0 = 0; y1 = ysiz; yi = 1; pi = dakpbytesperline; } else { y0 = ysiz-1; y1 = -1; yi =-1; pi =-dakpbytesperline; } if (header[2] < 8) rlestat = -2; else rlestat = -1; p = y0*dakpbytesperline+dakpframeplace; for (y=y0; y!=y1; y+=yi,p+=pi) for (x=x0; x!=x1; x+=xi) { if (rlestat < 128) { if ((rlestat&127) == 127) { rlestat = (int32_t)fptr[0]; fptr++; } if (header[1] == 1) { if (colbyte == 1) i = fptr[0]; else i = (int32_t)B_LITTLE16(B_UNBUF16(&fptr[0])); nptr = &cptr[i*pixbyte]; } else nptr = fptr; switch (pixbyte) { case 1: i = palcol[(int32_t)nptr[0]]; break; case 2: i = (int32_t)B_LITTLE16(B_UNBUF16(&nptr[0])); i = B_LITTLE32(((i&0x7c00)<<9) + ((i&0x03e0)<<6) + ((i&0x001f)<<3) + 0xff000000); break; case 3: i = (B_UNBUF32(&nptr[0])) | B_LITTLE32(0xff000000); break; case 4: i = (B_UNBUF32(&nptr[0])); break; } fptr += colbyte; } if (rlestat >= 0) rlestat--; if (((uint32_t)x < (uint32_t)daxres) && ((uint32_t)y < (uint32_t)dayres)) B_BUF32((void *) (x*4+p), i); } return 0; } //============================== TARGA ends ================================= //============================== BMP begins ================================= //TODO: handle BI_RLE8 and BI_RLE4 (compression types 1&2 respectively) // +---------------+ // | 0(2): "BM" | // +---------------------+| 10(4): rastoff| +------------------+ // |headsiz=12 (OS/2 1.x)|| 14(4): headsiz| | All new formats: | //++---------------------++-------------+-+-+------------------+-----------------------+ //| 18(2): xsiz | 18(4): xsiz | //| 20(2): ysiz | 22(4): ysiz | //| 22(2): planes (always 1) | 26(2): planes (always 1) | //| 24(2): cdim (1,4,8,24) | 28(2): cdim (1,4,8,16,24,32) | //| if (cdim < 16) | 30(4): compression (0,1,2,3!?,4) | //| 26(rastoff-14-headsiz): pal(bgr) | 34(4): (bitmap data size+3)&3 | //| | 46(4): N colors (0=2^cdim) | //| | if (cdim < 16) | //| | 14+headsiz(rastoff-14-headsiz): pal(bgr0) | //+---------------------+---------------+---------+------------------------------------+ // | rastoff(?): bitmap data | // +-------------------------+ static int32_t kbmprend(const char *buf, int32_t fleng, intptr_t dakpframeplace, int32_t dakpbytesperline, int32_t daxres, int32_t dayres) { int32_t i, j, x, y, x0, x1, y0, y1, rastoff, headsiz, xsiz, ysiz, cdim, comp, cptrinc, *lptr; const char *cptr; UNREFERENCED_PARAMETER(fleng); headsiz = B_UNBUF32(&buf[14]); if (headsiz == (int32_t)B_LITTLE32(12)) //OS/2 1.x (old format) { if (B_UNBUF16(&buf[22]) != B_LITTLE16(1)) return -1; xsiz = (int32_t)B_LITTLE16(B_UNBUF16(&buf[18])); ysiz = (int32_t)B_LITTLE16(B_UNBUF16(&buf[20])); cdim = (int32_t)B_LITTLE16(B_UNBUF16(&buf[24])); comp = 0; } else //All newer formats... { if (B_UNBUF16(&buf[26]) != B_LITTLE16(1)) return -1; xsiz = B_LITTLE32(B_UNBUF32(&buf[18])); ysiz = B_LITTLE32(B_UNBUF32(&buf[22])); cdim = (int32_t)B_LITTLE16(B_UNBUF16(&buf[28])); comp = B_LITTLE32(B_UNBUF32(&buf[30])); } if ((xsiz <= 0) || (!ysiz)) return -1; //cdim must be: (1,4,8,16,24,32) if (((uint32_t)(cdim-1) >= (uint32_t)32) || (!((1<>1); } for (palcol[i+3]=0; palcol[i+3]<32; palcol[i+3]++) { if (!(j&1)) break; j = (((uint32_t)j)>>1); } } } palcol[0] = 24-(palcol[0]+palcol[3]); palcol[1] = 16-(palcol[1]+palcol[4]); palcol[2] = 8-(palcol[2]+palcol[5]); palcol[3] = (-(1<<(24-palcol[3]))&0x00ff0000); palcol[4] = (-(1<<(16-palcol[4]))&0x0000ff00); palcol[5] = (-(1<<(8-palcol[5]))&0x000000ff); } cptrinc = (((xsiz*cdim+31)>>3)&~3); cptr = &buf[rastoff]; if (ysiz < 0) { ysiz = -ysiz; } else { cptr = &cptr[(ysiz-1)*cptrinc]; cptrinc = -cptrinc; } x0 = 0; x1 = xsiz; y0 = 0; y1 = ysiz; if (x1 > daxres) x1 = daxres; for (y=y0; y= (uint32_t)dayres) continue; lptr = (int32_t *)(y*dakpbytesperline+dakpframeplace); switch (cdim) { case 1: for (x=x0; x>3]>>((x&7)^7))&1)]; break; case 4: for (x=x0; x>1]>>(((x&1)^1)<<2))&15)]; break; case 8: for (x=x0; x xsiz) { daxres = min(daxres,x1); x1 += bpl-xsiz; } j = nplanes-1; daxres <<= 2; x0 <<= 2; x1 <<= 2; x <<= 2; x += j; if (nplanes == 1) //8-bit PCX { do { c = *cptr++; if (c < 192) i = 1; else { i = (c&63); c = *cptr++; } j = palcol[(int32_t)c]; for (; i; i--) { if ((uint32_t)y < (uint32_t)dayres) if ((uint32_t)x < (uint32_t)daxres) B_BUF32((void *) (x+p), j); x += 4; if (x >= x1) { x = x0; y++; p += dakpbytesperline; } } } while (y < y1); } else if (nplanes == 3) //24-bit PCX { do { c = *cptr++; if (c < 192) i = 1; else { i = (c&63); c = *cptr++; } for (; i; i--) { if ((uint32_t)y < (uint32_t)dayres) if ((uint32_t)x < (uint32_t)daxres) *(char *)(x+p) = c; x += 4; if (x >= x1) { j--; if (j < 0) { j = 3-1; y++; p += dakpbytesperline; } x = x0+j; } } } while (y < y1); } return 0; } //=============================== PCX ends ================================== //============================== DDS begins ================================= //Note:currently supports: DXT1,DXT2,DXT3,DXT4,DXT5,A8R8G8B8 #ifdef KPDDS static int32_t kddsrend(const char *buf, int32_t leng, intptr_t frameptr, int32_t bpl, int32_t xdim, int32_t ydim, int32_t xoff, int32_t yoff) { int32_t x, y, z = 0, xx, yy, xsiz, ysiz, dxt, al[2], ai, k, v, c0, c1, stride; intptr_t j; uint32_t lut[256], r[4], g[4], b[4], a[8], rr, gg, bb; uint8_t *uptr, *wptr; UNREFERENCED_PARAMETER(leng); xsiz = B_LITTLE32(B_UNBUF32(&buf[16])); ysiz = B_LITTLE32(B_UNBUF32(&buf[12])); if ((B_UNBUF32(&buf[80]))&B_LITTLE32(64)) //Uncompressed supports only A8R8G8B8 for now { if ((B_UNBUF32(&buf[88])) != B_LITTLE32(32)) return -1; if ((B_UNBUF32(&buf[92])) != B_LITTLE32(0x00ff0000)) return -1; if ((B_UNBUF32(&buf[96])) != B_LITTLE32(0x0000ff00)) return -1; if ((B_UNBUF32(&buf[100])) != B_LITTLE32(0x000000ff)) return -1; if ((B_UNBUF32(&buf[104])) != B_LITTLE32(0xff000000)) return -1; buf += 128; j = yoff*bpl + (xoff<<2) + frameptr; xx = (xsiz<<2); if (xoff < 0) { j -= (xoff<<2); buf -= (xoff<<2); xsiz += xoff; } xsiz = (min(xsiz,xdim-xoff)<<2); ysiz = min(ysiz,ydim); for (y=0; y= (uint32_t)ydim) continue; Bmemcpy((void *)j,(void *)buf,xsiz); } return 0; } if (!((B_UNBUF32(&buf[80]))&B_LITTLE32(4))) return -1; //FOURCC invalid dxt = buf[87]-'0'; if ((buf[84] != 'D') || (buf[85] != 'X') || (buf[86] != 'T') || (dxt < 1) || (dxt > 5)) return -1; buf += 128; if (!(dxt&1)) { for (z=256-1; z>0; z--) lut[z] = tabledivide32_noinline(255<<16, z); lut[0] = (1<<16); } if (dxt == 1) stride = (xsiz<<1); else stride = (xsiz<<2); for (y=0; y>8)&0xf8); g[0] = ((c0>>3)&0xfc); b[0] = ((c0<<3)&0xfc); a[0] = 255; c1 = B_LITTLE16(B_UNBUF16(&uptr[2])); r[1] = ((c1>>8)&0xf8); g[1] = ((c1>>3)&0xfc); b[1] = ((c1<<3)&0xfc); a[1] = 255; if ((c0 > c1) || (dxt != 1)) { r[2] = (((r[0]*2 + r[1] + 1)*(65536/3))>>16); g[2] = (((g[0]*2 + g[1] + 1)*(65536/3))>>16); b[2] = (((b[0]*2 + b[1] + 1)*(65536/3))>>16); a[2] = 255; r[3] = (((r[0] + r[1]*2 + 1)*(65536/3))>>16); g[3] = (((g[0] + g[1]*2 + 1)*(65536/3))>>16); b[3] = (((b[0] + b[1]*2 + 1)*(65536/3))>>16); a[3] = 255; } else { r[2] = (r[0] + r[1])>>1; g[2] = (g[0] + g[1])>>1; b[2] = (b[0] + b[1])>>1; a[2] = 255; r[3] = g[3] = b[3] = a[3] = 0; //Transparent } v = B_LITTLE32(B_UNBUF32(&uptr[4])); if (dxt >= 4) { a[0] = uptr[-8]; a[1] = uptr[-7]; k = a[1]-a[0]; if (k < 0) { z = a[0]*6 + a[1] + 3; for (j=2; j<8; j++) { a[j] = ((z*(65536/7))>>16); z += k; } } else { z = a[0]*4 + a[1] + 2; for (j=2; j<6; j++) { a[j] = ((z*(65536/5))>>16); z += k; } a[6] = 0; a[7] = 255; } al[0] = B_LITTLE32(B_UNBUF32(&uptr[-6])); al[1] = B_LITTLE32(B_UNBUF32(&uptr[-3])); } wptr = (uint8_t *)((y+yoff)*bpl + ((x+xoff)<<2) + frameptr); ai = 0; for (yy=0; yy<4; yy++,wptr+=bpl) { if ((uint32_t)(y+yy+yoff) >= (uint32_t)ydim) { ai += 4; continue; } for (xx=0; xx<4; xx++,ai++) { if ((uint32_t)(x+xx+xoff) >= (uint32_t)xdim) continue; j = ((v>>(ai<<1))&3); switch (dxt) { case 1: z = a[j]; break; case 2: case 3: z = ((uptr[(ai>>1)-8] >> ((xx&1)<<2))&15)*17; break; case 4: case 5: z = a[(al[yy>>1] >> ((ai&7)*3))&7]; break; } rr = r[j]; gg = g[j]; bb = b[j]; if (!(dxt&1)) { bb = min((bb*lut[z])>>16,255); gg = min((gg*lut[z])>>16,255); rr = min((rr*lut[z])>>16,255); } wptr[(xx<<2)+0] = (uint8_t)bb; wptr[(xx<<2)+1] = (uint8_t)gg; wptr[(xx<<2)+2] = (uint8_t)rr; wptr[(xx<<2)+3] = (uint8_t)z; } } } return 0; } #endif //=============================== DDS ends ================================== //=================== External picture interface begins ====================== static int32_t istarga(const uint8_t *buf, int32_t leng) { return ((leng >= 19) && (!(buf[1]&0xfe)) && (buf[2] < 12) && ((1< kzhashsiz) //Make sure string fits in kzhashbuf { int32_t i = kzhashsiz; do { i <<= 1; } while (kzhashpos+siz > i); kzhashbuf = (char *)Xrealloc(kzhashbuf,i); if (!kzhashbuf) return 0; kzhashsiz = i; } return 1; } static int32_t kzcalchash(const char *st) { int32_t i, hashind; for (i=0,hashind=0; st[i]; i++) hashind = toupperlookup[st[i]]-((hashind<<1)+hashind); return hashind%ARRAY_SIZE(kzhashead); } static int32_t kzcheckhash(const char *filnam, char **zipnam, int32_t *fileoffs, int32_t *fileleng, char *iscomp) { int32_t i; if (!kzhashbuf) return 0; if (filnam[0] == '|') filnam++; for (i=kzhashead[kzcalchash(filnam)]; i>=0; i=(B_UNBUF32(&kzhashbuf[i]))) if (!filnamcmp(filnam,&kzhashbuf[i+21])) { (*zipnam) = &kzhashbuf[B_UNBUF32(&kzhashbuf[i+8])]; (*fileoffs) = B_UNBUF32(&kzhashbuf[i+12]); (*fileleng) = B_UNBUF32(&kzhashbuf[i+16]); (*iscomp) = kzhashbuf[i+20]; return 1; } return 0; } void kzuninit() { DO_FREE_AND_NULL(kzhashbuf); kzhashpos = kzhashsiz = 0; kzdirnamhead = -1; } //If file found, loads internal directory from ZIP/GRP into memory (hash) to allow faster access later //If file not found, assumes it's a directory and adds it to an internal list int32_t kzaddstack(const char *filnam) { FILE *fil; int32_t i, j, k, leng, hashind, zipnamoffs, numfiles; char tempbuf[260+46]; fil = fopen(filnam,"rb"); if (!fil) //if file not found, assume it's a directory { //Add directory name to internal list (using kzhashbuf for convenience of dynamic allocation) i = strlen(filnam)+5; if (!kzcheckhashsiz(i)) return -1; B_BUF32(&kzhashbuf[kzhashpos], kzdirnamhead); kzdirnamhead = kzhashpos; strcpy(&kzhashbuf[kzhashpos+4],filnam); kzhashpos += i; return -1; } //Write ZIP/GRP filename to hash i = strlen(filnam)+1; if (!kzcheckhashsiz(i)) { fclose(fil); return -1; } strcpy(&kzhashbuf[kzhashpos],filnam); zipnamoffs = kzhashpos; kzhashpos += i; fread(&i,4,1,fil); if (i == (int32_t)B_LITTLE32(0x04034b50)) //'PK\3\4' is ZIP file id { fseek(fil,-22,SEEK_END); fread(tempbuf,22,1,fil); if (B_UNBUF32(&tempbuf[0]) == B_LITTLE32(0x06054b50)) //Fast way of finding dir info { numfiles = B_LITTLE16(B_UNBUF16(&tempbuf[10])); fseek(fil,B_LITTLE32(B_UNBUF32(&tempbuf[16])),SEEK_SET); } else //Slow way of finding dir info (used when ZIP has junk at end) { fseek(fil,0,SEEK_SET); numfiles = 0; while (1) { if (!fread(&j,4,1,fil)) { numfiles = -1; break; } if (j == (int32_t)B_LITTLE32(0x02014b50)) break; //Found central file header :) if (j != (int32_t)B_LITTLE32(0x04034b50)) { numfiles = -1; break; } fread(tempbuf,26,1,fil); fseek(fil,B_LITTLE32(B_UNBUF32(&tempbuf[14])) + B_LITTLE16(B_UNBUF16(&tempbuf[24])) + B_LITTLE16(B_UNBUF16(&tempbuf[22])),SEEK_CUR); numfiles++; } if (numfiles < 0) { fclose(fil); return -1; } fseek(fil,-4,SEEK_CUR); } for (i=0; i 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 int const namlen = strlen(filnam); for (i=kzdirnamhead; i>=0; i=B_UNBUF32(&kzhashbuf[i])) { strcpy(tempbuf,&kzhashbuf[i+4]); uint32_t const j = strlen(tempbuf); if (namlen+1+j >= sizeof(tempbuf)) continue; //don't allow int32_t filenames to buffer overrun if ((j) && (tempbuf[j-1] != '/') && (tempbuf[j-1] != '\\') && (filnam[0] != '/') && (filnam[0] != '\\')) #if defined(_WIN32) strcat(tempbuf,"\\"); #else strcat(tempbuf,"/"); #endif strcat(tempbuf,filnam); kzfs.fil = 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 const *s = "."; if (wildstpathleng > 0) { filnam[wildstpathleng] = 0; s = filnam; } hfind = opendir(s); if (!hfind) { if (!kzhashbuf) return 0; srchstat = 2; continue; } } break; // process srchstat == 1 #endif return 1; } while (0); } if (srchstat == 1) { while (1) { Bmemcpy(filnam,newildst,wildstpathleng); #if defined(_WIN32) if (!FindNextFile(hfind,&findata)) { FindClose(hfind); hfind = INVALID_HANDLE_VALUE; if (!kzhashbuf) return 0; srchstat = 2; break; } if (findata.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) continue; i = wildstpathleng; if (findata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) if ((findata.cFileName[0] == '.') && (!findata.cFileName[1])) continue; strcpy(&filnam[i],findata.cFileName); if (findata.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) strcat(&filnam[i],"\\"); #else if ((findata = readdir(hfind)) == NULL) { closedir(hfind); hfind = NULL; if (!kzhashbuf) return 0; srchstat = 2; break; } i = wildstpathleng; if (findata->d_type == DT_DIR) { if (findata->d_name[0] == '.' && !findata->d_name[1]) continue; } //skip . else if ((findata->d_type == DT_REG) || (findata->d_type == DT_LNK)) { if (findata->d_name[0] == '.') continue; } //skip hidden (dot) files else continue; //skip devices and fifos and such if (!wildmatch(findata->d_name,&newildst[wildstpathleng])) continue; strcpy(&filnam[i],findata->d_name); if (findata->d_type == DT_DIR) strcat(&filnam[i],"/"); #endif return 1; } } while (srchstat == 2) { if (srchzoff < 0) { srchstat = 3; break; } if (wildmatch(&kzhashbuf[srchzoff+21],newildst)) { //strcpy(filnam,&kzhashbuf[srchzoff+21]); filnam[0] = '|'; strcpy(&filnam[1],&kzhashbuf[srchzoff+21]); srchzoff = B_UNBUF32(&kzhashbuf[srchzoff+4]); return 1; } srchzoff = B_UNBUF32(&kzhashbuf[srchzoff+4]); } while (srchstat == 3) { if (srchdoff < 0) { srchstat = -1; break; } strcpy(newildst,&kzhashbuf[srchdoff+4]); i = strlen(newildst); if ((i) && (newildst[i-1] != '/') && (newildst[i-1] != '\\') && (filnam[0] != '/') && (filnam[0] != '\\')) #if defined(_WIN32) strcat(newildst,"\\"); #else strcat(newildst,"/"); #endif strcat(newildst,wildst); srchdoff = B_UNBUF32(&kzhashbuf[srchdoff]); srchstat = 0; goto kzfindfile_beg; } return 0; } //File searching code (supports inside ZIP files!) How to use this code: // char filnam[MAX_PATH]; // kzfindfilestart("vxl/*.vxl"); // while (kzfindfile(filnam)) puts(filnam); //NOTES: // * Directory names end with '\' or '/' (depending on system) // * Files inside zip begin with '|' // -------------------------------------------------------------------------- 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(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= gslider) { putbuf4zip(&slidebuf[(gslider-16384)&32767],gslider-16384,gslider); gslider += 16384; if (gslider-16384 >= kzfs.endpos) { kzfs.jmpplc = 2; kzfs.bfinal = bfinal; goto retkzread; kzreadplc2:; bfinal = kzfs.bfinal; } } k = peekbits(LOGQHUFSIZ0); if (qhufbit0[k]) { i = qhufval0[k]; suckbits((int32_t)qhufbit0[k]); } else i = hufgetsym(ibuf0,nbuf0); if (i < 256) { slidebuf[(gslidew++)&32767] = (uint8_t)i; continue; } if (i == 256) break; i = getbits(hxbit[i+30-257][0]) + hxbit[i+30-257][1]; k = peekbits(LOGQHUFSIZ1); if (qhufbit1[k]) { j = qhufval1[k]; suckbits((int32_t)qhufbit1[k]); } else j = hufgetsym(ibuf1,nbuf1); j = getbits(hxbit[j][0]) + hxbit[j][1]; for (; i; i--,gslidew++) slidebuf[gslidew&32767] = slidebuf[(gslidew-j)&32767]; } } while (!bfinal); gslider -= 16384; if (!((gslider^gslidew)&32768)) putbuf4zip(&slidebuf[gslider&32767],gslider,gslidew); else { putbuf4zip(&slidebuf[gslider&32767],gslider,gslidew&~32767); putbuf4zip(slidebuf,gslidew&~32767,gslidew); } kzreadplc3:; kzfs.jmpplc = 3; } retkzread:; i = kzfs.pos; kzfs.pos += leng; if (kzfs.pos > kzfs.leng) kzfs.pos = kzfs.leng; return kzfs.pos-i; } //WARNING: kzseek(<-32768,SEEK_CUR); or: // kzseek(0,SEEK_END); can make next kzread very slow!!! int32_t kzseek(int32_t offset, int32_t whence) { if (!kzfs.fil) return -1; switch (whence) { case SEEK_CUR: kzfs.pos += offset; break; case SEEK_END: kzfs.pos = kzfs.leng+offset; break; case SEEK_SET: default: kzfs.pos = offset; } if (kzfs.pos < 0) kzfs.pos = 0; if (kzfs.pos > kzfs.leng) kzfs.pos = kzfs.leng; return kzfs.pos; } //====================== ZIP decompression code ends ========================= //===================== HANDY PICTURE function begins ======================== #include "cache1d.h" void kpzdecode(int32_t const leng, intptr_t * const pic, int32_t * const xsiz, int32_t * const ysiz) { *pic = 0; kpgetdim(kpzbuf, leng, xsiz, ysiz); *pic = (intptr_t)Xmalloc(*ysiz * ((*xsiz)<<2)); if (!*pic) return; if (kprender(kpzbuf, leng, *pic, ((*xsiz)<<2), *xsiz, *ysiz) < 0) { Bfree((void *) *pic); *pic = (intptr_t)NULL; } } void kpzload(const char * const filnam, intptr_t * const pic, int32_t * const xsiz, int32_t * const ysiz) { kpzdecode(kpzbufload(filnam), pic, xsiz, ysiz); } //====================== HANDY PICTURE function ends =========================