home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / net / URLConnection.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  46.3 KB  |  1,259 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)URLConnection.java    1.54 98/10/02
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.net;
  16.  
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.io.OutputStream;
  20. import java.util.Hashtable;
  21. import java.util.Date;
  22. import java.util.StringTokenizer;
  23. import java.security.Permission;
  24. import java.security.AccessController;
  25.  
  26. /**
  27.  * The abstract class <code>URLConnection</code> is the superclass 
  28.  * of all classes that represent a communications link between the 
  29.  * application and a URL. Instances of this class can be used both to 
  30.  * read from and to write to the resource referenced by the URL. In 
  31.  * general, creating a connection to a URL is a multistep process: 
  32.  * <p>
  33.  * <center><table border=2>
  34.  * <tr><th><code>openConnection()</code></th>
  35.  *     <th><code>connect()</code></th></tr>
  36.  * <tr><td>Manipulate parameters that affect the connection to the remote 
  37.  *         resource.</td>
  38.  *     <td>Interact with the resource; query header fields and
  39.  *         contents.</td></tr>
  40.  * </table>
  41.  * ---------------------------->
  42.  * <br>time</center>
  43.  *
  44.  * <ol>
  45.  * <li>The connection object is created by invoking the
  46.  *     <code>openConnection</code> method on a URL.
  47.  * <li>The setup parameters and general request properties are manipulated.
  48.  * <li>The actual connection to the remote object is made, using the
  49.  *    <code>connect</code> method.
  50.  * <li>The remote object becomes available. The header fields and the contents
  51.  *     of the remote object can be accessed.
  52.  * </ol>
  53.  * <p>
  54.  * The setup parameters are modified using the following methods: 
  55.  * <ul>
  56.  *   <li><code>setAllowUserInteraction</code>
  57.  *   <li><code>setDoInput</code>
  58.  *   <li><code>setDoOutput</code>
  59.  *   <li><code>setIfModifiedSince</code>
  60.  *   <li><code>setUseCaches</code>
  61.  * </ul>
  62.  * <p>
  63.  * and the general request properties are modified using the method:
  64.  * <ul>
  65.  *   <li><code>setRequestProperty</code>
  66.  * </ul>
  67.  * <p>
  68.  * Default values for the <code>AllowUserInteraction</code> and 
  69.  * <code>UseCaches</code> parameters can be set using the methods 
  70.  * <code>setDefaultAllowUserInteraction</code> and 
  71.  * <code>setDefaultUseCaches</code>. Default values for general 
  72.  * request properties can be set using the 
  73.  * <code>setDefaultRequestProperty</code> method. 
  74.  * <p>
  75.  * Each of the above <code>set</code> methods has a corresponding 
  76.  * <code>get</code> method to retrieve the value of the parameter or 
  77.  * general request property. The specific parameters and general 
  78.  * request properties that are applicable are protocol specific. 
  79.  * <p>
  80.  * The following methods are used to access the header fields and 
  81.  * the contents after the connection is made to the remote object:
  82.  * <ul>
  83.  *   <li><code>getContent</code>
  84.  *   <li><code>getHeaderField</code>
  85.  *   <li><code>getInputStream</code>
  86.  *   <li><code>getOutputStream</code>
  87.  * </ul>
  88.  * <p>
  89.  * Certain header fields are accessed frequently. The methods:
  90.  * <ul>
  91.  *   <li><code>getContentEncoding</code>
  92.  *   <li><code>getContentLength</code>
  93.  *   <li><code>getContentType</code>
  94.  *   <li><code>getDate</code>
  95.  *   <li><code>getExpiration</code>
  96.  *   <li><code>getLastModifed</code>
  97.  * </ul>
  98.  * <p>
  99.  * provide convenient access to these fields. The 
  100.  * <code>getContentType</code> method is used by the 
  101.  * <code>getContent</code> method to determine the type of the remote 
  102.  * object; subclasses may find it convenient to override the 
  103.  * <code>getContentType</code> method. 
  104.  * <p>
  105.  * In the common case, all of the pre-connection parameters and 
  106.  * general request properties can be ignored: the pre-connection 
  107.  * parameters and request properties default to sensible values. For 
  108.  * most clients of this interface, there are only two interesting 
  109.  * methods: <code>getInputStream</code> and <code>getObject</code>, 
  110.  * which are mirrored in the <code>URL</code> class by convenience methods.
  111.  * <p>
  112.  * More information on the request properties and header fields of 
  113.  * an <code>http</code> connection can be found at:
  114.  * <blockquote><pre>
  115.  * http://www.w3.org/hypertext/WWW/Protocols/HTTP1.0/draft-ietf-http-spec.html
  116.  * </pre></blockquote>
  117.  *
  118.  * Note about <code>fileNameMap</code>: In versions prior to JDK 1.1.6, 
  119.  * field <code>fileNameMap</code> of <code>URLConnection</code> was public.
  120.  * In JDK 1.1.6 and later, <code>fileNameMap</code> is private; accessor 
  121.  * and mutator methods {@link #getFileNameMap() getFileNameMap} and 
  122.  * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added
  123.  * to access it.  This change is also described on the <a href=
  124.  * "http://java.sun.com/products/jdk/1.2/compatibility.html#incompatibilities1.1">
  125.  * JDK Compatibility</a> page.
  126.  *
  127.  * @author  James Gosling
  128.  * @version 1.54, 10/02/98
  129.  * @see     java.net.URL#openConnection()
  130.  * @see     java.net.URLConnection#connect()
  131.  * @see     java.net.URLConnection#getContent()
  132.  * @see     java.net.URLConnection#getContentEncoding()
  133.  * @see     java.net.URLConnection#getContentLength()
  134.  * @see     java.net.URLConnection#getContentType()
  135.  * @see     java.net.URLConnection#getDate()
  136.  * @see     java.net.URLConnection#getExpiration()
  137.  * @see     java.net.URLConnection#getHeaderField(int)
  138.  * @see     java.net.URLConnection#getHeaderField(java.lang.String)
  139.  * @see     java.net.URLConnection#getInputStream()
  140.  * @see     java.net.URLConnection#getLastModified()
  141.  * @see     java.net.URLConnection#getOutputStream()
  142.  * @see     java.net.URLConnection#setAllowUserInteraction(boolean)
  143.  * @see     java.net.URLConnection#setDefaultRequestProperty(java.lang.String, java.lang.String)
  144.  * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
  145.  * @see     java.net.URLConnection#setDoInput(boolean)
  146.  * @see     java.net.URLConnection#setDoOutput(boolean)
  147.  * @see     java.net.URLConnection#setIfModifiedSince(long)
  148.  * @see     java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
  149.  * @see     java.net.URLConnection#setUseCaches(boolean)
  150.  * @since   JDK1.0
  151.  */
  152. public abstract class URLConnection {
  153.  
  154.    /**
  155.      * The URL represents the remote object on the World Wide Web to 
  156.      * which this connection is opened. 
  157.      * <p>
  158.      * The value of this field can be accessed by the 
  159.      * <code>getURL</code> method. 
  160.      * <p>
  161.      * The default value of this variable is the value of the URL 
  162.      * argument in the <code>URLConnection</code> constructor. 
  163.      *
  164.      * @see     java.net.URLConnection#getURL()
  165.      * @see     java.net.URLConnection#url
  166.      */
  167.     protected URL url;
  168.  
  169.    /**
  170.      * This variable is set by the <code>setDoInput</code> method. Its 
  171.      * value is returned by the <code>getDoInput</code> method. 
  172.      * <p>
  173.      * A URL connection can be used for input and/or output. Setting the 
  174.      * <code>doInput</code> flag to <code>true</code> indicates that 
  175.      * the application intends to read data from the URL connection. 
  176.      * <p>
  177.      * The default value of this field is <code>true</code>. 
  178.      *
  179.      * @see     java.net.URLConnection#getDoInput()
  180.      * @see     java.net.URLConnection#setDoInput(boolean)
  181.      */
  182.     protected boolean doInput = true;
  183.  
  184.    /**
  185.      * This variable is set by the <code>setDoOutput</code> method. Its 
  186.      * value is returned by the <code>getDoInput</code> method. 
  187.      * <p>
  188.      * A URL connection can be used for input and/or output. Setting the 
  189.      * <code>doOutput</code> flag to <code>true</code> indicates 
  190.      * that the application intends to write data to the URL connection. 
  191.      * <p>
  192.      * The default value of this field is <code>false</code>. 
  193.      *
  194.      * @see     java.net.URLConnection#getDoOutput()
  195.      * @see     java.net.URLConnection#setDoOutput(boolean)
  196.      */
  197.     protected boolean doOutput = false;
  198.  
  199.     private static boolean defaultAllowUserInteraction = false;
  200.  
  201.    /**
  202.      * If <code>true</code>, this <code>URL</code> is being examined in 
  203.      * a context in which it makes sense to allow user interactions such 
  204.      * as popping up an authentication dialog. If <code>false</code>, 
  205.      * then no user interaction is allowed. 
  206.      * <p>
  207.      * The value of this field can be set by the 
  208.      * <code>setAllowUserInteraction</code> method.
  209.      * Its value is returned by the 
  210.      * <code>getAllowUserInteraction</code> method.
  211.      * Its default value is the value of the argument in the last invocation 
  212.      * of the <code>setDefaultAllowUserInteraction</code> method. 
  213.      *
  214.      * @see     java.net.URLConnection#getAllowUserInteraction()
  215.      * @see     java.net.URLConnection#setAllowUserInteraction(boolean)
  216.      * @see     java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
  217.      */
  218.     protected boolean allowUserInteraction = defaultAllowUserInteraction;
  219.  
  220.     private static boolean defaultUseCaches = true;
  221.  
  222.    /**
  223.      * If <code>true</code>, the protocol is allowed to use caching 
  224.      * whenever it can. If <code>false</code>, the protocol must always 
  225.      * try to get a fresh copy of the object. 
  226.      * <p>
  227.      * This field is set by the <code>setUseCaches</code> method. Its 
  228.      * value is returned by the <code>getUseCaches</code> method.
  229.      * <p>
  230.      * Its default value is the value given in the last invocation of the 
  231.      * <code>setDefaultUseCaches</code> method. 
  232.      *
  233.      * @see     java.net.URLConnection#setUseCaches(boolean)
  234.      * @see     java.net.URLConnection#getUseCaches()
  235.      * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
  236.      */
  237.     protected boolean useCaches = defaultUseCaches;
  238.  
  239.    /**
  240.      * Some protocols support skipping the fetching of the object unless 
  241.      * the object has been modified more recently than a certain time. 
  242.      * <p>
  243.      * A nonzero value gives a time as the number of seconds since 
  244.      * January 1, 1970, GMT. The object is fetched only if it has been 
  245.      * modified more recently than that time. 
  246.      * <p>
  247.      * This variable is set by the <code>setIfModifiedSince</code> 
  248.      * method. Its value is returned by the 
  249.      * <code>getIfModifiedSince</code> method.
  250.      * <p>
  251.      * The default value of this field is <code>0</code>, indicating 
  252.      * that the fetching must always occur. 
  253.      *
  254.      * @see     java.net.URLConnection#getIfModifiedSince()
  255.      * @see     java.net.URLConnection#setIfModifiedSince(long)
  256.      */
  257.     protected long ifModifiedSince = 0;
  258.  
  259.    /**
  260.      * If <code>false</code>, this connection object has not created a 
  261.      * communications link to the specified URL. If <code>true</code>, 
  262.      * the communications link has been established. 
  263.      */
  264.     protected boolean connected = false;
  265.  
  266.    /**
  267.     * @since   JDK1.1
  268.      */
  269.     private static FileNameMap fileNameMap;
  270.  
  271.     /**
  272.      * Returns the FileNameMap.
  273.      *
  274.      * @returns the FileNameMap
  275.      * @since JDK1.2
  276.      */
  277.     public static FileNameMap getFileNameMap() {
  278.     return new FileNameMap() {
  279.             public String getContentTypeFor(String fileName) {
  280.                 return fileNameMap.getContentTypeFor(fileName);
  281.             }
  282.         };
  283.     }
  284.  
  285.     /**
  286.      * Sets the FileNameMap.
  287.      * <p>
  288.      * If there is a security manager, this method first calls
  289.      * the security manager's <code>checkSetFactory</code> method 
  290.      * to ensure the operation is allowed. 
  291.      * This could result in a SecurityException.
  292.      *
  293.      * @param map the FileNameMap to be set
  294.      * @exception  SecurityException  if a security manager exists and its  
  295.      *             <code>checkSetFactory</code> method doesn't allow the operation.
  296.      * @see        SecurityManager#checkSetFactory
  297.      * @since JDK1.2
  298.      */
  299.     public static void setFileNameMap(FileNameMap map) {
  300.     SecurityManager sm = System.getSecurityManager();
  301.     if (sm != null) sm.checkSetFactory();
  302.     fileNameMap = map;
  303.     }
  304.  
  305.     /**
  306.      * Opens a communications link to the resource referenced by this 
  307.      * URL, if such a connection has not already been established. 
  308.      * <p>
  309.      * If the <code>connect</code> method is called when the connection 
  310.      * has already been opened (indicated by the <code>connected</code> 
  311.      * field having the value <code>true</code>), the call is ignored. 
  312.      * <p>
  313.      * URLConnection objects go through two phases: first they are
  314.      * created, then they are connected.  After being created, and
  315.      * before being connected, various options can be specified
  316.      * (e.g., doInput and UseCaches).  After connecting, it is an
  317.      * error to try to set them.  Operations that depend on being
  318.      * connected, like getContentLength, will implicitly perform the
  319.      * connection, if necessary.
  320.      *
  321.      * @exception  IOException  if an I/O error occurs while opening the
  322.      *               connection.
  323.      * @see java.net.URLConnection#connected */
  324.     abstract public void connect() throws IOException;
  325.  
  326.     /**
  327.      * Constructs a URL connection to the specified URL. A connection to 
  328.      * the object referenced by the URL is not created. 
  329.      *
  330.      * @param   url   the specified URL.
  331.      */
  332.     protected URLConnection(URL url) {
  333.     this.url = url;
  334.     }
  335.  
  336.     /**
  337.      * Returns the value of this <code>URLConnection</code>'s <code>URL</code>
  338.      * field.
  339.      *
  340.      * @return  the value of this <code>URLConnection</code>'s <code>URL</code>
  341.      *          field.
  342.      * @see     java.net.URLConnection#url
  343.      */
  344.     public URL getURL() {
  345.     return url;
  346.     }
  347.  
  348.     /**
  349.      * Returns the value of the <code>content-length</code> header field.
  350.      *
  351.      * @return  the content length of the resource that this connection's URL
  352.      *          references, or <code>-1</code> if the content length is
  353.      *          not known.
  354.      */
  355.     public int getContentLength() {
  356.     return getHeaderFieldInt("content-length", -1);
  357.     }
  358.  
  359.     /**
  360.      * Returns the value of the <code>content-type</code> header field.
  361.      *
  362.      * @return  the content type of the resource that the URL references,
  363.      *          or <code>null</code> if not known.
  364.      * @see     java.net.URLConnection#getHeaderField(java.lang.String)
  365.      */
  366.     public String getContentType() {
  367.     return getHeaderField("content-type");
  368.     }
  369.  
  370.     /**
  371.      * Returns the value of the <code>content-encoding</code> header field.
  372.      *
  373.      * @return  the content encoding of the resource that the URL references,
  374.      *          or <code>null</code> if not known.
  375.      * @see     java.net.URLConnection#getHeaderField(java.lang.String)
  376.      */
  377.     public String getContentEncoding() {
  378.     return getHeaderField("content-encoding");
  379.     }
  380.  
  381.     /**
  382.      * Returns the value of the <code>expires</code> header field. 
  383.      *
  384.      * @return  the expiration date of the resource that this URL references,
  385.      *          or 0 if not known. The value is the number of seconds since
  386.      *          January 1, 1970 GMT.
  387.      * @see     java.net.URLConnection#getHeaderField(java.lang.String)
  388.      */
  389.     public long getExpiration() {
  390.     return getHeaderFieldDate("expires", 0);
  391.     }
  392.  
  393.     /**
  394.      * Returns the value of the <code>date</code> header field. 
  395.      *
  396.      * @return  the sending date of the resource that the URL references,
  397.      *          or <code>0</code> if not known. The value returned is the
  398.      *          number of seconds since January 1, 1970 GMT.
  399.      * @see     java.net.URLConnection#getHeaderField(java.lang.String)
  400.      */
  401.     public long getDate() {
  402.     return getHeaderFieldDate("date", 0);
  403.     }
  404.  
  405.     /**
  406.      * Returns the value of the <code>last-modified</code> header field. 
  407.      * The result is the number of seconds since January 1, 1970 GMT.
  408.      *
  409.      * @return  the date the resource referenced by this
  410.      *          <code>URLConnection</code> was last modified, or 0 if not known.
  411.      * @see     java.net.URLConnection#getHeaderField(java.lang.String)
  412.      */
  413.     public long getLastModified() {
  414.     return getHeaderFieldDate("last-modified", 0);
  415.     }
  416.  
  417.     /**
  418.      * Returns the name of the specified header field.
  419.      *
  420.      * @param   name   the name of a header field.
  421.      * @return  the value of the named header field, or <code>null</code>
  422.      *          if there is no such field in the header.
  423.      */
  424.     public String getHeaderField(String name) {
  425.     return null;
  426.     }
  427.  
  428.     /**
  429.      * Returns the value of the named field parsed as a number.
  430.      * <p>
  431.      * This form of <code>getHeaderField</code> exists because some 
  432.      * connection types (e.g., <code>http-ng</code>) have pre-parsed 
  433.      * headers. Classes for that connection type can override this method 
  434.      * and short-circuit the parsing. 
  435.      *
  436.      * @param   name      the name of the header field.
  437.      * @param   Default   the default value.
  438.      * @return  the value of the named field, parsed as an integer. The
  439.      *          <code>Default</code> value is returned if the field is
  440.      *          missing or malformed.
  441.      */
  442.     public int getHeaderFieldInt(String name, int Default) {
  443.     try {
  444.         return Integer.parseInt(getHeaderField(name));
  445.     } catch(Throwable t) {}
  446.     return Default;
  447.     }
  448.  
  449.     /**
  450.      * Returns the value of the named field parsed as date.
  451.      * The result is the number of seconds since January 1, 1970 GMT
  452.      * represented by the named field. 
  453.      * <p>
  454.      * This form of <code>getHeaderField</code> exists because some 
  455.      * connection types (e.g., <code>http-ng</code>) have pre-parsed 
  456.      * headers. Classes for that connection type can override this method 
  457.      * and short-circuit the parsing. 
  458.      *
  459.      * @param   name     the name of the header field.
  460.      * @param   Default   a default value.
  461.      * @return  the value of the field, parsed as a date. The value of the
  462.      *          <code>Default</code> argument is returned if the field is
  463.      *          missing or malformed.
  464.      */
  465.     public long getHeaderFieldDate(String name, long Default) {
  466.     try {
  467.         return Date.parse(getHeaderField(name));
  468.     } catch(Throwable t) {}
  469.     return Default;
  470.     }
  471.  
  472.     /**
  473.      * Returns the key for the <code>n</code><sup>th</sup> header field.
  474.      *
  475.      * @param   n   an index.
  476.      * @return  the key for the <code>n</code><sup>th</sup> header field,
  477.      *          or <code>null</code> if there are fewer than <code>n</code>
  478.      *          fields.
  479.      */
  480.     public String getHeaderFieldKey(int n) {
  481.     return null;
  482.     }
  483.  
  484.     /**
  485.      * Returns the value for the <code>n</code><sup>th</sup> header field. 
  486.      * It returns <code>null</code> if there are fewer than 
  487.      * <code>n</code> fields. 
  488.      * <p>
  489.      * This method can be used in conjunction with the 
  490.      * <code>getHeaderFieldKey</code> method to iterate through all 
  491.      * the headers in the message. 
  492.      *
  493.      * @param   n   an index.
  494.      * @return  the value of the <code>n</code><sup>th</sup> header field.
  495.      * @see     java.net.URLConnection#getHeaderFieldKey(int)
  496.      */
  497.     public String getHeaderField(int n) {
  498.     return null;
  499.     }
  500.  
  501.     /**
  502.      * Retrieves the contents of this URL connection. 
  503.      * <p>
  504.      * This method first determines the content type of the object by 
  505.      * calling the <code>getContentType</code> method. If this is 
  506.      * the first time that the application has seen that specific content 
  507.      * type, a content handler for that content type is created: 
  508.      * <ol>
  509.      * <li>If the application has set up a content handler factory instance
  510.      *     using the <code>setContentHandlerFactory</code> method, the
  511.      *     <code>createContentHandler</code> method of that instance is called
  512.      *     with the content type as an argument; the result is a content
  513.      *     handler for that content type.
  514.      * <li>If no content handler factory has yet been set up, or if the
  515.      *     factory's <code>createContentHandler</code> method returns
  516.      *     <code>null</code>, then the application loads the class named:
  517.      *     <blockquote><pre>
  518.      *         sun.net.www.content.<<i>contentType</i>>
  519.      *     </pre></blockquote>
  520.      *     where <<i>contentType</i>> is formed by taking the
  521.      *     content-type string, replacing all slash characters with a
  522.      *     <code>period</code> ('.'), and all other non-alphanumeric characters
  523.      *     with the underscore character '<code>_</code>'. The alphanumeric
  524.      *     characters are specifically the 26 uppercase ASCII letters
  525.      *     '<code>A</code>' through '<code>Z</code>', the 26 lowercase ASCII
  526.      *     letters '<code>a</code>' through '<code>z</code>', and the 10 ASCII
  527.      *     digits '<code>0</code>' through '<code>9</code>'. If the specified
  528.      *     class does not exist, or is not a subclass of
  529.      *     <code>ContentHandler</code>, then an
  530.      *     <code>UnknownServiceException</code> is thrown.
  531.      * </ol>
  532.      *
  533.      * @return     the object fetched. The <code>instanceOf</code> operation
  534.      *               should be used to determine the specific kind of object
  535.      *               returned.
  536.      * @exception  IOException              if an I/O error occurs while
  537.      *               getting the content.
  538.      * @exception  UnknownServiceException  if the protocol does not support
  539.      *               the content type.
  540.      * @see        java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
  541.      * @see        java.net.URLConnection#getContentType()
  542.      * @see        java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
  543.      */
  544.     public Object getContent() throws IOException {
  545.         // Must call getInputStream before GetHeaderField gets called
  546.         // so that FileNotFoundException has a chance to be thrown up
  547.         // from here without being caught.
  548.         getInputStream();
  549.     return getContentHandler().getContent(this);
  550.     }
  551.  
  552.     /**  
  553.      * Returns a permission object representing the permission
  554.      * necessary to make the connection represented by this
  555.      * object. This method returns null if no permission is
  556.      * required to make the connection. By default, this method
  557.      * returns <code>java.security.AllPermission</code>. Subclasses
  558.      * should override this method and return the permission
  559.      * that best represents the permission required to make a 
  560.      * a connection to the URL. For example, a <code>URLConnection</code>
  561.      * representing a <code>file:</code> URL would return a 
  562.      * <code>java.io.FilePermission</code> object.
  563.      *
  564.      * <p>The permission returned may dependent upon the state of the
  565.      * connection. For example, the permission before connecting may be
  566.      * different from that after connecting. For example, an HTTP
  567.      * sever, say foo.com, may redirect the connection to a different
  568.      * host, say bar.com. Before connecting the permission returned by
  569.      * the connection will represent the permission needed to connect
  570.      * to foo.com, while the permission returned after connecting will
  571.      * be to bar.com.
  572.      * 
  573.      * <p>Permissions are generally used for two purposes: to protect
  574.      * caches of objects obtained through URLConnections, and to check
  575.      * the right of a recipient to learn about a particular URL. In
  576.      * the first case, the permission should be obtained
  577.      * <em>after</em> the object has been obtained. For example, in an
  578.      * HTTP connection, this will represent the permission to connect
  579.      * to the host from which the data was ultimately fetched. In the
  580.      * second case, the permission should be obtained and tested
  581.      * <em>before</em> connecting.
  582.      *
  583.      * @return the permission object representing the permission
  584.      * necessary to make the connection represented by this
  585.      * URLConnection. 
  586.      *
  587.      * @exception IOException if the computation of the permission
  588.      * requires network or file I/O and an exception occurs while
  589.      * computing it.  
  590.      */
  591.     public Permission getPermission() throws IOException {
  592.     return new java.security.AllPermission();
  593.     }
  594.  
  595.     /**
  596.      * Returns an input stream that reads from this open connection.
  597.      *
  598.      * @return     an input stream that reads from this open connection.
  599.      * @exception  IOException              if an I/O error occurs while
  600.      *               creating the input stream.
  601.      * @exception  UnknownServiceException  if the protocol does not support
  602.      *               input.
  603.      */
  604.     public InputStream getInputStream() throws IOException {
  605.     throw new UnknownServiceException("protocol doesn't support input");
  606.     }
  607.  
  608.     /**
  609.      * Returns an output stream that writes to this connection.
  610.      *
  611.      * @return     an output stream that writes to this connection.
  612.      * @exception  IOException              if an I/O error occurs while
  613.      *               creating the output stream.
  614.      * @exception  UnknownServiceException  if the protocol does not support
  615.      *               output.
  616.      */
  617.     public OutputStream getOutputStream() throws IOException {
  618.     throw new UnknownServiceException("protocol doesn't support output");
  619.     }
  620.  
  621.     /**
  622.      * Returns a <code>String</code> representation of this URL connection.
  623.      *
  624.      * @return  a string representation of this <code>URLConnection</code>.
  625.      */
  626.     public String toString() {
  627.     return this.getClass().getName() + ":" + url;
  628.     }
  629.  
  630.     /**
  631.      * Sets the value of the <code>doInput</code> field for this 
  632.      * <code>URLConnection</code> to the specified value. 
  633.      * <p>
  634.      * A URL connection can be used for input and/or output.  Set the DoInput
  635.      * flag to true if you intend to use the URL connection for input,
  636.      * false if not.  The default is true unless DoOutput is explicitly
  637.      * set to true, in which case DoInput defaults to false.
  638.      *
  639.      * @param   value   the new value.
  640.      * @see     java.net.URLConnection#doInput
  641.      */
  642.     public void setDoInput(boolean doinput) {
  643.     if (connected)
  644.         throw new IllegalAccessError("Already connected");
  645.     doInput = doinput;
  646.     }
  647.  
  648.     /**
  649.      * Returns the value of this <code>URLConnection</code>'s
  650.      * <code>doInput</code> flag.
  651.      *
  652.      * @return  the value of this <code>URLConnection</code>'s
  653.      *          <code>doInput</code> flag.
  654.      * @see     java.net.URLConnection#doInput
  655.      */
  656.     public boolean getDoInput() {
  657.     return doInput;
  658.     }
  659.  
  660.     /**
  661.      * Sets the value of the <code>doOutput</code> field for this 
  662.      * <code>URLConnection</code> to the specified value. 
  663.      * <p>
  664.      * A URL connection can be used for input and/or output.  Set the DoOutput
  665.      * flag to true if you intend to use the URL connection for output,
  666.      * false if not.  The default is false.
  667.      *
  668.      * @param   value   the new value.
  669.      * @see     java.net.URLConnection#doOutput
  670.      */
  671.     public void setDoOutput(boolean dooutput) {
  672.     if (connected)
  673.         throw new IllegalAccessError("Already connected");
  674.     doOutput = dooutput;
  675.     }
  676.  
  677.     /**
  678.      * Returns the value of this <code>URLConnection</code>'s
  679.      * <code>doOutput</code> flag.
  680.      *
  681.      * @return  the value of this <code>URLConnection</code>'s
  682.      *          <code>doOutput</code> flag.
  683.      * @see     java.net.URLConnection#doOutput
  684.      */
  685.     public boolean getDoOutput() {
  686.     return doOutput;
  687.     }
  688.  
  689.     /**
  690.      * Set the value of the <code>allowUserInteraction</code> field of 
  691.      * this <code>URLConnection</code>. 
  692.      *
  693.      * @param   allowuserinteraction   the new value.
  694.      * @see     java.net.URLConnection#allowUserInteraction
  695.      */
  696.     public void setAllowUserInteraction(boolean allowuserinteraction) {
  697.     if (connected)
  698.         throw new IllegalAccessError("Already connected");
  699.     allowUserInteraction = allowuserinteraction;
  700.     }
  701.  
  702.     /**
  703.      * Returns the value of the <code>allowUserInteraction</code> field for
  704.      * this object.
  705.      *
  706.      * @return  the value of the <code>allowUserInteraction</code> field for
  707.      *          this object.
  708.      * @see     java.net.URLConnection#allowUserInteraction
  709.      */
  710.     public boolean getAllowUserInteraction() {
  711.     return allowUserInteraction;
  712.     }
  713.  
  714.     /**
  715.      * Sets the default value of the 
  716.      * <code>allowUserInteraction</code> field for all future 
  717.      * <code>URLConnection</code> objects to the specified value. 
  718.      *
  719.      * @param   defaultallowuserinteraction   the new value.
  720.      * @see     java.net.URLConnection#allowUserInteraction
  721.      */
  722.     public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
  723.     defaultAllowUserInteraction = defaultallowuserinteraction;
  724.     }
  725.  
  726.     /**
  727.      * Returns the default value of the <code>allowUserInteraction</code>
  728.      * field.
  729.      * <p>
  730.      * Ths default is "sticky", being a part of the static state of all
  731.      * URLConnections.  This flag applies to the next, and all following
  732.      * URLConnections that are created.
  733.      *
  734.      * @return  the default value of the <code>allowUserInteraction</code>
  735.      *          field.
  736.      * @see     java.net.URLConnection#allowUserInteraction
  737.      */
  738.     public static boolean getDefaultAllowUserInteraction() {
  739.     return defaultAllowUserInteraction;
  740.     }
  741.  
  742.     /**
  743.      * Sets the value of the <code>useCaches</code> field of this 
  744.      * <code>URLConnection</code> to the specified value. 
  745.      * <p>
  746.      * Some protocols do caching of documents.  Occasionally, it is important
  747.      * to be able to "tunnel through" and ignore the caches (e.g., the
  748.      * "reload" button in a browser).  If the UseCaches flag on a connection
  749.      * is true, the connection is allowed to use whatever caches it can.
  750.      *  If false, caches are to be ignored.
  751.      *  The default value comes from DefaultUseCaches, which defaults to
  752.      * true.
  753.      *
  754.      * @see     java.net.URLConnection#useCaches
  755.      */
  756.     public void setUseCaches(boolean usecaches) {
  757.     if (connected)
  758.         throw new IllegalAccessError("Already connected");
  759.     useCaches = usecaches;
  760.     }
  761.  
  762.     /**
  763.      * Returns the value of this <code>URLConnection</code>'s
  764.      * <code>useCaches</code> field.
  765.      *
  766.      * @return  the value of this <code>URLConnection</code>'s
  767.      *          <code>useCaches</code> field.
  768.      * @see     java.net.URLConnection#useCaches
  769.      */
  770.     public boolean getUseCaches() {
  771.     return useCaches;
  772.     }
  773.  
  774.     /**
  775.      * Sets the value of the <code>ifModifiedSince</code> field of 
  776.      * this <code>URLConnection</code> to the specified value.
  777.      *
  778.      * @param   value   the new value.
  779.      * @see     java.net.URLConnection#ifModifiedSince
  780.      */
  781.     public void setIfModifiedSince(long ifmodifiedsince) {
  782.     if (connected)
  783.         throw new IllegalAccessError("Already connected");
  784.     ifModifiedSince = ifmodifiedsince;
  785.     }
  786.  
  787.     /**
  788.      * Returns the value of this object's <code>ifModifiedSince</code> field.
  789.      *
  790.      * @return  the value of this object's <code>ifModifiedSince</code> field.
  791.      * @see     java.net.URLConnection#ifModifiedSince
  792.      */
  793.     public long getIfModifiedSince() {
  794.     return ifModifiedSince;
  795.     }
  796.  
  797.    /**
  798.      * Returns the default value of a <code>URLConnection</code>'s
  799.      * <code>useCaches</code> flag.
  800.      * <p>
  801.      * Ths default is "sticky", being a part of the static state of all
  802.      * URLConnections.  This flag applies to the next, and all following
  803.      * URLConnections that are created.
  804.      *
  805.      * @return  the default value of a <code>URLConnection</code>'s
  806.      *          <code>useCaches</code> flag.
  807.      * @see     java.net.URLConnection#useCaches
  808.      */
  809.     public boolean getDefaultUseCaches() {
  810.     return defaultUseCaches;
  811.     }
  812.  
  813.    /**
  814.      * Sets the default value of the <code>useCaches</code> field to the 
  815.      * specified value. 
  816.      *
  817.      * @param   defaultusecaches   the new value.
  818.      * @see     java.net.URLConnection#useCaches
  819.      */
  820.     public void setDefaultUseCaches(boolean defaultusecaches) {
  821.     defaultUseCaches = defaultusecaches;
  822.     }
  823.  
  824.     /**
  825.      * Sets the general request property. 
  826.      *
  827.      * @param   key     the keyword by which the request is known
  828.      *                  (e.g., "<code>accept</code>").
  829.      * @param   value   the value associated with it.
  830.      */
  831.     public void setRequestProperty(String key, String value) {
  832.     if (connected)
  833.         throw new IllegalAccessError("Already connected");
  834.     }
  835.  
  836.     /**
  837.      * Returns the value of the named general request property for this
  838.      * connection.
  839.      *
  840.      * @return  the value of the named general request property for this
  841.      *           connection.
  842.      */
  843.     public String getRequestProperty(String key) {
  844.     if (connected)
  845.         throw new IllegalAccessError("Already connected");
  846.     return null;
  847.     }
  848.  
  849.     /**
  850.      * Sets the default value of a general request property. When a 
  851.      * <code>URLConnection</code> is created, it is initialized with 
  852.      * these properties. 
  853.      *
  854.      * @param   key     the keyword by which the request is known
  855.      *                  (e.g., "<code>accept</code>").
  856.      * @param   value   the value associated with the key.
  857.      */
  858.     public static void setDefaultRequestProperty(String key, String value) {
  859.     }
  860.  
  861.     /**
  862.      * Returns the value of the default request property. Default request 
  863.      * properties are set for every connection. 
  864.      *
  865.      * @return  the value of the default request property for the specified key.
  866.      * @see     java.net.URLConnection#setDefaultRequestProperty(java.lang.String, java.lang.String)
  867.      */
  868.     public static String getDefaultRequestProperty(String key) {
  869.     return null;
  870.     }
  871.  
  872.     /**
  873.      * The ContentHandler factory.
  874.      */
  875.     static ContentHandlerFactory factory;
  876.  
  877.     /**
  878.      * Sets the <code>ContentHandlerFactory</code> of an 
  879.      * application. It can be called at most once by an application. 
  880.      * <p>
  881.      * The <code>ContentHandlerFactory</code> instance is used to 
  882.      * construct a content handler from a content type 
  883.      * <p>
  884.      * If there is a security manager, this method first calls
  885.      * the security manager's <code>checkSetFactory</code> method 
  886.      * to ensure the operation is allowed. 
  887.      * This could result in a SecurityException.
  888.      *
  889.      * @param      fac   the desired factory.
  890.      * @exception  Error  if the factory has already been defined.
  891.      * @exception  SecurityException  if a security manager exists and its  
  892.      *             <code>checkSetFactory</code> method doesn't allow the operation.
  893.      * @see        java.net.ContentHandlerFactory
  894.      * @see        java.net.URLConnection#getContent()
  895.      * @see        SecurityManager#checkSetFactory
  896.      */
  897.     public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
  898.     if (factory != null) {
  899.         throw new Error("factory already defined");
  900.     }
  901.     SecurityManager security = System.getSecurityManager();
  902.     if (security != null) {
  903.         security.checkSetFactory();
  904.     }
  905.     factory = fac;
  906.     }
  907.  
  908.     private static Hashtable handlers = new Hashtable();
  909.     private static final ContentHandler UnknownContentHandlerP = new UnknownContentHandler();
  910.  
  911.     /**
  912.      * Gets the Content Handler appropriate for this connection.
  913.      * @param connection the connection to use.
  914.      */
  915.     synchronized ContentHandler getContentHandler()
  916.     throws UnknownServiceException
  917.     {
  918.     String contentType = getContentType();
  919.     ContentHandler handler = null;
  920.     if (contentType == null)
  921.         throw new UnknownServiceException("no content-type");
  922.     try {
  923.         handler = (ContentHandler) handlers.get(contentType);
  924.         if (handler != null)
  925.         return handler;
  926.     } catch(Exception e) {
  927.     }
  928.     if (factory != null)
  929.         handler = factory.createContentHandler(contentType);
  930.     if (handler == null) {
  931.         try {
  932.         handler = lookupContentHandlerClassFor(contentType);
  933.         } catch(Exception e) {
  934.         e.printStackTrace();
  935.         handler = UnknownContentHandlerP;
  936.         }
  937.         handlers.put(contentType, handler);
  938.     }
  939.     return handler;
  940.     }
  941.  
  942.     private static final String contentClassPrefix = "sun.net.www.content";
  943.     private static final String contentPathProp = "java.content.handler.pkgs";
  944.  
  945.     /**
  946.      * Looks for a content handler in a user-defineable set of places.
  947.      * By default it looks in sun.net.www.content, but users can define a 
  948.      * vertical-bar delimited set of class prefixes to search through in 
  949.      * addition by defining the java.content.handler.pkgs property.
  950.      * The class name must be of the form:
  951.      * <pre>
  952.      *     {package-prefix}.{major}.{minor}
  953.      * e.g.
  954.      *     YoyoDyne.experimental.text.plain
  955.      * </pre>
  956.      */
  957.     private ContentHandler lookupContentHandlerClassFor(String contentType)
  958.     throws InstantiationException, IllegalAccessException, ClassNotFoundException {
  959.     String contentHandlerClassName = typeToPackageName(contentType);
  960.  
  961.     String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
  962.  
  963.     StringTokenizer packagePrefixIter =
  964.         new StringTokenizer(contentHandlerPkgPrefixes, "|");
  965.     
  966.     while (packagePrefixIter.hasMoreTokens()) {
  967.         String packagePrefix = packagePrefixIter.nextToken().trim();
  968.  
  969.         try {
  970.         String name = packagePrefix + "." + contentHandlerClassName;
  971.         ContentHandler handler =
  972.             (ContentHandler) Class.forName(name).newInstance();
  973.         return handler;
  974.         } catch(Exception e) {
  975.         }
  976.     }
  977.     
  978.     return UnknownContentHandlerP;
  979.     }
  980.  
  981.     /**
  982.      * Utility function to map a MIME content type into an equivalent
  983.      * pair of class name components.  For example: "text/html" would
  984.      * be returned as "text.html"
  985.      */
  986.     private String typeToPackageName(String contentType) {
  987.     // make sure we canonicalize the class name: all lower case
  988.     contentType = contentType.toLowerCase();
  989.     int len = contentType.length();
  990.     char nm[] = new char[len];
  991.     contentType.getChars(0, len, nm, 0);
  992.     for (int i = 0; i < len; i++) {
  993.         char c = nm[i];
  994.         if (c == '/') {
  995.         nm[i] = '.';
  996.         } else if (!('A' <= c && c <= 'Z' ||
  997.                'a' <= c && c <= 'z' ||
  998.                '0' <= c && c <= '9')) {
  999.         nm[i] = '_';
  1000.         }
  1001.     }
  1002.     return new String(nm);
  1003.     }
  1004.  
  1005.  
  1006.     /**
  1007.      * Returns a vertical bar separated list of package prefixes for potential
  1008.      * content handlers.  Tries to get the java.content.handler.pkgs property
  1009.      * to use as a set of package prefixes to search.  Whether or not
  1010.      * that property has been defined, the sun.net.www.content is always
  1011.      * the last one on the returned package list.
  1012.      */
  1013.     private String getContentHandlerPkgPrefixes() {
  1014.     String packagePrefixList = (String) AccessController.doPrivileged(
  1015.             new sun.security.action.GetPropertyAction(contentPathProp, ""));
  1016.  
  1017.     if (packagePrefixList != "") {
  1018.         packagePrefixList += "|";
  1019.     }
  1020.     
  1021.     return packagePrefixList + contentClassPrefix;
  1022.     }
  1023.  
  1024.     /**
  1025.      * Tries to determine the content type of an object, based 
  1026.      * on the specified "file" component of a URL.
  1027.      * This is a convenience method that can be used by 
  1028.      * subclasses that override the <code>getContentType</code> method. 
  1029.      *
  1030.      * @param   fname   a filename.
  1031.      * @return  a guess as to what the content type of the object is,
  1032.      *          based upon its file name.
  1033.      * @see     java.net.URLConnection#getContentType()
  1034.      */
  1035.     protected static String guessContentTypeFromName(String fname) {
  1036.     String contentType = null;
  1037.     if (fileNameMap != null) {
  1038.         contentType = fileNameMap.getContentTypeFor(fname);
  1039.     }
  1040.  
  1041.     return contentType;
  1042.     }
  1043.  
  1044.     /**
  1045.      * Tries to determine the type of an input stream based on the 
  1046.      * characters at the beginning of the input stream. This method can 
  1047.      * be used by subclasses that override the 
  1048.      * <code>getContentType</code> method. 
  1049.      * <p>
  1050.      * Ideally, this routine would not be needed. But many 
  1051.      * <code>http</code> servers return the incorrect content type; in 
  1052.      * addition, there are many nonstandard extensions. Direct inspection 
  1053.      * of the bytes to determine the content type is often more accurate 
  1054.      * than believing the content type claimed by the <code>http</code> server.
  1055.      *
  1056.      * @param      is   an input stream that supports marks.
  1057.      * @return     a guess at the content type, or <code>null</code> if none
  1058.      *             can be determined.
  1059.      * @exception  IOException  if an I/O error occurs while reading the
  1060.      *               input stream.
  1061.      * @see        java.io.InputStream#mark(int)
  1062.      * @see        java.io.InputStream#markSupported()
  1063.      * @see        java.net.URLConnection#getContentType()
  1064.      */
  1065.     static public String guessContentTypeFromStream(InputStream is) throws IOException
  1066.     {
  1067.     is.mark(10);
  1068.     int c1 = is.read();
  1069.     int c2 = is.read();
  1070.     int c3 = is.read();
  1071.     int c4 = is.read();
  1072.     int c5 = is.read();
  1073.     int c6 = is.read();
  1074.     int c7 = is.read();
  1075.     int c8 = is.read();
  1076.     is.reset();
  1077.     if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE)
  1078.         return "application/java-vm";
  1079.     if (c1 == 0xAC && c2 == 0xED)
  1080.         // next two bytes are version number, currently 0x00 0x05
  1081.         return "application/x-java-serialized-object";
  1082.     if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8')
  1083.         return "image/gif";
  1084.     if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f')
  1085.         return "image/x-bitmap";
  1086.     if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && c5 == 'M' && c6 == '2')
  1087.         return "image/x-pixmap";
  1088.  
  1089.     if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64)
  1090.         return "audio/basic";  // .au format, big endian
  1091.     if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E)
  1092.         return "audio/basic";  // .au format, little endian
  1093.     if (c1 == '<')
  1094.         if (c2 == '!'
  1095.         || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
  1096.                    c3 == 'e' && c4 == 'a' && c5 == 'd')
  1097.              || c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))
  1098.         || ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' ||
  1099.                    c3 == 'E' && c4 == 'A' && c5 == 'D')
  1100.              || c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))
  1101.         return "text/html";
  1102.  
  1103.     if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF && c4 == 0xE0)
  1104.         return "image/jpeg";
  1105.     if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF && c4 == 0xEE)
  1106.         return "image/jpg";
  1107.  
  1108.     if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F')
  1109.         /* I don't know if this is official but evidence
  1110.          * suggests that .wav files start with "RIFF" - brown
  1111.          */
  1112.         return "audio/x-wav";  
  1113.     if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
  1114.         c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
  1115.         /* Above is signature of Microsoft Structured Storage.
  1116.          * Below this, could have tests for various SS entities.
  1117.          * For now, just test for FlashPix.
  1118.          */
  1119.         if (checkfpx(is))
  1120.         return "image/vnd.fpx";
  1121.     }
  1122.     return null;
  1123.     }
  1124.  
  1125.     /**
  1126.      * Check for FlashPix image data in InputStream is.  Return true if
  1127.      * the stream has FlashPix data, false otherwise.  Before calling this
  1128.      * method, the stream should have already been checked to be sure it
  1129.      * contains Microsoft Structured Storage data.
  1130.      */
  1131.     static private boolean checkfpx(InputStream is) throws IOException {
  1132.         /* Test for FlashPix image data in Microsoft Structured Storage format.
  1133.          * In general, should do this with calls to an SS implementation.
  1134.          * Lacking that, need to dig via offsets to get to the FlashPix
  1135.          * ClassID.  Details:
  1136.          *
  1137.          * Offset to Fpx ClsID from beginning of stream should be:  
  1138.          *
  1139.          * FpxClsidOffset = rootEntryOffset + clsidOffset
  1140.          *
  1141.          * where: clsidOffset = 0x50.  
  1142.          *        rootEntryOffset = headerSize + sectorSize*sectDirStart 
  1143.          *                          + 128*rootEntryDirectory
  1144.          *
  1145.          *        where:  headerSize = 0x200 (always)
  1146.          *                sectorSize = 2 raised to power of uSectorShift,
  1147.          *                             which is found in the header at
  1148.          *                             offset 0x1E.
  1149.          *                sectDirStart = found in the header at offset 0x30.
  1150.          *                rootEntryDirectory = in general, should search for 
  1151.          *                                     directory labelled as root.
  1152.          *                                     We will assume value of 0 (i.e.,
  1153.          *                                     rootEntry is in first directory)
  1154.          */
  1155.  
  1156.     // Mark the stream so we can reset it. 0x100 is enough for the first
  1157.     // few reads, but the mark will have to be reset and set again once
  1158.     // the offset to the root directory entry is computed. That offset
  1159.     // can be very large and isn't know until the stream has been read from
  1160.     is.mark(0x100);
  1161.     // Get the byte ordering located at 0x1E. 0xFE is Intel,
  1162.     // 0xFF is other 
  1163.     long toSkip = (long)0x1C;
  1164.     long skipped = 0;
  1165.     while (skipped != toSkip) {
  1166.         skipped += is.skip(toSkip - skipped);
  1167.     }
  1168.     long posn = skipped;
  1169.     int byteOrder = is.read();
  1170.     is.read();
  1171.     posn+=2;
  1172.     int uSectorShift;
  1173.     if(byteOrder == 0xFE) {
  1174.         uSectorShift = is.read();
  1175.         uSectorShift += is.read() << 8;
  1176.     }
  1177.     else {
  1178.         uSectorShift = is.read() << 8;
  1179.         uSectorShift += is.read();
  1180.     }
  1181.     posn += 2;
  1182.     toSkip = (long)0x30 - posn;
  1183.     skipped = 0;
  1184.     while (skipped != toSkip) {
  1185.         skipped += is.skip(toSkip - skipped);
  1186.     }
  1187.     posn += skipped;
  1188.     int sectDirStart;
  1189.     if(byteOrder == 0xFE) {
  1190.         sectDirStart = is.read();
  1191.         sectDirStart += is.read()<<8;
  1192.         sectDirStart += is.read()<<16;
  1193.         sectDirStart += is.read()<<24;
  1194.     }
  1195.     else {
  1196.         sectDirStart = is.read()<<24;
  1197.         sectDirStart += is.read()<<16;
  1198.         sectDirStart += is.read()<<8;
  1199.         sectDirStart += is.read();
  1200.     }
  1201.     posn += 4;
  1202.     is.reset(); // Reset back to the beginning
  1203.  
  1204.     toSkip = (long)0x200 + 
  1205.         (long)((int)1<<uSectorShift)*sectDirStart + (long)0x50;
  1206.  
  1207.     // How far can we skip? Is there any performance problem here?
  1208.     // This skip can be fairly long, at least 0x4c650 in at least
  1209.     // one case. Have to assume that the skip will fit in an int.
  1210.     is.mark((int)toSkip+0x30); // Leave room to read whole root dir
  1211.     skipped = 0;
  1212.     while (skipped != toSkip) {
  1213.         skipped += is.skip(toSkip - skipped);
  1214.     }
  1215.     /* should be at beginning of ClassID, which is as follows
  1216.      * (in Intel byte order):
  1217.      *    00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B
  1218.      *
  1219.      * This is stored from Windows as long,short,short,char[8]
  1220.      * so for byte order changes, the order only changes for 
  1221.      * the first 8 bytes in the ClassID.
  1222.      *
  1223.      * Test against this, ignoring second byte (Intel) since 
  1224.      * this could change depending on part of Fpx file we have.
  1225.      */
  1226.     int c[] = new int[16];
  1227.  
  1228.     for (int i=0; i<16; i++) c[i] = is.read();
  1229.     // intel byte order
  1230.     if (byteOrder == 0xFE && 
  1231.         c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 &&
  1232.         c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE &&
  1233.         c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
  1234.         c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
  1235.         c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
  1236.         is.reset();
  1237.         return true;
  1238.     }
  1239.     // non-intel byte order
  1240.     else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 &&
  1241.         c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE &&
  1242.         c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
  1243.         c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
  1244.         c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
  1245.         is.reset();
  1246.         return true;
  1247.     }
  1248.     is.reset();
  1249.     return false;
  1250.     }
  1251. }
  1252.  
  1253.  
  1254. class UnknownContentHandler extends ContentHandler {
  1255.     public Object getContent(URLConnection uc) throws IOException {
  1256.     return uc.getInputStream();
  1257.     }
  1258. }
  1259.