Line data Source code
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
4 : *
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/.
8 : */
9 :
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>
20 :
21 : #include <iostream>
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>
27 :
28 : #include <DirectoryStream.hxx>
29 : #include <DocumentHandler.hxx>
30 : #include <WPXSvInputStream.hxx>
31 :
32 : #include <xmloff/attrlist.hxx>
33 :
34 : #include "KeynoteImportFilter.hxx"
35 :
36 : using boost::shared_ptr;
37 :
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;
47 :
48 : using writerperfect::DocumentHandler;
49 : using writerperfect::WPXSvInputStream;
50 :
51 : namespace beans = com::sun::star::beans;
52 : namespace container = com::sun::star::container;
53 : namespace ucb = com::sun::star::ucb;
54 :
55 4 : bool KeynoteImportFilter::doImportDocument(librevenge::RVNGInputStream &rInput, OdpGenerator &rGenerator, utl::MediaDescriptor &)
56 : {
57 4 : return libetonyek::EtonyekDocument::parse(&rInput, &rGenerator);
58 : }
59 :
60 0 : bool KeynoteImportFilter::doDetectFormat(librevenge::RVNGInputStream &rInput, OUString &rTypeName)
61 : {
62 0 : if (libetonyek::EtonyekDocument::isSupported(&rInput))
63 : {
64 0 : rTypeName = "impress_Keynote_Document";
65 0 : return true;
66 : }
67 :
68 0 : return false;
69 : }
70 :
71 : // XExtendedFilterDetection
72 92 : 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)
74 : {
75 92 : sal_Int32 nLength = Descriptor.getLength();
76 92 : sal_Int32 nNewLength = nLength + 2;
77 92 : sal_Int32 nComponentDataLocation = -1;
78 92 : sal_Int32 nTypeNameLocation = -1;
79 92 : sal_Int32 nUCBContentLocation = -1;
80 92 : bool bIsPackage = false;
81 92 : bool bUCBContentChanged = false;
82 92 : const beans::PropertyValue *pValue = Descriptor.getConstArray();
83 92 : Reference < XInputStream > xInputStream;
84 184 : Reference < ucb::XContent > xContent;
85 184 : Sequence < beans::NamedValue > lComponentDataNV;
86 184 : Sequence < beans::PropertyValue > lComponentDataPV;
87 92 : bool bComponentDataNV = true;
88 :
89 799 : for (sal_Int32 i = 0 ; i < nLength; i++)
90 : {
91 707 : if (pValue[i].Name == "TypeName")
92 : {
93 87 : nTypeNameLocation = i;
94 87 : --nNewLength;
95 : }
96 707 : if (pValue[i].Name == "ComponentData")
97 : {
98 0 : bComponentDataNV = pValue[i].Value >>= lComponentDataNV;
99 0 : if (!bComponentDataNV)
100 0 : pValue[i].Value >>= lComponentDataPV;
101 0 : nComponentDataLocation = i;
102 0 : --nNewLength;
103 : }
104 707 : else if (pValue[i].Name == "InputStream")
105 : {
106 92 : pValue[i].Value >>= xInputStream;
107 : }
108 615 : else if (pValue[i].Name == "UCBContent")
109 : {
110 91 : pValue[i].Value >>= xContent;
111 91 : nUCBContentLocation = i;
112 : }
113 : }
114 :
115 : assert(nNewLength >= nLength);
116 :
117 92 : if (!xInputStream.is())
118 0 : return OUString();
119 :
120 184 : shared_ptr< librevenge::RVNGInputStream > input(new WPXSvInputStream(xInputStream));
121 :
122 : /* Apple Keynote documents come in two variants:
123 : * * actual files (zip), only produced by Keynote 5 (at least with
124 : * default settings)
125 : * * packages (IOW, directories), produced by Keynote 1-4 and again
126 : * starting with 6.
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
129 : * is needed.
130 : *
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
133 : * filter instead.
134 : */
135 92 : if (xContent.is())
136 : {
137 91 : ucbhelper::Content aContent(xContent, Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext());
138 : try
139 : {
140 91 : if (aContent.isFolder())
141 : {
142 0 : input.reset(new writerperfect::DirectoryStream(xContent));
143 0 : bIsPackage = true;
144 : }
145 : }
146 0 : catch (...)
147 : {
148 0 : return OUString();
149 91 : }
150 : }
151 :
152 92 : libetonyek::EtonyekDocument::Type type = libetonyek::EtonyekDocument::TYPE_UNKNOWN;
153 92 : const libetonyek::EtonyekDocument::Confidence confidence = libetonyek::EtonyekDocument::isSupported(input.get(), &type);
154 92 : if ((libetonyek::EtonyekDocument::CONFIDENCE_NONE == confidence) || (libetonyek::EtonyekDocument::TYPE_KEYNOTE != type))
155 88 : return OUString();
156 :
157 4 : if (confidence == libetonyek::EtonyekDocument::CONFIDENCE_SUPPORTED_PART)
158 : {
159 0 : if (bIsPackage) // we passed a directory stream, but the filter claims it's APXL file?
160 0 : return OUString();
161 :
162 0 : const Reference < container::XChild > xChild(xContent, UNO_QUERY);
163 0 : if (xChild.is())
164 : {
165 0 : const Reference < ucb::XContent > xPackageContent(xChild->getParent(), UNO_QUERY);
166 0 : if (xPackageContent.is())
167 : {
168 0 : input.reset(new writerperfect::DirectoryStream(xPackageContent));
169 0 : if (libetonyek::EtonyekDocument::CONFIDENCE_EXCELLENT == libetonyek::EtonyekDocument::isSupported(input.get()))
170 : {
171 0 : xContent = xPackageContent;
172 0 : bUCBContentChanged = true;
173 0 : bIsPackage = true;
174 : }
175 : else
176 : {
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...
179 0 : return OUString();
180 : }
181 0 : }
182 0 : }
183 : }
184 :
185 : // we do not need to insert ComponentData if this is not a package
186 4 : if (!bIsPackage && (nComponentDataLocation == -1))
187 4 : --nNewLength;
188 :
189 4 : if (nNewLength > nLength)
190 4 : Descriptor.realloc(nNewLength);
191 :
192 4 : if (nTypeNameLocation == -1)
193 : {
194 : assert(nLength < nNewLength);
195 4 : nTypeNameLocation = nLength++;
196 4 : Descriptor[nTypeNameLocation].Name = "TypeName";
197 : }
198 :
199 4 : if (bIsPackage && (nComponentDataLocation == -1))
200 : {
201 : assert(nLength < nNewLength);
202 0 : nComponentDataLocation = nLength++;
203 0 : Descriptor[nComponentDataLocation].Name = "ComponentData";
204 : }
205 :
206 4 : if (bIsPackage)
207 : {
208 0 : if (bComponentDataNV)
209 : {
210 0 : const sal_Int32 nCDSize = lComponentDataNV.getLength();
211 0 : lComponentDataNV.realloc(nCDSize + 1);
212 0 : beans::NamedValue aValue;
213 0 : aValue.Name = "IsPackage";
214 0 : aValue.Value = comphelper::makeBoolAny(true);
215 0 : lComponentDataNV[nCDSize] = aValue;
216 0 : Descriptor[nComponentDataLocation].Value <<= lComponentDataNV;
217 : }
218 : else
219 : {
220 0 : const sal_Int32 nCDSize = lComponentDataPV.getLength();
221 0 : lComponentDataPV.realloc(nCDSize + 1);
222 0 : beans::PropertyValue aProp;
223 0 : aProp.Name = "IsPackage";
224 0 : aProp.Value = comphelper::makeBoolAny(true);
225 0 : aProp.Handle = -1;
226 0 : aProp.State = beans::PropertyState_DIRECT_VALUE;
227 0 : lComponentDataPV[nCDSize] = aProp;
228 0 : Descriptor[nComponentDataLocation].Value <<= lComponentDataPV;
229 : }
230 : }
231 :
232 4 : if (bUCBContentChanged)
233 0 : Descriptor[nUCBContentLocation].Value <<= xContent;
234 :
235 8 : const OUString sTypeName("impress_AppleKeynote");
236 4 : Descriptor[nTypeNameLocation].Value <<= sTypeName;
237 :
238 96 : return sTypeName;
239 : }
240 :
241 13 : OUString KeynoteImportFilter_getImplementationName()
242 : throw (RuntimeException)
243 : {
244 13 : return OUString("org.libreoffice.comp.Impress.KeynoteImportFilter");
245 : }
246 :
247 7 : Sequence< OUString > SAL_CALL KeynoteImportFilter_getSupportedServiceNames()
248 : throw (RuntimeException)
249 : {
250 7 : Sequence < OUString > aRet(2);
251 7 : OUString *pArray = aRet.getArray();
252 7 : pArray[0] = "com.sun.star.document.ImportFilter";
253 7 : pArray[1] = "com.sun.star.document.ExtendedTypeDetection";
254 7 : return aRet;
255 : }
256 :
257 89 : Reference< XInterface > SAL_CALL KeynoteImportFilter_createInstance(const Reference< XComponentContext > &rContext)
258 : throw(Exception)
259 : {
260 89 : return static_cast<cppu::OWeakObject *>(new KeynoteImportFilter(rContext));
261 : }
262 :
263 : // XServiceInfo
264 1 : OUString SAL_CALL KeynoteImportFilter::getImplementationName()
265 : throw (RuntimeException, std::exception)
266 : {
267 1 : return KeynoteImportFilter_getImplementationName();
268 : }
269 :
270 0 : sal_Bool SAL_CALL KeynoteImportFilter::supportsService(const OUString &rServiceName)
271 : throw (RuntimeException, std::exception)
272 : {
273 0 : return cppu::supportsService(this, rServiceName);
274 : }
275 :
276 1 : Sequence< OUString > SAL_CALL KeynoteImportFilter::getSupportedServiceNames()
277 : throw (RuntimeException, std::exception)
278 : {
279 1 : return KeynoteImportFilter_getSupportedServiceNames();
280 18 : }
281 :
282 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|