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