예제 #1
0
파일: SDL_rwops.c 프로젝트: RDCH106/n64oid
static int SDLCALL win32_file_write(SDL_RWops *context, const void *ptr, int size, int num)
{

    int		total_bytes;
    DWORD	byte_written,nwritten;

    total_bytes = size*num;

    if (!context || context->hidden.win32io.h==INVALID_HANDLE_VALUE || total_bytes<=0 || !size)
        return 0;

    if (context->hidden.win32io.buffer.left) {
        SetFilePointer(context->hidden.win32io.h,-context->hidden.win32io.buffer.left,NULL,FILE_CURRENT);
        context->hidden.win32io.buffer.left = 0;
    }

    /* if in append mode, we must go to the EOF before write */
    if (context->hidden.win32io.append) {
        if ( SetFilePointer(context->hidden.win32io.h,0L,NULL,FILE_END) == INVALID_SET_FILE_POINTER ) {
            SDL_Error(SDL_EFWRITE);
            return 0;
        }
    }

    if (!WriteFile(context->hidden.win32io.h,ptr,total_bytes,&byte_written,NULL)) {
        SDL_Error(SDL_EFWRITE);
        return 0;
    }

    nwritten = byte_written/size;
    return nwritten;
}
예제 #2
0
파일: SDL_rwops.c 프로젝트: DAOWAce/pcsxr
static size_t SDLCALL
win32_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
{
    size_t total_need;
    size_t total_read = 0;
    size_t read_ahead;
    DWORD byte_read;

    total_need = size * maxnum;

    if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE
        || !total_need)
        return 0;

    if (context->hidden.win32io.buffer.left > 0) {
        void *data = (char *) context->hidden.win32io.buffer.data +
            context->hidden.win32io.buffer.size -
            context->hidden.win32io.buffer.left;
        read_ahead =
            SDL_min(total_need, context->hidden.win32io.buffer.left);
        SDL_memcpy(ptr, data, read_ahead);
        context->hidden.win32io.buffer.left -= read_ahead;

        if (read_ahead == total_need) {
            return maxnum;
        }
        ptr = (char *) ptr + read_ahead;
        total_need -= read_ahead;
        total_read += read_ahead;
    }

    if (total_need < READAHEAD_BUFFER_SIZE) {
        if (!ReadFile
            (context->hidden.win32io.h, context->hidden.win32io.buffer.data,
             READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
            SDL_Error(SDL_EFREAD);
            return 0;
        }
        read_ahead = SDL_min(total_need, (int) byte_read);
        SDL_memcpy(ptr, context->hidden.win32io.buffer.data, read_ahead);
        context->hidden.win32io.buffer.size = byte_read;
        context->hidden.win32io.buffer.left = byte_read - read_ahead;
        total_read += read_ahead;
    } else {
        if (!ReadFile
            (context->hidden.win32io.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
            SDL_Error(SDL_EFREAD);
            return 0;
        }
        total_read += byte_read;
    }
    return (total_read / size);
}
static int rfork_seek(SDL_RWops *context, int offset, int whence)
{
	rfork_data *d = (rfork_data *)context->hidden.unknown.data1;

	off_t newpos;
	switch (whence) {
		case SEEK_SET:
			newpos = offset;
			break;
		case SEEK_CUR:
			newpos = d->current + offset;
			break;
		case SEEK_END:
			newpos = d->size + offset;
			break;
		default:
			SDL_SetError("Unknown value for 'whence'");
			return -1;
	}

	if (newpos < 0 || newpos > d->size) {
		SDL_Error(SDL_EFSEEK);
		return -1;
	}

	d->current = newpos;
	return newpos;
}
예제 #4
0
파일: SDL_wave.c 프로젝트: OS2World/LIB-SDL
static int ReadChunk(SDL_RWops *src, Chunk *chunk)
{
	chunk->magic	= SDL_ReadLE32(src);
	chunk->length	= SDL_ReadLE32(src);
	chunk->data = (Uint8 *)malloc(chunk->length);
	if ( chunk->data == NULL ) {
		SDL_Error(SDL_ENOMEM);
		return(-1);
	}
	if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
		SDL_Error(SDL_EFREAD);
		free(chunk->data);
		return(-1);
	}
	return(chunk->length);
}
예제 #5
0
/**
* Generates an execution key for the fuzzer.
*
* \param runSeed        The run seed to use
* \param suiteName      The name of the test suite
* \param testName       The name of the test
* \param iteration      The iteration count
*
* \returns The generated execution key to initialize the fuzzer with.
*
*/
static Uint64
SDLTest_GenerateExecKey(const char *runSeed, char *suiteName, char *testName, int iteration)
{
    SDLTest_Md5Context md5Context;
    Uint64 *keys;
    char iterationString[16];
    Uint32 runSeedLength;
    Uint32 suiteNameLength;
    Uint32 testNameLength;
    Uint32 iterationStringLength;
    Uint32 entireStringLength;
    char *buffer;

    if (runSeed == NULL || runSeed[0] == '\0') {
        SDLTest_LogError("Invalid runSeed string.");
        return -1;
    }

    if (suiteName == NULL || suiteName[0] == '\0') {
        SDLTest_LogError("Invalid suiteName string.");
        return -1;
    }

    if (testName == NULL || testName[0] == '\0') {
        SDLTest_LogError("Invalid testName string.");
        return -1;
    }

    if (iteration <= 0) {
        SDLTest_LogError("Invalid iteration count.");
        return -1;
    }

    /* Convert iteration number into a string */
    SDL_memset(iterationString, 0, sizeof(iterationString));
    SDL_snprintf(iterationString, sizeof(iterationString) - 1, "%d", iteration);

    /* Combine the parameters into single string */
    runSeedLength = SDL_strlen(runSeed);
    suiteNameLength = SDL_strlen(suiteName);
    testNameLength = SDL_strlen(testName);
    iterationStringLength = SDL_strlen(iterationString);
    entireStringLength  = runSeedLength + suiteNameLength + testNameLength + iterationStringLength + 1;
    buffer = (char *)SDL_malloc(entireStringLength);
    if (buffer == NULL) {
        SDLTest_LogError("Failed to allocate buffer for execKey generation.");
        SDL_Error(SDL_ENOMEM);
        return 0;
    }
    SDL_snprintf(buffer, entireStringLength, "%s%s%s%d", runSeed, suiteName, testName, iteration);

    /* Hash string and use half of the digest as 64bit exec key */
    SDLTest_Md5Init(&md5Context);
    SDLTest_Md5Update(&md5Context, (unsigned char *)buffer, entireStringLength);
    SDLTest_Md5Final(&md5Context);
    SDL_free(buffer);
    keys = (Uint64 *)md5Context.digest;

    return keys[0];
}
예제 #6
0
static int SDLCALL dc_seek(SDL_RWops *context, int offset, int whence)
{
	off_t pos;
	int dc_whence;
	
	switch (whence) {
		case RW_SEEK_SET:		
			dc_whence = SEEK_SET;
			break;
		case RW_SEEK_CUR:
			dc_whence = SEEK_CUR;
			break;
		case RW_SEEK_END:
			dc_whence = SEEK_END;
			break;
		default:
			SDL_SetError("dc_seek: Unknown value for 'whence'");
			return -1;
	}
	
	pos = fs_seek(context->hidden.dc.fd, offset, dc_whence);
	
	if ( pos < 0 ) {
		SDL_Error(SDL_EFSEEK);
		return(-1);
	}
	
	return pos;
}
예제 #7
0
/**
* Generates a random run seed string for the harness. The generated seed
* will contain alphanumeric characters (0-9A-Z).
*
* Note: The returned string needs to be deallocated by the caller.
*
* \param length The length of the seed string to generate
*
* \returns The generated seed string
*/
char *
SDLTest_GenerateRunSeed(const int length)
{
    char *seed = NULL;
    SDLTest_RandomContext randomContext;
    int counter;

    /* Sanity check input */
    if (length <= 0) {
        SDLTest_LogError("The length of the harness seed must be >0.");
        return NULL;
    }

    /* Allocate output buffer */
    seed = (char *)SDL_malloc((length + 1) * sizeof(char));
    if (seed == NULL) {
        SDLTest_LogError("SDL_malloc for run seed output buffer failed.");
        SDL_Error(SDL_ENOMEM);
        return NULL;
    }

    /* Generate a random string of alphanumeric characters */
    SDLTest_RandomInitTime(&randomContext);
    for (counter = 0; counter < length; counter++) {
        unsigned int number = SDLTest_Random(&randomContext);
        char ch = (char) (number % (91 - 48)) + 48;
        if (ch >= 58 && ch <= 64) {
            ch = 65;
        }
        seed[counter] = ch;
    }
    seed[length] = '\0';

    return seed;
}
예제 #8
0
static int64_t zlib_file_seek(SDL_RWops* const context, int64_t offset, int whence) {
    auto const fp = reinterpret_cast<gzFile>(context->hidden.unknown.data1);

    const auto pos = gzseek(fp, offset, whence);
    if (pos == -1)
        return SDL_Error(SDL_EFSEEK);
    return pos;
}
예제 #9
0
파일: SDL_rwops.c 프로젝트: RDCH106/n64oid
static int SDLCALL stdio_seek(SDL_RWops *context, int offset, int whence)
{
    if ( fseek(context->hidden.stdio.fp, offset, whence) == 0 ) {
        return(ftell(context->hidden.stdio.fp));
    } else {
        SDL_Error(SDL_EFSEEK);
        return(-1);
    }
}
예제 #10
0
extern "C" Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence)
{
    Sint64 newPosition;

    switch (whence) {
        case RW_SEEK_SET:
            newPosition = offset;
            break;
        case RW_SEEK_CUR:
            newPosition = ctx->hidden.androidio.position + offset;
            break;
        case RW_SEEK_END:
            newPosition = ctx->hidden.androidio.size + offset;
            break;
        default:
            SDL_SetError("Unknown value for 'whence'");
            return -1;
    }

    /* Validate the new position */
    if (newPosition < 0) {
        SDL_Error(SDL_EFSEEK);
        return -1;
    }
    if (newPosition > ctx->hidden.androidio.size) {
        newPosition = ctx->hidden.androidio.size;
    }

    Sint64 movement = newPosition - ctx->hidden.androidio.position;
    if (movement > 0) {
        unsigned char buffer[4096];

        // The easy case where we're seeking forwards
        while (movement > 0) {
            Sint64 amount = sizeof (buffer);
            if (amount > movement) {
                amount = movement;
            }
            size_t result = Android_JNI_FileRead(ctx, buffer, 1, amount);
            if (result <= 0) {
                // Failed to read/skip the required amount, so fail
                return -1;
            }

            movement -= result;
        }

    } else if (movement < 0) {
        // We can't seek backwards so we have to reopen the file and seek
        // forwards which obviously isn't very efficient
        Android_JNI_FileClose(ctx, false);
        Android_JNI_FileOpen(ctx);
        Android_JNI_FileSeek(ctx, newPosition, RW_SEEK_SET);
    }

    return ctx->hidden.androidio.position;
}
예제 #11
0
파일: SDL_rwops.c 프로젝트: RDCH106/n64oid
static int SDLCALL stdio_read(SDL_RWops *context, void *ptr, int size, int maxnum)
{
    size_t nread;

    nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
    if ( nread == 0 && ferror(context->hidden.stdio.fp) ) {
        SDL_Error(SDL_EFREAD);
    }
    return(nread);
}
예제 #12
0
static int SDLCALL dc_read(SDL_RWops *context, void *ptr, int size, int maxnum)
{
	size_t nread = fs_read(context->hidden.dc.fd, ptr, size * maxnum); 
	
	if ( nread < 0 ) {
		SDL_Error(SDL_EFREAD);
		return -1;
	}
	return (nread / size);
}
예제 #13
0
파일: SDL_rwops.c 프로젝트: RDCH106/n64oid
static int SDLCALL stdio_write(SDL_RWops *context, const void *ptr, int size, int num)
{
    size_t nwrote;

    nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
    if ( nwrote == 0 && ferror(context->hidden.stdio.fp) ) {
        SDL_Error(SDL_EFWRITE);
    }
    return(nwrote);
}
예제 #14
0
static int zlib_file_close(SDL_RWops * context) {
    int status = 0;
    if (context) {
        auto const fp = reinterpret_cast<gzFile>(context->hidden.unknown.data1);

        if (gzclose(fp) != 0) {
            status = SDL_Error(SDL_EFWRITE);
        }
    }
    return status;
}
예제 #15
0
static size_t zlib_file_read(SDL_RWops* const context, void *ptr, size_t size, size_t maxnum) {
    auto const fp = reinterpret_cast<gzFile>(context->hidden.unknown.data1);

    const size_t nread = gzread(fp, ptr, size * maxnum);

    int error;
    gzerror(fp, &error);
    if (nread == 0 && error) {
        SDL_Error(SDL_EFREAD);
    }
    return nread;
}
예제 #16
0
static int SDLCALL dc_write(SDL_RWops *context, const void *ptr, int size, int num)
{
	size_t nwrote;
	nwrote = fs_write(context->hidden.dc.fd, ptr, size * num);
	
	if ( nwrote < 0 ) {
		SDL_Error(SDL_EFWRITE);
		return -1;
	}

	return(nwrote);
}
예제 #17
0
static size_t zlib_file_write(SDL_RWops* const context, const void *ptr, size_t size, size_t num) {
    auto const fp = reinterpret_cast<gzFile>(context->hidden.unknown.data1);

    const size_t nwrote = gzwrite(fp, ptr, size * num);

    int error;
    gzerror(fp, &error);
    if (nwrote == 0 && error) {
        SDL_Error(SDL_EFWRITE);
    }
    return (nwrote);
}
예제 #18
0
static int SDLCALL
stdio_close(SDL_RWops * context)
{
    int status = 0;
    if (context) {
        if (context->hidden.stdio.autoclose) {
            /* WARNING:  Check the return value here! */
            if (fclose(context->hidden.stdio.fp) != 0) {
                status = SDL_Error(SDL_EFWRITE);
            }
        }
        SDL_FreeRW(context);
    }
    return status;
}
예제 #19
0
파일: SDL_rwops.c 프로젝트: Daft-Freak/vogl
static Sint64 SDLCALL
stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
{
#ifdef HAVE_FSEEKO64
    if (fseeko64(context->hidden.stdio.fp, (off64_t)offset, whence) == 0) {
        return ftello64(context->hidden.stdio.fp);
    }
#elif defined(HAVE_FSEEKO)
    if (fseeko(context->hidden.stdio.fp, (off_t)offset, whence) == 0) {
        return ftello(context->hidden.stdio.fp);
    }
#else
    if (fseek(context->hidden.stdio.fp, offset, whence) == 0) {
        return (ftell(context->hidden.stdio.fp));
    }
#endif
    return SDL_Error(SDL_EFSEEK);
}
예제 #20
0
파일: SDL_rwops.c 프로젝트: ptitSeb/SDL2
static Sint64 SDLCALL
stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
{
#if defined(FSEEK_OFF_MIN) && defined(FSEEK_OFF_MAX)
    if (offset < (Sint64)(FSEEK_OFF_MIN) || offset > (Sint64)(FSEEK_OFF_MAX)) {
        return SDL_SetError("Seek offset out of range");
    }
#endif

    if (fseek(context->hidden.stdio.fp, (fseek_off_t)offset, whence) == 0) {
        Sint64 pos = ftell(context->hidden.stdio.fp);
        if (pos < 0) {
            return SDL_SetError("Couldn't get stream offset");
        }
        return pos;
    }
    return SDL_Error(SDL_EFSEEK);
}
예제 #21
0
static int stdio_write(SDL_RWops *context, const void *ptr, int size, int num) //maks
{
	size_t nwrote;
	SDL_mutexP(multipleArchiveMutEx);

	if(!bInAMultipleFuncion && context == archive)
	{		
		current = context;

		if(context->stdioFilePosition != context->filePosition)
		{
			//Position changed by a multiple file call
			//Restore
			fseek(context->hidden.stdio.fp, context->stdioFilePosition, SEEK_SET);
			context->filePosition = context->stdioFilePosition;
		}
	}

	nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
	if ( nwrote == 0 && ferror(context->hidden.stdio.fp) ) {
		SDL_Error(SDL_EFWRITE);
	}
	else
	{
		//maks flush the stream to see all saved data
		//if a crash happens
		fflush( context->hidden.stdio.fp );

		if(!bInAMultipleFuncion)
		{
			context->filePosition += nwrote*size;
			context->stdioFilePosition = context->filePosition;
		}
		
	}

	/*if(!bInAMultipleFuncion && context == archive)
	{
		SDL_mutexV(multipleArchiveMutEx);
	}*/

	SDL_mutexV(multipleArchiveMutEx);
	return(nwrote);
}
예제 #22
0
static int stdio_seek(SDL_RWops *context, int offset, int whence) //maks
{
	int res = -1;
	SDL_mutexP(multipleArchiveMutEx);

	if(!bInAMultipleFuncion && context == archive)
	{
		current = context;

		if(context->stdioFilePosition != context->filePosition && whence != SEEK_SET)
		{
			//Position changed by a multiple file call
			//Restore
			fseek(context->hidden.stdio.fp, context->stdioFilePosition, SEEK_SET);
			context->filePosition = context->stdioFilePosition;
		}
	}

	if ( fseek(context->hidden.stdio.fp, offset, whence) == 0 ) 
	{
		res = ftell(context->hidden.stdio.fp);

		if(!bInAMultipleFuncion)
		{
			context->stdioFilePosition = context->filePosition = res;
		}
	} 
	else 
	{
		SDL_Error(SDL_EFSEEK);
		res = -1;
	}

	/*if(!bInAMultipleFuncion && context == archive)
	{
		SDL_mutexV(multipleArchiveMutEx);		
	}*/

	SDL_mutexV(multipleArchiveMutEx);
	return res;
}
예제 #23
0
static int stdio_read(SDL_RWops *context, void *ptr, int size, int maxnum) //maks
{
	size_t nread;
	SDL_mutexP(multipleArchiveMutEx);

	if(!bInAMultipleFuncion && context == archive)
	{		
		current = context;

		if(context->stdioFilePosition != context->filePosition)
		{
			//Position changed by a multiple file call
			//Restore
			fseek(context->hidden.stdio.fp, context->stdioFilePosition, SEEK_SET);
			context->filePosition = context->stdioFilePosition;
		}
	}

	nread = fread(ptr, size, maxnum, context->hidden.stdio.fp); 
	if ( nread == 0 && ferror(context->hidden.stdio.fp) ) 
	{
		SDL_Error(SDL_EFREAD);
	}
	else
	{
		if(!bInAMultipleFuncion)
		{
			context->filePosition += nread*size;
			context->stdioFilePosition = context->filePosition;
		}
		
	}

	/*if(!bInAMultipleFuncion && context == archive)
	{
		SDL_mutexV(multipleArchiveMutEx);
	}*/

	SDL_mutexV(multipleArchiveMutEx);
	return(nread);
}
예제 #24
0
파일: SDL_rwops.c 프로젝트: DAOWAce/pcsxr
static long SDLCALL
win32_file_seek(SDL_RWops * context, long offset, int whence)
{
    DWORD win32whence;
    long file_pos;

    if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE) {
        SDL_SetError("win32_file_seek: invalid context/file not opened");
        return -1;
    }

    /* FIXME: We may be able to satisfy the seek within buffered data */
    if (whence == RW_SEEK_CUR && context->hidden.win32io.buffer.left) {
        offset -= (long)context->hidden.win32io.buffer.left;
    }
    context->hidden.win32io.buffer.left = 0;

    switch (whence) {
    case RW_SEEK_SET:
        win32whence = FILE_BEGIN;
        break;
    case RW_SEEK_CUR:
        win32whence = FILE_CURRENT;
        break;
    case RW_SEEK_END:
        win32whence = FILE_END;
        break;
    default:
        SDL_SetError("win32_file_seek: Unknown value for 'whence'");
        return -1;
    }

    file_pos =
        SetFilePointer(context->hidden.win32io.h, offset, NULL, win32whence);

    if (file_pos != INVALID_SET_FILE_POINTER)
        return file_pos;        /* success */

    SDL_Error(SDL_EFSEEK);
    return -1;                  /* error */
}
예제 #25
0
파일: SDL_bmp.c 프로젝트: Evengard/UniMod
int
SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst)
{
    Sint64 fp_offset;
    int i, pad;
    SDL_Surface *surface;
    Uint8 *bits;
    SDL_bool save32bit = SDL_FALSE;
    SDL_bool saveLegacyBMP = SDL_FALSE;

    /* The Win32 BMP file header (14 bytes) */
    char magic[2] = { 'B', 'M' };
    Uint32 bfSize;
    Uint16 bfReserved1;
    Uint16 bfReserved2;
    Uint32 bfOffBits;

    /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
    Uint32 biSize;
    Sint32 biWidth;
    Sint32 biHeight;
    Uint16 biPlanes;
    Uint16 biBitCount;
    Uint32 biCompression;
    Uint32 biSizeImage;
    Sint32 biXPelsPerMeter;
    Sint32 biYPelsPerMeter;
    Uint32 biClrUsed;
    Uint32 biClrImportant;

    /* The additional header members from the Win32 BITMAPV4HEADER struct (108 bytes in total) */
    Uint32 bV4RedMask = 0;
    Uint32 bV4GreenMask = 0;
    Uint32 bV4BlueMask = 0;
    Uint32 bV4AlphaMask = 0;
    Uint32 bV4CSType = 0;
    Sint32 bV4Endpoints[3 * 3] = {0};
    Uint32 bV4GammaRed = 0;
    Uint32 bV4GammaGreen = 0;
    Uint32 bV4GammaBlue = 0;

    /* Make sure we have somewhere to save */
    surface = NULL;
    if (dst) {
#ifdef SAVE_32BIT_BMP
        /* We can save alpha information in a 32-bit BMP */
        if (saveme->format->BitsPerPixel >= 8 && (saveme->format->Amask ||
            saveme->map->info.flags & SDL_COPY_COLORKEY)) {
            save32bit = SDL_TRUE;
        }
#endif /* SAVE_32BIT_BMP */

        if (saveme->format->palette && !save32bit) {
            if (saveme->format->BitsPerPixel == 8) {
                surface = saveme;
            } else {
                SDL_SetError("%d bpp BMP files not supported",
                             saveme->format->BitsPerPixel);
            }
        } else if ((saveme->format->BitsPerPixel == 24) && !save32bit &&
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
                   (saveme->format->Rmask == 0x00FF0000) &&
                   (saveme->format->Gmask == 0x0000FF00) &&
                   (saveme->format->Bmask == 0x000000FF)
#else
                   (saveme->format->Rmask == 0x000000FF) &&
                   (saveme->format->Gmask == 0x0000FF00) &&
                   (saveme->format->Bmask == 0x00FF0000)
#endif
            ) {
            surface = saveme;
        } else {
            SDL_PixelFormat format;

            /* If the surface has a colorkey or alpha channel we'll save a
               32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
            if (save32bit) {
                SDL_InitFormat(&format, SDL_PIXELFORMAT_BGRA32);
            } else {
                SDL_InitFormat(&format, SDL_PIXELFORMAT_BGR24);
            }
            surface = SDL_ConvertSurface(saveme, &format, 0);
            if (!surface) {
                SDL_SetError("Couldn't convert image to %d bpp",
                             format.BitsPerPixel);
            }
        }
    } else {
        /* Set no error here because it may overwrite a more useful message from
           SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */
        return -1;
    }

    if (save32bit) {
        saveLegacyBMP = SDL_GetHintBoolean(SDL_HINT_BMP_SAVE_LEGACY_FORMAT, SDL_FALSE);
    }

    if (surface && (SDL_LockSurface(surface) == 0)) {
        const int bw = surface->w * surface->format->BytesPerPixel;

        /* Set the BMP file header values */
        bfSize = 0;             /* We'll write this when we're done */
        bfReserved1 = 0;
        bfReserved2 = 0;
        bfOffBits = 0;          /* We'll write this when we're done */

        /* Write the BMP file header values */
        fp_offset = SDL_RWtell(dst);
        SDL_ClearError();
        SDL_RWwrite(dst, magic, 2, 1);
        SDL_WriteLE32(dst, bfSize);
        SDL_WriteLE16(dst, bfReserved1);
        SDL_WriteLE16(dst, bfReserved2);
        SDL_WriteLE32(dst, bfOffBits);

        /* Set the BMP info values */
        biSize = 40;
        biWidth = surface->w;
        biHeight = surface->h;
        biPlanes = 1;
        biBitCount = surface->format->BitsPerPixel;
        biCompression = BI_RGB;
        biSizeImage = surface->h * surface->pitch;
        biXPelsPerMeter = 0;
        biYPelsPerMeter = 0;
        if (surface->format->palette) {
            biClrUsed = surface->format->palette->ncolors;
        } else {
            biClrUsed = 0;
        }
        biClrImportant = 0;

        /* Set the BMP info values for the version 4 header */
        if (save32bit && !saveLegacyBMP) {
            biSize = 108;
            biCompression = BI_BITFIELDS;
            /* The BMP format is always little endian, these masks stay the same */
            bV4RedMask   = 0x00ff0000;
            bV4GreenMask = 0x0000ff00;
            bV4BlueMask  = 0x000000ff;
            bV4AlphaMask = 0xff000000;
            bV4CSType = LCS_WINDOWS_COLOR_SPACE;
            bV4GammaRed = 0;
            bV4GammaGreen = 0;
            bV4GammaBlue = 0;
        }

        /* Write the BMP info values */
        SDL_WriteLE32(dst, biSize);
        SDL_WriteLE32(dst, biWidth);
        SDL_WriteLE32(dst, biHeight);
        SDL_WriteLE16(dst, biPlanes);
        SDL_WriteLE16(dst, biBitCount);
        SDL_WriteLE32(dst, biCompression);
        SDL_WriteLE32(dst, biSizeImage);
        SDL_WriteLE32(dst, biXPelsPerMeter);
        SDL_WriteLE32(dst, biYPelsPerMeter);
        SDL_WriteLE32(dst, biClrUsed);
        SDL_WriteLE32(dst, biClrImportant);

        /* Write the BMP info values for the version 4 header */
        if (save32bit && !saveLegacyBMP) {
            SDL_WriteLE32(dst, bV4RedMask);
            SDL_WriteLE32(dst, bV4GreenMask);
            SDL_WriteLE32(dst, bV4BlueMask);
            SDL_WriteLE32(dst, bV4AlphaMask);
            SDL_WriteLE32(dst, bV4CSType);
            for (i = 0; i < 3 * 3; i++) {
                SDL_WriteLE32(dst, bV4Endpoints[i]);
            }
            SDL_WriteLE32(dst, bV4GammaRed);
            SDL_WriteLE32(dst, bV4GammaGreen);
            SDL_WriteLE32(dst, bV4GammaBlue);
        }

        /* Write the palette (in BGR color order) */
        if (surface->format->palette) {
            SDL_Color *colors;
            int ncolors;

            colors = surface->format->palette->colors;
            ncolors = surface->format->palette->ncolors;
            for (i = 0; i < ncolors; ++i) {
                SDL_RWwrite(dst, &colors[i].b, 1, 1);
                SDL_RWwrite(dst, &colors[i].g, 1, 1);
                SDL_RWwrite(dst, &colors[i].r, 1, 1);
                SDL_RWwrite(dst, &colors[i].a, 1, 1);
            }
        }

        /* Write the bitmap offset */
        bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
        if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
            SDL_Error(SDL_EFSEEK);
        }
        SDL_WriteLE32(dst, bfOffBits);
        if (SDL_RWseek(dst, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
            SDL_Error(SDL_EFSEEK);
        }

        /* Write the bitmap image upside down */
        bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
        pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
        while (bits > (Uint8 *) surface->pixels) {
            bits -= surface->pitch;
            if (SDL_RWwrite(dst, bits, 1, bw) != bw) {
                SDL_Error(SDL_EFWRITE);
                break;
            }
            if (pad) {
                const Uint8 padbyte = 0;
                for (i = 0; i < pad; ++i) {
                    SDL_RWwrite(dst, &padbyte, 1, 1);
                }
            }
        }

        /* Write the BMP file size */
        bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
        if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
            SDL_Error(SDL_EFSEEK);
        }
        SDL_WriteLE32(dst, bfSize);
        if (SDL_RWseek(dst, fp_offset + bfSize, RW_SEEK_SET) < 0) {
            SDL_Error(SDL_EFSEEK);
        }

        /* Close it up.. */
        SDL_UnlockSurface(surface);
        if (surface != saveme) {
            SDL_FreeSurface(surface);
        }
    }

    if (freedst && dst) {
        SDL_RWclose(dst);
    }
    return ((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
}
예제 #26
0
/**
* \brief Execute a test suite using the given run seed and execution key.
*
* The filter string is matched to the suite name (full comparison) to select a single suite,
* or if no suite matches, it is matched to the test names (full comparison) to select a single test.
*
* \param testSuites Suites containing the test case.
* \param userRunSeed Custom run seed provided by user, or NULL to autogenerate one.
* \param userExecKey Custom execution key provided by user, or 0 to autogenerate one.
* \param filter Filter specification. NULL disables. Case sensitive.
* \param testIterations Number of iterations to run each test case.
*
* \returns Test run result; 0 when all tests passed, 1 if any tests failed.
*/
int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *userRunSeed, Uint64 userExecKey, const char *filter, int testIterations)
{
    int totalNumberOfTests = 0;
    int failedNumberOfTests = 0;
    int suiteCounter;
    int testCounter;
    int iterationCounter;
    SDLTest_TestSuiteReference *testSuite;
    const SDLTest_TestCaseReference *testCase;
    const char *runSeed = NULL;
    char *currentSuiteName;
    char *currentTestName;
    Uint64 execKey;
    float runStartSeconds;
    float suiteStartSeconds;
    float testStartSeconds;
    float runEndSeconds;
    float suiteEndSeconds;
    float testEndSeconds;
    float runtime;
    int suiteFilter = 0;
    char *suiteFilterName = NULL;
    int testFilter = 0;
    char *testFilterName = NULL;
	SDL_bool forceTestRun = SDL_FALSE;
    int testResult = 0;
    int runResult = 0;
    Uint32 totalTestFailedCount = 0;
    Uint32 totalTestPassedCount = 0;
    Uint32 totalTestSkippedCount = 0;
    Uint32 testFailedCount = 0;
    Uint32 testPassedCount = 0;
    Uint32 testSkippedCount = 0;
    Uint32 countSum = 0;
    const SDLTest_TestCaseReference **failedTests;

    /* Sanitize test iterations */
    if (testIterations < 1) {
        testIterations = 1;
    }

    /* Generate run see if we don't have one already */
    if (userRunSeed == NULL || userRunSeed[0] == '\0') {
        runSeed = SDLTest_GenerateRunSeed(16);
        if (runSeed == NULL) {
            SDLTest_LogError("Generating a random seed failed");
            return 2;
        }
    } else {
        runSeed = userRunSeed;
    }


    /* Reset per-run counters */
    totalTestFailedCount = 0;
    totalTestPassedCount = 0;
    totalTestSkippedCount = 0;

    /* Take time - run start */
    runStartSeconds = GetClock();

    /* Log run with fuzzer parameters */
    SDLTest_Log("::::: Test Run /w seed '%s' started\n", runSeed);

	/* Count the total number of tests */
    suiteCounter = 0;
    while (testSuites[suiteCounter]) {
        testSuite=(SDLTest_TestSuiteReference *)testSuites[suiteCounter];
        suiteCounter++;
        testCounter = 0;
        while (testSuite->testCases[testCounter])
        {
            testCounter++;
			totalNumberOfTests++;
		}
	}

	/* Pre-allocate an array for tracking failed tests (potentially all test cases) */
	failedTests = (const SDLTest_TestCaseReference **)SDL_malloc(totalNumberOfTests * sizeof(SDLTest_TestCaseReference *));
	if (failedTests == NULL) {	
	   SDLTest_LogError("Unable to allocate cache for failed tests");
           SDL_Error(SDL_ENOMEM);	   
           return -1;
	}

    /* Initialize filtering */
    if (filter != NULL && filter[0] != '\0') {
        /* Loop over all suites to check if we have a filter match */
        suiteCounter = 0;
        while (testSuites[suiteCounter] && suiteFilter == 0) {
            testSuite=(SDLTest_TestSuiteReference *)testSuites[suiteCounter];
            suiteCounter++;
            if (testSuite->name != NULL && SDL_strcmp(filter, testSuite->name) == 0) {
                /* Matched a suite name */
                suiteFilter = 1;
                suiteFilterName = testSuite->name;
                SDLTest_Log("Filtering: running only suite '%s'", suiteFilterName);
                break;
            }

            /* Within each suite, loop over all test cases to check if we have a filter match */
            testCounter = 0;
            while (testSuite->testCases[testCounter] && testFilter == 0)
            {
                testCase = testSuite->testCases[testCounter];
                testCounter++;
                if (testCase->name != NULL && SDL_strcmp(filter, testCase->name) == 0) {
                    /* Matched a test name */
                    suiteFilter = 1;
                    suiteFilterName = testSuite->name;
                    testFilter = 1;
                    testFilterName = testCase->name;
                    SDLTest_Log("Filtering: running only test '%s' in suite '%s'", testFilterName, suiteFilterName);
                    break;
                }
            }
        }

        if (suiteFilter == 0 && testFilter == 0) {
            SDLTest_LogError("Filter '%s' did not match any test suite/case.", filter);
            SDLTest_Log("Exit code: 2");
            SDL_free((void *) failedTests);
            return 2;
        }
    }

    /* Loop over all suites */
    suiteCounter = 0;
    while(testSuites[suiteCounter]) {
        testSuite=(SDLTest_TestSuiteReference *)testSuites[suiteCounter];
        currentSuiteName = (char *)((testSuite->name) ? testSuite->name : SDLTEST_INVALID_NAME_FORMAT);
        suiteCounter++;

        /* Filter suite if flag set and we have a name */
        if (suiteFilter == 1 && suiteFilterName != NULL && testSuite->name != NULL &&
            SDL_strcmp(suiteFilterName, testSuite->name) != 0) {
                /* Skip suite */
                SDLTest_Log("===== Test Suite %i: '%s' skipped\n",
                    suiteCounter,
                    currentSuiteName);
        } else {

            /* Reset per-suite counters */
            testFailedCount = 0;
            testPassedCount = 0;
            testSkippedCount = 0;

            /* Take time - suite start */
            suiteStartSeconds = GetClock();

            /* Log suite started */
            SDLTest_Log("===== Test Suite %i: '%s' started\n",
                suiteCounter,
                currentSuiteName);

            /* Loop over all test cases */
            testCounter = 0;
            while(testSuite->testCases[testCounter])
            {
                testCase = testSuite->testCases[testCounter];
                currentTestName = (char *)((testCase->name) ? testCase->name : SDLTEST_INVALID_NAME_FORMAT);
                testCounter++;

                /* Filter tests if flag set and we have a name */
                if (testFilter == 1 && testFilterName != NULL && testCase->name != NULL &&
                    SDL_strcmp(testFilterName, testCase->name) != 0) {
                        /* Skip test */
                        SDLTest_Log("===== Test Case %i.%i: '%s' skipped\n",
                            suiteCounter,
                            testCounter,
                            currentTestName);
                } else {
                    /* Override 'disabled' flag if we specified a test filter (i.e. force run for debugging) */
                    if (testFilter == 1 && !testCase->enabled) {
                        SDLTest_Log("Force run of disabled test since test filter was set");
						forceTestRun = SDL_TRUE;
                    }

                    /* Take time - test start */
                    testStartSeconds = GetClock();

                    /* Log test started */
                    SDLTest_Log("----- Test Case %i.%i: '%s' started",
                        suiteCounter,
                        testCounter,
                        currentTestName);
                    if (testCase->description != NULL && testCase->description[0] != '\0') {
                        SDLTest_Log("Test Description: '%s'",
                            (testCase->description) ? testCase->description : SDLTEST_INVALID_NAME_FORMAT);
                    }

                    /* Loop over all iterations */
                    iterationCounter = 0;
                    while(iterationCounter < testIterations)
                    {
                        iterationCounter++;

                        if (userExecKey != 0) {
                            execKey = userExecKey;
                        } else {
                            execKey = SDLTest_GenerateExecKey(runSeed, testSuite->name, testCase->name, iterationCounter);
                        }

                        SDLTest_Log("Test Iteration %i: execKey %" SDL_PRIu64, iterationCounter, execKey);
						testResult = SDLTest_RunTest(testSuite, testCase, execKey, forceTestRun);

                        if (testResult == TEST_RESULT_PASSED) {
                            testPassedCount++;
                            totalTestPassedCount++;
                        } else if (testResult == TEST_RESULT_SKIPPED) {
                            testSkippedCount++;
                            totalTestSkippedCount++;
                        } else {
                            testFailedCount++;
                            totalTestFailedCount++;
                        }
                    }

                    /* Take time - test end */
                    testEndSeconds = GetClock();
                    runtime = testEndSeconds - testStartSeconds;
                    if (runtime < 0.0f) runtime = 0.0f;

                    if (testIterations > 1) {
                        /* Log test runtime */
                        SDLTest_Log("Runtime of %i iterations: %.1f sec", testIterations, runtime);
                        SDLTest_Log("Average Test runtime: %.5f sec", runtime / (float)testIterations);
                    } else {
                        /* Log test runtime */
                        SDLTest_Log("Total Test runtime: %.1f sec", runtime);
                    }

                    /* Log final test result */
                    switch (testResult) {
                    case TEST_RESULT_PASSED:
                        SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Test", currentTestName, "Passed");
                        break;
                    case TEST_RESULT_FAILED:
                        SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Test", currentTestName, "Failed");
                        break;
                    case TEST_RESULT_NO_ASSERT:
                        SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT,"Test", currentTestName, "No Asserts");
                        break;
                    }

                    /* Collect failed test case references for repro-step display */
                    if (testResult == TEST_RESULT_FAILED) {
                        failedTests[failedNumberOfTests] = testCase;
                        failedNumberOfTests++;
                    }
                }
            }

            /* Take time - suite end */
            suiteEndSeconds = GetClock();
            runtime = suiteEndSeconds - suiteStartSeconds;
            if (runtime < 0.0f) runtime = 0.0f;

            /* Log suite runtime */
            SDLTest_Log("Total Suite runtime: %.1f sec", runtime);

            /* Log summary and final Suite result */
            countSum = testPassedCount + testFailedCount + testSkippedCount;
            if (testFailedCount == 0)
            {
                SDLTest_Log(SDLTEST_LOG_SUMMARY_FORMAT, "Suite", countSum, testPassedCount, testFailedCount, testSkippedCount);
                SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Suite", currentSuiteName, "Passed");
            }
            else
            {
                SDLTest_LogError(SDLTEST_LOG_SUMMARY_FORMAT, "Suite", countSum, testPassedCount, testFailedCount, testSkippedCount);
                SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Suite", currentSuiteName, "Failed");
            }

        }
    }

    /* Take time - run end */
    runEndSeconds = GetClock();
    runtime = runEndSeconds - runStartSeconds;
    if (runtime < 0.0f) runtime = 0.0f;

    /* Log total runtime */
    SDLTest_Log("Total Run runtime: %.1f sec", runtime);

    /* Log summary and final run result */
    countSum = totalTestPassedCount + totalTestFailedCount + totalTestSkippedCount;
    if (totalTestFailedCount == 0)
    {
        runResult = 0;
        SDLTest_Log(SDLTEST_LOG_SUMMARY_FORMAT, "Run", countSum, totalTestPassedCount, totalTestFailedCount, totalTestSkippedCount);
        SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Run /w seed", runSeed, "Passed");
    }
    else
    {
        runResult = 1;
        SDLTest_LogError(SDLTEST_LOG_SUMMARY_FORMAT, "Run", countSum, totalTestPassedCount, totalTestFailedCount, totalTestSkippedCount);
        SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Run /w seed", runSeed, "Failed");
    }

    /* Print repro steps for failed tests */
    if (failedNumberOfTests > 0) {
        SDLTest_Log("Harness input to repro failures:");
        for (testCounter = 0; testCounter < failedNumberOfTests; testCounter++) {
          SDLTest_Log(" --seed %s --filter %s", runSeed, failedTests[testCounter]->name);
        }
    }
    SDL_free((void *) failedTests);

    SDLTest_Log("Exit code: %d", runResult);
    return runResult;
}
예제 #27
0
SDL_Surface *
SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
{
    SDL_bool was_error;
    long fp_offset;
    int bmpPitch;
    int i, pad;
    SDL_Surface *surface;
    Uint32 Rmask;
    Uint32 Gmask;
    Uint32 Bmask;
    Uint32 Amask;
    SDL_Palette *palette;
    Uint8 *bits;
    Uint8 *top, *end;
    SDL_bool topDown;
    int ExpandBMP;

    /* The Win32 BMP file header (14 bytes) */
    char magic[2];
    Uint32 bfSize;
    Uint16 bfReserved1;
    Uint16 bfReserved2;
    Uint32 bfOffBits;

    /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
    Uint32 biSize;
    Sint32 biWidth;
    Sint32 biHeight;
    Uint16 biPlanes;
    Uint16 biBitCount;
    Uint32 biCompression;
    Uint32 biSizeImage;
    Sint32 biXPelsPerMeter;
    Sint32 biYPelsPerMeter;
    Uint32 biClrUsed;
    Uint32 biClrImportant;

    /* Make sure we are passed a valid data source */
    surface = NULL;
    was_error = SDL_FALSE;
    if (src == NULL) {
        was_error = SDL_TRUE;
        goto done;
    }

    /* Read in the BMP file header */
    fp_offset = SDL_RWtell(src);
    SDL_ClearError();
    if (SDL_RWread(src, magic, 1, 2) != 2) {
        SDL_Error(SDL_EFREAD);
        was_error = SDL_TRUE;
        goto done;
    }
    if (SDL_strncmp(magic, "BM", 2) != 0) {
        SDL_SetError("File is not a Windows BMP file");
        was_error = SDL_TRUE;
        goto done;
    }
    bfSize = SDL_ReadLE32(src);
    bfReserved1 = SDL_ReadLE16(src);
    bfReserved2 = SDL_ReadLE16(src);
    bfOffBits = SDL_ReadLE32(src);

    /* Read the Win32 BITMAPINFOHEADER */
    biSize = SDL_ReadLE32(src);
    if (biSize == 12) {
        biWidth = (Uint32) SDL_ReadLE16(src);
        biHeight = (Uint32) SDL_ReadLE16(src);
        biPlanes = SDL_ReadLE16(src);
        biBitCount = SDL_ReadLE16(src);
        biCompression = BI_RGB;
        biSizeImage = 0;
        biXPelsPerMeter = 0;
        biYPelsPerMeter = 0;
        biClrUsed = 0;
        biClrImportant = 0;
    } else {
        biWidth = SDL_ReadLE32(src);
        biHeight = SDL_ReadLE32(src);
        biPlanes = SDL_ReadLE16(src);
        biBitCount = SDL_ReadLE16(src);
        biCompression = SDL_ReadLE32(src);
        biSizeImage = SDL_ReadLE32(src);
        biXPelsPerMeter = SDL_ReadLE32(src);
        biYPelsPerMeter = SDL_ReadLE32(src);
        biClrUsed = SDL_ReadLE32(src);
        biClrImportant = SDL_ReadLE32(src);
    }
    if (biHeight < 0) {
        topDown = SDL_TRUE;
        biHeight = -biHeight;
    } else {
        topDown = SDL_FALSE;
    }

    /* Check for read error */
    if (SDL_strcmp(SDL_GetError(), "") != 0) {
        was_error = SDL_TRUE;
        goto done;
    }

    /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */
    switch (biBitCount) {
    case 1:
    case 4:
        ExpandBMP = biBitCount;
        biBitCount = 8;
        break;
    default:
        ExpandBMP = 0;
        break;
    }

    /* We don't support any BMP compression right now */
    Rmask = Gmask = Bmask = Amask = 0;
    switch (biCompression) {
    case BI_RGB:
        /* If there are no masks, use the defaults */
        if (bfOffBits == (14 + biSize)) {
            /* Default values for the BMP format */
            switch (biBitCount) {
            case 15:
            case 16:
                Rmask = 0x7C00;
                Gmask = 0x03E0;
                Bmask = 0x001F;
                break;
            case 24:
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
                Rmask = 0x000000FF;
                Gmask = 0x0000FF00;
                Bmask = 0x00FF0000;
#else
                Rmask = 0x00FF0000;
                Gmask = 0x0000FF00;
                Bmask = 0x000000FF;
#endif
                break;
            case 32:
                Amask = 0xFF000000;
                Rmask = 0x00FF0000;
                Gmask = 0x0000FF00;
                Bmask = 0x000000FF;
                break;
            default:
                break;
            }
            break;
        }
        /* Fall through -- read the RGB masks */

    case BI_BITFIELDS:
        switch (biBitCount) {
        case 15:
        case 16:
            Rmask = SDL_ReadLE32(src);
            Gmask = SDL_ReadLE32(src);
            Bmask = SDL_ReadLE32(src);
            break;
        case 32:
            Rmask = SDL_ReadLE32(src);
            Gmask = SDL_ReadLE32(src);
            Bmask = SDL_ReadLE32(src);
            Amask = SDL_ReadLE32(src);
            break;
        default:
            break;
        }
        break;
    default:
        SDL_SetError("Compressed BMP files not supported");
        was_error = SDL_TRUE;
        goto done;
    }

    /* Create a compatible surface, note that the colors are RGB ordered */
    surface =
        SDL_CreateRGBSurface(0, biWidth, biHeight, biBitCount, Rmask, Gmask,
                             Bmask, Amask);
    if (surface == NULL) {
        was_error = SDL_TRUE;
        goto done;
    }

    /* Load the palette, if any */
    palette = (surface->format)->palette;
    if (palette) {
        if (biClrUsed == 0) {
            biClrUsed = 1 << biBitCount;
        }
        if ((int) biClrUsed > palette->ncolors) {
            palette->ncolors = biClrUsed;
            palette->colors =
                (SDL_Color *) SDL_realloc(palette->colors,
                                          palette->ncolors *
                                          sizeof(*palette->colors));
            if (!palette->colors) {
                SDL_OutOfMemory();
                was_error = SDL_TRUE;
                goto done;
            }
        } else if ((int) biClrUsed < palette->ncolors) {
            palette->ncolors = biClrUsed;
        }
        if (biSize == 12) {
            for (i = 0; i < (int) biClrUsed; ++i) {
                SDL_RWread(src, &palette->colors[i].b, 1, 1);
                SDL_RWread(src, &palette->colors[i].g, 1, 1);
                SDL_RWread(src, &palette->colors[i].r, 1, 1);
                palette->colors[i].unused = SDL_ALPHA_OPAQUE;
            }
        } else {
            for (i = 0; i < (int) biClrUsed; ++i) {
                SDL_RWread(src, &palette->colors[i].b, 1, 1);
                SDL_RWread(src, &palette->colors[i].g, 1, 1);
                SDL_RWread(src, &palette->colors[i].r, 1, 1);
                SDL_RWread(src, &palette->colors[i].unused, 1, 1);
            }
        }
    }

    /* Read the surface pixels.  Note that the bmp image is upside down */
    if (SDL_RWseek(src, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
        SDL_Error(SDL_EFSEEK);
        was_error = SDL_TRUE;
        goto done;
    }
    top = (Uint8 *)surface->pixels;
    end = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
    switch (ExpandBMP) {
    case 1:
        bmpPitch = (biWidth + 7) >> 3;
        pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
        break;
    case 4:
        bmpPitch = (biWidth + 1) >> 1;
        pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
        break;
    default:
        pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0);
        break;
    }
    if (topDown) {
        bits = top;
    } else {
        bits = end - surface->pitch;
    }
    while (bits >= top && bits < end) {
        switch (ExpandBMP) {
        case 1:
        case 4:{
                Uint8 pixel = 0;
                int shift = (8 - ExpandBMP);
                for (i = 0; i < surface->w; ++i) {
                    if (i % (8 / ExpandBMP) == 0) {
                        if (!SDL_RWread(src, &pixel, 1, 1)) {
                            SDL_SetError("Error reading from BMP");
                            was_error = SDL_TRUE;
                            goto done;
                        }
                    }
                    *(bits + i) = (pixel >> shift);
                    pixel <<= ExpandBMP;
                }
            }
            break;

        default:
            if (SDL_RWread(src, bits, 1, surface->pitch)
                != surface->pitch) {
                SDL_Error(SDL_EFREAD);
                was_error = SDL_TRUE;
                goto done;
            }
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
            /* Byte-swap the pixels if needed. Note that the 24bpp
               case has already been taken care of above. */
            switch (biBitCount) {
            case 15:
            case 16:{
                    Uint16 *pix = (Uint16 *) bits;
                    for (i = 0; i < surface->w; i++)
                        pix[i] = SDL_Swap16(pix[i]);
                    break;
                }

            case 32:{
                    Uint32 *pix = (Uint32 *) bits;
                    for (i = 0; i < surface->w; i++)
                        pix[i] = SDL_Swap32(pix[i]);
                    break;
                }
            }
#endif
            break;
        }
        /* Skip padding bytes, ugh */
        if (pad) {
            Uint8 padbyte;
            for (i = 0; i < pad; ++i) {
                SDL_RWread(src, &padbyte, 1, 1);
            }
        }
        if (topDown) {
            bits += surface->pitch;
        } else {
            bits -= surface->pitch;
        }
    }
  done:
    if (was_error) {
        if (src) {
            SDL_RWseek(src, fp_offset, RW_SEEK_SET);
        }
        if (surface) {
            SDL_FreeSurface(surface);
        }
        surface = NULL;
    }
    if (freesrc && src) {
        SDL_RWclose(src);
    }
    return (surface);
}
예제 #28
0
int
SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst)
{
    long fp_offset;
    int i, pad;
    SDL_Surface *surface;
    Uint8 *bits;

    /* The Win32 BMP file header (14 bytes) */
    char magic[2] = { 'B', 'M' };
    Uint32 bfSize;
    Uint16 bfReserved1;
    Uint16 bfReserved2;
    Uint32 bfOffBits;

    /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
    Uint32 biSize;
    Sint32 biWidth;
    Sint32 biHeight;
    Uint16 biPlanes;
    Uint16 biBitCount;
    Uint32 biCompression;
    Uint32 biSizeImage;
    Sint32 biXPelsPerMeter;
    Sint32 biYPelsPerMeter;
    Uint32 biClrUsed;
    Uint32 biClrImportant;

    /* Make sure we have somewhere to save */
    surface = NULL;
    if (dst) {
        SDL_bool save32bit = SDL_FALSE;
#ifdef SAVE_32BIT_BMP
        /* We can save alpha information in a 32-bit BMP */
        if (saveme->map->info.flags & SDL_COPY_COLORKEY ||
            saveme->format->Amask) {
            save32bit = SDL_TRUE;
        }
#endif /* SAVE_32BIT_BMP */

        if (saveme->format->palette && !save32bit) {
            if (saveme->format->BitsPerPixel == 8) {
                surface = saveme;
            } else {
                SDL_SetError("%d bpp BMP files not supported",
                             saveme->format->BitsPerPixel);
            }
        } else if ((saveme->format->BitsPerPixel == 24) &&
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
                   (saveme->format->Rmask == 0x00FF0000) &&
                   (saveme->format->Gmask == 0x0000FF00) &&
                   (saveme->format->Bmask == 0x000000FF)
#else
                   (saveme->format->Rmask == 0x000000FF) &&
                   (saveme->format->Gmask == 0x0000FF00) &&
                   (saveme->format->Bmask == 0x00FF0000)
#endif
            ) {
            surface = saveme;
        } else {
            SDL_PixelFormat format;

            /* If the surface has a colorkey or alpha channel we'll save a
               32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
            if (save32bit) {
                SDL_InitFormat(&format, 
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
                               SDL_PIXELFORMAT_ARGB8888
#else
                               SDL_PIXELFORMAT_BGRA8888
#endif
                               );
            } else {
                SDL_InitFormat(&format, SDL_PIXELFORMAT_BGR24);
            }
            surface = SDL_ConvertSurface(saveme, &format, 0);
            if (!surface) {
                SDL_SetError("Couldn't convert image to %d bpp",
                             format.BitsPerPixel);
            }
        }
    }

    if (surface && (SDL_LockSurface(surface) == 0)) {
        const int bw = surface->w * surface->format->BytesPerPixel;

        /* Set the BMP file header values */
        bfSize = 0;             /* We'll write this when we're done */
        bfReserved1 = 0;
        bfReserved2 = 0;
        bfOffBits = 0;          /* We'll write this when we're done */

        /* Write the BMP file header values */
        fp_offset = SDL_RWtell(dst);
        SDL_ClearError();
        SDL_RWwrite(dst, magic, 2, 1);
        SDL_WriteLE32(dst, bfSize);
        SDL_WriteLE16(dst, bfReserved1);
        SDL_WriteLE16(dst, bfReserved2);
        SDL_WriteLE32(dst, bfOffBits);

        /* Set the BMP info values */
        biSize = 40;
        biWidth = surface->w;
        biHeight = surface->h;
        biPlanes = 1;
        biBitCount = surface->format->BitsPerPixel;
        biCompression = BI_RGB;
        biSizeImage = surface->h * surface->pitch;
        biXPelsPerMeter = 0;
        biYPelsPerMeter = 0;
        if (surface->format->palette) {
            biClrUsed = surface->format->palette->ncolors;
        } else {
            biClrUsed = 0;
        }
        biClrImportant = 0;

        /* Write the BMP info values */
        SDL_WriteLE32(dst, biSize);
        SDL_WriteLE32(dst, biWidth);
        SDL_WriteLE32(dst, biHeight);
        SDL_WriteLE16(dst, biPlanes);
        SDL_WriteLE16(dst, biBitCount);
        SDL_WriteLE32(dst, biCompression);
        SDL_WriteLE32(dst, biSizeImage);
        SDL_WriteLE32(dst, biXPelsPerMeter);
        SDL_WriteLE32(dst, biYPelsPerMeter);
        SDL_WriteLE32(dst, biClrUsed);
        SDL_WriteLE32(dst, biClrImportant);

        /* Write the palette (in BGR color order) */
        if (surface->format->palette) {
            SDL_Color *colors;
            int ncolors;

            colors = surface->format->palette->colors;
            ncolors = surface->format->palette->ncolors;
            for (i = 0; i < ncolors; ++i) {
                SDL_RWwrite(dst, &colors[i].b, 1, 1);
                SDL_RWwrite(dst, &colors[i].g, 1, 1);
                SDL_RWwrite(dst, &colors[i].r, 1, 1);
                SDL_RWwrite(dst, &colors[i].unused, 1, 1);
            }
        }

        /* Write the bitmap offset */
        bfOffBits = SDL_RWtell(dst) - fp_offset;
        if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
            SDL_Error(SDL_EFSEEK);
        }
        SDL_WriteLE32(dst, bfOffBits);
        if (SDL_RWseek(dst, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
            SDL_Error(SDL_EFSEEK);
        }

        /* Write the bitmap image upside down */
        bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
        pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
        while (bits > (Uint8 *) surface->pixels) {
            bits -= surface->pitch;
            if (SDL_RWwrite(dst, bits, 1, bw) != bw) {
                SDL_Error(SDL_EFWRITE);
                break;
            }
            if (pad) {
                const Uint8 padbyte = 0;
                for (i = 0; i < pad; ++i) {
                    SDL_RWwrite(dst, &padbyte, 1, 1);
                }
            }
        }

        /* Write the BMP file size */
        bfSize = SDL_RWtell(dst) - fp_offset;
        if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
            SDL_Error(SDL_EFSEEK);
        }
        SDL_WriteLE32(dst, bfSize);
        if (SDL_RWseek(dst, fp_offset + bfSize, RW_SEEK_SET) < 0) {
            SDL_Error(SDL_EFSEEK);
        }

        /* Close it up.. */
        SDL_UnlockSurface(surface);
        if (surface != saveme) {
            SDL_FreeSurface(surface);
        }
    }

    if (freedst && dst) {
        SDL_RWclose(dst);
    }
    return ((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
}
예제 #29
0
int SDL_SaveBMP_RW (SDL_Surface *saveme, SDL_RWops *dst, int freedst)
{
	long fp_offset;
	int i, pad;
	SDL_Surface *surface;
	Uint8 *bits;

	/* The Win32 BMP file header (14 bytes) */
	char   magic[2] = { 'B', 'M' };
	Uint32 bfSize;
	Uint16 bfReserved1;
	Uint16 bfReserved2;
	Uint32 bfOffBits;

	/* The Win32 BITMAPINFOHEADER struct (40 bytes) */
	Uint32 biSize;
	Sint32 biWidth;
	Sint32 biHeight;
	Uint16 biPlanes;
	Uint16 biBitCount;
	Uint32 biCompression;
	Uint32 biSizeImage;
	Sint32 biXPelsPerMeter;
	Sint32 biYPelsPerMeter;
	Uint32 biClrUsed;
	Uint32 biClrImportant;

	/* Make sure we have somewhere to save */
	surface = NULL;
	if ( dst ) {
		if ( saveme->format->palette ) {
			if ( saveme->format->BitsPerPixel == 8 ) {
				surface = saveme;
			} else {
				SDL_SetError("%d bpp BMP files not supported",
						saveme->format->BitsPerPixel);
			}
		}
		else if ( (saveme->format->BitsPerPixel == 24) &&
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
				(saveme->format->Rmask == 0x00FF0000) &&
				(saveme->format->Gmask == 0x0000FF00) &&
				(saveme->format->Bmask == 0x000000FF)
#else
				(saveme->format->Rmask == 0x000000FF) &&
				(saveme->format->Gmask == 0x0000FF00) &&
				(saveme->format->Bmask == 0x00FF0000)
#endif
			  ) {
			surface = saveme;
		} else {
			SDL_Rect bounds;

			/* Convert to 24 bits per pixel */
			surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
					saveme->w, saveme->h, 24,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
					0x00FF0000, 0x0000FF00, 0x000000FF,
#else
					0x000000FF, 0x0000FF00, 0x00FF0000,
#endif
					0);
			if ( surface != NULL ) {
				bounds.x = 0;
				bounds.y = 0;
				bounds.w = saveme->w;
				bounds.h = saveme->h;
				if ( SDL_LowerBlit(saveme, &bounds, surface,
							&bounds) < 0 ) {
					SDL_FreeSurface(surface);
					SDL_SetError(
					"Couldn't convert image to 24 bpp");
					surface = NULL;
				}
			}
		}
	}

	if ( surface && (SDL_LockSurface(surface) == 0) ) {
		/* Set the BMP file header values */
		bfSize = 0;		 /* We'll write this when we're done */
		bfReserved1 = 0;
		bfReserved2 = 0;
		bfOffBits = 0;		/* We'll write this when we're done */

		/* Write the BMP file header values */
		fp_offset = SDL_RWtell(dst);
		SDL_ClearError();
		SDL_RWwrite(dst, magic, 2, 1);
		SDL_WriteLE32(dst, bfSize);
		SDL_WriteLE16(dst, bfReserved1);
		SDL_WriteLE16(dst, bfReserved2);
		SDL_WriteLE32(dst, bfOffBits);

		/* Set the BMP info values */
		biSize = 40;
		biWidth = surface->w;
		biHeight = surface->h;
		biPlanes = 1;
		biBitCount = surface->format->BitsPerPixel;
		biCompression = BI_RGB;
		biSizeImage = surface->h*surface->pitch;
		biXPelsPerMeter = 0;
		biYPelsPerMeter = 0;
		if ( surface->format->palette ) {
			biClrUsed = surface->format->palette->ncolors;
		} else {
			biClrUsed = 0;
		}
		biClrImportant = 0;

		/* Write the BMP info values */
		SDL_WriteLE32(dst, biSize);
		SDL_WriteLE32(dst, biWidth);
		SDL_WriteLE32(dst, biHeight);
		SDL_WriteLE16(dst, biPlanes);
		SDL_WriteLE16(dst, biBitCount);
		SDL_WriteLE32(dst, biCompression);
		SDL_WriteLE32(dst, biSizeImage);
		SDL_WriteLE32(dst, biXPelsPerMeter);
		SDL_WriteLE32(dst, biYPelsPerMeter);
		SDL_WriteLE32(dst, biClrUsed);
		SDL_WriteLE32(dst, biClrImportant);

		/* Write the palette (in BGR color order) */
		if ( surface->format->palette ) {
			SDL_Color *colors;
			int       ncolors;

			colors = surface->format->palette->colors;
			ncolors = surface->format->palette->ncolors;
			for ( i=0; i<ncolors; ++i ) {
				SDL_RWwrite(dst, &colors[i].b, 1, 1);
				SDL_RWwrite(dst, &colors[i].g, 1, 1);
				SDL_RWwrite(dst, &colors[i].r, 1, 1);
				SDL_RWwrite(dst, &colors[i].unused, 1, 1);
			}
		}

		/* Write the bitmap offset */
		bfOffBits = SDL_RWtell(dst)-fp_offset;
		if ( SDL_RWseek(dst, fp_offset+10, SEEK_SET) < 0 ) {
			SDL_Error(SDL_EFSEEK);
		}
		SDL_WriteLE32(dst, bfOffBits);
		if ( SDL_RWseek(dst, fp_offset+bfOffBits, SEEK_SET) < 0 ) {
			SDL_Error(SDL_EFSEEK);
		}

		/* Write the bitmap image upside down */
		bits = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
		pad  = ((surface->pitch%4) ? (4-(surface->pitch%4)) : 0);
		while ( bits > (Uint8 *)surface->pixels ) {
			bits -= surface->pitch;
			if ( SDL_RWwrite(dst, bits, 1, surface->pitch)
							!= surface->pitch) {
				SDL_Error(SDL_EFWRITE);
				break;
			}
			if ( pad ) {
				const Uint8 padbyte = 0;
				for ( i=0; i<pad; ++i ) {
					SDL_RWwrite(dst, &padbyte, 1, 1);
				}
			}
		}

		/* Write the BMP file size */
		bfSize = SDL_RWtell(dst)-fp_offset;
		if ( SDL_RWseek(dst, fp_offset+2, SEEK_SET) < 0 ) {
			SDL_Error(SDL_EFSEEK);
		}
		SDL_WriteLE32(dst, bfSize);
		if ( SDL_RWseek(dst, fp_offset+bfSize, SEEK_SET) < 0 ) {
			SDL_Error(SDL_EFSEEK);
		}

		/* Close it up.. */
		SDL_UnlockSurface(surface);
		if ( surface != saveme ) {
			SDL_FreeSurface(surface);
		}
	}

	if ( freedst && dst ) {
		SDL_RWclose(dst);
	}
	return((strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
}
예제 #30
0
파일: SDL_bmp.c 프로젝트: Evengard/UniMod
SDL_Surface *
SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
{
    SDL_bool was_error;
    Sint64 fp_offset = 0;
    int bmpPitch;
    int i, pad;
    SDL_Surface *surface;
    Uint32 Rmask = 0;
    Uint32 Gmask = 0;
    Uint32 Bmask = 0;
    Uint32 Amask = 0;
    SDL_Palette *palette;
    Uint8 *bits;
    Uint8 *top, *end;
    SDL_bool topDown;
    int ExpandBMP;
    SDL_bool haveRGBMasks = SDL_FALSE;
    SDL_bool haveAlphaMask = SDL_FALSE;
    SDL_bool correctAlpha = SDL_FALSE;

    /* The Win32 BMP file header (14 bytes) */
    char magic[2];
    /* Uint32 bfSize = 0; */
    /* Uint16 bfReserved1 = 0; */
    /* Uint16 bfReserved2 = 0; */
    Uint32 bfOffBits = 0;

    /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
    Uint32 biSize = 0;
    Sint32 biWidth = 0;
    Sint32 biHeight = 0;
    /* Uint16 biPlanes = 0; */
    Uint16 biBitCount = 0;
    Uint32 biCompression = 0;
    /* Uint32 biSizeImage = 0; */
    /* Sint32 biXPelsPerMeter = 0; */
    /* Sint32 biYPelsPerMeter = 0; */
    Uint32 biClrUsed = 0;
    /* Uint32 biClrImportant = 0; */

    (void) haveRGBMasks;
    (void) haveAlphaMask;

    /* Make sure we are passed a valid data source */
    surface = NULL;
    was_error = SDL_FALSE;
    if (src == NULL) {
        was_error = SDL_TRUE;
        goto done;
    }

    /* Read in the BMP file header */
    fp_offset = SDL_RWtell(src);
    SDL_ClearError();
    if (SDL_RWread(src, magic, 1, 2) != 2) {
        SDL_Error(SDL_EFREAD);
        was_error = SDL_TRUE;
        goto done;
    }
    if (SDL_strncmp(magic, "BM", 2) != 0) {
        SDL_SetError("File is not a Windows BMP file");
        was_error = SDL_TRUE;
        goto done;
    }
    /* bfSize = */ SDL_ReadLE32(src);
    /* bfReserved1 = */ SDL_ReadLE16(src);
    /* bfReserved2 = */ SDL_ReadLE16(src);
    bfOffBits = SDL_ReadLE32(src);

    /* Read the Win32 BITMAPINFOHEADER */
    biSize = SDL_ReadLE32(src);
    if (biSize == 12) {   /* really old BITMAPCOREHEADER */
        biWidth = (Uint32) SDL_ReadLE16(src);
        biHeight = (Uint32) SDL_ReadLE16(src);
        /* biPlanes = */ SDL_ReadLE16(src);
        biBitCount = SDL_ReadLE16(src);
        biCompression = BI_RGB;
    } else if (biSize >= 40) {  /* some version of BITMAPINFOHEADER */
        Uint32 headerSize;
        biWidth = SDL_ReadLE32(src);
        biHeight = SDL_ReadLE32(src);
        /* biPlanes = */ SDL_ReadLE16(src);
        biBitCount = SDL_ReadLE16(src);
        biCompression = SDL_ReadLE32(src);
        /* biSizeImage = */ SDL_ReadLE32(src);
        /* biXPelsPerMeter = */ SDL_ReadLE32(src);
        /* biYPelsPerMeter = */ SDL_ReadLE32(src);
        biClrUsed = SDL_ReadLE32(src);
        /* biClrImportant = */ SDL_ReadLE32(src);

        /* 64 == BITMAPCOREHEADER2, an incompatible OS/2 2.x extension. Skip this stuff for now. */
        if (biSize == 64) {
            /* ignore these extra fields. */
            if (biCompression == BI_BITFIELDS) {
                /* this value is actually huffman compression in this variant. */
                SDL_SetError("Compressed BMP files not supported");
                was_error = SDL_TRUE;
                goto done;
            }
        } else {
            /* This is complicated. If compression is BI_BITFIELDS, then
               we have 3 DWORDS that specify the RGB masks. This is either
               stored here in an BITMAPV2INFOHEADER (which only differs in
               that it adds these RGB masks) and biSize >= 52, or we've got
               these masks stored in the exact same place, but strictly
               speaking, this is the bmiColors field in BITMAPINFO immediately
               following the legacy v1 info header, just past biSize. */
            if (biCompression == BI_BITFIELDS) {
                haveRGBMasks = SDL_TRUE;
                Rmask = SDL_ReadLE32(src);
                Gmask = SDL_ReadLE32(src);
                Bmask = SDL_ReadLE32(src);

                /* ...v3 adds an alpha mask. */
                if (biSize >= 56) {  /* BITMAPV3INFOHEADER; adds alpha mask */
                    haveAlphaMask = SDL_TRUE;
                    Amask = SDL_ReadLE32(src);
                }
            } else {
                /* the mask fields are ignored for v2+ headers if not BI_BITFIELD. */
                if (biSize >= 52) {  /* BITMAPV2INFOHEADER; adds RGB masks */
                    /*Rmask = */ SDL_ReadLE32(src);
                    /*Gmask = */ SDL_ReadLE32(src);
                    /*Bmask = */ SDL_ReadLE32(src);
                }
                if (biSize >= 56) {  /* BITMAPV3INFOHEADER; adds alpha mask */
                    /*Amask = */ SDL_ReadLE32(src);
                }
            }

            /* Insert other fields here; Wikipedia and MSDN say we're up to
               v5 of this header, but we ignore those for now (they add gamma,
               color spaces, etc). Ignoring the weird OS/2 2.x format, we
               currently parse up to v3 correctly (hopefully!). */
        }

        /* skip any header bytes we didn't handle... */
        headerSize = (Uint32) (SDL_RWtell(src) - (fp_offset + 14));
        if (biSize > headerSize) {
            SDL_RWseek(src, (biSize - headerSize), RW_SEEK_CUR);
        }
    }
    if (biHeight < 0) {
        topDown = SDL_TRUE;
        biHeight = -biHeight;
    } else {
        topDown = SDL_FALSE;
    }

    /* Check for read error */
    if (SDL_strcmp(SDL_GetError(), "") != 0) {
        was_error = SDL_TRUE;
        goto done;
    }

    /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */
    switch (biBitCount) {
    case 1:
    case 4:
        ExpandBMP = biBitCount;
        biBitCount = 8;
        break;
    default:
        ExpandBMP = 0;
        break;
    }

    /* We don't support any BMP compression right now */
    switch (biCompression) {
    case BI_RGB:
        /* If there are no masks, use the defaults */
        SDL_assert(!haveRGBMasks);
        SDL_assert(!haveAlphaMask);
        /* Default values for the BMP format */
        switch (biBitCount) {
        case 15:
        case 16:
            Rmask = 0x7C00;
            Gmask = 0x03E0;
            Bmask = 0x001F;
            break;
        case 24:
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
            Rmask = 0x000000FF;
            Gmask = 0x0000FF00;
            Bmask = 0x00FF0000;
#else
            Rmask = 0x00FF0000;
            Gmask = 0x0000FF00;
            Bmask = 0x000000FF;
#endif
            break;
        case 32:
            /* We don't know if this has alpha channel or not */
            correctAlpha = SDL_TRUE;
            Amask = 0xFF000000;
            Rmask = 0x00FF0000;
            Gmask = 0x0000FF00;
            Bmask = 0x000000FF;
            break;
        default:
            break;
        }
        break;

    case BI_BITFIELDS:
        break;  /* we handled this in the info header. */

    default:
        SDL_SetError("Compressed BMP files not supported");
        was_error = SDL_TRUE;
        goto done;
    }

    /* Create a compatible surface, note that the colors are RGB ordered */
    surface =
        SDL_CreateRGBSurface(0, biWidth, biHeight, biBitCount, Rmask, Gmask,
                             Bmask, Amask);
    if (surface == NULL) {
        was_error = SDL_TRUE;
        goto done;
    }

    /* Load the palette, if any */
    palette = (surface->format)->palette;
    if (palette) {
        SDL_assert(biBitCount <= 8);
        if (biClrUsed == 0) {
            biClrUsed = 1 << biBitCount;
        }
        if ((int) biClrUsed > palette->ncolors) {
            SDL_Color *colors;
            int ncolors = biClrUsed;
            colors =
                (SDL_Color *) SDL_realloc(palette->colors,
                                          ncolors *
                                          sizeof(*palette->colors));
            if (!colors) {
                SDL_OutOfMemory();
                was_error = SDL_TRUE;
                goto done;
            }
            palette->ncolors = ncolors;
            palette->colors = colors;
        } else if ((int) biClrUsed < palette->ncolors) {
            palette->ncolors = biClrUsed;
        }
        if (biSize == 12) {
            for (i = 0; i < (int) biClrUsed; ++i) {
                SDL_RWread(src, &palette->colors[i].b, 1, 1);
                SDL_RWread(src, &palette->colors[i].g, 1, 1);
                SDL_RWread(src, &palette->colors[i].r, 1, 1);
                palette->colors[i].a = SDL_ALPHA_OPAQUE;
            }
        } else {
            for (i = 0; i < (int) biClrUsed; ++i) {
                SDL_RWread(src, &palette->colors[i].b, 1, 1);
                SDL_RWread(src, &palette->colors[i].g, 1, 1);
                SDL_RWread(src, &palette->colors[i].r, 1, 1);
                SDL_RWread(src, &palette->colors[i].a, 1, 1);

                /* According to Microsoft documentation, the fourth element
                   is reserved and must be zero, so we shouldn't treat it as
                   alpha.
                */
                palette->colors[i].a = SDL_ALPHA_OPAQUE;
            }
        }
    }

    /* Read the surface pixels.  Note that the bmp image is upside down */
    if (SDL_RWseek(src, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
        SDL_Error(SDL_EFSEEK);
        was_error = SDL_TRUE;
        goto done;
    }
    top = (Uint8 *)surface->pixels;
    end = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
    switch (ExpandBMP) {
    case 1:
        bmpPitch = (biWidth + 7) >> 3;
        pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
        break;
    case 4:
        bmpPitch = (biWidth + 1) >> 1;
        pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
        break;
    default:
        pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0);
        break;
    }
    if (topDown) {
        bits = top;
    } else {
        bits = end - surface->pitch;
    }
    while (bits >= top && bits < end) {
        switch (ExpandBMP) {
        case 1:
        case 4:{
                Uint8 pixel = 0;
                int shift = (8 - ExpandBMP);
                for (i = 0; i < surface->w; ++i) {
                    if (i % (8 / ExpandBMP) == 0) {
                        if (!SDL_RWread(src, &pixel, 1, 1)) {
                            SDL_SetError("Error reading from BMP");
                            was_error = SDL_TRUE;
                            goto done;
                        }
                    }
                    *(bits + i) = (pixel >> shift);
                    pixel <<= ExpandBMP;
                }
            }
            break;

        default:
            if (SDL_RWread(src, bits, 1, surface->pitch)
                != surface->pitch) {
                SDL_Error(SDL_EFREAD);
                was_error = SDL_TRUE;
                goto done;
            }
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
            /* Byte-swap the pixels if needed. Note that the 24bpp
               case has already been taken care of above. */
            switch (biBitCount) {
            case 15:
            case 16:{
                    Uint16 *pix = (Uint16 *) bits;
                    for (i = 0; i < surface->w; i++)
                        pix[i] = SDL_Swap16(pix[i]);
                    break;
                }

            case 32:{
                    Uint32 *pix = (Uint32 *) bits;
                    for (i = 0; i < surface->w; i++)
                        pix[i] = SDL_Swap32(pix[i]);
                    break;
                }
            }
#endif
            break;
        }
        /* Skip padding bytes, ugh */
        if (pad) {
            Uint8 padbyte;
            for (i = 0; i < pad; ++i) {
                SDL_RWread(src, &padbyte, 1, 1);
            }
        }
        if (topDown) {
            bits += surface->pitch;
        } else {
            bits -= surface->pitch;
        }
    }
    if (correctAlpha) {
        CorrectAlphaChannel(surface);
    }
  done:
    if (was_error) {
        if (src) {
            SDL_RWseek(src, fp_offset, RW_SEEK_SET);
        }
        SDL_FreeSurface(surface);
        surface = NULL;
    }
    if (freesrc && src) {
        SDL_RWclose(src);
    }
    return (surface);
}