Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
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 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "pdfiadaptor.hxx"
22 : #include "filterdet.hxx"
23 : #include "saxemitter.hxx"
24 : #include "odfemitter.hxx"
25 : #include "inc/wrapper.hxx"
26 : #include "inc/contentsink.hxx"
27 : #include "tree/pdfiprocessor.hxx"
28 :
29 : #include <osl/file.h>
30 : #include <osl/thread.h>
31 : #include <osl/diagnose.h>
32 : #include <cppuhelper/factory.hxx>
33 : #include <cppuhelper/implementationentry.hxx>
34 : #include <com/sun/star/lang/XMultiComponentFactory.hpp>
35 : #include <com/sun/star/uno/RuntimeException.hpp>
36 : #include <com/sun/star/io/XInputStream.hpp>
37 : #include <com/sun/star/frame/XLoadable.hpp>
38 : #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
39 : #include <com/sun/star/io/XSeekable.hpp>
40 :
41 :
42 : #include <boost/shared_ptr.hpp>
43 :
44 : using namespace com::sun::star;
45 :
46 :
47 : namespace pdfi
48 : {
49 :
50 0 : PDFIHybridAdaptor::PDFIHybridAdaptor( const uno::Reference< uno::XComponentContext >& xContext ) :
51 : PDFIHybridAdaptorBase( m_aMutex ),
52 : m_xContext( xContext ),
53 0 : m_xModel()
54 : {
55 0 : }
56 :
57 : // XFilter
58 0 : sal_Bool SAL_CALL PDFIHybridAdaptor::filter( const uno::Sequence< beans::PropertyValue >& rFilterData ) throw( uno::RuntimeException )
59 : {
60 0 : sal_Bool bRet = sal_False;
61 0 : if( m_xModel.is() )
62 : {
63 0 : uno::Reference< io::XStream > xSubStream;
64 0 : rtl::OUString aPwd;
65 0 : const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
66 0 : sal_Int32 nAttribs = rFilterData.getLength();
67 0 : sal_Int32 nPwPos = -1;
68 0 : for( sal_Int32 i = 0; i < nAttribs; i++ )
69 : {
70 : #if OSL_DEBUG_LEVEL > 1
71 : rtl::OUString aVal( RTL_CONSTASCII_USTRINGPARAM( "<no string>" ) );
72 : pAttribs[i].Value >>= aVal;
73 : OSL_TRACE( "filter: Attrib: %s = %s\n",
74 : rtl::OUStringToOString( pAttribs[i].Name, RTL_TEXTENCODING_UTF8 ).getStr(),
75 : rtl::OUStringToOString( aVal, RTL_TEXTENCODING_UTF8 ).getStr() );
76 : #endif
77 0 : if ( pAttribs[i].Name == "EmbeddedSubstream" )
78 0 : pAttribs[i].Value >>= xSubStream;
79 0 : else if ( pAttribs[i].Name == "Password" )
80 : {
81 0 : nPwPos = i;
82 0 : pAttribs[i].Value >>= aPwd;
83 : }
84 : }
85 0 : bool bAddPwdProp = false;
86 0 : if( ! xSubStream.is() )
87 : {
88 0 : uno::Reference< io::XInputStream > xInput;
89 0 : for( sal_Int32 i = 0; i < nAttribs; i++ )
90 : {
91 0 : if ( pAttribs[i].Name == "InputStream" )
92 : {
93 0 : pAttribs[i].Value >>= xInput;
94 0 : break;
95 : }
96 : }
97 0 : if( xInput.is() )
98 : {
99 : // TODO(P2): extracting hybrid substream twice - once during detection, second time here
100 0 : uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY );
101 0 : if( xSeek.is() )
102 0 : xSeek->seek( 0 );
103 0 : oslFileHandle aFile = NULL;
104 0 : sal_uInt64 nWritten = 0;
105 0 : rtl::OUString aURL;
106 0 : if( osl_createTempFile( NULL, &aFile, &aURL.pData ) == osl_File_E_None )
107 : {
108 : OSL_TRACE( "created temp file %s", rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() );
109 0 : const sal_Int32 nBufSize = 4096;
110 0 : uno::Sequence<sal_Int8> aBuf(nBufSize);
111 : // copy the bytes
112 : sal_Int32 nBytes;
113 0 : do
114 : {
115 0 : nBytes = xInput->readBytes( aBuf, nBufSize );
116 0 : if( nBytes > 0 )
117 : {
118 0 : osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
119 0 : if( static_cast<sal_Int32>(nWritten) != nBytes )
120 : {
121 0 : xInput.clear();
122 0 : break;
123 : }
124 : }
125 : } while( nBytes == nBufSize );
126 0 : osl_closeFile( aFile );
127 0 : if( xInput.is() )
128 : {
129 0 : rtl::OUString aEmbedMimetype;
130 0 : rtl::OUString aOrgPwd( aPwd );
131 0 : xSubStream = getAdditionalStream( aURL, aEmbedMimetype, aPwd, m_xContext, rFilterData, true );
132 0 : if( aOrgPwd != aPwd )
133 0 : bAddPwdProp = true;
134 : }
135 0 : osl_removeFile( aURL.pData );
136 : }
137 : else
138 0 : xSubStream.clear();
139 0 : }
140 : }
141 0 : if( xSubStream.is() )
142 : {
143 0 : uno::Sequence< uno::Any > aArgs( 2 );
144 0 : aArgs[0] <<= m_xModel;
145 0 : aArgs[1] <<= xSubStream;
146 :
147 : OSL_TRACE( "try to instantiate subfilter" );
148 0 : uno::Reference< document::XFilter > xSubFilter;
149 : try {
150 : xSubFilter = uno::Reference<document::XFilter>(
151 0 : m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
152 : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.OwnSubFilter" ) ),
153 : aArgs,
154 0 : m_xContext ),
155 0 : uno::UNO_QUERY );
156 : }
157 0 : catch(const uno::Exception& e)
158 : {
159 : (void)e;
160 : OSL_TRACE( "subfilter exception: %s\n",
161 : OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
162 : }
163 :
164 : OSL_TRACE( "subfilter: %p", xSubFilter.get() );
165 0 : if( xSubFilter.is() )
166 : {
167 0 : if( bAddPwdProp )
168 : {
169 0 : uno::Sequence<beans::PropertyValue> aFilterData( rFilterData );
170 0 : if( nPwPos == -1 )
171 : {
172 0 : nPwPos = aFilterData.getLength();
173 0 : aFilterData.realloc( nPwPos+1 );
174 0 : aFilterData[nPwPos].Name = rtl::OUString(
175 0 : RTL_CONSTASCII_USTRINGPARAM( "Password" ) );
176 : }
177 0 : aFilterData[nPwPos].Value <<= aPwd;
178 0 : bRet = xSubFilter->filter( aFilterData );
179 : }
180 : else
181 0 : bRet = xSubFilter->filter( rFilterData );
182 0 : }
183 0 : }
184 : #if OSL_DEBUG_LEVEL > 1
185 : else
186 : OSL_TRACE( "PDFIAdaptor::filter: no embedded substream set" );
187 : #endif
188 : }
189 : #if OSL_DEBUG_LEVEL > 1
190 : else
191 : OSL_TRACE( "PDFIAdaptor::filter: no model set" );
192 : #endif
193 :
194 0 : return bRet;
195 : }
196 :
197 0 : void SAL_CALL PDFIHybridAdaptor::cancel() throw()
198 : {
199 0 : }
200 :
201 : //XImporter
202 0 : void SAL_CALL PDFIHybridAdaptor::setTargetDocument( const uno::Reference< lang::XComponent >& xDocument ) throw( lang::IllegalArgumentException )
203 : {
204 : OSL_TRACE( "PDFIAdaptor::setTargetDocument" );
205 0 : m_xModel = uno::Reference< frame::XModel >( xDocument, uno::UNO_QUERY );
206 0 : if( xDocument.is() && ! m_xModel.is() )
207 0 : throw lang::IllegalArgumentException();
208 0 : }
209 :
210 : //---------------------------------------------------------------------------------------
211 :
212 2 : PDFIRawAdaptor::PDFIRawAdaptor( const uno::Reference< uno::XComponentContext >& xContext ) :
213 : PDFIAdaptorBase( m_aMutex ),
214 : m_xContext( xContext ),
215 : m_xModel(),
216 : m_pVisitorFactory(),
217 2 : m_bEnableToplevelText(false)
218 : {
219 2 : }
220 :
221 2 : void PDFIRawAdaptor::setTreeVisitorFactory(const TreeVisitorFactorySharedPtr& rVisitorFactory)
222 : {
223 2 : m_pVisitorFactory = rVisitorFactory;
224 2 : }
225 :
226 2 : bool PDFIRawAdaptor::parse( const uno::Reference<io::XInputStream>& xInput,
227 : const uno::Reference<task::XInteractionHandler>& xIHdl,
228 : const rtl::OUString& rPwd,
229 : const uno::Reference<task::XStatusIndicator>& xStatus,
230 : const XmlEmitterSharedPtr& rEmitter,
231 : const rtl::OUString& rURL )
232 : {
233 : // container for metaformat
234 : boost::shared_ptr<PDFIProcessor> pSink(
235 2 : new PDFIProcessor(xStatus, m_xContext));
236 :
237 : // TEMP! TEMP!
238 2 : if( m_bEnableToplevelText )
239 0 : pSink->enableToplevelText();
240 :
241 2 : bool bSuccess=false;
242 :
243 2 : if( xInput.is() )
244 0 : bSuccess = xpdf_ImportFromStream( xInput, pSink, xIHdl, rPwd, m_xContext );
245 : else
246 2 : bSuccess = xpdf_ImportFromFile( rURL, pSink, xIHdl, rPwd, m_xContext );
247 :
248 2 : if( bSuccess )
249 2 : pSink->emit(*rEmitter,*m_pVisitorFactory);
250 :
251 2 : return bSuccess;
252 : }
253 :
254 2 : bool PDFIRawAdaptor::odfConvert( const rtl::OUString& rURL,
255 : const uno::Reference<io::XOutputStream>& xOutput,
256 : const uno::Reference<task::XStatusIndicator>& xStatus )
257 : {
258 2 : XmlEmitterSharedPtr pEmitter = createOdfEmitter(xOutput);
259 : const bool bSuccess = parse(uno::Reference<io::XInputStream>(),
260 : uno::Reference<task::XInteractionHandler>(),
261 : rtl::OUString(),
262 2 : xStatus,pEmitter,rURL);
263 :
264 : // tell input stream that it is no longer needed
265 2 : xOutput->closeOutput();
266 :
267 2 : return bSuccess;
268 : }
269 :
270 : // XImportFilter
271 0 : sal_Bool SAL_CALL PDFIRawAdaptor::importer( const uno::Sequence< beans::PropertyValue >& rSourceData,
272 : const uno::Reference< xml::sax::XDocumentHandler >& rHdl,
273 : const uno::Sequence< rtl::OUString >& /*rUserData*/ ) throw( uno::RuntimeException )
274 : {
275 : // get the InputStream carrying the PDF content
276 0 : uno::Reference< io::XInputStream > xInput;
277 0 : uno::Reference< task::XStatusIndicator > xStatus;
278 0 : uno::Reference< task::XInteractionHandler > xInteractionHandler;
279 0 : rtl::OUString aURL;
280 0 : rtl::OUString aPwd;
281 0 : const beans::PropertyValue* pAttribs = rSourceData.getConstArray();
282 0 : sal_Int32 nAttribs = rSourceData.getLength();
283 0 : for( sal_Int32 i = 0; i < nAttribs; i++, pAttribs++ )
284 : {
285 : OSL_TRACE("importer Attrib: %s", OUStringToOString( pAttribs->Name, RTL_TEXTENCODING_UTF8 ).getStr() );
286 0 : if ( pAttribs->Name == "InputStream" )
287 0 : pAttribs->Value >>= xInput;
288 0 : else if ( pAttribs->Name == "URL" )
289 0 : pAttribs->Value >>= aURL;
290 0 : else if ( pAttribs->Name == "StatusIndicator" )
291 0 : pAttribs->Value >>= xStatus;
292 0 : else if ( pAttribs->Name == "InteractionHandler" )
293 0 : pAttribs->Value >>= xInteractionHandler;
294 0 : else if ( pAttribs->Name == "Password" )
295 0 : pAttribs->Value >>= aPwd;
296 : }
297 0 : if( !xInput.is() )
298 0 : return sal_False;
299 :
300 0 : XmlEmitterSharedPtr pEmitter = createSaxEmitter(rHdl);
301 0 : const bool bSuccess = parse(xInput,xInteractionHandler, aPwd, xStatus,pEmitter,aURL);
302 :
303 : // tell input stream that it is no longer needed
304 0 : xInput->closeInput();
305 0 : xInput.clear();
306 :
307 0 : return bSuccess;
308 : }
309 :
310 : //XImporter
311 0 : void SAL_CALL PDFIRawAdaptor::setTargetDocument( const uno::Reference< lang::XComponent >& xDocument ) throw( lang::IllegalArgumentException )
312 : {
313 : OSL_TRACE( "PDFIAdaptor::setTargetDocument" );
314 0 : m_xModel = uno::Reference< frame::XModel >( xDocument, uno::UNO_QUERY );
315 0 : if( xDocument.is() && ! m_xModel.is() )
316 0 : throw lang::IllegalArgumentException();
317 0 : }
318 :
319 : }
320 :
321 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|