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; }
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; }
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); }
/** * 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]; }
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; }
/** * 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; }
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; }
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); } }
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; }
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); }
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); }
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); }
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; }
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; }
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); }
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); }
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; }
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); }
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); }
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); }
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; }
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); }
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 */ }
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); }
/** * \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; }
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); }
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); }
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); }
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); }