summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2016-02-23 09:13:40 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-02-23 09:14:36 +0100
commit6f94cab9c43f88624b58a47ad03ad5f87032595d (patch)
treea2b0e4843d81befabcf929e3b5cd94b1b21a58f4
parent4f6e3108d9b9b67f21d11d597f2e607acafabd72 (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.pngbin0 -> 767 bytes
-rw-r--r--sw/qa/extras/rtfimport/data/tdf59699.rtf10
-rw-r--r--sw/qa/extras/rtfimport/rtfimport.cxx9
-rw-r--r--writerfilter/Library_writerfilter.mk1
-rw-r--r--writerfilter/inc/rtftok/RTFDocument.hxx3
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx3
-rw-r--r--writerfilter/source/dmapper/FieldTypes.hxx1
-rw-r--r--writerfilter/source/filter/RtfFilter.cxx2
-rw-r--r--writerfilter/source/rtftok/rtfdocumentfactory.cxx4
-rw-r--r--writerfilter/source/rtftok/rtfdocumentimpl.cxx67
-rw-r--r--writerfilter/source/rtftok/rtfdocumentimpl.hxx6
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
new file mode 100644
index 000000000000..437f613c178c
--- /dev/null
+++ b/sw/qa/extras/rtfimport/data/libreoffice.png
Binary files differ
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