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