/* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ package com.sun.star.script.framework.io; import java.net.*; import java.io.*; import java.util.*; import java.util.zip.*; import com.sun.star.ucb.XSimpleFileAccess; import com.sun.star.uno.UnoRuntime; import com.sun.star.io.XInputStream; import com.sun.star.io.XOutputStream; import com.sun.star.io.XTruncate; import com.sun.star.script.framework.log.LogUtils; import com.sun.star.script.framework.provider.PathUtils; public class UCBStreamHandler extends URLStreamHandler { public final static String separator = "/ucb/"; private XSimpleFileAccess m_xSimpleFileAccess = null; private HashMap m_jarStreamMap = new HashMap(12); private static String m_ucbscheme; public UCBStreamHandler( String scheme, XSimpleFileAccess xSFA ) { LogUtils.DEBUG( "UCBStreamHandler ctor, scheme = " + scheme ); UCBStreamHandler.m_ucbscheme = scheme; this.m_xSimpleFileAccess = xSFA; } @Override public void parseURL(URL url, String spec, int start, int limit) { LogUtils.DEBUG("**XUCBStreamHandler, parseURL: " + url + " spec: " + spec + " start: " + start + " limit: " + limit ); String file = url.getFile(); if (file == null) file = spec.substring(start, limit); else file += spec.substring(start, limit); LogUtils.DEBUG("**For scheme = " + m_ucbscheme ); LogUtils.DEBUG("**Setting path = " + file ); setURL(url, m_ucbscheme, null, -1, null, null, file, null, null); } @Override public URLConnection openConnection(URL u) throws IOException { return new UCBConnection(u); } private class UCBConnection extends URLConnection { public UCBConnection(URL url) { super(url); } @Override public void connect() { } @Override public InputStream getInputStream() throws IOException { LogUtils.DEBUG("UCBConnectionHandler GetInputStream on " + url ); String sUrl = url.toString(); if (sUrl.lastIndexOf(separator) == -1) { LogUtils.DEBUG("getInputStream straight file load" ); return getFileStreamFromUCB(sUrl); } else { String path = sUrl.substring(0, sUrl.lastIndexOf(separator) ); String file = sUrl.substring( sUrl.lastIndexOf(separator) + separator.length()); LogUtils.DEBUG("getInputStream, load of file from another file eg. " + file + " from " + path ); return getUCBStream(file, path); } } @Override public OutputStream getOutputStream() throws IOException { LogUtils.DEBUG("UCBConnectionHandler getOutputStream on " + url ); OutputStream os = null; try { String sUrl = url.toString(); if ( !( sUrl.lastIndexOf(separator) == -1) ) { String path = sUrl.substring(0, sUrl.lastIndexOf(separator)); if ( m_xSimpleFileAccess.isReadOnly( path ) ) { throw new java.io.IOException("File is read only"); } LogUtils.DEBUG("getOutputStream, create o/p stream for file eg. " + path ); // we will only deal with simple file write XOutputStream xos = m_xSimpleFileAccess.openFileWrite( path ); XTruncate xtrunc = UnoRuntime.queryInterface( XTruncate.class, xos ); if ( xtrunc != null ) { xtrunc.truncate(); } os = new XOutputStreamWrapper( xos ); } if ( os == null ) { throw new IOException("Failed to get OutputStream for " + sUrl ); } } catch ( com.sun.star.ucb.CommandAbortedException cae ) { LogUtils.DEBUG("caught exception: " + cae.toString() + " getting writable stream from " + url ); throw new IOException( cae.toString() ); } catch ( com.sun.star.uno.Exception e ) { LogUtils.DEBUG("caught unknown exception: " + e.toString() + " getting writable stream from " + url ); throw new IOException( e.toString() ); } return os; } } private InputStream getUCBStream(String file, String path) throws IOException { InputStream is = null; InputStream result = null; try { if (path.endsWith(".jar")) { is = m_jarStreamMap.get(path); if (is == null) { is = getFileStreamFromUCB(path); m_jarStreamMap.put(path, is); } else { try { is.reset(); } catch (IOException e) { is.close(); is = getFileStreamFromUCB(path); m_jarStreamMap.put(path, is); } } result = getFileStreamFromJarStream(file, is); } else { String fileUrl = PathUtils.make_url(path,file); result = getFileStreamFromUCB(fileUrl); } } finally { if (is != null) { try { is.close(); } catch (IOException ioe) { LogUtils.DEBUG("Caught exception closing stream: " + ioe.getMessage()); } } } return result; } private InputStream getFileStreamFromJarStream(String file, InputStream is) throws IOException { ZipEntry entry; ZipInputStream zis = new ZipInputStream(is); while (zis.available() != 0) { entry = zis.getNextEntry(); if (entry.getName().equals(file)) { return zis; } } return null; } private InputStream getFileStreamFromUCB(String path) throws IOException { InputStream result = null; XInputStream xInputStream = null; try { LogUtils.DEBUG("Trying to read from " + path ); xInputStream = m_xSimpleFileAccess.openFileRead(path); LogUtils.DEBUG("sfa appeared to read file " ); byte[][] inputBytes = new byte[1][]; int sz = m_xSimpleFileAccess.getSize(path); // TODO don't depend on result of available() or size() // just read stream 'till complete if ( sz == 0 ) { if ( xInputStream.available() > 0 ) { sz = xInputStream.available(); } } LogUtils.DEBUG("size of file " + path + " is " + sz ); LogUtils.DEBUG("available = " + xInputStream.available() ); inputBytes[0] = new byte[sz]; int ln = xInputStream.readBytes(inputBytes, sz); if (ln != sz) { throw new IOException( "Failed to read " + sz + " bytes from XInputStream"); } result = new ByteArrayInputStream(inputBytes[0]); } catch (com.sun.star.io.IOException ioe) { LogUtils.DEBUG("caught exception " + ioe ); throw new IOException(ioe.getMessage()); } catch (com.sun.star.uno.Exception e) { LogUtils.DEBUG("caught exception " + e ); throw new IOException(e.getMessage()); } finally { if (xInputStream != null) { try { xInputStream.closeInput(); } catch (Exception e2) { LogUtils.DEBUG( "Error closing XInputStream:" + e2.getMessage()); } } } return result; } }