--- /home/cpdev/src/classpath/gnu/java/net/protocol/jar/Connection.java	2005-07-02 21:03:05.000000000 +0000
+++ gnu/java/net/protocol/jar/Connection.java	2005-07-15 05:34:09.000000000 +0000
@@ -38,6 +38,8 @@
 
 package gnu.java.net.protocol.jar;
 
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -47,9 +49,15 @@
 import java.net.ProtocolException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Locale;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 /**
@@ -60,52 +68,21 @@
  */
 public final class Connection extends JarURLConnection
 {
+  private static Hashtable file_cache = new Hashtable();
+
+  /**
+   * HTTP-style DateFormat, used to format the last-modified header.
+   */
+  private static SimpleDateFormat dateFormat
+    = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'",
+                           new Locale ("En", "Us", "Unix"));
+
   private JarFile jar_file;
-  private JarEntry jar_entry;
-  private URL jar_url;
-  
-  public static class JarFileCache
-  {
-    private static Hashtable cache = new Hashtable();
-    private static final int READBUFSIZE = 4*1024;
-    
-    public static synchronized JarFile get (URL url) throws IOException
-    {
-      JarFile jf = (JarFile) cache.get (url);
-
-      if (jf != null)
-        return jf;
-      
-      if ("file".equals (url.getProtocol()))
-	{
-	  File f = new File (url.getFile());
-	  jf = new JarFile (f, true, ZipFile.OPEN_READ);
-	}
-      else
-	{
-	  URLConnection urlconn = url.openConnection();
-	  InputStream is = urlconn.getInputStream();
-	  byte[] buf = new byte [READBUFSIZE];
-	  File f = File.createTempFile ("cache", "jar");
-	  FileOutputStream fos = new FileOutputStream (f); 
-	  int len = 0;
-	  
-	  while ((len = is.read (buf)) != -1)
-	    {
-	      fos.write (buf, 0, len);
-	    }
-	  
-	  fos.close();
-	  // Always verify the Manifest, open read only and delete when done.
-	  jf = new JarFile (f, true,
-			    ZipFile.OPEN_READ | ZipFile.OPEN_DELETE);
-	}
-          
-      cache.put (url, jf);
-      
-      return jf;
-    }
-  }
+
+  /**
+   * Cached JarURLConnection objects.
+   */
+  static HashMap connectionCache = new HashMap();
 
   protected Connection(URL url)
     throws MalformedURLException
@@ -119,17 +96,23 @@
     if (connected)
       return;
 
-    jar_url = getJarFileURL();
-    jar_file = JarFileCache.get (jar_url);
-    String entry_name = getEntryName();
-    
-    if (entry_name != null
-        && !entry_name.equals (""))
+    if (getUseCaches())
       {
-        jar_entry = (JarEntry) jar_file.getEntry (entry_name);
+	jarFileURLConnection =
+          (URLConnection) connectionCache.get(getJarFileURL());
 
-        if(jar_entry == null)
-          throw new IOException ("No entry for " + entry_name + " exists.");
+	if (jarFileURLConnection == null)
+	  {
+	    jarFileURLConnection = getJarFileURL().openConnection();
+	    jarFileURLConnection.setUseCaches(true);
+	    jarFileURLConnection.connect();
+	    connectionCache.put(getJarFileURL(), jarFileURLConnection);
+	  }
+      }
+    else
+      {
+	jarFileURLConnection = getJarFileURL().openConnection();
+	jarFileURLConnection.connect();
       }
 
     connected = true;
@@ -142,11 +125,64 @@
 
     if (! doInput)
       throw new ProtocolException("Can't open InputStream if doInput is false");
+
+    if (getEntryName() == null)
+      {
+	// This is a JarURLConnection for the entire jar file.  
+
+	InputStream in = new BufferedInputStream
+	  (jarFileURLConnection.getInputStream());
+	return new JarInputStream(in);
+      }
+
+    // Reaching this point, we're looking for an entry of a jar file.
+
+    JarFile jarfile = null;
+
+    try
+      {
+	jarfile = getJarFile ();
+      }
+    catch (IOException x)
+      {
+	/* ignore */
+      }
     
