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