home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / net / URLConnection.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  44.3 KB  |  1,231 lines

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