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/container/XChild.hpp>
13 : #include <com/sun/star/io/XInputStream.hpp>
14 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
15 : #include <com/sun/star/ucb/XContent.hpp>
16 : #include <com/sun/star/xml/sax/XAttributeList.hpp>
17 : #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
18 : #include <com/sun/star/xml/sax/InputSource.hpp>
19 : #include <com/sun/star/xml/sax/XParser.hpp>
20 : #include <com/sun/star/io/XSeekable.hpp>
21 : #include <com/sun/star/uno/Reference.h>
22 : #include <comphelper/processfactory.hxx>
23 : #include <comphelper/types.hxx>
24 : #include <cppuhelper/supportsservice.hxx>
25 : #include <iostream>
26 : #include <libetonyek/libetonyek.h>
27 : #include <libodfgen/libodfgen.hxx>
28 : #include <osl/diagnose.h>
29 : #include <rtl/tencinfo.h>
30 : #include <ucbhelper/content.hxx>
31 : #include <xmloff/attrlist.hxx>
32 :
33 : #include "common/DirectoryStream.hxx"
34 : #include "common/DocumentHandler.hxx"
35 : #include "common/WPXSvStream.hxx"
36 : #include "KeynoteImportFilter.hxx"
37 :
38 : using boost::shared_ptr;
39 :
40 : using namespace ::com::sun::star::uno;
41 : using com::sun::star::uno::Reference;
42 : using com::sun::star::io::XInputStream;
43 : using com::sun::star::io::XSeekable;
44 : using com::sun::star::uno::Sequence;
45 : using com::sun::star::uno::Any;
46 : using com::sun::star::uno::UNO_QUERY;
47 : using com::sun::star::uno::XInterface;
48 : using com::sun::star::uno::Exception;
49 : using com::sun::star::uno::RuntimeException;
50 : using com::sun::star::beans::PropertyValue;
51 : using com::sun::star::document::XFilter;
52 : using com::sun::star::document::XExtendedFilterDetection;
53 : using com::sun::star::document::XImporter;
54 : using com::sun::star::xml::sax::InputSource;
55 : using com::sun::star::xml::sax::XAttributeList;
56 : using com::sun::star::xml::sax::XDocumentHandler;
57 : using com::sun::star::xml::sax::XParser;
58 :
59 : namespace beans = com::sun::star::beans;
60 : namespace container = com::sun::star::container;
61 : namespace ucb = com::sun::star::ucb;
62 :
63 : namespace
64 : {
65 :
66 : template<class T>
67 0 : sal_Bool lcl_queryIsPackage( const Sequence<T> &lComponentData )
68 : {
69 0 : sal_Bool bIsPackage = sal_False;
70 :
71 0 : const sal_Int32 nLength = lComponentData.getLength();
72 0 : const T *pValue = lComponentData.getConstArray();
73 0 : for ( sal_Int32 i = 0; i < nLength; ++i)
74 : {
75 0 : if ( pValue[i].Name == "IsPackage" )
76 : {
77 0 : pValue[i].Value >>= bIsPackage;
78 0 : break;
79 : }
80 : }
81 :
82 0 : return bIsPackage;
83 : }
84 :
85 0 : sal_Bool lcl_isPackage( const Any &rComponentData )
86 : {
87 0 : Sequence < beans::NamedValue > lComponentDataNV;
88 0 : Sequence < beans::PropertyValue > lComponentDataPV;
89 :
90 0 : if ( rComponentData >>= lComponentDataNV )
91 0 : return lcl_queryIsPackage( lComponentDataNV );
92 0 : else if ( rComponentData >>= lComponentDataPV )
93 0 : return lcl_queryIsPackage( lComponentDataPV );
94 :
95 0 : return false;
96 : }
97 : }
98 :
99 0 : sal_Bool SAL_CALL KeynoteImportFilter::filter( const Sequence< ::com::sun::star::beans::PropertyValue >& aDescriptor )
100 : throw (RuntimeException, std::exception)
101 : {
102 : SAL_INFO("writerperfect", "KeynoteImportFilter::filter");
103 0 : sal_Int32 nLength = aDescriptor.getLength();
104 0 : const PropertyValue *pValue = aDescriptor.getConstArray();
105 0 : Reference < XInputStream > xInputStream;
106 0 : Reference < ucb::XContent > xContent;
107 0 : sal_Bool bIsPackage = sal_False;
108 0 : for ( sal_Int32 i = 0 ; i < nLength; i++)
109 : {
110 0 : if ( pValue[i].Name == "ComponentData" )
111 0 : bIsPackage = lcl_isPackage( pValue[i].Value );
112 0 : else if ( pValue[i].Name == "InputStream" )
113 0 : pValue[i].Value >>= xInputStream;
114 0 : else if ( pValue[i].Name == "UCBContent" )
115 0 : pValue[i].Value >>= xContent;
116 : }
117 0 : if ( !xInputStream.is() )
118 : {
119 : OSL_ASSERT( false );
120 0 : return sal_False;
121 : }
122 :
123 0 : if ( bIsPackage && !xContent.is() )
124 : {
125 : SAL_WARN("writerperfect", "the input claims to be a package, but does not have UCBContent");
126 0 : bIsPackage = false;
127 : }
128 :
129 : // An XML import service: what we push sax messages to..
130 : Reference < XDocumentHandler > xInternalHandler(
131 0 : mxContext->getServiceManager()->createInstanceWithContext(
132 0 : "com.sun.star.comp.Draw.XMLOasisImporter", mxContext),
133 0 : css::uno::UNO_QUERY_THROW);
134 :
135 : // The XImporter sets up an empty target document for XDocumentHandler to write to..
136 0 : Reference < XImporter > xImporter(xInternalHandler, UNO_QUERY);
137 0 : xImporter->setTargetDocument( mxDoc );
138 :
139 : // OO Graphics Handler: abstract class to handle document SAX messages, concrete implementation here
140 : // writes to in-memory target doc
141 0 : DocumentHandler xHandler(xInternalHandler);
142 :
143 0 : shared_ptr< WPXInputStream > input;
144 0 : if ( bIsPackage )
145 0 : input.reset( new writerperfect::DirectoryStream( xContent ) );
146 : else
147 0 : input.reset( new WPXSvInputStream( xInputStream ) );
148 :
149 0 : OdpGenerator exporter(&xHandler, ODF_FLAT_XML);
150 0 : bool tmpParseResult = libetonyek::KEYDocument::parse(input.get(), &exporter);
151 0 : return tmpParseResult;
152 : }
153 :
154 0 : void SAL_CALL KeynoteImportFilter::cancel( )
155 : throw (RuntimeException, std::exception)
156 : {
157 : SAL_INFO("writerperfect", "KeynoteImportFilter::cancel");
158 0 : }
159 :
160 : // XImporter
161 0 : void SAL_CALL KeynoteImportFilter::setTargetDocument( const Reference< ::com::sun::star::lang::XComponent >& xDoc )
162 : throw (::com::sun::star::lang::IllegalArgumentException, RuntimeException, std::exception)
163 : {
164 : SAL_INFO("writerperfect", "KeynoteImportFilter::setTargetDocument");
165 0 : mxDoc = xDoc;
166 0 : }
167 :
168 : // XExtendedFilterDetection
169 0 : OUString SAL_CALL KeynoteImportFilter::detect( com::sun::star::uno::Sequence< PropertyValue >& Descriptor )
170 : throw( com::sun::star::uno::RuntimeException, std::exception )
171 : {
172 : SAL_INFO("writerperfect", "KeynoteImportFilter::detect");
173 :
174 0 : sal_Int32 nLength = Descriptor.getLength();
175 0 : sal_Int32 nNewLength = nLength + 2;
176 0 : sal_Int32 nComponentDataLocation = -1;
177 0 : sal_Int32 nTypeNameLocation = -1;
178 0 : sal_Int32 nUCBContentLocation = -1;
179 0 : bool bIsPackage = false;
180 0 : bool bUCBContentChanged = false;
181 0 : const PropertyValue *pValue = Descriptor.getConstArray();
182 0 : Reference < XInputStream > xInputStream;
183 0 : Reference < ucb::XContent > xContent;
184 0 : Sequence < beans::NamedValue > lComponentDataNV;
185 0 : Sequence < beans::PropertyValue > lComponentDataPV;
186 0 : bool bComponentDataNV = true;
187 :
188 0 : for ( sal_Int32 i = 0 ; i < nLength; i++)
189 : {
190 0 : if ( pValue[i].Name == "TypeName" )
191 : {
192 0 : nTypeNameLocation = i;
193 0 : --nNewLength;
194 : }
195 0 : if ( pValue[i].Name == "ComponentData" )
196 : {
197 0 : bComponentDataNV = pValue[i].Value >>= lComponentDataNV;
198 0 : if (!bComponentDataNV)
199 0 : pValue[i].Value >>= lComponentDataPV;
200 0 : nComponentDataLocation = i;
201 0 : --nNewLength;
202 : }
203 0 : else if ( pValue[i].Name == "InputStream" )
204 : {
205 0 : pValue[i].Value >>= xInputStream;
206 : }
207 0 : else if ( pValue[i].Name == "UCBContent" )
208 : {
209 0 : pValue[i].Value >>= xContent;
210 0 : nUCBContentLocation = i;
211 : }
212 : }
213 :
214 : assert(nNewLength >= nLength);
215 :
216 0 : if (!xInputStream.is())
217 0 : return OUString();
218 :
219 0 : shared_ptr< WPXInputStream > input( new WPXSvInputStream( xInputStream ) );
220 :
221 : /* Apple Keynote documents come in two variants:
222 : * * actual files (zip), only produced by Keynote 5 (at least with
223 : * default settings)
224 : * * packages (IOW, directories), produced by Keynote 1-4 and again
225 : * starting with 6.
226 : * But since the libetonyek import only works with a stream, we need
227 : * to pass it one for the whole package. Here we determine if that
228 : * is needed.
229 : *
230 : * Note: for convenience, we also recognize that the main XML file
231 : * from a package was passed and pass the whole package to the
232 : * filter instead.
233 : */
234 0 : if ( xContent.is() )
235 : {
236 0 : ucbhelper::Content aContent( xContent, Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
237 : try
238 : {
239 0 : if ( aContent.isFolder() )
240 : {
241 0 : input.reset( new writerperfect::DirectoryStream( xContent ) );
242 0 : bIsPackage = true;
243 : }
244 : }
245 0 : catch (...)
246 : {
247 0 : return OUString();
248 : }
249 :
250 0 : libetonyek::KEYDocumentType type = libetonyek::KEY_DOCUMENT_TYPE_UNKNOWN;
251 0 : if ( !libetonyek::KEYDocument::isSupported( input.get(), &type ) )
252 0 : return OUString();
253 :
254 0 : if ( type == libetonyek::KEY_DOCUMENT_TYPE_APXL_FILE )
255 : {
256 : assert( !bIsPackage );
257 :
258 0 : const Reference < container::XChild > xChild( xContent, UNO_QUERY );
259 0 : if ( xChild.is() )
260 : {
261 0 : const Reference < ucb::XContent > xPackageContent( xChild->getParent(), UNO_QUERY );
262 0 : if ( xPackageContent.is() )
263 : {
264 0 : input.reset( new writerperfect::DirectoryStream( xPackageContent ) );
265 0 : if ( libetonyek::KEYDocument::isSupported( input.get() ) )
266 : {
267 0 : xContent = xPackageContent;
268 0 : bUCBContentChanged = true;
269 0 : bIsPackage = true;
270 : }
271 0 : }
272 0 : }
273 0 : }
274 : }
275 :
276 : // we do not need to insert ComponentData if this is not a package
277 0 : if ( !bIsPackage && ( nComponentDataLocation == -1 ) )
278 0 : --nNewLength;
279 :
280 0 : if ( nNewLength > nLength )
281 0 : Descriptor.realloc( nNewLength );
282 :
283 0 : if ( nTypeNameLocation == -1 )
284 : {
285 : assert( nLength < nNewLength );
286 0 : nTypeNameLocation = nLength++;
287 0 : Descriptor[nTypeNameLocation].Name = "TypeName";
288 : }
289 :
290 0 : if ( bIsPackage && ( nComponentDataLocation == -1 ) )
291 : {
292 : assert( nLength < nNewLength );
293 0 : nComponentDataLocation = nLength++;
294 0 : Descriptor[nComponentDataLocation].Name = "ComponentData";
295 : }
296 :
297 0 : if ( bIsPackage )
298 : {
299 0 : if (bComponentDataNV)
300 : {
301 0 : const sal_Int32 nCDSize = lComponentDataNV.getLength();
302 0 : lComponentDataNV.realloc( nCDSize + 1 );
303 0 : beans::NamedValue aValue;
304 0 : aValue.Name = "IsPackage";
305 0 : aValue.Value = comphelper::makeBoolAny(true);
306 0 : lComponentDataNV[nCDSize] = aValue;
307 0 : Descriptor[nComponentDataLocation].Value <<= lComponentDataNV;
308 : }
309 : else
310 : {
311 0 : const sal_Int32 nCDSize = lComponentDataPV.getLength();
312 0 : lComponentDataPV.realloc( nCDSize + 1 );
313 0 : beans::PropertyValue aProp;
314 0 : aProp.Name = "IsPackage";
315 0 : aProp.Value = comphelper::makeBoolAny(true);
316 0 : aProp.Handle = -1;
317 0 : aProp.State = beans::PropertyState_DIRECT_VALUE;
318 0 : lComponentDataPV[nCDSize] = aProp;
319 0 : Descriptor[nComponentDataLocation].Value <<= lComponentDataPV;
320 : }
321 : }
322 :
323 0 : if ( bUCBContentChanged )
324 0 : Descriptor[nUCBContentLocation].Value <<= xContent;
325 :
326 0 : const OUString sTypeName("impress_AppleKeynote");
327 0 : Descriptor[nTypeNameLocation].Value <<= sTypeName;
328 :
329 0 : return sTypeName;
330 : }
331 :
332 : // XInitialization
333 0 : void SAL_CALL KeynoteImportFilter::initialize( const Sequence< Any >& aArguments )
334 : throw (Exception, RuntimeException, std::exception)
335 : {
336 : SAL_INFO("writerperfect", "KeynoteImportFilter::initialize");
337 0 : Sequence < PropertyValue > aAnySeq;
338 0 : sal_Int32 nLength = aArguments.getLength();
339 0 : if ( nLength && ( aArguments[0] >>= aAnySeq ) )
340 : {
341 0 : const PropertyValue *pValue = aAnySeq.getConstArray();
342 0 : nLength = aAnySeq.getLength();
343 0 : for ( sal_Int32 i = 0 ; i < nLength; i++)
344 : {
345 0 : if ( pValue[i].Name == "Type" )
346 : {
347 0 : pValue[i].Value >>= msFilterName;
348 0 : break;
349 : }
350 : }
351 0 : }
352 0 : }
353 :
354 0 : OUString KeynoteImportFilter_getImplementationName ()
355 : throw (RuntimeException)
356 : {
357 : SAL_INFO("writerperfect", "KeynoteImportFilter_getImplementationName");
358 0 : return OUString ( "org.libreoffice.comp.Impress.KeynoteImportFilter" );
359 : }
360 :
361 : #define SERVICE_NAME1 "com.sun.star.document.ImportFilter"
362 : #define SERVICE_NAME2 "com.sun.star.document.ExtendedTypeDetection"
363 :
364 0 : Sequence< OUString > SAL_CALL KeynoteImportFilter_getSupportedServiceNames( )
365 : throw (RuntimeException)
366 : {
367 : SAL_INFO("writerperfect", "KeynoteImportFilter_getSupportedServiceNames");
368 0 : Sequence < OUString > aRet(2);
369 0 : OUString *pArray = aRet.getArray();
370 0 : pArray[0] = OUString ( SERVICE_NAME1 );
371 0 : pArray[1] = OUString ( SERVICE_NAME2 );
372 0 : return aRet;
373 : }
374 :
375 : #undef SERVICE_NAME2
376 : #undef SERVICE_NAME1
377 :
378 0 : Reference< XInterface > SAL_CALL KeynoteImportFilter_createInstance( const Reference< XComponentContext > & rContext)
379 : throw( Exception )
380 : {
381 : SAL_INFO("writerperfect", "KeynoteImportFilter_createInstance");
382 0 : return (cppu::OWeakObject *) new KeynoteImportFilter( rContext );
383 : }
384 :
385 : // XServiceInfo
386 0 : OUString SAL_CALL KeynoteImportFilter::getImplementationName( )
387 : throw (RuntimeException, std::exception)
388 : {
389 : SAL_INFO("writerperfect", "KeynoteImportFilter::getImplementationName");
390 0 : return KeynoteImportFilter_getImplementationName();
391 : }
392 :
393 0 : sal_Bool SAL_CALL KeynoteImportFilter::supportsService( const OUString &rServiceName )
394 : throw (RuntimeException, std::exception)
395 : {
396 : SAL_INFO("writerperfect", "KeynoteImportFilter::supportsService");
397 0 : return cppu::supportsService(this, rServiceName);
398 : }
399 :
400 0 : Sequence< OUString > SAL_CALL KeynoteImportFilter::getSupportedServiceNames( )
401 : throw (RuntimeException, std::exception)
402 : {
403 : SAL_INFO("writerperfect", "KeynoteImportFilter::getSupportedServiceNames");
404 0 : return KeynoteImportFilter_getSupportedServiceNames();
405 0 : }
406 :
407 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|