New comit of SDL2
[supertux.git] / src / SDL2 / IMG_bmp.c
1 /*
2   SDL_image:  An example image loading library for use with SDL
3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21
22 #if (!defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND)) || !defined(BMP_USES_IMAGEIO)
23
24 /* This is a BMP image file loading framework
25  *
26  * ICO/CUR file support is here as well since it uses similar internal
27  * representation
28  *
29  * A good test suite of BMP images is available at:
30  * http://entropymine.com/jason/bmpsuite/bmpsuite/html/bmpsuite.html
31  */
32
33 #include <stdio.h>
34 #include <string.h>
35
36 #include "SDL_image.h"
37
38 #ifdef LOAD_BMP
39
40 /* See if an image is contained in a data source */
41 int IMG_isBMP(SDL_RWops *src)
42 {
43     Sint64 start;
44     int is_BMP;
45     char magic[2];
46
47     if ( !src )
48         return 0;
49     start = SDL_RWtell(src);
50     is_BMP = 0;
51     if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
52         if ( SDL_strncmp(magic, "BM", 2) == 0 ) {
53             is_BMP = 1;
54         }
55     }
56     SDL_RWseek(src, start, RW_SEEK_SET);
57     return(is_BMP);
58 }
59
60 static int IMG_isICOCUR(SDL_RWops *src, int type)
61 {
62     Sint64 start;
63     int is_ICOCUR;
64
65     /* The Win32 ICO file header (14 bytes) */
66     Uint16 bfReserved;
67     Uint16 bfType;
68     Uint16 bfCount;
69
70     if ( !src )
71         return 0;
72     start = SDL_RWtell(src);
73     is_ICOCUR = 0;
74     bfReserved = SDL_ReadLE16(src);
75     bfType = SDL_ReadLE16(src);
76     bfCount = SDL_ReadLE16(src);
77     if ((bfReserved == 0) && (bfType == type) && (bfCount != 0))
78         is_ICOCUR = 1;
79     SDL_RWseek(src, start, RW_SEEK_SET);
80
81     return (is_ICOCUR);
82 }
83
84 int IMG_isICO(SDL_RWops *src)
85 {
86     return IMG_isICOCUR(src, 1);
87 }
88
89 int IMG_isCUR(SDL_RWops *src)
90 {
91     return IMG_isICOCUR(src, 2);
92 }
93
94 #include "SDL_error.h"
95 #include "SDL_video.h"
96 #include "SDL_endian.h"
97
98 /* Compression encodings for BMP files */
99 #ifndef BI_RGB
100 #define BI_RGB      0
101 #define BI_RLE8     1
102 #define BI_RLE4     2
103 #define BI_BITFIELDS    3
104 #endif
105
106 static int readRlePixels(SDL_Surface * surface, SDL_RWops * src, int isRle8)
107 {
108     /*
109     | Sets the surface pixels from src.  A bmp image is upside down.
110     */
111     int pitch = surface->pitch;
112     int height = surface->h;
113     Uint8 *start = (Uint8 *)surface->pixels;
114     Uint8 *end = start + (height*pitch);
115     Uint8 *bits = end-pitch, *spot;
116     int ofs = 0;
117     Uint8 ch;
118     Uint8 needsPad;
119
120 #define COPY_PIXEL(x)   spot = &bits[ofs++]; if(spot >= start && spot < end) *spot = (x)
121
122     for (;;) {
123         if ( !SDL_RWread(src, &ch, 1, 1) ) return 1;
124         /*
125         | encoded mode starts with a run length, and then a byte
126         | with two colour indexes to alternate between for the run
127         */
128         if ( ch ) {
129             Uint8 pixel;
130             if ( !SDL_RWread(src, &pixel, 1, 1) ) return 1;
131             if ( isRle8 ) {                 /* 256-color bitmap, compressed */
132                 do {
133                     COPY_PIXEL(pixel);
134                 } while (--ch);
135             } else {                         /* 16-color bitmap, compressed */
136                 Uint8 pixel0 = pixel >> 4;
137                 Uint8 pixel1 = pixel & 0x0F;
138                 for (;;) {
139                     COPY_PIXEL(pixel0); /* even count, high nibble */
140                     if (!--ch) break;
141                     COPY_PIXEL(pixel1); /* odd count, low nibble */
142                     if (!--ch) break;
143                 }
144             }
145         } else {
146             /*
147             | A leading zero is an escape; it may signal the end of the bitmap,
148             | a cursor move, or some absolute data.
149             | zero tag may be absolute mode or an escape
150             */
151             if ( !SDL_RWread(src, &ch, 1, 1) ) return 1;
152             switch (ch) {
153             case 0:                         /* end of line */
154                 ofs = 0;
155                 bits -= pitch;               /* go to previous */
156                 break;
157             case 1:                         /* end of bitmap */
158                 return 0;                    /* success! */
159             case 2:                         /* delta */
160                 if ( !SDL_RWread(src, &ch, 1, 1) ) return 1;
161                 ofs += ch;
162                 if ( !SDL_RWread(src, &ch, 1, 1) ) return 1;
163                 bits -= (ch * pitch);
164                 break;
165             default:                        /* no compression */
166                 if (isRle8) {
167                     needsPad = ( ch & 1 );
168                     do {
169                         Uint8 pixel;
170                         if ( !SDL_RWread(src, &pixel, 1, 1) ) return 1;
171                         COPY_PIXEL(pixel);
172                     } while (--ch);
173                 } else {
174                     needsPad = ( ((ch+1)>>1) & 1 ); /* (ch+1)>>1: bytes size */
175                     for (;;) {
176                         Uint8 pixel;
177                         if ( !SDL_RWread(src, &pixel, 1, 1) ) return 1;
178                         COPY_PIXEL(pixel >> 4);
179                         if (!--ch) break;
180                         COPY_PIXEL(pixel & 0x0F);
181                         if (!--ch) break;
182                     }
183                 }
184                 /* pad at even boundary */
185                 if ( needsPad && !SDL_RWread(src, &ch, 1, 1) ) return 1;
186                 break;
187             }
188         }
189     }
190 }
191
192 static void CorrectAlphaChannel(SDL_Surface *surface)
193 {
194     /* Check to see if there is any alpha channel data */
195     SDL_bool hasAlpha = SDL_FALSE;
196 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
197     int alphaChannelOffset = 0;
198 #else
199     int alphaChannelOffset = 3;
200 #endif
201     Uint8 *alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
202     Uint8 *end = alpha + surface->h * surface->pitch;
203
204     while (alpha < end) {
205         if (*alpha != 0) {
206             hasAlpha = SDL_TRUE;
207             break;
208         }
209         alpha += 4;
210     }
211
212     if (!hasAlpha) {
213         alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
214         while (alpha < end) {
215             *alpha = SDL_ALPHA_OPAQUE;
216             alpha += 4;
217         }
218     }
219 }
220
221 static SDL_Surface *LoadBMP_RW (SDL_RWops *src, int freesrc)
222 {
223     SDL_bool was_error;
224     Sint64 fp_offset;
225     int bmpPitch;
226     int i, pad;
227     SDL_Surface *surface;
228     Uint32 Rmask;
229     Uint32 Gmask;
230     Uint32 Bmask;
231     Uint32 Amask;
232     SDL_Palette *palette;
233     Uint8 *bits;
234     Uint8 *top, *end;
235     SDL_bool topDown;
236     int ExpandBMP;
237     SDL_bool correctAlpha = SDL_FALSE;
238
239     /* The Win32 BMP file header (14 bytes) */
240     char   magic[2];
241     Uint32 bfSize;
242     Uint16 bfReserved1;
243     Uint16 bfReserved2;
244     Uint32 bfOffBits;
245
246     /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
247     Uint32 biSize;
248     Sint32 biWidth;
249     Sint32 biHeight;
250     Uint16 biPlanes;
251     Uint16 biBitCount;
252     Uint32 biCompression;
253     Uint32 biSizeImage;
254     Sint32 biXPelsPerMeter;
255     Sint32 biYPelsPerMeter;
256     Uint32 biClrUsed;
257     Uint32 biClrImportant;
258
259     /* Make sure we are passed a valid data source */
260     surface = NULL;
261     was_error = SDL_FALSE;
262     if ( src == NULL ) {
263         was_error = SDL_TRUE;
264         goto done;
265     }
266
267     /* Read in the BMP file header */
268     fp_offset = SDL_RWtell(src);
269     SDL_ClearError();
270     if ( SDL_RWread(src, magic, 1, 2) != 2 ) {
271         SDL_Error(SDL_EFREAD);
272         was_error = SDL_TRUE;
273         goto done;
274     }
275     if ( SDL_strncmp(magic, "BM", 2) != 0 ) {
276         IMG_SetError("File is not a Windows BMP file");
277         was_error = SDL_TRUE;
278         goto done;
279     }
280     bfSize      = SDL_ReadLE32(src);
281     bfReserved1 = SDL_ReadLE16(src);
282     bfReserved2 = SDL_ReadLE16(src);
283     bfOffBits   = SDL_ReadLE32(src);
284
285     /* Read the Win32 BITMAPINFOHEADER */
286     biSize      = SDL_ReadLE32(src);
287     if ( biSize == 12 ) {
288         biWidth     = (Uint32)SDL_ReadLE16(src);
289         biHeight    = (Uint32)SDL_ReadLE16(src);
290         biPlanes    = SDL_ReadLE16(src);
291         biBitCount  = SDL_ReadLE16(src);
292         biCompression   = BI_RGB;
293         biSizeImage = 0;
294         biXPelsPerMeter = 0;
295         biYPelsPerMeter = 0;
296         biClrUsed   = 0;
297         biClrImportant  = 0;
298     } else {
299         biWidth     = SDL_ReadLE32(src);
300         biHeight    = SDL_ReadLE32(src);
301         biPlanes    = SDL_ReadLE16(src);
302         biBitCount  = SDL_ReadLE16(src);
303         biCompression   = SDL_ReadLE32(src);
304         biSizeImage = SDL_ReadLE32(src);
305         biXPelsPerMeter = SDL_ReadLE32(src);
306         biYPelsPerMeter = SDL_ReadLE32(src);
307         biClrUsed   = SDL_ReadLE32(src);
308         biClrImportant  = SDL_ReadLE32(src);
309     }
310     if (biHeight < 0) {
311         topDown = SDL_TRUE;
312         biHeight = -biHeight;
313     } else {
314         topDown = SDL_FALSE;
315     }
316
317     /* Check for read error */
318     if ( strcmp(SDL_GetError(), "") != 0 ) {
319         was_error = SDL_TRUE;
320         goto done;
321     }
322
323     /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */
324     switch (biBitCount) {
325         case 1:
326         case 4:
327             ExpandBMP = biBitCount;
328             biBitCount = 8;
329             break;
330         default:
331             ExpandBMP = 0;
332             break;
333     }
334
335     /* RLE4 and RLE8 BMP compression is supported */
336     Rmask = Gmask = Bmask = Amask = 0;
337     switch (biCompression) {
338         case BI_RGB:
339             /* If there are no masks, use the defaults */
340             if ( bfOffBits == (14+biSize) ) {
341                 /* Default values for the BMP format */
342                 switch (biBitCount) {
343                     case 15:
344                     case 16:
345                         Rmask = 0x7C00;
346                         Gmask = 0x03E0;
347                         Bmask = 0x001F;
348                         break;
349                     case 24:
350 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
351                         Rmask = 0x000000FF;
352                         Gmask = 0x0000FF00;
353                         Bmask = 0x00FF0000;
354 #else
355                         Rmask = 0x00FF0000;
356                         Gmask = 0x0000FF00;
357                         Bmask = 0x000000FF;
358 #endif
359                         break;
360                     case 32:
361                         /* We don't know if this has alpha channel or not */
362                         correctAlpha = SDL_TRUE;
363                         Amask = 0xFF000000;
364                         Rmask = 0x00FF0000;
365                         Gmask = 0x0000FF00;
366                         Bmask = 0x000000FF;
367                         break;
368                     default:
369                         break;
370                 }
371                 break;
372             }
373             /* Fall through -- read the RGB masks */
374
375         default:
376             switch (biBitCount) {
377                 case 15:
378                 case 16:
379                     Rmask = SDL_ReadLE32(src);
380                     Gmask = SDL_ReadLE32(src);
381                     Bmask = SDL_ReadLE32(src);
382                     break;
383                 case 32:
384                     Rmask = SDL_ReadLE32(src);
385                     Gmask = SDL_ReadLE32(src);
386                     Bmask = SDL_ReadLE32(src);
387                     Amask = SDL_ReadLE32(src);
388                     break;
389                 default:
390                     break;
391             }
392             break;
393     }
394
395     /* Create a compatible surface, note that the colors are RGB ordered */
396     surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
397             biWidth, biHeight, biBitCount, Rmask, Gmask, Bmask, Amask);
398     if ( surface == NULL ) {
399         was_error = SDL_TRUE;
400         goto done;
401     }
402
403     /* Load the palette, if any */
404     palette = (surface->format)->palette;
405     if ( palette ) {
406         if ( SDL_RWseek(src, fp_offset+14+biSize, RW_SEEK_SET) < 0 ) {
407             SDL_Error(SDL_EFSEEK);
408             was_error = SDL_TRUE;
409             goto done;
410         }
411
412         /*
413         | guich: always use 1<<bpp b/c some bitmaps can bring wrong information
414         | for colorsUsed
415         */
416         /* if ( biClrUsed == 0 ) {  */
417         biClrUsed = 1 << biBitCount;
418         /* } */
419         if ( biSize == 12 ) {
420             for ( i = 0; i < (int)biClrUsed; ++i ) {
421                 SDL_RWread(src, &palette->colors[i].b, 1, 1);
422                 SDL_RWread(src, &palette->colors[i].g, 1, 1);
423                 SDL_RWread(src, &palette->colors[i].r, 1, 1);
424                 palette->colors[i].a = SDL_ALPHA_OPAQUE;
425             }
426         } else {
427             for ( i = 0; i < (int)biClrUsed; ++i ) {
428                 SDL_RWread(src, &palette->colors[i].b, 1, 1);
429                 SDL_RWread(src, &palette->colors[i].g, 1, 1);
430                 SDL_RWread(src, &palette->colors[i].r, 1, 1);
431                 SDL_RWread(src, &palette->colors[i].a, 1, 1);
432
433                 /* According to Microsoft documentation, the fourth element
434                    is reserved and must be zero, so we shouldn't treat it as
435                    alpha.
436                 */
437                 palette->colors[i].a = SDL_ALPHA_OPAQUE;
438             }
439         }
440         palette->ncolors = biClrUsed;
441     }
442
443     /* Read the surface pixels.  Note that the bmp image is upside down */
444     if ( SDL_RWseek(src, fp_offset+bfOffBits, RW_SEEK_SET) < 0 ) {
445         SDL_Error(SDL_EFSEEK);
446         was_error = SDL_TRUE;
447         goto done;
448     }
449     if ((biCompression == BI_RLE4) || (biCompression == BI_RLE8)) {
450         was_error = (SDL_bool)readRlePixels(surface, src, biCompression == BI_RLE8);
451         if (was_error) IMG_SetError("Error reading from BMP");
452         goto done;
453     }
454     top = (Uint8 *)surface->pixels;
455     end = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
456     switch (ExpandBMP) {
457         case 1:
458             bmpPitch = (biWidth + 7) >> 3;
459             pad  = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0);
460             break;
461         case 4:
462             bmpPitch = (biWidth + 1) >> 1;
463             pad  = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0);
464             break;
465         default:
466             pad  = ((surface->pitch%4) ?
467                     (4-(surface->pitch%4)) : 0);
468             break;
469     }
470     if ( topDown ) {
471         bits = top;
472     } else {
473         bits = end - surface->pitch;
474     }
475     while ( bits >= top && bits < end ) {
476         switch (ExpandBMP) {
477             case 1:
478             case 4: {
479             Uint8 pixel = 0;
480             int   shift = (8-ExpandBMP);
481             for ( i=0; i<surface->w; ++i ) {
482                 if ( i%(8/ExpandBMP) == 0 ) {
483                     if ( !SDL_RWread(src, &pixel, 1, 1) ) {
484                         IMG_SetError("Error reading from BMP");
485                         was_error = SDL_TRUE;
486                         goto done;
487                     }
488                 }
489                 *(bits+i) = (pixel>>shift);
490                 pixel <<= ExpandBMP;
491             } }
492             break;
493
494             default:
495             if ( SDL_RWread(src, bits, 1, surface->pitch) != surface->pitch ) {
496                 SDL_Error(SDL_EFREAD);
497                 was_error = SDL_TRUE;
498                 goto done;
499             }
500 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
501             /* Byte-swap the pixels if needed. Note that the 24bpp
502                case has already been taken care of above. */
503             switch(biBitCount) {
504                 case 15:
505                 case 16: {
506                     Uint16 *pix = (Uint16 *)bits;
507                     for(i = 0; i < surface->w; i++)
508                         pix[i] = SDL_Swap16(pix[i]);
509                     break;
510                 }
511
512                 case 32: {
513                     Uint32 *pix = (Uint32 *)bits;
514                     for(i = 0; i < surface->w; i++)
515                         pix[i] = SDL_Swap32(pix[i]);
516                     break;
517                 }
518             }
519 #endif
520             break;
521         }
522         /* Skip padding bytes, ugh */
523         if ( pad ) {
524             Uint8 padbyte;
525             for ( i=0; i<pad; ++i ) {
526                 SDL_RWread(src, &padbyte, 1, 1);
527             }
528         }
529         if ( topDown ) {
530             bits += surface->pitch;
531         } else {
532             bits -= surface->pitch;
533         }
534     }
535     if (correctAlpha) {
536         CorrectAlphaChannel(surface);
537     }
538 done:
539     if ( was_error ) {
540         if ( src ) {
541             SDL_RWseek(src, fp_offset, RW_SEEK_SET);
542         }
543         if ( surface ) {
544             SDL_FreeSurface(surface);
545         }
546         surface = NULL;
547     }
548     if ( freesrc && src ) {
549         SDL_RWclose(src);
550     }
551     return(surface);
552 }
553
554 static Uint8
555 SDL_Read8(SDL_RWops * src)
556 {
557     Uint8 value;
558
559     SDL_RWread(src, &value, 1, 1);
560     return (value);
561 }
562
563 static SDL_Surface *
564 LoadICOCUR_RW(SDL_RWops * src, int type, int freesrc)
565 {
566     SDL_bool was_error;
567     Sint64 fp_offset;
568     int bmpPitch;
569     int i, pad;
570     SDL_Surface *surface;
571     Uint32 Rmask;
572     Uint32 Gmask;
573     Uint32 Bmask;
574     Uint8 *bits;
575     int ExpandBMP;
576     int maxCol = 0;
577     int icoOfs = 0;
578     Uint32 palette[256];
579
580     /* The Win32 ICO file header (14 bytes) */
581     Uint16 bfReserved;
582     Uint16 bfType;
583     Uint16 bfCount;
584
585     /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
586     Uint32 biSize;
587     Sint32 biWidth;
588     Sint32 biHeight;
589     Uint16 biPlanes;
590     Uint16 biBitCount;
591     Uint32 biCompression;
592     Uint32 biSizeImage;
593     Sint32 biXPelsPerMeter;
594     Sint32 biYPelsPerMeter;
595     Uint32 biClrUsed;
596     Uint32 biClrImportant;
597
598     /* Make sure we are passed a valid data source */
599     surface = NULL;
600     was_error = SDL_FALSE;
601     if (src == NULL) {
602         was_error = SDL_TRUE;
603         goto done;
604     }
605
606     /* Read in the ICO file header */
607     fp_offset = SDL_RWtell(src);
608     SDL_ClearError();
609
610     bfReserved = SDL_ReadLE16(src);
611     bfType = SDL_ReadLE16(src);
612     bfCount = SDL_ReadLE16(src);
613     if ((bfReserved != 0) || (bfType != type) || (bfCount == 0)) {
614         IMG_SetError("File is not a Windows %s file", type == 1 ? "ICO" : "CUR");
615         was_error = SDL_TRUE;
616         goto done;
617     }
618
619     /* Read the Win32 Icon Directory */
620     for (i = 0; i < bfCount; i++) {
621         /* Icon Directory Entries */
622         int bWidth = SDL_Read8(src);    /* Uint8, but 0 = 256 ! */
623         int bHeight = SDL_Read8(src);   /* Uint8, but 0 = 256 ! */
624         int bColorCount = SDL_Read8(src);       /* Uint8, but 0 = 256 ! */
625         Uint8 bReserved = SDL_Read8(src);
626         Uint16 wPlanes = SDL_ReadLE16(src);
627         Uint16 wBitCount = SDL_ReadLE16(src);
628         Uint32 dwBytesInRes = SDL_ReadLE32(src);
629         Uint32 dwImageOffset = SDL_ReadLE32(src);
630
631         if (!bWidth)
632             bWidth = 256;
633         if (!bHeight)
634             bHeight = 256;
635         if (!bColorCount)
636             bColorCount = 256;
637
638         //printf("%dx%d@%d - %08x\n", bWidth, bHeight, bColorCount, dwImageOffset);
639         if (bColorCount > maxCol) {
640             maxCol = bColorCount;
641             icoOfs = dwImageOffset;
642             //printf("marked\n");
643         }
644     }
645
646     /* Advance to the DIB Data */
647     if (SDL_RWseek(src, icoOfs, RW_SEEK_SET) < 0) {
648         SDL_Error(SDL_EFSEEK);
649         was_error = SDL_TRUE;
650         goto done;
651     }
652
653     /* Read the Win32 BITMAPINFOHEADER */
654     biSize = SDL_ReadLE32(src);
655     if (biSize == 40) {
656         biWidth = SDL_ReadLE32(src);
657         biHeight = SDL_ReadLE32(src);
658         biPlanes = SDL_ReadLE16(src);
659         biBitCount = SDL_ReadLE16(src);
660         biCompression = SDL_ReadLE32(src);
661         biSizeImage = SDL_ReadLE32(src);
662         biXPelsPerMeter = SDL_ReadLE32(src);
663         biYPelsPerMeter = SDL_ReadLE32(src);
664         biClrUsed = SDL_ReadLE32(src);
665         biClrImportant = SDL_ReadLE32(src);
666     } else {
667         IMG_SetError("Unsupported ICO bitmap format");
668         was_error = SDL_TRUE;
669         goto done;
670     }
671
672     /* Check for read error */
673     if (SDL_strcmp(SDL_GetError(), "") != 0) {
674         was_error = SDL_TRUE;
675         goto done;
676     }
677
678     /* We don't support any BMP compression right now */
679     switch (biCompression) {
680     case BI_RGB:
681         /* Default values for the BMP format */
682         switch (biBitCount) {
683         case 1:
684         case 4:
685             ExpandBMP = biBitCount;
686             biBitCount = 8;
687             break;
688         case 8:
689             ExpandBMP = 8;
690             break;
691         case 32:
692             Rmask = 0x00FF0000;
693             Gmask = 0x0000FF00;
694             Bmask = 0x000000FF;
695             ExpandBMP = 0;
696             break;
697         default:
698             IMG_SetError("ICO file with unsupported bit count");
699             was_error = SDL_TRUE;
700             goto done;
701         }
702         break;
703     default:
704         IMG_SetError("Compressed ICO files not supported");
705         was_error = SDL_TRUE;
706         goto done;
707     }
708
709     /* Create a RGBA surface */
710     biHeight = biHeight >> 1;
711     //printf("%d x %d\n", biWidth, biHeight);
712     surface =
713         SDL_CreateRGBSurface(0, biWidth, biHeight, 32, 0x00FF0000,
714                              0x0000FF00, 0x000000FF, 0xFF000000);
715     if (surface == NULL) {
716         was_error = SDL_TRUE;
717         goto done;
718     }
719
720     /* Load the palette, if any */
721     //printf("bc %d bused %d\n", biBitCount, biClrUsed);
722     if (biBitCount <= 8) {
723         if (biClrUsed == 0) {
724             biClrUsed = 1 << biBitCount;
725         }
726         for (i = 0; i < (int) biClrUsed; ++i) {
727             SDL_RWread(src, &palette[i], 4, 1);
728         }
729     }
730
731     /* Read the surface pixels.  Note that the bmp image is upside down */
732     bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
733     switch (ExpandBMP) {
734     case 1:
735         bmpPitch = (biWidth + 7) >> 3;
736         pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
737         break;
738     case 4:
739         bmpPitch = (biWidth + 1) >> 1;
740         pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
741         break;
742     case 8:
743         bmpPitch = biWidth;
744         pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
745         break;
746     default:
747         bmpPitch = biWidth * 4;
748         pad = 0;
749         break;
750     }
751     while (bits > (Uint8 *) surface->pixels) {
752         bits -= surface->pitch;
753         switch (ExpandBMP) {
754         case 1:
755         case 4:
756         case 8:
757             {
758                 Uint8 pixel = 0;
759                 int shift = (8 - ExpandBMP);
760                 for (i = 0; i < surface->w; ++i) {
761                     if (i % (8 / ExpandBMP) == 0) {
762                         if (!SDL_RWread(src, &pixel, 1, 1)) {
763                             IMG_SetError("Error reading from ICO");
764                             was_error = SDL_TRUE;
765                             goto done;
766                         }
767                     }
768                     *((Uint32 *) bits + i) = (palette[pixel >> shift]);
769                     pixel <<= ExpandBMP;
770                 }
771             }
772             break;
773
774         default:
775             if (SDL_RWread(src, bits, 1, surface->pitch)
776                 != surface->pitch) {
777                 SDL_Error(SDL_EFREAD);
778                 was_error = SDL_TRUE;
779                 goto done;
780             }
781             break;
782         }
783         /* Skip padding bytes, ugh */
784         if (pad) {
785             Uint8 padbyte;
786             for (i = 0; i < pad; ++i) {
787                 SDL_RWread(src, &padbyte, 1, 1);
788             }
789         }
790     }
791     /* Read the mask pixels.  Note that the bmp image is upside down */
792     bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
793     ExpandBMP = 1;
794     bmpPitch = (biWidth + 7) >> 3;
795     pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
796     while (bits > (Uint8 *) surface->pixels) {
797         Uint8 pixel = 0;
798         int shift = (8 - ExpandBMP);
799
800         bits -= surface->pitch;
801         for (i = 0; i < surface->w; ++i) {
802             if (i % (8 / ExpandBMP) == 0) {
803                 if (!SDL_RWread(src, &pixel, 1, 1)) {
804                     IMG_SetError("Error reading from ICO");
805                     was_error = SDL_TRUE;
806                     goto done;
807                 }
808             }
809             *((Uint32 *) bits + i) |= ((pixel >> shift) ? 0 : 0xFF000000);
810             pixel <<= ExpandBMP;
811         }
812         /* Skip padding bytes, ugh */
813         if (pad) {
814             Uint8 padbyte;
815             for (i = 0; i < pad; ++i) {
816                 SDL_RWread(src, &padbyte, 1, 1);
817             }
818         }
819     }
820   done:
821     if (was_error) {
822         if (src) {
823             SDL_RWseek(src, fp_offset, RW_SEEK_SET);
824         }
825         if (surface) {
826             SDL_FreeSurface(surface);
827         }
828         surface = NULL;
829     }
830     if (freesrc && src) {
831         SDL_RWclose(src);
832     }
833     return (surface);
834 }
835
836 /* Load a BMP type image from an SDL datasource */
837 SDL_Surface *IMG_LoadBMP_RW(SDL_RWops *src)
838 {
839     return(LoadBMP_RW(src, 0));
840 }
841
842 /* Load a ICO type image from an SDL datasource */
843 SDL_Surface *IMG_LoadICO_RW(SDL_RWops *src)
844 {
845     return(LoadICOCUR_RW(src, 1, 0));
846 }
847
848 /* Load a CUR type image from an SDL datasource */
849 SDL_Surface *IMG_LoadCUR_RW(SDL_RWops *src)
850 {
851     return(LoadICOCUR_RW(src, 2, 0));
852 }
853
854 #else
855
856 /* See if an image is contained in a data source */
857 int IMG_isBMP(SDL_RWops *src)
858 {
859     return(0);
860 }
861
862 int IMG_isICO(SDL_RWops *src)
863 {
864     return(0);
865 }
866
867 int IMG_isCUR(SDL_RWops *src)
868 {
869     return(0);
870 }
871
872 /* Load a BMP type image from an SDL datasource */
873 SDL_Surface *IMG_LoadBMP_RW(SDL_RWops *src)
874 {
875     return(NULL);
876 }
877
878 /* Load a BMP type image from an SDL datasource */
879 SDL_Surface *IMG_LoadCUR_RW(SDL_RWops *src)
880 {
881     return(NULL);
882 }
883
884 /* Load a BMP type image from an SDL datasource */
885 SDL_Surface *IMG_LoadICO_RW(SDL_RWops *src)
886 {
887     return(NULL);
888 }
889
890 #endif /* LOAD_BMP */
891
892 #endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */