Blob Blame History Raw
From a4ab4fdafc33088429a6c6bcdcf3c072b3a834a9 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Mon, 12 Dec 2016 15:23:55 +0100
Subject: [PATCH 2/2] emit bmps with color palette correctly

Change-Id: I731ab9629fdc08c54b43cdcb21a81633bd89f569
---
 src/lib/VSDContentCollector.cpp | 52 +++++++++++++++++++++++++++++++++++++----
 src/lib/libvisio_utils.h        |  2 ++
 2 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/src/lib/VSDContentCollector.cpp b/src/lib/VSDContentCollector.cpp
index c20e626..229120f 100644
--- a/src/lib/VSDContentCollector.cpp
+++ b/src/lib/VSDContentCollector.cpp
@@ -7,6 +7,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+#include <cassert>
 #include <string.h> // for memcpy
 #include <set>
 #include <stack>
@@ -33,6 +34,48 @@ static unsigned bitmapId = 0;
 
 #define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000)
 
+namespace
+{
+
+unsigned computeBMPDataOffset(librevenge::RVNGInputStream *const input, const unsigned long maxLength)
+{
+  assert(input);
+
+  using namespace libvisio;
+
+  // determine header size
+  unsigned headerSize = readU32(input);
+  if (headerSize > maxLength)
+    headerSize = 40; // assume v.3 bitmap header size
+  unsigned off = headerSize;
+
+  // determine palette size
+  input->seek(10, librevenge::RVNG_SEEK_CUR);
+  unsigned bpp = readU16(input);
+  // sanitize bpp
+  if (bpp > 32)
+    bpp = 32;
+  const unsigned allowedBpp[] = {1, 4, 8, 16, 24, 32};
+  size_t bppIdx = 0;
+  while (bppIdx < VSD_NUM_ELEMENTS(allowedBpp) && bpp < allowedBpp[bppIdx])
+    ++bppIdx;
+  if (bpp < allowedBpp[bppIdx])
+    bpp = allowedBpp[bppIdx];
+  input->seek(16, librevenge::RVNG_SEEK_CUR);
+  unsigned paletteColors = readU32(input);
+  if (bpp < 16 && paletteColors == 0)
+    paletteColors = 1 << bpp;
+  assert(maxLength >= off);
+  if (paletteColors > 0 && (paletteColors < (maxLength - off) / 4))
+    off += 4 * paletteColors;
+
+  off += 14; // file header size
+
+  return off;
+}
+
+} // anonymous namespace
+
 libvisio::VSDContentCollector::VSDContentCollector(
   librevenge::RVNGDrawingInterface *painter,
   std::vector<std::map<unsigned, XForm> > &groupXFormsSequence,
@@ -1359,10 +1402,11 @@ void libvisio::VSDContentCollector::_handleForeignData(const librevenge::RVNGBin
       m_currentForeignData.append((unsigned char)0x00);
       m_currentForeignData.append((unsigned char)0x00);
 
-      m_currentForeignData.append((unsigned char)0x36);
-      m_currentForeignData.append((unsigned char)0x00);
-      m_currentForeignData.append((unsigned char)0x00);
-      m_currentForeignData.append((unsigned char)0x00);
+      const unsigned dataOff = computeBMPDataOffset(binaryData.getDataStream(), binaryData.size());
+      m_currentForeignData.append((unsigned char)(dataOff & 0xff));
+      m_currentForeignData.append((unsigned char)((dataOff >> 8) & 0xff));
+      m_currentForeignData.append((unsigned char)((dataOff >> 16) & 0xff));
+      m_currentForeignData.append((unsigned char)((dataOff >> 24) & 0xff));
     }
     m_currentForeignData.append(binaryData);
 
diff --git a/src/lib/libvisio_utils.h b/src/lib/libvisio_utils.h
index c6c3a03..2a4880e 100644
--- a/src/lib/libvisio_utils.h
+++ b/src/lib/libvisio_utils.h
@@ -70,6 +70,8 @@ typedef unsigned __int64 uint64_t;
 #define VSD_DEBUG(M)
 #endif
 
+#define VSD_NUM_ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
+
 namespace libvisio
 {
 
-- 
2.9.3