1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* KeynoteImportFilter: Sets up the filter, and calls OdpExporter
3 * to do the actual filtering
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 #include <com/sun/star/beans/NamedValue.hpp>
12 #include <com/sun/star/beans/PropertyValue.hpp>
13 #include <com/sun/star/io/XInputStream.hpp>
14 #include <com/sun/star/uno/Reference.h>
15 #include <com/sun/star/ucb/XContent.hpp>
16 #include <comphelper/processfactory.hxx>
17 #include <cppuhelper/supportsservice.hxx>
19 #include <libetonyek/libetonyek.h>
20 #include <ucbhelper/content.hxx>
21 #include <unotools/ucbhelper.hxx>
23 #include <DirectoryStream.hxx>
24 #include <WPXSvInputStream.hxx>
26 #include "KeynoteImportFilter.hxx"
28 using writerperfect::WPXSvInputStream
;
30 namespace beans
= com::sun::star::beans
;
31 namespace ucb
= com::sun::star::ucb
;
33 bool KeynoteImportFilter::doImportDocument(weld::Window
*, librevenge::RVNGInputStream
& rInput
,
34 OdpGenerator
& rGenerator
, utl::MediaDescriptor
&)
36 return libetonyek::EtonyekDocument::parse(&rInput
, &rGenerator
);
39 bool KeynoteImportFilter::doDetectFormat(librevenge::RVNGInputStream
& rInput
, OUString
& rTypeName
)
41 if (libetonyek::EtonyekDocument::isSupported(&rInput
))
43 rTypeName
= "impress_Keynote_Document";
50 // XExtendedFilterDetection
52 KeynoteImportFilter::detect(css::uno::Sequence
<css::beans::PropertyValue
>& Descriptor
)
54 sal_Int32 nLength
= Descriptor
.getLength();
55 sal_Int32 nNewLength
= nLength
+ 2;
56 sal_Int32 nComponentDataLocation
= -1;
57 sal_Int32 nTypeNameLocation
= -1;
58 sal_Int32 nUCBContentLocation
= -1;
59 bool bIsPackage
= false;
60 bool bUCBContentChanged
= false;
61 const beans::PropertyValue
* pValue
= Descriptor
.getConstArray();
62 css::uno::Reference
<com::sun::star::io::XInputStream
> xInputStream
;
63 css::uno::Reference
<ucb::XContent
> xContent
;
64 css::uno::Sequence
<beans::NamedValue
> lComponentDataNV
;
65 css::uno::Sequence
<beans::PropertyValue
> lComponentDataPV
;
66 bool bComponentDataNV
= true;
68 for (sal_Int32 i
= 0; i
< nLength
; i
++)
70 if (pValue
[i
].Name
== "TypeName")
72 nTypeNameLocation
= i
;
75 if (pValue
[i
].Name
== "ComponentData")
77 bComponentDataNV
= pValue
[i
].Value
>>= lComponentDataNV
;
78 if (!bComponentDataNV
)
79 pValue
[i
].Value
>>= lComponentDataPV
;
80 nComponentDataLocation
= i
;
83 else if (pValue
[i
].Name
== "InputStream")
85 pValue
[i
].Value
>>= xInputStream
;
87 else if (pValue
[i
].Name
== "UCBContent")
89 pValue
[i
].Value
>>= xContent
;
90 nUCBContentLocation
= i
;
94 assert(nNewLength
>= nLength
);
96 if (!xInputStream
.is())
99 std::unique_ptr
<librevenge::RVNGInputStream
> input
100 = std::make_unique
<WPXSvInputStream
>(xInputStream
);
102 /* Apple Keynote documents come in two variants:
103 * * actual files (zip), only produced by Keynote 5 (at least with
105 * * packages (IOW, directories), produced by Keynote 1-4 and again
107 * But since the libetonyek import only works with a stream, we need
108 * to pass it one for the whole package. Here we determine if that
111 * Note: for convenience, we also recognize that the main XML file
112 * from a package was passed and pass the whole package to the
117 ucbhelper::Content
aContent(xContent
, utl::UCBContentHelper::getDefaultCommandEnvironment(),
118 comphelper::getProcessComponentContext());
121 if (aContent
.isFolder())
123 input
= std::make_unique
<writerperfect::DirectoryStream
>(xContent
);
133 libetonyek::EtonyekDocument::Type type
= libetonyek::EtonyekDocument::TYPE_UNKNOWN
;
134 const libetonyek::EtonyekDocument::Confidence confidence
135 = libetonyek::EtonyekDocument::isSupported(input
.get(), &type
);
136 if ((libetonyek::EtonyekDocument::CONFIDENCE_NONE
== confidence
)
137 || (libetonyek::EtonyekDocument::TYPE_KEYNOTE
!= type
))
140 if (confidence
== libetonyek::EtonyekDocument::CONFIDENCE_SUPPORTED_PART
)
142 if (bIsPackage
) // we passed a directory stream, but the filter claims it's APXL file?
145 std::unique_ptr
<writerperfect::DirectoryStream
> xDir
146 = writerperfect::DirectoryStream::createForParent(xContent
);
147 auto pDir
= xDir
.get();
148 input
= std::move(xDir
);
151 if (libetonyek::EtonyekDocument::CONFIDENCE_EXCELLENT
152 == libetonyek::EtonyekDocument::isSupported(input
.get()))
154 xContent
= pDir
->getContent();
155 bUCBContentChanged
= true;
160 // The passed stream has been detected as APXL file, but its parent dir is not a valid Keynote
161 // package? Something is wrong here...
167 // we do not need to insert ComponentData if this is not a package
168 if (!bIsPackage
&& (nComponentDataLocation
== -1))
171 if (nNewLength
> nLength
)
172 Descriptor
.realloc(nNewLength
);
173 auto pDescriptor
= Descriptor
.getArray();
175 if (nTypeNameLocation
== -1)
177 assert(nLength
< nNewLength
);
178 nTypeNameLocation
= nLength
++;
179 pDescriptor
[nTypeNameLocation
].Name
= "TypeName";
182 if (bIsPackage
&& (nComponentDataLocation
== -1))
184 assert(nLength
< nNewLength
);
185 nComponentDataLocation
= nLength
++;
186 pDescriptor
[nComponentDataLocation
].Name
= "ComponentData";
191 if (bComponentDataNV
)
193 const sal_Int32 nCDSize
= lComponentDataNV
.getLength();
194 lComponentDataNV
.realloc(nCDSize
+ 1);
195 beans::NamedValue aValue
;
196 aValue
.Name
= "IsPackage";
197 aValue
.Value
<<= true;
198 lComponentDataNV
.getArray()[nCDSize
] = aValue
;
199 pDescriptor
[nComponentDataLocation
].Value
<<= lComponentDataNV
;
203 const sal_Int32 nCDSize
= lComponentDataPV
.getLength();
204 lComponentDataPV
.realloc(nCDSize
+ 1);
205 beans::PropertyValue aProp
;
206 aProp
.Name
= "IsPackage";
207 aProp
.Value
<<= true;
209 aProp
.State
= beans::PropertyState_DIRECT_VALUE
;
210 lComponentDataPV
.getArray()[nCDSize
] = aProp
;
211 pDescriptor
[nComponentDataLocation
].Value
<<= lComponentDataPV
;
215 if (bUCBContentChanged
)
216 pDescriptor
[nUCBContentLocation
].Value
<<= xContent
;
218 static constexpr OUString
sTypeName(u
"impress_AppleKeynote"_ustr
);
219 pDescriptor
[nTypeNameLocation
].Value
<<= sTypeName
;
225 OUString SAL_CALL
KeynoteImportFilter::getImplementationName()
227 return "org.libreoffice.comp.Impress.KeynoteImportFilter";
230 sal_Bool SAL_CALL
KeynoteImportFilter::supportsService(const OUString
& rServiceName
)
232 return cppu::supportsService(this, rServiceName
);
235 css::uno::Sequence
<OUString
> SAL_CALL
KeynoteImportFilter::getSupportedServiceNames()
237 return { "com.sun.star.document.ImportFilter", "com.sun.star.document.ExtendedTypeDetection" };
240 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
241 org_libreoffice_comp_Impress_KeynoteImportFilter_get_implementation(
242 css::uno::XComponentContext
* const context
, const css::uno::Sequence
<css::uno::Any
>&)
244 return cppu::acquire(new KeynoteImportFilter(context
));
247 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */