diff options
Diffstat (limited to 'filter/source/xsltfilter/XSLTFilterOLEExtracter.java')
-rw-r--r-- | filter/source/xsltfilter/XSLTFilterOLEExtracter.java | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/filter/source/xsltfilter/XSLTFilterOLEExtracter.java b/filter/source/xsltfilter/XSLTFilterOLEExtracter.java new file mode 100644 index 000000000000..60de16a7070c --- /dev/null +++ b/filter/source/xsltfilter/XSLTFilterOLEExtracter.java @@ -0,0 +1,395 @@ + +/************************************************************************ + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: XSLTFilterOLEExtracter.java,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************///Standard Java classes +import java.io.FileWriter; +import java.util.zip.Inflater; +import java.util.zip.Deflater; + +//StarOffice Interfaces and UNO +import com.sun.star.bridge.XBridgeFactory; +import com.sun.star.bridge.XBridge; +import com.sun.star.connection.XConnector; +import com.sun.star.connection.XConnection; +import com.sun.star.container.XNameContainer; +import com.sun.star.embed.XTransactedObject; +import com.sun.star.io.XStream; +import com.sun.star.io.XSeekable; +import com.sun.star.io.XInputStream; +import com.sun.star.io.XOutputStream; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XComponent; +import com.sun.star.uno.XComponentContext; +import com.sun.star.uno.UnoRuntime; + +/** This class is an xalan extension class. It provider 2 elements + * and 2 functions to used in xslt script. With this elements and functions + * we can convert between oledata between Wordml and OOo flat. + * To use it, we need a running OOo. There are two ways to get the XMultiServiceFactory. + * When called by OOo xslt filter, an XMultiServiceFactory will be add to the transformer + * by setParameter(), then we can get it using getParameter(). Another way is using an + * XConnection to connect to a running OOo. We connect to a running OOo, we need know the + * uno url. It can be set in the xslt script. The default uno url is: + * "uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager" + * see XSLTXalanOLEExtracter.java + */ +public class XSLTFilterOLEExtracter { + + protected XMultiServiceFactory m_xMSF; + protected XNameContainer m_Storage; + protected XStream m_RootStream; + protected XConnection m_Connection; + protected String sConnectionString; + private static final String UNO_URL = "uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager"; + + public XSLTFilterOLEExtracter() { + } + + public void init(String unoUrl) { + if (unoUrl == null || unoUrl.equals("")) { + unoUrl = UNO_URL; + } + debugln("Init with uno url=" + unoUrl); + if (null == m_xMSF) { + try { + m_xMSF = connectAwareGetServiceFactory(); + } catch (Exception ex) { + System.err.println("Could not connect to the office '" + unoUrl + "'\n" + ex.getMessage()); + } + } + } + + public void exit() { + m_Storage = null; + m_xMSF = null; + if (null != m_Connection) { + try { + m_Connection.close(); + } catch (Exception ex) { + System.err.println("Could not close connection to the office.\n" + ex.getMessage()); + } + } + } + //If aName = "oledata.mso" then we load the root storage from the given base64 string + //Otherwise we compress the stream and add it to the root storage under the name of aName + public void insertByName(String aName, String aBase64) { + debugln("insertByName(" + aName + " : " + aBase64 + ")"); + if (aName.equals("oledata.mso")) { + loadRootStorageFromBase64(aBase64); + } else { + ensureCreateRootStorage(); + insertSubStorage(aName, aBase64); + } + } + //If aName = "oledata.mso" then we return the base64 encoded string of the root storage + //Otherwise we return the base64 encoded string of the sub stream under the name of aName + public String getByName(String aName) { + if (aName.equals("oledata.mso")) { + try { + //get the length and seek to 0 + XSeekable xSeek = (XSeekable) UnoRuntime.queryInterface(XSeekable.class, m_RootStream); + int oleLength = (int) xSeek.getLength(); + xSeek.seek(0); + xSeek = null; + //read all bytes + XInputStream xInput = m_RootStream.getInputStream(); + byte oledata[][] = new byte[1][oleLength]; + xInput.readBytes(oledata, oleLength); + //return the base64 encoded string + return Base64.encodeBytes(oledata[0]); + } catch (Exception ex) { + ex.printStackTrace(); + } + } else { + return getEncodedSubStorage(aName); + } + return ""; + } + //get the sub stream which name = aName, decompress it and return the base64 encoded string + public String getEncodedSubStorage(String aName) { + debugln("getByName(" + aName + ")"); + try { + if (!m_Storage.hasByName(aName)) { + return "Not Found:" + aName; + } + Object oSubStream = m_Storage.getByName(aName); + if (oSubStream == null) { + return "Not Found:" + aName; + } + XInputStream xSubStream = (XInputStream) UnoRuntime.queryInterface(XInputStream.class, + oSubStream); + if (xSubStream == null) { + return "Not Found:" + aName; + } + //The first four byte are the length of the uncompressed data + byte pLength[][] = new byte[1][4]; + XSeekable xSeek = (XSeekable) UnoRuntime.queryInterface(XSeekable.class, xSubStream); + xSeek.seek(0); + xSeek = null; + //Get the uncompressed length + int readbytes = xSubStream.readBytes(pLength, 4); + if (4 != readbytes) { + System.out.println("readbytes:" + readbytes); + return "Can not read the length."; + } + int oleLength = (pLength[0][0] << 0) + (pLength[0][1] << 8) + (pLength[0][2] << 16) + (pLength[0][3] << 24); + byte pContents[][] = new byte[1][oleLength]; + //Read all bytes. The compressed length should less then the uncompressed length + readbytes = xSubStream.readBytes(pContents, oleLength); + if (oleLength < readbytes) { + return "oleLength :" + oleLength + " readbytes: " + readbytes; + } + + // Decompress the bytes + Inflater decompresser = new Inflater(); + decompresser.setInput(pContents[0], 0, readbytes); + byte[] result = new byte[oleLength]; + int resultLength = decompresser.inflate(result); + decompresser.end(); + + //return the base64 string of the uncompressed data + return Base64.encodeBytes(result); + } catch (Exception ex) { + ex.printStackTrace(); + } + return ""; + } + + public XStream CreateTempFileStream(XMultiServiceFactory xMSF) { + // try to get temporary file representation + XStream xTempFileStream = null; + try { + Object oTempFile = xMSF.createInstance("com.sun.star.io.TempFile"); + xTempFileStream = (XStream) UnoRuntime.queryInterface(XStream.class, oTempFile); + } catch (Exception e) { + } + + if (xTempFileStream == null) { + System.out.println("Can't create temporary file!"); + } + + return xTempFileStream; + } + //decode the base64 string and create an com.sun.star.embed.OLESimpleStorage from it + public void loadRootStorageFromBase64(String aBase64) { + try { + //Decode and write the data to an temp stream + byte[] oledata = Base64.decode(aBase64); + m_RootStream = CreateTempFileStream(m_xMSF); + XOutputStream xOutput = m_RootStream.getOutputStream(); + xOutput.writeBytes(oledata); + xOutput.flush(); + //Get the input stream and seek to begin + XInputStream xInput = m_RootStream.getInputStream(); + XSeekable xSeek = (XSeekable) UnoRuntime.queryInterface(XSeekable.class, xInput); + xSeek.seek(0); + oledata = null; + xSeek = null; + + //create an com.sun.star.embed.OLESimpleStorage from the temp stream + Object pArgs[] = new Object[1]; + pArgs[0] = (Object) xInput; + Object oTempStorage = m_xMSF.createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", pArgs); + pArgs = null; + + m_Storage = (XNameContainer) UnoRuntime.queryInterface(XNameContainer.class, oTempStorage); + } catch (Exception e) { + e.printStackTrace(); + } + } + //Create a empty OLESimpleStorage if there is not one + public void ensureCreateRootStorage() { + if (null == m_RootStream || null == m_Storage) { + try { + m_RootStream = CreateTempFileStream(m_xMSF); + + Object pArgs[] = new Object[1]; + pArgs[0] = (Object) m_RootStream; + Object oTempStorage = m_xMSF.createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", pArgs); + pArgs = null; + + m_Storage = (XNameContainer) UnoRuntime.queryInterface(XNameContainer.class, oTempStorage); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + //decode the base64 string and insert the length and the compressed data of it to + //the root storage as a sub stream under aName + public void insertSubStorage(String aName, String aBase64) { + try { + //decode the base64 string + byte[] oledata = Base64.decode(aBase64); + //create a temp stream to write data to + XStream subStream = CreateTempFileStream(m_xMSF); + XInputStream xInput = subStream.getInputStream(); + XOutputStream xOutput = subStream.getOutputStream(); + //write the length to the temp stream + byte oleHead[] = new byte[4]; + oleHead[0] = (byte) ((oledata.length >>> 0) & 0xFF); + oleHead[1] = (byte) ((oledata.length >>> 8) & 0xFF); + oleHead[2] = (byte) ((oledata.length >>> 16) & 0xFF); + oleHead[3] = (byte) ((oledata.length >>> 24) & 0xFF); + xOutput.writeBytes(oleHead); + + // Compress the bytes + byte[] output = new byte[oledata.length]; + Deflater compresser = new Deflater(); + compresser.setInput(oledata); + compresser.finish(); + int compressedDataLength = compresser.deflate(output); + //realloc the data length + byte[] compressedBytes = new byte[compressedDataLength]; + for (int i = 0; i < compressedDataLength; i++) { + compressedBytes[i] = output[i]; + } + + //write the compressed data to the temp stream + xOutput.writeBytes(compressedBytes); + //seek to 0 + XSeekable xSeek = (XSeekable) UnoRuntime.queryInterface(XSeekable.class, xInput); + xSeek.seek(0); + xSeek = null; + oledata = null; + + //insert the temp stream as a sub stream and use an XTransactedObject to commit it immediately + XTransactedObject xTransact = (XTransactedObject) UnoRuntime.queryInterface(XTransactedObject.class, m_Storage); + m_Storage.insertByName(aName, xInput); + xTransact.commit(); + xTransact = null; + + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** separtates the uno-url into 3 different parts. + */ + protected static String[] parseUnoUrl(String url) { + String[] aRet = new String[3]; + + if (!url.startsWith("uno:")) { + return null; + } + + int semicolon = url.indexOf(';'); + if (semicolon == -1) { + return null; + } + + aRet[0] = url.substring(4, semicolon); + int nextSemicolon = url.indexOf(';', semicolon + 1); + + if (semicolon == -1) { + return null; + } + aRet[1] = url.substring(semicolon + 1, nextSemicolon); + + aRet[2] = url.substring(nextSemicolon + 1); + return aRet; + } + //connect to running OOo and keep an XConnection object so that we can disconnect from OOo as we wish + protected XMultiServiceFactory connectAwareGetServiceFactory() throws com.sun.star.uno.Exception, + com.sun.star.uno.RuntimeException, + Exception { + + // Get component context + XComponentContext xComponentContext = + com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(null); + + // instantiate connector service + Object x = xComponentContext.getServiceManager().createInstanceWithContext( + "com.sun.star.connection.Connector", xComponentContext); + + XConnector xConnector = (XConnector) UnoRuntime.queryInterface(XConnector.class, x); + + String a[] = parseUnoUrl(sConnectionString); + if (null == a) { + throw new com.sun.star.uno.Exception("Couldn't parse uno-url " + sConnectionString); + } + + // connect using the connection string part of the uno-url only. + m_Connection = xConnector.connect(a[0]); + + x = xComponentContext.getServiceManager().createInstanceWithContext( + "com.sun.star.bridge.BridgeFactory", xComponentContext); + + XBridgeFactory xBridgeFactory = (XBridgeFactory) UnoRuntime.queryInterface( + XBridgeFactory.class, x); + + // create a nameless bridge with no instance provider + // using the middle part of the uno-url + XBridge bridge = xBridgeFactory.createBridge("", a[1], m_Connection, null); + + // query for the XComponent interface and add this as event listener + XComponent xComponent = (XComponent) UnoRuntime.queryInterface( + XComponent.class, bridge); + + // get the remote instance + x = bridge.getInstance(a[2]); + + // Did the remote server export this object ? + if (null == x) { + throw new com.sun.star.uno.Exception( + "Server didn't provide an instance for" + a[2], null); + } + + XMultiServiceFactory xFac = (XMultiServiceFactory) UnoRuntime.queryInterface(XMultiServiceFactory.class, x); + return xFac; + } + protected static boolean DEBUG = false; + protected static boolean DEBUGCHK = false; + protected static String debugfile; + + protected static void debugln(String s) { + debug(s + "\n"); + } + + protected static void debug(String s) { + if (!DEBUGCHK) { + if (System.getProperty("xsltfilter.debug") == null) { + DEBUGCHK = true; + return; + } else { + debugfile = System.getProperty("xsltfilter.debug"); + DEBUG = true; + } + } + if (!DEBUG) { + return; + } + try { + FileWriter dbgwriter = new FileWriter(debugfile, true); + dbgwriter.write(s); + dbgwriter.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} |