IMG_bmp.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 16 Mar 2019 18:34:22 -0700
changeset 639 03bd33e8cb49
parent 638 e3e9d7430674
permissions -rw-r--r--
Fixed CVE-2019-7635 and bug 4498 - Heap-Buffer Overflow in Blit1to4 pertaining to SDL_blit_1.c

Petr Pisar

The root cause is that the POC BMP file declares 3 colors used and 4 bpp palette, but pixel at line 28 and column 1 (counted from 0) has color number 3. Then when the image loaded into a surface is passed to SDL_DisplayFormat(), in order to convert it to a video format, a used bliting function looks up a color number 3 in a 3-element long color bliting map. (The map obviously has the same number entries as the surface format has colors.)

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