Amiga: harden host-side bmp/xpm to iff converters

Replace #pragma-pack BMP header reads with little-endian byte
readers so the tool works on any host endianness.  Add dimension
and color-count range checks, zero-init pixel remap table, check
calloc, free bmpdata on early returns, send malloc errors to
stderr.  Add bp>xbuf guards to xpmgetline's strip loop.
This commit is contained in:
Ingo Paschke
2026-05-12 15:18:44 +02:00
parent cb46d9effd
commit 157c005f02
2 changed files with 83 additions and 11 deletions
+69 -7
View File
@@ -65,6 +65,41 @@ static const RGB amiv_pal[16] = {
{0xFF,0xBB,0x99}, /* 15 peach */
};
/* --------------------------------------------------------- */
/* Little-endian readers (BMP is LE regardless of host) */
/* --------------------------------------------------------- */
static int
read_u16le(FILE *fp, uint16_t *out)
{
int lo = fgetc(fp), hi = fgetc(fp);
if (hi == EOF) return 0;
*out = (uint16_t)(((unsigned) hi << 8) | (unsigned) lo);
return 1;
}
static int
read_u32le(FILE *fp, uint32_t *out)
{
int b0 = fgetc(fp), b1 = fgetc(fp);
int b2 = fgetc(fp), b3 = fgetc(fp);
if (b3 == EOF) return 0;
*out = ((uint32_t)(unsigned) b3 << 24)
| ((uint32_t)(unsigned) b2 << 16)
| ((uint32_t)(unsigned) b1 << 8)
| (uint32_t)(unsigned) b0;
return 1;
}
static int
read_i32le(FILE *fp, int32_t *out)
{
uint32_t v;
if (!read_u32le(fp, &v)) return 0;
*out = (int32_t) v;
return 1;
}
/* --------------------------------------------------------- */
/* Colour helpers */
/* --------------------------------------------------------- */
@@ -345,7 +380,7 @@ main(int argc, char **argv)
int nplanes, maxcol;
int i, y;
RGB outpal[256];
int remap[256];
int remap[256] = {0};
uint8_t *remapped;
uint8_t *plane_data[8];
uint8_t cmap_rgb[256 * 3];
@@ -370,8 +405,22 @@ main(int argc, char **argv)
bmpfp = fopen(argv[3], "rb");
if (!bmpfp) { perror(argv[3]); return 1; }
if (fread(&fhdr, sizeof(fhdr), 1, bmpfp) != 1
|| fread(&ihdr, sizeof(ihdr), 1, bmpfp) != 1) {
if (!read_u16le(bmpfp, &fhdr.bfType)
|| !read_u32le(bmpfp, &fhdr.bfSize)
|| !read_u16le(bmpfp, &fhdr.bfReserved1)
|| !read_u16le(bmpfp, &fhdr.bfReserved2)
|| !read_u32le(bmpfp, &fhdr.bfOffBits)
|| !read_u32le(bmpfp, &ihdr.biSize)
|| !read_i32le(bmpfp, &ihdr.biWidth)
|| !read_i32le(bmpfp, &ihdr.biHeight)
|| !read_u16le(bmpfp, &ihdr.biPlanes)
|| !read_u16le(bmpfp, &ihdr.biBitCount)
|| !read_u32le(bmpfp, &ihdr.biCompression)
|| !read_u32le(bmpfp, &ihdr.biSizeImage)
|| !read_i32le(bmpfp, &ihdr.biXPelsPerMeter)
|| !read_i32le(bmpfp, &ihdr.biYPelsPerMeter)
|| !read_u32le(bmpfp, &ihdr.biClrUsed)
|| !read_u32le(bmpfp, &ihdr.biClrImportant)) {
fprintf(stderr, "Failed to read BMP header\n");
return 1;
}
@@ -388,6 +437,11 @@ main(int argc, char **argv)
img_w = ihdr.biWidth;
img_h = abs(ihdr.biHeight);
if (img_w <= 0 || img_w > 16384 || img_h <= 0 || img_h > 16384) {
fprintf(stderr, "BMP dimensions out of range: %dx%d\n",
img_w, img_h);
return 1;
}
ncolors = ihdr.biClrUsed ? ihdr.biClrUsed : 256;
if (ncolors > 256) ncolors = 256;
@@ -410,13 +464,15 @@ main(int argc, char **argv)
rowstride = (img_w + 3) & ~3;
bmpdata = malloc(rowstride * img_h);
if (!bmpdata) {
printf("%s\n", "malloc failure on bmpdata");
fprintf(stderr, "malloc failure on bmpdata\n");
return 1;
}
fseek(bmpfp, fhdr.bfOffBits, SEEK_SET);
if (fread(bmpdata, 1, rowstride * img_h, bmpfp)
!= (size_t)(rowstride * img_h)) {
fprintf(stderr, "Failed to read pixel data\n");
free(bmpdata);
fclose(bmpfp);
return 1;
}
fclose(bmpfp);
@@ -424,7 +480,8 @@ main(int argc, char **argv)
/* flip bottom-up to top-down */
pixels = malloc(img_w * img_h);
if (!pixels) {
printf("%s\n", "malloc failure on pixels");
fprintf(stderr, "malloc failure on pixels\n");
free(bmpdata);
return 1;
}
if (ihdr.biHeight > 0) {
@@ -450,7 +507,7 @@ main(int argc, char **argv)
remapped = malloc(img_w * img_h);
if (!remapped) {
printf("%s\n", "malloc failure on remapped");
fprintf(stderr, "malloc failure on remapped\n");
return 1;
}
for (i = 0; i < img_w * img_h; i++)
@@ -458,8 +515,13 @@ main(int argc, char **argv)
/* convert to bitplanes */
planesize = (img_w / 8) * img_h;
for (i = 0; i < nplanes; i++)
for (i = 0; i < nplanes; i++) {
plane_data[i] = calloc(1, planesize);
if (!plane_data[i]) {
fprintf(stderr, "calloc failure for plane %d\n", i);
return 1;
}
}
to_planes(remapped, img_w, img_h,
nplanes, plane_data);
+14 -4
View File
@@ -62,12 +62,13 @@ xpmgetline(void)
/* strip trailing <",> and whitespace */
for (bp = xbuf; *bp; bp++)
;
bp--;
while (isspace((unsigned char)*bp))
if (bp > xbuf)
bp--;
if (*bp == ',')
while (bp > xbuf && isspace((unsigned char)*bp))
bp--;
if (*bp == '"')
if (bp > xbuf && *bp == ',')
bp--;
if (bp > xbuf && *bp == '"')
bp--;
bp++;
*bp = '\0';
@@ -209,10 +210,19 @@ main(int argc, char **argv)
return 1;
}
if (XpmScreen.Colors < 1 || XpmScreen.Colors > 256) {
fprintf(stderr,
"xpm2iff_host: unsupported color count %d\n",
XpmScreen.Colors);
return 1;
}
/* nplanes = ceil(log2(Colors)) */
nplanes = 0;
i = XpmScreen.Colors - 1;
while (i > 0) { nplanes++; i >>= 1; }
if (nplanes == 0)
nplanes = 1;
colors = 1 << nplanes;