/* * @(#)DataSource.java 1.27 02/08/21 * * Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved. */ package com.sun.media.protocol; import java.awt.Component; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.io.*; import java.net.*; import javax.media.Manager; import javax.media.Time; import javax.media.MediaLocator; import javax.media.ExtendedCachingControl; import javax.media.DownloadProgressListener; import javax.media.protocol.*; import com.sun.media.util.*; import com.sun.media.JMFSecurity; import com.sun.media.IESecurity; import com.sun.media.JMFSecurityManager; import com.sun.media.ui.CacheControlComponent; import com.ms.security.PermissionID; import com.ms.security.PolicyEngine; public class DataSource extends PullDataSource { protected boolean connected = false; private String contentType = null; private PullSourceStream[] pssArray = new PullSourceStream[1]; private CachedPullSourceStream cachedStream = null; private long contentLength = SourceStream.LENGTH_UNKNOWN; // -1 private InputStream inputStream; private String fileSeparator = System.getProperty("file.separator"); private boolean downLoadThreadStarted = false; private boolean isEnabledCaching = false; private ExtendedCachingControl[] cachingControls = new ExtendedCachingControl[0]; 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 String getContentType() { if (!connected) return null; return contentType; } public void connect() throws IOException { if (connected) return; MediaLocator locator = getLocator(); if (locator == null) { throw(new IOException(this + ": connect() failed")); } URL url; URLConnection urlC; try { url = locator.getURL(); urlC = url.openConnection(); // This will not throw security exception urlC.setAllowUserInteraction(true); } catch (MalformedURLException e) { // System.err.println(getLocator() + // ": Don't know how to deal with non-URL locator yet!"); throw(new IOException(this + ": connect() failed")); } String protocol = url.getProtocol(); // Note that even if we don't have connect privileges we can play // media from the same server from which the applet is downloaded. // Try to see if you can getInputStream without asking for // connect privilege boolean needConnectPermission = true; try { inputStream = urlC.getInputStream(); needConnectPermission = false; // System.out.println("got getInputStream without asking for security needConnectPermission " + needConnectPermission); } catch (Throwable e) { // System.err.println("Unable to getInputStream without asking for permission " + e); } if (inputStream == null) { 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 (Exception e) { if (JMFSecurityManager.DEBUG) { System.err.println("Unable to get connect " + " privilege " + e); } jmfSecurity.permissionFailureNotification(JMFSecurity.CONNECT); throw new IOException("Unable to get connect permission" + e.getMessage()); // securityPrivelege = false; } } try { if ( (jmfSecurity != null) && (jmfSecurity.getName().startsWith("jdk12"))) { Constructor cons = jdk12ConnectionAction.cons; inputStream = (InputStream) jdk12.doPrivM.invoke( jdk12.ac, new Object[] { cons.newInstance( new Object[] { urlC, })}); } else { inputStream = urlC.getInputStream(); } } catch (Throwable e) { // System.err.println("Unable to open a URL connection " + e); throw new IOException(JMFI18N.getResource("error.connectionerror") + e.getMessage()); } } if (inputStream == null) { throw new IOException(JMFI18N.getResource("error.connectionerror") + "Unable to open a URL connection"); } if (protocol.equals("ftp")) { contentType = "content/unknown"; // The contentType will be obtained after the // getCorrectedContentType call } else { contentType = urlC.getContentType(); contentLength = urlC.getContentLength(); // System.out.println("contentLength is " + contentLength); } contentType = ContentType.getCorrectedContentType(contentType, locator.getRemainder()); contentType = ContentDescriptor.mimeTypeToPackageName(contentType); // System.out.println("contentType is " + contentType); boolean cachingRequested = ((Boolean) Manager.getHint(Manager.CACHING)).booleanValue(); // Don't do caching for hotmedia or flash if ( contentType.endsWith(".mvr") || contentType.endsWith("x_shockwave_flash") || contentType.endsWith("futuresplash") ) { // System.err.println("Caching not done for hotmedia or flash"); cachingRequested = false; } String filePrefix = null; if ( cachingRequested ) { // user wants caching. check to see if caching is allowed filePrefix = Manager.getCacheDirectory(); if (filePrefix != null) { Object allowCachingObj = com.sun.media.util.Registry.get("secure.allowCaching"); if (allowCachingObj != null) { isEnabledCaching = ((Boolean) allowCachingObj).booleanValue(); } } } if (isEnabledCaching) { // TODO: remove file name extension, eg .mov from cache file String fileName = filePrefix + fileSeparator + generateFileName(getLocator().getRemainder()); try { cachedStream = new CachedPullSourceStream(inputStream, fileName, contentLength, protocol); pssArray[0] = cachedStream; cachingControls = new ExtendedCachingControl[1]; cachingControls[0] = new CachingControl(cachedStream); com.sun.media.Log.comment("Caching in " + filePrefix); } catch(IOException e) { isEnabledCaching = false; } } if (!isEnabledCaching) { try { pssArray[0] = new BasicPullSourceStream(url, inputStream, contentLength, needConnectPermission ); cachedStream=null; } catch(Exception ie) { pssArray[0] = null; throw new IOException(JMFI18N.getResource("error.connectionerror") + ie.getMessage()); } } connected = true; } public void disconnect() { if (!connected) return; if (cachedStream != null) { cachedStream.close(); cachedStream = null; } pssArray[0] = null; connected = false; } public void start() throws IOException { if (!connected) return; // TODO: see if you need downLoadThreadStarted if (cachedStream != null) { if (!downLoadThreadStarted) { cachedStream.startDownload(); downLoadThreadStarted = true; } else { cachedStream.resumeDownload(); } } } public void stop() throws IOException { // TODO if (!connected) return; // if (cachedStream != null) { // cachedStream.pauseDownload(); // } } public PullSourceStream[] getStreams() { return pssArray; } public Time getDuration() { return null; } public Object[] getControls() { return cachingControls; } public Object getControl(String controlType) { if ( (cachingControls.length > 0) && (controlType.equals("javax.media.CachingControl")) ) { return cachingControls[0]; } else { return null; } } // TODO: can be moved into a file-utils file // Generate a new file name by combining actual filename // + a random number + extension. static public String generateFileName(String infile) { String filename, ext = null; int sepindex = 0; java.util.Random generator = new java.util.Random(); int dotindex = infile.lastIndexOf('.'); int suffix = generator.nextInt(); // // if dotindex is not found, it implies extension // doesn't exist. Then set the dotindex to the // length of the input file, infile. if (dotindex != -1) { ext = new String(infile.substring(dotindex)); } else { dotindex = infile.length(); } sepindex = infile.lastIndexOf(File.separatorChar); // some URL's on Wintel use either slash. So should we. sepindex = Math.max(infile.lastIndexOf('/'), sepindex); // // If sepindex equals to -1, the input file name doesn't // have a separator. Copy the filename from 0 up to the // the extension. if (sepindex >= dotindex) { dotindex = infile.length(); ext = null; } filename = infile.substring(sepindex + 1, dotindex); String in; if (ext != null) in = new String(filename + suffix + ext); else in = new String(filename + suffix); return convertNonAlphaNumericToUnderscore(in); } // Convert all non-alpha-numeric characters other than periods // to underscores (_). private static String convertNonAlphaNumericToUnderscore(String in) { if (in == null) return null; // ... run through each char and convert // !([A-Za-z0--9]) -> '_' int len = in.length(); char nm[] = new char[len]; in.getChars(0, len, nm, 0); for (int i = 0; i < len; i++) { char c = nm[i]; if (!(c == '.' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9')) { nm[i] = '_'; } } return new String(nm); } class CachingControl implements javax.media.ExtendedCachingControl { private CacheControlComponent controlComponent; private Component progressBar; private CachedPullSourceStream cpss; CachingControl(CachedPullSourceStream cpss) { // TODO: CacheControlComponent may need cleanup this.cpss = cpss; controlComponent = new CacheControlComponent(this, null); progressBar = controlComponent.getProgressBar(); } // What is the purpose of this method in CachingControl? ? // Should we implement it by returning true if the // dowload thread is alive? public boolean isDownloading() { return cpss.isDownloading(); } public long getContentLength() { return contentLength; } public long getContentProgress() { return cpss.getContentProgress(); } public Component getProgressBarComponent() { return progressBar; } public Component getControlComponent() { return controlComponent; } public void pauseDownload() { cpss.pauseDownload(); } public void resumeDownload() { cpss.resumeDownload(); } public long getStartOffset() { return cpss.getStartOffset(); } public long getEndOffset() { return cpss.getEndOffset(); } public void setBufferSize(Time t) { //TODO } public Time getBufferSize() { return null; // TODO } public void addDownloadProgressListener(DownloadProgressListener l, int numKiloBytes) { cpss.addDownloadProgressListener(l, numKiloBytes); } public void removeDownloadProgressListener(DownloadProgressListener l) { cpss.removeDownloadProgressListener(l); } } }