diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2016-02-23 09:13:40 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2016-02-23 09:14:36 +0100 |
commit | 6f94cab9c43f88624b58a47ad03ad5f87032595d (patch) | |
tree | a2b0e4843d81befabcf929e3b5cd94b1b21a58f4 | |
parent | 4f6e3108d9b9b67f21d11d597f2e607acafabd72 (diff) |
tdf#59699 RTF import: handle INCLUDEPICTURE field
On one hand, don't handle a fieldmark for it in dmapper.
On the other hand, handle the field in the RTF tokenizer as it would be
{\pict ...hexdump... }, that will result in an inline picture, as
wanted.
Change-Id: I554fdf017920350144300fd86617bf74eed8995b
-rw-r--r-- | sw/qa/extras/rtfimport/data/libreoffice.png | bin | 0 -> 767 bytes | |||
-rw-r--r-- | sw/qa/extras/rtfimport/data/tdf59699.rtf | 10 | ||||
-rw-r--r-- | sw/qa/extras/rtfimport/rtfimport.cxx | 9 | ||||
-rw-r--r-- | writerfilter/Library_writerfilter.mk | 1 | ||||
-rw-r--r-- | writerfilter/inc/rtftok/RTFDocument.hxx | 3 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 3 | ||||
-rw-r--r-- | writerfilter/source/dmapper/FieldTypes.hxx | 1 | ||||
-rw-r--r-- | writerfilter/source/filter/RtfFilter.cxx | 2 | ||||
-rw-r--r-- | writerfilter/source/rtftok/rtfdocumentfactory.cxx | 4 | ||||
-rw-r--r-- | writerfilter/source/rtftok/rtfdocumentimpl.cxx | 67 | ||||
-rw-r--r-- | writerfilter/source/rtftok/rtfdocumentimpl.hxx | 6 |
11 files changed, 96 insertions, 10 deletions
diff --git a/sw/qa/extras/rtfimport/data/libreoffice.png b/sw/qa/extras/rtfimport/data/libreoffice.png Binary files differnew file mode 100644 index 000000000000..437f613c178c --- /dev/null +++ b/sw/qa/extras/rtfimport/data/libreoffice.png diff --git a/sw/qa/extras/rtfimport/data/tdf59699.rtf b/sw/qa/extras/rtfimport/data/tdf59699.rtf new file mode 100644 index 000000000000..94331cc62113 --- /dev/null +++ b/sw/qa/extras/rtfimport/data/tdf59699.rtf @@ -0,0 +1,10 @@ +{\rtf1 +\pard\plain +{\field +{\*\fldinst +{ INCLUDEPICTURE "libreoffice.png" \\* MERGEFORMAT \\d } +} +{\fldrslt} +} +\par +} diff --git a/sw/qa/extras/rtfimport/rtfimport.cxx b/sw/qa/extras/rtfimport/rtfimport.cxx index 52b9fd066999..b1a62929d20e 100644 --- a/sw/qa/extras/rtfimport/rtfimport.cxx +++ b/sw/qa/extras/rtfimport/rtfimport.cxx @@ -48,6 +48,7 @@ #include <com/sun/star/text/VertOrientation.hpp> #include <com/sun/star/text/WritingMode2.hpp> #include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> #include <rtl/ustring.hxx> #include <vcl/outdev.hxx> @@ -633,6 +634,14 @@ DECLARE_RTFIMPORT_TEST(testFdo49659, "fdo49659.rtf") CPPUNIT_ASSERT_EQUAL(graphic::GraphicType::PIXEL, getProperty<sal_Int8>(xGraphic, "GraphicType")); } +DECLARE_OOXMLIMPORT_TEST(testTdf59699, "tdf59699.rtf") +{ + // This resulted in a lang.IndexOutOfBoundsException: the referenced graphic data wasn't imported. + uno::Reference<beans::XPropertySet> xImage(getShape(1), uno::UNO_QUERY); + auto xGraphic = getProperty<uno::Reference<graphic::XGraphic> >(xImage, "Graphic"); + CPPUNIT_ASSERT(xGraphic.is()); +} + DECLARE_RTFIMPORT_TEST(testFdo46966, "fdo46966.rtf") { /* diff --git a/writerfilter/Library_writerfilter.mk b/writerfilter/Library_writerfilter.mk index 792b1620b8dd..8d3508d2d95e 100644 --- a/writerfilter/Library_writerfilter.mk +++ b/writerfilter/Library_writerfilter.mk @@ -21,6 +21,7 @@ $(eval $(call gb_Library_set_include,writerfilter,\ $$(INCLUDE) \ -I$(SRCDIR)/writerfilter/inc \ -I$(SRCDIR)/writerfilter/source \ + -I$(SRCDIR)/writerfilter/source/dmapper \ )) $(eval $(call gb_Library_use_sdk_api,writerfilter)) diff --git a/writerfilter/inc/rtftok/RTFDocument.hxx b/writerfilter/inc/rtftok/RTFDocument.hxx index ac40a9ce4f26..c3f65b7d5be4 100644 --- a/writerfilter/inc/rtftok/RTFDocument.hxx +++ b/writerfilter/inc/rtftok/RTFDocument.hxx @@ -15,6 +15,7 @@ #include <com/sun/star/lang/XComponent.hpp> #include <com/sun/star/frame/XFrame.hpp> #include <com/sun/star/task/XStatusIndicator.hpp> +#include <unotools/mediadescriptor.hxx> namespace writerfilter { @@ -44,7 +45,7 @@ public: css::uno::Reference<css::lang::XComponent> const& xDstDoc, css::uno::Reference<css::frame::XFrame> const& xFrame, css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator, - bool bIsNewDoc); + const utl::MediaDescriptor& rMediaDescriptor); }; } // namespace rtftok } // namespace writerfilter diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 8783535b3641..3dc0040fce1a 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -2807,7 +2807,7 @@ if(!bFilled) {OUString("HYPERLINK"), "", FIELD_HYPERLINK }, {OUString("IF"), "ConditionalText", FIELD_IF }, // {OUString("INFO"), "",FIELD_INFO }, -// {OUString("INCLUDEPICTURE"), "", FIELD_INCLUDEPICTURE}, + {OUString("INCLUDEPICTURE"), "", FIELD_INCLUDEPICTURE}, {OUString("KEYWORDS"), "DocInfo.KeyWords", FIELD_KEYWORDS }, {OUString("LASTSAVEDBY"), "DocInfo.ChangeAuthor", FIELD_LASTSAVEDBY }, {OUString("MACROBUTTON"), "Macro", FIELD_MACROBUTTON }, @@ -3572,6 +3572,7 @@ void DomainMapper_Impl::CloseFieldCommand() case FIELD_CITATION: case FIELD_TC: case FIELD_EQ: + case FIELD_INCLUDEPICTURE: bCreateField = false; break; case FIELD_FORMCHECKBOX : diff --git a/writerfilter/source/dmapper/FieldTypes.hxx b/writerfilter/source/dmapper/FieldTypes.hxx index dc5eb7c559d7..5c446a30c354 100644 --- a/writerfilter/source/dmapper/FieldTypes.hxx +++ b/writerfilter/source/dmapper/FieldTypes.hxx @@ -120,7 +120,6 @@ enum FieldId ,FIELD_INFO /* INCLUDEPICTURE path \* MERGEFORMAT-> old filter imports an embedded picture - todo: not yet supported */ ,FIELD_INCLUDEPICTURE /* KEYWORDS keyword \* defaultswitch \* Numberingswitch \* MERGEFORMAT -> diff --git a/writerfilter/source/filter/RtfFilter.cxx b/writerfilter/source/filter/RtfFilter.cxx index b2f05551627a..a482dccccb16 100644 --- a/writerfilter/source/filter/RtfFilter.cxx +++ b/writerfilter/source/filter/RtfFilter.cxx @@ -145,7 +145,7 @@ sal_Bool RtfFilter::filter(const uno::Sequence< beans::PropertyValue >& aDescrip writerfilter::dmapper::SourceDocumentType eType = writerfilter::dmapper::SourceDocumentType::RTF; writerfilter::Stream::Pointer_t pStream(writerfilter::dmapper::DomainMapperFactory::createMapper(m_xContext, xInputStream, m_xDstDoc, bRepairStorage, eType, aMediaDesc)); writerfilter::rtftok::RTFDocument::Pointer_t pDocument( - writerfilter::rtftok::RTFDocumentFactory::createDocument(m_xContext, xInputStream, m_xDstDoc, xFrame, xStatusIndicator, bIsNewDoc)); + writerfilter::rtftok::RTFDocumentFactory::createDocument(m_xContext, xInputStream, m_xDstDoc, xFrame, xStatusIndicator, aMediaDesc)); pDocument->resolve(*pStream); bResult = true; sal_uInt32 nEndTime = osl_getGlobalTimer(); diff --git a/writerfilter/source/rtftok/rtfdocumentfactory.cxx b/writerfilter/source/rtftok/rtfdocumentfactory.cxx index 0722bff44ee3..aadfc38e71ce 100644 --- a/writerfilter/source/rtftok/rtfdocumentfactory.cxx +++ b/writerfilter/source/rtftok/rtfdocumentfactory.cxx @@ -19,9 +19,9 @@ RTFDocument::Pointer_t RTFDocumentFactory::createDocument(css::uno::Reference< c css::uno::Reference< css::lang::XComponent > const& xDstDoc, css::uno::Reference< css::frame::XFrame > const& xFrame, css::uno::Reference< css::task::XStatusIndicator > const& xStatusIndicator, - bool bIsNewDoc) + const utl::MediaDescriptor& rMediaDescriptor) { - return std::make_shared<RTFDocumentImpl>(xContext, xInputStream, xDstDoc, xFrame, xStatusIndicator, bIsNewDoc); + return std::make_shared<RTFDocumentImpl>(xContext, xInputStream, xDstDoc, xFrame, xStatusIndicator, rMediaDescriptor); } } // namespace rtftok diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx index bf41bbe37c49..7473a9860e09 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx @@ -34,6 +34,8 @@ #include <ooxml/resourceids.hxx> #include <oox/token/namespaces.hxx> #include <oox/drawingml/drawingmltypes.hxx> +#include <rtl/uri.hxx> +#include <dmapper/DomainMapper_Impl.hxx> #include <rtfsdrimport.hxx> #include <rtflookahead.hxx> #include <rtfcharsets.hxx> @@ -211,7 +213,7 @@ RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& x uno::Reference<lang::XComponent> const& xDstDoc, uno::Reference<frame::XFrame> const& xFrame, uno::Reference<task::XStatusIndicator> const& xStatusIndicator, - bool bIsNewDoc) + const utl::MediaDescriptor& rMediaDescriptor) : m_xContext(xContext), m_xInputStream(xInputStream), m_xDstDoc(xDstDoc), @@ -270,7 +272,8 @@ RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& x m_bHadSect(false), m_nCellxMax(0), m_nListPictureId(0), - m_bIsNewDoc(bIsNewDoc) + m_bIsNewDoc(!rMediaDescriptor.getUnpackedValueOrDefault("InsertMode", false)), + m_rMediaDescriptor(rMediaDescriptor) { OSL_ASSERT(xInputStream.is()); m_pInStream.reset(utl::UcbStreamHelper::CreateStream(xInputStream, true)); @@ -341,7 +344,7 @@ void RTFDocumentImpl::resolveSubstream(sal_Size nPos, Id nId, OUString& rIgnoreF { sal_Size nCurrent = Strm().Tell(); // Seek to header position, parse, then seek back. - auto pImpl = std::make_shared<RTFDocumentImpl>(m_xContext, m_xInputStream, m_xDstDoc, m_xFrame, m_xStatusIndicator, m_bIsNewDoc); + auto pImpl = std::make_shared<RTFDocumentImpl>(m_xContext, m_xInputStream, m_xDstDoc, m_xFrame, m_xStatusIndicator, m_rMediaDescriptor); pImpl->setSuperstream(this); pImpl->setStreamType(nId); pImpl->setIgnoreFirst(rIgnoreFirst); @@ -1548,6 +1551,24 @@ RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword) if (!aBuf.isEmpty() && !isalnum(ch)) bFoundCode = true; } + + if (aBuf.toString() == "INCLUDEPICTURE") + { + // Extract the field argument of INCLUDEPICTURE: we handle that + // at a tokenizer level, as DOCX has no such field. + aBuf.append(ch); + while (true) + { + Strm().ReadChar(ch); + if (ch == '}') + break; + aBuf.append(ch); + } + OUString aFieldCommand = OStringToOUString(aBuf.toString(), RTL_TEXTENCODING_UTF8); + std::tuple<OUString, std::vector<OUString>, std::vector<OUString> > aResult = writerfilter::dmapper::lcl_SplitFieldCommand(aFieldCommand); + m_aPicturePath = std::get<1>(aResult).empty() ? OUString() : std::get<1>(aResult).front(); + } + Strm().Seek(nPos); // Form data should be handled only for form fields if any @@ -5149,6 +5170,46 @@ RTFError RTFDocumentImpl::popState() break; case Destination::FIELDRESULT: singleChar(cFieldEnd); + + if (!m_aPicturePath.isEmpty()) + { + // Read the picture into m_aStates.top().aDestinationText. + pushState(); + dispatchDestination(RTF_PICT); + if (m_aPicturePath.endsWith(".png")) + dispatchFlag(RTF_PNGBLIP); + OUString aFileURL = m_rMediaDescriptor.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_URL(), OUString()); + OUString aPictureURL; + try + { + aPictureURL = rtl::Uri::convertRelToAbs(aFileURL, m_aPicturePath); + } + catch(const rtl::MalformedUriException& rException) + { + SAL_WARN("writerfilter", "rtl::Uri::convertRelToAbs() failed: " << rException.getMessage()); + } + + if (!aPictureURL.isEmpty()) + { + SvFileStream aStream(aPictureURL, StreamMode::READ); + if (aStream.IsOpen()) + { + OUStringBuffer aBuf; + while (aStream.good()) + { + unsigned char ch = 0; + aStream.ReadUChar(ch); + if (ch < 16) + aBuf.append("0"); + aBuf.append(OUString::number(ch, 16)); + } + m_aStates.top().aDestinationText = aBuf; + } + } + popState(); + m_aPicturePath.clear(); + } + break; case Destination::LEVELTEXT: { diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx b/writerfilter/source/rtftok/rtfdocumentimpl.hxx index 830eddd232cc..227e940c3ecf 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx @@ -332,7 +332,7 @@ public: css::uno::Reference<css::lang::XComponent> const& xDstDoc, css::uno::Reference<css::frame::XFrame> const& xFrame, css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator, - bool bIsNewDoc); + const utl::MediaDescriptor& rMediaDescriptor); virtual ~RTFDocumentImpl(); // RTFDocument @@ -564,6 +564,8 @@ private: RTFReferenceTable::Entries_t m_aStyleTableEntries; int m_nCurrentStyleIndex; bool m_bFormField; + /// For the INCLUDEPICTURE field's argument. + OUString m_aPicturePath; // Unicode characters are collected here so we don't have to send them one by one. OUStringBuffer m_aUnicodeBuffer; /// Same for hex characters. @@ -592,6 +594,8 @@ private: /// New document means not pasting into an existing one. bool m_bIsNewDoc; + /// The media descriptor contains e.g. the base URL of the document. + const utl::MediaDescriptor& m_rMediaDescriptor; }; } // namespace rtftok } // namespace writerfilter |