/* * @(#)BasicPullSourceStream.java 1.13 02/08/21 * * Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved. */ package com.sun.media.protocol; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.io.*; import java.net.*; import javax.media.*; import javax.media.protocol.*; import com.sun.media.util.*; import com.sun.media.JMFSecurity; import com.sun.media.JMFSecurityManager; import com.sun.media.IESecurity; import com.ms.security.PermissionID; import com.ms.security.PolicyEngine; public class BasicPullSourceStream implements PullSourceStream, Seekable { /** * the stream which PullSourceStream's inheriting classes handles */ protected InputStream stream; /** * the current location in the stream */ protected long location; /** * a flag to indicate EOF reached */ protected boolean eofReached; protected long contentLength; protected URL url; protected URLConnection urlC; private boolean needConnectPermission; private static JMFSecurity jmfSecurity = null; private static boolean securityPrivelege = false; private Method m[] = new Method[1]; private Class cl[] = new Class[1]; private Object args[][] = new Object[1][0]; static { try { jmfSecurity = JMFSecurityManager.getJMFSecurity(); securityPrivelege = true; } catch (SecurityException e) { } } public BasicPullSourceStream(URL url, InputStream stream, long contentLength, boolean needConnectPermission ) throws IOException { this.needConnectPermission = needConnectPermission; // System.out.println("bpss: needConnectPermission is " + needConnectPermission); if (stream != null) { this.stream = stream; // stream is opened this.contentLength = contentLength; } else { // Check with Doron if we can remove the else block. // TODO: if not, add security stuff. try { urlC = url.openConnection(); this.contentLength = urlC.getContentLength(); this.stream = urlC.getInputStream(); if (this.stream == null) throw new IOException("Got null input stream from url connection"); } catch (IOException ie) { throw new IOException("error in connection"); } } location = 0; eofReached = false; this.url = url; } /** * Get the current content type for this stream. * * @returns The current ContentDescriptor for this stream. */ public ContentDescriptor getContentDescriptor() { return null; } /** * Find out if the end of the stream has been reached. * * @returns true if there is no more data. */ public boolean endOfStream() { return eofReached; } /** * willReadBlock indicates whether there data available now. * * @returns true if read would block, false if not. */ public boolean willReadBlock() { try { return (stream.available() == 0); } catch (IOException e) { System.err.println("Exception PullSourceStream::willReadBlock " + e.toString()); return true; } } /** * read will perform a blocking read from stream. If * buffer is null up to length bytes are read and discarded. * * @param buffer buffer to read into * @param offset offset in the buffer to put data * @param length bytes to read * @returns bytes read or -1 for end of media * @exception IOException */ public int read(byte buffer[], int offset, int length) throws IOException { int bytesRead; int len = length; int off = offset; do { bytesRead = stream.read(buffer, off, len); if (bytesRead == -1) { eofReached = true; int totalBytesRead = length - len; return (totalBytesRead > 0) ? totalBytesRead : -1; } else { location += bytesRead; len -= bytesRead; off += bytesRead; } } while (len != 0); return length; } /** * Obtain the collection of objects that control the object that implements * this interface. If no controls are supported, a zero length array * is returned. * * @returns the collection of object controls */ // CURRENTLLY DOES NOTHING public Object[] getControls() { Object[] objects = new Object[0]; return objects; } /** * Obtain the object that implements the specified Class or Interface The * full class or interface name must be used. If the control is not * supported then null is returned. * * @returns the object that implements the control, or null. */ // CURRENTLLY DOES NOTHING public Object getControl(String controlType) { return null; } /** * Seek to the specified point in the stream. * * @param where the position to seek to * @returns the new stream position */ public long seek(long where) { long oldLocation = location; location = where; try { if (where < oldLocation) { reopenStream(); eofReached = false; return skip(stream, where); } else { return skip(stream, (where - oldLocation)); } } catch (IOException e) { // System.err.println("Exception in PullSourceStream::seek(long) " + // e.toString()); //System.exit(0); return 0; // dummy } } void reopenStream() { // reopen the stream and go to new location // System.out.println("$$$ bpss: seek back"); try { if (stream!=null) { stream.close(); } // System.out.println("bpss: seek: needConnectPermission " + // needConnectPermission); if (needConnectPermission) { if ( /*securityPrivelege && */ (jmfSecurity != null) ) { try { if (jmfSecurity.getName().startsWith("jmf-security")) { jmfSecurity.requestPermission(m, cl, args, JMFSecurity.CONNECT); m[0].invoke(cl[0], args[0]); } else if (jmfSecurity.getName().startsWith("internet")) { PolicyEngine.checkPermission(PermissionID.NETIO); PolicyEngine.assertPermission(PermissionID.NETIO); } } catch (Throwable e) { if (JMFSecurityManager.DEBUG) { System.err.println("Unable to get connect " + " privilege " + e); } securityPrivelege = false; throw new IOException(JMFI18N.getResource("error.connectionerror") + e.getMessage()); } } } urlC = url.openConnection(); // This will not throw Security Exceptions try { if ( (jmfSecurity != null) && (jmfSecurity.getName().startsWith("jdk12"))) { Constructor cons = jdk12ConnectionAction.cons; stream = (InputStream) jdk12.doPrivM.invoke( jdk12.ac, new Object[] { cons.newInstance( new Object[] {urlC} ) } ); } else { // stream=url.openStream(); stream = urlC.getInputStream(); } } catch (Exception e) { System.err.println("Unable to re-open a URL connection " + e); throw new IOException(JMFI18N.getResource("error.connectionerror") + e.getMessage()); } } catch (IOException ex) { } } /** * Obtain the current point in the stream. * * @returns the current point in the stream */ public long tell() { return location; } /** * Find out if this source can position anywhere in the stream. * If the stream is not random access, it can only be repositioned to the beginning. * * @returns returns true if the stream is random access, false if the * stream can only be reset to the beginning. */ public boolean isRandomAccess() { return true; } /** * close the stream which PullSourceStream handles * * @exception if an I/O error occurs */ public void close() { try { stream.close(); stream = null; } catch (Exception e) { System.out.println("BasicPullSourceStream close - IOException"); } } public long getContentLength() { return contentLength; } private long skip(InputStream istream, long amount) throws IOException { long remaining = amount; while (remaining > 0) { long actual = istream.skip(remaining); remaining -= actual; } return amount; } }