-
Brutzman, Don authoredBrutzman, Don authored
InputSource.java 14.40 KiB
/*****************************************************************************
* Web3d.org Copyright (c) 2001 - 2006
* Java Source
*
* This source is licensed under the GNU LGPL v2.1
* Please read http://www.gnu.org/copyleft/lgpl.html for more information
*
* This software comes with the standard NO WARRANTY disclaimer for any
* purpose. Use it at your own risk. If there's a problem you get to fix it.
*
****************************************************************************/
package org.web3d.vrml.sav;
// External imports
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.zip.GZIPInputStream;
import java.net.URLDecoder;
import org.ietf.uri.ResourceConnection;
import org.ietf.uri.URIUtils;
import org.ietf.uri.URL;
import org.ietf.uri.event.ProgressListener;
// Local imports
import org.web3d.vrml.util.URLChecker;
import org.xj3d.io.ReadProgressListener;
import org.xj3d.io.ReportableInputStream;
import org.xj3d.io.ReportableInputStreamReader;
import org.xj3d.io.ReportableReader;
/**
* Representation of an input stream of bytes to the reader.
* <p>
*
* @author Justin Couch
* @version $Revision: 1.19 $
*/
public class InputSource {
/** The encoding of the underlying stream. */
private String encoding;
/** The URL that represents the base of the passed file */
private String baseURL;
/** The fully qualified URL to the resource */
private String realURL;
/** The inputstream supplying bytes to us */
private InputStream stream;
/** The Reader representing the supply of characters to us */
private Reader reader;
/** The read progress listener */
private ReadProgressListener readProgressListener;
/** The progress listener */
private ProgressListener progressListener;
/** The size in bytes to issue update events */
private int updateSize;
/** The content type of the source */
private String contentType;
/**
* Create an input source representation of the given URI string. This
* may use the given string as a fully qualified URI that needs resolving.
*
* @param uri The URI to open
* @throws MalformedURLException if uri can not be resolved as a URL complete with proper scheme
*/
public InputSource(String uri) throws MalformedURLException {
this(new File(uri));
}
/**
* Create an input source representing the given file. It does not check
* for the file existing or a directory on creation. This will be done at
* the point stream is requested
*
* @param file the file to be used as the source
* @throws MalformedURLException if the file uri can not be resolved as a URL complete with proper scheme
*/
public InputSource(File file) throws MalformedURLException {
this(new URL(file.getPath())); // <- This must be an org.ietf.uri.URL not a java.net.URL
}
/**
* Create an input source representing the given URL. It does not open the
* URL until the stream is requested.
*
* @param url The URL to use
*/
public InputSource(java.net.URL url) {
this(new URL(url));
}
/**
* Create an input source representing the given URL. It does not open the
* URL until the stream is requested.
*
* @param url The org.ietf.uri.URL to use
*/
public InputSource(URL url) {
realURL = url.toExternalForm();
// debug
// System.out.println("InputSource: " + url.getClass() + ":"); // paths can be long for console
// System.out.println(" " + realURL);
extractBaseUrl();
}
/**
* Create an input source from the input stream and the defined base URL.
* The base is required because it is not possible to determine this from
* the stream.
*
* @param urlBase The name of the base URL for this stream
* @param is The underlying stream to use
*/
public InputSource(String urlBase, InputStream is) {
this(urlBase, is, null);
}
/**
* Create an input source from the input stream and the defined base URL
* with the option of providing a known full URL. The base is required
* because it is not possible to determine this from the stream. If the
* real URL is not known, then set a value of null.
*
* @param urlBase The name of the base URL for this stream
* @param is The underlying stream to use
* @param fullUrl The fully qualified URL string
*/
public InputSource(String urlBase, InputStream is, String fullUrl) {
baseURL = urlBase;
stream = is;
realURL = fullUrl;
}
/**
* Create an input source from the reader and the defined base URL. The
* base is required because it is not possible to determine this from
* the stream.
*
* @param urlBase The name of the base URL for this stream
* @param rdr The underlying reader to use
*/
public InputSource(String urlBase, Reader rdr) {
this(urlBase, rdr, null);
}
/**
* Create an input source from the reader and the defined base URL with
* with the option of providing a known full URL. The base is required
* because it is not possible to determine this from the stream. If the
* real URL is not known, then set a value of null.
*
* @param urlBase The name of the base URL for this stream
* @param rdr The underlying Reader to use
* @param fullUrl The fully qualified URL string
*/
public InputSource(String urlBase, Reader rdr, String fullUrl) {
baseURL = urlBase;
reader = rdr;
realURL = fullUrl;
}
private void extractBaseUrl() {
realURL = URLChecker.prependFileScheme(realURL);
try {
String[] stripped_file = URIUtils.stripFile(URLDecoder.decode(realURL, "UTF-8"));
String path = stripped_file[0];
// System.out.println("[InputSource] extractBaseUrl():"); // paths can be long for console
// System.out.println(" " + path);
// Would this really work? What if the uri is a URN?
int index = path.lastIndexOf("/");
baseURL = path.substring(0, index + 1);
} catch(UnsupportedEncodingException uee) {
uee.printStackTrace(System.err);
}
}
/**
* Get the encoding, binary or string of the underlying stream. The
* encoding is that of the character stream of the file rather than the
* VRML encoding statement in the file header eg UTF8. This will not be
* available until the stream has been opened.
*
* @return The encoding string
*/
public String getEncoding() {
return encoding;
}
/**
* Get a stream of the characters from the source. The encoding is the
* same as that given by the getEncoding() method. If the underlying
* stream has not been opened, then this will force it to open.
*
* @return The reader representing the underlying stream
* @throws IOException An error opening the stream
*/
public Reader getCharacterStream() throws IOException {
Reader ret_val = null;
if(reader == null) {
if(stream == null) {
URL url;
try {
url = new URL(realURL);
final ResourceConnection conn = url.getResource();
if (progressListener != null)
conn.addProgressListener(progressListener);
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
conn.connect();
return null;
});
stream = conn.getInputStream();
contentType = conn.getContentType();
encoding = conn.getContentEncoding();
// If it is a gzip stream, then wrap the ordinary stream with
// something that can decode it.
if (encoding != null && encoding.equals("x-gzip")) {
stream = new GZIPInputStream(stream);
}
if (readProgressListener != null) {
ReportableInputStreamReader ris =
new ReportableInputStreamReader(false,
updateSize,
readProgressListener,
stream);
ret_val = ris;
} else {
ret_val = new InputStreamReader(stream);
}
} catch(MalformedURLException mue) {
throw new IOException("Unable to locate file");
} catch(PrivilegedActionException pae) {
throw (IOException)pae.getException();
}
} else {
if (readProgressListener != null) {
ret_val = new ReportableInputStreamReader(false,
updateSize,
readProgressListener,
stream);
} else {
ret_val = new InputStreamReader(stream);
}
}
reader = ret_val;
} else {
if (!(reader instanceof ReportableReader) && readProgressListener != null) {
ret_val = new ReportableReader(false,
updateSize,
readProgressListener,
reader);
} else {
ret_val = reader;
}
}
return ret_val;
}
/**
* Get a stream of raw bytes from the source. If the underlying stream
* has not been opened, this will force it to open. The current
* implementation barfs if the user supplied a raw stream.
*
* @return The stream representing the underlying bytes
* @throws IOException An error opening the stream
*/
public InputStream getByteStream() throws IOException {
if((reader != null) && (stream == null))
throw new IOException("Raw reader provided. Can't make stream");
if(stream == null) {
URL url;
try {
url = new URL(realURL);
final ResourceConnection conn = url.getResource();
if (progressListener != null)
conn.addProgressListener(progressListener);
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
conn.connect();
return null;
});
stream = conn.getInputStream();
contentType = conn.getContentType();
encoding = conn.getContentEncoding();
if (encoding != null && encoding.equals("x-gzip")) {
stream = new GZIPInputStream(stream);
}
if (readProgressListener != null) {
ReportableInputStream ris =
new ReportableInputStream(false,
updateSize,
readProgressListener,
stream);
return ris;
}
} catch(MalformedURLException mue) {
throw new IOException("Unable to locate file");
} catch(PrivilegedActionException pae) {
throw (IOException)pae.getException();
}
} else {
if (!(stream instanceof ReportableInputStream) && readProgressListener != null) {
stream = new ReportableInputStream(false,
updateSize,
readProgressListener,
stream);
}
}
return stream;
}
/**
* Get the base URL of this stream. This is used by code that may need to
* resolve other relative URIs in the stream.
*
* @return A string representing the base URL of this connection
*/
public String getBaseURL() {
return baseURL;
}
/**
* Get the fully qualified URL string to the source. If this is not known,
* then null is returned and the user should use the base URL.
*
* @return A string representing the full URL of this connection or null
*/
public String getURL() {
return realURL;
}
/**
* Close the underlying stream used by the source.
*
* @throws IOException An error closing the stream
*/
public void close() throws IOException {
if(stream != null)
stream.close();
if(reader != null)
reader.close();
}
/**
* Set the read progress listener. If set it will be notified of read
* progress. This listener is used to expose the stream state to the URI library.
*
* @param listener The progress listener.
* @param updateSize The number of bytes before issuing an update message.
*/
public void setReadProgressListener(ReadProgressListener listener,
int updateSize) {
readProgressListener = listener;
this.updateSize = updateSize;
}
/**
* Set the progress listener. This will notify the listener on changes
* in download state and progress.
*
* @param listener The progress listener.
*/
public void setProgressListener(ProgressListener listener) {
progressListener = listener;
}
/**
* Set the content type of this source.
* @param type the type to set
*/
public void setContentType(String type) {
contentType = type;
}
/**
* Get the content type of this source.
* @return the content type
*/
public String getContentType() {
return contentType;
}
}