-    if (jar_entry == null)
-      throw new IOException (jar_url + " couldn't be found.");
-    
-    return jar_file.getInputStream (jar_entry);
+    if (jarfile != null)
+      {
+	// this is the easy way...
+	ZipEntry entry = jarfile.getEntry
+	  (gnu.java.net.protocol.file.Connection.unquote(getEntryName()));
+        
+	if (entry != null)
+	  return jarfile.getInputStream (entry);
+	else
+	  return null;
+      }
+    else
+      {
+	// If the jar file is not local, ...
+	JarInputStream zis = new JarInputStream(
+			jarFileURLConnection.getInputStream ());
+
+	String entryName = gnu.java.net.protocol.file.Connection.unquote(getEntryName());
+
+	// This is hideous, we're doing a linear search...
+	for (ZipEntry entry = zis.getNextEntry(); 
+	     entry != null; 
+	     entry = zis.getNextEntry())
+	  {
+	    if (entryName.equals(entry.getName()))
+	      {
+		int size = (int) entry.getSize();
+		byte[] data = new byte[size];
+		zis.read (data, 0, size);
+		return new ByteArrayInputStream (data);
+	      }
+	  }
+      }
+
+    return null;
   }
 
   public synchronized JarFile getJarFile() throws IOException
@@ -157,14 +193,100 @@
     if (! doInput)
       throw new ProtocolException("Can't open JarFile if doInput is false");
 
+    if (jar_file != null)
+      return jar_file;
+
+    URL jarFileURL = getJarFileURL();
+
+    if (jarFileURL.getProtocol().equals ("file")
+	&& jarFileURL.getHost().equals (""))
+      {
+	if (getUseCaches())
+	  {
+	    jar_file = (JarFile) file_cache.get (jarFileURL);
+	    if (jar_file == null)
+	      {
+		jar_file = new JarFile 
+		  (gnu.java.net.protocol.file.Connection.unquote(jarFileURL.getFile()));
+		file_cache.put (jarFileURL, jar_file);
+	      }
+	  }
+	else
+	  jar_file = new JarFile 
+	    (gnu.java.net.protocol.file.Connection.unquote(jarFileURL.getFile()));
+      }
+    else
+      {
+	URLConnection urlconn = jarFileURL.openConnection();
+	InputStream is = urlconn.getInputStream();
+	byte[] buf = new byte[4*1024];
+	File f = File.createTempFile("cache", "jar");
+	FileOutputStream fos = new FileOutputStream(f);
+	int len = 0;
+	while ((len = is.read(buf)) != -1)
+	  fos.write(buf, 0, len);
+        fos.close();
+	// Always verify the Manifest, open read only and delete when done.
+	jar_file = new JarFile (f, true,
+				ZipFile.OPEN_READ | ZipFile.OPEN_DELETE);
+      }
+
     return jar_file;
   }
 
+  public String getHeaderField(String field)
+  {
+    try
+      {
+	if (!connected)
+	  connect();
+
+	if (field.equals("content-type"))
+          return guessContentTypeFromName(getJarEntry().getName());
+	else if (field.equals("content-length"))
+          return Long.toString(getJarEntry().getSize());
+	else if (field.equals("last-modified"))
+	  {
+	    synchronized (dateFormat)
+	      {
+        	return dateFormat.format(new Date(getJarEntry().getTime()));
+	      }
+	  }
+      }
+    catch (IOException e)
+      {
+        // Fall through.
+      }
+    return null;
+  }
+
   public int getContentLength()
   {
     if (!connected)
       return -1;
 
-    return (int) jar_entry.getSize();
+    try
+      {
+        return (int) getJarEntry().getSize();
+      }
+    catch (IOException e)
+      {
+	return -1;
+      }
+  }
+
+  public long getLastModified()
+  {
+    if (!connected)
+      return -1;
+
+    try
+      {
+	return getJarEntry().getTime();
+      }
+    catch (IOException e)
+      {
+	return -1;
+      }
   }
 }
