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/container/XChild.hpp>
14 #include <com/sun/star/io/XInputStream.hpp>
15 #include <com/sun/star/uno/Reference.h>
16 #include <com/sun/star/ucb/XContent.hpp>
17 #include <comphelper/processfactory.hxx>
18 #include <comphelper/types.hxx>
19 #include <cppuhelper/supportsservice.hxx>
22 #include <libetonyek/libetonyek.h>
23 #include <libodfgen/libodfgen.hxx>
24 #include <osl/diagnose.h>
25 #include <rtl/tencinfo.h>
26 #include <ucbhelper/content.hxx>
28 #include <DirectoryStream.hxx>
29 #include <DocumentHandler.hxx>
30 #include <WPXSvInputStream.hxx>
32 #include <xmloff/attrlist.hxx>
34 #include "KeynoteImportFilter.hxx"
36 using std::shared_ptr
;
38 using com::sun::star::io::XInputStream
;
39 using com::sun::star::uno::Reference
;
40 using com::sun::star::uno::RuntimeException
;
41 using com::sun::star::uno::Sequence
;
42 using com::sun::star::uno::UNO_QUERY
;
43 using com::sun::star::uno::XComponentContext
;
44 using com::sun::star::uno::XInterface
;
46 using writerperfect::DocumentHandler
;
47 using writerperfect::WPXSvInputStream
;
49 namespace beans
= com::sun::star::beans
;
50 namespace container
= com::sun::star::container
;
51 namespace ucb
= com::sun::star::ucb
;
53 bool KeynoteImportFilter::doImportDocument(librevenge::RVNGInputStream
&rInput
, OdpGenerator
&rGenerator
, utl::MediaDescriptor
&)
55 return libetonyek::EtonyekDocument::parse(&rInput
, &rGenerator
);
58 bool KeynoteImportFilter::doDetectFormat(librevenge::RVNGInputStream
&rInput
, OUString
&rTypeName
)
60 if (libetonyek::EtonyekDocument::isSupported(&rInput
))
62 rTypeName
= "impress_Keynote_Document";
69 // XExtendedFilterDetection
70 OUString SAL_CALL
KeynoteImportFilter::detect(css::uno::Sequence
< css::beans::PropertyValue
> &Descriptor
)
71 throw(css::uno::RuntimeException
, std::exception
)
73 sal_Int32 nLength
= Descriptor
.getLength();
74 sal_Int32 nNewLength
= nLength
+ 2;
75 sal_Int32 nComponentDataLocation
= -1;
76 sal_Int32 nTypeNameLocation
= -1;
77 sal_Int32 nUCBContentLocation
= -1;
78 bool bIsPackage
= false;
79 bool bUCBContentChanged
= false;
80 const beans::PropertyValue
*pValue
= Descriptor
.getConstArray();
81 Reference
< XInputStream
> xInputStream
;
82 Reference
< ucb::XContent
> xContent
;
83 Sequence
< beans::NamedValue
> lComponentDataNV
;
84 Sequence
< beans::PropertyValue
> lComponentDataPV
;
85 bool bComponentDataNV
= true;
87 for (sal_Int32 i
= 0 ; i
< nLength
; i
++)
89 if (pValue
[i
].Name
== "TypeName")
91 nTypeNameLocation
= i
;
94 if (pValue
[i
].Name
== "ComponentData")
96 bComponentDataNV
= pValue
[i
].Value
>>= lComponentDataNV
;
97 if (!bComponentDataNV
)
98 pValue
[i
].Value
>>= lComponentDataPV
;
99 nComponentDataLocation
= i
;
102 else if (pValue
[i
].Name
== "InputStream")
104 pValue
[i
].Value
>>= xInputStream
;
106 else if (pValue
[i
].Name
== "UCBContent")
108 pValue
[i
].Value
>>= xContent
;
109 nUCBContentLocation
= i
;
113 assert(nNewLength
>= nLength
);
115 if (!xInputStream
.is())
118 shared_ptr
< librevenge::RVNGInputStream
> input(new WPXSvInputStream(xInputStream
));
120 /* Apple Keynote documents come in two variants:
121 * * actual files (zip), only produced by Keynote 5 (at least with
123 * * packages (IOW, directories), produced by Keynote 1-4 and again
125 * But since the libetonyek import only works with a stream, we need
126 * to pass it one for the whole package. Here we determine if that
129 * Note: for convenience, we also recognize that the main XML file
130 * from a package was passed and pass the whole package to the
135 ucbhelper::Content
aContent(xContent
, Reference
< ucb::XCommandEnvironment
>(), comphelper::getProcessComponentContext());
138 if (aContent
.isFolder())
140 input
.reset(new writerperfect::DirectoryStream(xContent
));
150 libetonyek::EtonyekDocument::Type type
= libetonyek::EtonyekDocument::TYPE_UNKNOWN
;
151 const libetonyek::EtonyekDocument::Confidence confidence
= libetonyek::EtonyekDocument::isSupported(input
.get(), &type
);
152 if ((libetonyek::EtonyekDocument::CONFIDENCE_NONE
== confidence
) || (libetonyek::EtonyekDocument::TYPE_KEYNOTE
!= type
))
155 if (confidence
== libetonyek::EtonyekDocument::CONFIDENCE_SUPPORTED_PART
)
157 if (bIsPackage
) // we passed a directory stream, but the filter claims it's APXL file?
160 const Reference
< container::XChild
> xChild(xContent
, UNO_QUERY
);
163 const Reference
< ucb::XContent
> xPackageContent(xChild
->getParent(), UNO_QUERY
);
164 if (xPackageContent
.is())
166 input
.reset(new writerperfect::DirectoryStream(xPackageContent
));
167 if (libetonyek::EtonyekDocument::CONFIDENCE_EXCELLENT
== libetonyek::EtonyekDocument::isSupported(input
.get()))
169 xContent
= xPackageContent
;
170 bUCBContentChanged
= true;
175 // The passed stream has been detected as APXL file, but its parent dir is not a valid Keynote
176 // package? Something is wrong here...
183 // we do not need to insert ComponentData if this is not a package
184 if (!bIsPackage
&& (nComponentDataLocation
== -1))
187 if (nNewLength
> nLength
)
188 Descriptor
.realloc(nNewLength
);
190 if (nTypeNameLocation
== -1)
192 assert(nLength
< nNewLength
);
193 nTypeNameLocation
= nLength
++;
194 Descriptor
[nTypeNameLocation
].Name
= "TypeName";
197 if (bIsPackage
&& (nComponentDataLocation
== -1))
199 assert(nLength
< nNewLength
);
200 nComponentDataLocation
= nLength
++;
201 Descriptor
[nComponentDataLocation
].Name
= "ComponentData";
206 if (bComponentDataNV
)
208 const sal_Int32 nCDSize
= lComponentDataNV
.getLength();
209 lComponentDataNV
.realloc(nCDSize
+ 1);
210 beans::NamedValue aValue
;
211 aValue
.Name
= "IsPackage";
212 aValue
.Value
<<= true;
213 lComponentDataNV
[nCDSize
] = aValue
;
214 Descriptor
[nComponentDataLocation
].Value
<<= lComponentDataNV
;
218 const sal_Int32 nCDSize
= lComponentDataPV
.getLength();
219 lComponentDataPV
.realloc(nCDSize
+ 1);
220 beans::PropertyValue aProp
;
221 aProp
.Name
= "IsPackage";
222 aProp
.Value
<<= true;
224 aProp
.State
= beans::PropertyState_DIRECT_VALUE
;
225 lComponentDataPV
[nCDSize
] = aProp
;
226 Descriptor
[nComponentDataLocation
].Value
<<= lComponentDataPV
;
230 if (bUCBContentChanged
)
231 Descriptor
[nUCBContentLocation
].Value
<<= xContent
;
233 const OUString
sTypeName("impress_AppleKeynote");
234 Descriptor
[nTypeNameLocation
].Value
<<= sTypeName
;
240 OUString SAL_CALL
KeynoteImportFilter::getImplementationName()
241 throw (RuntimeException
, std::exception
)
243 return OUString("org.libreoffice.comp.Impress.KeynoteImportFilter");
246 sal_Bool SAL_CALL
KeynoteImportFilter::supportsService(const OUString
&rServiceName
)
247 throw (RuntimeException
, std::exception
)
249 return cppu::supportsService(this, rServiceName
);
252 Sequence
< OUString
> SAL_CALL
KeynoteImportFilter::getSupportedServiceNames()
253 throw (RuntimeException
, std::exception
)
255 Sequence
< OUString
> aRet(2);
256 OUString
*pArray
= aRet
.getArray();
257 pArray
[0] = "com.sun.star.document.ImportFilter";
258 pArray
[1] = "com.sun.star.document.ExtendedTypeDetection";
263 SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*SAL_CALL
264 org_libreoffice_comp_Impress_KeynoteImportFilter_get_implementation(
265 css::uno::XComponentContext
*const context
,
266 const css::uno::Sequence
<css::uno::Any
> &)
268 return cppu::acquire(new KeynoteImportFilter(context
));
271 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */