[Libreoffice-commits] core.git: include/vcl vcl/source

Luboš Luňák (via logerrit) logerrit at kemper.freedesktop.org
Fri Mar 12 14:37:19 UTC 2021


 include/vcl/filter/PngImageReader.hxx    |    5 +
 vcl/source/filter/png/PngImageReader.cxx |   87 ++++++++++++++++++++++++++++---
 2 files changed, 85 insertions(+), 7 deletions(-)

New commits:
commit e286bd791bfaa00746ea143303761f76e0af1f0d
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Mar 5 19:42:41 2021 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Fri Mar 12 15:36:32 2021 +0100

    add support for Microsoft Gif chunk to PngImageReader
    
    Change-Id: I7d7f47041c48eb1a19e2aaee0c6da8c675ada4b1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112039
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>

diff --git a/include/vcl/filter/PngImageReader.hxx b/include/vcl/filter/PngImageReader.hxx
index 97b2616883b2..2cd57549cf49 100644
--- a/include/vcl/filter/PngImageReader.hxx
+++ b/include/vcl/filter/PngImageReader.hxx
@@ -34,6 +34,11 @@ public:
     PngImageReader(SvStream& rStream);
 
     bool read(BitmapEx& rBitmap);
+
+    // Returns the contents of the msOG chunk (containing a Gif image), if it exists.
+    // Does not change position in the stream.
+    static std::unique_ptr<sal_uInt8[]> getMicrosoftGifChunk(SvStream& rStream,
+                                                             sal_Int32* chunkSize = nullptr);
 };
 
 } // namespace vcl
diff --git a/vcl/source/filter/png/PngImageReader.cxx b/vcl/source/filter/png/PngImageReader.cxx
index 3351e314b3fe..829f3dd45bca 100644
--- a/vcl/source/filter/png/PngImageReader.cxx
+++ b/vcl/source/filter/png/PngImageReader.cxx
@@ -10,6 +10,7 @@
 
 #include <vcl/filter/PngImageReader.hxx>
 #include <png.h>
+#include <rtl/crc.h>
 #include <tools/stream.hxx>
 #include <vcl/bitmap.hxx>
 #include <vcl/alpha.hxx>
@@ -40,18 +41,20 @@ void lclReadStream(png_structp pPng, png_bytep pOutBytes, png_size_t nBytesToRea
     }
 }
 
-bool reader(SvStream& rStream, BitmapEx& rBitmapEx, bool bUseBitmap32)
-{
-    enum
-    {
-        PNG_SIGNATURE_SIZE = 8
-    };
+constexpr int PNG_SIGNATURE_SIZE = 8;
 
+bool isPng(SvStream& rStream)
+{
     // Check signature bytes
     sal_uInt8 aHeader[PNG_SIGNATURE_SIZE];
     rStream.ReadBytes(aHeader, PNG_SIGNATURE_SIZE);
 
-    if (png_sig_cmp(aHeader, 0, PNG_SIGNATURE_SIZE))
+    return png_sig_cmp(aHeader, 0, PNG_SIGNATURE_SIZE) == 0;
+}
+
+bool reader(SvStream& rStream, BitmapEx& rBitmapEx, bool bUseBitmap32)
+{
+    if (!isPng(rStream))
         return false;
 
     png_structp pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
@@ -347,6 +350,64 @@ bool reader(SvStream& rStream, BitmapEx& rBitmapEx, bool bUseBitmap32)
     return true;
 }
 
+std::unique_ptr<sal_uInt8[]> getMsGifChunk(SvStream& rStream, sal_Int32* chunkSize)
+{
+    if (chunkSize)
+        *chunkSize = 0;
+    if (!isPng(rStream))
+        return nullptr;
+    // It's easier to read manually the contents and find the chunk than
+    // try to get it using libpng.
+    // https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_format
+    // Each chunk is: 4 bytes length, 4 bytes type, <length> bytes, 4 bytes crc
+    for (;;)
+    {
+        sal_uInt32 length, type, crc;
+        rStream.ReadUInt32(length);
+        rStream.ReadUInt32(type);
+        if (!rStream.good())
+            return nullptr;
+        constexpr sal_uInt32 PNGCHUNK_msOG = 0x6d734f47; // Microsoft Office Animated GIF
+        constexpr sal_uInt64 MSGifHeaderSize = 11; // "MSOFFICE9.0"
+        if (type == PNGCHUNK_msOG && length > MSGifHeaderSize)
+        {
+            // calculate chunktype CRC (swap it back to original byte order)
+            sal_uInt32 typeForCrc = type;
+#if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
+            typeForCrc = OSL_SWAPDWORD(typeForCrc);
+#endif
+            sal_uInt32 computedCrc = rtl_crc32(0, &typeForCrc, 4);
+            const sal_uInt64 pos = rStream.Tell();
+            if (pos + length >= rStream.TellEnd())
+                return nullptr; // broken PNG
+
+            char msHeader[MSGifHeaderSize];
+            if (rStream.ReadBytes(msHeader, MSGifHeaderSize) != MSGifHeaderSize)
+                return nullptr;
+            computedCrc = rtl_crc32(computedCrc, msHeader, MSGifHeaderSize);
+            length -= MSGifHeaderSize;
+
+            std::unique_ptr<sal_uInt8[]> chunk(new sal_uInt8[length]);
+            if (rStream.ReadBytes(chunk.get(), length) != length)
+                return nullptr;
+            computedCrc = rtl_crc32(computedCrc, chunk.get(), length);
+            rStream.ReadUInt32(crc);
+            if (crc != computedCrc)
+                continue; // invalid chunk, ignore
+            if (chunkSize)
+                *chunkSize = length;
+            return chunk;
+        }
+        if (rStream.remainingSize() < length)
+            return nullptr;
+        rStream.SeekRel(length);
+        rStream.ReadUInt32(crc);
+        constexpr sal_uInt32 PNGCHUNK_IEND = 0x49454e44;
+        if (type == PNGCHUNK_IEND)
+            return nullptr;
+    }
+}
+
 } // anonymous namespace
 
 namespace vcl
@@ -364,6 +425,18 @@ bool PngImageReader::read(BitmapEx& rBitmapEx)
     return reader(mrStream, rBitmapEx, bSupportsBitmap32);
 }
 
+std::unique_ptr<sal_uInt8[]> PngImageReader::getMicrosoftGifChunk(SvStream& rStream,
+                                                                  sal_Int32* chunkSize)
+{
+    sal_uInt64 originalPosition = rStream.Tell();
+    SvStreamEndian originalEndian = rStream.GetEndian();
+    rStream.SetEndian(SvStreamEndian::BIG);
+    std::unique_ptr<sal_uInt8[]> chunk = getMsGifChunk(rStream, chunkSize);
+    rStream.SetEndian(originalEndian);
+    rStream.Seek(originalPosition);
+    return chunk;
+}
+
 } // namespace vcl
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list