comparison src/video/SDL_bmp.c @ 3310:b907e83deb88

Fixed crash with right side up BMP files
author Sam Lantinga <slouken@libsdl.org>
date Sat, 26 Sep 2009 06:21:36 +0000
parents 69ab1117dd3b
children 74d2f44a85de
comparison
equal deleted inserted replaced
3309:e1f161215f72 3310:b907e83deb88
47 47
48 48
49 SDL_Surface * 49 SDL_Surface *
50 SDL_LoadBMP_RW(SDL_RWops * src, int freesrc) 50 SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
51 { 51 {
52 int was_error; 52 SDL_bool was_error;
53 long fp_offset; 53 long fp_offset;
54 int bmpPitch; 54 int bmpPitch;
55 int i, pad; 55 int i, pad;
56 SDL_Surface *surface; 56 SDL_Surface *surface;
57 Uint32 Rmask; 57 Uint32 Rmask;
58 Uint32 Gmask; 58 Uint32 Gmask;
59 Uint32 Bmask; 59 Uint32 Bmask;
60 SDL_Palette *palette; 60 SDL_Palette *palette;
61 Uint8 *bits; 61 Uint8 *bits;
62 Uint8 *top, *end;
63 SDL_bool topDown;
62 int ExpandBMP; 64 int ExpandBMP;
63 65
64 /* The Win32 BMP file header (14 bytes) */ 66 /* The Win32 BMP file header (14 bytes) */
65 char magic[2]; 67 char magic[2];
66 Uint32 bfSize; 68 Uint32 bfSize;
81 Uint32 biClrUsed; 83 Uint32 biClrUsed;
82 Uint32 biClrImportant; 84 Uint32 biClrImportant;
83 85
84 /* Make sure we are passed a valid data source */ 86 /* Make sure we are passed a valid data source */
85 surface = NULL; 87 surface = NULL;
86 was_error = 0; 88 was_error = SDL_FALSE;
87 if (src == NULL) { 89 if (src == NULL) {
88 was_error = 1; 90 was_error = SDL_TRUE;
89 goto done; 91 goto done;
90 } 92 }
91 93
92 /* Read in the BMP file header */ 94 /* Read in the BMP file header */
93 fp_offset = SDL_RWtell(src); 95 fp_offset = SDL_RWtell(src);
94 SDL_ClearError(); 96 SDL_ClearError();
95 if (SDL_RWread(src, magic, 1, 2) != 2) { 97 if (SDL_RWread(src, magic, 1, 2) != 2) {
96 SDL_Error(SDL_EFREAD); 98 SDL_Error(SDL_EFREAD);
97 was_error = 1; 99 was_error = SDL_TRUE;
98 goto done; 100 goto done;
99 } 101 }
100 if (SDL_strncmp(magic, "BM", 2) != 0) { 102 if (SDL_strncmp(magic, "BM", 2) != 0) {
101 SDL_SetError("File is not a Windows BMP file"); 103 SDL_SetError("File is not a Windows BMP file");
102 was_error = 1; 104 was_error = SDL_TRUE;
103 goto done; 105 goto done;
104 } 106 }
105 bfSize = SDL_ReadLE32(src); 107 bfSize = SDL_ReadLE32(src);
106 bfReserved1 = SDL_ReadLE16(src); 108 bfReserved1 = SDL_ReadLE16(src);
107 bfReserved2 = SDL_ReadLE16(src); 109 bfReserved2 = SDL_ReadLE16(src);
130 biXPelsPerMeter = SDL_ReadLE32(src); 132 biXPelsPerMeter = SDL_ReadLE32(src);
131 biYPelsPerMeter = SDL_ReadLE32(src); 133 biYPelsPerMeter = SDL_ReadLE32(src);
132 biClrUsed = SDL_ReadLE32(src); 134 biClrUsed = SDL_ReadLE32(src);
133 biClrImportant = SDL_ReadLE32(src); 135 biClrImportant = SDL_ReadLE32(src);
134 } 136 }
137 if (biHeight < 0) {
138 topDown = SDL_TRUE;
139 biHeight = -biHeight;
140 } else {
141 topDown = SDL_FALSE;
142 }
135 143
136 /* Check for read error */ 144 /* Check for read error */
137 if (SDL_strcmp(SDL_GetError(), "") != 0) { 145 if (SDL_strcmp(SDL_GetError(), "") != 0) {
138 was_error = 1; 146 was_error = SDL_TRUE;
139 goto done; 147 goto done;
140 } 148 }
141 149
142 /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */ 150 /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */
143 switch (biBitCount) { 151 switch (biBitCount) {
197 break; 205 break;
198 } 206 }
199 break; 207 break;
200 default: 208 default:
201 SDL_SetError("Compressed BMP files not supported"); 209 SDL_SetError("Compressed BMP files not supported");
202 was_error = 1; 210 was_error = SDL_TRUE;
203 goto done; 211 goto done;
204 } 212 }
205 213
206 /* Create a compatible surface, note that the colors are RGB ordered */ 214 /* Create a compatible surface, note that the colors are RGB ordered */
207 surface = 215 surface =
208 SDL_CreateRGBSurface(0, biWidth, biHeight, biBitCount, Rmask, Gmask, 216 SDL_CreateRGBSurface(0, biWidth, biHeight, biBitCount, Rmask, Gmask,
209 Bmask, 0); 217 Bmask, 0);
210 if (surface == NULL) { 218 if (surface == NULL) {
211 was_error = 1; 219 was_error = SDL_TRUE;
212 goto done; 220 goto done;
213 } 221 }
214 222
215 /* Load the palette, if any */ 223 /* Load the palette, if any */
216 palette = (surface->format)->palette; 224 palette = (surface->format)->palette;
224 (SDL_Color *) SDL_realloc(palette->colors, 232 (SDL_Color *) SDL_realloc(palette->colors,
225 palette->ncolors * 233 palette->ncolors *
226 sizeof(*palette->colors)); 234 sizeof(*palette->colors));
227 if (!palette->colors) { 235 if (!palette->colors) {
228 SDL_OutOfMemory(); 236 SDL_OutOfMemory();
229 was_error = 1; 237 was_error = SDL_TRUE;
230 goto done; 238 goto done;
231 } 239 }
232 } else if ((int) biClrUsed < palette->ncolors) { 240 } else if ((int) biClrUsed < palette->ncolors) {
233 palette->ncolors = biClrUsed; 241 palette->ncolors = biClrUsed;
234 } 242 }
250 } 258 }
251 259
252 /* Read the surface pixels. Note that the bmp image is upside down */ 260 /* Read the surface pixels. Note that the bmp image is upside down */
253 if (SDL_RWseek(src, fp_offset + bfOffBits, RW_SEEK_SET) < 0) { 261 if (SDL_RWseek(src, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
254 SDL_Error(SDL_EFSEEK); 262 SDL_Error(SDL_EFSEEK);
255 was_error = 1; 263 was_error = SDL_TRUE;
256 goto done; 264 goto done;
257 } 265 }
258 bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch); 266 top = (Uint8 *)surface->pixels;
267 end = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
259 switch (ExpandBMP) { 268 switch (ExpandBMP) {
260 case 1: 269 case 1:
261 bmpPitch = (biWidth + 7) >> 3; 270 bmpPitch = (biWidth + 7) >> 3;
262 pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0); 271 pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
263 break; 272 break;
267 break; 276 break;
268 default: 277 default:
269 pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0); 278 pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0);
270 break; 279 break;
271 } 280 }
272 while (bits > (Uint8 *) surface->pixels) { 281 if (topDown) {
273 bits -= surface->pitch; 282 bits = top;
283 } else {
284 bits = end - surface->pitch;
285 }
286 while (bits >= top && bits < end) {
274 switch (ExpandBMP) { 287 switch (ExpandBMP) {
275 case 1: 288 case 1:
276 case 4: 289 case 4:{
277 {
278 Uint8 pixel = 0; 290 Uint8 pixel = 0;
279 int shift = (8 - ExpandBMP); 291 int shift = (8 - ExpandBMP);
280 for (i = 0; i < surface->w; ++i) { 292 for (i = 0; i < surface->w; ++i) {
281 if (i % (8 / ExpandBMP) == 0) { 293 if (i % (8 / ExpandBMP) == 0) {
282 if (!SDL_RWread(src, &pixel, 1, 1)) { 294 if (!SDL_RWread(src, &pixel, 1, 1)) {
283 SDL_SetError("Error reading from BMP"); 295 SDL_SetError("Error reading from BMP");
284 was_error = 1; 296 was_error = SDL_TRUE;
285 goto done; 297 goto done;
286 } 298 }
287 } 299 }
288 *(bits + i) = (pixel >> shift); 300 *(bits + i) = (pixel >> shift);
289 pixel <<= ExpandBMP; 301 pixel <<= ExpandBMP;
293 305
294 default: 306 default:
295 if (SDL_RWread(src, bits, 1, surface->pitch) 307 if (SDL_RWread(src, bits, 1, surface->pitch)
296 != surface->pitch) { 308 != surface->pitch) {
297 SDL_Error(SDL_EFREAD); 309 SDL_Error(SDL_EFREAD);
298 was_error = 1; 310 was_error = SDL_TRUE;
299 goto done; 311 goto done;
300 } 312 }
301 #if SDL_BYTEORDER == SDL_BIG_ENDIAN 313 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
302 /* Byte-swap the pixels if needed. Note that the 24bpp 314 /* Byte-swap the pixels if needed. Note that the 24bpp
303 case has already been taken care of above. */ 315 case has already been taken care of above. */
304 switch (biBitCount) { 316 switch (biBitCount) {
305 case 15: 317 case 15:
306 case 16: 318 case 16:{
307 {
308 Uint16 *pix = (Uint16 *) bits; 319 Uint16 *pix = (Uint16 *) bits;
309 for (i = 0; i < surface->w; i++) 320 for (i = 0; i < surface->w; i++)
310 pix[i] = SDL_Swap16(pix[i]); 321 pix[i] = SDL_Swap16(pix[i]);
311 break; 322 break;
312 } 323 }
313 324
314 case 32: 325 case 32:{
315 {
316 Uint32 *pix = (Uint32 *) bits; 326 Uint32 *pix = (Uint32 *) bits;
317 for (i = 0; i < surface->w; i++) 327 for (i = 0; i < surface->w; i++)
318 pix[i] = SDL_Swap32(pix[i]); 328 pix[i] = SDL_Swap32(pix[i]);
319 break; 329 break;
320 } 330 }
326 if (pad) { 336 if (pad) {
327 Uint8 padbyte; 337 Uint8 padbyte;
328 for (i = 0; i < pad; ++i) { 338 for (i = 0; i < pad; ++i) {
329 SDL_RWread(src, &padbyte, 1, 1); 339 SDL_RWread(src, &padbyte, 1, 1);
330 } 340 }
341 }
342 if (topDown) {
343 bits += surface->pitch;
344 } else {
345 bits -= surface->pitch;
331 } 346 }
332 } 347 }
333 done: 348 done:
334 if (was_error) { 349 if (was_error) {
335 if (src) { 350 if (src) {