From 5d863d458dbf0ba581f550b2e82788878c1e5b31 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Tue, 2 Dec 2014 17:09:30 +0100 Subject: fdo#86664 VSD import: handle metadata (cherry picked from commit 9b61cf4a70b9c3023d035a1b0f7cc1488dd55e22) (cherry picked from commit 386014bb5ee1fb611bbc00c37c04cdf191a833b7) Change-Id: Icec212a93df10b212a9ae614b5c1ced6bf25ff7f --- external/libvisio/UnpackedTarball_libvisio.mk | 1 + external/libvisio/vsd-metadata.patch.1 | 651 ++++++++++++++++++++++++++ 2 files changed, 652 insertions(+) create mode 100644 external/libvisio/vsd-metadata.patch.1 (limited to 'external') diff --git a/external/libvisio/UnpackedTarball_libvisio.mk b/external/libvisio/UnpackedTarball_libvisio.mk index 4451eb51d151..dddf0b7ceeec 100644 --- a/external/libvisio/UnpackedTarball_libvisio.mk +++ b/external/libvisio/UnpackedTarball_libvisio.mk @@ -14,6 +14,7 @@ $(eval $(call gb_UnpackedTarball_set_tarball,libvisio,$(VISIO_TARBALL))) $(eval $(call gb_UnpackedTarball_add_patches,libvisio,\ external/libvisio/libvisio_quote.patch.1 \ external/libvisio/vsdx-metadata.patch.1 \ + external/libvisio/vsd-metadata.patch.1 \ )) # vim: set noet sw=4 ts=4: diff --git a/external/libvisio/vsd-metadata.patch.1 b/external/libvisio/vsd-metadata.patch.1 new file mode 100644 index 000000000000..1704bad7c099 --- /dev/null +++ b/external/libvisio/vsd-metadata.patch.1 @@ -0,0 +1,651 @@ +commit a7f7ccbd4089965511dc59c3ae7869b360c8ca9f +Author: Miklos Vajna +Date: Tue Dec 2 17:05:23 2014 +0100 + + Move _appendUCS4() to libvisio_utils + +diff --git a/src/lib/VSDContentCollector.cpp b/src/lib/VSDContentCollector.cpp +index 822a5f4..083fd91 100644 +--- a/src/lib/VSDContentCollector.cpp ++++ b/src/lib/VSDContentCollector.cpp +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + + #include "VSDContentCollector.h" +@@ -33,27 +32,6 @@ static unsigned bitmapId = 0; + + #define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000) + +-namespace +-{ +- +-static void _appendUCS4(librevenge::RVNGString &text, UChar32 ucs4Character) +-{ +- // Convert carriage returns to new line characters +- // Writerperfect/LibreOffice will replace them by +- if (ucs4Character == (UChar32) 0x0d || ucs4Character == (UChar32) 0x0e) +- ucs4Character = (UChar32) '\n'; +- +- unsigned char outbuf[U8_MAX_LENGTH+1]; +- int i = 0; +- U8_APPEND_UNSAFE(&outbuf[0], i, ucs4Character); +- outbuf[i] = 0; +- +- text.append((char *)outbuf); +-} +- +-} // anonymous namespace +- +- + libvisio::VSDContentCollector::VSDContentCollector( + librevenge::RVNGDrawingInterface *painter, + std::vector > &groupXFormsSequence, +@@ -2870,7 +2848,7 @@ void libvisio::VSDContentCollector::appendCharacters(librevenge::RVNGString &tex + ucs4Character = 0x20; + else + ucs4Character = symbolmap[*iter - 0x20]; +- _appendUCS4(text, ucs4Character); ++ appendUCS4(text, ucs4Character); + } + } + else +@@ -2934,7 +2912,7 @@ void libvisio::VSDContentCollector::appendCharacters(librevenge::RVNGString &tex + if (0x1e == ucs4Character) + _appendField(text); + else +- _appendUCS4(text, ucs4Character); ++ appendUCS4(text, ucs4Character); + } + } + } +@@ -2960,7 +2938,7 @@ void libvisio::VSDContentCollector::appendCharacters(librevenge::RVNGString &tex + if (0xfffc == ucs4Character) + _appendField(text); + else +- _appendUCS4(text, ucs4Character); ++ appendUCS4(text, ucs4Character); + } + } + } +diff --git a/src/lib/libvisio_utils.cpp b/src/lib/libvisio_utils.cpp +index b137e24..e622417 100644 +--- a/src/lib/libvisio_utils.cpp ++++ b/src/lib/libvisio_utils.cpp +@@ -107,6 +107,20 @@ const librevenge::RVNGString libvisio::getColourString(const Colour &c) + return sColour; + } + ++void libvisio::appendUCS4(librevenge::RVNGString &text, UChar32 ucs4Character) ++{ ++ // Convert carriage returns to new line characters ++ // Writerperfect/LibreOffice will replace them by ++ if (ucs4Character == (UChar32) 0x0d || ucs4Character == (UChar32) 0x0e) ++ ucs4Character = (UChar32) '\n'; ++ ++ unsigned char outbuf[U8_MAX_LENGTH+1]; ++ int i = 0; ++ U8_APPEND_UNSAFE(&outbuf[0], i, ucs4Character); ++ outbuf[i] = 0; ++ ++ text.append((char *)outbuf); ++} + + + /* vim:set shiftwidth=2 softtabstop=2 expandtab: */ +diff --git a/src/lib/libvisio_utils.h b/src/lib/libvisio_utils.h +index 08ebb04..60be13f 100644 +--- a/src/lib/libvisio_utils.h ++++ b/src/lib/libvisio_utils.h +@@ -47,6 +47,7 @@ typedef unsigned __int64 uint64_t; + + #include + #include ++#include + + // debug message includes source file and line number + //#define VERBOSE_DEBUG 1 +@@ -79,6 +80,8 @@ double readDouble(librevenge::RVNGInputStream *input); + + const librevenge::RVNGString getColourString(const Colour &c); + ++void appendUCS4(librevenge::RVNGString &text, UChar32 ucs4Character); ++ + class EndOfStreamException + { + }; +commit 005b45ddf64a8320a0143336d431a016507d2085 +Author: Miklos Vajna +Date: Tue Dec 2 17:01:35 2014 +0100 + + fdo#86729 VSD: import metadata + + Only title as a start. + +diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am +index 955aac4..f4d86fa 100644 +--- a/src/lib/Makefile.am ++++ b/src/lib/Makefile.am +@@ -39,6 +39,7 @@ libvisio_@VSD_MAJOR_VERSION@_@VSD_MINOR_VERSION@_la_SOURCES = \ + VSDPages.cpp \ + VSDParagraphList.cpp \ + VSDParser.cpp \ ++ VSDMetaData.cpp \ + VSDShapeList.cpp \ + VSDStencils.cpp \ + VSDStyles.cpp \ +@@ -58,6 +59,7 @@ libvisio_@VSD_MAJOR_VERSION@_@VSD_MINOR_VERSION@_la_SOURCES = \ + VSDPages.h \ + VSDParagraphList.h \ + VSDParser.h \ ++ VSDMetaData.h \ + VSDShapeList.h \ + VSDStencils.h \ + VSDStyles.h \ +diff --git a/src/lib/Makefile.in b/src/lib/Makefile.in +index a51ac14..0f8dd91 100644 +--- a/src/lib/Makefile.in ++++ b/src/lib/Makefile.in +@@ -131,10 +131,10 @@ am_libvisio_@VSD_MAJOR_VERSION@_@VSD_MINOR_VERSION@_la_OBJECTS = \ + VSDInternalStream.lo VSDCharacterList.lo \ + VSDContentCollector.lo VSDFieldList.lo VSDGeometryList.lo \ + VSDOutputElementList.lo VSDPages.lo VSDParagraphList.lo \ +- VSDParser.lo VSDShapeList.lo VSDStencils.lo VSDStyles.lo \ +- VSDStylesCollector.lo VSDXMLHelper.lo VDXParser.lo \ +- VSDXMLParserBase.lo VSDXMLTokenMap.lo VSDXParser.lo \ +- VSDXTheme.lo VSDXMetaData.lo $(am__objects_1) ++ VSDParser.lo VSDMetaData.lo VSDShapeList.lo VSDStencils.lo \ ++ VSDStyles.lo VSDStylesCollector.lo VSDXMLHelper.lo \ ++ VDXParser.lo VSDXMLParserBase.lo VSDXMLTokenMap.lo \ ++ VSDXParser.lo VSDXTheme.lo VSDXMetaData.lo $(am__objects_1) + libvisio_@VSD_MAJOR_VERSION@_@VSD_MINOR_VERSION@_la_OBJECTS = $(am_libvisio_@VSD_MAJOR_VERSION@_@VSD_MINOR_VERSION@_la_OBJECTS) + AM_V_lt = $(am__v_lt_@AM_V@) + am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +@@ -400,6 +400,7 @@ libvisio_@VSD_MAJOR_VERSION@_@VSD_MINOR_VERSION@_la_SOURCES = \ + VSDPages.cpp \ + VSDParagraphList.cpp \ + VSDParser.cpp \ ++ VSDMetaData.cpp \ + VSDShapeList.cpp \ + VSDStencils.cpp \ + VSDStyles.cpp \ +@@ -419,6 +420,7 @@ libvisio_@VSD_MAJOR_VERSION@_@VSD_MINOR_VERSION@_la_SOURCES = \ + VSDPages.h \ + VSDParagraphList.h \ + VSDParser.h \ ++ VSDMetaData.h \ + VSDShapeList.h \ + VSDStencils.h \ + VSDStyles.h \ +@@ -539,6 +541,7 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VSDFieldList.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VSDGeometryList.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VSDInternalStream.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VSDMetaData.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VSDOutputElementList.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VSDPages.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VSDParagraphList.Plo@am__quote@ +diff --git a/src/lib/VSDMetaData.cpp b/src/lib/VSDMetaData.cpp +new file mode 100644 +index 0000000..209cc34 +--- /dev/null ++++ b/src/lib/VSDMetaData.cpp +@@ -0,0 +1,180 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* ++ * This file is part of the libvisio project. ++ * ++ * This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ */ ++ ++#include "VSDMetaData.h" ++#include ++ ++libvisio::VSDMetaData::VSDMetaData() ++{ ++} ++ ++libvisio::VSDMetaData::~VSDMetaData() ++{ ++} ++ ++bool libvisio::VSDMetaData::parse(librevenge::RVNGInputStream *input) ++{ ++ if (!input) ++ return false; ++ ++ readPropertySetStream(input); ++ ++ return true; ++} ++ ++void libvisio::VSDMetaData::readPropertySetStream(librevenge::RVNGInputStream *input) ++{ ++ // ByteOrder ++ input->seek(2, librevenge::RVNG_SEEK_CUR); ++ // Version ++ input->seek(2, librevenge::RVNG_SEEK_CUR); ++ // SystemIdentifier ++ input->seek(4, librevenge::RVNG_SEEK_CUR); ++ // CLSID ++ input->seek(16, librevenge::RVNG_SEEK_CUR); ++ // NumPropertySets ++ input->seek(4, librevenge::RVNG_SEEK_CUR); ++ // FMTID0 ++ input->seek(16, librevenge::RVNG_SEEK_CUR); ++ uint32_t offset0 = readU32(input); ++ readPropertySet(input, offset0); ++} ++ ++void libvisio::VSDMetaData::readPropertySet(librevenge::RVNGInputStream *input, uint32_t offset) ++{ ++ input->seek(offset, librevenge::RVNG_SEEK_SET); ++ ++ // Size ++ input->seek(4, librevenge::RVNG_SEEK_CUR); ++ uint32_t numProperties = readU32(input); ++ for (uint32_t i = 0; i < numProperties; ++i) ++ readPropertyIdentifierAndOffset(input); ++ for (uint32_t i = 0; i < numProperties; ++i) ++ { ++ if (i >= m_idsAndOffsets.size()) ++ break; ++ readTypedPropertyValue(input, i, offset + m_idsAndOffsets[i].second); ++ } ++} ++ ++#define CODEPAGE_PROPERTY_IDENTIFIER 0x00000001 ++ ++uint32_t libvisio::VSDMetaData::getCodePage() ++{ ++ for (size_t i = 0; i < m_idsAndOffsets.size(); ++i) ++ { ++ if (m_idsAndOffsets[i].first == CODEPAGE_PROPERTY_IDENTIFIER) ++ { ++ if (i >= m_typedPropertyValues.size()) ++ break; ++ return m_typedPropertyValues[i]; ++ } ++ } ++ ++ return 0; ++} ++ ++void libvisio::VSDMetaData::readPropertyIdentifierAndOffset(librevenge::RVNGInputStream *input) ++{ ++ uint32_t propertyIdentifier = readU32(input); ++ uint32_t offset = readU32(input); ++ m_idsAndOffsets.push_back(std::make_pair(propertyIdentifier, offset)); ++} ++ ++#define VT_I2 0x0002 ++#define VT_LPSTR 0x001E ++ ++#define PIDSI_TITLE 0x00000002 ++ ++void libvisio::VSDMetaData::readTypedPropertyValue(librevenge::RVNGInputStream *input, uint32_t index, uint32_t offset) ++{ ++ input->seek(offset, librevenge::RVNG_SEEK_SET); ++ uint16_t type = readU16(input); ++ // Padding ++ input->seek(2, librevenge::RVNG_SEEK_CUR); ++ ++ if (type == VT_I2) ++ { ++ uint16_t value = readU16(input); ++ m_typedPropertyValues[index] = value; ++ } ++ else if (type == VT_LPSTR) ++ { ++ librevenge::RVNGString string = readCodePageString(input); ++ if (!string.empty()) ++ { ++ if (index >= m_idsAndOffsets.size()) ++ return; ++ ++ switch (m_idsAndOffsets[index].first) ++ { ++ case PIDSI_TITLE: ++ m_metaData.insert("dc:title", string); ++ break; ++ } ++ } ++ } ++} ++ ++librevenge::RVNGString libvisio::VSDMetaData::readCodePageString(librevenge::RVNGInputStream *input) ++{ ++ uint32_t size = readU32(input); ++ ++ std::vector characters; ++ for (uint32_t i = 0; i < size; ++i) ++ characters.push_back(readU8(input)); ++ ++ uint32_t codepage = getCodePage(); ++ librevenge::RVNGString string; ++ ++ if (codepage == 65001) ++ { ++ // http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130%28v=vs.85%29.aspx ++ // says this is UTF-8. ++ for (std::vector::const_iterator i = characters.begin(); i != characters.end(); ++i) ++ string.append((const char)*i); ++ } ++ else ++ { ++ UErrorCode status = U_ZERO_ERROR; ++ UConverter *conv = 0; ++ ++ switch (codepage) ++ { ++ case 1252: ++ // http://msdn.microsoft.com/en-us/goglobal/bb964654 ++ conv = ucnv_open("windows-1252", &status); ++ break; ++ } ++ ++ if (U_SUCCESS(status) && conv) ++ { ++ const char *src = (const char *)&characters[0]; ++ const char *srcLimit = (const char *)src + characters.size(); ++ while (src < srcLimit) ++ { ++ UChar32 ucs4Character = ucnv_getNextUChar(conv, &src, srcLimit, &status); ++ if (U_SUCCESS(status) && U_IS_UNICODE_CHAR(ucs4Character)) ++ appendUCS4(string, ucs4Character); ++ } ++ } ++ ++ if (conv) ++ ucnv_close(conv); ++ } ++ ++ return string; ++} ++ ++const librevenge::RVNGPropertyList &libvisio::VSDMetaData::getMetaData() ++{ ++ return m_metaData; ++} ++ ++/* vim:set shiftwidth=2 softtabstop=2 expandtab: */ +diff --git a/src/lib/VSDMetaData.h b/src/lib/VSDMetaData.h +new file mode 100644 +index 0000000..c185894 +--- /dev/null ++++ b/src/lib/VSDMetaData.h +@@ -0,0 +1,51 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* ++ * This file is part of the libvisio project. ++ * ++ * This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ */ ++ ++#ifndef __VSDMETADATA_H__ ++#define __VSDMETADATA_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include "libvisio_utils.h" ++ ++namespace libvisio ++{ ++ ++class VSDMetaData ++{ ++public: ++ VSDMetaData(); ++ ~VSDMetaData(); ++ bool parse(librevenge::RVNGInputStream *input); ++ const librevenge::RVNGPropertyList &getMetaData(); ++ ++private: ++ VSDMetaData(const VSDMetaData &); ++ VSDMetaData &operator=(const VSDMetaData &); ++ ++ void readPropertySetStream(librevenge::RVNGInputStream *input); ++ void readPropertySet(librevenge::RVNGInputStream *input, uint32_t offset); ++ void readPropertyIdentifierAndOffset(librevenge::RVNGInputStream *input); ++ void readTypedPropertyValue(librevenge::RVNGInputStream *input, uint32_t index, uint32_t offset); ++ librevenge::RVNGString readCodePageString(librevenge::RVNGInputStream *input); ++ ++ uint32_t getCodePage(); ++ ++ std::vector< std::pair > m_idsAndOffsets; ++ std::map m_typedPropertyValues; ++ librevenge::RVNGPropertyList m_metaData; ++}; ++ ++} // namespace libvisio ++ ++#endif // __VSDMETADATA_H__ ++/* vim:set shiftwidth=2 softtabstop=2 expandtab: */ +diff --git a/src/lib/VSDParser.cpp b/src/lib/VSDParser.cpp +index 1b8133f..9d6e175 100644 +--- a/src/lib/VSDParser.cpp ++++ b/src/lib/VSDParser.cpp +@@ -19,9 +19,10 @@ + #include "VSDDocumentStructure.h" + #include "VSDContentCollector.h" + #include "VSDStylesCollector.h" ++#include "VSDMetaData.h" + +-libvisio::VSDParser::VSDParser(librevenge::RVNGInputStream *input, librevenge::RVNGDrawingInterface *painter) +- : m_input(input), m_painter(painter), m_header(), m_collector(0), m_shapeList(), m_currentLevel(0), ++libvisio::VSDParser::VSDParser(librevenge::RVNGInputStream *input, librevenge::RVNGDrawingInterface *painter, librevenge::RVNGInputStream *container) ++ : m_input(input), m_painter(painter), m_container(container), m_header(), m_collector(0), m_shapeList(), m_currentLevel(0), + m_stencils(), m_currentStencil(0), m_shape(), m_isStencilStarted(false), m_isInStyles(false), + m_currentShapeLevel(0), m_currentShapeID(MINUS_ONE), m_extractStencils(false), m_colours(), + m_isBackgroundPage(false), m_isShapeStarted(false), m_shadowOffsetX(0.0), m_shadowOffsetY(0.0), +@@ -136,6 +137,9 @@ bool libvisio::VSDParser::parseMain() + + VSDContentCollector contentCollector(m_painter, groupXFormsSequence, groupMembershipsSequence, documentPageShapeOrders, styles, m_stencils); + m_collector = &contentCollector; ++ if (m_container) ++ parseMetaData(); ++ + VSD_DEBUG_MSG(("VSDParser::parseMain 2nd pass\n")); + if (!parseDocument(&trailerStream, shift)) + return false; +@@ -143,6 +147,25 @@ bool libvisio::VSDParser::parseMain() + return true; + } + ++bool libvisio::VSDParser::parseMetaData() ++{ ++ if (!m_container) ++ return false; ++ m_container->seek(0, librevenge::RVNG_SEEK_SET); ++ if (!m_container->isStructured()) ++ return false; ++ librevenge::RVNGInputStream *stream = m_container->getSubStreamByName("\x05SummaryInformation"); ++ if (!stream) ++ return false; ++ ++ VSDMetaData metaData; ++ metaData.parse(stream); ++ m_collector->collectMetaData(metaData.getMetaData()); ++ ++ delete stream; ++ return true; ++} ++ + bool libvisio::VSDParser::parseDocument(librevenge::RVNGInputStream *input, unsigned shift) + { + try +diff --git a/src/lib/VSDParser.h b/src/lib/VSDParser.h +index aabb0db..b2bba54 100644 +--- a/src/lib/VSDParser.h ++++ b/src/lib/VSDParser.h +@@ -45,7 +45,7 @@ struct Pointer + class VSDParser + { + public: +- explicit VSDParser(librevenge::RVNGInputStream *input, librevenge::RVNGDrawingInterface *painter); ++ explicit VSDParser(librevenge::RVNGInputStream *input, librevenge::RVNGDrawingInterface *painter, librevenge::RVNGInputStream *container = 0); + virtual ~VSDParser(); + bool parseMain(); + bool extractStencils(); +@@ -113,6 +113,8 @@ protected: + // parser of one pass + bool parseDocument(librevenge::RVNGInputStream *input, unsigned shift); + ++ bool parseMetaData(); ++ + // Stream handlers + void handleStreams(librevenge::RVNGInputStream *input, unsigned ptrType, unsigned shift, unsigned level); + void handleStream(const Pointer &ptr, unsigned idx, unsigned level); +@@ -133,6 +135,7 @@ protected: + + librevenge::RVNGInputStream *m_input; + librevenge::RVNGDrawingInterface *m_painter; ++ librevenge::RVNGInputStream *m_container; + ChunkHeader m_header; + VSDCollector *m_collector; + VSDShapeList m_shapeList; +diff --git a/src/lib/VisioDocument.cpp b/src/lib/VisioDocument.cpp +index be14b68..f834478 100644 +--- a/src/lib/VisioDocument.cpp ++++ b/src/lib/VisioDocument.cpp +@@ -158,7 +158,7 @@ static bool parseBinaryVisioDocument(librevenge::RVNGInputStream *input, libreve + parser = new libvisio::VSD6Parser(docStream, painter); + break; + case 11: +- parser = new libvisio::VSDParser(docStream, painter); ++ parser = new libvisio::VSDParser(docStream, painter, input); + break; + default: + break; +commit 2e467f4e487bd8fd8440057e1d79f89b2a966419 +Author: Miklos Vajna +Date: Tue Dec 2 17:02:14 2014 +0100 + + fdo#86664 VSD: import Creation/ModifiedTime + +diff --git a/src/lib/VSDMetaData.cpp b/src/lib/VSDMetaData.cpp +index 209cc34..3fd5bf9 100644 +--- a/src/lib/VSDMetaData.cpp ++++ b/src/lib/VSDMetaData.cpp +@@ -8,6 +8,7 @@ + */ + + #include "VSDMetaData.h" ++#include + #include + + libvisio::VSDMetaData::VSDMetaData() +@@ -172,6 +173,58 @@ librevenge::RVNGString libvisio::VSDMetaData::readCodePageString(librevenge::RVN + return string; + } + ++bool libvisio::VSDMetaData::parseTimes(librevenge::RVNGInputStream *input) ++{ ++ // Parse the header ++ // HeaderSignature: 8 bytes ++ // HeaderCLSID: 16 bytes ++ // MinorVersion: 2 bytes ++ // MajorVersion: 2 bytes ++ // ByteOrder: 2 bytes ++ input->seek(30, librevenge::RVNG_SEEK_CUR); ++ uint16_t sectorShift = readU16(input); ++ // MiniSectorShift: 2 bytes ++ // Reserved: 6 bytes ++ // NumDirectorySectors: 4 bytes ++ // NumFATSectors: 4 bytes ++ input->seek(16, librevenge::RVNG_SEEK_CUR); ++ uint32_t firstDirSectorLocation = readU32(input); ++ ++ // Seek to the Root Directory Entry ++ size_t sectorSize = pow(2, sectorShift); ++ input->seek((firstDirSectorLocation + 1) * sectorSize, librevenge::RVNG_SEEK_SET); ++ // DirectoryEntryName: 64 bytes ++ // DirectoryEntryNameLength: 2 bytes ++ // ObjectType: 1 byte ++ // ColorFlag: 1 byte ++ // LeftSiblingID: 4 bytes ++ // RightSiblingID: 4 bytes ++ // ChildID: 4 bytes ++ // CLSID: 16 bytes ++ // StateBits: 4 bytes ++ // CreationTime: 8 bytes ++ input->seek(108, librevenge::RVNG_SEEK_CUR); ++ uint64_t modifiedTime = readU64(input); ++ ++ // modifiedTime is number of 100ns since Jan 1 1601 ++ static const uint64_t epoch = 11644473600; ++ time_t sec = (modifiedTime / 10000000) - epoch; ++ const struct tm *time = localtime(&sec); ++ if (time) ++ { ++ static const int MAX_BUFFER = 1024; ++ char buffer[MAX_BUFFER]; ++ strftime(&buffer[0], MAX_BUFFER-1, "%Y-%m-%dT%H:%M:%SZ", time); ++ librevenge::RVNGString result; ++ result.append(buffer); ++ // Visio UI uses modifiedTime for both purposes. ++ m_metaData.insert("meta:creation-date", result); ++ m_metaData.insert("dc:date", result); ++ return true; ++ } ++ return false; ++} ++ + const librevenge::RVNGPropertyList &libvisio::VSDMetaData::getMetaData() + { + return m_metaData; +diff --git a/src/lib/VSDMetaData.h b/src/lib/VSDMetaData.h +index c185894..581b0a2 100644 +--- a/src/lib/VSDMetaData.h ++++ b/src/lib/VSDMetaData.h +@@ -26,6 +26,7 @@ public: + VSDMetaData(); + ~VSDMetaData(); + bool parse(librevenge::RVNGInputStream *input); ++ bool parseTimes(librevenge::RVNGInputStream *input); + const librevenge::RVNGPropertyList &getMetaData(); + + private: +diff --git a/src/lib/VSDParser.cpp b/src/lib/VSDParser.cpp +index 9d6e175..3af5bd0 100644 +--- a/src/lib/VSDParser.cpp ++++ b/src/lib/VSDParser.cpp +@@ -160,6 +160,8 @@ bool libvisio::VSDParser::parseMetaData() + + VSDMetaData metaData; + metaData.parse(stream); ++ m_container->seek(0, librevenge::RVNG_SEEK_SET); ++ metaData.parseTimes(m_container); + m_collector->collectMetaData(metaData.getMetaData()); + + delete stream; +commit 89ccb97fedc69e4508581ddcd93c9ea6740855c1 +Author: Miklos Vajna +Date: Tue Dec 2 18:50:16 2014 +0100 + + error C3861: ´localtime´: identifier not found + + Change-Id: Ic0ccfc0b6cdd030772d09e7d235c63d440ba2f1b + +diff --git a/src/lib/VSDMetaData.cpp b/src/lib/VSDMetaData.cpp +index 3fd5bf9..61f01a9 100644 +--- a/src/lib/VSDMetaData.cpp ++++ b/src/lib/VSDMetaData.cpp +@@ -10,6 +10,7 @@ + #include "VSDMetaData.h" + #include + #include ++#include + + libvisio::VSDMetaData::VSDMetaData() + { -- cgit v1.2.3