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/.
10 #include <boost/shared_ptr.hpp>
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 boost::shared_ptr
;
38 using com::sun::star::io::XInputStream
;
39 using com::sun::star::uno::Any
;
40 using com::sun::star::uno::Exception
;
41 using com::sun::star::uno::Reference
;
42 using com::sun::star::uno::RuntimeException
;
43 using com::sun::star::uno::Sequence
;
44 using com::sun::star::uno::UNO_QUERY
;
45 using com::sun::star::uno::XComponentContext
;
46 using com::sun::star::uno::XInterface
;
48 using writerperfect::DocumentHandler
;
49 using writerperfect::WPXSvInputStream
;
51 namespace beans
= com::sun::star::beans
;
52 namespace container
= com::sun::star::container
;
53 namespace ucb
= com::sun::star::ucb
;
55 bool KeynoteImportFilter::doImportDocument(librevenge::RVNGInputStream
&rInput
, OdpGenerator
&rGenerator
, utl::MediaDescriptor
&)
57 return libetonyek::EtonyekDocument::parse(&rInput
, &rGenerator
);
60 bool KeynoteImportFilter::doDetectFormat(librevenge::RVNGInputStream
&rInput
, OUString
&rTypeName
)
62 if (libetonyek::EtonyekDocument::isSupported(&rInput
))
64 rTypeName
= "impress_Keynote_Document";
71 // XExtendedFilterDetection
72 OUString SAL_CALL
KeynoteImportFilter::detect(com::sun::star::uno::Sequence
< com::sun::star::beans::PropertyValue
> &Descriptor
)
73 throw(com::sun::star::uno::RuntimeException
, std::exception
)
75 sal_Int32 nLength
= Descriptor
.getLength();
76 sal_Int32 nNewLength
= nLength
+ 2;
77 sal_Int32 nComponentDataLocation
= -1;
78 sal_Int32 nTypeNameLocation
= -1;
79 sal_Int32 nUCBContentLocation
= -1;
80 bool bIsPackage
= false;
81 bool bUCBContentChanged
= false;
82 const beans::PropertyValue
*pValue
= Descriptor
.getConstArray();
83 Reference
< XInputStream
> xInputStream
;
84 Reference
< ucb::XContent
> xContent
;
85 Sequence
< beans::NamedValue
> lComponentDataNV
;
86 Sequence
< beans::PropertyValue
> lComponentDataPV
;
87 bool bComponentDataNV
= true;
89 for (sal_Int32 i
= 0 ; i
< nLength
; i
++)
91 if (pValue
[i
].Name
== "TypeName")
93 nTypeNameLocation
= i
;
96 if (pValue
[i
].Name
== "ComponentData")
98 bComponentDataNV
= pValue
[i
].Value
>>= lComponentDataNV
;
99 if (!bComponentDataNV
)
100 pValue
[i
].Value
>>= lComponentDataPV
;
101 nComponentDataLocation
= i
;
104 else if (pValue
[i
].Name
== "InputStream")
106 pValue
[i
].Value
>>= xInputStream
;
108 else if (pValue
[i
].Name
== "UCBContent")
110 pValue
[i
].Value
>>= xContent
;
111 nUCBContentLocation
= i
;
115 assert(nNewLength
>= nLength
);
117 if (!xInputStream
.is())
120 shared_ptr
< librevenge::RVNGInputStream
> input(new WPXSvInputStream(xInputStream
));
122 /* Apple Keynote documents come in two variants:
123 * * actual files (zip), only produced by Keynote 5 (at least with
125 * * packages (IOW, directories), produced by Keynote 1-4 and again
127 * But since the libetonyek import only works with a stream, we need
128 * to pass it one for the whole package. Here we determine if that
131 * Note: for convenience, we also recognize that the main XML file
132 * from a package was passed and pass the whole package to the
137 ucbhelper::Content
aContent(xContent
, Reference
< ucb::XCommandEnvironment
>(), comphelper::getProcessComponentContext());
140 if (aContent
.isFolder())
142 input
.reset(new writerperfect::DirectoryStream(xContent
));
152 libetonyek::EtonyekDocument::Type type
= libetonyek::EtonyekDocument::TYPE_UNKNOWN
;
153 const libetonyek::EtonyekDocument::Confidence confidence
= libetonyek::EtonyekDocument::isSupported(input
.get(), &type
);
154 if ((libetonyek::EtonyekDocument::CONFIDENCE_NONE
== confidence
) || (libetonyek::EtonyekDocument::TYPE_KEYNOTE
!= type
))
157 if (confidence
== libetonyek::EtonyekDocument::CONFIDENCE_SUPPORTED_PART
)
159 if (bIsPackage
) // we passed a directory stream, but the filter claims it's APXL file?
162 const Reference
< container::XChild
> xChild(xContent
, UNO_QUERY
);
165 const Reference
< ucb::XContent
> xPackageContent(xChild
->getParent(), UNO_QUERY
);
166 if (xPackageContent
.is())
168 input
.reset(new writerperfect::DirectoryStream(xPackageContent
));
169 if (libetonyek::EtonyekDocument::CONFIDENCE_EXCELLENT
== libetonyek::EtonyekDocument::isSupported(input
.get()))
171 xContent
= xPackageContent
;
172 bUCBContentChanged
= true;
177 // The passed stream has been detected as APXL file, but its parent dir is not a valid Keynote
178 // package? Something is wrong here...
185 // we do not need to insert ComponentData if this is not a package
186 if (!bIsPackage
&& (nComponentDataLocation
== -1))
189 if (nNewLength
> nLength
)
190 Descriptor
.realloc(nNewLength
);
192 if (nTypeNameLocation
== -1)
194 assert(nLength
< nNewLength
);
195 nTypeNameLocation
= nLength
++;
196 Descriptor
[nTypeNameLocation
].Name
= "TypeName";
199 if (bIsPackage
&& (nComponentDataLocation
== -1))
201 assert(nLength
< nNewLength
);
202 nComponentDataLocation
= nLength
++;
203 Descriptor
[nComponentDataLocation
].Name
= "ComponentData";
208 if (bComponentDataNV
)
210 const sal_Int32 nCDSize
= lComponentDataNV
.getLength();
211 lComponentDataNV
.realloc(nCDSize
+ 1);
212 beans::NamedValue aValue
;
213 aValue
.Name
= "IsPackage";
214 aValue
.Value
= comphelper::makeBoolAny(true);
215 lComponentDataNV
[nCDSize
] = aValue
;
216 Descriptor
[nComponentDataLocation
].Value
<<= lComponentDataNV
;
220 const sal_Int32 nCDSize
= lComponentDataPV
.getLength();
221 lComponentDataPV
.realloc(nCDSize
+ 1);
222 beans::PropertyValue aProp
;
223 aProp
.Name
= "IsPackage";
224 aProp
.Value
= comphelper::makeBoolAny(true);
226 aProp
.State
= beans::PropertyState_DIRECT_VALUE
;
227 lComponentDataPV
[nCDSize
] = aProp
;
228 Descriptor
[nComponentDataLocation
].Value
<<= lComponentDataPV
;
232 if (bUCBContentChanged
)
233 Descriptor
[nUCBContentLocation
].Value
<<= xContent
;
235 const OUString
sTypeName("impress_AppleKeynote");
236 Descriptor
[nTypeNameLocation
].Value
<<= sTypeName
;
241 OUString
KeynoteImportFilter_getImplementationName()
242 throw (RuntimeException
)
244 return OUString("org.libreoffice.comp.Impress.KeynoteImportFilter");
247 Sequence
< OUString
> SAL_CALL
KeynoteImportFilter_getSupportedServiceNames()
248 throw (RuntimeException
)
250 Sequence
< OUString
> aRet(2);
251 OUString
*pArray
= aRet
.getArray();
252 pArray
[0] = "com.sun.star.document.ImportFilter";
253 pArray
[1] = "com.sun.star.document.ExtendedTypeDetection";
257 Reference
< XInterface
> SAL_CALL
KeynoteImportFilter_createInstance(const Reference
< XComponentContext
> &rContext
)
260 return (cppu::OWeakObject
*) new KeynoteImportFilter(rContext
);
264 OUString SAL_CALL
KeynoteImportFilter::getImplementationName()
265 throw (RuntimeException
, std::exception
)
267 return KeynoteImportFilter_getImplementationName();
270 sal_Bool SAL_CALL
KeynoteImportFilter::supportsService(const OUString
&rServiceName
)
271 throw (RuntimeException
, std::exception
)
273 return cppu::supportsService(this, rServiceName
);
276 Sequence
< OUString
> SAL_CALL
KeynoteImportFilter::getSupportedServiceNames()
277 throw (RuntimeException
, std::exception
)
279 return KeynoteImportFilter_getSupportedServiceNames();
282 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */