PageRenderTime 54ms CodeModel.GetById 13ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 1ms

/project/jni/sdl_image/IMG_bmp.c

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