2 /************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2008 by Sun Microsystems, Inc.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * $RCSfile: XSLTFilterOLEExtracter.java,v $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************///Standard Java classes
31 import java
.io
.FileWriter
;
32 import java
.util
.zip
.Inflater
;
33 import java
.util
.zip
.Deflater
;
35 //StarOffice Interfaces and UNO
36 import com
.sun
.star
.bridge
.XBridgeFactory
;
37 import com
.sun
.star
.bridge
.XBridge
;
38 import com
.sun
.star
.connection
.XConnector
;
39 import com
.sun
.star
.connection
.XConnection
;
40 import com
.sun
.star
.container
.XNameContainer
;
41 import com
.sun
.star
.embed
.XTransactedObject
;
42 import com
.sun
.star
.io
.XStream
;
43 import com
.sun
.star
.io
.XSeekable
;
44 import com
.sun
.star
.io
.XInputStream
;
45 import com
.sun
.star
.io
.XOutputStream
;
46 import com
.sun
.star
.lang
.XMultiServiceFactory
;
47 import com
.sun
.star
.lang
.XComponent
;
48 import com
.sun
.star
.uno
.XComponentContext
;
49 import com
.sun
.star
.uno
.UnoRuntime
;
51 /** This class is an xalan extension class. It provider 2 elements
52 * and 2 functions to used in xslt script. With this elements and functions
53 * we can convert between oledata between Wordml and OOo flat.
54 * To use it, we need a running OOo. There are two ways to get the XMultiServiceFactory.
55 * When called by OOo xslt filter, an XMultiServiceFactory will be add to the transformer
56 * by setParameter(), then we can get it using getParameter(). Another way is using an
57 * XConnection to connect to a running OOo. We connect to a running OOo, we need know the
58 * uno url. It can be set in the xslt script. The default uno url is:
59 * "uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager"
60 * see XSLTXalanOLEExtracter.java
62 public class XSLTFilterOLEExtracter
{
64 protected XMultiServiceFactory m_xMSF
;
65 protected XNameContainer m_Storage
;
66 protected XStream m_RootStream
;
67 protected XConnection m_Connection
;
68 protected String sConnectionString
;
69 private static final String UNO_URL
= "uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager";
71 public XSLTFilterOLEExtracter() {
74 public void init(String unoUrl
) {
75 if (unoUrl
== null || unoUrl
.equals("")) {
78 debugln("Init with uno url=" + unoUrl
);
81 m_xMSF
= connectAwareGetServiceFactory();
82 } catch (Exception ex
) {
83 System
.err
.println("Could not connect to the office '" + unoUrl
+ "'\n" + ex
.getMessage());
91 if (null != m_Connection
) {
94 } catch (Exception ex
) {
95 System
.err
.println("Could not close connection to the office.\n" + ex
.getMessage());
99 //If aName = "oledata.mso" then we load the root storage from the given base64 string
100 //Otherwise we compress the stream and add it to the root storage under the name of aName
101 public void insertByName(String aName
, String aBase64
) {
102 debugln("insertByName(" + aName
+ " : " + aBase64
+ ")");
103 if (aName
.equals("oledata.mso")) {
104 loadRootStorageFromBase64(aBase64
);
106 ensureCreateRootStorage();
107 insertSubStorage(aName
, aBase64
);
110 //If aName = "oledata.mso" then we return the base64 encoded string of the root storage
111 //Otherwise we return the base64 encoded string of the sub stream under the name of aName
112 public String
getByName(String aName
) {
113 if (aName
.equals("oledata.mso")) {
115 //get the length and seek to 0
116 XSeekable xSeek
= (XSeekable
) UnoRuntime
.queryInterface(XSeekable
.class, m_RootStream
);
117 int oleLength
= (int) xSeek
.getLength();
121 XInputStream xInput
= m_RootStream
.getInputStream();
122 byte oledata
[][] = new byte[1][oleLength
];
123 xInput
.readBytes(oledata
, oleLength
);
124 //return the base64 encoded string
125 return Base64
.encodeBytes(oledata
[0]);
126 } catch (Exception ex
) {
127 ex
.printStackTrace();
130 return getEncodedSubStorage(aName
);
134 //get the sub stream which name = aName, decompress it and return the base64 encoded string
135 public String
getEncodedSubStorage(String aName
) {
136 debugln("getByName(" + aName
+ ")");
138 if (!m_Storage
.hasByName(aName
)) {
139 return "Not Found:" + aName
;
141 Object oSubStream
= m_Storage
.getByName(aName
);
142 if (oSubStream
== null) {
143 return "Not Found:" + aName
;
145 XInputStream xSubStream
= (XInputStream
) UnoRuntime
.queryInterface(XInputStream
.class,
147 if (xSubStream
== null) {
148 return "Not Found:" + aName
;
150 //The first four byte are the length of the uncompressed data
151 byte pLength
[][] = new byte[1][4];
152 XSeekable xSeek
= (XSeekable
) UnoRuntime
.queryInterface(XSeekable
.class, xSubStream
);
155 //Get the uncompressed length
156 int readbytes
= xSubStream
.readBytes(pLength
, 4);
157 if (4 != readbytes
) {
158 System
.out
.println("readbytes:" + readbytes
);
159 return "Can not read the length.";
161 int oleLength
= (pLength
[0][0] << 0) + (pLength
[0][1] << 8) + (pLength
[0][2] << 16) + (pLength
[0][3] << 24);
162 byte pContents
[][] = new byte[1][oleLength
];
163 //Read all bytes. The compressed length should less then the uncompressed length
164 readbytes
= xSubStream
.readBytes(pContents
, oleLength
);
165 if (oleLength
< readbytes
) {
166 return "oleLength :" + oleLength
+ " readbytes: " + readbytes
;
169 // Decompress the bytes
170 Inflater decompresser
= new Inflater();
171 decompresser
.setInput(pContents
[0], 0, readbytes
);
172 byte[] result
= new byte[oleLength
];
173 int resultLength
= decompresser
.inflate(result
);
176 //return the base64 string of the uncompressed data
177 return Base64
.encodeBytes(result
);
178 } catch (Exception ex
) {
179 ex
.printStackTrace();
184 public XStream
CreateTempFileStream(XMultiServiceFactory xMSF
) {
185 // try to get temporary file representation
186 XStream xTempFileStream
= null;
188 Object oTempFile
= xMSF
.createInstance("com.sun.star.io.TempFile");
189 xTempFileStream
= (XStream
) UnoRuntime
.queryInterface(XStream
.class, oTempFile
);
190 } catch (Exception e
) {
193 if (xTempFileStream
== null) {
194 System
.out
.println("Can't create temporary file!");
197 return xTempFileStream
;
199 //decode the base64 string and create an com.sun.star.embed.OLESimpleStorage from it
200 public void loadRootStorageFromBase64(String aBase64
) {
202 //Decode and write the data to an temp stream
203 byte[] oledata
= Base64
.decode(aBase64
);
204 m_RootStream
= CreateTempFileStream(m_xMSF
);
205 XOutputStream xOutput
= m_RootStream
.getOutputStream();
206 xOutput
.writeBytes(oledata
);
208 //Get the input stream and seek to begin
209 XInputStream xInput
= m_RootStream
.getInputStream();
210 XSeekable xSeek
= (XSeekable
) UnoRuntime
.queryInterface(XSeekable
.class, xInput
);
215 //create an com.sun.star.embed.OLESimpleStorage from the temp stream
216 Object pArgs
[] = new Object
[1];
217 pArgs
[0] = (Object
) xInput
;
218 Object oTempStorage
= m_xMSF
.createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", pArgs
);
221 m_Storage
= (XNameContainer
) UnoRuntime
.queryInterface(XNameContainer
.class, oTempStorage
);
222 } catch (Exception e
) {
226 //Create a empty OLESimpleStorage if there is not one
227 public void ensureCreateRootStorage() {
228 if (null == m_RootStream
|| null == m_Storage
) {
230 m_RootStream
= CreateTempFileStream(m_xMSF
);
232 Object pArgs
[] = new Object
[1];
233 pArgs
[0] = (Object
) m_RootStream
;
234 Object oTempStorage
= m_xMSF
.createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", pArgs
);
237 m_Storage
= (XNameContainer
) UnoRuntime
.queryInterface(XNameContainer
.class, oTempStorage
);
238 } catch (Exception e
) {
243 //decode the base64 string and insert the length and the compressed data of it to
244 //the root storage as a sub stream under aName
245 public void insertSubStorage(String aName
, String aBase64
) {
247 //decode the base64 string
248 byte[] oledata
= Base64
.decode(aBase64
);
249 //create a temp stream to write data to
250 XStream subStream
= CreateTempFileStream(m_xMSF
);
251 XInputStream xInput
= subStream
.getInputStream();
252 XOutputStream xOutput
= subStream
.getOutputStream();
253 //write the length to the temp stream
254 byte oleHead
[] = new byte[4];
255 oleHead
[0] = (byte) ((oledata
.length
>>> 0) & 0xFF);
256 oleHead
[1] = (byte) ((oledata
.length
>>> 8) & 0xFF);
257 oleHead
[2] = (byte) ((oledata
.length
>>> 16) & 0xFF);
258 oleHead
[3] = (byte) ((oledata
.length
>>> 24) & 0xFF);
259 xOutput
.writeBytes(oleHead
);
261 // Compress the bytes
262 byte[] output
= new byte[oledata
.length
];
263 Deflater compresser
= new Deflater();
264 compresser
.setInput(oledata
);
266 int compressedDataLength
= compresser
.deflate(output
);
267 //realloc the data length
268 byte[] compressedBytes
= new byte[compressedDataLength
];
269 for (int i
= 0; i
< compressedDataLength
; i
++) {
270 compressedBytes
[i
] = output
[i
];
273 //write the compressed data to the temp stream
274 xOutput
.writeBytes(compressedBytes
);
276 XSeekable xSeek
= (XSeekable
) UnoRuntime
.queryInterface(XSeekable
.class, xInput
);
281 //insert the temp stream as a sub stream and use an XTransactedObject to commit it immediately
282 XTransactedObject xTransact
= (XTransactedObject
) UnoRuntime
.queryInterface(XTransactedObject
.class, m_Storage
);
283 m_Storage
.insertByName(aName
, xInput
);
287 } catch (Exception e
) {
292 /** separtates the uno-url into 3 different parts.
294 protected static String
[] parseUnoUrl(String url
) {
295 String
[] aRet
= new String
[3];
297 if (!url
.startsWith("uno:")) {
301 int semicolon
= url
.indexOf(';');
302 if (semicolon
== -1) {
306 aRet
[0] = url
.substring(4, semicolon
);
307 int nextSemicolon
= url
.indexOf(';', semicolon
+ 1);
309 if (semicolon
== -1) {
312 aRet
[1] = url
.substring(semicolon
+ 1, nextSemicolon
);
314 aRet
[2] = url
.substring(nextSemicolon
+ 1);
317 //connect to running OOo and keep an XConnection object so that we can disconnect from OOo as we wish
318 protected XMultiServiceFactory
connectAwareGetServiceFactory() throws com
.sun
.star
.uno
.Exception
,
319 com
.sun
.star
.uno
.RuntimeException
,
322 // Get component context
323 XComponentContext xComponentContext
=
324 com
.sun
.star
.comp
.helper
.Bootstrap
.createInitialComponentContext(null);
326 // instantiate connector service
327 Object x
= xComponentContext
.getServiceManager().createInstanceWithContext(
328 "com.sun.star.connection.Connector", xComponentContext
);
330 XConnector xConnector
= (XConnector
) UnoRuntime
.queryInterface(XConnector
.class, x
);
332 String a
[] = parseUnoUrl(sConnectionString
);
334 throw new com
.sun
.star
.uno
.Exception("Couldn't parse uno-url " + sConnectionString
);
337 // connect using the connection string part of the uno-url only.
338 m_Connection
= xConnector
.connect(a
[0]);
340 x
= xComponentContext
.getServiceManager().createInstanceWithContext(
341 "com.sun.star.bridge.BridgeFactory", xComponentContext
);
343 XBridgeFactory xBridgeFactory
= (XBridgeFactory
) UnoRuntime
.queryInterface(
344 XBridgeFactory
.class, x
);
346 // create a nameless bridge with no instance provider
347 // using the middle part of the uno-url
348 XBridge bridge
= xBridgeFactory
.createBridge("", a
[1], m_Connection
, null);
350 // query for the XComponent interface and add this as event listener
351 XComponent xComponent
= (XComponent
) UnoRuntime
.queryInterface(
352 XComponent
.class, bridge
);
354 // get the remote instance
355 x
= bridge
.getInstance(a
[2]);
357 // Did the remote server export this object ?
359 throw new com
.sun
.star
.uno
.Exception(
360 "Server didn't provide an instance for" + a
[2], null);
363 XMultiServiceFactory xFac
= (XMultiServiceFactory
) UnoRuntime
.queryInterface(XMultiServiceFactory
.class, x
);
366 protected static boolean DEBUG
= false;
367 protected static boolean DEBUGCHK
= false;
368 protected static String debugfile
;
370 protected static void debugln(String s
) {
374 protected static void debug(String s
) {
376 if (System
.getProperty("xsltfilter.debug") == null) {
380 debugfile
= System
.getProperty("xsltfilter.debug");
388 FileWriter dbgwriter
= new FileWriter(debugfile
, true);
391 } catch (Exception e
) {