1 /*
2  * OpenBOR - http://www.chronocrash.com
3  * -----------------------------------------------------------------------
4  * All rights reserved, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2014 OpenBOR Team
7  */
8 
9 // Functions to load GIF, PCX and BMP files.
10 // Last update: 26-jan-2003
11 // Now loading to screens or bitmaps,
12 // creating them on-the-fly if necessary.
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <assert.h>
17 #include "utils.h"
18 #include "types.h"
19 #include "borendian.h"
20 #include "bitmap.h"
21 #include "screen.h"
22 #include "packfile.h"
23 #include "png.h"
24 #include "pngdec.h"
25 
26 #ifndef DC
27 #pragma pack (1)
28 #endif
29 
30 // ============================== Globals ===============================
31 
32 static int handle = -1;
33 static int res[2] = {0, 0};	// Resolution of opened image
34 
35 // ============================== BMP loading ===============================
36 
37 typedef struct
38 {
39     unsigned short	bm;
40     int		        filesize;
41     int		        reserved;
42     int		        picstart;
43     int		        headersize;
44     int		        xsize;
45     int		        ysize;
46     unsigned short	numplanes;
47     unsigned short	bpp;
48     int		        compression;
49     int		        picsize;
50     int		        hres;
51     int		        vres;
52     int		        numcolors_used;
53     int		        numcolors_important;
54 } s_bmpheader;
55 
56 static s_bmpheader bmp_header;
57 
58 #if DC || GP2X || SYMBIAN
build_bmp_header(s_bmpheader * h,const unsigned char * s)59 static void build_bmp_header(s_bmpheader *h, const unsigned char *s)
60 {
61 
62     h->bm          = readlsb32(s + 0x00);
63     h->filesize    = readlsb32(s + 0x02);
64     h->reserved    = readlsb32(s + 0x06);
65     h->picstart    = readlsb32(s + 0x0A);
66     h->headersize  = readlsb32(s + 0x0E);
67     h->xsize       = readlsb32(s + 0x12);
68     h->ysize       = readlsb32(s + 0x16);
69     h->numplanes   = readlsb32(s + 0x1A);
70     h->bpp         = readlsb32(s + 0x1C);
71     h->compression = readlsb32(s + 0x1E);
72     h->picsize     = readlsb32(s + 0x22);
73     h->hres        = readlsb32(s + 0x26);
74     h->vres        = readlsb32(s + 0x2A);
75     h->numcolors_used      = readlsb32(s + 0x2E);
76     h->numcolors_important = readlsb32(s + 0x32);
77 }
78 #endif
79 
80 // Open a BMP stream
openbmp(char * filename,char * packfilename)81 static int openbmp(char *filename, char *packfilename)
82 {
83 
84 #if DC || GP2X || SYMBIAN
85     unsigned char mybmpheader[0x36];
86 #endif
87 
88     if((handle = openpackfile(filename, packfilename)) == -1)
89     {
90         return 0;
91     }
92 #if DC || GP2X || SYMBIAN
93     if(readpackfile(handle, &mybmpheader, 0x36) != 0x36)
94     {
95 #else
96     if(readpackfile(handle, &bmp_header, sizeof(s_bmpheader)) != sizeof(s_bmpheader))
97     {
98 #endif
99         closepackfile(handle);
100         return 0;
101     }
102 
103 #if DC || GP2X || SYMBIAN
104     build_bmp_header(&bmp_header, mybmpheader);
105 #else
106     bmp_header.bm = SwapLSB16(bmp_header.bm);
107     bmp_header.numplanes = SwapLSB16(bmp_header.numplanes);
108     bmp_header.bpp = SwapLSB16(bmp_header.bpp);
109 
110     bmp_header.filesize = SwapLSB32(bmp_header.filesize);
111     bmp_header.reserved = SwapLSB32(bmp_header.reserved);
112     bmp_header.picstart = SwapLSB32(bmp_header.picstart);
113     bmp_header.headersize = SwapLSB32(bmp_header.headersize);
114     bmp_header.xsize = SwapLSB32(bmp_header.xsize);
115     bmp_header.ysize = SwapLSB32(bmp_header.ysize);
116     bmp_header.filesize = SwapLSB32(bmp_header.filesize);
117 
118     bmp_header.compression = SwapLSB32(bmp_header.compression);
119     bmp_header.picsize = SwapLSB32(bmp_header.picsize);
120     bmp_header.hres = SwapLSB32(bmp_header.hres);
121     bmp_header.vres = SwapLSB32(bmp_header.vres);
122     bmp_header.numcolors_used = SwapLSB32(bmp_header.numcolors_used);
123     bmp_header.numcolors_important = SwapLSB32(bmp_header.numcolors_important);
124 #endif
125 
126     if(bmp_header.bm != 0x4D42 || bmp_header.bpp != 8 || bmp_header.compression)
127     {
128         closepackfile(handle);
129         return 0;
130     }
131     res[0] = bmp_header.xsize;
132     res[1] = bmp_header.ysize;
133     return 1;
134 }
135 
136 // Read data from the bitmap file
137 static int readbmp(unsigned char *buf, unsigned char *pal, int maxwidth, int maxheight)
138 {
139 
140     unsigned char *linebuffer;
141     int y, s, d;
142     int pb = PAL_BYTES;
143 
144     if(buf)
145     {
146         y = 0;
147         while(y < maxheight && y < bmp_header.ysize)
148         {
149             linebuffer = buf + y * maxwidth;
150             seekpackfile(handle, bmp_header.picstart + ((bmp_header.ysize - y - 1)*bmp_header.xsize), SEEK_SET);
151             readpackfile(handle, linebuffer, bmp_header.xsize);
152             ++y;
153         }
154     }
155 
156     if(pal && (linebuffer = (unsigned char *)malloc(1024)))
157     {
158         seekpackfile(handle, bmp_header.picstart - 1024, SEEK_SET);
159         readpackfile(handle, linebuffer, 1024);
160         if(pb == 512) // 16bit 565
161         {
162             for(s = 0, d = 0; s < 1024; s += 4, d += 2)
163             {
164                 *(unsigned short *)(pal + d) = colour16(linebuffer[s + 2], linebuffer[s + 1], linebuffer[s]);
165             }
166         }
167         else if(pb == 768) // 24bit palette, RGBA-BGR
168         {
169             for(s = 0, d = 0; s < 1024; s += 4, d += 3)
170             {
171                 pal[d] = linebuffer[s + 2];
172                 pal[d + 1] = linebuffer[s + 1];
173                 pal[d + 2] = linebuffer[s];
174             }
175         }
176         else if(pb == 1024)
177         {
178             for(s = 0, d = 0; s < 1024; s += 4, d += 4)
179             {
180                 *(unsigned *)(pal + d) = colour32(linebuffer[s + 2], linebuffer[s + 1], linebuffer[s]);
181             }
182         }
183         free(linebuffer);
184         linebuffer = NULL;
185     }
186 
187     return 1;
188 }
189 
190 //static void closebmp(){
191 //	closepackfile(handle);
192 //	handle = -1;
193 //}
194 
195 //============================ PNG, use libpng =============================
196 static int png_height = 0;
197 static png_structp png_ptr = NULL;
198 static png_infop info_ptr = NULL;
199 static png_bytep *row_pointers = NULL;
200 
201 static void png_read_fn(png_structp pngp, png_bytep outp, png_size_t size)
202 {
203     readpackfile(*(int *)(png_get_io_ptr(pngp)), outp, size);
204 }
205 
206 static void png_read_destroy_all()
207 {
208     if(png_ptr)
209     {
210         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
211     }
212     info_ptr = NULL;
213     png_ptr = NULL;
214 }
215 
216 static void closepng()
217 {
218     int y;
219     png_read_destroy_all();
220     if(row_pointers)
221     {
222         for (y = 0; y < png_height; y++)
223         {
224             free(row_pointers[y]);
225             row_pointers[y] = NULL;
226         }
227         free(row_pointers);
228         row_pointers = NULL;
229     }
230     png_height = 0;
231     if(handle >= 0)
232     {
233         closepackfile(handle);
234     }
235     handle = -1;
236 }
237 
238 static int openpng(char *filename, char *packfilename)
239 {
240     unsigned char header[8];    // 8 is the maximum size that can be checked
241     int y;
242 
243     if((handle = openpackfile(filename, packfilename)) == -1)
244     {
245         goto openpng_abort;
246     }
247 
248     if(readpackfile(handle, header, 8) != 8)
249     {
250         goto openpng_abort;
251     }
252 
253     if (png_sig_cmp(header, 0, 8))
254     {
255         goto openpng_abort;
256     }
257 
258     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
259 
260     if (!png_ptr)
261     {
262         goto openpng_abort;
263     }
264 
265     //UT: use customized file read function here, because we use pak file methods instead of stdio
266     png_set_read_fn(png_ptr, &handle, png_read_fn);
267 
268     info_ptr = png_create_info_struct(png_ptr);
269     if (!info_ptr)
270     {
271         goto openpng_abort;
272     }
273 
274     png_set_sig_bytes(png_ptr, 8);
275     png_read_info(png_ptr, info_ptr);
276 
277     //UT: not formal here, but just read what we need since we use only 8bit png for now
278     res[0] = png_get_image_width(png_ptr, info_ptr);
279     png_height = res[1] = png_get_image_height(png_ptr, info_ptr);
280     // should only be a 8bit image by now
281     if (png_get_bit_depth(png_ptr, info_ptr) != 8)
282     {
283         goto openpng_abort;
284     }
285 
286     png_read_update_info(png_ptr, info_ptr);
287 
288     row_pointers = (png_bytep *) malloc(sizeof(png_bytep) * png_height);
289     for (y = 0; y < png_height; y++)
290     {
291         row_pointers[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr));
292     }
293 
294     png_read_image(png_ptr, row_pointers);
295     return 1;
296 openpng_abort:
297     closepng();
298     return 0;
299 }
300 
301 static int readpng(unsigned char *buf, unsigned char *pal, int maxwidth, int maxheight)
302 {
303     int i, j, cw, ch;
304     png_colorp png_pal_ptr = 0;
305     int png_pal_num = 0;
306     int pb = PAL_BYTES;
307 
308     cw = res[0] > maxwidth ? maxwidth : res[0];
309     ch = res[1] > maxheight ? maxheight : res[1];
310     if(buf)
311     {
312         for(i = 0; i < ch; i++)
313         {
314             memcpy(buf + (maxwidth * i), row_pointers[i], cw);
315         }
316     }
317     if(pal)
318     {
319         if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY)
320         {
321             // set palette for grayscale images
322             for(i = 0; i < 256; i++)
323             {
324                 pal[i * 3] = pal[i * 3 + 1] = pal[i * 3 + 2] = i;
325             }
326             return 1;
327         }
328         else if(png_get_PLTE(png_ptr, info_ptr, &png_pal_ptr, &png_pal_num) != PNG_INFO_PLTE ||
329                 png_pal_ptr == NULL)
330         {
331             return 0;
332         }
333 
334         png_pal_ptr[0].red = png_pal_ptr[0].green = png_pal_ptr[0].blue = 0;
335         if(pb == 512) // 16bit 565
336         {
337             for(i = 0, j = 0; i < 512 && j < png_pal_num; i += 2, j++)
338             {
339                 *(unsigned short *)(pal + i) = colour16(png_pal_ptr[j].red, png_pal_ptr[j].green, png_pal_ptr[j].blue);
340             }
341         }
342         else if(pb == 768) // 24bit
343         {
344             for(i = 0; i < png_pal_num; i++)
345             {
346                 pal[i * 3] = png_pal_ptr[i].red;
347                 pal[i * 3 + 1] = png_pal_ptr[i].green;
348                 pal[i * 3 + 2] = png_pal_ptr[i].blue;
349             }
350         }
351         else if(pb == 1024) // 32bit
352         {
353 
354             for(i = 0, j = 0; i < 1024 && j < png_pal_num; i += 4, j++)
355             {
356                 *(unsigned *)(pal + i) = colour32(png_pal_ptr[j].red, png_pal_ptr[j].green, png_pal_ptr[j].blue);
357             }
358         }
359     }
360     return 1;
361 }
362 
363 
364 // ============================== GIF loading ===============================
365 
366 
367 typedef struct
368 {
369     char		    magic[6];
370     unsigned short	screenwidth, screenheight;
371     unsigned char	flags;
372     unsigned char	background;
373     unsigned char	aspect;
374 } gifheaderstruct;
375 
376 #if DC || GP2X || SYMBIAN
377 #define sizeof_gifheaderstruct 13
378 #endif
379 
380 typedef struct
381 {
382     unsigned short   left, top, width, height;
383     unsigned char    flags;
384 } gifblockstruct;
385 
386 #if DC || GP2X || SYMBIAN
387 #define sizeof_iblock 9
388 #endif
389 
390 static gifheaderstruct gif_header;
391 
392 static unsigned char readbyte(int handle)
393 {
394     unsigned char c = 0;
395     readpackfile(handle, &c, 1);
396     return c;
397 }
398 
399 #define NO_CODE -1
400 
401 static int decodegifblock(int handle, unsigned char *buf, int width, int height, unsigned char bits, gifblockstruct *gb)
402 {
403     short bits2;
404     short codesize;
405     short codesize2;
406     short nextcode;
407     short thiscode;
408     short oldtoken;
409     short currentcode;
410     short oldcode;
411     short bitsleft;
412     short blocksize;
413     int line = 0;
414     int byte = gb->left;
415     int pass = 0;
416 
417     unsigned char *p;
418     unsigned char *u;
419 
420     unsigned char *q;
421     unsigned char b[255];
422     unsigned char *linebuffer;
423 
424     static unsigned char firstcodestack[4096];
425     static unsigned char lastcodestack[4096];
426     static short codestack[4096];
427 
428     static short wordmasktable[] = {    0x0000, 0x0001, 0x0003, 0x0007,
429                                         0x000f, 0x001f, 0x003f, 0x007f,
430                                         0x00ff, 0x01ff, 0x03ff, 0x07ff,
431                                         0x0fff, 0x1fff, 0x3fff, 0x7fff
432                                    };
433 
434     static short inctable[] = { 8, 8, 4, 2, 0 };
435     static short startable[] = { 0, 4, 2, 1, 0 };
436 
437     p = q = b;
438     bitsleft = 8;
439 
440     if (bits < 2 || bits > 8)
441     {
442         return 0;    // Bad symbol
443     }
444     bits2 = 1 << bits;
445     nextcode = bits2 + 2;
446     codesize2 = 1 << (codesize = bits + 1);
447     oldcode = oldtoken = NO_CODE;
448 
449     linebuffer = buf + (gb->top * width);
450 
451     // loop until something breaks
452     for(;;)
453     {
454         if(bitsleft == 8)
455         {
456             if(++p >= q && (((blocksize = (unsigned char)readbyte(handle)) < 1) ||
457                             (q = (p = b) + readpackfile(handle, b, blocksize)) < (b + blocksize)))
458             {
459                 return 0;        // Unexpected EOF
460             }
461             bitsleft = 0;
462         }
463         thiscode = *p;
464         if((currentcode = (codesize + bitsleft)) <= 8)
465         {
466             *p >>= codesize;
467             bitsleft = currentcode;
468         }
469         else
470         {
471             if(++p >= q && (((blocksize = (unsigned char)readbyte(handle)) < 1) ||
472                             (q = (p = b) + readpackfile(handle, b, blocksize)) < (b + blocksize)))
473             {
474                 return 0;        // Unexpected EOF
475             }
476 
477             thiscode |= *p << (8 - bitsleft);
478             if(currentcode <= 16)
479             {
480                 *p >>= (bitsleft = currentcode - 8);
481             }
482             else
483             {
484                 if(++p >= q && (((blocksize = (unsigned char)readbyte(handle)) < 1) ||
485                                 (q = (p = b) + readpackfile(handle, b, blocksize)) < (b + blocksize)))
486                 {
487                     return 0;    // Unexpected EOF
488                 }
489 
490                 thiscode |= *p << (16 - bitsleft);
491                 *p >>= (bitsleft = currentcode - 16);
492             }
493         }
494         thiscode &= wordmasktable[codesize];
495         currentcode = thiscode;
496 
497         if(thiscode == (bits2 + 1))
498         {
499             break;
500         }
501         if(thiscode > nextcode)
502         {
503             return 0;    // Bad code
504         }
505 
506         if(thiscode == bits2)
507         {
508             nextcode = bits2 + 2;
509             codesize2 = 1 << (codesize = (bits + 1));
510             oldtoken = oldcode = NO_CODE;
511             continue;
512         }
513 
514         u = firstcodestack;
515 
516         if(thiscode == nextcode)
517         {
518             if(oldcode == NO_CODE)
519             {
520                 return 0;    // Bad code
521             }
522             *u++ = oldtoken;
523             thiscode = oldcode;
524         }
525 
526         while(thiscode >= bits2)
527         {
528             *u++ = lastcodestack [thiscode];
529             thiscode = codestack[thiscode];
530         }
531 
532         oldtoken = thiscode;
533         do
534         {
535             if(byte < width && line < (height - gb->top))
536             {
537                 linebuffer[byte] = thiscode;
538             }
539             byte++;
540             if(byte >= gb->left + gb->width)
541             {
542                 byte = gb->left;
543                 // check for interlaced image
544                 if(gb->flags & 0x40)
545                 {
546                     line += inctable[pass];
547                     if(line >= gb->height)
548                     {
549                         line = startable[++pass];
550                     }
551                 }
552                 else
553                 {
554                     ++line;
555                 }
556                 linebuffer = buf + (width * (gb->top + line));
557             }
558             if (u <= firstcodestack)
559             {
560                 break;
561             }
562             thiscode = *--u;
563         }
564         while(1);
565 
566         if(nextcode < 4096 && oldcode != NO_CODE)
567         {
568             codestack[nextcode] = oldcode;
569             lastcodestack[nextcode] = oldtoken;
570             if(++nextcode >= codesize2 && codesize < 12)
571             {
572                 codesize2 = 1 << ++codesize;
573             }
574         }
575         oldcode = currentcode;
576     }
577     return 1;
578 }
579 
580 static void passgifblock(int handle)
581 {
582     int len;
583 
584     // Discard extension function code
585     len = readbyte(handle);
586     // Skip all contained blocks
587     while((len = readbyte(handle)) != 0)
588     {
589         seekpackfile(handle, len, SEEK_CUR);
590     }
591 }
592 
593 static int opengif(char *filename, char *packfilename)
594 {
595 
596     if((handle = openpackfile(filename, packfilename)) == -1)
597     {
598         return 0;
599     }
600 
601 #if DC || GP2X || SYMBIAN
602     if(readpackfile(handle, &gif_header, sizeof_gifheaderstruct) != sizeof_gifheaderstruct)
603     {
604 #else
605     if(readpackfile(handle, &gif_header, sizeof(gifheaderstruct)) != sizeof(gifheaderstruct))
606     {
607 #endif
608         closepackfile(handle);
609         return 0;
610     }
611     if(gif_header.magic[0] != 'G' || gif_header.magic[1] != 'I' || gif_header.magic[2] != 'F')
612     {
613         // Not a GIF file!
614         closepackfile(handle);
615         return 0;
616     }
617 
618     gif_header.screenwidth = SwapLSB16(gif_header.screenwidth);
619     gif_header.screenheight = SwapLSB16(gif_header.screenheight);
620 
621     res[0] = gif_header.screenwidth;
622     res[1] = gif_header.screenheight;
623 
624     return 1;
625 }
626 
627 static int readgif(unsigned char *buf, unsigned char *pal, int maxwidth, int maxheight)
628 {
629 
630     gifblockstruct iblock;
631     int bitdepth;
632     int numcolours;
633     int i, j;
634     int done = 0;
635     unsigned char *pbuf;
636     unsigned char c;
637     int pb = PAL_BYTES;
638 
639 
640     bitdepth = (gif_header.flags & 7) + 1;
641     numcolours = (1 << bitdepth);
642 
643 
644     // get palette if present and if wanted
645     if(gif_header.flags & 0x80)
646     {
647         if(pal)
648         {
649             if(pb == 512) // 16bit 565
650             {
651                 pbuf = malloc(768);
652                 if(readpackfile(handle, pbuf, numcolours * 3) != numcolours * 3)
653                 {
654                     free(pbuf);
655                     pbuf = NULL;
656                     return 0;
657                 }
658                 for(i = 0, j = 0; i < 512; i += 2, j += 3)
659                 {
660                     *(unsigned short *)(pal + i) = colour16(pbuf[j], pbuf[j + 1], pbuf[j + 2]);
661                 }
662                 free(pbuf);
663                 pbuf = NULL;
664             }
665             else if(pb == 768) // 24bit
666             {
667                 if(readpackfile(handle, pal, numcolours * 3) != numcolours * 3)
668                 {
669                     return 0;
670                 }
671             }
672             else if(pb == 1024) // 32bit
673             {
674                 pbuf = malloc(768);
675                 if(readpackfile(handle, pbuf, numcolours * 3) != numcolours * 3)
676                 {
677                     free(pbuf);
678                     pbuf = NULL;
679                     return 0;
680                 }
681                 for(i = 0, j = 0; i < 1024; i += 4, j += 3)
682                 {
683                     *(unsigned *)(pal + i) = colour32(pbuf[j], pbuf[j + 1], pbuf[j + 2]);
684                 }
685                 free(pbuf);
686                 pbuf = NULL;
687             }
688         }
689         else
690         {
691             seekpackfile(handle, numcolours * 3, SEEK_CUR);
692         }
693     }
694 
695     if(!buf)
696     {
697         return 1;
698     }
699 
700     // step through the blocks while(c==',' || c=='!' || c==0)
701     while(!done)
702     {
703         if(readpackfile(handle, &c, 1) != 1)
704         {
705             break;
706         }
707         switch(c)
708         {
709         case ',':        // An image block
710 
711 #if DC || GP2X || SYMBIAN
712             if(readpackfile(handle, &iblock, sizeof_iblock) != sizeof_iblock)
713             {
714 #else
715             if(readpackfile(handle, &iblock, sizeof(iblock)) != sizeof(iblock))
716             {
717 #endif
718                 return 0;
719             }
720 
721             iblock.left = SwapLSB16(iblock.left);
722             iblock.top = SwapLSB16(iblock.top);
723             iblock.width = SwapLSB16(iblock.width);
724             iblock.height = SwapLSB16(iblock.height);
725 
726             // get local palette if present and wanted
727             if((iblock.flags & 0x80) && pal)
728             {
729                 if(pal)
730                 {
731                     i = 3 * (1 << ((iblock.flags & 0x0007) + 1));
732                     if(readpackfile(handle, pal, i) != numcolours)
733                     {
734                         return 0;
735                     }
736                 }
737                 else
738                 {
739                     seekpackfile(handle, numcolours * 3, SEEK_CUR);
740                 }
741             }
742 
743             // get the initial LZW code bits
744             if(readpackfile(handle, &c, 1) != 1)
745             {
746                 return 0;
747             }
748             if(c < 2 || c > 8)
749             {
750                 return 0;
751             }
752             if(!decodegifblock(handle, buf, maxwidth, maxheight, c, &iblock))
753             {
754                 return 0;
755             }
756             break;
757         case '!':
758             // Extension block, read past it
759             passgifblock(handle);
760             break;
761         case 0:
762             // Isn't this an EOF?
763             break;
764         default:
765             done = 1;
766         }
767     }
768     return 1;
769 }
770 
771 // ============================== PCX loading ===============================
772 
773 typedef struct
774 {
775     char            manufacturer;
776     char            version;
777     char            encoding;
778     char            bitspp;
779     unsigned short  xmin, ymin;
780     unsigned short  xmax, ymax;
781     unsigned short  hres, vres;
782     char            unused[48];
783     char            reserved;
784     char            colorplanes;
785     unsigned short  bytesperline;
786     unsigned short  paltype;
787     char            unused2[58];
788 } s_pcxheader;
789 
790 static s_pcxheader pcx_header;
791 
792 static int openpcx(char *filename, char *packname)
793 {
794     if((handle = openpackfile(filename, packname)) == -1)
795     {
796         return 0;
797     }
798     if(readpackfile(handle, &pcx_header, 128) != 128)
799     {
800         closepackfile(handle);
801         return 0;
802     }
803 
804     pcx_header.xmin = SwapLSB16(pcx_header.xmin);
805     pcx_header.ymin = SwapLSB16(pcx_header.ymin);
806     pcx_header.xmax = SwapLSB16(pcx_header.xmax);
807     pcx_header.ymax = SwapLSB16(pcx_header.ymax);
808     pcx_header.hres = SwapLSB16(pcx_header.hres);
809     pcx_header.vres = SwapLSB16(pcx_header.vres);
810     pcx_header.bytesperline = SwapLSB16(pcx_header.bytesperline);
811     pcx_header.paltype = SwapLSB16(pcx_header.paltype);
812 
813     if(pcx_header.colorplanes == 3)
814     {
815         closepackfile(handle);
816         return 0;
817     }
818 
819     res[0] = pcx_header.xmax;
820     res[1] = pcx_header.ymax;
821 
822     return 1;
823 }
824 
825 static int readpcx(unsigned char *buf, unsigned char *pal, int maxwidth, int maxheight)
826 {
827 
828     unsigned char *codebuffer;
829     unsigned int i, j;
830     unsigned x, y;
831     unsigned spos;        // Searchpos (file)
832     unsigned cpos;        // codepos
833     unsigned dpos;        // Destination
834     unsigned char repbyte;
835     unsigned char *pbuf;
836     int pb = PAL_BYTES;
837 
838     if(buf)
839     {
840 
841         if(!(codebuffer = (unsigned char *)malloc(64000)))
842         {
843             return 0;
844         }
845 
846         x = 0;
847         y = 0;
848         spos = 0;
849         dpos = 0;
850 
851         while(y <= pcx_header.ymax && y < maxheight)
852         {
853 
854             seekpackfile(handle, 128 + spos, SEEK_SET);
855 
856             if((readpackfile(handle, codebuffer, 64000)) == -1)
857             {
858                 free(codebuffer);
859                 codebuffer = NULL;
860                 return 0;
861             }
862 
863             cpos = 0;
864 
865             while(cpos < 63990 && y <= pcx_header.ymax && y < maxheight)
866             {
867                 if(codebuffer[cpos] > 192)
868                 {
869                     i = codebuffer[cpos] - 192;
870                     repbyte = codebuffer[cpos + 1];
871                     do
872                     {
873                         if(x < maxwidth)
874                         {
875                             buf[dpos] = (signed char)repbyte;
876                         }
877                         ++dpos;
878                         if((++x) >= pcx_header.bytesperline)
879                         {
880                             x = 0;
881                             ++y;
882                             dpos = y * maxwidth;
883                         }
884                     }
885                     while(--i);
886                     cpos += 2;
887                 }
888                 else
889                 {
890                     if(x < maxwidth)
891                     {
892                         buf[dpos] = (signed char)codebuffer[cpos];
893                     }
894                     ++cpos;
895                     ++dpos;
896                     if((++x) >= pcx_header.bytesperline)
897                     {
898                         x = 0;
899                         ++y;
900                         dpos = y * maxwidth;
901                     }
902                 }
903             }
904             spos += cpos;
905         }
906         free(codebuffer);
907         codebuffer = NULL;
908     }
909 
910     if(pal)
911     {
912         seekpackfile(handle, -768, SEEK_END);
913         if(pb == 512) // 16bit 565
914         {
915             pbuf = malloc(768);
916             if(readpackfile(handle, pbuf, 768) != 768)
917             {
918                 free(pbuf);
919                 pbuf = NULL;
920                 return 0;
921             }
922             for(i = 0, j = 0; i < 512; i += 2, j += 3)
923             {
924                 *(unsigned short *)(pal + i) = colour16(pbuf[j], pbuf[j + 1], pbuf[j + 2]);
925             }
926             free(pbuf);
927             pbuf = NULL;
928         }
929         else if(pb == 768) // 24bit
930         {
931             if(readpackfile(handle, pal, 768) != 768)
932             {
933                 return 0;
934             }
935         }
936         else if(pb == 1024) // 32bit
937         {
938             pbuf = malloc(768);
939             if(readpackfile(handle, pbuf, 768) != 768)
940             {
941                 free(pbuf);
942                 pbuf = NULL;
943                 return 0;
944             }
945             for(i = 0, j = 0; i < 1024; i += 4, j += 3)
946             {
947                 *(unsigned *)(pal + i) = colour32(pbuf[j], pbuf[j + 1], pbuf[j + 2]);
948             }
949             free(pbuf);
950             pbuf = NULL;
951         }
952     }
953     return 1;
954 }
955 
956 //static void closepcx(){
957 //    closepackfile(handle);
958 //    handle = -1;
959 //}
960 
961 // ============================== auto loading ===============================
962 
963 #define OT_GIF 1
964 #define OT_BMP 2
965 #define OT_PCX 3
966 #define OT_PNG 4
967 
968 static int open_type = 0;
969 
970 static int openimage(char *filename, char *packfile)
971 {
972     char fnam[128];
973     int len = strlen(filename);
974     char *ext = filename + len - 4;
975     open_type = 0;
976 
977     if(0 == stricmp(ext, ".png") && openpng(filename, packfile))
978     {
979         open_type = OT_PNG;
980         return 1;
981     }
982     else if(0 == stricmp(ext, ".gif") && opengif(filename, packfile))
983     {
984         open_type = OT_GIF;
985         return 1;
986     }
987     else if(0 == stricmp(ext, ".pcx") && openpcx(filename, packfile))
988     {
989         open_type = OT_PCX;
990         return 1;
991     }
992     else if(0 == stricmp(ext, ".bmp") && openbmp(filename, packfile))
993     {
994         open_type = OT_BMP;
995         return 1;
996     }
997 
998     sprintf(fnam, "%s.png", filename);
999     if(openpng(fnam, packfile))
1000     {
1001         open_type = OT_PNG;
1002         return 1;
1003     }
1004 
1005     sprintf(fnam, "%s.gif", filename);
1006     if(opengif(fnam, packfile))
1007     {
1008         open_type = OT_GIF;
1009         return 1;
1010     }
1011 
1012     sprintf(fnam, "%s.pcx", filename);
1013     if(openpcx(fnam, packfile))
1014     {
1015         open_type = OT_PCX;
1016         return 1;
1017     }
1018 
1019     sprintf(fnam, "%s.bmp", filename);
1020     if(openbmp(fnam, packfile))
1021     {
1022         open_type = OT_BMP;
1023         return 1;
1024     }
1025     return 0;
1026 }
1027 
1028 static int readimage(unsigned char *buf, unsigned char *pal, int maxwidth, int maxheight)
1029 {
1030     int result = 0;
1031     switch(open_type)
1032     {
1033     case OT_GIF:
1034         result = readgif(buf, pal, maxwidth, maxheight);
1035 #ifdef VERBOSE
1036         printf("calling readimage %p %p %d %d with format %s, result is %d\n", buf, pal, maxwidth, maxheight, "GIF", result);
1037 #endif
1038         break;
1039     case OT_PCX:
1040         result = readpcx(buf, pal, maxwidth, maxheight);
1041 #ifdef VERBOSE
1042         printf("calling readimage %p %p %d %d with format %s, result is %d\n", buf, pal, maxwidth, maxheight, "PCX", result);
1043 #endif
1044         break;
1045     case OT_BMP:
1046         result = readbmp(buf, pal, maxwidth, maxheight);
1047 #ifdef VERBOSE
1048         printf("calling readimage %p %p %d %d with format %s, result is %d\n", buf, pal, maxwidth, maxheight, "BMP", result);
1049 #endif
1050         break;
1051     case OT_PNG:
1052         result = readpng(buf, pal, maxwidth, maxheight);
1053 #ifdef VERBOSE
1054         printf("calling readimage %p %p %d %d with format %s, result is %d\n", buf, pal, maxwidth, maxheight, "PNG", result);
1055 #endif
1056         break;
1057     }
1058     if(pal)
1059     {
1060         memset(pal, 0, (PAL_BYTES) >> 8);
1061     }
1062     return result;
1063 }
1064 
1065 static void closeimage()
1066 {
1067     if(open_type == OT_PNG)
1068     {
1069         closepng();
1070     }
1071     else
1072     {
1073         if(handle > 0)
1074         {
1075             closepackfile(handle);
1076         }
1077         handle = -1;
1078     }
1079 }
1080 
1081 // ============================== Interface ===============================
1082 
1083 int loadscreen(char *filename, char *packfile, unsigned char *pal, int format, s_screen **screen)
1084 {
1085     int result;
1086     unsigned char *p;
1087 #ifdef VERBOSE
1088     printf("loadscreen called packfile: %s, filename %s\n", packfile, filename);
1089 #endif
1090     if((*screen))
1091     {
1092         freescreen(screen);
1093     }
1094     if(!openimage(filename, packfile))
1095     {
1096         return 0;
1097     }
1098     if(!(*screen) || ((*screen)->width != res[0] && (*screen)->height != res[1] && (*screen)->pixelformat != format))
1099     {
1100         (*screen) = allocscreen(res[0], res[1], format);
1101         if((*screen) == NULL)
1102         {
1103             closeimage();
1104             //assert(0);
1105             return 0;
1106         }
1107     }
1108     if(pal)
1109     {
1110         p = pal;
1111     }
1112     else
1113     {
1114         p = (*screen)->palette;
1115     }
1116     result = readimage((unsigned char *)(*screen)->data, p, (*screen)->width, (*screen)->height);
1117     closeimage();
1118     if(!result)
1119     {
1120         freescreen(screen);
1121         //assert(0);
1122         return 0;
1123     }
1124     return 1;
1125 }
1126 
1127 int loadscreen32(char *filename, char *packfile, s_screen **screen)
1128 {
1129     void *data;
1130     int handle, filesize;
1131     char fnam[128];
1132 #ifdef VERBOSE
1133     printf("loadscreen called packfile: %s, filename %s\n", packfile, filename);
1134 #endif
1135     if((*screen))
1136     {
1137         freescreen(screen);
1138     }
1139 
1140     if((handle = openpackfile(filename, packfile)) == -1)
1141     {
1142         sprintf(fnam, "%s.png", filename);
1143         if((handle = openpackfile(fnam, packfile)) == -1)
1144         {
1145             return 0;
1146         }
1147     }
1148     filesize = seekpackfile(handle, 0, SEEK_END);
1149     data = malloc(filesize);
1150     assert(seekpackfile(handle, 0, SEEK_SET) == 0);
1151     if (!data || readpackfile(handle, data, filesize) != filesize)
1152     {
1153         closepackfile(handle);
1154         free(data);
1155         return 0;
1156     }
1157     closepackfile(handle);
1158 
1159     (*screen) = pngToScreen(data);
1160     free(data);
1161     if (!(*screen)) return 0;
1162     return 1;
1163 }
1164 
1165 s_bitmap *loadbitmap(char *filename, char *packfile, int format)
1166 {
1167     int result;
1168     s_bitmap *bitmap;
1169     int maxwidth, maxheight;
1170 
1171     if(!openimage(filename, packfile))
1172     {
1173         return NULL;
1174     }
1175 
1176     maxwidth = res[0];
1177     maxheight = res[1];
1178     //if(maxwidth > 4096) maxwidth = 4096;
1179     //if(maxheight > 4096) maxheight = 4096;
1180     bitmap = allocbitmap(maxwidth, maxheight, format);
1181     if(!bitmap)
1182     {
1183         closeimage();
1184         return NULL;
1185     }
1186 
1187     result = readimage((unsigned char *)bitmap->data, bitmap->palette, maxwidth, maxheight);
1188     closeimage();
1189     if(!result)
1190     {
1191         freebitmap(bitmap);
1192         return NULL;
1193     }
1194     return bitmap;
1195 }
1196 
1197 int loadimagepalette(char *filename, char *packfile, unsigned char *pal)
1198 {
1199     int result;
1200 
1201     if(!openimage(filename, packfile))
1202     {
1203         return 0;
1204     }
1205 
1206     result = readimage(NULL, pal, 0, 0);
1207     closeimage();
1208     return  result;
1209 }
1210