fix: validate OPF cover items as images (#2062)

This commit is contained in:
Leopoldo Pla Sempere
2026-05-25 16:40:41 -04:00
committed by GitHub
parent e3298c6e43
commit f69650fb86
3 changed files with 68 additions and 14 deletions
+38 -11
View File
@@ -320,6 +320,14 @@ int bmpDrawCallback(JPEGDRAW* pDraw) {
const int blockX = pDraw->x;
const int blockY = pDraw->y;
// Guard against unexpected callback geometry so we never index past row buffers.
if (blockX < 0 || blockY < 0 || blockX >= ctx->srcWidth || blockY >= ctx->srcHeight) {
LOG_ERR("JPG", "Unexpected JPEG block origin (%d,%d) for decode grid %dx%d", blockX, blockY, ctx->srcWidth,
ctx->srcHeight);
ctx->error = true;
return 0;
}
// Copy block pixels into MCU row buffer
for (int r = 0; r < blockH && r < MAX_MCU_HEIGHT; r++) {
const int copyW = (blockX + validW <= ctx->srcWidth) ? validW : (ctx->srcWidth - blockX);
@@ -403,8 +411,16 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(HalFile& jpegFile, Print& b
const int srcWidth = jpeg->getWidth();
const int srcHeight = jpeg->getHeight();
const bool progressiveDecode = (jpeg->getJPEGType() == JPEG_MODE_PROGRESSIVE);
// JPEGDEC forces progressive streams to JPEG_SCALE_EIGHTH in DecodeJPEG,
// so callback coordinates and MCU buffering must use the reduced decode grid.
const int decodedSrcWidth = progressiveDecode ? ((srcWidth + 7) >> 3) : srcWidth;
const int decodedSrcHeight = progressiveDecode ? ((srcHeight + 7) >> 3) : srcHeight;
LOG_DBG("JPG", "JPEG dimensions: %dx%d", srcWidth, srcHeight);
if (progressiveDecode) {
LOG_DBG("JPG", "Progressive JPEG decode uses 1/8 source: %dx%d", decodedSrcWidth, decodedSrcHeight);
}
constexpr int MAX_IMAGE_WIDTH = 2048;
constexpr int MAX_IMAGE_HEIGHT = 3072;
@@ -418,6 +434,15 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(HalFile& jpegFile, Print& b
// Calculate output dimensions (pre-scale to fit display exactly)
int outWidth = srcWidth;
int outHeight = srcHeight;
if (targetWidth <= 0 || targetHeight <= 0) {
// Without an explicit target, keep decoder-native dimensions.
outWidth = decodedSrcWidth;
outHeight = decodedSrcHeight;
}
const int scaleSrcWidth = decodedSrcWidth;
const int scaleSrcHeight = decodedSrcHeight;
uint32_t scaleX_fp = 65536; // 1.0 in 16.16 fixed point
uint32_t scaleY_fp = 65536;
bool needsScaling = false;
@@ -437,12 +462,14 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(HalFile& jpegFile, Print& b
if (outWidth < 1) outWidth = 1;
if (outHeight < 1) outHeight = 1;
scaleX_fp = (static_cast<uint32_t>(srcWidth) << 16) / outWidth;
scaleY_fp = (static_cast<uint32_t>(srcHeight) << 16) / outHeight;
needsScaling = true;
LOG_DBG("JPG", "Scaling source %dx%d (decode grid %dx%d) -> %dx%d (target %dx%d)", srcWidth, srcHeight,
scaleSrcWidth, scaleSrcHeight, outWidth, outHeight, targetWidth, targetHeight);
}
LOG_DBG("JPG", "Scaling %dx%d -> %dx%d (target %dx%d)", srcWidth, srcHeight, outWidth, outHeight, targetWidth,
targetHeight);
if (scaleSrcWidth != outWidth || scaleSrcHeight != outHeight) {
scaleX_fp = (static_cast<uint32_t>(scaleSrcWidth) << 16) / outWidth;
scaleY_fp = (static_cast<uint32_t>(scaleSrcHeight) << 16) / outHeight;
needsScaling = true;
}
// Write BMP header with output dimensions
@@ -460,8 +487,8 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(HalFile& jpegFile, Print& b
BmpConvertCtx ctx = {};
ctx.bmpOut = &bmpOut;
ctx.srcWidth = srcWidth;
ctx.srcHeight = srcHeight;
ctx.srcWidth = scaleSrcWidth;
ctx.srcHeight = scaleSrcHeight;
ctx.outWidth = outWidth;
ctx.outHeight = outHeight;
ctx.oneBit = oneBit;
@@ -471,13 +498,13 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(HalFile& jpegFile, Print& b
ctx.scaleY_fp = scaleY_fp;
ctx.error = false;
// MCU row buffer: MAX_MCU_HEIGHT rows × srcWidth columns of grayscale
ctx.mcuBuf = makeUniqueNoThrow<uint8_t[]>(MAX_MCU_HEIGHT * srcWidth);
// MCU row buffer: MAX_MCU_HEIGHT rows × decoded srcWidth columns of grayscale
ctx.mcuBuf = makeUniqueNoThrow<uint8_t[]>(MAX_MCU_HEIGHT * ctx.srcWidth);
if (!ctx.mcuBuf) {
LOG_ERR("JPG", "OOM: MCU buffer (%d bytes)", MAX_MCU_HEIGHT * srcWidth);
LOG_ERR("JPG", "OOM: MCU buffer (%d bytes)", MAX_MCU_HEIGHT * ctx.srcWidth);
return false;
}
memset(ctx.mcuBuf.get(), 0, MAX_MCU_HEIGHT * srcWidth);
memset(ctx.mcuBuf.get(), 0, MAX_MCU_HEIGHT * ctx.srcWidth);
ctx.bmpRow = makeUniqueNoThrow<uint8_t[]>(bytesPerRow);
if (!ctx.bmpRow) {