Fixed decoding 4-bit RLE encoded BMP files

Also flipped the return value of readRlePixels() to match convention.

Fixes https://github.com/libsdl-org/sdl2-compat/issues/308
This commit is contained in:
Sam Lantinga 2025-02-03 19:34:38 -08:00
parent 8ccf85c59e
commit 07c22da464
1 changed files with 31 additions and 56 deletions

View File

@ -76,16 +76,16 @@ static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8)
int ofs = 0;
Uint8 ch;
Uint8 needsPad;
const int pixels_per_byte = (isRle8 ? 1 : 2);
#define COPY_PIXEL(x) \
spot = &bits[ofs++]; \
if (spot >= start && spot < end) \
*spot = (x)
// !!! FIXME: for all these reads, handle error vs eof? handle -2 if non-blocking?
for (;;) {
if (!SDL_ReadU8(src, &ch)) {
return true;
return false;
}
/*
| encoded mode starts with a run length, and then a byte
@ -94,26 +94,12 @@ static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8)
if (ch) {
Uint8 pixel;
if (!SDL_ReadU8(src, &pixel)) {
return true;
return false;
}
if (isRle8) { // 256-color bitmap, compressed
ch /= pixels_per_byte;
do {
COPY_PIXEL(pixel);
} while (--ch);
} else { // 16-color bitmap, compressed
Uint8 pixel0 = pixel >> 4;
Uint8 pixel1 = pixel & 0x0F;
for (;;) {
COPY_PIXEL(pixel0); // even count, high nibble
if (!--ch) {
break;
}
COPY_PIXEL(pixel1); // odd count, low nibble
if (!--ch) {
break;
}
}
}
} else {
/*
| A leading zero is an escape; it may signal the end of the bitmap,
@ -121,7 +107,7 @@ static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8)
| zero tag may be absolute mode or an escape
*/
if (!SDL_ReadU8(src, &ch)) {
return true;
return false;
}
switch (ch) {
case 0: // end of line
@ -129,47 +115,33 @@ static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8)
bits -= pitch; // go to previous
break;
case 1: // end of bitmap
return false; // success!
printf("SUCCESS!\n");
return true; // success!
case 2: // delta
if (!SDL_ReadU8(src, &ch)) {
return true;
return false;
}
ofs += ch;
ofs += ch / pixels_per_byte;
if (!SDL_ReadU8(src, &ch)) {
return true;
return false;
}
bits -= (ch * pitch);
bits -= ((ch / pixels_per_byte) * pitch);
break;
default: // no compression
if (isRle8) {
ch /= pixels_per_byte;
needsPad = (ch & 1);
do {
Uint8 pixel;
if (!SDL_ReadU8(src, &pixel)) {
return true;
return false;
}
COPY_PIXEL(pixel);
} while (--ch);
} else {
needsPad = (((ch + 1) >> 1) & 1); // (ch+1)>>1: bytes size
for (;;) {
Uint8 pixel;
if (!SDL_ReadU8(src, &pixel)) {
return true;
}
COPY_PIXEL(pixel >> 4);
if (!--ch) {
break;
}
COPY_PIXEL(pixel & 0x0F);
if (!--ch) {
break;
}
}
}
// pad at even boundary
if (needsPad && !SDL_ReadU8(src, &ch)) {
return true;
return false;
}
break;
}
@ -513,10 +485,13 @@ SDL_Surface *SDL_LoadBMP_IO(SDL_IOStream *src, bool closeio)
goto done;
}
if ((biCompression == BI_RLE4) || (biCompression == BI_RLE8)) {
was_error = readRlePixels(surface, src, biCompression == BI_RLE8);
if (was_error) {
if (!readRlePixels(surface, src, biCompression == BI_RLE8)) {
SDL_SetError("Error reading from datastream");
goto done;
}
// Success!
was_error = false;
goto done;
}
top = (Uint8 *)surface->pixels;