vcl/source/filter/png/PngImageReader.cxx | 72 ++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 19 deletions(-)
New commits: commit 03b0afa5fdf8f4bd0fb23dbfd1c19d50202c07bd Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Wed Apr 30 17:42:56 2025 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Wed Apr 30 14:42:37 2025 +0200 vcl: more fine grained handling of error in PNG reader Handle if the error happens at init, reading and after reading differently. At init we don't need to handle the bitmap as nothing has yet been writtent to it. Also after reading we can handle it like no error happened, because we have read the data completely but the error happened after that (like missing IEND chunk for example). Change the error and warning messgaes when reading from the stream. Change-Id: I927b8679f168da43e8e6e00663ff551064b870c8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184811 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/vcl/source/filter/png/PngImageReader.cxx b/vcl/source/filter/png/PngImageReader.cxx index 595a3a0b0c67..e35216919bdc 100644 --- a/vcl/source/filter/png/PngImageReader.cxx +++ b/vcl/source/filter/png/PngImageReader.cxx @@ -41,12 +41,14 @@ void lclReadStream(png_structp pPng, png_bytep pOutBytes, png_size_t nBytesToRea if (nBytesRead != nBytesToRead) { if (!nBytesRead) - png_error(pPng, "Error reading"); + { + png_error(pPng, "Stream read: no data read from the stream."); + } else { // Make sure to not reuse old data (could cause infinite loop). memset(pOutBytes + nBytesRead, 0, nBytesToRead - nBytesRead); - png_warning(pPng, "Short read"); + png_warning(pPng, "Stream read: read less bytes than asked for."); } } } @@ -370,23 +372,8 @@ bool reader(SvStream& rStream, ImportOutput& rImportOutput, if (setjmp(png_jmpbuf(pPng))) { - if (!bUseExistingBitmap) - { - // Set the bitmap if it contains something, even on failure. This allows - // reading images that are only partially broken. - pWriteAccessInstance.reset(); - pWriteAccessAlphaInstance.reset(); - if (!aBitmap.IsEmpty() && !aBitmapAlpha.IsEmpty()) - aBitmapEx = BitmapEx(aBitmap, aBitmapAlpha); - else if (!aBitmap.IsEmpty()) - aBitmapEx = BitmapEx(aBitmap); - if (!aBitmapEx.IsEmpty() && !prefSize.IsEmpty()) - { - aBitmapEx.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); - aBitmapEx.SetPrefSize(prefSize); - } - rImportOutput.moBitmap = aBitmapEx; - } + pWriteAccessInstance.reset(); + pWriteAccessAlphaInstance.reset(); return false; } @@ -521,6 +508,31 @@ bool reader(SvStream& rStream, ImportOutput& rImportOutput, BitmapScopedWriteAccess& pWriteAccessAlpha = pAlphaAccess ? *pAlphaAccess : pWriteAccessAlphaInstance; + if (setjmp(png_jmpbuf(pPng))) + { + pWriteAccessInstance.reset(); + pWriteAccessAlphaInstance.reset(); + + if (!bUseExistingBitmap) + { + // Set the bitmap if it contains something, even on failure. This allows + // reading images that are only partially broken. + pWriteAccessInstance.reset(); + pWriteAccessAlphaInstance.reset(); + if (!aBitmap.IsEmpty() && !aBitmapAlpha.IsEmpty()) + aBitmapEx = BitmapEx(aBitmap, aBitmapAlpha); + else if (!aBitmap.IsEmpty()) + aBitmapEx = BitmapEx(aBitmap); + if (!aBitmapEx.IsEmpty() && !prefSize.IsEmpty()) + { + aBitmapEx.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + aBitmapEx.SetPrefSize(prefSize); + } + rImportOutput.moBitmap = aBitmapEx; + } + return false; + } + if (colorType == PNG_COLOR_TYPE_RGB) { ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat(); @@ -665,6 +677,28 @@ bool reader(SvStream& rStream, ImportOutput& rImportOutput, } } + // If an error is thrown when calling png_read_end + if (setjmp(png_jmpbuf(pPng))) + { + if (!bUseExistingBitmap) + { + pWriteAccessInstance.reset(); + pWriteAccessAlphaInstance.reset(); + if (!aBitmap.IsEmpty() && !aBitmapAlpha.IsEmpty()) + aBitmapEx = BitmapEx(aBitmap, aBitmapAlpha); + else if (!aBitmap.IsEmpty()) + aBitmapEx = BitmapEx(aBitmap); + if (!aBitmapEx.IsEmpty() && !prefSize.IsEmpty()) + { + aBitmapEx.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + aBitmapEx.SetPrefSize(prefSize); + } + rImportOutput.moBitmap = aBitmapEx; + } + // Return true in this case, as we read the bitmap + return true; + } + png_read_end(pPng, pInfo); if (!bUseExistingBitmap)