Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * Version: MPL 1.1 / GPLv3+ / LGPLv3+
4 : : *
5 : : * The contents of this file are subject to the Mozilla Public License Version
6 : : * 1.1 (the "License"); you may not use this file except in compliance with
7 : : * the License or as specified alternatively below. You may obtain a copy of
8 : : * the License at http://www.mozilla.org/MPL/
9 : : *
10 : : * Software distributed under the License is distributed on an "AS IS" basis,
11 : : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : : * for the specific language governing rights and limitations under the
13 : : * License.
14 : : *
15 : : * The Initial Developer of the Original Code is
16 : : * Fong Lin <pflin@novell.com>
17 : : * Portions created by the Initial Developer are Copyright (C) 2010 the
18 : : * Initial Developer. All Rights Reserved.
19 : : *
20 : : * Contributor(s):
21 : : * Fong Lin <pflin@novell.com>
22 : : * Noel Power <noel.power@novell.com>
23 : : *
24 : : * For minor contributions see the git repository.
25 : : *
26 : : * Alternatively, the contents of this file may be used under the terms of
27 : : * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
28 : : * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
29 : : * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
30 : : * instead of those above.
31 : : */
32 : : #include <osl/diagnose.h>
33 : : #include <sal/macros.h>
34 : : #include <rtl/tencinfo.h>
35 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
36 : : #include <com/sun/star/io/XInputStream.hpp>
37 : : #include <com/sun/star/xml/sax/XAttributeList.hpp>
38 : : #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
39 : : #include <com/sun/star/xml/sax/XParser.hpp>
40 : : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
41 : : #include <com/sun/star/io/XInputStream.hpp>
42 : : #include <com/sun/star/uno/Reference.hxx>
43 : : #include <xmloff/attrlist.hxx>
44 : :
45 : : #include <ucbhelper/content.hxx>
46 : :
47 : : #include <tools/stream.hxx>
48 : :
49 : : #include "LotusWordProImportFilter.hxx"
50 : :
51 : : #include <vector>
52 : :
53 : : #include "lwpfilter.hxx"
54 : :
55 : : using namespace ::rtl;
56 : : using namespace com::sun::star;
57 : : using rtl::OString;
58 : : using rtl::OUStringBuffer;
59 : : using rtl::OUString;
60 : : using com::sun::star::uno::Sequence;
61 : : using com::sun::star::lang::XComponent;
62 : : using com::sun::star::uno::Any;
63 : : using com::sun::star::uno::UNO_QUERY;
64 : : using com::sun::star::uno::XInterface;
65 : : using com::sun::star::uno::Exception;
66 : : using com::sun::star::uno::RuntimeException;
67 : : using com::sun::star::io::XInputStream;
68 : : using com::sun::star::lang::XMultiServiceFactory;
69 : : using com::sun::star::beans::PropertyValue;
70 : : using com::sun::star::document::XFilter;
71 : : using com::sun::star::document::XExtendedFilterDetection;
72 : : using com::sun::star::ucb::XCommandEnvironment;
73 : :
74 : : using com::sun::star::document::XImporter;
75 : : using com::sun::star::xml::sax::XAttributeList;
76 : : using com::sun::star::xml::sax::XDocumentHandler;
77 : : using com::sun::star::xml::sax::XParser;
78 : :
79 : : // W o r d P r o
80 : : static const sal_Int8 header[] = { 0x57, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f };
81 : :
82 : : const sal_Int32 MAXCHARS = 65534;
83 : :
84 : : // Simple xml importer, currently the importer is very very simple
85 : : // it only extracts pure text from the wordpro file. Absolutely no formating
86 : : // information is currently imported.
87 : : // To reflect the current state of this importer the sax events sent
88 : : // to the document handler are also the simplest possible. In addition to
89 : : // the the basic attributes set up for the 'office:document' element
90 : : // all the imported text is inserted into 'text:p' elements.
91 : : // The parser extracts the pure text and creates simple a simple 'text:p'
92 : : // element to contain that text. In the event of the text exceeding
93 : : // MAXCHARS new 'text:p' elements are created as needed
94 : : class SimpleXMLImporter
95 : : {
96 : : private:
97 : :
98 : : uno::Reference< XDocumentHandler > m_xDocHandler;
99 : : std::vector< OUString > m_vStringChunks;
100 : : SvStream& m_InputStream;
101 : :
102 : : bool CheckValidData( sal_Int8 nChar ) const
103 : : {
104 : : if( ( nChar >= 0x20 && nChar <= 0x7E ) && ( nChar != 0X40 ) )
105 : : return true;
106 : : return false;
107 : : }
108 : :
109 : : void addAttribute( SvXMLAttributeList* pAttrList, const char* key, const char* val )
110 : : {
111 : : pAttrList->AddAttribute( OUString::createFromAscii( key ), OUString::createFromAscii( val ) );
112 : : }
113 : :
114 : : void writeTextChunk( const OUString& sChunk )
115 : : {
116 : : SvXMLAttributeList *pAttrList = new SvXMLAttributeList();
117 : : uno::Reference < XAttributeList > xAttrList(pAttrList);
118 : :
119 : : pAttrList->AddAttribute( OUString(RTL_CONSTASCII_USTRINGPARAM("text:style-name")), OUString(RTL_CONSTASCII_USTRINGPARAM("Standard")));
120 : :
121 : : m_xDocHandler->startElement( OUString(RTL_CONSTASCII_USTRINGPARAM("text:p")), xAttrList );
122 : : m_xDocHandler->characters( sChunk );
123 : : m_xDocHandler->endElement( OUString(RTL_CONSTASCII_USTRINGPARAM("text:p") ) );
124 : : }
125 : :
126 : : void writeDocContentPreamble()
127 : : {
128 : : SvXMLAttributeList *pDocContentPropList = new SvXMLAttributeList();
129 : : uno::Reference < XAttributeList > xDocContentList(pDocContentPropList);
130 : : addAttribute( pDocContentPropList, "xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0" );
131 : : addAttribute( pDocContentPropList, "xmlns:style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0");
132 : : addAttribute( pDocContentPropList, "xmlns:text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0" );
133 : : addAttribute( pDocContentPropList, "xmlns:table", "urn:oasis:names:tc:opendocument:xmlns:table:1.0" );
134 : : addAttribute( pDocContentPropList, "xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" );
135 : : addAttribute( pDocContentPropList, "xmlns:fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" );
136 : : addAttribute( pDocContentPropList, "xmlns:xlink", "http://www.w3.org/1999/xlink" );
137 : : addAttribute( pDocContentPropList, "xmlns:dc", "http://purl.org/dc/elements/1.1/" );
138 : : addAttribute( pDocContentPropList, "xmlns:meta", "urn:oasis:names:tc:opendocument:xmlns:meta:1.0" );
139 : : addAttribute( pDocContentPropList, "xmlns:number", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" );
140 : : addAttribute( pDocContentPropList, "xmlns:svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" );
141 : : addAttribute( pDocContentPropList, "xmlns:chart", "urn:oasis:names:tc:opendocument:xmlns:chart:1.0" );
142 : : addAttribute( pDocContentPropList, "xmlns:dr3d", "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" );
143 : : addAttribute( pDocContentPropList, "xmlns:math", "http://www.w3.org/1998/Math/MathML" );
144 : : addAttribute( pDocContentPropList, "xmlns:form", "urn:oasis:names:tc:opendocument:xmlns:form:1.0" );
145 : : addAttribute( pDocContentPropList, "xmlns:script", "urn:oasis:names:tc:opendocument:xmlns:script:1.0" );
146 : : addAttribute( pDocContentPropList, "xmlns:ooo", "http://openoffice.org/2004/office" );
147 : : addAttribute( pDocContentPropList, "xmlns:ooow", "http://openoffice.org/2004/writer" );
148 : : addAttribute( pDocContentPropList, "xmlns:oooc", "http://openoffice.org/2004/calc" );
149 : : addAttribute( pDocContentPropList, "xmlns:dom", "http://www.w3.org/2001/xml-events" );
150 : : addAttribute( pDocContentPropList, "xmlns:xforms", "http://www.w3.org/2002/xforms" );
151 : : addAttribute( pDocContentPropList, "xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
152 : : addAttribute( pDocContentPropList, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
153 : : addAttribute( pDocContentPropList, "office:version", "1.0");
154 : : m_xDocHandler->startElement(OUString(RTL_CONSTASCII_USTRINGPARAM("office:document-content" ) ), xDocContentList );
155 : : }
156 : :
157 : : void parseDoc()
158 : : {
159 : : sal_uInt8 nDelim, nDummy, nLen, nData;
160 : : sal_uInt16 nOpcode;
161 : : OUStringBuffer sBuf( MAXCHARS );
162 : : sal_Int32 nChars = 0;
163 : :
164 : : while( !m_InputStream.IsEof())
165 : : {
166 : : m_InputStream >> nDelim;
167 : : if( nDelim == 0x40 )
168 : : {
169 : : m_InputStream >> nDummy >> nOpcode;
170 : : switch( nOpcode )
171 : : {
172 : : case 0xC00B: // Dictionary Word
173 : : m_InputStream >> nLen >> nDummy;
174 : : while( nLen > 0 && !m_InputStream.IsEof() )
175 : : {
176 : : sal_uInt8 nChar;
177 : : m_InputStream >> nChar;
178 : : if( CheckValidData( nChar ) )
179 : : {
180 : : sBuf.appendAscii( (sal_Char*)(&nChar),1 );
181 : : if ( ++nChars >= MAXCHARS )
182 : : {
183 : : m_vStringChunks.push_back( sBuf.makeStringAndClear() );
184 : : nChars = 0;
185 : : }
186 : : }
187 : : nLen--;
188 : : }
189 : : break;
190 : :
191 : : case 0x0242: // Non Dictionary word
192 : : m_InputStream >> nData;
193 : : if( nData == 0x02 )
194 : : {
195 : : m_InputStream >> nLen >> nDummy;
196 : : while( nLen > 0 && !m_InputStream.IsEof() )
197 : : {
198 : : m_InputStream >> nData;
199 : : if( CheckValidData( nData ) )
200 : : {
201 : : sBuf.appendAscii( (sal_Char*)(&nData),1 );
202 : : if ( ++nChars >= MAXCHARS )
203 : : {
204 : : m_vStringChunks.push_back( sBuf.makeStringAndClear() );
205 : : nChars = 0;
206 : : }
207 : : }
208 : : nLen--;
209 : : }
210 : : }
211 : : break;
212 : : }
213 : : }
214 : : }
215 : : if ( nChars )
216 : : m_vStringChunks.push_back( sBuf.makeStringAndClear() );
217 : : }
218 : :
219 : : void writeXML()
220 : : {
221 : : if ( !m_vStringChunks.empty() )
222 : : {
223 : : m_xDocHandler->startDocument();
224 : : SvXMLAttributeList *pAttrList = new SvXMLAttributeList();
225 : : writeDocContentPreamble(); // writes "office:document-content" elem
226 : : uno::Reference < XAttributeList > xAttrList(pAttrList);
227 : :
228 : : m_xDocHandler->startElement( OUString(RTL_CONSTASCII_USTRINGPARAM("office:body")), xAttrList );
229 : :
230 : : // process strings imported
231 : : std::vector< OUString >::const_iterator it = m_vStringChunks.begin();
232 : : std::vector< OUString >::const_iterator it_end = m_vStringChunks.end();
233 : : for ( ; it!=it_end; ++it )
234 : : writeTextChunk( *it );
235 : :
236 : : m_xDocHandler->endElement( OUString(RTL_CONSTASCII_USTRINGPARAM("office:body") ) );
237 : : m_xDocHandler->endElement( OUString(RTL_CONSTASCII_USTRINGPARAM("office:document-content")));
238 : : m_xDocHandler->endDocument();
239 : : }
240 : : }
241 : : public:
242 : :
243 : : SimpleXMLImporter( const uno::Reference< XDocumentHandler >& xDocHandler, SvStream& rStream ) : m_xDocHandler( xDocHandler ), m_InputStream( rStream ) {}
244 : :
245 : : void import()
246 : : {
247 : : parseDoc();
248 : : writeXML();
249 : : }
250 : : };
251 : :
252 : 18 : sal_Bool SAL_CALL LotusWordProImportFilter::importImpl( const Sequence< ::com::sun::star::beans::PropertyValue >& aDescriptor )
253 : : throw (RuntimeException)
254 : : {
255 : :
256 : 18 : sal_Int32 nLength = aDescriptor.getLength();
257 : 18 : const PropertyValue * pValue = aDescriptor.getConstArray();
258 : 18 : OUString sURL;
259 [ + + ]: 36 : for ( sal_Int32 i = 0 ; i < nLength; i++)
260 : : {
261 : : //Note, we should attempt to use InputStream here first!
262 [ + - ]: 18 : if ( pValue[i].Name == "URL" )
263 : 18 : pValue[i].Value >>= sURL;
264 : : }
265 : :
266 [ + - ][ + - ]: 18 : SvFileStream inputStream( sURL, STREAM_READ );
[ + - ]
267 [ + - ][ - + ]: 18 : if ( inputStream.IsEof() || ( inputStream.GetError() != SVSTREAM_OK ) )
[ - + ]
268 : 0 : return sal_False;
269 : :
270 : : // An XML import service: what we push sax messages to..
271 [ + - ]: 18 : OUString sXMLImportService ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Writer.XMLImporter" ) );
272 : :
273 [ + - ][ + - ]: 18 : uno::Reference< XDocumentHandler > xInternalHandler( mxMSF->createInstance( sXMLImportService ), UNO_QUERY );
[ + - ]
274 [ + - ]: 18 : uno::Reference < XImporter > xImporter(xInternalHandler, UNO_QUERY);
275 [ - + ]: 18 : if (xImporter.is())
276 [ # # ][ # # ]: 0 : xImporter->setTargetDocument(mxDoc);
277 : :
278 [ + - ][ + - ]: 18 : return ( ReadWordproFile( inputStream, xInternalHandler) == 0 );
279 : :
280 : : }
281 : :
282 : 18 : sal_Bool SAL_CALL LotusWordProImportFilter::filter( const Sequence< ::com::sun::star::beans::PropertyValue >& aDescriptor )
283 : : throw (RuntimeException)
284 : : {
285 : 18 : return importImpl ( aDescriptor );
286 : : }
287 : 0 : void SAL_CALL LotusWordProImportFilter::cancel( )
288 : : throw (RuntimeException)
289 : : {
290 : 0 : }
291 : :
292 : : // XImporter
293 : 0 : void SAL_CALL LotusWordProImportFilter::setTargetDocument( const uno::Reference< ::com::sun::star::lang::XComponent >& xDoc )
294 : : throw (::com::sun::star::lang::IllegalArgumentException, RuntimeException)
295 : : {
296 : 0 : meType = FILTER_IMPORT;
297 : 0 : mxDoc = xDoc;
298 : 0 : }
299 : :
300 : : // XExtendedFilterDetection
301 : 10 : OUString SAL_CALL LotusWordProImportFilter::detect( com::sun::star::uno::Sequence< PropertyValue >& Descriptor )
302 : : throw( com::sun::star::uno::RuntimeException )
303 : : {
304 : :
305 [ + - ]: 10 : OUString sTypeName(RTL_CONSTASCII_USTRINGPARAM("writer_LotusWordPro_Document"));
306 : 10 : sal_Int32 nLength = Descriptor.getLength();
307 : 10 : OUString sURL;
308 : 10 : const PropertyValue * pValue = Descriptor.getConstArray();
309 : 10 : uno::Reference < XInputStream > xInputStream;
310 [ + + ]: 80 : for ( sal_Int32 i = 0 ; i < nLength; i++)
311 : : {
312 [ - + ]: 70 : if ( pValue[i].Name == "TypeName" )
313 : 0 : pValue[i].Value >>= sTypeName;
314 [ + + ]: 70 : else if ( pValue[i].Name == "InputStream" )
315 [ + - ]: 10 : pValue[i].Value >>= xInputStream;
316 [ + + ]: 60 : else if ( pValue[i].Name == "URL" )
317 : 10 : pValue[i].Value >>= sURL;
318 : : }
319 : :
320 : 10 : uno::Reference< com::sun::star::ucb::XCommandEnvironment > xEnv;
321 [ - + ]: 10 : if (!xInputStream.is())
322 : : {
323 : : try
324 : : {
325 [ # # ]: 0 : ::ucbhelper::Content aContent(sURL, xEnv);
326 [ # # ][ # # ]: 0 : xInputStream = aContent.openStream();
[ # # # # ]
327 : : }
328 [ # # ]: 0 : catch ( Exception& )
329 : : {
330 : 0 : return ::rtl::OUString();
331 : : }
332 : :
333 [ # # ]: 0 : if (!xInputStream.is())
334 : 0 : return ::rtl::OUString();
335 : : }
336 : :
337 [ + - ]: 10 : Sequence< ::sal_Int8 > aData;
338 : 10 : sal_Int32 nLen = SAL_N_ELEMENTS( header );
339 [ + - ][ + - ]: 20 : if ( !( ( nLen == xInputStream->readBytes( aData, nLen ) )
[ + - ]
340 [ + - ][ + - ]: 10 : && ( memcmp( ( void* )header, (void*) aData.getConstArray(), nLen ) == 0 ) ) )
341 : 10 : sTypeName = ::rtl::OUString();
342 : :
343 [ + - ]: 10 : return sTypeName;
344 : : }
345 : :
346 : :
347 : : // XInitialization
348 : 0 : void SAL_CALL LotusWordProImportFilter::initialize( const Sequence< Any >& aArguments )
349 : : throw (Exception, RuntimeException)
350 : : {
351 [ # # ]: 0 : Sequence < PropertyValue > aAnySeq;
352 : 0 : sal_Int32 nLength = aArguments.getLength();
353 [ # # ][ # # ]: 0 : if ( nLength && ( aArguments[0] >>= aAnySeq ) )
[ # # ][ # # ]
354 : : {
355 : 0 : const PropertyValue * pValue = aAnySeq.getConstArray();
356 : 0 : nLength = aAnySeq.getLength();
357 [ # # ]: 0 : for ( sal_Int32 i = 0 ; i < nLength; i++)
358 : : {
359 [ # # ]: 0 : if ( pValue[i].Name == "Type" )
360 : : {
361 : 0 : pValue[i].Value >>= msFilterName;
362 : 0 : break;
363 : : }
364 : : }
365 [ # # ]: 0 : }
366 : 0 : }
367 : 9 : OUString LotusWordProImportFilter_getImplementationName ()
368 : : throw (RuntimeException)
369 : : {
370 : 9 : return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Writer.LotusWordProImportFilter" ) );
371 : : }
372 : :
373 : : #define SERVICE_NAME1 "com.sun.star.document.ImportFilter"
374 : : #define SERVICE_NAME2 "com.sun.star.document.ExtendedTypeDetection"
375 : 0 : sal_Bool SAL_CALL LotusWordProImportFilter_supportsService( const OUString& ServiceName )
376 : : throw (RuntimeException)
377 : : {
378 [ # # ][ # # ]: 0 : return ServiceName == SERVICE_NAME1 || ServiceName == SERVICE_NAME2;
379 : : }
380 : 9 : Sequence< OUString > SAL_CALL LotusWordProImportFilter_getSupportedServiceNames( )
381 : : throw (RuntimeException)
382 : : {
383 : 9 : Sequence < OUString > aRet(2);
384 [ + - ]: 9 : OUString* pArray = aRet.getArray();
385 [ + - ]: 9 : pArray[0] = OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME1 ) );
386 [ + - ]: 9 : pArray[1] = OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME2 ) );
387 : 9 : return aRet;
388 : : }
389 : : #undef SERVICE_NAME2
390 : : #undef SERVICE_NAME1
391 : :
392 : 13 : uno::Reference< XInterface > SAL_CALL LotusWordProImportFilter_createInstance( const uno::Reference< XMultiServiceFactory > & rSMgr)
393 : : throw( Exception )
394 : : {
395 [ + - ]: 13 : return (cppu::OWeakObject*) new LotusWordProImportFilter( rSMgr );
396 : : }
397 : :
398 : : // XServiceInfo
399 : 0 : OUString SAL_CALL LotusWordProImportFilter::getImplementationName( )
400 : : throw (RuntimeException)
401 : : {
402 : 0 : return LotusWordProImportFilter_getImplementationName();
403 : : }
404 : 0 : sal_Bool SAL_CALL LotusWordProImportFilter::supportsService( const OUString& rServiceName )
405 : : throw (RuntimeException)
406 : : {
407 : 0 : return LotusWordProImportFilter_supportsService( rServiceName );
408 : : }
409 : 0 : Sequence< OUString > SAL_CALL LotusWordProImportFilter::getSupportedServiceNames( )
410 : : throw (RuntimeException)
411 : : {
412 : 0 : return LotusWordProImportFilter_getSupportedServiceNames();
413 : : }
414 : :
415 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|