aboutsummaryrefslogtreecommitdiff
path: root/libjava/java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java')
-rw-r--r--libjava/java/lang/Class.h4
-rw-r--r--libjava/java/lang/Class.java38
-rw-r--r--libjava/java/lang/ClassLoader.java168
-rw-r--r--libjava/java/lang/VMClassLoader.java117
-rw-r--r--libjava/java/lang/natClass.cc6
-rw-r--r--libjava/java/lang/natClassLoader.cc90
-rw-r--r--libjava/java/net/JarURLConnection.java301
-rw-r--r--libjava/java/net/URLClassLoader.java221
-rw-r--r--libjava/java/security/SecureClassLoader.java23
-rw-r--r--libjava/java/util/jar/JarEntry.java39
-rw-r--r--libjava/java/util/jar/JarFile.java56
-rw-r--r--libjava/java/util/jar/JarInputStream.java32
-rw-r--r--libjava/java/util/zip/ZipEntry.java12
-rw-r--r--libjava/java/util/zip/ZipFile.java2
14 files changed, 875 insertions, 234 deletions
diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h
index c4600bf..b038c34 100644
--- a/libjava/java/lang/Class.h
+++ b/libjava/java/lang/Class.h
@@ -16,6 +16,7 @@ details. */
#include <java/lang/Object.h>
#include <java/lang/String.h>
+#include <java/net/URL.h>
// We declare these here to avoid including cni.h.
extern "C" void _Jv_InitClass (jclass klass);
@@ -108,6 +109,7 @@ public:
jstring getName (void);
+ java::net::URL *getResource (jstring resourceName);
java::io::InputStream *getResourceAsStream (jstring resourceName);
JArray<jobject> *getSigners (void);
@@ -182,7 +184,7 @@ private:
friend jclass _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass,
java::lang::ClassLoader *loader);
- friend void _Jv_InternClassStrings (jclass);
+ friend void _Jv_PrepareCompiledClass (jclass);
#ifdef INTERPRETER
friend jboolean _Jv_IsInterpretedClass (jclass);
diff --git a/libjava/java/lang/Class.java b/libjava/java/lang/Class.java
index bc826e9..f9bd59b 100644
--- a/libjava/java/lang/Class.java
+++ b/libjava/java/lang/Class.java
@@ -80,13 +80,41 @@ public final class Class implements Serializable
public native int getModifiers ();
public native String getName ();
- // FIXME: can't implement this until we have java.net.
- // public URL getResource (String resourceName);
+ public java.net.URL getResource (String resourceName)
+ {
+ String name = resourcePath (resourceName);
+ ClassLoader loader = getClassLoader ();
+ if (loader == null)
+ return ClassLoader.getSystemResource (name);
+ else
+ return loader.getResource (name);
+ }
- // FIXME: implement.
- public InputStream getResourceAsStream (String resourceName)
+ public java.io.InputStream getResourceAsStream (String resourceName)
{
- return null;
+ String name = resourcePath (resourceName);
+ ClassLoader loader = getClassLoader ();
+ if (loader == null)
+ return ClassLoader.getSystemResourceAsStream (name);
+ else
+ return loader.getResourceAsStream (name);
+ }
+
+ private String resourcePath (String resourceName)
+ {
+ if (resourceName.startsWith ("/"))
+ return resourceName.substring (1);
+
+ Class c = this;
+ while (c.isArray ())
+ c = c.getComponentType ();
+
+ String packageName = c.getName ().replace ('.', '/');
+ int end = packageName.lastIndexOf ('/');
+ if (end == -1)
+ return resourceName;
+ else
+ return packageName.substring (0, end+1) + resourceName;
}
// FIXME: implement. Requires java.security.
diff --git a/libjava/java/lang/ClassLoader.java b/libjava/java/lang/ClassLoader.java
index 3135740..4d520bb 100644
--- a/libjava/java/lang/ClassLoader.java
+++ b/libjava/java/lang/ClassLoader.java
@@ -26,6 +26,13 @@ import java.util.Stack;
public abstract class ClassLoader {
static private ClassLoader system;
+ private ClassLoader parent;
+
+ public ClassLoader getParent ()
+ {
+ /* FIXME: security */
+ return parent;
+ }
private static native ClassLoader getVMClassLoader0 ();
@@ -36,17 +43,29 @@ public abstract class ClassLoader {
}
/**
- * Creates a <code>ClassLoader</code>. The only thing this
+ * Creates a <code>ClassLoader</code> with no parent.
+ * @exception java.lang.SecurityException if not allowed
+ */
+ protected ClassLoader()
+ {
+ this (null);
+ }
+
+ /**
+ * Creates a <code>ClassLoader</code> with the given parent.
+ * The parent may be <code>null</code>.
+ * The only thing this
* constructor does, is to call
* <code>checkCreateClassLoader</code> on the current
* security manager.
* @exception java.lang.SecurityException if not allowed
*/
- protected ClassLoader()
+ protected ClassLoader(ClassLoader parent)
{
SecurityManager security = System.getSecurityManager ();
if (security != null)
security.checkCreateClassLoader ();
+ this.parent = parent;
}
/**
@@ -59,22 +78,68 @@ public abstract class ClassLoader {
public Class loadClass(String name)
throws java.lang.ClassNotFoundException, java.lang.LinkageError
{
- return loadClass (name, true);
+ return loadClass (name, false);
}
/**
- * Loads the class by the given name.
- * As per java 1.1, this has been deprecated. Use
- * <code>loadClass(String)</code>
- * instead.
+ * Loads the class by the given name. The default implementation
+ * will search for the class in the following order (similar to jdk 1.2)
+ * <ul>
+ * <li> First <code>findLoadedClass</code>.
+ * <li> If parent is non-null, <code>parent.loadClass</code>;
+ * otherwise <code>findSystemClass</code>.
+ * <li> <code>findClass</code>.
+ * </ul>
+ * If <code>link</code> is true, <code>resolveClass</code> is then
+ * called. <p> Normally, this need not be overridden; override
+ * <code>findClass</code> instead.
* @param name the name of the class.
* @param link if the class should be linked.
* @return the class loaded.
* @exception java.lang.ClassNotFoundException
* @deprecated
*/
- protected abstract Class loadClass(String name, boolean link)
- throws java.lang.ClassNotFoundException, java.lang.LinkageError;
+ protected Class loadClass(String name, boolean link)
+ throws java.lang.ClassNotFoundException, java.lang.LinkageError
+ {
+ Class c = findLoadedClass (name);
+
+ if (c == null)
+ {
+ try {
+ if (parent != null)
+ return parent.loadClass (name, link);
+ else
+ c = findSystemClass (name);
+ } catch (ClassNotFoundException ex) {
+ /* ignore, we'll try findClass */;
+ }
+ }
+
+ if (c == null)
+ c = findClass (name);
+
+ if (c == null)
+ throw new ClassNotFoundException (name);
+
+ if (link)
+ resolveClass (c);
+
+ return c;
+ }
+
+ /** Find a class. This should be overridden by subclasses; the
+ * default implementation throws ClassNotFoundException.
+ *
+ * @param name Name of the class to find.
+ * @return The class found.
+ * @exception java.lang.ClassNotFoundException
+ */
+ protected Class findClass (String name)
+ throws ClassNotFoundException
+ {
+ throw new ClassNotFoundException ();
+ }
/**
* Defines a class, given the class-data. According to the JVM, this
@@ -251,7 +316,7 @@ public abstract class ClassLoader {
}
/** Internal method. Calls _Jv_PrepareClass and
- * _Jv_InternClassStrings. This is only called from resolveClass. */
+ * _Jv_PrepareCompiledClass. This is only called from resolveClass. */
private static native void linkClass0(Class clazz)
throws java.lang.LinkageError;
@@ -263,15 +328,19 @@ public abstract class ClassLoader {
/**
* Returns a class found in a system-specific way, typically
- * via the <code>java.class.path</code> system property.
+ * via the <code>java.class.path</code> system property. Loads the
+ * class if necessary.
*
* @param name the class to resolve.
* @return the class loaded.
* @exception java.lang.LinkageError
* @exception java.lang.ClassNotFoundException
*/
- protected native Class findSystemClass(String name)
- throws java.lang.ClassNotFoundException, java.lang.LinkageError;
+ protected Class findSystemClass(String name)
+ throws java.lang.ClassNotFoundException, java.lang.LinkageError
+ {
+ return getSystemClassLoader ().loadClass (name);
+ }
/*
* Does currently nothing.
@@ -280,10 +349,11 @@ public abstract class ClassLoader {
/* claz.setSigners (signers); */
}
- /*
+ /**
* If a class named <code>name</code> was previously loaded using
* this <code>ClassLoader</code>, then it is returned. Otherwise
- * it returns <code>null</code>.
+ * it returns <code>null</code>. (Unlike the JDK this is native,
+ * since we implement the class table internally.)
* @param name class to find.
* @return the class loaded, or null.
*/
@@ -297,10 +367,6 @@ public abstract class ClassLoader {
return system.getResource (name);
}
- public static final byte[] getSystemResourceAsBytes(String name) {
- return system.getResourceAsBytes (name);
- }
-
/**
* Return an InputStream representing the resource name.
* This is essentially like
@@ -309,7 +375,6 @@ public abstract class ClassLoader {
* @param name resource to load
* @return an InputStream, or null
* @see java.lang.ClassLoader#getResource(String)
- * @see java.lang.ClassLoader#getResourceAsBytes(String)
* @see java.io.InputStream
*/
public InputStream getResourceAsStream(String name)
@@ -324,41 +389,8 @@ public abstract class ClassLoader {
}
/**
- * Return a byte array <code>byte[]</code> representing the
- * resouce <code>name</code>. This only works for resources
- * that have a known <code>content-length</code>, and
- * it will block while loading the resource. Returns null
- * for error conditions.<p>
- * Since it is synchroneous, this is only convenient for
- * resources that are "readily" available. System resources
- * can conveniently be loaded this way, and the runtime
- * system uses this to load class files. <p>
- * To find the class data for a given class, use
- * something like the following:
- * <ul><code>
- * String res = clazz.getName().replace ('.', '/')) + ".class";<br>
- * byte[] data = getResourceAsBytes (res);
- * </code></ul>
- * @param name resource to load
- * @return a byte array, or null
- * @see java.lang.ClassLoader#getResource(String)
- * @see java.lang.ClassLoader#getResourceAsStream(String)
- */
- public byte[] getResourceAsBytes(String name) {
- try {
- URL res = getResource (name);
- if (res == null) return null;
- URLConnection conn = res.openConnection ();
- int len = conn.getContentLength ();
- if (len == -1) return null;
- return readbytes (conn.getInputStream (), len);
- } catch (java.io.IOException x) {
- return null;
- }
- }
-
- /**
* Return an java.io.URL representing the resouce <code>name</code>.
+ * The default implementation just returns <code>null</code>.
* @param name resource to load
* @return a URL, or null if there is no such resource.
* @see java.lang.ClassLoader#getResourceAsBytes(String)
@@ -369,31 +401,5 @@ public abstract class ClassLoader {
return null;
}
- /**
- * Utility routine to read a resource fully, even if the given
- * InputStream only provides partial results.
- */
- private static byte[] readbytes (InputStream is, int length)
- {
- try {
-
- byte[] data = new byte[length];
- int read;
- int off = 0;
-
- while (off != length)
- {
- read = is.read (data, off, (int) (length-off));
-
- if (read == -1)
- return null;
-
- off += read;
- }
-
- return data;
- } catch (java.io.IOException x) {
- return null;
- }
- }
}
+
diff --git a/libjava/java/lang/VMClassLoader.java b/libjava/java/lang/VMClassLoader.java
deleted file mode 100644
index 026f6d8..0000000
--- a/libjava/java/lang/VMClassLoader.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/* Copyright (C) 1999 Cygnus Solutions
-
- This file is part of libgcj.
-
-This software is copyrighted work licensed under the terms of the
-Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
-details. */
-
-/* Author: Kresten Krab Thorup <krab@gnu.org> */
-
-package java.lang;
-
-import java.io.*;
-import java.net.URL;
-import gnu.gcj.util.path.SearchPath;
-
-final class VMClassLoader extends java.lang.ClassLoader
-{
- private SearchPath path;
- private final String path_seperator;
- private final String file_seperator;
- private final char file_seperator_char;
-
- private VMClassLoader () {
- path_seperator = System.getProperty ("path.separator", ":");
- file_seperator = System.getProperty ("file.separator", "/");
-
- file_seperator_char = file_seperator.charAt (0);
-
- String class_path = System.getProperty ("java.class.path", ".");
- path = new SearchPath (class_path);
- }
-
- protected Class loadClass(String name,
- boolean resolve)
- throws java.lang.ClassNotFoundException, java.lang.LinkageError
- {
- return loadClassInternal (name, resolve, false);
- }
-
- /** I'm a little in doubt here, if this method is
- actually supposed to throw a LinkageError, or not.
- The spec, 20.14.3, is a little unclear. It says:
-
- `` The general contract of loadClass is that, given the name
- of a class, it either returns the Class object for the class
- or throws a ClassNotFoundException.''
-
- However, by making LinkageError a checked exception,
- i.e., mention it directly in the throws clause,
- we'll force caller to consider that case as well.
- **/
-
- protected Class loadClassInternal(String name,
- boolean resolve,
- boolean fromBootLoader)
- throws java.lang.ClassNotFoundException, java.lang.LinkageError
- {
- Class clazz;
-
- /** TODO: call _Jv_VerifyClassName **/
- if ( (name.indexOf ('/') != -1)
- || (name.charAt (0) == '.')
- || (name.indexOf (file_seperator) != -1)
- || (name.indexOf ("..") != -1))
- {
- throw new IllegalArgumentException (name);
- }
-
- // already loaded?
- clazz = findLoadedClass (name);
-
- // we need access to the boot class loader here
- if (clazz == null && !fromBootLoader)
- clazz = findBootClass (name);
-
- if (clazz == null)
- {
- StringBuffer res = new StringBuffer ();
-
- // here we do actually replace .'s with /'s because
- // we're going to find something in the file system.
- res.append (name.replace ('.', file_seperator_char));
- res.append (".class");
-
- byte[] data = getResourceAsBytes (res.toString ());
-
- if (data == null)
- throw new ClassNotFoundException (name);
-
- clazz = defineClass (name, data, 0, data.length);
-
- }
-
- if (resolve && clazz != null)
- resolveClass (clazz);
-
- return clazz;
- }
-
- private native Class findBootClass (String name);
-
- public InputStream getResourceAsStream(String name)
- {
- return path.getStream (name);
- }
-
- public URL getResource(String name)
- {
- return path.getURL (name);
- }
-
- public byte[] getResourceAsBytes(String name)
- {
- return path.getBytes (name);
- }
-}
diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc
index 01058dc..ff5e9c6 100644
--- a/libjava/java/lang/natClass.cc
+++ b/libjava/java/lang/natClass.cc
@@ -92,8 +92,6 @@ java::lang::Class::forName (jstring className)
if (! klass)
JvThrow (new java::lang::ClassNotFoundException (className));
- _Jv_InitClass (klass);
-
return klass;
}
@@ -354,6 +352,8 @@ java::lang::Class::newInstance (void)
|| java::lang::reflect::Modifier::isAbstract(accflags))
JvThrow (new java::lang::InstantiationException);
+ _Jv_InitClass (this);
+
_Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature);
if (! meth)
JvThrow (new java::lang::NoSuchMethodException);
@@ -408,7 +408,7 @@ java::lang::Class::initializeClass (void)
{
// Step 1.
_Jv_MonitorEnter (this);
- _Jv_InternClassStrings (this);
+ _Jv_PrepareCompiledClass (this);
}
}
else
diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc
index 0caaa4c..c35417c 100644
--- a/libjava/java/lang/natClassLoader.cc
+++ b/libjava/java/lang/natClassLoader.cc
@@ -20,8 +20,9 @@ details. */
#include <java/lang/Character.h>
#include <java/lang/Thread.h>
#include <java/lang/ClassLoader.h>
-#include <java/lang/VMClassLoader.h>
+#include <gnu/gcj/runtime/VMClassLoader.h>
#include <java/lang/InternalError.h>
+#include <java/lang/IllegalAccessError.h>
#include <java/lang/LinkageError.h>
#include <java/lang/ClassFormatError.h>
#include <java/lang/NoClassDefFoundError.h>
@@ -46,7 +47,7 @@ extern java::lang::Class ClassLoaderClass;
/////////// java.lang.ClassLoader native methods ////////////
#ifdef INTERPRETER
-java::lang::VMClassLoader *redirect = 0;
+gnu::gcj::runtime::VMClassLoader *redirect = 0;
#endif
java::lang::ClassLoader*
@@ -54,7 +55,7 @@ java::lang::ClassLoader::getVMClassLoader0 ()
{
#ifdef INTERPRETER
if (redirect == 0)
- redirect = new java::lang::VMClassLoader;
+ redirect = new gnu::gcj::runtime::VMClassLoader;
return redirect;
#else
return 0;
@@ -144,7 +145,7 @@ _Jv_WaitForState (jclass klass, int state)
if (state == JV_STATE_LINKED)
{
_Jv_MonitorExit (klass);
- _Jv_InternClassStrings (klass);
+ _Jv_PrepareCompiledClass (klass);
return;
}
@@ -179,7 +180,7 @@ java::lang::ClassLoader::linkClass0 (java::lang::Class *klass)
}
#endif
- _Jv_InternClassStrings (klass);
+ _Jv_PrepareCompiledClass (klass);
}
void
@@ -193,7 +194,7 @@ java::lang::ClassLoader::markClassErrorState0 (java::lang::Class *klass)
/** this is the only native method in VMClassLoader, so
we define it here. */
jclass
-java::lang::VMClassLoader::findBootClass (jstring name)
+gnu::gcj::runtime::VMClassLoader::findSystemClass (jstring name)
{
return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), 0);
}
@@ -204,22 +205,27 @@ java::lang::ClassLoader::findLoadedClass (jstring name)
return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), this);
}
-jclass
-java::lang::ClassLoader::findSystemClass (jstring name)
-{
- return _Jv_FindClass (_Jv_makeUtf8Const (name), 0);
-}
-
-
-/* This is the final step of linking, internalizing the constant strings
- * of a class. This is called for both compiled and interpreted
- * classes, and it is *only* called from ClassLoader::linkClass0,
- * which is always in a context where the current thread has a lock on
- * the class in question. We define it here, and not in resolve.cc, so that
- * the entire resolve.cc can be #ifdef'ed away when not using the
- * interpreter. */
+static const int PUBLIC = 0x001;
+static const int PRIVATE = 0x002;
+static const int PROTECTED = 0x004;
+static const int STATIC = 0x008;
+static const int FINAL = 0x010;
+static const int SYNCHRONIZED = 0x020;
+static const int VOLATILE = 0x040;
+static const int TRANSIENT = 0x080;
+static const int NATIVE = 0x100;
+static const int INTERFACE = 0x200;
+static const int ABSTRACT = 0x400;
+static const int ALL_FLAGS = 0x7FF;
+
+
+/** This function does class-preparation for compiled classes.
+ NOTE: This function replicates functionality from
+ _Jv_ResolvePoolEntry, and this is intentional, since that function
+ is
+ */
void
-_Jv_InternClassStrings(jclass klass)
+_Jv_PrepareCompiledClass(jclass klass)
{
if (klass->state >= JV_STATE_LINKED)
return;
@@ -228,14 +234,44 @@ _Jv_InternClassStrings(jclass klass)
klass->state = JV_STATE_LINKED;
_Jv_Constants *pool = &klass->constants;
- for (int i = 1; i < pool->size; ++i)
+ for (int index = 1; index < pool->size; ++index)
{
- if (pool->tags[i] == JV_CONSTANT_String)
+ if (pool->tags[index] == JV_CONSTANT_Class)
+ {
+ _Jv_Utf8Const *name = pool->data[index].utf8;
+
+ jclass found;
+ if (name->data[0] == '[')
+ found = _Jv_FindClassFromSignature (&name->data[0],
+ klass->loader);
+ else
+ found = _Jv_FindClass (name, klass->loader);
+
+ if (! found)
+ {
+ jstring str = _Jv_NewStringUTF (name->data);
+ JvThrow (new java::lang::ClassNotFoundException (str));
+ }
+
+ if ((found->accflags & PUBLIC) == PUBLIC
+ || (_Jv_ClassNameSamePackage (found->name,
+ klass->name)))
+ {
+ pool->data[index].clazz = found;
+ pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
+ }
+ else
+ {
+ JvThrow (new java::lang::IllegalAccessError (found->getName()));
+ }
+ }
+
+ else if (pool->tags[index] == JV_CONSTANT_String)
{
jstring str;
- str = _Jv_NewStringUtf8Const (pool->data[i].utf8);
- pool->data[i].string = str;
- pool->tags[i] |= JV_CONSTANT_ResolvedFlag;
+ str = _Jv_NewStringUtf8Const (pool->data[index].utf8);
+ pool->data[index].o = str;
+ pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
}
}
@@ -443,7 +479,7 @@ jclass _Jv_FindClass (_Jv_Utf8Const *name,
}
// Load using the bootstrap loader jmspec 5.3.1
- klass = redirect -> loadClassInternal (sname, false, true);
+ klass = redirect -> loadClass (sname, false);
// register that we're an initiating loader
if (klass)
diff --git a/libjava/java/net/JarURLConnection.java b/libjava/java/net/JarURLConnection.java
new file mode 100644
index 0000000..8eb4b7d
--- /dev/null
+++ b/libjava/java/net/JarURLConnection.java
@@ -0,0 +1,301 @@
+/* Copyright (C) 1999 Cygnus Solutions
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package java.net;
+
+import java.net.*;
+import java.io.*;
+import java.util.jar.*;
+import java.util.zip.*;
+import java.util.Vector;
+import java.util.Hashtable;
+
+/**
+ * @author Kresten Krab Thorup <krab@gnu.org>
+ * @date Aug 10, 1999.
+ */
+
+
+public abstract class JarURLConnection extends URLConnection
+{
+ // three different ways to say the same thing
+ private final URL jarFileURL;
+
+ /** The connection to the jar file itself. A JarURLConnection
+ * can represent an entry in a jar file or an entire jar file. In
+ * either case this describes just the jar file itself. */
+ protected URLConnection jarFileURLConnection;
+
+ // If this is a connection to a jar file element this is set, otherwose null.
+ private final String element;
+
+ // Cached JarURLConnection's
+ static Hashtable conn_cache = new Hashtable();
+
+ public URL getJarFileURL ()
+ {
+ return jarFileURL;
+ }
+
+ public String getEntryName ()
+ {
+ return element;
+ }
+
+ public JarURLConnection(URL url)
+ throws MalformedURLException
+ {
+ super(url);
+
+ String spec = url.getFile();
+ int bang = spec.indexOf ("!/", 0);
+ if (bang == -1)
+ throw new MalformedURLException (url + ": No `!/' in spec.");
+
+ // Extact the url for the jar itself.
+ jarFileURL = new URL(spec.substring (0, bang));
+
+ // Get the name of the element, if any.
+ element = (bang+2==spec.length() ? null : spec.substring (bang+2));
+ }
+
+ public synchronized void connect() throws IOException
+ {
+ // Call is ignored if already connected.
+ if (connected)
+ return;
+
+ if (getUseCaches())
+ {
+ jarFileURLConnection = (URLConnection) conn_cache.get (jarFileURL);
+
+ if (jarFileURLConnection == null)
+ {
+ jarFileURLConnection = jarFileURL.openConnection ();
+ jarFileURLConnection.setUseCaches (true);
+ jarFileURLConnection.connect ();
+ conn_cache.put (jarFileURL, jarFileURLConnection);
+ }
+ }
+ else
+ {
+ jarFileURLConnection = jarFileURL.openConnection ();
+ jarFileURLConnection.connect ();
+ }
+
+ connected = true;
+ }
+
+ public InputStream getInputStream() throws IOException
+ {
+ if (!connected)
+ connect();
+
+ if (! doInput)
+ throw new ProtocolException("Can't open InputStream if doInput is false");
+
+ if (element == null)
+ {
+ // This is a JarURLConnection for the entire jar file.
+
+ InputStream jar_is = new BufferedInputStream(jarFileURLConnection.getInputStream ());
+ return new JarInputStream(jar_is);
+ }
+
+ // Reaching this point, we're looking for an element of a jar file.
+
+ JarFile jarfile = null;
+
+ try
+ {
+ jarfile = getJarFile ();
+ }
+ catch (java.io.IOException x)
+ {
+ /* ignore */
+ }
+
+ if (jarfile != null)
+ {
+ // this is the easy way...
+ return jarfile.getInputStream (jarfile.getEntry (element));
+ }
+ else
+ {
+ // If the jar file is not local, ...
+ JarInputStream zis = new JarInputStream(jarFileURLConnection.getInputStream ());
+
+ // This is hideous, we're doing a linear search...
+ for (ZipEntry ent = zis.getNextEntry ();
+ ent != null;
+ ent = zis.getNextEntry ())
+ {
+ if (element.equals (ent.getName ()))
+ {
+ int size = (int)ent.getSize();
+ byte[] data = new byte[size];
+ zis.read (data, 0, size);
+ return new ByteArrayInputStream (data);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public JarEntry getJarEntry (String name)
+ throws java.io.IOException
+ {
+ JarFile jarfile = null;
+
+ if (! doInput)
+ throw new ProtocolException("Can't open JarEntry if doInput is false");
+
+ try
+ {
+ jarfile = getJarFile ();
+ }
+ catch (java.io.IOException x)
+ {
+ /* ignore */
+ }
+
+ if (jarfile == null)
+ {
+ JarInputStream zis = new JarInputStream(jarFileURLConnection.getInputStream ());
+
+ // This is hideous, we're doing a linear search for the thing...
+ for (ZipEntry ent = zis.getNextEntry ();
+ ent != null;
+ ent = zis.getNextEntry ())
+ {
+ if (element.equals (ent.getName ()))
+ {
+ return new JarEntry (ent);
+ }
+ }
+ }
+
+ else
+ {
+ return jarfile.getJarEntry (element);
+ }
+
+ return null;
+ }
+
+ public abstract JarFile getJarFile() throws java.io.IOException;
+
+
+ // Steal and borrow from protocol/file/Connection.java
+
+ private Hashtable hdrHash = new Hashtable();
+ private Vector hdrVec = new Vector();
+ private boolean gotHeaders = false;
+
+ // Override default method in URLConnection.
+ public String getHeaderField(String name)
+ {
+ try
+ {
+ getHeaders();
+ }
+ catch (IOException x)
+ {
+ return null;
+ }
+ return (String) hdrHash.get(name.toLowerCase());
+ }
+
+ // Override default method in URLConnection.
+ public String getHeaderField(int n)
+ {
+ try
+ {
+ getHeaders();
+ }
+ catch (IOException x)
+ {
+ return null;
+ }
+ if (n < hdrVec.size())
+ return getField((String) hdrVec.elementAt(n));
+
+ return null;
+ }
+
+ // Override default method in URLConnection.
+ public String getHeaderFieldKey(int n)
+ {
+ try
+ {
+ getHeaders();
+ }
+ catch (IOException x)
+ {
+ return null;
+ }
+ if (n < hdrVec.size())
+ return getKey((String) hdrVec.elementAt(n));
+
+ return null;
+ }
+
+ private String getKey(String str)
+ {
+ if (str == null)
+ return null;
+ int index = str.indexOf(':');
+ if (index >= 0)
+ return str.substring(0, index);
+ else
+ return null;
+ }
+
+ private String getField(String str)
+ {
+ if (str == null)
+ return null;
+ int index = str.indexOf(':');
+ if (index >= 0)
+ return str.substring(index + 1).trim();
+ else
+ return str;
+ }
+
+ private void getHeaders() throws IOException
+ {
+ if (gotHeaders)
+ return;
+ gotHeaders = true;
+
+ connect();
+
+ // Yes, it is overkill to use the hash table and vector here since
+ // we're only putting one header in the file, but in case we need
+ // to add others later and for consistency, we'll implement it this way.
+
+ // Add the only header we know about right now: Content-length.
+ long len;
+
+ if (element == null)
+ len = jarFileURLConnection.getContentLength ();
+ else
+ len = getJarEntry (element).getSize ();
+
+ String line = "Content-length: " + len;
+ hdrVec.addElement(line);
+
+ // The key will never be null in this scenario since we build up the
+ // headers ourselves. If we ever rely on getting a header from somewhere
+ // else, then we may have to check if the result of getKey() is null.
+ String key = getKey(line);
+ hdrHash.put(key.toLowerCase(), Long.toString(len));
+ }
+
+}
diff --git a/libjava/java/net/URLClassLoader.java b/libjava/java/net/URLClassLoader.java
new file mode 100644
index 0000000..df34306
--- /dev/null
+++ b/libjava/java/net/URLClassLoader.java
@@ -0,0 +1,221 @@
+/* Copyright (C) 1999 Cygnus Solutions
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package java.net;
+
+import java.io.*;
+import java.util.jar.*;
+import java.util.Vector;
+
+public class URLClassLoader extends ClassLoader
+{
+ // The URLStreamHandlerFactory
+ URLStreamHandlerFactory factory = null;
+
+ // `path' contains simply the URL's we're using for the searching.
+ private Vector path;
+
+ // If path[n] is a zip/jar, then this holds a JarURLConnection for that thing,
+ // otherwise, path[n] is null.
+ private Vector info;
+
+ private URLStreamHandler getHandler0 (String protocol)
+ {
+ if (factory != null)
+ return factory.createURLStreamHandler(protocol);
+ else
+ return null;
+ }
+
+ public URLClassLoader (URL[] urls)
+ {
+ this (urls, null, null);
+ }
+
+ public URLClassLoader (URL[] urls, ClassLoader parent)
+ {
+ this (urls, parent, null);
+ }
+
+ public URLClassLoader (URL[] urls, ClassLoader parent,
+ URLStreamHandlerFactory fac)
+ {
+ super (parent);
+
+ factory = fac;
+
+ if (urls == null || urls.length == 0)
+ {
+ path = new Vector (1);
+ info = new Vector (1);
+ return;
+ }
+
+ path = new Vector (urls.length);
+ info = new Vector (urls.length);
+
+ for (int i = 0; i < urls.length; i++)
+ {
+ URL u = urls[i];
+
+ // If it is a jar url, then we'll search it as is.
+ if (! u.getProtocol ().equals ("jar"))
+ {
+ String f = u.getFile ();
+
+ // If it ends with '/' we'll take it for a directory,
+ // otherwise it's a jar file. This is how JDK 1.2 defines
+ // it, so we will not try to be smart here.
+ if (f.charAt (f.length ()-1) != '/')
+ {
+ try
+ {
+ u = new URL ("jar", "", -1, (u.toExternalForm ())+"!/",
+ getHandler0 ("jar"));
+ }
+ catch (MalformedURLException x)
+ {
+ /* ignore */
+ }
+ }
+ }
+
+ path.insertElementAt (u, i);
+
+ if (u.getProtocol ().equals ("jar"))
+ {
+ JarURLConnection conn = null;
+ try
+ {
+ conn = (JarURLConnection) u.openConnection ();
+ }
+ catch (java.io.IOException x)
+ {
+ /* ignore */
+ }
+ info.insertElementAt (conn, i);
+ }
+ else
+ {
+ info.insertElementAt (null, i);
+ }
+ }
+ }
+
+ public URL getResource (String name)
+ {
+ for (int i = 0; i < path.size(); i++)
+ {
+ URL u = (URL)path.elementAt (i);
+
+ try {
+ JarURLConnection conn = (JarURLConnection) info.elementAt (i);
+
+ if (conn != null)
+ {
+ if (conn.getJarEntry (name) != null)
+ return new URL(u, name, getHandler0 (u.getProtocol()));
+ }
+ else
+ {
+ URL p = new URL (u, name, getHandler0 (u.getProtocol()));
+
+ InputStream is = p.openStream();
+ if (is != null)
+ {
+ is.close();
+ return p;
+ }
+ }
+
+ // if we get an exception ... try the next path element
+ } catch (IOException x) {
+ continue;
+ }
+ }
+
+ return null;
+ }
+
+ /** IN jdk 1.2 this method is not overridden, but we gain performance
+ by doing so.
+ */
+
+ public InputStream getResourceAsStream (String name)
+ {
+ for (int i = 0; i < path.size(); i++)
+ {
+ URL u = (URL)path.elementAt (i);
+
+ try {
+ JarURLConnection conn = (JarURLConnection) info.elementAt (i);
+
+ if (conn != null)
+ {
+ JarFile file = conn.getJarFile ();
+ JarEntry ent = file.getJarEntry (name);
+ if (ent != null)
+ return file.getInputStream(ent);
+ }
+ else
+ {
+ InputStream is = new URL(u, name, getHandler0 (u.getProtocol())).openStream();
+ if (is != null)
+ return is;
+ }
+
+ // if we get an exception ... try the next path element
+ } catch (IOException x) {
+ continue;
+ }
+ }
+
+ return null;
+ }
+
+ // and finally, we can implement our class loader functionality.
+ protected Class findClass (String name)
+ throws ClassNotFoundException
+ {
+ if (name == null)
+ throw new ClassNotFoundException ("null");
+
+ try
+ {
+ InputStream is = getResourceAsStream (name.replace ('.', '/') + ".class");
+
+ if (is == null)
+ throw new ClassNotFoundException (name);
+
+ // Here we have to rely on available() to provide the length of
+ // the class; which might not be exactly right in some cases...
+
+ int len = is.available ();
+ byte[] data = new byte[len];
+
+ int left = len;
+ int off = 0;
+ while (left > 0)
+ {
+ int c = is.read (data, off, len-off);
+ if (c == -1 || c == 0)
+ throw new InternalError ("premature end of file");
+ left -= c;
+ off += c;
+ }
+
+ return defineClass (name, data, 0, len);
+ }
+ catch (java.io.IOException x)
+ {
+ throw new ClassNotFoundException(name);
+ }
+ }
+
+}
+
diff --git a/libjava/java/security/SecureClassLoader.java b/libjava/java/security/SecureClassLoader.java
new file mode 100644
index 0000000..b195035
--- /dev/null
+++ b/libjava/java/security/SecureClassLoader.java
@@ -0,0 +1,23 @@
+/* Copyright (C) 1998, 1999 Cygnus Solutions
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package java.security;
+
+public class SecureClassLoader extends ClassLoader
+{
+ public SecureClassLoader ()
+ {
+ this (null);
+ }
+
+ public SecureClassLoader (ClassLoader parent)
+ {
+ super (parent);
+ }
+}
+
diff --git a/libjava/java/util/jar/JarEntry.java b/libjava/java/util/jar/JarEntry.java
new file mode 100644
index 0000000..0fe202b
--- /dev/null
+++ b/libjava/java/util/jar/JarEntry.java
@@ -0,0 +1,39 @@
+/* Copyright (C) 1999 Cygnus Solutions
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package java.util.jar;
+
+import java.util.zip.*;
+
+/**
+ * Does not implement the security and manifest methods.
+ *
+ * @author Kresten Krab Thorup <krab@gnu.org>
+ * @date August 10, 1999.
+ */
+
+public class JarEntry extends ZipEntry
+{
+ ZipEntry zip;
+
+ public JarEntry (ZipEntry ent)
+ {
+ super (ent);
+ }
+
+ public JarEntry (JarEntry ent)
+ {
+ super (ent);
+ }
+
+ public JarEntry (String name)
+ {
+ super (name);
+ }
+
+}
diff --git a/libjava/java/util/jar/JarFile.java b/libjava/java/util/jar/JarFile.java
new file mode 100644
index 0000000..efab3c2
--- /dev/null
+++ b/libjava/java/util/jar/JarFile.java
@@ -0,0 +1,56 @@
+/* Copyright (C) 1999 Cygnus Solutions
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package java.util.jar;
+
+import java.util.zip.*;
+import java.io.File;
+
+/**
+ * Does not implement any of the security. Just a place holder, so
+ * that I can implement URLClassLoader.
+ *
+ * @author Kresten Krab Thorup <krab@gnu.org>
+ * @date August 10, 1999.
+ */
+
+public class JarFile extends ZipFile
+{
+ private boolean verify;
+
+ public JarFile (String file) throws java.io.IOException
+ {
+ super (file);
+ }
+
+ public JarFile (File file) throws java.io.IOException
+ {
+ super (file);
+ }
+
+ public JarFile (String file, boolean verify) throws java.io.IOException
+ {
+ super (file);
+ this.verify = verify;
+ }
+
+ public JarFile (File file, boolean verify) throws java.io.IOException
+ {
+ super (file);
+ this.verify = verify;
+ }
+
+ public JarEntry getJarEntry (String name)
+ {
+ ZipEntry ent = getEntry(name);
+ if (ent == null)
+ return null;
+ else
+ return new JarEntry(ent);
+ }
+}
diff --git a/libjava/java/util/jar/JarInputStream.java b/libjava/java/util/jar/JarInputStream.java
new file mode 100644
index 0000000..476e75f
--- /dev/null
+++ b/libjava/java/util/jar/JarInputStream.java
@@ -0,0 +1,32 @@
+/* Copyright (C) 1999 Cygnus Solutions
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package java.util.jar;
+
+import java.util.zip.*;
+
+/**
+ * Does not implement any of the security. Just a place holder, so
+ * that I can implement URLClassLoader.
+ *
+ * @author Kresten Krab Thorup <krab@gnu.org>
+ * @date August 10, 1999.
+ */
+
+public class JarInputStream extends ZipInputStream
+{
+ public JarEntry getNextJarEntry () throws java.io.IOException
+ {
+ return new JarEntry (getNextEntry ());
+ }
+
+ public JarInputStream (java.io.InputStream is)
+ {
+ super(is);
+ }
+}
diff --git a/libjava/java/util/zip/ZipEntry.java b/libjava/java/util/zip/ZipEntry.java
index 9bd3c41..915c4b2 100644
--- a/libjava/java/util/zip/ZipEntry.java
+++ b/libjava/java/util/zip/ZipEntry.java
@@ -46,6 +46,18 @@ public class ZipEntry implements ZipConstants
this.name = name;
}
+ public ZipEntry (ZipEntry ent)
+ {
+ comment = ent.comment;
+ compressedSize = ent.compressedSize;
+ crc = ent.crc;
+ extra = ent.extra;
+ method = ent.method;
+ size = ent.size;
+ time = ent.time;
+ relativeOffset = ent.relativeOffset;
+ }
+
public String getComment () { return comment; }
public long getCompressedSize () { return compressedSize; }
diff --git a/libjava/java/util/zip/ZipFile.java b/libjava/java/util/zip/ZipFile.java
index bfb077d..1b0ebce 100644
--- a/libjava/java/util/zip/ZipFile.java
+++ b/libjava/java/util/zip/ZipFile.java
@@ -22,12 +22,14 @@ public class ZipFile implements ZipConstants
{
file = new RandomAccessFile(fname, "r");
name = fname;
+ readDirectory ();
}
public ZipFile (File f) throws IOException
{
file = new RandomAccessFile(f, "r");
name = f.getName();
+ readDirectory ();
}
void readDirectory () throws IOException