merge the formfield patch from ooo-build
[ooovba.git] / filter / source / xsltfilter / XSLTFilterOLEExtracter.java
blobcdb63cc7743e5f6bf9f7ca6dff1e4fd5589759a1
2 /************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * Copyright 2008 by Sun Microsystems, Inc.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * $RCSfile: XSLTFilterOLEExtracter.java,v $
11 * $Revision: 1.6 $
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("")) {
76 unoUrl = UNO_URL;
78 debugln("Init with uno url=" + unoUrl);
79 if (null == m_xMSF) {
80 try {
81 m_xMSF = connectAwareGetServiceFactory();
82 } catch (Exception ex) {
83 System.err.println("Could not connect to the office '" + unoUrl + "'\n" + ex.getMessage());
88 public void exit() {
89 m_Storage = null;
90 m_xMSF = null;
91 if (null != m_Connection) {
92 try {
93 m_Connection.close();
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);
105 } else {
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")) {
114 try {
115 //get the length and seek to 0
116 XSeekable xSeek = (XSeekable) UnoRuntime.queryInterface(XSeekable.class, m_RootStream);
117 int oleLength = (int) xSeek.getLength();
118 xSeek.seek(0);
119 xSeek = null;
120 //read all bytes
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();
129 } else {
130 return getEncodedSubStorage(aName);
132 return "";
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 + ")");
137 try {
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,
146 oSubStream);
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);
153 xSeek.seek(0);
154 xSeek = null;
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);
174 decompresser.end();
176 //return the base64 string of the uncompressed data
177 return Base64.encodeBytes(result);
178 } catch (Exception ex) {
179 ex.printStackTrace();
181 return "";
184 public XStream CreateTempFileStream(XMultiServiceFactory xMSF) {
185 // try to get temporary file representation
186 XStream xTempFileStream = null;
187 try {
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) {
201 try {
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);
207 xOutput.flush();
208 //Get the input stream and seek to begin
209 XInputStream xInput = m_RootStream.getInputStream();
210 XSeekable xSeek = (XSeekable) UnoRuntime.queryInterface(XSeekable.class, xInput);
211 xSeek.seek(0);
212 oledata = null;
213 xSeek = null;
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);
219 pArgs = null;
221 m_Storage = (XNameContainer) UnoRuntime.queryInterface(XNameContainer.class, oTempStorage);
222 } catch (Exception e) {
223 e.printStackTrace();
226 //Create a empty OLESimpleStorage if there is not one
227 public void ensureCreateRootStorage() {
228 if (null == m_RootStream || null == m_Storage) {
229 try {
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);
235 pArgs = null;
237 m_Storage = (XNameContainer) UnoRuntime.queryInterface(XNameContainer.class, oTempStorage);
238 } catch (Exception e) {
239 e.printStackTrace();
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) {
246 try {
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);
265 compresser.finish();
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);
275 //seek to 0
276 XSeekable xSeek = (XSeekable) UnoRuntime.queryInterface(XSeekable.class, xInput);
277 xSeek.seek(0);
278 xSeek = null;
279 oledata = null;
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);
284 xTransact.commit();
285 xTransact = null;
287 } catch (Exception e) {
288 e.printStackTrace();
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:")) {
298 return null;
301 int semicolon = url.indexOf(';');
302 if (semicolon == -1) {
303 return null;
306 aRet[0] = url.substring(4, semicolon);
307 int nextSemicolon = url.indexOf(';', semicolon + 1);
309 if (semicolon == -1) {
310 return null;
312 aRet[1] = url.substring(semicolon + 1, nextSemicolon);
314 aRet[2] = url.substring(nextSemicolon + 1);
315 return aRet;
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,
320 Exception {
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);
333 if (null == a) {
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 ?
358 if (null == x) {
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);
364 return xFac;
366 protected static boolean DEBUG = false;
367 protected static boolean DEBUGCHK = false;
368 protected static String debugfile;
370 protected static void debugln(String s) {
371 debug(s + "\n");
374 protected static void debug(String s) {
375 if (!DEBUGCHK) {
376 if (System.getProperty("xsltfilter.debug") == null) {
377 DEBUGCHK = true;
378 return;
379 } else {
380 debugfile = System.getProperty("xsltfilter.debug");
381 DEBUG = true;
384 if (!DEBUG) {
385 return;
387 try {
388 FileWriter dbgwriter = new FileWriter(debugfile, true);
389 dbgwriter.write(s);
390 dbgwriter.close();
391 } catch (Exception e) {
392 e.printStackTrace();